diff --git a/.agent/rules/commit_style.md b/.agent/rules/commit_style.md new file mode 100644 index 000000000000..668bbbbde84e --- /dev/null +++ b/.agent/rules/commit_style.md @@ -0,0 +1,28 @@ +--- +trigger: always_on +--- + +# Agent Commit Rules + +The user requires all commit messages generated by the agent to follow a specific style and include a proper sign-off. + +## Commit Message Style + +Commit messages must be formatted with a subject line and a body, following this format: +``` +: + + +``` + +* **``**: A short name or tag representing the feature or component being modified. +* **``**: A succinct one-line description of the change. +* **``**: A detailed description of the changes made in the commit. The body must be at least one sentence describing the changes. + +## Sign-off + +Every commit message must end with a `Signed-off-by:` line using the patch author's name and email (from the local git config): + +``` +Signed-off-by: +``` diff --git a/.agent/rules/documentation.md b/.agent/rules/documentation.md new file mode 100644 index 000000000000..5d88e6aa3dd4 --- /dev/null +++ b/.agent/rules/documentation.md @@ -0,0 +1,13 @@ +# Documentation Rules + +The user expects all new features and in-code documentation to adhere to Doxygen standards. + +## Doxygen Requirements + +1. **Mandatory Documentation:** All new features, functions, and structures must include Doxygen comments describing their purpose, parameters, and return values. +2. **Clean Build:** Any in-code documentation added or modified must build with Doxygen without producing any new errors or warnings. +3. **Format:** Use standard Doxygen formatting tags (e.g., `@brief`, `@param`, `@return` or `\brief`, `\param`, `\return`). Ensure the styling matches the existing codebase conventions. + +## Directory Documentation + +When creating a new file or modifying an existing one, check if there is an `architecture.md` or `readme.md` (or `README.md`) file in the same directory. If present, evaluate whether the code changes require an update to these documentation files and make the necessary updates to keep them synchronized with the code. diff --git a/.agent/rules/topology2_design.md b/.agent/rules/topology2_design.md new file mode 100644 index 000000000000..35d98473a57c --- /dev/null +++ b/.agent/rules/topology2_design.md @@ -0,0 +1,12 @@ +--- +trigger: glob +glob: tools/topology/topology2/** +--- + +# Topology2 Design Rule + +When working in tools/topology/topology2, follow the canonical guidance in +.github/instructions/topology2-design.instructions.md. + +Apply those instructions for topology structure, ID assignment, routing, +platform overrides, and topology target registration. \ No newline at end of file diff --git a/.agent/workflows/build_and_validate.md b/.agent/workflows/build_and_validate.md new file mode 100644 index 000000000000..7a3614fc8254 --- /dev/null +++ b/.agent/workflows/build_and_validate.md @@ -0,0 +1,22 @@ +--- +description: Build and validate new C code features +--- + +This workflow describes the process for building and validating any new C code features in the SOF repository. + +**Note:** The QEMU build targets must be used for both building and testing. The user requires the build must be error and warning free and the ztests must all pass. + +// turbo-all +1. Build the new C code feature using the `xtensa-build-zephyr.py` script. + ```bash + source ../.venv/bin/activate + ./scripts/xtensa-build-zephyr.py qemu_xtensa + ``` + +2. Validate the feature with a ztest run using the `sof-qemu-run.sh` script. + ```bash + source ../.venv/bin/activate + ./scripts/sof-qemu-run.sh build-qemu_xtensa + ``` + +3. Ensure that all new features and functions have appropriate Doxygen comments and that the Doxygen documentation builds without errors or warnings. \ No newline at end of file diff --git a/.agent/workflows/module_development.md b/.agent/workflows/module_development.md new file mode 100644 index 000000000000..6036da58034d --- /dev/null +++ b/.agent/workflows/module_development.md @@ -0,0 +1,22 @@ +--- +description: Develop and validate new audio processing modules +--- + +This workflow describes the expected steps to create and validate a new audio processing module within the SOF repository. + +// turbo-all +1. **(Optional)** Generate the module skeleton using the `sdk-create-module.py` script. + ```bash + # Run the script with relevant arguments to create a new module template + ./scripts/sdk-create-module.py --name --version + ``` + +2. Develop the module logic within the generated skeleton. + +3. Validate the module by executing the module within the host testbench. This ensures that the module functions as expected outside of full system simulations. + ```bash + # Configure and run the testbench against the developed module + ./scripts/host-testbench.sh -l + ``` + +4. Document the new module using Doxygen comments. Validate that the Doxygen build completes without errors or warnings. Add a README.md for the module. \ No newline at end of file diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000000..145353dd0a2d --- /dev/null +++ b/.clang-format @@ -0,0 +1,121 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Note: The list of ForEachMacros can be obtained using: +# +# git grep -h '^#define [^[:space:]]*FOR_EACH[^[:space:]]*(' include/ \ +# | sed "s,^#define \([^[:space:]]*FOR_EACH[^[:space:]]*\)(.*$, - '\1'," \ +# | sort | uniq +# +# References: +# - https://clang.llvm.org/docs/ClangFormatStyleOptions.html +# +# Based on https://github.com/zephyrproject-rtos/zephyr/blob/main/.clang-format + +--- +BasedOnStyle: LLVM +AlignConsecutiveMacros: AcrossComments +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AttributeMacros: + - __aligned + - __deprecated + - __packed + - __printf_like + - __syscall + - __syscall_always_inline + - __subsystem +BitFieldColonSpacing: After +BreakBeforeBraces: Linux +ColumnLimit: 100 +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +ForEachMacros: + - 'ARRAY_FOR_EACH' + - 'ARRAY_FOR_EACH_PTR' + - 'FOR_EACH' + - 'FOR_EACH_FIXED_ARG' + - 'FOR_EACH_IDX' + - 'FOR_EACH_IDX_FIXED_ARG' + - 'FOR_EACH_NONEMPTY_TERM' + - 'FOR_EACH_FIXED_ARG_NONEMPTY_TERM' + - 'RB_FOR_EACH' + - 'RB_FOR_EACH_CONTAINER' + - 'SYS_DLIST_FOR_EACH_CONTAINER' + - 'SYS_DLIST_FOR_EACH_CONTAINER_SAFE' + - 'SYS_DLIST_FOR_EACH_NODE' + - 'SYS_DLIST_FOR_EACH_NODE_SAFE' + - 'SYS_SEM_LOCK' + - 'SYS_SFLIST_FOR_EACH_CONTAINER' + - 'SYS_SFLIST_FOR_EACH_CONTAINER_SAFE' + - 'SYS_SFLIST_FOR_EACH_NODE' + - 'SYS_SFLIST_FOR_EACH_NODE_SAFE' + - 'SYS_SLIST_FOR_EACH_CONTAINER' + - 'SYS_SLIST_FOR_EACH_CONTAINER_SAFE' + - 'SYS_SLIST_FOR_EACH_NODE' + - 'SYS_SLIST_FOR_EACH_NODE_SAFE' + - '_WAIT_Q_FOR_EACH' + - '_WAIT_Q_FOR_EACH_SAFE' + - 'Z_FOR_EACH' + - 'Z_FOR_EACH_ENGINE' + - 'Z_FOR_EACH_EXEC' + - 'Z_FOR_EACH_FIXED_ARG' + - 'Z_FOR_EACH_FIXED_ARG_EXEC' + - 'Z_FOR_EACH_IDX' + - 'Z_FOR_EACH_IDX_EXEC' + - 'Z_FOR_EACH_IDX_FIXED_ARG' + - 'Z_FOR_EACH_IDX_FIXED_ARG_EXEC' + - 'Z_GENLIST_FOR_EACH_CONTAINER' + - 'Z_GENLIST_FOR_EACH_CONTAINER_SAFE' + - 'Z_GENLIST_FOR_EACH_NODE' + - 'Z_GENLIST_FOR_EACH_NODE_SAFE' + - 'STRUCT_SECTION_FOREACH' + - 'STRUCT_SECTION_FOREACH_ALTERNATE' + - 'TYPE_SECTION_FOREACH' + - 'K_SPINLOCK' + - 'COAP_RESOURCE_FOREACH' + - 'COAP_SERVICE_FOREACH' + - 'COAP_SERVICE_FOREACH_RESOURCE' + - 'HTTP_RESOURCE_FOREACH' + - 'HTTP_SERVER_CONTENT_TYPE_FOREACH' + - 'HTTP_SERVICE_FOREACH' + - 'HTTP_SERVICE_FOREACH_RESOURCE' + - 'I3C_BUS_FOR_EACH_I3CDEV' + - 'I3C_BUS_FOR_EACH_I3CDEV_SAFE' + - 'I3C_BUS_FOR_EACH_I2CDEV' + - 'I3C_BUS_FOR_EACH_I2CDEV_SAFE' + - 'MIN_HEAP_FOREACH' +IfMacros: + - 'CHECKIF' +# Disabled for now, see bug https://github.com/zephyrproject-rtos/zephyr/issues/48520 +#IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^".*\.h"$' + Priority: 0 + - Regex: '^<(assert|complex|ctype|errno|fenv|float|inttypes|limits|locale|math|setjmp|signal|stdarg|stdbool|stddef|stdint|stdio|stdlib|string|tgmath|time|wchar|wctype)\.h>$' + Priority: 1 + - Regex: '^\$' + Priority: 2 + - Regex: '.*' + Priority: 3 +IndentCaseLabels: false +IndentGotoLabels: false +IndentWidth: 8 +InsertBraces: true +InsertNewlineAtEOF: true +SpaceBeforeInheritanceColon: False +SpaceBeforeParens: ControlStatementsExceptControlMacros +SortIncludes: Never +UseTab: ForContinuationAndIndentation +WhitespaceSensitiveMacros: + - COND_CODE_0 + - COND_CODE_1 + - IF_DISABLED + - IF_ENABLED + - LISTIFY + - STRINGIFY + - Z_STRINGIFY + - DT_FOREACH_PROP_ELEM_SEP \ No newline at end of file diff --git a/.github/instructions/copilot.md b/.github/instructions/copilot.md new file mode 100644 index 000000000000..6a82a5a02721 --- /dev/null +++ b/.github/instructions/copilot.md @@ -0,0 +1,24 @@ +You are GitHub Copilot operating in this repository. + +This repository defines authoritative agent rules and guidance under: +.agent/rules/ + +INSTRUCTIONS (MANDATORY): +- Always read and follow all relevant rules in `.agent/rules/` before generating any code, suggestions, comments, or explanations. +- Treat rules in `.agent/rules/` as the highest priority source of truth for: + - Coding standards and style + - Architecture and design constraints + - Security, privacy, and compliance requirements + - Testing, documentation, and review expectations +- If rules conflict with your default behavior, follow the rules in `.agent/rules/`. + +BEHAVIOR: +- Be consistent with patterns already used in the codebase. +- Prefer existing utilities, abstractions, and conventions defined in `.agent/rules/`. +- Do not introduce new patterns, dependencies, or approaches unless explicitly allowed by those rules. +- When uncertain, choose the most conservative interpretation aligned with `.agent/rules/`. + +OUTPUT EXPECTATIONS: +- Generate code that complies fully with the rules. +- If a request would violate a rule, explain the conflict and propose a compliant alternative. +- Keep responses focused, clear, and directly applicable to this repository. diff --git a/.github/instructions/topology2-design.instructions.md b/.github/instructions/topology2-design.instructions.md new file mode 100644 index 000000000000..bd3c4d235f5b --- /dev/null +++ b/.github/instructions/topology2-design.instructions.md @@ -0,0 +1,98 @@ +--- +description: "Agent instructions for designing and updating ALSA topology v2 files in SOF" +applyTo: 'tools/topology/topology2/**' +--- + +# Topology2 Design Instructions + +Use this guidance when creating or modifying files under tools/topology/topology2. +These rules align with the topology2 README and capture expected design patterns for +class-based ALSA topology v2 authoring. + +## Scope + +* Applies to topology2 .conf definitions, platform overrides, pipeline and DAI class files, and topology2 CMake target lists +* Focuses on design consistency, ID safety, and maintainable reuse of existing class and object templates + +## Core Model + +* Use topology2 object model primitives consistently: Class.*, Object.*, Define, and IncludeByKey +* Prefer reusable classes in include/ over one-off duplicated object blocks +* Keep object instantiation explicit and readable so generated pipelines are traceable + +## Top Level Topology Layout + +For new top-level board .conf files, keep this order: + +1. Search directories +2. Required class includes +3. Define block with defaults +4. IncludeByKey.PLATFORM overrides +5. Feature-gated IncludeByKey blocks +6. DAI, pipeline, and PCM objects +7. Route definitions + +## Reuse Before New Base Files + +* Prefer extending an existing base input .conf with variable overrides from CMake targets +* Add a new base .conf only when existing topologies cannot represent the use case cleanly +* When adding a new target, use this tuple structure. In CMake quoted strings, escape each semicolon as `\;`. + +```text +Logical tuple format: +"input-conf;output-name;variable1=value1,variable2=value2" + +CMake string form: +"input-conf\;output-name\;variable1=value1,variable2=value2" +``` + +## ID Conventions and Safety + +* Keep PCM IDs unique within a single topology +* Keep pipeline indexes unique within a single topology +* Pair FE and BE pipelines as N and N+1 where applicable +* For SoundWire pipelines, follow index equals PCM ID times 10 unless a documented topology-specific exception exists +* For HDMI pipelines, keep stride-10 layout with host at N0 and DAI at N1 +* When combining features such as SDW, PCH DMIC, HDMI, deep buffer, or compress, verify there are no ID collisions after overrides + +## Routing Rules + +* Connect FE mixin outputs to BE mixout inputs using Object.Base.route +* Keep route naming and widget references aligned with topology naming patterns +* Validate that each route endpoint maps to a declared widget in the same compiled topology + +## Widget Naming + +* Follow naming pattern type.pipeline-index.instance +* Keep naming stable and descriptive for easier graph inspection and debug + +## Platform Overrides + +* Use IncludeByKey.PLATFORM for platform-specific Define overrides +* Restrict platform-specific tuning to platform/intel/*.conf instead of duplicating board-level logic +* Ensure platform keys remain consistent with the authoritative in-tree overrides under tools/topology/topology2/platform/intel/*.conf; current examples include tgl, adl, mtl, lnl, ptl, and nvl + +## CMake Target Placement + +Register targets in the correct file for platform generation: + +* Tiger Lake and Alder Lake: production/tplg-targets-cavs25.cmake +* Meteor Lake: production/tplg-targets-ace1.cmake +* Lunar Lake: production/tplg-targets-ace2.cmake +* Panther Lake: production/tplg-targets-ace3.cmake +* Nova Lake / sof-nvl-*: production/tplg-targets-ace4.cmake +* i.MX8 platforms: production/tplg-targets-imx8.cmake +* SDCA generic topologies: production/tplg-targets-sdca-generic.cmake +* HDA generic: production/tplg-targets-hda-generic.cmake +* Development and test topologies: development/tplg-targets.cmake + +If a target family is not listed above, use the existing tplg-targets-*.cmake +file that already contains similar topologies as the source of truth, and keep new +targets grouped with the same platform or product family in either production/ or +development/. + +## Validation Expectations + +* Keep topology2 buildable through the topologies2 target +* Preserve compatibility with alsatplg pre-processing mode used by the build system +* Ensure topology edits remain synchronized with nearby architecture or README documentation when design behavior changes diff --git a/.github/workflows/SPDX-README.md b/.github/workflows/SPDX-README.md index 14d50291dbe9..5bc30f0cc9b5 100644 --- a/.github/workflows/SPDX-README.md +++ b/.github/workflows/SPDX-README.md @@ -1,7 +1,7 @@ Read this section if there are some SPDX warnings above. -Pleasing checkpatch is hard when adding new files because: +Adding correct SPDX headers to new files can be tricky because: -- checkpatch requests a different SPDX style for .c versus .h files. +- a different SPDX style is expected for .c versus .h files. This is because some .h files are included in linker scripts or assembly code. - Some SOF reviewers reject C99 comments starting with // diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index bfebeaa26954..19fee4a98ca4 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -8,10 +8,13 @@ name: Build test all components # yamllint disable-line rule:truthy on: [pull_request, workflow_dispatch, workflow_call] +permissions: + contents: read + jobs: stub-build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: # Keep these names short due to questionable Github UI choices @@ -38,7 +41,7 @@ jobs: libasan8:i386 libubsan1:i386 libquadmath0:i386 \ sudo apt-get -y install \ - libc6-dev-i386 libstdc++-12-dev:i386 + libc6-dev-i386 libstdc++-14-dev:i386 - name: apt-get install build tools run: diff --git a/.github/workflows/checkpatch_list.sh b/.github/workflows/checkpatch_list.sh deleted file mode 100755 index 921f35ad25b1..000000000000 --- a/.github/workflows/checkpatch_list.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: BSD-3-Clause - -set -e - -# The purpose of this script is not to stop on the first checkpatch -# failure and report at the end instead. -# -# Sample invocation: -# $0 --codespell --strict < PR_SHAs.txt -main() -{ - local failures=0 - while read -r sha ; do - printf '\n -------------- \n\n' - ./scripts/checkpatch.pl $@ -g $sha || failures=$((failures+1)) - done - printf '\n -------------- \n\n' - - if [ $failures -ne 0 ]; then - cat .github/workflows/SPDX-README.md - fi - - return $failures -} - -main "$@" diff --git a/.github/workflows/close-stale.yml b/.github/workflows/close-stale.yml new file mode 100644 index 000000000000..052878a5cdd2 --- /dev/null +++ b/.github/workflows/close-stale.yml @@ -0,0 +1,31 @@ +--- +name: "Close stale issues" + +# yamllint disable-line rule:truthy +on: + schedule: + - cron: "30 1 * * *" + +permissions: + contents: read + +jobs: + stale: + name: Find stale issues + runs-on: ubuntu-24.04 + if: github.repository == 'thesofproject/sof' + permissions: + issues: write + + steps: + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 + with: + stale-issue-message: 'This issue has been marked as stale because it has been open (more + than) 60 days with no activity. Remove the stale label or add a comment saying that you + would like to have the label removed otherwise this issue will automatically be closed + in 14 days. Note, that you can always re-open a closed issue at any time.' + days-before-stale: 60 + days-before-close: 14 + stale-issue-label: 'stale' + exempt-issue-labels: 'metabug,in progress,enhancement' + operations-per-run: 400 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000000..4f7c29d6c831 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,50 @@ +--- +name: "CodeQL Analysis" +# yamllint disable-line rule:truthy +on: + pull_request: + branches: + - 'main' + +permissions: + contents: read + +# Specifies group name that stops previous workflows if the name matches +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze GitHub Actions Workflows + runs-on: ubuntu-latest + permissions: + security-events: write # Required to upload SARIF results + actions: read # Required to read workflow information + contents: read # Required to checkout repository + + strategy: + fail-fast: false + matrix: + language: ['actions'] # Analyze GitHub Actions workflows + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Initialize CodeQL + uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v4 + with: + languages: ${{ matrix.language }} + # Optional: Specify custom queries + # queries: security-extended,security-and-quality + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v4 + with: + category: "/language:${{ matrix.language }}" + upload: true + # Upload SARIF results to GitHub Security tab + output: sarif-results diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index 63a076fc086a..ea9e0a20d150 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -14,45 +14,10 @@ name: codestyle # yamllint disable-line rule:truthy on: [pull_request, workflow_call, workflow_dispatch] -jobs: - checkpatch: - runs-on: ubuntu-22.04 - - strategy: - fail-fast: false - matrix: - strictness: [null, --subjective] - - env: - PR_NUM: ${{github.event.number}} - # TODO: reduce duplication with scripts/sof-*-commit-hook.sh - # thanks to either some .conf file or some wrapper script - CHK_CMD_OPTS: --ignore UNKNOWN_COMMIT_ID --codespell - - steps: - # depth 2 so: - # ^1. we can show the Subject of the current target branch tip - # ^2. we reconnect/graft to the later fetch pull/1234/head, - - uses: actions/checkout@v4 - with: {fetch-depth: 2} - - - name: install codespell - run: sudo apt-get -y install codespell && dpkg -L codespell | grep dict - - # See shallowness issue https://github.com/thesofproject/linux/issues/2556 - - name: fetch PR commits - run: | - .github/workflows/shallowfetchPRcommits.sh \ - ${GITHUB_REPOSITORY} "$PR_NUM" - # show what we got - git --no-pager log --oneline --graph --decorate --max-count=50 - - - name: checkpatch - env: - STRICTNESS: ${{ matrix.strictness }} - run: .github/workflows/checkpatch_list.sh ${CHK_CMD_OPTS} - ${STRICTNESS} < PR_SHAs.txt +permissions: + contents: read +jobs: yamllint: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/daily-tests.yml b/.github/workflows/daily-tests.yml index 5ecd2b83df86..139c946c3d84 100644 --- a/.github/workflows/daily-tests.yml +++ b/.github/workflows/daily-tests.yml @@ -13,6 +13,9 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: +permissions: + contents: read + jobs: # Keep in .yml alphabetical order @@ -23,9 +26,6 @@ jobs: # TODO: separate "fetchPRcommits" which can't work in daily tests # uses: ./.github/workflows/codestyle.yml - XTOS-make-install: - uses: ./.github/workflows/installer.yml - zephyr-fuzz-IPC: uses: ./.github/workflows/ipc_fuzzer.yml with: diff --git a/.github/workflows/installer.yml b/.github/workflows/installer.yml deleted file mode 100644 index 012b1bddd42e..000000000000 --- a/.github/workflows/installer.yml +++ /dev/null @@ -1,63 +0,0 @@ ---- -# 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: installer - -# 'workflow_dispatch' allows running this workflow manually from the -# 'Actions' tab -# yamllint disable-line rule:truthy -on: [push, pull_request, workflow_dispatch, workflow_call] - -jobs: - checktree: - runs-on: ubuntu-22.04 - - strategy: - fail-fast: false - matrix: # just a vector in this case - make_env: [ - IPC_VERSION= UNSIGNED_list='imx8m' SIGNED_list=, # default version - ] - - steps: - - uses: actions/checkout@v4 - with: {fetch-depth: 0, submodules: recursive, filter: 'tree:0'} - - - name: docker - run: docker pull thesofproject/sof && docker tag thesofproject/sof sof - - # -j3 tests the ability to build multiple platforms - # concurrently. It makes the build log unreadable, so retry with - # a single thread in case of failure - - name: build all and stage - env: - gh_make_env: ${{ matrix.make_env }} - # Use 'eval' to have two different levels of whitespace: - # 1. between vars, and 2. inside _lists. Quoting is hard, even - # harder through 'docker-run.sh'. - run: eval env_array=($gh_make_env) && - ./scripts/docker-run.sh - make -j3 -C installer/ tarball "${env_array[@]}" || - VERBOSE=1 NO_PROCESSORS=1 USE_XARGS=no - ./scripts/docker-run.sh - make -j1 -C installer/ tarball "${env_array[@]}" - - - name: check staging tree - env: - gh_make_env: ${{ matrix.make_env }} - run: eval env_array=($gh_make_env) && - make -C installer/ checktree "${env_array[@]}" - - - name: test make cleanall - run: | - make -C installer cleanall - # Make sure there's nothing left - rm -rf scripts/kconfig/__pycache__/ - ! git status --porcelain --ignored | grep . diff --git a/.github/workflows/ipc_fuzzer.yml b/.github/workflows/ipc_fuzzer.yml index 6773af045689..755dbf4b5d9b 100644 --- a/.github/workflows/ipc_fuzzer.yml +++ b/.github/workflows/ipc_fuzzer.yml @@ -22,10 +22,13 @@ on: pull_request: # TODO: can we provide a default inputs here too? +permissions: + contents: read + jobs: simple-IPC-fuzz_sh: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -53,7 +56,7 @@ jobs: libasan8:i386 libubsan1:i386 libquadmath0:i386 \ sudo apt-get -y install \ - libc6-dev-i386 libstdc++-12-dev:i386 + libc6-dev-i386 libstdc++-14-dev:i386 - name: apt-get install build tools run: diff --git a/.github/workflows/llext.yml b/.github/workflows/llext.yml index 21b812b47600..149c9e2e3571 100644 --- a/.github/workflows/llext.yml +++ b/.github/workflows/llext.yml @@ -7,9 +7,18 @@ name: Zephyr LLEXT # yamllint disable-line rule:truthy on: [pull_request, workflow_dispatch] +defaults: + run: + shell: bash + +permissions: + contents: read + jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 + container: + image: thesofproject/zephyr-lite:v0.29.0 strategy: fail-fast: false @@ -17,33 +26,30 @@ jobs: platform: [mtl, lnl] steps: - - name: free space - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - - - name: git clone sof + - name: checkout uses: actions/checkout@v4 with: - path: ./workspace/sof + path: sof fetch-depth: 0 # fix git describe filter: 'tree:0' - - name: west clones - run: pip3 install west && cd workspace/sof/ && west init -l && - west update --narrow --fetch-opt=--depth=5 + - name: west update + working-directory: sof + run: | + west init -l + west update --narrow --fetch-opt=--depth=5 - - name: Download docker image && ls /opt/toolchains/ - run: cd workspace && ./sof/zephyr/docker-run.sh ls -l /opt/toolchains/ + - name: print all available sdks in /opt/toolchains/ + run: | + ls -l /opt/toolchains/ - name: llext build run: | - cd workspace && ./sof/zephyr/docker-run.sh /bin/sh -c \ - "ln -s /opt/toolchains/zephyr-sdk-* ~/; - python sof/scripts/xtensa-build-zephyr.py \ - --cmake-args=-DEXTRA_CFLAGS=-Werror \ - --cmake-args=-DEXTRA_CXXFLAGS=-Werror \ - --cmake-args=-DEXTRA_AFLAGS='-Werror -Wa,--fatal-warnings' \ - --cmake-args=--warn-uninitialized \ - --overlay=sof/app/configs/${{ matrix.platform }}/modules.conf \ - ${{ matrix.platform }}" + ln -s /opt/toolchains/zephyr-sdk-* ~/ + python sof/scripts/xtensa-build-zephyr.py \ + --cmake-args=-DEXTRA_CFLAGS=-Werror \ + --cmake-args=-DEXTRA_CXXFLAGS=-Werror \ + --cmake-args=-DEXTRA_AFLAGS='-Werror -Wa,--fatal-warnings' \ + --cmake-args=--warn-uninitialized \ + --overlay=sof/app/configs/${{ matrix.platform }}/modules.conf \ + ${{ matrix.platform }} diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 3f26a1093541..0bd3865dec97 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -31,10 +31,13 @@ on: # Allows to call this forkflow from other workflows workflow_call: +permissions: + contents: read + jobs: doxygen: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 @@ -61,138 +64,3 @@ jobs: run: printf 'WARN_AS_ERROR = FAIL_ON_WARNINGS\n' >> doc/sof.doxygen.in && ninja -C docbuild -v doc - - - # This is unfortunately a mix of sof-docs/.github/ + the previous job - # above, duplicating a bit of both: please keep in sync with both. We - # build sof-docs here too because waiting for sof-docs CI to find - # regressions introduced in sof.git is very time-consuming, see - # example in - # https://github.com/thesofproject/sof/pull/5731#issuecomment-1175630147 - sof-docs: - runs-on: ubuntu-20.04 # sof-docs is still stuck to this for now - - steps: - - uses: actions/checkout@v4 - with: - filter: 'tree:0' - - - name: apt-get update - run: sudo apt-get update - - - name: apt-get install - run: sudo apt-get -y install - doxygen make default-jre graphviz cmake ninja-build - - - name: doxygen - run: cmake -GNinja -S doc/ -B doxybuild/ && ninja -C doxybuild/ -v doc - - # Nested git clone, this is fine - - name: clone sof-docs - run: git clone https://github.com/thesofproject/sof-docs sof-docs/ - - - name: PATH += .local/bin - run: echo "$HOME/.local/bin" >> $GITHUB_PATH - - - name: 'pip install -r sof-docs/scripts/requirements.txt' - run: pip install -r sof-docs/scripts/requirements.txt - - - name: build sof-docs - run: make -C sof-docs/ html SOF_DOC_BUILD="$(pwd)"/doxybuild/ - - - # This is a bit redundant with the other jobs below and with the (much - # faster!) installer[.yml] but it may differ in which platforms are - # built. This makes sure platforms without any open-source toolchain - # are added in the right place and do not accidentally break the -a - # option, Docker testing etc. - gcc-build-default-platforms: - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@v4 - with: {fetch-depth: 0, submodules: recursive, filter: 'tree:0'} - - - name: docker - run: docker pull thesofproject/sof && docker tag thesofproject/sof sof - - - name: xtensa-build-all.sh -a - run: ./scripts/docker-run.sh ./scripts/xtensa-build-all.sh -a || - ./scripts/docker-run.sh ./scripts/xtensa-build-all.sh -a -j 1 - - - gcc-build-only: - runs-on: ubuntu-22.04 - - strategy: - fail-fast: false - matrix: - # Use groups to avoid spamming the web interface. Pay attention - # to COMMAS. Don't use a single big group so a single failure - # does not block all other builds. - platform: [rn rmb, - mt8186 mt8195 mt8188, - ] - - steps: - - - uses: actions/checkout@v4 - with: {fetch-depth: 0, submodules: recursive, filter: 'tree:0'} - - - name: docker - run: docker pull thesofproject/sof && docker tag thesofproject/sof sof - - - name: xtensa-build-all.sh platforms - env: - PLATFORM: ${{ matrix.platform }} - run: ./scripts/docker-run.sh - ./scripts/xtensa-build-all.sh -r ${PLATFORM} - - # Warning: there is a fair amount of duplication between 'build-only' - # and 'qemu-boot' because github does not support YAML anchors as of Jan - # 2021. Defining our new actions would be overkill. Another popular - # option is to generate this file from a source with YAML anchors - # before committing it; also deemed overkill for the current amount of - # duplication. - - qemu-boot-test: - runs-on: ubuntu-22.04 - - strategy: - fail-fast: false - matrix: - # Compiler-based groups, see HOST= compilers in - # xtensa-build-all.sh. Pay attention to commas and whitespace. - # The main reason for these groups is to avoid the matrix - # swarming the Github web interface and burying other checks. - # See longer example above. - platform: [imx8m, - ] - - steps: - - - uses: actions/checkout@v4 - with: {fetch-depth: 0, submodules: recursive, filter: 'tree:0'} - - - name: turn off HAVE_AGENT - run: echo CONFIG_HAVE_AGENT=n > - src/arch/xtensa/configs/override/no-agent.config - - - name: docker SOF - run: docker pull thesofproject/sof && docker tag thesofproject/sof sof - - - name: xtensa-build-all.sh -o no-agent platforms - env: - PLATFORM: ${{ matrix.platform }} - run: ./scripts/docker-run.sh - ./scripts/xtensa-build-all.sh -o no-agent -r ${PLATFORM} - - - name: docker QEMU - run: docker pull thesofproject/sofqemu && - docker tag thesofproject/sofqemu sofqemu - - - name: qemu-check - env: - PLATFORM: ${{ matrix.platform }} - run: ./scripts/docker-qemu.sh - ../sof.git/scripts/qemu-check.sh ${PLATFORM} diff --git a/.github/workflows/repro-build.yml b/.github/workflows/repro-build.yml index 034ae4ac286a..abe48a8cecb2 100644 --- a/.github/workflows/repro-build.yml +++ b/.github/workflows/repro-build.yml @@ -14,9 +14,12 @@ name: Reproducible builds # yamllint disable-line rule:truthy on: [pull_request, workflow_dispatch, workflow_call] +permissions: + contents: read + jobs: main: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/rimage.yml b/.github/workflows/rimage.yml index b6e66c23c449..53059681ae9d 100644 --- a/.github/workflows/rimage.yml +++ b/.github/workflows/rimage.yml @@ -22,11 +22,14 @@ on: paths: - tools/rimage/** +permissions: + contents: read + jobs: # Basic build test build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 env: # FIXME: add -Wpointer-arith _CFLGS: -Werror -Wall -Wmissing-prototypes @@ -46,7 +49,7 @@ jobs: # cppcheck cppcheck: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: {submodules: recursive, fetch-depth: 0, filter: 'tree:0'} diff --git a/.github/workflows/sof-docs.yml b/.github/workflows/sof-docs.yml new file mode 100644 index 000000000000..63af4acfc714 --- /dev/null +++ b/.github/workflows/sof-docs.yml @@ -0,0 +1,62 @@ +--- +# yamllint disable-line rule:truthy +on: + push: + branches: + - 'main' + - 'stable-**' + - '**-stable' + pull_request: + branches: + - 'main' + - 'stable-**' + - '**-stable' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + # Allows to call this forkflow from other workflows + workflow_call: + +permissions: + contents: read + +jobs: + + # This is unfortunately a mix of sof-docs/.github/ + pull-request.yml#doxygen + # duplicating a bit of both: please keep in sync with both. We + # build sof-docs here too because waiting for sof-docs CI to find + # regressions introduced in sof.git is very time-consuming, see + # example in + # https://github.com/thesofproject/sof/pull/5731#issuecomment-1175630147 + sof-docs: + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + with: + filter: 'tree:0' + + - name: apt-get update + run: sudo apt-get update + + - name: apt-get install + run: | + sudo apt-get -yq install doxygen make \ + default-jre graphviz cmake ninja-build \ + libjpeg-dev + + - name: doxygen + run: cmake -GNinja -S doc/ -B doxybuild/ && ninja -C doxybuild/ -v doc + + # Nested git clone, this is fine + - name: clone sof-docs + run: git clone https://github.com/thesofproject/sof-docs sof-docs/ + + - name: PATH += .local/bin + run: echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: 'pip install -r sof-docs/scripts/requirements.txt' + run: pip install -r sof-docs/scripts/requirements.txt + + - name: build sof-docs + run: LAX=1 make -C sof-docs/ html SOF_DOC_BUILD="$(pwd)"/doxybuild/ diff --git a/.github/workflows/sparse-zephyr.yml b/.github/workflows/sparse-zephyr.yml index a22e6e8954d5..5afa6361f51a 100644 --- a/.github/workflows/sparse-zephyr.yml +++ b/.github/workflows/sparse-zephyr.yml @@ -7,6 +7,13 @@ name: Sparse Zephyr # yamllint disable-line rule:truthy on: [push, pull_request, workflow_dispatch, workflow_call] +defaults: + run: + shell: bash + +permissions: + contents: read + jobs: # As of sparse commit ce1a6720f69e / Sept 2022, the exit status of # sparse.c is an unusable mess and always zero in practice. Moreover @@ -14,10 +21,15 @@ jobs: # small subset of specific warnings defined in # sof/scripts/parse_sparse_output.sh warnings-subset: + # disable until https://github.com/zephyrproject-rtos/zephyr/issues/93444 + # is fixed + if: false # We're sharing the sparse binary with the zephyr-build container so keep # this in sync with it. - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 + container: + image: thesofproject/zephyr-lite:v0.29.0 strategy: fail-fast: false @@ -25,43 +37,39 @@ jobs: platform: [tgl, mtl, lnl] steps: - - name: free space - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - - name: git clone sparse analyzer uses: actions/checkout@v4 with: repository: thesofproject/sparse fetch-depth: 0 filter: 'tree:0' - path: workspace/sparse + path: sparse # As of its 2023 commit 98b203419679, sparse-llvm.c uses symbols # (LLVMConstGEP, LLVMBuildLoad, LLVMBuildCall,...) which are: # - -Wdeprecated in LLVM v14 # - Removed in LLVM v16 - name: build sparse analyzer - run: cd workspace/sparse && make -j4 # HAVE_LLVM=no + working-directory: sparse + run: | + make -j4 # HAVE_LLVM=no - name: git clone sof uses: actions/checkout@v4 with: - path: ./workspace/sof + path: sof fetch-depth: 0 # fix git describe filter: 'tree:0' - - name: west clones - run: pip3 install west && cd workspace/sof/ && west init -l && - west update --narrow --fetch-opt=--depth=5 + - name: west update + working-directory: sof + run: | + west init -l + west update --narrow --fetch-opt=--depth=5 - # Not strictly necessary but saves a lot of scrolling in the next step - # Caching a 12G image is unfortunately not possible: - # https://github.com/ScribeMD/docker-cache/issues/304 - # For faster builds we would have to pay for some persistent runners. - - name: Download docker image && ls /opt/toolchains/ - run: cd workspace && ./sof/zephyr/docker-run.sh ls -l /opt/toolchains/ + - name: print all available sdks in /opt/toolchains/ + run: | + ls -l /opt/toolchains/ # --pristine is important to reproduce _warnings_. It makes no # difference for github but it's useful for anyone trying to @@ -69,13 +77,11 @@ jobs: # "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 + ./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' - (set -x; ./sof/scripts/parse_sparse_output.sh ${{ matrix.platforms.platform }} <_.log) + printf '\n\n\t\t\t ---- Messages below are treated as sparse errors --- \n\n\n' + (set -x; ./sof/scripts/parse_sparse_output.sh ${{ matrix.platforms.platform }} <_.log) diff --git a/.github/workflows/testbench.yml b/.github/workflows/testbench.yml index 9c1dfdfb22ec..d54b1db331db 100644 --- a/.github/workflows/testbench.yml +++ b/.github/workflows/testbench.yml @@ -28,34 +28,84 @@ on: workflow_dispatch: workflow_call: -jobs: +permissions: + contents: read - build-run: - runs-on: ubuntu-22.04 +jobs: + build-and-test: + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 - with: {fetch-depth: 0, filter: 'tree:0'} - - - name: docker - run: docker pull thesofproject/sof && docker tag thesofproject/sof sof + - name: Checkout SOF repository (PR source) + uses: actions/checkout@v4 + with: + path: sof + # note: libasound-dev needed for testbench build which still + # requires system ALSA headers to be present - name: apt get run: sudo apt-get update && - sudo apt-get -y install valgrind alsa-utils libasound2-dev ninja-build - octave octave-signal + sudo apt-get -y install valgrind ninja-build + octave octave-signal automake autoconf libtool + gettext libasound2-dev + + # Ubuntu 24.04 ships autoconf 2.71, but current alsa-lib/alsa-utils + # require >= 2.72. Build a newer autoconf from the GNU release + # tarball and install it into /usr/local (ahead of /usr/bin in PATH). + - name: Install autoconf 2.72 + run: | + cd ${GITHUB_WORKSPACE} + wget -q https://ftp.gnu.org/gnu/autoconf/autoconf-2.72.tar.gz + tar xf autoconf-2.72.tar.gz + cd autoconf-2.72 + ./configure --prefix=/usr/local + make -j"$(nproc)" + sudo make install + hash -r + autoconf --version | head -n1 + + - name: Build Alsa-lib + run: | + cd ${GITHUB_WORKSPACE} + git clone https://github.com/thesofproject/alsa-lib.git + cd alsa-lib + git checkout 08b532cd3da9ac8f683bcb4e4beb9b74c39c1782 -b build + ./gitcompile --prefix=${GITHUB_WORKSPACE}/tools + make install + + - name: Build Alsa-utils + run: | + cd ${GITHUB_WORKSPACE} + git clone https://github.com/thesofproject/alsa-utils.git + cd alsa-utils + git checkout 9feb22ba45b48729729c8d194aaf1bc082a6842a -b build + ./gitcompile --prefix=${GITHUB_WORKSPACE}/tools \ + --with-alsa-prefix=${GITHUB_WORKSPACE}/tools \ + --with-alsa-inc-prefix=${GITHUB_WORKSPACE}/tools/include \ + --with-sysroot=${GITHUB_WORKSPACE}/tools \ + --with-udev-rules-dir=${GITHUB_WORKSPACE}/tools \ + PKG_CONFIG_PATH=${GITHUB_WORKSPACE}/tools \ + LDFLAGS=-L${GITHUB_WORKSPACE}/tools/lib \ + --disable-old-symbols \ + --enable-alsatopology \ + --with-asound-state-dir=${GITHUB_WORKSPACE}/tools/var/lib/alsa \ + --with-systemdsystemunitdir=${GITHUB_WORKSPACE}/tools/lib/systemd/system + make install # testbench needs some topologies. - name: build test topologies - run: CMAKE_BUILD_TYPE=Release ./scripts/docker-run.sh - ./scripts/build-tools.sh -Y || + run: | + CMAKE_BUILD_TYPE=Release ./sof/scripts/build-tools.sh -Y || VERBOSE=1 NO_PROCESSORS=1 USE_XARGS=no - CMAKE_BUILD_TYPE=Release ./scripts/docker-run.sh - ./scripts/build-tools.sh -Y + CMAKE_BUILD_TYPE=Release ./sof/scripts/build-tools.sh -Y + # build testbench - name: build testbench - run: ./scripts/rebuild-testbench.sh || - ./scripts/rebuild-testbench.sh -j 1 + run: | + ./sof/scripts/rebuild-testbench.sh || + ./sof/scripts/rebuild-testbench.sh -j 1 + # run testbench - name: run testbench - run: ./scripts/host-testbench.sh + run: | + ./sof/scripts/host-testbench.sh diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml index 9c8197a6cbcc..825b571321d8 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -7,32 +7,81 @@ name: User space tools/ directory # yamllint disable-line rule:truthy on: [pull_request, workflow_dispatch, workflow_call] +permissions: + contents: read + jobs: # This is not the same as building every ./build-tools.sh option. top-level_default_CMake_target_ALL: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: filter: 'tree:0' + path: sof + + - name: apt get + run: sudo apt-get update && + sudo apt-get -y install ninja-build + automake autoconf libtool gettext libasound2-dev + pkg-config + + # Ubuntu 24.04 ships autoconf 2.71, but current alsa-lib/alsa-utils + # require >= 2.72. Build a newer autoconf from the GNU release + # tarball and install it into /usr/local (ahead of /usr/bin in PATH). + - name: Install autoconf 2.72 + run: | + cd ${GITHUB_WORKSPACE} + wget -q https://ftp.gnu.org/gnu/autoconf/autoconf-2.72.tar.gz + tar xf autoconf-2.72.tar.gz + cd autoconf-2.72 + ./configure --prefix=/usr/local + make -j"$(nproc)" + sudo make install + hash -r + autoconf --version | head -n1 + + - name: Build Alsa-lib + run: | + cd ${GITHUB_WORKSPACE} + git clone https://github.com/thesofproject/alsa-lib.git + cd alsa-lib + git checkout 08b532cd3da9ac8f683bcb4e4beb9b74c39c1782 -b build + ./gitcompile --prefix=${GITHUB_WORKSPACE}/tools + make install - # The ALSA version in Ubuntu 20.04 is buggy - # (https://github.com/thesofproject/sof/issues/2543) and likely - # getting out of date soon - - name: docker - run: docker pull thesofproject/sof && docker tag thesofproject/sof sof + - name: Build Alsa-utils + run: | + cd ${GITHUB_WORKSPACE} + git clone https://github.com/thesofproject/alsa-utils.git + cd alsa-utils + git checkout 9feb22ba45b48729729c8d194aaf1bc082a6842a -b build + ./gitcompile --prefix=${GITHUB_WORKSPACE}/tools \ + --with-alsa-prefix=${GITHUB_WORKSPACE}/tools \ + --with-alsa-inc-prefix=${GITHUB_WORKSPACE}/tools/include \ + --with-sysroot=${GITHUB_WORKSPACE}/tools \ + --with-udev-rules-dir=${GITHUB_WORKSPACE}/tools \ + PKG_CONFIG_PATH=${GITHUB_WORKSPACE}/tools \ + LDFLAGS=-L${GITHUB_WORKSPACE}/tools/lib \ + --disable-old-symbols \ + --enable-alsatopology \ + --with-asound-state-dir=${GITHUB_WORKSPACE}/tools/var/lib/alsa \ + --with-systemdsystemunitdir=${GITHUB_WORKSPACE}/tools/lib/systemd/system + make install # For some reason gcc has more warnings in Release mode - name: build-tools - run: CMAKE_BUILD_TYPE=Release ./scripts/docker-run.sh - ./scripts/build-tools.sh || + env: + PKG_CONFIG_PATH: ${{ github.workspace }}/tools/lib/pkgconfig + LD_LIBRARY_PATH: ${{ github.workspace }}/tools/lib + PATH: ${{ github.workspace }}/tools/bin:/usr/local/bin:/usr/bin:/bin + run: CMAKE_BUILD_TYPE=Release ./sof/scripts/build-tools.sh || VERBOSE=1 NO_PROCESSORS=1 USE_XARGS=no - CMAKE_BUILD_TYPE=Release ./scripts/docker-run.sh - ./scripts/build-tools.sh + CMAKE_BUILD_TYPE=Release ./sof/scripts/build-tools.sh SOF-alsa-plugin: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: {filter: 'tree:0'} diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 391807f6a336..de8577e87171 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -10,6 +10,9 @@ name: Unit tests # yamllint disable-line rule:truthy on: [pull_request, workflow_dispatch, workflow_call] +permissions: + contents: read + jobs: cmocka_utests: runs-on: ubuntu-latest diff --git a/.github/workflows/zephyr-main.yml b/.github/workflows/zephyr-main.yml new file mode 100644 index 000000000000..0b6f0cbe3e28 --- /dev/null +++ b/.github/workflows/zephyr-main.yml @@ -0,0 +1,17 @@ +--- +name: Zephyr Main Branch + +# yamllint disable-line rule:truthy +on: + schedule: + - cron: '0 4,16 * * *' + workflow_dispatch: + +permissions: + contents: read + +jobs: + zephyr-main-builds: + uses: ./.github/workflows/zephyr.yml + with: + zephyr_revision: 'zmain' diff --git a/.github/workflows/zephyr-shell.yml b/.github/workflows/zephyr-shell.yml new file mode 100644 index 000000000000..23f8e6947b22 --- /dev/null +++ b/.github/workflows/zephyr-shell.yml @@ -0,0 +1,64 @@ +--- +# SPDX-License-Identifier: BSD-3-Clause +# Tools that can save round-trips to github and a lot of time: +# +# yamllint -f parsable zephyr-shell.yml +# pip3 install ruamel.yaml.cmd +# yaml merge-expand zephyr-shell.yml exp.yml && diff -w -u zephyr-shell.yml exp.yml +# +# github.com also has a powerful web editor that can be used without +# committing. + +name: Zephyr Shell + +# 'workflow_dispatch' allows running this workflow manually from the +# 'Actions' tab +# yamllint disable-line rule:truthy +on: [pull_request, workflow_dispatch] + +defaults: + run: + shell: bash + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-24.04 + container: + image: thesofproject/zephyr-lite:v0.29.0 + + strategy: + fail-fast: false + matrix: + platform: [tgl, mtl, lnl] + + steps: + - name: checkout + uses: actions/checkout@v4 + with: + path: sof + fetch-depth: 0 # fix git describe + filter: 'tree:0' + + - name: west update + working-directory: sof + run: | + west init -l + west update --narrow --fetch-opt=--depth=5 + + - name: print all available sdks in /opt/toolchains/ + run: | + ls -l /opt/toolchains/ + + - name: shell build + run: | + ln -s /opt/toolchains/zephyr-sdk-* ~/ + python sof/scripts/xtensa-build-zephyr.py \ + --cmake-args=-DEXTRA_CFLAGS=-Werror \ + --cmake-args=-DEXTRA_CXXFLAGS=-Werror \ + --cmake-args=-DEXTRA_AFLAGS='-Werror -Wa,--fatal-warnings' \ + --cmake-args=--warn-uninitialized \ + --overlay=sof/app/shell_overlay.conf \ + ${{ matrix.platform }} diff --git a/.github/workflows/zephyr-unit-tests.yml b/.github/workflows/zephyr-unit-tests.yml new file mode 100644 index 000000000000..ed089a148597 --- /dev/null +++ b/.github/workflows/zephyr-unit-tests.yml @@ -0,0 +1,61 @@ +--- +name: "Unit tests" +# yamllint disable-line rule:truthy +on: + pull_request: + branches: + - 'main' + +permissions: + contents: read + +# Specifies group name that stops previous workflows if the name matches +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + zephyr-utests: + name: Zephyr Unit Tests (ZTest) + runs-on: ubuntu-24.04 + timeout-minutes: 10 + + steps: + - name: Install build tools + run: | + sudo apt-get update + sudo apt-get -y install clang llvm ninja-build device-tree-compiler \ + python3-pyelftools + # Install multilib packages required for native_sim i386 target + sudo apt-get install gcc-multilib g++-multilib + + - name: Checkout SOF repository + uses: actions/checkout@v4 + with: + path: ./workspace/sof + fetch-depth: 2 + filter: 'tree:0' + + - name: West update + run: | + cd workspace/sof + pip3 install west + west init -l + west update --narrow --fetch-opt=--filter=tree:0 + + - name: Install Python dependencies + run: | + cd workspace/zephyr + pip3 install --user -r scripts/requirements.txt + + - name: Build and run unit tests + run: | + cd workspace + export ZEPHYR_TOOLCHAIN_VARIANT=host/llvm + west twister --testsuite-root sof/test/ztest/unit/ --platform native_sim --verbose \ + --inline-logs + # This part is commented out because it is not needed at the moment. + # - name: Install Zephyr SDK + # run: | + # cd workspace/zephyr + # west sdk install --version 0.16.9 -t xtensa-intel_ace30_ptl_zephyr-elf diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml index 3fe3e8982d58..ecfc6f4089ee 100644 --- a/.github/workflows/zephyr.yml +++ b/.github/workflows/zephyr.yml @@ -5,7 +5,17 @@ name: Zephyr # 'workflow_dispatch' allows running this workflow manually from the # 'Actions' tab # yamllint disable-line rule:truthy -on: [push, pull_request, workflow_dispatch, workflow_call] +on: + push: + pull_request: + workflow_dispatch: + workflow_call: + inputs: + zephyr_revision: + description: 'Zephyr revision to build against' + type: string + required: false + default: 'mnfst' # Specifies group name that stops previous wokrflows if the name matches concurrency: @@ -14,19 +24,26 @@ concurrency: group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} cancel-in-progress: true -jobs: +permissions: + contents: read +jobs: manifest-check: runs-on: ubuntu-latest + defaults: + run: + shell: bash + container: + image: thesofproject/zephyr-lite:v0.29.0 steps: - uses: actions/checkout@v4 with: - path: ./workspace/sof + path: sof filter: 'tree:0' - name: plain west update + working-directory: sof run: | - : This plain 'west update' does not provide 100% certainty that : all the manifest revisions make sense but it is quick and : will catch many revision problems. Other jobs typically @@ -35,8 +52,6 @@ jobs: : is useful for testing unmerged Zephyr commits but risks : accepting "invalid" ones, this will not. - pip3 install west - cd workspace/sof/ west init -l west update --fetch-opt=--filter=tree:0 @@ -45,9 +60,8 @@ jobs: # XTOS submodules and... temporarily break every CI, which is why # it hasn't been done yet. - name: git submodules consistency + working-directory: sof run: | - - cd workspace/sof git submodule update --init --recursive west update @@ -65,59 +79,65 @@ jobs: # sof/scripts/xtensa-build-zephyr.py configuration script. Then this # job will be disappear, folded back in the regular build-* jobs below. LP64-WIP: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 + defaults: + run: + shell: bash + container: + image: thesofproject/zephyr-lite:v0.29.0 steps: - uses: actions/checkout@v4 with: - path: ./workspace/sof + path: sof filter: 'tree:0' - - name: free space + - name: west update + working-directory: sof run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - - - name: west clones - run: pip3 install west && cd workspace/sof/ && west init -l && - west update --narrow --fetch-opt=--filter=tree:0 + west init -l + west update --narrow --fetch-opt=--filter=tree:0 - # Not strictly necessary but saves a lot of scrolling in the next step - # Caching a 12G image is unfortunately not possible: - # https://github.com/ScribeMD/docker-cache/issues/304 - # For faster builds we would have to pay for some persistent runners. - - name: Download docker image && ls /opt/toolchains/ - run: cd workspace && ./sof/zephyr/docker-run.sh ls -l /opt/toolchains/ + - name: print all available sdks in /opt/toolchains/ + run: | + ls -l /opt/toolchains/ - name: 64 bits build run: | - cd workspace && ./sof/zephyr/docker-run.sh /bin/sh -c \ - 'ln -s /opt/toolchains/zephyr-sdk-* ~/; - west build --board imx93_evk/mimx9352/a55 sof/app \ - -- -DEXTRA_CFLAGS=-Werror -DEXTRA_CXXFLAGS=-Werror \ - -DEXTRA_AFLAGS=-Werror' - + ln -s /opt/toolchains/zephyr-sdk-* ~/ + west build --board imx93_evk/mimx9352/a55 sof/app \ + -- -DEXTRA_CFLAGS=-Werror -DEXTRA_CXXFLAGS=-Werror \ + -DEXTRA_AFLAGS=-Werror build-linux: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 + defaults: + run: + shell: bash + container: + image: thesofproject/zephyr-lite:v0.29.0 strategy: fail-fast: false matrix: # These keys are kept short because Github's left column is not resizable. # Search "zephyr_revision" and see below what they expand to. zephyr_revision: [ - mnfst, # special value: don't override sof/west.yml - zmain, # Zephyr's main branch + "${{ inputs.zephyr_revision || 'mnfst' }}" ] # Using groups to avoid spamming the small results box with too # many lines. Pay attention to COMMAS. IPC_platforms: [ # - IPC3 default - imx8 imx8x imx8m imx8ulp, - # - IPC4 default - mtl, lnl, ptl, + imx8 imx8x, + imx8m imx8ulp, + # - IPC4 default, released + mtl, + lnl, + # active development + ptl, # Temporary testbed for Zephyr development. - tgl tgl-h, + tgl, + tgl-h ] build_opts: [""] # Sparse matrices are complicated, you must read this page slowly: @@ -126,12 +146,14 @@ jobs: # specify one extra -d combination without affecting the main matrix - build_opts: -d zephyr_revision: mnfst - IPC_platforms: mtl + IPC_platforms: lnl - # This is "duplication of effort" but it makes sure no one - # breaks --all, see for instance #9262 and previous commit. + # Due to GitHub size limitations we can't afford to run --all and + # duplicate builds already built in previous steps. + # This will now build any platform that would've run with --all that + # isn't already built above. - zephyr_revision: mnfst - IPC_platforms: --all + IPC_platforms: wcl imx95 steps: - uses: actions/checkout@v4 @@ -141,21 +163,16 @@ jobs: with: fetch-depth: 0 filter: 'tree:0' - path: ./workspace/sof + path: sof - - name: free space + - name: west update + working-directory: sof run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - - - name: west clones - - run: pip3 install west && cd workspace/sof/ && west init -l && - time west update --narrow --fetch-opt=--filter=tree:0 + west init -l + west update --narrow --fetch-opt=--filter=tree:0 - name: select zephyr revision run: | - cd workspace if [ 'mnfst' = '${{ matrix.zephyr_revision }}' ]; then rem_rev=$(git -C zephyr rev-parse HEAD) else @@ -165,11 +182,17 @@ jobs: esac ( cd sof/submanifests/ sed -e "s#=sof_zephyr_revision_override=#${rem_rev}#" \ - sof-ci-jenkins/zephyr-override-template.yml > test-zephyr-main.yml + sof-ci-jenkins/zephyr-override-template.yml \ + > test-zephyr-main.yml ) time west update --narrow --fetch-opt=--filter=tree:0 fi + # Get some tags to fix `git describe` hence BUILD_VERSION, etc. + # Keep in sync with build-windows below + - name: Fetch tags for git describe + working-directory: zephyr + run: | # Because we used git tricks to speed things up, we now have two git # problems: # @@ -179,69 +202,78 @@ jobs: # does not use --tags. # # 2. west fetches using the remote URL, not the remote name. So remote - # branches (if any) are missing from --decorate below - # - # => an "empty" and quick fetch _with_ a refspec and the remote name fixes - # both issues in no time. - - cd zephyr - time git fetch --filter=tree:0 "$(git remote |head -n1)" "$rem_rev":_branch_placeholder - git branch -D _branch_placeholder + # branches are missing from --decorate below. Cosmetic but annoying. set -x + # Fix problem 2. Do NOT assume anything about remote names: nothing is guaranteed. + _zurl=$(west list -f '{url}' zephyr) + # Use an ugly remote name to avoid a collision + git remote add sof_zep_rem "$_zurl" + time git fetch --filter=tree:0 sof_zep_rem "$rem_rev" + # Fix problem 1. Indirectly fetches useless branches but is very quick thanks to + # the --filter + time git fetch --filter=tree:0 --tags sof_zep_rem + west list west status git log --oneline -n 5 --decorate --graph --no-abbrev-commit + git describe --long --always --dirty + git describe --long --always --dirty --tags - # Not strictly necessary but saves a lot of scrolling in the next step - # Caching a 12G image is unfortunately not possible: - # https://github.com/ScribeMD/docker-cache/issues/304 - # For faster builds we would have to pay for some persistent runners. - - name: Download docker image && ls /opt/toolchains/ - run: cd workspace && ./sof/zephyr/docker-run.sh ls -l /opt/toolchains/ + - name: print all available sdks in /opt/toolchains/ + run: | + ls -l /opt/toolchains/ - # https://github.com/zephyrproject-rtos/docker-image - # Note: env variables can be passed to the container with - # -e https_proxy=... - name: build - run: cd workspace && ./sof/zephyr/docker-run.sh - ./sof/zephyr/docker-build.sh --cmake-args=-DEXTRA_CFLAGS=-Werror - --cmake-args=-DEXTRA_CXXFLAGS=-Werror - --cmake-args=-DEXTRA_AFLAGS='-Werror -Wa,--fatal-warnings' - --cmake-args=--warn-uninitialized - --overlay=sof/app/configs/repro-build.conf - --no-tarball - ${{ matrix.build_opts }} ${{ matrix.IPC_platforms }} + run: | + ./sof/zephyr/docker-build.sh --cmake-args=-DEXTRA_CFLAGS=-Werror \ + --cmake-args=-DEXTRA_CXXFLAGS=-Werror \ + --cmake-args=-DEXTRA_AFLAGS='-Werror -Wa,--fatal-warnings' \ + --cmake-args=--warn-uninitialized \ + --overlay=sof/app/configs/repro-build.conf \ + --no-tarball \ + ${{ matrix.build_opts }} ${{ matrix.IPC_platforms }} - name: Upload build artifacts uses: actions/upload-artifact@v4 - if: ${{ matrix.zephyr_revision == 'mnfst' }} + if: always() with: name: linux-build ${{ matrix.build_opts }} ${{ matrix.IPC_platforms }} if-no-files-found: error path: | - ${{ github.workspace }}/workspace/build-sof-staging - ${{ github.workspace }}/workspace/**/compile_commands.json + build-sof-staging + ./**/compile_commands.json build-windows: runs-on: windows-latest strategy: fail-fast: false matrix: + # Search "zephyr_revision" and see below what they expand to. + zephyr_revision: [ + "${{ inputs.zephyr_revision || 'mnfst' }}" + ] # Using groups to avoid spamming the small results box with too # many lines. Pay attention to COMMAS. platforms: [ # - IPC3 default - imx8 imx8x imx8m imx8ulp, - # - IPC4 default + imx8 imx8x, + imx8m imx8ulp, + # - IPC4 default, released mtl, - tgl tgl-h, + lnl, + # active development + ptl, + # legacy + tgl, + tgl-h ] build_opts: [""] # Sparse matrices are complicated, see comments on Linux matrix above. include: - build_opts: -d - platforms: mtl + zephyr_revision: mnfst + platforms: lnl steps: @@ -270,12 +302,12 @@ jobs: # Keep this SDK version identical to the one in # sof/zephyr/docker-run.sh - - name: Cache Zephyr SDK 0.17.0 + - name: Cache Zephyr SDK 1.0.0 id: cache-zephyr-sdk uses: actions/cache@v4 with: - path: zephyr-sdk-0.17.0_windows-x86_64.7z - key: ${{ runner.os }}-cache-zephyr-sdk-0-17-0 + path: zephyr-sdk-1.0.0_windows-x86_64_gnu.7z + key: ${{ runner.os }}-cache-zephyr-sdk-1-0-0 # Wget is needed by Zephyr SDK setup.cmd installation script - name: Download wget @@ -283,11 +315,11 @@ jobs: run: | curl -L -O http://downloads.sourceforge.net/gnuwin32/wget-1.11.4-1-bin.zip - - name: Download Zephyr SDK 0.17.0 + - name: Download Zephyr SDK 1.0.0 if: ${{ steps.cache-zephyr-sdk.outputs.cache-hit != 'true' }} run: | # yamllint disable-line rule:line-length curl -L -O ` - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.17.0/zephyr-sdk-0.17.0_windows-x86_64.7z + https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v1.0.0/zephyr-sdk-1.0.0_windows-x86_64_gnu.7z # Unzips every .zip package to directory matching its name without extension - name: Unzip downloaded packages @@ -310,12 +342,12 @@ jobs: # setup.cmd may not be called in from msys shell as it does not parse # forward slash script input arguments correctly. - name: Install Zephyr SDK - run: zephyr-sdk-0.17.0_windows-x86_64/zephyr-sdk-0.17.0/setup.cmd /t all /h /c + run: zephyr-sdk-1.0.0_windows-x86_64_gnu/zephyr-sdk-1.0.0/setup.cmd /t all /h /c - name: Setup Python uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.12' - name: West install run: pip3 install west @@ -327,19 +359,50 @@ jobs: west init -l sof west update --narrow --fetch-opt=--filter=tree:0 - # Get some tags to fix `git describe`, see build-linux comments above. - cd zephyr + - name: select zephyr revision + working-directory: ${{ github.workspace }}/workspace + run: | + if ('mnfst' -eq '${{ matrix.zephyr_revision }}') { + $rem_rev = $(git -C zephyr rev-parse HEAD) + } else { + switch ('${{ matrix.zephyr_revision }}') { + 'zmain' { $rem_rev = 'main' } + default { Write-Error 'Unknown matrix.zephyr_revision'; exit 1 } + } + Push-Location sof/submanifests/ + (Get-Content sof-ci-jenkins/zephyr-override-template.yml) ` + -replace '=sof_zephyr_revision_override=', "$rem_rev" ` + | Set-Content test-zephyr-main.yml + Pop-Location + west update --narrow --fetch-opt=--filter=tree:0 + } + + # Get some tags to fix `git describe` etc., see detailed build-linux comments above. + - name: Fetch tags for git describe + working-directory: ${{ github.workspace }}/workspace/zephyr + # Keep in sync with build-linux above + run: | + # Set-PSDebug -Trace 2 $_rev = "$(git rev-parse HEAD)" - git fetch --filter=tree:0 "$(west list -f '{url}' zephyr)" "${_rev}:_branch_placeholder" - git branch -D _branch_placeholder + $_zurl = "$(west list -f '{url}' zephyr)" + git remote add sof_zep_rem "${_zurl}" + # Unlike Linux above, hardcode "main" for now. Will make no difference most + # of the time but keeps this bit consistent with Linux, tested and ready to use. + git fetch --filter=tree:0 sof_zep_rem main + git fetch --filter=tree:0 --tags sof_zep_rem + west list + west status + git log --oneline -n 5 --decorate --graph --no-abbrev-commit + git describe --long --always --dirty + git describe --long --always --dirty --tags # Call Setup Python again to save the PIP packages in cache - name: Setup Python uses: actions/setup-python@v5 id: cache-python with: - python-version: '3.10' + python-version: '3.12' cache: 'pip' cache-dependency-path: workspace/zephyr/scripts/requirements.txt @@ -354,17 +417,17 @@ jobs: choco install ninja ninja.exe --version - # MSYS2 provides gcc x64_86 toolchain & openssl + # MSYS2 provides gcc x86_64 toolchain, openssl & gperf # 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 + uses: msys2/setup-msys2@cafece8e6baf9247cf9b1bf95097b0b983cc558d # v2 with: msystem: MSYS - install: gcc openssl-devel + install: gcc openssl-devel gperf path-type: inherit - name: Build @@ -382,6 +445,7 @@ jobs: - name: Upload build artifacts uses: actions/upload-artifact@v4 + if: always() with: name: windows-build ${{ matrix.build_opts }} ${{ matrix.platforms }} if-no-files-found: error @@ -428,11 +492,14 @@ jobs: run: | diffs=0; ls -l - # Check not too much is missing (it happened!) + # Look for a few samples to + # check not too much is missing (it happened!) # http://mywiki.wooledge.org/ParsingLs - for regdir in 'linux-build *mtl' \ - 'windows-build *mtl' \ - 'windows-build *tgl tgl-h'; do + for regdir in 'linux-build *-d *.*' \ + 'linux-build *.*lnl.*' \ + 'windows-build *.*mtl.*' \ + 'windows-build *tgl-h' \ + 'windows-build *tgl'; do find . -maxdepth 1 | grep -q "\./${regdir}\$" || { >&2 printf 'Missing %s\n' "${regdir}"; exit 1; } done diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 000000000000..45303525aa81 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,37 @@ +--- +name: "Zizmor GitHub Actions Analysis" +# yamllint disable-line rule:truthy +on: + push: + branches: + - 'main' + pull_request: + branches: + - 'main' + +permissions: {} + +# Specifies group name that stops previous workflows if the name matches +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + zizmor: + name: Analyze workflows with zizmor + runs-on: ubuntu-latest + permissions: + security-events: write # Required to upload SARIF results to the Security tab + actions: read # Required to read workflow information + contents: read # Required to checkout repository + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 + with: + inputs: .github/workflows/ diff --git a/.gitignore b/.gitignore index 9d50048ab954..043112c6ff78 100644 --- a/.gitignore +++ b/.gitignore @@ -49,7 +49,6 @@ tools/test/audio/reports/* tools/test/audio/zeros_in.raw __pycache__ -.checkpatch-camelcase.git.* build*/ diff --git a/tools/rimage/scripts/const_structs.checkpatch b/.sourcegraph/ignore similarity index 100% rename from tools/rimage/scripts/const_structs.checkpatch rename to .sourcegraph/ignore diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a788a0800c5e..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,112 +0,0 @@ ---- -# Suggested tools that can save round-trips to github and a lot of time: -# -# yamllint .travis.yml -# ~/.gem/ruby/2.7.0/bin/travis lint .travis.yml -# yaml merge-expand .travis.yml exp.yml && diff -b -u .travis.yml exp.yml - -language: c -# Ubuntu 20.04 LTS -dist: focal - -git: - depth: false - -services: - - docker - -# We don't need the strict sequence of stages; for now we use stages -# only as presentation labels. Nothing in stage "tests" will run if -# anything in buildonly fails; in the future we may want to get rid of -# stages. -stages: - - buildonly - - tests - - -# 'name:'-less jobs appear with their env, e.g.: PLATFORM=tgl -jobs: - include: - - # stage buildonly - - - &build-platform - stage: buildonly - before_install: - &docker-pull-sof - docker pull thesofproject/sof && docker tag thesofproject/sof sof - script: - ./scripts/docker-run.sh ./scripts/xtensa-build-all.sh -r $PLATFORM - env: PLATFORM='jsl' - - - <<: *build-platform - env: PLATFORM='sue' - - - <<: *build-platform - env: PLATFORM='tgl' - - - <<: *build-platform - env: PLATFORM='tgl-h' - - - name: "./scripts/build-tools.sh Release" - before_install: *docker-pull-sof - script: CMAKE_BUILD_TYPE=Release ./scripts/docker-run.sh ./scripts/build-tools.sh - - # stage tests - - - &qemuboottest - stage: tests - script: - - echo CONFIG_HAVE_AGENT=n > src/arch/xtensa/configs/override/no-agent.config - - ./scripts/docker-run.sh ./scripts/xtensa-build-all.sh -o no-agent -r $PLATFORM - - ./scripts/docker-qemu.sh ../sof.git/scripts/qemu-check.sh $PLATFORM - env: PLATFORM='byt cht' - before_install: - - *docker-pull-sof - - docker pull thesofproject/sofqemu && - docker tag thesofproject/sofqemu sofqemu - - - <<: *qemuboottest - env: PLATFORM='bdw hsw' - - - <<: *qemuboottest - env: PLATFORM='apl skl kbl' - - - <<: *qemuboottest - env: PLATFORM='cnl icl' - - - <<: *qemuboottest - env: PLATFORM='imx8 imx8x imx8m' - - - - name: testbench - before_install: *docker-pull-sof - script: - # testbench needs some topologies - - ./scripts/docker-run.sh ./scripts/build-tools.sh -t - - ./scripts/docker-run.sh ./scripts/rebuild-testbench.sh - - ./scripts/host-testbench.sh - - - - name: doxygen - - before_install: sudo apt-get -y install ninja-build doxygen graphviz - - script: - - # Show ALL warnings. Warnings don't cause doxygen to fail (yet). - - mkdir -p doxybuild && pushd doxybuild && cmake -GNinja -S ../doc && - ninja -v doc - - popd - - # Build again (it's very quick) and report a failure in Travis if - # any issue. This time doxygen stops on the first issue. - - printf 'WARN_AS_ERROR = YES\n' >> doc/sof.doxygen.in - - ninja -C doxybuild -v doc - -notifications: - irc: - channels: - - "chat.freenode.net#sof" - on_success: always - on_failure: always diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000000..462c39f0d343 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,22 @@ +# Sound Open Firmware (SOF) Agent Workflows and Rules + +This document outlines the rules AI agents must follow when checking out branches, writing code, documenting features, and running the development environment. Follow these rules carefully: + +## Development Standards + +### Commitment and Sign-off Rules +* **Commit Subject:** Must follow the format `subsystem: component: short description` matching the SOF project convention. Use the git history of the modified file(s) (`git log --oneline -10 -- `) to determine the correct subsystem and component prefix. Examples: + * `audio: chain_dma: add user-space scheduling support` + * `ipc4: handler: fix large config dispatch` + * `schedule: zephyr_domain: add user-space LL thread` +* **Commit Body:** Should describe the changes in detail in the commit message body. +* **Sign-off:** All commits must be signed off by the developer (`Signed-off-by: Name `) using the identity from the local git config. + +### Documentation Requirements +* **Doxygen Comments:** Any new C code or features must include Doxygen comments. +* **Documentation Builds:** Integration of new code must not introduce any new Doxygen errors or warnings. Code additions should be verified against a clean documentation build. +* **Architectural Consistency:** When adding or updating a file, any `architecture.md` or `README.md` in the same directory must be reviewed. The agent is responsible for ensuring documentation stays in sync with code logic changes. + +### Codestyle and Linting +* **Standard:** Use `clangd` instead of `checkpatch` for codestyle verification. +* **Rationale:** `checkpatch` is prone to confusion with assembly and non-standard C; `clangd` provides better integration with IDEs and AI tools and is easier to maintain. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 000000000000..e236a2b659e6 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,46 @@ +# Sound Open Firmware (SOF) Architecture + +This document provides a high-level overview of the Sound Open Firmware (SOF) architecture. SOF provides an open-source audio DSP firmware and an SDK for audio development. + +## 1. High-Level Overview + +At a macro level, the SOF stack consists of: +* **Host Driver (OS):** The OS-level driver (Linux ALSA/ASoC, Windows, etc.) that acts as the frontend, managing audio devices, streams, and IPC communication. +* **Firmware (DSP):** The embedded firmware running on the Audio DSP (typically Xtensa/Tensilica or other DSPs). +* **Topology:** A configuration file loaded by the host driver that defines the hardware constraints, routing, and instantiated audio processing graphs (pipelines). + +## 2. Firmware Architecture + +The SOF firmware is built with a modular, layered architecture to support multiple platforms, DSP architectures, and operating systems. + +### 2.1 OS Abstraction and RTOS +* **Zephyr RTOS:** Modern SOF extensively leverages the Zephyr RTOS for core operating system services, including thread scheduling, synchronization, logging, and hardware abstraction. +* **XTOS / Bare-metal (Legacy):** Older platforms or specific stripped-down environments might use XTOS or bare-metal abstractions. + +### 2.2 Inter-Process Communication (IPC) +The IPC subsystem is responsible for all communication between the Host OS and the DSP Firmware. +* **Message Passing:** Uses hardware mailboxes, shared memory, and interrupts to send messages. +* **Commands:** Includes stream setup, pipeline instantiation, run/pause/stop commands, volume changes, and parameter updates. +* **Versions:** IPC relies on a versioned message protocol (e.g., IPC3, IPC4) allowing the host and firmware to understand each other's commands. + +### 2.3 Audio Processing Pipelines +At the core of the SOF firmware is the DSP pipeline. A pipeline is a directed graph consisting of connected audio modules (components) that process streams of data. +* **Endpoints:** Pipelines connect external interfaces (like I2S/HDA/DMIC DAIs - Digital Audio Interfaces) to host DMA buffers. +* **Scheduling:** Each pipeline is scheduled to run periodically based on its timing requirements and deadlines. SOF provides an LL (Low Latency) scheduler and an EDF (Earliest Deadline First) scheduler. + +### 2.4 Audio Components (Modules) +The firmware processing graph is assembled using individual audio modules, which are dynamically instantiated based on the topology file: +* **Host / DAI Components:** Read/write audio frames from/to DMA buffers or hardware interfaces. +* **Copier:** Moves data between buffers or other components without modification. +* **Volume / Mixer:** Changes signal amplitude or mixes multiple streams. +* **SRC (Sample Rate Converter):** Resamples audio streams. +* **Effect Modules:** EQs (Equalizers), DRCs (Dynamic Range Compressors), smart amplifiers, arrays, and other algorithmic components. + +### 2.5 Memory Management +The DSP handles multiple memory domains depending on the hardware (SRAM, L1 Cache, L2, external memory). +* **Heaps:** Different memory heaps exist for dynamic allocation (e.g., system heap, buffer heap, runtime heap) to ensure real-time constraints and avoid fragmentation. +* **Data Buffers:** Audio buffers are carefully allocated in appropriate memory to minimize power consumption and pipeline latency. + +## 3. Topologies + +The host driver parses a topology file (`.tplg`) which describes the expected processing graphs. Instead of hardcoding audio routing in the firmware, SOF uses these topology constraints. The firmware receives the component creation sequences, parameter configurations, and connections over IPC to construct pipelines at runtime. diff --git a/CODEOWNERS b/CODEOWNERS index ec5ab51af9b6..9cd3ec9bcb48 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -12,8 +12,8 @@ # include files src/include/sof/drivers/dmic.h @singalsu src/include/ipc/** @thesofproject/steering-committee -src/include/ipc/** @randerwang @marcinszkudlinski @pblaszko -src/include/ipc4/** @randerwang @marcinszkudlinski @pblaszko +src/include/ipc/** @randerwang @tmleman @pblaszko +src/include/ipc4/** @randerwang @tmleman @pblaszko src/include/kernel/** @thesofproject/steering-committee src/include/user/** @thesofproject/steering-committee src/include/sof/debug/gdb/* @abonislawski @@ -62,7 +62,7 @@ src/drivers/mediatek/mt8195/* @yaochunhung @kuanhsuncheng # other libs src/math/* @singalsu -src/ipc/* @bardliao @marcinszkudlinski @pblaszko +src/ipc/* @bardliao @tmleman @pblaszko # src/lib/* TODO src/debug/gdb/* @abonislawski src/schedule @pblaszko @marcinszkudlinski @dbaluta @LaurentiuM1234 diff --git a/Kconfig.sof b/Kconfig.sof index 77dbe3de34fe..df63811e652b 100644 --- a/Kconfig.sof +++ b/Kconfig.sof @@ -1,110 +1,10 @@ # SPDX-License-Identifier: BSD-3-Clause -config XT_WAITI_DELAY - bool - default n - help - LX6 Xtensa platforms may require additional delay to flush loads - and stores before entering WAITI. config HOST_PTABLE bool default n -config XT_HAVE_RESET_VECTOR_ROM - bool - default n - help - Select if your platform has the reset vector - in ROM. - -config XT_IRQ_MAP - bool - default n - -config DMA_GW - bool - default n - -config MEM_WND - bool - default n - -config INTEL_IOMUX - bool - default n - -config DMA_HW_LLI - bool - default n - help - Hardware linked list is DMA feature, which allows - to automatically reload the next programmed linked list - item from memory without stopping the transfer. Without - it the transfer stops after every lli read and FW needs - to manually setup the next transfer. - - Any platforms with hardware linked list support - should set this. - -config DMA_SUSPEND_DRAIN - bool - default n - help - Some platforms cannot just simple disable DMA - channel during the transfer, because it will - hang the whole DMA controller. Instead we can - suspend the channel and drain the FIFO in order - to stop the channel as soon as possible. - - Any platforms without the ability to disable - the DMA channel right away should set this. - -config DMA_FIFO_PARTITION - bool - default n - help - Some platforms require to manually set DMA - FIFO partitions before starting any transfer. - - Any platforms without automatic FIFO partitions - should set this. - -config XT_INTERRUPT_LEVEL_1 - bool - default n - help - Select if the platform supports any interrupts of level 1. - Disabling this option allows for less memory consumption. - -config XT_INTERRUPT_LEVEL_2 - bool - default n - help - Select if the platform supports any interrupts of level 2. - Disabling this option allows for less memory consumption. - -config XT_INTERRUPT_LEVEL_3 - bool - default n - help - Select if the platform supports any interrupts of level 3. - Disabling this option allows for less memory consumption. - -config XT_INTERRUPT_LEVEL_4 - bool - default n - help - Select if the platform supports any interrupts of level 4. - Disabling this option allows for less memory consumption. - -config XT_INTERRUPT_LEVEL_5 - bool - default n - help - Select if the platform supports any interrupts of level 5. - Disabling this option allows for less memory consumption. - config COMPILER_WORKAROUND_CACHE_ATTR bool default n @@ -130,12 +30,35 @@ config COLD_STORE_EXECUTE_DRAM option to enable this feature to save SRAM and to speed up SRAM copying of performance-critical data and code. -rsource "src/Kconfig" -# See zephyr/modules/Kconfig -if !ZEPHYR_SOF_MODULE - rsource "Kconfig.xtos-build" -endif +config COLD_STORE_EXECUTE_DEBUG + bool "Enable checks for cold code on hot paths" + depends on !SOF_USERSPACE_LL + help + This enables an assert_can_be_cold() check, which causes an exception + if called in the LL task context and assert() evaluation is enabled. + +config FAST_GET + bool "Enable simple refcounting DRAM data copier" + help + Enable simple refcounting DRAM data copier for copying processing + module data from DRAM to SRAM when the data is needed and freeing + the SRAM when the data is not needed anymore. If multiple module + instances need the same chunk the same copy is used with reference + counting. Source is src/lib/fast-get.c. The option should be selected + on platforms, where __cold_rodata is supported. + +config SOF_OS_LINUX_COMPAT_PRIORITY + bool "Prioritize backwards compatibility for old Linux kernels" + help + Build option to maintain maximal backwards compatibility with old + versions of Linux SOF driver. When this is not set, firmware may + require newer version of host, and/or use features that are not + available in stable Linux kernel trees. + +rsource "Kconfig.xtos" + +rsource "src/Kconfig" if ZEPHYR_SOF_MODULE rsource "Kconfig.zephyr-log" @@ -163,22 +86,6 @@ config DEBUG_MEMORY_USAGE_SCAN This feature does not affect standard memory operations, especially allocation and deallocation. -config DEBUG_LOCKS - bool "Spinlock debug" - default n - help - It adds additional information to the spinlocks about - the current user of the lock. Also executes panic - on deadlock. - -config DEBUG_LOCKS_VERBOSE - bool "Spinlock verbose debug" - depends on DEBUG_LOCKS - default n - help - In addition to DEBUG_LOCKS it also adds spinlock traces - every time the lock is acquired. - config DEBUG_IPC_COUNTERS bool "IPC counters" depends on CAVS @@ -187,6 +94,19 @@ config DEBUG_IPC_COUNTERS help Select for enabling tracing IPC counter in SRAM_REG mailbox +config DEBUG_IPC_TIMINGS + bool "Enable IPC message handling time logging" + depends on DEBUG + default n + help + Adds a logging after IPC handling before putting IPC reply + to send queue. The logging contains both the reply and the + original request message headers and the time that it took + to process the request in micro seconds. The value can be + used to collect statistics on changes in firmware response + times. This also disables the logging of the received + request on core 0 to avoid flooding the logs too much. + config SCHEDULE_LOG_CYCLE_STATISTICS bool "Log cycles per tick statistics for each task separately" default y @@ -236,8 +156,4 @@ config DSP_RESIDENCY_COUNTERS R0, R1, R2 are abstract states which can be used differently based on platform implementation. -if !ZEPHYR_SOF_MODULE - rsource "Kconfig.xtos-dbg" -endif - endmenu diff --git a/Kconfig.xtos b/Kconfig.xtos new file mode 100644 index 000000000000..2aa6b991fe7a --- /dev/null +++ b/Kconfig.xtos @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: BSD-3-Clause + +# This file contains build options needed to support +# legacy driver code that still partially rely on XTOS +# definitions, even when used with Zephyr RTOS. +# +# When all platforms have moved over to native Zephyr +# drivers, this file can be removed + +config XT_WAITI_DELAY + bool + default n + help + LX6 Xtensa platforms may require additional delay to flush loads + and stores before entering WAITI. + +config XT_HAVE_RESET_VECTOR_ROM + bool + default n + help + Select if your platform has the reset vector + in ROM. + +config XT_IRQ_MAP + bool + default n + +config DMA_HW_LLI + bool + default n + help + Hardware linked list is DMA feature, which allows + to automatically reload the next programmed linked list + item from memory without stopping the transfer. Without + it the transfer stops after every lli read and FW needs + to manually setup the next transfer. + + Any platforms with hardware linked list support + should set this. + +config DMA_SUSPEND_DRAIN + bool + default n + help + Some platforms cannot just simple disable DMA + channel during the transfer, because it will + hang the whole DMA controller. Instead we can + suspend the channel and drain the FIFO in order + to stop the channel as soon as possible. + + Any platforms without the ability to disable + the DMA channel right away should set this. + +config DMA_FIFO_PARTITION + bool + default n + help + Some platforms require to manually set DMA + FIFO partitions before starting any transfer. + + Any platforms without automatic FIFO partitions + should set this. + +config XT_INTERRUPT_LEVEL_1 + bool + default n + help + Select if the platform supports any interrupts of level 1. + Disabling this option allows for less memory consumption. + +config XT_INTERRUPT_LEVEL_2 + bool + default n + help + Select if the platform supports any interrupts of level 2. + Disabling this option allows for less memory consumption. + +config XT_INTERRUPT_LEVEL_3 + bool + default n + help + Select if the platform supports any interrupts of level 3. + Disabling this option allows for less memory consumption. + +config XT_INTERRUPT_LEVEL_4 + bool + default n + help + Select if the platform supports any interrupts of level 4. + Disabling this option allows for less memory consumption. + +config XT_INTERRUPT_LEVEL_5 + bool + default n + help + Select if the platform supports any interrupts of level 5. + Disabling this option allows for less memory consumption. diff --git a/Kconfig.xtos-build b/Kconfig.xtos-build deleted file mode 100644 index b2956a46bbf9..000000000000 --- a/Kconfig.xtos-build +++ /dev/null @@ -1,43 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -comment "XTOS options / compiler" - -choice - prompt "Optimization" - default OPTIMIZE_FOR_PERFORMANCE - help - Controls how compiler should optimize binary. - This config should affect only compiler settings and is - not meant to be used for conditional compilation of code. - -config OPTIMIZE_FOR_PERFORMANCE - bool "Optimize for performance" - help - Apply compiler optimizations prioritizing performance. - It means -O2 for GCC or equivalent for other compilers. - -config OPTIMIZE_FOR_SIZE - bool "Optimize for size" - help - Apply compiler optimizations prioritizing binary size. - It means -Os for GCC or equivalent for other compilers. - -config OPTIMIZE_FOR_DEBUG - bool "Optimize for debug" - help - Apply compiler optimizations prioritizing debugging experience. - It means -Og for GCC or equivalent for other compilers. - -config OPTIMIZE_FOR_NONE - bool "Don't optimize" - help - Apply no compiler optimizations. - It means -O0 for GCC or equivalent for other compilers. - -endchoice - -config BUILD_VM_ROM - bool "Build VM ROM" - default n - help - Select if you want to build VM ROM diff --git a/Kconfig.xtos-dbg b/Kconfig.xtos-dbg deleted file mode 100644 index 6994d2271994..000000000000 --- a/Kconfig.xtos-dbg +++ /dev/null @@ -1,23 +0,0 @@ -config DEBUG_HEAP - bool "Heap debug" - default n - help - Select for enable heap alloc debugging - -config DEBUG_BLOCK_FREE - bool "Blocks freeing debug" - default n - help - It enables checking if free was called multiple times on - already freed block of memory. Enabling this feature increases - number of memory writes and reads, due to checks for memory patterns - that may be performed on allocation and deallocation. - -config DEBUG_FORCE_COHERENT_BUFFER - bool "Force the allocator to allocate coherent buffer only" - default n - help - Select if we want to force the allocator to return coherent/uncached - buffer only. - This should be selected for debug purpose only, as accessing buffer - without caching it will reduce the read/write performance. diff --git a/README.md b/README.md index 1cf8da093bfa..e1fa62ce9b09 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ### Status [![Daily Actions](https://github.com/thesofproject/sof/actions/workflows/daily-tests.yml/badge.svg)](https://github.com/thesofproject/sof/actions/workflows/daily-tests.yml) +[![Zephyr Main Branch](https://github.com/thesofproject/sof/actions/workflows/zephyr-main.yml/badge.svg)](https://github.com/thesofproject/sof/actions/workflows/zephyr-main.yml) ### Community @@ -13,6 +14,17 @@ Additional community support is available via the `#sof` channel in the Zephyr P See [docs](https://thesofproject.github.io/latest/index.html) +## Quickstart + +You can easily set up the complete SOF development environment, including Zephyr SDK and QEMU, by running our interactive installer script. To run the installer locally: + +```bash +curl -fsSLo sdk-install.sh https://raw.githubusercontent.com/thesofproject/vscode-workspace/main/sdk-install.sh +bash sdk-install.sh +``` + +The script will guide you through the process of installing system dependencies, cloning the repositories, configuring Python virtual environments, and setting up the Zephyr SDK and QEMU. + ## Running the tests See [unit testing documentation](https://thesofproject.github.io/latest/developer_guides/unit_tests.html) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index da9db799d387..832d4eb12098 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -10,6 +10,6 @@ target_sources(app PRIVATE ) zephyr_library_include_directories(app PUBLIC - ${sof_module}/src/arch/xtensa/include - ${sof_module}/src/include + ${CMAKE_CURRENT_SOURCE_DIR}/../src/arch/xtensa/include + ${CMAKE_CURRENT_SOURCE_DIR}/../src/include ) diff --git a/app/Kconfig b/app/Kconfig index 1ea5b4d46f61..56ada456367e 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -4,5 +4,13 @@ config SCHED_CPU_MASK_PIN_ONLY config SMP_BOOT_DELAY default y if SMP +# Allow compiler to determine whether to generate FLIX instructions. +choice COMPILER_CODEGEN_VLIW + default COMPILER_CODEGEN_VLIW_AUTO if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "xt-clang" +endchoice + source "Kconfig.zephyr" +if SOC_FAMILY_INTEL_ADSP + rsource "boards/intel_adsp/Kconfig.defconfig" +endif diff --git a/app/boards/acp_6_0_adsp.conf b/app/boards/acp_6_0_adsp.conf index 2e4332e31dcd..b527ea3753a7 100644 --- a/app/boards/acp_6_0_adsp.conf +++ b/app/boards/acp_6_0_adsp.conf @@ -8,3 +8,33 @@ CONFIG_ZEPHYR_LOG=n CONFIG_DMA=y CONFIG_ZEPHYR_NATIVE_DRIVERS=n CONFIG_AMS=n +CONFIG_COMP_SRC=n +CONFIG_COMP_FIR=n +CONFIG_COMP_IIR=n +CONFIG_COMP_DCBLOCK=n +CONFIG_COMP_CROSSOVER=n +CONFIG_COMP_DRC=n +CONFIG_COMP_MULTIBAND_DRC=n +CONFIG_COMP_TONE=n +CONFIG_COMP_KPB=n +CONFIG_MAXIM_DSM=n +CONFIG_COMP_ASRC=n +CONFIG_COMP_IGO_NR=n +CONFIG_COMP_COPIER=n +CONFIG_COMP_RTNR=n +CONFIG_COMP_ARIA=n +CONFIG_COMP_BASEFW_IPC4=n +CONFIG_COMP_UP_DOWN_MIXER=n +CONFIG_COMP_TDFB=n +CONFIG_COMP_SEL=n +CONFIG_COMP_MIXER=n +CONFIG_ASRC_SUPPORT_CONVERSION_24000_TO_08000=n +CONFIG_ASRC_SUPPORT_CONVERSION_24000_TO_16000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_08000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_11025=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_12000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_16000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_22050=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_24000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_32000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_44100=n diff --git a/app/boards/acp_7_0_adsp.conf b/app/boards/acp_7_0_adsp.conf new file mode 100644 index 000000000000..5eb2ff9f7b95 --- /dev/null +++ b/app/boards/acp_7_0_adsp.conf @@ -0,0 +1,55 @@ +CONFIG_ACP_7_0=y +CONFIG_HAVE_AGENT=n +CONFIG_DCACHE_LINE_SIZE_DETECT=n +CONFIG_DCACHE_LINE_SIZE=128 +CONFIG_DYNAMIC_INTERRUPTS=y +CONFIG_SHARED_INTERRUPTS=n +CONFIG_ZEPHYR_LOG=y +CONFIG_LOG_MODE_DEFERRED=n +CONFIG_LOG_MODE_MINIMAL=y +CONFIG_DMA=y +CONFIG_DMA_DOMAIN=n +CONFIG_ZEPHYR_NATIVE_DRIVERS=y +CONFIG_INTC_AMD_ACP=y +CONFIG_DMA_AMD_ACP_HOST=y +CONFIG_DMA_AMD_ACP_SDW=y +CONFIG_DAI_AMD_SDW=y +CONFIG_DMA_AMD_ACP_TDM=y +CONFIG_DAI_AMD_TDM=y +CONFIG_AMS=n +CONFIG_WRAP_ACTUAL_POSITION=y +CONFIG_TRACE=n +CONFIG_COMP_VOLUME=y +CONFIG_COMP_SRC=n +CONFIG_COMP_FIR=n +CONFIG_COMP_IIR=n +CONFIG_COMP_DCBLOCK=n +CONFIG_COMP_CROSSOVER=n +CONFIG_COMP_DRC=n +CONFIG_COMP_MULTIBAND_DRC=n +CONFIG_COMP_TONE=n +CONFIG_COMP_KPB=n +CONFIG_MAXIM_DSM=n +CONFIG_COMP_ASRC=n +CONFIG_COMP_IGO_NR=n +CONFIG_COMP_COPIER=n +CONFIG_COMP_RTNR=n +CONFIG_COMP_ARIA=n +CONFIG_COMP_BASEFW_IPC4=n +CONFIG_COMP_UP_DOWN_MIXER=n +CONFIG_COMP_TDFB=n +CONFIG_COMP_SEL=n +CONFIG_COMP_MIXER=n +CONFIG_ASRC_SUPPORT_CONVERSION_24000_TO_08000=n +CONFIG_ASRC_SUPPORT_CONVERSION_24000_TO_16000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_08000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_11025=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_12000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_16000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_22050=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_24000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_32000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_44100=n +CONFIG_CORE_COUNT=1 +CONFIG_FORMAT_CONVERT_HIFI3=n +CONFIG_COMP_MFCC=n \ No newline at end of file diff --git a/app/boards/acp_7_x_adsp.conf b/app/boards/acp_7_x_adsp.conf new file mode 100644 index 000000000000..04c63271c9ac --- /dev/null +++ b/app/boards/acp_7_x_adsp.conf @@ -0,0 +1,57 @@ +CONFIG_ACP_7_X=y +CONFIG_HAVE_AGENT=n +CONFIG_DCACHE_LINE_SIZE_DETECT=n +CONFIG_DCACHE_LINE_SIZE=128 +CONFIG_DYNAMIC_INTERRUPTS=y +CONFIG_SHARED_INTERRUPTS=n +CONFIG_ZEPHYR_LOG=y +CONFIG_LOG_MODE_DEFERRED=n +CONFIG_LOG_MODE_MINIMAL=y +CONFIG_DMA=y +CONFIG_DMA_DOMAIN=n +CONFIG_ZEPHYR_NATIVE_DRIVERS=y +CONFIG_INTC_AMD_ACP=y +CONFIG_DMA_AMD_ACP_HOST=y +CONFIG_DMA_AMD_ACP_SDW=y +CONFIG_DMA_AMD_ACP_SDW_CHANNEL_COUNT=64 +CONFIG_DMA_AMD_ACP_TDM=y +CONFIG_DAI_AMD_SDW=y +CONFIG_DAI_AMD_TDM=y +CONFIG_AMS=n +CONFIG_WRAP_ACTUAL_POSITION=y +CONFIG_TRACE=n +CONFIG_COMP_VOLUME=y +CONFIG_COMP_SRC=n +CONFIG_COMP_FIR=n +CONFIG_COMP_IIR=n +CONFIG_COMP_DCBLOCK=n +CONFIG_COMP_CROSSOVER=n +CONFIG_COMP_DRC=n +CONFIG_COMP_MULTIBAND_DRC=n +CONFIG_COMP_TONE=n +CONFIG_COMP_KPB=n +CONFIG_MAXIM_DSM=n +CONFIG_COMP_ASRC=n +CONFIG_COMP_IGO_NR=n +CONFIG_COMP_COPIER=n +CONFIG_COMP_RTNR=n +CONFIG_COMP_ARIA=n +CONFIG_COMP_BASEFW_IPC4=n +CONFIG_COMP_UP_DOWN_MIXER=n +CONFIG_COMP_TDFB=n +CONFIG_COMP_SEL=n +CONFIG_COMP_MIXER=n +CONFIG_ASRC_SUPPORT_CONVERSION_24000_TO_08000=n +CONFIG_ASRC_SUPPORT_CONVERSION_24000_TO_16000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_08000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_11025=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_12000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_16000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_22050=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_24000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_32000=n +CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_44100=n +CONFIG_CORE_COUNT=1 +CONFIG_FORMAT_CONVERT_HIFI3=n +CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB=y +CONFIG_XTENSA_INTERRUPT_NONPREEMPTABLE=y diff --git a/app/boards/imx8mp_evk_mimx8ml8_adsp.conf b/app/boards/imx8mp_evk_mimx8ml8_adsp.conf index f1ed34f8dc99..da9e56d759a4 100644 --- a/app/boards/imx8mp_evk_mimx8ml8_adsp.conf +++ b/app/boards/imx8mp_evk_mimx8ml8_adsp.conf @@ -4,6 +4,7 @@ CONFIG_FORMAT_CONVERT_HIFI3=n CONFIG_KPB_FORCE_COPY_TYPE_NORMAL=n CONFIG_DMA=y CONFIG_DMA_NXP_SDMA=y +CONFIG_DAI_NXP_MICFIL=y CONFIG_TRACE=n CONFIG_SHARED_INTERRUPTS=y CONFIG_ZEPHYR_NATIVE_DRIVERS=y diff --git a/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay b/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay index c977fb8410e9..6748b621985a 100644 --- a/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay +++ b/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay @@ -23,3 +23,7 @@ rx-sync-mode = <1>; status = "okay"; }; + +&micfil { + status = "okay"; +}; diff --git a/app/boards/imx8mp_evk_mimx8ml8_m7_ddr.conf b/app/boards/imx8mp_evk_mimx8ml8_m7_ddr.conf new file mode 100644 index 000000000000..290f27a2b933 --- /dev/null +++ b/app/boards/imx8mp_evk_mimx8ml8_m7_ddr.conf @@ -0,0 +1,15 @@ +CONFIG_IMX8M_CM7=y +CONFIG_ZEPHYR_NATIVE_DRIVERS=y +CONFIG_CACHE_MANAGEMENT=y +CONFIG_NOCACHE_MEMORY=y +CONFIG_DYNAMIC_INTERRUPTS=y +CONFIG_SHARED_INTERRUPTS=y +CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK=y +CONFIG_ROMSTART_RELOCATION_ROM=y +CONFIG_DMA_NXP_SOF_HOST_DMA_ALIGN=32 +CONFIG_DMA=y +CONFIG_DMA_NXP_SDMA=y +CONFIG_DAI_NXP_SAI=y +CONFIG_SAI_HAS_MCLK_CONFIG_OPTION=y +CONFIG_COMP_ASRC=n + diff --git a/app/boards/imx8mp_evk_mimx8ml8_m7_ddr.overlay b/app/boards/imx8mp_evk_mimx8ml8_m7_ddr.overlay new file mode 100644 index 000000000000..3f712e3ad00c --- /dev/null +++ b/app/boards/imx8mp_evk_mimx8ml8_m7_ddr.overlay @@ -0,0 +1,27 @@ +/* + * Copyright 2026 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + host_dma: dma { + compatible = "nxp,sof-host-dma"; + dma-channels = <32>; + #dma-cells = <0>; + }; +}; + +&sdma3 { + status = "okay"; +}; + +&sai3 { + pinctrl-0 = <&sai3_default>; + pinctrl-names = "default"; + rx-fifo-watermark = <64>; + tx-fifo-watermark = <64>; + fifo-depth = <96>; + rx-sync-mode = <1>; + status = "okay"; +}; diff --git a/app/boards/imx95_evk_mimx9596_m7_ddr.overlay b/app/boards/imx95_evk_mimx9596_m7_ddr.overlay index 34882b5d59fd..4c9ce43c9452 100644 --- a/app/boards/imx95_evk_mimx9596_m7_ddr.overlay +++ b/app/boards/imx95_evk_mimx9596_m7_ddr.overlay @@ -5,6 +5,11 @@ */ / { + /* this'll select Cortex-M SysTick as the system timer */ + chosen { + /delete-property/ zephyr,system-timer; + }; + host_dma: dma { compatible = "nxp,sof-host-dma"; dma-channels = <32>; @@ -17,9 +22,23 @@ rx-fifo-watermark = <96>; fifo-depth = <96>; rx-sync-mode = <1>; + dmas = <&edma2 30 60>, <&edma2 31 61>; status = "okay"; }; +&edma1 { + status = "disabled"; +}; + &edma2 { + compatible = "nxp,edma"; + reg = <0x42000000 (DT_SIZE_K(64) * 33)>; + valid-channels = <30>, <31>; + interrupts = <143 0>, <143 0>; + /delete-property/ nxp,version; + /delete-property/ dma-channels; + /delete-property/ dma-requests; + /delete-property/ no-error-irq; + /delete-property/ channels-shared-irq-mask; status = "okay"; }; diff --git a/app/boards/intel_adsp/Kconfig.defconfig b/app/boards/intel_adsp/Kconfig.defconfig new file mode 100644 index 000000000000..f705960eee1a --- /dev/null +++ b/app/boards/intel_adsp/Kconfig.defconfig @@ -0,0 +1,185 @@ +# Common defaults for all Intel ADSP SOF targets +# +# SPDX-License-Identifier: BSD-3-Clause + +# --- +# NOTICE! defconfig files cannot override settings that already have +# a default set. Thus some settings (especially choice values with +# a default), must be set in the board config files even if the value +# is same for all Intel DSPs. +# --- + +# SOF / IPC configuration +# ----------------------- + +config IPC4_BASE_FW_INTEL + default y + +# SOF / audio pipeline and module settings +# ---------------------------------------- + +config COMP_CHAIN_DMA + default y + +config COMP_KPB + default y + +config COMP_UP_DOWN_MIXER + default y + +config COMP_VOLUME_WINDOWS_FADE + default y + +config FAST_GET + default y + +config FORMAT_A_LAW + default y + +config FORMAT_FLOAT + default y + +config FORMAT_MU_LAW + default y + +config FORMAT_U8 + default y + +config PCM_CONVERTER_FORMAT_A_LAW + default y + +config PCM_CONVERTER_FORMAT_FLOAT + default y + +config PCM_CONVERTER_FORMAT_MU_LAW + default y + +config PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32 + default y + +config PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32 + default y + +config PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32 + default y + +config PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32 + default y + +config PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 + default y + +config PCM_CONVERTER_FORMAT_S24_C32_AND_S24_C24 + default y + +config PCM_CONVERTER_FORMAT_U8 + default y + +config PIPELINE_2_0 + default y + +# SOF / infrastructure +# ---------------------------------------- + +config L3_HEAP + default y if ACE + +config ZEPHYR_DP_SCHEDULER + default y + +config ZEPHYR_NATIVE_DRIVERS + default y + +# SOF / logging +# ---------------------------------------- + +config ZEPHYR_LOG + default y + +# Zephyr / device drivers +# ---------------------------------------- + +config CLOCK_CONTROL + default y + +# note: CONFIG_CLOCK_CONTROL_ADSP is enabled by default +# based on DT definition. + +config DAI + default y + +config DAI_INTEL_DMIC + default y + +config DAI_INTEL_SSP + default y + +config INTEL_ADSP_IPC + default y + +config INTEL_ADSP_TIMER + default y + +config MM_DRV + default y + +config UAOL + default y if ACE + + +# # Zephyr / power settings +# ---------------------------------------- + +config PM + default y + +config PM_DEVICE + default y + +config PM_DEVICE_RUNTIME + default y + +config PM_DEVICE_SYSTEM_MANAGED + default y + +config POWER_DOMAIN + default y + +# note: POWER_DOMAIN_INTEL_ADSP will be set based on DT + +# Zephyr / logging +# ---------------------------------------- + +config LOG_BACKEND_ADSP_MTRACE + default y + +config LOG_FUNC_NAME_PREFIX_ERR + default y + +config LOG_FUNC_NAME_PREFIX_WRN + default y + +config LOG_FUNC_NAME_PREFIX_INF + default y + +config LOG_FUNC_NAME_PREFIX_DBG + default y + +config LOG_CORE_ID_PREFIX + default y + +config LOG_TIMESTAMP_64BIT + default y + +# Zephyr / debugging +# ---------------------------------------- + +config ZTEST + default SOF_BOOT_TEST_SUPPORTED && SOF_BOOT_TEST_ALLOWED + +# Zephyr / debug slot manager +# ---------------------------------------- + +config INTEL_ADSP_DEBUG_SLOT_MANAGER + default y + diff --git a/app/boards/intel_adsp_ace15_mtpm.conf b/app/boards/intel_adsp_ace15_mtpm.conf index 9044699a1519..0b5472cd282a 100644 --- a/app/boards/intel_adsp_ace15_mtpm.conf +++ b/app/boards/intel_adsp_ace15_mtpm.conf @@ -3,50 +3,40 @@ CONFIG_RIMAGE_SIGNING_SCHEMA="mtl" # SOF / IPC configuration CONFIG_IPC_MAJOR_4=y -CONFIG_IPC4_BASE_FW_INTEL=y # SOF / audio pipeline and module settings CONFIG_COMP_ARIA=y -CONFIG_COMP_CHAIN_DMA=y CONFIG_COMP_CROSSOVER=y CONFIG_COMP_DRC=y -CONFIG_COMP_KPB=y +CONFIG_COMP_TESTER=m CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y CONFIG_COMP_SRC_LITE=y CONFIG_COMP_MFCC=y CONFIG_COMP_MULTIBAND_DRC=y -CONFIG_COMP_UP_DOWN_MIXER=y -CONFIG_COMP_VOLUME_WINDOWS_FADE=y CONFIG_FORMAT_CONVERT_HIFI3=n -CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S24_C32_AND_S24_C24=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32=y -CONFIG_PIPELINE_2_0=y CONFIG_SAMPLE_KEYPHRASE=y +CONFIG_COMP_PHASE_VOCODER=y +CONFIG_COMP_STFT_PROCESS=y # SOF / audio modules / mocks # This mock is part of official sof-bin releases because the CI that # tests it can't use extra CONFIGs. See #9410, #8722 and #9386 -CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=y +CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=m CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK=y # SOF / infrastructure CONFIG_AMS=y CONFIG_COUNTER=y CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL=y -CONFIG_L3_HEAP=y CONFIG_LL_WATCHDOG=y CONFIG_PROBE=y CONFIG_PROBE_DMA_MAX=2 CONFIG_SOF_TELEMETRY=y CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS=y CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS=y -CONFIG_ZEPHYR_NATIVE_DRIVERS=y -CONFIG_ZEPHYR_DP_SCHEDULER=y +CONFIG_ZEPHYR_TWB_SCHEDULER=y CONFIG_COLD_STORE_EXECUTE_DRAM=y +CONFIG_SOF_BOOT_TEST_SUPPORTED=n # SOF / loadable modules CONFIG_INTEL_MODULES=y @@ -65,52 +55,36 @@ CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_MIN=y CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_LLEXT=y CONFIG_LLEXT_STORAGE_WRITABLE=y +CONFIG_LLEXT_EXPERIMENTAL=y +CONFIG_LLEXT_EDK=n CONFIG_MODULES=y CONFIG_TIMING_FUNCTIONS=y CONFIG_WATCHDOG=y +CONFIG_TIMESLICE_PER_THREAD=y +CONFIG_THREAD_RUNTIME_STATS=y +CONFIG_SCHED_THREAD_USAGE=y # Zephyr / device drivers -CONFIG_CLOCK_CONTROL=y -CONFIG_CLOCK_CONTROL_ADSP=y -CONFIG_DAI=y CONFIG_DAI_DMIC_HAS_OWNERSHIP=y CONFIG_DAI_DMIC_HAS_MULTIPLE_LINE_SYNC=y CONFIG_DAI_DMIC_HW_IOCLK=38400000 CONFIG_DAI_INIT_PRIORITY=70 -CONFIG_DAI_INTEL_DMIC=y -CONFIG_DAI_INTEL_DMIC_NHLT=y -CONFIG_DAI_INTEL_SSP=y -CONFIG_DMA=y CONFIG_DMA_DW_LLI_POOL_SIZE=50 CONFIG_DMA_INTEL_ADSP_GPDMA=y -CONFIG_INTEL_ADSP_IPC=y -CONFIG_INTEL_ADSP_TIMER=y CONFIG_MEMORY_WIN_2_SIZE=12288 CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM=y +CONFIG_MM_DRV_INTEL_VIRTUAL_REGION_COUNT=3 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=38400000 CONFIG_SYS_CLOCK_TICKS_PER_SEC=12000 # Zephyr / power settings CONFIG_ADSP_IDLE_CLOCK_GATING=y CONFIG_ADSP_IMR_CONTEXT_SAVE=n -CONFIG_PM=y -CONFIG_PM_DEVICE=y -CONFIG_PM_DEVICE_RUNTIME=y -CONFIG_PM_DEVICE_SYSTEM_MANAGED=y -CONFIG_PM_DEVICE_POWER_DOMAIN=y -CONFIG_PM_POLICY_CUSTOM=y -CONFIG_POWER_DOMAIN=y -CONFIG_POWER_DOMAIN_INTEL_ADSP=y +CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL=y +CONFIG_PM_DEVICE_RUNTIME_ASYNC=n # Zephyr / logging - CONFIG_LOG_BACKEND_ADSP=n -CONFIG_LOG_BACKEND_ADSP_MTRACE=y CONFIG_LOG_BACKEND_SOF_PROBE=n -CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y -CONFIG_LOG_FUNC_NAME_PREFIX_WRN=y -CONFIG_LOG_FUNC_NAME_PREFIX_INF=y -CONFIG_LOG_FUNC_NAME_PREFIX_DBG=y -CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y -CONFIG_LOG_TIMESTAMP_64BIT=y CONFIG_WINSTREAM_CONSOLE=n +CONFIG_LOG_FLUSH_SLEEP_US=5000 diff --git a/app/boards/intel_adsp_ace20_lnl.conf b/app/boards/intel_adsp_ace20_lnl.conf index 022a3a9a40b6..c0b225650c01 100644 --- a/app/boards/intel_adsp_ace20_lnl.conf +++ b/app/boards/intel_adsp_ace20_lnl.conf @@ -3,37 +3,26 @@ CONFIG_RIMAGE_SIGNING_SCHEMA="lnl" # SOF / IPC configuration CONFIG_IPC_MAJOR_4=y -CONFIG_IPC4_BASE_FW_INTEL=y # SOF / audio pipeline and module settings CONFIG_COMP_ARIA=y -CONFIG_COMP_CHAIN_DMA=y CONFIG_COMP_DRC=m -CONFIG_COMP_KPB=y +CONFIG_COMP_TESTER=m CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y -CONFIG_COMP_UP_DOWN_MIXER=y -CONFIG_COMP_VOLUME_WINDOWS_FADE=y CONFIG_FORMAT_CONVERT_HIFI3=n -CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S24_C32_AND_S24_C24=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32=y -CONFIG_PIPELINE_2_0=y CONFIG_SAMPLE_KEYPHRASE=y +CONFIG_COMP_PHASE_VOCODER=y +CONFIG_COMP_STFT_PROCESS=y # SOF / infrastructure CONFIG_AMS=y CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL=n -CONFIG_L3_HEAP=y CONFIG_PROBE=y CONFIG_PROBE_DMA_MAX=2 CONFIG_SOF_TELEMETRY=y CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS=y CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS=y -CONFIG_ZEPHYR_DP_SCHEDULER=y -CONFIG_ZEPHYR_NATIVE_DRIVERS=y +CONFIG_COLD_STORE_EXECUTE_DRAM=y # SOF / loadable modules CONFIG_INTEL_MODULES=y @@ -49,48 +38,30 @@ CONFIG_COUNTER=y CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_LLEXT=y CONFIG_LLEXT_STORAGE_WRITABLE=y +CONFIG_LLEXT_EXPERIMENTAL=y +CONFIG_LLEXT_EDK=n CONFIG_MODULES=y CONFIG_TIMING_FUNCTIONS=y # Zephyr / device drivers -CONFIG_CLOCK_CONTROL=y -CONFIG_CLOCK_CONTROL_ADSP=y -CONFIG_DAI=y CONFIG_DAI_DMIC_HAS_MULTIPLE_LINE_SYNC=y CONFIG_DAI_DMIC_HAS_OWNERSHIP=n CONFIG_DAI_DMIC_HW_IOCLK=38400000 CONFIG_DAI_INIT_PRIORITY=70 -CONFIG_DAI_INTEL_DMIC=y -CONFIG_DAI_INTEL_DMIC_NHLT=y -CONFIG_DAI_INTEL_SSP=y -CONFIG_DMA=y CONFIG_DMA_INTEL_ADSP_GPDMA=n -CONFIG_INTEL_ADSP_IPC=y -CONFIG_INTEL_ADSP_TIMER=y CONFIG_MEMORY_WIN_2_SIZE=12288 CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM=y +CONFIG_MM_DRV_INTEL_VIRTUAL_REGION_COUNT=3 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=38400000 CONFIG_SYS_CLOCK_TICKS_PER_SEC=12000 # Zephyr / power settings CONFIG_ADSP_IDLE_CLOCK_GATING=y CONFIG_ADSP_IMR_CONTEXT_SAVE=y -CONFIG_PM=y -CONFIG_PM_DEVICE=y -CONFIG_PM_DEVICE_POWER_DOMAIN=y -CONFIG_PM_DEVICE_RUNTIME=y -CONFIG_PM_DEVICE_SYSTEM_MANAGED=y -CONFIG_PM_POLICY_CUSTOM=y -CONFIG_POWER_DOMAIN=y -CONFIG_POWER_DOMAIN_INTEL_ADSP=y +CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL=y +CONFIG_PM_DEVICE_RUNTIME_ASYNC=n # Zephyr / logging CONFIG_LOG_BACKEND_ADSP=n -CONFIG_LOG_BACKEND_ADSP_MTRACE=y -CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y -CONFIG_LOG_FUNC_NAME_PREFIX_WRN=y -CONFIG_LOG_FUNC_NAME_PREFIX_INF=y -CONFIG_LOG_FUNC_NAME_PREFIX_DBG=y -CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y -CONFIG_LOG_TIMESTAMP_64BIT=y CONFIG_WINSTREAM_CONSOLE=n +CONFIG_LOG_FLUSH_SLEEP_US=5000 diff --git a/app/boards/intel_adsp_ace30_ptl.conf b/app/boards/intel_adsp_ace30_ptl.conf index 62106d05e02e..b6ac41938398 100644 --- a/app/boards/intel_adsp_ace30_ptl.conf +++ b/app/boards/intel_adsp_ace30_ptl.conf @@ -3,42 +3,35 @@ CONFIG_RIMAGE_SIGNING_SCHEMA="ptl" # SOF / IPC configuration CONFIG_IPC_MAJOR_4=y -CONFIG_IPC4_BASE_FW_INTEL=y # SOF / audio pipeline and module settings -CONFIG_COMP_SRC=y -CONFIG_MM_DRV=y -CONFIG_COMP_ARIA=y -CONFIG_COMP_CHAIN_DMA=y -CONFIG_COMP_DRC=y -CONFIG_COMP_KPB=y +CONFIG_COMP_TESTER=m CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y -CONFIG_COMP_UP_DOWN_MIXER=y -CONFIG_COMP_VOLUME_WINDOWS_FADE=y CONFIG_FORMAT_CONVERT_HIFI3=n -CONFIG_FORMAT_U8=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S24_C32_AND_S24_C24=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32=y -CONFIG_PCM_CONVERTER_FORMAT_U8=y -CONFIG_PIPELINE_2_0=y + +# SOF / audio modules / mocks +# This mock is part of official sof-bin releases because the CI that +# tests it can't use extra CONFIGs. See #9410, #8722 and #9386 +CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=m +CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK=y +CONFIG_COMP_STFT_PROCESS=y # SOF / infrastructure CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL=n CONFIG_PROBE=y CONFIG_PROBE_DMA_MAX=2 -CONFIG_ZEPHYR_DP_SCHEDULER=y -CONFIG_ZEPHYR_NATIVE_DRIVERS=y +CONFIG_SOF_TELEMETRY=y +CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS=y +CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS=y +CONFIG_COLD_STORE_EXECUTE_DRAM=y # SOF / loadable modules CONFIG_INTEL_MODULES=y +CONFIG_LIBRARY_AUTH_SUPPORT=y CONFIG_LIBRARY_MANAGER=y CONFIG_LIBRARY_BASE_ADDRESS=0xa0688000 CONFIG_LIBRARY_BUILD_LIB=y -CONFIG_LIBRARY_DEFAULT_MODULAR=n +CONFIG_LIBRARY_DEFAULT_MODULAR=y # SOF / logging CONFIG_SOF_LOG_LEVEL_INF=y @@ -46,46 +39,42 @@ CONFIG_SOF_LOG_LEVEL_INF=y # Zephyr / OS features CONFIG_COUNTER=y CONFIG_HEAP_MEM_POOL_SIZE=8192 -CONFIG_L3_HEAP=y CONFIG_LLEXT=y CONFIG_LLEXT_STORAGE_WRITABLE=y +CONFIG_LLEXT_EXPERIMENTAL=y +CONFIG_LLEXT_EDK=n CONFIG_MODULES=y # Zephyr / device drivers -CONFIG_CLOCK_CONTROL=y -CONFIG_CLOCK_CONTROL_ADSP=y -CONFIG_DAI=y CONFIG_DAI_INIT_PRIORITY=70 -CONFIG_DAI_INTEL_DMIC=y CONFIG_DAI_DMIC_HW_IOCLK=38400000 -CONFIG_DAI_INTEL_DMIC_NHLT=y CONFIG_DAI_DMIC_HAS_OWNERSHIP=n CONFIG_DAI_DMIC_HAS_MULTIPLE_LINE_SYNC=y -CONFIG_DAI_INTEL_SSP=y -CONFIG_DMA=y CONFIG_DMA_INTEL_ADSP_GPDMA=n CONFIG_DMA_DW_LLI_POOL_SIZE=50 -CONFIG_INTEL_ADSP_IPC=y -CONFIG_INTEL_ADSP_TIMER=y +CONFIG_MEMORY_WIN_2_SIZE=12288 CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM=y +CONFIG_MM_DRV_INTEL_VIRTUAL_REGION_COUNT=3 +CONFIG_XTENSA_MMU_NUM_L2_TABLES=128 CONFIG_SYS_CLOCK_TICKS_PER_SEC=12000 # Zephyr / power settings CONFIG_ADSP_IMR_CONTEXT_SAVE=y -CONFIG_PM=y -CONFIG_PM_DEVICE=y -CONFIG_PM_DEVICE_RUNTIME=y -CONFIG_PM_DEVICE_POWER_DOMAIN=y -CONFIG_PM_DEVICE_SYSTEM_MANAGED=y -CONFIG_PM_POLICY_CUSTOM=y -CONFIG_POWER_DOMAIN=y -CONFIG_POWER_DOMAIN_INTEL_ADSP=y +CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL=y +CONFIG_PM_DEVICE_RUNTIME_ASYNC=n # Zephyr / logging -CONFIG_LOG=y -CONFIG_LOG_BACKEND_ADSP_MTRACE=y -CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y -CONFIG_LOG_FUNC_NAME_PREFIX_WRN=y -CONFIG_LOG_FUNC_NAME_PREFIX_INF=y -CONFIG_LOG_FUNC_NAME_PREFIX_DBG=y -CONFIG_LOG_MODE_DEFERRED=y +CONFIG_LOG_BACKEND_ADSP=n +CONFIG_LOG_FLUSH_SLEEP_US=5000 +CONFIG_WINSTREAM_CONSOLE=n + +# Userspace options +CONFIG_USERSPACE=y +CONFIG_DYNAMIC_THREAD=y +CONFIG_DYNAMIC_THREAD_ALLOC=y +CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y +CONFIG_SOF_STACK_SIZE=8192 +CONFIG_SOF_USERSPACE_PROXY=y +CONFIG_MAX_THREAD_BYTES=3 + +CONFIG_MAX_DOMAIN_PARTITIONS=32 diff --git a/app/boards/intel_adsp_ace30_ptl_sim.conf b/app/boards/intel_adsp_ace30_ptl_sim.conf index eb72fb6598cc..477450d2d271 100644 --- a/app/boards/intel_adsp_ace30_ptl_sim.conf +++ b/app/boards/intel_adsp_ace30_ptl_sim.conf @@ -1,6 +1,5 @@ CONFIG_PANTHERLAKE=y CONFIG_IPC_MAJOR_4=y -CONFIG_IPC4_BASE_FW_INTEL=y # turn off SOF drivers CONFIG_COMP_SRC=y @@ -9,40 +8,25 @@ CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y # power settings CONFIG_PM=n -CONFIG_PM_POLICY_CUSTOM=y # enable Zephyr drivers -CONFIG_ZEPHYR_NATIVE_DRIVERS=y -CONFIG_DAI=y CONFIG_DAI_INIT_PRIORITY=70 -CONFIG_DAI_INTEL_DMIC=y CONFIG_DAI_DMIC_HW_IOCLK=19200000 -CONFIG_DAI_INTEL_DMIC_NHLT=y CONFIG_DAI_DMIC_HAS_OWNERSHIP=y CONFIG_DAI_DMIC_HAS_MULTIPLE_LINE_SYNC=y CONFIG_DAI_INTEL_SSP=n -CONFIG_DMA=y CONFIG_DMA_INTEL_ADSP_GPDMA=n CONFIG_DMA_DW_LLI_POOL_SIZE=50 CONFIG_INTEL_MODULES=n CONFIG_LIBRARY_MANAGER=n -CONFIG_INTEL_ADSP_TIMER=y CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_RIMAGE_SIGNING_SCHEMA="ptl" CONFIG_FORMAT_CONVERT_HIFI3=n -CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S24_C32_AND_S24_C24=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32=y CONFIG_LOG=n CONFIG_LOG_MODE_DEFERRED=n CONFIG_LOG_FUNC_NAME_PREFIX_INF=n -CONFIG_COMP_VOLUME_WINDOWS_FADE=y -CONFIG_COMP_UP_DOWN_MIXER=y CONFIG_SYS_CLOCK_TICKS_PER_SEC=12000 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=19200000 @@ -55,11 +39,9 @@ CONFIG_INTEL_ADSP_IPC=y # Temporary disabled options -CONFIG_PM_DEVICE=y CONFIG_PM_DEVICE_RUNTIME=n CONFIG_PM_DEVICE_POWER_DOMAIN=n +CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL=y CONFIG_COMP_KPB=n -CONFIG_CLOCK_CONTROL_ADSP=y -CONFIG_CLOCK_CONTROL=y CONFIG_USERSPACE=y diff --git a/app/boards/intel_adsp_ace30_wcl.conf b/app/boards/intel_adsp_ace30_wcl.conf new file mode 100644 index 000000000000..2196af333e65 --- /dev/null +++ b/app/boards/intel_adsp_ace30_wcl.conf @@ -0,0 +1,66 @@ +CONFIG_WILDCATLAKE=y +CONFIG_RIMAGE_SIGNING_SCHEMA="ptl" + +# SOF / IPC configuration +CONFIG_IPC_MAJOR_4=y + +# SOF / audio pipeline and module settings +CONFIG_COMP_TESTER=m +CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y +CONFIG_FORMAT_CONVERT_HIFI3=n + +# SOF / audio modules / mocks +# This mock is part of official sof-bin releases because the CI that +# tests it can't use extra CONFIGs. See #9410, #8722 and #9386 +CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=m +CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK=y +CONFIG_COMP_STFT_PROCESS=y + +# SOF / infrastructure +CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL=n +CONFIG_PROBE=y +CONFIG_PROBE_DMA_MAX=2 +CONFIG_SOF_TELEMETRY=y +CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS=y +CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS=y +CONFIG_COLD_STORE_EXECUTE_DRAM=y + +# SOF / loadable modules +CONFIG_INTEL_MODULES=y +CONFIG_LIBRARY_MANAGER=y +CONFIG_LIBRARY_AUTH_SUPPORT=y +CONFIG_LIBRARY_BASE_ADDRESS=0xa0688000 +CONFIG_LIBRARY_BUILD_LIB=y +CONFIG_LIBRARY_DEFAULT_MODULAR=y + +# SOF / logging +CONFIG_SOF_LOG_LEVEL_INF=y + +# Zephyr / OS features +CONFIG_HEAP_MEM_POOL_SIZE=8192 +CONFIG_LLEXT=y +CONFIG_LLEXT_STORAGE_WRITABLE=y +CONFIG_LLEXT_EXPERIMENTAL=y +CONFIG_LLEXT_EDK=n +CONFIG_MODULES=y + +# Zephyr / device drivers +CONFIG_DAI_INIT_PRIORITY=70 +CONFIG_DAI_DMIC_HW_IOCLK=38400000 +CONFIG_DAI_DMIC_HAS_OWNERSHIP=n +CONFIG_DAI_DMIC_HAS_MULTIPLE_LINE_SYNC=y +CONFIG_DMA_INTEL_ADSP_GPDMA=n +CONFIG_MEMORY_WIN_2_SIZE=12288 +CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM=y +CONFIG_MM_DRV_INTEL_VIRTUAL_REGION_COUNT=3 +CONFIG_SYS_CLOCK_TICKS_PER_SEC=12000 + +# Zephyr / power settings +CONFIG_ADSP_IMR_CONTEXT_SAVE=y +CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL=y +CONFIG_PM_DEVICE_RUNTIME_ASYNC=n + +# Zephyr / logging +CONFIG_LOG_BACKEND_ADSP=n +CONFIG_LOG_FLUSH_SLEEP_US=5000 +CONFIG_WINSTREAM_CONSOLE=n diff --git a/app/boards/intel_adsp_ace30_wcl_sim.conf b/app/boards/intel_adsp_ace30_wcl_sim.conf new file mode 100644 index 000000000000..288305be6313 --- /dev/null +++ b/app/boards/intel_adsp_ace30_wcl_sim.conf @@ -0,0 +1,43 @@ +CONFIG_WILDCATLAKE=y +CONFIG_IPC_MAJOR_4=y + +# turn off SOF drivers +CONFIG_COMP_SRC=y + +CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y + +# power settings +CONFIG_PM=n + +# enable Zephyr drivers +CONFIG_DAI_INIT_PRIORITY=70 +CONFIG_DAI_DMIC_HW_IOCLK=19200000 +CONFIG_DAI_DMIC_HAS_OWNERSHIP=y +CONFIG_DAI_DMIC_HAS_MULTIPLE_LINE_SYNC=y +CONFIG_DAI_INTEL_SSP=n +CONFIG_DMA_INTEL_ADSP_GPDMA=n +CONFIG_INTEL_MODULES=n +CONFIG_LIBRARY_MANAGER=n +CONFIG_INTEL_ADSP_TIMER=y + +CONFIG_HEAP_MEM_POOL_SIZE=8192 +CONFIG_RIMAGE_SIGNING_SCHEMA="ptl" + +CONFIG_LOG=n +CONFIG_LOG_MODE_DEFERRED=n +CONFIG_LOG_FUNC_NAME_PREFIX_INF=n +CONFIG_SYS_CLOCK_TICKS_PER_SEC=12000 +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=19200000 + +CONFIG_LOG_BACKEND_ADSP_MTRACE=n +CONFIG_SOF_LOG_LEVEL_INF=n +CONFIG_SOF_LOG_LEVEL_OFF=y +CONFIG_ZEPHYR_LOG=n + +# Temporary disabled options +CONFIG_PM_DEVICE_RUNTIME=n +CONFIG_PM_DEVICE_POWER_DOMAIN=n +CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL=y +CONFIG_COMP_KPB=n + +CONFIG_USERSPACE=y diff --git a/app/boards/intel_adsp_ace40_nvl.conf b/app/boards/intel_adsp_ace40_nvl.conf new file mode 100644 index 000000000000..bb39cf026ada --- /dev/null +++ b/app/boards/intel_adsp_ace40_nvl.conf @@ -0,0 +1,68 @@ +CONFIG_NOVALAKE=y +CONFIG_RIMAGE_SIGNING_SCHEMA="nvl" + +# SOF / IPC configuration +CONFIG_IPC_MAJOR_4=y + +# SOF / audio pipeline and module settings +CONFIG_COMP_SRC=y +CONFIG_COMP_ARIA=y +CONFIG_COMP_DRC=y +CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y +CONFIG_COMP_TESTER=y +CONFIG_FORMAT_CONVERT_HIFI3=n + +# SOF / audio modules / mocks +# This mock is part of official sof-bin releases because the CI that +# tests it can't use extra CONFIGs. See #9410, #8722 and #9386 +CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=m +CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK=y + +# SOF / infrastructure +CONFIG_PROBE=y +CONFIG_PROBE_DMA_MAX=2 +CONFIG_COLD_STORE_EXECUTE_DRAM=y + +# SOF / loadable modules +CONFIG_INTEL_MODULES=y +CONFIG_LIBRARY_MANAGER=y +CONFIG_LIBRARY_BASE_ADDRESS=0xa0688000 +CONFIG_LIBRARY_BUILD_LIB=y +CONFIG_LIBRARY_DEFAULT_MODULAR=y + +# SOF / logging +CONFIG_TRACE=n +CONFIG_SOF_LOG_LEVEL_INF=y + +# Zephyr / OS features +CONFIG_HEAP_MEM_POOL_SIZE=8192 +CONFIG_LLEXT=y +CONFIG_LLEXT_STORAGE_WRITABLE=y +CONFIG_LLEXT_EXPERIMENTAL=y +CONFIG_LLEXT_EDK=n +CONFIG_MODULES=y + +# Zephyr / device drivers +CONFIG_DAI_INIT_PRIORITY=70 +CONFIG_DAI_DMIC_HW_IOCLK=38400000 +CONFIG_DAI_DMIC_HAS_OWNERSHIP=n +CONFIG_DAI_DMIC_HAS_MULTIPLE_LINE_SYNC=y +CONFIG_DMA_INTEL_ADSP_GPDMA=n +CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM=y +CONFIG_MM_DRV_INTEL_VIRTUAL_REGION_COUNT=3 +CONFIG_SYS_CLOCK_TICKS_PER_SEC=12000 + +# Zephyr / power settings +CONFIG_ADSP_IMR_CONTEXT_SAVE=y +CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL=y +CONFIG_SRAM_RETENTION_MODE=n +CONFIG_PM_DEVICE_RUNTIME_ASYNC=n + +# Zephyr / logging +CONFIG_LOG_BACKEND_ADSP=n +CONFIG_WINSTREAM_CONSOLE=n +CONFIG_LOG_RUNTIME_FILTERING=y +CONFIG_LOG_RUNTIME_DEFAULT_LEVEL=1 + +# Zephyr / debug: temporary, until fixed +CONFIG_GDBSTUB=n diff --git a/app/boards/intel_adsp_ace40_nvls.conf b/app/boards/intel_adsp_ace40_nvls.conf new file mode 100644 index 000000000000..bb39cf026ada --- /dev/null +++ b/app/boards/intel_adsp_ace40_nvls.conf @@ -0,0 +1,68 @@ +CONFIG_NOVALAKE=y +CONFIG_RIMAGE_SIGNING_SCHEMA="nvl" + +# SOF / IPC configuration +CONFIG_IPC_MAJOR_4=y + +# SOF / audio pipeline and module settings +CONFIG_COMP_SRC=y +CONFIG_COMP_ARIA=y +CONFIG_COMP_DRC=y +CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y +CONFIG_COMP_TESTER=y +CONFIG_FORMAT_CONVERT_HIFI3=n + +# SOF / audio modules / mocks +# This mock is part of official sof-bin releases because the CI that +# tests it can't use extra CONFIGs. See #9410, #8722 and #9386 +CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=m +CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK=y + +# SOF / infrastructure +CONFIG_PROBE=y +CONFIG_PROBE_DMA_MAX=2 +CONFIG_COLD_STORE_EXECUTE_DRAM=y + +# SOF / loadable modules +CONFIG_INTEL_MODULES=y +CONFIG_LIBRARY_MANAGER=y +CONFIG_LIBRARY_BASE_ADDRESS=0xa0688000 +CONFIG_LIBRARY_BUILD_LIB=y +CONFIG_LIBRARY_DEFAULT_MODULAR=y + +# SOF / logging +CONFIG_TRACE=n +CONFIG_SOF_LOG_LEVEL_INF=y + +# Zephyr / OS features +CONFIG_HEAP_MEM_POOL_SIZE=8192 +CONFIG_LLEXT=y +CONFIG_LLEXT_STORAGE_WRITABLE=y +CONFIG_LLEXT_EXPERIMENTAL=y +CONFIG_LLEXT_EDK=n +CONFIG_MODULES=y + +# Zephyr / device drivers +CONFIG_DAI_INIT_PRIORITY=70 +CONFIG_DAI_DMIC_HW_IOCLK=38400000 +CONFIG_DAI_DMIC_HAS_OWNERSHIP=n +CONFIG_DAI_DMIC_HAS_MULTIPLE_LINE_SYNC=y +CONFIG_DMA_INTEL_ADSP_GPDMA=n +CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM=y +CONFIG_MM_DRV_INTEL_VIRTUAL_REGION_COUNT=3 +CONFIG_SYS_CLOCK_TICKS_PER_SEC=12000 + +# Zephyr / power settings +CONFIG_ADSP_IMR_CONTEXT_SAVE=y +CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL=y +CONFIG_SRAM_RETENTION_MODE=n +CONFIG_PM_DEVICE_RUNTIME_ASYNC=n + +# Zephyr / logging +CONFIG_LOG_BACKEND_ADSP=n +CONFIG_WINSTREAM_CONSOLE=n +CONFIG_LOG_RUNTIME_FILTERING=y +CONFIG_LOG_RUNTIME_DEFAULT_LEVEL=1 + +# Zephyr / debug: temporary, until fixed +CONFIG_GDBSTUB=n diff --git a/app/boards/intel_adsp_cavs25.conf b/app/boards/intel_adsp_cavs25.conf index 72104567491a..7cd938ec7ff8 100644 --- a/app/boards/intel_adsp_cavs25.conf +++ b/app/boards/intel_adsp_cavs25.conf @@ -3,11 +3,9 @@ CONFIG_RIMAGE_SIGNING_SCHEMA="tgl-cavs" # SOF / IPC configuration CONFIG_IPC_MAJOR_4=y -CONFIG_IPC4_BASE_FW_INTEL=y # SOF / audio pipeline and module settings CONFIG_COMP_ARIA=y -CONFIG_COMP_CHAIN_DMA=y CONFIG_COMP_CROSSOVER=y CONFIG_COMP_DRC=y CONFIG_COMP_MFCC=y @@ -18,17 +16,11 @@ CONFIG_PCM_CONVERTER_FORMAT_S16LE=y CONFIG_PCM_CONVERTER_FORMAT_S24LE=y CONFIG_PCM_CONVERTER_FORMAT_S32LE=y CONFIG_PCM_CONVERTER_FORMAT_S24_3LE=y -CONFIG_PCM_CONVERTER_FORMAT_FLOAT=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32=y # SOF / infrastructure CONFIG_AMS=y CONFIG_LP_MEMORY_BANKS=1 CONFIG_HP_MEMORY_BANKS=30 -CONFIG_ZEPHYR_NATIVE_DRIVERS=y # SOF / loadable modules CONFIG_INTEL_MODULES=y @@ -44,29 +36,14 @@ CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_MIN=y CONFIG_HEAP_MEM_POOL_SIZE=8192 # Zephyr / device drivers -CONFIG_CLOCK_CONTROL=y -CONFIG_CLOCK_CONTROL_ADSP=y -CONFIG_DAI=y CONFIG_DAI_INIT_PRIORITY=70 -CONFIG_DAI_INTEL_SSP=y -CONFIG_DAI_INTEL_DMIC=y -CONFIG_DAI_INTEL_ALH=y -CONFIG_DAI_INTEL_DMIC_NHLT=y -CONFIG_DAI_INTEL_HDA=y CONFIG_DAI_DMIC_HW_IOCLK=38400000 -CONFIG_DMA=y CONFIG_DMA_DW_LLI_POOL_SIZE=100 CONFIG_DMA_DW_HW_LLI=y CONFIG_DMA_DW_FIFO_PARTITION=y CONFIG_DMA_INTEL_ADSP_GPDMA_HAS_LLP=y -CONFIG_INTEL_ADSP_IPC=y -CONFIG_INTEL_ADSP_TIMER=y -CONFIG_MM_DRV=y # Zephyr / power settings -CONFIG_PM=y -CONFIG_PM_DEVICE=y -CONFIG_PM_DEVICE_RUNTIME=y CONFIG_PM_POLICY_CUSTOM=y # Zephyr / logging @@ -76,6 +53,5 @@ CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y CONFIG_LOG_FUNC_NAME_PREFIX_WRN=y CONFIG_LOG_FUNC_NAME_PREFIX_INF=y CONFIG_LOG_FUNC_NAME_PREFIX_DBG=y -CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y CONFIG_LOG_TIMESTAMP_64BIT=y CONFIG_WINSTREAM_CONSOLE=n diff --git a/app/boards/intel_adsp_cavs25_tgph.conf b/app/boards/intel_adsp_cavs25_tgph.conf index b29a7ba18970..0c1d1dab1ad6 100644 --- a/app/boards/intel_adsp_cavs25_tgph.conf +++ b/app/boards/intel_adsp_cavs25_tgph.conf @@ -3,11 +3,9 @@ CONFIG_RIMAGE_SIGNING_SCHEMA="tgl-cavs" # SOF / IPC configuration CONFIG_IPC_MAJOR_4=y -CONFIG_IPC4_BASE_FW_INTEL=y # SOF / audio pipeline and module settings CONFIG_COMP_ARIA=y -CONFIG_COMP_CHAIN_DMA=y CONFIG_COMP_CROSSOVER=y CONFIG_COMP_DRC=y CONFIG_COMP_MFCC=y @@ -18,16 +16,10 @@ CONFIG_PCM_CONVERTER_FORMAT_S16LE=y CONFIG_PCM_CONVERTER_FORMAT_S24LE=y CONFIG_PCM_CONVERTER_FORMAT_S32LE=y CONFIG_PCM_CONVERTER_FORMAT_S24_3LE=y -CONFIG_PCM_CONVERTER_FORMAT_FLOAT=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32=y -CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32=y # SOF / infrastructure CONFIG_LP_MEMORY_BANKS=1 CONFIG_HP_MEMORY_BANKS=30 -CONFIG_ZEPHYR_NATIVE_DRIVERS=y # SOF / loadable modules CONFIG_INTEL_MODULES=y @@ -43,24 +35,12 @@ CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_MIN=y CONFIG_HEAP_MEM_POOL_SIZE=8192 # Zephyr / device drivers -CONFIG_CLOCK_CONTROL=y -CONFIG_CLOCK_CONTROL_ADSP=y -CONFIG_DAI=y CONFIG_DAI_INIT_PRIORITY=70 -CONFIG_DAI_INTEL_SSP=y -CONFIG_DAI_INTEL_DMIC=y -CONFIG_DAI_INTEL_ALH=y -CONFIG_DAI_INTEL_DMIC_NHLT=y -CONFIG_DAI_INTEL_HDA=y CONFIG_DAI_DMIC_HW_IOCLK=38400000 -CONFIG_DMA=y CONFIG_DMA_DW_LLI_POOL_SIZE=100 CONFIG_DMA_DW_HW_LLI=y CONFIG_DMA_DW_FIFO_PARTITION=y CONFIG_DMA_INTEL_ADSP_GPDMA_HAS_LLP=y -CONFIG_INTEL_ADSP_IPC=y -CONFIG_INTEL_ADSP_TIMER=y -CONFIG_MM_DRV=y # Zephyr / power settings CONFIG_PM=y @@ -75,6 +55,5 @@ CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y CONFIG_LOG_FUNC_NAME_PREFIX_WRN=y CONFIG_LOG_FUNC_NAME_PREFIX_INF=y CONFIG_LOG_FUNC_NAME_PREFIX_DBG=y -CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y CONFIG_LOG_TIMESTAMP_64BIT=y CONFIG_WINSTREAM_CONSOLE=n diff --git a/app/boards/mt8188_mt8188_adsp.conf b/app/boards/mt8188_mt8188_adsp.conf index 0d44864b6144..0b77906a891f 100644 --- a/app/boards/mt8188_mt8188_adsp.conf +++ b/app/boards/mt8188_mt8188_adsp.conf @@ -4,3 +4,7 @@ # Board-level config goes in Zephyr (and ideally in DTS). App-level # config goes in prj.conf. CONFIG_MTK=y + +# Override project default setting so 1 millisecond is exactly +# represented by an integral number of ticks. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=13000 diff --git a/app/boards/mt8195_mt8195_adsp.conf b/app/boards/mt8195_mt8195_adsp.conf index 0d44864b6144..0b77906a891f 100644 --- a/app/boards/mt8195_mt8195_adsp.conf +++ b/app/boards/mt8195_mt8195_adsp.conf @@ -4,3 +4,7 @@ # Board-level config goes in Zephyr (and ideally in DTS). App-level # config goes in prj.conf. CONFIG_MTK=y + +# Override project default setting so 1 millisecond is exactly +# represented by an integral number of ticks. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=13000 diff --git a/app/boards/mt8196_mt8196_adsp.conf b/app/boards/mt8196_mt8196_adsp.conf index 0d44864b6144..95f7ac3a5655 100644 --- a/app/boards/mt8196_mt8196_adsp.conf +++ b/app/boards/mt8196_mt8196_adsp.conf @@ -4,3 +4,7 @@ # Board-level config goes in Zephyr (and ideally in DTS). App-level # config goes in prj.conf. CONFIG_MTK=y +CONFIG_RIMAGE_SIGNING_SCHEMA="mt8196" +CONFIG_ZEPHYR_NATIVE_DRIVERS=y +CONFIG_DMA=y +CONFIG_DAI=y diff --git a/app/boards/mt8365_mt8365_adsp.conf b/app/boards/mt8365_mt8365_adsp.conf new file mode 100644 index 000000000000..7c9d3647e8cc --- /dev/null +++ b/app/boards/mt8365_mt8365_adsp.conf @@ -0,0 +1,10 @@ +# Boilerplate. Because the "Platform" is a kconfig "choice" (of which +# "MTK" is an member), it can't be selected automatically from other +# kconfigs, nor expressed as a default. Don't put anything else here. +# Board-level config goes in Zephyr (and ideally in DTS). App-level +# config goes in prj.conf. +CONFIG_MTK=y + +# Override project default setting so 1 millisecond is exactly +# represented by an integral number of ticks. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=13000 \ No newline at end of file diff --git a/app/boards/native_sim_libfuzzer.conf b/app/boards/native_sim_libfuzzer.conf index ece1e35845c9..ba17224424cf 100644 --- a/app/boards/native_sim_libfuzzer.conf +++ b/app/boards/native_sim_libfuzzer.conf @@ -5,6 +5,8 @@ CONFIG_ASSERT=y CONFIG_EXCEPTION_DEBUG=y CONFIG_ARCH_POSIX_TRAP_ON_FATAL=y CONFIG_SYS_HEAP_BIG_ONLY=y +CONFIG_SYS_HEAP_HARDENING_EXTREME=y +CONFIG_STACK_SENTINEL=y CONFIG_ZEPHYR_NATIVE_DRIVERS=y CONFIG_ARCH_POSIX_LIBFUZZER=y CONFIG_ZEPHYR_POSIX_FUZZ_TICKS=100 diff --git a/app/boards/qemu_xtensa_dc233c.conf b/app/boards/qemu_xtensa_dc233c.conf new file mode 100644 index 000000000000..effed89802af --- /dev/null +++ b/app/boards/qemu_xtensa_dc233c.conf @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause +CONFIG_IPC_MAJOR_4=y +CONFIG_ZTEST=y +CONFIG_MM_DRV=y +CONFIG_ZEPHYR_NATIVE_DRIVERS=y + +# Ensure the kernel can exit QEMU on shutdown/panic +CONFIG_REBOOT=y diff --git a/app/boards/qemu_xtensa_dc233c_mmu.conf b/app/boards/qemu_xtensa_dc233c_mmu.conf new file mode 100644 index 000000000000..8489a30197e6 --- /dev/null +++ b/app/boards/qemu_xtensa_dc233c_mmu.conf @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: BSD-3-Clause +CONFIG_IPC_MAJOR_4=y +CONFIG_USERSPACE=y +CONFIG_ZTEST=y +CONFIG_TEST_USERSPACE=y +CONFIG_MM_DRV=y +CONFIG_ZEPHYR_NATIVE_DRIVERS=y + +# Ensure the kernel can exit QEMU on shutdown/panic +CONFIG_REBOOT=y diff --git a/app/compr/README.txt b/app/compr/README.txt new file mode 100644 index 000000000000..a9c28957edbb --- /dev/null +++ b/app/compr/README.txt @@ -0,0 +1,37 @@ +Cadence Codec Configuration Overlays +===================================== + +This directory contains Kconfig overlay files for enabling Cadence codec support +in SOF firmware builds. + +Prerequisites +------------- +The Cadence codec libraries must be placed in the cadence_libs directory, one level +up from the SOF project directory: + sof/../cadence_libs/ + +Available Overlay Files +----------------------- +cadence.conf - Base Cadence codec module only (no individual codecs) +mp3.conf - MP3 decoder and encoder +aac.conf - AAC decoder +vorbis.conf - Vorbis decoder +all_codecs.conf - All supported codecs (MP3, AAC, Vorbis) + +Usage Examples +-------------- +Use with scripts/xtensa-build-zephyr.py via -o parameter: + +# Base module only (e.g., for Tiger Lake) +scripts/xtensa-build-zephyr.py tgl -o app/compr/cadence.conf + +# Single codec +scripts/xtensa-build-zephyr.py mtl -o app/compr/mp3.conf + +# Multiple codecs (use separate -o for each) +scripts/xtensa-build-zephyr.py mtl -o app/compr/mp3.conf -o app/compr/aac.conf + +# All codecs +scripts/xtensa-build-zephyr.py mtl -o app/compr/all_codecs.conf + +For more information about Cadence codecs, see the SOF documentation. diff --git a/app/compr/aac.conf b/app/compr/aac.conf new file mode 100644 index 000000000000..2adf1db86007 --- /dev/null +++ b/app/compr/aac.conf @@ -0,0 +1,4 @@ +# Cadence AAC decoder +CONFIG_CADENCE_CODEC=y +CONFIG_CADENCE_CODEC_AAC_DEC=y +CONFIG_CADENCE_CODEC_AAC_DEC_LIB="../cadence_libs/xa_aac_dec.a" diff --git a/app/compr/all_codecs.conf b/app/compr/all_codecs.conf new file mode 100644 index 000000000000..26b507f7f452 --- /dev/null +++ b/app/compr/all_codecs.conf @@ -0,0 +1,11 @@ +# All Cadence codecs (MP3, AAC, Vorbis) +CONFIG_CADENCE_CODEC=y +CONFIG_CADENCE_CODEC_MP3_DEC=y +CONFIG_CADENCE_CODEC_MP3_DEC_LIB="../cadence_libs/xa_mp3_dec.a" +CONFIG_CADENCE_CODEC_MP3_ENC=y +CONFIG_CADENCE_CODEC_MP3_ENC_LIB="../cadence_libs/xa_mp3_enc.a" +CONFIG_CADENCE_CODEC_AAC_DEC=y +CONFIG_CADENCE_CODEC_AAC_DEC_LIB="../cadence_libs/xa_aac_dec.a" +CONFIG_CADENCE_CODEC_VORBIS_DEC=y +CONFIG_CADENCE_CODEC_VORBIS_DEC_LIB="../cadence_libs/xa_vorbis_dec.a" + diff --git a/app/compr/cadence.conf b/app/compr/cadence.conf new file mode 100644 index 000000000000..9223140cab73 --- /dev/null +++ b/app/compr/cadence.conf @@ -0,0 +1,2 @@ +# Cadence codec module base support +CONFIG_CADENCE_CODEC=y diff --git a/app/compr/mp3.conf b/app/compr/mp3.conf new file mode 100644 index 000000000000..968f97295f57 --- /dev/null +++ b/app/compr/mp3.conf @@ -0,0 +1,6 @@ +# Cadence MP3 decoder and encoder +CONFIG_CADENCE_CODEC=y +CONFIG_CADENCE_CODEC_MP3_DEC=y +CONFIG_CADENCE_CODEC_MP3_DEC_LIB="../cadence_libs/xa_mp3_dec.a" +CONFIG_CADENCE_CODEC_MP3_ENC=y +CONFIG_CADENCE_CODEC_MP3_ENC_LIB="../cadence_libs/xa_mp3_enc.a" diff --git a/app/compr/vorbis.conf b/app/compr/vorbis.conf new file mode 100644 index 000000000000..064ac71b6616 --- /dev/null +++ b/app/compr/vorbis.conf @@ -0,0 +1,4 @@ +# Cadence Vorbis decoder +CONFIG_CADENCE_CODEC=y +CONFIG_CADENCE_CODEC_VORBIS_DEC=y +CONFIG_CADENCE_CODEC_VORBIS_DEC_LIB="../cadence_libs/xa_vorbis_dec.a" diff --git a/app/configs/mtl/modules.conf b/app/configs/mtl/modules.conf index fbef3ae182c7..36ad94c263ab 100644 --- a/app/configs/mtl/modules.conf +++ b/app/configs/mtl/modules.conf @@ -20,3 +20,4 @@ CONFIG_COMP_CROSSOVER=m CONFIG_COMP_MULTIBAND_DRC=m CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING=m CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=m +CONFIG_COMP_TESTER=m diff --git a/app/debug_overlay.conf b/app/debug_overlay.conf index 3827976086d8..e99910ebfff1 100644 --- a/app/debug_overlay.conf +++ b/app/debug_overlay.conf @@ -1,9 +1,11 @@ CONFIG_DEBUG=y CONFIG_ASSERT=y -# Disabled until DSP panic #8621 is fixed -# CONFIG_ZTEST=y -# CONFIG_SOF_BOOT_TEST=y +CONFIG_ZTEST_NO_YIELD=n +CONFIG_ZTEST_SUMMARY=n +CONFIG_ZTEST_TEST_DELAY_MS=1 +CONFIG_SOF_BOOT_TEST_ALLOWED=y +CONFIG_TEST_EXTRA_STACK_SIZE=7168 CONFIG_DAI_VERBOSE_GLITCH_WARNINGS=y @@ -15,3 +17,17 @@ CONFIG_DAI_VERBOSE_GLITCH_WARNINGS=y # CONFIG_SYS_HEAP_VALIDATE=y # CONFIG_SPIN_VALIDATE=y # CONFIG_SPIN_LOCK_TIME_LIMIT=50000 + +CONFIG_COLD_STORE_EXECUTE_DEBUG=y + +# GDB stub + +CONFIG_GDBSTUB=y +CONFIG_GDBSTUB_ENTER_IMMEDIATELY=n + +# Logging options +# Set default runtime log level to INFO (3) to maintain expected behavior in SOF CI. +# This ensures firmware starts with INFO level logging, same as previous configuration. +# Testing with runtime filtering enabled ensures the same feature set is validated. +# Note: This setting has no effect if CONFIG_LOG_RUNTIME_FILTERING is disabled. +CONFIG_LOG_RUNTIME_DEFAULT_LEVEL=3 diff --git a/app/debug_stream_overlay.conf b/app/debug_stream_overlay.conf index 0195e5070b33..7edd6bf6709c 100644 --- a/app/debug_stream_overlay.conf +++ b/app/debug_stream_overlay.conf @@ -1,9 +1,24 @@ # Enable debug-stream protocol CONFIG_SOF_DEBUG_STREAM_SLOT=y +# Enable text message sending with ds_msg() +CONFIG_SOF_DEBUG_STREAM_TEXT_MSG=y # Add thread_info-client for debug stream CONFIG_SOF_DEBUG_STREAM_THREAD_INFO=y # Zephyr option for storing human readable thread names CONFIG_THREAD_NAME=y +# For Zephyr to compile with thread names on PTL we need to increase THREAD_BYTES +CONFIG_MAX_THREAD_BYTES=4 +# Shrink number of CPU sections +# As the number of supported cores shrink, the available circular +# buffer size increases. This means increased bandwidth. This is +# particularly useful, when debugging a problem on core 0. +#CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS=1 + +# Direct the assert prints to debug stream +# This option obeys CONFIG_EXCEPTION_DUMP_HOOK_ONLY. If it is selected +# the assert print is sent only to debug stream. Without it the assert +# prints are printed with vprintk too, +CONFIG_SOF_DEBUG_STREAM_TEXT_MSG_ASSERT_PRINT=y # Debug window slot configuration 1 # The CONFIG_SOF_TELEMETRY uses slot 2, but with performance and IO-performance @@ -12,9 +27,15 @@ CONFIG_MEMORY_WIN_2_SIZE=16384 CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS=n CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS=n -# If we turn telemetry off all together, we can use slot 2. Slot 1 is used by mtrace +# If we turn telemetry off altogether, we can use slot 2. Slot 1 is used by mtrace #CONFIG_SOF_DEBUG_STREAM_SLOT_NUMBER=2 #CONFIG_SOF_TELEMETRY=n #CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS=n #CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS=n +# Enable Zephyr exception printing hook; debug stream is sensitive to this option too +CONFIG_EXCEPTION_DUMP_HOOK=y +# Do not try to send exception prints through logs; this causes problems on PTL with mtrace +CONFIG_EXCEPTION_DUMP_HOOK_ONLY=y +# Print also backtrace through the exception hook +CONFIG_XTENSA_BACKTRACE_EXCEPTION_DUMP_HOOK=y diff --git a/app/os_linux_overlay.conf b/app/os_linux_overlay.conf new file mode 100644 index 000000000000..18024b4e6106 --- /dev/null +++ b/app/os_linux_overlay.conf @@ -0,0 +1,27 @@ +# +# Overlay definitions to build SOF firmware for use +# with SOF driver in Linux kernel +# + +# As a general rule, update of SOF firmware shall never +# break existing systems by depending on Linux kernel patches +# that have been upstreamed after commercial availability +# of a product. +CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY=y + +# SOF Linux driver does not require FW to retain its +# state, so context save can be disabled +CONFIG_ADSP_IMR_CONTEXT_SAVE=n +CONFIG_SOF_USERSPACE_PROXY=n + +# Logging options + +# Set default runtime log level to INFO (3). +# Note: This setting only has effect when CONFIG_LOG_RUNTIME_FILTERING is enabled. +# By default, the runtime level equals the compile-time level, but it is explicitly +# set here to INFO to ensure expected behavior if platform configurations set a +# lower default level (e.g., ERROR). +CONFIG_LOG_RUNTIME_DEFAULT_LEVEL=3 + +# Disable additional VMH buffers to use memory for virtual regions. +CONFIG_VIRTUAL_HEAP_EXTENDED=n diff --git a/app/overlays/lnl/fpga_overlay.conf b/app/overlays/lnl/fpga_overlay.conf index eebbfee72648..0cc927a119ee 100644 --- a/app/overlays/lnl/fpga_overlay.conf +++ b/app/overlays/lnl/fpga_overlay.conf @@ -1,3 +1,8 @@ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=19200000 CONFIG_DAI_DMIC_HW_IOCLK=19200000 CONFIG_XTENSA_CCOUNT_HZ=40000000 + +# improves LPSRAM and HPSRAM access time +CONFIG_SRAM_RETENTION_MODE=n + +CONFIG_IDC_TIMEOUT_US=50000 diff --git a/app/overlays/mt8196/ctc_overlay.conf b/app/overlays/mt8196/ctc_overlay.conf new file mode 100644 index 000000000000..f609996f03c1 --- /dev/null +++ b/app/overlays/mt8196/ctc_overlay.conf @@ -0,0 +1,2 @@ +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING=y diff --git a/app/overlays/mt8196/dts_overlay.conf b/app/overlays/mt8196/dts_overlay.conf new file mode 100644 index 000000000000..0160eaea199a --- /dev/null +++ b/app/overlays/mt8196/dts_overlay.conf @@ -0,0 +1,3 @@ +CONFIG_COMP_IIR=y +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_DTS_CODEC=y diff --git a/app/overlays/mt8196/waves_ctc_overlay.conf b/app/overlays/mt8196/waves_ctc_overlay.conf new file mode 100644 index 000000000000..fcd9e1e5730b --- /dev/null +++ b/app/overlays/mt8196/waves_ctc_overlay.conf @@ -0,0 +1,3 @@ +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_WAVES_CODEC=y +CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING=y diff --git a/app/overlays/mt8196/waves_overlay.conf b/app/overlays/mt8196/waves_overlay.conf new file mode 100644 index 000000000000..6e0143275ba6 --- /dev/null +++ b/app/overlays/mt8196/waves_overlay.conf @@ -0,0 +1,2 @@ +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_WAVES_CODEC=y diff --git a/app/overlays/mtl/dax_overlay.conf b/app/overlays/mtl/dax_overlay.conf new file mode 100644 index 000000000000..8bf245126b57 --- /dev/null +++ b/app/overlays/mtl/dax_overlay.conf @@ -0,0 +1,16 @@ +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING=y +CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING_MOCK=n +CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL=n +CONFIG_SOF_STACK_SIZE=8192 +CONFIG_IDC_TIMEOUT_US=50000 + +# LLEXT +CONFIG_LLEXT_HEAP_SIZE=32 +# Disabled due to issues encountered on the MTL platform. +# See https://github.com/thesofproject/sof/issues/10370 +CONFIG_LLEXT_EXPERIMENTAL=n + +# Log settings +CONFIG_LOG_BUFFER_SIZE=8192 +CONFIG_MTRACE_LOG_CACHE_BUF_SIZE=12288 diff --git a/app/overlays/mtl/fpga_overlay.conf b/app/overlays/mtl/fpga_overlay.conf index eebbfee72648..0cc927a119ee 100644 --- a/app/overlays/mtl/fpga_overlay.conf +++ b/app/overlays/mtl/fpga_overlay.conf @@ -1,3 +1,8 @@ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=19200000 CONFIG_DAI_DMIC_HW_IOCLK=19200000 CONFIG_XTENSA_CCOUNT_HZ=40000000 + +# improves LPSRAM and HPSRAM access time +CONFIG_SRAM_RETENTION_MODE=n + +CONFIG_IDC_TIMEOUT_US=50000 diff --git a/app/overlays/nvl/fpga_overlay.conf b/app/overlays/nvl/fpga_overlay.conf new file mode 100644 index 000000000000..176598376be0 --- /dev/null +++ b/app/overlays/nvl/fpga_overlay.conf @@ -0,0 +1,8 @@ +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=19200000 +CONFIG_DAI_DMIC_HW_IOCLK=19200000 +CONFIG_XTENSA_CCOUNT_HZ=40105000 + +# limit logs to minimize runtime overhead of logging +CONFIG_SOF_LOG_LEVEL_ERR=y + +CONFIG_IDC_TIMEOUT_US=50000 diff --git a/app/overlays/ptl/ctc_overlay.conf b/app/overlays/ptl/ctc_overlay.conf new file mode 100644 index 000000000000..f609996f03c1 --- /dev/null +++ b/app/overlays/ptl/ctc_overlay.conf @@ -0,0 +1,2 @@ +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING=y diff --git a/app/overlays/ptl/dax_overlay.conf b/app/overlays/ptl/dax_overlay.conf new file mode 100644 index 000000000000..7dcdf749dbe1 --- /dev/null +++ b/app/overlays/ptl/dax_overlay.conf @@ -0,0 +1,13 @@ +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING=y +CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING_MOCK=n +CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL=n +CONFIG_SOF_STACK_SIZE=8192 +CONFIG_IDC_TIMEOUT_US=50000 + +# LLEXT +CONFIG_LLEXT_HEAP_SIZE=32 + +# Log settings +CONFIG_LOG_BUFFER_SIZE=8192 +CONFIG_MTRACE_LOG_CACHE_BUF_SIZE=12288 diff --git a/app/overlays/ptl/dts_overlay.conf b/app/overlays/ptl/dts_overlay.conf new file mode 100644 index 000000000000..793559ad5de7 --- /dev/null +++ b/app/overlays/ptl/dts_overlay.conf @@ -0,0 +1,6 @@ +CONFIG_COMP_IIR=m +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_DTS_CODEC=y +CONFIG_LLEXT_HEAP_SIZE=64 +CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL=n +CONFIG_SOF_STACK_SIZE=8192 diff --git a/app/overlays/ptl/fpga_overlay.conf b/app/overlays/ptl/fpga_overlay.conf index 3fdf9d658c3c..f2f0eee4ab2d 100644 --- a/app/overlays/ptl/fpga_overlay.conf +++ b/app/overlays/ptl/fpga_overlay.conf @@ -3,3 +3,8 @@ CONFIG_DAI_DMIC_HW_IOCLK=19200000 # limit logs to minimize runtime overhead of logging CONFIG_SOF_LOG_LEVEL_ERR=y + +# improves LPSRAM and HPSRAM access time +CONFIG_SRAM_RETENTION_MODE=n + +CONFIG_IDC_TIMEOUT_US=50000 diff --git a/app/overlays/ptl/ll_userspace_overlay.conf b/app/overlays/ptl/ll_userspace_overlay.conf new file mode 100644 index 000000000000..8888a66f4c24 --- /dev/null +++ b/app/overlays/ptl/ll_userspace_overlay.conf @@ -0,0 +1,38 @@ +# This is overlay configuration file to enable user-space LL audio +# pipeline support. This overlay is intended for development +# purposes. If user-space LL is enabled for some build target by +# default, the settings should be made in the SOF board file directly. + +# Enable user-space LL support in SOF +# ----------------------------------- + +CONFIG_SOF_USERSPACE_LL=y + +# make the drivers work in user-space +CONFIG_SOF_USERSPACE_INTERFACE_DMA=y +CONFIG_DAI_USERSPACE=y + +# Temporary settings that are needed currently to enable user-space LL +# -------------------------------------------------------------------- + +# problem with DSP panics due to illegal instruction hit in user-space if cold +# store execution is enabled. Disable it for now until rootcause is found. +CONFIG_COLD_STORE_EXECUTE_DRAM=n +CONFIG_COLD_STORE_EXECUTE_DEBUG=n + +# telemetry not yet user-space compatible +CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS=n +CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS=n + +# disable loadable modules (hits privilege issues in user-space now) +CONFIG_LLEXT_STORAGE_WRITABLE=n +CONFIG_LLEXT_EXPERIMENTAL=n +CONFIG_MODULES=n + +# some of current boot tests interfere with user-space setup +CONFIG_SOF_BOOT_TEST_ALLOWED=n + +# misc features not yet compatible with user-space +CONFIG_CROSS_CORE_STREAM=n +CONFIG_INTEL_ADSP_MIC_PRIVACY=n +CONFIG_XRUN_NOTIFICATIONS_ENABLE=n diff --git a/app/overlays/ptl/userspace_overlay.conf b/app/overlays/ptl/userspace_overlay.conf new file mode 100644 index 000000000000..c484a2182807 --- /dev/null +++ b/app/overlays/ptl/userspace_overlay.conf @@ -0,0 +1,14 @@ +CONFIG_USERSPACE=y +CONFIG_XTENSA_MMU_NUM_L2_TABLES=86 +CONFIG_MAX_THREAD_BYTES=4 + +CONFIG_INIT_STACKS=n +CONFIG_THREAD_STACK_INFO=n +CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y +CONFIG_DYNAMIC_THREAD=y +CONFIG_DYNAMIC_THREAD_POOL_SIZE=4 +CONFIG_DYNAMIC_THREAD_ALLOC=n +# IADK module adapter store some buffers on stack, so we need to increase stack size +CONFIG_DYNAMIC_THREAD_STACK_SIZE=8192 +CONFIG_SOF_STACK_SIZE=8192 +CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD=y diff --git a/app/overlays/wcl/fpga_overlay.conf b/app/overlays/wcl/fpga_overlay.conf new file mode 100644 index 000000000000..f2f0eee4ab2d --- /dev/null +++ b/app/overlays/wcl/fpga_overlay.conf @@ -0,0 +1,10 @@ +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=19200000 +CONFIG_DAI_DMIC_HW_IOCLK=19200000 + +# limit logs to minimize runtime overhead of logging +CONFIG_SOF_LOG_LEVEL_ERR=y + +# improves LPSRAM and HPSRAM access time +CONFIG_SRAM_RETENTION_MODE=n + +CONFIG_IDC_TIMEOUT_US=50000 diff --git a/app/prj.conf b/app/prj.conf index e072f1df2fd2..5c22e19d6e0e 100644 --- a/app/prj.conf +++ b/app/prj.conf @@ -1,4 +1,3 @@ -CONFIG_SOF=y CONFIG_BUILD_OUTPUT_BIN=n # The additional stripped .elf files are deterministic. @@ -21,15 +20,16 @@ CONFIG_LOG=y CONFIG_LOG_PRINTK=y # Log processing is offloaded to a low-priority thread. CONFIG_LOG_MODE_DEFERRED=y -# Wake the low-priority log thread every 100ms and/or -# if more than 5 messages are queued by the frontend. -CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD=5 -CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=100 +# Wake the low-priority log thread every time new log +# messages are available +CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD=1 # Frontend buffer must be large enough to cover all # typical bursts of log messages. CONFIG_LOG_BUFFER_SIZE=4096 # Use stack that is sufficient for SOF backends CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=4096 +# Use Linux kernel style timestamp format +CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y # Requires heap_info() be implemented, but no Zephyr wrapper CONFIG_DEBUG_MEMORY_USAGE_SCAN=n diff --git a/app/sample.yaml b/app/sample.yaml index 4739c74609a2..e40ad5cc4902 100644 --- a/app/sample.yaml +++ b/app/sample.yaml @@ -16,6 +16,10 @@ tests: - intel_adsp/ace20_lnl - intel_adsp/ace30/ptl - intel_adsp/ace30/ptl/sim + - intel_adsp/ace30/wcl + - intel_adsp/ace30/wcl/sim + - intel_adsp/ace40/nvl + - intel_adsp/ace40/nvls - imx8qm_mek/mimx8qm6/adsp - imx8qxp_mek/mimx8qx6/adsp - imx8mp_evk/mimx8ml8/adsp diff --git a/app/src/main.c b/app/src/main.c index 0f5c1f84fe0e..12cc3ffdc73a 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -5,10 +5,17 @@ */ #include - +#include #include + LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG); +/* define qemu boot tests if any qemu target is defined, add targets to end */ +#if defined(CONFIG_BOARD_QEMU_XTENSA_DC233C) ||\ + defined(CONFIG_BOARD_QEMU_XTENSA_DC233C_MMU) +#define QEMU_BOOT_TESTS +#endif + /** * Should be included from sof/schedule/task.h * but triggers include chain issue @@ -50,11 +57,30 @@ static int sof_app_main(void) return 0; } +#if CONFIG_SOF_BOOT_TEST && defined(QEMU_BOOT_TESTS) +/* cleanly exit qemu so CI can continue and check test results */ +static inline void qemu_xtensa_exit(int status) +{ + register int syscall_id __asm__ ("a2") = 1; /* SYS_exit is 1 */ + register int exit_status __asm__ ("a3") = status; + + __asm__ __volatile__ ( + "simcall\n" + : + : "r" (syscall_id), "r" (exit_status) + : "memory" + ); +} +#endif + #if CONFIG_ZTEST void test_main(void) { sof_app_main(); - k_sleep(K_FOREVER); +#if CONFIG_SOF_BOOT_TEST && defined(QEMU_BOOT_TESTS) + sof_run_boot_tests(); + qemu_xtensa_exit(0); +#endif } #else int main(void) diff --git a/doc/sof.doxygen.in b/doc/sof.doxygen.in index bfbea17a7149..6379da500f11 100644 --- a/doc/sof.doxygen.in +++ b/doc/sof.doxygen.in @@ -40,3 +40,4 @@ TYPEDEF_HIDES_STRUCT = YES #FILTER_SOURCE_FILES = YES HTML_TIMESTAMP = NO +WARN_AS_ERROR = NO diff --git a/lmdk/cmake/ldscripts/data_linker_script.txt b/lmdk/cmake/ldscripts/data_linker_script.txt index c04a5ea3d97f..9327079f4d7b 100644 --- a/lmdk/cmake/ldscripts/data_linker_script.txt +++ b/lmdk/cmake/ldscripts/data_linker_script.txt @@ -15,7 +15,7 @@ SECTIONS { _data_end = ABSOLUTE(.); } >HPSRAM_seg : data_phdr - .rodata : ALIGN(4096) { + .rodata : { _rodata_start = ABSOLUTE(.); *(.gnu.linkonce.r.*) *(.rodata) diff --git a/lmdk/libraries/dummy/dummy_mtl.toml b/lmdk/libraries/dummy/dummy_mtl.toml index 3094e10f3396..58b3820331fa 100644 --- a/lmdk/libraries/dummy/dummy_mtl.toml +++ b/lmdk/libraries/dummy/dummy_mtl.toml @@ -60,7 +60,7 @@ count = 1 [[module.entry]] name = "DUMMY" - uuid = "01010101-0101-0101-0101-010101010101" + uuid = "01234567-89AB-CDEF-0102-030405060708" affinity_mask = "0x1" instance_count = "15" domain_types = "0" diff --git a/lmdk/libraries/smart_amp_test/CMakeLists.txt b/lmdk/libraries/smart_amp_test/CMakeLists.txt deleted file mode 100644 index 0282a83bbf90..000000000000 --- a/lmdk/libraries/smart_amp_test/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/../../cmake/xtensa-toolchain.cmake") - -project(smart_amp_test) - -macro(is_zephyr ret) - if(CONFIG_ZEPHYR_SOF_MODULE) - set(${ret} TRUE) - else() - set(${ret} FALSE) - endif() -endmacro() - -# list of modules to be built and included into this loadable library -set(MODULES_LIST smart_amp_test) - -# toml file for rimage to generate manifets -set(TOML "${CMAKE_CURRENT_LIST_DIR}/smart_amp_test.toml") - -# TODO: Move it somewhere??? -add_definitions(-DMAJOR_IADSP_API_VERSION=5) -add_definitions(-DMIDDLE_IADSP_API_VERSION=0) -add_definitions(-DMINOR_IADSP_API_VERSION=0) - -include(../../cmake/build.cmake) diff --git a/lmdk/libraries/smart_amp_test/smart_amp_test.toml b/lmdk/libraries/smart_amp_test/smart_amp_test.toml deleted file mode 100644 index 34f3463343dd..000000000000 --- a/lmdk/libraries/smart_amp_test/smart_amp_test.toml +++ /dev/null @@ -1,79 +0,0 @@ -version = [3, 0] - -[adsp] -name = "mtl" -image_size = "0x2C0000" # (22) bank * 128KB -alias_mask = "0xE0000000" - -[[adsp.mem_zone]] -type = "ROM" -base = "0x1FF80000" -size = "0x400" -[[adsp.mem_zone]] -type = "IMR" -base = "0xA104A000" -size = "0x2000" -[[adsp.mem_zone]] -type = "SRAM" -base = "0xa00f0000" -size = "0x100000" - -[[adsp.mem_alias]] -type = "uncached" -base = "0x40000000" -[[adsp.mem_alias]] -type = "cached" -base = "0xA0000000" - -[cse] -partition_name = "ADSP" -[[cse.entry]] -name = "ADSP.man" -offset = "0x5c" -length = "0x464" -[[cse.entry]] -name = "ADSP.met" -offset = "0x4c0" -length = "0x70" -[[cse.entry]] -name = "ADSP" -offset = "0x540" -length = "0x0" # calculated by rimage - -[css] - -[signed_pkg] -name = "ADSP" -[[signed_pkg.module]] -name = "ADSP.met" - -[adsp_file] -[[adsp_file.comp]] -base_offset = "0x2000" - -[fw_desc.header] -name = "ADSPFW" -load_offset = "0x40000" - -[module] -count = 1 - - [[module.entry]] - name = "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] diff --git a/lmdk/modules/dummy/dummy.c b/lmdk/modules/dummy/dummy.c index 7c9f49289542..de126062bad0 100644 --- a/lmdk/modules/dummy/dummy.c +++ b/lmdk/modules/dummy/dummy.c @@ -18,7 +18,8 @@ __attribute__((section(".module"))) const struct sof_man_module_manifest dummy_module_manifest = { .module = { .name = "DUMMY", - .uuid = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + .uuid = { 0x01234567, 0x89AB, 0xCDEF, { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08 }}, .entry_point = (uint32_t)dummyPackageEntryPoint, .type = { .load_type = SOF_MAN_MOD_TYPE_MODULE, diff --git a/lmdk/modules/smart_amp_test/CMakeLists.txt b/lmdk/modules/smart_amp_test/CMakeLists.txt deleted file mode 100644 index 4c10559fcc03..000000000000 --- a/lmdk/modules/smart_amp_test/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -target_sources(smart_amp_test PRIVATE ${SOF_BASE}/src/samples/audio/smart_amp_test_ipc4.c) - -set_target_properties(smart_amp_test PROPERTIES - HPSRAM_ADDR "0xa06c1000" -) - -target_compile_definitions(smart_amp_test PRIVATE - __SOF_MODULE_SERVICE_BUILD__=1 - CONFIG_XTENSA=1 - CONFIG_IPC_MAJOR_4=1 -) - -target_include_directories(smart_amp_test PRIVATE - "${SOF_BASE}/src/include" - "${SOF_BASE}/posix/include" -) diff --git a/posix/include/rtos/alloc.h b/posix/include/rtos/alloc.h index d64ea319f48e..c599afe08d82 100644 --- a/posix/include/rtos/alloc.h +++ b/posix/include/rtos/alloc.h @@ -28,129 +28,147 @@ * @{ */ -/** - * \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) +/* + * for compatibility with the initial `flags` meaning + * SOF_MEM_FLAG_ should start at BIT(2) + * the first two positions are reserved for SOF_BUF_ flags + */ + + /** \brief Allocate DMA-able memory. */ +#define SOF_MEM_FLAG_DMA BIT(2) +/** \brief realloc() skips copying the original content. */ +#define SOF_MEM_FLAG_NO_COPY BIT(3) +/** \brief Allocate uncached address. */ +#define SOF_MEM_FLAG_COHERENT BIT(4) +/** \brief Allocate L3 address. */ +#define SOF_MEM_FLAG_L3 BIT(5) +/** \brief Allocate Low power memory address. */ +#define SOF_MEM_FLAG_LOW_POWER BIT(6) +/** \brief Allocate kernel memory address. */ +#define SOF_MEM_FLAG_KERNEL BIT(7) +/** \brief Allocate user memory address. */ +#define SOF_MEM_FLAG_USER BIT(8) +/** \brief Allocate shared user memory address. */ +#define SOF_MEM_FLAG_USER_SHARED_BUFFER BIT(9) +/** \brief Use allocation method for large buffers. */ +#define SOF_MEM_FLAG_LARGE_BUFFER BIT(10) /** @} */ /** * 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. + * @param alignment Alignment 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); +void *rmalloc_align(uint32_t flags, size_t bytes, + uint32_t alignment); + +/** + * Similar to rmalloc_align(), but no alignment can be specified. + */ +void *rmalloc(uint32_t flags, 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); +void *rzalloc(uint32_t flags, size_t bytes); /** - * Allocates memory block from SOF_MEM_ZONE_BUFFER. + * Allocates memory block. * @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, +void *rballoc_align(uint32_t flags, 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) +static inline void *rballoc(uint32_t flags, size_t bytes) { - return rballoc_align(flags, caps, bytes, PLATFORM_DCACHE_ALIGN); + return rballoc_align(flags, 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. + * Frees the memory block. + * @param ptr Pointer to the memory block. + */ +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 *rbrealloc_align(void *ptr, uint32_t flags, uint32_t caps, size_t bytes, - size_t old_bytes, uint32_t alignment); +void *rzalloc_core_sys(int core, size_t bytes); + +struct k_heap; +static inline void k_heap_init(struct k_heap *heap, void *mem, size_t bytes) +{ +} +void *sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, + size_t alignment); +void sof_heap_free(struct k_heap *heap, void *addr); +struct k_heap *sof_sys_heap_get(void); +struct k_heap *sof_sys_user_heap_get(void); + +/* Posix version of struct mod_alloc_ctx without vregion support */ +struct vregion; + +struct mod_alloc_ctx { + struct k_heap *heap; + struct vregion *vreg; +}; /** - * Similar to rballoc_align(), returns resized buffer aligned to - * PLATFORM_DCACHE_ALIGN. + * Allocate memory from a mod_alloc_ctx context. + * Dummy version, only heap allocation is supported */ -static inline void *rbrealloc(void *ptr, uint32_t flags, uint32_t caps, - size_t bytes, size_t old_bytes) +static inline void *sof_ctx_alloc(struct mod_alloc_ctx *ctx, uint32_t flags, + size_t size, size_t alignment) { - return rbrealloc_align(ptr, flags, caps, bytes, old_bytes, - PLATFORM_DCACHE_ALIGN); + return sof_heap_alloc(ctx ? ctx->heap : NULL, flags, size, alignment); } /** - * 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. + * Allocate zero-initialized memory from a mod_alloc_ctx context. + * @param ctx Allocation context. + * @param flags Allocation flags (SOF_MEM_FLAG_*). + * @param size Size in bytes. + * @param alignment Required alignment in bytes. + * @return Pointer to allocated memory or NULL on failure. */ -void rfree(void *ptr); +static inline void *sof_ctx_zalloc(struct mod_alloc_ctx *ctx, uint32_t flags, + size_t size, size_t alignment) +{ + void *ptr = sof_ctx_alloc(ctx, flags, size, alignment); + + if (ptr) + memset(ptr, 0, size); + + return ptr; +} /** - * Allocates memory block from the system heap reserved for the specified core. - * @param core Core id. - * @param bytes Size in bytes. + * Free memory allocated from a mod_alloc_ctx context. + * @param ctx Allocation context. + * @param ptr Pointer to free. */ -void *rzalloc_core_sys(int core, size_t bytes); +static inline void sof_ctx_free(struct mod_alloc_ctx *ctx, void *ptr) +{ + if (!ptr) + return; + + sof_heap_free(ctx ? ctx->heap : NULL, ptr); +} /** * Calculates length of the null-terminated string. @@ -167,6 +185,8 @@ int rstrlen(const char *s); */ int rstrcmp(const char *s1, const char *s2); +static inline void l3_heap_save(void) {} + /** @}*/ #endif /* __SOF_LIB_ALLOC_H__ */ diff --git a/posix/include/rtos/idc.h b/posix/include/rtos/idc.h index 8bfbb5c5ad19..a9a03258712f 100644 --- a/posix/include/rtos/idc.h +++ b/posix/include/rtos/idc.h @@ -34,9 +34,6 @@ /** \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 @@ -196,8 +193,6 @@ 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); diff --git a/posix/include/rtos/kernel.h b/posix/include/rtos/kernel.h index 5921d86b0012..9fa3962a3589 100644 --- a/posix/include/rtos/kernel.h +++ b/posix/include/rtos/kernel.h @@ -10,6 +10,7 @@ #include +#include #include #ifdef __ZEPHYR__ @@ -28,6 +29,13 @@ typedef struct { #define Z_TIMEOUT_MS(t) ((k_timeout_t) { .ticks = clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, t) }) +struct k_thread; +static inline bool thread_is_userspace(struct k_thread *thread) +{ + (void)thread; + return false; +} + static inline void k_sleep(k_timeout_t timeout) { wait_delay(timeout.ticks); @@ -43,4 +51,8 @@ static inline void k_usleep(int32_t us) wait_delay_us(us); } +struct k_heap { + int unused; +}; + #endif /* __POSIX_RTOS_KERNEL_H__ */ diff --git a/posix/include/rtos/mutex.h b/posix/include/rtos/mutex.h index 16c773f4cae4..19b360bdaea5 100644 --- a/posix/include/rtos/mutex.h +++ b/posix/include/rtos/mutex.h @@ -40,4 +40,26 @@ static inline int k_mutex_unlock(struct k_mutex *mutex) return 0; } +/* provide a no-op implementation for zephyr/sys/mutex.h */ + +struct sys_mutex { +}; + +#define SYS_MUTEX_DEFINE(name) \ + struct sys_mutex name + +static inline void sys_mutex_init(struct sys_mutex *mutex) +{ +} + +static inline int sys_mutex_lock(struct sys_mutex *mutex, k_timeout_t timeout) +{ + return 0; +} + +static inline int sys_mutex_unlock(struct sys_mutex *mutex) +{ + return 0; +} + #endif diff --git a/posix/include/rtos/sof.h b/posix/include/rtos/sof.h index 3cbb2e7bfefa..d6aa0fce66db 100644 --- a/posix/include/rtos/sof.h +++ b/posix/include/rtos/sof.h @@ -110,11 +110,6 @@ struct sof { 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); diff --git a/posix/include/rtos/spinlock.h b/posix/include/rtos/spinlock.h index beb20ab6e847..22580246519f 100644 --- a/posix/include/rtos/spinlock.h +++ b/posix/include/rtos/spinlock.h @@ -13,125 +13,12 @@ #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 +struct k_spinlock { +}; -#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 */ +typedef uint32_t k_spinlock_key_t; #define trace_lock(__e) do {} while (0) #define tracev_lock(__e) do {} while (0) @@ -139,25 +26,18 @@ extern struct tr_ctx sl_tr; #define spin_lock_dbg(line) do {} while (0) #define spin_unlock_dbg(line) do {} while (0) -#endif /* CONFIG_DEBUG_LOCKS */ +#define k_spinlock_init(lock) do {} while (0) -/* all SMP spinlocks need init, nothing todo on UP */ -static inline void _spinlock_init(struct k_spinlock *lock, int line) +static inline k_spinlock_key_t k_spin_lock(struct k_spinlock *l) { - arch_spinlock_init(lock); -#if CONFIG_DEBUG_LOCKS - lock->user = line; -#endif + return 0; } -#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__) +static inline void k_spin_unlock(struct k_spinlock *l, + k_spinlock_key_t key) +{ + (void)l; + (void)key; +} #endif /* __POSIX_RTOS_SPINLOCK_H__ */ diff --git a/posix/include/rtos/task.h b/posix/include/rtos/task.h index 5aca574a5787..bb09ac63bac4 100644 --- a/posix/include/rtos/task.h +++ b/posix/include/rtos/task.h @@ -18,6 +18,7 @@ struct comp_dev; struct sof; +struct schedule_data; /** \brief Predefined LL task priorities. */ #define SOF_TASK_PRI_HIGH 0 /* priority level 0 - high */ @@ -60,6 +61,7 @@ struct task { uint16_t priority; /**< priority of the task (used by LL) */ uint16_t core; /**< execution core */ uint16_t flags; /**< custom flags */ + struct schedule_data *sch; /**< scheduler bound to task */ enum task_state state; /**< current state */ void *data; /**< custom data passed to all ops */ struct list_item list; /**< used by schedulers to hold tasks */ diff --git a/posix/include/rtos/userspace_helper.h b/posix/include/rtos/userspace_helper.h new file mode 100644 index 000000000000..bb5d7670e9a1 --- /dev/null +++ b/posix/include/rtos/userspace_helper.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + * Author: Jaroslaw Stelter + * Adrian Warecki + */ + +/** + * \brief Userspace support functions. + */ +#ifndef __RTOS_USERSPACE_HELPER_H__ +#define __RTOS_USERSPACE_HELPER_H__ + +#include +#include + +#include + +#define APP_TASK_BSS +#define APP_TASK_DATA +#define APP_SYSUSER_BSS +#define APP_SYSUSER_DATA + +struct sys_heap; + +#ifdef CONFIG_USERSPACE +/** + * Initialize private processing module heap. + * @param N/A. + * @return pointer to the k_heap structure. + * + * @note + * Function used only when CONFIG_USERSPACE is set. + * The private heap is used only for non-privileged modules for all processing module allocations + * that should be isolated. The heap helps to accumulate all dynamic allocations in single memory + * region which is then added to modules memory domain. + */ +static inline struct k_heap *module_driver_heap_init(void) +{ + return NULL; +} +#endif + +/** + * Free private processing module heap. + * @param sys_heap pointer to the sys_heap structure. + * + * @note + * Function used only when CONFIG_USERSPACE is set. + * Frees private module heap. + */ +static inline void module_driver_heap_remove(struct k_heap *mod_drv_heap) +{ } + +#endif /* __RTOS_USERSPACE_HELPER_H__ */ diff --git a/posix/include/rtos/wait.h b/posix/include/rtos/wait.h index b6874888a763..c6cd029ec6b6 100644 --- a/posix/include/rtos/wait.h +++ b/posix/include/rtos/wait.h @@ -30,10 +30,6 @@ 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"); } diff --git a/posix/include/sof/lib/dma.h b/posix/include/sof/lib/dma.h index ffae21574916..cb829dcaa21a 100644 --- a/posix/include/sof/lib/dma.h +++ b/posix/include/sof/lib/dma.h @@ -34,6 +34,8 @@ #endif struct comp_buffer; +struct comp_dev; +struct k_heap; /** \addtogroup sof_dma_drivers DMA Drivers * DMA Drivers API specification. @@ -510,13 +512,14 @@ static inline void dma_sg_init(struct dma_sg_elem_array *ea) ea->elems = NULL; } -int dma_sg_alloc(struct dma_sg_elem_array *ea, - enum mem_zone zone, +int dma_sg_alloc(struct k_heap *heap, + struct dma_sg_elem_array *ea, + uint32_t flags, 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); +void dma_sg_free(struct k_heap *heap, struct dma_sg_elem_array *ea); /** * \brief Get the total size of SG buffer @@ -550,7 +553,8 @@ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, * conversion function. DMA buffer consume should be performed after the data has been copied * to all sinks. */ -int stream_copy_from_no_consume(struct comp_buffer __sparse_cache *source, +int stream_copy_from_no_consume(struct comp_dev *dev, + struct comp_buffer __sparse_cache *source, struct comp_buffer __sparse_cache *sink, dma_process_func process, uint32_t source_bytes, uint32_t chmap); diff --git a/posix/include/sof/lib/memory.h b/posix/include/sof/lib/memory.h index 9a784ec7f19d..456049a3bddb 100644 --- a/posix/include/sof/lib/memory.h +++ b/posix/include/sof/lib/memory.h @@ -18,4 +18,7 @@ #define __cold_rodata #endif +#define assert_can_be_cold() do {} while (0) +#define dbg_path_hot_confirm() do {} while (0) + #endif /* __SOF_LIB_MEMORY_H__ */ diff --git a/posix/include/sof/lib/mm_heap.h b/posix/include/sof/lib/mm_heap.h index 7bdab176eb5f..84bcc893d101 100644 --- a/posix/include/sof/lib/mm_heap.h +++ b/posix/include/sof/lib/mm_heap.h @@ -88,7 +88,7 @@ uint32_t mm_pm_context_size(void); void init_heap(struct sof *sof); /* frees entire heap (supported for secondary core system heap atm) */ -void free_heap(enum mem_zone zone); +void free_heap(void); /* status */ void heap_trace_all(int force); @@ -101,7 +101,7 @@ void heap_trace(struct mm_heap *heap, int size); * @param out output variable * @return error code or zero */ -int heap_info(enum mem_zone zone, int index, struct mm_info *out); +int heap_info(int index, struct mm_info *out); #endif /* retrieve memory map pointer */ diff --git a/scripts/README.docker b/scripts/README.docker deleted file mode 100644 index 902c1e1eafdf..000000000000 --- a/scripts/README.docker +++ /dev/null @@ -1,34 +0,0 @@ -The docker container provided in docker_build sets up a build environment for -building Sound Open Firmware. A working docker installation is needed to run -the docker build container. - -Note: In order to run docker as non sudo/root user please run. - -sudo usermod -aG docker your-user-name - -Then logout and login again. - -Quick Start: - -First, build the docker container. This step needs to be done initially and -when the toolchain or alsa dependencies are updated. - -cd scripts/docker_build - -./docker-build.sh - -After the container is built, it can be used to run the scripts. - -To build for tigerlake: -./scripts/docker-run.sh ./scripts/xtensa-build-all.sh -l tgl -or (may need password test0000 for rimage install) -./scripts/docker-run.sh ./scripts/xtensa-build-all.sh tgl - -To rebuild the topology and logger: -./scripts/docker-run.sh ./scripts/build-tools.sh - -An incremental sof.git build: -./scripts/docker-run.sh make - -Or enter a shell: -./scripts/docker-run.sh bash diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 000000000000..30441422899b --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,167 @@ +# SOF Helper Scripts + +This folder contains a lot of useful scripts that can speed up development for routine tasks or simplify execution of complex tasks. + +## Build Scripts + +SOF has several build targets depending on whether you are building firmware, tooling, documentation or topologies. This directory has a helper for each. + +### Firmware Build (`xtensa-build-zephyr.py`) + +Firmware can either be built using west commands directly or by the `xtensa-build-zephyr.py` script. This script wraps up the west commands and can build using either the Zephyr SDK compiler or the Cadence xtensa compiler for xtensa targets. + +Please run the script with `--help` to see all options. + +E.g to build SOF for Intel Pantherlake: + +1) Enable the python virtual environment for west. This should be in your SOF workspace installation directory. Default is `~/work/sof` (only needs run once). + +```bash +source ~/work/sof/.venv/bin/activate +``` + +2) Now run the build script. *Note: most build errors are a result of ingredients being out of sync with the west manifest. Please run `west update` and rebuild before fixing/reporting build errors.* + +```bash +./scripts/xtensa-build-zephyr.py -p ptl +``` + +### Reproducible Output Builds (`test-repro-build.sh`) + +This script can be used to locally reproduce the exact build steps and environment of specific CI validation tests. + +```bash +./scripts/test-repro-build.sh --help +``` + +## Tools and Topologies + +Tooling and topology can be built together using one script. To build all topologies please run: + +```bash +./scripts/build-tools.sh +``` + +**Options for `build-tools.sh`:** + +* `-c` : Rebuild `ctl/` tool +* `-l` : Rebuild `logger/` tool +* `-p` : Rebuild `probes/` tool +* `-T` : Rebuild ALL `topology/` targets +* `-X` : Rebuild topology1 only +* `-Y` : Rebuild topology2 only +* `-t` : Rebuild test topologies +* `-A` : Clone and rebuild the local ALSA git version for `alsa-lib` and `alsa-utils` with latest non-distro features. +* `-C` : No build, only CMake re-configuration. Shows CMake targets. + +*Warning: building tools is incremental by default. To build from scratch delete the `tools/build_tools` directory or use `-C`.* + +### ALSA Specific Build (`build-alsa-tools.sh`) + +If you want to pull down and explicitly recompile only the associated ALSA libraries from their public `alsa-lib` GitHub upstream independently of SOF topologies: + +```bash +./scripts/build-alsa-tools.sh +``` + +## Testbench and Emulation + +Testbench is a host application that is used to run SOF processing modules on developers PC. This allows for module development using regular host based tooling. + +### Rebuilding the Testbench (`rebuild-testbench.sh`) + +This script cleans and rebuilds the host test application binary. Ensure you supply the correct target platform wrapper or fuzzing backend. + +**Usage Options:** + +* `-p ` : Build testbench binary for `xt-run` for selected platform (e.g. `-p tgl`). When omitted, performs a `BUILD_TYPE=native`, compile-only check. +* `-f` : Build testbench via a compiler provided by a fuzzer (default path: `.../AFL/afl-gcc`). +* `-j` : Number of parallel make jobs (defaults to `nproc`). + +### Running the Testbench (`host-testbench.sh`) + +Starts the testing sequences. This invokes specific components to ensure basic inputs process without segfaults. + +```bash +./scripts/host-testbench.sh +``` + +### QEMU Check (`qemu-check.sh`) + +Automated verifier for executing firmware builds under QEMU emulation. + +**Usage:** + +```bash +./scripts/qemu-check.sh [platform(s)] +``` + +* Supported platforms are: `imx8`, `imx8x`, `imx8m`. +* Runs all supported platforms by default if none are provided. + +## SDK Support + +There is some SDK support in this directory for speeding up or simplifying tasks with multiple steps. + +### New Modules (`sdk-create-module.py`) + +A new module can be created by running the SDK Create Module script. This python helper copies the SOF template audio module and renames all strings, Cmakefiles, and Kconfigs automatically. It also correctly registers a new DSP UUID and TOML entries. + +Please run: + +```bash +./scripts/sdk-create-module.py new_module_name +``` + +## Docker + +The docker container provided in `docker_build` sets up a build environment for building Sound Open Firmware. A working docker installation is needed to run the docker build container. + +*Note: In order to run docker as non sudo/root user please run:* + +```bash +sudo usermod -aG docker your-user-name +``` + +Then logout and login again. + +**Quick Start:** + +First, build the docker container. This step needs to be done initially and when the toolchain or ALSA dependencies are updated. + +```bash +cd scripts/docker_build +./docker-build.sh +``` + +After the container is built, it can be used to run the scripts. + +To build for tigerlake: + +```bash +./scripts/docker-run.sh ./scripts/xtensa-build-all.sh -l tgl +``` + +or (this command may prompt for a password during rimage installation inside the container) + +```bash +./scripts/docker-run.sh ./scripts/xtensa-build-all.sh tgl +``` + +To rebuild the topology and logger: + +```bash +./scripts/docker-run.sh ./scripts/build-tools.sh +``` + +An incremental `sof.git` build: + +```bash +./scripts/docker-run.sh make +``` + +Or enter a shell: + +```bash +./scripts/docker-run.sh bash +``` diff --git a/scripts/build-alsa-tools.sh b/scripts/build-alsa-tools.sh new file mode 100755 index 000000000000..01cdb761ee1b --- /dev/null +++ b/scripts/build-alsa-tools.sh @@ -0,0 +1,127 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2025 Intel Corporation. All rights reserved. + +# fail immediately on any errors +set -e + +# Array of ALSA Git repository URLs. Add or remove repositories as needed. +declare -a REPOS=( + "https://github.com/thesofproject/alsa-lib.git" + "https://github.com/thesofproject/alsa-utils.git" + # Add more repositories here... +) + +# Commit ID to check for (optional). If specified, the script will update +# the repository if this commit ID is not found. Leave empty to skip. +# This array order must align with REPO array above. +declare -a COMMIT_ID=( + "08b532cd3da9ac8f683bcb4e4beb9b74c39c1782" + "9feb22ba45b48729729c8d194aaf1bc082a6842a" + # Add more IDs here... +) + +# Directory where repositories will be cloned/updated. +if [[ -z "$SOF_WORKSPACE" ]]; then + # Environment variable is empty or unset so use default + BASE_DIR="$HOME/work/sof" +else + # Environment variable exists and has a value + BASE_DIR="$SOF_WORKSPACE" +fi + +# Arguments to pass to ./configure for each repository. Add or remove +declare -a CONFIGURE_ARGS=( + "--prefix=${BASE_DIR}/tools" + "--prefix=${BASE_DIR}/tools \ + --with-alsa-prefix=${BASE_DIR}/tools \ + --with-alsa-inc-prefix=${BASE_DIR}/tools/include \ + --with-sysroot=${BASE_DIR}/tools \ + --with-udev-rules-dir=${BASE_DIR}/tools \ + PKG_CONFIG_PATH=${BASE_DIR}/tools \ + LDFLAGS=-L${BASE_DIR}/tools/lib \ + --with-asound-state-dir=${BASE_DIR}/tools/var/lib/alsa \ + --with-systemdsystemunitdir=${BASE_DIR}/tools/lib/systemd/system" +) + +# Arguments to pass to make for each repository. Add or remove arguments as needed. +declare -a TARGET_ARGS=( + "--disable-old-symbols" + "--enable-alsatopology" +) + +# Function to check if a commit ID exists in a repository +check_commit() { + local repo_dir="$1" + local commit_id="$2" + + if [ -z "$commit_id" ]; then + return 0 # Skip check if no commit ID is provided + fi + + if ! git -C "$repo_dir" rev-parse --quiet --verify "$commit_id" >/dev/null 2>&1; then + return 1 # Commit ID not found + else + return 0 # Commit ID found + fi +} + + +# Function to update the repository +update_repo() { + local repo_dir="$1" + echo "Updating repository: $repo_dir" + git -C "$repo_dir" fetch --all + git -C "$repo_dir" pull +} + +# Function to build and install the repository +build_and_install() { + local repo_dir="$1" + local configure_args="$2" + local target_args="$3" + + echo "Building and installing: $repo_dir $configure_args $target_args" + + if [ ! -f "$repo_dir/gitcompile" ]; then + echo "Error: gitcompile not found in $repo_dir" >&2 + exit 1 + fi + + # if Makefile exists then we can just run make + if [ ! -f "$repo_dir/Makefile" ]; then + (cd "$repo_dir" && ./gitcompile $configure_args $target_args) || \ + { echo "configure failed in $repo_dir"; exit 1; } + else + (cd "$repo_dir" && make -j) || { echo "make failed in $repo_dir"; exit 1; } + fi + + (cd "$repo_dir" && make install) || { echo "make install failed in $repo_dir"; exit 1; } + + echo "Build and installation complete for $repo_dir" +} + +# Main script logic +mkdir -p "$BASE_DIR" + +for ((i = 0; i < ${#REPOS[@]}; i++)); do + echo "Counter: $i, Value: ${REPOS[i]}" + repo_url=${REPOS[i]} + + repo_name=$(basename "$repo_url" .git) # Extract repo name + repo_dir="$BASE_DIR/$repo_name" + + if [ ! -d "$repo_dir" ]; then + echo "Cloning repository: $repo_url" + git clone "$repo_url" "$repo_dir" || { echo "git clone failed for $repo_url"; exit 1; } + elif ! check_commit "$repo_dir" "${COMMIT_ID[i]}"; then + update_repo "$repo_dir" + else + echo "Repository $repo_name is up to date." + fi + + build_and_install "$repo_dir" "${CONFIGURE_ARGS[i]}" + +done + +echo "All repositories processed." diff --git a/scripts/build-tools.sh b/scripts/build-tools.sh index de41f652debf..6304265820cd 100755 --- a/scripts/build-tools.sh +++ b/scripts/build-tools.sh @@ -16,7 +16,7 @@ Attention: the list of selected shortcuts below is _not_ exhaustive. To build _everything_ don't select any particular target; this will build CMake's default target "ALL". -usage: $0 [-c|-f|-h|-l|-p|-t|-T|-X|-Y] +usage: $0 [-c|-f|-h|-l|-p|-t|-T|-X|-Y|-A] -h Display help -c Rebuild ctl/ @@ -26,6 +26,7 @@ usage: $0 [-c|-f|-h|-l|-p|-t|-T|-X|-Y] -X Rebuild topology1 only -Y Rebuild topology2 only -t Rebuild test/topology/ (or tools/test/topology/tplg-build.sh directly) + -A Clone and rebuild local ALSA lib and utils. -C No build, only CMake re-configuration. Shows CMake targets. EOFUSAGE @@ -106,6 +107,7 @@ main() fi DO_BUILD_ctl=false + DO_BUILD_alsa=false DO_BUILD_logger=false DO_BUILD_probes=false DO_BUILD_tests=false @@ -118,7 +120,7 @@ main() # eval is a sometimes necessary evil # shellcheck disable=SC2034 - while getopts "cfhlptTCXY" OPTION; do + while getopts "cfhlptTCXYA" OPTION; do case "$OPTION" in c) DO_BUILD_ctl=true ;; l) DO_BUILD_logger=true ;; @@ -128,12 +130,17 @@ main() X) DO_BUILD_topologies1=true ;; Y) DO_BUILD_topologies2=true ;; C) CMAKE_ONLY=true ;; + A) DO_BUILD_alsa=true ;; h) print_usage; exit 1;; *) print_usage; exit 1;; esac done shift "$((OPTIND - 1))" + if "$DO_BUILD_alsa"; then + $SOF_TOP/scripts/build-alsa-tools.sh + fi + if "$CMAKE_ONLY"; then reconfigure_build print_build_info diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl deleted file mode 100755 index 86c25faec864..000000000000 --- a/scripts/checkpatch.pl +++ /dev/null @@ -1,7619 +0,0 @@ -#!/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 $verbose = 0; -my %verbose_messages = (); -my %verbose_emitted = (); -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 $gitroot = $ENV{'GIT_DIR'}; -$gitroot = ".git" if !defined($gitroot); -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 $user_codespellfile = ""; -my $conststructsfile = "$D/const_structs.checkpatch"; -my $docsfile = "$D/../Documentation/dev-tools/checkpatch.rst"; -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'; -my $tabsize = 8; -my ${CONFIG_} = "CONFIG_"; - -sub help { - my ($exitcode) = @_; - - print << "EOM"; -Usage: $P [OPTION]... [FILE]... -Version: $V - -Options: - -q, --quiet quiet - -v, --verbose verbose mode - --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 - --tab-size=n set the number of spaces for tab (default $tabsize) - --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:$codespellfile) - --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'. - --kconfig-prefix=WORD use WORD as a prefix for Kconfig symbols (default - ${CONFIG_}) - -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 - while ($text =~ /(?:(\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) { - if (defined($1)) { - if (exists($types{$2})) { - $types{$2} .= ",$1" if ($types{$2} ne $1); - } else { - $types{$2} = $1; - } - } else { - $types{$2} = "UNDETERMINED"; - } - } - - print("#\tMessage type\n\n"); - if ($color) { - print(" ( Color coding: "); - print(RED . "ERROR" . RESET); - print(" | "); - print(YELLOW . "WARNING" . RESET); - print(" | "); - print(GREEN . "CHECK" . RESET); - print(" | "); - print("Multiple levels / Undetermined"); - print(" )\n\n"); - } - - foreach my $type (sort keys %types) { - my $orig_type = $type; - if ($color) { - my $level = $types{$type}; - if ($level eq "ERROR") { - $type = RED . $type . RESET; - } elsif ($level eq "WARN") { - $type = YELLOW . $type . RESET; - } elsif ($level eq "CHK") { - $type = GREEN . $type . RESET; - } - } - print(++$count . "\t" . $type . "\n"); - if ($verbose && exists($verbose_messages{$orig_type})) { - my $message = $verbose_messages{$orig_type}; - $message =~ s/\n/\n\t/g; - print("\t" . $message . "\n\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; -} - -sub load_docs { - open(my $docs, '<', "$docsfile") - or warn "$P: Can't read the documentation file $docsfile $!\n"; - - my $type = ''; - my $desc = ''; - my $in_desc = 0; - - while (<$docs>) { - chomp; - my $line = $_; - $line =~ s/\s+$//; - - if ($line =~ /^\s*\*\*(.+)\*\*$/) { - if ($desc ne '') { - $verbose_messages{$type} = trim($desc); - } - $type = $1; - $desc = ''; - $in_desc = 1; - } elsif ($in_desc) { - if ($line =~ /^(?:\s{4,}|$)/) { - $line =~ s/^\s{4}//; - $desc .= $line; - $desc .= "\n"; - } else { - $verbose_messages{$type} = trim($desc); - $type = ''; - $desc = ''; - $in_desc = 0; - } - } - } - - if ($desc ne '') { - $verbose_messages{$type} = trim($desc); - } - close($docs); -} - -# 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, - 'v|verbose!' => \$verbose, - '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, - 'tab-size=i' => \$tabsize, - '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' => \$user_codespellfile, - 'typedefsfile=s' => \$typedefsfile, - 'color=s' => \$color, - 'no-color' => \$color, #keep old behaviors of -nocolor - 'nocolor' => \$color, #keep old behaviors of -nocolor - 'kconfig-prefix=s' => \${CONFIG_}, - 'h|help' => \$help, - 'version' => \$help -) or $help = 2; - -if ($user_codespellfile) { - # Use the user provided codespell file unconditionally - $codespellfile = $user_codespellfile; -} elsif (!(-f $codespellfile)) { - # If /usr/share/codespell/dictionary.txt is not present, try to find it - # under codespell's install directory: /data/dictionary.txt - if (($codespell || $help) && which("codespell") ne "" && which("python") ne "") { - my $python_codespell_dict = << "EOF"; - -import os.path as op -import codespell_lib -codespell_dir = op.dirname(codespell_lib.__file__) -codespell_file = op.join(codespell_dir, 'data', 'dictionary.txt') -print(codespell_file, end='') -EOF - - my $codespell_dict = `python -c "$python_codespell_dict" 2> /dev/null`; - $codespellfile = $codespell_dict if (-f $codespell_dict); - } -} - -# $help is 1 if either -h, --help or --version is passed as option - exitcode: 0 -# $help is 2 if invalid option is passed - exitcode: 1 -help($help - 1) if ($help); - -die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix)); -die "$P: --verbose cannot be used with --terse\n" if ($verbose && $terse); - -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 "$P: Invalid color mode: $color\n"; -} - -load_docs() if ($verbose); -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, '-'); -} - -# skip TAB size 1 to avoid additional checks on $tabsize - 1 -die "$P: Invalid TAB size: $tabsize\n" if ($tabsize < 2); - -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{ - __sparse_cache| - __sparse_force| - __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| - volatile| - __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| - __alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) - }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{(?:\b[Lu])?"[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(?:_array)?(?:_node)? | - 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 $tracing_logging_tags = qr{(?xi: - [=-]*> | - <[=-]* | - \[ | - \] | - start | - called | - entered | - entry | - enter | - in | - inside | - here | - begin | - exit | - end | - done | - leave | - completed | - out | - return | - [\.\!:\s]* -)}; - -sub edit_distance_min { - my (@arr) = @_; - my $len = scalar @arr; - if ((scalar @arr) < 1) { - # if underflow, return - return; - } - my $min = $arr[0]; - for my $i (0 .. ($len-1)) { - if ($arr[$i] < $min) { - $min = $arr[$i]; - } - } - return $min; -} - -sub get_edit_distance { - my ($str1, $str2) = @_; - $str1 = lc($str1); - $str2 = lc($str2); - $str1 =~ s/-//g; - $str2 =~ s/-//g; - my $len1 = length($str1); - my $len2 = length($str2); - # two dimensional array storing minimum edit distance - my @distance; - for my $i (0 .. $len1) { - for my $j (0 .. $len2) { - if ($i == 0) { - $distance[$i][$j] = $j; - } elsif ($j == 0) { - $distance[$i][$j] = $i; - } elsif (substr($str1, $i-1, 1) eq substr($str2, $j-1, 1)) { - $distance[$i][$j] = $distance[$i - 1][$j - 1]; - } else { - my $dist1 = $distance[$i][$j - 1]; #insert distance - my $dist2 = $distance[$i - 1][$j]; # remove - my $dist3 = $distance[$i - 1][$j - 1]; #replace - $distance[$i][$j] = 1 + edit_distance_min($dist1, $dist2, $dist3); - } - } - } - return $distance[$len1][$len2]; -} - -sub find_standard_signature { - my ($sign_off) = @_; - my @standard_signature_tags = ( - 'Signed-off-by:', 'Co-developed-by:', 'Acked-by:', 'Tested-by:', - 'Reviewed-by:', 'Reported-by:', 'Suggested-by:' - ); - foreach my $signature (@standard_signature_tags) { - return $signature if (get_edit_distance($sign_off, $signature) <= 2); - } - - return ""; -} - -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], -); - -my $word_pattern = '\b[A-Z]?[a-z]{2,}\b'; - -#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 (defined $$wordsRef); - $$wordsRef .= $line; - } - close($file); - return 1; - } - - return 0; -} - -my $const_structs; -if (show_type("CONST_STRUCT")) { - read_words(\$const_structs, $conststructsfile) - or warn "No structs that should be const will be found - file '$conststructsfile': $!\n"; -} - -if (defined($typedefsfile)) { - my $typeOtherTypedefs; - read_words(\$typeOtherTypedefs, $typedefsfile) - or warn "No additional types will be considered - file '$typedefsfile': $!\n"; - $typeTypedefs .= '|' . $typeOtherTypedefs if (defined $typeOtherTypedefs); -} - -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*\])+){0,4} - (?:\s+$Inline|\s+$Modifier)* - }x; - $TypeMisordered = qr{ - $NonptrTypeMisordered - (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+){0,4} - (?:\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*\(| - (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\( -)}; - -our %allow_repeated_words = ( - add => '', - added => '', - bad => '', - be => '', -); - -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; - } - } -} - -our %maintained_status = (); - -sub is_maintained_obsolete { - my ($filename) = @_; - - return 0 if (!$tree || !(-e "$root/scripts/get_maintainer.pl")); - - if (!exists($maintained_status{$filename})) { - $maintained_status{$filename} = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`; - } - - return $maintained_status{$filename} =~ /obsolete/i; -} - -sub is_SPDX_License_valid { - my ($license) = @_; - - return 1 if (!$tree || which("python3") eq "" || !(-x "$root/scripts/spdxcheck.py") || !(-e "$gitroot")); - - my $root_path = abs_path($root); - my $status = `cd "$root_path"; echo "$license" | 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 "$gitroot") { - 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 "$gitroot") { - $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_is_single_file { - my ($filename) = @_; - - return 0 if ((which("git") eq "") || !(-e "$gitroot")); - - my $output = `${git_command} ls-files -- $filename 2>/dev/null`; - my $count = $output =~ tr/\n//; - return $count eq 1 && $output =~ m{^${filename}$}; -} - -sub git_commit_info { - my ($commit, $id, $desc) = @_; - - return ($id, $desc) if ((which("git") eq "") || !(-e "$gitroot")); - - 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\./ || - $lines[0] =~ /^fatal: bad object $commit/) { - $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 "$gitroot"); - -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; - my $is_git_file = git_is_single_file($filename); - my $oldfile = $file; - $file = 1 if ($is_git_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, $_); - $vname = qq("$1") if ($filename eq '-' && $_ =~ m/^Subject:\s+(.+)/i); - } - 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(); - $file = $oldfile if ($is_git_file); -} - -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", "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 $quoted = ""; - my $name_comment = ""; - 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 = ""; - } - } - - # Extract comments from names excluding quoted parts - # "John D. (Doe)" - Do not extract - if ($name =~ s/\"(.+)\"//) { - $quoted = $1; - } - while ($name =~ s/\s*($balanced_parens)\s*/ /) { - $name_comment .= trim($1); - } - $name =~ s/^[ \"]+|[ \"]+$//g; - $name = trim("$quoted $name"); - - $address = trim($address); - $address =~ s/^\<|\>$//g; - $comment = trim($comment); - - if ($name =~ /[^\w \-]/i) { ##has "must quote" chars - $name =~ s/(?"; - } - $formatted_email .= "$comment"; - return $formatted_email; -} - -sub reformat_email { - my ($email) = @_; - - my ($email_name, $name_comment, $email_address, $comment) = parse_email($email); - return format_email($email_name, $name_comment, $email_address, $comment); -} - -sub same_email_addresses { - my ($email1, $email2) = @_; - - my ($email1_name, $name1_comment, $email1_address, $comment1) = parse_email($email1); - my ($email2_name, $name2_comment, $email2_address, $comment2) = parse_email($email2); - - return $email1_name eq $email2_name && - $email1_address eq $email2_address && - $name1_comment eq $name2_comment && - $comment1 eq $comment2; -} - -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 % $tabsize) != 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) = @_; - - # If c99 comment on the current line, or the line before or after - my ($current_comment) = ($rawlines[$end_line - 1] =~ m@^\+.*(//.*$)@); - return $current_comment if (defined $current_comment); - ($current_comment) = ($rawlines[$end_line - 2] =~ m@^[\+ ].*(//.*$)@); - return $current_comment if (defined $current_comment); - ($current_comment) = ($rawlines[$end_line] =~ m@^[\+ ].*(//.*$)@); - return $current_comment if (defined $current_comment); - - # Catch a comment on the end of the line itself. - ($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); - } - - if ($terse) { - $output = (split('\n', $output))[0] . "\n"; - } - - if ($verbose && exists($verbose_messages{$type}) && - !exists($verbose_emitted{$type})) { - $output .= $verbose_messages{$type} . "\n\n"; - $verbose_emitted{$type} = 1; - } - - 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 = $tabsize; - 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 get_raw_comment { - my ($line, $rawline) = @_; - my $comment = ''; - - for my $i (0 .. (length($line) - 1)) { - if (substr($line, $i, 1) eq "$;") { - $comment .= substr($rawline, $i, 1); - } - } - - return $comment; -} - -sub exclude_global_initialisers { - my ($realfile) = @_; - - # Do not check for BPF programs (tools/testing/selftests/bpf/progs/*.c, samples/bpf/*_kern.c, *.bpf.c). - return $realfile =~ m@^tools/testing/selftests/bpf/progs/.*\.c$@ || - $realfile =~ m@^samples/bpf/.*_kern\.c$@ || - $realfile =~ m@/bpf/.*\.bpf\.c$@; -} - -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 $author_sob = ''; - 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_patch_separator = 0; #Found a --- line - 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_git_commit_id_linenr = -1; - - 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.txt$@) { - $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]; - my $raw_comment = get_raw_comment($line, $rawline); - -# 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.rst\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; - my $curline = $linenr; - while(defined($rawlines[$curline]) && ($rawlines[$curline++] =~ /^[ \t]\s*(.*)/)) { - $author .= $1; - } - $author = encode("utf8", $author) if ($line =~ /=\?utf-8\?/i); - $author =~ s/"//g; - $author = reformat_email($author); - } - -# Check the patch for a signoff: - if ($line =~ /^\s*signed-off-by:\s*(.*)/i) { - $signoff++; - $in_commit_log = 0; - if ($author ne '' && $authorsignoff != 1) { - if (same_email_addresses($1, $author)) { - $authorsignoff = 1; - } else { - my $ctx = $1; - my ($email_name, $email_comment, $email_address, $comment1) = parse_email($ctx); - my ($author_name, $author_comment, $author_address, $comment2) = parse_email($author); - - if (lc $email_address eq lc $author_address && $email_name eq $author_name) { - $author_sob = $ctx; - $authorsignoff = 2; - } elsif (lc $email_address eq lc $author_address) { - $author_sob = $ctx; - $authorsignoff = 3; - } elsif ($email_name eq $author_name) { - $author_sob = $ctx; - $authorsignoff = 4; - - my $address1 = $email_address; - my $address2 = $author_address; - - if ($address1 =~ /(\S+)\+\S+(\@.*)/) { - $address1 = "$1$2"; - } - if ($address2 =~ /(\S+)\+\S+(\@.*)/) { - $address2 = "$1$2"; - } - if ($address1 eq $address2) { - $authorsignoff = 5; - } - } - } - } - } - -# Check for patch separator - if ($line =~ /^---$/) { - $has_patch_separator = 1; - $in_commit_log = 0; - } - -# 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/) { - my $suggested_signature = find_standard_signature($sign_off); - if ($suggested_signature eq "") { - WARN("BAD_SIGN_OFF", - "Non-standard signature: $sign_off\n" . $herecurr); - } else { - if (WARN("BAD_SIGN_OFF", - "Non-standard signature: '$sign_off' - perhaps '$suggested_signature'?\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/$sign_off/$suggested_signature/; - } - } - } - 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, $name_comment, $email_address, $comment) = parse_email($email); - my $suggested_email = format_email(($email_name, $name_comment, $email_address, $comment)); - if ($suggested_email eq "") { - ERROR("BAD_SIGN_OFF", - "Unrecognized email address: '$email'\n" . $herecurr); - } else { - my $dequoted = $suggested_email; - $dequoted =~ s/^"//; - $dequoted =~ s/" 1) { - WARN("BAD_SIGN_OFF", - "Use a single name comment in email: '$email'\n" . $herecurr); - } - - - # stable@vger.kernel.org or stable@kernel.org shouldn't - # have an email name. In addition comments should strictly - # begin with a # - if ($email =~ /^.*stable\@(?:vger\.)?kernel\.org/i) { - if (($comment ne "" && $comment !~ /^#.+/) || - ($email_name ne "")) { - my $cur_name = $email_name; - my $new_comment = $comment; - $cur_name =~ s/[a-zA-Z\s\-\"]+//g; - - # Remove brackets enclosing comment text - # and # from start of comments to get comment text - $new_comment =~ s/^\((.*)\)$/$1/; - $new_comment =~ s/^\[(.*)\]$/$1/; - $new_comment =~ s/^[\s\#]+|\s+$//g; - - $new_comment = trim("$new_comment $cur_name") if ($cur_name ne $new_comment); - $new_comment = " # $new_comment" if ($new_comment ne ""); - my $new_email = "$email_address$new_comment"; - - if (WARN("BAD_STABLE_ADDRESS_STYLE", - "Invalid email format for stable: '$email', prefer '$new_email'\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/\Q$email\E/$new_email/; - } - } - } elsif ($comment ne "" && $comment !~ /^(?:#.+|\(.+\))$/) { - my $new_comment = $comment; - - # Extract comment text from within brackets or - # c89 style /*...*/ comments - $new_comment =~ s/^\[(.*)\]$/$1/; - $new_comment =~ s/^\/\*(.*)\*\/$/$1/; - - $new_comment = trim($new_comment); - $new_comment =~ s/^[^\w]$//; # Single lettered comment with non word character is usually a typo - $new_comment = "($new_comment)" if ($new_comment ne ""); - my $new_email = format_email($email_name, $name_comment, $email_address, $new_comment); - - if (WARN("BAD_SIGN_OFF", - "Unexpected content after email: '$email', should be: '$new_email'\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/\Q$email\E/$new_email/; - } - } - } - -# 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 Gerrit Change-Ids not in any patch context - if ($realfile eq '' && !$has_patch_separator && $line =~ /^\s*change-id:/i) { - if (ERROR("GERRIT_CHANGE_ID", - "Remove Gerrit Change-Id's before submitting upstream\n" . $herecurr) && - $fix) { - fix_delete_line($fixlinenr, $rawline); - } - } - -# 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:|$signature_tags)/i || - # A Fixes: or Link: line or signature tag 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 lines starting with a # - if ($in_commit_log && $line =~ /^#/) { - if (WARN("COMMIT_COMMENT_SYMBOL", - "Commit log lines starting with '#' are dropped by git as comments\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/^/ /; - } - } - -# Check for git id commit length and improperly formed commit descriptions -# A correctly formed commit description is: -# commit ("Complete commit subject") -# with the commit subject '("' prefix and '")' suffix -# This is a fairly compilicated block as it tests for what appears to be -# bare SHA-1 hash with minimum length of 5. It also avoids several types of -# possible SHA-1 matches. -# A commit match can span multiple lines so this block attempts to find a -# complete typical commit on a maximum of 3 lines - if ($perl_version_ok && - $in_commit_log && !$commit_log_possible_stack_dump && - $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink|base-commit):/i && - $line !~ /^This reverts commit [0-9a-f]{7,40}/ && - (($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i || - ($line =~ /\bcommit\s*$/i && defined($rawlines[$linenr]) && $rawlines[$linenr] =~ /^\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 $id = '0123456789ab'; - my $orig_desc = "commit description"; - my $description = ""; - my $herectx = $herecurr; - my $has_parens = 0; - my $has_quotes = 0; - - my $input = $line; - if ($line =~ /(?:\bcommit\s+[0-9a-f]{5,}|\bcommit\s*$)/i) { - for (my $n = 0; $n < 2; $n++) { - if ($input =~ /\bcommit\s+[0-9a-f]{5,}\s*($balanced_parens)/i) { - $orig_desc = $1; - $has_parens = 1; - # Always strip leading/trailing parens then double quotes if existing - $orig_desc = substr($orig_desc, 1, -1); - if ($orig_desc =~ /^".*"$/) { - $orig_desc = substr($orig_desc, 1, -1); - $has_quotes = 1; - } - last; - } - last if ($#lines < $linenr + $n); - $input .= " " . trim($rawlines[$linenr + $n]); - $herectx .= "$rawlines[$linenr + $n]\n"; - } - $herectx = $herecurr if (!$has_parens); - } - - if ($input =~ /\b(c)ommit\s+([0-9a-f]{5,})\b/i) { - $init_char = $1; - $orig_commit = lc($2); - $short = 0 if ($input =~ /\bcommit\s+[0-9a-f]{12,40}/i); - $long = 1 if ($input =~ /\bcommit\s+[0-9a-f]{41,}/i); - $space = 0 if ($input =~ /\bcommit [0-9a-f]/i); - $case = 0 if ($input =~ /\b[Cc]ommit\s+[0-9a-f]{5,40}[^A-F]/); - } elsif ($input =~ /\b([0-9a-f]{12,40})\b/i) { - $orig_commit = lc($1); - } - - ($id, $description) = git_commit_info($orig_commit, - $id, $orig_desc); - - if (defined($id) && - ($short || $long || $space || $case || ($orig_desc ne $description) || !$has_quotes) && - $last_git_commit_id_linenr != $linenr - 1) { - ERROR("GIT_COMMIT_ID", - "Please use git commit description style 'commit <12+ chars of sha1> (\"\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $herectx); - } - #don't report the next line if this line ends in commit and the sha1 hash is the next line - $last_git_commit_id_linenr = $linenr if ($line =~ /\bcommit\s*$/i); - } - -# Check for added, moved or deleted files - if (!$SOF) { - if (!$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 adding new DT bindings not in schema format - if (!$in_commit_log && - ($line =~ /^new file mode\s*\d+\s*$/) && - ($realfile =~ m@^Documentation/devicetree/bindings/.*\.txt$@)) { - WARN("DT_SCHEMA_BINDING_PATCH", - "DT bindings should be in DT schema format. See: Documentation/devicetree/bindings/writing-schema.rst\n"); - } - -# 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 =~ /(?:^|[^\w\-'`])($misspellings)(?:[^\w\-'`]|$)/gi) { - my $typo = $1; - my $blank = copy_spacing($rawline); - my $ptr = substr($blank, 0, $-[1]) . "^" x length($typo); - my $hereptr = "$hereline$ptr\n"; - 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" . $hereptr) && - $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); - } - } - -# check for repeated words separated by a single space -# avoid false positive from list command eg, '-rw-r--r-- 1 root root' - if (($rawline =~ /^\+/ || $in_commit_log) && - $rawline !~ /[bcCdDlMnpPs\?-][rwxsStT-]{9}/) { - pos($rawline) = 1 if (!$in_commit_log); - while ($rawline =~ /\b($word_pattern) (?=($word_pattern))/g) { - - my $first = $1; - my $second = $2; - my $start_pos = $-[1]; - my $end_pos = $+[2]; - if ($first =~ /(?:struct|union|enum)/) { - pos($rawline) += length($first) + length($second) + 1; - next; - } - - next if (lc($first) ne lc($second)); - next if ($first eq 'long'); - - # check for character before and after the word matches - my $start_char = ''; - my $end_char = ''; - $start_char = substr($rawline, $start_pos - 1, 1) if ($start_pos > ($in_commit_log ? 0 : 1)); - $end_char = substr($rawline, $end_pos, 1) if ($end_pos < length($rawline)); - - next if ($start_char =~ /^\S$/); - next if (index(" \t.,;?!", $end_char) == -1); - - # avoid repeating hex occurrences like 'ff ff fe 09 ...' - if ($first =~ /\b[0-9a-f]{2,}\b/i) { - next if (!exists($allow_repeated_words{lc($first)})); - } - - if (WARN("REPEATED_WORD", - "Possible repeated word: '$first'\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/\b$first $second\b/$first/; - } - } - - # if it's a repeated word on consecutive lines in a comment block - if ($prevline =~ /$;+\s*$/ && - $prevrawline =~ /($word_pattern)\s*$/) { - my $last_word = $1; - if ($rawline =~ /^\+\s*\*\s*$last_word /) { - if (WARN("REPEATED_WORD", - "Possible repeated word: '$last_word'\n" . $hereprev) && - $fix) { - $fixed[$fixlinenr] =~ s/(\+\s*\*\s*)$last_word /$1/; - } - } - } - } - -# 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 $ln = $linenr; - my $needs_help = 0; - my $has_help = 0; - my $help_length = 0; - while (defined $lines[$ln]) { - my $f = $lines[$ln++]; - - next if ($f =~ /^-/); - last if ($f !~ /^[\+ ]/); # !patch context - - if ($f =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { - $needs_help = 1; - next; - } - if ($f =~ /^\+\s*help\s*$/) { - $has_help = 1; - next; - } - - $f =~ s/^.//; # strip patch context [+ ] - $f =~ s/#.*//; # strip # directives - $f =~ s/^\s+//; # strip leading blanks - next if ($f =~ /^$/); # skip blank lines - - # At the end of this Kconfig block: - # 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 =~ /^(?:config|menuconfig|choice|endchoice| - if|endif|menu|endmenu|source)\b/x) { - last; - } - $help_length++ if ($has_help); - } - if ($needs_help && - $help_length < $min_conf_desc_length) { - my $stat_real = get_stat_real($linenr, $ln - 1); - WARN("CONFIG_DESCRIPTION", - "please write a help paragraph that fully describes the config symbol\n" . "$here\n$stat_real\n"); - } - } - -# check MAINTAINERS entries - if ($realfile =~ /^MAINTAINERS$/) { -# check MAINTAINERS entries for the right form - if ($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/; - } - } -# check MAINTAINERS entries for the right ordering too - my $preferred_order = 'MRLSWQBCPTFXNK'; - if ($rawline =~ /^\+[A-Z]:/ && - $prevrawline =~ /^[\+ ][A-Z]:/) { - $rawline =~ /^\+([A-Z]):\s*(.*)/; - my $cur = $1; - my $curval = $2; - $prevrawline =~ /^[\+ ]([A-Z]):\s*(.*)/; - my $prev = $1; - my $prevval = $2; - my $curindex = index($preferred_order, $cur); - my $previndex = index($preferred_order, $prev); - if ($curindex < 0) { - WARN("MAINTAINERS_STYLE", - "Unknown MAINTAINERS entry type: '$cur'\n" . $herecurr); - } else { - if ($previndex >= 0 && $curindex < $previndex) { - WARN("MAINTAINERS_STYLE", - "Misordered MAINTAINERS entry - list '$cur:' before '$prev:'\n" . $hereprev); - } elsif ((($prev eq 'F' && $cur eq 'F') || - ($prev eq 'X' && $cur eq 'X')) && - ($prevval cmp $curval) > 0) { - WARN("MAINTAINERS_STYLE", - "Misordered MAINTAINERS entry - list file patterns in alphabetic order\n" . $hereprev); - } - } - } - } - - 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|yaml)$/) { - $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); - } - if ($realfile =~ m@^Documentation/devicetree/bindings/@ && - not $spdx_license =~ /GPL-2\.0.*BSD-2-Clause/) { - my $msg_level = \&WARN; - $msg_level = \&CHK if ($file); - if (&{$msg_level}("SPDX_LICENSE_TAG", - - "DT binding documents should be licensed (GPL-2.0-only OR BSD-2-Clause)\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/SPDX-License-Identifier: .*/SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)/; - } - } - } - } - } - -# check for embedded filenames - if ($rawline =~ /^\+.*\Q$realfile\E/) { - WARN("EMBEDDED_FILENAME", - "It's generally not useful to have the filename in the file\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/) { - if (WARN("MISSING_EOF_NEWLINE", - "adding a line without newline at end of file\n" . $herecurr) && - $fix) { - fix_delete_line($fixlinenr+1, "No newline at end of file"); - } - } - -# check for .L prefix local symbols in .S files - if ($realfile =~ /\.S$/ && - $line =~ /^\+\s*(?:[A-Z]+_)?SYM_[A-Z]+_(?:START|END)(?:_[A-Z_]+)?\s*\(\s*\.L/) { - WARN("AVOID_L_PREFIX", - "Avoid using '.L' prefixed local symbol names for denoting a range of code via 'SYM_*_START/END' annotations; see Documentation/asm-annotations.rst\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 $tabsize 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/(^\+.*) {$tabsize,$tabsize}\t/$1\t\t/) {} - while ($fixed[$fixlinenr] =~ - s/(^\+.*) +\t/$1\t/) {} - } - } - -# check for assignments on the start of a line - if ($sline =~ /^\+\s+($Assignment)[^=]/) { - my $operator = $1; - if (CHK("ASSIGNMENT_CONTINUATIONS", - "Assignment operator '$1' should be on the previous line\n" . $hereprev) && - $fix && $prevrawline =~ /^\+/) { - # add assignment operator to the previous line, remove from current line - $fixed[$fixlinenr - 1] .= " $operator"; - $fixed[$fixlinenr] =~ s/\Q$operator\E\s*//; - } - } - -# check for && or || at the start of a line - if ($rawline =~ /^\+\s*(&&|\|\|)/) { - my $operator = $1; - if (CHK("LOGICAL_CONTINUATIONS", - "Logical continuations should be on the previous line\n" . $hereprev) && - $fix && $prevrawline =~ /^\+/) { - # insert logical operator at last non-comment, non-whitepsace char on previous line - $prevline =~ /[\s$;]*$/; - my $line_end = substr($prevrawline, $-[0]); - $fixed[$fixlinenr - 1] =~ s/\Q$line_end\E$/ $operator$line_end/; - $fixed[$fixlinenr] =~ s/\Q$operator\E\s*//; - } - } - -# 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 % $tabsize) { - if (WARN("TABSTOP", - "Statements should start on a tabstop\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/$tabsize)@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 / $tabsize) . - " " x ($pos % $tabsize); - 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 > 3) { # Do not warn about the initial copyright comment block after SPDX-License-Identifier - 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 -# (declarations must have the same indentation and not be at the start of line) - if (($prevline =~ /\+(\s+)\S/) && $sline =~ /^\+$1\S/) { - # use temporaries - my $sl = $sline; - my $pl = $prevline; - # remove $Attribute/$Sparse uses to simplify comparisons - $sl =~ s/\b(?:$Attribute|$Sparse)\b//g; - $pl =~ s/\b(?:$Attribute|$Sparse)\b//g; - if (($pl =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || - # function pointer declarations - $pl =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ || - # foo bar; where foo is some local typedef or #define - $pl =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || - # known declaration macros - $pl =~ /^\+\s+$declaration_macros/) && - # for "else if" which can look like "$Ident $Ident" - !($pl =~ /^\+\s+$c90_Keywords\b/ || - # other possible extensions of declaration lines - $pl =~ /(?:$Compare|$Assignment|$Operators)\s*$/ || - # not starting a section or a macro "\" extended line - $pl =~ /(?:\{\s*|\\)$/) && - # looks like a declaration - !($sl =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || - # function pointer declarations - $sl =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ || - # foo bar; where foo is some local typedef or #define - $sl =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || - # known declaration macros - $sl =~ /^\+\s+$declaration_macros/ || - # start of struct or union or enum - $sl =~ /^\+\s+(?:static\s+)?(?:const\s+)?(?:union|struct|enum|typedef)\b/ || - # start or end of block or continuation of declaration - $sl =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ || - # bitfield continuation - $sl =~ /^\+\s+$Ident\s*:\s*\d+\s*[,;]/ || - # other possible extensions of declaration lines - $sl =~ /^\+\s+\(?\s*(?:$Compare|$Assignment|$Operators)/)) { - 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, return or break -# and is indented the same # of tabs - if ($sline =~ /^\+([\t]+)break\s*;\s*$/) { - my $tabs = $1; - if ($prevline =~ /^\+$tabs(goto|return|break)\b/) { - if (WARN("UNNECESSARY_BREAK", - "break is not useful after a $1\n" . $hereprev) && - $fix) { - fix_delete_line($fixlinenr, $rawline); - } - } - } - -# 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 % $tabsize) != 0 || - ($sindent < $indent) || - ($sindent == $indent && - ($s !~ /^\s*(?:\}|\{|else\b)/)) || - ($sindent > $indent + $tabsize))) { - 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 self assignments used to avoid compiler warnings -# e.g.: int foo = foo, *bar = NULL; -# struct foo bar = *(&(bar)); - if ($line =~ /^\+\s*(?:$Declare)?([A-Za-z_][A-Za-z\d_]*)\s*=/) { - my $var = $1; - if ($line =~ /^\+\s*(?:$Declare)?$var\s*=\s*(?:$var|\*\s*\(?\s*&\s*\(?\s*$var\s*\)?\s*\)?)\s*[;,]/) { - WARN("SELF_ASSIGNMENT", - "Do not use self-assignments to avoid compiler warnings\n" . $herecurr); - } - } - -# 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.*\((.*)\)/)) { - # Handle definitions which produce identifiers with - # a prefix: - # XXX(foo); - # EXPORT_SYMBOL(something_foo); - my $name = $1; - $name =~ s/^\s*($Ident).*/$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.*\((.*)\)/)) { -#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*;/ && - !exclude_global_initialisers($realfile)) { - 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 const static or static <non ptr type> const declarations -# prefer 'static const <foo>' over 'const static <foo>' and 'static <foo> const' - if ($sline =~ /^\+\s*const\s+static\s+($Type)\b/ || - $sline =~ /^\+\s*static\s+($BasicType)\s+const\b/) { - if (WARN("STATIC_CONST", - "Move const after static - use 'static const $1'\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/\bconst\s+static\b/static const/; - $fixed[$fixlinenr] =~ s/\bstatic\s+($BasicType)\s+const\b/static const $1/; - } - } - -# 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); - } - - if(!$SOF) { - -# 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); - } - -# prefer variants of (subsystem|netdev|dev|pr)_<level> to printk(KERN_<LEVEL> - if ($line =~ /\b(printk(_once|_ratelimited)?)\s*\(\s*KERN_([A-Z]+)/) { - my $printk = $1; - my $modifier = $2; - my $orig = $3; - $modifier = "" if (!defined($modifier)); - my $level = lc($orig); - $level = "warn" if ($level eq "warning"); - my $level2 = $level; - $level2 = "dbg" if ($level eq "debug"); - $level .= $modifier; - $level2 .= $modifier; - WARN("PREFER_PR_LEVEL", - "Prefer [subsystem eg: netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then pr_$level(... to $printk(KERN_$orig ...\n" . $herecurr); - } - -# prefer dev_<level> to dev_printk(KERN_<LEVEL> - 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); - } - - } # !$SOF - -# trace_printk should not be used in production code. - if ($line =~ /\b(trace_printk|trace_puts|ftrace_vprintk)\s*\(/) { - WARN("TRACE_PRINTK", - "Do not use $1() in production code (this can be ignored if built only with a debug config option)\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); - } - -# ENOTSUPP is not a standard error code and should be avoided in new patches. -# Folks usually mean EOPNOTSUPP (also called ENOTSUP), when they type ENOTSUPP. -# Similarly to ENOSYS warning a small number of false positives is expected. - if (!$file && $line =~ /\bENOTSUPP\b/) { - if (WARN("ENOTSUPP", - "ENOTSUPP is not a SUSV4 error code, prefer EOPNOTSUPP\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/\bENOTSUPP\b/EOPNOTSUPP/; - } - } - -# 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./ and $realfile !~ m@.*\.lds\.h$@) { - 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 -## # falsely 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); - } - } - -# check that goto labels aren't indented (allow a single space indentation) -# and ignore bitfield definitions like foo:1 -# Strictly, labels can have whitespace after the identifier and before the : -# but this is not allowed here as many ?: uses would appear to be labels - if ($sline =~ /^.\s+[A-Za-z_][A-Za-z\d_]*:(?!\s*\d+)/ && - $sline !~ /^. [A-Za-z\d_][A-Za-z\d_]*:/ && - $sline !~ /^.\s+default:/) { - if (WARN("INDENTED_LABEL", - "labels should not be indented\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ - s/^(.)\s+/$1/; - } - } - -# check if a statement with a comma should be two statements like: -# foo = bar(), /* comma should be semicolon */ -# bar = baz(); - if (defined($stat) && - $stat =~ /^\+\s*(?:$Lval\s*$Assignment\s*)?$FuncArg\s*,\s*(?:$Lval\s*$Assignment\s*)?$FuncArg\s*;\s*$/) { - my $cnt = statement_rawlines($stat); - my $herectx = get_stat_here($linenr, $cnt, $here); - WARN("SUSPECT_COMMA_SEMICOLON", - "Possible comma where semicolon could be used\n" . $herectx); - } - -# 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' && $name !~ /^EPOLL/) { - 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) { - if (ERROR("ASSIGN_IN_IF", - "do not use assignment in if condition\n" . $herecurr) && - $fix && $perl_version_ok) { - if ($rawline =~ /^\+(\s+)if\s*\(\s*(\!)?\s*\(\s*(($Lval)\s*=\s*$LvalOrFunc)\s*\)\s*(?:($Compare)\s*($FuncArg))?\s*\)\s*(\{)?\s*$/) { - my $space = $1; - my $not = $2; - my $statement = $3; - my $assigned = $4; - my $test = $8; - my $against = $9; - my $brace = $15; - fix_delete_line($fixlinenr, $rawline); - fix_insert_line($fixlinenr, "$space$statement;"); - my $newline = "${space}if ("; - $newline .= '!' if defined($not); - $newline .= '(' if (defined $not && defined($test) && defined($against)); - $newline .= "$assigned"; - $newline .= " $test $against" if (defined($test) && defined($against)); - $newline .= ')' if (defined $not && defined($test) && defined($against)); - $newline .= ')'; - $newline .= " {" if (defined($brace)); - fix_insert_line($fixlinenr + 1, $newline); - } - } - } - - # 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 some autogenerated defines and enum values - $var !~ /^(?:[A-Z]+_){1,5}[A-Z]{1,3}[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, RANGE_mA_VALUE) - $var !~ /^(?:[a-z0-9_]*|[A-Z0-9_]*)?_?[a-z][A-Z](?:_[a-z0-9_]+|_[A-Z0-9_]+)?$/ && -#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/\([^\(\)]*\)/1u/ || - $dstat =~ s/\{[^\{\}]*\}/1u/ || - $dstat =~ s/.\[[^\[\]]*\]/1u/) - { - } - - # Flatten any obvious string concatenation. - 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 !~ /^while\s*$Constant\s*$Constant\s*$/ && # 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(__must_be_array|offsetof|sizeof|sizeof_field|__stringify|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 unnecessary function tracing like uses -# This does not use $logFunctions because there are many instances like -# 'dprintk(FOO, "%s()\n", __func__);' which do not match $logFunctions - if ($rawline =~ /^\+.*\([^"]*"$tracing_logging_tags{0,3}%s(?:\s*\(\s*\)\s*)?$tracing_logging_tags{0,3}(?:\\n)?"\s*,\s*__func__\s*\)\s*;/) { - if (WARN("TRACING_LOGGING", - "Unnecessary ftrace-like logging - prefer using ftrace\n" . $herecurr) && - $fix) { - fix_delete_line($fixlinenr, $rawline); - } - } - -# 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-Z_]/ || - ($line =~ /([A-Za-z0-9_]+)$String/ && $1 !~ /^[Lu]$/)) { - 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*[Lu]?"/) { - 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 unnecessary use of %h[xudi] and %hh[xudi] in logging functions - if (defined $stat && - $line =~ /\b$logFunctions\s*\(/ && - index($stat, '"') >= 0) { - my $lc = $stat =~ tr@\n@@; - $lc = $lc + $linenr; - my $stat_real = get_stat_real($linenr, $lc); - pos($stat_real) = index($stat_real, '"'); - while ($stat_real =~ /[^\"%]*(%[\#\d\.\*\-]*(h+)[idux])/g) { - my $pspec = $1; - my $h = $2; - my $lineoff = substr($stat_real, 0, $-[1]) =~ tr@\n@@; - if (WARN("UNNECESSARY_MODIFIER", - "Integer promotion: Using '$h' in '$pspec' is unnecessary\n" . "$here\n$stat_real\n") && - $fix && $fixed[$fixlinenr + $lineoff] =~ /^\+/) { - my $nspec = $pspec; - $nspec =~ s/h//g; - $fixed[$fixlinenr + $lineoff] =~ s/\Q$pspec\E/$nspec/; - } - } - } - -# 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 - }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 data_race without a comment. - if ($line =~ /\bdata_race\s*\(/) { - if (!ctx_has_comment($first_line, $linenr)) { - WARN("DATA_RACE", - "data_race without comment\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 compiler attributes - if ($realfile !~ m@\binclude/uapi/@ && - $rawline =~ /\b__attribute__\s*\(\s*($balanced_parens)\s*\)/) { - my $attr = $1; - $attr =~ s/\s*\(\s*(.*)\)\s*/$1/; - - my %attr_list = ( - "alias" => "__alias", - "aligned" => "__aligned", - "always_inline" => "__always_inline", - "assume_aligned" => "__assume_aligned", - "cold" => "__cold", - "const" => "__attribute_const__", - "copy" => "__copy", - "designated_init" => "__designated_init", - "externally_visible" => "__visible", - "format" => "printf|scanf", - "gnu_inline" => "__gnu_inline", - "malloc" => "__malloc", - "mode" => "__mode", - "no_caller_saved_registers" => "__no_caller_saved_registers", - "noclone" => "__noclone", - "noinline" => "noinline", - "nonstring" => "__nonstring", - "noreturn" => "__noreturn", - "packed" => "__packed", - "pure" => "__pure", - "section" => "__section", - "used" => "__used", - "weak" => "__weak" - ); - - while ($attr =~ /\s*(\w+)\s*(${balanced_parens})?/g) { - my $orig_attr = $1; - my $params = ''; - $params = $2 if defined($2); - my $curr_attr = $orig_attr; - $curr_attr =~ s/^[\s_]+|[\s_]+$//g; - if (exists($attr_list{$curr_attr})) { - my $new = $attr_list{$curr_attr}; - if ($curr_attr eq "format" && $params) { - $params =~ /^\s*\(\s*(\w+)\s*,\s*(.*)/; - $new = "__$1\($2"; - } else { - $new = "$new$params"; - } - if (WARN("PREFER_DEFINED_ATTRIBUTE_MACRO", - "Prefer $new over __attribute__(($orig_attr$params))\n" . $herecurr) && - $fix) { - my $remove = "\Q$orig_attr\E" . '\s*' . "\Q$params\E" . '(?:\s*,\s*)?'; - $fixed[$fixlinenr] =~ s/$remove//; - $fixed[$fixlinenr] =~ s/\b__attribute__/$new __attribute__/; - $fixed[$fixlinenr] =~ s/\}\Q$new\E/} $new/; - $fixed[$fixlinenr] =~ s/ __attribute__\s*\(\s*\(\s*\)\s*\)//; - } - } - } - - # Check for __attribute__ unused, prefer __always_unused or __maybe_unused - if ($attr =~ /^_*unused/) { - WARN("PREFER_DEFINED_ATTRIBUTE_MACRO", - "__always_unused or __maybe_unused is preferred over __attribute__((__unused__))\n" . $herecurr); - } - } - -# 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) { - if ($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; - 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'; - } - if (WARN("TYPECAST_INT_CONSTANT", - "Unnecessary typecast of c90 int constant - '$cast$const' could be '$const$suffix'\n" . $herecurr) && - $fix) { - $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 $qualifier; - my $bad_specifier = ""; - my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); - $fmt =~ s/%%//g; - - while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) { - $specifier = $1; - $extension = $2; - $qualifier = $3; - if ($extension !~ /[4SsBKRraEehMmIiUDdgVCbGNOxtf]/ || - ($extension eq "f" && - defined $qualifier && $qualifier !~ /^w/) || - ($extension eq "4" && - defined $qualifier && $qualifier !~ /^cc/)) { - $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]/) { - $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)/; -# } -# } -# } - -# strlcpy uses that should likely be strscpy - if ($line =~ /\bstrlcpy\s*\(/) { - WARN("STRLCPY", - "Prefer strscpy over strlcpy - see: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw\@mail.gmail.com/\n" . $herecurr); - } - -# 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*;/) - { - 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.txt\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((?:devm_)?(?: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 IS_ENABLED() without CONFIG_<FOO> ($rawline for comments too) - if ($rawline =~ /\bIS_ENABLED\s*\(\s*(\w+)\s*\)/ && $1 !~ /^${CONFIG_}/) { - WARN("IS_ENABLED_CONFIG", - "IS_ENABLED($1) is normally used as IS_ENABLED(${CONFIG_}$1)\n" . $herecurr); - } - -# 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 /* fallthrough */ like comment, prefer fallthrough; - my @fallthroughs = ( - 'fallthrough', - '@fallthrough@', - 'lint -fallthrough[ \t]*', - 'intentional(?:ly)?[ \t]*fall(?:(?:s | |-)[Tt]|t)hr(?:ough|u|ew)', - '(?:else,?\s*)?FALL(?:S | |-)?THR(?:OUGH|U|EW)[ \t.!]*(?:-[^\n\r]*)?', - 'Fall(?:(?:s | |-)[Tt]|t)hr(?:ough|u|ew)[ \t.!]*(?:-[^\n\r]*)?', - 'fall(?:s | |-)?thr(?:ough|u|ew)[ \t.!]*(?:-[^\n\r]*)?', - ); - if ($raw_comment ne '') { - foreach my $ft (@fallthroughs) { - if ($raw_comment =~ /$ft/) { - my $msg_level = \&WARN; - $msg_level = \&CHK if ($file); - &{$msg_level}("PREFER_FALLTHROUGH", - "Prefer 'fallthrough;' over fallthrough comment\n" . $herecurr); - last; - } - } - } - -# 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 (defined($const_structs) && - $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 -# ignore designated initializers using NR_CPUS - 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[^\]]*\.\.\.[^\]]*\]/ && - $line !~ /^.\s*\.\w+\s*=\s*.*\bNR_CPUS\b/) - { - 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); - } - -# return sysfs_emit(foo, fmt, ...) fmt without newline - if ($line =~ /\breturn\s+sysfs_emit\s*\(\s*$FuncArg\s*,\s*($String)/ && - substr($rawline, $-[6], $+[6] - $-[6]) !~ /\\n"$/) { - my $offset = $+[6] - 1; - if (WARN("SYSFS_EMIT", - "return sysfs_emit(...) formats should include a terminating newline\n" . $herecurr) && - $fix) { - substr($fixed[$fixlinenr], $offset, 0) = '\\n'; - } - } - -# 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 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 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 != 1) { - # authorsignoff values: - # 0 -> missing sign off - # 1 -> sign off identical - # 2 -> names and addresses match, comments mismatch - # 3 -> addresses match, names different - # 4 -> names match, addresses different - # 5 -> names match, addresses excluding subaddress details (refer RFC 5233) match - - my $sob_msg = "'From: $author' != 'Signed-off-by: $author_sob'"; - - if ($authorsignoff == 0) { - ERROR("NO_AUTHOR_SIGN_OFF", - "Missing Signed-off-by: line by nominal patch author '$author'\n"); - } elsif ($authorsignoff == 2) { - CHK("FROM_SIGN_OFF_MISMATCH", - "From:/Signed-off-by: email comments mismatch: $sob_msg\n"); - } elsif ($authorsignoff == 3) { - WARN("FROM_SIGN_OFF_MISMATCH", - "From:/Signed-off-by: email name mismatch: $sob_msg\n"); - } elsif ($authorsignoff == 4) { - WARN("FROM_SIGN_OFF_MISMATCH", - "From:/Signed-off-by: email address mismatch: $sob_msg\n"); - } elsif ($authorsignoff == 5) { - WARN("FROM_SIGN_OFF_MISMATCH", - "From:/Signed-off-by: email subaddress mismatch: $sob_msg\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/scripts/cmake/llext_write_uuids.cmake b/scripts/cmake/llext_write_uuids.cmake new file mode 100644 index 000000000000..ad608c0e5e17 --- /dev/null +++ b/scripts/cmake/llext_write_uuids.cmake @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-3-Clause + +# Used by LLEXT modules to create a file with module UUIDs +file(STRINGS ${ZEPHYR_BINARY_DIR}/${MODULE}_llext/rimage_config.toml uuids REGEX "^[ \t]*uuid *=") + +set(UUIDS_LIST_FILE ${ZEPHYR_BINARY_DIR}/${MODULE}_llext/llext.uuid) +file(REMOVE ${UUIDS_LIST_FILE}) +foreach(line IN LISTS uuids) + # extract UUID value - drop the 'uuid = ' part of the assignment line + string(REGEX REPLACE "^[ \t]*uuid *= \"([0-9A-Fa-f\\-]*)\"" "\\1" uuid ${line}) + string(TOUPPER ${uuid} uuid) + file(APPEND ${UUIDS_LIST_FILE} "${uuid}\n") +endforeach() diff --git a/scripts/cmake/misc.cmake b/scripts/cmake/misc.cmake index 77ae05ee2754..647b69c8c478 100644 --- a/scripts/cmake/misc.cmake +++ b/scripts/cmake/misc.cmake @@ -58,6 +58,14 @@ macro(add_local_sources_ifdef condition target) endif() endmacro() +# helper macro used similarly as add_local_sources_ifdef +# Zephyr duplicate in sof/zephyr/CMakeLists.txt; keep in sync +macro(sof_list_append_ifdef feature_toggle list) + if(${${feature_toggle}}) + list(APPEND ${list} ${ARGN}) + endif() +endmacro() + # Adds sources to target like target_sources, but assumes that # paths are relative to subdirectory. # Works like: diff --git a/scripts/cmake/uuid-registry.cmake b/scripts/cmake/uuid-registry.cmake index 80b6310d1be8..0d3b287a7d62 100644 --- a/scripts/cmake/uuid-registry.cmake +++ b/scripts/cmake/uuid-registry.cmake @@ -5,8 +5,8 @@ # Simple target. FOUR (really 4.5, as LIBRARY builds use the same # CMakeLists.txt but differ significantly in how it executes) # different cmake environments into which it needs to build. -is_zephyr(zephyr_is) -if(zephyr_is) +is_zephyr(zephyr) +if(zephyr) set(TOPDIR ${sof_top_dir}) set(UUID_REG_H ${PROJECT_BINARY_DIR}/include/generated/uuid-registry.h) set(DEP_TARGET zephyr_interface) diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch deleted file mode 100644 index ab2bbb5402c0..000000000000 --- a/scripts/const_structs.checkpatch +++ /dev/null @@ -1,4 +0,0 @@ -comp_func_map -dma_ops -dai_driver -freq_table \ No newline at end of file diff --git a/scripts/docker-run.sh b/scripts/docker-run.sh index 96791d03a6e5..29383275152b 100755 --- a/scripts/docker-run.sh +++ b/scripts/docker-run.sh @@ -5,8 +5,6 @@ # Runs a given script in the docker container you can generate from the # docker_build directory. # Example: -# To build sof for tigerlake: -# ./scripts/docker-run.sh ./scripts/xtensa-build-all.sh tgl # To build topology: # ./scripts/docker-run.sh ./scripts/build-tools.sh diff --git a/scripts/docker_build/sof_builder/Dockerfile b/scripts/docker_build/sof_builder/Dockerfile index 90c082e4a173..843b5a448663 100644 --- a/scripts/docker_build/sof_builder/Dockerfile +++ b/scripts/docker_build/sof_builder/Dockerfile @@ -117,6 +117,7 @@ ENV PATH="/home/sof/work/xtensa-imx8ulp-elf/bin:${PATH}" ENV PATH="/home/sof/work/xtensa-mt8186-elf/bin:${PATH}" ENV PATH="/home/sof/work/xtensa-mt8195-elf/bin:${PATH}" ENV PATH="/home/sof/work/xtensa-mt8188-elf/bin:${PATH}" +ENV PATH="/home/sof/work/xtensa-mt8196-elf/bin:${PATH}" ARG NEWLIB_REPO=https://github.com/jcmvbkbc/newlib-xtensa.git RUN cd "$HOME" && \ diff --git a/scripts/docker_build/zephyr_lite/Dockerfile b/scripts/docker_build/zephyr_lite/Dockerfile new file mode 100644 index 000000000000..c6d6e28159c8 --- /dev/null +++ b/scripts/docker_build/zephyr_lite/Dockerfile @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2025 Intel Corporation. All rights reserved. + +# Use zephyr-build as base image +FROM ghcr.io/zephyrproject-rtos/zephyr-build:v0.29.0 as base + +# Remove additional toolchains. +# As this is not ideal solution there is a plan to build docker image without zephyr-build as the base +# and install only needed toolchains in the future. +USER root + +RUN rm -rvf /opt/toolchains/zephyr-sdk-1.0.0/hosttools/sysroots && \ + rm -rvf /opt/fvps && \ + cd /opt/toolchains/zephyr-sdk-1.0.0/gnu && \ + rm -rvf arc* \ + micro* \ + mips* \ + nios* \ + risc* \ + sparc* \ + x86* \ + xtensa-espressif* \ + xtensa-sample* \ + xtensa-dc233c* + +# Use ubuntu24.04 as base for zephyr-lite +FROM ubuntu:24.04 as zephyr-lite + +# Copy only required files from base image to zephyr-lite +# /opt for toolchains and sdk +# /usr for binaries and libs +# /home for libs installed in .local +# /etc/ssl for ssl certs for python packages +COPY --from=base /opt /opt +COPY --from=base /usr /usr +COPY --from=base /home /home +COPY --from=base /etc/ssl /etc/ssl + +USER root + +# Create a user if it doesn't already exist and grant them permission to /home/user. +# Add user to dialout and sudo group +RUN useradd -ms /bin/bash user && \ + chown -R user:user /home/user && \ + chown -R user:user /opt/python && \ + usermod -a -G dialout,sudo user + +USER user + +# Install cmake and jsonschema in venv +RUN /opt/python/venv/bin/pip install 'cmake>=3.21' jsonschema + +# Set zephyr env variables +ENV PATH="/opt/python/venv/bin/:$PATH" +ENV ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-1.0.0 +ENV ZSDK_VERSION=1.0.0 +ENV ZEPHYR_TOOLCHAIN_VARIANT=zephyr + +CMD ["/bin/bash", "-l"] diff --git a/scripts/fuzz.sh b/scripts/fuzz.sh index e29a0eed1623..b8b69b5fd1d2 100755 --- a/scripts/fuzz.sh +++ b/scripts/fuzz.sh @@ -189,7 +189,7 @@ setup() SOF_TOP=$(cd "$(dirname "$0")/.." && pwd) export SOF_TOP - export ZEPHYR_TOOLCHAIN_VARIANT=llvm + export ZEPHYR_TOOLCHAIN_VARIANT=host/llvm # Define ZEPHYR_BASE so this can be invoked even outside the west workspace. local WS_TOP diff --git a/scripts/gen-doc.sh b/scripts/gen-doc.sh index 489dce9cbb2c..7b36c0da96d6 100755 --- a/scripts/gen-doc.sh +++ b/scripts/gen-doc.sh @@ -6,8 +6,25 @@ # According to instructions: # https://thesofproject.github.io/latest/howtos/process/docbuild.html -# fail immediately on any errors -set -e +# this needs to run from the Zephyr python virtual environment +# so that the python packages are available (and more up to date than +# the system packages). + +# check if Zephyr environment is set up +if [ ! -z "$ZEPHYR_BASE" ]; then + VENV_DIR="$ZEPHYR_BASE/.venv" + echo "Using Zephyr environment at $ZEPHYR_BASE" +elif [ ! -z "$SOF_WORKSPACE" ]; then + VENV_DIR="$SOF_WORKSPACE/zephyr/.venv" + echo "Using SOF/Zephyr environment at $SOF_WORKSPACE" +else + # fallback to the zephyr default from the getting started guide + VENV_DIR="$HOME/zephyrproject/.venv" + echo "Using default Zephyr environment at $VENV_DIR" +fi + +# start the virtual environment +source ${VENV_DIR}/bin/activate function print_usage() { @@ -21,11 +38,11 @@ function print_usage() # make it runnable from any location # user shouldn't be confused from which dir this script has to be run SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) - # expected paths of repositories needed for documentation process SOF_REPO=$(dirname "$SCRIPT_DIR") DOCS_REPO="$(dirname "$SOF_REPO")/sof-docs" PUBLISH_REPO="$(dirname "$SOF_REPO")/thesofproject.github.io" +BUILD_DIR="$(dirname "$SOF_REPO")/build-sof-docs" # parse arguments DO_BUILD=false @@ -73,12 +90,10 @@ then fi fi -cd "$SOF_REPO/doc" - if "$DO_CLEAN" then echo "Cleaning $SOF_REPO" - cmake . + cd ${BUILD_DIR} make clean make doc-clean fi @@ -86,7 +101,8 @@ fi if "$DO_BUILD" then echo "Building $SOF_REPO" - cmake . + cd "$SOF_REPO/doc" + cmake -S . -B ${BUILD_DIR} make doc fi @@ -133,3 +149,6 @@ then cd "$DOCS_REPO" make publish fi + +# cleanup +deactivate diff --git a/scripts/gen-uuid-reg.py b/scripts/gen-uuid-reg.py index 3bdd7258cca9..316f35315544 100755 --- a/scripts/gen-uuid-reg.py +++ b/scripts/gen-uuid-reg.py @@ -31,6 +31,9 @@ def emit_uuid_rec(uu, sym): uuidinit = "{ " + ", ".join(wrecs) + ", { " + ", ".join(byts) + " } }" out_recs.append(f"#define _UUIDREG_{sym} {uuidinit}") + uuidstr = uu[:23] + '-' + uu[23:] + out_recs.append(f'#define UUIDREG_STR_{sym.upper()} "{uuidstr}"') + def main(): with open(sys.argv[1]) as f: for line in f.readlines(): @@ -50,6 +53,7 @@ def main(): all_uuids.add(uu) all_syms.add(sym) emit_uuid_rec(uu, sym) + print(f"Added UUID {uu} with symbol {sym}") with open(sys.argv[2], "w") as f: f.write(header) diff --git a/scripts/host-testbench.sh b/scripts/host-testbench.sh index 81119c960035..4780b78f6de6 100755 --- a/scripts/host-testbench.sh +++ b/scripts/host-testbench.sh @@ -119,4 +119,19 @@ test_component aria 24 24 48000 "$FullTest" # test with asrc test_component asrc 32 32 48000 "$FullTest" +# test with template component +test_component template_comp 32 32 48000 "$FullTest" + +# test with Dolby DAX with stub +test_component dolby-dax 32 32 48000 "$FullTest" + +# test with level_multiplier +test_component level_multiplier 32 32 48000 "$FullTest" + +# test with micsel +test_component micsel 32 32 48000 "$FullTest" + +# test with sound_dose +test_component sound_dose 32 32 48000 "$FullTest" + echo "All tests are done!" diff --git a/scripts/llext_link_helper.py b/scripts/llext_link_helper.py index c745b388cd03..f10777c9918f 100755 --- a/scripts/llext_link_helper.py +++ b/scripts/llext_link_helper.py @@ -26,6 +26,10 @@ def parse_args(): parser.add_argument('params', nargs='+', help='Additional linker parameters') parser.add_argument("-f", "--file", required=True, type=str, help='Object file name') + parser.add_argument("-c", "--copy", required=True, type=str, + help='Objcopy command') + parser.add_argument("-o", "--output", required=True, type=str, + help='Output file name') parser.add_argument("-t", "--text-addr", required=True, type=str, help='.text section address') parser.add_argument("-s", "--size-file", required=True, type=str, @@ -76,6 +80,7 @@ def main(): executable = [] writable = [] readonly = [] + readonly_dram = [] text_found = False @@ -101,10 +106,7 @@ def main(): if (s_flags & (SH_FLAGS.SHF_ALLOC | SH_FLAGS.SHF_EXECINSTR) == SH_FLAGS.SHF_ALLOC | SH_FLAGS.SHF_EXECINSTR and s_type == 'SHT_PROGBITS'): - # An executable section, currently only a single .text is supported. - # In general additional executable sections are possible, e.g. - # .init. In the future support for arbitrary such sections can be - # added, similar to writable and read-only data below. + # An executable section. if s_name == '.text': text_found = True text_addr = max_alignment(text_addr, 0x1000, s_alignment) @@ -123,7 +125,10 @@ def main(): if s_type == 'SHT_PROGBITS' and s_flags & SH_FLAGS.SHF_ALLOC: # .rodata or other read-only sections - readonly.append(section) + if s_name == '.coldrodata': + readonly_dram.append(section) + else: + readonly.append(section) if not text_found: raise RuntimeError('No .text section found in the object file') @@ -136,24 +141,45 @@ def main(): # run at arbitrary memory locations. One of the use-cases is running # parts of the module directly in DRAM - sacrificing performance but # saving scarce SRAM. We achieve this by placing non-performance - # critical functions in a .cold ELF section. When compiling and linking - # such functions, an additional .cold.literal section is automatically - # created. Note, that for some reason the compiler also marks that - # section as executable. + # critical functions in a .cold ELF section, read-only data in a + # .coldrodata ELF section, etc. When compiling and linking such + # functions, an additional .cold.literal section is automatically + # created. Note, that for some reason the compiler also marks .cold as + # executable. # This script links those sections at address 0. We could hard-code # section names, but so far we choose to only link .text the "original" - # way and all other executable sections we link at 0. - exe_addr = 0 + # way and all other executable sections we link at 0. For data sections + # we accept only the .coldrodata name for now. + + dram_addr = 0 + first_dram_text = None + first_dram_rodata = None for section in executable: s_alignment = section.header['sh_addralign'] s_name = section.name - exe_addr = align_up(exe_addr, s_alignment) + if not first_dram_text: + first_dram_text = s_name + + dram_addr = align_up(dram_addr, s_alignment) + + command.append(f'-Wl,--section-start={s_name}=0x{dram_addr:x}') - command.append(f'-Wl,--section-start={s_name}=0x{exe_addr:x}') + dram_addr += section.header['sh_size'] + + for section in readonly_dram: + s_alignment = section.header['sh_addralign'] + s_name = section.name - exe_addr += section.header['sh_size'] + if not first_dram_rodata: + first_dram_rodata = s_name + + dram_addr = align_up(dram_addr, s_alignment) + + command.append(f'-Wl,--section-start={s_name}=0x{dram_addr:x}') + + dram_addr += section.header['sh_size'] start_addr = align_up(text_addr + text_size, 0x1000) @@ -182,9 +208,20 @@ def main(): start_addr += section.header['sh_size'] + command.extend(['-o', f'{args.file}.tmp']) command.extend(args.params) subprocess.run(command) + copy_command = [args.copy] + + if first_dram_text: + copy_command.extend(['--set-section-alignment', f'{first_dram_text}=4096']) + if first_dram_rodata: + copy_command.extend(['--set-section-alignment', f'{first_dram_rodata}=4096']) + + copy_command.extend([f'{args.file}.tmp', f'{args.output}']) + subprocess.run(copy_command) + if __name__ == "__main__": main() diff --git a/scripts/rebuild-testbench.sh b/scripts/rebuild-testbench.sh index fee09fd243ae..996d16f45a8c 100755 --- a/scripts/rebuild-testbench.sh +++ b/scripts/rebuild-testbench.sh @@ -97,7 +97,7 @@ export_xtensa_setup() cat <<EOFSETUP > "$export_script" export XTENSA_TOOLS_ROOT=$XTENSA_TOOLS_ROOT export XTENSA_CORE=$XTENSA_CORE -XTENSA_PATH=$tools_bin +export XTENSA_PATH=$tools_bin EOFSETUP } diff --git a/scripts/sdk-create-module.py b/scripts/sdk-create-module.py new file mode 100755 index 000000000000..bc80db16dfe9 --- /dev/null +++ b/scripts/sdk-create-module.py @@ -0,0 +1,437 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-3-Clause +# +# Creates new module based on template module. + +import os +import sys +import shutil +import uuid +import re + +def process_directory(directory_path, old_text, new_text): + """ + Recursively walks through a directory to rename files and replace content. + This function processes files first, then directories, to allow for renaming + of the directories themselves after their contents are handled. + """ + # Walk through the directory tree + for dirpath, dirnames, filenames in os.walk(directory_path, topdown=False): + # --- Process Files --- + for filename in filenames: + original_filepath = os.path.join(dirpath, filename) + + # a) Replace content within files + # Only process C/H files for content replacement + if filename.endswith(('.c', '.h', '.cpp', '.hpp', '.txt', '.toml', 'Kconfig')): + replace_text_in_file(original_filepath, old_text, new_text) + if filename.endswith(('.c', '.h', '.cpp', '.hpp', '.txt', '.toml', 'Kconfig')): + replace_text_in_file(original_filepath, old_text.upper(), new_text.upper()) + if filename.endswith(('.c', '.h', '.cpp', '.hpp', '.txt', '.toml', 'Kconfig')): + replace_text_in_file(original_filepath, "template", new_text) + if filename.endswith(('.c', '.h', '.cpp', '.hpp', '.txt', '.toml', 'Kconfig')): + replace_text_in_file(original_filepath, "TEMPLATE", new_text.upper()) + + # b) Rename the file if its name contains the template text + if "template" in filename: + new_filename = filename.replace("template", new_text) + new_filepath = os.path.join(dirpath, new_filename) + print(f" -> Renaming file: '{original_filepath}' to '{new_filepath}'") + os.rename(original_filepath, new_filepath) + +def replace_text_in_file(filepath, old_text, new_text): + """ + Replaces all occurrences of old_text with new_text in a given file. + """ + try: + # Read the file content + with open(filepath, 'r', encoding='utf-8') as file: + content = file.read() + + # Perform the replacement + new_content = content.replace(old_text, new_text) + + # If content has changed, write it back + if new_content != content: + print(f" -> Updating content in: '{filepath}'") + with open(filepath, 'w', encoding='utf-8') as file: + file.write(new_content) + + except Exception as e: + print(f" -> [WARNING] Could not process file '{filepath}'. Reason: {e}") + +def insert_uuid_name(filepath: str, new_name: str): + """ + Inserts a newly generated UUID and a given name into a file, maintaining + alphabetical order by name. Ignores and preserves lines starting with '#'. + + Args: + filepath (str): The path to the file to be updated. + new_name (str): The name to associate with the new UUID. + """ + data_entries = [] + other_lines = [] # To store comments and blank lines + + # --- 1. Read existing entries and comments from the file --- + try: + with open(filepath, 'r', encoding='utf-8') as f: + for line in f: + stripped_line = line.strip() + # Check for comments or blank lines + if not stripped_line or stripped_line.startswith('#'): + other_lines.append(line) # Preserve the original line with newline + continue + + # It's a data line, so process it + # Split only on the first space to handle names that might contain spaces + parts = stripped_line.split(' ', 1) + if len(parts) == 2: + data_entries.append((parts[0], parts[1])) + except FileNotFoundError: + print(f"File '{filepath}' not found. A new file will be created.") + except Exception as e: + print(f"An error occurred while reading the file: {e}") + return + + # --- 2. Check if the name already exists in data entries --- + if any(name == new_name for _, name in data_entries): + print(f"Name '{new_name}' already exists in the file. No changes made.") + return + + # --- 3. Add the new entry to the data list --- + new_uuid = str(uuid.uuid4()) + + # We split the string from the right at the last hyphen and then join the parts. + parts = new_uuid.rsplit('-', 1) + custom_format_uuid = ''.join(parts) + + data_entries.append((custom_format_uuid, new_name)) + print(f"Generated new entry: {new_uuid} {new_name}") + + # --- 4. Sort the list of data entries by name (the second element of the tuple) --- + data_entries.sort(key=lambda item: item[1]) + + # --- 5. Write the comments and then the sorted data back to the file --- + try: + with open(filepath, 'w', encoding='utf-8') as f: + # Write all the comments and other non-data lines first + for line in other_lines: + f.write(line) + + # Write the sorted data entries + for entry_uuid, entry_name in data_entries: + f.write(f"{entry_uuid} {entry_name}\n") + print(f"Successfully updated '{filepath}'.") + except Exception as e: + print(f"An error occurred while writing to the file: {e}") + +# Define the markers for the managed block in the CMakeLists.txt file. +CMAKE_START_MARKER = " # directories and files included conditionally (alphabetical order)" +CMAKE_END_MARKER = " # end of directories and files included conditionally (alphabetical order)" + +def insert_cmake_rule(filepath: str, kconfig_option: str, subdir_name: str): + """ + Reads a CMakeLists.txt file, adds a new rule, and writes it back. + + Args: + filepath (str): Path to the CMakeLists.txt file. + kconfig_option (str): The Kconfig flag to check. + subdir_name (str): The subdirectory to add. + """ + if not os.path.exists(filepath): + print(f"[ERROR] File not found at: '{filepath}'") + return + + # --- 1. Read the entire file content --- + with open(filepath, 'r', encoding='utf-8') as f: + lines = f.readlines() + + # --- 2. Find the start and end of the managed block --- + try: + start_index = lines.index(CMAKE_START_MARKER + '\n') + end_index = lines.index(CMAKE_END_MARKER + '\n') + except ValueError: + print(f"[ERROR] Could not find the required marker blocks in '{filepath}'.") + print(f"Please ensure the file contains both '{CMAKE_START_MARKER}' and '{CMAKE_END_MARKER}'.") + return + + # --- 3. Extract the lines before, during, and after the block --- + lines_before = lines[:start_index + 1] + block_lines = lines[start_index + 1 : end_index] + lines_after = lines[end_index:] + + # --- 4. Parse the existing rules within the block --- + rules = [] + # Regex to find: if(CONFIG_NAME) ... add_subdirectory(subdir) ... endif() + # This is robust against extra whitespace and blank lines. + block_content = "".join(block_lines) + pattern = re.compile( + r"if\s*\((?P<kconfig>CONFIG_[A-Z0-9_]+)\)\s*" + r"add_subdirectory\s*\((?P<subdir>[a-zA-Z0-9_]+)\)\s*" + r"endif\(\)", + re.DOTALL + ) + + for match in pattern.finditer(block_content): + rules.append(match.groupdict()) + + # --- 5. Check if the rule already exists --- + if any(rule['kconfig'] == kconfig_option for rule in rules): + print(f"[INFO] Rule for '{kconfig_option}' already exists. No changes made.") + return + + # --- 6. Add the new rule and sort alphabetically --- + rules.append({'kconfig': kconfig_option, 'subdir': subdir_name}) + rules.sort(key=lambda r: r['kconfig']) + print(f"Adding rule for '{kconfig_option}' -> '{subdir_name}' and re-sorting.") + + # --- 7. Rebuild the block content from the sorted rules --- + new_block_lines = [] + for i, rule in enumerate(rules): + new_block_lines.append(f"\tif({rule['kconfig']})\n") + new_block_lines.append(f"\t\tadd_subdirectory({rule['subdir']})\n") + new_block_lines.append("\tendif()\n") + + # --- 8. Assemble the new file content and write it back --- + new_content = "".join(lines_before + new_block_lines + lines_after) + with open(filepath, 'w', encoding='utf-8') as f: + f.write(new_content) + + print(f"Successfully updated '{filepath}'.") + +# Define the markers for the managed block in the Kconfig file. +KCONFIG_START_MARKER = "# --- Kconfig Sources (alphabetical order) ---" +KCONFIG_END_MARKER = "# --- End Kconfig Sources (alphabetical order) ---" + +def insert_kconfig_source(filepath: str, source_path: str): + """ + Reads a Kconfig file, adds a new rsource rule, and writes it back. + + Args: + filepath (str): Path to the Kconfig file. + source_path (str): The path to the Kconfig file to be sourced. + """ + if not os.path.exists(filepath): + print(f"[ERROR] File not found at: '{filepath}'") + return + + # --- 1. Read the entire file content --- + try: + with open(filepath, 'r', encoding='utf-8') as f: + lines = f.readlines() + except Exception as e: + print(f"[ERROR] Could not read file: {e}") + return + + # --- 2. Find the start and end of the managed block --- + try: + start_index = lines.index(KCONFIG_START_MARKER + '\n') + end_index = lines.index(KCONFIG_END_MARKER + '\n') + except ValueError: + print(f"[ERROR] Could not find the required marker blocks in '{filepath}'.") + print(f"Please ensure the file contains both '{KCONFIG_START_MARKER}' and '{KCONFIG_END_MARKER}'.") + return + + # --- 3. Extract the lines before, during, and after the block --- + lines_before = lines[:start_index + 1] + block_lines = lines[start_index + 1 : end_index] + lines_after = lines[end_index:] + + # --- 4. Parse the existing rsource rules within the block --- + source_paths = [] + # Regex to find: rsource "path/to/file" + pattern = re.compile(r'rsource\s+"(?P<path>.*?)"') + + for line in block_lines: + match = pattern.search(line) + if match: + source_paths.append(match.group('path')) + + # --- 5. Check if the source path already exists --- + if source_path in source_paths: + print(f"[INFO] Source path '{source_path}' already exists. No changes made.") + return + + # --- 6. Add the new path and sort alphabetically --- + source_paths.append(source_path) + source_paths.sort() + print(f"Adding source '{source_path}' and re-sorting.") + + # --- 7. Rebuild the block content from the sorted paths --- + new_block_lines = [] + for path in source_paths: + new_block_lines.append(f'rsource "{path}"\n') + + # --- 8. Assemble the new file content and write it back --- + new_content = "".join(lines_before + new_block_lines + lines_after) + with open(filepath, 'w', encoding='utf-8') as f: + f.write(new_content) + + print(f"Successfully updated '{filepath}'.") + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) + +# Define the markers for the managed block in the header file. +HEADER_START_MARKER = "/* Start of modules in alphabetical order */" +HEADER_END_MARKER = "/* End of modules in alphabetical order */" + +def insert_c_declaration(header_path: str, name: str) -> bool: + """ + Inserts a C function declaration alphabetically into a header file between + start and end markers. + + The function declaration format is: + "void sys_comp_module_${name}_interface_init(void);" + + Args: + header_path (str): The full path to the C header file. + name (str): The component name to be inserted into the function declaration. + HEADER_START_MARKER (str): The string marking the beginning of the declaration block. + HEADER_END_MARKER (str): The string marking the end of the declaration block. + + Returns: + bool: True if the file was modified or already up-to-date, False on error. + """ + new_declaration = f"void sys_comp_module_{name}_interface_init(void);" + line_to_insert = new_declaration + "\n" + + # --- 1. Read existing lines from the header file --- + try: + with open(header_path, 'r') as f: + lines = f.readlines() + except FileNotFoundError: + print(f"Error: Header file not found at '{header_path}'", file=sys.stderr) + return False + except IOError as e: + print(f"Error: Could not read file '{header_path}': {e}", file=sys.stderr) + return False + + # --- 2. Find start and end markers --- + start_index = -1 + end_index = -1 + for i, line in enumerate(lines): + if HEADER_START_MARKER in line: + start_index = i + elif HEADER_END_MARKER in line: + end_index = i + break # Assume end marker always comes after the start marker + + if start_index == -1 or end_index == -1: + print(f"Error: Start ('{HEADER_START_MARKER}') or end ('{HEADER_END_MARKER}') marker not found.", file=sys.stderr) + return False + if end_index <= start_index: + print(f"Error: End marker appears before start marker.", file=sys.stderr) + return False + + # --- 3. Check if the declaration already exists within the block --- + # Isolate the block of lines where declarations are allowed + declaration_block = lines[start_index + 1 : end_index] + if line_to_insert in declaration_block: + print(f"Declaration for '{name}' already exists within the block. No changes made.") + return True + + # --- 4. Find the correct alphabetical insertion point within the block --- + relative_insert_index = len(declaration_block) + for i, line in enumerate(declaration_block): + # Compare with the stripped content of each line in the block + if line.strip() > new_declaration: + relative_insert_index = i + break + + # Calculate the final insertion index relative to the whole file + final_insert_index = start_index + 1 + relative_insert_index + + # --- 5. Insert the new line into the main list of lines --- + lines.insert(final_insert_index, line_to_insert) + print(f"Inserting declaration for '{name}' at line {final_insert_index + 1}.") + + # --- 6. Write the modified list back to the file --- + try: + with open(header_path, 'w') as f: + f.writelines(lines) + except IOError as e: + print(f"Error: Could not write to file '{header_path}': {e}", file=sys.stderr) + return False + + return True + +def main(): + """ + Main function to drive the script logic. + """ + print("--- SOF SDK New Module Creator ---") + + # Argument Validation --- + if len(sys.argv) == 2 and sys.argv[1] in ['-h', '--help']: + print("Usage: sdk-create-module.py <new_module_name>") + sys.exit(0) + elif len(sys.argv) != 2: + print("\n[ERROR] Invalid number of arguments.") + print("Usage: sdk-create-module.py <new_module_name>") + sys.exit(1) + + # Configuration --- paths are with respect to script dir + modules_root = SCRIPT_DIR + "/../src/audio" + template_name = "template" + new_module_name = sys.argv[1] + uuid_file = SCRIPT_DIR + "/../uuid-registry.txt" + cmake_file = SCRIPT_DIR + "/../src/audio/CMakeLists.txt" + kconfig_file = SCRIPT_DIR + "/../src/audio/Kconfig" + component_file = SCRIPT_DIR + "/../src/include/sof/audio/component.h" + + template_dir = os.path.join(modules_root, template_name) + new_module_dir = os.path.join(modules_root, new_module_name) + + print(f"\nConfiguration:") + print(f" - Modules Root: '{modules_root}'") + print(f" - Template Name: '{template_name}'") + print(f" - New Module Name:'{new_module_name}'") + print(f" - UUID file: '{uuid_file}'") + print(f" - Cmake file: '{cmake_file}'") + print(f" - Kconfig file: '{kconfig_file}'") + print(f" - Component file: '{component_file}'") + + # Check for Pre-existing Directories --- + if not os.path.isdir(template_dir): + print(f"\n[ERROR] Template directory not found at: '{template_dir}'") + sys.exit(1) + + if os.path.exists(new_module_dir): + print(f"\n[ERROR] A directory with the new module name already exists: '{new_module_dir}'") + sys.exit(1) + + # Copy Template Directory --- + try: + print(f"\n[1/6] Copying template directory...") + shutil.copytree(template_dir, new_module_dir) + print(f" -> Successfully copied to '{new_module_dir}'") + except OSError as e: + print(f"\n[ERROR] Could not copy directory. Reason: {e}") + sys.exit(1) + + # Rename Files and Replace Content --- + # We walk through the newly created directory. + print(f"\n[2/6] Renaming files and replacing content...") + process_directory(new_module_dir, template_name, new_module_name) + insert_c_declaration(component_file, new_module_name) + + # Generate UUID for the new module --- + print("\n[3/6] Generating UUID for module...") + insert_uuid_name(uuid_file, new_module_name) + + # Add CMake rule for new module --- + print("\n[4/6] Module creation process finished successfully!") + kconfig_option = f"CONFIG_COMP_{new_module_name.upper()}" + print(f" -> Adding CMake rule for '{kconfig_option}'") + insert_cmake_rule(cmake_file, kconfig_option, new_module_name) + + # Add Kconfig rsource for new module + print("\n[5/6] Module creation process finished successfully!") + insert_kconfig_source(kconfig_file, f"{new_module_name}/Kconfig") + + print("\n[6/6] Module creation process finished successfully!") + print("--- Done ---") + +if __name__ == "__main__": + main() + diff --git a/scripts/set_xtensa_params.sh b/scripts/set_xtensa_params.sh index 622e30ddfbe0..a3932818edc1 100644 --- a/scripts/set_xtensa_params.sh +++ b/scripts/set_xtensa_params.sh @@ -9,7 +9,6 @@ # These variables are currently used in/by: # -# - xtensa-build-all.sh (XTOS) # - script/rebuild-testbench.sh # - before Zephyr's `twister` or `west build` # @@ -67,6 +66,11 @@ case "$platform" in XTENSA_CORE="ace30_LX7HiFi4_PIF" TOOLCHAIN_VER="RI-2022.10-linux" ;; + nvl) + PLATFORM="$platform" + XTENSA_CORE="ace4px_HiFi5MMU_PIF_nlib" + TOOLCHAIN_VER="RI-2022.10-linux" + ;; # NXP imx8) @@ -135,7 +139,23 @@ case "$platform" in HOST="xtensa-mt8195-elf" TOOLCHAIN_VER="RI-2019.1-linux" ;; - + mt8196) + XTENSA_CORE="HiFi5_MPU_lock_2023_11" + HOST="xtensa-mt8196-elf" + TOOLCHAIN_VER="RI-2023.11-linux" + ;; + mt8365) + PLATFORM="mt8365" + XTENSA_CORE="hifi4_Aquila_E2_PROD" + HOST="xtensa-mt8365-elf" + TOOLCHAIN_VER="RG-2018.9-linux" + ;; + qemu_xtensa | qemu_xtensa_mmu) + PLATFORM="$1" + XTENSA_CORE="" + HOST="xtensa-zephyr-elf" + TOOLCHAIN_VER="" + ;; *) >&2 printf 'Unknown xtensa platform=%s\n' "$platform" return 1 @@ -144,7 +164,7 @@ esac # Pre-zephyr "XTOS" build, testbench,... case "$platform" in - mtl|lnl|ptl|acp_7_0) + mtl|lnl|ptl|acp_7_0|mt8196|nvl) SOF_CC_BASE='clang';; *) SOF_CC_BASE='xcc';; @@ -152,6 +172,8 @@ esac # For Zephyr unit tests case "$platform" in + qemu_xtensa | qemu_xtensa_mmu) + ZEPHYR_TOOLCHAIN_VARIANT='zephyr';; imx8*|mtl|lnl) ZEPHYR_TOOLCHAIN_VARIANT='xt-clang';; *) # The previous, main case/esac already caught invalid input. diff --git a/scripts/sof-crash-decode.py b/scripts/sof-crash-decode.py new file mode 100755 index 000000000000..2db0222f620d --- /dev/null +++ b/scripts/sof-crash-decode.py @@ -0,0 +1,571 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2026 Intel Corporation. All rights reserved. +""" +decode_crash.py - Zephyr Xtensa Crash Dump Decoder + +Parses a Zephyr crash dump, extracts CPU registers/backtraces, and correlates them +to source code files and function names using the `objdump` output of the ELF file. + +Dependencies: + - python3 + - binutils for your target architecture (e.g. xtensa-zephyr-elf-objdump) + - Optional: `xclip`, `xsel`, or `wl-paste` (for --clipboard support on Linux) + +Usage Examples: + # 1. Provide the ELF and read crash from stdin + cat crash.txt | ./sof-crash-decode.py --elf zephyr.elf + + # 2. Automatically locate ELF/objdump from a Zephyr build directory, read crash from file + ./sof-crash-decode.py --build-dir build-qemu_xtensa/ --dump crash.txt + + # 3. Read directly from the system clipboard + ./sof-crash-decode.py --build-dir build-qemu_xtensa/ --clipboard + + # 4. Pipe a live trace to the decoder + tail -f log.txt | ./sof-crash-decode.py --build-dir build_dir/ + +""" + +import sys +import re +import argparse +import subprocess +import bisect +import os +import json +import shlex +import ast +import operator + + +# Largest shift we accept: linker addresses/sizes fit well under 2**64, so a +# bigger shift is nonsensical and only serves to build a huge integer. +_MAX_SHIFT = 64 +# Reject any literal or intermediate result beyond 64 bits, and cap the source +# length, so a crafted expression can't build a huge integer or stall the parse. +_MAX_VALUE = 1 << 64 +_MAX_EXPR_LEN = 256 + + +def _trunc_div(a, b): + # truncate toward zero (C semantics); Python's // floors instead + q = abs(a) // abs(b) + return -q if (a < 0) != (b < 0) else q + + +def _lshift(a, b): + # reject absurd shift counts to avoid building a massive integer + if b < 0 or b > _MAX_SHIFT: + raise ValueError("shift count out of range") + return a << b + + +# Operators allowed when evaluating arithmetic from an untrusted linker script. +_SAFE_OPS = { + ast.Add: operator.add, ast.Sub: operator.sub, + ast.Mult: operator.mul, ast.Div: _trunc_div, + ast.Mod: operator.mod, ast.LShift: _lshift, + ast.RShift: operator.rshift, ast.BitOr: operator.or_, + ast.BitAnd: operator.and_, ast.BitXor: operator.xor, + ast.USub: operator.neg, ast.UAdd: operator.pos, +} + + +def safe_eval_int(expr): + """Evaluate an integer arithmetic expression without executing code. + + A crash bundle's linker.cmd is attacker-controllable, so its MEMORY + expressions must never be passed to eval(). Only integer literals and + basic arithmetic operators are accepted, and values are bounded to 64 + bits. Anything unsupported or out of range raises an exception + (ValueError, or ZeroDivisionError on '/ 0'); the caller treats any such + failure as 'skip this entry'. + """ + def _check(value): + if abs(value) >= _MAX_VALUE: + raise ValueError("value out of range") + return value + + def _eval(node): + if isinstance(node, ast.Expression): + return _eval(node.body) + if isinstance(node, ast.Constant): + # reject bool (a subclass of int) and everything non-integer + if type(node.value) is int: + return _check(node.value) + raise ValueError("non-integer constant") + if isinstance(node, ast.BinOp) and type(node.op) in _SAFE_OPS: + return _check(_SAFE_OPS[type(node.op)](_eval(node.left), + _eval(node.right))) + if isinstance(node, ast.UnaryOp) and type(node.op) in _SAFE_OPS: + return _check(_SAFE_OPS[type(node.op)](_eval(node.operand))) + raise ValueError("unsupported expression") + + if len(expr) > _MAX_EXPR_LEN: + raise ValueError("expression too long") + return _eval(ast.parse(expr, mode='eval')) + +XTENSA_EXCCAUSE = { + 0: "No Error (or IllegalInstruction)", + 1: "Syscall", + 2: "InstructionFetchError", + 3: "LoadStoreError", + 4: "Level1Interrupt", + 5: "Alloca", + 6: "IntegerDivideByZero", + 8: "Privileged", + 9: "LoadStoreAlignment", + 12: "InstrPIFDataError", + 13: "LoadStorePIFDataError", + 14: "InstrPIFAddrError", + 15: "LoadStorePIFAddrError", + 16: "InstTLBMiss", + 17: "InstTLBMultiHit", + 18: "InstFetchPrivilege", + 20: "InstFetchProhibited", + 24: "LoadStoreTLBMiss", + 25: "LoadStoreTLBMultiHit", + 26: "LoadStorePrivilege", + 28: "LoadStoreProhibited", + 32: "Coprocessor0Disabled", + 33: "Coprocessor1Disabled", + 34: "Coprocessor2Disabled", + 35: "Coprocessor3Disabled", + 36: "Coprocessor4Disabled", + 37: "Coprocessor5Disabled", + 38: "Coprocessor6Disabled", + 39: "Coprocessor7Disabled", +} + +def parse_crash_log(content): + + registers = {} + backtraces = [] + + # Detect QEMU format + if re.search(r'\bPC=[0-9a-fA-F]+\b', content): + reg_pattern = re.compile(r'\b([A-Z0-9]+)=([0-9a-fA-F]+)\b') + for match in reg_pattern.finditer(content): + reg = match.group(1) + val = int(match.group(2), 16) + + if reg == 'EXCVADDR': + reg = 'VADDR' + elif re.match(r'^A\d{2}$', reg): + reg = f"A{int(reg[1:])}" + elif re.match(r'^AR\d{2}$', reg): + reg = f"AR{int(reg[2:])}" + + if re.match(r'^(PC|PR|SP|A\d+|AR\d+|EXCCAUSE|VADDR|LBEG|LEND|SAR|EPC\d+|EPS\d+|PS)$', reg): + registers[reg] = val + else: + # Standard format + # regex for registers: we want standalone pairs like PC 0x123 or A0 0x123 or EXCCAUSE 9 + reg_pattern = re.compile(r'\b([A-Z0-9]+)\s+(0x[0-9a-fA-F]+|\d+|(?:nil))\b') + for match in reg_pattern.finditer(content): + reg = match.group(1) + val_str = match.group(2) + if val_str == "(nil)": + val = 0 + elif val_str.startswith("0x"): + val = int(val_str, 16) + else: + val = int(val_str) + + # Keep only known registers or likely candidates + if re.match(r'^(PC|PR|SP|A\d+|AR\d+|EXCCAUSE|VADDR|LBEG|LEND|SAR|EPC\d+|EPS\d+|PS)$', reg): + registers[reg] = val + + # Backtrace parsing + bt_idx = content.find("Backtrace:") + if bt_idx != -1: + bt_line = content[bt_idx:content.find('\n', bt_idx)] + bt_pattern = re.compile(r'(0x[0-9a-fA-F]+):(0x[0-9a-fA-F]+)') + for match in bt_pattern.finditer(bt_line): + pc = int(match.group(1), 16) + sp = int(match.group(2), 16) + backtraces.append((pc, sp)) + + return registers, backtraces, content + +def get_objdump_output(elf_path, objdump_cmd): + print(f"Running {objdump_cmd} -d -S -l \"{elf_path}\" ...") + try: + # Check if objdump exists + result = subprocess.run([objdump_cmd, "-d", "-S", "-l", elf_path], + capture_output=True, text=True, check=True) + return result.stdout + except FileNotFoundError: + print(f"Error: {objdump_cmd} not found. Please provide the correct objdump command using --objdump.") + sys.exit(1) + except subprocess.CalledProcessError as e: + print(f"Error running objdump: {e}") + sys.exit(1) + +def parse_linker_cmd(filepath): + regions = [] + try: + with open(filepath, 'r') as f: + content = f.read() + m_block = re.search(r'MEMORY\s*\{(.*?)\}', content, re.DOTALL) + if m_block: + for line in m_block.group(1).splitlines(): + line = line.strip() + if not line or ':' not in line: continue + name, rest = line.split(':', 1) + name = name.strip() + m_org = re.search(r'org\s*=\s*(.*?),', rest) + m_len = re.search(r'len\s*=\s*(.*)', rest) + if m_org and m_len: + org_expr = m_org.group(1).strip() + len_expr = m_len.group(1).strip() + try: + org_val = safe_eval_int(org_expr) + len_val = safe_eval_int(len_expr) + # Ignore debug regions + if not (name.startswith('.debug') or name.startswith('.stab')): + regions.append({'name': name, 'start': org_val, 'end': org_val + len_val}) + except Exception: + pass + except Exception as e: + print(f"Warning: Failed to parse {filepath}: {e}") + return regions + +def parse_zephyr_stat(filepath): + sections = [] + try: + with open(filepath, 'r') as f: + for line in f: + m = re.match(r'^\s*\[\s*\d+\]\s+(\S+)\s+[A-Z0-9]+\s+([0-9a-fA-F]+)\s+[0-9a-fA-F]+\s+([0-9a-fA-F]+)', line) + if m: + name = m.group(1) + start = int(m.group(2), 16) + size = int(m.group(3), 16) + # Ignore debug sections + if size > 0 and not (name.startswith('.debug') or name.startswith('.stab')): + sections.append({'name': name, 'start': start, 'end': start + size}) + except Exception as e: + print(f"Warning: Failed to parse {filepath}: {e}") + return sections + +def parse_zephyr_dts(filepath): + regions = [] + try: + with open(filepath, 'r') as f: + lines = f.read().splitlines() + + current_node_path = [] + for line in lines: + line = line.strip() + # Simple node match: node_name: some_name@addr { + m_node = re.match(r'^(?:[a-zA-Z0-9_]+:\s*)?([a-zA-Z0-9_\-]+(?:@[0-9a-fA-Fx]+)?)\s*\{', line) + if m_node: + node_name = m_node.group(1) + current_node_path.append(node_name) + continue + + if line == "};": + if current_node_path: + current_node_path.pop() + continue + + # match reg = < ... > + m_reg = re.match(r'^reg\s*=\s*<\s*(.*?)\s*>;', line) + if m_reg and current_node_path: + reg_vals = m_reg.group(1).split() + if len(reg_vals) >= 2: + try: + addr = int(reg_vals[0], 16) if reg_vals[0].startswith('0x') else int(reg_vals[0]) + size = int(reg_vals[1], 16) if reg_vals[1].startswith('0x') else int(reg_vals[1]) + if size > 0: + node_name = current_node_path[-1] + regions.append({'name': node_name, 'start': addr, 'end': addr + size}) + except ValueError: + pass + except Exception as e: + print(f"Warning: Failed to parse {filepath}: {e}") + return regions + +def build_address_map(objdump_text): + current_func = "<unknown>" + current_context = [] + last_was_asm = False + address_map = {} + + func_re = re.compile(r'^([0-9a-fA-F]+)\s+<([^>]+)>:$') + asm_re = re.compile(r'^\s*([0-9a-fA-F]+):\s+(.*)$') + + for line in objdump_text.splitlines(): + line = line.rstrip() + if not line or line.startswith("Disassembly of section"): + continue + + m_func = func_re.match(line) + if m_func: + current_func = m_func.group(2) + current_context = [] + last_was_asm = False + continue + + m_asm = asm_re.match(line) + if m_asm: + addr = int(m_asm.group(1), 16) + address_map[addr] = { + 'func': current_func, + 'context': list(current_context), + 'asm': m_asm.group(2) + } + last_was_asm = True + continue + + if last_was_asm: + current_context = [] + last_was_asm = False + current_context.append(line) + + return address_map + +def find_closest_instruction(addr, address_map, sorted_addresses): + if addr in address_map: + return addr, address_map[addr] + + # Extract lower 29 bits for physical address mappings on Xtensa + physical = addr & 0x1FFFFFFF + if physical in address_map: + return physical, address_map[physical] + + idx = bisect.bisect_right(sorted_addresses, physical) + if idx > 0: + closest = sorted_addresses[idx-1] + # Return if within 16 bytes (typical small instruction offset) + if physical - closest < 16: + return closest, address_map[closest] + + return addr, None + +def decode_ps_bits(val): + intlevel = val & 0xF + excm = (val >> 4) & 1 + um = (val >> 5) & 1 + ring = (val >> 6) & 3 + owb = (val >> 8) & 0xF + callinc = (val >> 16) & 3 + woe = (val >> 18) & 1 + + flags = [] + flags.append(f"INTLEVEL:{intlevel}") + if excm: flags.append("EXCM") + flags.append(f"UM:{um}") + flags.append(f"RING:{ring}") + flags.append(f"OWB:{owb}") + flags.append(f"CALLINC:{callinc}") + flags.append(f"WOE:{woe}") + + return " | ".join(flags) + +def main(): + # Set default color explicitly at start + print("\x1b[0m", end='', flush=True) + + parser = argparse.ArgumentParser(description="Decode Xtensa/Zephyr crash dump using objdump.") + parser.add_argument("--elf", required=False, help="Path to the ELF file. Overridden if --build-dir is provided.") + parser.add_argument("--build-dir", required=False, help="Path to the Zephyr build directory.") + parser.add_argument("--dump", default="-", help="Path to the crash dump file. Default is '-' for stdin.") + parser.add_argument("--clipboard", action="store_true", help="Read crash dump from the clipboard instead of file/stdin.") + parser.add_argument("--objdump", default="xtensa-sof-zephyr-elf-objdump", help="Objdump command to use. e.g. xtensa-zephyr-elf-objdump") + args = parser.parse_args() + + objdump_cmd = args.objdump + + if args.build_dir: + # Resolve zephyr.elf + default_elf = os.path.join(args.build_dir, "zephyr", "zephyr.elf") + if os.path.isfile(default_elf): + args.elf = default_elf + + # Try to find objdump from compile_commands + cc_path = os.path.join(args.build_dir, "compile_commands.json") + if not os.path.isfile(cc_path): + cc_path = os.path.join(args.build_dir, "compile_commands.txt") + + if os.path.isfile(cc_path): + try: + with open(cc_path, 'r') as f: + cc_data = json.load(f) + if cc_data and len(cc_data) > 0 and 'command' in cc_data[0]: + # The command might contain arguments, we extract the first token + cmd_tokens = shlex.split(cc_data[0]['command']) + compiler_path = cmd_tokens[0] + # Replace gcc, g++, clang, etc. with objdump + if compiler_path.endswith('gcc') or compiler_path.endswith('g++') or compiler_path.endswith('cc'): + new_cmd = re.sub(r'(g?cc|g\+\+)$', 'objdump', compiler_path) + if os.path.isfile(new_cmd) and os.access(new_cmd, os.X_OK): + objdump_cmd = new_cmd + except Exception as e: + print(f"Warning: Failed to parse {cc_path} to deduce objdump: {e}") + + linker_regions = [] + stat_sections = [] + dts_regions = [] + if args.build_dir: + linker_cmd_path = os.path.join(args.build_dir, "zephyr", "linker.cmd") + zephyr_stat_path = os.path.join(args.build_dir, "zephyr", "zephyr.stat") + zephyr_dts_path = os.path.join(args.build_dir, "zephyr", "zephyr.dts") + + if os.path.isfile(linker_cmd_path): + linker_regions = parse_linker_cmd(linker_cmd_path) + if os.path.isfile(zephyr_stat_path): + stat_sections = parse_zephyr_stat(zephyr_stat_path) + if os.path.isfile(zephyr_dts_path): + dts_regions = parse_zephyr_dts(zephyr_dts_path) + + if not args.elf: + print("Error: --elf or --build-dir must be provided.") + sys.exit(1) + + if not os.path.isfile(args.elf): + print(f"Cannot find ELF file: {args.elf}") + sys.exit(1) + + if args.clipboard: + try: + dump_content = subprocess.check_output(['xclip', '-o', '-selection', 'clipboard'], text=True) + except (subprocess.CalledProcessError, FileNotFoundError): + try: + dump_content = subprocess.check_output(['xsel', '--clipboard', '--output'], text=True) + except (subprocess.CalledProcessError, FileNotFoundError): + try: + dump_content = subprocess.check_output(['wl-paste'], text=True) + except (subprocess.CalledProcessError, FileNotFoundError): + print("Error: Could not read from clipboard. Make sure xclip, xsel, or wl-paste is installed.") + sys.exit(1) + elif args.dump == "-": + dump_content = sys.stdin.read() + else: + if not os.path.isfile(args.dump): + print(f"Cannot find Dump file: {args.dump}") + sys.exit(1) + with open(args.dump, 'r') as f: + dump_content = f.read() + + registers, backtraces, raw_content = parse_crash_log(dump_content) + + print(f"Found {len(registers)} registers and {len(backtraces)} backtrace elements in crash dump.") + + print("Parsing objdump (this may take a few seconds)...") + + # Actually, many systems might use standard xtensa-zephyr-elf-objdump + # We can try to dynamically choose if the user just provided a prefix or left default + + # Try running the objdump to ensure it exists + import shutil + if not os.path.isfile(objdump_cmd) and not shutil.which(objdump_cmd) and "zephyr" in objdump_cmd: + # try without sof if user has a different one + alt_cmds = [ + "xtensa-zephyr-elf-objdump", + "xtensa-intel-elf-objdump", + "zephyr-sdk/xtensa-zephyr-elf-objdump", + "objdump" + ] + for alt in alt_cmds: + if shutil.which(alt): + print(f"Warning: {objdump_cmd} not found, falling back to {alt}") + objdump_cmd = alt + break + + objdump_text = get_objdump_output(args.elf, objdump_cmd) + address_map = build_address_map(objdump_text) + sorted_addresses = sorted(address_map.keys()) + + print("\n--- Summary ---") + print("PS Register Legend:") + print(" INTLEVEL : Interrupt Level EXCM : Exception Mode") + print(" UM : User Mode (1=User) RING : Privilege Ring") + print(" OWB : Old Window Base WOE : Window Overflow Enable") + print(" CALLINC : Call Increment") + print() + + def print_decoded(name, val): + if val == 0: + print(f"{name:5}: 0x00000000 -> (nil)") + return + + addr, info = find_closest_instruction(val, address_map, sorted_addresses) + if info: + print(f"{name:5}: 0x{val:08x} -> <{info['func']}>") + for ctx in info['context']: + ctx_strip = ctx.strip() + if re.match(r'^[^ \t:]+:\d+', ctx_strip): + print(f" \x1b[35m{ctx_strip}\x1b[0m") + else: + print(f" \x1b[93m{ctx_strip}\x1b[0m") + print(f" \x1b[93m{addr:08x}: {info['asm']}\x1b[0m") + print() + else: + dts_str = "" + for d in dts_regions: + if d['start'] <= val < d['end']: + dts_str = f", DT: {d['name']}" + break + region_str = "" + for r in linker_regions: + if r['start'] <= val < r['end']: + region_str = f", Region: {r['name']}" + break + sec_str = "" + for s in stat_sections: + if s['start'] <= val < s['end']: + sec_str = f", Section: {s['name']}" + break + + if dts_str or region_str or sec_str: + print(f"{name:5}: 0x{val:08x} -> <unknown{dts_str}{region_str}{sec_str}>") + else: + print(f"{name:5}: 0x{val:08x} -> <unknown/no code section>") + + # Prioritize specific registers + for reg in ['PC', 'EXCCAUSE', 'VADDR', 'SP', 'PS']: + if reg in registers: + if reg == 'EXCCAUSE': + cause_code = registers[reg] + cause_str = XTENSA_EXCCAUSE.get(cause_code, "Unknown/Unassigned") + print(f"EXCCAUSE: {cause_code} ({cause_str})") + elif reg == 'VADDR': + print(f"{reg:5}: 0x{registers[reg]:08x}") + elif reg == 'PS': + print(f"{reg:5}: 0x{registers[reg]:08x} -> [{decode_ps_bits(registers[reg])}]\n") + else: + print_decoded(reg, registers[reg]) + + for i in range(1, 8): + reg = f"EPC{i}" + if reg in registers: + print_decoded(reg, registers[reg]) + + print() + for i in range(2, 8): + reg = f"EPS{i}" + if reg in registers: + print(f"{reg:5}: 0x{registers[reg]:08x} -> [{decode_ps_bits(registers[reg])}]") + + print("\n--- Physical Windowed Registers (A) ---") + for i in range(16): + reg = f"A{i}" + if reg in registers: + print_decoded(reg, registers[reg]) + + print("\n--- Saved Stack Registers (AR) ---") + for i in range(64): + reg = f"AR{i}" + if reg in registers: + print_decoded(reg, registers[reg]) + + print("\n--- Backtrace Decode ---") + # Backtraces: + for i, (pc, sp) in enumerate(backtraces): + print(f"Frame {i}: SP = 0x{sp:08x}") + print_decoded("PC", pc) + +if __name__ == '__main__': + main() diff --git a/scripts/sof-post-commit-hook.sh b/scripts/sof-post-commit-hook.sh deleted file mode 100755 index 171ab58a2471..000000000000 --- a/scripts/sof-post-commit-hook.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2018 Intel Corporation. All rights reserved. - -set -e -# TODO: reduce duplication with scripts/sof-pre-commit-hook.sh -# and with .github/workflows/ with either some .conf file -# or some wrapper script -exec git show --format=email HEAD | - ./scripts/checkpatch.pl --no-tree --strict --codespell diff --git a/scripts/sof-pre-commit-hook.sh b/scripts/sof-pre-commit-hook.sh deleted file mode 100755 index cd754f6db661..000000000000 --- a/scripts/sof-pre-commit-hook.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2018 Intel Corporation. All rights reserved. - -exec git diff --cached | scripts/checkpatch.pl --no-tree --codespell --no-signoff -q - - diff --git a/scripts/sof-qemu-run.py b/scripts/sof-qemu-run.py new file mode 100755 index 000000000000..fc985e254d51 --- /dev/null +++ b/scripts/sof-qemu-run.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2026 Intel Corporation. All rights reserved. +""" +sof-qemu-run.py - Automated QEMU test runner and crash analyzer + +This script runs `west -v build -t run` for Zephyr, monitors the output, and +waits for 2 seconds after the last log event. If a Zephyr/QEMU crash occurs, +it decodes it using `sof-crash-decode.py`. If no crash occurred, it enters +the QEMU monitor (Ctrl-A c), issues `info registers`, and passes the output +to the crash decoder. +""" + +import sys +import pexpect +import subprocess +import argparse +import os + +import re + +# ANSI Color Codes +COLOR_RED = "\x1b[31;1m" +COLOR_YELLOW = "\x1b[33;1m" +COLOR_RESET = "\x1b[0m" + +def colorize_line(line): + """Colorize significant Zephyr log items.""" + if "<err>" in line or "[ERR]" in line or "Fatal fault" in line or "Oops" in line: + return COLOR_RED + line + COLOR_RESET + elif "<wrn>" in line or "[WRN]" in line: + return COLOR_YELLOW + line + COLOR_RESET + return line + +def check_for_crash(output): + """ + Check if the collected output indicates a crash. + Look for known Zephyr/Xtensa oops or exceptions, or QEMU crash register dumps. + """ + crash_keywords = [ + "Fatal fault", + "Oops", + "ZEPHYR FATAL ERROR", + "Exception", + "PC=", # QEMU PC output format + "EXCCAUSE=", + "Backtrace:" + ] + for keyword in crash_keywords: + if keyword in output: + return True + return False + +def run_sof_crash_decode(build_dir, dump_content): + """ + Invokes sof-crash-decode.py and feeds it the crash dump via stdin. + """ + # Find sof-crash-decode.py in the same directory as this script, or fallback to relative path + decoder_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "sof-crash-decode.py") + if not os.path.isfile(decoder_script): + decoder_script = "sof-crash-decode.py" + + print("\n====================================") + print("Running sof-crash-decode.py Analysis") + print("====================================\n") + + cmd = [sys.executable, decoder_script, "--build-dir", build_dir] + + try: + proc = subprocess.Popen(cmd, stdin=subprocess.PIPE) + proc.communicate(input=dump_content.encode('utf-8')) + except Exception as e: + print(f"Failed to run sof-crash-decode.py: {e}") + +def main(): + parser = argparse.ArgumentParser(description="Run QEMU via west and automatically decode crashes.") + parser.add_argument("--build-dir", default="build", help="Path to the build directory containing zephyr.elf, linker.cmd, etc. Defaults to 'build'.") + parser.add_argument("--log-file", default="qemu-run.log", help="Path to save the QEMU output log. Defaults to 'qemu-run.log'.") + args = parser.parse_args() + + # Make absolute path just in case + build_dir = os.path.abspath(args.build_dir) + + print(f"Starting QEMU test runner. Monitoring for crashes (Build Dir: {args.build_dir})...") + + # We will use pexpect to spawn the west command to get PTY features + import shutil + west_path = shutil.which("west") + if not west_path: + print("[sof-qemu-run] Error: 'west' command not found in PATH.") + print("Please ensure you have sourced the Zephyr environment (e.g., source zephyr-env.sh).") + sys.exit(1) + + child = pexpect.spawn(west_path, ["-v", "build", "-t", "run"], encoding='utf-8') + + # We will accumulate output to check for crashes + full_output = "" + + with open(args.log_file, "w") as log_file: + try: + # Loop reading output until EOF or a timeout occurs + qemu_started = False + while True: + try: + # Read character by character or line by line + # Pexpect's readline() doesn't consistently trigger timeout on idle + # We can use read_nonblocking and an explicit exceptTIMEOUT + index = child.expect([r'\r\n', pexpect.TIMEOUT, pexpect.EOF], timeout=2) + if index == 0: + line = child.before + '\n' + # Strip ANSI escape codes from output to write raw text to log file + clean_line = re.sub(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])', '', line) + log_file.write(clean_line) + log_file.flush() + + colored_line = colorize_line(line) + sys.stdout.write(colored_line) + sys.stdout.flush() + + full_output += line + if not qemu_started and ("Booting Zephyr OS" in line or "To exit from QEMU" in line or "qemu-system-" in line): + qemu_started = True + elif index == 1: # TIMEOUT + if qemu_started or check_for_crash(full_output): + print("\n\n[sof-qemu-run] 2 seconds passed since last log event. Checking status...") + break + else: + # Still building or loading, continue waiting + pass + elif index == 2: # EOF + print("\n\n[sof-qemu-run] QEMU process terminated.") + break + + except pexpect.TIMEOUT: + if qemu_started or check_for_crash(full_output): + print("\n\n[sof-qemu-run] 2 seconds passed since last log event. Checking status...") + break + else: + # Still building or loading, continue waiting + pass + except pexpect.EOF: + print("\n\n[sof-qemu-run] QEMU process terminated.") + break + + except KeyboardInterrupt: + print("\n[sof-qemu-run] Interrupted by user.") + # Proceed with what we have + + crashed = check_for_crash(full_output) + + if crashed: + print("\n[sof-qemu-run] Detected crash signature in standard output!") + # Stop QEMU if it's still running + if child.isalive(): + child.sendline("\x01x") # Ctrl-A x to quit qemu + child.close(force=True) + + run_sof_crash_decode(build_dir, full_output) + else: + print("\n[sof-qemu-run] No crash detected. Interacting with QEMU Monitor to grab registers...") + + # We need to send Ctrl-A c to enter the monitor + if child.isalive(): + child.send("\x01c") # Ctrl-A c + try: + # Wait for (qemu) prompt + child.expect(r"\(qemu\)", timeout=5) + # Send "info registers" + child.sendline("info registers") + # Wait for the next prompt + child.expect(r"\(qemu\)", timeout=5) + + info_regs_output = child.before + print("\n[sof-qemu-run] Successfully extracted registers from QEMU monitor.\n") + + # Quit qemu safely + child.sendline("quit") + child.expect(pexpect.EOF, timeout=2) + child.close() + + # Run the decoder on the intercepted register output + run_sof_crash_decode(build_dir, info_regs_output) + except pexpect.TIMEOUT: + print("\n[sof-qemu-run] Timed out waiting for QEMU monitor. Is it running?") + child.close(force=True) + except pexpect.EOF: + print("\n[sof-qemu-run] QEMU terminated before we could run monitor commands.") + else: + print("\n[sof-qemu-run] Process is no longer alive, cannot extract registers.") + +if __name__ == "__main__": + main() diff --git a/scripts/sof-qemu-run.sh b/scripts/sof-qemu-run.sh new file mode 100755 index 000000000000..e1ece1dd5125 --- /dev/null +++ b/scripts/sof-qemu-run.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2026 Intel Corporation. All rights reserved. + +# Define the build directory from the first argument (or default) +BUILD_DIR="${1:-build}" + +# Find and source the zephyr environment script, typically via the sof-venv wrapper +# or directly if running in a known zephyrproject layout. +# We will use the existing helper sof-venv.sh to get the right environment. + +# Get the directory of this script +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SOF_WORKSPACE="$(dirname "$(dirname "$SCRIPT_DIR")")" + +# Use the SOF workspace to locate the virtual environment +VENV_DIR="$SOF_WORKSPACE/.venv" +echo "Using SOF environment at $SOF_WORKSPACE" + +# start the virtual environment +source ${VENV_DIR}/bin/activate + +# Execute the QEMU runner from within the correct build directory +cd "${BUILD_DIR}" || exit 1 + +# Finally run the python script which will now correctly inherit 'west' from the sourced environment. +python3 "${SCRIPT_DIR}/sof-qemu-run.py" --build-dir "${BUILD_DIR}" + diff --git a/scripts/sof-rebuild-processing-comp-blobs.sh b/scripts/sof-rebuild-processing-comp-blobs.sh index 26410c811259..617669c10646 100755 --- a/scripts/sof-rebuild-processing-comp-blobs.sh +++ b/scripts/sof-rebuild-processing-comp-blobs.sh @@ -10,10 +10,24 @@ if [ -z "${SOF_WORKSPACE}" ]; then fi if ! command -v octave &> /dev/null; then - echo "Error: this scrip needs GNU Octave, see https://octave.org/" + echo "Error: this script needs GNU Octave, see https://octave.org/" exit 1 fi +"$SOF_WORKSPACE"/sof/scripts/build-tools.sh -c + +if ! command -v sof-ctl &> /dev/null; then + echo "Error: The sof-ctl utility is not found from path for executables. It is needed" + echo " to retrieve SOF ABI header It can be added with e.g. symlink to user's binaries:" + echo " ln -s $SOF_WORKSPACE/sof/tools/build_tools/ctl/sof-ctl $HOME/bin/sof-ctl" + exit 1 +fi + +cmp --quiet "$(which sof-ctl)" "$SOF_WORKSPACE"/sof/tools/build_tools/ctl/sof-ctl || { + echo "Error: The sof-ctl in user's path is not the same as sof-ctl build from tools." + exit 1 +} + OCTAVE="octave --quiet --no-window-system" cd "$SOF_WORKSPACE"/sof/src/audio/aria/tune; $OCTAVE sof_aria_blobs.m cd "$SOF_WORKSPACE"/sof/src/audio/crossover/tune; $OCTAVE sof_example_crossover.m @@ -25,4 +39,6 @@ cd "$SOF_WORKSPACE"/sof/src/audio/eq_iir/tune; $OCTAVE sof_example_iir_bandsplit cd "$SOF_WORKSPACE"/sof/src/audio/eq_iir/tune; $OCTAVE sof_example_spk_eq.m cd "$SOF_WORKSPACE"/sof/src/audio/multiband_drc/tune; $OCTAVE sof_example_multiband_drc.m cd "$SOF_WORKSPACE"/sof/src/audio/tdfb/tune; ./sof_example_all.sh +cd "$SOF_WORKSPACE"/sof/src/audio/selector/tune; $OCTAVE ./sof_selector_blobs.m cd "$SOF_WORKSPACE"/sof/tools/tune/mfcc; $OCTAVE setup_mfcc.m +cd "$SOF_WORKSPACE"/sof/src/audio/level_multiplier/tune; $OCTAVE sof_level_multiplier_blobs.m diff --git a/scripts/sof-testbench-build-profile.sh b/scripts/sof-testbench-build-profile.sh index ca92f42a6f0d..73a880a353b9 100755 --- a/scripts/sof-testbench-build-profile.sh +++ b/scripts/sof-testbench-build-profile.sh @@ -11,7 +11,9 @@ usage() { echo } -MODULES_S32="asrc dcblock drc drc_multiband eqfir eqiir gain src tdfb" +MODULES_S32_44K_48K="asrc src" +MODULES_S32="dcblock drc drc_multiband dolby-dax eqfir eqiir gain level_multiplier micsel \ + sound_dose stft_process_1536_240_ template_comp tdfb" MODULES_S24="aria" if [ -z "${SOF_WORKSPACE}" ]; then @@ -46,28 +48,36 @@ shift $((OPTIND-1)) SCRIPTS=$SOF_WORKSPACE/sof/scripts mkdir -p "$PDIR" "$SCRIPTS"/rebuild-testbench.sh -p "$PLATFORM" +HELPER="$SCRIPTS"/sof-testbench-helper.sh echo "Profiler reports are stored to $PDIR" # Run sof-hda-generic.tplg playback echo "Profiling sof-hda-generic.tplg ..." -sof-testbench-helper.sh -x -t production/sof-hda-generic.tplg -n 1,2 \ - -p "$PDIR/profile-$PLATFORM-generic.txt" > "$PDIR/log-$PLATFORM-generic.txt" +$HELPER -x -t production/sof-hda-generic.tplg -n 1,2 \ + -p "$PDIR/profile-$PLATFORM-generic.txt" > "$PDIR/log-$PLATFORM-generic.txt" # Run sof-hda-benchmark-generic.tplg playback echo "Profiling sof-hda-benchmark-generic.tplg ..." -sof-testbench-helper.sh -x -t development/sof-hda-benchmark-generic.tplg -n 1,2,3 \ - -p "$PDIR/profile-$PLATFORM-benchmark.txt" > "$PDIR/log-$PLATFORM-benchmark.txt" +$HELPER -x -t development/sof-hda-benchmark-generic.tplg -n 1,2,3 \ + -p "$PDIR/profile-$PLATFORM-benchmark.txt" > "$PDIR/log-$PLATFORM-benchmark.txt" # Profile modules +for mod in $MODULES_S32_44K_48K +do + echo "Profiling $mod ..." + $HELPER -r 44100 -x -m "$mod" \ + -p "$PDIR/profile-$PLATFORM-$mod.txt" > "$PDIR/log-$PLATFORM-$mod.txt" +done + for mod in $MODULES_S32 do echo "Profiling $mod ..." - sof-testbench-helper.sh -x -m "$mod" -p "$PDIR/profile-$PLATFORM-$mod.txt" > "$PDIR/log-$PLATFORM-$mod.txt" + $HELPER -x -m "$mod" -p "$PDIR/profile-$PLATFORM-$mod.txt" > "$PDIR/log-$PLATFORM-$mod.txt" done for mod in $MODULES_S24 do echo "Profiling $mod ..." - sof-testbench-helper.sh -b 24 -x -m "$mod" -p "$PDIR/profile-$PLATFORM-$mod.txt" > "$PDIR/log-$PLATFORM-$mod.txt" + $HELPER -b 24 -x -m "$mod" -p "$PDIR/profile-$PLATFORM-$mod.txt" > "$PDIR/log-$PLATFORM-$mod.txt" done diff --git a/scripts/sof-testbench-helper.sh b/scripts/sof-testbench-helper.sh index 5de7d8d43a7b..ea7a6590ee67 100755 --- a/scripts/sof-testbench-helper.sh +++ b/scripts/sof-testbench-helper.sh @@ -15,7 +15,8 @@ usage() { echo " -n <pipelines>, default 1,2" echo " -o <output wav>, default none" echo " -p <profiling result text>, use with -x, default none" - echo " -r <rate>, default 48000" + echo " -r <rate>, input rate, default 48000" + echo " -R <rate>, output rate, default 48000" echo " -t <force topology>, default none, e.g. production/sof-hda-generic.tplg" echo " -v runs with valgrind, not available with -x" echo " -x runs testbench with xt-run simulator" @@ -55,7 +56,7 @@ PROFILE=false TPLG0= VALGRIND= -while getopts "b:c:hi:km:n:o:p:r:t:vx" opt; do +while getopts "b:c:hi:km:n:o:p:r:R:t:vx" opt; do case "${opt}" in b) BITS=${OPTARG} @@ -89,6 +90,8 @@ while getopts "b:c:hi:km:n:o:p:r:t:vx" opt; do ;; r) RATE_IN=${OPTARG} + ;; + R) RATE_OUT=${OPTARG} ;; t) @@ -147,10 +150,10 @@ if [[ "$XTRUN" == true ]]; then echo " input: $INFILE1, output: $OUTFILE1, trace: $TRACEFILE, profile: $PROFILETXT" source "$XTB4_SETUP" if [[ $PROFILE == true ]]; then - "$XTENSA_PATH"/xt-run --profile="$PROFILEOUT" "$XTB4" $OPTS 2> "$TRACEFILE" + "$XTENSA_PATH"/xt-run --mem_model --profile="$PROFILEOUT" "$XTB4" $OPTS 2> "$TRACEFILE" "$XTENSA_PATH"/xt-gprof "$XTB4" "$PROFILEOUT" > "$PROFILETXT" else - "$XTENSA_PATH"/xt-run "$XTB4" $OPTS 2> "$TRACEFILE" + "$XTENSA_PATH"/xt-run --mem_model "$XTB4" $OPTS 2> "$TRACEFILE" fi else if [ ! -x "$TB4" ]; then diff --git a/scripts/tensorflow-clone.sh b/scripts/tensorflow-clone.sh new file mode 100755 index 000000000000..d3f67d0a835e --- /dev/null +++ b/scripts/tensorflow-clone.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2025 Intel Corporation. All rights reserved. + +# fail immediately on any errors +set -e + +# Array of TFLM Git repository URLs. Add or remove repositories as needed. +declare -a REPOS=( + "https://github.com/thesofproject/nnlib-hifi4" + "https://github.com/tensorflow/tflite-micro" + "https://github.com/thesofproject/flatbuffers" + "https://github.com/google/gemmlowp" + "https://github.com/google/ruy" +) + +# Commit ID to check for (optional). If specified, the script will update +# the repository if this commit ID is not found. Leave empty to skip. +declare -a COMMIT_ID=( + "cdedfb1a1044eb774915de21b63a1b6aa93276f6" + "e86d97b6237f88ab5925c0b41e3e3589a1560d86" + "f5acabf4e1a3fcba024081bb1871a2ed59aa1c28" + "719139ce755a0f31cbf1c37f7f98adcc7fc9f425" + "d37128311b445e758136b8602d1bbd2a755e115d" +) + +# Directory where repositories will be cloned/updated. +BASE_DIR="$HOME/work/sof" # Or any other desired location + +# Function to check if a commit ID exists in a repository +check_commit() { + local repo_dir="$1" + local commit_id="$2" + + if [ -z "$commit_id" ]; then + return 0 # Skip check if no commit ID is provided + fi + + if ! git -C "$repo_dir" rev-parse --quiet --verify "$commit_id" >/dev/null 2>&1; then + return 1 # Commit ID not found + else + return 0 # Commit ID found + fi +} + + +# Function to update the repository +update_repo() { + local repo_dir="$1" + echo "Updating repository: $repo_dir" + git -C "$repo_dir" fetch --all + git -C "$repo_dir" pull +} + +# Main script logic +mkdir -p "$BASE_DIR" + +for ((i = 0; i < ${#REPOS[@]}; i++)); do + echo "Counter: $i, Value: ${REPOS[i]}" + repo_url=${REPOS[i]} + + repo_name=$(basename "$repo_url" .git) # Extract repo name + repo_dir="$BASE_DIR/$repo_name" + + if [ ! -d "$repo_dir" ]; then + echo "Cloning repository: $repo_url" + git clone "$repo_url" "$repo_dir" || { echo "git clone failed for $repo_url"; exit 1; } + elif ! check_commit "$repo_dir" "${COMMIT_ID[i]}"; then + update_repo "$repo_dir" + else + echo "Repository $repo_name is up to date." + fi +done + +echo "All repositories processed." diff --git a/scripts/test-repro-build.sh b/scripts/test-repro-build.sh index a6d0f7dad643..3a3cea4660fd 100755 --- a/scripts/test-repro-build.sh +++ b/scripts/test-repro-build.sh @@ -190,4 +190,6 @@ main() printf "\n\n ---- FAIL: differences found between %s/b0/ and b1/ --- \n\n" "$(pwd)" } +test -x "${SOF_TOP}"/scripts/xtensa-build-all.sh || exit 0 + main "$@" diff --git a/scripts/vscode-task.sh b/scripts/vscode-task.sh new file mode 100755 index 000000000000..b5a3ba1cecd5 --- /dev/null +++ b/scripts/vscode-task.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2025 Intel Corporation. All rights reserved. + +# Simple helper script for vscode task support. +# Current vscode tasks have difficulty executing multiple commands. + +# check if Zephyr environment is set up +if [ ! -z "$ZEPHYR_BASE" ]; then + VENV_DIR="$ZEPHYR_BASE/.venv" + echo "Using Zephyr environment at $ZEPHYR_BASE" +elif [ ! -z "$SOF_WORKSPACE" ]; then + VENV_DIR="$SOF_WORKSPACE/zephyr/.venv" + echo "Using SOF/Zephyr environment at $SOF_WORKSPACE" +else + # fallback to the zephyr default from the getting started guide + VENV_DIR="$HOME/zephyrproject/.venv" + echo "Using default Zephyr environment at $VENV_DIR" +fi + +# start the virtual environment +source ${VENV_DIR}/bin/activate + +# The vscode workspace is the parent directory of the SOF Firmware directory +# we need to cd into sof to run the zephyr build script +cd sof + +# run the zephyr script +./scripts/xtensa-build-zephyr.py "$@" + +# cleanup +deactivate diff --git a/scripts/xtensa-build-all.sh b/scripts/xtensa-build-all.sh deleted file mode 100755 index a7d83c9fbd3e..000000000000 --- a/scripts/xtensa-build-all.sh +++ /dev/null @@ -1,315 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2018 Intel Corporation. All rights reserved. - -# stop on most errors -set -e - -# Platforms built and tested by default in CI using the `-a` option. -# They must have a toolchain available in the latest Docker image. -DEFAULT_PLATFORMS=( - imx8m - rn rmb vangogh - mt8186 mt8195 mt8188 -) - -# Work in progress can be added to this "staging area" without breaking -# the -a option for everyone. -SUPPORTED_PLATFORMS=( "${DEFAULT_PLATFORMS[@]}" ) - -# Container work is in progress -SUPPORTED_PLATFORMS+=( acp_6_3 acp_7_0 ) - -BUILD_ROM=no -BUILD_DEBUG=no -BUILD_FORCE_UP=no -BUILD_JOBS=$(nproc --all) -BUILD_VERBOSE= -PLATFORMS=() - -SOF_TOP=$(cd "$(dirname "$0")/.." && pwd) - -# As CMake forks one compiler process for each source file, the XTensa -# compiler spends much more time idle waiting for the license server -# over the network than actually using CPU or disk. A factor 3 has been -# found optimal for 16 nproc 25ms away from the server; your mileage may -# vary. -# -# The entire, purely local gcc build is so fast (~ 1s) that observing -# any difference between -j nproc and -j nproc*N is practically -# impossible so let's not waste RAM when building with gcc. - -if [ -n "$XTENSA_TOOLS_ROOT" ]; then - BUILD_JOBS=$((BUILD_JOBS * 3)) -fi - - -die() -{ - >&2 printf '%s ERROR: ' "$0" - # We want die() to be usable exactly like printf - # shellcheck disable=SC2059 - >&2 printf "$@" - exit 1 -} - -print_usage() -{ - cat <<EOF -Re-configures and re-builds SOF using the corresponding compiler and the -<platform>_defconfig file. Implements and saves the manual configuration -described in -https://thesofproject.github.io/latest/developer_guides/firmware/cmake.html - -usage: $0 [options] platform(s) - - -r Build rom if available (gcc only) - -a Build all default platforms fully supported by the latest Docker image and CI - -u Force CONFIG_MULTICORE=n - -d Enable debug build - -c Interactive menuconfig - -o arg, copies src/arch/xtensa/configs/override/<arg>.config - to the build directory after invoking CMake and before Make. - -k Configure rimage to use a non-default \${RIMAGE_PRIVATE_KEY} - DEPRECATED: use the more flexible \${PRIVATE_KEY_OPTION} below. - -v Verbose Makefile log - -i Optional IPC_VERSION: can be set to IPC3, IPC4 or an empty string. - If set to "IPCx" then CONFIG_IPC_MAJOR_x will be set. If set to - IPC4 then a platform specific overlay may be used. - -j n Set number of make build jobs. Jobs=#cores when no flag. - Infinite when not specified. - -m path to MEU tool. CMake disables rimage signing which produces a - .uns[igned] file signed by MEU. For a non-default key use the - PRIVATE_KEY_OPTION, see below. - -To use a non-default key you must define the right CMake parameter in the -following environment variable: - - PRIVATE_KEY_OPTION='-DMEU_PRIVATE_KEY=path/to/key' $0 -m /path/to/meu ... -or: - PRIVATE_KEY_OPTION='-DRIMAGE_PRIVATE_KEY=path/to/key' $0 ... - -This script supports XtensaTools but only when installed in a specific -directory structure, example: - -myXtensa/ -└── install/ - ├── builds/ - │   ├── RD-2012.5-linux/ - │   │   └── Intel_HiFiEP/ - │   └── RG-2017.8-linux/ - │   ├── LX4_langwell_audio_17_8/ - │   └── X4H3I16w2D48w3a_2017_8/ - └── tools/ - ├── RD-2012.5-linux/ - │   └── XtensaTools/ - └── RG-2017.8-linux/ - └── XtensaTools/ - -$ XTENSA_TOOLS_ROOT=/path/to/myXtensa $0 ... - -Known platforms: ${SUPPORTED_PLATFORMS[*]} - -EOF -} - -# parse the args -while getopts "rudi:j:ckvao:m:" OPTION; do - case "$OPTION" in - r) BUILD_ROM=yes ;; - u) BUILD_FORCE_UP=yes ;; - d) BUILD_DEBUG=yes ;; - i) IPC_VERSION=$OPTARG ;; - j) BUILD_JOBS=$OPTARG ;; - c) MAKE_MENUCONFIG=yes ;; - k) USE_PRIVATE_KEY=yes ;; - o) OVERRIDE_CONFIG=$OPTARG ;; - v) BUILD_VERBOSE='VERBOSE=1' ;; - a) PLATFORMS=("${DEFAULT_PLATFORMS[@]}") ;; - m) MEU_TOOL_PATH=$OPTARG ;; - *) print_usage; exit 1 ;; - esac -done -shift $((OPTIND-1)) - -#default signing tool -SIGNING_TOOL=RIMAGE - -if [ -n "${OVERRIDE_CONFIG}" ] -then - OVERRIDE_CONFIG="${SOF_TOP}/src/arch/xtensa/configs/override/$OVERRIDE_CONFIG.config" - [ -f "${OVERRIDE_CONFIG}" ] || die 'Invalid override config file %s\n' "${OVERRIDE_CONFIG}" -fi - -if [ -n "${MEU_TOOL_PATH}" ] -then - [ -d "${MEU_TOOL_PATH}" ] || die 'Invalid MEU TOOL PATH %s\n' "${MEU_TOOL_PATH}" - MEU_PATH_OPTION=-DMEU_PATH="${MEU_TOOL_PATH}" - SIGNING_TOOL=MEU -fi - -# parse platform args -for arg in "$@"; do - platform=none - for i in "${SUPPORTED_PLATFORMS[@]}"; do - if [ x"$i" = x"$arg" ]; then - PLATFORMS=("${PLATFORMS[@]}" "$i") - platform=$i - shift || true - break - fi - done - if [ "$platform" == "none" ]; then - echo "Error: Unknown platform specified: $arg" - echo "Known platforms are: ${SUPPORTED_PLATFORMS[*]}" - exit 1 - fi -done - -# check target platform(s) have been passed in -if [ ${#PLATFORMS[@]} -eq 0 ]; -then - echo "Error: No platform specified. Known platforms: " \ - "${SUPPORTED_PLATFORMS[*]}" - print_usage - exit 1 -fi - -if [ "x$USE_PRIVATE_KEY" == "xyes" ] -then - >&2 printf \ - 'WARNING: -k and RIMAGE_PRIVATE_KEY are deprecated, see usage.\n' - if [ -z ${RIMAGE_PRIVATE_KEY+x} ] - then - echo "Error: No variable specified for RIMAGE_PRIVATE_KEY" - exit 1 - fi - PRIVATE_KEY_OPTION="-DRIMAGE_PRIVATE_KEY=${RIMAGE_PRIVATE_KEY}" -fi - -OLDPATH=$PATH -CURDIR="$(pwd)" - -# build platforms -for platform in "${PLATFORMS[@]}" -do - - printf '\n ------\n %s\n ------\n' "$platform" - - HAVE_ROM='no' - DEFCONFIG_PATCH='' - PLATFORM_PRIVATE_KEY='' - - source "${SOF_TOP}"/scripts/set_xtensa_params.sh "$platform" || - die 'set_xtensa_params.sh failed' - - test -z "${PRIVATE_KEY_OPTION}" || PLATFORM_PRIVATE_KEY="${PRIVATE_KEY_OPTION}" - - if [ -n "$XTENSA_TOOLS_ROOT" ] - then - XTENSA_TOOLS_DIR="$XTENSA_TOOLS_ROOT/install/tools/$TOOLCHAIN_VER" - XTENSA_BUILDS_DIR="$XTENSA_TOOLS_ROOT/install/builds/$TOOLCHAIN_VER" - - [ -d "$XTENSA_TOOLS_DIR" ] || { - >&2 printf 'ERROR: %s\t is not a directory\n' "$XTENSA_TOOLS_DIR" - exit 1 - } - fi - - # CMake uses ROOT_DIR for includes and libraries a bit like - # --sysroot would. - ROOT="$SOF_TOP/../xtensa-root/$HOST" - - if [ -n "$XTENSA_TOOLS_ROOT" ] - then - TOOLCHAIN=xt - ROOT="$XTENSA_BUILDS_DIR/$XTENSA_CORE/xtensa-elf" - # CMake cannot set (evil) build-time environment variables at configure time: -# https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#how-can-i-get-or-set-environment-variables - export XTENSA_SYSTEM=$XTENSA_BUILDS_DIR/$XTENSA_CORE/config - printf 'XTENSA_SYSTEM=%s\n' "${XTENSA_SYSTEM}" - PATH=$XTENSA_TOOLS_DIR/XtensaTools/bin:$OLDPATH - build_dir_suffix='xcc' - else - # Override SOF_CC_BASE from set_xtensa_params.sh - SOF_CC_BASE='gcc' - TOOLCHAIN=$HOST - PATH=$SOF_TOP/../$HOST/bin:$OLDPATH - build_dir_suffix='gcc' - DEFCONFIG_PATCH="" - fi - - BUILD_DIR=build_${platform}_${build_dir_suffix} - printf "Build in %s\n" "$BUILD_DIR" - - # only delete binary related to this build - rm -fr "$BUILD_DIR" - mkdir "$BUILD_DIR" - cd "$BUILD_DIR" - - printf 'PATH=%s\n' "$PATH" - ( set -x # log the main commands and their parameters - cmake -DTOOLCHAIN="$TOOLCHAIN" \ - -DSOF_CC_BASE="$SOF_CC_BASE" \ - -DROOT_DIR="$ROOT" \ - -DMEU_OPENSSL="${MEU_OPENSSL}" \ - "${MEU_PATH_OPTION}" \ - "${PLATFORM_PRIVATE_KEY}" \ - -DINIT_CONFIG=${PLATFORM}${DEFCONFIG_PATCH}_defconfig \ - -DEXTRA_CFLAGS="${EXTRA_CFLAGS}" \ - "$SOF_TOP" - ) - - if [ -n "$OVERRIDE_CONFIG" ] - then - cp "$OVERRIDE_CONFIG" override.config - fi - - if [[ "x$MAKE_MENUCONFIG" == "xyes" ]] - then - cmake --build . -- menuconfig - fi - - case "$IPC_VERSION" in - '') ;; - IPC3) - echo 'CONFIG_IPC_MAJOR_3=y' >> override.config - ;; - IPC4) - test -z "$IPC4_CONFIG_OVERLAY" || - cat "${SOF_TOP}/src/arch/xtensa/configs/override/$IPC4_CONFIG_OVERLAY.config" \ - >> override.config - echo 'CONFIG_IPC_MAJOR_4=y' >> override.config - ;; - *) die "Invalid -i '%s' argument\n" "$IPC_VERSION" ;; - esac - - if [[ "x$BUILD_DEBUG" == "xyes" ]] - then - echo "CONFIG_DEBUG=y" >> override.config - fi - - if [[ "x$BUILD_ROM" == "xyes" && "x$HAVE_ROM" == "xyes" ]] - then - echo "CONFIG_BUILD_VM_ROM=y" >> override.config - fi - - if [ "x$BUILD_FORCE_UP" == "xyes" ] - then - echo "Force building UP(xtensa)..." - echo "CONFIG_MULTICORE=n" >> override.config - fi - - if [ -e override.config ] - then - cmake --build . -- overrideconfig - fi - - cmake --build . -- bin -j "${BUILD_JOBS}" ${BUILD_VERBOSE} - - cd "$CURDIR" -done # for platform in ... - -# list all the images -ls -l build_*/*.ri build_*/src/arch/xtensa/rom*.bin || true -ls -l build_*/sof diff --git a/scripts/xtensa-build-zephyr.py b/scripts/xtensa-build-zephyr.py index 0b9ce18b2fb0..a3f6581999b9 100755 --- a/scripts/xtensa-build-zephyr.py +++ b/scripts/xtensa-build-zephyr.py @@ -40,6 +40,7 @@ import dataclasses import concurrent.futures as concurrent import tarfile +import re from west import configuration as west_config @@ -91,6 +92,12 @@ class PlatformConfig: # These cannot be built by everyone out of the box yet. # For instance: there's no open-source toolchain available for them yet. extra_platform_configs = { + "wcl-sim" : PlatformConfig( + "intel", "intel_adsp/ace30/wcl/sim", + f"RI-2022.10{xtensa_tools_version_postfix}", + "ace30_LX7HiFi4_PIF", + ipc4 = True + ), "ptl-sim" : PlatformConfig( "intel", "intel_adsp/ace30/ptl/sim", f"RI-2022.10{xtensa_tools_version_postfix}", @@ -104,6 +111,19 @@ class PlatformConfig: "rmb_LX7_HiFi5_PROD", RIMAGE_KEY = "key param ignored by acp_6_0" ), + "acp_7_0" : PlatformConfig( + "amd", "acp_7_0_adsp/acp_7_0", + f"RI-2023.11{xtensa_tools_version_postfix}", + "ACP_7_0_HiFi5_NNE_PROD", + RIMAGE_KEY = "key param ignored by acp_7_0" + ), + "acp_7_x" : PlatformConfig( + "amd", "acp_7_x_adsp/acp_7_x", + f"RI-2022.9{xtensa_tools_version_postfix}", + "ACP73x_HiFi5_NNE_PROD", + RIMAGE_KEY = "key param ignored by acp_7_x", + aliases = ["acp7x"] + ), # MediaTek platforms # (move to platform_configs_all on next Zephyr SDK release after 0.17.0) "mt8195" : PlatformConfig( @@ -126,6 +146,11 @@ class PlatformConfig: f"RJ-2024.3{xtensa_tools_version_postfix}", "HiFi5_MPU_lock_2023_11", ), + "mt8365" : PlatformConfig( + "mtk", "mt8365/mt8365/adsp", + f"RJ-2024.3{xtensa_tools_version_postfix}", + "hifi4_Aquila_E2_PROD", + ), } # These can all be built out of the box. --all builds all these. @@ -137,7 +162,7 @@ class PlatformConfig: f"RG-2017.8{xtensa_tools_version_postfix}", "cavs2x_LX6HiFi3_2017_8", "xcc", - aliases = ['adl', 'adl-n', 'ehl', 'rpl'], + aliases = ['adl', 'adl-n', 'rpl'], ipc4 = True ), "tgl-h" : PlatformConfig( @@ -167,7 +192,24 @@ class PlatformConfig: "ace30_LX7HiFi4_PIF", ipc4 = True ), - + "wcl" : PlatformConfig( + "intel", "intel_adsp/ace30/wcl", + f"RI-2022.10{xtensa_tools_version_postfix}", + "ace30_LX7HiFi4_PIF", + ipc4 = True + ), + "nvl" : PlatformConfig( + "intel", "intel_adsp/ace40/nvl", + f"RI-2022.10{xtensa_tools_version_postfix}", + "ace4px_HiFi5MMU_PIF_nlib", + ipc4 = True + ), + "nvl-s" : PlatformConfig( + "intel", "intel_adsp/ace40/nvls", + f"RI-2022.10{xtensa_tools_version_postfix}", + "ace4px_HiFi5MMU_PIF_nlib", + ipc4 = True + ), # NXP platforms "imx8" : PlatformConfig( "imx", "imx8qm_mek/mimx8qm6/adsp", @@ -187,6 +229,10 @@ class PlatformConfig: "hifi4_mscale_v2_0_2_prod", RIMAGE_KEY = "key param ignored by imx8m" ), + "imx8m_cm7" : PlatformConfig( + "imx", "imx8mp_evk/mimx8ml8/m7/ddr", + "", "", "", "" + ), "imx8ulp" : PlatformConfig( "imx", "imx8ulp_evk/mimx8ud7/adsp", f"RI-2023.11{xtensa_tools_version_postfix}", @@ -197,6 +243,14 @@ class PlatformConfig: "imx", "imx95_evk/mimx9596/m7/ddr", "", "", "", "" ), + "qemu_xtensa" : PlatformConfig( + "zephyr", "qemu_xtensa/dc233c", + "", "", "zephyr" + ), + "qemu_xtensa_mmu" : PlatformConfig( + "zephyr", "qemu_xtensa/dc233c/mmu", + "", "", "zephyr" + ), } platform_configs = platform_configs_all.copy() @@ -371,6 +425,10 @@ def parse_args(): help="""Do not create a tar file of the installed firmware files under build-sof-staging.""") parser.add_argument("--version", required=False, action="store_true", help="Prints version of this script.") + parser.add_argument("-m", "--menuconfig", required=False, action="store_true", + help="Build menuconfig for target") + parser.add_argument("-z", "--zephyrsdk", required=False, action="store_true", + help="Force Build using Zephyr SDK for target") args = parser.parse_args() @@ -659,9 +717,13 @@ def clean_staging(platform): def rimage_west_configuration(platform_dict, dest_dir): """Configure rimage in a new file `dest_dir/westconfig.ini`, starting from the workspace .west/config. - Returns a tuple (west ConfigFile, pathlib.Path to that new file). + Returns a tuple: (west.configuration.Configuration, pathlib.Path to that new file). """ + # This complex and painful saving and copying can be dropped and + # greatly simplified once any of these alternatives gets finally + # implemented in `west config`: + # https://github.com/zephyrproject-rtos/west/issues/429 or 849, 867,.. saved_local_var = os.environ.get('WEST_CONFIG_LOCAL') workspace_west_config_path = os.environ.get('WEST_CONFIG_LOCAL', str(west_top / ".west" / "config")) @@ -809,7 +871,12 @@ def build_platforms(): _dict = dataclasses.asdict(platform_configs[platform]) platform_dict = { k:v for (k,v) in _dict.items() if _dict[k] is not None } - xtensa_tools_root_dir = os.getenv("XTENSA_TOOLS_ROOT") + if args.zephyrsdk: + print("Using Zephyr SDK for building") + xtensa_tools_root_dir = None + else: + print("Using Xtensa tools for building") + xtensa_tools_root_dir = os.getenv("XTENSA_TOOLS_ROOT") # when XTENSA_TOOLS_ROOT environmental variable is set, # use user installed Xtensa tools not Zephyr SDK if "XTENSA_TOOLS_VERSION" in platform_dict and xtensa_tools_root_dir: @@ -851,9 +918,13 @@ def build_platforms(): platform_build_dir_name = f"build-{platform}" PLAT_CONFIG = platform_dict["PLAT_CONFIG"] + build_cmd = ["west"] build_cmd += ["-v"] * args.verbose - build_cmd += ["build", "--build-dir", platform_build_dir_name] + if args.menuconfig: + build_cmd += ["build", "-t", "menuconfig", "--build-dir", platform_build_dir_name] + else: + build_cmd += ["build", "--build-dir", platform_build_dir_name] source_dir = pathlib.Path(SOF_TOP, "app") build_cmd += ["--board", PLAT_CONFIG, str(source_dir)] if args.pristine: @@ -899,6 +970,15 @@ def build_platforms(): platform_dict, STAGING_DIR / "sof-info" / platform ) + + # SOF marks ELF sections in the range [SOF_MODULE_DRAM_LINK_START, SOF_MODULE_DRAM_LINK_END] + # as "detached". On imx8m_cm7 that address range overlaps with the M7 ITCM, so rimage would + # incorrectly classify ITCM sections as detached. Pass -d to ignore detached classification + if platform == "imx8m_cm7": + existing = platform_wcfg.get("rimage.extra-args") or "" + platform_wcfg.set("rimage.extra-args", + shlex.join(shlex.split(existing) + ["-d"])) + platf_build_environ['WEST_CONFIG_LOCAL'] = str(wcfg_path) # Make sure the build logs don't leave anything hidden @@ -906,6 +986,22 @@ def build_platforms(): env=platf_build_environ, sof_log_env=True) print() + # Delete the LLEXT VMA accumulator file before every build. + # llext_offset_calc.py uses module_size as a persistent counter + # across cmake custom-command invocations. If ninja is invoked + # more than once without a pristine rebuild this counter keeps + # accumulating, pushing pre-linked VMAs beyond the valid LLEXT + # virtual region and causing sys_mm_drv_map_region() to fail + # silently at runtime (IPC4_MOD_NOT_INITIALIZED error 104). + # llext_offset_calc.py already handles a missing file as size=0, + # so deletion is the simplest and most reliable reset. + zephyr_build_dir = pathlib.Path(abs_build_dir) / "zephyr" + if zephyr_build_dir.is_dir(): + acc_path = zephyr_build_dir / "module_size" + if acc_path.is_file(): + acc_path.unlink() + print(f"Deleted LLEXT VMA accumulator: {acc_path}") + # Build try: execute_command(build_cmd, cwd=west_top, env=platf_build_environ, sof_log_env=True) @@ -916,6 +1012,10 @@ def build_platforms(): else: # unknown failure raise cpe + # no output to display if building menuconfig + if args.menuconfig: + return + # reproducible-zephyr.ri is less useful now that show_installed_files() shows # checksums too. However: - it's still useful when only the .ri file is # available (no build logs for the other image), - it makes sure sof_ri_info.py @@ -967,73 +1067,77 @@ def install_lib(platform, sof_output_dir, abs_build_dir, platform_wconfig): sof_lib_dir.mkdir(parents=True, exist_ok=True) - with os.scandir(str(abs_build_dir)) as iter: - for entry in iter: - if (not entry.is_dir or - not entry.name.endswith('_llext')): - continue - - entry_path = pathlib.Path(entry.path) - - uuids = entry_path / 'llext.uuid' - if not os.path.exists(uuids): - print(f"Directory {entry.name} has no llext.uuid file. Skipping.") - continue + dirlist = [d for d in os.listdir(str(abs_build_dir)) if os.path.isdir(abs_build_dir / d)] + # Find all auxiliary modules, they're called "aux1_", "aux2_", etc., + # where lower numbers mean fewer dependent levels, so we need to sort + # them in reversed order to have all dependencies satisfied + pattern_aux = re.compile(r'^aux\d_.+_llext$') + aux = sorted([d for d in dirlist if pattern_aux.match(d)], reverse=True) + llext_dirs = [d for d in dirlist if d.endswith('_llext') and d not in aux] + final_list = aux + llext_dirs + + for entry in final_list: + entry_path = abs_build_dir / entry + + uuids = entry_path / 'llext.uuid' + if not os.path.exists(uuids): + print(f"Directory {entry} has no llext.uuid file. Skipping.") + continue - # replace '_llext' with '.llext', e.g. - # eq_iir_llext/eq_iir.llext - llext_base = entry.name[:-6] - llext_file = llext_base + '.llext' - lib_name = '' - - lib_fname = entry_path / 'lib_name.txt' - if os.path.exists(lib_fname): - with open(lib_fname, 'r') as libs_f: - lib_name = libs_f.read() - if lib_name not in libs.keys(): - libs[lib_name] = [] - libs[lib_name].append(str(entry_path / llext_file)) - else: - dst = sof_lib_dir / llext_file - - rimage_cfg = entry_path / 'rimage_config.toml' - llext_input = entry_path / (llext_base + '.llext') - llext_output = entry_path / (llext_file + '.ri') - - # See why the shlex() parsing step is required at - # https://docs.zephyrproject.org/latest/develop/west/sign.html#rimage - # and in Zephyr commit 030b740bd1ec - sign_cmd = [rimage_cmd, "-o", str(llext_output), - "-e", "-c", str(rimage_cfg), - "-k", str(signing_key), "-l", "-r"] - if _ws_args is not None: - sign_cmd.extend(shlex.split(_ws_args)) - sign_cmd.append(str(llext_input)) - execute_command(sign_cmd, cwd=west_top) - - # An intuitive way to make this multiline would be - # with (open(dst, 'wb') as fdst, open(llext_output, 'rb') as fllext, - # open(llext_output.with_suffix('.llext.xman'), 'rb') as fman): - # but a Python version, used on Windows errored out on this. - # Thus we're left with a choice between a 150-character - # long line and an illogical split like this - with open(dst, 'wb') as fdst, open(llext_output, 'rb') as fllext, open( - llext_output.with_suffix('.ri.xman'), 'rb') as fman: - # Concatenate the manifest and the llext - shutil.copyfileobj(fman, fdst) - shutil.copyfileobj(fllext, fdst) - - # Create symbolic links for all UUIDs - with open(uuids, 'r') as uuids_f: - for uuid in uuids_f: - if os.path.exists(lib_fname): - if lib_name not in lib_uuids.keys(): - lib_uuids[lib_name] = [] - lib_uuids[lib_name].append(uuid.strip()) - else: - linkname = uuid.strip() + '.bin' - symlink_or_copy(sof_lib_dir, llext_file, - sof_lib_dir, linkname) + # replace '_llext' with '.llext', e.g. + # eq_iir_llext/eq_iir.llext + llext_base = entry[:-6] + llext_file = llext_base + '.llext' + lib_name = '' + + lib_fname = entry_path / 'lib_name.txt' + if os.path.exists(lib_fname): + with open(lib_fname, 'r') as libs_f: + lib_name = libs_f.read() + if lib_name not in libs.keys(): + libs[lib_name] = [] + libs[lib_name].append(str(entry_path / llext_file)) + else: + dst = sof_lib_dir / llext_file + + rimage_cfg = entry_path / 'rimage_config.toml' + llext_input = entry_path / (llext_base + '.llext') + llext_output = entry_path / (llext_file + '.ri') + + # See why the shlex() parsing step is required at + # https://docs.zephyrproject.org/latest/develop/west/sign.html#rimage + # and in Zephyr commit 030b740bd1ec + sign_cmd = [rimage_cmd, "-o", str(llext_output), + "-e", "-c", str(rimage_cfg), + "-k", str(signing_key), "-l", "-r"] + if _ws_args is not None: + sign_cmd.extend(shlex.split(_ws_args)) + sign_cmd.append(str(llext_input)) + execute_command(sign_cmd, cwd=west_top) + + # An intuitive way to make this multiline would be + # with (open(dst, 'wb') as fdst, open(llext_output, 'rb') as fllext, + # open(llext_output.with_suffix('.llext.xman'), 'rb') as fman): + # but a Python version, used on Windows errored out on this. + # Thus we're left with a choice between a 150-character + # long line and an illogical split like this + with open(dst, 'wb') as fdst, open(llext_output, 'rb') as fllext, open( + llext_output.with_suffix('.ri.xman'), 'rb') as fman: + # Concatenate the manifest and the llext + shutil.copyfileobj(fman, fdst) + shutil.copyfileobj(fllext, fdst) + + # Create symbolic links for all UUIDs + with open(uuids, 'r') as uuids_f: + for uuid in uuids_f: + if os.path.exists(lib_fname): + if lib_name not in lib_uuids.keys(): + lib_uuids[lib_name] = [] + lib_uuids[lib_name].append(uuid.strip()) + else: + linkname = uuid.strip() + '.bin' + symlink_or_copy(sof_lib_dir, llext_file, + sof_lib_dir, linkname) lib_install_dir = sof_output_dir / platform if args.key_type_subdir != "none": @@ -1090,8 +1194,9 @@ def install_platform(platform, sof_output_dir, platf_build_environ, platform_wco install_key_dir = install_key_dir / args.key_type_subdir os.makedirs(install_key_dir, exist_ok=True) - # looses file owner and group - file is commonly accessible - shutil.copy2(abs_build_dir / "zephyr.ri", install_key_dir / output_fwname) + # looses file owner and group - file is commonly accessible, dont install qemu. + if platform not in ("qemu_xtensa", "qemu_xtensa_mmu"): + shutil.copy2(abs_build_dir / "zephyr.ri", install_key_dir / output_fwname) if args.deployable_build and platform_configs[platform].ipc4: # IPC4 deployable builds are using separate directories per platforms @@ -1241,9 +1346,11 @@ def gzip_compress(fname, gzdst=None): # Don't run sof_ri_info and ignore silently .ri files that don't have one. RI_INFO_UNSUPPORTED = [] -RI_INFO_UNSUPPORTED += ['imx8', 'imx8x', 'imx8m', 'imx8ulp', 'imx95'] -RI_INFO_UNSUPPORTED += ['rn', 'acp_6_0'] -RI_INFO_UNSUPPORTED += ['mt8186', 'mt8188', 'mt8195', 'mt8196'] +RI_INFO_UNSUPPORTED += ['imx8', 'imx8x', 'imx8m', 'imx8m_cm7', 'imx8ulp', 'imx95'] +RI_INFO_UNSUPPORTED += ['rn', 'acp_6_0', 'acp_7_0', 'acp_7_x'] +RI_INFO_UNSUPPORTED += ['mt8186', 'mt8188', 'mt8195', 'mt8196', 'mt8365'] +RI_INFO_UNSUPPORTED += ['qemu_xtensa', 'qemu_xtensa_mmu'] + # For temporary workarounds. Unlike _UNSUPPORTED above, the platforms below will print a warning. RI_INFO_FIXME = [ ] @@ -1302,6 +1409,8 @@ def main(): build_rimage() build_platforms() + if args.menuconfig: + return if not args.no_tarball: create_tarball() show_installed_files() diff --git a/smex/elf.c b/smex/elf.c index eb0994530c6b..6069f12f6b92 100644 --- a/smex/elf.c +++ b/smex/elf.c @@ -44,8 +44,29 @@ static int elf_read_sections(struct elf_module *module, bool verbose) return count > 0 ? -ENODATA : -errno; } - /* read in strings */ - module->strings = calloc(1, section[hdr->shstrndx].size); + /* the string-table section index comes from the ELF header and is used + * to index section[]; reject an out-of-range value before dereferencing + */ + if (hdr->shstrndx >= hdr->shnum) { + fprintf(stderr, "error: %s invalid shstrndx %u >= shnum %u\n", + module->elf_file, hdr->shstrndx, hdr->shnum); + return -ENOEXEC; + } + + /* a zero-size string section leaves module->strings unusable and would + * break later string lookups; reject it explicitly + */ + if (section[hdr->shstrndx].size == 0) { + fprintf(stderr, "error: %s has zero-size string section\n", + module->elf_file); + return -ENOEXEC; + } + + /* read in strings; allocate one extra byte (calloc zeroes it) so the + * table is always NUL-terminated and string lookups cannot run off the + * end even if the section itself lacks a terminator + */ + module->strings = calloc(1, section[hdr->shstrndx].size + 1); if (!module->strings) { fprintf(stderr, "error: failed %s to read ELF strings for %d\n", module->elf_file, -errno); @@ -67,6 +88,18 @@ static int elf_read_sections(struct elf_module *module, bool verbose) return count > 0 ? -ENODATA : -errno; } + /* every section name is used as an offset into the string table; make + * sure each stays within it so later "module->strings + name" reads + * cannot run past the table + */ + for (i = 0; i < hdr->shnum; i++) { + if (section[i].name >= section[hdr->shstrndx].size) { + fprintf(stderr, "error: %s section %d name offset %u out of range\n", + module->elf_file, i, section[i].name); + return -ENOEXEC; + } + } + module->bss_index = elf_find_section(module, ".bss"); if (module->bss_index < 0) { fprintf(stderr, "Can't find .bss section in %s", @@ -392,8 +425,22 @@ int elf_find_section(const struct elf_module *module, const char *name) return -EINVAL; } + if (hdr->shstrndx >= hdr->shnum) { + fprintf(stderr, "error: invalid shstrndx %u >= shnum %u\n", + hdr->shstrndx, hdr->shnum); + return -EINVAL; + } + section = &module->section[hdr->shstrndx]; + /* a zero-size string section would make the buffer[size - 1] + * NUL-termination below write before the allocation + */ + if (section->size == 0) { + fprintf(stderr, "error: zero-size string section\n"); + return -EINVAL; + } + /* alloc data data */ buffer = calloc(1, section->size); if (!buffer) @@ -482,6 +529,10 @@ int elf_read_section(const struct elf_module *module, const char *section_name, error: free(*dst_buff); + /* clear the caller's pointer so a caller cleanup path (e.g. ldc.c's + * "if (buffer) free(buffer)") does not free the same buffer again + */ + *dst_buff = NULL; return ret; } diff --git a/smex/ldc.c b/smex/ldc.c index 4eccdb1c0918..a44b67a05973 100644 --- a/smex/ldc.c +++ b/smex/ldc.c @@ -26,6 +26,13 @@ static int fw_version_copy(const struct elf_module *src, if (section_size < 0) return section_size; + if ((size_t)section_size < sizeof(struct sof_ipc_fw_ready)) { + fprintf(stderr, "error: .fw_ready section too small: %d\n", + section_size); + free(buffer); + return -EINVAL; + } + memcpy(&header->version, &((struct sof_ipc_fw_ready *)buffer)->version, sizeof(header->version)); @@ -50,13 +57,37 @@ static int fw_version_copy(const struct elf_module *src, return section_size; ext_hdr = (struct ext_man_elem_header *)buffer; - while ((uintptr_t)ext_hdr < (uintptr_t)buffer + section_size) { + while ((uintptr_t)ext_hdr + sizeof(*ext_hdr) <= + (uintptr_t)buffer + section_size) { if (ext_hdr->type == EXT_MAN_ELEM_DBG_ABI) { + /* make sure the whole dbg-abi element is within the + * section before reading it + */ + if (ext_hdr->elem_size < sizeof(struct ext_man_dbg_abi) || + (uintptr_t)ext_hdr + sizeof(struct ext_man_dbg_abi) > + (uintptr_t)buffer + section_size) { + fprintf(stderr, "error: %s truncated dbg-abi element\n", + src->elf_file); + free(buffer); + return -ENOEXEC; + } header->version.abi_version = ((struct ext_man_dbg_abi *) ext_hdr)->dbg_abi.abi_dbg_version; break; } + /* a malformed element size would loop forever (0) or advance + * the cursor past the section; reject the image rather than + * silently stopping + */ + if (ext_hdr->elem_size == 0 || + (uintptr_t)ext_hdr + ext_hdr->elem_size > + (uintptr_t)buffer + section_size) { + fprintf(stderr, "error: %s malformed ext-manifest element\n", + src->elf_file); + free(buffer); + return -ENOEXEC; + } //move to the next entry ext_hdr = (struct ext_man_elem_header *) ((uint8_t *)ext_hdr + ext_hdr->elem_size); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 29d1ad54a8bb..e1455a75bd7e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,7 +11,7 @@ add_subdirectory(module) if(CONFIG_SAMPLES) add_subdirectory(samples) endif() -add_local_sources(sof spinlock.c) + add_subdirectory(drivers) if (CONFIG_TRACE) diff --git a/src/Kconfig b/src/Kconfig index 378cd533b0b7..0ad749042db8 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -15,6 +15,9 @@ rsource "probe/Kconfig" rsource "samples/Kconfig" rsource "schedule/Kconfig" +rsource "schedule/Kconfig.threads_prio" + +rsource "idc/Kconfig" rsource "ipc/Kconfig" @@ -25,3 +28,5 @@ rsource "library_manager/Kconfig" rsource "debug/telemetry/Kconfig" rsource "debug/debug_stream/Kconfig" + +rsource "debug/tester/Kconfig" diff --git a/src/arch/host/Kconfig b/src/arch/host/Kconfig deleted file mode 100644 index de92f43a868c..000000000000 --- a/src/arch/host/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -# Host architecture configs - -config CORE_COUNT - int - default 1 - help - Number of used cores diff --git a/src/arch/host/configs/library_defconfig b/src/arch/host/configs/library_defconfig index 1b9483ffe858..1279dd26c924 100644 --- a/src/arch/host/configs/library_defconfig +++ b/src/arch/host/configs/library_defconfig @@ -2,22 +2,28 @@ CONFIG_COMP_ARIA=y CONFIG_COMP_ASRC=y CONFIG_COMP_CROSSOVER=y CONFIG_COMP_DCBLOCK=y +CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING=y CONFIG_COMP_DRC=y CONFIG_COMP_FIR=y CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=y CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING=y CONFIG_COMP_IIR=y CONFIG_COMP_IGO_NR=y +CONFIG_COMP_LEVEL_MULTIPLIER=y CONFIG_COMP_MFCC=y CONFIG_COMP_MODULE_ADAPTER=y CONFIG_COMP_MULTIBAND_DRC=y CONFIG_COMP_MUX=y +CONFIG_COMP_PHASE_VOCODER=y CONFIG_COMP_RTNR=y CONFIG_COMP_SEL=y +CONFIG_COMP_SOUND_DOSE=y CONFIG_COMP_SRC=y CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y +CONFIG_COMP_STFT_PROCESS=y CONFIG_COMP_STUBS=y CONFIG_COMP_TDFB=y +CONFIG_COMP_TONE=y CONFIG_COMP_VOLUME=y CONFIG_COMP_VOLUME_LINEAR_RAMP=y CONFIG_COMP_VOLUME_WINDOWS_FADE=y diff --git a/src/arch/host/include/arch/spinlock.h b/src/arch/host/include/arch/spinlock.h deleted file mode 100644 index 360cb72bdb1f..000000000000 --- a/src/arch/host/include/arch/spinlock.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -/* TODO: this needs fixed as part of the "host does not need rtos headers work" */ -#ifdef __POSIX_RTOS_SPINLOCK_H__ - -#ifndef __ARCH_SPINLOCK_H__ -#define __ARCH_SPINLOCK_H__ - -struct k_spinlock { -}; - -static inline void arch_spinlock_init(struct k_spinlock *lock) {} -static inline void arch_spin_lock(struct k_spinlock *lock) {} -static inline void arch_spin_unlock(struct k_spinlock *lock) {} - -#endif /* __ARCH_SPINLOCK_H__ */ - -#else - -#error "This file shouldn't be included from outside of sof/spinlock.h" - -#endif /* __SOF_SPINLOCK_H__ */ diff --git a/src/arch/xtensa/CMakeLists.txt b/src/arch/xtensa/CMakeLists.txt deleted file mode 100644 index e8478444b66e..000000000000 --- a/src/arch/xtensa/CMakeLists.txt +++ /dev/null @@ -1,548 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -# platform-specific values - -if(CONFIG_IMX8) - set(platform_folder imx8) -elseif(CONFIG_IMX8X) - set(platform_folder imx8) -elseif(CONFIG_IMX8M) - set(platform_folder imx8m) -elseif(CONFIG_IMX8ULP) - set(platform_folder imx8ulp) -elseif(CONFIG_RENOIR) - set(platform_folder amd/renoir) -elseif(CONFIG_REMBRANDT) - set(platform_folder amd/rembrandt) -elseif(CONFIG_VANGOGH) - set(platform_folder amd/vangogh) -elseif(CONFIG_ACP_6_3) - set(platform_folder amd/acp_6_3) -elseif(CONFIG_ACP_7_0) - set(platform_folder amd/acp_7_0) -elseif(CONFIG_MT8186) - set(platform_folder mt8186) -elseif(CONFIG_MT8188) - set(platform_folder mt8188) -elseif(CONFIG_MT8195) - set(platform_folder mt8195) -else() - message(FATAL_ERROR "Platform not defined, check your Kconfiguration?") -endif() - -set(fw_name ${CONFIG_RIMAGE_SIGNING_SCHEMA}) - -# File name without directory -get_filename_component(_plf_ld_script ${platform_folder} NAME) -set(platform_ld_script ${_plf_ld_script}.x) -set(platform_rom_ld_script rom.x) - -if(CONFIG_AMD) - target_include_directories(sof_options INTERFACE ${PROJECT_SOURCE_DIR}/src/platform/amd/common/include) -endif() - -# includes - -# None of these should be included if Zephyr strict headers are used. -if (NOT CONFIG_SOF_ZEPHYR_STRICT_HEADERS) -target_include_directories(sof_options INTERFACE - ${PROJECT_SOURCE_DIR}/src/arch/xtensa/include - ${PROJECT_SOURCE_DIR}/src/arch/xtensa/xtos - ${PROJECT_SOURCE_DIR}/xtos/include -) -endif() - -target_include_directories(sof_options INTERFACE ${PROJECT_SOURCE_DIR}/src/platform/${platform_folder}/include) - -if(XCC) - target_include_directories(sof_options INTERFACE ${ROOT_DIR}/arch/include) -else() - target_include_directories(sof_options INTERFACE ${PROJECT_SOURCE_DIR}/src/platform/${platform_folder}/include/arch) -endif() - -target_include_directories(sof_options INTERFACE ${ROOT_DIR}/include) - -if(BUILD_UNIT_TESTS) - set(stdlib_flag "") -else() - set(stdlib_flag "-nostdlib") -endif() - -get_optimization_flag(optimization_flag) - -if(BUILD_CLANG_SCAN) - # pretend to be xtensa compiler to go trough the same paths for AST - target_compile_definitions(sof_options INTERFACE -D__XTENSA__=1) - - if(XCC) - # clang has to compile objects in order to analyze sources, - # so it needs xcc's headers - find_program(XCC_PATH NAMES "xt-xcc" PATHS ENV PATH NO_DEFAULT_PATH) - get_filename_component(XCC_DIR ${XCC_PATH} DIRECTORY) - target_include_directories(sof_options INTERFACE ${XCC_DIR}/../xtensa-elf/include) - endif() - - # Clang by default compiles for host architecture, - # but xtensa is always 32 bit, what may cause mismatch in definitions, - # that depend on bitness, so force compilation for 32 bit. - set(XTENSA_C_ASM_FLAGS -m32) - set(XTENSA_C_FLAGS) -else() - set(XTENSA_C_ASM_FLAGS -mlongcalls) - set(XTENSA_C_FLAGS -mtext-section-literals) -endif() - -# linker flags - GCC >= 10.x uses libc -if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 10.0) - target_link_libraries(sof_options INTERFACE ${stdlib_flag} -lgcc -lc -Wl,--no-check-sections -ucall_user_start -Wl,-static) -else() - target_link_libraries(sof_options INTERFACE ${stdlib_flag} -lgcc -Wl,--no-check-sections -ucall_user_start -Wl,-static) -endif() - -# C & ASM flags -if(CONFIG_COMPILER_INLINE_FUNCTION_OPTION) - target_compile_options(sof_options INTERFACE ${stdlib_flag} ${XTENSA_C_ASM_FLAGS}) -else() - target_compile_options(sof_options INTERFACE ${stdlib_flag} -fno-inline-functions ${XTENSA_C_ASM_FLAGS}) -endif() - -# C flags -# TODO: Generator expressions are supported only with Make and Ninja, -# if we want to support other generators, we would have to find some other way -# for setting flags just for C files. -# Possible solutions: -# 1) CMAKE_<LANG>_FLAGS - works, but is global, we prefer target_* functions -# 2) set_source_files_properties - need to be done for each source file, it's -# better to have set of default flags and change it only for special cases -# 3) custom function that is used instead of target_sources and sets flags -# for each added source based on file extension - -separate_arguments(EXTRA_CFLAGS_AS_LIST NATIVE_COMMAND ${EXTRA_CFLAGS}) - -# No space between -imacros and its argument to avoid CMake -# de-duplication "feature" -target_compile_options(sof_options INTERFACE - $<$<COMPILE_LANGUAGE:C>: - -${optimization_flag} -g - -Wall -Werror - -Wmissing-prototypes - -Wpointer-arith - ${XTENSA_C_FLAGS} - ${EXTRA_CFLAGS_AS_LIST} - > - -imacros${CONFIG_H_PATH} - ) - -if(BUILD_UNIT_TESTS) - # rest of this file is not needed for unit tests - return() -endif() - -if(XCC) - file(GLOB LINK_DEPS - ${ROOT_DIR}/arch/include/xtensa/config/core-isa*) -else() - file(GLOB LINK_DEPS - ${PROJECT_SOURCE_DIR}/src/platform/${platform_folder}/include/arch/xtensa/config/core-isa*) -endif() - -# linker scripts - -function(sof_add_ld_script binary_name script_name) - - set(lds_in ${PROJECT_SOURCE_DIR}/src/platform/${platform_folder}/${script_name}.in) - set(lds_out ${PROJECT_BINARY_DIR}/${script_name}) - - get_target_property(incdirs sof_options INTERFACE_INCLUDE_DIRECTORIES) - - set(iflags "") - set(glob_predicates "") - foreach(d ${incdirs}) - list(APPEND iflags "-I${d}") - list(APPEND glob_predicates "${d}/*.h") - endforeach() - - get_target_property(incdirs sof_public_headers INTERFACE_INCLUDE_DIRECTORIES) - - foreach(d ${incdirs}) - list(APPEND iflags "-I${d}") - list(APPEND glob_predicates "${d}/*.h") - endforeach() - - file(GLOB lds_headers ${glob_predicates}) - - add_custom_command(OUTPUT ${lds_out} - COMMAND ${CMAKE_C_COMPILER} -E -DLINKER -P ${iflags} -o ${lds_out} -x c ${lds_in} - -imacros${CONFIG_H_PATH} - DEPENDS ${lds_in} ${LINK_DEPS} genconfig ${CONFIG_H_PATH} ${lds_headers} - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - COMMENT "Generating linker script: ${lds_out}" - VERBATIM - USES_TERMINAL - ) - - add_custom_target("ld_script_${script_name}" DEPENDS ${lds_out}) - add_dependencies(${binary_name} "ld_script_${script_name}") - set_target_properties(${binary_name} PROPERTIES LINK_DEPENDS ${lds_in}) -endfunction() - -sof_add_ld_script(sof ${platform_ld_script}) - -# binaries - -add_library(reset STATIC "") -target_link_libraries(reset sof_options) -target_compile_options(reset PRIVATE -mtext-section-literals) - -add_subdirectory(debug) -add_subdirectory(drivers) -add_subdirectory(hal) -add_subdirectory(lib) -add_subdirectory(schedule) -add_subdirectory(xtos) - -add_local_sources(reset xtos/memctl_default.S xtos/reset-vector.S) - -add_local_sources(sof - xtos/crt1-boards.S - xtos/_vectors.S - init.c - exc-dump.S -) - -# TODO: order of these libraries does matter, what is bad, -# we should switch to building with thin archives without symbols index -# and made it before final link so dependencies won't matter -target_link_libraries(sof_static_libraries INTERFACE xtos) -target_link_libraries(sof_static_libraries INTERFACE hal) - -if(CONFIG_XT_INTERRUPT_LEVEL_2) -target_link_libraries(sof_static_libraries INTERFACE xlevel2) -endif() -if(CONFIG_XT_INTERRUPT_LEVEL_3) -target_link_libraries(sof_static_libraries INTERFACE xlevel3) -endif() -if(CONFIG_XT_INTERRUPT_LEVEL_4) -target_link_libraries(sof_static_libraries INTERFACE xlevel4) -endif() -if(CONFIG_XT_INTERRUPT_LEVEL_5) -target_link_libraries(sof_static_libraries INTERFACE xlevel5) -endif() - -target_link_libraries(sof_static_libraries INTERFACE reset) - -target_link_libraries(sof_ld_flags INTERFACE "-Wl,-Map=sof.map") -target_link_libraries(sof_ld_flags INTERFACE "-T${PROJECT_BINARY_DIR}/${platform_ld_script}") - -# Copy the linker output from the top-level to this subdirectory -add_custom_target( - prepare_sof_post_process - # "global" .ELF target used everywhere and declared and produced at the top - DEPENDS sof - COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/sof sof-pre -) - -# contains steps that should be performed before fw image is ready for being -# processed by tools like rimage and MEU -add_custom_target(sof_post_process - DEPENDS process_base_module -) - -# contains extra output that should be generated for bin target -add_custom_target(bin_extras) - -# Do nothing / pass-through -add_custom_target(process_base_module - COMMAND ${CMAKE_COMMAND} -E copy sof-pre sof-${fw_name} - DEPENDS prepare_sof_post_process -) - -if(CONFIG_BUILD_VM_ROM) - add_executable(rom "") - target_link_libraries(rom PRIVATE sof_options) - target_link_libraries(rom PRIVATE "-T${PROJECT_BINARY_DIR}/${platform_rom_ld_script}") - sof_add_ld_script(rom ${platform_rom_ld_script}) - - # We have to make additional define, because sources - # are reused for other objects with different flags. - target_compile_definitions(rom PRIVATE -DCONFIG_VM_ROM) - - add_local_sources(rom - xtos/crt1-boards-rom.S - xtos/memctl_default.S - xtos/reset-vector.S - ) - - add_custom_target( - rom_dump - COMMAND ${CMAKE_COMMAND} -E copy rom rom-${fw_name} - COMMAND ${CMAKE_OBJCOPY} -O binary rom rom-${fw_name}.bin - COMMAND ${CMAKE_OBJDUMP} -h -D rom > rom-${fw_name}.lmap - COMMAND ${CMAKE_OBJDUMP} -S rom > rom-${fw_name}.lst - COMMAND ${CMAKE_OBJDUMP} -D rom > rom-${fw_name}.dis - DEPENDS rom - VERBATIM - USES_TERMINAL - ) - - add_dependencies(bin_extras rom_dump) -endif() - -if(BUILD_CLANG_SCAN) - # steps below don't compile parts of fw, - # so they are not needed for scan-build - return() -endif() - -add_custom_target( - sof_dump - COMMAND ${CMAKE_OBJDUMP} -S sof-${fw_name} > sof-${fw_name}.lst - COMMAND ${CMAKE_OBJDUMP} -h sof-${fw_name} > sof-${fw_name}.lmap - COMMAND ${CMAKE_OBJDUMP} -D sof-${fw_name} > sof-${fw_name}.dis - DEPENDS sof_post_process - VERBATIM - USES_TERMINAL -) - -include(ExternalProject) - -# smex - -ExternalProject_Add(smex_ep - DEPENDS check_version_h - DOWNLOAD_COMMAND "" - SOURCE_DIR "${PROJECT_SOURCE_DIR}/smex" - PREFIX "${PROJECT_BINARY_DIR}/smex_ep" - BINARY_DIR "${PROJECT_BINARY_DIR}/smex_ep/build" - EXCLUDE_FROM_ALL TRUE - BUILD_ALWAYS 1 - INSTALL_COMMAND "" -) - -add_custom_target( - run_smex - COMMAND ${PROJECT_BINARY_DIR}/smex_ep/build/smex - -l sof-${fw_name}.ldc - sof-${fw_name} - DEPENDS sof_post_process smex_ep - VERBATIM - USES_TERMINAL -) - -# rimage - -ExternalProject_Add(rimage_ep - DEPENDS check_version_h - SOURCE_DIR "${RIMAGE_TOP}" - PREFIX "${PROJECT_BINARY_DIR}/rimage_ep" - BINARY_DIR "${PROJECT_BINARY_DIR}/rimage_ep/build" - EXCLUDE_FROM_ALL TRUE - BUILD_ALWAYS 1 - INSTALL_COMMAND "" -) - -if(NOT DEFINED RIMAGE_PRIVATE_KEY) - set(RIMAGE_PRIVATE_KEY ${PROJECT_SOURCE_DIR}/keys/otc_private_key.pem) -endif() - -if(NOT DEFINED RIMAGE_IMR_TYPE) - # default value for non-production firmware - set(RIMAGE_IMR_TYPE 3) -endif() - -if(NOT MEU_OPENSSL) - set(MEU_OPENSSL "/usr/bin/openssl") -endif() -# Don't ask users to keep secret their openssl location depending on -# what they build in the moment. -set(silenceUnusedWarning "${MEU_OPENSSL}") - -if(MEU_PATH OR DEFINED MEU_NO_SIGN) # Don't sign with rimage - if(NOT DEFINED MEU_OFFSET) - execute_process( - COMMAND ${MEU_PATH}/meu -ver - OUTPUT_VARIABLE MEU_VERSION_FULL_TEXT - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE meu_ver_res - ) - if(NOT ${meu_ver_res} EQUAL 0) - message(WARNING "${MEU_PATH}/meu -ver" - " failed with: ${meu_ver_res}") - endif() - - string(REGEX MATCH "Version:[\t\n ]*([^\t\n ]+)" ignored "${MEU_VERSION_FULL_TEXT}") - set(MEU_VERSION ${CMAKE_MATCH_1}) - - if(MEU_VERSION VERSION_LESS 12.0.0.1035) - set(MEU_OFFSET 1152) - elseif(MEU_VERSION VERSION_LESS 15.0.0.0) - set(MEU_OFFSET 1088) - else() - set(MEU_OFFSET 1344) - endif() - endif() - message(STATUS MEU_OFFSET=${MEU_OFFSET}) - - # Passing -s ${MEU_OFFSET} disables rimage signing and produces - # one .uns file and one .met file instead of a .ri file. - add_custom_target( - run_rimage - COMMAND ${PROJECT_BINARY_DIR}/rimage_ep/build/rimage - -o sof-${fw_name}.ri - -c "${RIMAGE_TOP}/config/${fw_name}.toml" - -s ${MEU_OFFSET} - -k ${RIMAGE_PRIVATE_KEY} - -i ${RIMAGE_IMR_TYPE} - -f ${SOF_MAJOR}.${SOF_MINOR}.${SOF_MICRO} - -b ${SOF_BUILD} - -e - sof-${fw_name} - DEPENDS sof_post_process rimage_ep - VERBATIM - USES_TERMINAL - ) - - if(NOT DEFINED MEU_FLAGS) - set(MEU_FLAGS - -f ${MEU_PATH}/generic_meu_conf.xml - -mnver 0.0.0.0 - -key ${MEU_PRIVATE_KEY} - -stp ${MEU_OPENSSL} - ${MEU_EXTRA_FLAGS} - ) - endif() - - if(MEU_NO_SIGN) - add_custom_target(run_meu DEPENDS run_rimage) - else() - add_custom_target( - run_meu - COMMAND ${MEU_PATH}/meu -w ./ -s sof-${fw_name} - ${MEU_FLAGS} - -o sof-${fw_name}.ri - DEPENDS run_rimage - VERBATIM - USES_TERMINAL - ) - endif() -else() # sign with rimage - add_custom_target( - run_rimage - COMMAND ${PROJECT_BINARY_DIR}/rimage_ep/build/rimage - -o sof-${fw_name}.ri - -c "${RIMAGE_TOP}/config/${fw_name}.toml" - -k ${RIMAGE_PRIVATE_KEY} - -i ${RIMAGE_IMR_TYPE} - -f ${SOF_MAJOR}.${SOF_MINOR}.${SOF_MICRO} - -b ${SOF_BUILD} - -e - sof-${fw_name} - DEPENDS sof_post_process rimage_ep - VERBATIM - USES_TERMINAL - ) - - add_custom_target(run_meu DEPENDS run_rimage) -endif() # sign with MEU / nothing / rimage - -if(NOT DEFINED FIRMWARE_NAME) - set(fw_output_name "${fw_name}") -else() - set(fw_output_name "${FIRMWARE_NAME}") -endif() - -if(${CMAKE_HOST_WIN32}) - set(GLUE_CMD copy /b sof-${fw_name}.ri.xman + sof-${fw_name}.ri sof-${fw_name}.rix) -else() - set(GLUE_CMD cat sof-${fw_name}.ri.xman sof-${fw_name}.ri > sof-${fw_name}.rix) -endif() - -add_custom_target( - glue_binary_files - COMMAND ${GLUE_CMD} - COMMAND ${CMAKE_COMMAND} -E remove sof-${fw_name}.ri - COMMAND ${CMAKE_COMMAND} -E rename sof-${fw_name}.rix sof-${fw_name}.ri - DEPENDS run_meu - VERBATIM - USES_TERMINAL - BYPRODUCTS sof-${fw_name}.ri # almost like a proper add_custom_command() -) - - -# Keep lists below in sync with rimage/config/*.toml - -# .ri not signed: nothing variable in it to erase. -# NXP -set(UNSIGNED_RI imx8 imx8x imx8m imx8ulp) -# AMD -list(APPEND UNSIGNED_RI rn rmb vangogh acp_6_3 acp_7_0) -# MediaTek -list(APPEND UNSIGNED_RI mt8186 mt8188 mt8195) - -if(${fw_name} IN_LIST UNSIGNED_RI) # mere copy - add_custom_command(OUTPUT reproducible.ri - COMMENT "Copying sof.ri to reproducible.ri as is" - # TODO: drop the glue_binary_files dependency once the - # edit-in-place and add_custom_target() messes are all fixed - DEPENDS glue_binary_files sof-${fw_name}.ri - COMMAND cmake -E copy sof-${fw_name}.ri reproducible.ri - VERBATIM - ) -else() # strip variables - add_custom_command(OUTPUT reproducible.ri - COMMENT "Creating reproducible.ri" - DEPENDS glue_binary_files sof-${fw_name}.ri - COMMAND ${PROJECT_SOURCE_DIR}/tools/sof_ri_info/sof_ri_info.py - --no_headers --no_modules --no_memory # could use a -q option... - --erase_vars reproducible.ri sof-${fw_name}.ri - VERBATIM - ) -endif() - - -# Top-level 'bin' target collecting all dependencies. Copies final .ri -# file from current subdirectory to top level build directory -# ${PROJECT_BINARY_DIR}. - -# TODO: get rid of ${fw_output_name} and ${fw_name} below. Different -# platforms are already built in different build directories, we will -# never support building multiple platforms in the same build directory. -if(MEU_NO_SIGN) - add_custom_target( - bin ALL - # copy rimage output that can be used to sign firmware - COMMAND ${CMAKE_COMMAND} -E copy sof-${fw_name}.ri.uns ${PROJECT_BINARY_DIR}/sof-${fw_output_name}.ri.uns - COMMAND ${CMAKE_COMMAND} -E copy sof-${fw_name}.ri.met ${PROJECT_BINARY_DIR}/sof-${fw_output_name}.ri.met - COMMAND ${CMAKE_COMMAND} -E copy sof-${fw_name}.ri.uns ${PROJECT_BINARY_DIR}/sof.ri.uns - COMMAND ${CMAKE_COMMAND} -E copy sof-${fw_name}.ri.met ${PROJECT_BINARY_DIR}/sof.ri.met - DEPENDS run_meu bin_extras glue_binary_files sof_dump - VERBATIM - USES_TERMINAL - ) -else() - add_custom_target( - bin ALL - COMMAND ${CMAKE_COMMAND} -E copy sof-${fw_name}.ri ${PROJECT_BINARY_DIR}/sof-${fw_output_name}.ri - COMMAND ${CMAKE_COMMAND} -E copy sof-${fw_name}.ri ${PROJECT_BINARY_DIR}/sof.ri - DEPENDS run_meu bin_extras glue_binary_files sof_dump reproducible.ri - VERBATIM - USES_TERMINAL - ) -endif() - -if(CONFIG_TRACE) - add_custom_target(copy_dictionaries - COMMAND ${CMAKE_COMMAND} -E copy sof-${fw_name}.ldc ${PROJECT_BINARY_DIR}/sof-${fw_output_name}.ldc - COMMAND ${CMAKE_COMMAND} -E copy sof-${fw_name}.ldc ${PROJECT_BINARY_DIR}/sof.ldc - DEPENDS run_smex - VERBATIM - USES_TERMINAL - ) - add_dependencies(bin copy_dictionaries) - endif() - -install( - FILES ${PROJECT_BINARY_DIR}/sof-${fw_output_name}.ri - ${PROJECT_BINARY_DIR}/sof-${fw_output_name}.ldc - DESTINATION bin -) diff --git a/src/arch/xtensa/Kconfig b/src/arch/xtensa/Kconfig index e015a80f1e2a..3bb2d4abd80d 100644 --- a/src/arch/xtensa/Kconfig +++ b/src/arch/xtensa/Kconfig @@ -8,12 +8,3 @@ config NO_SECONDARY_CORE_ROM help Indicates that secondary core have rom, alternate reset vector is needed if not - -config WAKEUP_HOOK - bool - default n - help - Enables hook that is called and after coming back from WAITI. - This config should be selected by other platform-level configs. - Platforms that use it, have to implement hook function - platform_interrupt_on_wakeup. diff --git a/src/arch/xtensa/configs/acp_7_0_defconfig b/src/arch/xtensa/configs/acp_7_0_defconfig index 9b7427f6e3aa..c5e3d4952294 100644 --- a/src/arch/xtensa/configs/acp_7_0_defconfig +++ b/src/arch/xtensa/configs/acp_7_0_defconfig @@ -30,7 +30,7 @@ CONFIG_COMP_ARIA=n CONFIG_COMP_BASEFW_IPC4=n CONFIG_COMP_UP_DOWN_MIXER=n CONFIG_COMP_TDFB=n -#CONFIG_COMP_MUX=n +CONFIG_COMP_MUX=n CONFIG_COMP_SEL=n CONFIG_COMP_MIXER=n -CONFIG_AMD_BINARY_BUILD=n +CONFIG_PROBE=n diff --git a/src/arch/xtensa/configs/acp_7_x_defconfig b/src/arch/xtensa/configs/acp_7_x_defconfig new file mode 100644 index 000000000000..d978611fadde --- /dev/null +++ b/src/arch/xtensa/configs/acp_7_x_defconfig @@ -0,0 +1,32 @@ +CONFIG_ACP_7_X=y +CONFIG_RIMAGE_SIGNING_SCHEMA="acp_7_3" +CONFIG_TRACE_CHANNEL=7 +CONFIG_WRAP_ACTUAL_POSITION=y +CONFIG_CORE_COUNT=1 +CONFIG_FORMAT_CONVERT_HIFI3=n +CONFIG_LP_SRAM=n +CONFIG_HAVE_AGENT=n +CONFIG_COMP_VOLUME=y +CONFIG_COMP_SRC=n +CONFIG_COMP_FIR=n +CONFIG_COMP_IIR=n +CONFIG_COMP_DCBLOCK=n +CONFIG_COMP_CROSSOVER=n +CONFIG_COMP_DRC=n +CONFIG_COMP_MULTIBAND_DRC=n +CONFIG_COMP_TONE=n +CONFIG_COMP_SWITCH=n +CONFIG_COMP_KPB=n +CONFIG_MAXIM_DSM=n +CONFIG_COMP_ASRC=n +CONFIG_COMP_IGO_NR=n +CONFIG_COMP_COPIER=n +CONFIG_COMP_RTNR=n +CONFIG_COMP_ARIA=n +CONFIG_COMP_BASEFW_IPC4=n +CONFIG_COMP_UP_DOWN_MIXER=n +CONFIG_COMP_TDFB=n +CONFIG_COMP_MUX=n +CONFIG_COMP_SEL=n +CONFIG_COMP_MIXER=n +CONFIG_PROBE=n diff --git a/src/arch/xtensa/configs/mt8196_defconfig b/src/arch/xtensa/configs/mt8196_defconfig new file mode 100644 index 000000000000..f030ddc4fe2f --- /dev/null +++ b/src/arch/xtensa/configs/mt8196_defconfig @@ -0,0 +1,16 @@ +CONFIG_MT8196=y +CONFIG_CORE_COUNT=1 +CONFIG_COMP_VOLUME=y +CONFIG_COMP_SRC=n +CONFIG_COMP_FIR=n +CONFIG_COMP_IIR=n +CONFIG_COMP_DCBLOCK=n +CONFIG_COMP_TDFB=n +CONFIG_COMP_TONE=n +CONFIG_COMP_MIXER=n +CONFIG_COMP_MUX=n +CONFIG_COMP_KPB=n +CONFIG_COMP_SEL=n +CONFIG_COMP_ASRC=n +CONFIG_DEBUG=y +CONFIG_SCHEDULE_LL_NO_RESCHEDULE_TASK=y diff --git a/src/arch/xtensa/configs/mt8365_defconfig b/src/arch/xtensa/configs/mt8365_defconfig new file mode 100644 index 000000000000..3631692a10ff --- /dev/null +++ b/src/arch/xtensa/configs/mt8365_defconfig @@ -0,0 +1,15 @@ +CONFIG_MT8365=y +CONFIG_CORE_COUNT=1 +CONFIG_XT_VIRTUAL_OPS=1 +CONFIG_COMP_VOLUME=y +CONFIG_COMP_SRC=n +CONFIG_COMP_FIR=n +CONFIG_COMP_IIR=n +CONFIG_COMP_DCBLOCK=n +CONFIG_COMP_TDFB=n +CONFIG_COMP_TONE=n +CONFIG_COMP_MIXER=n +CONFIG_COMP_MUX=n +CONFIG_COMP_KPB=n +CONFIG_COMP_SEL=n +CONFIG_COMP_ASRC=n diff --git a/src/arch/xtensa/configs/override/mt8196_chrome_dts.config b/src/arch/xtensa/configs/override/mt8196_chrome_dts.config new file mode 100644 index 000000000000..0160eaea199a --- /dev/null +++ b/src/arch/xtensa/configs/override/mt8196_chrome_dts.config @@ -0,0 +1,3 @@ +CONFIG_COMP_IIR=y +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_DTS_CODEC=y diff --git a/src/arch/xtensa/configs/override/mt8196_chrome_waves.config b/src/arch/xtensa/configs/override/mt8196_chrome_waves.config new file mode 100644 index 000000000000..6e0143275ba6 --- /dev/null +++ b/src/arch/xtensa/configs/override/mt8196_chrome_waves.config @@ -0,0 +1,2 @@ +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_WAVES_CODEC=y diff --git a/src/arch/xtensa/debug/CMakeLists.txt b/src/arch/xtensa/debug/CMakeLists.txt deleted file mode 100644 index 2148cd3bd201..000000000000 --- a/src/arch/xtensa/debug/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -if (CONFIG_GDB_DEBUG) - add_subdirectory(gdb) -endif() diff --git a/src/arch/xtensa/debug/gdb/CMakeLists.txt b/src/arch/xtensa/debug/gdb/CMakeLists.txt deleted file mode 100644 index 2718ca511758..000000000000 --- a/src/arch/xtensa/debug/gdb/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -add_local_sources(sof init.S debugexception.S utilities.c) diff --git a/src/arch/xtensa/debug/gdb/debugexception.S b/src/arch/xtensa/debug/gdb/debugexception.S deleted file mode 100644 index d129261256e2..000000000000 --- a/src/arch/xtensa/debug/gdb/debugexception.S +++ /dev/null @@ -1,230 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Marcin Rajwa <marcin.rajwa@linux.intel.com> - */ - -/* - * Debug context switch. - * - */ - -#include <arch/debug/gdb/xtensa-defs.h> -#include <xtensa/config/core-isa.h> -#include <xtensa/specreg.h> - -#define DENSITY_BREAK_INS_IDENT 0x40 -#define NEXT_INST_OFFSET 0x03 -#define PS_EXCM_EXCEPTION_MODE 0x10 -#define PS_EXCM_MODE_MASK (~PS_EXCM_EXCEPTION_MODE) -#define DEBUG_GDB_MEM_LOC 0x9E008060 - -/* -Save special register designated by 'reg' into -backup space calculated by offset 'loc * 4' from -memory pointed by a3. -*/ -.macro SAVE_ reg, loc - rsr a1, \reg - s32i a1, a3, \loc * 4 -.endm - -.macro SAVE reg - SAVE_ \reg, \reg -.endm - -/* -Load special register designated by 'reg' from -backup space calculated by offset 'loc * 4' from -memory pointed by a3. -*/ -.macro LOAD_ reg, loc - l32i a1, a3, \loc * 4 - wsr a1, \reg -.endm - -.macro LOAD reg - LOAD_ \reg, \reg -.endm - - - -.text - -/* -Temporary stack for context switch -TODO: move it to dedicated GDB_STACK section -*/ - -gdb_stack: - .fill 0x1000 , 4 , 0 -gdb_stack_end: - -.global DebugExceptionEntry -.align 4 - -/* -Backup important special registers plus -all regular ones (whole register file). -Change EXCM field of PS back to normal mode -after an interrupt took place. -*/ -DebugExceptionEntry: - - movi a2, aregs - s32i a0, a2, 0 - s32i a1, a2, 4 - rsr a1, DEBUG_EXCSAVE - s32i a1, a2, 8 - s32i a3, a2, 12 - - movi a3, sregs - SAVE LBEG - SAVE LEND - SAVE LCOUNT - SAVE SAR - SAVE WINDOWBASE - SAVE WINDOWSTART - - rsr a1, DEBUG_PC - l8ui a2, a1, 1 - movi a0, DENSITY_BREAK_INS_IDENT - bne a2, a0, 1f - addi a1, a1, NEXT_INST_OFFSET -1: - s32i a1, a3, DEBUG_PC * 4 - - SAVE EXCSAVE_1 - SAVE_ DEBUG_PS, PS - SAVE EXCCAUSE - SAVE DEBUGCAUSE - SAVE EXCVADDR - - /* - (XCHAL_NUM_AREGS / 4 - 1) - A number which holds information on how many - registers are left to backup. Divide by four since we backup registers - in group of four. Minus one, since one group has already been saved. - */ - movi a1, XCHAL_NUM_AREGS / 4 - 1 - movi a2, aregs -1: - s32i a4, a2, 16 - s32i a5, a2, 20 - s32i a6, a2, 24 - s32i a7, a2, 28 - - addi a6, a2, 16 - addi a5, a1, -1 - rotw 1 - bnez a1, 1b - - movi a1, 1 - wsr a1, windowstart - movi a0, 0 - wsr a0, windowbase - rsync - - /* Setup of stack frame with 20 bytes for extra save area */ - movi a0, 0 - movi a1, gdb_stack + STACK_SIZE - 20 - rsr a2, PS - - /* Set exception mode back to normal */ - movi a3, PS_EXCM_MODE_MASK - and a2, a2, a3 - wsr a2, PS - rsync - - /* reset icountlevel - essential when coming back from single step */ - movi a2, 0x00 - wsr a2, ICOUNTLEVEL - - movi a4, gdb_handle_exception - callx4 a4 - -/* -Restore important special registers plus -all regular ones (whole register file). -Change EXCM field of PS back to exception mode -and return from interrupt. -*/ -DebugExceptionExit: - movi a2, DebugExceptionEntry - wsr a2, DEBUG_EXCSAVE - - rsr a4, PS - movi a3, PS_EXCM_EXCEPTION_MODE - or a4, a4, a3 - wsr a4, PS - rsync - - movi a3, sregs - LOAD LBEG - LOAD LEND - LOAD LCOUNT - LOAD SAR - LOAD WINDOWBASE - rsync - - movi a3, sregs - LOAD WINDOWSTART - LOAD DEBUG_PC - LOAD EXCSAVE_1 - LOAD EXCCAUSE - LOAD EXCVADDR - LOAD INTENABLE - rsync - - movi a6, aregs - movi a5, XCHAL_NUM_AREGS / 4 - 2 -1: - l32i a0, a6, 0 - l32i a1, a6, 4 - l32i a2, a6, 8 - l32i a3, a6, 12 - - beqz a5, 2f - addi a10, a6, 16 - addi a9, a5, -1 - rotw 1 - j 1b -2: - l32i a4, a6, 16 - l32i a5, a6, 20 - l32i a7, a6, 28 - l32i a6, a6, 24 - rotw 2 - - rfi XCHAL_DEBUGLEVEL - - -/* -Put some important interrupt related registers into memory window -pointed by DEBUG_GDB_MEM_LOC -*/ -.global gdb_debug_info -.align 4 - -gdb_debug_info: - - entry a1, 16 - movi a3, DEBUG_GDB_MEM_LOC - l32i a4, a2, 0 //load 4 bytes of message ID from incoming argv - rsr a4, EPC_1 - rsr a5, EPC_2 - rsr a6, EXCCAUSE - rsr a7, DEPC - rsr a8, DEBUG_PS - - s32i a4, a3, 0 - s32i a5, a3, 4 - s32i a6, a3, 8 - s32i a7, a3, 12 - s32i a8, a3, 16 - - isync - rsync - retw - -.size gdb_debug_info, . -gdb_debug_info diff --git a/src/arch/xtensa/debug/gdb/init.S b/src/arch/xtensa/debug/gdb/init.S deleted file mode 100644 index 336816aa41d4..000000000000 --- a/src/arch/xtensa/debug/gdb/init.S +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Marcin Rajwa <marcin.rajwa@linux.intel.com> - */ - -/* - * Init debug exeption and enable global breakpoints. - * - */ - -#include <arch/debug/gdb/xtensa-defs.h> - -.text -.global gdb_init_debug_exception -.align 4 - -gdb_init_debug_exception: - entry a1, 16 - - movi a3, DebugExceptionEntry - wsr a3, DEBUG_EXCSAVE - - /* enable breakpoints */ - movi a3, 1 - wsr a3, DEBUG_IBREAKENABLE - - isync - rsync - retw - -.size gdb_init_debug_exception, . - gdb_init_debug_exception diff --git a/src/arch/xtensa/debug/gdb/utilities.c b/src/arch/xtensa/debug/gdb/utilities.c deleted file mode 100644 index 35579d763026..000000000000 --- a/src/arch/xtensa/debug/gdb/utilities.c +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2019 Intel Corporation. All rights reserved. -// -// Author: Marcin Rajwa <marcin.rajwa@linux.intel.com> - -/* - * Xtensa related functions for GDB. - * - */ -#define GDB_DISABLE_LOWER_INTERRUPTS_MASK ~0x1F - -#include <arch/debug/gdb/utilities.h> -#include <xtensa/config/core-isa.h> -#include <xtensa/specreg.h> - -void arch_gdb_read_sr(int sr) -{ - int val; - - asm volatile ("movi a3, 1f + 1\n" - "s8i %1, a3, 0\n" - "dhwb a3, 0\n" - "ihi a3, 0\n" - "isync\n" - "1:\n" - "rsr %0, lbeg\n" - : "=r"(val) - : "r"(sr) - : "a3", "memory"); -} - -void arch_gdb_write_sr(int sr, int *sregs) -{ - asm volatile ("movi a3, 1f + 1\n" - "s8i %1, a3, 0\n" - "dhwb a3, 0\n" - "ihi a3, 0\n" - "isync\n" - "1:\n" - "wsr %0, lbeg\n" - : - : "r"(sregs[sr]), "r"(sr) - : "a3", "memory"); -} - -unsigned char arch_gdb_load_from_memory(void *mem) -{ - unsigned long v; - unsigned long addr = (unsigned long)mem; - unsigned char ch; - - asm volatile ("_l32i %0, %1, 0\n" - : "=r"(v) - : "r"(addr & ~3) - : "memory"); - ch = v >> (addr & 3) * 8; - - return ch; -} - -void arch_gdb_memory_load_and_store(void *mem, unsigned char ch) -{ - unsigned long tmp; - unsigned long addr = (unsigned long)mem; - - asm volatile ("_l32i %0, %1, 0\n" - "and %0, %0, %2\n" - "or %0, %0, %3\n" - "_s32i %0, %1, 0\n" - "dhwb %1, 0\n" - "ihi %1, 0\n" - : "=&r"(tmp) - : "r"(addr & ~3), "r"(0xffffffff ^ (0xff << - (addr & 3) * 8)), - "r"(ch << (addr & 3) * 8) - : "memory"); -} - -void arch_gdb_single_step(int *sregs) -{ - /* leave debug just for one instruction */ - sregs[ICOUNT] = 0xfffffffe; - sregs[ICOUNTLEVEL] = XCHAL_DEBUGLEVEL; - /* disable low level interrupts */ - sregs[INTENABLE] &= ~GDB_DISABLE_LOWER_INTERRUPTS_MASK; - arch_gdb_write_sr(ICOUNTLEVEL, sregs); - arch_gdb_write_sr(ICOUNT, sregs); - arch_gdb_write_sr(INTENABLE, sregs); -} diff --git a/src/arch/xtensa/drivers/CMakeLists.txt b/src/arch/xtensa/drivers/CMakeLists.txt deleted file mode 100644 index 09565763093a..000000000000 --- a/src/arch/xtensa/drivers/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -add_local_sources(sof interrupt.c cache_attr.c) - -if(NOT CONFIG_ZEPHYR_SOF_MODULE) - add_local_sources(sof timer.c) -endif() diff --git a/src/arch/xtensa/drivers/interrupt.c b/src/arch/xtensa/drivers/interrupt.c deleted file mode 100644 index f9ca5ba252f1..000000000000 --- a/src/arch/xtensa/drivers/interrupt.c +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2020 Intel Corporation. All rights reserved. -// -// Author: Janusz Jankowski <janusz.jankowski@linux.intel.com> - -#include <rtos/interrupt.h> - -#if CONFIG_WAKEUP_HOOK -void arch_interrupt_on_wakeup(void) -{ - platform_interrupt_on_wakeup(); -} -#endif diff --git a/src/arch/xtensa/drivers/timer.c b/src/arch/xtensa/drivers/timer.c deleted file mode 100644 index 71c93590c293..000000000000 --- a/src/arch/xtensa/drivers/timer.c +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2016 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - -#include <rtos/interrupt.h> -#include <rtos/timer.h> -#include <sof/lib/memory.h> -#include <xtensa/config/core-isa.h> -#include <xtensa/hal.h> -#include <errno.h> -#include <stdint.h> - -void timer_64_handler(void *arg) -{ - struct timer *timer = arg; - uint32_t ccompare; - - if (timer->id >= ARCH_TIMER_COUNT) - return; - - /* get comparator value - will tell us timeout reason */ - ccompare = xthal_get_ccompare(timer->id); - - /* is this a 32 bit rollover ? */ - if (ccompare == 1) { - /* roll over the timer */ - timer->hitime++; - arch_timer_clear(timer); - } else { - /* no roll over, run the handler */ - if (timer->handler) - timer->handler(timer->data); - } - - /* get next timeout value */ - if (timer->hitimeout == timer->hitime) { - /* timeout is in this 32 bit period */ - ccompare = timer->lowtimeout; - } else { - /* timeout is in another 32 bit period */ - ccompare = 1; - } - - xthal_set_ccompare(timer->id, ccompare); -} - -int timer64_register(struct timer *timer, void(*handler)(void *arg), void *arg) -{ - if (timer->id >= ARCH_TIMER_COUNT) - return -EINVAL; - - timer->handler = handler; - timer->data = arg; - timer->hitime = 0; - timer->hitimeout = 0; - - return 0; -} - -uint64_t arch_timer_get_system(struct timer *timer) -{ - uint64_t time = 0; - uint32_t flags; - uint32_t low; - uint32_t high; - uint32_t ccompare; - - if (timer->id >= ARCH_TIMER_COUNT) - goto out; - - ccompare = xthal_get_ccompare(timer->id); - - flags = arch_interrupt_global_disable(); - - /* read low 32 bits */ - low = xthal_get_ccount(); - - /* check and see whether 32bit IRQ is pending for timer */ - if (arch_interrupt_get_status() & (1 << timer->irq) && ccompare == 1) { - /* yes, overflow has occured but handler has not run */ - high = timer->hitime + 1; - } else { - /* no overflow */ - high = timer->hitime; - } - - time = ((uint64_t)high << 32) | low; - - arch_interrupt_global_enable(flags); - -out: - - return time; -} - -int64_t arch_timer_set(struct timer *timer, uint64_t ticks) -{ - uint32_t time = 1; - uint32_t hitimeout = ticks >> 32; - uint32_t flags; - int64_t ret; - - if (timer->id >= ARCH_TIMER_COUNT) { - ret = -EINVAL; - goto out; - } - - /* value of 1 represents rollover */ - if ((ticks & 0xffffffff) == 0x1) - ticks++; - - flags = arch_interrupt_global_disable(); - - /* same hi 64 bit context as ticks ? */ - if (hitimeout < timer->hitime) { - /* cant be in the past */ - arch_interrupt_global_enable(flags); - ret = -EINVAL; - goto out; - } - - /* check whether new timeout requires timer - * rollover. If so, ccompare value should - * be set to 1 in order to increment timer->hitime - * properly in timer_64_handler(). - */ - if (timer->hitime < hitimeout) - time = 1; - else - time = ticks; - - timer->hitimeout = hitimeout; - timer->lowtimeout = ticks; - - xthal_set_ccompare(timer->id, time); - - arch_interrupt_global_enable(flags); - - ret = ticks; - -out: - - return ret; -} diff --git a/src/arch/xtensa/exc-dump.S b/src/arch/xtensa/exc-dump.S deleted file mode 100644 index 060cc9c4a829..000000000000 --- a/src/arch/xtensa/exc-dump.S +++ /dev/null @@ -1,156 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - */ - -#include <arch/debug/offset-defs.h> -#include <xtensa/config/core-isa.h> -#include <xtensa/corebits.h> - - .section .text, "ax" - .align 64 -literals: - .literal_position - .global arch_dump_regs_a - .type arch_dump_regs_a, @function - -/* - * params: - * a2 - ptr to dump mem buffer - */ -arch_dump_regs_a: - entry a1, 16 - - /* all accessible physical registers */ - - s32i a0, a2, REG_OFFSET_AR_BEGIN - s32i a1, a2, REG_OFFSET_AR_BEGIN + 0x4 - s32i a2, a2, REG_OFFSET_AR_BEGIN + 0x8 - s32i a3, a2, REG_OFFSET_AR_BEGIN + 0xc - s32i a4, a2, REG_OFFSET_AR_BEGIN + 0x10 - s32i a5, a2, REG_OFFSET_AR_BEGIN + 0x14 - s32i a6, a2, REG_OFFSET_AR_BEGIN + 0x18 - s32i a7, a2, REG_OFFSET_AR_BEGIN + 0x1c - memw - - /* store PS */ - rsr a3, PS - s32i a3, a2, REG_OFFSET_PS - - /* - * copy original a2 to a3 as we will increment it in the loop with - * offset to AR registers with addition of 8 registers already read. - * It will be the base for next reg dump - */ - movi a3, REG_OFFSET_AR_BEGIN + 8*4 - add a3, a2, a3 - - /* - * storing rest of AREGS starts here - * a4 - number of 8-reg chunks to save (a0-a7 already done) - */ - movi a4, XCHAL_NUM_AREGS / 8 - 1 - - /* set exception mode if we are on core 0 */ - rsr a6, PRID - bnez a6, mask_interrupts_on_core0 - movi a5, PS_EXCM | PS_INTLEVEL(0x5) - wsr a5, PS - rsync - - /* exception mode set so no need to set interrupt mask */ - j store_register_loop - -mask_interrupts_on_core0: - /* - * if we are in core context different than 0 - * disable interrupts on core 0 - * only level 2 interrupts disabled for now on - */ - /* TODO */ - -store_register_loop: - s32i a8, a3, 0 - s32i a9, a3, 4 - s32i a10, a3, 8 - s32i a11, a3, 0xc - s32i a12, a3, 0x10 - s32i a13, a3, 0x14 - s32i a14, a3, 0x18 - s32i a15, a3, 0x1c - - addi a11, a3, 32 // after rotation a11 will be next a3 - addi a12, a4, -1 // after rotation a12 will be next a4 - iter decrement - /* - * restore registers from current window to preserve backtrace - * upon return - */ - addi a3, a3, -20 - l32i a4, a3, 4 - l32i a3, a3, 0 - rotw 2 - bnez a4, store_register_loop - rotw 2 - memw - -dump_special_registers: - rsr a6, EPC2 - s32i a6, a2, REG_OFFSET_EPC2 - rsr a6, EPC3 - s32i a6, a2, REG_OFFSET_EPC3 - rsr a6, EPC4 - s32i a6, a2, REG_OFFSET_EPC4 -#if XCHAL_INTLEVEL5_MASK - rsr a6, EPC5 - s32i a6, a2, REG_OFFSET_EPC5 -#endif -#if XCHAL_INTLEVEL6_MASK - rsr a6, EPC6 - s32i a6, a2, REG_OFFSET_EPC6 -#endif -#if XCHAL_INTLEVEL7_MASK - rsr a6, EPC7 - s32i a6, a2, REG_OFFSET_EPC7 -#endif - rsr a6, EPS2 - s32i a6, a2, REG_OFFSET_EPS2 - rsr a6, EPS3 - s32i a6, a2, REG_OFFSET_EPS3 - rsr a6, EPS4 - s32i a6, a2, REG_OFFSET_EPS4 -#if XCHAL_INTLEVEL5_MASK - rsr a6, EPS5 - s32i a6, a2, REG_OFFSET_EPS5 -#endif -#if XCHAL_INTLEVEL6_MASK - rsr a6, EPS6 - s32i a6, a2, REG_OFFSET_EPS6 -#endif -#if XCHAL_INTLEVEL7_MASK - rsr a6, EPS7 - s32i a6, a2, REG_OFFSET_EPS7 -#endif - rsr a6, DEPC - s32i a6, a2, REG_OFFSET_DEPC - rsr a6, DEBUGCAUSE - s32i a6, a2, REG_OFFSET_DEBUGCAUSE - rsr a6, EXCCAUSE - s32i a6, a2, REG_OFFSET_EXCCAUSE - rsr a6, INTERRUPT - s32i a6, a2, REG_OFFSET_INTERRUPT - rsr a6, EXCVADDR - s32i a6, a2, REG_OFFSET_EXCVADDR - rsr a6, EXCSAVE1 - s32i a6, a2, REG_OFFSET_EXCSAVE1 - rsr a6, WINDOWBASE - s32i a6, a2, REG_OFFSET_WINDOWBASE - rsr a6, WINDOWSTART - s32i a6, a2, REG_OFFSET_WINDOWSTART - - /* restore processor_state */ -restore_processor_state: - /* restore previously saved PS before return */ - l32i a3, a2, REG_OFFSET_PS - wsr a3, PS - rsync - retw diff --git a/src/arch/xtensa/hal/CMakeLists.txt b/src/arch/xtensa/hal/CMakeLists.txt deleted file mode 100644 index 605c3f1beb67..000000000000 --- a/src/arch/xtensa/hal/CMakeLists.txt +++ /dev/null @@ -1,143 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -set(STATE_DEFS - -D__SPLIT__extra_size - -D__SPLIT__extra_align - -D__SPLIT__cpregs_size - -D__SPLIT__cpregs_align - -D__SPLIT__cp_names - -D__SPLIT__all_extra_size - -D__SPLIT__all_extra_align - -D__SPLIT__num_coprocessors - -D__SPLIT__cp_num - -D__SPLIT__cp_max - -D__SPLIT__cp_mask - -D__SPLIT__cp_id_mappings - -D__SPLIT__cp_mask_mappings - -D__SPLIT__init_mem_extra - -D__SPLIT__init_mem_cp - -D__SPLIT__save_extra - -D__SPLIT__restore_extra - -D__SPLIT__save_cpregs - -D__SPLIT__save_cp0 - -D__SPLIT__save_cp1 - -D__SPLIT__save_cp2 - -D__SPLIT__save_cp3 - -D__SPLIT__save_cp4 - -D__SPLIT__save_cp5 - -D__SPLIT__save_cp6 - -D__SPLIT__save_cp7 - -D__SPLIT__restore_cpregs - -D__SPLIT__restore_cp0 - -D__SPLIT__restore_cp1 - -D__SPLIT__restore_cp2 - -D__SPLIT__restore_cp3 - -D__SPLIT__restore_cp4 - -D__SPLIT__restore_cp5 - -D__SPLIT__restore_cp6 - -D__SPLIT__restore_cp7 - -D__SPLIT__cpregs_save_fn - -D__SPLIT__cpregs_restore_fn - -D__SPLIT__validate_cp - -D__SPLIT__invalidate_cp - -D__SPLIT__get_cpenable - -D__SPLIT__set_cpenable -) - -set(DISASS_DEFS - -D__SPLIT__op0_format_lengths - -D__SPLIT__byte0_format_lengths - -D__SPLIT__disassemble_size - -D__SPLIT__disassemble -) - -set(MISC_DEFS - -D__SPLIT__clear_regcached_code -) - -# Call0 ABI means the xthal... and xthal..._nw functions are -# identical. If we're building for Call0 ABI, omit the ..._nw -# functions (except for xthal_get_intpending_nw, an interrupt handler -# helper function for which there is no duplicate and which does not -# obey _any_ calling conventions). -set(INTERRUPTS_DEFS - -D__SPLIT__num_intlevels - -D__SPLIT__num_interrupts - -D__SPLIT__excm_level - -D__SPLIT__intlevel - -D__SPLIT__get_intenable - -D__SPLIT__set_intenable - -D__SPLIT__get_interrupt - -D__SPLIT__set_intset - -D__SPLIT__set_intclear -) - -set(CACHE_DEFS - -D__SPLIT__get_cacheattr - -D__SPLIT__get_icacheattr - -D__SPLIT__set_cacheattr - -D__SPLIT__set_icacheattr - -D__SPLIT__set_dcacheattr - -D__SPLIT__set_idcacheattr - -D__SPLIT__idcache_is_enabled - -D__SPLIT__icache_is_enabled - -D__SPLIT__dcache_is_enabled - -D__SPLIT__idcache_is_enabled - -D__SPLIT__icache_all_invalidate - -D__SPLIT__dcache_all_invalidate - -D__SPLIT__dcache_all_writeback - -D__SPLIT__dcache_all_writeback_inv - -D__SPLIT__icache_all_unlock - -D__SPLIT__dcache_all_unlock - -D__SPLIT__icache_region_invalidate - -D__SPLIT__dcache_region_invalidate - -D__SPLIT__dcache_region_writeback - -D__SPLIT__dcache_region_writeback_inv - -D__SPLIT__icache_region_lock - -D__SPLIT__dcache_region_lock - -D__SPLIT__icache_region_unlock - -D__SPLIT__dcache_region_unlock - -D__SPLIT__icache_line_invalidate - -D__SPLIT__dcache_line_invalidate - -D__SPLIT__dcache_line_writeback - -D__SPLIT__dcache_line_writeback_inv - -D__SPLIT__icache_line_lock - -D__SPLIT__dcache_line_lock - -D__SPLIT__icache_line_unlock - -D__SPLIT__dcache_line_unlock - -D__SPLIT__icache_sync - -D__SPLIT__dcache_sync - -D__SPLIT__icache_get_ways - -D__SPLIT__icache_set_ways - -D__SPLIT__dcache_get_ways - -D__SPLIT__dcache_set_ways - -D__SPLIT__cache_coherence_on - -D__SPLIT__cache_coherence_off - -D__SPLIT__set_cache_prefetch_long - -D__SPLIT__set_cache_prefetch - -D__SPLIT__get_cache_prefetch - -D__SPLIT__hw_configid0 - -D__SPLIT__hw_configid1 - -D__SPLIT__release_major - -D__SPLIT__release_minor -) - -add_library(hal STATIC "") -target_link_libraries(hal sof_options) -target_compile_definitions(hal PRIVATE - ${STATE_DEFS} - ${DISASS_DEFS} - ${MISC_DEFS} - ${INTERRUPTS_DEFS} - ${CACHE_DEFS} -) - -add_local_sources(hal - cache_asm.S - clock.S - int_asm.S - interrupts.c - memcopy.S - windowspill_asm.S - atomics.c -) diff --git a/src/arch/xtensa/hal/atomics.c b/src/arch/xtensa/hal/atomics.c deleted file mode 100644 index d7abc128f966..000000000000 --- a/src/arch/xtensa/hal/atomics.c +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -#include <stdint.h> -#include <xtensa/hal.h> - -int _xt_atomic_compare_exchange_4(int *address, int32_t test_value, int32_t set_value); - -int _xt_atomic_compare_exchange_4(int *address, int32_t test_value, int32_t set_value) -{ - return xthal_compare_and_set(address, test_value, set_value); -} diff --git a/src/arch/xtensa/hal/attribute.c b/src/arch/xtensa/hal/attribute.c deleted file mode 100644 index 7d663b2e55fe..000000000000 --- a/src/arch/xtensa/hal/attribute.c +++ /dev/null @@ -1,282 +0,0 @@ -/* attribute.c - Cache attribute (memory access mode) related functions */ - -/* $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/attribute.c#1 $ */ - -/* - * Copyright (c) 2004-2009 Tensilica 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. - */ - -#include <xtensa/config/core.h> - - - -/* - * Set the "cache attribute" (encoded memory access modes) - * of the region of memory specified by <vaddr> and <size>. - * - * This function is only supported on processor configurations - * with region protection (or XEA1). It has no effect on - * a processor configured with an MMU (with autorefill). - * - * SPECIFYING THE MEMORY REGION - * The full (4 GB) address space may be specified with an - * address of zero and a size of 0xFFFFFFFF (or -1); - * in fact whenever <vaddr>+<size> equal 0xFFFFFFFF, <size> - * is interpreted as one byte greater than that specified. - * - * If the specified memory range exactly covers a series - * of consecutive 512 MB regions, the cache attributes of - * these regions are updated with the requested attribute. - * If this is not the case, e.g. if either or both the - * start and end of the range only partially cover a 512 MB - * region, one of three results are possible: - * - * 1. By default, the cache attribute of all regions - * covered, even just partially, is changed to - * the requested attribute. - * - * 2. If the XTHAL_CAFLAG_EXACT flag is specified, - * a non-zero error code is returned. - * - * 3. If the XTHAL_CAFLAG_NO_PARTIAL flag is specified - * (but not the EXACT flag), only regions fully - * covered by the specified range are updated with - * the requested attribute. - * - * WRITEBACK CACHE HANDLING - * This function automatically writes back dirty data when - * switching a region from writeback mode to a non-writeback mode. - * This writeback is done safely, ie. by first switching to writethrough - * mode, then invoking xthal_dcache_all_writeback(), then switching to - * the selected <cattr> mode. Such a sequence is necessary to ensure - * there is no longer any dirty data in the memory region by the time - * this function returns, even in the presence of interrupts, speculation, etc. - * This avoids memory coherency problems when switching from writeback - * to bypass mode (in bypass mode, loads go directly to memory, ignoring - * any dirty data in the cache; also, such dirty data can still be castout - * due to seemingly unrelated stores). - * This automatic write-back can be disabled using the XTHAL_CAFLAG_NO_AUTO_WB flag. - * - * CACHE DISABLE THEN ENABLE HANDLING - * To avoid cache coherency issues when the cache is disabled, then - * memory is modified, then then cache is re-enabled (thus making - * visible stale cache entries), this function automatically - * invalidates the cache when any region switches to bypass mode. - * For efficiency, the entire cache is invalidated -- this is done - * using writeback-invalidate operations to ensure coherency even - * when other regions still have write-back caches enabled. - * This automatic invalidate can be disabled using the XTHAL_CAFLAG_NO_AUTO_INV flag. - * - * Parameters: - * vaddr starting virtual address of region of memory - * - * size number of bytes in region of memory - * (see above, SPECIFYING THE MEMORY REGION) - * - * cattr cache attribute (encoded); - * typically taken from compile-time HAL constants - * XCHAL_CA_{BYPASS[BUF], WRITETHRU, WRITEBACK[_NOALLOC], ILLEGAL} - * (defined in <xtensa/config/core.h>); - * in XEA1, this corresponds to the value of a nibble - * in the CACHEATTR register; - * in XEA2, this corresponds to the value of the - * cache attribute (CA) field of each TLB entry - * - * On MPU configurations, the cattr is composed of accessRights - * and memoryType. The accessRights occupy bits 0..3 and are - * typically taken from the XTHAL_AR constants. The memory type - * is specified by either a bitwise or-ing of the XTHAL_MEM_... - * constants or if none of the XTHAL_MEM_... constants are - * specified, bits 4..12 are used for the memory type (that - * allows a cattr obtained by xthal_v2p() to be passed directly. - * - * In addition on MPU configurations if the - * XTHAL_MPU_USE_EXISTING_MEMORY_TYPE bit is set then the existing - * memoryType at the first address in the region is used for the - * memoryType of the new region. - * - * Likewise, if the XTHAL_MPU_USE_EXISTING_ACCESS_RIGHTS bit is set - * in cattr, then the existing accessRights at the first address - * in the region are used for the accessRights of the new region. - * - * flags bitwise combination of flags XTHAL_CAFLAG_* - * (see xtensa/hal.h for brief description of each flag); - * (see also various descriptions above); - * - * The XTHAL_CAFLAG_EXPAND flag prevents attribute changes - * to regions whose current cache attribute already provide - * greater access than the requested attribute. - * This ensures access to each region can only "expand", - * and thus continue to work correctly in most instances, - * possibly at the expense of performance. This helps - * make this flag safer to use in a variety of situations. - * For the purposes of this flag, cache attributes are - * ordered (in "expansion" order, from least to greatest - * access) as follows: - * XCHAL_CA_ILLEGAL no access allowed - * (various special and reserved attributes) - * XCHAL_CA_WRITEBACK writeback cached - * XCHAL_CA_WRITEBACK_NOALLOC writeback no-write-alloc - * XCHAL_CA_WRITETHRU writethrough cached - * XCHAL_CA_BYPASSBUF bypass with write buffering - * XCHAL_CA_BYPASS bypass (uncached) - * This is consistent with requirements of certain - * devices that no caches be used, or in certain cases - * that writethrough caching is allowed but not writeback. - * Thus, bypass mode is assumed to work for most/all types - * of devices and memories (albeit at reduced performance - * compared to cached modes), and is ordered as providing - * greatest access (to most devices). - * Thus, this XTHAL_CAFLAG_EXPAND flag has no effect when - * requesting the XCHAL_CA_BYPASS attribute (one can always - * expand to bypass mode). And at the other extreme, - * no action is ever taken by this function when specifying - * both the XTHAL_CAFLAG_EXPAND flag and the XCHAL_CA_ILLEGAL - * cache attribute. - * - * The XTHAL_CAFLAG_EXPAND is not supported on MPU configurations. - * - * Returns: - * 0 successful, or size is zero - * -1 XTHAL_CAFLAG_NO_PARTIAL flag specified and address range - * is valid with a non-zero size, however no 512 MB region (or page) - * is completely covered by the range - * -2 XTHAL_CAFLAG_EXACT flag specified, and address range does - * not exactly specify a 512 MB region (or page) - * -3 invalid address range specified (wraps around the end of memory) - * -4 function not supported in this processor configuration - */ -int xthal_set_region_attribute( void *vaddr, unsigned size, unsigned cattr, unsigned flags ) -{ -#if XCHAL_HAVE_MPU - if (cattr & 0xffffe000) // check if XTHAL mem flags were supplied - // in this case just pass cattr as the memType paramenter - return xthal_mpu_set_region_attribute(vaddr, size, cattr, cattr, flags); - else - // otherwise we take the bits 0-3 for accessRights and bits 4-13 as the memoryType - return xthal_mpu_set_region_attribute(vaddr, size, cattr & 0xf, (cattr & 0x1ff0) >> 4, flags); -#elif XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY - return -4; /* full MMU not supported */ -#else -/* These cache attribute encodings are valid for XEA1 and region protection only: */ -# if XCHAL_HAVE_PTP_MMU -# define CA_BYPASS XCHAL_CA_BYPASS -# ifdef XCHAL_CA_BYPASSBUF -# define CA_BYPASSBUF XCHAL_CA_BYPASSBUF -# else -# define CA_BYPASSBUF XCHAL_CA_BYPASS -# endif -# define CA_WRITETHRU XCHAL_CA_WRITETHRU -# define CA_WRITEBACK XCHAL_CA_WRITEBACK -# define CA_WRITEBACK_NOALLOC XCHAL_CA_WRITEBACK_NOALLOC -# define CA_ILLEGAL XCHAL_CA_ILLEGAL -# else -/* Hardcode these, because they get remapped when caches or writeback not configured: */ -# define CA_BYPASS 2 -# define CA_BYPASSBUF 6 -# define CA_WRITETHRU 1 -# define CA_WRITEBACK 4 -# define CA_WRITEBACK_NOALLOC 5 -# define CA_ILLEGAL 15 -# endif -# define CA_MASK 0xF /*((1L<<XCHAL_CA_BITS)-1)*/ /* mask of cache attribute bits */ -# define IS_CACHED(attr) ((attr == CA_BYPASS) || (attr == CA_BYPASSBUF)) - - unsigned start_region, start_offset, end_vaddr, end_region, end_offset; - unsigned cacheattr, cachewrtr, i, disabled_cache = 0; - - if (size == 0) - return 0; - end_vaddr = (unsigned)vaddr + size - 1; - if (end_vaddr < (unsigned)vaddr) - return -3; /* address overflow/wraparound error */ - if (end_vaddr == 0xFFFFFFFE /*&& (unsigned)vaddr == 0*/ ) - end_vaddr = 0xFFFFFFFF; /* allow specifying 4 GB */ - start_region = ((unsigned)vaddr >> 29); - start_offset = ((unsigned)vaddr & 0x1FFFFFFF); - end_region = (end_vaddr >> 29); - end_offset = ((end_vaddr+1) & 0x1FFFFFFF); - if (flags & XTHAL_CAFLAG_EXACT) { - if (start_offset != 0 || end_offset != 0) - return -2; /* not an exact-sized range */ - } else if (flags & XTHAL_CAFLAG_NO_PARTIAL) { - if (start_offset != 0) - start_region++; - if (end_offset != 0) - end_region--; - if (start_region > end_region) - return -1; /* nothing fully covered by specified range */ - } - cacheattr = cachewrtr = xthal_get_cacheattr(); - cattr &= CA_MASK; -# if XCHAL_ICACHE_SIZE == 0 && XCHAL_DCACHE_SIZE == 0 - if (cattr == CA_WRITETHRU || cattr == CA_WRITEBACK || cattr == CA_WRITEBACK_NOALLOC) - cattr = CA_BYPASS; /* no caches configured, only do protection */ -# elif XCHAL_DCACHE_IS_WRITEBACK == 0 - if (cattr == CA_WRITEBACK || cattr == CA_WRITEBACK_NOALLOC) - cattr = CA_WRITETHRU; /* no writeback configured for data cache */ -# endif - for (i = start_region; i <= end_region; i++) { - unsigned sh = (i << 2); /* bit offset of nibble for region i */ - unsigned oldattr = ((cacheattr >> sh) & CA_MASK); - unsigned newattr = cattr; - if (flags & XTHAL_CAFLAG_EXPAND) { - /* This array determines whether a cache attribute can be changed - * from <a> to <b> with the EXPAND flag; an attribute's "pri" - * value (from this array) can only monotonically increase: */ - const static signed char _Xthal_ca_pri[16] = {[CA_ILLEGAL] = -1, - [CA_WRITEBACK] = 3, [CA_WRITEBACK_NOALLOC] = 3, [CA_WRITETHRU] = 4, [CA_BYPASSBUF] = 8, [CA_BYPASS] = 9 }; - if (_Xthal_ca_pri[newattr] < _Xthal_ca_pri[oldattr]) - newattr = oldattr; /* avoid going to lesser access */ - } - if (IS_CACHED(newattr) && !IS_CACHED(oldattr)) - disabled_cache = 1; /* we're disabling the cache for some region */ -# if XCHAL_DCACHE_IS_WRITEBACK - { - unsigned tmpattr = newattr; - if ((oldattr == CA_WRITEBACK || oldattr == CA_WRITEBACK_NOALLOC) - && newattr != CA_WRITEBACK && newattr != CA_WRITEBACK_NOALLOC) /* leaving writeback mode? */ - tmpattr = CA_WRITETHRU; /* leave it safely! */ - cachewrtr = ((cachewrtr & ~(CA_MASK << sh)) | (tmpattr << sh)); - } -# endif - cacheattr = ((cacheattr & ~(CA_MASK << sh)) | (newattr << sh)); - } -# if XCHAL_DCACHE_IS_WRITEBACK - if (cacheattr != cachewrtr /* need to leave writeback safely? */ - && (flags & XTHAL_CAFLAG_NO_AUTO_WB) == 0) { - xthal_set_cacheattr(cachewrtr); /* set to writethru first, to safely writeback any dirty data */ - xthal_dcache_all_writeback(); /* much quicker than scanning entire 512MB region(s) */ - } -# endif - xthal_set_cacheattr(cacheattr); - /* After disabling the cache, invalidate cache entries - * to avoid coherency issues when later re-enabling it: */ - if (disabled_cache && (flags & XTHAL_CAFLAG_NO_AUTO_INV) == 0) { - xthal_dcache_all_writeback_inv(); /* we might touch regions of memory still enabled write-back, - so must use writeback-invalidate, not just invalidate */ - xthal_icache_all_invalidate(); - } - return( 0 ); -#endif /* !(XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY) */ -} - diff --git a/src/arch/xtensa/hal/cache.c b/src/arch/xtensa/hal/cache.c deleted file mode 100644 index 4f6e292e6153..000000000000 --- a/src/arch/xtensa/hal/cache.c +++ /dev/null @@ -1,53 +0,0 @@ -// -// cache.c -- cache management routines -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/cache.c#1 $ - -// Copyright (c) 2002 Tensilica 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. - -#include <xtensa/config/core.h> - -// size of the cache lines in log2(bytes) -const unsigned char Xthal_icache_linewidth = XCHAL_ICACHE_LINEWIDTH; -const unsigned char Xthal_dcache_linewidth = XCHAL_DCACHE_LINEWIDTH; - -// size of the cache lines in bytes -const unsigned short Xthal_icache_linesize = XCHAL_ICACHE_LINESIZE; -const unsigned short Xthal_dcache_linesize = XCHAL_DCACHE_LINESIZE; - -// number of cache sets in log2(lines per way) -const unsigned char Xthal_icache_setwidth = XCHAL_ICACHE_SETWIDTH; -const unsigned char Xthal_dcache_setwidth = XCHAL_DCACHE_SETWIDTH; - -// cache set associativity (number of ways) -const unsigned int Xthal_icache_ways = XCHAL_ICACHE_WAYS; -const unsigned int Xthal_dcache_ways = XCHAL_DCACHE_WAYS; - -// size of the caches in bytes (ways * 2^(linewidth + setwidth)) -const unsigned int Xthal_icache_size = XCHAL_ICACHE_SIZE; -const unsigned int Xthal_dcache_size = XCHAL_DCACHE_SIZE; - -// cache features -const unsigned char Xthal_dcache_is_writeback = XCHAL_DCACHE_IS_WRITEBACK; -const unsigned char Xthal_icache_line_lockable = XCHAL_ICACHE_LINE_LOCKABLE; -const unsigned char Xthal_dcache_line_lockable = XCHAL_DCACHE_LINE_LOCKABLE; - diff --git a/src/arch/xtensa/hal/cache_asm.S b/src/arch/xtensa/hal/cache_asm.S deleted file mode 100644 index 9bb10438936b..000000000000 --- a/src/arch/xtensa/hal/cache_asm.S +++ /dev/null @@ -1,1073 +0,0 @@ -// -// cache_asm.S - assembly language cache management routines -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/cache_asm.S#1 $ - -// Copyright (c) 1999-2015 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. - -#include <xtensa/cacheasm.h> -#include <xtensa/cacheattrasm.h> -#include <xtensa/xtensa-versions.h> - - - - -//---------------------------------------------------------------------- -// Huge Range cache routines -//---------------------------------------------------------------------- - - // void xthal_dcache_hugerange_<name>(void *addr, unsigned size); - // - // Invalidate and/or writeback dcache entries for an arbitrary large - // virtual address range with a single scan of the dcache. - // Assumes no address translation, i.e. virtual = physical. - // - // a2 = ptr to range - // a3 = size of range - // - // Note: -128 is a valid immediate for ADDI, but +128 is not, - // and ADDI can relax to ADDMI for multiples of 256. So scanning - // cache backwards (from end to start) allows all cache line sizes - // without creating an extra instruction for the ADDI. - // - .macro dcache_hugefunc name, instruction - .text - .align 4 - .type xthal_dcache_hugerange_\name,@function - .global xthal_dcache_hugerange_\name -xthal_dcache_hugerange_\name: - abi_entry -#if (!defined(XCHAL_HAVE_NX) || XCHAL_HAVE_NX == 0) && XCHAL_DCACHE_SIZE > 0 \ - && XCHAL_HAVE_DCACHE_TEST && XCHAL_HAVE_MINMAX && XCHAL_HAVE_LOOPS - movi a4, XCHAL_DCACHE_SIZE*2 // size at which to use huge algorithm - movi a7, -XCHAL_DCACHE_LINESIZE // for rounding to cache line size - bltu a3, a4, 7f // use normal (line-by-line hit) function -#if XCHAL_HAVE_PREFETCH - movi a11, 0 - xsr.prefctl a11 // temporarily disable prefetch (invalidates prefetch bufs!) -#endif - add a5, a3, a2 // a5 = end of range - and a4, a2, a7 // a4 = low end, rounded to containing cache line - addi a5, a5, /*XCHAL_DCACHE_LINESIZE*/-1 - and a5, a5, a7 // a5 = high end, rounded to containing cache line - movi a7, XCHAL_DCACHE_SIZE/XCHAL_DCACHE_LINESIZE // a7 = number of lines in dcache - movi a3, XCHAL_DCACHE_SIZE-XCHAL_DCACHE_LINESIZE // way index - mov a6, a5 - //movi a8, -XCHAL_DCACHE_SETSIZE // use if LDCT gives non-zero index bits - movi a10, (XCHAL_DCACHE_SIZE/XCHAL_DCACHE_WAYS) - 1 - - loopgtz a7, 1f - ldct a7, a3 // a3 = cache tag for cache entry [a7] - \instruction a2, 0 - .begin schedule - //extui a9, a3, 0, XCHAL_DCACHE_SETWIDTH+XCHAL_DCACHE_LINEWIDTH - and a9, a3, a10 - addi a3, a3, -XCHAL_DCACHE_LINESIZE - .end schedule - .begin schedule - //and a7, a7, a8 // uncomment if LDCT reports non-zero index bits - maxu a6, a6, a4 // a4 = low end of range - minu a2, a6, a5 // a5 = high end of range - or a6, a7, a9 - .end schedule -1: - - \instruction a2, 0 - maxu a6, a6, a4 - minu a2, a6, a5 - \instruction a2, 0 -#if XCHAL_HAVE_PREFETCH - wsr.prefctl a11 // restore prefetch -#endif - isync_return_nop - abi_return -#endif /* dcache supports hugerange */ -// Jump to non-huge routine -7: j.l xthal_dcache_region_\name + ABI_ENTRY_MINSIZE, a4 - .size xthal_dcache_hugerange_\name, . - xthal_dcache_hugerange_\name - .endm - - - - // void xthal_icache_hugerange_<name>(void *addr, unsigned size); - // - // Invalidate icache entries for an arbitrary large - // virtual address range with a single scan of the icache. - // Assumes no address translation, i.e. virtual = physical. - // - // a2 = ptr to range - // a3 = size of range - // - // Note: -128 is a valid immediate for ADDI, but +128 is not, - // and ADDI can relax to ADDMI for multiples of 256. So scanning - // cache backwards (from end to start) allows all cache line sizes - // without creating an extra instruction for the ADDI. - // - .macro icache_hugefunc name, instruction - .text - .align 4 - .type xthal_icache_hugerange_\name,@function - .global xthal_icache_hugerange_\name -xthal_icache_hugerange_\name: - abi_entry -#if (!defined(XCHAL_HAVE_NX) || XCHAL_HAVE_NX == 0) &&XCHAL_ICACHE_SIZE > 0 && \ - XCHAL_HAVE_ICACHE_TEST && XCHAL_HAVE_MINMAX && XCHAL_HAVE_LOOPS - movi a4, XCHAL_ICACHE_SIZE*2 // size at which to use huge algorithm - movi a7, -XCHAL_ICACHE_LINESIZE // for rounding to cache line size - bltu a3, a4, 7f // use normal (line-by-line hit) function - add a5, a3, a2 // a5 = end of range - and a4, a2, a7 // a4 = low end, rounded to containing cache line - addi a5, a5, XCHAL_ICACHE_LINESIZE-1 - and a5, a5, a7 // a5 = high end, rounded to containing cache line - movi a7, XCHAL_ICACHE_SIZE/XCHAL_ICACHE_LINESIZE // a7 = number of lines in dcache - movi a3, XCHAL_ICACHE_SIZE-XCHAL_ICACHE_LINESIZE // way index - mov a6, a5 - //movi a8, -XCHAL_ICACHE_SETSIZE // use if LICT gives non-zero index bits - movi a10, (XCHAL_ICACHE_SIZE/XCHAL_ICACHE_WAYS) - 1 - - loopgtz a7, 1f - lict a7, a3 // a3 = cache tag for cache entry [a7] - \instruction a2, 0 - .begin schedule - //extui a9, a3, 0, XCHAL_ICACHE_SETWIDTH+XCHAL_ICACHE_LINEWIDTH - and a9, a3, a10 - addi a3, a3, -XCHAL_ICACHE_LINESIZE - .end schedule - .begin schedule - //and a7, a7, a8 // uncomment if LDCT reports non-zero index bits - maxu a6, a6, a4 // a4 = low end of range - minu a2, a6, a5 // a5 = high end of range - or a6, a7, a9 - .end schedule -1: - - \instruction a2, 0 - maxu a6, a6, a4 - minu a2, a6, a5 - \instruction a2, 0 - isync_return_nop - abi_return -#endif /* icache supports hugerange */ -7: j.l xthal_icache_region_\name + ABI_ENTRY_MINSIZE, a4 - .size xthal_icache_hugerange_\name, . - xthal_icache_hugerange_\name - .endm - - - - - .text - -//---------------------------------------------------------------------- -// Read CACHEATTR register -//---------------------------------------------------------------------- - -#if defined(__SPLIT__get_cacheattr) ||\ - defined(__SPLIT__get_cacheattr_nw) - -// unsigned xthal_get_cacheattr(void); - -DECLFUNC(xthal_get_cacheattr) -DECLFUNC(xthal_get_dcacheattr) -# if XCHAL_HAVE_CACHEATTR /* single CACHEATTR register used for both I and D */ -DECLFUNC(xthal_get_icacheattr) -# endif - abi_entry - dcacheattr_get - abi_return - endfunc - -#endif - -#if defined(__SPLIT__get_icacheattr) ||\ - defined(__SPLIT__get_icacheattr_nw) - -// unsigned xthal_get_icacheattr(void); - -# if !XCHAL_HAVE_CACHEATTR /* possibly independent CACHEATTR states used for I and D */ -DECLFUNC(xthal_get_icacheattr) - abi_entry - icacheattr_get - abi_return - endfunc -# endif - -#endif /*split*/ - - -//---------------------------------------------------------------------- -// Write CACHEATTR register, or equivalent. -//---------------------------------------------------------------------- - -/* - * Set CACHEATTR register in a safe manner. - * - * void xthal_set_cacheattr( unsigned new_cacheattr ); - * void xthal_set_icacheattr( unsigned new_cacheattr ); - * void xthal_set_dcacheattr( unsigned new_cacheattr ); - */ - -#if defined(__SPLIT__set_cacheattr) ||\ - defined(__SPLIT__set_cacheattr_nw) - -# if XCHAL_HAVE_CACHEATTR /* single CACHEATTR register used for both I and D accesses */ -DECLFUNC(xthal_set_icacheattr) -DECLFUNC(xthal_set_dcacheattr) -# endif -DECLFUNC(xthal_set_cacheattr) - abi_entry - cacheattr_set - abi_return - endfunc - -#endif /*split*/ - - -#if XCHAL_HAVE_CACHEATTR - - /* - * Already done above. - * - * Since we can't enable/disable the icache and dcache independently, - * and don't have a nice place to store a state which would enable - * us to only enable them both when both have been requested to be - * enabled, we simply enable both for any request to enable either, - * and disable both for any request to disable either cache. - */ - -#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR || (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY) - -# if defined(__SPLIT__set_icacheattr) \ - || defined(__SPLIT__set_icacheattr_nw) - -DECLFUNC(xthal_set_icacheattr) - abi_entry - icacheattr_set - isync_return_nop - abi_return - endfunc - -# endif - -# if defined(__SPLIT__set_dcacheattr) \ - || defined(__SPLIT__set_dcacheattr_nw) - -DECLFUNC(xthal_set_dcacheattr) - abi_entry - dcacheattr_set - abi_return - endfunc - -# endif /*split*/ - -#else /* full MMU (pre-v3): */ - -# if defined(__SPLIT__set_idcacheattr) \ - || defined(__SPLIT__set_idcacheattr_nw) - -// These functions aren't applicable to arbitrary MMU configurations. -// Do nothing in this case. - -DECLFUNC(xthal_set_icacheattr) -DECLFUNC(xthal_set_dcacheattr) - abi_entry - abi_return - endfunc - -# endif /*split*/ - -#endif /* cacheattr/MMU type */ - - -//---------------------------------------------------------------------- -// Determine (guess) whether caches are "enabled" -//---------------------------------------------------------------------- - -/* - * There is no "cache enable" bit in the Xtensa architecture, - * but we can use CACHEATTR (if it or its equivalent exists) - * as an indication that caches have been enabled. - */ - -#if XCHAL_HAVE_CACHEATTR - -# if defined(__SPLIT__idcache_is_enabled) || \ - defined(__SPLIT__idcache_is_enabled_nw) - -DECLFUNC(xthal_icache_is_enabled) -DECLFUNC(xthal_dcache_is_enabled) - abi_entry - cacheattr_is_enabled 2f - movi a2, 0 - abi_return -2: movi a2, 1 - abi_return - endfunc - -# endif /*split*/ - -#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR - -# if defined(__SPLIT__icache_is_enabled) || \ - defined(__SPLIT__icache_is_enabled_nw) - -DECLFUNC(xthal_icache_is_enabled) - abi_entry - icacheattr_is_enabled 2f - movi a2, 0 - abi_return -2: movi a2, 1 - abi_return - endfunc - -# endif - -# if defined(__SPLIT__dcache_is_enabled) || \ - defined(__SPLIT__dcache_is_enabled_nw) - -DECLFUNC(xthal_dcache_is_enabled) - abi_entry - dcacheattr_is_enabled 2f - movi a2, 0 - abi_return -2: movi a2, 1 - abi_return - endfunc - -# endif /*split*/ - -#else - -// These functions aren't applicable to arbitrary MMU configurations. -// Assume caches are enabled in this case (!). - -# if defined(__SPLIT__idcache_is_enabled) || \ - defined(__SPLIT__idcache_is_enabled_nw) - -DECLFUNC(xthal_icache_is_enabled) -DECLFUNC(xthal_dcache_is_enabled) - abi_entry - movi a2, 1 - abi_return - endfunc -# endif /*split*/ - -#endif - - - -//---------------------------------------------------------------------- -// invalidate the icache -//---------------------------------------------------------------------- - -#if defined(__SPLIT__icache_all_invalidate) || \ - defined(__SPLIT__icache_all_invalidate_nw) - -// void xthal_icache_all_invalidate(void); - -DECLFUNC(xthal_icache_all_invalidate) - abi_entry - icache_invalidate_all a2, a3 - isync_return_nop - abi_return - endfunc - -//---------------------------------------------------------------------- -// invalidate the dcache -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_all_invalidate) || \ - defined(__SPLIT__dcache_all_invalidate_nw) - -// void xthal_dcache_all_invalidate(void); - -DECLFUNC(xthal_dcache_all_invalidate) - abi_entry - dcache_invalidate_all a2, a3 - abi_return - endfunc - -//---------------------------------------------------------------------- -// write dcache dirty data -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_all_writeback) || \ - defined(__SPLIT__dcache_all_writeback_nw) - -// void xthal_dcache_all_writeback(void); - -DECLFUNC(xthal_dcache_all_writeback) - abi_entry - dcache_writeback_all a2, a3, a4 - abi_return - endfunc - -//---------------------------------------------------------------------- -// write dcache dirty data and invalidate -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_all_writeback_inv) || \ - defined(__SPLIT__dcache_all_writeback_inv_nw) - -// void xthal_dcache_all_writeback_inv(void); - -DECLFUNC(xthal_dcache_all_writeback_inv) - abi_entry - dcache_writeback_inv_all a2, a3, a4 - abi_return - endfunc - -//---------------------------------------------------------------------- -// unlock instructions from icache -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__icache_all_unlock) || \ - defined(__SPLIT__icache_all_unlock_nw) - -// void xthal_icache_all_unlock(void); - -DECLFUNC(xthal_icache_all_unlock) - abi_entry - icache_unlock_all a2, a3 - abi_return - endfunc - -//---------------------------------------------------------------------- -// unlock data from dcache -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_all_unlock) || \ - defined(__SPLIT__dcache_all_unlock_nw) - -// void xthal_dcache_all_unlock(void); - -DECLFUNC(xthal_dcache_all_unlock) - abi_entry - dcache_unlock_all a2, a3 - abi_return - endfunc - -//---------------------------------------------------------------------- -// invalidate the address range in the icache -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__icache_region_invalidate) || \ - defined(__SPLIT__icache_region_invalidate_nw) - -// void xthal_icache_region_invalidate( void *addr, unsigned size ); - -DECLFUNC(xthal_icache_region_invalidate) - abi_entry - icache_invalidate_region a2, a3, a4 - isync_return_nop - abi_return - endfunc - -#endif - -#if defined(__SPLIT__icache_hugerange_invalidate) - -// void xthal_icache_hugerange_invalidate( void *addr, unsigned size ); -icache_hugefunc invalidate, ihi - -#endif - -#if defined(__SPLIT__icache_hugerange_unlock) - -# if XCHAL_ICACHE_LINE_LOCKABLE -// void xthal_icache_hugerange_unlock( void *addr, unsigned size ); -icache_hugefunc unlock, ihu -# endif - -#endif - -#if defined(__SPLIT__dcache_hugerange_invalidate) - -// void xthal_dcache_hugerange_invalidate( void *addr, unsigned size ); -dcache_hugefunc invalidate, dhi - -#endif - -#if defined(__SPLIT__dcache_hugerange_unlock) - -# if XCHAL_DCACHE_LINE_LOCKABLE -// void xthal_dcache_hugerange_unlock( void *addr, unsigned size ); -dcache_hugefunc unlock, dhu -# endif - -#endif - -#if defined(__SPLIT__dcache_hugerange_writeback) - -// void xthal_dcache_hugerange_writeback( void *addr, unsigned size ); -dcache_hugefunc writeback, dhwb - -#endif - -#if defined(__SPLIT__dcache_hugerange_writeback_inv) - -// void xthal_dcache_hugerange_writeback_inv( void *addr, unsigned size ); -dcache_hugefunc writeback_inv, dhwbi - - - -//---------------------------------------------------------------------- -// invalidate the address range in the dcache -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_region_invalidate) || \ - defined(__SPLIT__dcache_region_invalidate_nw) - -// void xthal_dcache_region_invalidate( void *addr, unsigned size ); - -DECLFUNC(xthal_dcache_region_invalidate) - abi_entry - dcache_invalidate_region a2, a3, a4 - abi_return - endfunc - -//---------------------------------------------------------------------- -// write dcache region dirty data -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_region_writeback) || \ - defined(__SPLIT__dcache_region_writeback_nw) - -// void xthal_dcache_region_writeback( void *addr, unsigned size ); - -DECLFUNC(xthal_dcache_region_writeback) - abi_entry - dcache_writeback_region a2, a3, a4, a5 - abi_return - endfunc - -//---------------------------------------------------------------------- -// write dcache region dirty data and invalidate -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_region_writeback_inv) || \ - defined(__SPLIT__dcache_region_writeback_inv_nw) - -// void xthal_dcache_region_writeback_inv( void *addr, unsigned size ); - -DECLFUNC(xthal_dcache_region_writeback_inv) - abi_entry - dcache_writeback_inv_region a2, a3, a4, a5 - abi_return - endfunc - -//---------------------------------------------------------------------- -// lock instructions in icache region -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__icache_region_lock) || \ - defined(__SPLIT__icache_region_lock_nw) - -// void xthal_icache_region_lock(void); - -DECLFUNC(xthal_icache_region_lock) - abi_entry - icache_lock_region a2, a3, a4 - abi_return - endfunc - -//---------------------------------------------------------------------- -// lock data in dcache region -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_region_lock) || \ - defined(__SPLIT__dcache_region_lock_nw) - -// void xthal_dcache_region_lock(void); - -DECLFUNC(xthal_dcache_region_lock) - abi_entry - dcache_lock_region a2, a3, a4 - abi_return - endfunc - -//---------------------------------------------------------------------- -// unlock instructions from icache region -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__icache_region_unlock) || \ - defined(__SPLIT__icache_region_unlock_nw) - -// void xthal_icache_region_unlock(void); - -DECLFUNC(xthal_icache_region_unlock) - abi_entry - icache_unlock_region a2, a3, a4 - abi_return - endfunc - -//---------------------------------------------------------------------- -// unlock data from dcache region -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_region_unlock) || \ - defined(__SPLIT__dcache_region_unlock_nw) - -// void xthal_dcache_region_unlock(void); - -DECLFUNC(xthal_dcache_region_unlock) - abi_entry - dcache_unlock_region a2, a3, a4 - abi_return - endfunc - - -//---------------------------------------------------------------------- -// invalidate single icache line -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__icache_line_invalidate) || \ - defined(__SPLIT__icache_line_invalidate_nw) - -// void xthal_icache_line_invalidate(void *addr); - -DECLFUNC(xthal_icache_line_invalidate) - abi_entry - icache_invalidate_line a2, 0 - isync_return_nop - abi_return - endfunc - - -//---------------------------------------------------------------------- -// invalidate single dcache line -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_line_invalidate) || \ - defined(__SPLIT__dcache_line_invalidate_nw) - -// void xthal_dcache_line_invalidate(void *addr); - -DECLFUNC(xthal_dcache_line_invalidate) - abi_entry - dcache_invalidate_line a2, 0 - abi_return - endfunc - -//---------------------------------------------------------------------- -// write single dcache line dirty data -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_line_writeback) || \ - defined(__SPLIT__dcache_line_writeback_nw) - -// void xthal_dcache_line_writeback(void *addr); - -DECLFUNC(xthal_dcache_line_writeback) - abi_entry - dcache_writeback_line a2, 0 - abi_return - endfunc - -//---------------------------------------------------------------------- -// write single dcache line dirty data and invalidate -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_line_writeback_inv) || \ - defined(__SPLIT__dcache_line_writeback_inv_nw) - -// void xthal_dcache_line_writeback_inv(void *addr); - -DECLFUNC(xthal_dcache_line_writeback_inv) - abi_entry - dcache_writeback_inv_line a2, 0 - abi_return - endfunc - -//---------------------------------------------------------------------- -// lock instructions in icache line -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__icache_line_lock) || \ - defined(__SPLIT__icache_line_lock_nw) - -// void xthal_icache_line_lock(void); - -DECLFUNC(xthal_icache_line_lock) - abi_entry - icache_lock_line a2, 0 - abi_return - endfunc - -//---------------------------------------------------------------------- -// lock data in dcache line -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_line_lock) || \ - defined(__SPLIT__dcache_line_lock_nw) - -// void xthal_dcache_line_lock(void); - -DECLFUNC(xthal_dcache_line_lock) - abi_entry - dcache_lock_line a2, 0 - abi_return - endfunc - -//---------------------------------------------------------------------- -// unlock instructions from icache line -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__icache_line_unlock) || \ - defined(__SPLIT__icache_line_unlock_nw) - -// void xthal_icache_line_unlock(void); - -DECLFUNC(xthal_icache_line_unlock) - abi_entry - icache_unlock_line a2, 0 - abi_return - endfunc - -//---------------------------------------------------------------------- -// unlock data from dcache line -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_line_unlock) || \ - defined(__SPLIT__dcache_line_unlock_nw) - -// void xthal_dcache_line_unlock(void); - -DECLFUNC(xthal_dcache_line_unlock) - abi_entry - dcache_unlock_line a2, 0 - abi_return - endfunc - -//---------------------------------------------------------------------- -// sync icache and memory (???) -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__icache_sync) || \ - defined(__SPLIT__icache_sync_nw) - -// void xthal_icache_sync(void); - -DECLFUNC(xthal_icache_sync) - abi_entry - icache_sync a2 - isync_return_nop - abi_return - endfunc - -//---------------------------------------------------------------------- -// sync dcache and memory (???) -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__dcache_sync) || \ - defined(__SPLIT__dcache_sync_nw) - -// void xthal_dcache_sync(void); - -DECLFUNC(xthal_dcache_sync) - abi_entry - dcache_sync a2 - abi_return - endfunc - -//---------------------------------------------------------------------- -// Get/Set icache number of ways enabled -//---------------------------------------------------------------------- - -#endif - -#if defined (__SPLIT__icache_get_ways) || \ - defined (__SPLIT__icache_get_ways_nw) - -// unsigned int xthal_icache_get_ways(void); - -DECLFUNC(xthal_icache_get_ways) - abi_entry - icache_get_ways a2 - abi_return - endfunc - -#endif - -#if defined (__SPLIT__icache_set_ways) || \ - defined(__SPLIT__icache_set_ways_nw) - -/// void xthal_icache_set_ways(unsigned int ways); - -DECLFUNC(xthal_icache_set_ways) - abi_entry - icache_set_ways a2 a3 a4 - abi_return - endfunc - -//---------------------------------------------------------------------- -// Get/Set dcache number of ways enabled -//---------------------------------------------------------------------- - -#endif - -#if defined (__SPLIT__dcache_get_ways) || \ - defined (__SPLIT__dcache_get_ways_nw) - -// unsigned int xthal_dcache_get_ways(void); - -DECLFUNC(xthal_dcache_get_ways) - abi_entry - dcache_get_ways a2 - abi_return - endfunc - -#endif - -#if defined (__SPLIT__dcache_set_ways) || \ - defined (__SPLIT__dcache_set_ways_nw) - -// void xthal_dcache_set_ways(unsigned int ways); - -DECLFUNC(xthal_dcache_set_ways) - abi_entry - dcache_set_ways a2 a3 a4 - abi_return - endfunc - -//---------------------------------------------------------------------- -// opt into and out of coherence -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__cache_coherence_on) || \ - defined(__SPLIT__cache_coherence_on_nw) - -// The opt-in routine assumes cache was initialized at reset, -// so it's equivalent to the low-level coherence_on routine. - -// void xthal_cache_coherence_optin(void) -// void xthal_cache_coherence_on(void) - -DECLFUNC(xthal_cache_coherence_optin) -DECLFUNC(xthal_cache_coherence_on) - abi_entry - cache_coherence_on a2, a3 - abi_return - endfunc - -#endif - -#if defined(__SPLIT__cache_coherence_off) || \ - defined(__SPLIT__cache_coherence_off_nw) - -// The coherence_off routines should not normally be called directly. -// Use the xthal_cache_coherence_optout() C routine instead -// (which first empties the cache). - -// void xthal_cache_coherence_off - -DECLFUNC(xthal_cache_coherence_off) - abi_entry - cache_coherence_off a2, a3 - abi_return - endfunc - - -//---------------------------------------------------------------------- -// Control cache prefetch -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__set_cache_prefetch_long) || \ - defined(__SPLIT__set_cache_prefetch_long_nw) - -# if XCHAL_HAVE_BE -# define aH a2 /* msb word = prefctl mask */ -# define aL a3 /* lsb word = prefctl value */ -# else -# define aH a3 /* msb word = prefctl mask */ -# define aL a2 /* lsb word = prefctl value */ -# endif - -// Set cache prefetch state (-1=enable, 0=disable, and see XTHAL_*PREFETCH_*), -// and return previous one. -// -// int xthal_set_cache_prefetch_long( unsigned long long ); -// -DECLFUNC(xthal_set_cache_prefetch_long) - abi_entry -# if XCHAL_HAVE_PREFETCH - movi a5, XCHAL_CACHE_PREFCTL_DEFAULT - addi a4, aL, 1 // does prefctl value aL == -1 ? - moveqz aL, a5, a4 // if yes (XTHAL_PREFETCH_ENABLE), set it to default - movgez a2, aL, aL // if the high bit is not set, then we want to transfer the contents of aL to prefctl - // so we move it to a2 - bgez aL, 1f // high bit set indicates masked update - ssai 16 // 16-bit right shifts - src a5, aL, aH // get 16-bit-swapped 32-bit value - src a5, a5, a5 // get 32-bit value (rotate by 16) - rsr.prefctl a4 - src a3, aH, aL // get 32-bit mask - or a4, a4, a3 // set masked bits - xor a4, a4, a3 // clear masked bits - and a5, a5, a3 // only use masked bits - or a2, a4, a5 // combine masked bits -1: -# if XCHAL_HW_MIN_VERSION <= XTENSA_HWVERSION_RC_2010_1 /* for erratum #325 */ - j 1f ; .align 8 ; 1: xsr.prefctl a2 ; isync // ensure XSR.PREFCTL;ISYNC wholly within an icache line -# else - xsr.prefctl a2 -# endif -# else - movi a2, 0 -# endif - abi_return - endfunc - -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__set_cache_prefetch) || \ - defined(__SPLIT__set_cache_prefetch_nw) - -// FOR BACKWARD COMPATIBILITY WITH PRE-RF RELEASE OBJECT CODE ONLY. -// Set cache prefetch state (-1=enable, 0=disable, and see the -// definitions of XTHAL_*PREFETCH_* with only the lower 32 bits set), -// and return previous one. -// int xthal_set_cache_prefetch( int ) -// -DECLFUNC(xthal_set_cache_prefetch) - abi_entry -# if XCHAL_HAVE_PREFETCH - movi a3, XCHAL_CACHE_PREFCTL_DEFAULT - addi a4, a2, 1 // does a2 == -1 ? - moveqz a2, a3, a4 // if yes (XTHAL_PREFETCH_ENABLE), set it to default - bbci.l a2, 31, 1f // high bit set indicates masked update - rsr.prefctl a4 - extui a5, a2, 16, 15 - or a4, a4, a5 // set masked bits - xor a4, a4, a5 // clear masked bits - and a2, a2, a5 // only use masked bits - or a2, a4, a2 // combine masked bits -1: -# if XCHAL_HW_MIN_VERSION <= XTENSA_HWVERSION_RC_2010_1 /* for erratum #325 */ - j 1f ; .align 8 ; 1: xsr.prefctl a2 ; isync // ensure XSR.PREFCTL;ISYNC wholly within an icache line -# else - xsr.prefctl a2 -# endif -# else - movi a2, 0 -# endif - abi_return - endfunc - -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__get_cache_prefetch) ||\ - defined(__SPLIT__get_cache_prefetch_nw) - -// Return current cache prefetch state. -// int xthal_get_cache_prefetch( void ) -DECLFUNC(xthal_get_cache_prefetch) - abi_entry -# if XCHAL_HAVE_PREFETCH - rsr.prefctl a2 -# else - movi a2, 0 -# endif - abi_return - endfunc - -//---------------------------------------------------------------------- -// Misc configuration info -//---------------------------------------------------------------------- -#endif - -// Eventually these will move to their own file: -#if defined(__SPLIT__hw_configid0) - .set xthals_hw_configid0, XCHAL_HW_CONFIGID0 -#endif - -#if defined(__SPLIT__hw_configid1) - .set xthals_hw_configid1, XCHAL_HW_CONFIGID1 -#endif - -#if defined(__SPLIT__release_major) - .set xthals_release_major, XTHAL_RELEASE_MAJOR -#endif - -#if defined(__SPLIT__release_minor) - .set xthals_release_minor, XTHAL_RELEASE_MINOR - -#endif /*split*/ - - .global xthals_hw_configid0, xthals_hw_configid1 - .global xthals_release_major, xthals_release_minor - -//---------------------------------------------------------------------- - diff --git a/src/arch/xtensa/hal/clock.S b/src/arch/xtensa/hal/clock.S deleted file mode 100644 index 7ea86d3f1b15..000000000000 --- a/src/arch/xtensa/hal/clock.S +++ /dev/null @@ -1,138 +0,0 @@ -// -// clock.S - assembly language clock routines -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/clock.S#1 $ - -// Copyright (c) 2003-2010 Tensilica 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. - -#include <xtensa/coreasm.h> - - -// A useful looping macro: -// 'iterate' invokes 'what' (an instruction, pseudo-op or other macro) -// multiple times, passing it a numbered parameter from 'from' to 'to' -// inclusively. Does not invoke 'what' at all if from > to. -// Maximum difference between 'from' and 'to' is 99 minus nesting depth -// (GNU 'as' doesn't allow nesting deeper than 100). -// - .macro iterate from, to, what - .ifeq ((\to-\from) & ~0xFFF) - \what \from - iterate "(\from+1)", \to, \what - .endif - .endm // iterate - - -//---------------------------------------------------------------------- -// Read CCOUNT register -//---------------------------------------------------------------------- - -// unsigned xthal_get_ccount(void) -// - .global xthal_get_ccount - .type xthal_get_ccount,@function - .align 4 -xthal_get_ccount: - abi_entry -#if XCHAL_HAVE_CCOUNT - rsr.ccount a2 -/* - * The following alternative (in absence of CCOUNT) doesn't work well, - * because ICOUNT is often used for debugging. (And when it isn't, - * one would have to ensure that ICOUNTLEVEL is high enough and that - * ICOUNT is incremented to zero in the debug exception handler upon - * ICOUNT exceptions.) - * - * #elif XCHAL_HAVE_DEBUG - * rsr.icount a2 // no CCOUNT, return ICOUNT if available - */ -#else - movi a2, 0 // else no counter at all, just return zero -#endif - abi_return - .size xthal_get_ccount, . - xthal_get_ccount - - -//---------------------------------------------------------------------- -// Access CCOMPAREn registers -//---------------------------------------------------------------------- - -// void xthal_set_ccompare(int, unsigned) -// - .global xthal_set_ccompare - .type xthal_set_ccompare,@function - .align 4 -xthal_set_ccompare: - abi_entry -#if XCHAL_NUM_TIMERS > 0 - bnez a2, 1f - wsr.ccompare0 a3 - rsync - abi_return -#endif -1: -#if XCHAL_NUM_TIMERS > 1 - bnei a2, 1, 2f - wsr.ccompare1 a3 - rsync - abi_return -#endif -2: -#if XCHAL_NUM_TIMERS > 2 - bnei a2, 2, 3f - wsr.ccompare2 a3 - rsync -#endif -3: - abi_return - .size xthal_set_ccompare, . - xthal_set_ccompare - - -// unsigned xthal_get_ccompare(int) -// - .global xthal_get_ccompare - .type xthal_get_ccompare,@function - .align 4 -xthal_get_ccompare: - abi_entry -#if XCHAL_NUM_TIMERS > 0 - bnez a2, 1f - rsr.ccompare0 a2 - abi_return -#endif -1: -#if XCHAL_NUM_TIMERS > 1 - bnei a2, 1, 2f - rsr.ccompare1 a2 - abi_return -#endif -2: -#if XCHAL_NUM_TIMERS > 2 - bnei a2, 2, 3f - rsr.ccompare2 a2 - abi_return -#endif -3: - movi a2, 0 - abi_return - .size xthal_get_ccompare, . - xthal_get_ccompare - diff --git a/src/arch/xtensa/hal/coherence.c b/src/arch/xtensa/hal/coherence.c deleted file mode 100644 index 066557325bcf..000000000000 --- a/src/arch/xtensa/hal/coherence.c +++ /dev/null @@ -1,59 +0,0 @@ -/* coherence.c - Cache coherence opt-in / opt-out functions */ - -/* $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/coherence.c#1 $ */ - -/* - * Copyright (c) 2008 Tensilica 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. - */ - -#include <xtensa/config/core.h> - - -/* - * Opt-out of cache coherence. - * - * Caveat: on a core with full MMU, cache attribute handling done here only - * works well with the default (reset) TLB mapping of eight 512MB regions. - * It likely won't work correctly when other page sizes are in use (it may - * appear to work but be open to race conditions, depending on situation). - */ -void xthal_cache_coherence_optout( void ) -{ -#if XCHAL_HAVE_EXTERN_REGS && XCHAL_DCACHE_IS_COHERENT - unsigned ca = xthal_get_cacheattr(); - /* Writeback all dirty entries. Writethru mode avoids new dirty entries. */ - xthal_set_region_attribute(0,0xFFFFFFFF, XCHAL_CA_WRITETHRU, XTHAL_CAFLAG_EXPAND); - xthal_dcache_all_writeback(); - /* Invalidate all cache entries. Cache-bypass mode avoids new entries. */ - xthal_set_region_attribute(0,0xFFFFFFFF, XCHAL_CA_BYPASS, XTHAL_CAFLAG_EXPAND); - xthal_dcache_all_writeback_inv(); - /* Wait for everything to settle. */ - asm("memw"); - xthal_dcache_sync(); - xthal_icache_sync(); - /* Opt-out of cache coherency protocol. */ - xthal_cache_coherence_off(); - /* Restore cache attributes, as of entry to this function. */ - xthal_set_cacheattr(ca); -#endif -} - diff --git a/src/arch/xtensa/hal/debug.c b/src/arch/xtensa/hal/debug.c deleted file mode 100644 index 9e2b2654d303..000000000000 --- a/src/arch/xtensa/hal/debug.c +++ /dev/null @@ -1,525 +0,0 @@ -// -// debug.c - debug related constants and functions -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/debug.c#1 $ - -// Copyright (c) 2002 Tensilica 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. - -#include <xtensa/hal.h> -#include <xtensa/config/core.h> - - -/* 1 if debug option configured, 0 if not: */ -const int Xthal_debug_configured = XCHAL_HAVE_DEBUG; - -/* Number of instruction and data break registers: */ -const int Xthal_num_ibreak = XCHAL_NUM_IBREAK; -const int Xthal_num_dbreak = XCHAL_NUM_DBREAK; - - -#ifdef INCLUDE_DEPRECATED_HAL_DEBUG_CODE -/* This array is incorrect: */ -const unsigned short Xthal_ill_inst_16[16] = -{ -#if XCHAL_HAVE_BE - 0xfd0f, 0xfd1f, 0xfd2f, 0xfd3f, - 0xfd4f, 0xfd5f, 0xfd6f, 0xfd7f, - 0xfd8f, 0xfd9f, 0xfdaf, 0xfdbf, - 0xfdcf, 0xfddf, 0xfdef, 0xfdff -#else - 0xf0fd, 0xf1fd, 0xf2fd, 0xf3fd, - 0xf4fd, 0xf5fd, 0xf6fd, 0xf7fd, - 0xf8fd, 0xf9fd, 0xfafd, 0xfbfd, - 0xfcfd, 0xfdfd, 0xfefd, 0xfffd -#endif -}; -#endif /* INCLUDE_DEPRECATED_HAL_DEBUG_CODE */ - - -#undef XTHAL_24_BIT_BREAK -#undef XTHAL_16_BIT_BREAK -#define XTHAL_24_BIT_BREAK 0x80000000 -#define XTHAL_16_BIT_BREAK 0x40000000 - - - -// set software breakpoint and synchronize cache -unsigned int -xthal_set_soft_break(void *addr) -{ - unsigned inst; - int is24bit = (xthal_disassemble_size( (unsigned char *)addr ) == 3); - unsigned int ret_val; - -#if XCHAL_HAVE_BE - inst = ((((char *)addr)[0])<<24) + - ((((char *)addr)[1])<<16) + - ((((char *)addr)[2])<<8); -#else - inst = ((((char *)addr)[0])) + - ((((char *)addr)[1])<<8) + - ((((char *)addr)[2])<<16); -#endif -#if XCHAL_HAVE_BE - if (is24bit) { - ret_val = XTHAL_24_BIT_BREAK & ((inst>>8)&0xffffff); - ((unsigned char *)addr)[0] = 0x00; - ((unsigned char *)addr)[1] = 0x04; - ((unsigned char *)addr)[2] = 0x00; - } else { - ret_val = XTHAL_16_BIT_BREAK & ((inst>>16)&0xffff); - ((unsigned char *)addr)[0] = 0xD2; - ((unsigned char *)addr)[1] = 0x0f; - } -#else - if (is24bit) { - ret_val = XTHAL_24_BIT_BREAK & (inst&0xffffff); - ((unsigned char *)addr)[0] = 0x00; - ((unsigned char *)addr)[1] = 0x40; - ((unsigned char *)addr)[2] = 0x00; - } else { - ret_val = XTHAL_16_BIT_BREAK & (inst&0xffff); - ((unsigned char *)addr)[0] = 0x2D; - ((unsigned char *)addr)[1] = 0xf0; - } -#endif - *((unsigned int *)addr) = inst; -#if XCHAL_DCACHE_IS_WRITEBACK - xthal_dcache_region_writeback((void*)addr, 3); -#endif -#if XCHAL_ICACHE_SIZE > 0 - xthal_icache_region_invalidate((void*)addr, 3); -#endif - return ret_val; -} - - -// remove software breakpoint and synchronize cache -void -xthal_remove_soft_break(void *addr, unsigned int inst) -{ -#if XCHAL_HAVE_BE - if (inst&XTHAL_24_BIT_BREAK) { - ((unsigned char *)addr)[0] = (inst>>16)&0xff; - ((unsigned char *)addr)[1] = (inst>>8)&0xff; - ((unsigned char *)addr)[2] = inst&0xff; - } else { - ((unsigned char *)addr)[0] = (inst>>8)&0xff; - ((unsigned char *)addr)[1] = inst&0xff; - } -#else - ((unsigned char *)addr)[0] = inst&0xff; - ((unsigned char *)addr)[1] = (inst>>8)&0xff; - if (inst&XTHAL_24_BIT_BREAK) - ((unsigned char *)addr)[2] = (inst>>16)&0xff; -#endif -#if XCHAL_DCACHE_IS_WRITEBACK - xthal_dcache_region_writeback((void*)addr, 3); -#endif -#if XCHAL_ICACHE_SIZE > 0 - xthal_icache_region_invalidate((void*)addr, 3); -#endif -} - - - - -#ifdef INCLUDE_DEPRECATED_HAL_DEBUG_CODE - -// return instruction type -unsigned int -xthal_inst_type(void *addr) -{ - unsigned int inst_type = 0; - unsigned inst; -// unsigned int inst = *((unsigned int *)addr); - unsigned char op0, op1, op2; - unsigned char i, m, n, r, s, t, z; - -#if XCHAL_HAVE_BE - inst = ((((char *)addr)[0])<<24) + - ((((char *)addr)[1])<<16) + - ((((char *)addr)[2])<<8); - op0 = inst>>28; - op1 = (inst>>12)&0xf; - op2 = (inst>>16)&0xf; - i = (inst>>27)&0x1; - z = (inst>>26)&0x1; - m = (inst>>24)&0x3; - n = (inst>>26)&0x3; - r = (inst>>16)&0xf; - s = (inst>>20)&0xf; - t = (inst>>24)&0xf; -#else - inst = ((((char *)addr)[0])) + - ((((char *)addr)[1])<<8) + - ((((char *)addr)[2])<<16); - op0 = inst&0xf; - op1 = (inst&0xf0000)>>16; - op2 = (inst&0xf00000)>>20; - i = (inst&0x80)>>7; - z = (inst&0x40)>>6; - m = (inst&0xc0)>>6; - n = (inst&0x30)>>4; - r = (inst&0xf000)>>12; - s = (inst&0xf00)>>8; - t = (inst&0xf0)>4; -#endif - switch (op0) { - case 0x0: - inst_type |= XTHAL_24_BIT_INST; - if ((op1==0)&&(op2==0)) - switch (r) { - case 0: - if (m==0x2) { - if (!(n&0x2)) // RET, RETW - inst_type |= XTHAL_RET_INST; - else if (n==0x2) // JX - inst_type |= (XTHAL_JUMP_INST|XTHAL_DEST_REG_INST); - inst_type |= (s<<28); - } else if (m==3) // CALLX - inst_type |= (XTHAL_JUMP_INST|XTHAL_DEST_REG_INST); - inst_type |= (s<<28); - break; - case 0x3: - if (t==0) - switch (s) { - case 0x0: // RFE - inst_type |= XTHAL_RFE_INST; - break; - case 0x1: // RFUE - inst_type |= XTHAL_RFUE_INST; - break; - case 0x4: // RFW - case 0x5: - inst_type |= XTHAL_RFW_INST; - break; - } - else if (t==1) // RFI - inst_type |= XTHAL_RFI_INST; - break; - case 0x4: // BREAK - inst_type |= XTHAL_BREAK_INST; - break; - case 0x5: // SYSCALL - inst_type |= XTHAL_SYSCALL_INST; - break; - } - break; - case 0x5: // CALL - inst_type |= XTHAL_24_BIT_INST; - inst_type |= (XTHAL_JUMP_INST|XTHAL_DEST_REL_INST); - break; - case 0x6: // B - inst_type |= XTHAL_24_BIT_INST; - if (n==0) // J - inst_type |= (XTHAL_JUMP_INST|XTHAL_DEST_REL_INST); - else if ((n==0x1)||(n==0x2)) - inst_type |= (XTHAL_BRANCH_INST|XTHAL_DEST_REL_INST); - else { - if (m&0x2) - inst_type |= (XTHAL_BRANCH_INST|XTHAL_DEST_REL_INST); - else if ((m==0x1)&&((r==0x0)||(r==0x1))) - inst_type |= (XTHAL_BRANCH_INST|XTHAL_DEST_REL_INST); - } - break; - case 0x7: // B - inst_type |= XTHAL_24_BIT_INST; - inst_type |= (XTHAL_BRANCH_INST|XTHAL_DEST_REL_INST); - break; -#if XCHAL_HAVE_DENSITY - case 0x8: // L32I.N - case 0x9: // S32I.N - case 0xA: // ADD.N - case 0xb: // ADDI.N - inst_type |= XTHAL_16_BIT_INST; - break; - case 0xc: - inst_type |= XTHAL_16_BIT_INST; // MOVI.N BEQZ.N, BNEZ.N - if (i) - inst_type |= (XTHAL_BRANCH_INST|XTHAL_DEST_REL_INST); - break; - case 0xd: // MOV.N NOP.N - inst_type |= XTHAL_16_BIT_INST; - if (r==0xf) - switch(t) { - case 0x0: - case 0x1: - inst_type |= XTHAL_RET_INST; // RET.N, RETW.N - break; - case 0x2: - inst_type |= XTHAL_BREAK_INST; // BREAK.N - break; - } - break; -#endif /* XCHAL_HAVE_DENSITY */ - default: - inst_type |= XTHAL_24_BIT_INST; - } - return inst_type; -} - -// returns branch address -unsigned int -xthal_branch_addr(void *addr) -{ - unsigned int b_addr = (unsigned int) addr; - unsigned inst; -// unsigned int inst = *((unsigned int *)addr); - int offset; - unsigned int inst_type = xthal_inst_type(addr); - unsigned int inst_type_mask; -#if XCHAL_HAVE_BE - inst = ((((char *)addr)[0])<<24) + - ((((char *)addr)[1])<<16) + - ((((char *)addr)[2])<<8); -#else - inst = ((((char *)addr)[0])) + - ((((char *)addr)[1])<<8) + - ((((char *)addr)[2])<<16); -#endif -#if XCHAL_HAVE_DENSITY - inst_type_mask = XTHAL_16_BIT_INST|XTHAL_BRANCH_INST|XTHAL_DEST_REL_INST; - if ((inst_type&inst_type_mask)==inst_type_mask) { -# if XCHAL_HAVE_BE - b_addr += (4+((inst&0x3000000)>>20)+((inst&0xf0000)>>16)); -# else - b_addr += (4+(inst&0x30)+((inst&0xf000)>>12)); -# endif - } -#endif /* XCHAL_HAVE_DENSITY */ - inst_type_mask = XTHAL_24_BIT_INST|XTHAL_BRANCH_INST|XTHAL_DEST_REL_INST; - if ((inst_type&inst_type_mask)==inst_type_mask) { -#if XCHAL_HAVE_BE - if ((inst&0xf0000000)==0x70000000) - offset = ((int)(inst<<16))>>24; - else if ((inst&0xf2000000)==0x62000000) - offset = ((int)(inst<<16))>>24; - else - offset = ((int)(inst<<12))>>20; -#else - if ((inst&0xf)==0x7) - offset = ((int)(inst<<8))>>24; - else if ((inst&0x2f)==0x26) - offset = ((int)(inst<<8))>>24; - else - offset = ((int)(inst<<8))>>20; -#endif - b_addr += 4 + offset; - } - inst_type_mask = XTHAL_24_BIT_INST|XTHAL_JUMP_INST|XTHAL_DEST_REL_INST; - if ((inst_type&inst_type_mask)==inst_type_mask) { -#if XCHAL_HAVE_BE - if ((inst&0xfc000000)==0x60000000) - offset = ((int)(inst<<6))>>14; - else - { - b_addr &= 0xfffffffc; - offset = ((int)(inst<<6))>>12; - } -#else - if ((inst&0x3f)==0x6) - offset = ((int)(inst<<8))>>14; - else - { - b_addr &= 0xfffffffc; - offset = ((int)(inst<<8))>>12; - } -#endif - b_addr += 4 + offset; - } - return b_addr; -} - -// return pc of next instruction for a given state -unsigned int xthal_get_npc(XTHAL_STATE *user_state) -{ - unsigned inst_type; - unsigned npc; - inst_type = xthal_inst_type((void *)user_state->pc); - if (inst_type & XTHAL_24_BIT_INST) - npc = user_state->pc + 3; - else - npc = user_state->pc + 2; - if (inst_type & XTHAL_RFW_INST) { - /* Can not debug level 1 interrupts */ - // xt_panic(); - } else if (inst_type & XTHAL_RFUE_INST) { - /* Can not debug level 1 interrupts */ - // xt_panic(); - } else if (inst_type & XTHAL_RFI_INST) { - /* Can not debug level 1 interrupts */ - // xt_panic(); - } else if (inst_type & XTHAL_RFE_INST) { - /* Can not debug level 1 interrupts */ - // xt_panic(); - } else if (inst_type & XTHAL_RET_INST) { - npc = (user_state->pc&0xc0000000)+(user_state->ar[0]&0x3fffffff); - } else if (inst_type & XTHAL_BREAK_INST) { - /* Can not debug break */ - // xt_panic(); - } else if (inst_type & XTHAL_SYSCALL_INST) { - /* Can not debug exceptions */ - // xt_panic(); - } else if (inst_type & XTHAL_LOOP_END) { - // xt_panic(); - } else if (inst_type & XTHAL_JUMP_INST) { - if (inst_type & XTHAL_DEST_REG_INST) { - return user_state->ar[inst_type>>28]; - } else if (inst_type & XTHAL_DEST_REL_INST) { - return xthal_branch_addr((void *)user_state->pc); - } - } else if (inst_type & XTHAL_BRANCH_INST) { - int branch_taken = 0; - unsigned short inst; - unsigned char op0, t, s, r, m, n; - memcpy(&inst, (void *)user_state->pc, 2); -#if XCHAL_HAVE_BE - op0 = (inst&0xf000)>>12; - t = (inst&0x0f00)>>8; - s = (inst&0x00f0)>>4; - r = (inst&0x000f); - m = t&3; - n = t>>2; -#else - op0 = (inst&0x000f); - t = (inst&0x00f0)>>4; - s = (inst&0x0f00)>>8; - r = (inst&0xf000)>>12; - m = t>>2; - n = t&3; -#endif - if (inst_type &XTHAL_16_BIT_INST) { -#if XCHAL_HAVE_BE - if (inst&0x400) /* BNEZ.N */ - branch_taken = (user_state->ar[(inst>>4)&0xf]!=0); - else /* BEQZ.N */ - branch_taken = (user_state->ar[(inst>>4)&0xf]==0); -#else - if (inst&0x40) /* BNEZ.N */ - branch_taken = (user_state->ar[(inst>>8)&0xf]!=0); - else /* BEQZ.N */ - branch_taken = (user_state->ar[(inst>>8)&0xf]==0); -#endif - } - if (op0==0x6) { - if (n==1) { - if (m==0) { /* BEQZ */ - branch_taken = (user_state->ar[s]==0); - } else if (m==1) { /* BNEZ */ - branch_taken = (user_state->ar[s]!=0); - } else if (m==2) { /* BLTZ */ - branch_taken = (((int)user_state->ar[s])<0); - } else if (m==3) { /* BGEZ */ - branch_taken = (((int)user_state->ar[s])>=0); - } - } else if (n==2) { - int b4const[16] = - { -1, 1, 2, 3, 4, 5, 6, 7, - 8, 10, 12, 16, 32, 62, 128, 256 }; - if (m==0) { /* BEQI */ - branch_taken = (user_state->ar[s]==b4const[r]); - } else if (m==1) { /* BNEI */ - branch_taken = (user_state->ar[s]!=b4const[r]); - } else if (m==2) { /* BLTI */ - branch_taken = (((int)user_state->ar[s])<b4const[r]); - } else if (m==3) { /* BGEI */ - branch_taken = (((int)user_state->ar[s])>=b4const[r]); - } - } else if (n==3) { - int b4constu[16] = - { 32768, 65536, 2, 3, 4, 5, 6, 7, - 8, 10, 12, 16, 32, 62, 128, 256 }; - if (m==2) { /* BLTUI */ - branch_taken = (user_state->ar[s]<b4constu[r]); - } else if (m==3) { /* BGEUI */ - branch_taken = (user_state->ar[s]>=b4constu[r]); - } - } - } else if (op0==0x7) { - if (r==0) { /* BNONE */ - branch_taken = ((user_state->ar[s]&user_state->ar[t])==0); - } else if (r==1) { /* BEQ */ - branch_taken = (user_state->ar[s]==user_state->ar[t]); - } else if (r==2) { /* BLT */ - branch_taken = ((int)user_state->ar[s]<(int)user_state->ar[t]); - } else if (r==3) { /* BLTU */ - branch_taken = (user_state->ar[s]<user_state->ar[t]); - } else if (r==4) { /* BALL */ - branch_taken = (((~user_state->ar[s])&user_state->ar[t])==0); - } else if (r==5) { /* BBC */ -#if XCHAL_HAVE_BE - branch_taken = ((user_state->ar[s]&(0x80000000>>user_state->ar[t]))==0); - } else if (r==6) { /* BBCI */ - branch_taken = ((user_state->ar[s]&(0x80000000>>t))==0); - } else if (r==7) { /* BBCI */ - branch_taken = ((user_state->ar[s]&(0x80000000>>(t+16)))==0); -#else - branch_taken = ((user_state->ar[s]&(1<<user_state->ar[t]))==0); - } else if (r==6) { /* BBCI */ - branch_taken = ((user_state->ar[s]&(1<<t))==0); - } else if (r==7) { /* BBCI */ - branch_taken = ((user_state->ar[s]&(1<<(t+16)))==0); -#endif - } else if (r==8) { /* BANY */ - branch_taken = ((user_state->ar[s]&user_state->ar[t])!=0); - } else if (r==9) { /* BNE */ - branch_taken = (user_state->ar[s]!=user_state->ar[t]); - } else if (r==10) { /* BGE */ - branch_taken = ((int)user_state->ar[s]>=(int)user_state->ar[t]); - } else if (r==11) { /* BGEU */ - branch_taken = (user_state->ar[s]>=user_state->ar[t]); - } else if (r==12) { /* BNALL */ - branch_taken = (((~user_state->ar[s])&user_state->ar[t])!=0); - } else if (r==13) { /* BBS */ -#if XCHAL_HAVE_BE - branch_taken = ((user_state->ar[s]&(0x80000000>>user_state->ar[t]))!=0); - } else if (r==14) { /* BBSI */ - branch_taken = ((user_state->ar[s]&(0x80000000>>t))!=0); - } else if (r==15) { /* BBSI */ - branch_taken = ((user_state->ar[s]&(0x80000000>>(t+16)))!=0); -#else - branch_taken = ((user_state->ar[s]&(1<<user_state->ar[t]))!=0); - } else if (r==14) { /* BBSI */ - branch_taken = ((user_state->ar[s]&(1<<t))!=0); - } else if (r==15) { /* BBSI */ - branch_taken = ((user_state->ar[s]&(1<<(t+16)))!=0); -#endif - } - } - if (branch_taken) { - if (inst_type & XTHAL_DEST_REG_INST) { - return user_state->ar[inst_type>>24]; - } else if (inst_type & XTHAL_DEST_REL_INST) { - return xthal_branch_addr((void *)user_state->pc); - } - } -#if XCHAL_HAVE_LOOPS - else if (user_state->lcount && (npc==user_state->lend)) - return user_state->lbeg; -#endif - } - return npc; -} - -#endif /* INCLUDE_DEPRECATED_HAL_DEBUG_CODE */ - diff --git a/src/arch/xtensa/hal/debug_hndlr.S b/src/arch/xtensa/hal/debug_hndlr.S deleted file mode 100644 index 172f61c03966..000000000000 --- a/src/arch/xtensa/hal/debug_hndlr.S +++ /dev/null @@ -1,146 +0,0 @@ -// -// debug_hndlr.S -- default Xtensa debug exception handler -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/debug_hndlr.S#1 $ - -// Copyright (c) 2003-2010 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/config/system.h> - -#if XCHAL_HAVE_DEBUG && XCHAL_HAVE_EXCEPTIONS - - /* - * Default debug exception handler. - * - * Note that the debug exception vector must save a3 - * in EXCSAVE+XCHAL_DEBUGLEVEL before jumping here. - * - * This handler is used when no debugger is present. - * The end result of executing this default handler - * is as if no debug exception had occurred, eg. as if - * the core was running at PS.INTLEVEL >= DEBUGLEVEL. - * - * Because the debug exception vector might get - * placed in ROM, and be expected to work regardless - * of what executable image or OS is running in RAM, - * we're very careful not to use any RAM here. - * We don't know what RAM we can safely use. - * This tricky part to accomplishing this feat - * is to use only *one* register (a3, which was - * saved in EXCSAVE+XCHAL_DEBUGLEVEL), because we don't - * have RAM in which to safely store other regs. - * - * A real debugger application would normally - * have some kind of conventions, or special - * hardware support, to have its own RAM workspace - * in which to save context and do real work - * in this handler. - */ - - -#if XSHAL_DEBUG_VECTOR_ISROM - // Debug exception vector is in ROM, so place the handler - // in ROM also. Otherwise running different executables - // with that ROM will not work because the handler would - // likely not be there or be at the wrong address. - // - .section .srom.text, "ax" -#else - // Debug exception vector is in RAM, so we can safely - // place the handler in RAM as well. - // - .text -#endif - - .global xthal_debugexc_defhndlr_nw - .align 4 -xthal_debugexc_defhndlr_nw: - rsr.debugcause a3 // get cause of debug exception - - // Check for possible debug causes, in priority order. - // We only handle the highest priority condition present. - // (If there are multiple conditions, the lower priority - // condition(s) will normally trigger upon return from - // this exception handler.) - - bbci.l a3, DEBUGCAUSE_ICOUNT_SHIFT, 1f // ICOUNT trap? - movi a3, 0 - wsr.icount a3 // clear ICOUNT - j 3f - -/* - * Ensure that we have IBREAKs, otherwise the IBREAKENABLE - * special register is not there: - */ -#if XCHAL_NUM_IBREAK > 0 -1: bbci.l a3, DEBUGCAUSE_IBREAK_SHIFT, 1f // IBREAK match? - movi a3, 0 - wsr.ibreakenable a3 // disable IBREAK traps - j 3f -#endif - -/* Also check for DBREAK registers: */ -#if XCHAL_NUM_DBREAK > 0 -1: bbci.l a3, DEBUGCAUSE_DBREAK_SHIFT, 1f // DBREAK match? - movi a3, 0 - wsr.dbreakc0 a3 // disable DBREAK register 0 -# if XCHAL_NUM_DBREAK > 1 - wsr.dbreakc1 a3 // disable DBREAK register 1 -# endif - j 3f -#endif - -1: bbci.l a3, DEBUGCAUSE_BREAK_SHIFT, 1f // BREAK instruction? - //readsr epc XCHAL_DEBUGLEVEL a3 // get PC pointing to BREAK - //l8ui a3, a3, 1 // get first 4-bit operand of BREAK (in 2nd byte) - //extui a3, a3, (XCHAL_HAVE_BE*4), 4 // pos depends on endianness - //bnei a3, 1, 3f // is it a BREAK 1,x instruction? - readsr epc XCHAL_DEBUGLEVEL a3 // get PC pointing to BREAK - addi a3, a3, 3 // skip BREAK instruction - writesr epc XCHAL_DEBUGLEVEL a3 // update PC - j 3f - -1: bbci.l a3, DEBUGCAUSE_BREAKN_SHIFT, 1f // BREAK.N instruction? - readsr epc XCHAL_DEBUGLEVEL a3 // get PC pointing to BREAK - addi a3, a3, 2 // skip BREAK.N instruction - writesr epc XCHAL_DEBUGLEVEL a3 // update PC - j 3f - -1: bbci.l a3, DEBUGCAUSE_DEBUGINT_SHIFT, 1f // debug interrupt? - // Nothing to do... - j 3f - -1: // Unknown debug case? ignore - -3: readsr excsave XCHAL_DEBUGLEVEL a3 // restore a3 - rfi XCHAL_DEBUGLEVEL // return from debug exception - - .size xthal_debugexc_defhndlr_nw, . - xthal_debugexc_defhndlr_nw - - -#if XSHAL_DEBUG_VECTOR_ISROM - .text // in case this gets included by something else -#endif - -#endif /* XCHAL_HAVE_DEBUG */ - diff --git a/src/arch/xtensa/hal/disass.c b/src/arch/xtensa/hal/disass.c deleted file mode 100644 index 5f8d8517c551..000000000000 --- a/src/arch/xtensa/hal/disass.c +++ /dev/null @@ -1,153 +0,0 @@ -// -// disass.c - disassembly routines for Xtensa -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/disass.c#1 $ - -// Copyright (c) 2004-2013 Tensilica 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. - -#include <xtensa/hal.h> -#include <xtensa/config/core.h> - -#ifdef XCHAL_OP0_FORMAT_LENGTHS -extern const unsigned char Xthal_op0_format_lengths[16]; -#endif -extern const unsigned char Xthal_byte0_format_lengths[256]; - - -#if defined(__SPLIT__op0_format_lengths) - -/* Instruction length in bytes as function of its op0 field (first nibble): */ -#ifdef XCHAL_OP0_FORMAT_LENGTHS -const unsigned char Xthal_op0_format_lengths[16] = { - XCHAL_OP0_FORMAT_LENGTHS -}; -#endif - - -#elif defined(__SPLIT__byte0_format_lengths) - -/* Instruction length in bytes as function of its first byte: */ -const unsigned char Xthal_byte0_format_lengths[256] = { - XCHAL_BYTE0_FORMAT_LENGTHS -}; - - -#elif defined(__SPLIT__disassemble_size) - -// -// Disassembly is currently not supported in xtensa hal. -// - -int xthal_disassemble_size( unsigned char *instr_buf ) -{ -#ifdef XCHAL_OP0_FORMAT_LENGTHS - /* Extract op0 field of instruction (first nibble used for decoding): */ -# if XCHAL_HAVE_BE - int op0 = ((*instr_buf >> 4) & 0xF); -# else - int op0 = (*instr_buf & 0xF); -# endif - /*return (op0 & 8) ? 2 : 3;*/ /* simple case only works consistently on older hardware */ - return Xthal_op0_format_lengths[op0]; -#else - return Xthal_byte0_format_lengths[*instr_buf]; -#endif -} - - -#elif defined(__SPLIT__disassemble) - -/* - * Note: we make sure to avoid the use of library functions, - * to minimize dependencies. - */ -int xthal_disassemble( - unsigned char *instr_buffer, /* the address of the instructions */ - void *tgt_address, /* where the instruction is to be */ - char *buffer, /* where the result goes */ - unsigned buflen, /* size of buffer */ - unsigned options /* what to display */ - ) -{ -#define OUTC(c) do{ if( p < endp ) *p = c; p++; }while(0) - int i, n; - char *p = buffer, *endp = buffer + buflen - 1; - /*static char *ret = " decoding not supported";*/ - static const char _hexc[16] = "0123456789ABCDEF"; - - n = xthal_disassemble_size( instr_buffer ); - - if( options & XTHAL_DISASM_OPT_ADDR ) { - unsigned addr = (unsigned)tgt_address; - for( i = 0; i < 8; i++ ) { - OUTC( _hexc[(addr >> 28) & 0xF] ); - addr <<= 4; - } - } - - if( options & XTHAL_DISASM_OPT_OPHEX ) { - if( p > buffer ) - OUTC( ' ' ); - for( i = 0; i < 3; i++ ) { - if( i < n ) { - OUTC( _hexc[(*instr_buffer >> 4) & 0xF] ); - OUTC( _hexc[*instr_buffer++ & 0xF] ); - } else { - OUTC( ' ' ); - OUTC( ' ' ); - } - OUTC( ' ' ); - } - } - - if( options & XTHAL_DISASM_OPT_OPCODE ) { - if( p > buffer ) - OUTC( ' ' ); - OUTC( '?' ); - OUTC( '?' ); - OUTC( '?' ); - OUTC( ' ' ); - OUTC( ' ' ); - OUTC( ' ' ); - OUTC( ' ' ); - } - - if( options & XTHAL_DISASM_OPT_PARMS ) { - if( p > buffer ) - OUTC( ' ' ); - OUTC( '?' ); - OUTC( '?' ); - OUTC( '?' ); - } - - if( p < endp ) - *p = 0; - else if( buflen > 0 ) - *endp = 0; - - return p - buffer; /* return length needed, even if longer than buflen */ -} - -#undef OUTC - - -#endif /*split*/ diff --git a/src/arch/xtensa/hal/int_asm.S b/src/arch/xtensa/hal/int_asm.S deleted file mode 100644 index 4ce36da45a26..000000000000 --- a/src/arch/xtensa/hal/int_asm.S +++ /dev/null @@ -1,643 +0,0 @@ -// -// int_asm.S - assembly language interrupt utility routines -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/int_asm.S#1 $ - -// Copyright (c) 2003-2010 Tensilica 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. - -#include <xtensa/coreasm.h> - - -#if XCHAL_HAVE_INTERRUPTS -/* Offsets of XtHalVPriState structure members (Xthal_vpri_state variable): */ -#define XTHAL_VPRI_VPRI_OFS 0x00 -#define XTHAL_VPRI_LOCKLEVEL_OFS 0x01 -#define XTHAL_VPRI_LOCKVPRI_OFS 0x02 -#define XTHAL_VPRI_PAD0_OFS 0x03 -#define XTHAL_VPRI_ENABLED_OFS 0x04 -#define XTHAL_VPRI_LOCKMASK_OFS 0x08 -#define XTHAL_VPRI_PAD1_OFS 0x0C -#define XTHAL_VPRI_ENABLEMAP_OFS 0x10 -#define XTHAL_VPRI_RESOLVEMAP_OFS (0x10+0x40*(XCHAL_NUM_INTLEVELS+1)) -#define XTHAL_VPRI_END_OFS (0x10+0x40*(XCHAL_NUM_INTLEVELS*2+1)) -#endif /* XCHAL_HAVE_INTERRUPTS */ - - -#if defined(__SPLIT__get_intenable) || \ - defined(__SPLIT__get_intenable_nw) - -//---------------------------------------------------------------------- -// Access INTENABLE register from C -//---------------------------------------------------------------------- - -// unsigned xthal_get_intenable(void) -// -DECLFUNC(xthal_get_intenable) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - rsr.intenable a2 -# else - movi a2, 0 // if no INTENABLE (no interrupts), tell caller nothing is enabled -# endif - abi_return - endfunc - -#endif - -#if defined(__SPLIT__set_intenable) || \ - defined(__SPLIT__set_intenable_nw) - -// void xthal_set_intenable(unsigned) -// -DECLFUNC(xthal_set_intenable) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - wsr.intenable a2 -# endif - abi_return - endfunc - - -//---------------------------------------------------------------------- -// Access INTERRUPT, INTSET, INTCLEAR register from C -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__get_interrupt) || \ - defined (__SPLIT__get_interrupt_nw) - -// unsigned xthal_get_interrupt(void) -// -DECLFUNC (xthal_get_interrupt) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - rsr.interrupt a2 -# else - movi a2, 0 // if no INTERRUPT (no interrupts), tell caller nothing is pending -# endif - abi_return - endfunc - -#endif - -#if defined(__SPLIT__get_intread) || \ - defined(__SPLIT__get_intread_nw) - -DECLFUNC (xthal_get_intread) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - rsr.interrupt a2 -# else - movi a2, 0 // if no INTERRUPT (no interrupts), tell caller nothing is pending -# endif - abi_return - endfunc - -#endif - -#if defined(__SPLIT__set_intset) || \ - defined(__SPLIT__set_intset_nw) - -// void xthal_set_intset(unsigned) -// -DECLFUNC(xthal_set_intset) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - wsr.intset a2 -# endif - abi_return - endfunc - -#endif - -#if defined(__SPLIT__set_intclear) || \ - defined(__SPLIT__set_intclear_nw) - -// void xthal_set_intclear(unsigned) -// -DECLFUNC(xthal_set_intclear) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - wsr.intclear a2 -# endif - abi_return - endfunc - - - -//---------------------------------------------------------------------- -// Virtual PS.INTLEVEL support: -// allows running C code at virtual PS.INTLEVEL > 0 -// using INTENABLE to simulate the masking that PS.INTLEVEL would do. -//---------------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__get_vpri) ||\ - defined(__SPLIT__get_vpri_nw) - -// unsigned xthal_get_vpri(void); - -DECLFUNC(xthal_get_vpri) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - movi a2, Xthal_vpri_state - l8ui a2, a2, XTHAL_VPRI_VPRI_OFS -# else - movi a2, 0 // no interrupts, report we're always at level 0 -# endif - abi_return - endfunc - -#endif - -#if defined(__SPLIT__set_vpri_nw) - -// unsigned xthal_set_vpri_nw(unsigned) -// -// Must be called at PS.INTLEVEL <= 1. -// Doesn't touch the stack (doesn't reference a1 at all). -// Normally, PS should be restored with a6 after return from this call -// (it isn't restored automatically because some exception handlers -// want to keep ints locked for a while). -// -// On entry: -// a2 = new virtual interrupt priority (0x00 .. 0x1F) -// a3-a6 = undefined -// PS.INTLEVEL <= 1 -// On exit: -// a2 = previous virtual interrupt priority (0x0F .. 0x1F, or 0 if no interrupts) -// a3-a5 = clobbered -// a6 = PS as it was on entry -// PS.INTLEVEL = 1 -// !!!!!!!!! PS.WOE = 0 (but not if there are no interrupts; is this really needed???) -// INTENABLE = updated according to new vpri - -_SYM(xthal_set_vpri_nw) - -# if XCHAL_HAVE_INTERRUPTS - /* Make sure a2 is in the range 0x0F .. 0x1F: */ - movi a3, 0x1F // highest legal virtual interrupt priority - sub a4, a2, a3 // (a4 = newlevel - maxlevel) - movgez a2, a3, a4 // newlevel = maxlevel if (newlevel - maxlevel) >= 0 - movi a3, 15 // lowest legal virtual interrupt priority - sub a4, a2, a3 // (a4 = newlevel - 15) - movltz a2, a3, a4 // newlevel = 15 if newlevel < 15 - -xthal_set_vpri_nw_common: - movi a4, Xthal_vpri_state // address of vpri state structure - - /* - * Lockout interrupts for exclusive access to virtual priority structure - * while we examine and modify it. - * Note that we accessed a4 and don't access any further than a6, - * so we won't cause any spills, so we could leave WOE enabled (if it is), - * but we clear it because that might be what the caller wants, - * and is cleaner. - */ - // Get PS and mask off INTLEVEL: - rsil a6, 1 // save a6 = PS, set PS.INTLEVEL = 1 - - // Clear PS.WOE. (Can we get rid of this?!!!!!): - movi a3, ~0x00040000 // mask to... - rsr.ps a5 // get and save a6 = PS -//a2,a3,a4,a5,a6 - and a5, a5, a3 // ... clear a5.WOE - wsr.ps a5 // clear PS.WOE - rsync - -//a2,a4,a6 - /* Get mask of interrupts to be turned off at requested level: */ - l32i a5, a4, XTHAL_VPRI_ENABLED_OFS // get the global mask - addx4 a3, a2, a4 // a3 = a4 + a2*4 (index into enablemap[] array) -//a2,a3,a4,a5,a6 - l32i a3, a3, XTHAL_VPRI_ENABLEMAP_OFS // get the per-level mask - and a3, a5, a3 // new INTENABLE value according to new intlevel - wsr.intenable a3 // set it! -//a2,a4,a6 - - l8ui a5, a4, XTHAL_VPRI_VPRI_OFS // previous virtual priority - s8i a2, a4, XTHAL_VPRI_VPRI_OFS // new virtual priority - - // Let the caller restore PS: - //wsr.ps a6 // restore PS.INTLEVEL - //rsync - - mov a2, a5 // return previous virtual intlevel - -# else /* ! XCHAL_HAVE_INTERRUPTS */ -xthal_set_vpri_nw_common: -# if XCHAL_HAVE_EXCEPTIONS - rsr.ps a6 // return PS for caller to restore -# else - movi a6, 0 -# endif - movi a2, 0 // no interrupts, report we're always at virtual priority 0 -# endif /* XCHAL_HAVE_INTERRUPTS */ - ret - endfunc - - - -// unsigned xthal_set_vpri_intlevel_nw(unsigned); -// -// Same as xthal_set_vpri_nw() except that it accepts -// an interrupt level rather than a virtual interrupt priority. -// This just converts intlevel to vpri and jumps to xthal_set_vpri_nw. - -_SYM(xthal_set_vpri_intlevel_nw) -# if XCHAL_HAVE_INTERRUPTS - movi a3, 0x10 - movnez a2, a3, a2 // a2 = (a2 ? 0x10 : 0) - addi a2, a2, 0x0F // a2 += 0x0F -# endif - j xthal_set_vpri_nw_common // set vpri to a2 - endfunc - - - -#endif - -#if defined(__SPLIT__set_vpri) - -// unsigned xthal_set_vpri (unsigned newvpri); -// -// Normal windowed call (PS.INTLEVEL=0 and PS.WOE=1 on entry and exit). -// (PS.UM = 0 or 1) -// -// Returns previous virtual interrupt priority -// (0x0F .. 0x1F, or 0 if no interrupts). -// -// On entry: -// a2 = new virtual interrupt priority (0x00 .. 0x1F) -// On exit: -// a2 = previous vpri -// INTENABLE = updated according to new vpri - -DECLFUNC(xthal_set_vpri) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - /* Make sure a2 is in the range 0x0F .. 0x1F: */ - movi a3, 0x1F // highest legal virtual interrupt priority - sub a4, a2, a3 // (a4 = newlevel - maxlevel) - movgez a2, a3, a4 // newlevel = maxlevel if (newlevel - maxlevel) >= 0 - movi a3, 15 // lowest legal virtual interrupt priority - sub a4, a2, a3 // (a4 = newlevel - 15) - movltz a2, a3, a4 // newlevel = 15 if newlevel < 15 - -xthal_set_vpri_common1: - movi a4, Xthal_vpri_state // address of vpri state structure - - /* - * Lockout interrupts for exclusive access to virtual priority structure - * while we examine and modify it. - * Note that we accessed a4 and don't access any further than a6, - * so we won't cause any spills, so we can leave WOE enabled. - */ - // Get PS and mask off INTLEVEL: - rsil a6, 1 // save a6 = PS, set PS.INTLEVEL = 1 - - l8ui a7, a4, XTHAL_VPRI_VPRI_OFS // previous virtual priority (vpri) - - /* Get mask of interrupts to be turned off at requested level: */ - l32i a5, a4, XTHAL_VPRI_ENABLED_OFS // get the global mask - addx4 a3, a2, a4 // a3 = a4 + a2*4 (index into enablemap[] array) - l32i a3, a3, XTHAL_VPRI_ENABLEMAP_OFS // get the per-level mask - s8i a2, a4, XTHAL_VPRI_VPRI_OFS // new virtual priority (in load-slot) - and a3, a5, a3 // new INTENABLE value according to new intlevel - wsr.intenable a3 // set it! - - wsr.ps a6 // restore PS.INTLEVEL - rsync - - mov a2, a7 // return previous vpri - -# else /* ! XCHAL_HAVE_INTERRUPTS */ - movi a2, 0 // no interrupts, report we're always at virtual priority 0 -# endif /* XCHAL_HAVE_INTERRUPTS */ - abi_return - endfunc - - - -// unsigned xthal_set_vpri_intlevel (unsigned intlevel); -// -// Equivalent to xthal_set_vpri(XTHAL_VPRI(intlevel,0xF)). -// This just converts intlevel to vpri and jumps inside xthal_set_vpri. - -DECLFUNC(xthal_set_vpri_intlevel) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - movi a3, 0x10 - movnez a2, a3, a2 // a2 = (a2 ? 0x10 : 0) - addi a2, a2, 0x0F // a2 += 0x0F - j xthal_set_vpri_common1 // set vpri to a2 -# else - movi a2, 0 // no interrupts, report we're always at virtual priority 0 - abi_return -# endif - endfunc - - - -// unsigned xthal_set_vpri_lock (void); -// -// Equivalent to xthal_set_vpri(0x1F); -// Returns previous virtual interrupt priority. -// -DECLFUNC(xthal_set_vpri_lock) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - movi a2, 0x1F // lock at intlevel 1 - j xthal_set_vpri_common1 -# else - movi a2, 0 // no interrupts, report we're always at virtual priority 0 - abi_return -# endif - endfunc - - -#endif - -#if defined(__SPLIT__get_intpending_nw) - -// unsigned xthal_get_intpending_nw(void) -// -// Of the pending level-1 interrupts, returns -// the bitmask of interrupts at the highest software priority, -// and the index of the first of these. -// It also disables interrupts of that software priority and lower -// via INTENABLE. -// -// On entry: -// a0 = return PC -// a1 = sp -// a2-a6 = (available) (undefined) -// PS.INTLEVEL = 1 -// PS.WOE = 0 -// On exit: -// a0 = return PC -// a1 = sp (NOTE: stack is untouched, a1 is never referenced) -// a2 = index of first highest-soft-pri pending l1 interrupt (0..31), or -1 if none -// a3 = bitmask of highest-soft-pri pending l1 interrupts (0 if none) (may be deprecated) -// a4 = (clobbered) -// a5 = new vpri (not typically used by caller? so might get deprecated...?) -// a6 = old vpri (eg. to be saved as part of interrupt context's state) -// INTENABLE = updated according to new vpri -// INTERRUPT bit cleared for interrupt returned in a2 (if any), if software or edge-triggered or write-error -// all others = preserved - -_SYM(xthal_get_intpending_nw) -# if XCHAL_HAVE_INTERRUPTS - // Give us one more register to play with - //wsr.excsave1 a4 - - // Figure out which interrupt to process - - /* - Perform a binary search to find a mask of the interrupts that are - ready at the highest virtual priority level. - Xthal_vpri_resolvemap is a binary tree implemented within an array, - sorted by priority: each node contains the set of interrupts in - the range of priorities corresponding to the right half of its branch. - The mask of enabled & pending interrupts is compared with each node to - determine in which subbranch (left or right) the highest priority one is - present. After 4 such masks and comparisons (for 16 priorities), we have - determined the priority of the highest priority enabled&pending interrupt. - - Table entries for intlevel 'i' are bitmasks defined as follows (map=Xthal_vpri_resolvemap[i-1]): - map[8+(x=0)] = ints at pri x + 8..15 (8-15) - map[4+(x=0,8)] = ints at pri x + 4..7 (4-7,12-15) - map[2+(x=0,4,8,12)] = ints at pri x + 2..3 (2-3,6-7,10-11,14-15) - map[1+(x=0,2..12,14)] = ints at pri x + 1 (1,3,5,7,9,11,13,15) - map[0] = 0 (unused; for alignment) - */ - - rsr.interrupt a4 // a4 = mask of interrupts pending, including those disabled - rsr.intenable a2 // a2 = mask of interrupts enabled - movi a3, Xthal_vpri_state - and a4, a2, a4 // a4 = mask of enabled interrupts pending - beqz a4, gipfail // if none (can happen for spurious level-triggered interrupts, - // or ???), we're done - - mov a5, a3 - l32i a2, a5, XTHAL_VPRI_RESOLVEMAP_OFS+8*4 - bnone a2, a4, 1f - addi a5, a5, 8*4 -1: l32i a2, a5, XTHAL_VPRI_RESOLVEMAP_OFS+4*4 - bnone a2, a4, 1f - addi a5, a5, 4*4 -1: l32i a2, a5, XTHAL_VPRI_RESOLVEMAP_OFS+2*4 - bnone a2, a4, 1f - addi a5, a5, 2*4 -1: l32i a2, a5, XTHAL_VPRI_RESOLVEMAP_OFS+1*4 - bnone a2, a4, 1f - addi a5, a5, 1*4 -1: - -# if 0 - a5 = address of map ... - l32i a2, a5, XTHAL_VPRI_RESOLVEMAP_OFS+8*4 - addi a?, a5, 8*4 - and a2, a2, a4 - movnez a5, a?, a2 - l32i a2, a5, XTHAL_VPRI_RESOLVEMAP_OFS+4*4 - addi a?, a5, 4*4 - and a2, a2, a4 - movnez a5, a?, a2 - l32i a2, a5, XTHAL_VPRI_RESOLVEMAP_OFS+2*4 - addi a?, a5, 2*4 - and a2, a2, a4 - movnez a5, a?, a2 - l32i a2, a5, XTHAL_VPRI_RESOLVEMAP_OFS+1*4 - addi a?, a5, 1*4 - and a2, a2, a4 - movnez a5, a?, a2 -# endif - - // Here: - // a3 = Xthal_vpri_state - // a5 = Xthal_vpri_state + softpri*4 - // a4 = mask of enabled interrupts pending - // a2,a6 = available - - // Lock interrupts during virtual priority data structure transaction: - //rsil a6, 1 // set PS.INTLEVEL = 1 (a6 ignored) - // a2,a6 = available - - // The highest priority interrupt(s) in a4 is at softpri = (a5-a3) / 4. - // So interrupts in enablemap[1][softpri] are not in a4 (they are higher priority). - // The set of interrupts at softpri are: - // enablemap[1][softpri-1] - enablemap[1][softpri] - // So and'ing a4 with enablemap[1][softpri - 1] will give us - // the set of interrupts pending at the highest soft priority. - // - l32i a2, a5, XTHAL_VPRI_ENABLEMAP_OFS + 16*4 - 4 // get enablemap[1][softpri-1] - and a4, a2, a4 // only keep interrupts of highest pri (softpri) - - // a4 now has mask of pending interrupts at highest ready level (new vpri) - - // Update INTENABLE for this new virtual priority - l32i a2, a5, XTHAL_VPRI_ENABLEMAP_OFS + 16*4 // get vpri-specific mask = enablemap[1][softpri] - l32i a6, a3, XTHAL_VPRI_ENABLED_OFS // get global mask - sub a5, a5, a3 // a5 = softpri * 4 (for below; here for efficiency) - and a2, a2, a6 // and together - wsr.intenable a2 // disable interrupts at or below new vpri - // a2,a6 = available - - // Update new virtual priority: - l8ui a6, a3, XTHAL_VPRI_VPRI_OFS // get old vpri (returned) - srli a5, a5, 2 // a5 = softpri (0..15) - addi a5, a5, 0x10 // a5 = 0x10 + softpri = new virtual priority - s8i a5, a3, XTHAL_VPRI_VPRI_OFS // store new vpri (returned) - - // Undo the temporary lock (if was at PS.INTLEVEL > 1): - //rsil a2, 1 - - mov a3, a4 // save for the caller (in case it wants it?) - - // Choose one of the set of highest-vpri pending interrupts to process. - // For speed (and simplicity), use this simple two-instruction sequence - // to select the least significant bit set in a4. This implies that - // interrupts with a lower interrupt number take precedence over those - // with a higher interrupt number (!!). - // - neg a2, a4 // keep only the least-significant bit that is set... - and a4, a2, a4 // ... in a4 - - // Software, edge-triggered, and write-error interrupts are cleared by writing to the - // INTCLEAR pseudo-reg (to clear relevant bits of the INTERRUPT register). - // To simplify interrupt handlers (so they avoid tracking which type of - // interrupt they handle and act accordingly), clear such interrupts here. - // To avoid race conditions, the clearing must occur *after* we undertake - // to process the interrupt, and *before* actually handling the interrupt. - // Interrupt handlers may additionally clear the interrupt themselves - // at appropriate points if needed to avoid unnecessary interrupts. - // -#define CLEARABLE_INTLEVEL1_MASK (XCHAL_INTLEVEL1_MASK & XCHAL_INTCLEARABLE_MASK) -# if CLEARABLE_INTLEVEL1_MASK != 0 - //movi a2, CLEARABLE_INTLEVEL1_MASK - //and a2, a2, a4 - //wsr.intclear a2 - wsr.intclear a4 // no effect if a4 not a software or edge-triggered or write-error interrupt -# endif - - // Convert the single-bit interrupt mask to an interrupt number. - // (ie. compute log2 using either the NSAU instruction or a binary search) - - find_ms_setbit a2, a4, a2, 0 // set a2 to index of lsbit set in a4 (0..31) - // NOTE: assumes a4 != 0 (otherwise a2 is undefined[?]) - - // a2 has vector number (0..31) - - //rsr.excsave1 a4 - ret - -gipfail: - l8ui a6, a3, XTHAL_VPRI_VPRI_OFS // get old vpri - mov a5, a6 // is also new vpri (unchanged) -# else /* XCHAL_HAVE_INTERRUPTS */ - // No interrupts configured! - movi a5, 0 // return zero new vpri - movi a6, 0 // return zero old vpri -# endif /* XCHAL_HAVE_INTERRUPTS */ - movi a2, -1 // return bogus vector number (eg. can be quickly tested for negative) - movi a3, 0 // return zero bitmask of interrupts pending - ret - endfunc - -// ----------------------------------------------------------------- - -#endif - -#if defined(__SPLIT__vpri_lock) || \ - defined(__SPLIT__vpri_lock_nw) - -// void xthal_vpri_lock() -// -// Used internally by the Core HAL to block interrupts of higher or equal -// priority than Xthal_vpri_locklevel during virtual interrupt operations. -// -DECLFUNC(xthal_vpri_lock) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - rsil a6, 1 // save a6 = PS, set PS.INTLEVEL = 1 - - // if( Xthal_vpri_level < Xthal_vpri_locklevel ) - // - movi a2, Xthal_vpri_state // a2 := address of global var. Xthal_vpri_state - //interlock - l8ui a3, a2, XTHAL_VPRI_VPRI_OFS // a3 := Xthal_vpri_level == Xthal_vpri_state.vpri - l8ui a5, a2, XTHAL_VPRI_LOCKLEVEL_OFS // a5 := Xthal_vpri_locklevel - l32i a4, a2, XTHAL_VPRI_ENABLED_OFS // a4 := Xthal_vpri_enabled - bgeu a3, a5, xthal_vpri_lock_done - - // xthal_set_intenable( Xthal_vpri_enablemap[0][Xthal_vpri_locklevel] & Xthal_vpri_enabled ); - // - addx4 a3, a5, a2 // a3 := a2 + a5*4 (index into enablemap[] array) - l32i a3, a3, XTHAL_VPRI_ENABLEMAP_OFS // a3 := Xthal_vpri_enablemap[0][Xthal_vpri_locklevel] - //interlock - and a2, a4, a3 - wsr.intenable a2 - -xthal_vpri_lock_done: - wsr.ps a6 // restore PS.INTLEVEL - rsync -# endif - abi_return - endfunc - -#endif - -#if defined(__SPLIT__vpri_unlock) || \ - defined(__SPLIT__vpri_unlock_nw) - -// void xthal_vpri_unlock(void) -// -// Enable interrupts according to the current virtual interrupt priority. -// This effectively "unlocks" interrupts disabled by xthal_vpri_lock() -// (assuming the virtual interrupt priority hasn't changed). -// -DECLFUNC(xthal_vpri_unlock) - abi_entry -# if XCHAL_HAVE_INTERRUPTS - // - // This should be free of race-conditions. - // - // xthal_set_intenable( Xthal_vpri_enablemap[0][Xthal_vpri_level] & Xthal_vpri_enabled ); - // - movi a2, Xthal_vpri_state // a2 := address of global var. Xthal_vpri_state - //interlock - l8ui a3, a2, XTHAL_VPRI_VPRI_OFS // a3 := Xthal_vpri_level == Xthal_vpri_state.vpri - l32i a4, a2, XTHAL_VPRI_ENABLED_OFS // a4 := Xthal_vpri_enabled - addx4 a3, a3, a2 // a3 := a2 + a3*4 (index into enablemap[] array) - l32i a3, a3, XTHAL_VPRI_ENABLEMAP_OFS // a3 := Xthal_vpri_enablemap[0][Xthal_vpri_level] - //interlock - and a2, a4, a3 - wsr.intenable a2 -# endif - abi_return - endfunc - -#endif /*SPLIT*/ - diff --git a/src/arch/xtensa/hal/interrupts.c b/src/arch/xtensa/hal/interrupts.c deleted file mode 100644 index 1bf8bd99c559..000000000000 --- a/src/arch/xtensa/hal/interrupts.c +++ /dev/null @@ -1,850 +0,0 @@ -// -// interrupts.c - interrupts related constants and functions -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/interrupts.c#1 $ - -// Copyright (c) 2002-2004 Tensilica 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. - -#include <xtensa/config/core.h> - -#if XCHAL_HAVE_INTERRUPTS - -/* For internal use by the HAL: */ -// static void xthal_vpri_lock(void); -// static void xthal_vpri_unlock(void); -extern void xthal_vpri_lock(void); -extern void xthal_vpri_unlock(void); - - -/* - * Definitions: - * - * Virtual interrupt level = 0 .. 0xFF - * - * ... - */ - -#define XTHAL_DEFAULT_SOFTPRI 4 /* default software priority (range 0..15) */ - /* IMPORTANT: if you change this, you also - need to update the initial resolvemap[] - value below... */ - -/* - * Macros to convert between: - * intlevel (0..15) and software priority within an intlevel (0..15) - * and - * virtual interrupt priority (0..0xFF), which is a combination of the above two. - */ -#define XTHAL_VPRI_INTLEVEL(vpri) (((vpri) >> 4) & 0xF) -#define XTHAL_VPRI_SOFTPRI(vpri) ((vpri) & 0xF) -#define XTHAL_VPRI(intlevel,softpri) ((((intlevel)&0xF)<<4)|((softpri)&0xF)) - - -/* - * Virtual priority management data structures. - * This structure is instantiated as Xthal_vpri_state (below). - * - * IMPORTANT: if you change anything in this structure, - * you must accordingly change structure offsets - * defined in int_asm.S . - * - * IMPORTANT: the worst-case offset of the resolvemap[] field is 976 bytes - * (0x10 + 0x40*15), which is accessed in int_asm.S at a further - * offset of 8*4==32 for a total offset of 1008, very close - * to l32i's offset limit of 1020. So you can't push it much - * further. - * - * [INTERNAL NOTE: There might be a trick that will save 64 bytes, - * if really needed, by trimming 15 word entries from the start - * of enablemap[] ... -MG] - */ -typedef struct XtHalVPriState { - /* - * Current virtual interrupt priority (0x0F .. 0xFF) - * (or actually, 0x0F .. XCHAL_NUM_INTLEVELS*0x10+0x0F). - * Virtual priorities 0x00 to 0x0E are mapped to 0x0F (they're all - * equivalent, because there's no such thing as a level 0 interrupt), - * which may help optimize the size of enablemap[] in the future. - * Virtual priorities above XCHAL_NUM_INTLEVELS*0x10+0x0F are - * mapped to XCHAL_NUM_INTLEVELS*0x10+0x0F, which is equivalent. - * - * NOTE: this variable is actually part of the processor context, - * which means (for most OSes) that it must be saved - * in the task control block along with other register state. - */ - unsigned char vpri; // current virtual interrupt priority (0x0F..0xFF) - unsigned char locklevel; // real interrupt level used to get exclusive - // access to this structure; MUST be at least one (1) - unsigned char lockvpri; // virtual interrupt level used to get exclusive - // access to this structure; MUST be XTHAL_VPRI(locklevel,15) - // (so it's at least 0x1F); placed here for efficiency - unsigned char pad0; // (alignment padding, unused) - - unsigned enabled; // mask of which interrupts are enabled, regardless of level - // (level masking is applied on top of this) - - unsigned lockmask; // (unused?) INTENABLE value used to lock out - // interrupts for exclusive access to this structure - - unsigned pad1; // (alignment padding, unused) - - /* - * For each virtual interrupt priority, this array provides the - * bitmask of interrupts of greater virtual priority - * (ie. the set of interrupts to enable at that virtual priority, - * if all interrupts were enabled in field 'enabled'). - */ - unsigned enablemap[XCHAL_NUM_INTLEVELS+1][16]; - - /* - * Table entries for intlevel 'i' are bitmasks defined as follows, - * with map == Xthal_vpri_resolvemap[i-1]: - * map[8+(x=0)] = ints at pri x + 8..15 (8-15) - * map[4+(x=0,8)] = ints at pri x + 4..7 (4-7,12-15) - * map[2+(x=0,4,8,12)] = ints at pri x + 2..3 (2-3,6-7,10-11,14-15) - * map[1+(x=0,2..12,14)] = ints at pri x + 1 (1,3,5,7,9,11,13,15) - * map[0] = 0 (unused; for alignment) - */ - unsigned resolvemap[XCHAL_NUM_INTLEVELS][16]; - -} XtHalVPriState; - - -extern XtHalVPriState Xthal_vpri_state; -extern unsigned char Xthal_int_vpri[32]; -extern XtHalVoidFunc * Xthal_tram_trigger_fn; - -extern void xthal_null_func(void); - -/* Shorthand for structure members: */ -#define Xthal_vpri_level Xthal_vpri_state.vpri -#define Xthal_vpri_locklevel Xthal_vpri_state.locklevel -#define Xthal_vpri_lockvpri Xthal_vpri_state.lockvpri -#define Xthal_vpri_enabled Xthal_vpri_state.enabled -#define Xthal_vpri_lockmask Xthal_vpri_state.lockmask // unused? -#define Xthal_vpri_enablemap Xthal_vpri_state.enablemap -#define Xthal_vpri_resolvemap Xthal_vpri_state.resolvemap -#if 0 -Combined refs: - - enablemap, vpri, enabled (xthal_set_vpri[_nw]) - - enablemap, vpri, enabled, resolvemap (xthal_get_intpending_nw) - - enablemap, vpri, enabled, locklevel (xthal_vpri_lock) - - enablemap, vpri, enabled (xthal_vpri_unlock) -#endif - -#endif /* XCHAL_HAVE_INTERRUPTS */ - - - -#if defined(__SPLIT__num_intlevels) - -// the number of interrupt levels -const unsigned char Xthal_num_intlevels = XCHAL_NUM_INTLEVELS; - -#endif - -#if defined(__SPLIT__num_interrupts) - -// the number of interrupts -const unsigned char Xthal_num_interrupts = XCHAL_NUM_INTERRUPTS; - -#endif - -#if defined(__SPLIT__excm_level) - -// the highest level of interrupts masked by PS.EXCM (if XEA2) -const unsigned char Xthal_excm_level = XCHAL_EXCM_LEVEL; - -#endif - -#if defined(__SPLIT__intlevel_mask) - -// mask of interrupts at each intlevel -const unsigned Xthal_intlevel_mask[16] = { - XCHAL_INTLEVEL_MASKS -}; - -#endif - -#if defined(__SPLIT__intlevel_andbelow_mask) - -// mask for level 1 to N interrupts -const unsigned Xthal_intlevel_andbelow_mask[16] = { - XCHAL_INTLEVEL_ANDBELOW_MASKS -}; - -#endif - -#if defined(__SPLIT__intlevel) - -// level per interrupt -const unsigned char Xthal_intlevel[32] = { - XCHAL_INT_LEVELS -}; - -#endif - -#if defined(__SPLIT__inttype) - -// type of each interrupt -const unsigned char Xthal_inttype[32] = { - XCHAL_INT_TYPES -}; - -#endif - -#if defined(__SPLIT__inttype_mask) - -const unsigned Xthal_inttype_mask[XTHAL_MAX_INTTYPES] = { - XCHAL_INTTYPE_MASKS -}; - -#endif - -#if defined(__SPLIT__timer_interrupt) - -// interrupts assigned to each timer (CCOMPARE0 to CCOMPARE3), -1 if unassigned -const int Xthal_timer_interrupt[XTHAL_MAX_TIMERS] = { - XCHAL_TIMER_INTERRUPTS -}; - -#endif - -#if defined(__SPLIT__vpri) - -#if XCHAL_HAVE_INTERRUPTS - -/* - * Note: this structure changes dynamically at run-time, - * but is initialized here for efficiency and simplicity, - * according to configuration. - */ -XtHalVPriState Xthal_vpri_state = { - 0x00, /* vpri */ - 1, /* locklevel */ - 0x1F, /* lockvpri */ - 0, /* pad0 */ - 0x00000000, /* enabled */ - 0x00000000, /* lockmask (unused?) */ - 0, /* pad1 */ - -#define DEFAULT_ENABLEMAP(levela,levelb) \ - { (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 0 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 1 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 2 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 3 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 4 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 5 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 6 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 7 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 8 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 9 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >10 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >11 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >12 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >13 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >14 ? levela : levelb)), \ - (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >15 ? levela : levelb)) } - - /* Xthal_vpri_enablemap[XCHAL_NUM_INTLEVELS+1][16]: */ - { - DEFAULT_ENABLEMAP(XCHAL_INTLEVEL0_ANDBELOW_MASK,XCHAL_INTLEVEL0_ANDBELOW_MASK), -#if XCHAL_NUM_INTLEVELS >= 1 - DEFAULT_ENABLEMAP(XCHAL_INTLEVEL0_ANDBELOW_MASK,XCHAL_INTLEVEL1_ANDBELOW_MASK), -#endif -#if XCHAL_NUM_INTLEVELS >= 2 - DEFAULT_ENABLEMAP(XCHAL_INTLEVEL1_ANDBELOW_MASK,XCHAL_INTLEVEL2_ANDBELOW_MASK), -#endif -#if XCHAL_NUM_INTLEVELS >= 3 - DEFAULT_ENABLEMAP(XCHAL_INTLEVEL2_ANDBELOW_MASK,XCHAL_INTLEVEL3_ANDBELOW_MASK), -#endif -#if XCHAL_NUM_INTLEVELS >= 4 - DEFAULT_ENABLEMAP(XCHAL_INTLEVEL3_ANDBELOW_MASK,XCHAL_INTLEVEL4_ANDBELOW_MASK), -#endif -#if XCHAL_NUM_INTLEVELS >= 5 - DEFAULT_ENABLEMAP(XCHAL_INTLEVEL4_ANDBELOW_MASK,XCHAL_INTLEVEL5_ANDBELOW_MASK), -#endif -#if XCHAL_NUM_INTLEVELS >= 6 - DEFAULT_ENABLEMAP(XCHAL_INTLEVEL5_ANDBELOW_MASK,XCHAL_INTLEVEL6_ANDBELOW_MASK), -#endif -#if XCHAL_NUM_INTLEVELS >= 7 -# error Interrupt levels greater than 6 not currently supported in the HAL interrupt routines. -#endif - }, - - /* Xthal_vpri_resolvemap[XCHAL_NUM_INTLEVELS][16]: */ - { -#if XCHAL_NUM_INTLEVELS >= 1 /* set for default soft priority of 4: */ - {0,0,0,0, XCHAL_INTLEVEL1_MASK,0,0,0, 0,0,0,0, 0,0,0,0}, -#endif -#if XCHAL_NUM_INTLEVELS >= 2 /* set for default soft priority of 4: */ - {0,0,0,0, XCHAL_INTLEVEL2_MASK,0,0,0, 0,0,0,0, 0,0,0,0}, -#endif -#if XCHAL_NUM_INTLEVELS >= 3 /* set for default soft priority of 4: */ - {0,0,0,0, XCHAL_INTLEVEL3_MASK,0,0,0, 0,0,0,0, 0,0,0,0}, -#endif -#if XCHAL_NUM_INTLEVELS >= 4 /* set for default soft priority of 4: */ - {0,0,0,0, XCHAL_INTLEVEL4_MASK,0,0,0, 0,0,0,0, 0,0,0,0}, -#endif -#if XCHAL_NUM_INTLEVELS >= 5 /* set for default soft priority of 4: */ - {0,0,0,0, XCHAL_INTLEVEL5_MASK,0,0,0, 0,0,0,0, 0,0,0,0}, -#endif -#if XCHAL_NUM_INTLEVELS >= 6 /* set for default soft priority of 4: */ - {0,0,0,0, XCHAL_INTLEVEL6_MASK,0,0,0, 0,0,0,0, 0,0,0,0}, -#endif -#if XCHAL_NUM_INTLEVELS >= 7 /* set for default soft priority of 4: */ -# error Interrupt levels greater than 6 not currently supported in the HAL interrupt routines. -#endif - } - -}; - - -/* - * Virtual (software) priority (0x00..0xFF) of each interrupt. - * This isn't referenced by assembler. - */ -unsigned char Xthal_int_vpri[32] = { -#define DEFAULT_INTVPRI(level) (level ? ((level << 4) | XTHAL_DEFAULT_SOFTPRI) : 0) - DEFAULT_INTVPRI( XCHAL_INT0_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT1_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT2_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT3_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT4_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT5_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT6_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT7_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT8_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT9_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT10_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT11_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT12_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT13_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT14_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT15_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT16_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT17_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT18_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT19_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT20_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT21_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT22_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT23_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT24_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT25_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT26_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT27_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT28_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT29_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT30_LEVEL ), - DEFAULT_INTVPRI( XCHAL_INT31_LEVEL ) -}; - - -#if 0 -/* - * A number of things may have already been written not calling - * this function, so it isn't straightforward to start requiring it: - */ -void xthal_vpri_init( int default_vpri ) -{ - int i, j; - - Xthal_vpri_level = 0; /* vpri */ - Xthal_vpri_locklevel = 1; /* locklevel */ - Xthal_vpri_lockvpri = 0x1F; /* lockvpri */ - Xthal_vpri_enabled = 0x00000000; /* enabled */ - Xthal_vpri_lockmask = 0x00000000; /* lockmask (unused?) */ - for( i = 0; i < XCHAL_NUM_INTLEVELS; i++ ) { - for( j = 0; j < 16; j++ ) - Xthal_vpri_enablemap[i][j] = XCHAL_INTLEVEL15_ANDBELOW_MASK - & ~Xthal_intlevel_andbelow_mask[i - (j < default_vpri && i > 0)]; - } - for( i = 1; i < XCHAL_NUM_INTLEVELS; i++ ) { - for( j = 0; j < 16; j++ ) - Xthal_vpri_resolvemap[i-1][j] = 0; - if( (default_vpri & 1) != 0 ) - Xthal_vpri_resolvemap[i-1][default_vpri & 0xF] |= Xthal_intlevel_mask[i]; - if( (default_vpri & 2) != 0 ) - Xthal_vpri_resolvemap[i-1][default_vpri & 0xE] |= Xthal_intlevel_mask[i]; - if( (default_vpri & 4) != 0 ) - Xthal_vpri_resolvemap[i-1][default_vpri & 0xC] |= Xthal_intlevel_mask[i]; - if( (default_vpri & 8) != 0 ) - Xthal_vpri_resolvemap[i-1][default_vpri & 0x8] |= Xthal_intlevel_mask[i]; - } - for( i = 0; i < 32; i++ ) - Xthal_int_vpri[i] = (Xthal_intlevel[i] << 4) | (default_vpri & 0xF); -} -#endif /*0*/ - -void xthal_null_func(void) { } -XtHalVoidFunc *Xthal_tram_trigger_fn = xthal_null_func; - - -#endif /* XCHAL_HAVE_INTERRUPTS */ - -#endif - -#if defined(__SPLIT__vpri_to_intlevel) - -/* - * xthal_vpri_to_intlevel - * - * Converts a virtual interrupt priority to the closest equivalent - * (equal or higher) interrupt level. - */ -unsigned xthal_vpri_to_intlevel(unsigned vpri) -{ -#if XCHAL_HAVE_INTERRUPTS - return( XTHAL_VPRI_INTLEVEL( vpri ) ); -#else - return( vpri ); -#endif -} - -#endif - -#if defined(__SPLIT__intlevel_to_vpri) - -/* - * xthal_intlevel_to_vpri - * - * Converts an interrupt level to a virtual interrupt priority. - */ -unsigned xthal_intlevel_to_vpri(unsigned intlevel) -{ -#if XCHAL_HAVE_INTERRUPTS - return( XTHAL_VPRI( intlevel, 0xF ) ); -#else - return( intlevel ); -#endif -} - -#endif - -#if defined(__SPLIT__vpri_int_enable) - -/* - * xthal_int_enable - * - * Enables given set of interrupts, and returns previous enabled-state of these interrupts. - */ -unsigned xthal_int_enable(unsigned mask) -{ -#if XCHAL_HAVE_INTERRUPTS - unsigned prev_enabled, syncmask; - - xthal_vpri_lock(); - prev_enabled = Xthal_vpri_enabled | Xthal_tram_enabled; - - /* Figure out which bits must go in Xthal_tram_enabled: */ - syncmask = (mask & Xthal_tram_pending & Xthal_tram_sync); - if( syncmask != 0 ) { - Xthal_tram_enabled |= syncmask; - mask &= ~syncmask; - /* - * If we are re-enabling a pending trampolined interrupt, - * there is a possibility that the level-1 software interrupt - * is no longer pending, having already occurred (without processing - * the trampoline because it was disabled). So we have to - * ensure that the level-1 software interrupt used for trampolining - * is pending. - * We let the BSP do this rather than the HAL, because it could - * potentially use an external level-1 interrupt to trampoline - * (if proper hardware was available) rather than a software interrupt. - */ - (*Xthal_tram_trigger_fn)(); - } - /* The rest go in the global enabled mask: */ - Xthal_vpri_enabled |= mask; - - xthal_vpri_unlock(); /* update INTENABLE as per current vpri */ - return( prev_enabled ); - -#else /* XCHAL_HAVE_INTERRUPTS */ - return( 0 ); -#endif /* XCHAL_HAVE_INTERRUPTS */ -} - -#endif - -#if defined(__SPLIT__vpri_int_disable) - -/* - * xthal_int_disable - * - * Disables given set of interrupts, and returns previous enabled-state of these interrupts. - */ -unsigned xthal_int_disable(unsigned mask) -{ -#if XCHAL_HAVE_INTERRUPTS - unsigned prev_enabled; - - xthal_vpri_lock(); - prev_enabled = Xthal_vpri_enabled | Xthal_tram_enabled; - Xthal_vpri_enabled &= ~mask; - Xthal_tram_enabled &= ~mask; - xthal_vpri_unlock(); /* update INTENABLE as per current vpri */ - return( prev_enabled ); -#else - return( 0 ); -#endif -} - -#endif - -#if defined(__SPLIT__set_vpri_locklevel) - -void xthal_set_vpri_locklevel(unsigned intlevel) -{ -#if XCHAL_HAVE_INTERRUPTS - if( intlevel < 1 ) - intlevel = 1; - else if( intlevel > XCHAL_NUM_INTLEVELS ) - intlevel = XCHAL_NUM_INTLEVELS; - Xthal_vpri_state.locklevel = intlevel; - Xthal_vpri_state.lockvpri = XTHAL_VPRI(intlevel, 15); -#endif -} - -#endif - -#if defined(__SPLIT__get_vpri_locklevel) - -unsigned xthal_get_vpri_locklevel(void) -{ -#if XCHAL_HAVE_INTERRUPTS - return( Xthal_vpri_state.locklevel ); -#else - return( 1 ); /* must return at least 1, some OSes assume this */ -#endif -} - -#endif - -#if defined(__SPLIT__set_int_vpri) - -/* - * xthal_set_int_vpri (was intSetL1Pri) - * - * Set the virtual (software) priority of an interrupt. - * Note: the intlevel of an interrupt CANNOT be changed -- this is - * set in hardware according to the core configuration file. - * - * intnum interrupt number (0..31) - * vpri virtual interrupt priority (0..15, or intlevel*16+(0..15) ) - */ -int xthal_set_int_vpri(int intnum, int vpri) -{ -#if XCHAL_HAVE_INTERRUPTS - unsigned mask, maskoff, basepri, prevpri, intlevel, *maskp, i; - - /* - * Verify parameters: - */ - if( (unsigned)intnum >= XCHAL_NUM_INTERRUPTS || (unsigned)vpri > 0xFF ) - return( 0 ); /* error: bad parameter(s) */ - /* - * If requested priority specifies an intlevel, it must match that - * of the interrupt specified; otherwise (0..15) the proper intlevel of - * the specified interrupt is assumed, and added to the parameter: - */ - intlevel = Xthal_intlevel[intnum]; /* intnum's intlevel */ - if( intlevel == 0 || intlevel > XCHAL_NUM_INTLEVELS ) - return( 0 ); /* error: no support for setting priority of NMI etc. */ - basepri = intlevel << 4; /* intnum's base soft-pri. */ - if( vpri > 0x0F ) { /* intlevel portion given? */ - if( (vpri & 0xF0) != basepri ) /* then it must be correct */ - return( 0 ); /* error: intlevel mismatch */ - vpri &= 0x0F; /* remove it */ - } - - mask = 1L << intnum; - - /* - * Lock interrupts during virtual priority data structure updates: - */ - xthal_vpri_lock(); - - /* - * Update virtual priority of 'intnum': - */ - prevpri = Xthal_int_vpri[intnum]; /* save for return value */ - Xthal_int_vpri[intnum] = basepri | vpri; - /* This interrupt must only be enabled at virtual priorities lower than its own: */ - for( i = 0; i < vpri; i++ ) - Xthal_vpri_enablemap[0][basepri++] |= mask; - maskoff = ~mask; - for( ; i <= 0x0F; i++ ) - Xthal_vpri_enablemap[0][basepri++] &= maskoff; - - /* - * Update the prioritization table used to resolve priorities by binary search: - */ - /* Remove interrupt <intnum> from prioritization table: */ - maskp = Xthal_vpri_resolvemap[intlevel-1]; - for (i=0; i<16; i++) - maskp[i] &= maskoff; - /* Add interrupt <intnum> to prioritization table at its (new) given priority: */ - if( vpri & 0x1 ) - maskp[vpri] |= mask; - if( vpri & 0x2 ) - maskp[vpri & 0xE] |= mask; - if( vpri & 0x4 ) - maskp[vpri & 0xC] |= mask; - if( vpri & 0x8 ) - maskp[vpri & 0x8] |= mask; - - /* - * Unlock interrupts (back to current level) and update INTENABLE: - */ - xthal_vpri_unlock(); - - return( prevpri ); -#else /* XCHAL_HAVE_INTERRUPTS */ - return( 0 ); -#endif /* XCHAL_HAVE_INTERRUPTS */ -} /* xthal_set_int_vpri */ - -#endif - -#if defined(__SPLIT__get_int_vpri) - -int xthal_get_int_vpri(int intnum) -{ -#if XCHAL_HAVE_INTERRUPTS - if( (unsigned)intnum >= XCHAL_NUM_INTERRUPTS ) - return( 0 ); /* error: bad parameter */ - return( Xthal_int_vpri[intnum] ); -#else - return( 0 ); -#endif -} - - -#endif - -#if defined(__SPLIT__trampolines) - - - /* - SUPPORT FOR TRAMPOLINES - - NOTE: trampolining is a special case. - There are two ways (defined here) to trampoline down - from a high-level interrupt to a level-one interrupt. - - a) Synchronous (restrained) trampolining. - Trampolining without clearing the high-level interrupt, - letting the level-one interrupt handler clear the - source of the interrupt. - Here the high-level interrupt must be kept disabled - while trampolining down, and re-enabled after the - level-one interrupt handler completes. - This is what one might do to "convert" a high-level - interrupt into a level-one interrupt. - The high-level interrupt handler code can be generic. - [One could argue this type of trampolining isn't required, - which may? be true...] - b) Asynchronous (free) trampolining. - Trampolining when clearing the high-level interrupt - right away in the high-level interrupt handler. - Here the high-level interrupt is allowed to remain - enabled while trampolining occurs. This is very - useful when some processing must occur with low - latency, but the rest of the processing can occur - at lower (eg. level-one) priority. It is particularly - useful when the lower-priority processing occurs - for only some of the high-level interrupts. - Of course this requires custom assembler code to - handle the high-level interrupt and clear the source - of the interrupt, so the high-level interrupt handler - cannot be generic (as opposed to synchronous trampolining). - - In both cases, a level-one software interrupt is used - for trampolining (one could also trampoline from level - m to n, m > n, n > 1, but that isn't nearly as useful; - it's generally the ability to execute C code and - to process exceptions that is sought after). - - Default trampolining support is currently implemented as follows. - - Trampoline handler: - - A high-level interrupt is considered enabled if *either* - its INTENABLE bit or its xt_tram_ints bit is set - (note that both should never be set at the same time). - - */ - - -/* These are described in xtensa/hal.h (assumed initialized to zero, in BSS): */ -unsigned Xthal_tram_pending; -unsigned Xthal_tram_enabled; -unsigned Xthal_tram_sync; - - - -XtHalVoidFunc* xthal_set_tram_trigger_func( XtHalVoidFunc *trigger_fn ) -{ -#if XCHAL_HAVE_INTERRUPTS - XtHalVoidFunc *fn; - - fn = Xthal_tram_trigger_fn; - Xthal_tram_trigger_fn = trigger_fn; - return( fn ); -#else - (void)trigger_fn; - return( 0 ); -#endif -} - - -/* - * xthal_tram_set_sync - * - * Configure type of trampoline for a high-level interrupt. - * By default any trampoline is asynchronous, this need only - * be called to tell the Core HAL that a high-level interrupt - * will be using synchronous trampolining (down to a level-1 interrupt). - * - * intnum interrupt number (0 .. 31) - * sync 0 = async, 1 = synchronous - * - * Returns previous sync state of interrupt (0 or 1) - * or -1 if invalid interrupt number provided. - */ -int xthal_tram_set_sync( int intnum, int sync ) -{ -#if XCHAL_HAVE_INTERRUPTS - unsigned mask; - int prev; - - if( (unsigned)intnum >= XCHAL_NUM_INTERRUPTS ) - return( -1 ); - mask = 1L << intnum; - prev = ((Xthal_tram_sync & mask) != 0); - if( sync ) - Xthal_tram_sync |= mask; - else - Xthal_tram_sync &= ~mask; - return( prev ); -#else /* XCHAL_HAVE_INTERRUPTS */ - return( 0 ); -#endif /* XCHAL_HAVE_INTERRUPTS */ -} - - -/* - * xthal_tram_pending_to_service - * - * This is called by the trampoline interrupt handler - * (eg. by a level-one software interrupt handler) - * to obtain the bitmask of high-level interrupts - * that it must service. - * Returns that bitmask (note: this can sometimes be zero, - * eg. if currently executing level-one code disables the high-level - * interrupt before the trampoline handler has a chance to run). - * - * This call automatically clears the trampoline pending - * bits for the interrupts in the returned mask. - * So the caller *must* process all interrupts that have - * a corresponding bit set if the value returned by this function - * (otherwise those interrupts may likely be lost). - * - * This function should be called with level-one interrupts disabled - * (via INTENABLE; can't be via PS.INTLEVEL because this is C code). - */ -unsigned xthal_tram_pending_to_service( void ) -{ -#if XCHAL_HAVE_INTERRUPTS - unsigned service_mask; - - service_mask = ( Xthal_tram_pending - & (Xthal_vpri_enabled | Xthal_tram_enabled) ) ; - - /* - * Clear trampoline pending bits. - * Each bit must be cleared *before* processing of the corresponding - * interrupt occurs, to avoid missing interrupts. - * Here we just clear all bits for simplicity and convenience. - */ - Xthal_tram_pending &= ~service_mask; - - return( service_mask ); -#else /* XCHAL_HAVE_INTERRUPTS */ - return( 0 ); -#endif /* XCHAL_HAVE_INTERRUPTS */ -} - -/* - * xthal_tram_done - * - * This is called by the trampoline interrupt handler - * (eg. by a level-one software interrupt handler) - * to indicate that processing of a trampolined interrupt - * (eg. one or more of the bits it received from - * xthal_tram_acknowledge()) has completed. - * - * For asynchronously trampolined interrupt(s), there is nothing to do. - * For synchronously trampolined interrupt(s), the high-level - * interrupt(s) must be re-enabled (presumably the level-one - * interrupt handler that just completed has cleared the source - * of the high-level interrupt). - * - * This function should be called with level-one interrupts disabled - * (via INTENABLE; can't be via PS.INTLEVEL because this is C code). - */ -void xthal_tram_done( unsigned serviced_mask ) -{ -#if XCHAL_HAVE_INTERRUPTS - serviced_mask &= Xthal_tram_enabled; /* sync. trampolined interrupts that completed */ - Xthal_tram_enabled &= ~serviced_mask; - xthal_int_enable( serviced_mask ); -#endif -} - -#endif - -#if defined(__SPLIT__deprecated) - - -/**********************************************************************/ - -#ifdef INCLUDE_DEPRECATED_HAL_CODE -/* These definitions were present in an early beta version of the HAL and should not be used: */ -const unsigned Xthal_num_int_levels = XCHAL_NUM_INTLEVELS; -const unsigned Xthal_num_ints = XCHAL_NUM_INTERRUPTS; -__asm__(".global Xthal_int_level_mask\n" ".set Xthal_int_level_mask, Xthal_intlevel_mask+4"); -__asm__(".global Xthal_int_level1_to_n_mask\n" ".set Xthal_int_level1_to_n_mask, Xthal_intlevel_andbelow_mask+8"); -/*const unsigned Xthal_int_level_mask[15] = { XCHAL_INTLEVEL_MASKS }; ... minus the first entry ...*/ -/*const unsigned Xthal_int_level1_to_n_mask[14] = { XCHAL_INTLEVEL_ANDBELOW_MASKS }; ... minus the first two entries ...*/ -const unsigned Xthal_int_level[32] = { XCHAL_INT_LEVELS }; -const unsigned Xthal_int_type_edge = XCHAL_INTTYPE_MASK_EXTERN_EDGE; -const unsigned Xthal_int_type_level = XCHAL_INTTYPE_MASK_EXTERN_LEVEL; -const unsigned Xthal_int_type_timer = XCHAL_INTTYPE_MASK_TIMER; -const unsigned Xthal_int_type_software = XCHAL_INTTYPE_MASK_SOFTWARE; -#endif /* INCLUDE_DEPRECATED_HAL_CODE */ - - -#endif /* SPLITs */ - diff --git a/src/arch/xtensa/hal/mem_ecc_parity.S b/src/arch/xtensa/hal/mem_ecc_parity.S deleted file mode 100644 index 2a85a3ecb37b..000000000000 --- a/src/arch/xtensa/hal/mem_ecc_parity.S +++ /dev/null @@ -1,285 +0,0 @@ -// -// mem_ecc_parity.S - utility routines for the local memory ECC/parity option -// (memory error checking and exceptions) -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/mem_ecc_parity.S#1 $ - -// Copyright (c) 2006-2010 Tensilica 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. - -#include <xtensa/coreasm.h> - - -/* - * For most functions, the link-time HAL defines two entry points: - * xthal_...() and xthal_..._nw(). The former is the main entry point - * invoked from C code, or assembly code that follows the C ABI. - * The latter is for use in assembly code that cannot easily follow - * all the requirements of the windowed ABI, e.g. in exception handlers; - * these use the call0 ABI instead (in most cases; some use their own conventions). - * - * When software tools are configured to use the call0 ABI, both variants - * are identical (with some exceptions as noted). To avoid duplicating - * code, we define both labels for the same function body. The Makefile - * defines __SPLIT__..._nw macros with windowed ABI but not with Call0 ABI. - * Use SYM_NW() for the _nw variants defined with the __SPLIT_..._nw macros, - * i.e. for call0 ABI variants when windowed ABI is in use; these are not - * C callable so SYM_NW() does not specify .type information. - * Use SYMBOL() otherwise, which defines both symbols if call0 ABI is selected. - */ - -#if defined (__XTENSA_CALL0_ABI__) -# define SYMBOL(x) .global x ; .type x,@function ; \ - .global x ## _nw ; .type x ## _nw,@function ; \ - .align 4 ; x: ; x ## _nw: -#else -# define SYMBOL(x) .global x ; .type x,@function ; .align 4 ; x: -#endif -#define SYM_NW(x) .global x ; .align 4 ; x: - - -/* Compute smaller of I and D cache line sizes: */ -#if XCHAL_ICACHE_LINEWIDTH < XCHAL_DCACHE_LINEWIDTH && XCHAL_ICACHE_SIZE > 0 -# define CACHE_LINEWIDTH_MIN XCHAL_ICACHE_LINEWIDTH -# define CACHE_LINESIZE_MIN XCHAL_ICACHE_LINESIZE -#else -# define CACHE_LINEWIDTH_MIN XCHAL_DCACHE_LINEWIDTH -# define CACHE_LINESIZE_MIN XCHAL_DCACHE_LINESIZE -#endif - - - .text - -//------------------------------------------------------------------------ -// Inject errors into instruction and/or data RAMs, or cache data or tags -//------------------------------------------------------------------------ - -#if defined(__SPLIT__memep_inject_error) - -// void xthal_memep_inject_error(void *addr, int size, int flags); -// where: -// addr (a2) pointer to local memory, or cache address -// size (a3) size in bytes (gets aligned to words or lines) -// flags (a4) is a combination of the following bits: -// bit 31-5: (reserved) -// bit 4: 0 = inject non-correctable error, -// 16 = inject correctable error (if ECC) -// bit 3: (reserved) -// bit 2: 0 = local memory, 4 = cache -// bit 1: 0 = data cache, 2 = instruction cache -// bit 0: 0 = cache data, 1 = cache tag -// -// (note: data cache data is handled same as local memories; -// to access specific dcache data entries, you have to setup -// a region or page in cache-isolate mode yourself) - -SYMBOL(xthal_memep_inject_error) - abi_entry - -#if XCHAL_HAVE_MEM_ECC_PARITY - - // These MOVIs may be L32Rs, load them before enabling test mode: - movi a6, 0x02020202 // XOR'ing this creates a correctable error - bbsi.l a4, 4, 1f // branch if correctable error requested - movi a6, 0x03030303 // XOR'ing this creates a non-correctable error -1: - - // Lock out all interrupts, to avoid interrupt handlers running with - // test mode enabled (corrupting their stores, likely leading to - // non-correctable memory errors). - // - // If NMI is possible, you're toast - // (no stores during NMI handler will have properly computed ECC/parity bits) - // although you might make the NMI handler check MESR.ERRTEST and save/clear - // it if it's set on entry, so that its stores work correctly. - // - // If memory exceptions are possible, might be okay as long as the - // handler checks whether test mode is on, and turns it off temporarily - // to do its work. - // -# if XCHAL_HAVE_INTERRUPTS - rsil a11, 15 -# endif - - // Save current MESR and set test mode: - - rsr.mesr a8 - bbsi.l a8, MESR_ERRTEST_SHIFT, .Lproceed // already in test mode? - addmi a9, a8, MESR_ERRTEST // enable test mode - bbci.l a8, MESR_ERRENAB_SHIFT, 1f - addmi a9, a9, - MESR_ERRENAB // disable error checks -1: xsr.mesr a9 - beq a8, a9, .Lproceed // clean update, continue - bbci.l a9, MESR_RCE_SHIFT, .Lproceed // we likely restored a lost RCE, just keep it - // At this point, either we: - // a) cleared an RCE record that got created between RSR and XSR - // b) cleared LCE bits that got set between RSR and XSR - // c) more eclectic, and presumably much less likely, cases of - // RCE/LCE bits being cleared and set again between RSR and XSR - // due to multiple memory errors and memory error exceptions - // in that period; for now, we ignore this possibility - // (decreasing returns on addressing these arbitrarily complex cases) - // Assuming (a) or (b), restore the bits we took away. - //addmi a8, a8, MESR_ERRTEST - addmi a9, a9, MESR_ERRTEST - bbci.l a9, MESR_ERRENAB_SHIFT, 1f - addmi a9, a9, - MESR_ERRENAB // disable error checks -1: wsr.mesr a9 - //xsr.mesr a9 - //beq a8, a9, .Lproceed // updated fine, continue - // - // Above we could have used XSR instead of WSR. - // However, it's not clear at this point what's the cleanest thing - // to do if what we read back doesn't match what we expected, - // because at that point we have multiple errors to deal with. - // Unless we have code here to handle (fix and/or log) these errors, - // we have to chuck something away or write a bunch more code to - // handle another LCE bit getting set etc (also starting to be - // a low probability occurrence). -.Lproceed: - // Test mode enabled. From this point until we restore MESR, - // the only loads and stores done are for injecting errors. - -# if XCHAL_ICACHE_SIZE || XCHAL_DCACHE_SIZE - bbci.l a4, 2, .L_inject_local // branch if injecting to local memory - bbsi.l a4, 1, .L_inject_icache // branch if injecting to icache - // Inject errors in dcache: - bbci.l a4, 0, .L_inject_local // branch if injecting to dcache data -# if XCHAL_DCACHE_SIZE && XCHAL_HAVE_DCACHE_TEST - // Inject errors in dcache tags: - - // Round addr/size to fully rather than partially cover - // all aligned cache lines: - extui a9, a2, 0, XCHAL_DCACHE_LINEWIDTH - sub a2, a2, a9 - add a3, a3, a9 - addi a3, a3, XCHAL_DCACHE_LINESIZE-1 - srli a3, a3, XCHAL_DCACHE_LINEWIDTH // size in cache lines - - floopgtz a3, .Ldctagloop - ldct a9, a2 // load dcache line tag - rsr.mecr a7 // get check bits - xor a7, a7, a6 // ECC: single-bit error; Parity: NO-OP - wsr.mecr a7 // setup modified check bits - sdct a9, a2 // store tag with modified check bits - addi a2, a2, XCHAL_DCACHE_LINESIZE // increment to next line - floopend a3, .Ldctagloop -# endif /* have dcache */ - j .L_inject_done - - // Inject errors in icache: -.L_inject_icache: -# if XCHAL_ICACHE_SIZE && XCHAL_HAVE_ICACHE_TEST - bbci.l a4, 0, .L_inject_icw // branch if injecting to icache data - - // Inject errors in icache tags: - // Round addr/size to fully rather than partially cover - // all aligned cache lines: - extui a9, a2, 0, XCHAL_ICACHE_LINEWIDTH - sub a2, a2, a9 - add a3, a3, a9 - addi a3, a3, XCHAL_ICACHE_LINESIZE-1 - srli a3, a3, XCHAL_ICACHE_LINEWIDTH // size in cache lines - - floopgtz a3, .Lictagloop - lict a9, a2 // load icache line tag - rsr.mecr a7 // get check bits - xor a7, a7, a6 // ECC: single-bit error; Parity: NO-OP - wsr.mecr a7 // setup modified check bits - sict a9, a2 // store tag with modified check bits - addi a2, a2, XCHAL_ICACHE_LINESIZE // increment to next line - floopend a3, .Lictagloop - j .L_inject_done - -.L_inject_icw: -# if XCHAL_ICACHE_ACCESS_SIZE <= 4 /* SICW does not work usefully (replicates data) if accessWidth > 32 bits */ - // Inject errors in icache data words: - // Round addr/size to fully rather than partially cover - // all aligned 32-bit words: - extui a9, a2, 0, 2 - sub a2, a2, a9 - add a3, a3, a9 - addi a3, a3, 3 - srli a3, a3, 2 // size in words - - floopgtz a3, .Licwloop - licw a9, a2 // load word of icache line data - rsr.mecr a7 // get check bits - xor a7, a7, a6 // ECC: single-bit error; Parity: NO-OP - wsr.mecr a7 // setup modified check bits - sicw a9, a2 // store data with modified check bits - addi a2, a2, 4 // increment to next word - floopend a3, .Licwloop -# endif -# endif /* have icache */ - j .L_inject_done -# endif /* have icache or dcache */ - -.L_inject_local: - // Round addr/size to fully rather than partially cover - // all aligned 32-bit words: - extui a9, a2, 0, 2 - sub a2, a2, a9 - add a3, a3, a9 - addi a3, a3, 3 - srli a3, a3, 2 // size in words - - floopgtz a3, .Lendloop - l32i a9, a2, 0 // load data - rsr.mecr a7 // get check bits - xor a7, a7, a6 // ECC: single-bit error; Parity: NO-OP - wsr.mecr a7 // setup modified check bits - s32i a9, a2, 0 // store data with modified check bits - addi a2, a2, 4 // increment to next word - floopend a3, .Lendloop - -.L_inject_done: - // Restore MESR (a8 is the saved original MESR): - bbsi.l a8, MESR_ERRTEST_SHIFT, 2f // was already in test mode - rsr.mesr a6 - addmi a9, a6, - MESR_ERRTEST // disable test mode - bbci.l a8, MESR_ERRENAB_SHIFT, 1f - addmi a9, a9, MESR_ERRENAB // enable error checks -1: xsr.mesr a9 - beq a6, a9, 2f // clean update, done - bbci.l a9, MESR_RCE_SHIFT, 2f // we likely restored a lost RCE, just keep it - addmi a9, a9, - MESR_ERRTEST - bbci.l a8, MESR_ERRENAB_SHIFT, 1f - addmi a9, a9, MESR_ERRENAB // disable error checks -1: wsr.mesr a9 -2: - - // Restore PS.INTLEVEL: -# if XCHAL_HAVE_INTERRUPTS - wsr.ps a11 - rsync -# endif -#endif /* XCHAL_HAVE_MEM_ECC_PARITY */ - - abi_return - - .size xthal_memep_inject_error, . - xthal_memep_inject_error - - -#endif /*split*/ - -//---------------------------------------------------------------------- - diff --git a/src/arch/xtensa/hal/memcopy.S b/src/arch/xtensa/hal/memcopy.S deleted file mode 100644 index 5cabcf166d9b..000000000000 --- a/src/arch/xtensa/hal/memcopy.S +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Core HAL library functions xthal_memcpy and xthal_bcopy - */ - -/* - * Copyright (c) 2003, 2006, 2010 Tensilica 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. - */ - -#include <xtensa/coreasm.h> - - -#ifdef __XTENSA_EB__ -# define BL(b,l) b -#else -# define BL(b,l) l -#endif - - .macro srcel r, early, late // combine early and late words, shift into \r - src \r, BL(\early,\late), BL(\late,\early) - .endm - - .macro ssa8f r // set shift-amount for shift *from* given 2-bit alignment - BL(ssa8b,ssa8l) \r - .endm - - .macro ssa8t r // set shift-amount for shift *to* given 2-bit alignment - BL(ssa8l,ssa8b) \r // (reverse of ssa8f) - .endm - - .macro s2ll r, s // shift-to-later logical (away from zero-addressed byte) - BL(srl,sll) \r, \s - .endm - - .macro s2el r, s // shift-to-early logical (towards zero-addressed byte) - BL(sll,srl) \r, \s - .endm - -/* - * void *xthal_memcpy(void *dst, const void *src, size_t len); - * void *xthal_bcopy(const void *src, void *dst, size_t len); - * - * This function is intended to do the same thing as the standard - * library function memcpy() (or bcopy()) for most cases. - * However, it uses strictly 32-bit load and store instructions - * to copy data. This ensures this function will work - * where the source and/or destination references an - * instruction RAM or ROM, which can only be accessed - * using l32i (IRAM+IROM) and s32i (IRAM). - * - * The bcopy version is provided here to avoid the overhead - * of an extra call, for callers that require this convention. - * - * The (general case) algorithm is as follows: - * If destination is unaligned, align it by copying 1 to 3 bytes. - * If source is aligned, - * do 16 bytes with a loop, and then finish up with - * 8, 4, and 0-3 byte copies conditional on the length; - * else (if source is unaligned), - * do the same, but use SRC to align the source data. - * This code tries to use fall-through branches for the common - * case of aligned source and destination and multiple - * of 4 length. - * - * Register use: - * a0/ return address - * a1/ stack pointer - * a2/ return value - * a3/ src - * a4/ length - * a5/ dst - * a6/ tmp - * a7/ tmp - * a8/ tmp - * a9/ tmp - * a10/ tmp - * a11/ tmp - * a12/ tmp - */ - -/* xthal_bcopy and xthal_memcpy need to allocate the same stack size - * on entry since they share the same function-return code. Also, - * there is more than one return point. */ - -#define SAVE_A0 0 -#define SAVE_A3 4 -#define SAVE_A4 8 -#define SAVE_A5 12 -#define SAVE_A12 16 -#define STKSIZE 32 - - - .text - .align 4 - .global xthal_bcopy - .type xthal_bcopy,@function -xthal_bcopy: -#ifdef __XTENSA_CALL0_ABI__ - addi sp, sp, -STKSIZE - s32i a12, a1, SAVE_A12 -#else - entry sp, 32 // allow for call8 below -#endif - // a2=src, a3=dst, a4=len - mov a5, a3 // copy dst so that a2 is return value - mov a3, a2 - mov a2, a5 - j .Lcommon // go to common code for memcpy+bcopy - - .size xthal_bcopy, . - xthal_bcopy - - - -/* - * Destination is unaligned - */ - - .align 4 -xthal_memcpy.prefixcode: // purely for purpose of .size -.Ldstunaligned: - mov a10, a5 - mov a11, a3 - movi a12, 4 - sub a6, a12, a6 // number of bytes to copy for dst alignment - mov a12, a6 -#ifdef __XTENSA_CALL0_ABI__ - s32i a0, a1, SAVE_A0 // preserve live registers - s32i a3, a1, SAVE_A3 - s32i a4, a1, SAVE_A4 - s32i a5, a1, SAVE_A5 - call0 xthal_copy123 - l32i a0, a1, SAVE_A0 // restore live registers - l32i a3, a1, SAVE_A3 - l32i a4, a1, SAVE_A4 - l32i a5, a1, SAVE_A5 - mov a6, a12 // restore a6 from callee-saved register -#else - call8 xthal_copy123 -#endif - add a5, a5, a6 - add a3, a3, a6 - sub a4, a4, a6 - j .Ldstaligned - - // Not sure how else to count code that precedes a function, in .size: - .size xthal_memcpy.prefixcode, . - xthal_memcpy.prefixcode - - - .align 4 - .global xthal_memcpy - .type xthal_memcpy,@function -xthal_memcpy: -#ifdef __XTENSA_CALL0_ABI__ - addi sp, sp, -STKSIZE - s32i a12, a1, SAVE_A12 -#else - entry sp, 32 // allow for call8 below -#endif - // a2=dst, a3=src, a4=len - mov a5, a2 // copy dst so that a2 is return value -.Lcommon: -#ifdef __XTENSA_CALL0_ABI__ - /* - * have to restore the stack - */ - _bgeui a4, 4, 1f - mov a12, a0 // preserve return address - call0 xthal_copy123 - mov a0, a12 // restore return address - l32i a12, a1, SAVE_A12 - addi sp, sp, STKSIZE - ret -1: -#else - bltui a4, 4, xthal_copy123_pastentry // NOTE: sometimes relaxes -#endif - - extui a6, a2, 0, 2 // destination unalignment offset - bnez a6, .Ldstunaligned // align the destination -.Ldstaligned: // return here once dst is aligned - srli a7, a4, 4 // number of loop iterations of 16-bytes each - extui a11, a3, 0, 2 // source unalignment offset - _bnez a11, .Lsrcunaligned // if source not aligned, use shifting copy - /* - * Destination and source are 32-bit aligned, use 32-bit copy. - */ -#if XCHAL_HAVE_LOOPS - loopnez a7, .Loop1done -#else /* !XCHAL_HAVE_LOOPS */ - beqz a7, .Loop1done - slli a8, a7, 4 - add a8, a8, a3 // a8 = end of last 16B source chunk -#endif /* !XCHAL_HAVE_LOOPS */ -.Loop1: - l32i a6, a3, 0 - l32i a7, a3, 4 - s32i a6, a5, 0 - l32i a6, a3, 8 - s32i a7, a5, 4 - l32i a7, a3, 12 - s32i a6, a5, 8 - addi a3, a3, 16 - s32i a7, a5, 12 - addi a5, a5, 16 -#if !XCHAL_HAVE_LOOPS - blt a3, a8, .Loop1 -#endif /* !XCHAL_HAVE_LOOPS */ -.Loop1done: - bbci.l a4, 3, .L2 - // copy 8 bytes - l32i a6, a3, 0 - l32i a7, a3, 4 - addi a3, a3, 8 - s32i a6, a5, 0 - s32i a7, a5, 4 - addi a5, a5, 8 -.L2: - bbci.l a4, 2, .L3 - // copy 4 bytes - l32i a6, a3, 0 - addi a3, a3, 4 - s32i a6, a5, 0 - addi a5, a5, 4 -.L3: - // Copy last 0 to 3 bytes using 32-bit accesses (aligned source and destination): - extui a4, a4, 0, 2 // any bytes to copy? - beqz a4, 1f // if not, skip this to avoid extraneous loads/stores - l32i a6, a3, 0 // get source word - l32i a7, a5, 0 // get destination word - ssa8f a4 // shift from length (end of source) - s2ll a6, a6 // align source to last byte - s2el a7, a7 // align parts of a7 following modified bytes, to early byte - ssa8t a4 // shift to end of modified destination (length) - srcel a7, a6, a7 // combine source with late-dst to form last word - s32i a7, a5, 0 // update last word -1: - -#ifdef __XTENSA_CALL0_ABI__ - l32i a12, a1, SAVE_A12 - addi sp, sp, STKSIZE - ret -#else - retw -#endif - - .size xthal_memcpy, . - xthal_memcpy - - - // void xthal_copy123(dst, src, len); - // - // Copy from 0 to 3 bytes, using only 32-bit loads and stores, - // with arbitrarily aligned source and destination. - // - // arg1 = a2 = dst - // arg2 = a3 = src - // arg3 = a4 = len - - .global xthal_copy123 - .type xthal_copy123,@function - .align 4 -xthal_copy123: - abi_entry - -xthal_copy123_pastentry: - _beqz a4, cdone // don't load or store if zero bytes - // First get the bytes: - movi a5, ~3 - and a5, a3, a5 // align src address - l32i a6, a5, 0 - l32i a7, a5, 4 - ssa8f a3 - srcel a3, a6, a7 - // a3 now contains source bytes, aligned to 1st byte (memory order) - // (source address is no longer needed at this point) - - // Does destination span two words?: - extui a10, a2, 0, 2 // destination alignment - sub a5, a2, a10 // align destination address - l32i a8, a5, 0 // get first destination word regardless - add a6, a10, a4 // dst_align + len - ssa8f a2 // shift from dst_align (to 1st or last byte) - s2ll a10, a8 // a10 = first part of destination, aligned to last byte - bltui a6, 4, oneword // branch if destination contained in single word - - // Two-word destination case: - l32i a8, a5, 4 // get second word - ssa8t a2 // shift to dst_align - srcel a10, a10, a3 // with a10 in early bytes, a3 in later bytes - s32i a10, a5, 0 // update first word - addi a5, a5, 4 // advance to last word for common code below - //movi a10, 0 // not needed, gets dropped - -oneword: - // One-word (and two-word) destination case: - // a8 = contents of last destination word - // a10 = early part of a8 preceding modified bytes, shifted towards last byte - // - ssa8f a4 // shift from length (end of source) - srcel a3, a10, a3 // combine early-destination with source, aligned to last byte - - ssa8f a6 // shift from end of modified destination (dst_align+len) - s2el a8, a8 // align parts of a8 following modified bytes, to early byte - ssa8t a6 // shift to end of modified destination (dst_align+len) - srcel a8, a3, a8 // combine early-dst+source with late-dst to form last word - s32i a8, a5, 0 // update last word -cdone: abi_return // return dst - -/* - * Destination is aligned, Source is unaligned - */ - - .align 4 -.Lsrcunaligned: - // Copy 16 bytes per iteration for word-aligned dst and unaligned src - ssa8f a3 // set shift amount from byte offset -#define SIM_CHECKS_ALIGNMENT 1 /* set to 1 when running on ISS (simulator) with the - lint or ferret client, or 0 to save a few cycles */ -#if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT - extui a11, a3, 0, 2 // save unalignment offset for below - sub a3, a3, a11 // align a3 -#endif - l32i a6, a3, 0 // load first word -#if XCHAL_HAVE_LOOPS - loopnez a7, .Loop2done -#else /* !XCHAL_HAVE_LOOPS */ - beqz a7, .Loop2done - slli a10, a7, 4 - add a10, a10, a3 // a10 = end of last 16B source chunk -#endif /* !XCHAL_HAVE_LOOPS */ -.Loop2: - l32i a7, a3, 4 - l32i a8, a3, 8 - srcel a6, a6, a7 - s32i a6, a5, 0 - l32i a9, a3, 12 - srcel a7, a7, a8 - s32i a7, a5, 4 - l32i a6, a3, 16 - srcel a8, a8, a9 - s32i a8, a5, 8 - addi a3, a3, 16 - srcel a9, a9, a6 - s32i a9, a5, 12 - addi a5, a5, 16 -#if !XCHAL_HAVE_LOOPS - blt a3, a10, .Loop2 -#endif /* !XCHAL_HAVE_LOOPS */ -.Loop2done: - bbci.l a4, 3, .L12 - // copy 8 bytes - l32i a7, a3, 4 - l32i a8, a3, 8 - srcel a6, a6, a7 - s32i a6, a5, 0 - addi a3, a3, 8 - srcel a7, a7, a8 - s32i a7, a5, 4 - addi a5, a5, 8 - mov a6, a8 -.L12: - bbci.l a4, 2, .L13 - // copy 4 bytes - l32i a7, a3, 4 - addi a3, a3, 4 - srcel a6, a6, a7 - s32i a6, a5, 0 - addi a5, a5, 4 - mov a6, a7 -.L13: - // Copy last 0 to 3 bytes using 32-bit accesses (shifting source, aligned destination): - //_beqz a4[1:0], cdone // don't load or store if zero bytes - l32i a7, a3, 4 // get source word - l32i a3, a5, 0 // get destination word - srcel a6, a6, a7 // source bytes, aligned to early (1st) byte - ssa8f a4 // shift from length (end of source) - s2ll a6, a6 // combine early-destination with source, aligned to last byte - s2el a3, a3 // align parts of a3 following modified bytes, to early byte - ssa8t a4 // shift to end of modified destination (length) - srcel a3, a6, a3 // combine early-dst+source with late-dst to form last word - s32i a3, a5, 0 // update last word -.Ldone: -#ifdef __XTENSA_CALL0_ABI__ - l32i a12, a1, SAVE_A12 - addi sp, sp, STKSIZE - ret -#else - retw -#endif - - .size xthal_copy123, . - xthal_copy123 - diff --git a/src/arch/xtensa/hal/misc.c b/src/arch/xtensa/hal/misc.c deleted file mode 100644 index 7742851e291f..000000000000 --- a/src/arch/xtensa/hal/misc.c +++ /dev/null @@ -1,178 +0,0 @@ -// -// misc.c - miscellaneous constants -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/misc.c#1 $ - -// Copyright (c) 2004-2005 Tensilica 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. - -#include <xtensa/config/core.h> - - -// Software release info (not configuration-specific!): -const unsigned int Xthal_release_major = XTHAL_RELEASE_MAJOR; -const unsigned int Xthal_release_minor = XTHAL_RELEASE_MINOR; -const char * const Xthal_release_name = XTHAL_RELEASE_NAME; -#ifdef XTHAL_RELEASE_INTERNAL -const char * const Xthal_release_internal = XTHAL_RELEASE_INTERNAL; -#else -const char * const Xthal_release_internal = 0; -#endif -/* Old format, for backward compatibility: */ -const unsigned int Xthal_rev_no = (XTHAL_MAJOR_REV<<16)|XTHAL_MINOR_REV; - -// number of registers in register window, or number of registers if not windowed -const unsigned int Xthal_num_aregs = XCHAL_NUM_AREGS; -const unsigned char Xthal_num_aregs_log2 = XCHAL_NUM_AREGS_LOG2; - -const unsigned char Xthal_memory_order = XCHAL_MEMORY_ORDER; -const unsigned char Xthal_have_windowed = XCHAL_HAVE_WINDOWED; -const unsigned char Xthal_have_density = XCHAL_HAVE_DENSITY; -const unsigned char Xthal_have_booleans = XCHAL_HAVE_BOOLEANS; -const unsigned char Xthal_have_loops = XCHAL_HAVE_LOOPS; -const unsigned char Xthal_have_nsa = XCHAL_HAVE_NSA; -const unsigned char Xthal_have_minmax = XCHAL_HAVE_MINMAX; -const unsigned char Xthal_have_sext = XCHAL_HAVE_SEXT; -const unsigned char Xthal_have_clamps = XCHAL_HAVE_CLAMPS; -const unsigned char Xthal_have_mac16 = XCHAL_HAVE_MAC16; -const unsigned char Xthal_have_mul16 = XCHAL_HAVE_MUL16; -const unsigned char Xthal_have_fp = XCHAL_HAVE_FP; -const unsigned char Xthal_have_speculation = XCHAL_HAVE_SPECULATION; -const unsigned char Xthal_have_exceptions = XCHAL_HAVE_EXCEPTIONS; -const unsigned char Xthal_xea_version = XCHAL_XEA_VERSION; -const unsigned char Xthal_have_interrupts = XCHAL_HAVE_INTERRUPTS; -const unsigned char Xthal_have_highlevel_interrupts = XCHAL_HAVE_HIGHLEVEL_INTERRUPTS; -const unsigned char Xthal_have_nmi = XCHAL_HAVE_NMI; -const unsigned char Xthal_have_prid = XCHAL_HAVE_PRID; -const unsigned char Xthal_have_release_sync = XCHAL_HAVE_RELEASE_SYNC; -const unsigned char Xthal_have_s32c1i = XCHAL_HAVE_S32C1I; -const unsigned char Xthal_have_threadptr = XCHAL_HAVE_THREADPTR; - -const unsigned char Xthal_have_pif = XCHAL_HAVE_PIF; -const unsigned short Xthal_num_writebuffer_entries = XCHAL_NUM_WRITEBUFFER_ENTRIES; - -const unsigned int Xthal_build_unique_id = XCHAL_BUILD_UNIQUE_ID; -// Release info for hardware targeted by software upgrades: -const unsigned int Xthal_hw_configid0 = XCHAL_HW_CONFIGID0; -const unsigned int Xthal_hw_configid1 = XCHAL_HW_CONFIGID1; -const unsigned int Xthal_hw_release_major = XCHAL_HW_VERSION_MAJOR; -const unsigned int Xthal_hw_release_minor = XCHAL_HW_VERSION_MINOR; -const char * const Xthal_hw_release_name = XCHAL_HW_VERSION_NAME; -const unsigned int Xthal_hw_min_version_major = XCHAL_HW_MIN_VERSION_MAJOR; -const unsigned int Xthal_hw_min_version_minor = XCHAL_HW_MIN_VERSION_MINOR; -const unsigned int Xthal_hw_max_version_major = XCHAL_HW_MAX_VERSION_MAJOR; -const unsigned int Xthal_hw_max_version_minor = XCHAL_HW_MAX_VERSION_MINOR; -#ifdef XCHAL_HW_RELEASE_INTERNAL -const char * const Xthal_hw_release_internal = XCHAL_HW_RELEASE_INTERNAL; -#else -const char * const Xthal_hw_release_internal = 0; -#endif - -/* MMU related info... */ - -const unsigned char Xthal_have_spanning_way = XCHAL_HAVE_SPANNING_WAY; -const unsigned char Xthal_have_identity_map = XCHAL_HAVE_IDENTITY_MAP; -const unsigned char Xthal_have_mimic_cacheattr = XCHAL_HAVE_MIMIC_CACHEATTR; -const unsigned char Xthal_have_xlt_cacheattr = XCHAL_HAVE_XLT_CACHEATTR; -const unsigned char Xthal_have_cacheattr = XCHAL_HAVE_CACHEATTR; -const unsigned char Xthal_have_tlbs = XCHAL_HAVE_TLBS; -#if XCHAL_HAVE_MPU -const unsigned char Xthal_mmu_asid_bits = 0; -const unsigned char Xthal_mmu_asid_kernel = 0; -const unsigned char Xthal_mmu_rings = 0; -const unsigned char Xthal_mmu_ring_bits = 0; -const unsigned char Xthal_mmu_sr_bits = 0; -const unsigned char Xthal_mmu_ca_bits = 0; -#else -const unsigned char Xthal_mmu_asid_bits = XCHAL_MMU_ASID_BITS; -const unsigned char Xthal_mmu_asid_kernel = XCHAL_MMU_ASID_KERNEL; -const unsigned char Xthal_mmu_rings = XCHAL_MMU_RINGS; -const unsigned char Xthal_mmu_ring_bits = XCHAL_MMU_RING_BITS; -const unsigned char Xthal_mmu_sr_bits = XCHAL_MMU_SR_BITS; -const unsigned char Xthal_mmu_ca_bits = XCHAL_MMU_CA_BITS; -#endif -#if XCHAL_HAVE_TLBS -const unsigned int Xthal_mmu_max_pte_page_size = XCHAL_MMU_MAX_PTE_PAGE_SIZE; -const unsigned int Xthal_mmu_min_pte_page_size = XCHAL_MMU_MIN_PTE_PAGE_SIZE; -const unsigned char Xthal_itlb_way_bits = XCHAL_ITLB_WAY_BITS; -const unsigned char Xthal_itlb_ways = XCHAL_ITLB_WAYS; -const unsigned char Xthal_itlb_arf_ways = XCHAL_ITLB_ARF_WAYS; -const unsigned char Xthal_dtlb_way_bits = XCHAL_DTLB_WAY_BITS; -const unsigned char Xthal_dtlb_ways = XCHAL_DTLB_WAYS; -const unsigned char Xthal_dtlb_arf_ways = XCHAL_DTLB_ARF_WAYS; -#else -const unsigned int Xthal_mmu_max_pte_page_size = 0; -const unsigned int Xthal_mmu_min_pte_page_size = 0; -const unsigned char Xthal_itlb_way_bits = 0; -const unsigned char Xthal_itlb_ways = 0; -const unsigned char Xthal_itlb_arf_ways = 0; -const unsigned char Xthal_dtlb_way_bits = 0; -const unsigned char Xthal_dtlb_ways = 0; -const unsigned char Xthal_dtlb_arf_ways = 0; -#endif - - -/* Internal memories... */ - -const unsigned char Xthal_num_instrom = XCHAL_NUM_INSTROM; -const unsigned char Xthal_num_instram = XCHAL_NUM_INSTRAM; -const unsigned char Xthal_num_datarom = XCHAL_NUM_DATAROM; -const unsigned char Xthal_num_dataram = XCHAL_NUM_DATARAM; -const unsigned char Xthal_num_xlmi = XCHAL_NUM_XLMI; - -/* Define arrays of internal memories' addresses and sizes: */ -#define MEMTRIPLET(n,mem,memcap) _MEMTRIPLET(n,mem,memcap) -#define _MEMTRIPLET(n,mem,memcap) MEMTRIPLET##n(mem,memcap) -#define MEMTRIPLET0(mem,memcap) \ - const unsigned int Xthal_##mem##_vaddr[1] = { 0 }; \ - const unsigned int Xthal_##mem##_paddr[1] = { 0 }; \ - const unsigned int Xthal_##mem##_size [1] = { 0 }; -#define MEMTRIPLET1(mem,memcap) \ - const unsigned int Xthal_##mem##_vaddr[1] = { XCHAL_##memcap##0_VADDR }; \ - const unsigned int Xthal_##mem##_paddr[1] = { XCHAL_##memcap##0_PADDR }; \ - const unsigned int Xthal_##mem##_size [1] = { XCHAL_##memcap##0_SIZE }; -#define MEMTRIPLET2(mem,memcap) \ - const unsigned int Xthal_##mem##_vaddr[2] = { XCHAL_##memcap##0_VADDR, XCHAL_##memcap##1_VADDR }; \ - const unsigned int Xthal_##mem##_paddr[2] = { XCHAL_##memcap##0_PADDR, XCHAL_##memcap##1_PADDR }; \ - const unsigned int Xthal_##mem##_size [2] = { XCHAL_##memcap##0_SIZE, XCHAL_##memcap##1_SIZE }; -MEMTRIPLET(XCHAL_NUM_INSTROM, instrom, INSTROM) -MEMTRIPLET(XCHAL_NUM_INSTRAM, instram, INSTRAM) -MEMTRIPLET(XCHAL_NUM_DATAROM, datarom, DATAROM) -MEMTRIPLET(XCHAL_NUM_DATARAM, dataram, DATARAM) -MEMTRIPLET(XCHAL_NUM_XLMI, xlmi, XLMI) - -/* Timer info... */ - -const unsigned char Xthal_have_ccount = XCHAL_HAVE_CCOUNT; -const unsigned char Xthal_num_ccompare = XCHAL_NUM_TIMERS; - -#ifdef INCLUDE_DEPRECATED_HAL_CODE -const unsigned char Xthal_have_old_exc_arch = XCHAL_HAVE_XEA1; -const unsigned char Xthal_have_mmu = XCHAL_HAVE_TLBS; -const unsigned int Xthal_num_regs = XCHAL_NUM_AREGS; /*DEPRECATED*/ -const unsigned char Xthal_num_irom = XCHAL_NUM_INSTROM; /*DEPRECATED*/ -const unsigned char Xthal_num_iram = XCHAL_NUM_INSTRAM; /*DEPRECATED*/ -const unsigned char Xthal_num_drom = XCHAL_NUM_DATAROM; /*DEPRECATED*/ -const unsigned char Xthal_num_dram = XCHAL_NUM_DATARAM; /*DEPRECATED*/ -const unsigned int Xthal_configid0 = XCHAL_HW_CONFIGID0; -const unsigned int Xthal_configid1 = XCHAL_HW_CONFIGID1; -#endif - diff --git a/src/arch/xtensa/hal/miscellaneous.S b/src/arch/xtensa/hal/miscellaneous.S deleted file mode 100644 index 1a3ebf49b001..000000000000 --- a/src/arch/xtensa/hal/miscellaneous.S +++ /dev/null @@ -1,56 +0,0 @@ -// -// miscellaneous.S - miscellaneous assembly language routines -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/miscellaneous.S#1 $ - -// Copyright (c) 2011 Tensilica 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. - -#include <xtensa/cacheasm.h> -#include <xtensa/cacheattrasm.h> -#include <xtensa/xtensa-versions.h> - - - .text - -//---------------------------------------------------------------------- -// Clear any remnant register state pointing to (or containing) code. -// Specifically, clear loop registers (LCOUNT) to avoid hardware loopback -// from LEND to LBEGIN when new code is loaded where code containing a -// zero-overhead loop was located. See the HAL chapter of the Tensilica -// System Software Reference Manual for details on the use of this function. -//---------------------------------------------------------------------- - -#if defined(__SPLIT__clear_regcached_code) || \ - defined(__SPLIT__clear_regcached_code_nw) - -DECLFUNC(xthal_clear_regcached_code) - abi_entry -# if XCHAL_HAVE_LOOPS - movi a2, 0 - wsr.lcount a2 -# endif - isync_retw_nop - abi_return - endfunc - -#endif - diff --git a/src/arch/xtensa/hal/mmu.c b/src/arch/xtensa/hal/mmu.c deleted file mode 100644 index ef4165206795..000000000000 --- a/src/arch/xtensa/hal/mmu.c +++ /dev/null @@ -1,93 +0,0 @@ -// -// mmu.c - MMU related functions -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/mmu.c#1 $ - -// Copyright (c) 2002, 2008 Tensilica 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. - -#include <xtensa/config/core.h> - -/* - * Convert a virtual address to a physical address - * (through static maps only). - * Returns 0 if successful (*paddrp is set), -1 if not (no mapping). - */ -int xthal_static_v2p( unsigned vaddr, unsigned *paddrp /*, unsigned len, unsigned rasid*/ ) -{ -#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY - if( vaddr >= XCHAL_KSEG_CACHED_VADDR - && vaddr <= XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_CACHED_SIZE ) - vaddr += XCHAL_KSEG_CACHED_PADDR - XCHAL_KSEG_CACHED_VADDR; - else if( vaddr >= XCHAL_KSEG_BYPASS_VADDR - && vaddr <= XCHAL_KSEG_BYPASS_VADDR + XCHAL_KSEG_BYPASS_SIZE ) - vaddr += XCHAL_KSEG_BYPASS_PADDR - XCHAL_KSEG_BYPASS_VADDR; - else if( vaddr >= XCHAL_KIO_CACHED_VADDR - && vaddr <= XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_SIZE ) - vaddr += XCHAL_KIO_CACHED_PADDR - XCHAL_KIO_CACHED_VADDR; - else if( vaddr >= XCHAL_KIO_BYPASS_VADDR - && vaddr <= XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_SIZE ) - vaddr += XCHAL_KIO_BYPASS_PADDR - XCHAL_KIO_BYPASS_VADDR; - else - return( -1 ); /* no known mapping */ -#endif /* XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY */ - *paddrp = vaddr; /* virtual == physical */ - return( 0 ); -} - -/* - * Convert a physical address to a virtual address - * (through static maps only). - * Returns 0 if successful (*vaddrp is set), -1 if not (no mapping). - * - * NOTE: A physical address can be mapped from multiple virtual addresses - * (or one or none). - * There should be better parameter(s) to help select the mapping returned - * (eg. cache mode, address, asid, etc), or somehow return them all. - * Mappings returned currently assume the current RASID setting. - */ -int xthal_static_p2v( unsigned paddr, unsigned *vaddrp, /*unsigned len, unsigned rasid,*/ unsigned cached ) -{ -#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY - if( cached ) { - if( paddr >= XCHAL_KSEG_CACHED_PADDR - && paddr <= XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_SIZE ) - paddr += XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_CACHED_PADDR; - else if( paddr >= XCHAL_KIO_BYPASS_PADDR - && paddr <= XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_SIZE ) - paddr += XCHAL_KIO_BYPASS_VADDR - XCHAL_KIO_BYPASS_PADDR; - else - return -1; /* no known mapping */ - } else { - if( paddr >= XCHAL_KSEG_BYPASS_PADDR - && paddr <= XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_SIZE ) - paddr += XCHAL_KSEG_BYPASS_VADDR - XCHAL_KSEG_BYPASS_PADDR; - else if( paddr >= XCHAL_KIO_CACHED_PADDR - && paddr <= XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_SIZE ) - paddr += XCHAL_KIO_CACHED_VADDR - XCHAL_KIO_CACHED_PADDR; - else - return -1; /* no known mapping */ - } -#endif /* XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY */ - *vaddrp = paddr; /* virtual == physical */ - return( 0 ); -} - diff --git a/src/arch/xtensa/hal/mp_asm.S b/src/arch/xtensa/hal/mp_asm.S deleted file mode 100644 index cc203436ad67..000000000000 --- a/src/arch/xtensa/hal/mp_asm.S +++ /dev/null @@ -1,123 +0,0 @@ -// -// mp_asm.S - multi-processor synchronization routines -// -// $Id$ - -// Copyright (c) 2003, 2005, 2010 Tensilica 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. - -#include <xtensa/coreasm.h> - - -/* - int xthal_compare_and_set( int *address, int test_value, int set_value ) - - Atomically sets *address to set_value if *address equals test_value. - Returns the previous value of *address (the one compared with test_value). - - Uses the S32C1I instruction if available. - S32C1I requires special support from the memory controller for - memory accessed via the PIF interface. For this and other reasons, - S32C1I might not work on the entire 4GB address range. This function - does not test address validity. That is the responsibility of the - software invoking this function. -*/ - .text - .align 4 - .global xthal_compare_and_set - .type xthal_compare_and_set,@function - -xthal_compare_and_set: - abi_entry - // a2 == address - // a3 == test value - // a4 == set value - -#if XCHAL_HAVE_EXCLUSIVE - mov a6, a4 // a6 = copy of set_value -1: - l32ex a5, a2 // a5 = *address, set monitor - bne a5, a3, 2f // skip write if *address != test_value - mov a4, a6 // a4 = set_value - s32ex a4, a2 // *address = set_value - getex a4 // get result of store - beqz a4, 1b -2: - mov a2, a5 // a2 = *address, return value - clrex // in case we skipped write -#elif XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION_MAJOR >= 2200 - mov a6, a4 // a6 = copy of set_value - movi a5, -1 - xor a5, a5, a3 // a5 = ~a3 - wsr.scompare1 a3 // set test_value -1: - mov a4, a6 // a4 = set_value - s32c1i a4, a2, 0 - bne a4, a5, 2f // if a4 != ~SCOMPARE1 then done - l32i a4, a2, 0 // a4 = *address - bne a4, a5, 1b // retry if *address != ~SCOMPARE1 -2: - mov a2, a4 -#else - mov a7, a2 // a7 == address, a2 is return val -# if XCHAL_HAVE_INTERRUPTS - rsil a5, 15 // a5 == new ps -# endif - l32i a2, a7, 0 // a2 == value to test, return val - bne a3, a2, done // test - - s32i a4, a7, 0 // write the new value - -done: -# if XCHAL_HAVE_INTERRUPTS - wsr.ps a5 // restore the PS - rsync -# endif -#endif - abi_return - - .size xthal_compare_and_set, . - xthal_compare_and_set - - -/* - unsigned xthal_get_prid( void ); - - Returns the value of the PRID register (processor ID), - or 0 if not configured. - (Note: this register, when present, cannot / must-not - change value during runtime; on certain processors, - its value may get sampled only at reset. - It can never be written to, hence - there is no xthal_set_prid() function.) -*/ - .align 4 - .global xthal_get_prid - .type xthal_get_prid,@function -xthal_get_prid: - abi_entry -#if XCHAL_HAVE_PRID - rsr.prid a2 -#else - movi a2, 0 -#endif - abi_return - .size xthal_get_prid, . - xthal_get_prid - diff --git a/src/arch/xtensa/hal/mpu.c b/src/arch/xtensa/hal/mpu.c deleted file mode 100644 index bacbfc6ff0c7..000000000000 --- a/src/arch/xtensa/hal/mpu.c +++ /dev/null @@ -1,1830 +0,0 @@ -/* - * Copyright (c) 2004-2015 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. - */ -#include <xtensa/config/core.h> - -#if XCHAL_HAVE_MPU -#include <xtensa/core-macros.h> -#include <xtensa/hal.h> -#include <string.h> -#include <stdlib.h> - -/* - * General notes: - * Wherever an address is represented as an unsigned, it has only the 27 most significant bits. This is how - * the addresses are represented in the MPU. It has the benefit that we don't need to worry about overflow. - * - * The asserts in the code are ignored unless an assert handler is set (as it is during testing). - * - * If an assert handler is set, then the MPU map is checked for correctness after every update. - * - * On some configs (actually all configs right now), the MPU entries must be aligned to the background map. - * The constant: XCHAL_MPU_ALIGN_REQ indicates if alignment is required: - * - * The rules for a valid map are: - * - * 1) The entries' vStartAddress fields must always be in non-descending order. - * 2) The entries' memoryType and accessRights must contain valid values - * - * If XCHAL_MPU_ALIGN_REQ == 1 then the following additional rules are enforced: - * 3) If entry0's Virtual Address Start field is nonzero, then that field must equal one of the - * Background Map's Virtual Address Start field values if software ever intends to assert entry0's MPUENB bit. - * 4) If entryN's MPUENB bit will ever be negated while at the same time entryN+1's MPUENB bit is asserted, - * then entryN+1's Virtual Address Start field must equal one of the Background Map's Virtual Address Start field values. - * - * The internal function are first, and the external 'xthal_' functions are at the end. - * - */ -extern void (*_xthal_assert_handler)(); -extern void xthal_write_map_raw(const xthal_MPU_entry* fg, unsigned int n); -extern void xthal_read_map_raw(const xthal_MPU_entry* fg); -extern xthal_MPU_entry _xthal_get_entry(const xthal_MPU_entry* fg, const xthal_MPU_entry* bg, - unsigned int addr, int* infgmap); - -#define MPU_ADDRESS_MASK (0xffffffff << XCHAL_MPU_ALIGN_BITS) -#define MPU_ALIGNMENT_MASK (0xffffffff - MPU_ADDRESS_MASK) - -#define MPU_VSTART_CORRECTNESS_MASK ((0x1 << (XCHAL_MPU_ALIGN_BITS)) - 1) -// Set this to 1 for more extensive internal checking / 0 for production -#define MPU_DEVELOPMENT_MODE 0 - -#if XCHAL_MPU_ALIGN_REQ -#define XCHAL_MPU_WORST_CASE_ENTRIES_FOR_REGION 3 -#else -#define XCHAL_MPU_WORST_CASE_ENTRIES_FOR_REGION 2 -#endif - -/* - * At some point it is faster to commit/invalidate the entire cache rather than going on line at a time. - * If a region is bigger than 'CACHE_REGION_THRESHOLD' we operate on the entire cache. - */ -#if XCHAL_DCACHE_LINESIZE -#define CACHE_REGION_THRESHOLD (32 * XCHAL_DCACHE_LINESIZE / XCHAL_MPU_ALIGN) -#else -#define CACHE_REGION_THRESHOLD 0 -#endif - - -/* - * Normally these functions are no-ops, but the MPU test harness sets an assert handler to detect any inconsistencies in MPU - * entries or any other unexpected internal condition. - */ -#if MPU_DEVELOPMENT_MODE -static void my_assert(int arg) -{ - if (_xthal_assert_handler && !arg) - _xthal_assert_handler(); -} - -static void assert_map_valid() -{ - - if (_xthal_assert_handler) - { - xthal_MPU_entry fg[XCHAL_MPU_ENTRIES]; - xthal_read_map(fg); - if (xthal_check_map(fg, XCHAL_MPU_ENTRIES)) - _xthal_assert_handler(); - } -} - -static void assert_attributes_equivalent(unsigned addr, const xthal_MPU_entry* initial, - const xthal_MPU_entry* fg, const xthal_MPU_entry* bg) -{ - - xthal_MPU_entry e1 = _xthal_get_entry(initial, bg, addr, 0); - xthal_MPU_entry e2 = _xthal_get_entry(fg, bg, addr, 0); - my_assert((XTHAL_MPU_ENTRY_GET_ACCESS(e1) == XTHAL_MPU_ENTRY_GET_ACCESS(e2)) && (XTHAL_MPU_ENTRY_GET_MEMORY_TYPE(e1) == XTHAL_MPU_ENTRY_GET_MEMORY_TYPE(e2))); -} - -static void assert_maps_equivalent(const xthal_MPU_entry* initial, const xthal_MPU_entry* fg, - const xthal_MPU_entry* bg) -{ - /* this function checks that for every address the MPU entries 'initial' result in the same attributes as the entries in 'fg'. - * We only need to check at the addresses that appear in 'initial', 'fg', or 'bg'. - */ - int i; - for (i = 0; i < XCHAL_MPU_ENTRIES; i++) - { - assert_attributes_equivalent(XTHAL_MPU_ENTRY_GET_VSTARTADDR(initial[i]), initial, fg, bg); - assert_attributes_equivalent(XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]), initial, fg, bg); - } - for (i = 0; i < XCHAL_MPU_BACKGROUND_ENTRIES; i++) - assert_attributes_equivalent(XTHAL_MPU_ENTRY_GET_VSTARTADDR(bg[i]), initial, fg, bg); -} -#else -#define my_assert(x) -#define assert_map_valid(x) -#endif - -#if 0 -// These functions aren't used, but am leaving the definitions in place -// for possible future use. -static inline unsigned read_mpucfg() -{ - unsigned long tmp; - __asm__ __volatile__("rsr.mpucfg %0\n\t" - : "=a" (tmp)); - return tmp; -} - -static inline unsigned read_mpuenb() -{ - unsigned long tmp; - __asm__ __volatile__("rsr.mpuenb %0\n\t" - : "=a" (tmp)); - return tmp; -} - -/* This function writes the enable for the MPU entries */ -static inline void write_mpuenb(unsigned v) -{ - __asm__ __volatile__("wsr.mpuenb %0\n\t" - : : "a" (v)); -} - -#endif - -static inline void isync() -{ - __asm__ __volatile__("isync\n\t"); -} - -/* This function writes the cache disable register which - * disables the cache by 512MB registers to save power*/ -static inline void write_cacheadrdis(unsigned v) -{ - __asm__ __volatile__("wsr.cacheadrdis %0\n\t" - : : "a" (v)); -} - -inline static int is_cacheable(unsigned int mt); - -#if 0 -static inline void read_map_entry(unsigned en_num, xthal_MPU_entry* en) -{ - unsigned as; - unsigned at0; - unsigned at1; - as = en_num; - __asm__ __volatile__("RPTLB0 %0, %1\n\t" : "+a" (at0) : "a" (as)); - __asm__ __volatile__("RPTLB1 %0, %1\n\t" : "+a" (at1) : "a" (as)); - en->as = at0; - en->at = at1; -} -#endif - -inline static int is_cacheable(unsigned int mt) -{ - return (0x180 & mt) || ((mt & 0x18) == 0x10) || ((mt & 0x30) == 0x30); -} - -inline static int is_writeback(unsigned int mt) -{ - return (((0x180 & mt) && (mt & 0x11)) || - ((((mt & 0x18) == 0x10) || ((mt & 0x30) == 0x30)) & 0x1)); -} - -inline static int is_device(unsigned int mt) -{ - return ((mt & 0x1f0) == 0); -} - -inline static int is_kernel_readable(int accessRights) -{ - switch (accessRights) - { - case XTHAL_AR_R: - case XTHAL_AR_Rr: - case XTHAL_AR_RX: - case XTHAL_AR_RXrx: - case XTHAL_AR_RW: - case XTHAL_AR_RWX: - case XTHAL_AR_RWr: - case XTHAL_AR_RWrw: - case XTHAL_AR_RWrwx: - case XTHAL_AR_RWXrx: - case XTHAL_AR_RWXrwx: - return 1; - case XTHAL_AR_NONE: - case XTHAL_AR_Ww: - return 0; - default: - return XTHAL_BAD_ACCESS_RIGHTS; - } -} - -inline static int is_kernel_writeable(int accessRights) -{ - switch (accessRights) - { - case XTHAL_AR_RW: - case XTHAL_AR_RWX: - case XTHAL_AR_RWr: - case XTHAL_AR_RWrw: - case XTHAL_AR_RWrwx: - case XTHAL_AR_RWXrx: - case XTHAL_AR_RWXrwx: - case XTHAL_AR_Ww: - return 1; - case XTHAL_AR_NONE: - case XTHAL_AR_R: - case XTHAL_AR_Rr: - case XTHAL_AR_RX: - case XTHAL_AR_RXrx: - return 0; - default: - return XTHAL_BAD_ACCESS_RIGHTS; - } -} - -inline static int is_kernel_executable(int accessRights) -{ - switch (accessRights) - { - case XTHAL_AR_RX: - case XTHAL_AR_RXrx: - case XTHAL_AR_RWX: - case XTHAL_AR_RWXrx: - case XTHAL_AR_RWXrwx: - return 1; - case XTHAL_AR_NONE: - case XTHAL_AR_Ww: - case XTHAL_AR_R: - case XTHAL_AR_Rr: - case XTHAL_AR_RW: - case XTHAL_AR_RWr: - case XTHAL_AR_RWrw: - case XTHAL_AR_RWrwx: - return 0; - default: - return XTHAL_BAD_ACCESS_RIGHTS; - } -} - -inline static int is_user_readable(int accessRights) -{ - switch (accessRights) - { - case XTHAL_AR_Rr: - case XTHAL_AR_RXrx: - case XTHAL_AR_RWr: - case XTHAL_AR_RWrw: - case XTHAL_AR_RWrwx: - case XTHAL_AR_RWXrx: - case XTHAL_AR_RWXrwx: - return 1; - case XTHAL_AR_R: - case XTHAL_AR_RX: - case XTHAL_AR_RW: - case XTHAL_AR_RWX: - case XTHAL_AR_NONE: - case XTHAL_AR_Ww: - return 0; - default: - return XTHAL_BAD_ACCESS_RIGHTS; - } -} - -inline static int is_user_writeable(int accessRights) -{ - switch (accessRights) - { - case XTHAL_AR_Ww: - case XTHAL_AR_RWrw: - case XTHAL_AR_RWrwx: - case XTHAL_AR_RWXrwx: - return 1; - case XTHAL_AR_NONE: - case XTHAL_AR_R: - case XTHAL_AR_Rr: - case XTHAL_AR_RX: - case XTHAL_AR_RXrx: - case XTHAL_AR_RW: - case XTHAL_AR_RWX: - case XTHAL_AR_RWr: - case XTHAL_AR_RWXrx: - return 0; - default: - return XTHAL_BAD_ACCESS_RIGHTS; - } -} - -inline static int is_user_executable(int accessRights) -{ - switch (accessRights) - { - case XTHAL_AR_RXrx: - case XTHAL_AR_RWrwx: - case XTHAL_AR_RWXrx: - case XTHAL_AR_RWXrwx: - return 1; - case XTHAL_AR_RW: - case XTHAL_AR_RWX: - case XTHAL_AR_RWr: - case XTHAL_AR_RWrw: - case XTHAL_AR_R: - case XTHAL_AR_Rr: - case XTHAL_AR_RX: - case XTHAL_AR_NONE: - case XTHAL_AR_Ww: - return 0; - default: - return XTHAL_BAD_ACCESS_RIGHTS; - } -} - -/* This function returns the map entry that is used for the address 'addr' (27msb). - * - */ -#if defined(__SPLIT__mpu_basic) - -xthal_MPU_entry _xthal_get_entry(const xthal_MPU_entry* fg, const xthal_MPU_entry* bg, - unsigned int addr, int* infgmap) -{ - int i; - for (i = XCHAL_MPU_ENTRIES - 1; i >= 0; i--) - { - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) <= addr) - { - if (XTHAL_MPU_ENTRY_GET_VALID(fg[i])) - { - if (infgmap) - *infgmap = 1; - return fg[i]; - } - else - break; - } - } - for (i = XCHAL_MPU_BACKGROUND_ENTRIES - 1; i >= 0; i--) - { - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(bg[i]) <= addr) - { - if (infgmap) - *infgmap = 0; - return bg[i]; - } - } - return bg[0]; // never reached ... just to get rid of compilation warning -} - -/* returns true if the supplied address (27msb) is in the background map. */ -int _xthal_in_bgmap(unsigned int address, const xthal_MPU_entry* bg) -{ - int i; - for (i = 0; i < XCHAL_MPU_BACKGROUND_ENTRIES; i++) - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(bg[i]) == address) - return 1; - return 0; -} - -#endif - -#if defined(__SPLIT__mpu_attributes) - -/* This function updates the map entry as well as internal duplicate of the map - * state in fg. The assumption is that reading map entries could be somewhat - * expensive in some situations so we are keeping a copy of the map in memory when - * doing extensive map manipulations. - */ -static void write_map_entry(xthal_MPU_entry* fg, unsigned en_num, xthal_MPU_entry en) -{ - en.at = (en.at & 0xffffffe0) | (en_num & 0x1f); - xthal_mpu_set_entry(en); - assert_map_valid(); - fg[en_num] = en; -} - -static void move_map_down(xthal_MPU_entry* fg, int dup, int idx) -{ - /* moves the map entry list down one (leaving duplicate entries at idx and idx+1. This function assumes that the last - * entry is invalid ... call MUST check this - */ - unsigned int i; - for (i = dup; i > idx; i--) - { - write_map_entry(fg, i, fg[i - 1]); - } -} - -static void move_map_up(xthal_MPU_entry* fg, int dup, int idx) -{ - /* moves the map entry list up one (leaving duplicate entries at idx and idx-1, removing the entry at dup - */ - int i; - for (i = dup; i < idx - 1; i++) - { - write_map_entry(fg, i, fg[i + 1]); - } -} - -static int bubble_free_to_ip(xthal_MPU_entry* fg, int ip, int required) -{ - /* This function shuffles the entries in the MPU to get at least 'required' free entries at - * the insertion point 'ip'. This function returns the new insertion point (after all the shuffling). - */ - int i; - int rv = ip; - if (required < 1) - return ip; - my_assert(required <= XCHAL_MPU_ENTRIES); - /* first we search for duplicate or unused entries at an index less than 'ip'. We start looking at ip-1 - * (rather than 0) to minimize the number of shuffles required. - */ - for (i = ip - 2; i >= 0 && required;) - { - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) == XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i + 1])) - { - move_map_up(fg, i, ip); - rv--; - required--; - } - i--; - } - // if there are any invalid entries at top of the map, we can remove them to make space - while (required) - { - if (!XTHAL_MPU_ENTRY_GET_VALID(fg[0])) - { - move_map_up(fg, 0, ip); - rv--; - required--; - } - else - break; - } - /* If there are not enough unneeded entries at indexes less than ip, then we search at indexes > ip. - * We start the search at ip+1 and move down, again to minimize the number of shuffles required. - */ - - for (i = ip + 1; i < XCHAL_MPU_ENTRIES && required;) - { - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) == XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i - 1])) - { - move_map_down(fg, i, ip); - required--; - } - else - i++; - } - my_assert(required == 0); - return rv; -} - - -/* This function removes 'inaccessible' entries from the MPU map (those that are hidden by previous entries - * in the map). It leaves any entries that match background entries in place. - */ -static void remove_inaccessible_entries(xthal_MPU_entry* fg, const xthal_MPU_entry* bg) -{ - int i; - for (i = 1; i < XCHAL_MPU_ENTRIES; i++) - { - if (((XTHAL_MPU_ENTRY_GET_VALID(fg[i]) == XTHAL_MPU_ENTRY_GET_VALID(fg[i - 1])) && (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) > XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i - 1])) - && (XTHAL_MPU_ENTRY_GET_MEMORY_TYPE(fg[i]) == XTHAL_MPU_ENTRY_GET_MEMORY_TYPE(fg[i - 1])) && (XTHAL_MPU_ENTRY_GET_ACCESS(fg[i]) == XTHAL_MPU_ENTRY_GET_ACCESS(fg[i - 1])) && - /* we can only remove the background map entry if either background alignment is not required, or - * if the previous entry is enabled. - */ - (!_xthal_in_bgmap(XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]), bg))) - || ((!XTHAL_MPU_ENTRY_GET_VALID(fg[i]) && (!XTHAL_MPU_ENTRY_GET_VALID(fg[i - 1])) && (!_xthal_in_bgmap(XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]), bg))))) - { - write_map_entry(fg, i, fg[i - 1]); - } - } -} - -/* This function takes bitwise or'd combination of access rights and memory type, and extracts - * the access rights. It returns the access rights, or -1. - */ -static int encode_access_rights(int cattr) -{ - cattr = cattr & 0xF; - if ((cattr) > 0 && (cattr < 4)) - return -1; - else - return cattr; -} - -/* - * returns the largest value rv, such that for every index < rv, - * entrys[index].vStartAddress < first. - * - * Assumes an ordered entry array (even disabled entries must be ordered). - * value returned is in the range [0, XCHAL_MPU_ENTRIES]. - * - */ -static int find_entry(xthal_MPU_entry* fg, unsigned first) -{ - int i; - for (i = XCHAL_MPU_ENTRIES - 1; i >= 0; i--) - { - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) <= first) - return i + 1; - } - return 0; // if it is less than all existing entries return 0 -} - -/* - * This function returns 1 if there is an exact match for first and first+size - * so that no manipulations are necessary before safing and updating the attributes - * for [first, first+size). The the first and end entries - * must be valid, as well as all the entries in between. Otherwise the memory - * type might change across the region and we wouldn't be able to safe the caches. - * - * An alternative would be to require alignment regions in this case, but that seems - * more wasteful. - */ -static int needed_entries_exist(xthal_MPU_entry* fg, unsigned first, unsigned last) -{ - int i; - for (i = 0; i < XCHAL_MPU_ENTRIES; i++) - { - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) == first) - { - int j; - /* special case ... is last at the end of the address space - * ... if so there is no end entry needed. - */ - if (last == 0xFFFFFFFF) - { - int k; - for (k = i; k < XCHAL_MPU_ENTRIES; k++) - if (!XTHAL_MPU_ENTRY_GET_VALID(fg[k])) - return 0; - return 1; - } - /* otherwise search for the end entry */ - for (j = i; j < XCHAL_MPU_ENTRIES; j++) - if (last == XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[j])) - { - int k; - for (k = i; k <= j; k++) - if (!XTHAL_MPU_ENTRY_GET_VALID(fg[k])) - return 0; - return 1; - } - return 0; - } - } - return 0; -} - -/* This function computes the number of MPU entries that are available for use in creating a new - * region. - */ -static int number_available(xthal_MPU_entry* fg) -{ - int i; - int rv = 0; - int valid_seen = 0; - for (i = 0; i < XCHAL_MPU_ENTRIES; i++) - { - if (!valid_seen) - { - if (XTHAL_MPU_ENTRY_GET_VALID(fg[i])) - valid_seen = 1; - else - { - rv++; - continue; - } - } - else - { - if (i && (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) == XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i - 1]))) - rv++; - } - } - return rv; -} - -/* - * This function returns index of the background map entry that maps the address 'first' if there are no - * enabled/applicable foreground map entries. - */ -static int get_bg_map_index(const xthal_MPU_entry* bg, unsigned first) -{ - int i; - for (i = XCHAL_MPU_BACKGROUND_ENTRIES - 1; i >= 0; i--) - if (first > XTHAL_MPU_ENTRY_GET_VSTARTADDR(bg[i])) - return i; - return 0; -} - -inline static unsigned int covert_to_writethru_memtype(unsigned int wb_memtype) -{ - unsigned int prefix = wb_memtype & 0x1f0; - if (prefix == 0x10) - return wb_memtype & 0xfffffffe; - else - return wb_memtype & 0xffffffee; -} - -/* - * This function takes the region pointed to by ip, and makes it safe from the aspect of cache coherency, before - * changing the memory type and possibly corrupting the cache. If wb is 0, then that indicates - * that we should ignore uncommitted entries. If the inv argument is 0 that indicates that we shouldn't invalidate - * the cache before switching to bypass. - */ -static void safe_region(xthal_MPU_entry* fg, int ip, unsigned end_of_segment, int memoryType, int wb, int inv, - unsigned int* post_inv_all) -{ - unsigned length = end_of_segment - XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[ip]); // initially keep length 27msb to avoid possibility of overflow - if (!length) - return; // if the region is empty, there is no need to safe it - - int cmemType = XTHAL_MPU_ENTRY_GET_MEMORY_TYPE(fg[ip]); - - if (memoryType == cmemType) - return; // not changing memory types ... we don't need to do anything - - int mt_is_wb = is_writeback(memoryType); - int mt_is_ch = is_cacheable(memoryType); - - // nothing needs to be done in these cases - if (mt_is_wb || (!wb && (!inv || mt_is_ch))) - return; - - int need_flush = wb && (is_writeback(cmemType) && !is_writeback(memoryType)); - int need_invalidate = inv && (is_cacheable(cmemType) && !is_cacheable(memoryType)); - - void* addr = (void*) XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[ip]); - - int write_by_region = length < CACHE_REGION_THRESHOLD; - - if (need_flush) - { - XTHAL_MPU_ENTRY_SET_MEMORY_TYPE(fg[ip], covert_to_writethru_memtype(XTHAL_MPU_ENTRY_GET_MEMORY_TYPE(fg[ip]))); - // If the AR == NONE, the writing back the cache may generate exception. Temporarily open up the protections ... - // ... - if (XTHAL_MPU_ENTRY_GET_ACCESS(fg[ip]) == XTHAL_AR_NONE) - XTHAL_MPU_ENTRY_SET_ACCESS(fg[ip], XTHAL_AR_RWXrwx); - // bit 0 determines if it wb/wt - write_map_entry(fg, ip, fg[ip]); - if (!write_by_region) - { - /* unfortunately there is no straight forward way to avoid the possibility of doing - * multiple xthal_dcache_all_writeback() calls during a region update. The reason for this - * is that: - * - * 1) The writeback must be done before the memory type is changed to non-cacheable before - * an invalidate (see below) - * - * 2) it isn't possible to reorganize the loop so that all the writebacks are done before - * any of the invalidates because if part of the region of interest is (initially) mapped - * by the background map, then a single foreground entry is reused to 'safe' across - * each background map entry that is overlapped. - */ - xthal_dcache_all_writeback(); - } - else if (length) - xthal_dcache_region_writeback(addr, length); - } - - if (need_invalidate) - { - XTHAL_MPU_ENTRY_SET_MEMORY_TYPE(fg[ip], - XTHAL_ENCODE_MEMORY_TYPE(XCHAL_CA_BYPASS)); - write_map_entry(fg, ip, fg[ip]); - /* only need to call all_invalidate once ... check - * if it has already been done. - */ - if (!*post_inv_all) - { - if (!write_by_region) - { - *post_inv_all = 1; - } - else if (length) - { - xthal_icache_region_invalidate(addr, length); - xthal_dcache_region_writeback_inv(addr, length); - } - } - } -} - -static unsigned max(unsigned a, unsigned b, unsigned c) -{ - if (a > b && a > c) - return a; - else if (b > c) - return b; - else - return c; -} - -/* This function returns the next address to commit which will be the greatest of the following: - * 1) The start of the region we are creating - * 2) The vStartAddress of the previous entry - * 3) The background map entry that precedes the current address (last address committed). - */ -static unsigned next_address_to_commit(xthal_MPU_entry* fg, const xthal_MPU_entry* bg, unsigned first, - int current_index) -{ - unsigned current = XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[current_index]); - return max(first, XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[current_index - 1]), XTHAL_MPU_ENTRY_GET_VSTARTADDR(bg[get_bg_map_index(bg, current)])); -} - -/* - * This function does a series of calls to safe_region() to ensure that no data will be corrupted when changing the memory type - * of an MPU entry. These calls are made for every entry address in the range[first,end), as well as at any background region boundary - * in the range[first,end). In general it is necessary to safe at the background region boundaries, because the memory type could - * change at that address. - * - * This function is written to reuse already needed entries for the background map 'safes' which complicates things somewhat. - * - * After the calls to safe region are complete, then the entry attributes are updated for every entry in the range [first,end). - */ -static void safe_and_commit_overlaped_regions(xthal_MPU_entry* fg, const xthal_MPU_entry*bg, unsigned first, - unsigned last, int memoryType, int accessRights, int wb, int inv) -{ - int i; - unsigned int next; - unsigned end_of_segment = last; - unsigned post_inv_all = 0; - unsigned int cachedisadr; - write_cacheadrdis(0); - for (i = XCHAL_MPU_ENTRIES - 1; i >= 0; i--) - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) < last) - { - // first we want to commit the first entry - safe_region(fg, i, end_of_segment, memoryType, wb, inv, &post_inv_all); - end_of_segment = XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]); - do - { - next = next_address_to_commit(fg, bg, first, i); - if (next == XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i - 1])) - i--; - XTHAL_MPU_ENTRY_SET_VSTARTADDR(fg[i], next); - safe_region(fg, i, last, memoryType, wb, inv, &post_inv_all); - end_of_segment = XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]); - } while (next > first); - if (post_inv_all) - { - xthal_icache_all_invalidate(); - xthal_dcache_all_writeback_inv(); - } - for (; i < XCHAL_MPU_ENTRIES && XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) < last; i++) - { - XTHAL_MPU_ENTRY_SET_MEMORY_TYPE(fg[i], memoryType); - XTHAL_MPU_ENTRY_SET_ACCESS(fg[i], accessRights); - XTHAL_MPU_ENTRY_SET_VALID(fg[i], 1); - write_map_entry(fg, i, fg[i]); - } - break; - } - cachedisadr = xthal_calc_cacheadrdis(fg, XCHAL_MPU_ENTRIES); - write_cacheadrdis(cachedisadr); -} - -static void handle_invalid_pred(xthal_MPU_entry* fg, const xthal_MPU_entry* bg, unsigned first, int ip) -{ - /* Handle the case where there is an invalid entry immediately preceding the entry we - * are creating. If the entries addresses correspond to the same bg map, then we - * make the previous entry valid with same attributes as the background map entry. - * - * The case where an invalid entry exists immediately preceding whose address corresponds to a different - * background map entry is handled by create_aligning_entries_if_required(), so nothing is done here. - */ - /* todo ... optimization opportunity, the following block loops through the background map up to 4 times, - * - */ - if (!ip || XTHAL_MPU_ENTRY_GET_VALID(fg[ip - 1])) - return; - { - int i; - unsigned fgipm1_addr = XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[ip - 1]); - int first_in_bg_map = 0; - int first_bg_map_index = -1; - int fgipm1_bg_map_index = -1; -#if MPU_DEVELOPMENT_MODE - unsigned fgip_addr = XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[ip]); - int fgip_bg_map_index = -1; -#endif - for (i = XCHAL_MPU_BACKGROUND_ENTRIES - 1; i >= 0; i--) - { - unsigned addr = XTHAL_MPU_ENTRY_GET_VSTARTADDR(bg[i]); - if (addr == first) - first_in_bg_map = 1; - if (addr < fgipm1_addr && fgipm1_bg_map_index == -1) - fgipm1_bg_map_index = i; -#if MPU_DEVELOPMENT_MODE - if (addr < fgip_addr && fgip_bg_map_index == -1) - fgip_bg_map_index = i; -#endif - if (addr < first && first_bg_map_index == -1) - first_bg_map_index = i; - } - if (!first_in_bg_map && (first_bg_map_index == fgipm1_bg_map_index)) - { - // There should be a subsequent entry that falls in the address range of same - // background map entry ... if not, we have a problem because the following - // will corrupt the memory map -#if MPU_DEVELOPMENT_MODE - { - my_assert(fgip_bg_map_index == fgipm1_bg_map_index); - } -#endif - xthal_MPU_entry temp = _xthal_get_entry(fg, bg, XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[ip - 1]), 0); - XTHAL_MPU_ENTRY_SET_VSTARTADDR(temp, XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[ip - 1])); - write_map_entry(fg, ip - 1, temp); - } - } -} - -/* This function inserts a entry (unless it already exists) with vStartAddress of first. The new entry has - * the same accessRights and memoryType as the address first had before the call. - * - * If 'invalid' is specified, then insert an invalid region if no foreground entry exists for the address 'first'. - */ -static int insert_entry_if_needed_with_existing_attr(xthal_MPU_entry* fg, const xthal_MPU_entry* bg, - unsigned first, int invalid) -{ - int i; - int ip; - int infg; - int found = 0; - - for (i = XCHAL_MPU_ENTRIES - 1; i >= 0; i--) - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) == first) - { - if (XTHAL_MPU_ENTRY_GET_VALID(fg[i]) || invalid) - return XTHAL_SUCCESS; - else - { - found = 1; - ip = i; - break; - } - } - - if (!found) - { - if (!number_available(fg)) - return XTHAL_OUT_OF_ENTRIES; - - ip = find_entry(fg, first); - ip = bubble_free_to_ip(fg, ip, 1); - } - if (!invalid) - handle_invalid_pred(fg, bg, first, ip); - xthal_MPU_entry n; - memset(&n, 0, sizeof(n)); - n = _xthal_get_entry(fg, bg, first, &infg); - - if (invalid && !infg) // If the entry mapping is currently in the foreground we can't make - // the entry invalid without corrupting the attributes of the following entry. - XTHAL_MPU_ENTRY_SET_VALID(n, 0); - XTHAL_MPU_ENTRY_SET_VSTARTADDR(n,first); - write_map_entry(fg, ip, n); - return XTHAL_SUCCESS; -} - -static unsigned int smallest_entry_greater_than_equal(xthal_MPU_entry* fg, unsigned x) -{ - int i; - for (i = 0; i < XCHAL_MPU_ENTRIES; i++) - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) >= x) - return XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]); - return 0; -} - -/* This function creates background map aligning entries if required.*/ -static unsigned int create_aligning_entries_if_required(xthal_MPU_entry* fg, const xthal_MPU_entry* bg, - unsigned x) -{ -#if XCHAL_MPU_ALIGN_REQ - int i; - int rv; - unsigned next_entry_address = 0; - unsigned next_entry_valid = 0; - int preceding_bg_entry_index_x = get_bg_map_index(bg, x); - unsigned preceding_bg_entry_x_addr = XTHAL_MPU_ENTRY_GET_VSTARTADDR(bg[preceding_bg_entry_index_x]); - for (i = XCHAL_MPU_ENTRIES - 1; i >= 0; i--) - { - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) < x) - { - if (XTHAL_MPU_ENTRY_GET_VALID(fg[i])) - return XTHAL_SUCCESS; // If there is a valid entry immediately before the proposed new entry - // ... then no aligning entries are required - break; - } - else - { - next_entry_address = XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]); - next_entry_valid = XTHAL_MPU_ENTRY_GET_VALID(fg[i]); - } - } - - /* - * before creating the aligning entry, we may need to create an entry or entries a higher - * addresses to limit the scope of the aligning entry. - */ - if ((!next_entry_address) || (!next_entry_valid) || (_xthal_in_bgmap(next_entry_address, bg))) - { - /* in this case, we can just create an invalid entry at the start of the new region because - * a valid entry could have an alignment problem. An invalid entry is safe because we know that - * the next entry is either invalid, or is on a bg map entry - */ - if ((rv = insert_entry_if_needed_with_existing_attr(fg, bg, x, 1)) != XTHAL_SUCCESS) - { - return rv; - } - } - else - { - unsigned next_bg_entry_index; - for (next_bg_entry_index = 0; next_bg_entry_index < XCHAL_MPU_BACKGROUND_ENTRIES; next_bg_entry_index++) - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(bg[next_bg_entry_index]) > x) - break; - if (next_entry_address == XTHAL_MPU_ENTRY_GET_VSTARTADDR(bg[next_bg_entry_index])) // In this case there is no intervening bg entry - // between the new entry x, and the next existing entry so, we don't need any limiting entry - // (the existing next_entry serves as the limiting entry) - { /* intentionally empty */ - } - else - { - // In this case we need to create a valid region at the background entry that immediately precedes - // next_entry_address, and then create an invalid entry at the background entry immediately after - // x - if ((rv = insert_entry_if_needed_with_existing_attr(fg, bg, XTHAL_MPU_ENTRY_GET_VSTARTADDR(_xthal_get_entry(fg, bg, x, 0)), 0)) - != XTHAL_SUCCESS) - { - return rv; - } - if ((rv = insert_entry_if_needed_with_existing_attr(fg, bg, - XTHAL_MPU_ENTRY_GET_VSTARTADDR(_xthal_get_entry(fg, bg, XTHAL_MPU_ENTRY_GET_VSTARTADDR(bg[next_bg_entry_index]), 0)), 1)) != XTHAL_SUCCESS) - { - return rv; - } - } - } - - /* now we are finally ready to create the aligning entry.*/ - if (!(x == preceding_bg_entry_x_addr)) - if ((rv = insert_entry_if_needed_with_existing_attr(fg, bg, preceding_bg_entry_x_addr, 0)) != XTHAL_SUCCESS) - { - return rv; - } - - return XTHAL_SUCCESS; - -#else - return XTHAL_SUCCESS; -#endif -} - -static unsigned start_initial_region(xthal_MPU_entry* fg, const xthal_MPU_entry* bg, unsigned first, - unsigned end) -{ - int i; - unsigned addr; - for (i = XCHAL_MPU_BACKGROUND_ENTRIES - 1; i >= 0; i--) - { - addr = XTHAL_MPU_ENTRY_GET_VSTARTADDR(bg[i]); - if (addr <= first) - break; - if (addr < end) - return addr; - } - return first; -} - -static int safe_add_region(unsigned first, unsigned last, unsigned accessRights, unsigned memoryType, - unsigned writeback, unsigned invalidate) -{ - /* This function sets the memoryType and accessRights on a region of memory. If necessary additional MPU entries - * are created so that the attributes of any memory outside the specified region are not changed. - * - * This function has 2 stages: - * 1) The map is updated one entry at a time to create (if necessary) new entries to mark the beginning and end of the - * region as well as addition alignment entries if needed. During this stage the map is always correct, and the memoryType - * and accessRights for every address remain the same. - * 2) The entries inside the update region are then safed for cache consistency (if necessary) and then written with - * the new accessRights, and memoryType. - * - * If the function fails (by running out of available map entries) during stage 1 then everything is still consistent and - * it is safe to return an error code. - * - * If XCHAL_MPU_ALIGN_REQ is provided then extra entries are create if needed - * to satisfy these alignment conditions: - * - * 1) If entry0's Virtual Address Start field is nonzero, then that field must equal one of the Background Map's - * Virtual Address Start field values if software ever intends to assert entry0's MPUENB bit. - * 2) If entryN's MPUENB bit will ever be negated while at the same time entryN+1's MPUENB bit is - * asserted, then entryN+1's Virtual Address Start field must equal one of the Background Map's Virtual Address Start field values. - * - * Between 0 and 2 available entries will be used by this function. In addition, if XCHAL_MPU_ALIGN_REQ == 1 up to ??? - * additional entries will be needed to meet background map alignment requirements. - * - * This function keeps a copy of the current map in 'fg'. This is kept in sync with contents of the MPU at all times. - * - */ - - int rv; - - xthal_MPU_entry fg[XCHAL_MPU_ENTRIES]; -#if MPU_DEVELOPMENT_MODE - xthal_MPU_entry on_entry[XCHAL_MPU_ENTRIES]; - xthal_read_map(on_entry); -#endif - xthal_read_map(fg); - assert_map_valid(); - - /* First we check and see if consecutive entries at first, and first + size already exist. - * in this important special case we don't need to do anything but safe and update the entries [first, first+size). - * - */ - - if (!needed_entries_exist(fg, first, last)) - { - unsigned x; - unsigned pbg; - - /* - * If we are tight on entries, the first step is to remove any redundant entries in the MPU - * to make room to ensure that there is room for the new entries we need. - * - * We need to call it here ... once we have started transforming the map it is too late - * (the process involves creating inaccessible entries that could potentially get removed). - */ - if (number_available(fg) < XCHAL_MPU_WORST_CASE_ENTRIES_FOR_REGION) - remove_inaccessible_entries(fg, Xthal_mpu_bgmap); -#if MPU_DEVELOPMENT_MODE - assert_maps_equivalent(on_entry, fg, Xthal_mpu_bgmap); -#endif - // First we create foreground entries that 'duplicate' background entries to aide in - // maintaining proper alignment. - if ((rv = create_aligning_entries_if_required(fg, Xthal_mpu_bgmap, first)) != XTHAL_SUCCESS) - return rv; - - // First we write the terminating entry for our region - // 5 cases: - // 1) end is at the end of the address space, then we don't need to do anything ... takes 0 entries - // 2) There is an existing entry at end ... another nop ... 0 entries - // 3) end > than any existing entry ... in this case we just create a new invalid entry at end to mark - // end of the region. No problem with alignment ... this takes 1 entry - // 4) otherwise if there is a background map boundary between end and x ,the smallest existing entry that is - // greater than end, then we first create an equivalent foreground map entry for the background map entry that immediately - // precedes x, and then we write an invalid entry for end. Takes 2 entries - // 5) otherwise x is in the same background map entry as end, in this case we write a new foreground entry with the existing - // attributes at end - - if (last == 0xFFFFFFFF) - { /* the end is the end of the address space ... do nothing */ - } - else - { - x = smallest_entry_greater_than_equal(fg, last); - if (last == x) - { /* another nop */ - } - else if (last > x) - { /* there is no entry that has a start after the new region ends - ... we handle this by creating an invalid entry at the end point */ - if ((rv = insert_entry_if_needed_with_existing_attr(fg, Xthal_mpu_bgmap, last, 1)) != XTHAL_SUCCESS) - { -#if MPU_DEVELOPMENT_MODE - assert_maps_equivalent(on_entry, fg, Xthal_mpu_bgmap); -#endif - return rv; - } -#if MPU_DEVELOPMENT_MODE - assert_maps_equivalent(on_entry, fg, Xthal_mpu_bgmap); -#endif - } - else - { - pbg = XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[get_bg_map_index(Xthal_mpu_bgmap, x)]); - /* so there is an existing entry we must deal with. We next need to find - * if there is an existing background entry in between the end of - * the new region and beginning of the next. - */ - if ((pbg != x) && (pbg > last)) - { - /* okay ... there is an intervening background map entry. We need - * to handle this by inserting an aligning entry (if the architecture requires it) - * and then placing writing an invalid entry at end. - */ - if (XCHAL_MPU_ALIGN_REQ) - { - if ((rv = insert_entry_if_needed_with_existing_attr(fg, Xthal_mpu_bgmap, pbg, 0)) != XTHAL_SUCCESS) - { -#if MPU_DEVELOPMENT_MODE - assert_maps_equivalent(on_entry, fg, Xthal_mpu_bgmap); -#endif - return rv; - } -#if MPU_DEVELOPMENT_MODE - assert_maps_equivalent(on_entry, fg, Xthal_mpu_bgmap); -#endif - } - if ((rv = insert_entry_if_needed_with_existing_attr(fg, Xthal_mpu_bgmap, last, 1)) != XTHAL_SUCCESS) - { -#if MPU_DEVELOPMENT_MODE - assert_maps_equivalent(on_entry, fg, Xthal_mpu_bgmap); -#endif - return rv; - } -#if MPU_DEVELOPMENT_MODE - assert_maps_equivalent(on_entry, fg, Xthal_mpu_bgmap); -#endif - } - else - /* ok so there are no background map entry in between end and x, in this case - * we just need to create a new entry at end writing the existing attributes. - */ - if ((rv = insert_entry_if_needed_with_existing_attr(fg, Xthal_mpu_bgmap, last, 1)) != XTHAL_SUCCESS) - { -#if MPU_DEVELOPMENT_MODE - assert_maps_equivalent(on_entry, fg, Xthal_mpu_bgmap); -#endif - return rv; - } -#if MPU_DEVELOPMENT_MODE - assert_maps_equivalent(on_entry, fg, Xthal_mpu_bgmap); -#endif - } - } - - /* last, but not least we need to insert a entry at the starting address for our new region */ - if ((rv = insert_entry_if_needed_with_existing_attr(fg, Xthal_mpu_bgmap, start_initial_region(fg, Xthal_mpu_bgmap, first, last), 0)) - != XTHAL_SUCCESS) - { -#if MPU_DEVELOPMENT_MODE - assert_maps_equivalent(on_entry, fg, Xthal_mpu_bgmap); -#endif - return rv; - } -#if MPU_DEVELOPMENT_MODE - assert_maps_equivalent(on_entry, fg, Xthal_mpu_bgmap); -#endif - } - // up to this point, the attributes of every byte in the address space should be the same as when this function - // was called. - safe_and_commit_overlaped_regions(fg, Xthal_mpu_bgmap, first, last, memoryType, accessRights, writeback, invalidate); - - assert_map_valid(); - return XTHAL_SUCCESS; -} - -// checks if x (full 32bit) is mpu_aligned for MPU -static unsigned int mpu_aligned(unsigned x) -{ - return !(x & MPU_ALIGNMENT_MASK); -} - -static unsigned int mpu_align(unsigned int x, unsigned int roundUp) -{ - if (roundUp) - return (x + MPU_ALIGNMENT_MASK) & MPU_ADDRESS_MASK; - else - return (x & MPU_ADDRESS_MASK); -} - -#endif - -#if defined(__SPLIT__mpu_check) -static int bad_accessRights(unsigned ar) -{ - if (ar == 0 || (ar >= 4 && ar <= 15)) - return 0; - else - return 1; -} - -/* this function checks if the supplied map 'fg' is a valid MPU map using 3 criteria: - * 1) if an entry is valid, then that entries accessRights must be defined (0 or 4-15). - * 2) The map entries' 'vStartAddress's must be in increasing order. - * 3) If the architecture requires background map alignment then: - * a) If entry0's 'vStartAddress' field is nonzero, then that field must equal - * one of the Background Map's 'vStartAddress' field values if the entry 0's valid bit is set. - * b) If entryN's 'valid' bit is 0 and entry[N+1]'s 'valid' bit is 1, then - * entry[N+1]'s 'vStartAddress' field must equal one of the Background Map's 'vStartAddress' field values. - * - * This function returns XTHAL_SUCCESS if the map satisfies the condition, otherwise it returns - * XTHAL_BAD_ACCESS_RIGHTS, XTHAL_OUT_OF_ORDER_MAP, or XTHAL_MAP_NOT_ALIGNED. - * - */ -static int check_map(const xthal_MPU_entry* fg, unsigned int n, const xthal_MPU_entry* bg) -{ - int i; - unsigned current = 0; - if (!n) - return XTHAL_SUCCESS; - if (n > XCHAL_MPU_ENTRIES) - return XTHAL_OUT_OF_ENTRIES; - for (i = 0; i < n; i++) - { - if (XTHAL_MPU_ENTRY_GET_VALID(fg[i]) && bad_accessRights(XTHAL_MPU_ENTRY_GET_ACCESS(fg[i]))) - return XTHAL_BAD_ACCESS_RIGHTS; - if ((XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) < current)) - return XTHAL_OUT_OF_ORDER_MAP; - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]) & MPU_VSTART_CORRECTNESS_MASK) - return XTHAL_MAP_NOT_ALIGNED; - current = XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i]); - } - if (XCHAL_MPU_ALIGN_REQ && XTHAL_MPU_ENTRY_GET_VALID(fg[0]) && XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[0]) - && !_xthal_in_bgmap(XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[0]), bg)) - return XTHAL_MAP_NOT_ALIGNED; - for (i = 0; i < n- 1; i++) - if (XCHAL_MPU_ALIGN_REQ && !XTHAL_MPU_ENTRY_GET_VALID(fg[i]) && XTHAL_MPU_ENTRY_GET_VALID(fg[i + 1]) - && !_xthal_in_bgmap(XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[i + 1]), bg)) - return XTHAL_MAP_NOT_ALIGNED; - return XTHAL_SUCCESS; -} - - - -/* - * this function checks that the bit-wise or-ed XTHAL_MEM_... bits in x correspond to a valid - * MPU memoryType. If x is valid, then 0 is returned, otherwise XTHAL_BAD_MEMORY_TYPE is - * returned. - */ -static int check_memory_type(unsigned x) -{ - unsigned system_cache_type = _XTHAL_MEM_CACHE_MASK(x); - unsigned processor_cache_type = (((x) & _XTHAL_LOCAL_CACHE_BITS) >> 4); - if ((system_cache_type > XTHAL_MEM_NON_CACHEABLE) || (processor_cache_type > XTHAL_MEM_NON_CACHEABLE)) - return XTHAL_BAD_MEMORY_TYPE; - int processor_cache_type_set = 1; - if (!processor_cache_type) - { - processor_cache_type = system_cache_type << 4; - processor_cache_type_set = 0; - } - unsigned device = _XTHAL_MEM_IS_DEVICE(x); - unsigned system_noncacheable = _XTHAL_IS_SYSTEM_NONCACHEABLE(x); - - if (device | system_noncacheable) - { - if ((system_cache_type || processor_cache_type_set) && device) - return XTHAL_BAD_MEMORY_TYPE; - if (processor_cache_type_set) - return XTHAL_BAD_MEMORY_TYPE; // if memory is device or non cacheable, then processor cache type should not be set - if (system_noncacheable && (x & XTHAL_MEM_INTERRUPTIBLE)) - return XTHAL_BAD_MEMORY_TYPE; - { - unsigned z = x & XTHAL_MEM_SYSTEM_SHAREABLE; - if ((z == XTHAL_MEM_INNER_SHAREABLE) || (z == XTHAL_MEM_OUTER_SHAREABLE)) - return XTHAL_BAD_MEMORY_TYPE; - } - } - else - { - if ((x & XTHAL_MEM_SYSTEM_SHAREABLE) == XTHAL_MEM_SYSTEM_SHAREABLE) - return XTHAL_BAD_MEMORY_TYPE; - if ((x & (XTHAL_MEM_BUFFERABLE | XTHAL_MEM_INTERRUPTIBLE))) - return XTHAL_BAD_MEMORY_TYPE; - } - - return 0; -} -#endif - -#endif // is MPU - -#if defined(__SPLIT__mpu_basic) -/* - * These functions accept encoded access rights, and return 1 if the supplied memory type has the property specified by the function name. - */ -extern int xthal_is_kernel_readable(int accessRights) -{ -#if XCHAL_HAVE_MPU - return is_kernel_readable(accessRights); -#else - return XTHAL_UNSUPPORTED; -#endif -} - -extern int xthal_is_kernel_writeable(int accessRights) -{ -#if XCHAL_HAVE_MPU - return is_kernel_writeable(accessRights); -#else - return XTHAL_UNSUPPORTED; -#endif -} - -extern int xthal_is_kernel_executable(int accessRights) -{ -#if XCHAL_HAVE_MPU - return is_kernel_executable(accessRights); -#else - return XTHAL_UNSUPPORTED; -#endif -} - -extern int xthal_is_user_readable(int accessRights) -{ -#if XCHAL_HAVE_MPU - return is_user_readable(accessRights); -#else - return XTHAL_UNSUPPORTED; -#endif -} - -extern int xthal_is_user_writeable(int accessRights) -{ -#if XCHAL_HAVE_MPU - return is_user_writeable(accessRights); -#else - return XTHAL_UNSUPPORTED; -#endif -} - -extern int xthal_is_user_executable(int accessRights) -{ -#if XCHAL_HAVE_MPU - return is_user_executable(accessRights); -#else - return XTHAL_UNSUPPORTED; -#endif -} - -/* - * These functions accept either an encoded or unencoded memory type, and - * return 1 if the supplied memory type has property specified by the - * function name. - */ -int xthal_is_cacheable(unsigned int mt) -{ -#if XCHAL_HAVE_MPU - return is_cacheable(mt); -#else - return XTHAL_UNSUPPORTED; -#endif -} - -int xthal_is_writeback(unsigned int mt) -{ -#if XCHAL_HAVE_MPU - return is_writeback(mt); -#else - return XTHAL_UNSUPPORTED; -#endif -} - -int xthal_is_device(unsigned int mt) -{ -#if XCHAL_HAVE_MPU - return is_device(mt); -#else - return XTHAL_UNSUPPORTED; -#endif -} -#endif - -/* - * This function converts a bit-wise combination of the XTHAL_MEM_.. constants - * to the corresponding MPU memory type (9-bits). - * - * If none of the XTHAL_MEM_.. bits are present in the argument, then - * bits 4-12 (9-bits) are returned ... this supports using an already encoded - * memoryType (perhaps obtained from an xthal_MPU_entry structure) as input - * to xthal_set_region_attribute(). - * - * This function first checks that the supplied constants are a valid and - * supported combination. If not, it returns XTHAL_BAD_MEMORY_TYPE. - */ -#if defined(__SPLIT__mpu_check) -int xthal_encode_memory_type(unsigned int x) -{ -#if XCHAL_HAVE_MPU - const unsigned int MemoryTypeMask = 0x1ff0; - const unsigned int MemoryFlagMask = 0xffffe000; - /* - * Encodes the memory type bits supplied in an | format (XCHAL_CA_PROCESSOR_CACHE_WRITEALLOC | XCHAL_CA_PROCESSOR_CACHE_WRITEBACK) - */ - unsigned memoryFlags = x & MemoryFlagMask; - if (!memoryFlags) - return (x & MemoryTypeMask) >> XTHAL_AR_WIDTH; - else - { - int chk = check_memory_type(memoryFlags); - if (chk < 0) - return chk; - else - return XTHAL_ENCODE_MEMORY_TYPE(memoryFlags); - } -#else - return XTHAL_UNSUPPORTED; -#endif -} -#endif - -#if defined(__SPLIT__mpu_rmap) - -/* - * Copies the current MPU entry list into 'entries' which - * must point to available memory of at least - * sizeof(xthal_MPU_entry) * XCHAL_MPU_ENTRIES. - * - * This function returns XTHAL_SUCCESS. - * XTHAL_INVALID, or - * XTHAL_UNSUPPORTED. - */ -int xthal_read_map(xthal_MPU_entry* fg_map) -{ -#if XCHAL_HAVE_MPU - unsigned i; - if (!fg_map) - return XTHAL_INVALID; - xthal_read_map_raw(fg_map); - return XTHAL_SUCCESS; -#else - return XTHAL_UNSUPPORTED; -#endif -} - -#if XCHAL_HAVE_MPU - #undef XCHAL_MPU_BGMAP - #define XCHAL_MPU_BGMAP(s,vstart,vend,rights,mtype,x...) XTHAL_MPU_ENTRY(vstart,1,rights,mtype), -const xthal_MPU_entry Xthal_mpu_bgmap[] = { XCHAL_MPU_BACKGROUND_MAP(0) }; -#endif - - -/* - * Copies the MPU background map into 'entries' which must point - * to available memory of at least - * sizeof(xthal_MPU_entry) * XCHAL_MPU_BACKGROUND_ENTRIES. - * - * This function returns XTHAL_SUCCESS. - * XTHAL_INVALID, or - * XTHAL_UNSUPPORTED. - */ -int xthal_read_background_map(xthal_MPU_entry* bg_map) -{ -#if XCHAL_HAVE_MPU - if (!bg_map) - return XTHAL_INVALID; - memcpy(bg_map, Xthal_mpu_bgmap, sizeof(Xthal_mpu_bgmap)); - return XTHAL_SUCCESS; -#else - return XTHAL_UNSUPPORTED; -#endif -} -#endif -/* - * Writes the map pointed to by 'entries' to the MPU. Before updating - * the map, it commits any uncommitted - * cache writes, and invalidates the cache if necessary. - * - * This function does not check for the correctness of the map. Generally - * xthal_check_map() should be called first to check the map. - * - * If n == 0 then the existing map is cleared, and no new map is written - * (useful for returning to reset state) - * - * If (n > 0 && n < XCHAL_MPU_ENTRIES) then a new map is written with - * (XCHAL_MPU_ENTRIES-n) padding entries added to ensure a properly ordered - * map. The resulting foreground map will be equivalent to the map vector - * fg, but the position of the padding entries should not be relied upon. - * - * If n == XCHAL_MPU_ENTRIES then the complete map as specified by fg is - * written. - * - * xthal_write_map() disables the MPU foreground map during the MPU - * update and relies on the background map. - * - * As a result any interrupt that does not meet the following conditions - * must be disabled before calling xthal_write_map(): - * 1) All code and data needed for the interrupt must be - * mapped by the background map with sufficient access rights. - * 2) The interrupt code must not access the MPU. - * - */ -#if defined(__SPLIT__mpu_wmap) -void xthal_write_map(const xthal_MPU_entry* fg, unsigned int n) -{ -#if XCHAL_HAVE_MPU - unsigned int cacheadrdis = xthal_calc_cacheadrdis(fg, n); - xthal_dcache_all_writeback_inv(); - xthal_icache_all_invalidate(); - xthal_write_map_raw(fg, n); - write_cacheadrdis(cacheadrdis); - isync(); // ditto -#endif -} -#endif - -#if defined(__SPLIT__mpu_check) -/* - * Checks if entry vector 'fg' of length 'n' is a valid MPU access map. - * Returns: - * XTHAL_SUCCESS if valid, - * XTHAL_OUT_OF_ENTRIES - * XTHAL_MAP_NOT_ALIGNED, - * XTHAL_BAD_ACCESS_RIGHTS, - * XTHAL_OUT_OF_ORDER_MAP, or - * XTHAL_UNSUPPORTED if config doesn't have an MPU. - */ -int xthal_check_map(const xthal_MPU_entry* fg, unsigned int n) -{ -#if XCHAL_HAVE_MPU - return check_map(fg, XCHAL_MPU_ENTRIES, Xthal_mpu_bgmap); -#else - return XTHAL_UNSUPPORTED; -#endif -} -#endif - -#if defined(__SPLIT__mpu_basic) -/* - * Returns the MPU entry that maps 'vaddr'. If 'infgmap' is non-NULL then it is - * set to 1 if 'vaddr' is mapped by the foreground map, or 0 if 'vaddr' - * is mapped by the background map. - */ -extern xthal_MPU_entry xthal_get_entry_for_address(void* paddr, int* infgmap) - { -#if XCHAL_HAVE_MPU - xthal_MPU_entry e; - unsigned int p; - __asm__ __volatile__("PPTLB %0, %1\n\t" : "=a" (p) : "a" (paddr)); - if ((p & 0x80000000)) - { - if (infgmap) - *infgmap = 1; - e.at = (p & 0x1fffff); - __asm__ __volatile__("RPTLB0 %0, %1\n\t" : "=a" (e.as) : "a" (p & 0x1f)); - return e; - } - else - { - int i; - if (infgmap) - *infgmap = 0; - for (i = XCHAL_MPU_BACKGROUND_ENTRIES - 1; i > 0; i--) - { - if (XTHAL_MPU_ENTRY_GET_VSTARTADDR(Xthal_mpu_bgmap[i]) <= (unsigned) paddr) - { - return Xthal_mpu_bgmap[i]; - } - } // in background map - return Xthal_mpu_bgmap[0]; - } -#else - xthal_MPU_entry e; - return e; -#endif - } -#endif -/* - * This function is intended as an MPU specific version of - * xthal_set_region_attributes(). xthal_set_region_attributes() calls - * this function for MPU configurations. - * - * This function sets the attributes for the region [vaddr, vaddr+size) - * in the MPU. - * - * Depending on the state of the MPU this function will require from - * 0 to 3 unused MPU entries. - * - * This function typically will move, add, and subtract entries from - * the MPU map during execution, so that the resulting map may - * be quite different than when the function was called. - * - * This function does make the following guarantees: - * 1) The MPU access map remains in a valid state at all times - * during its execution. - * 2) At all points during (and after) completion the memoryType - * and accessRights remain the same for all addresses - * that are not in the range [vaddr, vaddr+size). - * 3) If XTHAL_SUCCESS is returned, then the range - * [vaddr, vaddr+size) will have the accessRights and memoryType - * specified. - * - * The accessRights parameter should be either a 4-bit value corresponding - * to an MPU access mode (as defined by the XTHAL_AR_.. constants), or - * XTHAL_MPU_USE_EXISTING_ACCESS_RIGHTS. - * - * The memoryType parameter should be either a bit-wise or-ing of XTHAL_MEM_.. - * constants that represent a valid MPU memoryType, a 9-bit MPU memoryType - * value, or XTHAL_MPU_USE_EXISTING_MEMORY_TYPE. - * - * In addition to the error codes that xthal_set_region_attribute() - * returns, this function can also return: XTHAL_BAD_ACCESS_RIGHTS - * (if the access rights bits map to an unsupported combination), or - * XTHAL_OUT_OF_ENTRIES (if there are not enough unused MPU entries). - * - * If this function is called with an invalid MPU map, then this function - * will return one of the codes that is returned by xthal_check_map(). - * - * The flag, XTHAL_CAFLAG_EXPAND, is not supported. - * - */ -#if defined(__SPLIT__mpu_attributes) -int xthal_mpu_set_region_attribute(void* vaddr, unsigned size, int accessRights, int memoryType, unsigned flags) -{ -#if XCHAL_HAVE_MPU - unsigned int first; - unsigned int last; - int rv; - - if (flags & XTHAL_CAFLAG_EXPAND) - return XTHAL_UNSUPPORTED; - if (size == 0) - return XTHAL_ZERO_SIZED_REGION; - first = (unsigned) vaddr; - last = first + size; - if (last != 0xFFFFFFFF) - last--; - if (first >= last) - return XTHAL_INVALID_ADDRESS_RANGE; // Wraps around - - if (accessRights & XTHAL_MPU_USE_EXISTING_ACCESS_RIGHTS) - { - accessRights = XTHAL_MPU_ENTRY_GET_ACCESS(xthal_get_entry_for_address(vaddr, 0)); - } - else - { - accessRights = encode_access_rights(accessRights); - if (accessRights < 0) - return XTHAL_BAD_ACCESS_RIGHTS; - } - if (memoryType & XTHAL_MPU_USE_EXISTING_MEMORY_TYPE) - { - memoryType = XTHAL_MPU_ENTRY_GET_MEMORY_TYPE(xthal_get_entry_for_address(vaddr, 0)); - } - else - { - if (memoryType & 0xffffe000) // Tests if any of the XTHAL MEM flags are present - memoryType = xthal_encode_memory_type(memoryType); - else - if (memoryType & 0xfffffe00) // Tests if any of bits from 9 to 13 are set indicating - // that the memoryType was improperly shifted - // we flag this as an error - return XTHAL_BAD_MEMORY_TYPE; - if (memoryType < 0) - return XTHAL_BAD_MEMORY_TYPE; - } - if (flags & XTHAL_CAFLAG_EXACT) - if (!mpu_aligned(first) || !mpu_aligned(last + 1)) - return XTHAL_INEXACT; - - first = mpu_align(first, (flags & XTHAL_CAFLAG_NO_PARTIAL)); - if (last != 0xffffffff) - { - last = mpu_align(last + 1, !(flags & XTHAL_CAFLAG_NO_PARTIAL)); - if (first >= last) - return ((flags & XTHAL_CAFLAG_NO_PARTIAL) ? XTHAL_ZERO_SIZED_REGION : 0); - } - rv = safe_add_region(first, last, accessRights, memoryType, !(flags & XTHAL_CAFLAG_NO_AUTO_WB), - !(flags & XTHAL_CAFLAG_NO_AUTO_INV)); - isync(); - return rv; -#else - return XTHAL_UNSUPPORTED; -#endif -} -#endif - - -#if defined(__SPLIT__mpu_cachedis) - -inline static unsigned int max2(unsigned int a, unsigned int b) - { - if (a>b) - return a; - else - return b; - } - -inline static unsigned int mask_cachedis(unsigned int current, int first_region, - int last_region) - { - unsigned int x; - x = ((1 << (last_region - first_region + 1)) - 1) << first_region; - current &= ~x; - return current; - } - -/* - * xthal_calc_cacheadrdis() computes the value that should be written - * to the CACHEADRDIS register. The return value has bits 0-7 set according as: - * bit n: is zero if any part of the region [512MB * n, 512MB* (n-1)) is cacheable. - * is one if NO part of the region [512MB * n, 512MB* (n-1)) is cacheable. - * - * This function looks at both the loops through both the foreground and background maps - * to find cacheable area. Once one cacheable area is found in a 512MB region, then we - * skip to the next 512MB region. - */ -unsigned int xthal_calc_cacheadrdis(const xthal_MPU_entry* fg, unsigned int num_entries) - { -#if XCHAL_HAVE_MPU - unsigned int cachedis = 0xff; - int fg_index = num_entries - 1; - int bg_index = XCHAL_MPU_BACKGROUND_ENTRIES - 1; - int working_region = 7; - int ending_region; - unsigned int vaddr = 0xffffffff; - while (bg_index >= 0 || fg_index >= 0) - { - if ((fg_index >= 0 && XTHAL_MPU_ENTRY_GET_VALID(fg[fg_index]))) - { - vaddr = XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[fg_index]); - ending_region = vaddr >> 29; - if (ending_region <= working_region) - { - unsigned int mt = XTHAL_MPU_ENTRY_GET_MEMORY_TYPE(fg[fg_index]); - if (is_cacheable(mt)) - { - cachedis = mask_cachedis(cachedis, ending_region, - working_region); - /* Optimize since we have found one cacheable entry in the region ... no need to look for more */ - if (ending_region == 0) - return cachedis; - else - working_region = ending_region - 1; - } - else - if (vaddr & 0x1fffffff) // If vaddr is on a 512MB region we want to move to the next region - working_region = ending_region; - else - working_region = ending_region - 1; - } - } - else if ((bg_index >= 0) - && ((fg_index <= 0) - || XTHAL_MPU_ENTRY_GET_VALID(fg[fg_index-1]))&& vaddr) - { - unsigned int caddr; - unsigned int low_addr = ( - (fg_index >= 0) ? - (XTHAL_MPU_ENTRY_GET_VSTARTADDR(fg[fg_index])) : - 0); - /* First skip any background entries that start after the address of interest */ - while ((caddr = XTHAL_MPU_ENTRY_GET_VSTARTADDR(Xthal_mpu_bgmap[bg_index])) >= vaddr) - bg_index--; - do - { - caddr = max2(XTHAL_MPU_ENTRY_GET_VSTARTADDR(Xthal_mpu_bgmap[bg_index]), - low_addr); - ending_region = caddr >> 29; - if (ending_region <= working_region) - { - unsigned int mt = XTHAL_MPU_ENTRY_GET_MEMORY_TYPE( - Xthal_mpu_bgmap[bg_index]); - if (is_cacheable(mt)) - { - cachedis = mask_cachedis(cachedis, ending_region, - working_region); - /* Optimize since we have found one cacheable entry in the region ... - * no need to look for more */ - if (ending_region == 0) - return cachedis; // we are done - else - working_region = ending_region - 1; - } - else - if (caddr & 0x1fffffff) - working_region = ending_region; - else - working_region = ending_region - 1; - } - bg_index--; - }while (caddr > low_addr); - vaddr = caddr; - } - fg_index--; - if (!vaddr) - break; - } - return cachedis; -#else - return 0; -#endif - } -#endif - -#if defined(__SPLIT__mpu_basic) -void (*_xthal_assert_handler)(); -/* Undocumented internal testing function */ -extern void _xthal_set_assert_handler(void (*handler)()) -{ -#if XCHAL_HAVE_MPU - _xthal_assert_handler = handler; -#endif -} -#endif diff --git a/src/arch/xtensa/hal/mpu_asm.S b/src/arch/xtensa/hal/mpu_asm.S deleted file mode 100644 index a2a544bd354d..000000000000 --- a/src/arch/xtensa/hal/mpu_asm.S +++ /dev/null @@ -1,78 +0,0 @@ -// -// mpu_asm.S - Assembler routine(s) for the MPU -// -// $Id$ - -// Copyright (c) 2015 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/mpuasm.h> - -#if defined(__SPLIT__write_map_raw) ||\ - defined(__SPLIT__write_map_raw_nw) - -/* - void xthal_write_map_raw( const struct xthal_MPU_entry* map, unsigned n); - - Updates the MPU with the MPU entries provided: - map pointer to array of MPU entries - n number of entries in array (0 <= n <= XCHAL_MPU_ENTRIES) - - The entries provided must have monotonically increasing addresses. - This function otherwise orders its updates to ensure the MPU always has - all its entries in monotonically increasing sequence. - - on entry - a2 => vector of MPU entries to write - a3 => number of entries to write - a4-a7 => destroyed -*/ - -DECLFUNC (xthal_write_map_raw) - abi_entry - mpu_write_map a2, a3, a4, a5, a6, a7 - abi_return - endfunc - -#endif - -/* - void xthal_read_map_raw(struct xthal_MPU_entry* map); - - Reads the current map from the MPU and puts it the vector - pointed to by map. - - a2 => vector of MPU entries where the current MPU state is copied - a3-a4 => destroyed -*/ - -#if defined(__SPLIT__read_map_raw) ||\ - defined(__SPLIT__read_map_raw_nw) - -DECLFUNC (xthal_read_map_raw) - abi_entry - mpu_read_map a2, a3, a4 - abi_return - endfunc - -#endif - diff --git a/src/arch/xtensa/hal/set_region_translate.c b/src/arch/xtensa/hal/set_region_translate.c deleted file mode 100644 index 27ed6b80a50b..000000000000 --- a/src/arch/xtensa/hal/set_region_translate.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright (c) 2004-2014 Tensilica 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. - */ -#include <xtensa/config/core.h> - -#if XCHAL_HAVE_XEA2 && (!XCHAL_HAVE_MPU) -/* - * C-stubs to issue the tlb related instructions (with dsync and isync's if needed). - * - */ -static inline void write_dtlb_entry(unsigned vpn_way, unsigned ppn_ca) { - __asm__ __volatile__("wdtlb %1, %0; dsync\n\t" - : : "r" (vpn_way), "r" (ppn_ca) ); -} - -static inline void write_itlb_entry(unsigned vpn_way, unsigned ppn_ca) { - __asm__ __volatile__("witlb %1, %0; isync\n\t" - : : "r" (vpn_way), "r" (ppn_ca) ); -} - -static inline unsigned read_dtlb1_entry(unsigned addr) { - unsigned long tmp; - __asm__ __volatile__("rdtlb1 %0, %1\n\t" - : "=a" (tmp) - : "a" (addr)); - return tmp; -} - -static inline unsigned read_itlb1_entry(unsigned addr) { - unsigned long tmp; - __asm__ __volatile__("ritlb1 %0, %1\n\t" - : "=a" (tmp) - : "a" (addr)); - return tmp; -} - -static inline unsigned probe_dtlb(unsigned addr) { - unsigned long tmp; - __asm__ __volatile__("pdtlb %0, %1\n\t" - : "=a" (tmp) - : "a" (addr)); - return tmp; -} - -static inline unsigned probe_itlb(unsigned addr) { - unsigned long tmp; - __asm__ __volatile__("pitlb %0, %1\n\t" - : "=a" (tmp) - : "a" (addr)); - return tmp; -} - -static inline void invalidate_dtlb_entry(unsigned addr) { - __asm__ __volatile__("idtlb %0; dsync \n\t" - : : "a" (addr)); -} - -static inline void invalidate_itlb_entry(unsigned addr) { - __asm__ __volatile__("iitlb %0 ; isync\n\t" - : : "a" (addr)); -} - -static inline unsigned read_dtlbcfg() { - unsigned long tmp; - __asm__ __volatile__("rsr.dtlbcfg %0\n\t" - : "=a" (tmp)); - return tmp; -} - -static inline unsigned read_itlbcfg() { - unsigned long tmp; - __asm__ __volatile__("rsr.itlbcfg %0\n\t" - : "=a" (tmp)); - return tmp; -} - -#endif - -/* - * xthal_set_region_translation_raw is a quick and simple function - * to set both physical address <paddr> and cache attribute <cattr> for - * a 512MB region at <vaddr>. - * - * Parameters: - * void* vaddr 512MB aligned pointer representing the start of virtual address region - * void* paddr 512MB aligned pointer representing the start of physical address region - * unsigned cattr 4 bit value encoding the caching properties and rights (MMU only). - * - * returns 0 (XCHAL_SUCCESS) if successful - * returns non zero (XCHAL_UNSUPPORTED) on failure - * - * This function has the following limitations: - * - * 1) Requires either the Region Translation Option or a v3 MMU running in the default mode (with spanning way) - * 2) It does no error checking. - * 3) Deals with one 512MB region (vaddr and paddr are required to be 512MB aligned although that is not explicitly checked) - * 4) It requires the caller to do any cache flushing that is needed - * 5) Doesn't support mnemonically setting the 'rights' (rwx, rw, ... ) bit on the MMU - * 6) It is illegal to change the mapping of the region containing the current PC (not checked) - * - */ -int xthal_set_region_translation_raw(void *vaddr, void *paddr, unsigned cattr) { -#if XCHAL_HAVE_MPU - return XTHAL_UNSUPPORTED; -#else -#if XCHAL_HAVE_XEA2 -#if XCHAL_HAVE_XLT_CACHEATTR || (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY) -# if XCHAL_HAVE_XLT_CACHEATTR - unsigned vpn_way = (unsigned)vaddr; -# else - unsigned vpn_way = ((unsigned) vaddr & 0xFFFFFFF0) + XCHAL_SPANNING_WAY; -# endif - unsigned ppn_ca = ((unsigned) paddr & 0xFFFFFFF0) + (cattr & 0xF); - write_dtlb_entry(vpn_way, ppn_ca); - write_itlb_entry(vpn_way, ppn_ca); - return XTHAL_SUCCESS; -#else - return XTHAL_UNSUPPORTED; -#endif -#else - return XTHAL_UNSUPPORTED; -#endif -#endif -} - -/* - * xthal_v2p() takes a virtual address as input, and if that virtual address is mapped to a physical address - * by the MMU, it returns the: - * a) corresponding physical address - * b) the tlb way that is used to translate the address - * c) cache attribute for translation - * - * Parameters: - * void* vaddr A pointer representing the virtual address (there are no alignment requirements for this address) - * void** paddr This value can be 0, or can point to a pointer variable which will be updated to contain the physical address - * unsigned* way This value can be 0, or can point to an unsigned variable which will be updated to contain the TLB way. - * unsigned* cattr This value can be 0, or can point to an unsigned variable which will be updated to contain the cache attr - * For MPU configurations bits 0..3 hold the access rights and bits 4..8 hold the encoded memory type - * - * Returns 0 (XCHAL_SUCCESS) if successful - * XTHAL_NO_MAPPING if there is no current mapping for the virtual address - * XCHAL_UNSUPPORTED if unsupported - * - * Limitations: - * Assumes that architecture variable DVARWAY56 is "Variable" - * Uses the D-TLBS for the translation ... assumption is that ITLB's have same mappings - */ -int xthal_v2p(void* vaddr, void** paddr, unsigned *way, unsigned* cattr) { -#if XCHAL_HAVE_XEA2 -#if XCHAL_HAVE_MPU - if (paddr) - *paddr = vaddr; - if (way) - *way = 0; - if (cattr) - { - struct xthal_MPU_entry x = xthal_get_entry_for_address(vaddr, 0); - *cattr = XTHAL_MPU_ENTRY_GET_ACCESS(x) | XTHAL_MPU_ENTRY_GET_MEMORY_TYPE(x) << XTHAL_AR_WIDTH; - } - return XTHAL_SUCCESS; -#else - unsigned long probe = probe_dtlb((unsigned) vaddr); -#if !XCHAL_HAVE_PTP_MMU - if (!(0x1 & probe)) - return XTHAL_NO_MAPPING; - if (way) - *way = 1; - if (paddr || cattr) { - unsigned long temp; - temp = read_dtlb1_entry(probe); - unsigned ppn = 0xe0000000 & temp; - unsigned att = 0xf & temp; - if (paddr) - *paddr = ((void*) (ppn + (((unsigned) vaddr) & 0x1fffffff))); - if (cattr) - *cattr = att; - } -#else - { - unsigned iway; - if (!(0x10 & probe)) - return XTHAL_NO_MAPPING; - iway = 0xf & probe; - if (way) - *way = iway; - if (paddr || cattr) { - unsigned temp; - unsigned ppn; - unsigned ppn1; - unsigned dtlbcfg = read_dtlbcfg(); - temp = read_dtlb1_entry(probe); - unsigned att = 0xf & temp; - if (cattr) - *cattr = att; - if (paddr) - switch (iway) // followin code derived from fig 4-40 from ISA MMU Option Data (at) Format for RxTLB1 - { /* 4k pages */ - case 0: - case 1: - case 2: - case 3: - case 7: - case 8: - case 9: - ppn = 0xfffff000; // 4k pages - break; - case 4: { - switch ((dtlbcfg & (0x3 << 16)) >> 16) // bits 16 & 17 - { - case 0: // 1MB pages - ppn = 0xfff00000; - break; - case 1: // 4MB pages - ppn = 0xffc00000; - break; - case 2: // 16MB pages - ppn = 0xff000000; - break; - case 3: // 64MB pages - ppn = 0xfc000000; - break; - default: - return XTHAL_UNSUPPORTED; - } - } - break; - case 5: - if ((dtlbcfg & (1 << 20))) - ppn = 0xf8000000; // 128MB pages - else - ppn = 0xf0000000; // 256MB pages - break; - case 6: - if ((dtlbcfg & (1 << 24))) - ppn = 0xe0000000; // 512MB pages - else - ppn = 0xf0000000; // 256MB pages - break; - default: - return XTHAL_UNSUPPORTED; - break; - } - ppn1 = ppn & temp; - *paddr = ((void*) (ppn1 + (((unsigned) vaddr) & (~ppn)))); - } - } -#endif - return XTHAL_SUCCESS; -#endif -#else - return XTHAL_UNSUPPORTED; -#endif -} - -/* these constants borrowed from xthal_set_region_attribute */ -# if XCHAL_HAVE_PTP_MMU -# define CA_BYPASS XCHAL_CA_BYPASS -# define CA_WRITETHRU XCHAL_CA_WRITETHRU -# define CA_WRITEBACK XCHAL_CA_WRITEBACK -# define CA_WRITEBACK_NOALLOC XCHAL_CA_WRITEBACK_NOALLOC -# define CA_ILLEGAL XCHAL_CA_ILLEGAL -# else -/* Hardcode these, because they get remapped when caches or writeback not configured: */ -# define CA_BYPASS 2 -# define CA_WRITETHRU 1 -# define CA_WRITEBACK 4 -# define CA_WRITEBACK_NOALLOC 5 -# define CA_ILLEGAL 15 -# endif - -/* internal function that returns 1 if the supplied attr indicates the - * cache is in writeback mode. - */ -static inline int is_writeback(unsigned attr) { -#if XCHAL_HAVE_XLT_CACHEATTR - return attr == CA_WRITEBACK || attr == CA_WRITEBACK_NOALLOC; -#endif -#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY - return (attr | 0x3) == CA_WRITEBACK; -#endif - return -1; /* unsupported */ -} - -/* - * xthal_set_region_translation() - * - * Establishes a new mapping (with the supplied cache attributes) - * between a virtual address region, and a physical address region. - * - * This function is only supported with following processor configurations: - * a) Region Translation - * b) v3 MMU with a spanning way running in the default mode - * - * If the specified memory range exactly covers a series - * of consecutive 512 MB regions, the address mapping and cache - * attributes of these regions are updated. - * - * If this is not the case, e.g. if either or both the - * start and end of the range only partially cover a 512 MB - * region, one of three results are possible: - * - * 1. By default, the cache attribute of all regions - * covered, even just partially, is changed to - * the requested attribute. - * - * 2. If the XTHAL_CAFLAG_EXACT flag is specified, - * a non-zero error code is returned. - * - * 3. If the XTHAL_CAFLAG_NO_PARTIAL flag is specified - * (but not the EXACT flag), only regions fully - * covered by the specified range are updated with - * the requested attribute. - * - * CACHE HANDLING - * - * This function automatically writes back dirty data before remapping a - * virtual address region. - * - * This writeback is done safely, ie. by first switching to writethrough - * mode, and then invoking xthal_dcache_all_writeback(). Such a sequence is - * necessary to ensure there is no longer any dirty data in the memory region by the time - * this function returns, even in the presence of interrupts, speculation, etc. - * This automatic write-back can be disabled using the XTHAL_CAFLAG_NO_AUTO_WB flag. - * - * This function also invalidates the caches after remapping a region because the - * cache could contain (now invalid) data from the previous mapping. - * This automatic invalidate can be disabled using the XTHAL_CAFLAG_NO_AUTO_INV flag. - * - * Parameters: - * vaddr starting virtual address of region of memory - * - * paddr starting physical address for the mapping (this should be 512MB aligned to vaddr such that ((vaddr ^ paddr) & 0x10000000 == 0) - * - * size number of bytes in region of memory - * (see above, SPECIFYING THE MEMORY REGION) - * - * cattr cache attribute (encoded); - * typically taken from compile-time HAL constants - * XCHAL_CA_{BYPASS, WRITETHRU, WRITEBACK[_NOALLOC], ILLEGAL} - * (defined in <xtensa/config/core.h>); - * in XEA1, this corresponds to the value of a nibble - * in the CACHEATTR register; - * in XEA2, this corresponds to the value of the - * cache attribute (CA) field of each TLB entry - * - * flags bitwise combination of flags XTHAL_CAFLAG_* - * - * XTHAL_CAFLAG_EXACT - If this flag is present, - * the mapping will only be done if the specified - * region exactly matches on or more 512MB pages otherwise - * XCHAL_INEXACT is returned (and no mapping is done). - * - * XTHAL_CAFLAG_NO_PARTIAL - If this flag is specified, then - * only pages that are completely covered by the specified region - * are affected. If this flag is specified, and no pages are completely - * covered by the region, then no pages are affected and XCHAL_NO_REGIONS_COVERED - * is returned. - * - * - * - * Returns: - * XCHAL_SUCCESS - successful, or size is zero - * - * XCHAL_NO_REGIONS_COVERED - XTHAL_CAFLAG_NO_PARTIAL flag specified and address range - * is valid with a non-zero size, however no 512 MB region (or page) - * is completely covered by the range - * - * XCHAL_INEXACT XTHAL_CAFLAG_EXACT flag specified, and address range does - * not exactly specify a 512 MB region (or page) - * - * XCHAL_INVALID_ADDRESS invalid address range specified (wraps around the end of memory) - * - * XCHAL_ADDRESS_MISALIGNED virtual and physical addresses are not aligned (512MB) - * - * - * XCHAL_UNSUPPORTED_ON_THIS_ARCH function not supported in this processor configuration - */ -int xthal_set_region_translation(void* vaddr, void* paddr, unsigned size, - unsigned cattr, unsigned flags) { -#if XCHAL_HAVE_XEA2 & !XCHAL_HAVE_MPU -#if XCHAL_HAVE_XLT_CACHEATTR || (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY) - const unsigned CA_MASK = 0xF; - const unsigned addr_mask = 0x1fffffff; - const unsigned addr_shift = 29; - unsigned vaddr_a = (unsigned) vaddr; - unsigned paddr_a = (unsigned) paddr; - unsigned end_vaddr; - unsigned end_paddr; - unsigned start_va_reg; - unsigned end_va_reg; - unsigned start_pa_reg; - unsigned icache_attr = 0; - int rv; - int i; - if (size == 0) - return XTHAL_SUCCESS; - if ((vaddr_a & addr_mask) ^ (paddr_a & addr_mask)) - return XTHAL_ADDRESS_MISALIGNED; - icache_attr = cattr & CA_MASK; -#if (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY) - // if using the mmu in spanning way mode then 'and in' the R, RX, RW, RWX bits - if ((cattr & 0x40000000) && (icache_attr < 12)) - icache_attr = icache_attr & ((cattr & 0xF0) >> 4); -#endif - end_vaddr = vaddr_a + size - 1; - end_paddr = paddr_a + size - 1; - - if ((end_vaddr < vaddr_a) || (end_paddr < paddr_a)) - return XTHAL_INVALID_ADDRESS; - start_va_reg = vaddr_a >> addr_shift; - end_va_reg = end_vaddr >> addr_shift; - start_pa_reg = paddr_a >> addr_shift; - if ((flags & XTHAL_CAFLAG_EXACT) - && ((size & addr_mask) || (vaddr_a & addr_mask) - || (paddr_a & addr_mask))) - return XTHAL_INEXACT; - if (flags & XTHAL_CAFLAG_NO_PARTIAL) { - if (vaddr_a & addr_mask) { - start_va_reg++; - start_pa_reg++; - } - if ((end_vaddr & addr_mask) != addr_mask) - end_va_reg--; - } - if (end_va_reg < start_va_reg) - return XTHAL_NO_REGIONS_COVERED; - /* - * Now we need to take care of any uncommitted cache writes in the affected regions - * 1) first determine if any regions are in write back mode - * 2) change those pages to write through - * 3) force the writeback of d-cache by calling xthal_dcach_all_writeback() - */ -#if ((XCHAL_DCACHE_SIZE >0) && XCHAL_DCACHE_IS_WRITEBACK) - if (!(flags & XTHAL_CAFLAG_NO_AUTO_WB)) { - unsigned old_cache_attr = xthal_get_cacheattr(); - unsigned cachewrtr = old_cache_attr; - unsigned need_safe_writeback = 0; - for (i = start_va_reg; i <= end_va_reg; i++) { - unsigned sh = i << 2; - unsigned old_attr = (old_cache_attr >> sh) & CA_MASK; - if (is_writeback(old_attr)) { - need_safe_writeback = 1; - cachewrtr = (cachewrtr & ~(CA_MASK << sh)) - | (CA_WRITETHRU << sh); - } - } - - if (need_safe_writeback) { - xthal_set_cacheattr(cachewrtr); /* set to writethru first, to safely writeback any dirty data */ - xthal_dcache_all_writeback(); /* much quicker than scanning entire 512MB region(s) */ - } - } -#endif - /* Now we set the affected region translations */ - for (i = start_va_reg; i <= end_va_reg; i++) { - if ((rv = xthal_set_region_translation_raw( - (void*) ((start_va_reg++) << addr_shift), - (void*) ((start_pa_reg++) << addr_shift), icache_attr))) - return rv; - } - - /* - * Now we need to invalidate the cache in the affected regions. For now invalidate entire cache, - * but investigate if there are faster alternatives on some architectures. - */ - if (!(flags & XTHAL_CAFLAG_NO_AUTO_INV)) { -# if XCHAL_DCACHE_SIZE > 0 - xthal_dcache_all_writeback_inv(); /* some areas in memory (outside the intended region) may have uncommitted - data so we need the writeback_inv(). */ -#endif -#if XCHAL_ICACHE_SIZE >0 - xthal_icache_all_invalidate(); -#endif - } - return XTHAL_SUCCESS; -#else - return XTHAL_UNSUPPORTED; -#endif -#else - return XTHAL_UNSUPPORTED; -#endif -} - -/* xthal_invalidate_region() - * invalidates the tlb entry for the specified region. - * - * This function is only supported on processor configurations - * with a v3 MMU with a spanning way. - * - * Parameter - * vaddr - virtual address of region to invalidate (512MB aligned) - * - * returns: - * XCHAL_SUCCESS - Success - * XCHAL_UNSUPPORTED_ON_THIS_ARCH - Unsupported - * - */ -int xthal_invalidate_region(void* vaddr) { -#if XCHAL_HAVE_XEA2 & !XCHAL_HAVE_MPU -#if (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY) - unsigned addr = (unsigned) vaddr; - if (addr & 0x1fffffff) - return XTHAL_INVALID_ADDRESS; - addr += XCHAL_SPANNING_WAY; - invalidate_dtlb_entry(addr); - invalidate_itlb_entry(addr); - return XTHAL_SUCCESS; -#else - return XTHAL_UNSUPPORTED; -#endif -#else - return XTHAL_UNSUPPORTED; -#endif -} - diff --git a/src/arch/xtensa/hal/state.c b/src/arch/xtensa/hal/state.c deleted file mode 100644 index 316ddb4e8298..000000000000 --- a/src/arch/xtensa/hal/state.c +++ /dev/null @@ -1,321 +0,0 @@ -// -// processor_state.c - processor state management routines -// - -// Copyright (c) 2005-2010 Tensilica 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. - -#include <xtensa/hal.h> -#include <xtensa/config/core.h> - - -//---------------------------------------------------------------------- - -#if defined(__SPLIT__extra_size) -// space for "extra" (user special registers and non-coprocessor TIE) state: -const unsigned int Xthal_extra_size = XCHAL_NCP_SA_SIZE; - -#elif defined(__SPLIT__extra_align) -const unsigned int Xthal_extra_align = XCHAL_NCP_SA_ALIGN; - -#elif defined(__SPLIT__cpregs_size) -// space for state of TIE coprocessors: -const unsigned int Xthal_cpregs_size[8] = - { - XCHAL_CP0_SA_SIZE, - XCHAL_CP1_SA_SIZE, - XCHAL_CP2_SA_SIZE, - XCHAL_CP3_SA_SIZE, - XCHAL_CP4_SA_SIZE, - XCHAL_CP5_SA_SIZE, - XCHAL_CP6_SA_SIZE, - XCHAL_CP7_SA_SIZE - }; - -#elif defined(__SPLIT__cpregs_align) -const unsigned int Xthal_cpregs_align[8] = - { - XCHAL_CP0_SA_ALIGN, - XCHAL_CP1_SA_ALIGN, - XCHAL_CP2_SA_ALIGN, - XCHAL_CP3_SA_ALIGN, - XCHAL_CP4_SA_ALIGN, - XCHAL_CP5_SA_ALIGN, - XCHAL_CP6_SA_ALIGN, - XCHAL_CP7_SA_ALIGN - }; - -#elif defined(__SPLIT__cp_names) -const char * const Xthal_cp_names[8] = - { - XCHAL_CP0_NAME, - XCHAL_CP1_NAME, - XCHAL_CP2_NAME, - XCHAL_CP3_NAME, - XCHAL_CP4_NAME, - XCHAL_CP5_NAME, - XCHAL_CP6_NAME, - XCHAL_CP7_NAME - }; - -#elif defined(__SPLIT__all_extra_size) -// total save area size (extra + all coprocessors + min 16-byte alignment everywhere) -const unsigned int Xthal_all_extra_size = XCHAL_TOTAL_SA_SIZE; - -#elif defined(__SPLIT__all_extra_align) -// maximum required alignment for the total save area (this might be useful): -const unsigned int Xthal_all_extra_align = XCHAL_TOTAL_SA_ALIGN; - -#elif defined(__SPLIT__num_coprocessors) -// number of coprocessors starting contiguously from zero -// (same as Xthal_cp_max, but included for Tornado2): -const unsigned int Xthal_num_coprocessors = XCHAL_CP_MAX; - -#elif defined(__SPLIT__cp_num) -// actual number of coprocessors: -const unsigned char Xthal_cp_num = XCHAL_CP_NUM; - -#elif defined(__SPLIT__cp_max) -// index of highest numbered coprocessor, plus one: -const unsigned char Xthal_cp_max = XCHAL_CP_MAX; - -// index of highest allowed coprocessor number, per cfg, plus one: -//const unsigned char Xthal_cp_maxcfg = XCHAL_CP_MAXCFG; - -#elif defined(__SPLIT__cp_mask) -// bitmask of which coprocessors are present: -const unsigned int Xthal_cp_mask = XCHAL_CP_MASK; - -#elif defined(__SPLIT__cp_id_mappings) -// Coprocessor ID from its name - -# ifdef XCHAL_CP0_IDENT -const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP0_IDENT) = 0; -# endif -# ifdef XCHAL_CP1_IDENT -const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP1_IDENT) = 1; -# endif -# ifdef XCHAL_CP2_IDENT -const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP2_IDENT) = 2; -# endif -# ifdef XCHAL_CP3_IDENT -const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP3_IDENT) = 3; -# endif -# ifdef XCHAL_CP4_IDENT -const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP4_IDENT) = 4; -# endif -# ifdef XCHAL_CP5_IDENT -const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP5_IDENT) = 5; -# endif -# ifdef XCHAL_CP6_IDENT -const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP6_IDENT) = 6; -# endif -# ifdef XCHAL_CP7_IDENT -const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP7_IDENT) = 7; -# endif - -#elif defined(__SPLIT__cp_mask_mappings) -// Coprocessor "mask" (1 << ID) from its name - -# ifdef XCHAL_CP0_IDENT -const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP0_IDENT) = (1 << 0); -# endif -# ifdef XCHAL_CP1_IDENT -const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP1_IDENT) = (1 << 1); -# endif -# ifdef XCHAL_CP2_IDENT -const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP2_IDENT) = (1 << 2); -# endif -# ifdef XCHAL_CP3_IDENT -const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP3_IDENT) = (1 << 3); -# endif -# ifdef XCHAL_CP4_IDENT -const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP4_IDENT) = (1 << 4); -# endif -# ifdef XCHAL_CP5_IDENT -const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP5_IDENT) = (1 << 5); -# endif -# ifdef XCHAL_CP6_IDENT -const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP6_IDENT) = (1 << 6); -# endif -# ifdef XCHAL_CP7_IDENT -const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP7_IDENT) = (1 << 7); -# endif - -//---------------------------------------------------------------------- - -#elif defined(__SPLIT__init_mem_extra) -// CMS: I have made the assumptions that 0's are safe initial -// values. That may be wrong at some point. -// -// initialize the extra processor -void -xthal_init_mem_extra(void *address) -/* not clear that it is safe to call memcpy and also not clear - that performance is important. */ -{ - unsigned int *ptr; - unsigned int *end; - - ptr = (unsigned int *)address; - end = (unsigned int *)((int)address + XCHAL_NCP_SA_SIZE); - while( ptr < end ) - { - *ptr++ = 0; - } -} - -#elif defined(__SPLIT__init_mem_cp) -// initialize the TIE coprocessor -void -xthal_init_mem_cp(void *address, int cp) -{ - unsigned int *ptr; - unsigned int *end; - - if( cp <= 7 ) - { - end = (unsigned int *)((int)address + Xthal_cpregs_size[cp]); - ptr = (unsigned int *)address; - while( ptr < end ) - { - *ptr++ = 0; - } - } -} - -#endif /*splitting*/ - - -/* Nothing implemented below this point. */ -/************************************************************************/ - -// save all extra+cp processor state (NOT IMPLEMENTED) -/*void xthal_save_all_extra(void *base) -{ - xthal_save_extra(base); - ... here we need to iterate over configured coprocessor register files ... -// xthal_save_cpregs(base+XCHAL_NCP_SA_SIZE, 0); -}*/ - -// restore all extra+cp processor state (NOT IMPLEMENTED) -/*void xthal_restore_all_extra(void *base) -{ - xthal_restore_extra(base); - ... here we need to iterate over configured coprocessor register files ... -// xthal_restore_cpregs(base+XCHAL_NCP_SA_SIZE, 0); -}*/ - - -// initialize the extra processor (NOT IMPLEMENTED) -/*void xthal_init_extra() -{ -}*/ - -// initialize the TIE coprocessor (NOT IMPLEMENTED) -/*void xthal_init_cp(int cp) -{ -}*/ - - -#if 0 - -/* read extra state register (NOT IMPLEMENTED) */ -int xthal_read_extra(void *base, unsigned reg, unsigned *value) -{ - if (reg&0x1000) { - switch(reg) { -#if XCHAL_HAVE_MAC16 - case 16: - *value = ((unsigned *)base)[0]; - return reg; - case 17: - *value = ((unsigned *)base)[1]; - return reg; - case 32: - *value = ((unsigned *)base)[2]; - return reg; - case 33: - *value = ((unsigned *)base)[3]; - return reg; - case 34: - *value = ((unsigned *)base)[4]; - return reg; - case 35: - *value = ((unsigned *)base)[5]; - return reg; -#endif /* XCHAL_HAVE_MAC16 */ - } - } - return -1; -} - -/* write extra state register (NOT IMPLEMENTED) */ -int xthal_write_extra(void *base, unsigned reg, unsigned value) -{ - if (reg&0x1000) { - switch(reg) { -#if XCHAL_HAVE_MAC16 - case 16: - ((unsigned *)base)[0] = value; - return reg; - case 17: - ((unsigned *)base)[1] = value; - return reg; - case 32: - ((unsigned *)base)[2] = value; - return reg; - case 33: - ((unsigned *)base)[3] = value; - return reg; - case 34: - ((unsigned *)base)[4] = value; - return reg; - case 35: - ((unsigned *)base)[5] = value; - return reg; -#endif /* XCHAL_HAVE_MAC16 */ - } - } - return -1; -} - -#endif /*0*/ - - -/* read TIE coprocessor register (NOT IMPLEMENTED) */ -/*int xthal_read_cpreg(void *base, int cp, unsigned reg, unsigned *value) -{ - return -1; -}*/ - -/* write TIE coproessor register (NOT IMPLEMENTED) */ -/*int xthal_write_cpreg(void *base, int cp, unsigned reg, unsigned value) -{ - return -1; -}*/ - -/* return coprocessor number based on register (NOT IMPLEMENTED) */ -/*int xthal_which_cp(unsigned reg) -{ - return -1; -}*/ - diff --git a/src/arch/xtensa/hal/state_asm.S b/src/arch/xtensa/hal/state_asm.S deleted file mode 100644 index 108986228584..000000000000 --- a/src/arch/xtensa/hal/state_asm.S +++ /dev/null @@ -1,433 +0,0 @@ -/* - * state_asm.S - assembly language processor management routines - */ - -/* - * Copyright (c) 2005-2010 Tensilica 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. - */ - -#include <xtensa/coreasm.h> - - .text - -//---------------------------------------------------------------------- -// save the extra processor state. -//---------------------------------------------------------------------- - -#if defined(__SPLIT__save_extra) ||\ - defined(__SPLIT__save_extra_nw) - -// void xthal_save_extra(void *base) - -DECLFUNC(xthal_save_extra) - abi_entry - xchal_extra_store_funcbody - abi_return - endfunc - - -//---------------------------------------------------------------------- -// restore the extra processor state. -//---------------------------------------------------------------------- - -#elif defined(__SPLIT__restore_extra) ||\ - defined(__SPLIT__restore_extra_nw) - -// void xthal_restore_extra(void *base) - -DECLFUNC(xthal_restore_extra) - abi_entry - xchal_extra_load_funcbody - abi_return - endfunc - -//---------------------------------------------------------------------- -// save the TIE COPROCESSORS state -//---------------------------------------------------------------------- - -#elif defined(__SPLIT__save_cpregs) ||\ - defined(__SPLIT__save_cpregs_nw) - -// void xthal_save_cpregs(void *base, int) -DECLFUNC(xthal_save_cpregs) - abi_entry - xchal_cpi_store_funcbody - abi_return - endfunc -#elif defined(__SPLIT__save_cp0) ||\ - defined(__SPLIT__save_cp0_nw) -// void xthal_save_cp0(void *base) -DECLFUNC(xthal_save_cp0) - abi_entry - xchal_cp0_store_a2 - abi_return - endfunc -#elif defined(__SPLIT__save_cp1) ||\ - defined(__SPLIT__save_cp1_nw) -// void xthal_save_cp1(void *base) -DECLFUNC(xthal_save_cp1) - abi_entry - xchal_cp1_store_a2 - abi_return - endfunc -#elif defined(__SPLIT__save_cp2) ||\ - defined(__SPLIT__save_cp2_nw) -// void xthal_save_cp2(void *base) -DECLFUNC(xthal_save_cp2) - abi_entry - xchal_cp2_store_a2 - abi_return - endfunc -#elif defined(__SPLIT__save_cp3) ||\ - defined(__SPLIT__save_cp3_nw) -// void xthal_save_cp3(void *base) -DECLFUNC(xthal_save_cp3) - abi_entry - xchal_cp3_store_a2 - abi_return - endfunc -#elif defined(__SPLIT__save_cp4) ||\ - defined(__SPLIT__save_cp4_nw) -// void xthal_save_cp4(void *base) -DECLFUNC(xthal_save_cp4) - abi_entry - xchal_cp4_store_a2 - abi_return - endfunc -#elif defined(__SPLIT__save_cp5) ||\ - defined(__SPLIT__save_cp5_nw) -// void xthal_save_cp5(void *base) -DECLFUNC(xthal_save_cp5) - abi_entry - xchal_cp5_store_a2 - abi_return - endfunc -#elif defined(__SPLIT__save_cp6) || \ - defined(__SPLIT__save_cp6_nw) -// void xthal_save_cp6(void *base) -DECLFUNC(xthal_save_cp6) - abi_entry - xchal_cp6_store_a2 - abi_return - endfunc -#elif defined(__SPLIT__save_cp7) ||\ - defined(__SPLIT__save_cp7_nw) -// void xthal_save_cp7(void *base) -DECLFUNC(xthal_save_cp7) - abi_entry - xchal_cp7_store_a2 - abi_return - endfunc - -//---------------------------------------------------------------------- -// restore the TIE coprocessor state -//---------------------------------------------------------------------- - -#elif defined(__SPLIT__restore_cpregs) ||\ - defined(__SPLIT__restore_cpregs_nw) - -// void xthal_restore_cpregs(void *base, int) - -DECLFUNC(xthal_restore_cpregs) - abi_entry - xchal_cpi_load_funcbody - abi_return - endfunc -#elif defined(__SPLIT__restore_cp0) ||\ - defined(__SPLIT__restore_cp0_nw) -// void xthal_restore_cp0(void *base) -DECLFUNC(xthal_restore_cp0) - abi_entry - xchal_cp0_load_a2 - abi_return - endfunc -#elif defined(__SPLIT__restore_cp1) ||\ - defined(__SPLIT__restore_cp1_nw) -// void xthal_restore_cp1(void *base) -DECLFUNC(xthal_restore_cp1) - abi_entry - xchal_cp1_load_a2 - abi_return - endfunc -#elif defined(__SPLIT__restore_cp2) ||\ - defined(__SPLIT__restore_cp2_nw) -// void xthal_restore_cp2(void *base) -DECLFUNC(xthal_restore_cp2) - abi_entry - xchal_cp2_load_a2 - abi_return - endfunc -#elif defined(__SPLIT__restore_cp3) || \ - defined(__SPLIT__restore_cp3_nw) -// void xthal_restore_cp3(void *base) -DECLFUNC(xthal_restore_cp3) - abi_entry - xchal_cp3_load_a2 - abi_return - endfunc -#elif defined(__SPLIT__restore_cp4) || \ - defined(__SPLIT__restore_cp4_nw) -// void xthal_restore_cp4(void *base) -DECLFUNC(xthal_restore_cp4) - abi_entry - xchal_cp4_load_a2 - abi_return - endfunc -#elif defined(__SPLIT__restore_cp5) || \ - defined(__SPLIT__restore_cp5_nw) -// void xthal_restore_cp5(void *base) -DECLFUNC(xthal_restore_cp5) - abi_entry - xchal_cp5_load_a2 - abi_return - endfunc -#elif defined(__SPLIT__restore_cp6) || \ - defined(__SPLIT__restore_cp6_nw) -// void xthal_restore_cp6(void *base) -DECLFUNC(xthal_restore_cp6) - abi_entry - xchal_cp6_load_a2 - abi_return - endfunc -#elif defined(__SPLIT__restore_cp7) || \ - defined(__SPLIT__restore_cp7_nw) -// void xthal_restore_cp7(void *base) -DECLFUNC(xthal_restore_cp7) - abi_entry - xchal_cp7_load_a2 - abi_return - endfunc - -#elif defined(__SPLIT__cpregs_save_fn) - .section .rodata, "a" -_SYM(Xthal_cpregs_save_fn) -# ifdef __XTENSA_CALL0_ABI__ -_SYM(Xthal_cpregs_save_nw_fn) -# endif - .long xthal_save_cp0 - .long xthal_save_cp1 - .long xthal_save_cp2 - .long xthal_save_cp3 - .long xthal_save_cp4 - .long xthal_save_cp5 - .long xthal_save_cp6 - .long xthal_save_cp7 - endfunc - .text - -#elif defined(__SPLIT__cpregs_save_nw_fn) -# ifndef __XTENSA_CALL0_ABI__ - .section .rodata, "a" -_SYM(Xthal_cpregs_save_nw_fn) - .long xthal_save_cp0_nw - .long xthal_save_cp1_nw - .long xthal_save_cp2_nw - .long xthal_save_cp3_nw - .long xthal_save_cp4_nw - .long xthal_save_cp5_nw - .long xthal_save_cp6_nw - .long xthal_save_cp7_nw - endfunc - .text -# endif - -#elif defined(__SPLIT__cpregs_restore_fn) - .section .rodata, "a" -_SYM(Xthal_cpregs_restore_fn) -# ifdef __XTENSA_CALL0_ABI__ -_SYM(Xthal_cpregs_restore_nw_fn) -# endif - .long xthal_restore_cp0 - .long xthal_restore_cp1 - .long xthal_restore_cp2 - .long xthal_restore_cp3 - .long xthal_restore_cp4 - .long xthal_restore_cp5 - .long xthal_restore_cp6 - .long xthal_restore_cp7 - endfunc - .text - -#elif defined(__SPLIT__cpregs_restore_nw_fn) -# ifndef __XTENSA_CALL0_ABI__ - .section .rodata, "a" -_SYM(Xthal_cpregs_restore_nw_fn) - .long xthal_restore_cp0_nw - .long xthal_restore_cp1_nw - .long xthal_restore_cp2_nw - .long xthal_restore_cp3_nw - .long xthal_restore_cp4_nw - .long xthal_restore_cp5_nw - .long xthal_restore_cp6_nw - .long xthal_restore_cp7_nw - endfunc - .text -# endif - - -//---------------------------------------------------------------------- -// coprocessor enable/disable -//---------------------------------------------------------------------- - -#elif defined(__SPLIT__validate_cp) ||\ - defined(__SPLIT__validate_cp_nw) - -// validate the register file. -// void xthal_validate_cp(int) - -DECLFUNC(xthal_validate_cp) - abi_entry -#if XCHAL_HAVE_CP - rsr.cpenable a3 - movi a4, 1 - ssl a2 - sll a4, a4 - or a3, a3, a4 - wsr.cpenable a3 -#endif - abi_return - endfunc - -#elif defined(__SPLIT__invalidate_cp) || \ - defined(__SPLIT__invalidate_cp_nw) - -// invalidate the register file. -// void xthal_invalidate_cp(int) - -DECLFUNC(xthal_invalidate_cp) - abi_entry -#if XCHAL_HAVE_CP - rsr.cpenable a3 - movi a4, 1 - ssl a2 - sll a4, a4 - and a4, a3, a4 - xor a3, a3, a4 - wsr.cpenable a3 -#endif - abi_return - endfunc - - -//---------------------------------------------------------------------- -// Access the CPENABLE register -//---------------------------------------------------------------------- - -#elif defined(__SPLIT__get_cpenable) || \ - defined(__SPLIT__get_cpenable_nw) - -// unsigned xthal_get_cpenable(void); - -DECLFUNC(xthal_get_cpenable) - abi_entry -#if XCHAL_HAVE_CP - rsr.cpenable a2 -#else - movi a2, 0 // if no CPENABLE (no coprocessors), none is ever enabled -#endif - abi_return - endfunc - -#elif defined(__SPLIT__set_cpenable) ||\ - defined(__SPLIT__set_cpenable_nw) - -// void xthal_set_cpenable(unsigned); -// -// Note: to help asm code performance (eg. OS task switch), -// this routine returns the previous value of CPENABLE in a3 -// (not a2, because that could require an extra mov instruction). -// This return value is not shown in the prototype, because -// C code won't see it. -// [Perhaps this should go in an RTOS-specific Core HAL or BSP. TBD.] - -DECLFUNC(xthal_set_cpenable) - abi_entry -#if XCHAL_HAVE_CP - //rsr.cpenable a3 // return previous CPENABLE - movi a3, 0 // for now, always return 0 (VxWorks currently done that way) - - wsr.cpenable a2 -#else - movi a3, 0 // if no CPENABLE (no coprocessors), none is ever enabled -#endif - abi_return - endfunc -#endif - - -/* Nothing implemented below this point. */ -/************************************************************************/ - -#if 0 - -//---------------------------------------------------------------------- -// initialize the processor state -//---------------------------------------------------------------------- - -// void xthal_init_extra_nw() - .global xthal_init_extra_nw - .align 4 -xthal_init_extra_nw: - //addi sp, sp, 0 - ... NOT IMPLEMENTED ... - ret - -//---------------------------------------------------------------------- -// initialize the TIE coprocessor -//---------------------------------------------------------------------- - -// void xthal_init_cp_nw(int) - .global xthal_init_cp_nw - .align 4 -xthal_init_cp_nw: - //addi sp, sp, 0 - ... NOT IMPLEMENTED ... - ret - -//---------------------------------------------------------------------- -// -//---------------------------------------------------------------------- - -// initialize the extra processor -// void xthal_init_mem_extra_nw() - .global xthal_init_mem_extra_nw - .align 4 -xthal_init_mem_extra_nw: - //addi sp, sp, 0 - ... NOT IMPLEMENTED ... - ret - -//---------------------------------------------------------------------- -// -//---------------------------------------------------------------------- - -// initialize the TIE coprocessor -// void xthal_init_mem_cp_nw(int) - .global xthal_init_mem_cp_nw - .align 4 -xthal_init_mem_cp_nw: - //addi sp, sp, 0 - ... NOT IMPLEMENTED ... - ret - -#endif /*0*/ - diff --git a/src/arch/xtensa/hal/syscache_asm.S b/src/arch/xtensa/hal/syscache_asm.S deleted file mode 100644 index 0716ddca17ff..000000000000 --- a/src/arch/xtensa/hal/syscache_asm.S +++ /dev/null @@ -1,141 +0,0 @@ -// -// syscache_asm.S - system-dependent assembly language cache management routines -// -// These functions are now obsolete. They cannot be properly implemented -// in the HAL, because the required settings of CACHEATTR are entirely -// system- or board-dependent. The HAL is not board specific; it is merely -// processor-configuration specific. These cache enable and disable -// functions do a "best-guess" of what values may be appropriate. -// They should be avoided. (Instead, use xthal_set_[id]cacheattr() -// and provide specific CACHEATTR values for the board or system. -// See the LSP ref manual for info on how to obtain such a value as -// computed by xt-genldscripts for a specific LSP, e.g. by using the -// address of the _memmap_cacheattr_reset symbol.) -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/syscache_asm.S#1 $ - -// Copyright (c) 2003-2013 Tensilica 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. - -#ifdef INCLUDE_DEPRECATED_HAL_CACHE_CODE - -#include <xtensa/cacheasm.h> -#include <xtensa/cacheattrasm.h> -#include <xtensa/config/system.h> - -/*** Modify this for your particular board or system: ***/ -#define CACHEATTR_DEFAULT XSHAL_ISS_CACHEATTR_DEFAULT -#define CACHEATTR_BYPASS XSHAL_ISS_CACHEATTR_BYPASS - -//---------------------------------------------------------------------- -// Enable and disable the caches -//---------------------------------------------------------------------- - - .text - - .global xthal_icache_enable - .global xthal_dcache_enable - .global xthal_icache_enable_nw - .global xthal_dcache_enable_nw - - .global xthal_icache_disable - .global xthal_dcache_disable - .global xthal_icache_disable_nw - .global xthal_dcache_disable_nw - - /* - * Since we can't enable/disable the icache and dcache independently, - * and don't have a nice place to store a state which would enable - * us to only enable them both when both have been requested to be - * enabled, we simply enable both for any request to enable either, - * and disable both for any request to disable either cache. - */ - - .align 4 -xthal_icache_enable: - abi_entry - movi a3, xthal_set_icacheattr - movi a6, CACHEATTR_DEFAULT // get cache-enabled attributes - callx4 a3 // enable i-cache - mov a2, a6 // (in case future version has a return value) - abi_return - .size xthal_icache_enable, . - xthal_icache_enable - - .align 4 -xthal_dcache_enable: - abi_entry - movi a3, xthal_set_dcacheattr - movi a6, CACHEATTR_DEFAULT // get cache-enabled attributes - callx4 a3 // enable d-cache - mov a2, a6 // (in case future version has a return value) - abi_return - .size xthal_dcache_enable, . - xthal_dcache_enable - - .align 4 -xthal_icache_disable: - abi_entry - movi a3, xthal_set_icacheattr - movi a6, CACHEATTR_BYPASS // get cache-disabled attributes - callx4 a3 // disable i-cache - mov a2, a6 // (in case future version has a return value) - abi_return - .size xthal_icache_disable, . - xthal_icache_disable - - .align 4 -xthal_dcache_disable: - abi_entry - movi a3, xthal_set_dcacheattr - movi a6, CACHEATTR_BYPASS // get cache-disabled attributes - callx4 a3 // disable d-cache - mov a2, a6 // (in case future version has a return value) - abi_return - .size xthal_dcache_disable, . - xthal_dcache_disable - - .align 4 -xthal_icache_enable_nw: - movi a3, xthal_set_icacheattr_nw - movi a2, CACHEATTR_DEFAULT // get cache-enabled attributes - jx a3 // enable i-cache - .size xthal_icache_enable_nw, . - xthal_icache_enable_nw - - .align 4 -xthal_dcache_enable_nw: - movi a3, xthal_set_dcacheattr_nw - movi a2, CACHEATTR_DEFAULT // get cache-enabled attributes - jx a3 // enable d-cache - .size xthal_dcache_enable_nw, . - xthal_dcache_enable_nw - - .align 4 -xthal_icache_disable_nw: - movi a3, xthal_set_icacheattr_nw - movi a2, CACHEATTR_BYPASS // get cache-disabled attributes - jx a3 // disable i-cache - .size xthal_icache_disable_nw, . - xthal_icache_disable_nw - - .align 4 -xthal_dcache_disable_nw: - movi a3, xthal_set_dcacheattr_nw - movi a2, CACHEATTR_BYPASS // get cache-disabled attributes - jx a3 // disable d-cache - .size xthal_dcache_disable_nw, . - xthal_dcache_disable_nw - -#endif /* INCLUDE_DEPRECATED_HAL_CACHE_CODE */ - diff --git a/src/arch/xtensa/hal/windowspill_asm.S b/src/arch/xtensa/hal/windowspill_asm.S deleted file mode 100644 index 4568a41f5175..000000000000 --- a/src/arch/xtensa/hal/windowspill_asm.S +++ /dev/null @@ -1,386 +0,0 @@ -// -// windowspill.S -- register window spill routine -// -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/windowspill_asm.S#1 $ - -// Copyright (c) 1999-2010 Tensilica 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. - -#include <xtensa/coreasm.h> - - -// xthal_window_spill_nw -// -// Spill live register windows to the stack. -// -// Required entry conditions: -// PS.WOE = 0 -// PS.INTLEVEL >= XCHAL_EXCM_LEVEL -// a1 = valid stack pointer (note: some regs may be spilled at a1-16) -// a0 = return PC (usually set by call0 or callx0 when calling this function) -// a2,a3 undefined -// a4 thru a15 valid, if they are part of window(s) to be spilled -// (Current window a0..a15 saved if necessary.) -// WINDOWSTART[WINDOWBASE] = 1 -// -// Exit conditions: -// PS.WOE, PS.INTLEVEL = same as on entry -// WINDOWBASE = same as on entry -// WINDOWSTART updated to reflect spilled windows -// (equals 1<<WINDOWBASE if successful return) -// a0 = return PC -// a1 = same as on entry -// a2 = error code: -// 0 --> successful -// (WINDOWSTART = 1<<WINDOWBASE) -// 1 --> invalid WINDOWSTART (WINDOWBASE bit not set) -// (WINDOWSTART unchanged) -// 2 --> invalid window size (not 4, 8 or 12 regs) -// (WINDOWSTART bits of successfully spilled -// windows are cleared, others left intact) -// a3 clobbered -// a4,a5,a8,a9,a12,a13 = same as on entry -// a6,a7,a10,a11,a14,a15 clobbered if they were part of window(s) -// to be spilled, otherwise they are the same as on entry -// loop registers (LCOUNT,LBEG,LEND) are NOT affected (they were in earlier versions) -// SAR clobbered -// -// All non-spilled register windows will be spilled. -// Beware that this may include a4..a15 of the current window, -// so generally these should not have been clobbered by the -// caller if it is at all possible that these registers -// are part of an unspilled window (it often is possible) -// (otherwise the spilled stack would be invalid). -// -// THIS MEANS: the caller is responsible for saving a0-a15 but -// the caller must leave a4-a15 intact when control is transferred -// here. -// -// It may be reentrant (but stack pointer is invalid during -// execution due to window rotations, so can't take interrupts -// and exceptions in the usual manner, so ... what does -// reentrancy really mean here?). - - - // The xthal_spill_registers_into_stack_nw entry point - // is kept here only for backwards compatibility. - // It will be removed in the very near future. - .global xthal_spill_registers_into_stack_nw - - .text - .align 4 - .global xthal_window_spill_nw -xthal_window_spill_nw: -xthal_spill_registers_into_stack_nw: // BACKWARD COMPATIBILITY ONLY - see above - -#if ! XCHAL_HAVE_WINDOWED - // Nothing to do -- window option was not selected. - movi a2, 0 // always report success - ret -#else /* XCHAL_HAVE_WINDOWED */ -#define WSBITS (XCHAL_NUM_AREGS / 4) /* width of WINDOWSTART register in bits */ -#define WBBITS (XCHAL_NUM_AREGS_LOG2 - 2) /* width of WINDOWBASE register in bits */ - /* - * Rearrange (rotate) window start bits relative to the current - * window (WINDOWBASE). WINDOWSTART currently looks like this: - * - * a15-a0 - * NAREG-1 | | 0 - * | vvvv | - * xxxxxxxxxx1yyyyy - * ^ - * | - * WINDOWBASE - * - * The start bit pointed to by WINDOWBASE must be set - * (we return an error if it isn't), as it corresponds - * to the start of the current window (shown as a0-a15). - * - * We want the window start bits rotated to look like this: - * 1yyyyyxxxxxxxxxx - * - * Note that there is one start bit for every four registers; - * and the total number of registers (NAREG) can be 32 or 64; - * so the number of start bits in WINDOWSTART is NAREG/4, - * and the size of WINDOWSTART can be 8 or 16. - */ - - rsr.windowbase a2 - addi a2, a2, 1 - ssr a2 // sar = WINDOWBASE + 1 - rsr.windowstart a3 - srl a2, a3 // a2 is 0... | 000000xxxxxxxxxx = WINDOWSTART >> sar - sll a3, a3 // a3 is 1yyyyy0000000000 | 0... = WINDOWSTART << (32 - sar) - bgez a3, .Linvalid_ws // verify that msbit is indeed set - - srli a3, a3, 32-WSBITS // a3 is 0... | 1yyyyy0000000000 = a3 >> (32-NAREG/4) - or a2, a2, a3 // a2 is 0... | 1yyyyyxxxxxxxxxx - - /* - * FIND THE FIRST ONE - * - * Now we have (in a2) the window start bits rotated in order - * from oldest (closest to lsbit) to current (msbit set). - * Each start bit (that is set), other than the current one, - * corresponds to a window frame to spill. - * - * Now find the first start bit, ie. the first frame to spill, - * by looking for the first bit set in a2 (from lsbit side). - */ - -#if XCHAL_HAVE_NSA - neg a3, a2 // keep only the least-significant bit set of a2 ... - and a3, a3, a2 // ... in a3 - nsau a3, a3 // get index of that bit, numbered from msbit (32 if absent) - ssl a3 // set sar = 32 - a3 = bit index numbered from lsbit + 1 -#else /* XCHAL_HAVE_NSA */ - wsr.windowstart a2 // temporarily save rotated start bits - // (we can use WINDOWSTART because WOE=0) - - // NOTE: this could be optimized a bit, by explicit coding rather than the macro. - find_ls_one a3, a2 // set a3 to index of lsmost bit set in a2 (a2 clobbered) - - addi a2, a3, 1 // index+1 - ssr a2 // set sar = index + 1 - rsr.windowstart a2 // restore a2 (rotated start bits) -#endif /* XCHAL_HAVE_NSA */ - srl a2, a2 // right-justify the rotated start bits (dropping lsbit set) - wsr.windowstart a2 // save rotated + justified window start bits, - // because a2 will disappear when modifying WINDOWBASE - // again, we can use WINDOWSTART because WOE=0 - - /* - * Rotate WindowBase so that a0 of the next window to spill is in a4 - * (ie. leaving us with a2 and a3 to play with, because a0 and a1 - * may be those of the original window which we must preserve). - */ - rsr.windowbase a2 -#if XCHAL_HAVE_NSA - addi a2, a2, 31 - sub a3, a2, a3 // a3 = WINDOWBASE + index = WINDOWBASE + (31 - msbit_index) -#else /* XCHAL_HAVE_NSA */ - add a3, a2, a3 // a3 = WINDOWBASE + index -#endif /* XCHAL_HAVE_NSA */ - wsr.windowbase a3 // effectively do: rotw index - rsync // wait for write to WINDOWBASE to complete - // Now our registers have changed! - - rsr.windowstart a2 // restore a2 (rotated + justified window start bits) - - /* - * We are now ready to start the window spill loop. - * Relative to the above, a2 and WINDOWBASE are now as follows: - * - * 1yyyyyxxxxxxxxxx = rotated start bits as shown above - * 1yyyyyxxxx100000 = actual rotated start bits (example) - * 0000001yyyyyxxxx ^ = a2 = rotated + justified start bits - * ^ xxx1^ = window being spilled - * ^ ^ - * | | - * original current - * WINDOWBASE WINDOWBASE - * - * The first window to spill (save) starts at what is now a4. - * The spill loop maintains the adjusted start bits in a2, - * shifting them right as each window is spilled. - */ - -.Lspill_loop: - // Top of save loop. - // Find the size of this call and branch to the appropriate save routine. - - beqz a2, .Ldone // if no start bit remaining, we're done - bbsi.l a2, 0, .Lspill4 // if next start bit is set, it's a call4 - bbsi.l a2, 1, .Lspill8 // if 2nd next bit set, it's a call8 - bbsi.l a2, 2, .Lspill12 // if 3rd next bit set, it's a call12 - j .Linvalid_window // else it's an invalid window! - - - - // SAVE A CALL4 -.Lspill4: - addi a3, a9, -16 // a3 gets call[i+1]'s sp - 16 - s32i a4, a3, 0 // store call[i]'s a0 - s32i a5, a3, 4 // store call[i]'s a1 - s32i a6, a3, 8 // store call[i]'s a2 - s32i a7, a3, 12 // store call[i]'s a3 - - srli a6, a2, 1 // move and shift the start bits - rotw 1 // rotate the window - - j .Lspill_loop - - // SAVE A CALL8 -.Lspill8: - addi a3, a13, -16 // a0 gets call[i+1]'s sp - 16 - s32i a4, a3, 0 // store call[i]'s a0 - s32i a5, a3, 4 // store call[i]'s a1 - s32i a6, a3, 8 // store call[i]'s a2 - s32i a7, a3, 12 // store call[i]'s a3 - - addi a3, a5, -12 // call[i-1]'s sp address - l32i a3, a3, 0 // a3 is call[i-1]'s sp - // (load slot) - addi a3, a3, -32 // a3 points to our spill area - - s32i a8, a3, 0 // store call[i]'s a4 - s32i a9, a3, 4 // store call[i]'s a5 - s32i a10, a3, 8 // store call[i]'s a6 - s32i a11, a3, 12 // store call[i]'s a7 - - srli a10, a2, 2 // move and shift the start bits - rotw 2 // rotate the window - - j .Lspill_loop - - // SAVE A CALL12 -.Lspill12: - rotw 1 // rotate to see call[i+1]'s sp - - addi a13, a13, -16 // set to the reg save area - s32i a0, a13, 0 // store call[i]'s a0 - s32i a1, a13, 4 // store call[i]'s a1 - s32i a2, a13, 8 // store call[i]'s a2 - s32i a3, a13, 12 // store call[i]'s a3 - - addi a3, a1, -12 // call[i-1]'s sp address - l32i a3, a3, 0 // a3 has call[i-1]'s sp - addi a13, a13, 16 // restore call[i+1]'s sp (here to fill load slot) - addi a3, a3, -48 // a3 points to our save area - - s32i a4, a3, 0 // store call[i]'s a4 - s32i a5, a3, 4 // store call[i]'s a5 - s32i a6, a3, 8 // store call[i]'s a6 - s32i a7, a3, 12 // store call[i]'s a7 - s32i a8, a3, 16 // store call[i]'s a4 - s32i a9, a3, 20 // store call[i]'s a5 - s32i a10, a3, 24 // store call[i]'s a6 - s32i a11, a3, 28 // store call[i]'s a7 - - rotw -1 // rotate to see start bits (a2) - srli a14, a2, 3 // move and shift the start bits - rotw 3 // rotate to next window - - j .Lspill_loop - - - -.Ldone: - rotw 1 // back to the original window - rsr.windowbase a2 // get (original) window base - ssl a2 // setup for shift left by WINDOWBASE - movi a2, 1 - sll a2, a2 // compute new WINDOWSTART = 1<<WINDOWBASE - wsr.windowstart a2 // and apply it - rsync - movi a2, 0 // done! - ret - //jx a0 - - - // Invalid WINDOWSTART register. - // -.Linvalid_ws: - movi a2, 1 // indicate invalid WINDOWSTART - ret // return from subroutine - - - // Invalid window size! - // The three bits following the start bit are all clear, so - // we have an invalid window state (can't determine a window size). - // - // So we exit with an error, but to do that we must first restore - // the original WINDOWBASE. We also compute a sensible - // WINDOWSTART that has the start bits of spilled windows - // cleared, but all other start bits intact, so someone debugging - // the failure can look at WINDOWSTART to see which window - // failed to spill. - // -.Linvalid_window: - slli a2, a2, 1 // space for missing start bit - addi a2, a2, 1 // add missing start bit - rsr.windowbase a3 // get current WINDOWBASE - bbsi.l a2, WSBITS-1, 2f // branch if current WINDOWBASE==original -1: addi a3, a3, -1 // decrement towards original WINDOWBASE - slli a2, a2, 1 // shift towards original WINDOWSTART alignment - bbci.l a2, WSBITS-1, 1b // repeat until ms start bit set - extui a3, a3, 0, WBBITS // mask out upper base bits, in case of carry-over -2: // Here, a3 = original WINDOWBASE; - // and msbit of start bits in a2 is set, and no other bits above it. - // Now rotate a2 to become the correct WINDOWSTART. - ssl a3 // set shift left ... (sar = 32 - orig WB) - slli a3, a2, 32-WSBITS // left-justify start bits - src a2, a2, a3 // rotate left by original WINDOWBASE - extui a2, a2, 0, WSBITS // keep only significant start bits - wsr.windowstart a2 // we've cleared only start bits of spilled windows - rsr.sar a3 // retrieve 32 - original WINDOWBASE - movi a2, 32 - sub a3, a2, a3 // restore original WINDOWBASE - wsr.windowbase a3 // back to original WINDOWBASE - rsync - - movi a2, 2 // indicate invalid window size - ret - -#endif /* XCHAL_HAVE_WINDOWED */ - - .size xthal_window_spill_nw, . - xthal_window_spill_nw - - -// void xthal_window_spill (void); -// -// Spill live register windows to the stack. -// -// This will spill all register windows except this -// function's window, and possibly that of its caller. -// (Currently, the caller's window is spilled and reloaded -// when this function returns. This may change with -// future optimisations.) -// -// Another, simpler way to implement this might be -// to use an appropriate sequence of call/entry/retw -// instructions to force overflow of any live windows. -// -// Assumes that PS.INTLEVEL=0 and PS.WOE=1 on entry/exit. -// - .text - .align 4 - .global xthal_window_spill - .type xthal_window_spill,@function -xthal_window_spill: - abi_entry -#if XCHAL_HAVE_WINDOWED - movi a6, ~(PS_WOE_MASK|PS_INTLEVEL_MASK) // (using a6 ensures any window using this a4..a7 is spilled) - rsr.ps a5 - mov a4, a0 // save a0 - and a2, a5, a6 // clear WOE, INTLEVEL - addi a2, a2, XCHAL_EXCM_LEVEL // set INTLEVEL = XCHAL_EXCM_LEVEL - wsr.ps a2 // apply to PS - rsync - call0 xthal_window_spill_nw - mov a0, a4 // restore a0 - wsr.ps a5 // restore PS - rsync -#endif /* XCHAL_HAVE_WINDOWED */ - abi_return - - .size xthal_window_spill, . - xthal_window_spill - diff --git a/src/arch/xtensa/include/arch/atomic.h b/src/arch/xtensa/include/arch/atomic.h deleted file mode 100644 index 195a87fa5810..000000000000 --- a/src/arch/xtensa/include/arch/atomic.h +++ /dev/null @@ -1,150 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifdef __SOF_ATOMIC_H__ - -#ifndef __ARCH_ATOMIC_H__ -#define __ARCH_ATOMIC_H__ - -#include <stdint.h> -#if XCHAL_HAVE_EXCLUSIVE && CONFIG_XTENSA_EXCLUSIVE && __XCC__ -#include <xtensa/tie/xt_core.h> -#endif -#include <xtensa/config/core-isa.h> - -typedef struct { - volatile int32_t value; -} atomic_t; - -static inline int32_t arch_atomic_read(const atomic_t *a) -{ - return (*(volatile int32_t *)&a->value); -} - -static inline void arch_atomic_set(atomic_t *a, int32_t value) -{ - a->value = value; -} - -static inline void arch_atomic_init(atomic_t *a, int32_t value) -{ - arch_atomic_set(a, value); -} - -#if XCHAL_HAVE_EXCLUSIVE && CONFIG_XTENSA_EXCLUSIVE && __XCC__ - -/* Use exclusive instructions */ -static inline int32_t arch_atomic_add(atomic_t *a, int32_t value) -{ - /*reference xtos : xipc_misc.h*/ - int32_t result = 0; - int32_t current; - - while (!result) { - current = XT_L32EX((int32_t *)a); - result = current + value; - XT_S32EX(result, (int32_t *)a); - XT_GETEX(result); - } - return current; -} - -static inline int32_t arch_atomic_sub(atomic_t *a, int32_t value) -{ - /*reference xtos : xipc_misc.h*/ - int32_t current; - int32_t result = 0; - - while (!result) { - current = XT_L32EX((int *)a); - result = current - value; - XT_S32EX(result, (int *)a); - XT_GETEX(result); - } - return current; -} - -#elif XCHAL_HAVE_S32C1I - -/* Use S32C1I instructions */ -static inline int32_t arch_atomic_add(atomic_t *a, int32_t value) -{ - int32_t result, current; - - __asm__ __volatile__( - "1: l32i %1, %2, 0\n" - " wsr %1, scompare1\n" - " add %0, %1, %3\n" - " s32c1i %0, %2, 0\n" - " bne %0, %1, 1b\n" - : "=&a" (result), "=&a" (current) - : "a" (&a->value), "a" (value) - : "memory"); - - return current; -} - -static inline int32_t arch_atomic_sub(atomic_t *a, int32_t value) -{ - int32_t result, current; - - __asm__ __volatile__( - "1: l32i %1, %2, 0\n" - " wsr %1, scompare1\n" - " sub %0, %1, %3\n" - " s32c1i %0, %2, 0\n" - " bne %0, %1, 1b\n" - : "=&a" (result), "=&a" (current) - : "a" (&a->value), "a" (value) - : "memory"); - - return current; -} - -#else - -#if CONFIG_CORE_COUNT > 1 - -#error No atomic ISA for SMP configuration - -#endif - -/* - * The ISA has no atomic operations so use integer arithmetic on uniprocessor systems. - * This helps support GCC and qemu emulation of certain targets. - */ - -/* integer arithmetic methods */ -static inline int32_t arch_atomic_add(atomic_t *a, int32_t value) -{ - int32_t result, current; - - current = arch_atomic_read(a); - result = current + value; - arch_atomic_set(a, result); - return current; -} - -static inline int32_t arch_atomic_sub(atomic_t *a, int32_t value) -{ - int32_t result, current; - - current = arch_atomic_read(a); - result = current - value; - arch_atomic_set(a, result); - return current; -} - -#endif /* XCHAL_HAVE_EXCLUSIVE && CONFIG_XTENSA_EXCLUSIVE && __XCC__ */ - -#endif /* __ARCH_ATOMIC_H__ */ - -#else - -#error "This file shouldn't be included from outside of sof/atomic.h" - -#endif /* __SOF_ATOMIC_H__ */ diff --git a/src/arch/xtensa/include/arch/compiler_info.h b/src/arch/xtensa/include/arch/compiler_info.h deleted file mode 100644 index 7a2d24ebe6db..000000000000 --- a/src/arch/xtensa/include/arch/compiler_info.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2019 Intel Corporation. All rights reserved. - * - * Author: Karol Trzcinski <karolx.trzcinski@linux.intel.com> - */ - -/** - * \file include/sof/compiler_info.h - * \brief Compiler version and name descriptor - * \author Karol Trzcinski <karolx.trzcinski@linux.intel.com> - */ - -#ifndef __ARCH_COMPILER_INFO_H__ -#define __ARCH_COMPILER_INFO_H__ - -#include <xtensa/hal.h> -#include <xtensa/config/core-isa.h> - -/* read used compilator name and version */ -/* CC_NAME must consist of 3 characters with null termination */ -/* See declaration of sof_ipc_cc_version. */ -#ifdef __XCC__ -#define CC_MAJOR (XTHAL_RELEASE_MAJOR / 1000) -#define CC_MINOR ((XTHAL_RELEASE_MAJOR % 1000) / 10) -#define CC_MICRO XTHAL_RELEASE_MINOR -#define CC_NAME "XCC" -#else -#define CC_MAJOR __GNUC__ -#define CC_MINOR __GNUC_MINOR__ -#define CC_MICRO __GNUC_PATCHLEVEL__ -#define CC_NAME "GCC" - -#if CC_MAJOR >= 10 -#define CC_USE_LIBC -#endif - -#endif - -#define CC_DESC " " XCC_TOOLS_VERSION - -#endif /* __ARCH_COMPILER_INFO_H__ */ diff --git a/src/arch/xtensa/include/arch/debug/backtrace.h b/src/arch/xtensa/include/arch/debug/backtrace.h deleted file mode 100644 index 38ecc66d7786..000000000000 --- a/src/arch/xtensa/include/arch/debug/backtrace.h +++ /dev/null @@ -1,47 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2020 Intel Corporation. All rights reserved. - */ - -#ifdef __SOF_DEBUG_BACKTRACE_H__ - -#ifndef __ARCH_DEBUG_BACKTRACE_H__ -#define __ARCH_DEBUG_BACKTRACE_H__ - -#include <rtos/task.h> -#include <xtensa/xtruntime-frames.h> -#include <stdint.h> - -static inline void *arch_get_stack_ptr(void) -{ - void *ptr; - - /* stack pointer is in a1 */ - __asm__ __volatile__ ("mov %0, a1" - : "=a" (ptr) - : - : "memory"); - return ptr; -} - -static inline void *arch_get_stack_entry(void) -{ - volatile xtos_task_context *task_ctx = task_context_get(); - - return task_ctx->stack_base; -} - -static inline uint32_t arch_get_stack_size(void) -{ - volatile xtos_task_context *task_ctx = task_context_get(); - - return task_ctx->stack_size; -} - -#endif /* __ARCH_DEBUG_BACKTRACE_H__ */ - -#else - -#error "This file shouldn't be included from outside of sof/debug/backtrace.h" - -#endif /* __SOF_DEBUG_BACKTRACE_H__ */ diff --git a/src/arch/xtensa/include/arch/debug/gdb/init.h b/src/arch/xtensa/include/arch/debug/gdb/init.h deleted file mode 100644 index 076d55f25bf5..000000000000 --- a/src/arch/xtensa/include/arch/debug/gdb/init.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2019 Intel Corporation. All rights reserved. - * - * Author: Marcin Rajwa <marcin.rajwa@linux.intel.com> - */ - -/* - * Header file for init.S - */ - -#ifdef __SOF_DEBUG_GDB_GDB_H__ - -#ifndef __ARCH_DEBUG_GDB_INIT_H__ -#define __ARCH_DEBUG_GDB_INIT_H__ - -extern void gdb_init_debug_exception(void); - -#endif /* __ARCH_DEBUG_GDB_INIT_H__ */ - -#else - -#error "This file shouldn't be included from outside of sof/debug/gdb/gdb.h" - -#endif /* __SOF_DEBUG_GDB_GDB_H__ */ diff --git a/src/arch/xtensa/include/arch/debug/gdb/utilities.h b/src/arch/xtensa/include/arch/debug/gdb/utilities.h deleted file mode 100644 index c786d774c6fe..000000000000 --- a/src/arch/xtensa/include/arch/debug/gdb/utilities.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2019 Intel Corporation. All rights reserved. - * - * Author: Marcin Rajwa <marcin.rajwa@linux.intel.com> - */ - -/* - * Header file for Xtensa-GDB utilities. - */ - -#ifndef __ARCH_DEBUG_GDB_UTILITIES_H__ -#define __ARCH_DEBUG_GDB_UTILITIES_H__ - -/* Implicit inclusion from sof/debug/gdb/gdb.h */ -#include <arch/debug/gdb/xtensa-defs.h> - -void arch_gdb_read_sr(int sr); -void arch_gdb_write_sr(int sr, int *sregs); -unsigned char arch_gdb_load_from_memory(void *mem); -void arch_gdb_memory_load_and_store(void *mem, unsigned char ch); -void arch_gdb_single_step(int *sregs); - -#endif /* __ARCH_DEBUG_GDB_UTILITIES_H__ */ diff --git a/src/arch/xtensa/include/arch/debug/gdb/xtensa-defs.h b/src/arch/xtensa/include/arch/debug/gdb/xtensa-defs.h deleted file mode 100644 index 8ae65da38472..000000000000 --- a/src/arch/xtensa/include/arch/debug/gdb/xtensa-defs.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2019 Intel Corporation. All rights reserved. - * - * Author: Marcin Rajwa <marcin.rajwa@linux.intel.com> - */ - -/* - * Header file for xtensa specific defs for GDB. - */ - -#ifndef __ARCH_DEBUG_GDB_XTENSA_DEFS_H__ -#define __ARCH_DEBUG_GDB_XTENSA_DEFS_H__ - -#include <xtensa/config/core-isa.h> -#include <xtensa/specreg.h> - -#define _AREG0 256 - -#define STACK_SIZE 1024 -#define DEBUG_PC (EPC + XCHAL_DEBUGLEVEL) -#define DEBUG_EXCSAVE (EXCSAVE + XCHAL_DEBUGLEVEL) -#define DEBUG_PS (EPS + XCHAL_DEBUGLEVEL) -#define DEBUG_WINDOWBASE WINDOWBASE -#define DEBUG_NUM_IBREAK XCHAL_NUM_IBREAK -#define DEBUG_IBREAKENABLE IBREAKENABLE -#define DEBUG_IBREAKA IBREAKA -#define DEBUG_INTENABLE INTENABLE -#define DEBUG_NUM_AREGS XCHAL_NUM_AREGS - -#endif /* __ARCH_DEBUG_GDB_XTENSA_DEFS_H__ */ diff --git a/src/arch/xtensa/include/arch/debug/offset-defs.h b/src/arch/xtensa/include/arch/debug/offset-defs.h deleted file mode 100644 index 682e90c5f97b..000000000000 --- a/src/arch/xtensa/include/arch/debug/offset-defs.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2019 Intel Corporation. All rights reserved. - */ - -#ifndef __ARCH_DEBUG_OFFSET_DEFS_H__ -#define __ARCH_DEBUG_OFFSET_DEFS_H__ - -#include <xtensa/config/core-isa.h> - -#define REG_OFFSET_EXCCAUSE 0x0 -#define REG_OFFSET_EXCVADDR 0x4 -#define REG_OFFSET_PS 0x8 -#define REG_OFFSET_EPC1 0xc -#define REG_OFFSET_EPC2 0x10 -#define REG_OFFSET_EPC3 0x14 -#define REG_OFFSET_EPC4 0x18 -#define REG_OFFSET_EPC5 0x1c -#define REG_OFFSET_EPC6 0x20 -#define REG_OFFSET_EPC7 0x24 -#define REG_OFFSET_EPS2 0x28 -#define REG_OFFSET_EPS3 0x2c -#define REG_OFFSET_EPS4 0x30 -#define REG_OFFSET_EPS5 0x34 -#define REG_OFFSET_EPS6 0x38 -#define REG_OFFSET_EPS7 0x3c -#define REG_OFFSET_DEPC 0x40 -#define REG_OFFSET_INTENABLE 0x44 -#define REG_OFFSET_INTERRUPT 0x48 -#define REG_OFFSET_SAR 0x4c -#define REG_OFFSET_DEBUGCAUSE 0x50 -#define REG_OFFSET_WINDOWBASE 0x54 -#define REG_OFFSET_WINDOWSTART 0x58 -#define REG_OFFSET_EXCSAVE1 0x5c -#define REG_OFFSET_AR_BEGIN 0x60 -#define REG_OFFSET_AR_END (REG_OFFSET_AR_BEGIN + 4 * XCHAL_NUM_AREGS) - -#endif /* __ARCH_DEBUG_OFFSET_DEFS_H__ */ diff --git a/src/arch/xtensa/include/arch/debug/panic.h b/src/arch/xtensa/include/arch/debug/panic.h deleted file mode 100644 index 4d940981d2ba..000000000000 --- a/src/arch/xtensa/include/arch/debug/panic.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2019 Intel Corporation. All rights reserved. - * - * Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#ifdef __XTOS_RTOS_PANIC_H__ - -#ifndef __ARCH_DEBUG_PANIC_H__ -#define __ARCH_DEBUG_PANIC_H__ - -#include <rtos/cache.h> -#include <ipc/trace.h> -#include <ipc/xtensa.h> -#include <xtensa/config/core-isa.h> -#include <stdint.h> - -/* xtensa core specific oops size */ -#define ARCH_OOPS_SIZE (sizeof(struct sof_ipc_dsp_oops_xtensa) \ - + (XCHAL_NUM_AREGS * sizeof(uint32_t))) - -void arch_dump_regs_a(void *dump_buf); - -static inline void fill_core_dump(struct sof_ipc_dsp_oops_xtensa *oops, - uintptr_t stack_ptr, uintptr_t *epc1) -{ - oops->arch_hdr.arch = ARCHITECTURE_ID; - oops->arch_hdr.totalsize = ARCH_OOPS_SIZE; -#if XCHAL_HW_CONFIGID_RELIABLE - oops->plat_hdr.configidhi = XCHAL_HW_CONFIGID0; - oops->plat_hdr.configidlo = XCHAL_HW_CONFIGID1; -#else - oops->plat_hdr.configidhi = 0; - oops->plat_hdr.configidlo = 0; -#endif - oops->plat_hdr.numaregs = XCHAL_NUM_AREGS; - oops->plat_hdr.stackoffset = oops->arch_hdr.totalsize - + sizeof(struct sof_ipc_panic_info); - oops->plat_hdr.stackptr = stack_ptr; - - if (epc1) - oops->epc1 = *epc1; - - /* With crosstool-ng gcc on some platforms this corrupts most of - * the other panic information, including the precious line - * number. See https://github.com/thesofproject/sof/issues/1346 - * Commenting this out loses the registers but avoids the - * corruption of the rest. - */ - arch_dump_regs_a((void *)&oops->exccause); -} - -static inline void arch_dump_regs(void *dump_buf, uintptr_t stack_ptr, - uintptr_t *epc1) -{ - fill_core_dump(dump_buf, stack_ptr, epc1); - - dcache_writeback_region((__sparse_force void __sparse_cache *)dump_buf, ARCH_OOPS_SIZE); -} - -#endif /* __ARCH_DEBUG_PANIC_H__ */ - -#else - -#error "This file shouldn't be included from outside of XTOS's rtos/panic.h" - -#endif /* __XTOS_RTOS_PANIC_H__ */ diff --git a/src/arch/xtensa/include/arch/drivers/idc.h b/src/arch/xtensa/include/arch/drivers/idc.h deleted file mode 100644 index 1a34697bdbba..000000000000 --- a/src/arch/xtensa/include/arch/drivers/idc.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2020 Intel Corporation. All rights reserved. - * - * Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#ifdef __XTOS_RTOS_IDC_H__ - -#ifndef __ARCH_DRIVERS_IDC_H__ -#define __ARCH_DRIVERS_IDC_H__ - -#include <sof/lib/cpu.h> -#include <xtos-structs.h> - -struct idc; - -/** - * \brief Returns IDC data. - * \return Pointer to pointer of IDC data. - */ -static inline struct idc **idc_get(void) -{ - struct core_context *ctx = (struct core_context *)cpu_read_threadptr(); - - return &ctx->idc; -} - -#endif /* __ARCH_DRIVERS_IDC_H__ */ - -#else - -#error "This file shouldn't be included from outside of XTOS's rtos/idc.h" - -#endif /* __XTOS_RTOS_IDC_H__ */ diff --git a/src/arch/xtensa/include/arch/drivers/timer.h b/src/arch/xtensa/include/arch/drivers/timer.h deleted file mode 100644 index c1bc02df76b5..000000000000 --- a/src/arch/xtensa/include/arch/drivers/timer.h +++ /dev/null @@ -1,82 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifdef __SOF_DRIVERS_TIMER_H__ - -#ifndef __ARCH_DRIVERS_TIMER_H__ -#define __ARCH_DRIVERS_TIMER_H__ - -#include <rtos/interrupt.h> -#include <sof/lib/memory.h> -#include <stdint.h> - -#define ARCH_TIMER_COUNT 3 - -struct timer { - uint32_t id; - int irq; - int logical_irq; /* used for external timers */ - const char *irq_name; - void (*handler)(void *data); /* optional timer handler */ - void *data; /* optional timer handler's data */ - uint32_t hitime; /* high end of 64bit timer */ - uint32_t hitimeout; - uint32_t lowtimeout; - uint64_t delta; -}; - -/* internal API calls */ -int timer64_register(struct timer *timer, void (*handler)(void *arg), - void *arg); -void timer_64_handler(void *arg); - -static inline int arch_timer_register(struct timer *timer, - void (*handler)(void *arg), void *arg) -{ - uint32_t flags; - int ret; - - flags = arch_interrupt_global_disable(); - timer64_register(timer, handler, arg); - ret = arch_interrupt_register(timer->irq, timer_64_handler, timer); - arch_interrupt_global_enable(flags); - - - return ret; -} - -static inline void arch_timer_unregister(struct timer *timer) -{ - arch_interrupt_unregister(timer->irq); -} - -static inline void arch_timer_enable(struct timer *timer) -{ - arch_interrupt_enable_mask(1 << timer->irq); -} - -static inline void arch_timer_disable(struct timer *timer) -{ - arch_interrupt_disable_mask(1 << timer->irq); -} - -uint64_t arch_timer_get_system(struct timer *timer); - -int64_t arch_timer_set(struct timer *timer, uint64_t ticks); - -static inline void arch_timer_clear(struct timer *timer) -{ - arch_interrupt_clear(timer->irq); -} - -#endif /* __ARCH_DRIVERS_TIMER_H__ */ - -#else - -#error "This file shouldn't be included from outside of sof/drivers/timer.h" - -#endif /* __SOF_DRIVERS_TIMER_H__ */ diff --git a/src/arch/xtensa/include/arch/lib/cache.h b/src/arch/xtensa/include/arch/lib/cache.h deleted file mode 100644 index 19bea9211c72..000000000000 --- a/src/arch/xtensa/include/arch/lib/cache.h +++ /dev/null @@ -1,160 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2017 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifdef __SOF_LIB_CACHE_H__ - -#ifndef __ARCH_LIB_CACHE_H__ -#define __ARCH_LIB_CACHE_H__ - -#include <xtensa/config/core-isa.h> - -#define DCACHE_LINE_SIZE XCHAL_DCACHE_LINESIZE - -#if !defined(__ASSEMBLER__) && !defined(LINKER) - -#include <xtensa/hal.h> -#include <sof/compiler_attributes.h> -#include <stddef.h> -#include <stdint.h> - -#ifdef CONFIG_COMPILER_WORKAROUND_CACHE_ATTR -#include <sof/drivers/cache_attr.h> -#endif - -#define SRAM_UNCACHED_ALIAS 0x20000000 - -#ifdef CONFIG_IMX - -#ifdef CONFIG_COMPILER_WORKAROUND_CACHE_ATTR -/* - * We want to avoid buggy compiler optimization (function inlining). - * So we replace the call to glb_addr_attr() from glb_is_cached() - * with a function pointer that is initialized in - * src/arch/xtensa/driver/cache_attr.c - */ -#define is_cached(address) glb_is_cached(address) - -#else /* CONFIG_COMPILER_WORKAROUND_CACHE_ATTR */ -/* - * The _memmap_cacheattr_reset linker script variable has - * dedicate cache attribute for every 512M in 4GB space - * 1: write through - * 2: cache bypass - * 4: write back - * F: invalid access - */ -extern uint32_t _memmap_cacheattr_reset; - -/* - * Since each hex digit keeps the attributes for a 512MB region, - * we have the following address ranges: - * Address range - hex digit - * 0 - 1FFFFFFF - 0 - * 20000000 - 3FFFFFFF - 1 - * 40000000 - 5FFFFFFF - 2 - * 60000000 - 7FFFFFFF - 3 - * 80000000 - 9FFFFFFF - 4 - * A0000000 - BFFFFFFF - 5 - * C0000000 - DFFFFFFF - 6 - * E0000000 - FFFFFFFF - 7 - */ - -/* - * Based on the above information, get the address region id (0-7) - */ -#define _addr_range(address) (((uintptr_t)(address) >> 29) & 0x7) -/* - * Get the position of the cache attribute for a certain memory region. - * There are 4 bits per hex digit. - */ -#define _addr_shift(address) ((_addr_range(address)) << 2) -/* - * For the given address, get the corresponding hex digit - * from the linker script variable that contains the cache attributes - */ -#define _addr_attr(address) ((((uint32_t)(&_memmap_cacheattr_reset)) >> \ - (_addr_shift(address))) & 0xF) -/* - * Check if the address is cacheable or not, by verifying the _addr_attr, - * which for cacheable addresses might be 1 or 4 - */ -#define is_cached(address) ((_addr_attr(address) == 1) || \ - (_addr_attr(address) == 4)) -#endif /* CONFIG_COMPILER_WORKAROUND_CACHE_ATTR */ - -#else /* CONFIG_IMX */ -#define is_cached(address) (!!((uintptr_t)(address) & SRAM_UNCACHED_ALIAS)) -#endif - -static inline void dcache_writeback_region(void __sparse_cache *addr, size_t size) -{ -#if XCHAL_DCACHE_SIZE > 0 - if (is_cached(addr)) - xthal_dcache_region_writeback((__sparse_force void *)addr, size); -#endif -} - -static inline void dcache_writeback_all(void) -{ -#if XCHAL_DCACHE_SIZE > 0 - xthal_dcache_all_writeback(); -#endif -} - -static inline void dcache_invalidate_region(void __sparse_cache *addr, size_t size) -{ -#if XCHAL_DCACHE_SIZE > 0 - if (is_cached(addr)) - xthal_dcache_region_invalidate((__sparse_force void *)addr, size); -#endif -} - -static inline void dcache_invalidate_all(void) -{ -#if XCHAL_DCACHE_SIZE > 0 - xthal_dcache_all_invalidate(); -#endif -} - -static inline void icache_invalidate_region(void *addr, size_t size) -{ -#if XCHAL_ICACHE_SIZE > 0 - xthal_icache_region_invalidate(addr, size); -#endif -} - -static inline void icache_invalidate_all(void) -{ -#if XCHAL_ICACHE_SIZE > 0 - xthal_icache_all_invalidate(); -#endif -} - -static inline void dcache_writeback_invalidate_region(void __sparse_cache *addr, size_t size) -{ -#if XCHAL_DCACHE_SIZE > 0 - if (is_cached(addr)) - xthal_dcache_region_writeback_inv((__sparse_force void *)addr, size); -#endif -} - -static inline void dcache_writeback_invalidate_all(void) -{ -#if XCHAL_DCACHE_SIZE > 0 - xthal_dcache_all_writeback_inv(); -#endif -} - -#endif /* !defined(__ASSEMBLER__) && !defined(LINKER) */ - -#endif /* __ARCH_LIB_CACHE_H__ */ - -#else - -#error "This file shouldn't be included from outside of sof/lib/cache.h" - -#endif /* __SOF_LIB_CACHE_H__ */ diff --git a/src/arch/xtensa/include/arch/lib/cpu.h b/src/arch/xtensa/include/arch/lib/cpu.h deleted file mode 100644 index acd89a114f08..000000000000 --- a/src/arch/xtensa/include/arch/lib/cpu.h +++ /dev/null @@ -1,146 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Rander Wang <rander.wang@linux.intel.com> - */ - -#ifdef __SOF_LIB_CPU_H__ - -#ifndef __ARCH_LIB_CPU_H__ -#define __ARCH_LIB_CPU_H__ - -#include <xtensa/config/core-isa.h> -#include <stdint.h> - -#if CONFIG_MULTICORE - -/** \brief CPU power down available flags */ -#define CPU_POWER_DOWN_MEMORY_ON BIT(0) /**< Power down core with memory - * enabled (required in d0ix - * flow) - */ - -void cpu_power_down_core(uint32_t flags); - -void cpu_alloc_core_context(int id); - -int arch_cpu_enable_core(int id); - -void arch_cpu_disable_core(int id); - -int arch_cpu_is_core_enabled(int id); - -int arch_cpu_enabled_cores(void); - -int arch_cpu_restore_secondary_cores(void); - -int arch_cpu_secondary_cores_prepare_d0ix(void); - -#else - -static inline int arch_cpu_enable_core(int id) { return 0; } - -static inline void arch_cpu_disable_core(int id) { } - -static inline int arch_cpu_is_core_enabled(int id) { return 1; } - -static inline int arch_cpu_enabled_cores(void) { return 1; } - -static inline int arch_cpu_restore_secondary_cores(void) {return 0; } - -static inline int arch_cpu_secondary_cores_prepare_d0ix(void) {return 0; } - -#endif - -static inline int arch_cpu_get_id(void) -{ - int prid; -#if XCHAL_HAVE_PRID - __asm__("rsr.prid %0" : "=a"(prid)); -#else - prid = PLATFORM_PRIMARY_CORE_ID; -#endif - return prid; -} - -#if !XCHAL_HAVE_THREADPTR -extern unsigned int _virtual_thread_start; -static unsigned int *virtual_thread_ptr = - (unsigned int *)&_virtual_thread_start; -#endif - -static inline void cpu_write_threadptr(int threadptr) -{ -#if XCHAL_HAVE_THREADPTR - __asm__ __volatile__( - "wur.threadptr %0" : : "a" (threadptr) : "memory"); -#else - *virtual_thread_ptr = threadptr; -#endif -} - -static inline int cpu_read_threadptr(void) -{ - int threadptr; -#if XCHAL_HAVE_THREADPTR - __asm__ __volatile__( - "rur.threadptr %0" : "=a"(threadptr)); -#else - threadptr = *virtual_thread_ptr; -#endif - return threadptr; -} - -static inline int cpu_read_vecbase(void) -{ - int vecbase; - - __asm__ __volatile__("rsr.vecbase %0" - : "=a"(vecbase)); - return vecbase; -} - -static inline int cpu_read_excsave2(void) -{ - int excsave2; - - __asm__ __volatile__("rsr.excsave2 %0" - : "=a"(excsave2)); - return excsave2; -} - -static inline int cpu_read_excsave3(void) -{ - int excsave3; - - __asm__ __volatile__("rsr.excsave3 %0" - : "=a"(excsave3)); - return excsave3; -} - -static inline int cpu_read_excsave4(void) -{ - int excsave4; - - __asm__ __volatile__("rsr.excsave4 %0" - : "=a"(excsave4)); - return excsave4; -} - -static inline int cpu_read_excsave5(void) -{ - int excsave5; - - __asm__ __volatile__("rsr.excsave5 %0" - : "=a"(excsave5)); - return excsave5; -} - -#endif /* __ARCH_LIB_CPU_H__ */ - -#else - -#error "This file shouldn't be included from outside of sof/lib/cpu.h" - -#endif /* __SOF_LIB_CPU_H__ */ diff --git a/src/arch/xtensa/include/arch/lib/wait.h b/src/arch/xtensa/include/arch/lib/wait.h deleted file mode 100644 index d4166f0a855c..000000000000 --- a/src/arch/xtensa/include/arch/lib/wait.h +++ /dev/null @@ -1,62 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2017 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifndef __ARCH_LIB_WAIT_H__ -#define __ARCH_LIB_WAIT_H__ - -#include <rtos/panic.h> -#include <rtos/interrupt.h> -#include <rtos/clk.h> -#include <ipc/trace.h> - -#include <xtensa/xtruntime.h> - -#if (CONFIG_XT_WAITI_DELAY) - -static inline void arch_wait_for_interrupt(int level) -{ - int i; - - /* need to make sure the interrupt level won't be lowered */ - if (level) - sof_panic(SOF_IPC_PANIC_WFI); - - /* this sequence must be atomic on LX6 */ - XTOS_SET_INTLEVEL(5); - - /* LX6 needs a delay */ - for (i = 0; i < 128; i++) - asm volatile("nop"); - - /* and to flush all loads/stores prior to wait */ - asm volatile("isync"); - asm volatile("extw"); - - /* now wait */ - asm volatile("waiti 0"); -} - -#else - -static inline void arch_wait_for_interrupt(int level) -{ - /* need to make sure the interrupt level won't be lowered */ - if (level) - sof_panic(SOF_IPC_PANIC_WFI); - - asm volatile("waiti 0"); -} - -#endif - -static inline void idelay(int n) -{ - while (n--) - asm volatile("nop"); -} - -#endif /* __ARCH_LIB_WAIT_H__ */ diff --git a/src/arch/xtensa/include/arch/schedule/task.h b/src/arch/xtensa/include/arch/schedule/task.h deleted file mode 100644 index a4c17d07725f..000000000000 --- a/src/arch/xtensa/include/arch/schedule/task.h +++ /dev/null @@ -1,76 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2017 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - * Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -/** - * \file arch/xtensa/include/arch/schedule/task.h - * \brief Arch task header file - * \authors Liam Girdwood <liam.r.girdwood@linux.intel.com> - * Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#ifdef __XTOS_RTOS_TASK_H__ - -#ifndef __ARCH_SCHEDULE_TASK_H__ -#define __ARCH_SCHEDULE_TASK_H__ - -/** - * \brief Returns main task data. - * \return Pointer to pointer of main task data. - */ -struct task **task_main_get(void); - -/** - * \brief Returns current system context. - */ -volatile void *task_context_get(void); - -/** - * \brief Switches system context. - * \param[in,out] task_ctx Task context to be set. - */ -void task_context_set(void *task_ctx); - -/** - * \brief Allocates task context. - * \param[in,out] task_ctx Assigned to allocated structure on return. - */ -int task_context_alloc(void **task_ctx); - -/** - * \brief Initializes task context. - * \param[in,out] task_ctx Task context to be initialized. - * \param[in] entry Entry point for task execution. - * \param[in] arg0 First argument to be passed to entry function. - * \param[in] arg1 Second argument to be passed to entry function. - * \param[in] task_core Id of the core that task will be executed on. - * \param[in] stack Address of the stack, if NULL then allocated internally. - * \param[in] stack_size Size of the stack, ignored if stack is NULL. - */ -int task_context_init(void *task_ctx, void *entry, void *arg0, void *arg1, - int task_core, void *stack, int stack_size); - -/** - * \brief Frees task context. - * \param[in,out] task_ctx Task with context to be freed. - */ -void task_context_free(void *task_ctx); - -/** - * \brief Performs cache operation on task's context. - * \param[in,out] task_ctx Context to be wtb/inv. - * \param[in] cmd Cache operation to be performed. - */ -void task_context_cache(void *task_ctx, int cmd); - -#endif /* __ARCH_SCHEDULE_TASK_H__ */ - -#else - -#error "This file shouldn't be included from outside of XTOS's rtos/task.h" - -#endif /* __XTOS_RTOS_TASK_H__ */ diff --git a/src/arch/xtensa/include/arch/sof.h b/src/arch/xtensa/include/arch/sof.h deleted file mode 100644 index 622b1e417eff..000000000000 --- a/src/arch/xtensa/include/arch/sof.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - * Janusz Jankowski <janusz.jankowski@linux.intel.com> - */ - -#ifdef __XTOS_RTOS_SOF_H__ - -#ifndef __ARCH_SOF_H__ -#define __ARCH_SOF_H__ - -/* entry point to main firmware */ -void _ResetVector(void); - -void boot_primary_core(void); - -#endif /* __ARCH_SOF_H__ */ - -#else - -#error "This file shouldn't be included from outside of XTOS's rtos/sof.h" - -#endif /* __XTOS_RTOS_SOF_H__ */ diff --git a/src/arch/xtensa/include/arch/spinlock.h b/src/arch/xtensa/include/arch/spinlock.h deleted file mode 100644 index ee6cfc4670a1..000000000000 --- a/src/arch/xtensa/include/arch/spinlock.h +++ /dev/null @@ -1,132 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifdef __XTOS_RTOS_SPINLOCK_H__ - -#ifndef __ARCH_SPINLOCK_H__ -#define __ARCH_SPINLOCK_H__ - -#include <stdint.h> -#include <xtensa/config/core-isa.h> - -struct k_spinlock { - volatile uint32_t lock; -#if CONFIG_DEBUG_LOCKS - uint32_t user; -#endif -}; - -static inline void arch_spinlock_init(struct k_spinlock *lock) -{ - lock->lock = 0; -} - -#if XCHAL_HAVE_EXCLUSIVE && CONFIG_XTENSA_EXCLUSIVE && __XCC__ - -static inline void arch_spin_lock(struct k_spinlock *lock) -{ - uint32_t result; - - __asm__ __volatile__( - " movi %0, 0\n" - " l32ex %0, %1\n" - "1: movi %0, 1\n" - " s32ex %0, %1\n" - " getex %0\n" - " bnez %0, 1b\n" - : "=&a" (result) - : "a" (&lock->lock) - : "memory"); -} - -#elif XCHAL_HAVE_S32C1I - -static inline void arch_spin_lock(struct k_spinlock *lock) -{ - uint32_t result; - - /* TODO: Should be platform specific, since on SMP platforms - * without uncached memory region we'll need additional cache - * invalidations in a loop - */ - __asm__ __volatile__( - " movi %0, 0\n" - " wsr %0, scompare1\n" - "1: movi %0, 1\n" - " s32c1i %0, %1, 0\n" - " bnez %0, 1b\n" - : "=&a" (result) - : "a" (&lock->lock) - : "memory"); -} - -#else - -#if CONFIG_CORE_COUNT > 1 - -#error No atomic ISA for SMP configuration - -#endif /* CONFIG_CORE_COUNT > 1 */ - -/* - * The ISA has no atomic operations so use integer arithmetic on uniprocessor systems. - * This helps support GCC and qemu emulation of certain targets. - */ -static inline void arch_spin_lock(struct k_spinlock *lock) -{ - uint32_t result; - - do { - if (lock->lock == 0) { - lock->lock = 1; - result = 1; - } - } while (!result); -} - -#endif /* XCHAL_HAVE_EXCLUSIVE && CONFIG_XTENSA_EXCLUSIVE && __XCC__ */ - -#if XCHAL_HAVE_EXCLUSIVE || XCHAL_HAVE_S32C1I - -static inline void arch_spin_unlock(struct k_spinlock *lock) -{ - uint32_t result; - - __asm__ __volatile__( - " movi %0, 0\n" - " s32ri %0, %1, 0\n" - : "=&a" (result) - : "a" (&lock->lock) - : "memory"); -} - -#else - -#if CONFIG_CORE_COUNT > 1 - -#error No atomic ISA for SMP configuration - -#endif /* CONFIG_CORE_COUNT > 1 */ - -/* - * The ISA has no atomic operations so use integer arithmetic on uniprocessor systems. - * This helps support GCC and qemu emulation of certain targets. - */ -static inline void arch_spin_unlock(struct k_spinlock *lock) -{ - lock->lock = 0; -} - -#endif /* XCHAL_HAVE_EXCLUSIVE || XCHAL_HAVE_S32C1I */ - -#endif /* __ARCH_SPINLOCK_H__ */ - -#else - -#error "This file shouldn't be included from outside of sof/spinlock.h" - -#endif /* __SOF_SPINLOCK_H__ */ diff --git a/src/arch/xtensa/include/arch/string.h b/src/arch/xtensa/include/arch/string.h deleted file mode 100644 index 7832337f2059..000000000000 --- a/src/arch/xtensa/include/arch/string.h +++ /dev/null @@ -1,80 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifdef __XTOS_RTOS_STRING_H__ - -#ifndef __ARCH_STRING_H__ -#define __ARCH_STRING_H__ - -#include <xtensa/hal.h> -#include <errno.h> -#include <stddef.h> -#include <string.h> - -#define arch_memcpy(dest, src, size) \ - xthal_memcpy(dest, src, size) - -#define bzero(ptr, size) \ - memset_s(ptr, size, 0, size) - -void *xthal_memcpy(void *dst, const void *src, size_t len); - -int memset_s(void *dest, size_t dest_size, - int data, size_t count); -int memcpy_s(void *dest, size_t dest_size, - const void *src, size_t count); - -void *__vec_memcpy(void *dst, const void *src, size_t len); -void *__vec_memset(void *dest, int data, size_t src_size); - -static inline int arch_memcpy_s(void *dest, size_t dest_size, - const void *src, size_t count) -{ - if (!dest || !src) - return -EINVAL; - - if ((dest >= src && (char *)dest < ((char *)src + count)) || - (src >= dest && (char *)src < ((char *)dest + dest_size))) - return -EINVAL; - - if (count > dest_size) - return -EINVAL; - -#if __XCC__ && XCHAL_HAVE_HIFI3 && !CONFIG_LIBRARY - __vec_memcpy(dest, src, count); -#else - memcpy(dest, src, count); -#endif - - return 0; -} - -static inline int arch_memset_s(void *dest, size_t dest_size, - int data, size_t count) -{ - if (!dest) - return -EINVAL; - - if (count > dest_size) - return -EINVAL; - -#if __XCC__ && XCHAL_HAVE_HIFI3 && !CONFIG_LIBRARY - if (!__vec_memset(dest, data, count)) - return -ENOMEM; -#else - memset(dest, data, count); -#endif - return 0; -} - -#endif /* __ARCH_STRING_H__ */ - -#else - -#error "This file shouldn't be included from outside of sof/string.h" - -#endif /* __SOF_STRING_H__ */ diff --git a/src/arch/xtensa/include/xtensa/board.h b/src/arch/xtensa/include/xtensa/board.h deleted file mode 100644 index c6b04a250575..000000000000 --- a/src/arch/xtensa/include/xtensa/board.h +++ /dev/null @@ -1,28 +0,0 @@ -/* This header is supposed to be obtained from <board>/xtensa/board.h - using a -I directive passed to the compiler. */ - -#error "Unspecified board. Missing -I directive to select supported Xtensa board, usually -I XTENSA_TOOLS_ROOT/xtensa-elf/include/xtensa/<BOARD> (XTENSA_TOOLS_ROOT is root of Xtensa Tools install, see xt-run --show-config=xttools)" - -/* - * Copyright (c) 2013 Tensilica 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. - */ - diff --git a/src/arch/xtensa/include/xtensa/c6x-compat.h b/src/arch/xtensa/include/xtensa/c6x-compat.h deleted file mode 100755 index ca91bd718397..000000000000 --- a/src/arch/xtensa/include/xtensa/c6x-compat.h +++ /dev/null @@ -1,1758 +0,0 @@ -/* - * Copyright (c) 2006-2010 Tensilica Inc. ALL RIGHTS RESERVED. - * - * 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. - */ - -#ifndef __C6X_COMPAT__H -#define __C6X_COMPAT__H - -/* Unimplemented functions _gmpy, _gmpy4, _xormpy, _lssub, _cmpy, _cmpyr, - _cmpyr1, _ddotpl2r, _ddotph2r */ - - -typedef long long C6X_COMPAT_LONG40; - - -#define _memd8(a) (*((double*)(a))) -#define _memd8_const(a) (*((const double*)(a))) - -#define _amemd8(a) (*((double*)(a))) -#define _amemd8_const(a) (*((const double*)(a))) - -#define _mem8(a) (*((unsigned long long*)(a))) -#define _mem8_const(a) (*((const unsigned long long*)(a))) - -#define _mem4(a) (*((unsigned*)(a))) -#define _mem4_const(a) (*((const unsigned*)(a))) -#define _amem4_const(a) (*((const unsigned*)(a))) - -/* NOTE: To emulate a C6X properly you should define global variables - for your Xtensa with these names. Some of the emulation routines - will set these values. */ - -extern int _carry; -extern int _overflow; - -// Utility routines - - -#define TESTBIT(x,n) (((x) >> (n)) & 1) - -#define NSA_BITS 32 - -static inline unsigned int norm_shift_amt_U_and_non_U(int is_signed, int inp) { -int j=0, k=0; -int x=inp; -if (is_signed) { - /* Invert signed val if negative */ - x= TESTBIT(x,(NSA_BITS-1))? ~x: x; - x= (x&1)|(x<<1); /* Shift up to return count-1 */ - if (x ==0) - return NSA_BITS-1; - } - if (x ==0) - return NSA_BITS; - /* Now count leading zeros */ - for (j=0, k=NSA_BITS-1; k>=0; j++, k--) { - if (TESTBIT(x,k)) - return j; - } - return NSA_BITS; -} - - - -static inline long long -orig_L40_set( long long L40_var1) { - long long L40_var_out; - - L40_var_out = L40_var1 & 0x000000ffffffffffLL; - - if( L40_var1 & 0x8000000000LL) - L40_var_out = L40_var_out | 0xffffff0000000000LL; - - return( L40_var_out); -} - - - -static inline signed long long -util_saturate_n_no_state(signed long long t, int n) -{ - signed long long maxv, minv; - maxv = (1LL << (n-1)) - 1; - minv = (-1LL << (n-1)); - if (t > maxv) { - t = maxv; - } else if (t < minv) { - t = minv; - } - return t; -} - - -static inline signed long long -util_saturate_n_sgn(signed long long t, int n) -{ - signed long long result; - signed long long maxv, minv; - maxv = (1LL << (n-1)) - 1; - minv = (-1LL << (n-1)); - if (t > 0) { - result = maxv; - _overflow = 1; - } else if (t < 0) { - result = minv; - _overflow = 1; - } else { - result = 0; - } - return result; -} - - - - -/* well-behaved signed shift right (left on negative) with - saturation */ -static inline signed long long -util_shift_right_saturate_n(signed long long t, int shval, int n) -{ - /* n should be <= 62 */ - long long result; - - signed long long mask; - int actual_shift = shval; - long long shft = actual_shift > 0 ? actual_shift : -actual_shift; - - if (t == 0 || actual_shift == 0) - return t; - - if (actual_shift >= n) { - return (t < 0) ? -1 : 0; - } - if (actual_shift <= -n) { - return util_saturate_n_sgn(t, n); - } - if (actual_shift > 0) { - return t >> actual_shift; - } - /* actual_shift < 0. Check for saturation after shift. */ - mask = (-1LL << (n-shft-1)); - if (t > 0 && ((mask & t) != 0)) { - return util_saturate_n_sgn(t, n); - } - if (t < 0 && ((mask & t) != mask)) { - return util_saturate_n_sgn(t, n); - } - result = t << shft; - - return result; -} - - -/* Implemented c6x standard C compatibility functions (alphabetical - order) */ - - -static inline int _abs(int src1) { - if ((unsigned) src1 == (unsigned) 0x80000000) { - return 0x7fffffff; - } - return abs(src1); -} - - -static inline int _abs2(int src1) { - short s1[2],r[2]; - int result; - *((int*)s1) = src1; - if ((unsigned short) s1[1] == (unsigned short) 0x8000) r[1] = 0x7fff; - else r[1] = abs(s1[1]); - if ((unsigned short) s1[0] == (unsigned short) 0x8000) r[0] = 0x7fff; - else r[0] = abs(s1[0]); - result = *(int*)r; - return result; - } - - - - -static inline int _add2(int src1, int src2) { - short s1[2], s2[2], r[2]; - int result; - *((int*)s1) = src1; - *((int*)s2) = src2; - r[0] = s1[0] + s2[0]; - r[1] = s1[1] + s2[1]; - result = *(int*)r; - return result; -} - -static inline int _add4(int src1, int src2) { - char c1[4], c2[4], r[4]; - int result; - *((int*)c1) = src1; - *((int*)c2) = src2; - r[0] = c1[0] + c2[0]; - r[1] = c1[1] + c2[1]; - r[2] = c1[2] + c2[2]; - r[3] = c1[3] + c2[3]; - result = *(int*)r; - return result; -} - - - -static inline long long _addsub(unsigned int src1, unsigned int src2) -{ - - int res_lo; - int res_hi; - - res_hi = src1+src2; - res_lo = src1-src2; - return (((unsigned long long) res_hi) << 32) | ((unsigned int) res_lo) ; -} - - -static inline long long _addsub2(unsigned int src1, unsigned int src2) -{ - short s1[2], s2[2], ra[2], rs[2]; - int res_lo; - int res_hi; - - *((int*)s1) = src1; - *((int*)s2) = src2; - ra[0] = s1[0] + s2[0]; - ra[1] = s1[1] + s2[1]; - rs[0] = s1[0] - s2[0]; - rs[1] = s1[1] - s2[1]; - - res_hi = *(int*)ra; - res_lo = *(int*)rs; - return (((unsigned long long) res_hi) << 32) | ((unsigned int) res_lo) ; -} - - -static inline int _avg2(int src1, int src2) { - int low = (((int)1 + (short) src1 + (short) src2) >> 1) & 0XFFFF; - int high1 = src1 >> 16; - int high2 = src2 >> 16; - int high = ((high1 + high2 + 1) >> 1)<< 16; - return high | low; -} - - - -static inline unsigned int _avgu4(unsigned int src1, unsigned int src2) { -unsigned int res0 = ((src1 & 0xFF) + (src2 & 0xFF) + 1) >> 1; - unsigned int res1 = (((src1 & 0xFF00) >> 8) + ((src2 & 0xFF00) >> 8) + 1) >> 1; - unsigned int res2 = (((src1 & 0xFF0000) >> 16) + ((src2 & 0xFF0000) >> 16) + 1) >> 1; - unsigned int res3 = (((src1 & 0xFF000000) >> 24) + ((src2 & 0xFF000000) >> 24) + 1) >> 1; - return (res3 << 24) | (res2 << 16) | (res1 << 8) | res0; -} - - -static inline int TEN_popc (unsigned char b) -{ - int i, result = 0; - for (i = 0; i < 8; i++){ - if (b & 0x1) - result++; - b >>= 1; - } - return result; -} - -static inline unsigned int _bitc4(unsigned int src1) -{ - unsigned int res0 = TEN_popc(src1 & 0xFF); - unsigned int res1 = TEN_popc((src1 & 0xFF00) >> 8); - unsigned int res2 = TEN_popc((src1 & 0xFF0000) >> 16); - unsigned int res3 = TEN_popc((src1 & 0xFF000000) >> 24); - return (res3 << 24) | (res2 << 16) | (res1 << 8) | res0; -} - -static inline unsigned int _bitr(unsigned int src) { - int i; - unsigned r = 0; - for (i = 0; i< 32; ++i) { - r = r | (((src >> i) & 1)<<(31-i)); - } - return r; -} - - -static inline unsigned int _clr(unsigned int src2, int csta, int cstb) -{ - csta &= 0x1f; - cstb &= 0x1f; - if (csta > cstb) - return src2; - else { - unsigned int mask = (((1 << (cstb - csta)) << 1) - 1) << csta; - return src2 & (~mask); - } -} - -static inline unsigned int _clrr(unsigned int src2, int src1) -{ - unsigned int csta = (src1 >> 5) & 0x1f; - unsigned int cstb = src1 & 0x1f; - if (csta > cstb) - return src2; - else { - unsigned int mask = (((1 << (cstb - csta)) << 1) - 1) << csta; - return src2 & (~mask); - } -} - - - - -static inline int _cmpeq2(int src1, int src2) { - short s1[2], s2[2]; - int r0, r1; - int result; - *((int*)s1) = src1; - *((int*)s2) = src2; - r0 = s1[0] == s2[0] ? 1 : 0; - r1 = s1[1] == s2[1] ? 1 : 0; - result = (r1 << 1) | r0; - return result; -} - -static inline int _cmpeq4(int src1, int src2) { - char s1[4], s2[4]; - int r0, r1, r2, r3; - int result; - *((int*)s1) = src1; - *((int*)s2) = src2; - r0 = s1[0] == s2[0] ? 1 : 0; - r1 = s1[1] == s2[1] ? 1 : 0; - r2 = s1[2] == s2[2] ? 1 : 0; - r3 = s1[3] == s2[3] ? 1 : 0; - result = (r3 << 3) | (r2 << 2) | (r1 << 1) | r0; - return result; -} - - -static inline int _cmpgt2(int src1, int src2) { - short s1[2], s2[2]; - int r1, r0; - int result; - *((int*)s1) = src1; - *((int*)s2) = src2; - r0 = s1[0] > s2[0] ? 1 : 0; - r1 = s1[1] > s2[1] ? 1 : 0; - result = (r1<<1) | r0; - return result; -} - - -static inline unsigned int _cmpgtu4(unsigned int src1, unsigned int src2) { - unsigned int s1_0 = (src1 & 0xFF); - unsigned int s1_1 = (src1 & 0xFF00) >> 8; - unsigned int s1_2 = (src1 & 0xFF0000) >> 16; - unsigned int s1_3 = (src1 & 0xFF000000) >> 24; - - unsigned int s2_0 = (src2 & 0xFF); - unsigned int s2_1 = (src2 & 0xFF00) >> 8; - unsigned int s2_2 = (src2 & 0xFF0000) >> 16; - unsigned int s2_3 = (src2 & 0xFF000000) >> 24; - - unsigned int result = 0; - - if (s1_0 > s2_0) - result |= 0x1; - - if (s1_1 > s2_1) - result |= 0x2; - - if (s1_2 > s2_2) - result |= 0x4; - - if (s1_3 > s2_3) - result |= 0x8; - - return result; -} - - - - -static inline long long _ddotp4(unsigned int src1, unsigned int src2) { - unsigned int res0, res1; - short s1_0 = (src1 & 0xffff); - short s1_1 = (src1 & 0xfff0000) >> 16; - - unsigned short s2_0 = (src2 & 0xff); - unsigned short s2_1 = (src2 & 0xff00) >> 8; - unsigned short s2_2 = (src2 & 0xff0000) >> 16; - unsigned short s2_3 = (src2 & 0xff000000) >> 24; - - res0 = ((int)s1_0) * s2_0 + ((int)s1_1) * s2_1; - res1 = ((int)s1_0) * s2_2 + ((int)s1_1) * s2_3; - - return (res1 << 16) | res0; -} - - -static inline long long _ddotph2(long long src1_o_src1_e, unsigned int src2) -{ - - unsigned int src1_o = src1_o_src1_e >> 32; - unsigned int src1_e = src1_o_src1_e & 0xFFFFFFFF; - short ls1_o = src1_o & 0XFFFF; - short hs1_o = src1_o >> 16; -// short ls1_e = src1_e & 0XFFFF; - short hs1_e = src1_e >> 16; - short ls2 = src2 & 0XFFFF; - short hs2 = src2 >> 16; - - unsigned long long res_hi = ls2 * ls1_o + hs2 * hs1_o; - unsigned int res_lo = ls1_o * hs2 + hs1_e * ls2; - return (res_hi << 32) | res_lo; -} - - -static inline long long _ddotpl2(long long src1_o_src1_e, unsigned int src2) -{ - unsigned int src1_o = src1_o_src1_e >> 32; - unsigned int src1_e = src1_o_src1_e & 0xFFFFFFFF; - short ls1_o = src1_o & 0XFFFF; -// short hs1_o = src1_o >> 16; - short ls1_e = src1_e & 0XFFFF; - short hs1_e = src1_e >> 16; - short ls2 = src2 & 0XFFFF; - short hs2 = src2 >> 16; - - unsigned long long res_hi = ls2 * hs1_e + hs2 * ls1_o; - unsigned res_lo = hs1_e * hs2 + ls1_e * ls2; - return (res_hi << 32) | res_lo; -} - - -static inline unsigned int _deal(unsigned int src) -{ - int i; - unsigned short lo = 0, hi = 0; - for (i = 0; i < 32; i+= 2) { - lo >>= 1; - lo |= (src & 0x1) << 15; - src >>= 1; - hi >>= 1; - hi |= (src & 0x1) << 15; - src >>= 1; - } - return (hi << 16) | lo; -} - - -static inline long long _dmv(unsigned int src1, unsigned int src2) -{ - return (((long long) src1) << 32) | src2; -} - - -static inline int _dotpn2(int src1, int src2) { -short int s1_h = src1>>16; - short int s1_l = src1; - short int s2_h = src2>>16; - short int s2_l = src2; - return s1_h * s2_h - s1_l * s2_l; -} - - -static inline int _dotp2(int src1, int src2) { - short int s1_h = src1>>16; - short int s1_l = src1; - short int s2_h = src2>>16; - short int s2_l = src2; - return s1_h * s2_h + s1_l * s2_l; -} - - - -static inline int _dotpnrsu2(int src1, unsigned int src2) -{ - short ls1 = src1 & 0XFFFF; - unsigned short ls2 = src2 & 0XFFFF; - short hs1 = src1 >> 16; - unsigned short hs2 = src2 >> 16; - - int result = (((long long) (int)(hs1 * hs2)) - ((long long) (int)(ls1 * ls2)) + (1 << 15)) >> 16; - return result; -} - - - -static inline int _dotprsu2(int src1, unsigned int src2) { - short ls1 = src1 & 0XFFFF; - unsigned short ls2 = (src2 & 0XFFFF); - short hs1 = src1 >> 16; - unsigned short hs2 = (src2 >> 16); - - int result = (((long long) (int) (ls1 * ls2)) + ((long long) (int) (hs1 * hs2)) + (1LL << 15)) >> 16; - return result; -} - - - - - - - -static inline int _dotpsu4(int src1, unsigned int src2) { - int result; - signed char s1_0 = (src1 & 0xff); - signed char s1_1 = (src1 & 0xff00) >> 8; - signed char s1_2 = (src1 & 0xff0000) >> 16; - signed char s1_3 = (src1 & 0xff000000) >> 24; - - unsigned int s2_0 = (src2 & 0xff); - unsigned int s2_1 = (src2 & 0xff00) >> 8; - unsigned int s2_2 = (src2 & 0xff0000) >> 16; - unsigned int s2_3 = (src2 & 0xff000000) >> 24; - - result = s1_0 * s2_0 + s1_1 * s2_1 + s1_2 * s2_2 + s1_3 * s2_3; - return result; -} - - -static inline unsigned int _dotpu4(unsigned int src1, unsigned int src2) { - unsigned char v1_0 = src1 & 0xff; - unsigned char v1_1 = (src1>>8) & 0xff; - unsigned char v1_2 = (src1>>16) & 0xff; - unsigned char v1_3 = (src1>>24) & 0xff; - - unsigned char v2_0 = src2 & 0xff; - unsigned char v2_1 = (src2>>8) & 0xff; - unsigned char v2_2 = (src2>>16) & 0xff; - unsigned char v2_3 = (src2>>24) & 0xff; - - unsigned v = v1_0 * v2_0 + v1_1 * v2_1 + v1_2 * v2_2 + v1_3 * v2_3; - return v; -} - - -static inline long long _dpack2(unsigned int src1, unsigned int src2){ -unsigned short s1[2], s2[2]; -*((int*)s1) = src1; -*((int*)s2) = src2; -return ((unsigned long long) s1[1] << 48) | ((unsigned long long) s2[1] << 32) | ((unsigned long long) s1[0] << 16) | ((unsigned long long) s2[0]); -} - - -static inline long long _dpackx2(unsigned int src1, unsigned int src2){ -unsigned short s1[2], s2[2]; -*((int*)s1) = src1; -*((int*)s2) = src2; -return ((unsigned long long) s2[0] << 48) | ((unsigned long long) s1[1] << 32) | ((unsigned long long) s1[0] << 16) | ((unsigned long long) s2[1]); -} - -static inline int _ext(int src2, unsigned int csta, unsigned int cstb) -{ - return (src2 << csta) >> cstb; -} - -static inline int _extr(int src2, int src1) -{ - unsigned int csta = (src1 >> 5) & 0x1f; - unsigned int cstb = src1 & 0x1f; - return (src2 << csta) >> cstb; -} - -static inline unsigned int _extu(unsigned int src2, unsigned int csta, unsigned int cstb) -{ - return (src2 << csta) >> cstb; -} - -static inline unsigned int _extur(unsigned int src2, int src1) -{ - unsigned int csta = (src1 >> 5) & 0x1f; - unsigned int cstb = src1 & 0x1f; - return (src2 << csta) >> cstb; -} - - -static inline unsigned long long _hi(double src) { - unsigned long long v; - *(double*)&v = src; - return v>>32; -} - -static inline unsigned int _hill (long long src) -{ - return (unsigned int) (src >> 32); -} - - - -static inline double _itod(unsigned hi, unsigned lo) { - double v; - unsigned long long ll = ((((unsigned long long)(hi))<<32) | (unsigned long long)((unsigned)lo)); - *((unsigned long long *)&v) = ll; - return v; -} - - -static inline long long _itoll(unsigned int src2, unsigned int src1) -{ - return (((long long) src2) << 32) | src1; -} - - -static inline C6X_COMPAT_LONG40 _labs(C6X_COMPAT_LONG40 src2) -{ - long long maxv = (1LL << (40 -1)) - 1; - long long minv = (-1LL << (40 - 1)); - C6X_COMPAT_LONG40 lres = orig_L40_set(src2); - - lres = lres < 0 ? -lres : lres; - if (lres > maxv) lres = maxv; - else if (lres < minv) lres = minv; - - return lres; -} - - -static inline C6X_COMPAT_LONG40 _ldotp2(int src1, int src2) { -return (C6X_COMPAT_LONG40) _dotp2(src1, src2); -} - - -static inline unsigned int _lmbd(unsigned int src1, unsigned int src2) -{ - return norm_shift_amt_U_and_non_U(0,(((int) (src1 << 31)) >> 31) ^ (~src2)); -} - - -static inline unsigned int _lnorm(C6X_COMPAT_LONG40 src2) { -if (src2 == 0) - return 39; - else { - int hi = (int)(src2 >> 32); - int lo = (int)src2; - - - long long temp = (unsigned long long)(unsigned)lo | (unsigned long long)hi << 32; - temp = orig_L40_set(temp); - - if (temp == 0) return 0; - int cnt = 0; - while (((temp >> 39) & 1) == ((temp >> 38) & 1)) { - temp <<= 1; - cnt++; - } - return cnt; - } -} - - -static inline unsigned long long _lo(double src) { - unsigned long long v; - *(double*)&v = src; - return v; -} - - -static inline unsigned int _loll (long long src) -{ - return (unsigned int) src; -} - - -static inline C6X_COMPAT_LONG40 _lsadd(int src1, C6X_COMPAT_LONG40 src2) -{ - long long maxv = (1LL << (40 -1)) - 1; - long long minv = (-1LL << (40 - 1)); - int hi = (int)(src2 >> 32); - int lo = (int)src2; - long long src2_int = (unsigned long long)(unsigned)lo | (unsigned long long)hi << 32; - - - long long src2_int2 = orig_L40_set(src2_int); - - long long res = src1 + src2_int2; - - if (res > maxv) { - res = maxv; - _overflow = 1; - } - else if (res < minv) { - res = minv; - _overflow = 1; - } - - long long res2 = orig_L40_set(res); - - res2 = (signed char)(res2 >> 32); - - C6X_COMPAT_LONG40 lres = (((C6X_COMPAT_LONG40) res2) << 32) | ((unsigned int)res); - return lres; -} - - - -static inline int _max2 (int src1, int src2) { - short s1[2], s2[2], r[2]; - int result; - *((int*)s1) = src1; - *((int*)s2) = src2; - r[0] = s1[0] > s2[0] ? s1[0] : s2[0]; - r[1] = s1[1] > s2[1] ? s1[1] : s2[1]; - result = *(int*)r; - return result; -} - - - - - - -static inline unsigned int _maxu4(unsigned int src1, unsigned int src2) { - unsigned int res0, res1, res2, res3; - unsigned int s1_0 = res0 = (src1 & 0xFF); - unsigned int s1_1 = res1 = (src1 & 0xFF00) >> 8; - unsigned int s1_2 = res2 = (src1 & 0xFF0000) >> 16; - unsigned int s1_3 = res3 = (src1 & 0xFF000000) >> 24; - - unsigned int s2_0 = (src2 & 0xFF); - unsigned int s2_1 = (src2 & 0xFF00) >> 8; - unsigned int s2_2 = (src2 & 0xFF0000) >> 16; - unsigned int s2_3 = (src2 & 0xFF000000) >> 24; - -// unsigned int res = 0; - - if (s1_0 < s2_0) - res0 = s2_0; - - if (s1_1 < s2_1) - res1 = s2_1; - - if (s1_2 < s2_2) - res2 = s2_2; - - if (s1_3 < s2_3) - res3 = s2_3; - - return (res3 << 24) | (res2 << 16) | (res1 << 8) | res0; - - -} - -static inline int _min2(int src1, int src2) { - short s1[2], s2[2], r[2]; - int result; - *((int*)s1) = src1; - *((int*)s2) = src2; - r[0] = s1[0] < s2[0] ? s1[0] : s2[0]; - r[1] = s1[1] < s2[1] ? s1[1] : s2[1]; - result = *(int*)r; - return result; -} - - -static inline unsigned int _minu4(unsigned int src1, unsigned int src2) { -unsigned int res0, res1, res2, res3; - unsigned int s1_0 = res0 = (src1 & 0xFF); - unsigned int s1_1 = res1 = (src1 & 0xFF00) >> 8; - unsigned int s1_2 = res2 = (src1 & 0xFF0000) >> 16; - unsigned int s1_3 = res3 = (src1 & 0xFF000000) >> 24; - - unsigned int s2_0 = (src2 & 0xFF); - unsigned int s2_1 = (src2 & 0xFF00) >> 8; - unsigned int s2_2 = (src2 & 0xFF0000) >> 16; - unsigned int s2_3 = (src2 & 0xFF000000) >> 24; - -// unsigned int res = 0; - - if (s1_0 > s2_0) - res0 = s2_0; - - if (s1_1 > s2_1) - res1 = s2_1; - - if (s1_2 > s2_2) - res2 = s2_2; - - if (s1_3 > s2_3) - res3 = s2_3; - - return (res3 << 24) | (res2 << 16) | (res1 << 8) | res0; -} - - -static inline int _mpy(int src1, int src2) { -return (short) src1 * (short) src2; -} - - -static inline int _mpyh(int src1, int src2) { -return (short) (src1 >> 16) * (short) (src2 >> 16); -} - - -static inline long long _mpyhill (int src1, int src2) -{ - short s1 = src1 >> 16; - return ((long long) src2) * s1; -} - -static inline int _mpyhir(int src1, int src2) -{ - short s1 = src1 >> 16; - long long result = ((long long) src2) * s1 + (1 << 14); - result >>= 15; - return result; -} - - -static inline int _mpyhl(int src1, int src2) { -return (short) (src1 >> 16) * (short) (src2); -} - -static inline unsigned int _mpyhlu(unsigned int src1, unsigned int src2) { -return (unsigned short) (src1 >> 16) * (unsigned short) (src2); -} - -static inline int _mpyhslu(int src1, unsigned int src2) { -return (short) (src1 >> 16) * (unsigned short) src2; -} - - -static inline int _mpyhsu(int src1, unsigned int src2) { -return (short) (src1 >>16) * (unsigned short) (src2 >>16); -} - - -static inline unsigned int _mpyhu(unsigned int src1, unsigned int src2) { -return (unsigned short) (src1 >>16) * (unsigned short) (src2 >> 16); -} - - -static inline int _mpyhuls(unsigned int src1, int src2) { -return (unsigned short) (src1 >>16) * (signed short) (src2); -} - - -static inline int _mpyhus(unsigned int src1, int src2) { -return (unsigned short) (src1 >> 16) * (short) (src2 >>16); -} - - - -static inline long long _mpyidll (int src1, int src2) -{ - return (long long) src1 * src2; -} - - -static inline int _mpylh(int src1, int src2) { -return (signed short) (src1 & 0xffff) * (signed short) (src2 >> 16); -} - -static inline unsigned int _mpylhu(unsigned int src1, unsigned int src2) { -return (unsigned short) src1 * (unsigned short) (src2 >> 16); -} - - -static inline long long _mpylill (int src1, int src2) -{ - return ((long long) src2) * ((short)src1); -} - - - -static inline int _mpylir(int src1, int src2) -{ - short s1 = src1; - long long result = ((long long) src2) * s1 + (1 << 14); - result >>= 15; - return result; -} - - -static inline int _mpylshu(int src1, unsigned int src2) { -return (short) src1 * (unsigned short) (src2 >> 16); -} - - -static inline int _mpyluhs(unsigned int src1, int src2) { -return (unsigned short) src1 * (short) (src2 >> 16); -} - - - -static inline int _mpysu(int src1, unsigned int src2) { -return (short) src1 * (unsigned short) src2; -} - - - -static inline long long _mpysu4ll (int src1, unsigned int src2) { - unsigned short res0, res1, res2, res3; - signed char s1_0 = (src1 & 0xff); - signed char s1_1 = (src1 & 0xff00) >> 8; - signed char s1_2 = (src1 & 0xff0000) >> 16; - signed char s1_3 = (src1 & 0xff000000) >> 24; - - unsigned short s2_0 = (src2 & 0xff); - unsigned short s2_1 = (src2 & 0xff00) >> 8; - unsigned short s2_2 = (src2 & 0xff0000) >> 16; - unsigned short s2_3 = (src2 & 0xff000000) >> 24; - - res0 = s1_0 * s2_0; - res1 = s1_1 * s2_1; - res2 = s1_2 * s2_2; - res3 = s1_3 * s2_3; - - return (((unsigned long long) res3) << 48) - | (((unsigned long long) res2) << 32) - | (((unsigned long long) res1) << 16) - | res0; -} - -static inline unsigned int _mpyu(unsigned int src1, unsigned int src2) { - unsigned v = (unsigned short)src1 * (unsigned short)src2; - return v; -} - -static inline int _mpyus(unsigned int src1, int src2) { -return (unsigned short) src1 * (short) src2; -} - -static inline long long _mpyu4ll (unsigned int src1, unsigned int src2) { - unsigned short res0, res1, res2, res3; - unsigned char s1_0 = (src1 & 0xff); - unsigned char s1_1 = (src1 & 0xff00) >> 8; - unsigned char s1_2 = (src1 & 0xff0000) >> 16; - unsigned char s1_3 = (src1 & 0xff000000) >> 24; - - unsigned short s2_0 = (src2 & 0xff); - unsigned short s2_1 = (src2 & 0xff00) >> 8; - unsigned short s2_2 = (src2 & 0xff0000) >> 16; - unsigned short s2_3 = (src2 & 0xff000000) >> 24; - - res0 = s1_0 * s2_0; - res1 = s1_1 * s2_1; - res2 = s1_2 * s2_2; - res3 = s1_3 * s2_3; - - return (((unsigned long long) res3) << 48) - | (((unsigned long long) res2) << 32) - | (((unsigned long long) res1) << 16) - | res0; -} - - -static inline long long _mpy2ir(unsigned int src1, unsigned int src2) -{ - if ((src1 == 0x8000) && (src2 == 0x80000000)) { - _overflow = 1; - return 0; - } - else { - short ls1 = src1 & 0xffff; - short hs1 = src1 >> 16; - unsigned long long hi = (((long long) hs1) * (int) src2 + (1 << 14)) >> 15; - unsigned long long lo = ((((long long) ls1) * (int) src2 + (1 << 14)) >> 15) & 0xFFFFFFFF; - return (hi << 32) | lo; - } -} - - -static inline long long _mpy2ll (int src1, int src2) { - short ls1 = src1 & 0xffff; - short hs1 = src1 >> 16; - short ls2 = src2 & 0xffff; - short hs2 = src2 >> 16; - - unsigned long long hi = hs1 * hs2; - unsigned long long lo = (ls1 * ls2) & 0xFFFFFFFF; - - return (hi << 32) | lo; - -} - - -static inline int _mpy32(int src1, int src2) -{ - return src1 * src2; -} - - -static inline long long _mpy32ll(int src1, int src2) -{ - return ((long long) src1) * src2; -} - -static inline long long _mpy32su(int src1, unsigned int src2) -{ - return ((long long) src1) * ((int) src2); -} - -static inline long long _mpy32u(unsigned int src1, unsigned int src2) -{ - return ((long long) ((int) src1)) * ((long long) ((int) src2)); -} - -static inline long long _mpy32us(unsigned int src1, int src2) -{ - return ((int) src1) * ((long long) src2); -} - -static inline int _mvd (int src2) -{ - return src2; -} - - -static inline unsigned int _norm(int src2) -{ - return norm_shift_amt_U_and_non_U(1,src2); -} - - -static inline unsigned int _pack2 (unsigned int src1, unsigned int src2) { - short s1[2], s2[2], r[2]; - int result; - *((int*)s1) = src1; - *((int*)s2) = src2; - r[0] = s2[0]; - r[1] = s1[0]; - result = *(int*)r; - return result; -} - - -static inline int _packh2 (unsigned int src1, unsigned int src2) { - unsigned v0 = src1 & 0xffff0000; - unsigned v1 = src2 >> 16; - unsigned v = v0|v1; - return v; - -} - -static inline unsigned int _packh4 (unsigned int src1, unsigned int src2) { - unsigned v3 = (src1 >> 24) & 0xff; - unsigned v2 = (src1 >> 8) & 0xff; - unsigned v1 = (src2 >> 24) & 0xff; - unsigned v0 = (src2 >> 8) & 0xff; - unsigned v = (v3<<24) | (v2<<16) | (v1 << 8) | v0; - return v; -} - -static inline unsigned int _packhl2 (unsigned int src1, unsigned int src2) { - unsigned v0 = src1 & 0xffff0000; - unsigned v1 = src2 & 0x0000ffff; - unsigned v = v0|v1; - return v; -} - -static inline unsigned int _packlh2 (unsigned int src1, unsigned int src2) { - unsigned v0 = src1 << 16; - unsigned v1 = (src2 >> 16) & 0xffff; - unsigned v = v0|v1; - return v; -} - - - - -static inline unsigned int _packl4 (unsigned int src1, unsigned int src2) { - unsigned v3 = (src1 >> 16) & 0xff; - unsigned v2 = (src1) & 0xff; - unsigned v1 = (src2 >> 16) & 0xff; - unsigned v0 = (src2) & 0xff; - unsigned v = (v3<<24) | (v2<<16) | (v1 << 8) | v0; - return v; -} - - - - -static inline unsigned int _rpack2 (unsigned int src1, unsigned int src2) { -int s1 = (int) src1; -int s2 = (int) src2; -s1 = util_shift_right_saturate_n (s1, -1, 32); -s2 = util_shift_right_saturate_n (s2, -1, 32); -return (unsigned int) (s1 & 0xffff0000) | (unsigned int) ((s2 & 0xffff0000) >>16); -} - - -static inline unsigned int _rotl (unsigned int src1, unsigned int src2) -{ - src2 &= 0x1f; - return (src1 << src2) | (src1 >> (32 - src2)); -} - - -static inline int _sadd(int src1, int src2) { -signed long long res; -signed long long maxv, minv; -maxv = (1LL << (32-1)) - 1; -minv = (-1LL << (32-1)); -res = (long long) src1 + (long long) src2; -if (res > maxv) { - res = maxv; - _overflow = 1; - } -else if (res < minv ) { - res = minv; - _overflow = 1; - } -return (int) res; -} - -static inline long long _saddsub(unsigned int src1, unsigned int src2) { -int radd; -signed long long rsub; - -signed long long maxv, minv; -maxv = (1LL << (32-1)) - 1; -minv = (-1LL << (32-1)); - -radd = (int) src1 + (int) src2; - -// saturate on subtract, not add - - -rsub = (long long) ((int) src1) - (long long) ((int) src2); -if (rsub > maxv) { - rsub = maxv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } -else if (rsub < minv ) { - rsub = minv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } - -return (((unsigned long long) radd) << 32) | ( rsub & 0x00000000ffffffff ) ; -} - - - -static inline long long _saddsub2(unsigned int src1, unsigned int src2) { -signed int radd[2]; -signed int rsub[2]; -signed short s1[2], s2[2]; - -signed int maxv, minv; -maxv = (1L << (16-1)) - 1; -minv = (-1L << (16-1)); - -*((int*)s1) = src1; -*((int*)s2) = src2; - -radd[0] = (int) s1[0] + (int) s2[0]; -radd[1] = (int) s1[1] + (int) s2[1]; - -rsub[0] = (int) s1[0] - (int) s2[0]; -rsub[1] = (int) s1[1] - (int) s2[1]; - -if (radd[0] > maxv) { - radd[0] = maxv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } -else if (radd[0] < minv ) { - radd[0] = minv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } - -if (radd[1] > maxv) { - radd[1] = maxv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } -else if (radd[1] < minv ) { - radd[1] = minv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } - - -if (rsub[0] > maxv) { - rsub[0] = maxv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } -else if (rsub[0] < minv ) { - rsub[0] = minv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } - -if (rsub[1] > maxv) { - rsub[1] = maxv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } -else if (rsub[1] < minv ) { - rsub[1] = minv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } - - -return ((((unsigned long long) radd[1]) & 0x000000000000ffff) << 48) | - ((((unsigned long long) radd[0]) & 0x000000000000ffff) << 32) | - ((((unsigned long long) rsub[1]) & 0x000000000000ffff) << 16) | - ((((unsigned long long) rsub[0]) & 0x000000000000ffff)); -} - - - -static inline int _sadd2(int src1, int src2) { -signed short s1[2], s2[2]; -signed int r[2], maxv, minv; - -maxv = (1L << (16-1)) - 1; -minv = (-1L << (16-1)); - - -*((int*)s1) = src1; -*((int*)s2) = src2; - -r[0] = (int) s1[0] + (int) s2[0]; -r[1] = (int) s1[1] + (int) s2[1]; - -if (r[0] > maxv) { - r[0] = maxv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } -else if (r[0] < minv ) { - r[0] = minv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } -if (r[1] > maxv) { - r[1] = maxv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } -else if (r[1] < minv ) { - r[1] = minv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } - -return ((r[1] & 0xffff) << 16 ) | (r[0] & 0xffff) ; -} - - -static inline int _saddus2(unsigned int src1, int src2) { -int res0, res1; - unsigned int s1_0 = (src1 & 0xffff); - unsigned int s1_1 = (src1 & 0xffff0000) >> 16; - - short s2_0 = (src2 & 0xffff); - short s2_1 = (src2 & 0xffff0000) >> 16; - - res0 = s1_0 + s2_0; - res1 = s1_1 + s2_1; - - if (res0 >= 0x10000) - res0 = 0xffff; - else if (res0 < 0) - res0 = 0; - - if (res1 >= 0x10000) - res1 = 0xffff; - else if (res1 < 0) - res1 = 0; - - return (res1 << 16) | res0; -} - - -static inline unsigned int _saddu4(unsigned int src1, unsigned int src2) { -unsigned int res0, res1, res2, res3; - unsigned int s1_0 = (src1 & 0xff); - unsigned int s1_1 = (src1 & 0xff00) >> 8; - unsigned int s1_2 = (src1 & 0xff0000) >> 16; - unsigned int s1_3 = (src1 & 0xff000000) >> 24; - - unsigned int s2_0 = (src2 & 0xff); - unsigned int s2_1 = (src2 & 0xff00) >> 8; - unsigned int s2_2 = (src2 & 0xff0000) >> 16; - unsigned int s2_3 = (src2 & 0xff000000) >> 24; - - res0 = s1_0 + s2_0; - res1 = s1_1 + s2_1; - res2 = s1_2 + s2_2; - res3 = s1_3 + s2_3; - - if (res0 >= 0x100) - res0 = 0xff; - - if (res1 >= 0x100) - res1 = 0xff; - - if (res2 >= 0x100) - res2 = 0xff; - - if (res3 >= 0x100) - res3 = 0xff; - - return (res3 << 24) | (res2 << 16) | (res1 << 8) | res0; - -} - - - -static inline int _sat(C6X_COMPAT_LONG40 src2) -{ - long long maxv = (1LL << (32-1)) - 1; - long long minv = (-1LL << (32-1)); - - int hi = (int)(src2 >> 32); - int lo = (int)src2; - long long temp = (unsigned long long)(unsigned)lo | (unsigned long long)hi << 32; - temp = orig_L40_set(temp); - - if (temp > maxv) { - temp = maxv; - _overflow = 1; - } - else if (temp < minv) { - temp = minv; - _overflow = 1; - } - return (int) temp; -} - -static inline unsigned int _set(unsigned int src2, unsigned int csta, unsigned int cstb) -{ - csta &= 0x1f; - cstb &= 0x1f; - if (csta > cstb) - return src2; - else { - unsigned int mask = (((1 << (cstb - csta)) << 1) - 1) << csta; - return src2 | mask; - } -} - -static inline unsigned int _setr(unsigned int src2, int src1) -{ - unsigned int csta = (src1 >> 5) & 0x1f; - unsigned int cstb = src1 & 0x1f; - if (csta > cstb) - return src2; - else { - unsigned int mask = (((1 << (cstb - csta)) << 1) - 1) << csta; - return src2 | mask; - } -} - - -static inline unsigned int _shfl (unsigned int src2) -{ - unsigned short lo = src2; - unsigned short hi = src2 >> 16; - unsigned int result = 0; - int i; - for (i = 0; i < 32; i+= 2) { - result >>= 1; - result |= (lo & 0x1) << 31; - lo >>= 1; - result >>= 1; - result |= (hi & 0x1) << 31; - hi >>= 1; - } - return result; -} - -static inline long long _shfl3 (unsigned int src1, unsigned int src2) -{ - unsigned short lo = src2; - unsigned short hi = src1 >> 16; - unsigned short mid = src1; - unsigned long long result = 0; - int i; - for (i = 0; i < 32; i+= 2) { - result >>= 1; - result |= ((unsigned long long) (lo & 0x1)) << 47; - lo >>= 1; - result >>= 1; - result |= ((unsigned long long) (mid & 0x1)) << 47; - mid >>= 1; - result >>= 1; - result |= ((unsigned long long) (hi & 0x1)) << 47; - hi >>= 1; - } - return result; -} - - - -static inline unsigned int _shlmb (unsigned int src1, unsigned int src2) -{ - return (src2 << 8) | (src1 >> 24); -} - -static inline unsigned int _shrmb (unsigned int src1, unsigned int src2) -{ - return (src2 >> 8) | (src1 << 24); -} - - -static inline unsigned int _shru2 (unsigned int src1, unsigned int src2) { -unsigned short hs1 = src1 >> 16; - unsigned short ls1 = src1 & 0xFFFF; - hs1 >>= src2; - ls1 >>= src2; - return (hs1 << 16) | ls1; -} - - -static inline int _shr2 (int src1, unsigned int src2) { - short s1[2], result[2]; - *((int*)s1) = src1; - src2 = src2 & 31; - result[0] = (int)s1[0] >> src2; - result[1] = (int)s1[1] >> src2; - - return *(int*)result; -} - - -static inline int _smpy (int src1, int src2) { -unsigned long long result; -result = (((short) src1 * (short) src2) << 1); - -if ((result & 0xffffffff) == 0x80000000){ - result = 0x7fffffff; - _overflow = 1; - } -return (int) (result); -} - -static inline int _smpyh (int src1, int src2) { -unsigned long long result; -result = ((short) (src1 >> 16) * (short) (src2 >> 16)) << 1; -if ((result & 0xffffffff) == 0x80000000){ - result = 0x7fffffff; - _overflow = 1; - } -return (int) (result); -} - -static inline int _smpyhl (int src1, int src2) { -unsigned long long result; -result = ((short) (src1 >> 16) * (short) (src2)) << 1; -if ((result & 0xffffffff) == 0x80000000){ - result = 0x7fffffff; - _overflow = 1; - } -return (int) (result); -} - -static inline int _smpylh (int src1, int src2) { -unsigned long long result; -result = ((short) (src1) * (short) (src2 >> 16)) << 1; -if ((result & 0xffffffff) == 0x80000000){ - result = 0x7fffffff; - _overflow = 1; - } -return (int) (result); -} - -static inline long long _smpy2ll (int src1, int src2) { - short ls1 = src1 & 0XFFFF; - short hs1 = src1 >> 16; - short ls2 = src2 & 0XFFFF; - short hs2 = src2 >> 16; - - unsigned long long hi = (hs1 * hs2) << 1; - unsigned long long lo = ((ls1 * ls2) << 1) & 0xFFFFFFFF; - if ((hi & 0xffffffff) == 0x80000000){ - hi = 0x7fffffff; - _overflow = 1; - } - - if ((lo & 0xffffffff) == 0x80000000){ - lo = 0x7fffffff; - _overflow = 1; - } - - return (hi << 32) | lo; -} - - - - -static inline int _smpy32(int src1, int src2) -{ - long long res = (long long) src1 * src2; - res <<= 1; - res >>= 32; - return res; -} - -static inline unsigned char TEN_satu8 (short src) -{ - if (src > 0xff) - return 0xff; - else if (src < 0) - return 0; - else - return src; -} - -static inline int _spack2 (int src1, int src2) { -short s1 = (short) util_saturate_n_no_state(src1,16); -short s2 = (short) util_saturate_n_no_state(src2,16); -return ( (unsigned int) s1 << 16) | (((int) s2) & 0xFFFF); -} - - -static inline unsigned int _spacku4 (int src1, int src2) { - short lolo = src2; - short lohi = src2 >> 16; - short hilo = src1; - short hihi = src1 >> 16; - - lolo = TEN_satu8(lolo); - lohi = TEN_satu8(lohi); - hilo = TEN_satu8(hilo); - hihi = TEN_satu8(hihi); - - return (((unsigned int) hihi) << 24) | (((unsigned int) hilo) << 16) | (lohi << 8) | lolo; -} - - - -static inline int _sshl (int src1, unsigned int src2) { -short local2 = (short)(src2 & 0x7FFF); -return (int) util_shift_right_saturate_n(src1, -local2, 32); -} - - - - -static inline int _sshvl (int src2, int src1) { - short s1; - if (src1 > 31) - s1 = 31; - else if (src1 < -31) - s1 = -31; - else - s1 = src1; - - return (int) util_shift_right_saturate_n(src2, -s1, 32); -} - - - - - -static inline int _sshvr (int src2, int src1) { -short s1; - if (src1 > 31) - s1 = 31; - else if (src1 < -31) - s1 = -31; - else - s1 = src1; - return (int) util_shift_right_saturate_n(src2, s1, 32); -} - - - - -static inline int _ssub(int src1, int src2) { -signed long long res; -signed long long maxv, minv; -maxv = (1LL << (32-1)) - 1; -minv = (-1LL << (32-1)); -res = (long long) src1 - (long long) src2; -if (res > maxv) { - res = maxv; - _overflow = 1; - } -else if (res < minv ) { - res = minv; - _overflow = 1; - } -return (int) res; -} - -static inline int _ssub2(int src1, int src2) { -signed short s1[2], s2[2]; -signed int r[2], maxv, minv; - -maxv = (1L << (16-1)) - 1; -minv = (-1L << (16-1)); - - -*((int*)s1) = src1; -*((int*)s2) = src2; - -r[0] = (int) s1[0] - (int) s2[0]; -r[1] = (int) s1[1] - (int) s2[1]; - -if (r[0] > maxv) { - r[0] = maxv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } -else if (r[0] < minv ) { - r[0] = minv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } -if (r[1] > maxv) { - r[1] = maxv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } -else if (r[1] < minv ) { - r[1] = minv; - /* NOTE: TI c6x does NOT set the overflow register even if results saturate */ - /* _overflow = 1; */ - } - -return ((r[1] & 0xffff) << 16 ) | (r[0] & 0xffff) ; -} - - -static inline int _subabs4 (int src1, int src2) { - int res0, res1, res2, res3; - unsigned int s1_0 = (src1 & 0xff); - unsigned int s1_1 = (src1 & 0xff00) >> 8; - unsigned int s1_2 = (src1 & 0xff0000) >> 16; - unsigned int s1_3 = (src1 & 0xff000000) >> 24; - - unsigned int s2_0 = (src2 & 0xff); - unsigned int s2_1 = (src2 & 0xff00) >> 8; - unsigned int s2_2 = (src2 & 0xff0000) >> 16; - unsigned int s2_3 = (src2 & 0xff000000) >> 24; - - res0 = s1_0 - s2_0; - res1 = s1_1 - s2_1; - res2 = s1_2 - s2_2; - res3 = s1_3 - s2_3; - - if (res0 < 0) - res0 = -res0; - - if (res1 < 0) - res1 = -res1; - - if (res2 < 0) - res2 = -res2; - - if (res3 < 0) - res3 = -res3; - - return (res3 << 24) | (res2 << 16) | (res1 << 8) | res0; -} - - -static inline unsigned int _subc (unsigned int src1, unsigned int src2) -{ - if ( src1 >= src2) - return ((src1 - src2) << 1) + 1; - else - return src1 << 1; -} - - - -static inline int _sub2(int src1, int src2) { - short s1[2], s2[2], r[2]; - int result; - *((int*)s1) = src1; - *((int*)s2) = src2; - r[0] = s1[0] - s2[0]; - r[1] = s1[1] - s2[1]; - result = *(int*)r; - return result; -} - - -static inline int _sub4(int src1, int src2) { - char c1[4], c2[4], r[4]; - int result; - *((int*)c1) = src1; - *((int*)c2) = src2; - r[0] = c1[0] - c2[0]; - r[1] = c1[1] - c2[1]; - r[2] = c1[2] - c2[2]; - r[3] = c1[3] - c2[3]; - result = *(int*)r; - return result; -} - - -static inline int _swap4 (unsigned int src1) { - unsigned char v0 = src1; - unsigned char v1 = src1 >> 8; - unsigned char v2 = src1 >> 16; - unsigned char v3 = src1 >> 24; - unsigned v = v0<<8 | v1 | v2<<24 | v3<<16; - return v; -} - -static inline unsigned int _unpkhu4 (unsigned int src1) { - unsigned v0 = src1>>24; - unsigned v1 = (src1>>16) & 0xff; - return (v0<<16) | v1; -} - -static inline unsigned int _unpklu4 (unsigned int src1) { - unsigned v1 = (src1>>8) & 0xff; - unsigned v0 = (src1) & 0xff; - return (v1<<16) | v0; -} - - - - -static inline unsigned int _xpnd2 (unsigned int src1) { - int v0 = (src1 & 0x1) ? 0x0000ffff : 0x00000000; - int v1 = (src1 & 0x2) ? 0xffff0000 : 0x00000000; - return v0|v1; -} - -static inline unsigned int _xpnd4 (unsigned int src1) { - int v0 = (src1 & 0x1) ? 0x000000ff : 0x00000000; - int v1 = (src1 & 0x2) ? 0x0000ff00 : 0x00000000; - int v2 = (src1 & 0x4) ? 0x00ff0000 : 0x00000000; - int v3 = (src1 & 0x8) ? 0xff000000 : 0x00000000; - int r = v0|v1|v2|v3; - return r; -} - - - -// end of Implemented in alphabetical order - - -#endif /* __C6X_COMPAT__H */ diff --git a/src/arch/xtensa/include/xtensa/cacheasm.h b/src/arch/xtensa/include/xtensa/cacheasm.h deleted file mode 100644 index 9cb2c8fcc6b8..000000000000 --- a/src/arch/xtensa/include/xtensa/cacheasm.h +++ /dev/null @@ -1,962 +0,0 @@ -/* - * xtensa/cacheasm.h -- assembler-specific cache related definitions - * that depend on CORE configuration - * - * This file is logically part of xtensa/coreasm.h , - * but is kept separate for modularity / compilation-performance. - */ - -/* - * Copyright (c) 2001-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. - */ - -#ifndef XTENSA_CACHEASM_H -#define XTENSA_CACHEASM_H - -#include <xtensa/coreasm.h> -#include <xtensa/corebits.h> -#include <xtensa/xtensa-xer.h> -#include <xtensa/xtensa-versions.h> - -/* - * This header file defines assembler macros of the form: - * <x>cache_<func> - * where <x> is 'i' or 'd' for instruction and data caches, - * and <func> indicates the function of the macro. - * - * The following functions <func> are defined, - * and apply only to the specified cache (I or D): - * - * reset - * Resets the cache. - * - * sync - * Makes sure any previous cache instructions have been completed; - * ie. makes sure any previous cache control operations - * have had full effect and been synchronized to memory. - * Eg. any invalidate completed [so as not to generate a hit], - * any writebacks or other pipelined writes written to memory, etc. - * - * invalidate_line (single cache line) - * invalidate_region (specified memory range) - * invalidate_all (entire cache) - * Invalidates all cache entries that cache - * data from the specified memory range. - * NOTE: locked entries are not invalidated. - * - * writeback_line (single cache line) - * writeback_region (specified memory range) - * writeback_all (entire cache) - * Writes back to memory all dirty cache entries - * that cache data from the specified memory range, - * and marks these entries as clean. - * NOTE: on some future implementations, this might - * also invalidate. - * NOTE: locked entries are written back, but never invalidated. - * NOTE: instruction caches never implement writeback. - * - * writeback_inv_line (single cache line) - * writeback_inv_region (specified memory range) - * writeback_inv_all (entire cache) - * Writes back to memory all dirty cache entries - * that cache data from the specified memory range, - * and invalidates these entries (including all clean - * cache entries that cache data from that range). - * NOTE: locked entries are written back but not invalidated. - * NOTE: instruction caches never implement writeback. - * - * lock_line (single cache line) - * lock_region (specified memory range) - * Prefetch and lock the specified memory range into cache. - * NOTE: if any part of the specified memory range cannot - * be locked, a Load/Store Error (for dcache) or Instruction - * Fetch Error (for icache) exception occurs. These macros don't - * do anything special (yet anyway) to handle this situation. - * - * unlock_line (single cache line) - * unlock_region (specified memory range) - * unlock_all (entire cache) - * Unlock cache entries that cache the specified memory range. - * Entries not already locked are unaffected. - * - * coherence_on - * coherence_off - * Turn off and on cache coherence - * - */ - - - -/*************************** GENERIC -- ALL CACHES ***************************/ - - -/* - * The following macros assume the following cache size/parameter limits - * in the current Xtensa core implementation: - * cache size: 1024 bytes minimum - * line size: 16 - 64 bytes - * way count: 1 - 4 - * - * Minimum entries per way (ie. per associativity) = 1024 / 64 / 4 = 4 - * Hence the assumption that each loop can execute four cache instructions. - * - * Correspondingly, the offset range of instructions is assumed able to cover - * four lines, ie. offsets {0,1,2,3} * line_size are assumed valid for - * both hit and indexed cache instructions. Ie. these offsets are all - * valid: 0, 16, 32, 48, 64, 96, 128, 192 (for line sizes 16, 32, 64). - * This is true of all original cache instructions - * (dhi, ihi, dhwb, dhwbi, dii, iii) which have offsets - * of 0 to 1020 in multiples of 4 (ie. 8 bits shifted by 2). - * This is also true of subsequent cache instructions - * (dhu, ihu, diu, iiu, diwb, diwbi, dpfl, ipfl) which have offsets - * of 0 to 240 in multiples of 16 (ie. 4 bits shifted by 4). - * - * (Maximum cache size, currently 32k, doesn't affect the following macros. - * Cache ways > MMU min page size cause aliasing but that's another matter.) - */ - - - -/* - * Macro to apply an 'indexed' cache instruction to the entire cache. - * - * Parameters: - * cainst instruction/ that takes an address register parameter - * and an offset parameter (in range 0 .. 3*linesize). - * size size of cache in bytes - * linesize size of cache line in bytes (always power-of-2) - * assoc_or1 number of associativities (ways/sets) in cache - * if all sets affected by cainst, - * or 1 if only one set (or not all sets) of the cache - * is affected by cainst (eg. DIWB or DIWBI [not yet ISA defined]). - * aa, ab unique address registers (temporaries). - * awb set to other than a0 if wb type of instruction - * loopokay 1 allows use of zero-overhead loops, 0 does not - * immrange range (max value) of cainst's immediate offset parameter, in bytes - * (NOTE: macro assumes immrange allows power-of-2 number of lines) - */ - - .macro cache_index_all cainst, size, linesize, assoc_or1, aa, ab, loopokay, maxofs, awb=a0 - - // Number of indices in cache (lines per way): - .set .Lindices, (\size / (\linesize * \assoc_or1)) - // Number of indices processed per loop iteration (max 4): - .set .Lperloop, .Lindices - .ifgt .Lperloop - 4 - .set .Lperloop, 4 - .endif - // Also limit instructions per loop if cache line size exceeds immediate range: - .set .Lmaxperloop, (\maxofs / \linesize) + 1 - .ifgt .Lperloop - .Lmaxperloop - .set .Lperloop, .Lmaxperloop - .endif - // Avoid addi of 128 which takes two instructions (addmi,addi): - .ifeq .Lperloop*\linesize - 128 - .ifgt .Lperloop - 1 - .set .Lperloop, .Lperloop / 2 - .endif - .endif - - // \size byte cache, \linesize byte lines, \assoc_or1 way(s) affected by each \cainst. - // XCHAL_ERRATUM_497 - don't execute using loop, to reduce the amount of added code - .ifne (\loopokay & XCHAL_HAVE_LOOPS && !XCHAL_ERRATUM_497) - - movi \aa, .Lindices / .Lperloop // number of loop iterations - // Possible improvement: need only loop if \aa > 1 ; - // however \aa == 1 is highly unlikely. - movi \ab, 0 // to iterate over cache - loop \aa, .Lend_cachex\@ - .set .Li, 0 ; .rept .Lperloop - \cainst \ab, .Li*\linesize - .set .Li, .Li+1 ; .endr - addi \ab, \ab, .Lperloop*\linesize // move to next line -.Lend_cachex\@: - - .else - - movi \aa, (\size / \assoc_or1) - // Possible improvement: need only loop if \aa > 1 ; - // however \aa == 1 is highly unlikely. - movi \ab, 0 // to iterate over cache - .ifne ((\awb !=a0) & XCHAL_ERRATUM_497) // don't use awb if set to a0 - movi \awb, 0 - .endif -.Lstart_cachex\@: - .set .Li, 0 ; .rept .Lperloop - \cainst \ab, .Li*\linesize - .set .Li, .Li+1 ; .endr - .ifne ((\awb !=a0) & XCHAL_ERRATUM_497) // do memw after 8 cainst wb instructions - addi \awb, \awb, .Lperloop - blti \awb, 8, .Lstart_memw\@ - memw - movi \awb, 0 -.Lstart_memw\@: - .endif - addi \ab, \ab, .Lperloop*\linesize // move to next line - bltu \ab, \aa, .Lstart_cachex\@ - .endif - - .endm - - -/* - * Macro to apply a 'hit' cache instruction to a memory region, - * ie. to any cache entries that cache a specified portion (region) of memory. - * Takes care of the unaligned cases, ie. may apply to one - * more cache line than $asize / lineSize if $aaddr is not aligned. - * - * - * Parameters are: - * cainst instruction/macro that takes an address register parameter - * and an offset parameter (currently always zero) - * and generates a cache instruction (eg. "dhi", "dhwb", "ihi", etc.) - * linesize_log2 log2(size of cache line in bytes) - * addr register containing start address of region (clobbered) - * asize register containing size of the region in bytes (clobbered) - * askew unique register used as temporary - * awb unique register used as temporary for erratum 497. - * - * Note: A possible optimization to this macro is to apply the operation - * to the entire cache if the region exceeds the size of the cache - * by some empirically determined amount or factor. Some experimentation - * is required to determine the appropriate factors, which also need - * to be tunable if required. - */ - - .macro cache_hit_region cainst, linesize_log2, addr, asize, askew, awb=a0 - - // Make \asize the number of iterations: - extui \askew, \addr, 0, \linesize_log2 // get unalignment amount of \addr - add \asize, \asize, \askew // ... and add it to \asize - addi \asize, \asize, (1 << \linesize_log2) - 1 // round up! - srli \asize, \asize, \linesize_log2 - - // Iterate over region: - .ifne ((\awb !=a0) & XCHAL_ERRATUM_497) // don't use awb if set to a0 - movi \awb, 0 - .endif - floopnez \asize, cacheh\@ - \cainst \addr, 0 - .ifne ((\awb !=a0) & XCHAL_ERRATUM_497) // do memw after 8 cainst wb instructions - addi \awb, \awb, 1 - blti \awb, 8, .Lstart_memw\@ - memw - movi \awb, 0 -.Lstart_memw\@: - .endif - addi \addr, \addr, (1 << \linesize_log2) // move to next line - floopend \asize, cacheh\@ - .endm - - - - - -/*************************** INSTRUCTION CACHE ***************************/ - - -/* - * Reset/initialize the instruction cache by simply invalidating it: - * (need to unlock first also, if cache locking implemented): - * - * Parameters: - * aa, ab unique address registers (temporaries) - */ - .macro icache_reset aa, ab, loopokay=0 - icache_unlock_all \aa, \ab, \loopokay - icache_invalidate_all \aa, \ab, \loopokay - .endm - - -/* - * Synchronize after an instruction cache operation, - * to be sure everything is in sync with memory as to be - * expected following any previous instruction cache control operations. - * - * Even if a config doesn't have caches, an isync is still needed - * when instructions in any memory are modified, whether by a loader - * or self-modifying code. Therefore, this macro always produces - * an isync, whether or not an icache is present. - * - * Parameters are: - * ar an address register (temporary) (currently unused, but may be used in future) - */ - .macro icache_sync ar - isync - .endm - - - -/* - * Invalidate a single line of the instruction cache. - * Parameters are: - * ar address register that contains (virtual) address to invalidate - * (may get clobbered in a future implementation, but not currently) - * offset (optional) offset to add to \ar to compute effective address to invalidate - * (note: some number of lsbits are ignored) - */ - .macro icache_invalidate_line ar, offset -#if XCHAL_ICACHE_SIZE > 0 - ihi \ar, \offset // invalidate icache line - icache_sync \ar -#endif - .endm - - - - -/* - * Invalidate instruction cache entries that cache a specified portion of memory. - * Parameters are: - * astart start address (register gets clobbered) - * asize size of the region in bytes (register gets clobbered) - * ac unique register used as temporary - */ - .macro icache_invalidate_region astart, asize, ac -#if XCHAL_ICACHE_SIZE > 0 - // Instruction cache region invalidation: - cache_hit_region ihi, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac - icache_sync \ac - // End of instruction cache region invalidation -#endif - .endm - - - -/* - * Invalidate entire instruction cache. - * - * Parameters: - * aa, ab unique address registers (temporaries) - */ - .macro icache_invalidate_all aa, ab, loopokay=1 -#if XCHAL_ICACHE_SIZE > 0 - // Instruction cache invalidation: - cache_index_all iii, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, XCHAL_ICACHE_WAYS, \aa, \ab, \loopokay, 1020 - icache_sync \aa - // End of instruction cache invalidation -#endif - .endm - - - -/* - * Lock (prefetch & lock) a single line of the instruction cache. - * - * Parameters are: - * ar address register that contains (virtual) address to lock - * (may get clobbered in a future implementation, but not currently) - * offset offset to add to \ar to compute effective address to lock - * (note: some number of lsbits are ignored) - */ - .macro icache_lock_line ar, offset -#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE - ipfl \ar, \offset /* prefetch and lock icache line */ - icache_sync \ar -#endif - .endm - - - -/* - * Lock (prefetch & lock) a specified portion of memory into the instruction cache. - * Parameters are: - * astart start address (register gets clobbered) - * asize size of the region in bytes (register gets clobbered) - * ac unique register used as temporary - */ - .macro icache_lock_region astart, asize, ac -#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE - // Instruction cache region lock: - cache_hit_region ipfl, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac - icache_sync \ac - // End of instruction cache region lock -#endif - .endm - - - -/* - * Unlock a single line of the instruction cache. - * - * Parameters are: - * ar address register that contains (virtual) address to unlock - * (may get clobbered in a future implementation, but not currently) - * offset offset to add to \ar to compute effective address to unlock - * (note: some number of lsbits are ignored) - */ - .macro icache_unlock_line ar, offset -#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE - ihu \ar, \offset /* unlock icache line */ - icache_sync \ar -#endif - .endm - - - -/* - * Unlock a specified portion of memory from the instruction cache. - * Parameters are: - * astart start address (register gets clobbered) - * asize size of the region in bytes (register gets clobbered) - * ac unique register used as temporary - */ - .macro icache_unlock_region astart, asize, ac -#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE - // Instruction cache region unlock: - cache_hit_region ihu, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac - icache_sync \ac - // End of instruction cache region unlock -#endif - .endm - - - -/* - * Unlock entire instruction cache. - * - * Parameters: - * aa, ab unique address registers (temporaries) - */ - .macro icache_unlock_all aa, ab, loopokay=1 -#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE - // Instruction cache unlock: - cache_index_all iiu, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, 1, \aa, \ab, \loopokay, 240 - icache_sync \aa - // End of instruction cache unlock -#endif - .endm - - - - - -/*************************** DATA CACHE ***************************/ - - - -/* - * Reset/initialize the data cache by simply invalidating it - * (need to unlock first also, if cache locking implemented): - * - * Parameters: - * aa, ab unique address registers (temporaries) - */ - .macro dcache_reset aa, ab, loopokay=0 - dcache_unlock_all \aa, \ab, \loopokay - dcache_invalidate_all \aa, \ab, \loopokay - .endm - - - - -/* - * Synchronize after a data cache operation, - * to be sure everything is in sync with memory as to be - * expected following any previous data cache control operations. - * - * Parameters are: - * ar an address register (temporary) (currently unused, but may be used in future) - */ - .macro dcache_sync ar, wbtype=0 -#if XCHAL_DCACHE_SIZE > 0 - // No synchronization is needed. - // (memw may be desired e.g. after writeback operation to help ensure subsequent - // external accesses are seen to follow that writeback, however that's outside - // the scope of this macro) - - //dsync - .ifne (\wbtype & XCHAL_ERRATUM_497) - memw - .endif -#endif - .endm - - - -/* - * Turn on cache coherence. - * - * WARNING: for RE-201x.x and later hardware, any interrupt that tries - * to change MEMCTL will see its changes dropped if the interrupt comes - * in the middle of this routine. If this might be an issue, call this - * routine with interrupts disabled. - * - * Parameters are: - * ar,at two scratch address registers (both clobbered) - */ - .macro cache_coherence_on ar at -#if XCHAL_DCACHE_IS_COHERENT -# if XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RE_2012_0 - /* Have MEMCTL. Enable snoop responses. */ - rsr.memctl \ar - movi \at, MEMCTL_SNOOP_EN - or \ar, \ar, \at - wsr.memctl \ar -# elif XCHAL_HAVE_EXTERN_REGS && XCHAL_HAVE_MX - /* Opt into coherence for MX (for backward compatibility / testing). */ - movi \ar, 1 - movi \at, XER_CCON - wer \ar, \at - extw -# endif -#endif - .endm - - - -/* - * Turn off cache coherence. - * - * NOTE: this is generally preceded by emptying the cache; - * see xthal_cache_coherence_optout() in hal/coherence.c for details. - * - * WARNING: for RE-201x.x and later hardware, any interrupt that tries - * to change MEMCTL will see its changes dropped if the interrupt comes - * in the middle of this routine. If this might be an issue, call this - * routine with interrupts disabled. - * - * Parameters are: - * ar,at two scratch address registers (both clobbered) - */ - .macro cache_coherence_off ar at -#if XCHAL_DCACHE_IS_COHERENT -# if XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RE_2012_0 - /* Have MEMCTL. Disable snoop responses. */ - rsr.memctl \ar - movi \at, ~MEMCTL_SNOOP_EN - and \ar, \ar, \at - wsr.memctl \ar -# elif XCHAL_HAVE_EXTERN_REGS && XCHAL_HAVE_MX - /* Opt out of coherence, for MX (for backward compatibility / testing). */ - extw - movi \at, 0 - movi \ar, XER_CCON - wer \at, \ar - extw -# endif -#endif - .endm - - - -/* - * Synchronize after a data store operation, - * to be sure the stored data is completely off the processor - * (and assuming there is no buffering outside the processor, - * that the data is in memory). This may be required to - * ensure that the processor's write buffers are emptied. - * A MEMW followed by a read guarantees this, by definition. - * We also try to make sure the read itself completes. - * - * Parameters are: - * ar an address register (temporary) - */ - .macro write_sync ar - memw // ensure previous memory accesses are complete prior to subsequent memory accesses - l32i \ar, sp, 0 // completing this read ensures any previous write has completed, because of MEMW - //slot - add \ar, \ar, \ar // use the result of the read to help ensure the read completes (in future architectures) - .endm - - -/* - * Invalidate a single line of the data cache. - * Parameters are: - * ar address register that contains (virtual) address to invalidate - * (may get clobbered in a future implementation, but not currently) - * offset (optional) offset to add to \ar to compute effective address to invalidate - * (note: some number of lsbits are ignored) - */ - .macro dcache_invalidate_line ar, offset -#if XCHAL_DCACHE_SIZE > 0 - dhi \ar, \offset - dcache_sync \ar -#endif - .endm - - - - - -/* - * Invalidate data cache entries that cache a specified portion of memory. - * Parameters are: - * astart start address (register gets clobbered) - * asize size of the region in bytes (register gets clobbered) - * ac unique register used as temporary - */ - .macro dcache_invalidate_region astart, asize, ac -#if XCHAL_DCACHE_SIZE > 0 - // Data cache region invalidation: - cache_hit_region dhi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac - dcache_sync \ac - // End of data cache region invalidation -#endif - .endm - - - -/* - * Invalidate entire data cache. - * - * Parameters: - * aa, ab unique address registers (temporaries) - */ - .macro dcache_invalidate_all aa, ab, loopokay=1 -#if XCHAL_DCACHE_SIZE > 0 - // Data cache invalidation: - cache_index_all dii, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, XCHAL_DCACHE_WAYS, \aa, \ab, \loopokay, 1020 - dcache_sync \aa - // End of data cache invalidation -#endif - .endm - - - -/* - * Writeback a single line of the data cache. - * Parameters are: - * ar address register that contains (virtual) address to writeback - * (may get clobbered in a future implementation, but not currently) - * offset offset to add to \ar to compute effective address to writeback - * (note: some number of lsbits are ignored) - */ - .macro dcache_writeback_line ar, offset -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK - dhwb \ar, \offset - dcache_sync \ar, wbtype=1 -#endif - .endm - - - -/* - * Writeback dirty data cache entries that cache a specified portion of memory. - * Parameters are: - * astart start address (register gets clobbered) - * asize size of the region in bytes (register gets clobbered) - * ac unique register used as temporary - */ - .macro dcache_writeback_region astart, asize, ac, awb -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK - // Data cache region writeback: - cache_hit_region dhwb, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac, \awb - dcache_sync \ac, wbtype=1 - // End of data cache region writeback -#endif - .endm - - - -/* - * Writeback entire data cache. - * Parameters: - * aa, ab unique address registers (temporaries) - */ - .macro dcache_writeback_all aa, ab, awb, loopokay=1 -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK - // Data cache writeback: - cache_index_all diwb, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab, \loopokay, 240, \awb, - dcache_sync \aa, wbtype=1 - // End of data cache writeback -#endif - .endm - - - -/* - * Writeback and invalidate a single line of the data cache. - * Parameters are: - * ar address register that contains (virtual) address to writeback and invalidate - * (may get clobbered in a future implementation, but not currently) - * offset offset to add to \ar to compute effective address to writeback and invalidate - * (note: some number of lsbits are ignored) - */ - .macro dcache_writeback_inv_line ar, offset -#if XCHAL_DCACHE_SIZE > 0 - dhwbi \ar, \offset /* writeback and invalidate dcache line */ - dcache_sync \ar, wbtype=1 -#endif - .endm - - - -/* - * Writeback and invalidate data cache entries that cache a specified portion of memory. - * Parameters are: - * astart start address (register gets clobbered) - * asize size of the region in bytes (register gets clobbered) - * ac unique register used as temporary - */ - .macro dcache_writeback_inv_region astart, asize, ac, awb -#if XCHAL_DCACHE_SIZE > 0 - // Data cache region writeback and invalidate: - cache_hit_region dhwbi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac, \awb - dcache_sync \ac, wbtype=1 - // End of data cache region writeback and invalidate -#endif - .endm - - - -/* - * Writeback and invalidate entire data cache. - * Parameters: - * aa, ab unique address registers (temporaries) - */ - .macro dcache_writeback_inv_all aa, ab, awb, loopokay=1 -#if XCHAL_DCACHE_SIZE > 0 - // Data cache writeback and invalidate: -#if XCHAL_DCACHE_IS_WRITEBACK - cache_index_all diwbi, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab, \loopokay, 240, \awb - dcache_sync \aa, wbtype=1 -#else /*writeback*/ - // Data cache does not support writeback, so just invalidate: */ - dcache_invalidate_all \aa, \ab, \loopokay -#endif /*writeback*/ - // End of data cache writeback and invalidate -#endif - .endm - - - - -/* - * Lock (prefetch & lock) a single line of the data cache. - * - * Parameters are: - * ar address register that contains (virtual) address to lock - * (may get clobbered in a future implementation, but not currently) - * offset offset to add to \ar to compute effective address to lock - * (note: some number of lsbits are ignored) - */ - .macro dcache_lock_line ar, offset -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE - dpfl \ar, \offset /* prefetch and lock dcache line */ - dcache_sync \ar -#endif - .endm - - - -/* - * Lock (prefetch & lock) a specified portion of memory into the data cache. - * Parameters are: - * astart start address (register gets clobbered) - * asize size of the region in bytes (register gets clobbered) - * ac unique register used as temporary - */ - .macro dcache_lock_region astart, asize, ac -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE - // Data cache region lock: - cache_hit_region dpfl, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac - dcache_sync \ac - // End of data cache region lock -#endif - .endm - - - -/* - * Unlock a single line of the data cache. - * - * Parameters are: - * ar address register that contains (virtual) address to unlock - * (may get clobbered in a future implementation, but not currently) - * offset offset to add to \ar to compute effective address to unlock - * (note: some number of lsbits are ignored) - */ - .macro dcache_unlock_line ar, offset -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE - dhu \ar, \offset /* unlock dcache line */ - dcache_sync \ar -#endif - .endm - - - -/* - * Unlock a specified portion of memory from the data cache. - * Parameters are: - * astart start address (register gets clobbered) - * asize size of the region in bytes (register gets clobbered) - * ac unique register used as temporary - */ - .macro dcache_unlock_region astart, asize, ac -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE - // Data cache region unlock: - cache_hit_region dhu, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac - dcache_sync \ac - // End of data cache region unlock -#endif - .endm - - - -/* - * Unlock entire data cache. - * - * Parameters: - * aa, ab unique address registers (temporaries) - */ - .macro dcache_unlock_all aa, ab, loopokay=1 -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE - // Data cache unlock: - cache_index_all diu, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab, \loopokay, 240 - dcache_sync \aa - // End of data cache unlock -#endif - .endm - - - -/* - * Get the number of enabled icache ways. Note that this may - * be different from the value read from the MEMCTL register. - * - * Parameters: - * aa address register where value is returned - */ - .macro icache_get_ways aa -#if XCHAL_ICACHE_SIZE > 0 -#if XCHAL_HAVE_ICACHE_DYN_WAYS - // Read from MEMCTL and shift/mask - rsr.memctl \aa - extui \aa, \aa, MEMCTL_ICWU_SHIFT, MEMCTL_ICWU_BITS - blti \aa, XCHAL_ICACHE_WAYS, .Licgw - movi \aa, XCHAL_ICACHE_WAYS -.Licgw: -#else - // All ways are always enabled - movi \aa, XCHAL_ICACHE_WAYS -#endif -#else - // No icache - movi \aa, 0 -#endif - .endm - - - -/* - * Set the number of enabled icache ways. - * - * Parameters: - * aa address register specifying number of ways (trashed) - * ab,ac address register for scratch use (trashed) - */ - .macro icache_set_ways aa, ab, ac -#if XCHAL_ICACHE_SIZE > 0 -#if XCHAL_HAVE_ICACHE_DYN_WAYS - movi \ac, MEMCTL_ICWU_CLR_MASK // set up to clear bits 18-22 - rsr.memctl \ab - and \ab, \ab, \ac - movi \ac, MEMCTL_INV_EN // set bit 23 - slli \aa, \aa, MEMCTL_ICWU_SHIFT // move to right spot - or \ab, \ab, \aa - or \ab, \ab, \ac - wsr.memctl \ab - isync -#else - // All ways are always enabled -#endif -#else - // No icache -#endif - .endm - - - -/* - * Get the number of enabled dcache ways. Note that this may - * be different from the value read from the MEMCTL register. - * - * Parameters: - * aa address register where value is returned - */ - .macro dcache_get_ways aa -#if XCHAL_DCACHE_SIZE > 0 -#if XCHAL_HAVE_DCACHE_DYN_WAYS - // Read from MEMCTL and shift/mask - rsr.memctl \aa - extui \aa, \aa, MEMCTL_DCWU_SHIFT, MEMCTL_DCWU_BITS - blti \aa, XCHAL_DCACHE_WAYS, .Ldcgw - movi \aa, XCHAL_DCACHE_WAYS -.Ldcgw: -#else - // All ways are always enabled - movi \aa, XCHAL_DCACHE_WAYS -#endif -#else - // No dcache - movi \aa, 0 -#endif - .endm - - - -/* - * Set the number of enabled dcache ways. - * - * Parameters: - * aa address register specifying number of ways (trashed) - * ab,ac address register for scratch use (trashed) - */ - .macro dcache_set_ways aa, ab, ac -#if (XCHAL_DCACHE_SIZE > 0) && XCHAL_HAVE_DCACHE_DYN_WAYS - movi \ac, MEMCTL_DCWA_CLR_MASK // set up to clear bits 13-17 - rsr.memctl \ab - and \ab, \ab, \ac // clear ways allocatable - slli \ac, \aa, MEMCTL_DCWA_SHIFT - or \ab, \ab, \ac // set ways allocatable - wsr.memctl \ab -#if XCHAL_DCACHE_IS_WRITEBACK - // Check if the way count is increasing or decreasing - extui \ac, \ab, MEMCTL_DCWU_SHIFT, MEMCTL_DCWU_BITS // bits 8-12 - ways in use - bge \aa, \ac, .Ldsw3 // equal or increasing - slli \ab, \aa, XCHAL_DCACHE_LINEWIDTH + XCHAL_DCACHE_SETWIDTH // start way number - slli \ac, \ac, XCHAL_DCACHE_LINEWIDTH + XCHAL_DCACHE_SETWIDTH // end way number -.Ldsw1: - diwbui.p \ab // auto-increments ab - bge \ab, \ac, .Ldsw2 - beqz \ab, .Ldsw2 - j .Ldsw1 -.Ldsw2: - rsr.memctl \ab -#endif -.Ldsw3: - // No dirty data to write back, just set the new number of ways - movi \ac, MEMCTL_DCWU_CLR_MASK // set up to clear bits 8-12 - and \ab, \ab, \ac // clear ways in use - movi \ac, MEMCTL_INV_EN - or \ab, \ab, \ac // set bit 23 - slli \aa, \aa, MEMCTL_DCWU_SHIFT - or \ab, \ab, \aa // set ways in use - wsr.memctl \ab -#else - // No dcache or no way disable support -#endif - .endm - -#endif /*XTENSA_CACHEASM_H*/ - diff --git a/src/arch/xtensa/include/xtensa/cacheattrasm.h b/src/arch/xtensa/include/xtensa/cacheattrasm.h deleted file mode 100644 index 211803aedbf3..000000000000 --- a/src/arch/xtensa/include/xtensa/cacheattrasm.h +++ /dev/null @@ -1,436 +0,0 @@ -/* - * xtensa/cacheattrasm.h -- assembler-specific CACHEATTR register related definitions - * that depend on CORE configuration - * - * This file is logically part of xtensa/coreasm.h (or perhaps xtensa/cacheasm.h), - * but is kept separate for modularity / compilation-performance. - */ - -/* - * Copyright (c) 2001-2009 Tensilica 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. - */ - -#ifndef XTENSA_CACHEATTRASM_H -#define XTENSA_CACHEATTRASM_H - -#include <xtensa/coreasm.h> - -/* Determine whether cache attributes are controlled using eight 512MB entries: */ -#define XCHAL_CA_8X512 (XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR \ - || (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY)) - - -/* - * This header file defines assembler macros of the form: - * <x>cacheattr_<func> - * where: - * <x> is 'i', 'd' or absent for instruction, data - * or both caches; and - * <func> indicates the function of the macro. - * - * The following functions are defined: - * - * icacheattr_get - * Reads I-cache CACHEATTR into a2 (clobbers a3-a5). - * - * dcacheattr_get - * Reads D-cache CACHEATTR into a2 (clobbers a3-a5). - * (Note: for configs with a real CACHEATTR register, the - * above two macros are identical.) - * - * cacheattr_set - * Writes both I-cache and D-cache CACHEATTRs from a2 (a3-a8 clobbered). - * Works even when changing one's own code's attributes. - * - * icacheattr_is_enabled label - * Branches to \label if I-cache appears to have been enabled - * (eg. if CACHEATTR contains a cache-enabled attribute). - * (clobbers a2-a5,SAR) - * - * dcacheattr_is_enabled label - * Branches to \label if D-cache appears to have been enabled - * (eg. if CACHEATTR contains a cache-enabled attribute). - * (clobbers a2-a5,SAR) - * - * cacheattr_is_enabled label - * Branches to \label if either I-cache or D-cache appears to have been enabled - * (eg. if CACHEATTR contains a cache-enabled attribute). - * (clobbers a2-a5,SAR) - * - * The following macros are only defined under certain conditions: - * - * icacheattr_set (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR) - * Writes I-cache CACHEATTR from a2 (a3-a8 clobbered). - * - * dcacheattr_set (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR) - * Writes D-cache CACHEATTR from a2 (a3-a8 clobbered). - */ - - - -/*************************** GENERIC -- ALL CACHES ***************************/ - -/* - * _cacheattr_get - * - * (Internal macro.) - * Returns value of CACHEATTR register (or closest equivalent) in a2. - * - * Entry: - * (none) - * Exit: - * a2 value read from CACHEATTR - * a3-a5 clobbered (temporaries) - */ - .macro _cacheattr_get tlb -#if XCHAL_HAVE_CACHEATTR - rsr.cacheattr a2 -#elif XCHAL_CA_8X512 - // We have a config that "mimics" CACHEATTR using a simplified - // "MMU" composed of a single statically-mapped way. - // DTLB and ITLB are independent, so there's no single - // cache attribute that can describe both. So for now - // just return the DTLB state. - movi a5, 0xE0000000 - movi a2, 0 - movi a3, XCHAL_SPANNING_WAY -1: add a3, a3, a5 // next segment - r&tlb&1 a4, a3 // get PPN+CA of segment at 0xE0000000, 0xC0000000, ..., 0 - dsync // interlock??? - slli a2, a2, 4 - extui a4, a4, 0, 4 // extract CA - or a2, a2, a4 - bgeui a3, 16, 1b -#else - // This macro isn't applicable to arbitrary MMU configurations. - // Just return zero. - movi a2, 0 -#endif - .endm - - .macro icacheattr_get - _cacheattr_get itlb - .endm - - .macro dcacheattr_get - _cacheattr_get dtlb - .endm - - -/* Default (powerup/reset) value of CACHEATTR, - all BYPASS mode (ie. disabled/bypassed caches): */ -#if XCHAL_HAVE_PTP_MMU -# define XCHAL_CACHEATTR_ALL_BYPASS 0x33333333 -#else -# define XCHAL_CACHEATTR_ALL_BYPASS 0x22222222 -#endif - -#if XCHAL_CA_8X512 - -#if XCHAL_HAVE_PTP_MMU -# define XCHAL_FCA_ENAMASK 0x0AA0 /* bitmap of fetch attributes that require enabled icache */ -# define XCHAL_LCA_ENAMASK 0x0FF0 /* bitmap of load attributes that require enabled dcache */ -# define XCHAL_SCA_ENAMASK 0x0CC0 /* bitmap of store attributes that require enabled dcache */ -#else -# define XCHAL_FCA_ENAMASK 0x003A /* bitmap of fetch attributes that require enabled icache */ -# define XCHAL_LCA_ENAMASK 0x0033 /* bitmap of load attributes that require enabled dcache */ -# define XCHAL_SCA_ENAMASK 0x0033 /* bitmap of store attributes that require enabled dcache */ -#endif -#define XCHAL_LSCA_ENAMASK (XCHAL_LCA_ENAMASK|XCHAL_SCA_ENAMASK) /* l/s attrs requiring enabled dcache */ -#define XCHAL_ALLCA_ENAMASK (XCHAL_FCA_ENAMASK|XCHAL_LSCA_ENAMASK) /* all attrs requiring enabled caches */ - -/* - * _cacheattr_is_enabled - * - * (Internal macro.) - * Branches to \label if CACHEATTR in a2 indicates an enabled - * cache, using mask in a3. - * - * Parameters: - * label where to branch to if cache is enabled - * Entry: - * a2 contains CACHEATTR value used to determine whether - * caches are enabled - * a3 16-bit constant where each bit correspond to - * one of the 16 possible CA values (in a CACHEATTR mask); - * CA values that indicate the cache is enabled - * have their corresponding bit set in this mask - * (eg. use XCHAL_xCA_ENAMASK , above) - * Exit: - * a2,a4,a5 clobbered - * SAR clobbered - */ - .macro _cacheattr_is_enabled label - movi a4, 8 // loop 8 times -.Lcaife\@: - extui a5, a2, 0, 4 // get CA nibble - ssr a5 // index into mask according to CA... - srl a5, a3 // ...and get CA's mask bit in a5 bit 0 - bbsi.l a5, 0, \label // if CA indicates cache enabled, jump to label - srli a2, a2, 4 // next nibble - addi a4, a4, -1 - bnez a4, .Lcaife\@ // loop for each nibble - .endm - -#else /* XCHAL_CA_8X512 */ - .macro _cacheattr_is_enabled label - j \label // macro not applicable, assume caches always enabled - .endm -#endif /* XCHAL_CA_8X512 */ - - - -/* - * icacheattr_is_enabled - * - * Branches to \label if I-cache is enabled. - * - * Parameters: - * label where to branch to if icache is enabled - * Entry: - * (none) - * Exit: - * a2-a5, SAR clobbered (temporaries) - */ - .macro icacheattr_is_enabled label -#if XCHAL_CA_8X512 - icacheattr_get - movi a3, XCHAL_FCA_ENAMASK -#endif - _cacheattr_is_enabled \label - .endm - -/* - * dcacheattr_is_enabled - * - * Branches to \label if D-cache is enabled. - * - * Parameters: - * label where to branch to if dcache is enabled - * Entry: - * (none) - * Exit: - * a2-a5, SAR clobbered (temporaries) - */ - .macro dcacheattr_is_enabled label -#if XCHAL_CA_8X512 - dcacheattr_get - movi a3, XCHAL_LSCA_ENAMASK -#endif - _cacheattr_is_enabled \label - .endm - -/* - * cacheattr_is_enabled - * - * Branches to \label if either I-cache or D-cache is enabled. - * - * Parameters: - * label where to branch to if a cache is enabled - * Entry: - * (none) - * Exit: - * a2-a5, SAR clobbered (temporaries) - */ - .macro cacheattr_is_enabled label -#if XCHAL_HAVE_CACHEATTR - rsr.cacheattr a2 - movi a3, XCHAL_ALLCA_ENAMASK -#elif XCHAL_CA_8X512 - icacheattr_get - movi a3, XCHAL_FCA_ENAMASK - _cacheattr_is_enabled \label - dcacheattr_get - movi a3, XCHAL_LSCA_ENAMASK -#endif - _cacheattr_is_enabled \label - .endm - - - -/* - * The ISA does not have a defined way to change the - * instruction cache attributes of the running code, - * ie. of the memory area that encloses the current PC. - * However, each micro-architecture (or class of - * configurations within a micro-architecture) - * provides a way to deal with this issue. - * - * Here are a few macros used to implement the relevant - * approach taken. - */ - -#if XCHAL_CA_8X512 && !XCHAL_HAVE_CACHEATTR - // We have a config that "mimics" CACHEATTR using a simplified - // "MMU" composed of a single statically-mapped way. - -/* - * icacheattr_set - * - * Entry: - * a2 cacheattr value to set - * Exit: - * a2 unchanged - * a3-a8 clobbered (temporaries) - */ - .macro icacheattr_set - - movi a5, 0xE0000000 // mask of upper 3 bits - movi a6, 3f // PC where ITLB is set - movi a3, XCHAL_SPANNING_WAY // start at region 0 (0 .. 7) - mov a7, a2 // copy a2 so it doesn't get clobbered - and a6, a6, a5 // upper 3 bits of local PC area - j 3f - - // Use micro-architecture specific method. - // The following 4-instruction sequence is aligned such that - // it all fits within a single I-cache line. Sixteen byte - // alignment is sufficient for this (using XCHAL_ICACHE_LINESIZE - // actually causes problems because that can be greater than - // the alignment of the reset vector, where this macro is often - // invoked, which would cause the linker to align the reset - // vector code away from the reset vector!!). - .begin no-transform - .align 16 /*XCHAL_ICACHE_LINESIZE*/ -1: witlb a4, a3 // write wired PTE (CA, no PPN) of 512MB segment to ITLB - isync - .end no-transform - nop - nop - - sub a3, a3, a5 // next segment (add 0x20000000) - bltui a3, 16, 4f // done? - - // Note that in the WITLB loop, we don't do any load/stores - // (may not be an issue here, but it is important in the DTLB case). -2: srli a7, a7, 4 // next CA -3: -# if XCHAL_HAVE_MIMIC_CACHEATTR - extui a4, a7, 0, 4 // extract CA to set -# else /* have translation, preserve it: */ - ritlb1 a8, a3 // get current PPN+CA of segment - //dsync // interlock??? - extui a4, a7, 0, 4 // extract CA to set - srli a8, a8, 4 // clear CA but keep PPN ... - slli a8, a8, 4 // ... - add a4, a4, a8 // combine new CA with PPN to preserve -# endif - beq a3, a6, 1b // current PC's region? if so, do it in a safe way - witlb a4, a3 // write wired PTE (CA [+PPN]) of 512MB segment to ITLB - sub a3, a3, a5 // next segment (add 0x20000000) - bgeui a3, 16, 2b - isync // make sure all ifetch changes take effect -4: - .endm // icacheattr_set - - -/* - * dcacheattr_set - * - * Entry: - * a2 cacheattr value to set - * Exit: - * a2 unchanged - * a3-a8 clobbered (temporaries) - */ - - .macro dcacheattr_set - - movi a5, 0xE0000000 // mask of upper 3 bits - movi a3, XCHAL_SPANNING_WAY // start at region 0 (0 .. 7) - mov a7, a2 // copy a2 so it doesn't get clobbered - // Note that in the WDTLB loop, we don't do any load/stores -2: // (including implicit l32r via movi) because it isn't safe. -# if XCHAL_HAVE_MIMIC_CACHEATTR - extui a4, a7, 0, 4 // extract CA to set -# else /* have translation, preserve it: */ - rdtlb1 a8, a3 // get current PPN+CA of segment - //dsync // interlock??? - extui a4, a7, 0, 4 // extract CA to set - srli a8, a8, 4 // clear CA but keep PPN ... - slli a8, a8, 4 // ... - add a4, a4, a8 // combine new CA with PPN to preserve -# endif - wdtlb a4, a3 // write wired PTE (CA [+PPN]) of 512MB segment to DTLB - sub a3, a3, a5 // next segment (add 0x20000000) - srli a7, a7, 4 // next CA - bgeui a3, 16, 2b - dsync // make sure all data path changes take effect - .endm // dcacheattr_set - -#endif /* XCHAL_CA_8X512 && !XCHAL_HAVE_CACHEATTR */ - - - -/* - * cacheattr_set - * - * Macro that sets the current CACHEATTR safely - * (both i and d) according to the current contents of a2. - * It works even when changing the cache attributes of - * the currently running code. - * - * Entry: - * a2 cacheattr value to set - * Exit: - * a2 unchanged - * a3-a8 clobbered (temporaries) - */ - .macro cacheattr_set - -#if XCHAL_HAVE_CACHEATTR -# if XCHAL_ICACHE_LINESIZE < 4 - // No i-cache, so can always safely write to CACHEATTR: - wsr.cacheattr a2 -# else - // The Athens micro-architecture, when using the old - // exception architecture option (ie. with the CACHEATTR register) - // allows changing the cache attributes of the running code - // using the following exact sequence aligned to be within - // an instruction cache line. (NOTE: using XCHAL_ICACHE_LINESIZE - // alignment actually causes problems because that can be greater - // than the alignment of the reset vector, where this macro is often - // invoked, which would cause the linker to align the reset - // vector code away from the reset vector!!). - j 1f - .begin no-transform - .align 16 /*XCHAL_ICACHE_LINESIZE*/ // align to within an I-cache line -1: wsr.cacheattr a2 - isync - .end no-transform - nop - nop -# endif -#elif XCHAL_CA_8X512 - // DTLB and ITLB are independent, but to keep semantics - // of this macro we simply write to both. - icacheattr_set - dcacheattr_set -#else - // This macro isn't applicable to arbitrary MMU configurations. - // Do nothing in this case. -#endif - .endm - - -#endif /*XTENSA_CACHEATTRASM_H*/ - diff --git a/src/arch/xtensa/include/xtensa/config/core.h b/src/arch/xtensa/include/xtensa/config/core.h deleted file mode 100644 index aa18c42a947d..000000000000 --- a/src/arch/xtensa/include/xtensa/config/core.h +++ /dev/null @@ -1,1420 +0,0 @@ -/* - * xtensa/config/core.h -- HAL definitions dependent on CORE configuration - * - * This header file is sometimes referred to as the "compile-time HAL" or CHAL. - * It pulls definitions tailored for a specific Xtensa processor configuration. - * - * Sources for binaries meant to be configuration-independent generally avoid - * including this file (they may use the configuration-specific HAL library). - * It is normal for the HAL library source itself to include this file. - */ - -/* - * Copyright (c) 2005-2015 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. - */ - - -#ifndef XTENSA_CONFIG_CORE_H -#define XTENSA_CONFIG_CORE_H - -/* xt-clang uses UINT32_C() without import it. This affects both Zephyr and XTOS. - * See #9413 for the longer story. - */ -#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) -# ifndef UINT32_C -# define UINT32_C(x) x -# endif -#else - /* UINT32_C(x) x ## U */ -# include <stdint.h> -#endif - -/* CONFIGURATION INDEPENDENT DEFINITIONS: */ -#ifdef __XTENSA__ -#include <xtensa/hal.h> -#include <xtensa/xtensa-versions.h> -#else -#include "../hal.h" -#include "../xtensa-versions.h" -#endif - -/* CONFIGURATION SPECIFIC DEFINITIONS: */ -#ifdef __XTENSA__ -#include <xtensa/config/core-isa.h> -#include <xtensa/config/core-matmap.h> -#include <xtensa/config/tie.h> -#else -#include "core-isa.h" -#include "core-matmap.h" -#include "tie.h" -#endif - -#if defined (_ASMLANGUAGE) || defined (__ASSEMBLER__) -#ifdef __XTENSA__ -#include <xtensa/config/tie-asm.h> -#else -#include "tie-asm.h" -#endif -#endif /*_ASMLANGUAGE or __ASSEMBLER__*/ - - -/*---------------------------------------------------------------------- - GENERAL - ----------------------------------------------------------------------*/ - -/* - * Separators for macros that expand into arrays. - * These can be predefined by files that #include this one, - * when different separators are required. - */ -/* Element separator for macros that expand into 1-dimensional arrays: */ -#ifndef XCHAL_SEP -#define XCHAL_SEP , -#endif -/* Array separator for macros that expand into 2-dimensional arrays: */ -#ifndef XCHAL_SEP2 -#define XCHAL_SEP2 },{ -#endif - - -/*---------------------------------------------------------------------- - ERRATA - ----------------------------------------------------------------------*/ - -/* - * Erratum T1020.H13, T1030.H7, T1040.H10, T1050.H4 (fixed in T1040.3 and T1050.1; - * relevant only in XEA1, kernel-vector mode, level-one interrupts and overflows enabled): - */ -#define XCHAL_MAYHAVE_ERRATUM_XEA1KWIN (XCHAL_HAVE_XEA1 && \ - (XCHAL_HW_RELEASE_AT_OR_BELOW(1040,2) != 0 \ - || XCHAL_HW_RELEASE_AT(1050,0))) -/* - * Erratum 453 present in RE-2013.2 up to RF-2014.0, fixed in RF-2014.1. - * Applies to specific set of configuration options. - * Part of the workaround is to add ISYNC at certain points in the code. - * The workaround gated by this macro can be disabled if not needed, e.g. if - * zero-overhead loop buffer will be disabled, by defining _NO_ERRATUM_453. - */ -#if ( XCHAL_HW_MAX_VERSION >= XTENSA_HWVERSION_RE_2013_2 && \ - XCHAL_HW_MIN_VERSION <= XTENSA_HWVERSION_RF_2014_0 && \ - XCHAL_ICACHE_SIZE != 0 && XCHAL_HAVE_PIF /*covers also AXI/AHB*/ && \ - XCHAL_HAVE_LOOPS && XCHAL_LOOP_BUFFER_SIZE != 0 && \ - XCHAL_CLOCK_GATING_GLOBAL && !defined(_NO_ERRATUM_453) ) -#define XCHAL_ERRATUM_453 1 -#else -#define XCHAL_ERRATUM_453 0 -#endif - -/* - * Erratum 497 present in RE-2012.2 up to RG/RF-2015.2 - * Applies to specific set of configuration options. - * Workaround is to add MEMWs after at most 8 cache WB instructions - */ -#if ( ((XCHAL_HW_MAX_VERSION >= XTENSA_HWVERSION_RE_2012_0 && \ - XCHAL_HW_MIN_VERSION <= XTENSA_HWVERSION_RF_2015_2) || \ - (XCHAL_HW_MAX_VERSION >= XTENSA_HWVERSION_RG_2015_0 && \ - XCHAL_HW_MIN_VERSION <= XTENSA_HWVERSION_RG_2015_2) \ - ) && \ - XCHAL_DCACHE_IS_WRITEBACK && \ - XCHAL_HAVE_AXI && \ - XCHAL_HAVE_PIF_WR_RESP && \ - XCHAL_HAVE_PIF_REQ_ATTR && !defined(_NO_ERRATUM_497) \ - ) -#define XCHAL_ERRATUM_497 1 -#else -#define XCHAL_ERRATUM_497 0 -#endif - - -/*---------------------------------------------------------------------- - ISA - ----------------------------------------------------------------------*/ - -#if XCHAL_HAVE_BE -# define XCHAL_HAVE_LE 0 -# define XCHAL_MEMORY_ORDER XTHAL_BIGENDIAN -#else -# define XCHAL_HAVE_LE 1 -# define XCHAL_MEMORY_ORDER XTHAL_LITTLEENDIAN -#endif - - - -/*---------------------------------------------------------------------- - INTERRUPTS - ----------------------------------------------------------------------*/ - -/* Indexing macros: */ -#define _XCHAL_INTLEVEL_MASK(n) XCHAL_INTLEVEL ## n ## _MASK -#define XCHAL_INTLEVEL_MASK(n) _XCHAL_INTLEVEL_MASK(n) /* n = 0 .. 15 */ -#define _XCHAL_INTLEVEL_ANDBELOWMASK(n) XCHAL_INTLEVEL ## n ## _ANDBELOW_MASK -#define XCHAL_INTLEVEL_ANDBELOW_MASK(n) _XCHAL_INTLEVEL_ANDBELOWMASK(n) /* n = 0 .. 15 */ -#define _XCHAL_INTLEVEL_NUM(n) XCHAL_INTLEVEL ## n ## _NUM -#define XCHAL_INTLEVEL_NUM(n) _XCHAL_INTLEVEL_NUM(n) /* n = 0 .. 15 */ -#define _XCHAL_INT_LEVEL(n) XCHAL_INT ## n ## _LEVEL -#define XCHAL_INT_LEVEL(n) _XCHAL_INT_LEVEL(n) /* n = 0 .. 31 */ -#define _XCHAL_INT_TYPE(n) XCHAL_INT ## n ## _TYPE -#define XCHAL_INT_TYPE(n) _XCHAL_INT_TYPE(n) /* n = 0 .. 31 */ -#define _XCHAL_TIMER_INTERRUPT(n) XCHAL_TIMER ## n ## _INTERRUPT -#define XCHAL_TIMER_INTERRUPT(n) _XCHAL_TIMER_INTERRUPT(n) /* n = 0 .. 3 */ - - -#define XCHAL_HAVE_HIGHLEVEL_INTERRUPTS XCHAL_HAVE_HIGHPRI_INTERRUPTS -#define XCHAL_NUM_LOWPRI_LEVELS 1 /* number of low-priority interrupt levels (always 1) */ -#define XCHAL_FIRST_HIGHPRI_LEVEL (XCHAL_NUM_LOWPRI_LEVELS+1) /* level of first high-priority interrupt (always 2) */ -/* Note: 1 <= LOWPRI_LEVELS <= EXCM_LEVEL < DEBUGLEVEL <= NUM_INTLEVELS < NMILEVEL <= 15 */ - -/* These values are constant for existing Xtensa processor implementations: */ -#define XCHAL_INTLEVEL0_MASK 0x00000000 -#define XCHAL_INTLEVEL8_MASK 0x00000000 -#define XCHAL_INTLEVEL9_MASK 0x00000000 -#define XCHAL_INTLEVEL10_MASK 0x00000000 -#define XCHAL_INTLEVEL11_MASK 0x00000000 -#define XCHAL_INTLEVEL12_MASK 0x00000000 -#define XCHAL_INTLEVEL13_MASK 0x00000000 -#define XCHAL_INTLEVEL14_MASK 0x00000000 -#define XCHAL_INTLEVEL15_MASK 0x00000000 - -/* Array of masks of interrupts at each interrupt level: */ -#define XCHAL_INTLEVEL_MASKS XCHAL_INTLEVEL0_MASK \ - XCHAL_SEP XCHAL_INTLEVEL1_MASK \ - XCHAL_SEP XCHAL_INTLEVEL2_MASK \ - XCHAL_SEP XCHAL_INTLEVEL3_MASK \ - XCHAL_SEP XCHAL_INTLEVEL4_MASK \ - XCHAL_SEP XCHAL_INTLEVEL5_MASK \ - XCHAL_SEP XCHAL_INTLEVEL6_MASK \ - XCHAL_SEP XCHAL_INTLEVEL7_MASK \ - XCHAL_SEP XCHAL_INTLEVEL8_MASK \ - XCHAL_SEP XCHAL_INTLEVEL9_MASK \ - XCHAL_SEP XCHAL_INTLEVEL10_MASK \ - XCHAL_SEP XCHAL_INTLEVEL11_MASK \ - XCHAL_SEP XCHAL_INTLEVEL12_MASK \ - XCHAL_SEP XCHAL_INTLEVEL13_MASK \ - XCHAL_SEP XCHAL_INTLEVEL14_MASK \ - XCHAL_SEP XCHAL_INTLEVEL15_MASK - -/* These values are constant for existing Xtensa processor implementations: */ -#define XCHAL_INTLEVEL0_ANDBELOW_MASK 0x00000000 -#define XCHAL_INTLEVEL8_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK -#define XCHAL_INTLEVEL9_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK -#define XCHAL_INTLEVEL10_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK -#define XCHAL_INTLEVEL11_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK -#define XCHAL_INTLEVEL12_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK -#define XCHAL_INTLEVEL13_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK -#define XCHAL_INTLEVEL14_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK -#define XCHAL_INTLEVEL15_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK - -/* Mask of all low-priority interrupts: */ -#define XCHAL_LOWPRI_MASK XCHAL_INTLEVEL1_ANDBELOW_MASK - -/* Mask of all interrupts masked by PS.EXCM (or CEXCM): */ -#define XCHAL_EXCM_MASK XCHAL_INTLEVEL_ANDBELOW_MASK(XCHAL_EXCM_LEVEL) - -/* Array of masks of interrupts at each range 1..n of interrupt levels: */ -#define XCHAL_INTLEVEL_ANDBELOW_MASKS XCHAL_INTLEVEL0_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL1_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL2_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL3_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL4_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL5_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL6_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL7_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL8_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL9_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL10_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL11_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL12_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL13_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL14_ANDBELOW_MASK \ - XCHAL_SEP XCHAL_INTLEVEL15_ANDBELOW_MASK - -#if 0 /*XCHAL_HAVE_NMI*/ -/* NMI "interrupt level" (for use with EXCSAVE_n, EPS_n, EPC_n, RFI n): */ -# define XCHAL_NMILEVEL (XCHAL_NUM_INTLEVELS+1) -#endif - -/* Array of levels of each possible interrupt: */ -#define XCHAL_INT_LEVELS XCHAL_INT0_LEVEL \ - XCHAL_SEP XCHAL_INT1_LEVEL \ - XCHAL_SEP XCHAL_INT2_LEVEL \ - XCHAL_SEP XCHAL_INT3_LEVEL \ - XCHAL_SEP XCHAL_INT4_LEVEL \ - XCHAL_SEP XCHAL_INT5_LEVEL \ - XCHAL_SEP XCHAL_INT6_LEVEL \ - XCHAL_SEP XCHAL_INT7_LEVEL \ - XCHAL_SEP XCHAL_INT8_LEVEL \ - XCHAL_SEP XCHAL_INT9_LEVEL \ - XCHAL_SEP XCHAL_INT10_LEVEL \ - XCHAL_SEP XCHAL_INT11_LEVEL \ - XCHAL_SEP XCHAL_INT12_LEVEL \ - XCHAL_SEP XCHAL_INT13_LEVEL \ - XCHAL_SEP XCHAL_INT14_LEVEL \ - XCHAL_SEP XCHAL_INT15_LEVEL \ - XCHAL_SEP XCHAL_INT16_LEVEL \ - XCHAL_SEP XCHAL_INT17_LEVEL \ - XCHAL_SEP XCHAL_INT18_LEVEL \ - XCHAL_SEP XCHAL_INT19_LEVEL \ - XCHAL_SEP XCHAL_INT20_LEVEL \ - XCHAL_SEP XCHAL_INT21_LEVEL \ - XCHAL_SEP XCHAL_INT22_LEVEL \ - XCHAL_SEP XCHAL_INT23_LEVEL \ - XCHAL_SEP XCHAL_INT24_LEVEL \ - XCHAL_SEP XCHAL_INT25_LEVEL \ - XCHAL_SEP XCHAL_INT26_LEVEL \ - XCHAL_SEP XCHAL_INT27_LEVEL \ - XCHAL_SEP XCHAL_INT28_LEVEL \ - XCHAL_SEP XCHAL_INT29_LEVEL \ - XCHAL_SEP XCHAL_INT30_LEVEL \ - XCHAL_SEP XCHAL_INT31_LEVEL - -/* Array of types of each possible interrupt: */ -#define XCHAL_INT_TYPES XCHAL_INT0_TYPE \ - XCHAL_SEP XCHAL_INT1_TYPE \ - XCHAL_SEP XCHAL_INT2_TYPE \ - XCHAL_SEP XCHAL_INT3_TYPE \ - XCHAL_SEP XCHAL_INT4_TYPE \ - XCHAL_SEP XCHAL_INT5_TYPE \ - XCHAL_SEP XCHAL_INT6_TYPE \ - XCHAL_SEP XCHAL_INT7_TYPE \ - XCHAL_SEP XCHAL_INT8_TYPE \ - XCHAL_SEP XCHAL_INT9_TYPE \ - XCHAL_SEP XCHAL_INT10_TYPE \ - XCHAL_SEP XCHAL_INT11_TYPE \ - XCHAL_SEP XCHAL_INT12_TYPE \ - XCHAL_SEP XCHAL_INT13_TYPE \ - XCHAL_SEP XCHAL_INT14_TYPE \ - XCHAL_SEP XCHAL_INT15_TYPE \ - XCHAL_SEP XCHAL_INT16_TYPE \ - XCHAL_SEP XCHAL_INT17_TYPE \ - XCHAL_SEP XCHAL_INT18_TYPE \ - XCHAL_SEP XCHAL_INT19_TYPE \ - XCHAL_SEP XCHAL_INT20_TYPE \ - XCHAL_SEP XCHAL_INT21_TYPE \ - XCHAL_SEP XCHAL_INT22_TYPE \ - XCHAL_SEP XCHAL_INT23_TYPE \ - XCHAL_SEP XCHAL_INT24_TYPE \ - XCHAL_SEP XCHAL_INT25_TYPE \ - XCHAL_SEP XCHAL_INT26_TYPE \ - XCHAL_SEP XCHAL_INT27_TYPE \ - XCHAL_SEP XCHAL_INT28_TYPE \ - XCHAL_SEP XCHAL_INT29_TYPE \ - XCHAL_SEP XCHAL_INT30_TYPE \ - XCHAL_SEP XCHAL_INT31_TYPE - -/* Array of masks of interrupts for each type of interrupt: */ -#define XCHAL_INTTYPE_MASKS XCHAL_INTTYPE_MASK_UNCONFIGURED \ - XCHAL_SEP XCHAL_INTTYPE_MASK_SOFTWARE \ - XCHAL_SEP XCHAL_INTTYPE_MASK_EXTERN_EDGE \ - XCHAL_SEP XCHAL_INTTYPE_MASK_EXTERN_LEVEL \ - XCHAL_SEP XCHAL_INTTYPE_MASK_TIMER \ - XCHAL_SEP XCHAL_INTTYPE_MASK_NMI \ - XCHAL_SEP XCHAL_INTTYPE_MASK_WRITE_ERROR \ - XCHAL_SEP XCHAL_INTTYPE_MASK_IDMA_DONE \ - XCHAL_SEP XCHAL_INTTYPE_MASK_IDMA_ERR \ - XCHAL_SEP XCHAL_INTTYPE_MASK_GS_ERR - -/* Interrupts that can be cleared using the INTCLEAR special register: */ -#define XCHAL_INTCLEARABLE_MASK (XCHAL_INTTYPE_MASK_SOFTWARE+XCHAL_INTTYPE_MASK_EXTERN_EDGE+XCHAL_INTTYPE_MASK_WRITE_ERROR) -/* Interrupts that can be triggered using the INTSET special register: */ -#define XCHAL_INTSETTABLE_MASK XCHAL_INTTYPE_MASK_SOFTWARE - -/* Array of interrupts assigned to each timer (CCOMPARE0 to CCOMPARE3): */ -#define XCHAL_TIMER_INTERRUPTS XCHAL_TIMER0_INTERRUPT \ - XCHAL_SEP XCHAL_TIMER1_INTERRUPT \ - XCHAL_SEP XCHAL_TIMER2_INTERRUPT \ - XCHAL_SEP XCHAL_TIMER3_INTERRUPT - - - -/* For backward compatibility and for the array macros, define macros for - * each unconfigured interrupt number (unfortunately, the value of - * XTHAL_INTTYPE_UNCONFIGURED is not zero): */ -#if XCHAL_NUM_INTERRUPTS == 0 -# define XCHAL_INT0_LEVEL 0 -# define XCHAL_INT0_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 1 -# define XCHAL_INT1_LEVEL 0 -# define XCHAL_INT1_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 2 -# define XCHAL_INT2_LEVEL 0 -# define XCHAL_INT2_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 3 -# define XCHAL_INT3_LEVEL 0 -# define XCHAL_INT3_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 4 -# define XCHAL_INT4_LEVEL 0 -# define XCHAL_INT4_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 5 -# define XCHAL_INT5_LEVEL 0 -# define XCHAL_INT5_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 6 -# define XCHAL_INT6_LEVEL 0 -# define XCHAL_INT6_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 7 -# define XCHAL_INT7_LEVEL 0 -# define XCHAL_INT7_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 8 -# define XCHAL_INT8_LEVEL 0 -# define XCHAL_INT8_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 9 -# define XCHAL_INT9_LEVEL 0 -# define XCHAL_INT9_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 10 -# define XCHAL_INT10_LEVEL 0 -# define XCHAL_INT10_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 11 -# define XCHAL_INT11_LEVEL 0 -# define XCHAL_INT11_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 12 -# define XCHAL_INT12_LEVEL 0 -# define XCHAL_INT12_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 13 -# define XCHAL_INT13_LEVEL 0 -# define XCHAL_INT13_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 14 -# define XCHAL_INT14_LEVEL 0 -# define XCHAL_INT14_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 15 -# define XCHAL_INT15_LEVEL 0 -# define XCHAL_INT15_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 16 -# define XCHAL_INT16_LEVEL 0 -# define XCHAL_INT16_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 17 -# define XCHAL_INT17_LEVEL 0 -# define XCHAL_INT17_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 18 -# define XCHAL_INT18_LEVEL 0 -# define XCHAL_INT18_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 19 -# define XCHAL_INT19_LEVEL 0 -# define XCHAL_INT19_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 20 -# define XCHAL_INT20_LEVEL 0 -# define XCHAL_INT20_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 21 -# define XCHAL_INT21_LEVEL 0 -# define XCHAL_INT21_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 22 -# define XCHAL_INT22_LEVEL 0 -# define XCHAL_INT22_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 23 -# define XCHAL_INT23_LEVEL 0 -# define XCHAL_INT23_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 24 -# define XCHAL_INT24_LEVEL 0 -# define XCHAL_INT24_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 25 -# define XCHAL_INT25_LEVEL 0 -# define XCHAL_INT25_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 26 -# define XCHAL_INT26_LEVEL 0 -# define XCHAL_INT26_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 27 -# define XCHAL_INT27_LEVEL 0 -# define XCHAL_INT27_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 28 -# define XCHAL_INT28_LEVEL 0 -# define XCHAL_INT28_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 29 -# define XCHAL_INT29_LEVEL 0 -# define XCHAL_INT29_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 30 -# define XCHAL_INT30_LEVEL 0 -# define XCHAL_INT30_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif -#if XCHAL_NUM_INTERRUPTS <= 31 -# define XCHAL_INT31_LEVEL 0 -# define XCHAL_INT31_TYPE XTHAL_INTTYPE_UNCONFIGURED -#endif - - -/* - * Masks and levels corresponding to each *external* interrupt. - */ - -#define XCHAL_EXTINT0_MASK (1 << XCHAL_EXTINT0_NUM) -#define XCHAL_EXTINT0_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT0_NUM) -#define XCHAL_EXTINT1_MASK (1 << XCHAL_EXTINT1_NUM) -#define XCHAL_EXTINT1_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT1_NUM) -#define XCHAL_EXTINT2_MASK (1 << XCHAL_EXTINT2_NUM) -#define XCHAL_EXTINT2_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT2_NUM) -#define XCHAL_EXTINT3_MASK (1 << XCHAL_EXTINT3_NUM) -#define XCHAL_EXTINT3_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT3_NUM) -#define XCHAL_EXTINT4_MASK (1 << XCHAL_EXTINT4_NUM) -#define XCHAL_EXTINT4_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT4_NUM) -#define XCHAL_EXTINT5_MASK (1 << XCHAL_EXTINT5_NUM) -#define XCHAL_EXTINT5_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT5_NUM) -#define XCHAL_EXTINT6_MASK (1 << XCHAL_EXTINT6_NUM) -#define XCHAL_EXTINT6_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT6_NUM) -#define XCHAL_EXTINT7_MASK (1 << XCHAL_EXTINT7_NUM) -#define XCHAL_EXTINT7_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT7_NUM) -#define XCHAL_EXTINT8_MASK (1 << XCHAL_EXTINT8_NUM) -#define XCHAL_EXTINT8_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT8_NUM) -#define XCHAL_EXTINT9_MASK (1 << XCHAL_EXTINT9_NUM) -#define XCHAL_EXTINT9_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT9_NUM) -#define XCHAL_EXTINT10_MASK (1 << XCHAL_EXTINT10_NUM) -#define XCHAL_EXTINT10_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT10_NUM) -#define XCHAL_EXTINT11_MASK (1 << XCHAL_EXTINT11_NUM) -#define XCHAL_EXTINT11_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT11_NUM) -#define XCHAL_EXTINT12_MASK (1 << XCHAL_EXTINT12_NUM) -#define XCHAL_EXTINT12_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT12_NUM) -#define XCHAL_EXTINT13_MASK (1 << XCHAL_EXTINT13_NUM) -#define XCHAL_EXTINT13_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT13_NUM) -#define XCHAL_EXTINT14_MASK (1 << XCHAL_EXTINT14_NUM) -#define XCHAL_EXTINT14_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT14_NUM) -#define XCHAL_EXTINT15_MASK (1 << XCHAL_EXTINT15_NUM) -#define XCHAL_EXTINT15_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT15_NUM) -#define XCHAL_EXTINT16_MASK (1 << XCHAL_EXTINT16_NUM) -#define XCHAL_EXTINT16_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT16_NUM) -#define XCHAL_EXTINT17_MASK (1 << XCHAL_EXTINT17_NUM) -#define XCHAL_EXTINT17_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT17_NUM) -#define XCHAL_EXTINT18_MASK (1 << XCHAL_EXTINT18_NUM) -#define XCHAL_EXTINT18_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT18_NUM) -#define XCHAL_EXTINT19_MASK (1 << XCHAL_EXTINT19_NUM) -#define XCHAL_EXTINT19_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT19_NUM) -#define XCHAL_EXTINT20_MASK (1 << XCHAL_EXTINT20_NUM) -#define XCHAL_EXTINT20_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT20_NUM) -#define XCHAL_EXTINT21_MASK (1 << XCHAL_EXTINT21_NUM) -#define XCHAL_EXTINT21_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT21_NUM) -#define XCHAL_EXTINT22_MASK (1 << XCHAL_EXTINT22_NUM) -#define XCHAL_EXTINT22_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT22_NUM) -#define XCHAL_EXTINT23_MASK (1 << XCHAL_EXTINT23_NUM) -#define XCHAL_EXTINT23_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT23_NUM) -#define XCHAL_EXTINT24_MASK (1 << XCHAL_EXTINT24_NUM) -#define XCHAL_EXTINT24_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT24_NUM) -#define XCHAL_EXTINT25_MASK (1 << XCHAL_EXTINT25_NUM) -#define XCHAL_EXTINT25_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT25_NUM) -#define XCHAL_EXTINT26_MASK (1 << XCHAL_EXTINT26_NUM) -#define XCHAL_EXTINT26_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT26_NUM) -#define XCHAL_EXTINT27_MASK (1 << XCHAL_EXTINT27_NUM) -#define XCHAL_EXTINT27_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT27_NUM) -#define XCHAL_EXTINT28_MASK (1 << XCHAL_EXTINT28_NUM) -#define XCHAL_EXTINT28_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT28_NUM) -#define XCHAL_EXTINT29_MASK (1 << XCHAL_EXTINT29_NUM) -#define XCHAL_EXTINT29_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT29_NUM) -#define XCHAL_EXTINT30_MASK (1 << XCHAL_EXTINT30_NUM) -#define XCHAL_EXTINT30_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT30_NUM) -#define XCHAL_EXTINT31_MASK (1 << XCHAL_EXTINT31_NUM) -#define XCHAL_EXTINT31_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT31_NUM) - - -/*---------------------------------------------------------------------- - EXCEPTIONS and VECTORS - ----------------------------------------------------------------------*/ - -/* For backward compatibility ONLY -- DO NOT USE (will be removed in future release): */ -#define XCHAL_HAVE_OLD_EXC_ARCH XCHAL_HAVE_XEA1 /* (DEPRECATED) 1 if old exception architecture (XEA1), 0 otherwise (eg. XEA2) */ -#define XCHAL_HAVE_EXCM XCHAL_HAVE_XEA2 /* (DEPRECATED) 1 if PS.EXCM bit exists (currently equals XCHAL_HAVE_TLBS) */ -#ifdef XCHAL_USER_VECTOR_VADDR -#define XCHAL_PROGRAMEXC_VECTOR_VADDR XCHAL_USER_VECTOR_VADDR -#define XCHAL_USEREXC_VECTOR_VADDR XCHAL_USER_VECTOR_VADDR -#endif -#ifdef XCHAL_USER_VECTOR_PADDR -# define XCHAL_PROGRAMEXC_VECTOR_PADDR XCHAL_USER_VECTOR_PADDR -# define XCHAL_USEREXC_VECTOR_PADDR XCHAL_USER_VECTOR_PADDR -#endif -#ifdef XCHAL_KERNEL_VECTOR_VADDR -# define XCHAL_STACKEDEXC_VECTOR_VADDR XCHAL_KERNEL_VECTOR_VADDR -# define XCHAL_KERNELEXC_VECTOR_VADDR XCHAL_KERNEL_VECTOR_VADDR -#endif -#ifdef XCHAL_KERNEL_VECTOR_PADDR -# define XCHAL_STACKEDEXC_VECTOR_PADDR XCHAL_KERNEL_VECTOR_PADDR -# define XCHAL_KERNELEXC_VECTOR_PADDR XCHAL_KERNEL_VECTOR_PADDR -#endif - -#if 0 -#if XCHAL_HAVE_DEBUG -# define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL) -/* This one should only get defined if the corresponding intlevel paddr macro exists: */ -# define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL_VECTOR_PADDR(XCHAL_DEBUGLEVEL) -#endif -#endif - -/* Indexing macros: */ -#define _XCHAL_INTLEVEL_VECTOR_VADDR(n) XCHAL_INTLEVEL ## n ## _VECTOR_VADDR -#define XCHAL_INTLEVEL_VECTOR_VADDR(n) _XCHAL_INTLEVEL_VECTOR_VADDR(n) /* n = 0 .. 15 */ - -/* - * General Exception Causes - * (values of EXCCAUSE special register set by general exceptions, - * which vector to the user, kernel, or double-exception vectors). - * - * DEPRECATED. Please use the equivalent EXCCAUSE_xxx macros - * defined in <xtensa/corebits.h>. (Note that these have slightly - * different names, they don't just have the XCHAL_ prefix removed.) - */ -#define XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION 0 /* Illegal Instruction */ -#define XCHAL_EXCCAUSE_SYSTEM_CALL 1 /* System Call */ -#define XCHAL_EXCCAUSE_INSTRUCTION_FETCH_ERROR 2 /* Instruction Fetch Error */ -#define XCHAL_EXCCAUSE_LOAD_STORE_ERROR 3 /* Load Store Error */ -#define XCHAL_EXCCAUSE_LEVEL1_INTERRUPT 4 /* Level 1 Interrupt */ -#define XCHAL_EXCCAUSE_ALLOCA 5 /* Stack Extension Assist */ -#define XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO 6 /* Integer Divide by Zero */ -#define XCHAL_EXCCAUSE_SPECULATION 7 /* Speculation */ -#define XCHAL_EXCCAUSE_PRIVILEGED 8 /* Privileged Instruction */ -#define XCHAL_EXCCAUSE_UNALIGNED 9 /* Unaligned Load Store */ -/*10..15 reserved*/ -#define XCHAL_EXCCAUSE_ITLB_MISS 16 /* ITlb Miss Exception */ -#define XCHAL_EXCCAUSE_ITLB_MULTIHIT 17 /* ITlb Mutltihit Exception */ -#define XCHAL_EXCCAUSE_ITLB_PRIVILEGE 18 /* ITlb Privilege Exception */ -#define XCHAL_EXCCAUSE_ITLB_SIZE_RESTRICTION 19 /* ITlb Size Restriction Exception */ -#define XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE 20 /* Fetch Cache Attribute Exception */ -/*21..23 reserved*/ -#define XCHAL_EXCCAUSE_DTLB_MISS 24 /* DTlb Miss Exception */ -#define XCHAL_EXCCAUSE_DTLB_MULTIHIT 25 /* DTlb Multihit Exception */ -#define XCHAL_EXCCAUSE_DTLB_PRIVILEGE 26 /* DTlb Privilege Exception */ -#define XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION 27 /* DTlb Size Restriction Exception */ -#define XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE 28 /* Load Cache Attribute Exception */ -#define XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE 29 /* Store Cache Attribute Exception */ -/*30..31 reserved*/ -#define XCHAL_EXCCAUSE_COPROCESSOR0_DISABLED 32 /* Coprocessor 0 disabled */ -#define XCHAL_EXCCAUSE_COPROCESSOR1_DISABLED 33 /* Coprocessor 1 disabled */ -#define XCHAL_EXCCAUSE_COPROCESSOR2_DISABLED 34 /* Coprocessor 2 disabled */ -#define XCHAL_EXCCAUSE_COPROCESSOR3_DISABLED 35 /* Coprocessor 3 disabled */ -#define XCHAL_EXCCAUSE_COPROCESSOR4_DISABLED 36 /* Coprocessor 4 disabled */ -#define XCHAL_EXCCAUSE_COPROCESSOR5_DISABLED 37 /* Coprocessor 5 disabled */ -#define XCHAL_EXCCAUSE_COPROCESSOR6_DISABLED 38 /* Coprocessor 6 disabled */ -#define XCHAL_EXCCAUSE_COPROCESSOR7_DISABLED 39 /* Coprocessor 7 disabled */ -/*40..63 reserved*/ - - -/* - * Miscellaneous special register fields. - * - * For each special register, and each field within each register: - * XCHAL_<regname>_VALIDMASK is the set of bits defined in the register. - * XCHAL_<regname>_<field>_BITS is the number of bits in the field. - * XCHAL_<regname>_<field>_NUM is 2^bits, the number of possible values - * of the field. - * XCHAL_<regname>_<field>_SHIFT is the position of the field within - * the register, starting from the least significant bit. - * - * DEPRECATED. Please use the equivalent macros defined in - * <xtensa/corebits.h>. (Note that these have different names.) - */ - -/* DBREAKC (special register number 160): */ -#define XCHAL_DBREAKC_VALIDMASK 0xC000003F -#define XCHAL_DBREAKC_MASK_BITS 6 -#define XCHAL_DBREAKC_MASK_NUM 64 -#define XCHAL_DBREAKC_MASK_SHIFT 0 -#define XCHAL_DBREAKC_MASK_MASK 0x0000003F -#define XCHAL_DBREAKC_LOADBREAK_BITS 1 -#define XCHAL_DBREAKC_LOADBREAK_NUM 2 -#define XCHAL_DBREAKC_LOADBREAK_SHIFT 30 -#define XCHAL_DBREAKC_LOADBREAK_MASK 0x40000000 -#define XCHAL_DBREAKC_STOREBREAK_BITS 1 -#define XCHAL_DBREAKC_STOREBREAK_NUM 2 -#define XCHAL_DBREAKC_STOREBREAK_SHIFT 31 -#define XCHAL_DBREAKC_STOREBREAK_MASK 0x80000000 -/* PS (special register number 230): */ -#define XCHAL_PS_VALIDMASK 0x00070F3F -#define XCHAL_PS_INTLEVEL_BITS 4 -#define XCHAL_PS_INTLEVEL_NUM 16 -#define XCHAL_PS_INTLEVEL_SHIFT 0 -#define XCHAL_PS_INTLEVEL_MASK 0x0000000F -#define XCHAL_PS_EXCM_BITS 1 -#define XCHAL_PS_EXCM_NUM 2 -#define XCHAL_PS_EXCM_SHIFT 4 -#define XCHAL_PS_EXCM_MASK 0x00000010 -#define XCHAL_PS_UM_BITS 1 -#define XCHAL_PS_UM_NUM 2 -#define XCHAL_PS_UM_SHIFT 5 -#define XCHAL_PS_UM_MASK 0x00000020 -#define XCHAL_PS_RING_BITS 2 -#define XCHAL_PS_RING_NUM 4 -#define XCHAL_PS_RING_SHIFT 6 -#define XCHAL_PS_RING_MASK 0x000000C0 -#define XCHAL_PS_OWB_BITS 4 -#define XCHAL_PS_OWB_NUM 16 -#define XCHAL_PS_OWB_SHIFT 8 -#define XCHAL_PS_OWB_MASK 0x00000F00 -#define XCHAL_PS_CALLINC_BITS 2 -#define XCHAL_PS_CALLINC_NUM 4 -#define XCHAL_PS_CALLINC_SHIFT 16 -#define XCHAL_PS_CALLINC_MASK 0x00030000 -#define XCHAL_PS_WOE_BITS 1 -#define XCHAL_PS_WOE_NUM 2 -#define XCHAL_PS_WOE_SHIFT 18 -#define XCHAL_PS_WOE_MASK 0x00040000 -/* EXCCAUSE (special register number 232): */ -#define XCHAL_EXCCAUSE_VALIDMASK 0x0000003F -#define XCHAL_EXCCAUSE_BITS 6 -#define XCHAL_EXCCAUSE_NUM 64 -#define XCHAL_EXCCAUSE_SHIFT 0 -#define XCHAL_EXCCAUSE_MASK 0x0000003F -/* DEBUGCAUSE (special register number 233): */ -#define XCHAL_DEBUGCAUSE_VALIDMASK 0x0000003F -#define XCHAL_DEBUGCAUSE_ICOUNT_BITS 1 -#define XCHAL_DEBUGCAUSE_ICOUNT_NUM 2 -#define XCHAL_DEBUGCAUSE_ICOUNT_SHIFT 0 -#define XCHAL_DEBUGCAUSE_ICOUNT_MASK 0x00000001 -#define XCHAL_DEBUGCAUSE_IBREAK_BITS 1 -#define XCHAL_DEBUGCAUSE_IBREAK_NUM 2 -#define XCHAL_DEBUGCAUSE_IBREAK_SHIFT 1 -#define XCHAL_DEBUGCAUSE_IBREAK_MASK 0x00000002 -#define XCHAL_DEBUGCAUSE_DBREAK_BITS 1 -#define XCHAL_DEBUGCAUSE_DBREAK_NUM 2 -#define XCHAL_DEBUGCAUSE_DBREAK_SHIFT 2 -#define XCHAL_DEBUGCAUSE_DBREAK_MASK 0x00000004 -#define XCHAL_DEBUGCAUSE_BREAK_BITS 1 -#define XCHAL_DEBUGCAUSE_BREAK_NUM 2 -#define XCHAL_DEBUGCAUSE_BREAK_SHIFT 3 -#define XCHAL_DEBUGCAUSE_BREAK_MASK 0x00000008 -#define XCHAL_DEBUGCAUSE_BREAKN_BITS 1 -#define XCHAL_DEBUGCAUSE_BREAKN_NUM 2 -#define XCHAL_DEBUGCAUSE_BREAKN_SHIFT 4 -#define XCHAL_DEBUGCAUSE_BREAKN_MASK 0x00000010 -#define XCHAL_DEBUGCAUSE_DEBUGINT_BITS 1 -#define XCHAL_DEBUGCAUSE_DEBUGINT_NUM 2 -#define XCHAL_DEBUGCAUSE_DEBUGINT_SHIFT 5 -#define XCHAL_DEBUGCAUSE_DEBUGINT_MASK 0x00000020 - - - - -/*---------------------------------------------------------------------- - TIMERS - ----------------------------------------------------------------------*/ - -/*#define XCHAL_HAVE_TIMERS XCHAL_HAVE_CCOUNT*/ - - - -/*---------------------------------------------------------------------- - INTERNAL I/D RAM/ROMs and XLMI - ----------------------------------------------------------------------*/ - -#define XCHAL_NUM_IROM XCHAL_NUM_INSTROM /* (DEPRECATED) */ -#define XCHAL_NUM_IRAM XCHAL_NUM_INSTRAM /* (DEPRECATED) */ -#define XCHAL_NUM_DROM XCHAL_NUM_DATAROM /* (DEPRECATED) */ -#define XCHAL_NUM_DRAM XCHAL_NUM_DATARAM /* (DEPRECATED) */ - -#define XCHAL_IROM0_VADDR XCHAL_INSTROM0_VADDR /* (DEPRECATED) */ -#define XCHAL_IROM0_PADDR XCHAL_INSTROM0_PADDR /* (DEPRECATED) */ -#define XCHAL_IROM0_SIZE XCHAL_INSTROM0_SIZE /* (DEPRECATED) */ -#define XCHAL_IROM1_VADDR XCHAL_INSTROM1_VADDR /* (DEPRECATED) */ -#define XCHAL_IROM1_PADDR XCHAL_INSTROM1_PADDR /* (DEPRECATED) */ -#define XCHAL_IROM1_SIZE XCHAL_INSTROM1_SIZE /* (DEPRECATED) */ -#define XCHAL_IRAM0_VADDR XCHAL_INSTRAM0_VADDR /* (DEPRECATED) */ -#define XCHAL_IRAM0_PADDR XCHAL_INSTRAM0_PADDR /* (DEPRECATED) */ -#define XCHAL_IRAM0_SIZE XCHAL_INSTRAM0_SIZE /* (DEPRECATED) */ -#define XCHAL_IRAM1_VADDR XCHAL_INSTRAM1_VADDR /* (DEPRECATED) */ -#define XCHAL_IRAM1_PADDR XCHAL_INSTRAM1_PADDR /* (DEPRECATED) */ -#define XCHAL_IRAM1_SIZE XCHAL_INSTRAM1_SIZE /* (DEPRECATED) */ -#define XCHAL_DROM0_VADDR XCHAL_DATAROM0_VADDR /* (DEPRECATED) */ -#define XCHAL_DROM0_PADDR XCHAL_DATAROM0_PADDR /* (DEPRECATED) */ -#define XCHAL_DROM0_SIZE XCHAL_DATAROM0_SIZE /* (DEPRECATED) */ -#define XCHAL_DROM1_VADDR XCHAL_DATAROM1_VADDR /* (DEPRECATED) */ -#define XCHAL_DROM1_PADDR XCHAL_DATAROM1_PADDR /* (DEPRECATED) */ -#define XCHAL_DROM1_SIZE XCHAL_DATAROM1_SIZE /* (DEPRECATED) */ -#define XCHAL_DRAM0_VADDR XCHAL_DATARAM0_VADDR /* (DEPRECATED) */ -#define XCHAL_DRAM0_PADDR XCHAL_DATARAM0_PADDR /* (DEPRECATED) */ -#define XCHAL_DRAM0_SIZE XCHAL_DATARAM0_SIZE /* (DEPRECATED) */ -#define XCHAL_DRAM1_VADDR XCHAL_DATARAM1_VADDR /* (DEPRECATED) */ -#define XCHAL_DRAM1_PADDR XCHAL_DATARAM1_PADDR /* (DEPRECATED) */ -#define XCHAL_DRAM1_SIZE XCHAL_DATARAM1_SIZE /* (DEPRECATED) */ - - - -/*---------------------------------------------------------------------- - CACHE - ----------------------------------------------------------------------*/ - - -/* Default PREFCTL value to enable prefetch. */ -#if XCHAL_HW_MIN_VERSION < XTENSA_HWVERSION_RE_2012_0 -#define XCHAL_CACHE_PREFCTL_DEFAULT 0x00044 /* enabled, not aggressive */ -#elif XCHAL_HW_MIN_VERSION < XTENSA_HWVERSION_RF_2014_0 -#define XCHAL_CACHE_PREFCTL_DEFAULT 0x01044 /* + enable prefetch to L1 */ -#elif ((XCHAL_PREFETCH_ENTRIES >= 16) && XCHAL_HAVE_CACHE_BLOCKOPS) -#define XCHAL_CACHE_PREFCTL_DEFAULT 0x81044 /* 12 entries for block ops */ -#elif ((XCHAL_PREFETCH_ENTRIES >= 8) && XCHAL_HAVE_CACHE_BLOCKOPS) -#define XCHAL_CACHE_PREFCTL_DEFAULT 0x51044 /* 5 entries for block ops */ -#else -#define XCHAL_CACHE_PREFCTL_DEFAULT 0x01044 /* 0 entries for block ops */ -#endif - - -/* Max for both I-cache and D-cache (used for general alignment): */ -#if XCHAL_ICACHE_LINESIZE > XCHAL_DCACHE_LINESIZE -# define XCHAL_CACHE_LINEWIDTH_MAX XCHAL_ICACHE_LINEWIDTH -# define XCHAL_CACHE_LINESIZE_MAX XCHAL_ICACHE_LINESIZE -#else -# define XCHAL_CACHE_LINEWIDTH_MAX XCHAL_DCACHE_LINEWIDTH -# define XCHAL_CACHE_LINESIZE_MAX XCHAL_DCACHE_LINESIZE -#endif - -#define XCHAL_ICACHE_SETSIZE (1<<XCHAL_ICACHE_SETWIDTH) -#define XCHAL_DCACHE_SETSIZE (1<<XCHAL_DCACHE_SETWIDTH) -/* Max for both I and D caches (used for cache-coherency page alignment): */ -#if XCHAL_ICACHE_SETWIDTH > XCHAL_DCACHE_SETWIDTH -# define XCHAL_CACHE_SETWIDTH_MAX XCHAL_ICACHE_SETWIDTH -# define XCHAL_CACHE_SETSIZE_MAX XCHAL_ICACHE_SETSIZE -#else -# define XCHAL_CACHE_SETWIDTH_MAX XCHAL_DCACHE_SETWIDTH -# define XCHAL_CACHE_SETSIZE_MAX XCHAL_DCACHE_SETSIZE -#endif - -/* Instruction cache tag bits: */ -#define XCHAL_ICACHE_TAG_V_SHIFT 0 -#define XCHAL_ICACHE_TAG_V 0x1 /* valid bit */ -#if XCHAL_ICACHE_WAYS > 1 -# define XCHAL_ICACHE_TAG_F_SHIFT 1 -# define XCHAL_ICACHE_TAG_F 0x2 /* fill (LRU) bit */ -#else -# define XCHAL_ICACHE_TAG_F_SHIFT 0 -# define XCHAL_ICACHE_TAG_F 0 /* no fill (LRU) bit */ -#endif -#if XCHAL_ICACHE_LINE_LOCKABLE -# define XCHAL_ICACHE_TAG_L_SHIFT (XCHAL_ICACHE_TAG_F_SHIFT+1) -# define XCHAL_ICACHE_TAG_L (1 << XCHAL_ICACHE_TAG_L_SHIFT) /* lock bit */ -#else -# define XCHAL_ICACHE_TAG_L_SHIFT XCHAL_ICACHE_TAG_F_SHIFT -# define XCHAL_ICACHE_TAG_L 0 /* no lock bit */ -#endif -/* Data cache tag bits: */ -#define XCHAL_DCACHE_TAG_V_SHIFT 0 -#define XCHAL_DCACHE_TAG_V 0x1 /* valid bit */ -#if XCHAL_DCACHE_WAYS > 1 -# define XCHAL_DCACHE_TAG_F_SHIFT 1 -# define XCHAL_DCACHE_TAG_F 0x2 /* fill (LRU) bit */ -#else -# define XCHAL_DCACHE_TAG_F_SHIFT 0 -# define XCHAL_DCACHE_TAG_F 0 /* no fill (LRU) bit */ -#endif -#if XCHAL_DCACHE_IS_WRITEBACK -# define XCHAL_DCACHE_TAG_D_SHIFT (XCHAL_DCACHE_TAG_F_SHIFT+1) -# define XCHAL_DCACHE_TAG_D (1 << XCHAL_DCACHE_TAG_D_SHIFT) /* dirty bit */ -#else -# define XCHAL_DCACHE_TAG_D_SHIFT XCHAL_DCACHE_TAG_F_SHIFT -# define XCHAL_DCACHE_TAG_D 0 /* no dirty bit */ -#endif -#if XCHAL_DCACHE_LINE_LOCKABLE -# define XCHAL_DCACHE_TAG_L_SHIFT (XCHAL_DCACHE_TAG_D_SHIFT+1) -# define XCHAL_DCACHE_TAG_L (1 << XCHAL_DCACHE_TAG_L_SHIFT) /* lock bit */ -#else -# define XCHAL_DCACHE_TAG_L_SHIFT XCHAL_DCACHE_TAG_D_SHIFT -# define XCHAL_DCACHE_TAG_L 0 /* no lock bit */ -#endif - -/* Whether MEMCTL register has anything useful */ -#define XCHAL_USE_MEMCTL (((XCHAL_LOOP_BUFFER_SIZE > 0) || \ - XCHAL_DCACHE_IS_COHERENT || \ - XCHAL_HAVE_ICACHE_DYN_WAYS || \ - XCHAL_HAVE_DCACHE_DYN_WAYS) && \ - (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RE_2012_0)) - -#if XCHAL_DCACHE_IS_COHERENT -#define _MEMCTL_SNOOP_EN 0x02 /* Enable snoop */ -#else -#define _MEMCTL_SNOOP_EN 0x00 /* Don't enable snoop */ -#endif - -#if (XCHAL_LOOP_BUFFER_SIZE == 0) || XCHAL_ERRATUM_453 -#define _MEMCTL_L0IBUF_EN 0x00 /* No loop buffer or don't enable */ -#else -#define _MEMCTL_L0IBUF_EN 0x01 /* Enable loop buffer */ -#endif - -/* Default MEMCTL values: */ -#if XCHAL_HAVE_ICACHE_DYN_WAYS || XCHAL_HAVE_DCACHE_DYN_WAYS -#define XCHAL_CACHE_MEMCTL_DEFAULT (0xFFFFFF00 | _MEMCTL_L0IBUF_EN) -#else -#define XCHAL_CACHE_MEMCTL_DEFAULT (0x00000000 | _MEMCTL_L0IBUF_EN) -#endif - -#define XCHAL_SNOOP_LB_MEMCTL_DEFAULT (_MEMCTL_SNOOP_EN | _MEMCTL_L0IBUF_EN) - - -/*---------------------------------------------------------------------- - MMU - ----------------------------------------------------------------------*/ - -/* See <xtensa/config/core-matmap.h> for more details. */ - -/* Has different semantic in open source headers (where it means HAVE_PTP_MMU), - so comment out starting with RB-2008.3 release; later, might get - get reintroduced as a synonym for XCHAL_HAVE_PTP_MMU instead: */ -/*#define XCHAL_HAVE_MMU XCHAL_HAVE_TLBS*/ /* (DEPRECATED; use XCHAL_HAVE_TLBS instead) */ - -/* Indexing macros: */ -#define _XCHAL_ITLB_SET(n,_what) XCHAL_ITLB_SET ## n ## _what -#define XCHAL_ITLB_SET(n,what) _XCHAL_ITLB_SET(n, _ ## what ) -#define _XCHAL_ITLB_SET_E(n,i,_what) XCHAL_ITLB_SET ## n ## _E ## i ## _what -#define XCHAL_ITLB_SET_E(n,i,what) _XCHAL_ITLB_SET_E(n,i, _ ## what ) -#define _XCHAL_DTLB_SET(n,_what) XCHAL_DTLB_SET ## n ## _what -#define XCHAL_DTLB_SET(n,what) _XCHAL_DTLB_SET(n, _ ## what ) -#define _XCHAL_DTLB_SET_E(n,i,_what) XCHAL_DTLB_SET ## n ## _E ## i ## _what -#define XCHAL_DTLB_SET_E(n,i,what) _XCHAL_DTLB_SET_E(n,i, _ ## what ) -/* - * Example use: XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,ENTRIES) - * to get the value of XCHAL_ITLB_SET<n>_ENTRIES where <n> is the first auto-refill set. - */ - -/* Number of entries per autorefill way: */ -#define XCHAL_ITLB_ARF_ENTRIES (1<<XCHAL_ITLB_ARF_ENTRIES_LOG2) -#define XCHAL_DTLB_ARF_ENTRIES (1<<XCHAL_DTLB_ARF_ENTRIES_LOG2) - -/* - * Determine whether we have a full MMU (with Page Table and Protection) - * usable for an MMU-based OS: - */ -#if 0 -#if XCHAL_HAVE_TLBS && !XCHAL_HAVE_SPANNING_WAY && XCHAL_ITLB_ARF_WAYS > 0 && XCHAL_DTLB_ARF_WAYS > 0 && XCHAL_MMU_RINGS >= 2 -# define XCHAL_HAVE_PTP_MMU 1 /* have full MMU (with page table [autorefill] and protection) */ -#else -# define XCHAL_HAVE_PTP_MMU 0 /* don't have full MMU */ -#endif -#endif - -/* - * For full MMUs, report kernel RAM segment and kernel I/O segment static page mappings: - */ -#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY -#define XCHAL_KSEG_CACHED_VADDR 0xD0000000 /* virt.addr of kernel RAM cached static map */ -#define XCHAL_KSEG_CACHED_PADDR 0x00000000 /* phys.addr of kseg_cached */ -#define XCHAL_KSEG_CACHED_SIZE 0x08000000 /* size in bytes of kseg_cached (assumed power of 2!!!) */ -#define XCHAL_KSEG_BYPASS_VADDR 0xD8000000 /* virt.addr of kernel RAM bypass (uncached) static map */ -#define XCHAL_KSEG_BYPASS_PADDR 0x00000000 /* phys.addr of kseg_bypass */ -#define XCHAL_KSEG_BYPASS_SIZE 0x08000000 /* size in bytes of kseg_bypass (assumed power of 2!!!) */ - -#define XCHAL_KIO_CACHED_VADDR 0xE0000000 /* virt.addr of kernel I/O cached static map */ -#define XCHAL_KIO_CACHED_PADDR 0xF0000000 /* phys.addr of kio_cached */ -#define XCHAL_KIO_CACHED_SIZE 0x10000000 /* size in bytes of kio_cached (assumed power of 2!!!) */ -#define XCHAL_KIO_BYPASS_VADDR 0xF0000000 /* virt.addr of kernel I/O bypass (uncached) static map */ -#define XCHAL_KIO_BYPASS_PADDR 0xF0000000 /* phys.addr of kio_bypass */ -#define XCHAL_KIO_BYPASS_SIZE 0x10000000 /* size in bytes of kio_bypass (assumed power of 2!!!) */ - -#define XCHAL_SEG_MAPPABLE_VADDR 0x00000000 /* start of largest non-static-mapped virtual addr area */ -#define XCHAL_SEG_MAPPABLE_SIZE 0xD0000000 /* size in bytes of " */ -/* define XCHAL_SEG_MAPPABLE2_xxx if more areas present, sorted in order of descending size. */ -#endif - - -/*---------------------------------------------------------------------- - MISC - ----------------------------------------------------------------------*/ - -/* Data alignment required if used for instructions: */ -#if XCHAL_INST_FETCH_WIDTH > XCHAL_DATA_WIDTH -# define XCHAL_ALIGN_MAX XCHAL_INST_FETCH_WIDTH -#else -# define XCHAL_ALIGN_MAX XCHAL_DATA_WIDTH -#endif - -/* - * Names kept for backward compatibility. - * (Here "RELEASE" is now a misnomer; these are product *versions*, not the releases - * under which they are released. In the T10##.# era there was no distinction.) - */ -#define XCHAL_HW_RELEASE_MAJOR XCHAL_HW_VERSION_MAJOR -#define XCHAL_HW_RELEASE_MINOR XCHAL_HW_VERSION_MINOR -#define XCHAL_HW_RELEASE_NAME XCHAL_HW_VERSION_NAME - - - - -/*---------------------------------------------------------------------- - COPROCESSORS and EXTRA STATE - ----------------------------------------------------------------------*/ - -#define XCHAL_EXTRA_SA_SIZE XCHAL_NCP_SA_SIZE -#define XCHAL_EXTRA_SA_ALIGN XCHAL_NCP_SA_ALIGN -#define XCHAL_CPEXTRA_SA_SIZE XCHAL_TOTAL_SA_SIZE -#define XCHAL_CPEXTRA_SA_ALIGN XCHAL_TOTAL_SA_ALIGN - -#if defined (_ASMLANGUAGE) || defined (__ASSEMBLER__) - - /* Invoked at start of save area load/store sequence macro to setup macro - * internal offsets. Not usually invoked directly. - * continue 0 for 1st sequence, 1 for subsequent consecutive ones. - * totofs offset from original ptr to next load/store location. - */ - .macro xchal_sa_start continue totofs - .ifeq \continue - .set .Lxchal_pofs_, 0 /* offset from original ptr to current \ptr */ - .set .Lxchal_ofs_, 0 /* offset from current \ptr to next load/store location */ - .endif - .if \totofs + 1 /* if totofs specified (not -1) */ - .set .Lxchal_ofs_, \totofs - .Lxchal_pofs_ /* specific offset from original ptr */ - .endif - .endm - - /* Align portion of save area and bring ptr in range if necessary. - * Used by save area load/store sequences. Not usually invoked directly. - * Allows combining multiple (sub-)sequences arbitrarily. - * ptr pointer to save area (may be off, see .Lxchal_pofs_) - * minofs,maxofs range of offset from cur ptr to next load/store loc; - * minofs <= 0 <= maxofs (0 must always be valid offset) - * range must be within +/- 30kB or so. - * ofsalign alignment granularity of minofs .. maxofs (pow of 2) - * (restriction on offset from ptr to next load/store loc) - * totalign align from orig ptr to next load/store loc (pow of 2) - */ - .macro xchal_sa_align ptr minofs maxofs ofsalign totalign - /* First align where we start accessing the next register - * per \totalign relative to original ptr (i.e. start of the save area): - */ - .set .Lxchal_ofs_, ((.Lxchal_pofs_ + .Lxchal_ofs_ + \totalign - 1) & -\totalign) - .Lxchal_pofs_ - /* If necessary, adjust \ptr to bring .Lxchal_ofs_ in acceptable range: */ - .if (((\maxofs) - .Lxchal_ofs_) & 0xC0000000) | ((.Lxchal_ofs_ - (\minofs)) & 0xC0000000) | (.Lxchal_ofs_ & (\ofsalign-1)) - .set .Ligmask, 0xFFFFFFFF /* TODO: optimize to addmi, per aligns and .Lxchal_ofs_ */ - addi \ptr, \ptr, (.Lxchal_ofs_ & .Ligmask) - .set .Lxchal_pofs_, .Lxchal_pofs_ + (.Lxchal_ofs_ & .Ligmask) - .set .Lxchal_ofs_, (.Lxchal_ofs_ & ~.Ligmask) - .endif - .endm - /* - * We could optimize for addi to expand to only addmi instead of - * "addmi;addi", where possible. Here's a partial example how: - * .set .Lmaxmask, -(\ofsalign) & -(\totalign) - * .if (((\maxofs) + ~.Lmaxmask + 1) & 0xFFFFFF00) && ((.Lxchal_ofs_ & ~.Lmaxmask) == 0) - * .set .Ligmask, 0xFFFFFF00 - * .elif ... ditto for negative ofs range ... - * .set .Ligmask, 0xFFFFFF00 - * .set ... adjust per offset ... - * .else - * .set .Ligmask, 0xFFFFFFFF - * .endif - */ - - /* Invoke this after xchal_XXX_{load,store} macros to restore \ptr. */ - .macro xchal_sa_ptr_restore ptr - .if .Lxchal_pofs_ - addi \ptr, \ptr, - .Lxchal_pofs_ - .set .Lxchal_ofs_, .Lxchal_ofs_ + .Lxchal_pofs_ - .set .Lxchal_pofs_, 0 - .endif - .endm - - /* - * Use as eg: - * xchal_atmps_store a1, SOMEOFS, XCHAL_SA_NUM_ATMPS, a4, a5 - * xchal_ncp_load a2, a0,a3,a4,a5 - * xchal_atmps_load a1, SOMEOFS, XCHAL_SA_NUM_ATMPS, a4, a5 - * - * Specify only the ARs you *haven't* saved/restored already, up to 4. - * They *must* be the *last* ARs (in same order) specified to save area - * load/store sequences. In the example above, a0 and a3 were already - * saved/restored and unused (thus available) but a4 and a5 were not. - */ -#define xchal_atmps_store xchal_atmps_loadstore s32i, -#define xchal_atmps_load xchal_atmps_loadstore l32i, - .macro xchal_atmps_loadstore inst ptr offset nreq aa=0 ab=0 ac=0 ad=0 - .set .Lnsaved_, 0 - .irp reg,\aa,\ab,\ac,\ad - .ifeq 0x\reg ; .set .Lnsaved_,.Lnsaved_+1 ; .endif - .endr - .set .Laofs_, 0 - .irp reg,\aa,\ab,\ac,\ad - .ifgt (\nreq)-.Lnsaved_ - \inst \reg, \ptr, .Laofs_+\offset - .set .Laofs_,.Laofs_+4 - .set .Lnsaved_,.Lnsaved_+1 - .endif - .endr - .endm - -/*#define xchal_ncp_load_a2 xchal_ncp_load a2,a3,a4,a5,a6*/ -/*#define xchal_ncp_store_a2 xchal_ncp_store a2,a3,a4,a5,a6*/ -#define xchal_extratie_load xchal_ncptie_load -#define xchal_extratie_store xchal_ncptie_store -#define xchal_extratie_load_a2 xchal_ncptie_load a2,a3,a4,a5,a6 -#define xchal_extratie_store_a2 xchal_ncptie_store a2,a3,a4,a5,a6 -#define xchal_extra_load xchal_ncp_load -#define xchal_extra_store xchal_ncp_store -#define xchal_extra_load_a2 xchal_ncp_load a2,a3,a4,a5,a6 -#define xchal_extra_store_a2 xchal_ncp_store a2,a3,a4,a5,a6 -#define xchal_extra_load_funcbody xchal_ncp_load a2,a3,a4,a5,a6 -#define xchal_extra_store_funcbody xchal_ncp_store a2,a3,a4,a5,a6 -#define xchal_cp0_store_a2 xchal_cp0_store a2,a3,a4,a5,a6 -#define xchal_cp0_load_a2 xchal_cp0_load a2,a3,a4,a5,a6 -#define xchal_cp1_store_a2 xchal_cp1_store a2,a3,a4,a5,a6 -#define xchal_cp1_load_a2 xchal_cp1_load a2,a3,a4,a5,a6 -#define xchal_cp2_store_a2 xchal_cp2_store a2,a3,a4,a5,a6 -#define xchal_cp2_load_a2 xchal_cp2_load a2,a3,a4,a5,a6 -#define xchal_cp3_store_a2 xchal_cp3_store a2,a3,a4,a5,a6 -#define xchal_cp3_load_a2 xchal_cp3_load a2,a3,a4,a5,a6 -#define xchal_cp4_store_a2 xchal_cp4_store a2,a3,a4,a5,a6 -#define xchal_cp4_load_a2 xchal_cp4_load a2,a3,a4,a5,a6 -#define xchal_cp5_store_a2 xchal_cp5_store a2,a3,a4,a5,a6 -#define xchal_cp5_load_a2 xchal_cp5_load a2,a3,a4,a5,a6 -#define xchal_cp6_store_a2 xchal_cp6_store a2,a3,a4,a5,a6 -#define xchal_cp6_load_a2 xchal_cp6_load a2,a3,a4,a5,a6 -#define xchal_cp7_store_a2 xchal_cp7_store a2,a3,a4,a5,a6 -#define xchal_cp7_load_a2 xchal_cp7_load a2,a3,a4,a5,a6 - -/* Empty placeholder macros for undefined coprocessors: */ -#if (XCHAL_CP_MASK & ~XCHAL_CP_PORT_MASK) == 0 -# if XCHAL_CP0_SA_SIZE == 0 - .macro xchal_cp0_store p a b c d continue=0 ofs=-1 select=-1 ; .endm - .macro xchal_cp0_load p a b c d continue=0 ofs=-1 select=-1 ; .endm -# endif -# if XCHAL_CP1_SA_SIZE == 0 - .macro xchal_cp1_store p a b c d continue=0 ofs=-1 select=-1 ; .endm - .macro xchal_cp1_load p a b c d continue=0 ofs=-1 select=-1 ; .endm -# endif -# if XCHAL_CP2_SA_SIZE == 0 - .macro xchal_cp2_store p a b c d continue=0 ofs=-1 select=-1 ; .endm - .macro xchal_cp2_load p a b c d continue=0 ofs=-1 select=-1 ; .endm -# endif -# if XCHAL_CP3_SA_SIZE == 0 - .macro xchal_cp3_store p a b c d continue=0 ofs=-1 select=-1 ; .endm - .macro xchal_cp3_load p a b c d continue=0 ofs=-1 select=-1 ; .endm -# endif -# if XCHAL_CP4_SA_SIZE == 0 - .macro xchal_cp4_store p a b c d continue=0 ofs=-1 select=-1 ; .endm - .macro xchal_cp4_load p a b c d continue=0 ofs=-1 select=-1 ; .endm -# endif -# if XCHAL_CP5_SA_SIZE == 0 - .macro xchal_cp5_store p a b c d continue=0 ofs=-1 select=-1 ; .endm - .macro xchal_cp5_load p a b c d continue=0 ofs=-1 select=-1 ; .endm -# endif -# if XCHAL_CP6_SA_SIZE == 0 - .macro xchal_cp6_store p a b c d continue=0 ofs=-1 select=-1 ; .endm - .macro xchal_cp6_load p a b c d continue=0 ofs=-1 select=-1 ; .endm -# endif -# if XCHAL_CP7_SA_SIZE == 0 - .macro xchal_cp7_store p a b c d continue=0 ofs=-1 select=-1 ; .endm - .macro xchal_cp7_load p a b c d continue=0 ofs=-1 select=-1 ; .endm -# endif -#endif - - /******************** - * Macros to create functions that save and restore the state of *any* TIE - * coprocessor (by dynamic index). - */ - - /* - * Macro that expands to the body of a function - * that stores the selected coprocessor's state (registers etc). - * Entry: a2 = ptr to save area in which to save cp state - * a3 = coprocessor number - * Exit: any register a2-a15 (?) may have been clobbered. - */ - .macro xchal_cpi_store_funcbody -#if (XCHAL_CP_MASK & ~XCHAL_CP_PORT_MASK) -# if XCHAL_CP0_SA_SIZE - bnez a3, 99f - xchal_cp0_store_a2 - j 90f -99: -# endif -# if XCHAL_CP1_SA_SIZE - bnei a3, 1, 99f - xchal_cp1_store_a2 - j 90f -99: -# endif -# if XCHAL_CP2_SA_SIZE - bnei a3, 2, 99f - xchal_cp2_store_a2 - j 90f -99: -# endif -# if XCHAL_CP3_SA_SIZE - bnei a3, 3, 99f - xchal_cp3_store_a2 - j 90f -99: -# endif -# if XCHAL_CP4_SA_SIZE - bnei a3, 4, 99f - xchal_cp4_store_a2 - j 90f -99: -# endif -# if XCHAL_CP5_SA_SIZE - bnei a3, 5, 99f - xchal_cp5_store_a2 - j 90f -99: -# endif -# if XCHAL_CP6_SA_SIZE - bnei a3, 6, 99f - xchal_cp6_store_a2 - j 90f -99: -# endif -# if XCHAL_CP7_SA_SIZE - bnei a3, 7, 99f - xchal_cp7_store_a2 - j 90f -99: -# endif -90: -#endif - .endm - - /* - * Macro that expands to the body of a function - * that loads the selected coprocessor's state (registers etc). - * Entry: a2 = ptr to save area from which to restore cp state - * a3 = coprocessor number - * Exit: any register a2-a15 (?) may have been clobbered. - */ - .macro xchal_cpi_load_funcbody -#if (XCHAL_CP_MASK & ~XCHAL_CP_PORT_MASK) -# if XCHAL_CP0_SA_SIZE - bnez a3, 99f - xchal_cp0_load_a2 - j 90f -99: -# endif -# if XCHAL_CP1_SA_SIZE - bnei a3, 1, 99f - xchal_cp1_load_a2 - j 90f -99: -# endif -# if XCHAL_CP2_SA_SIZE - bnei a3, 2, 99f - xchal_cp2_load_a2 - j 90f -99: -# endif -# if XCHAL_CP3_SA_SIZE - bnei a3, 3, 99f - xchal_cp3_load_a2 - j 90f -99: -# endif -# if XCHAL_CP4_SA_SIZE - bnei a3, 4, 99f - xchal_cp4_load_a2 - j 90f -99: -# endif -# if XCHAL_CP5_SA_SIZE - bnei a3, 5, 99f - xchal_cp5_load_a2 - j 90f -99: -# endif -# if XCHAL_CP6_SA_SIZE - bnei a3, 6, 99f - xchal_cp6_load_a2 - j 90f -99: -# endif -# if XCHAL_CP7_SA_SIZE - bnei a3, 7, 99f - xchal_cp7_load_a2 - j 90f -99: -# endif -90: -#endif - .endm - -#endif /*_ASMLANGUAGE or __ASSEMBLER__*/ - - -/* Other default macros for undefined coprocessors: */ -#ifndef XCHAL_CP0_NAME -# define XCHAL_CP0_NAME 0 -# define XCHAL_CP0_SA_CONTENTS_LIBDB_NUM 0 -# define XCHAL_CP0_SA_CONTENTS_LIBDB /* empty */ -#endif -#ifndef XCHAL_CP1_NAME -# define XCHAL_CP1_NAME 0 -# define XCHAL_CP1_SA_CONTENTS_LIBDB_NUM 0 -# define XCHAL_CP1_SA_CONTENTS_LIBDB /* empty */ -#endif -#ifndef XCHAL_CP2_NAME -# define XCHAL_CP2_NAME 0 -# define XCHAL_CP2_SA_CONTENTS_LIBDB_NUM 0 -# define XCHAL_CP2_SA_CONTENTS_LIBDB /* empty */ -#endif -#ifndef XCHAL_CP3_NAME -# define XCHAL_CP3_NAME 0 -# define XCHAL_CP3_SA_CONTENTS_LIBDB_NUM 0 -# define XCHAL_CP3_SA_CONTENTS_LIBDB /* empty */ -#endif -#ifndef XCHAL_CP4_NAME -# define XCHAL_CP4_NAME 0 -# define XCHAL_CP4_SA_CONTENTS_LIBDB_NUM 0 -# define XCHAL_CP4_SA_CONTENTS_LIBDB /* empty */ -#endif -#ifndef XCHAL_CP5_NAME -# define XCHAL_CP5_NAME 0 -# define XCHAL_CP5_SA_CONTENTS_LIBDB_NUM 0 -# define XCHAL_CP5_SA_CONTENTS_LIBDB /* empty */ -#endif -#ifndef XCHAL_CP6_NAME -# define XCHAL_CP6_NAME 0 -# define XCHAL_CP6_SA_CONTENTS_LIBDB_NUM 0 -# define XCHAL_CP6_SA_CONTENTS_LIBDB /* empty */ -#endif -#ifndef XCHAL_CP7_NAME -# define XCHAL_CP7_NAME 0 -# define XCHAL_CP7_SA_CONTENTS_LIBDB_NUM 0 -# define XCHAL_CP7_SA_CONTENTS_LIBDB /* empty */ -#endif - -#if XCHAL_CP_MASK == 0 -/* Filler info for unassigned coprocessors, to simplify arrays etc: */ -#define XCHAL_CP0_SA_SIZE 0 -#define XCHAL_CP0_SA_ALIGN 1 -#define XCHAL_CP1_SA_SIZE 0 -#define XCHAL_CP1_SA_ALIGN 1 -#define XCHAL_CP2_SA_SIZE 0 -#define XCHAL_CP2_SA_ALIGN 1 -#define XCHAL_CP3_SA_SIZE 0 -#define XCHAL_CP3_SA_ALIGN 1 -#define XCHAL_CP4_SA_SIZE 0 -#define XCHAL_CP4_SA_ALIGN 1 -#define XCHAL_CP5_SA_SIZE 0 -#define XCHAL_CP5_SA_ALIGN 1 -#define XCHAL_CP6_SA_SIZE 0 -#define XCHAL_CP6_SA_ALIGN 1 -#define XCHAL_CP7_SA_SIZE 0 -#define XCHAL_CP7_SA_ALIGN 1 -#endif - - -/* Indexing macros: */ -#define _XCHAL_CP_SA_SIZE(n) XCHAL_CP ## n ## _SA_SIZE -#define XCHAL_CP_SA_SIZE(n) _XCHAL_CP_SA_SIZE(n) /* n = 0 .. 7 */ -#define _XCHAL_CP_SA_ALIGN(n) XCHAL_CP ## n ## _SA_ALIGN -#define XCHAL_CP_SA_ALIGN(n) _XCHAL_CP_SA_ALIGN(n) /* n = 0 .. 7 */ - -#define XCHAL_CPEXTRA_SA_SIZE_TOR2 XCHAL_CPEXTRA_SA_SIZE /* Tor2Beta only - do not use */ - -/* Link-time HAL global variables that report coprocessor numbers by name - (names are case-preserved from the original TIE): */ -#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__) -# define _XCJOIN(a,b) a ## b -# define XCJOIN(a,b) _XCJOIN(a,b) -# ifdef XCHAL_CP0_NAME -extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP0_IDENT); -extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP0_IDENT); -# endif -# ifdef XCHAL_CP1_NAME -extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP1_IDENT); -extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP1_IDENT); -# endif -# ifdef XCHAL_CP2_NAME -extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP2_IDENT); -extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP2_IDENT); -# endif -# ifdef XCHAL_CP3_NAME -extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP3_IDENT); -extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP3_IDENT); -# endif -# ifdef XCHAL_CP4_NAME -extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP4_IDENT); -extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP4_IDENT); -# endif -# ifdef XCHAL_CP5_NAME -extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP5_IDENT); -extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP5_IDENT); -# endif -# ifdef XCHAL_CP6_NAME -extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP6_IDENT); -extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP6_IDENT); -# endif -# ifdef XCHAL_CP7_NAME -extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP7_IDENT); -extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP7_IDENT); -# endif -#endif - - - - -/*---------------------------------------------------------------------- - DERIVED - ----------------------------------------------------------------------*/ - -#if XCHAL_HAVE_BE -#define XCHAL_INST_ILLN 0xD60F /* 2-byte illegal instruction, msb-first */ -#define XCHAL_INST_ILLN_BYTE0 0xD6 /* 2-byte illegal instruction, 1st byte */ -#define XCHAL_INST_ILLN_BYTE1 0x0F /* 2-byte illegal instruction, 2nd byte */ -#else -#define XCHAL_INST_ILLN 0xF06D /* 2-byte illegal instruction, lsb-first */ -#define XCHAL_INST_ILLN_BYTE0 0x6D /* 2-byte illegal instruction, 1st byte */ -#define XCHAL_INST_ILLN_BYTE1 0xF0 /* 2-byte illegal instruction, 2nd byte */ -#endif -/* Belongs in xtensa/hal.h: */ -#define XTHAL_INST_ILL 0x000000 /* 3-byte illegal instruction */ - - -/* - * Because information as to exactly which hardware version is targeted - * by a given software build is not always available, compile-time HAL - * Hardware-Release "_AT" macros are fuzzy (return 0, 1, or XCHAL_MAYBE): - * (Here "RELEASE" is now a misnomer; these are product *versions*, not the releases - * under which they are released. In the T10##.# era there was no distinction.) - */ -#if XCHAL_HW_CONFIGID_RELIABLE -# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor) (XTHAL_REL_LE( XCHAL_HW_VERSION_MAJOR,XCHAL_HW_VERSION_MINOR, major,minor ) ? 1 : 0) -# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor) (XTHAL_REL_GE( XCHAL_HW_VERSION_MAJOR,XCHAL_HW_VERSION_MINOR, major,minor ) ? 1 : 0) -# define XCHAL_HW_RELEASE_AT(major,minor) (XTHAL_REL_EQ( XCHAL_HW_VERSION_MAJOR,XCHAL_HW_VERSION_MINOR, major,minor ) ? 1 : 0) -# define XCHAL_HW_RELEASE_MAJOR_AT(major) ((XCHAL_HW_VERSION_MAJOR == (major)) ? 1 : 0) -#else -# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor) ( ((major) < 1040 && XCHAL_HAVE_XEA2) ? 0 \ - : ((major) > 1050 && XCHAL_HAVE_XEA1) ? 1 \ - : XTHAL_MAYBE ) -# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor) ( ((major) >= 2000 && XCHAL_HAVE_XEA1) ? 0 \ - : (XTHAL_REL_LE(major,minor, 1040,0) && XCHAL_HAVE_XEA2) ? 1 \ - : XTHAL_MAYBE ) -# define XCHAL_HW_RELEASE_AT(major,minor) ( (((major) < 1040 && XCHAL_HAVE_XEA2) || \ - ((major) >= 2000 && XCHAL_HAVE_XEA1)) ? 0 : XTHAL_MAYBE) -# define XCHAL_HW_RELEASE_MAJOR_AT(major) XCHAL_HW_RELEASE_AT(major,0) -#endif - - -#endif /*XTENSA_CONFIG_CORE_H*/ - diff --git a/src/arch/xtensa/include/xtensa/core-macros.h b/src/arch/xtensa/include/xtensa/core-macros.h deleted file mode 100644 index 8b8a16b49a30..000000000000 --- a/src/arch/xtensa/include/xtensa/core-macros.h +++ /dev/null @@ -1,506 +0,0 @@ -/* - * xtensa/core-macros.h -- C specific definitions - * that depend on CORE configuration - */ - -/* - * Copyright (c) 2012 Tensilica 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. - */ - -#ifndef XTENSA_CACHE_H -#define XTENSA_CACHE_H - -#include <xtensa/config/core.h> - -/* Only define things for C code. */ -#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__) - - - -/*************************** CACHE ***************************/ - -/* All the macros are in the lower case now and some of them - * share the name with the existing functions from hal.h. - * Including this header file will define XTHAL_USE_CACHE_MACROS - * which directs hal.h not to use the functions. - */ - -/* - * Single-cache-line operations in C-callable inline assembly. - * Essentially macro versions (uppercase) of: - * - * xthal_icache_line_invalidate(void *addr); - * xthal_icache_line_lock(void *addr); - * xthal_icache_line_unlock(void *addr); - * xthal_icache_sync(void); - * - * NOTE: unlike the above functions, the following macros do NOT - * execute the xthal_icache_sync() as part of each line operation. - * This sync must be called explicitly by the caller. This is to - * allow better optimization when operating on more than one line. - * - * xthal_dcache_line_invalidate(void *addr); - * xthal_dcache_line_writeback(void *addr); - * xthal_dcache_line_writeback_inv(void *addr); - * xthal_dcache_line_lock(void *addr); - * xthal_dcache_line_unlock(void *addr); - * xthal_dcache_sync(void); - * xthal_dcache_line_prefetch_for_write(void *addr); - * xthal_dcache_line_prefetch_for_read(void *addr); - * - * All are made memory-barriers, given that's how they're typically used - * (ops operate on a whole line, so clobbers all memory not just *addr). - * - * NOTE: All the block block cache ops and line prefetches are implemented - * using intrinsics so they are better optimized regarding memory barriers etc. - * - * All block downgrade functions exist in two forms: with and without - * the 'max' parameter: This parameter allows compiler to optimize - * the functions whenever the parameter is smaller than the cache size. - * - * xthal_dcache_block_invalidate(void *addr, unsigned size); - * xthal_dcache_block_writeback(void *addr, unsigned size); - * xthal_dcache_block_writeback_inv(void *addr, unsigned size); - * xthal_dcache_block_invalidate_max(void *addr, unsigned size, unsigned max); - * xthal_dcache_block_writeback_max(void *addr, unsigned size, unsigned max); - * xthal_dcache_block_writeback_inv_max(void *addr, unsigned size, unsigned max); - * - * xthal_dcache_block_prefetch_for_read(void *addr, unsigned size); - * xthal_dcache_block_prefetch_for_write(void *addr, unsigned size); - * xthal_dcache_block_prefetch_modify(void *addr, unsigned size); - * xthal_dcache_block_prefetch_read_write(void *addr, unsigned size); - * xthal_dcache_block_prefetch_for_read_grp(void *addr, unsigned size); - * xthal_dcache_block_prefetch_for_write_grp(void *addr, unsigned size); - * xthal_dcache_block_prefetch_modify_grp(void *addr, unsigned size); - * xthal_dcache_block_prefetch_read_write_grp(void *addr, unsigned size) - * - * xthal_dcache_block_wait(); - * xthal_dcache_block_required_wait(); - * xthal_dcache_block_abort(); - * xthal_dcache_block_prefetch_end(); - * xthal_dcache_block_newgrp(); - */ - -/*** INSTRUCTION CACHE ***/ - -#define XTHAL_USE_CACHE_MACROS - -#if XCHAL_ICACHE_SIZE > 0 -# define xthal_icache_line_invalidate(addr) do { void *__a = (void*)(addr); \ - __asm__ __volatile__("ihi %0, 0" :: "a"(__a) : "memory"); \ - } while(0) -#else -# define xthal_icache_line_invalidate(addr) do {/*nothing*/} while(0) -#endif - -#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE -# define xthal_icache_line_lock(addr) do { void *__a = (void*)(addr); \ - __asm__ __volatile__("ipfl %0, 0" :: "a"(__a) : "memory"); \ - } while(0) -# define xthal_icache_line_unlock(addr) do { void *__a = (void*)(addr); \ - __asm__ __volatile__("ihu %0, 0" :: "a"(__a) : "memory"); \ - } while(0) -#else -# define xthal_icache_line_lock(addr) do {/*nothing*/} while(0) -# define xthal_icache_line_unlock(addr) do {/*nothing*/} while(0) -#endif - -/* - * Even if a config doesn't have caches, an isync is still needed - * when instructions in any memory are modified, whether by a loader - * or self-modifying code. Therefore, this macro always produces - * an isync, whether or not an icache is present. - */ -#define xthal_icache_sync() \ - __asm__ __volatile__("isync":::"memory") - - -/*** DATA CACHE ***/ - -#if XCHAL_DCACHE_SIZE > 0 - -# include <xtensa/tie/xt_datacache.h> - -# define xthal_dcache_line_invalidate(addr) do { void *__a = (void*)(addr); \ - __asm__ __volatile__("dhi %0, 0" :: "a"(__a) : "memory"); \ - } while(0) -# define xthal_dcache_line_writeback(addr) do { void *__a = (void*)(addr); \ - __asm__ __volatile__("dhwb %0, 0" :: "a"(__a) : "memory"); \ - } while(0) -# define xthal_dcache_line_writeback_inv(addr) do { void *__a = (void*)(addr); \ - __asm__ __volatile__("dhwbi %0, 0" :: "a"(__a) : "memory"); \ - } while(0) -# define xthal_dcache_sync() \ - __asm__ __volatile__("" /*"dsync"?*/:::"memory") -# define xthal_dcache_line_prefetch_for_read(addr) do { \ - XT_DPFR((const int*)addr, 0); \ - } while(0) -#else -# define xthal_dcache_line_invalidate(addr) do {/*nothing*/} while(0) -# define xthal_dcache_line_writeback(addr) do {/*nothing*/} while(0) -# define xthal_dcache_line_writeback_inv(addr) do {/*nothing*/} while(0) -# define xthal_dcache_sync() __asm__ __volatile__("":::"memory") -# define xthal_dcache_line_prefetch_for_read(addr) do {/*nothing*/} while(0) -#endif - -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE -# define xthal_dcache_line_lock(addr) do { void *__a = (void*)(addr); \ - __asm__ __volatile__("dpfl %0, 0" :: "a"(__a) : "memory"); \ - } while(0) -# define xthal_dcache_line_unlock(addr) do { void *__a = (void*)(addr); \ - __asm__ __volatile__("dhu %0, 0" :: "a"(__a) : "memory"); \ - } while(0) -#else -# define xthal_dcache_line_lock(addr) do {/*nothing*/} while(0) -# define xthal_dcache_line_unlock(addr) do {/*nothing*/} while(0) -#endif - -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK - -# define xthal_dcache_line_prefetch_for_write(addr) do { \ - XT_DPFW((const int*)addr, 0); \ - } while(0) -#else -# define xthal_dcache_line_prefetch_for_write(addr) do {/*nothing*/} while(0) -#endif - - -/***** Block Operations *****/ - -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_HAVE_CACHE_BLOCKOPS - -/* upgrades */ - -# define _XTHAL_DCACHE_BLOCK_UPGRADE(addr, size, type) \ - { \ - type((const int*)addr, size); \ - } - -/*downgrades */ - -# define _XTHAL_DCACHE_BLOCK_DOWNGRADE(addr, size, type) \ - unsigned _s = size; \ - unsigned _a = (unsigned) addr; \ - do { \ - unsigned __s = (_s > XCHAL_DCACHE_SIZE) ? \ - XCHAL_DCACHE_SIZE : _s; \ - type((const int*)_a, __s); \ - _s -= __s; \ - _a += __s; \ - } while(_s > 0); - -# define _XTHAL_DCACHE_BLOCK_DOWNGRADE_MAX(addr, size, type, max) \ - if (max <= XCHAL_DCACHE_SIZE) { \ - unsigned _s = size; \ - unsigned _a = (unsigned) addr; \ - type((const int*)_a, _s); \ - } \ - else { \ - _XTHAL_DCACHE_BLOCK_DOWNGRADE(addr, size, type); \ - } - -# define xthal_dcache_block_invalidate(addr, size) do { \ - _XTHAL_DCACHE_BLOCK_DOWNGRADE(addr, size, XT_DHI_B); \ - } while(0) -# define xthal_dcache_block_writeback(addr, size) do { \ - _XTHAL_DCACHE_BLOCK_DOWNGRADE(addr, size, XT_DHWB_B); \ - } while(0) -# define xthal_dcache_block_writeback_inv(addr, size) do { \ - _XTHAL_DCACHE_BLOCK_DOWNGRADE(addr, size, XT_DHWBI_B); \ - } while(0) - -# define xthal_dcache_block_invalidate_max(addr, size, max) do { \ - _XTHAL_DCACHE_BLOCK_DOWNGRADE_MAX(addr, size, XT_DHI_B, max); \ - } while(0) -# define xthal_dcache_block_writeback_max(addr, size, max) do { \ - _XTHAL_DCACHE_BLOCK_DOWNGRADE_MAX(addr, size, XT_DHWB_B, max); \ - } while(0) -# define xthal_dcache_block_writeback_inv_max(addr, size, max) do { \ - _XTHAL_DCACHE_BLOCK_DOWNGRADE_MAX(addr, size, XT_DHWBI_B, max); \ - } while(0) - -/* upgrades that are performed even with write-thru caches */ - -# define xthal_dcache_block_prefetch_read_write(addr, size) do { \ - _XTHAL_DCACHE_BLOCK_UPGRADE(addr, size, XT_DPFW_B); \ - } while(0) -# define xthal_dcache_block_prefetch_read_write_grp(addr, size) do { \ - _XTHAL_DCACHE_BLOCK_UPGRADE(addr, size, XT_DPFW_BF); \ - } while(0) -# define xthal_dcache_block_prefetch_for_read(addr, size) do { \ - _XTHAL_DCACHE_BLOCK_UPGRADE(addr, size, XT_DPFR_B); \ - } while(0) -# define xthal_dcache_block_prefetch_for_read_grp(addr, size) do { \ - _XTHAL_DCACHE_BLOCK_UPGRADE(addr, size, XT_DPFR_BF); \ - } while(0) - -/* abort all or end optional block cache operations */ -# define xthal_dcache_block_abort() do { \ - XT_PFEND_A(); \ - } while(0) -# define xthal_dcache_block_end() do { \ - XT_PFEND_O(); \ - } while(0) - -/* wait for all/required block cache operations to finish */ -# define xthal_dcache_block_wait() do { \ - XT_PFWAIT_A(); \ - } while(0) -# define xthal_dcache_block_required_wait() do { \ - XT_PFWAIT_R(); \ - } while(0) -/* Start a new group */ -# define xthal_dcache_block_newgrp() do { \ - XT_PFNXT_F(); \ - } while(0) -#else -# define xthal_dcache_block_invalidate(addr, size) do {/*nothing*/} while(0) -# define xthal_dcache_block_writeback(addr, size) do {/*nothing*/} while(0) -# define xthal_dcache_block_writeback_inv(addr, size) do {/*nothing*/} while(0) -# define xthal_dcache_block_invalidate_max(addr, size, max) do {/*nothing*/} while(0) -# define xthal_dcache_block_writeback_max(addr, size, max) do {/*nothing*/} while(0) -# define xthal_dcache_block_writeback_inv_max(addr, size, max) do {/*nothing*/} while(0) -# define xthal_dcache_block_prefetch_read_write(addr, size) do {/*nothing*/} while(0) -# define xthal_dcache_block_prefetch_read_write_grp(addr, size) do {/*nothing*/} while(0) -# define xthal_dcache_block_prefetch_for_read(addr, size) do {/*nothing*/} while(0) -# define xthal_dcache_block_prefetch_for_read_grp(addr, size) do {/*nothing*/} while(0) -# define xthal_dcache_block_end() do {/*nothing*/} while(0) -# define xthal_dcache_block_abort() do {/*nothing*/} while(0) -# define xthal_dcache_block_wait() do {/*nothing*/} while(0) -# define xthal_dcache_block_required_wait() do {/*nothing*/} while(0) -# define xthal_dcache_block_newgrp() do {/*nothing*/} while(0) -#endif - -#if XCHAL_DCACHE_SIZE > 0 && XCHAL_HAVE_CACHE_BLOCKOPS && XCHAL_DCACHE_IS_WRITEBACK - -# define xthal_dcache_block_prefetch_for_write(addr, size) do { \ - _XTHAL_DCACHE_BLOCK_UPGRADE(addr, size, XT_DPFW_B); \ - } while(0) -# define xthal_dcache_block_prefetch_modify(addr, size) do { \ - _XTHAL_DCACHE_BLOCK_UPGRADE(addr, size, XT_DPFM_B); \ - } while(0) -# define xthal_dcache_block_prefetch_for_write_grp(addr, size) do { \ - _XTHAL_DCACHE_BLOCK_UPGRADE(addr, size, XT_DPFW_BF); \ - } while(0) -# define xthal_dcache_block_prefetch_modify_grp(addr, size) do { \ - _XTHAL_DCACHE_BLOCK_UPGRADE(addr, size, XT_DPFM_BF); \ - } while(0) -#else -# define xthal_dcache_block_prefetch_for_write(addr, size) do {/*nothing*/} while(0) -# define xthal_dcache_block_prefetch_modify(addr, size) do {/*nothing*/} while(0) -# define xthal_dcache_block_prefetch_for_write_grp(addr, size) do {/*nothing*/} while(0) -# define xthal_dcache_block_prefetch_modify_grp(addr, size) do {/*nothing*/} while(0) -#endif - -/*************************** INTERRUPTS ***************************/ - -/* - * Macro versions of: - * unsigned xthal_get_intenable( void ); - * void xthal_set_intenable( unsigned ); - * unsigned xthal_get_interrupt( void ); - * void xthal_set_intset( unsigned ); - * void xthal_set_intclear( unsigned ); - * unsigned xthal_get_ccount(void); - * void xthal_set_ccompare(int, unsigned); - * unsigned xthal_get_ccompare(int); - * - * NOTE: for {set,get}_ccompare, the first argument MUST be a decimal constant. - */ - -#if XCHAL_HAVE_INTERRUPTS -# define XTHAL_GET_INTENABLE() ({ int __intenable; \ - __asm__("rsr.intenable %0" : "=a"(__intenable)); \ - __intenable; }) -# define XTHAL_SET_INTENABLE(v) do { int __intenable = (int)(v); \ - __asm__ __volatile__("wsr.intenable %0" :: "a"(__intenable):"memory"); \ - } while(0) -# define XTHAL_GET_INTERRUPT() ({ int __interrupt; \ - __asm__("rsr.interrupt %0" : "=a"(__interrupt)); \ - __interrupt; }) -# define XTHAL_SET_INTSET(v) do { int __interrupt = (int)(v); \ - __asm__ __volatile__("wsr.intset %0" :: "a"(__interrupt):"memory"); \ - } while(0) -# define XTHAL_SET_INTCLEAR(v) do { int __interrupt = (int)(v); \ - __asm__ __volatile__("wsr.intclear %0" :: "a"(__interrupt):"memory"); \ - } while(0) -# define XTHAL_GET_CCOUNT() ({ int __ccount; \ - __asm__("rsr.ccount %0" : "=a"(__ccount)); \ - __ccount; }) -# define XTHAL_SET_CCOUNT(v) do { int __ccount = (int)(v); \ - __asm__ __volatile__("wsr.ccount %0" :: "a"(__ccount):"memory"); \ - } while(0) -# define _XTHAL_GET_CCOMPARE(n) ({ int __ccompare; \ - __asm__("rsr.ccompare" #n " %0" : "=a"(__ccompare)); \ - __ccompare; }) -# define XTHAL_GET_CCOMPARE(n) _XTHAL_GET_CCOMPARE(n) -# define _XTHAL_SET_CCOMPARE(n,v) do { int __ccompare = (int)(v); \ - __asm__ __volatile__("wsr.ccompare" #n " %0 ; esync" :: "a"(__ccompare):"memory"); \ - } while(0) -# define XTHAL_SET_CCOMPARE(n,v) _XTHAL_SET_CCOMPARE(n,v) -#else -# define XTHAL_GET_INTENABLE() 0 -# define XTHAL_SET_INTENABLE(v) do {/*nothing*/} while(0) -# define XTHAL_GET_INTERRUPT() 0 -# define XTHAL_SET_INTSET(v) do {/*nothing*/} while(0) -# define XTHAL_SET_INTCLEAR(v) do {/*nothing*/} while(0) -# define XTHAL_GET_CCOUNT() 0 -# define XTHAL_SET_CCOUNT(v) do {/*nothing*/} while(0) -# define XTHAL_GET_CCOMPARE(n) 0 -# define XTHAL_SET_CCOMPARE(n,v) do {/*nothing*/} while(0) -#endif - -/* New functions added to accomodate XEA3 and allow deprecation of older - functions. For this release they just map to the older ones. */ - -/* Enables the specified interrupt. */ -static inline void xthal_interrupt_enable(unsigned intnum) -{ - xthal_int_enable(1 << intnum); -} - -/* Disables the specified interrupt. */ -static inline void xthal_interrupt_disable(unsigned intnum) -{ - xthal_int_disable(1 << intnum); -} - -/* Triggers the specified interrupt. */ -static inline void xthal_interrupt_trigger(unsigned intnum) -{ - xthal_set_intset(1 << intnum); -} - -/* Clears the specified interrupt. */ -static inline void xthal_interrupt_clear(unsigned intnum) -{ - xthal_set_intclear(1 << intnum); -} - - -/*************************** MISC ***************************/ - -/* - * Macro or inline versions of: - * void xthal_clear_regcached_code( void ); - * unsigned xthal_get_prid( void ); - * unsigned xthal_compare_and_set( int *addr, int testval, int setval ); - */ - -#if XCHAL_HAVE_LOOPS -# define XTHAL_CLEAR_REGCACHED_CODE() \ - __asm__ __volatile__("wsr.lcount %0" :: "a"(0) : "memory") -#else -# define XTHAL_CLEAR_REGCACHED_CODE() do {/*nothing*/} while(0) -#endif - -#if XCHAL_HAVE_PRID -# define XTHAL_GET_PRID() ({ int __prid; \ - __asm__("rsr.prid %0" : "=a"(__prid)); \ - __prid; }) -#else -# define XTHAL_GET_PRID() 0 -#endif - - -static inline unsigned XTHAL_COMPARE_AND_SET( int *addr, int testval, int setval ) -{ - int result; - -#if XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION_MAJOR >= 2200 - __asm__ __volatile__ ( - " wsr.scompare1 %2 \n" - " s32c1i %0, %3, 0 \n" - : "=a"(result) : "0" (setval), "a" (testval), "a" (addr) - : "memory"); -#elif XCHAL_HAVE_INTERRUPTS - int tmp; - __asm__ __volatile__ ( - " rsil %4, 15 \n" // %4 == saved ps - " l32i %0, %3, 0 \n" // %0 == value to test, return val - " bne %2, %0, 9f \n" // test - " s32i %1, %3, 0 \n" // write the new value - "9: wsr.ps %4 ; rsync \n" // restore the PS - : "=a"(result) - : "0" (setval), "a" (testval), "a" (addr), "a" (tmp) - : "memory"); -#else - __asm__ __volatile__ ( - " l32i %0, %3, 0 \n" // %0 == value to test, return val - " bne %2, %0, 9f \n" // test - " s32i %1, %3, 0 \n" // write the new value - "9: \n" - : "=a"(result) : "0" (setval), "a" (testval), "a" (addr) - : "memory"); -#endif - return result; -} - -#if XCHAL_HAVE_EXTERN_REGS - -static inline unsigned XTHAL_RER (unsigned int reg) -{ - unsigned result; - - __asm__ __volatile__ ( - " rer %0, %1" - : "=a" (result) : "a" (reg) : "memory"); - - return result; -} - -static inline void XTHAL_WER (unsigned reg, unsigned value) -{ - __asm__ __volatile__ ( - " wer %0, %1" - : : "a" (value), "a" (reg) : "memory"); -} - -#endif /* XCHAL_HAVE_EXTERN_REGS */ - -/* - * Sets a single entry at 'index' within the MPU - * - * The caller must ensure that the resulting MPU map is ordered. - */ -static inline void xthal_mpu_set_entry (xthal_MPU_entry entry) -{ -#if XCHAL_HAVE_MPU - __asm__ __volatile__("j 1f\n\t.align 8\n\t1: memw\n\twptlb %0, %1\n\t" : : "a" (entry.at), "a"(entry.as)); -#endif -} - -/* Same as xthal_mpu_set_entry except that this function must not be used to change the MPU entry - * for the currently executing instruction ... use xthal_mpu_set_entry instead. */ -static inline void xthal_mpu_set_entry_ (xthal_MPU_entry entry) -{ -#if XCHAL_HAVE_MPU - __asm__ __volatile__("wptlb %0, %1\n\t" : : "a" (entry.at), "a"(entry.as)); -#endif -} - - - -#endif /* C code */ - -#endif /*XTENSA_CACHE_H*/ - diff --git a/src/arch/xtensa/include/xtensa/coreasm.h b/src/arch/xtensa/include/xtensa/coreasm.h deleted file mode 100644 index 4113b7a0b041..000000000000 --- a/src/arch/xtensa/include/xtensa/coreasm.h +++ /dev/null @@ -1,1201 +0,0 @@ -/* - * xtensa/coreasm.h -- assembler-specific definitions that depend on - * CORE configuration. - * - * Source for configuration-independent binaries (which link in a - * configuration-specific HAL library) must NEVER include this file. - * It is perfectly normal, however, for the HAL itself to include this file. - * - * This file must NOT include xtensa/config/system.h. Any assembler - * header file that depends on system information should likely go - * in a new systemasm.h (or sysasm.h) header file. - * - * NOTE: macro beqi32 is NOT configuration-dependent, and is placed - * here until we have a proper configuration-independent header file. - */ - -/* - * Copyright (c) 2000-2018 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. - */ - -#ifndef XTENSA_COREASM_H -#define XTENSA_COREASM_H - -/* - * Tell header files this is assembly source, so they can avoid non-assembler - * definitions (eg. C types etc): - */ -#ifndef _ASMLANGUAGE /* conditionalize to avoid cpp warnings (3rd parties might use same macro) */ -#define _ASMLANGUAGE -#endif - -#include <xtensa/config/core.h> -#include <xtensa/config/specreg.h> -#include <xtensa/config/system.h> -#include <xtensa/xtensa-versions.h> - -/* - * Assembly-language specific definitions (assembly macros, etc.). - */ - -/*---------------------------------------------------------------------- - * find_ms_setbit - * - * This macro finds the most significant bit that is set in <as> - * and return its index + <base> in <ad>, or <base> - 1 if <as> is zero. - * The index counts starting at zero for the lsbit, so the return - * value ranges from <base>-1 (no bit set) to <base>+31 (msbit set). - * - * Parameters: - * <ad> destination address register (any register) - * <as> source address register - * <at> temporary address register (must be different than <as>) - * <base> constant value added to result (usually 0 or 1) - * On entry: - * <ad> = undefined if different than <as> - * <as> = value whose most significant set bit is to be found - * <at> = undefined - * no other registers are used by this macro. - * On exit: - * <ad> = <base> + index of msbit set in original <as>, - * = <base> - 1 if original <as> was zero. - * <as> clobbered (if not <ad>) - * <at> clobbered (if not <ad>) - * Example: - * find_ms_setbit a0, a4, a0, 0 -- return in a0 index of msbit set in a4 - */ - - .macro find_ms_setbit ad, as, at, base -#if XCHAL_HAVE_NSA - movi \at, 31+\base - nsau \as, \as // get index of \as, numbered from msbit (32 if absent) - sub \ad, \at, \as // get numbering from lsbit (0..31, -1 if absent) -#else /* XCHAL_HAVE_NSA */ - movi \at, \base // start with result of 0 (point to lsbit of 32) - - beqz \as, 2f // special case for zero argument: return -1 - bltui \as, 0x10000, 1f // is it one of the 16 lsbits? (if so, check lower 16 bits) - addi \at, \at, 16 // no, increment result to upper 16 bits (of 32) - //srli \as, \as, 16 // check upper half (shift right 16 bits) - extui \as, \as, 16, 16 // check upper half (shift right 16 bits) -1: - bltui \as, 0x100, 1f // is it one of the 8 lsbits? (if so, check lower 8 bits) - addi \at, \at, 8 // no, increment result to upper 8 bits (of 16) - srli \as, \as, 8 // shift right to check upper 8 bits -1: - bltui \as, 0x10, 1f // is it one of the 4 lsbits? (if so, check lower 4 bits) - addi \at, \at, 4 // no, increment result to upper 4 bits (of 8) - srli \as, \as, 4 // shift right 4 bits to check upper half -1: - bltui \as, 0x4, 1f // is it one of the 2 lsbits? (if so, check lower 2 bits) - addi \at, \at, 2 // no, increment result to upper 2 bits (of 4) - srli \as, \as, 2 // shift right 2 bits to check upper half -1: - bltui \as, 0x2, 1f // is it the lsbit? - addi \at, \at, 2 // no, increment result to upper bit (of 2) -2: - addi \at, \at, -1 // (from just above: add 1; from beqz: return -1) - //srli \as, \as, 1 -1: // done! \at contains index of msbit set (or -1 if none set) - .if 0x\ad - 0x\at // destination different than \at ? (works because regs are a0-a15) - mov \ad, \at // then move result to \ad - .endif -#endif /* XCHAL_HAVE_NSA */ - .endm // find_ms_setbit - -/*---------------------------------------------------------------------- - * find_ls_setbit - * - * This macro finds the least significant bit that is set in <as>, - * and return its index in <ad>. - * Usage is the same as for the find_ms_setbit macro. - * Example: - * find_ls_setbit a0, a4, a0, 0 -- return in a0 index of lsbit set in a4 - */ - - .macro find_ls_setbit ad, as, at, base - neg \at, \as // keep only the least-significant bit that is set... - and \as, \at, \as // ... in \as - find_ms_setbit \ad, \as, \at, \base - .endm // find_ls_setbit - -/*---------------------------------------------------------------------- - * find_ls_one - * - * Same as find_ls_setbit with base zero. - * Source (as) and destination (ad) registers must be different. - * Provided for backward compatibility. - */ - - .macro find_ls_one ad, as - find_ls_setbit \ad, \as, \ad, 0 - .endm // find_ls_one - -/*---------------------------------------------------------------------- - * floop, floopnez, floopgtz, floopend - * - * These macros are used for fast inner loops that - * work whether or not the Loops options is configured. - * If the Loops option is configured, they simply use - * the zero-overhead LOOP instructions; otherwise - * they use explicit decrement and branch instructions. - * - * They are used in pairs, with floop, floopnez or floopgtz - * at the beginning of the loop, and floopend at the end. - * - * Each pair of loop macro calls must be given the loop count - * address register and a unique label for that loop. - * - * Example: - * - * movi a3, 16 // loop 16 times - * floop a3, myloop1 - * : - * bnez a7, end1 // exit loop if a7 != 0 - * : - * floopend a3, myloop1 - * end1: - * - * Like the LOOP instructions, these macros cannot be - * nested, must include at least one instruction, - * cannot call functions inside the loop, etc. - * The loop can be exited by jumping to the instruction - * following floopend (or elsewhere outside the loop), - * or continued by jumping to a NOP instruction placed - * immediately before floopend. - * - * Unlike LOOP instructions, the register passed to floop* - * cannot be used inside the loop, because it is used as - * the loop counter if the Loops option is not configured. - * And its value is undefined after exiting the loop. - * And because the loop counter register is active inside - * the loop, you can't easily use this construct to loop - * across a register file using ROTW as you might with LOOP - * instructions, unless you copy the loop register along. - */ - - /* Named label version of the macros: */ - - .macro floop ar, endlabel - floop_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel - .endm - - .macro floopnez ar, endlabel - floopnez_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel - .endm - - .macro floopgtz ar, endlabel - floopgtz_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel - .endm - - .macro floopend ar, endlabel - floopend_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel - .endm - - /* Numbered local label version of the macros: */ -#if 0 /*UNTESTED*/ - .macro floop89 ar - floop_ \ar, 8, 9f - .endm - - .macro floopnez89 ar - floopnez_ \ar, 8, 9f - .endm - - .macro floopgtz89 ar - floopgtz_ \ar, 8, 9f - .endm - - .macro floopend89 ar - floopend_ \ar, 8b, 9 - .endm -#endif /*0*/ - - /* Underlying version of the macros: */ - - .macro floop_ ar, startlabel, endlabelref - .ifdef _infloop_ - .if _infloop_ - .err // Error: floop cannot be nested - .endif - .endif - .set _infloop_, 1 -#if XCHAL_HAVE_LOOPS - loop \ar, \endlabelref -#else /* XCHAL_HAVE_LOOPS */ -\startlabel: - addi \ar, \ar, -1 -#endif /* XCHAL_HAVE_LOOPS */ - .endm // floop_ - - .macro floopnez_ ar, startlabel, endlabelref - .ifdef _infloop_ - .if _infloop_ - .err // Error: floopnez cannot be nested - .endif - .endif - .set _infloop_, 1 -#if XCHAL_HAVE_LOOPS - loopnez \ar, \endlabelref -#else /* XCHAL_HAVE_LOOPS */ - beqz \ar, \endlabelref -\startlabel: - addi \ar, \ar, -1 -#endif /* XCHAL_HAVE_LOOPS */ - .endm // floopnez_ - - .macro floopgtz_ ar, startlabel, endlabelref - .ifdef _infloop_ - .if _infloop_ - .err // Error: floopgtz cannot be nested - .endif - .endif - .set _infloop_, 1 -#if XCHAL_HAVE_LOOPS - loopgtz \ar, \endlabelref -#else /* XCHAL_HAVE_LOOPS */ - bltz \ar, \endlabelref - beqz \ar, \endlabelref -\startlabel: - addi \ar, \ar, -1 -#endif /* XCHAL_HAVE_LOOPS */ - .endm // floopgtz_ - - - .macro floopend_ ar, startlabelref, endlabel - .ifndef _infloop_ - .err // Error: floopend without matching floopXXX - .endif - .ifeq _infloop_ - .err // Error: floopend without matching floopXXX - .endif - .set _infloop_, 0 -#if ! XCHAL_HAVE_LOOPS - bnez \ar, \startlabelref -#endif /* XCHAL_HAVE_LOOPS */ -\endlabel: - .endm // floopend_ - -/*---------------------------------------------------------------------- - * crsil -- conditional RSIL (read/set interrupt level) - * - * Executes the RSIL instruction if it exists, else just reads PS. - * The RSIL instruction does not exist in XEA2 if the interrupt - * option is not selected. - */ - - .macro crsil ar, newlevel -#if XCHAL_HAVE_INTERRUPTS - rsil \ar, \newlevel -#else - rsr.ps \ar -#endif - .endm // crsil - -/*---------------------------------------------------------------------- - * safe_movi_a0 -- move constant into a0 when L32R is not safe - * - * This macro is typically used by interrupt/exception handlers. - * Loads a 32-bit constant in a0, without using any other register, - * and without corrupting the LITBASE register, even when the - * value of the LITBASE register is unknown (eg. when application - * code and interrupt/exception handling code are built independently, - * and thus with independent values of the LITBASE register; - * debug monitors are one example of this). - * - * Worst-case size of resulting code: 17 bytes. - */ - - .macro safe_movi_a0 constant -#if XCHAL_HAVE_ABSOLUTE_LITERALS - /* Contort a PC-relative literal load even though we may be in litbase-relative mode: */ - j 1f - .begin no-transform // ensure what follows is assembled exactly as-is - .align 4 // ensure constant and call0 target ... - .byte 0 // ... are 4-byte aligned (call0 instruction is 3 bytes long) -1: call0 2f // read PC (that follows call0) in a0 - .long \constant // 32-bit constant to load into a0 -2: - .end no-transform - l32i a0, a0, 0 // load constant -#else - movi a0, \constant // no LITBASE, can assume PC-relative L32R -#endif - .endm - - - - -/*---------------------------------------------------------------------- - * window_spill{4,8,12} - * - * These macros spill callers' register windows to the stack. - * They work for both privileged and non-privileged tasks. - * Must be called from a windowed ABI context, eg. within - * a windowed ABI function (ie. valid stack frame, window - * exceptions enabled, not in exception mode, etc). - * - * This macro requires a single invocation of the window_spill_common - * macro in the same assembly unit and section. - * - * Note that using window_spill{4,8,12} macros is more efficient - * than calling a function implemented using window_spill_function, - * because the latter needs extra code to figure out the size of - * the call to the spilling function. - * - * Example usage: - * - * .text - * .align 4 - * .global some_function - * .type some_function,@function - * some_function: - * entry a1, 16 - * : - * : - * - * window_spill4 // Spill windows of some_function's callers; preserves a0..a3 only; - * // to use window_spill{8,12} in this example function we'd have - * // to increase space allocated by the entry instruction, because - * // 16 bytes only allows call4; 32 or 48 bytes (+locals) are needed - * // for call8/window_spill8 or call12/window_spill12 respectively. - * - * : - * - * retw - * - * window_spill_common // instantiates code used by window_spill4 - * - * - * On entry: - * none (if window_spill4) - * stack frame has enough space allocated for call8 (if window_spill8) - * stack frame has enough space allocated for call12 (if window_spill12) - * On exit: - * a4..a15 clobbered (if window_spill4) - * a8..a15 clobbered (if window_spill8) - * a12..a15 clobbered (if window_spill12) - * no caller windows are in live registers - */ - - .macro window_spill4 -#if XCHAL_HAVE_WINDOWED -# if XCHAL_NUM_AREGS == 16 - movi a15, 0 // for 16-register files, no need to call to reach the end -# elif XCHAL_NUM_AREGS == 32 - call4 .L__wdwspill_assist28 // call deep enough to clear out any live callers -# elif XCHAL_NUM_AREGS == 64 - call4 .L__wdwspill_assist60 // call deep enough to clear out any live callers -# endif -#endif - .endm // window_spill4 - - .macro window_spill8 -#if XCHAL_HAVE_WINDOWED -# if XCHAL_NUM_AREGS == 16 - movi a15, 0 // for 16-register files, no need to call to reach the end -# elif XCHAL_NUM_AREGS == 32 - call8 .L__wdwspill_assist24 // call deep enough to clear out any live callers -# elif XCHAL_NUM_AREGS == 64 - call8 .L__wdwspill_assist56 // call deep enough to clear out any live callers -# endif -#endif - .endm // window_spill8 - - .macro window_spill12 -#if XCHAL_HAVE_WINDOWED -# if XCHAL_NUM_AREGS == 16 - movi a15, 0 // for 16-register files, no need to call to reach the end -# elif XCHAL_NUM_AREGS == 32 - call12 .L__wdwspill_assist20 // call deep enough to clear out any live callers -# elif XCHAL_NUM_AREGS == 64 - call12 .L__wdwspill_assist52 // call deep enough to clear out any live callers -# endif -#endif - .endm // window_spill12 - - -/*---------------------------------------------------------------------- - * window_spill_function - * - * This macro outputs a function that will spill its caller's callers' - * register windows to the stack. Eg. it could be used to implement - * a version of xthal_window_spill() that works in non-privileged tasks. - * This works for both privileged and non-privileged tasks. - * - * Typical usage: - * - * .text - * .align 4 - * .global my_spill_function - * .type my_spill_function,@function - * my_spill_function: - * window_spill_function - * - * On entry to resulting function: - * none - * On exit from resulting function: - * none (no caller windows are in live registers) - */ - - .macro window_spill_function -#if XCHAL_HAVE_WINDOWED -# if XCHAL_NUM_AREGS == 32 - entry sp, 48 - bbci.l a0, 31, 1f // branch if called with call4 - bbsi.l a0, 30, 2f // branch if called with call12 - call8 .L__wdwspill_assist16 // called with call8, only need another 8 - retw -1: - call12 .L__wdwspill_assist16 // called with call4, only need another 12 - retw -2: - call4 .L__wdwspill_assist16 // called with call12, only need another 4 - retw -# elif XCHAL_NUM_AREGS == 64 - entry sp, 48 - bbci.l a0, 31, 1f // branch if called with call4 - bbsi.l a0, 30, 2f // branch if called with call12 - call4 .L__wdwspill_assist52 // called with call8, only need a call4 - retw -1: - call8 .L__wdwspill_assist52 // called with call4, only need a call8 - retw -2: - call12 .L__wdwspill_assist40 // called with call12, can skip a call12 - retw -# elif XCHAL_NUM_AREGS == 16 - entry sp, 16 - bbci.l a0, 31, 1f // branch if called with call4 - bbsi.l a0, 30, 2f // branch if called with call12 - movi a7, 0 // called with call8 - retw -1: - movi a11, 0 // called with call4 -2: - retw // if called with call12, everything already spilled - -// movi a15, 0 // trick to spill all but the direct caller -// j 1f -// // The entry instruction is magical in the assembler (gets auto-aligned) -// // so we have to jump to it to avoid falling through the padding. -// // We need entry/retw to know where to return. -//1: entry sp, 16 -// retw -# else -# error "unrecognized address register file size" -# endif - -#endif /* XCHAL_HAVE_WINDOWED */ - window_spill_common - .endm // window_spill_function - -/*---------------------------------------------------------------------- - * window_spill_common - * - * Common code used by any number of invocations of the window_spill## - * and window_spill_function macros. - * - * Must be instantiated exactly once within a given assembly unit, - * within call/j range of and same section as window_spill## - * macro invocations for that assembly unit. - * (Is automatically instantiated by the window_spill_function macro.) - */ - - .macro window_spill_common -#if XCHAL_HAVE_WINDOWED && (XCHAL_NUM_AREGS == 32 || XCHAL_NUM_AREGS == 64) - .ifndef .L__wdwspill_defined -# if XCHAL_NUM_AREGS >= 64 -.L__wdwspill_assist60: - entry sp, 32 - call8 .L__wdwspill_assist52 - retw -.L__wdwspill_assist56: - entry sp, 16 - call4 .L__wdwspill_assist52 - retw -.L__wdwspill_assist52: - entry sp, 48 - call12 .L__wdwspill_assist40 - retw -.L__wdwspill_assist40: - entry sp, 48 - call12 .L__wdwspill_assist28 - retw -# endif -.L__wdwspill_assist28: - entry sp, 48 - call12 .L__wdwspill_assist16 - retw -.L__wdwspill_assist24: - entry sp, 32 - call8 .L__wdwspill_assist16 - retw -.L__wdwspill_assist20: - entry sp, 16 - call4 .L__wdwspill_assist16 - retw -.L__wdwspill_assist16: - entry sp, 16 - movi a15, 0 - retw - .set .L__wdwspill_defined, 1 - .endif -#endif /* XCHAL_HAVE_WINDOWED with 32 or 64 aregs */ - .endm // window_spill_common - -/*---------------------------------------------------------------------- - * beqi32 - * - * macro implements version of beqi for arbitrary 32-bit immediate value - * - * beqi32 ax, ay, imm32, label - * - * Compares value in register ax with imm32 value and jumps to label if - * equal. Clobbers register ay if needed - * - */ - .macro beqi32 ax, ay, imm, label - .ifeq ((\imm-1) & ~7) // 1..8 ? - beqi \ax, \imm, \label - .else - .ifeq (\imm+1) // -1 ? - beqi \ax, \imm, \label - .else - .ifeq (\imm) // 0 ? - beqz \ax, \label - .else - // We could also handle immediates 10,12,16,32,64,128,256 - // but it would be a long macro... - movi \ay, \imm - beq \ax, \ay, \label - .endif - .endif - .endif - .endm // beqi32 - -/*---------------------------------------------------------------------- - * isync_retw_nop - * - * This macro must be invoked immediately after ISYNC if ISYNC - * would otherwise be immediately followed by RETW (or other instruction - * modifying WindowBase or WindowStart), in a context where - * kernel vector mode may be selected, and level-one interrupts - * and window overflows may be enabled, on an XEA1 configuration. - * - * On hardware with erratum "XEA1KWIN" (see <xtensa/core.h> for details), - * XEA1 code must have at least one instruction between ISYNC and RETW if - * run in kernel vector mode with interrupts and window overflows enabled. - */ - .macro isync_retw_nop -#if XCHAL_MAYHAVE_ERRATUM_XEA1KWIN - nop -#endif - .endm - -/*---------------------------------------------------------------------- - * isync_return_nop - * - * This macro should be used instead of isync_retw_nop in code that is - * intended to run on both the windowed and call0 ABIs - */ - .macro isync_return_nop -#ifdef __XTENSA_WINDOWED_ABI__ - isync_retw_nop -#endif - .endm - -/*---------------------------------------------------------------------- - * isync_erratum453 - * - * This macro must be invoked at certain points in the code, - * such as in exception and interrupt vectors in particular, - * to work around erratum 453. - */ - .macro isync_erratum453 -#if XCHAL_ERRATUM_453 - isync -#endif - .endm - - -/*---------------------------------------------------------------------- - * readsr - * - * wrapper for 'rsr' that constructs register names that involve levels - * e.g. EPCn etc. Use like so: - * readsr epc XCHAL_DEBUGLEVEL a2 - */ - .macro readsr reg suf ar - rsr.\reg\suf \ar - .endm - -/*---------------------------------------------------------------------- - * writesr - * - * wrapper for 'wsr' that constructs register names that involve levels - * e.g. EPCn etc. Use like so: - * writesr epc XCHAL_DEBUGLEVEL a2 - */ - .macro writesr reg suf ar - wsr.\reg\suf \ar - .endm - -/*---------------------------------------------------------------------- - * xchgsr - * - * wrapper for 'xsr' that constructs register names that involve levels - * e.g. EPCn etc. Use like so: - * xchgsr epc XCHAL_DEBUGLEVEL a2 - */ - .macro xchgsr reg suf ar - xsr.\reg\suf \ar - .endm - -/*---------------------------------------------------------------------- - * INDEX_SR - * - * indexing wrapper for rsr/wsr/xsr that constructs register names from - * the provided base name and the current index. Use like so: - * .set _idx, 0 - * INDEX_SR rsr.ccompare a2 - * - * this yields: rsr.ccompare0 a2 - */ - .macro INDEX_SR instr ar -.ifeq (_idx) - &instr&0 \ar -.endif -.ifeq (_idx-1) - &instr&1 \ar -.endif -.ifeq (_idx-2) - &instr&2 \ar -.endif -.ifeq (_idx-3) - &instr&3 \ar -.endif -.ifeq (_idx-4) - &instr&4 \ar -.endif -.ifeq (_idx-5) - &instr&5 \ar -.endif -.ifeq (_idx-6) - &instr&6 \ar -.endif -.ifeq (_idx-7) - &instr&7 \ar -.endif - .endm - - -/*---------------------------------------------------------------------- - * abs - * - * implements abs on machines that do not have it configured - */ - -#if !XCHAL_HAVE_ABS - .macro abs arr, ars - .ifc \arr, \ars - //src equal dest is less efficient - bgez \arr, 1f - neg \arr, \arr -1: - .else - neg \arr, \ars - movgez \arr, \ars, \ars - .endif - .endm -#endif /* !XCHAL_HAVE_ABS */ - - -/*---------------------------------------------------------------------- - * addx2 - * - * implements addx2 on machines that do not have it configured - * - */ - -#if !XCHAL_HAVE_ADDX - .macro addx2 arr, ars, art - .ifc \arr, \art - .ifc \arr, \ars - // addx2 a, a, a (not common) - .err - .else - add \arr, \ars, \art - add \arr, \ars, \art - .endif - .else - //addx2 a, b, c - //addx2 a, a, b - //addx2 a, b, b - slli \arr, \ars, 1 - add \arr, \arr, \art - .endif - .endm -#endif /* !XCHAL_HAVE_ADDX */ - -/*---------------------------------------------------------------------- - * addx4 - * - * implements addx4 on machines that do not have it configured - * - */ - -#if !XCHAL_HAVE_ADDX - .macro addx4 arr, ars, art - .ifc \arr, \art - .ifc \arr, \ars - // addx4 a, a, a (not common) - .err - .else - //# addx4 a, b, a - add \arr, \ars, \art - add \arr, \ars, \art - add \arr, \ars, \art - add \arr, \ars, \art - .endif - .else - //addx4 a, b, c - //addx4 a, a, b - //addx4 a, b, b - slli \arr, \ars, 2 - add \arr, \arr, \art - .endif - .endm -#endif /* !XCHAL_HAVE_ADDX */ - -/*---------------------------------------------------------------------- - * addx8 - * - * implements addx8 on machines that do not have it configured - * - */ - -#if !XCHAL_HAVE_ADDX - .macro addx8 arr, ars, art - .ifc \arr, \art - .ifc \arr, \ars - //addx8 a, a, a (not common) - .err - .else - //addx8 a, b, a - add \arr, \ars, \art - add \arr, \ars, \art - add \arr, \ars, \art - add \arr, \ars, \art - add \arr, \ars, \art - add \arr, \ars, \art - add \arr, \ars, \art - add \arr, \ars, \art - .endif - .else - //addx8 a, b, c - //addx8 a, a, b - //addx8 a, b, b - slli \arr, \ars, 3 - add \arr, \arr, \art - .endif - .endm -#endif /* !XCHAL_HAVE_ADDX */ - - -/*---------------------------------------------------------------------- - * rfe_rfue - * - * Maps to RFUE on XEA1, and RFE on XEA2. No mapping on XEAX. - */ - -#if XCHAL_HAVE_XEA1 - .macro rfe_rfue - rfue - .endm -#elif XCHAL_HAVE_XEA2 - .macro rfe_rfue - rfe - .endm -#endif - - -/*---------------------------------------------------------------------- - * abi_entry - * - * Generate proper function entry sequence for the current ABI - * (windowed or call0). Takes care of allocating stack space (up to 1kB) - * and saving the return PC, if necessary. The corresponding abi_return - * macro does the corresponding stack deallocation and restoring return PC. - * - * Parameters are: - * - * locsize Number of bytes to allocate on the stack - * for local variables (and for args to pass to - * callees, if any calls are made). Defaults to zero. - * The macro rounds this up to a multiple of 16. - * NOTE: large values are allowed (e.g. up to 1 GB). - * - * callsize Maximum call size made by this function. - * Leave zero (default) for leaf functions, i.e. if - * this function makes no calls to other functions. - * Otherwise must be set to 4, 8, or 12 according - * to whether the "largest" call made is a call[x]4, - * call[x]8, or call[x]12 (for call0 ABI, it makes - * no difference whether this is set to 4, 8 or 12, - * but it must be set to one of these values). - * - * NOTE: It is up to the caller to align the entry point, declare the - * function symbol, make it global, etc. - * - * NOTE: This macro relies on assembler relaxation for large values - * of locsize. It might not work with the no-transform directive. - * NOTE: For the call0 ABI, this macro ensures SP is allocated or - * de-allocated cleanly, i.e. without temporarily allocating too much - * (or allocating negatively!) due to addi relaxation. - * - * NOTE: Generating the proper sequence and register allocation for - * making calls in an ABI independent manner is a separate topic not - * covered by this macro. - * - * NOTE: To access arguments, you can't use a fixed offset from SP. - * The offset depends on the ABI, whether the function is leaf, etc. - * The simplest method is probably to use the .locsz symbol, which - * is set by this macro to the actual number of bytes allocated on - * the stack, in other words, to the offset from SP to the arguments. - * E.g. for a function whose arguments are all 32-bit integers, you - * can get the 7th and 8th arguments (1st and 2nd args stored on stack) - * using: - * l32i a2, sp, .locsz - * l32i a3, sp, .locsz+4 - * (this example works as long as locsize is under L32I's offset limit - * of 1020 minus up to 48 bytes of ABI-specific stack usage; - * otherwise you might first need to do "addi a?, sp, .locsz" - * or similar sequence). - * - * NOTE: For call0 ABI, this macro (and abi_return) may clobber a9 - * (a caller-saved register). - * - * Examples: - * abi_entry - * abi_entry 5 - * abi_entry 22, 8 - * abi_entry 0, 4 - */ - - /* - * Compute .locsz and .callsz without emitting any instructions. - * Used by both abi_entry and abi_return. - * Assumes locsize >= 0. - */ - .macro abi_entry_size locsize=0, callsize=0 -#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ -# if XCHAL_HAVE_XEA3 - .set .callsz, 32 /* call8 only */ -# else - .ifeq \callsize - .set .callsz, 16 - .else - .ifeq \callsize-4 - .set .callsz, 16 - .else - .ifeq \callsize-8 - .set .callsz, 32 - .else - .ifeq \callsize-12 - .set .callsz, 48 - .else - .error "abi_entry: invalid call size \callsize" - .endif - .endif - .endif - .endif -# endif - .set .locsz, .callsz + ((\locsize + 15) & -16) -#else - .set .callsz, \callsize - .if .callsz /* if calls, need space for return PC */ - .set .locsz, (\locsize + 4 + 15) & -16 - .else - .set .locsz, (\locsize + 15) & -16 - .endif -#endif - .endm - - .macro abi_entry locsize=0, callsize=0 - .iflt \locsize - .error "abi_entry: invalid negative size of locals (\locsize)" - .endif - abi_entry_size \locsize, \callsize -#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ -# define ABI_ENTRY_MINSIZE 3 /* size of abi_entry (no arguments) instructions in bytes */ - .ifgt .locsz - 32760 /* .locsz > 32760 (ENTRY's max range)? */ - /* Funky computation to try to have assembler use addmi efficiently if possible: */ - entry sp, 0x7F00 + (.locsz & 0xF0) - addi a12, sp, - ((.locsz & -0x100) - 0x7F00) - movsp sp, a12 - .else - entry sp, .locsz - .endif -#else -# define ABI_ENTRY_MINSIZE 0 /* size of abi_entry (no arguments) instructions in bytes */ - .if .locsz - .ifle .locsz - 128 /* if locsz <= 128 */ - addi sp, sp, -.locsz - .if .callsz - s32i a0, sp, .locsz - 4 - .endif - .elseif .callsz /* locsz > 128, with calls: */ - movi a9, .locsz - 16 /* note: a9 is caller-saved */ - addi sp, sp, -16 - s32i a0, sp, 12 - sub sp, sp, a9 - .else /* locsz > 128, no calls: */ - movi a9, .locsz - sub sp, sp, a9 - .endif /* end */ - .endif -#endif - .endm - - - -/*---------------------------------------------------------------------- - * abi_return - * - * Generate proper function exit sequence for the current ABI - * (windowed or call0). Takes care of freeing stack space and - * restoring the return PC, if necessary. - * NOTE: This macro MUST be invoked following a corresponding - * abi_entry macro invocation. For call0 ABI in particular, - * all stack and PC restoration are done according to the last - * abi_entry macro invoked before this macro in the assembly file. - * - * Normally this macro takes no arguments. However to allow - * for placing abi_return *before* abi_entry (as must be done - * for some highly optimized assembly), it optionally takes - * exactly the same arguments as abi_entry. - */ - - .macro abi_return locsize=-1, callsize=0 - .ifge \locsize - abi_entry_size \locsize, \callsize - .endif -#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ - retw -#else - .if .locsz - .iflt .locsz - 128 /* if locsz < 128 */ - .if .callsz - l32i a0, sp, .locsz - 4 - .endif - addi sp, sp, .locsz - .elseif .callsz /* locsz >= 128, with calls: */ - addi a9, sp, .locsz - 16 - l32i a0, a9, 12 - addi sp, a9, 16 - .else /* locsz >= 128, no calls: */ - movi a9, .locsz - add sp, sp, a9 - .endif /* end */ - .endif - ret -#endif - .endm - - -/* - * HW erratum fixes. - */ - - .macro hw_erratum_487_fix -#if defined XSHAL_ERRATUM_487_FIX - isync -#endif - .endm - -#if XCHAL_HAVE_XEA3 && XCHAL_HW_MIN_VERSION == XTENSA_HWVERSION_RH_2016_0 - .macro halt imm=0 -.Lhalt\@: j .Lhalt\@ - .endm - .macro halt.n - halt 0 - .endm -#endif - - -/* - * These macros are internal, subject to change, and should not be used in - * any new code. - */ - -#define _GBL(x) .global x -#define _TYP(x) .type x,@function -#define _ALN(x) .align x -#define _SIZ(x) .size x, . - x -#define _MKEND(x) .purgem endfunc ; .macro endfunc ; _SIZ(x) ; .purgem endfunc ; .macro endfunc ; .endm ; .endm -#define _SYMT(x) _GBL(x); _MKEND(x); _TYP(x); _ALN(4); x: -#define _SYM2(x) _GBL(x); _TYP(x); x: -#define _SYM(x) _GBL(x); _MKEND(x); _ALN(4); x: -.macro endfunc ; .endm - -/* - * the DECLFUNC() macro provides a mechanism for implementing both the - * standard and _nw interface with a single copy of the code. - * - * For Call0 ABI there is one function definition which is labeled with - * both the xthal_..._nw and xthal_... symbols. - * - * For windowed ABI, two compilations are involved (one with the __NW_FUNCTION__ - * symbol defined) resulting in two separate functions (the _nw one without - * the window adjustments). -*/ - -#if defined(__NW_FUNCTION__) -# define DECLFUNC(x) _SYMT(x ## _nw) -#else -# if defined (__XTENSA_CALL0_ABI__) -# define DECLFUNC(x) _SYMT(x); _SYM2(x ## _nw) -# else -# define DECLFUNC(x) _SYMT(x) -# endif -#endif - - -/* - * Macros to support virtual ops. - */ -#include <xtensa/tie/xt_virtualops.h> - -#ifndef XT_ADD_A - .macro add.a a,b,c ; add \a, \b, \c ; .endm -#endif - -#ifndef XT_ADDI_A - .macro addi.a a,b,c ; addi \a, \b, \c ; .endm -#endif - -#ifndef XT_ADDMI_A - .macro addmi.a a,b,c ; addmi \a, \b, \c ; .endm -#endif - -#ifndef XT_ADDX2_A - .macro addx2.a a,b,c ; addx2 \a, \b, \c ; .endm -#endif - -#ifndef XT_ADDX4_A - .macro addx4.a a,b,c ; addx4 \a, \b, \c ; .endm -#endif - -#ifndef XT_ADDX8_A - .macro addx8.a a,b,c ; addx8 \a, \b, \c ; .endm -#endif - -#ifndef XT_MOV_A - .macro mov.a a,b ; mov \a, \b ; .endm -#endif - -#ifndef XT_SUB_A - .macro sub.a a,b,c ; sub \a, \b, \c ; .endm -#endif - -/* Places the core-id in the requested AR register.*/ - .macro xt_core_id ar -#if XCHAL_HAVE_PRID -#if PRID_ID_BITS - rsr.prid \ar - extui \ar, \ar, PRID_ID_SHIFT, PRID_ID_BITS -#else - movi \ar, 0 -#endif -#else - movi \ar, 0 -#endif - .endm - -.macro clr_dcache scratch1, scratch2, scratch3 -#if defined(XCHAL_DCACHE_SIZE) && (XCHAL_DCACHE_SIZE > 0) - movi \scratch3, 0 - movi \scratch1, 0 - movi \scratch2, XCHAL_DCACHE_SIZE -1: - sdct \scratch3, \scratch1 - addi \scratch1, \scratch1, XCHAL_DCACHE_LINESIZE * (1 << XCHAL_DCACHE_LINES_PER_TAG_LOG2) - bne \scratch1, \scratch2, 1b - movi \scratch1, 0 -2: - sdcw \scratch3, \scratch1 - addi \scratch1, \scratch1, 4 - bne \scratch1, \scratch2, 2b -#endif -.endm - -.macro clr_icache scratch1, scratch2, scratch3 -#if defined(XCHAL_ICACHE_SIZE) && (XCHAL_ICACHE_SIZE > 0) - movi \scratch3, 0 - movi \scratch1, 0 - movi \scratch2, XCHAL_ICACHE_SIZE -1: - sict \scratch3, \scratch1 - addi \scratch1, \scratch1, XCHAL_ICACHE_LINESIZE - bne \scratch1, \scratch2, 1b - movi \scratch1, 0 -2: - sicw \scratch3, \scratch1 - addi \scratch1, \scratch1, 4 - bne \scratch1, \scratch2, 2b -#endif -.endm - -.macro clr_localmem base_addr, bytes, scratch1, scratch2, scratch3 - movi \scratch1, \base_addr - movi \scratch2, \base_addr + \bytes - movi \scratch3, 0 -1: - s32i \scratch3, \scratch1, 0 - addi \scratch1, \scratch1, 4 - bne \scratch1, \scratch2, 1b -.endm - -.macro clr_all_localmems scratch1, scratch2, scratch3 -#if defined(XCHAL_INSTRAM0_SIZE) && (XCHAL_INSTRAM0_SIZE > 0) - clr_localmem XCHAL_INSTRAM0_VADDR, XCHAL_INSTRAM0_SIZE, \scratch1, \scratch2, \scratch3 -#endif -#if defined(XCHAL_INSTRAM1_SIZE) && (XCHAL_INSTRAM1_SIZE > 0) - clr_localmem XCHAL_INSTRAM1_VADDR, XCHAL_INSTRAM1_SIZE, \scratch1, \scratch2, \scratch3 -#endif -#if defined(XCHAL_DATARAM0_SIZE) && (XCHAL_DATARAM0_SIZE > 0) - clr_localmem XCHAL_DATARAM0_VADDR, XCHAL_DATARAM0_SIZE, \scratch1, \scratch2, \scratch3 -#endif -#if defined(XCHAL_DATARAM1_SIZE) && (XCHAL_DATARAM1_SIZE > 0) - clr_localmem XCHAL_DATARAM1_VADDR, XCHAL_DATARAM1_SIZE, \scratch1, \scratch2, \scratch3 -#endif -#if defined(XCHAL_URAM0_SIZE) && (XCHAL_URAM0_SIZE > 0) - clr_localmem XCHAL_URAM0_VADDR, XCHAL_URAM0_SIZE, \scratch1, \scratch2, \scratch3 -#endif -#if defined(XCHAL_URAM1_SIZE) && (XCHAL_URAM1_SIZE > 0) - clr_localmem XCHAL_URAM1_VADDR, XCHAL_URAM1_SIZE, \scratch1, \scratch2, \scratch3 -#endif -.endm - -#endif /*XTENSA_COREASM_H*/ - diff --git a/src/arch/xtensa/include/xtensa/corebits.h b/src/arch/xtensa/include/xtensa/corebits.h deleted file mode 100644 index c14dabcdcc3c..000000000000 --- a/src/arch/xtensa/include/xtensa/corebits.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * xtensa/corebits.h - Xtensa Special Register field positions, masks, values. - * - * (In previous releases, these were defined in specreg.h, a generated file. - * This file is not generated, ie. it is processor configuration independent.) - */ - -/* $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/include/xtensa/corebits.h#1 $ */ - -/* - * Copyright (c) 2005-2011 Tensilica 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. - */ - -#ifndef XTENSA_COREBITS_H -#define XTENSA_COREBITS_H - -/* EXCCAUSE register fields: */ -#define EXCCAUSE_EXCCAUSE_SHIFT 0 -#define EXCCAUSE_EXCCAUSE_MASK 0x3F -/* EXCCAUSE register values: */ -/* - * General Exception Causes - * (values of EXCCAUSE special register set by general exceptions, - * which vector to the user, kernel, or double-exception vectors). - */ -#define EXCCAUSE_ILLEGAL 0 /* Illegal Instruction */ -#define EXCCAUSE_SYSCALL 1 /* System Call (SYSCALL instruction) */ -#define EXCCAUSE_INSTR_ERROR 2 /* Instruction Fetch Error */ -# define EXCCAUSE_IFETCHERROR 2 /* (backward compatibility macro, deprecated, avoid) */ -#define EXCCAUSE_LOAD_STORE_ERROR 3 /* Load Store Error */ -# define EXCCAUSE_LOADSTOREERROR 3 /* (backward compatibility macro, deprecated, avoid) */ -#define EXCCAUSE_LEVEL1_INTERRUPT 4 /* Level 1 Interrupt */ -# define EXCCAUSE_LEVEL1INTERRUPT 4 /* (backward compatibility macro, deprecated, avoid) */ -#define EXCCAUSE_ALLOCA 5 /* Stack Extension Assist (MOVSP instruction) for alloca */ -#define EXCCAUSE_DIVIDE_BY_ZERO 6 /* Integer Divide by Zero */ -#define EXCCAUSE_SPECULATION 7 /* Use of Failed Speculative Access (not implemented) */ -#define EXCCAUSE_PRIVILEGED 8 /* Privileged Instruction */ -#define EXCCAUSE_UNALIGNED 9 /* Unaligned Load or Store */ -/* Reserved 10..11 */ -#define EXCCAUSE_INSTR_DATA_ERROR 12 /* PIF Data Error on Instruction Fetch (RB-200x and later) */ -#define EXCCAUSE_LOAD_STORE_DATA_ERROR 13 /* PIF Data Error on Load or Store (RB-200x and later) */ -#define EXCCAUSE_INSTR_ADDR_ERROR 14 /* PIF Address Error on Instruction Fetch (RB-200x and later) */ -#define EXCCAUSE_LOAD_STORE_ADDR_ERROR 15 /* PIF Address Error on Load or Store (RB-200x and later) */ -#define EXCCAUSE_ITLB_MISS 16 /* ITLB Miss (no ITLB entry matches, hw refill also missed) */ -#define EXCCAUSE_ITLB_MULTIHIT 17 /* ITLB Multihit (multiple ITLB entries match) */ -#define EXCCAUSE_INSTR_RING 18 /* Ring Privilege Violation on Instruction Fetch */ -/* Reserved 19 */ /* Size Restriction on IFetch (not implemented) */ -#define EXCCAUSE_INSTR_PROHIBITED 20 /* Cache Attribute does not allow Instruction Fetch */ -/* Reserved 21..23 */ -#define EXCCAUSE_DTLB_MISS 24 /* DTLB Miss (no DTLB entry matches, hw refill also missed) */ -#define EXCCAUSE_DTLB_MULTIHIT 25 /* DTLB Multihit (multiple DTLB entries match) */ -#define EXCCAUSE_LOAD_STORE_RING 26 /* Ring Privilege Violation on Load or Store */ -/* Reserved 27 */ /* Size Restriction on Load/Store (not implemented) */ -#define EXCCAUSE_LOAD_PROHIBITED 28 /* Cache Attribute does not allow Load */ -#define EXCCAUSE_STORE_PROHIBITED 29 /* Cache Attribute does not allow Store */ -/* Reserved 30..31 */ -#define EXCCAUSE_CP_DISABLED(n) (32+(n)) /* Access to Coprocessor 'n' when disabled */ -#define EXCCAUSE_CP0_DISABLED 32 /* Access to Coprocessor 0 when disabled */ -#define EXCCAUSE_CP1_DISABLED 33 /* Access to Coprocessor 1 when disabled */ -#define EXCCAUSE_CP2_DISABLED 34 /* Access to Coprocessor 2 when disabled */ -#define EXCCAUSE_CP3_DISABLED 35 /* Access to Coprocessor 3 when disabled */ -#define EXCCAUSE_CP4_DISABLED 36 /* Access to Coprocessor 4 when disabled */ -#define EXCCAUSE_CP5_DISABLED 37 /* Access to Coprocessor 5 when disabled */ -#define EXCCAUSE_CP6_DISABLED 38 /* Access to Coprocessor 6 when disabled */ -#define EXCCAUSE_CP7_DISABLED 39 /* Access to Coprocessor 7 when disabled */ -/* Reserved 40..63 */ - -/* PS register fields: */ -#define PS_WOE_SHIFT 18 -#define PS_WOE_MASK 0x00040000 -#define PS_WOE PS_WOE_MASK -#define PS_CALLINC_SHIFT 16 -#define PS_CALLINC_MASK 0x00030000 -#define PS_CALLINC(n) (((n)&3)<<PS_CALLINC_SHIFT) /* n = 0..3 */ -#define PS_OWB_SHIFT 8 -#define PS_OWB_MASK 0x00000F00 -#define PS_OWB(n) (((n)&15)<<PS_OWB_SHIFT) /* n = 0..15 (or 0..7) */ -#define PS_RING_SHIFT 6 -#define PS_RING_MASK 0x000000C0 -#define PS_RING(n) (((n)&3)<<PS_RING_SHIFT) /* n = 0..3 */ -#define PS_UM_SHIFT 5 -#define PS_UM_MASK 0x00000020 -#define PS_UM PS_UM_MASK -#define PS_EXCM_SHIFT 4 -#define PS_EXCM_MASK 0x00000010 -#define PS_EXCM PS_EXCM_MASK -#define PS_INTLEVEL_SHIFT 0 -#define PS_INTLEVEL_MASK 0x0000000F -#define PS_INTLEVEL(n) ((n)&PS_INTLEVEL_MASK) /* n = 0..15 */ -/* ABI-derived field values: */ -#ifdef __XTENSA_CALL0_ABI__ -#define PS_WOE_ABI 0 -#define PS_WOECALL4_ABI 0 -#else -#define PS_WOE_ABI PS_WOE /* 0x40000 */ -#define PS_WOECALL4_ABI (PS_WOE | PS_CALLINC(1)) /* 0x50000, per call4 */ -#endif -/* Backward compatibility (deprecated): */ -#define PS_PROGSTACK_SHIFT PS_UM_SHIFT -#define PS_PROGSTACK_MASK PS_UM_MASK -#define PS_PROG_SHIFT PS_UM_SHIFT -#define PS_PROG_MASK PS_UM_MASK -#define PS_PROG PS_UM - -/* DBREAKCn register fields: */ -#define DBREAKC_MASK_SHIFT 0 -#define DBREAKC_MASK_MASK 0x0000003F -#define DBREAKC_LOADBREAK_SHIFT 30 -#define DBREAKC_LOADBREAK_MASK 0x40000000 -#define DBREAKC_STOREBREAK_SHIFT 31 -#define DBREAKC_STOREBREAK_MASK 0x80000000 - -/* DEBUGCAUSE register fields: */ -#define DEBUGCAUSE_DEBUGINT_SHIFT 5 -#define DEBUGCAUSE_DEBUGINT_MASK 0x20 /* debug interrupt */ -#define DEBUGCAUSE_BREAKN_SHIFT 4 -#define DEBUGCAUSE_BREAKN_MASK 0x10 /* BREAK.N instruction */ -#define DEBUGCAUSE_BREAK_SHIFT 3 -#define DEBUGCAUSE_BREAK_MASK 0x08 /* BREAK instruction */ -#define DEBUGCAUSE_DBREAK_SHIFT 2 -#define DEBUGCAUSE_DBREAK_MASK 0x04 /* DBREAK match */ -#define DEBUGCAUSE_IBREAK_SHIFT 1 -#define DEBUGCAUSE_IBREAK_MASK 0x02 /* IBREAK match */ -#define DEBUGCAUSE_ICOUNT_SHIFT 0 -#define DEBUGCAUSE_ICOUNT_MASK 0x01 /* ICOUNT would increment to zero */ - -/* MESR register fields: */ -#define MESR_MEME 0x00000001 /* memory error */ -#define MESR_MEME_SHIFT 0 -#define MESR_DME 0x00000002 /* double memory error */ -#define MESR_DME_SHIFT 1 -#define MESR_RCE 0x00000010 /* recorded memory error */ -#define MESR_RCE_SHIFT 4 -#define MESR_LCE -#define MESR_LCE_SHIFT ? -#define MESR_LCE_L -#define MESR_ERRENAB 0x00000100 -#define MESR_ERRENAB_SHIFT 8 -#define MESR_ERRTEST 0x00000200 -#define MESR_ERRTEST_SHIFT 9 -#define MESR_DATEXC 0x00000400 -#define MESR_DATEXC_SHIFT 10 -#define MESR_INSEXC 0x00000800 -#define MESR_INSEXC_SHIFT 11 -#define MESR_WAYNUM_SHIFT 16 -#define MESR_ACCTYPE_SHIFT 20 -#define MESR_MEMTYPE_SHIFT 24 -#define MESR_ERRTYPE_SHIFT 30 - -/* MEMCTL register fields: */ -#define MEMCTL_SNOOP_EN_SHIFT 1 -#define MEMCTL_SNOOP_EN 0x02 /* enable snoop responses (default 0) */ -#define MEMCTL_L0IBUF_EN_SHIFT 0 -#define MEMCTL_L0IBUF_EN 0x01 /* enable loop instr. buffer (default 1) */ -#define MEMCTL_INV_EN_SHIFT 23 -#define MEMCTL_INV_EN 0x00800000 /* invalidate cache ways being increased */ -#define MEMCTL_DCWU_SHIFT 8 -#define MEMCTL_DCWU_BITS 5 -#define MEMCTL_DCWA_SHIFT 13 -#define MEMCTL_DCWA_BITS 5 -#define MEMCTL_ICWU_SHIFT 18 -#define MEMCTL_ICWU_BITS 5 -#define MEMCTL_DCWU_MASK 0x00001F00 /* Bits 8-12 dcache ways in use */ -#define MEMCTL_DCWA_MASK 0x0003E000 /* Bits 13-17 dcache ways allocatable */ -#define MEMCTL_ICWU_MASK 0x007C0000 /* Bits 18-22 icache ways in use */ -#define MEMCTL_DCWU_CLR_MASK ~(MEMCTL_DCWU_MASK) -#define MEMCTL_DCWA_CLR_MASK ~(MEMCTL_DCWA_MASK) -#define MEMCTL_ICWU_CLR_MASK ~(MEMCTL_ICWU_MASK) -#define MEMCTL_DCW_CLR_MASK (MEMCTL_DCWU_CLR_MASK | MEMCTL_DCWA_CLR_MASK) -#define MEMCTL_IDCW_CLR_MASK (MEMCTL_DCW_CLR_MASK | MEMCTL_ICWU_CLR_MASK) - - -#endif /*XTENSA_COREBITS_H*/ - diff --git a/src/arch/xtensa/include/xtensa/hal.h b/src/arch/xtensa/include/xtensa/hal.h deleted file mode 100644 index 9db5df3bcda8..000000000000 --- a/src/arch/xtensa/include/xtensa/hal.h +++ /dev/null @@ -1,1518 +0,0 @@ -/* - xtensa/hal.h -- contains a definition of the Core HAL interface - - All definitions in this header file are independent of any specific - Xtensa processor configuration. Thus software (eg. OS, application, - etc) can include this header file and be compiled into configuration- - independent objects that can be distributed and eventually linked - to the HAL library (libhal.a) to create a configuration-specific - final executable. - - Certain definitions, however, are release/version-specific -- such as - the XTHAL_RELEASE_xxx macros (or additions made in later versions). - - - $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/target-os-src/hal.h.tpp#1 $ - - Copyright (c) 1999-2015 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. -*/ - -#ifndef XTENSA_HAL_H -#define XTENSA_HAL_H - - -/**************************************************************************** - Definitions Useful for Any Code, USER or PRIVILEGED - ****************************************************************************/ - - -/*---------------------------------------------------------------------- - Constant Definitions (shared with assembly) - ----------------------------------------------------------------------*/ - -/* - * Software (Xtensa Tools) version information. Not configuration-specific! - * - * NOTE: "release" is a misnomer here, these are really product "version" - * numbers. A "release" is a collection of product versions - * made available at once (together) to customers. - * In the past, release and version names all matched in T####.# form, - * making the distinction irrelevant. This is no longer the case. - */ -#define XTHAL_RELEASE_MAJOR 12000 -#define XTHAL_RELEASE_MINOR 8 -#define XTHAL_RELEASE_NAME "12.0.8" -#define XTHAL_REL_12 1 -#define XTHAL_REL_12_0 1 -#define XTHAL_REL_12_0_8 1 - -/* HAL version numbers (these names are for backward compatibility): */ -#define XTHAL_MAJOR_REV XTHAL_RELEASE_MAJOR -#define XTHAL_MINOR_REV XTHAL_RELEASE_MINOR -/* - * A bit of software release/version history on values of XTHAL_{MAJOR,MINOR}_REV: - * - * SW Version MAJOR MINOR Comment - * ======= ===== ===== ======= - * T1015.n n/a n/a (HAL not yet available) - * T1020.{0,1,2} 0 1 (HAL beta) - * T1020.{3,4} 0 2 First release. - * T1020.n (n>4) 0 2 or >3 (TBD) - * T1030.0 0 1 (HAL beta) - * T1030.{1,2} 0 3 Equivalent to first release. - * T1030.n (n>=3) 0 >= 3 (TBD) - * T1040.n 1040 n Full CHAL available from T1040.2 - * T1050.n 1050 n . - * 6.0.n 6000 n Xtensa Tools v6 (RA-200x.n) - * 7.0.n 7000 n Xtensa Tools v7 (RB-200x.n) - * 7.1.n 7010 n Xtensa Tools v7.1 (RB-200x.(n+2)) - * 8.0.n 8000 n Xtensa Tools v8 (RC-20xx.n) - * 9.0.n 9000 n Xtensa Tools v9 (RD-201x.n) - * 10.0.n 10000 n Xtensa Tools v10 (RE-201x.n) - * - * - * Note: there is a distinction between the software version with - * which something is compiled (accessible using XTHAL_RELEASE_* macros) - * and the software version with which the HAL library was compiled - * (accessible using Xthal_release_* global variables). This - * distinction is particularly relevant for vendors that distribute - * configuration-independent binaries (eg. an OS), where their customer - * might link it with a HAL of a different Xtensa software version. - * In this case, it may be appropriate for the OS to verify at run-time - * whether XTHAL_RELEASE_* and Xthal_release_* are compatible. - * [Guidelines as to which version is compatible with which are not - * currently provided explicitly, but might be inferred from reading - * OSKit documentation for all releases -- compatibility is also highly - * dependent on which HAL features are used. Each version is usually - * backward compatible, with very few exceptions if any.] - */ - -/* Version comparison operators (among major/minor pairs): */ -#define XTHAL_REL_GE(maja,mina, majb,minb) ((maja) > (majb) || \ - ((maja) == (majb) && (mina) >= (minb))) -#define XTHAL_REL_GT(maja,mina, majb,minb) ((maja) > (majb) || \ - ((maja) == (majb) && (mina) > (minb))) -#define XTHAL_REL_LE(maja,mina, majb,minb) ((maja) < (majb) || \ - ((maja) == (majb) && (mina) <= (minb))) -#define XTHAL_REL_LT(maja,mina, majb,minb) ((maja) < (majb) || \ - ((maja) == (majb) && (mina) < (minb))) -#define XTHAL_REL_EQ(maja,mina, majb,minb) ((maja) == (majb) && (mina) == (minb)) - -/* Fuzzy (3-way) logic operators: */ -#define XTHAL_MAYBE -1 /* 0=NO, 1=YES, -1=MAYBE */ -#define XTHAL_FUZZY_AND(a,b) (((a)==0 || (b)==0) ? 0 : ((a)==1 && (b)==1) ? 1 : XTHAL_MAYBE) -#define XTHAL_FUZZY_OR(a,b) (((a)==1 || (b)==1) ? 1 : ((a)==0 && (b)==0) ? 0 : XTHAL_MAYBE) -#define XTHAL_FUZZY_NOT(a) (((a)==0 || (a)==1) ? (1-(a)) : XTHAL_MAYBE) - - -/* - * Architectural limit, independent of configuration: - */ -#define XTHAL_MAX_CPS 8 /* max number of coprocessors (0..7) */ - -/* Misc: */ -#define XTHAL_LITTLEENDIAN 0 -#define XTHAL_BIGENDIAN 1 - - - -#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__) -#ifdef __cplusplus -extern "C" { -#endif - -/*---------------------------------------------------------------------- - HAL - ----------------------------------------------------------------------*/ - -/* Constant to be checked in build = (XTHAL_MAJOR_REV<<16)|XTHAL_MINOR_REV */ -extern const unsigned int Xthal_rev_no; - - -/*---------------------------------------------------------------------- - Optional/Custom Processor State - ----------------------------------------------------------------------*/ - -/* save & restore the extra processor state */ -extern void xthal_save_extra(void *base); -extern void xthal_restore_extra(void *base); - -extern void xthal_save_cpregs(void *base, int); -extern void xthal_restore_cpregs(void *base, int); -/* versions specific to each coprocessor id */ -extern void xthal_save_cp0(void *base); -extern void xthal_save_cp1(void *base); -extern void xthal_save_cp2(void *base); -extern void xthal_save_cp3(void *base); -extern void xthal_save_cp4(void *base); -extern void xthal_save_cp5(void *base); -extern void xthal_save_cp6(void *base); -extern void xthal_save_cp7(void *base); -extern void xthal_restore_cp0(void *base); -extern void xthal_restore_cp1(void *base); -extern void xthal_restore_cp2(void *base); -extern void xthal_restore_cp3(void *base); -extern void xthal_restore_cp4(void *base); -extern void xthal_restore_cp5(void *base); -extern void xthal_restore_cp6(void *base); -extern void xthal_restore_cp7(void *base); -/* pointers to each of the functions above */ -extern void* Xthal_cpregs_save_fn[XTHAL_MAX_CPS]; -extern void* Xthal_cpregs_restore_fn[XTHAL_MAX_CPS]; -/* similarly for non-windowed ABI (may be same or different) */ -extern void* Xthal_cpregs_save_nw_fn[XTHAL_MAX_CPS]; -extern void* Xthal_cpregs_restore_nw_fn[XTHAL_MAX_CPS]; - -/*extern void xthal_save_all_extra(void *base);*/ -/*extern void xthal_restore_all_extra(void *base);*/ - -/* space for processor state */ -extern const unsigned int Xthal_extra_size; -extern const unsigned int Xthal_extra_align; -extern const unsigned int Xthal_cpregs_size[XTHAL_MAX_CPS]; -extern const unsigned int Xthal_cpregs_align[XTHAL_MAX_CPS]; -extern const unsigned int Xthal_all_extra_size; -extern const unsigned int Xthal_all_extra_align; -/* coprocessor names */ -extern const char * const Xthal_cp_names[XTHAL_MAX_CPS]; - -/* initialize the extra processor */ -/*extern void xthal_init_extra(void);*/ -/* initialize the TIE coprocessor */ -/*extern void xthal_init_cp(int);*/ - -/* initialize the extra processor */ -extern void xthal_init_mem_extra(void *); -/* initialize the TIE coprocessor */ -extern void xthal_init_mem_cp(void *, int); - -/* the number of TIE coprocessors contiguous from zero (for Tor2) */ -extern const unsigned int Xthal_num_coprocessors; - -/* actual number of coprocessors */ -extern const unsigned char Xthal_cp_num; -/* index of highest numbered coprocessor, plus one */ -extern const unsigned char Xthal_cp_max; -/* index of highest allowed coprocessor number, per cfg, plus one */ -/*extern const unsigned char Xthal_cp_maxcfg;*/ -/* bitmask of which coprocessors are present */ -extern const unsigned int Xthal_cp_mask; - -/* read & write extra state register */ -/*extern int xthal_read_extra(void *base, unsigned reg, unsigned *value);*/ -/*extern int xthal_write_extra(void *base, unsigned reg, unsigned value);*/ - -/* read & write a TIE coprocessor register */ -/*extern int xthal_read_cpreg(void *base, int cp, unsigned reg, unsigned *value);*/ -/*extern int xthal_write_cpreg(void *base, int cp, unsigned reg, unsigned value);*/ - -/* return coprocessor number based on register */ -/*extern int xthal_which_cp(unsigned reg);*/ - - -/*---------------------------------------------------------------------- - Register Windows - ----------------------------------------------------------------------*/ - -/* number of registers in register window */ -extern const unsigned int Xthal_num_aregs; -extern const unsigned char Xthal_num_aregs_log2; - - -/*---------------------------------------------------------------------- - Cache - ----------------------------------------------------------------------*/ - -/* size of the cache lines in log2(bytes) */ -extern const unsigned char Xthal_icache_linewidth; -extern const unsigned char Xthal_dcache_linewidth; -/* size of the cache lines in bytes (2^linewidth) */ -extern const unsigned short Xthal_icache_linesize; -extern const unsigned short Xthal_dcache_linesize; - -/* size of the caches in bytes (ways * 2^(linewidth + setwidth)) */ -extern const unsigned int Xthal_icache_size; -extern const unsigned int Xthal_dcache_size; -/* cache features */ -extern const unsigned char Xthal_dcache_is_writeback; - -/* cache region operations*/ -extern void xthal_icache_region_invalidate( void *addr, unsigned size ); -extern void xthal_dcache_region_invalidate( void *addr, unsigned size ); -extern void xthal_dcache_region_writeback( void *addr, unsigned size ); -extern void xthal_dcache_region_writeback_inv( void *addr, unsigned size ); - -#ifndef XTHAL_USE_CACHE_MACROS -/* cache line operations*/ -extern void xthal_icache_line_invalidate(void *addr); -extern void xthal_dcache_line_invalidate(void *addr); -extern void xthal_dcache_line_writeback(void *addr); -extern void xthal_dcache_line_writeback_inv(void *addr); -/* sync icache and memory */ -extern void xthal_icache_sync( void ); -/* sync dcache and memory */ -extern void xthal_dcache_sync( void ); -#endif - -/* get/set number of icache ways enabled */ -extern unsigned int xthal_icache_get_ways(void); -extern void xthal_icache_set_ways(unsigned int ways); -/* get/set number of dcache ways enabled */ -extern unsigned int xthal_dcache_get_ways(void); -extern void xthal_dcache_set_ways(unsigned int ways); - -/* coherency (low-level -- not normally called directly) */ -extern void xthal_cache_coherence_on( void ); -extern void xthal_cache_coherence_off( void ); -/* coherency (high-level) */ -extern void xthal_cache_coherence_optin( void ); -extern void xthal_cache_coherence_optout( void ); - -/* - * Cache prefetch control. - * The parameter to xthal_set_cache_prefetch() contains both - * a PREFCTL register value and a mask of which bits to actually modify. - * This allows easily combining field macros (below) by ORing, - * leaving unspecified fields unmodified. - * - * For backward compatibility with the older version of this routine - * (that took 15-bit value and mask in a 32-bit parameter, for pre-RF - * cores with only the lower 15 bits of PREFCTL defined), the 32-bit - * value and mask are staggered as follows in a 64-bit parameter: - * param[63:48] are PREFCTL[31:16] if param[31] is set - * param[47:32] are mask[31:16] if param[31] is set - * param[31] is set if mask is used, 0 if not - * param[31:16] are mask[15:0] if param[31] is set - * param[31:16] are PREFCTL[31:16] if param[31] is clear - * param[15:0] are PREFCTL[15:0] - * - * Limitation: PREFCTL register bit 31 cannot be set without masking, - * and bit 15 must always be set when using masking, so it is hoped that - * these two bits will remain reserved, read-as-zero in PREFCTL. - */ -#define XTHAL_PREFETCH_ENABLE -1 /* enable inst+data prefetch */ -#define XTHAL_PREFETCH_DISABLE 0xFFFF0000 /* disab inst+data prefetch*/ -#define XTHAL_DCACHE_PREFETCH(n) (0x800F0000+((n)&0xF)) /* data-side */ -#define XTHAL_DCACHE_PREFETCH_OFF XTHAL_DCACHE_PREFETCH(0) /* disable */ -#define XTHAL_DCACHE_PREFETCH_LOW XTHAL_DCACHE_PREFETCH(4) /* less aggr.*/ -#define XTHAL_DCACHE_PREFETCH_MEDIUM XTHAL_DCACHE_PREFETCH(5) /* mid aggr. */ -#define XTHAL_DCACHE_PREFETCH_HIGH XTHAL_DCACHE_PREFETCH(8) /* more aggr.*/ -#define XTHAL_DCACHE_PREFETCH_L1_OFF 0x90000000 /* to prefetch buffers*/ -#define XTHAL_DCACHE_PREFETCH_L1 0x90001000 /* direct to L1 dcache*/ -#define XTHAL_ICACHE_PREFETCH(n) (0x80F00000+(((n)&0xF)<<4)) /* i-side */ -#define XTHAL_ICACHE_PREFETCH_OFF XTHAL_ICACHE_PREFETCH(0) /* disable */ -#define XTHAL_ICACHE_PREFETCH_LOW XTHAL_ICACHE_PREFETCH(4) /* less aggr.*/ -#define XTHAL_ICACHE_PREFETCH_MEDIUM XTHAL_ICACHE_PREFETCH(5) /* mid aggr. */ -#define XTHAL_ICACHE_PREFETCH_HIGH XTHAL_ICACHE_PREFETCH(8) /* more aggr.*/ -#define XTHAL_ICACHE_PREFETCH_L1_OFF 0xA0000000 /* (not implemented) */ -#define XTHAL_ICACHE_PREFETCH_L1 0xA0002000 /* (not implemented) */ -#define _XTHAL_PREFETCH_BLOCKS(n) ((n)<0?0:(n)<5?(n):(n)<15?((n)>>1)+2:9) -#define XTHAL_PREFETCH_BLOCKS(n) (0x0000000F80000000ULL + \ - (((unsigned long long)_XTHAL_PREFETCH_BLOCKS(n))<<48)) - -extern int xthal_get_cache_prefetch( void ); -extern int xthal_set_cache_prefetch( int ); -extern int xthal_set_cache_prefetch_long( unsigned long long ); -/* Only use the new extended function from now on: */ -#define xthal_set_cache_prefetch xthal_set_cache_prefetch_long -#define xthal_set_cache_prefetch_nw xthal_set_cache_prefetch_long_nw - - -/*---------------------------------------------------------------------- - Debug - ----------------------------------------------------------------------*/ - -/* 1 if debug option configured, 0 if not: */ -extern const int Xthal_debug_configured; - -/* Set (plant) and remove software breakpoint, both synchronizing cache: */ -extern unsigned int xthal_set_soft_break(void *addr); -extern void xthal_remove_soft_break(void *addr, unsigned int); - - -/*---------------------------------------------------------------------- - Disassembler - ----------------------------------------------------------------------*/ - -/* Max expected size of the return buffer for a disassembled instruction (hint only): */ -#define XTHAL_DISASM_BUFSIZE 80 - -/* Disassembly option bits for selecting what to return: */ -#define XTHAL_DISASM_OPT_ADDR 0x0001 /* display address */ -#define XTHAL_DISASM_OPT_OPHEX 0x0002 /* display opcode bytes in hex */ -#define XTHAL_DISASM_OPT_OPCODE 0x0004 /* display opcode name (mnemonic) */ -#define XTHAL_DISASM_OPT_PARMS 0x0008 /* display parameters */ -#define XTHAL_DISASM_OPT_ALL 0x0FFF /* display everything */ - -/* routine to get a string for the disassembled instruction */ -extern int xthal_disassemble( unsigned char *instr_buf, void *tgt_addr, - char *buffer, unsigned buflen, unsigned options ); - -/* routine to get the size of the next instruction. Returns 0 for - illegal instruction */ -extern int xthal_disassemble_size( unsigned char *instr_buf ); - - -/*---------------------------------------------------------------------- - Instruction/Data RAM/ROM Access - ----------------------------------------------------------------------*/ - -extern void* xthal_memcpy(void *dst, const void *src, unsigned len); -extern void* xthal_bcopy(const void *src, void *dst, unsigned len); - - -/*---------------------------------------------------------------------- - MP Synchronization - ----------------------------------------------------------------------*/ - -extern int xthal_compare_and_set( int *addr, int test_val, int compare_val ); - -/*extern const char Xthal_have_s32c1i;*/ - - -/*---------------------------------------------------------------------- - Miscellaneous - ----------------------------------------------------------------------*/ - -extern const unsigned int Xthal_release_major; -extern const unsigned int Xthal_release_minor; -extern const char * const Xthal_release_name; -extern const char * const Xthal_release_internal; - -extern const unsigned char Xthal_memory_order; -extern const unsigned char Xthal_have_windowed; -extern const unsigned char Xthal_have_density; -extern const unsigned char Xthal_have_booleans; -extern const unsigned char Xthal_have_loops; -extern const unsigned char Xthal_have_nsa; -extern const unsigned char Xthal_have_minmax; -extern const unsigned char Xthal_have_sext; -extern const unsigned char Xthal_have_clamps; -extern const unsigned char Xthal_have_mac16; -extern const unsigned char Xthal_have_mul16; -extern const unsigned char Xthal_have_fp; -extern const unsigned char Xthal_have_speculation; -extern const unsigned char Xthal_have_threadptr; - -extern const unsigned char Xthal_have_pif; -extern const unsigned short Xthal_num_writebuffer_entries; - -extern const unsigned int Xthal_build_unique_id; -/* Version info for hardware targeted by software upgrades: */ -extern const unsigned int Xthal_hw_configid0; -extern const unsigned int Xthal_hw_configid1; -extern const unsigned int Xthal_hw_release_major; -extern const unsigned int Xthal_hw_release_minor; -extern const char * const Xthal_hw_release_name; -extern const char * const Xthal_hw_release_internal; - -/* Clear any remnant code-dependent state (i.e. clear loop count regs). */ -extern void xthal_clear_regcached_code( void ); - -#ifdef __cplusplus -} -#endif -#endif /*!_ASMLANGUAGE && !_NOCLANGUAGE && !__ASSEMBLER__ */ - - - - - -/**************************************************************************** - Definitions Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code - ****************************************************************************/ - - -#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY - -/*---------------------------------------------------------------------- - Constant Definitions (shared with assembly) - ----------------------------------------------------------------------*/ - -/* - * Architectural limits, independent of configuration. - * Note that these are ISA-defined limits, not micro-architecture implementation - * limits enforced by the Xtensa Processor Generator (which may be stricter than - * these below). - */ -#define XTHAL_MAX_INTERRUPTS 32 /* max number of interrupts (0..31) */ -#define XTHAL_MAX_INTLEVELS 16 /* max number of interrupt levels (0..15) */ - /* (as of T1040, implementation limit is 7: 0..6) */ -#define XTHAL_MAX_TIMERS 4 /* max number of timers (CCOMPARE0..CCOMPARE3) */ - /* (as of T1040, implementation limit is 3: 0..2) */ - -/* Interrupt types: */ -#define XTHAL_INTTYPE_UNCONFIGURED 0 -#define XTHAL_INTTYPE_SOFTWARE 1 -#define XTHAL_INTTYPE_EXTERN_EDGE 2 -#define XTHAL_INTTYPE_EXTERN_LEVEL 3 -#define XTHAL_INTTYPE_TIMER 4 -#define XTHAL_INTTYPE_NMI 5 -#define XTHAL_INTTYPE_WRITE_ERROR 6 -#define XTHAL_INTTYPE_PROFILING 7 -#define XTHAL_INTTYPE_IDMA_DONE 8 -#define XTHAL_INTTYPE_IDMA_ERR 9 -#define XTHAL_INTTYPE_GS_ERR 10 -#define XTHAL_INTTYPE_SG_ERR 10 /* backward compatibility name - deprecated */ -#define XTHAL_MAX_INTTYPES 11 /* number of interrupt types */ - -/* Timer related: */ -#define XTHAL_TIMER_UNCONFIGURED -1 /* Xthal_timer_interrupt[] value for non-existent timers */ -#define XTHAL_TIMER_UNASSIGNED XTHAL_TIMER_UNCONFIGURED /* (for backwards compatibility only) */ - -/* Local Memory ECC/Parity: */ -#define XTHAL_MEMEP_PARITY 1 -#define XTHAL_MEMEP_ECC 2 -/* Flags parameter to xthal_memep_inject_error(): */ -#define XTHAL_MEMEP_F_LOCAL 0 /* local memory (default) */ -#define XTHAL_MEMEP_F_DCACHE_DATA 4 /* data cache data */ -#define XTHAL_MEMEP_F_DCACHE_TAG 5 /* data cache tag */ -#define XTHAL_MEMEP_F_ICACHE_DATA 6 /* instruction cache data */ -#define XTHAL_MEMEP_F_ICACHE_TAG 7 /* instruction cache tag */ -#define XTHAL_MEMEP_F_CORRECTABLE 16 /* inject correctable error - (default is non-corr.) */ - - -/* Access Mode bits (tentative): */ /* bit abbr unit short_name PPC equ - Description */ -#define XTHAL_AMB_EXCEPTION 0 /* 001 E EX fls: EXception none - exception on any access (aka "illegal") */ -#define XTHAL_AMB_HITCACHE 1 /* 002 C CH fls: use Cache on Hit ~(I CI) - [or H HC] way from tag match; - [or U UC] (ISA: same except Isolate case) */ -#define XTHAL_AMB_ALLOCATE 2 /* 004 A AL fl?: ALlocate none - [or F FI fill] refill cache on miss, way from LRU - (ISA: Read/Write Miss Refill) */ -#define XTHAL_AMB_WRITETHRU 3 /* 008 W WT --s: WriteThrough W WT - store immediately to memory (ISA: same) */ -#define XTHAL_AMB_ISOLATE 4 /* 010 I IS fls: ISolate none - use cache regardless of hit-vs-miss, - way from vaddr (ISA: use-cache-on-miss+hit) */ -#define XTHAL_AMB_GUARD 5 /* 020 G GU ?l?: GUard G * - non-speculative; spec/replay refs not permitted */ -#define XTHAL_AMB_COHERENT 6 /* 040 M MC ?ls: Mem/MP Coherent M - on read, other CPU/bus-master may need to supply data; - on write, maybe redirect to or flush other CPU dirty line; etc */ -#if 0 -#define XTHAL_AMB_BUFFERABLE x /* 000 B BU --s: BUfferable ? - write response may return earlier than from final destination */ -#define XTHAL_AMB_ORDERED x /* 000 O OR fls: ORdered G * - mem accesses cannot be out of order */ -#define XTHAL_AMB_FUSEWRITES x /* 000 F FW --s: FuseWrites none - allow combining/merging/coalescing multiple writes - (to same datapath data unit) into one - (implied by writeback) */ -#define XTHAL_AMB_TRUSTED x /* 000 T TR ?l?: TRusted none - memory will not bus error (if it does, - handle as fatal imprecise interrupt) */ -#define XTHAL_AMB_PREFETCH x /* 000 P PR fl?: PRefetch none - on refill, read line+1 into prefetch buffers */ -#define XTHAL_AMB_STREAM x /* 000 S ST ???: STreaming none - access one of N stream buffers */ -#endif /*0*/ - -#define XTHAL_AM_EXCEPTION (1<<XTHAL_AMB_EXCEPTION) -#define XTHAL_AM_HITCACHE (1<<XTHAL_AMB_HITCACHE) -#define XTHAL_AM_ALLOCATE (1<<XTHAL_AMB_ALLOCATE) -#define XTHAL_AM_WRITETHRU (1<<XTHAL_AMB_WRITETHRU) -#define XTHAL_AM_ISOLATE (1<<XTHAL_AMB_ISOLATE) -#define XTHAL_AM_GUARD (1<<XTHAL_AMB_GUARD) -#define XTHAL_AM_COHERENT (1<<XTHAL_AMB_COHERENT) -#if 0 -#define XTHAL_AM_BUFFERABLE (1<<XTHAL_AMB_BUFFERABLE) -#define XTHAL_AM_ORDERED (1<<XTHAL_AMB_ORDERED) -#define XTHAL_AM_FUSEWRITES (1<<XTHAL_AMB_FUSEWRITES) -#define XTHAL_AM_TRUSTED (1<<XTHAL_AMB_TRUSTED) -#define XTHAL_AM_PREFETCH (1<<XTHAL_AMB_PREFETCH) -#define XTHAL_AM_STREAM (1<<XTHAL_AMB_STREAM) -#endif /*0*/ - -/* - * Allowed Access Modes (bit combinations). - * - * Columns are: - * "FOGIWACE" - * Access mode bits (see XTHAL_AMB_xxx above). - * <letter> = bit is set - * '-' = bit is clear - * '.' = bit is irrelevant / don't care, as follows: - * E=1 makes all others irrelevant - * W,F relevant only for stores - * "2345" - * Indicates which Xtensa releases support the corresponding - * access mode. Releases for each character column are: - * 2 = prior to T1020.2: T1015 (V1.5), T1020.0, T1020.1 - * 3 = T1020.2 and later: T1020.2+, T1030 - * 4 = T1040 - * 5 = T1050 (maybe), LX1, LX2, LX2.1 - * 7 = LX2.2 - * 8 = LX3, LX4 - * 9 = LX5 - * And the character column contents are: - * <number> = supported by release(s) - * "." = unsupported by release(s) - * "?" = support unknown - */ - /* foMGIWACE 2345789 */ -/* For instruction fetch: */ -#define XTHAL_FAM_EXCEPTION 0x001 /* ........E 2345789 exception */ -/*efine XTHAL_FAM_ISOLATE*/ /*0x012*/ /* .---I.-C- ....... isolate */ -#define XTHAL_FAM_BYPASS 0x000 /* .----.--- 2345789 bypass */ -/*efine XTHAL_FAM_NACACHED*/ /*0x002*/ /* .----.-C- ....... cached no-allocate (frozen) */ -#define XTHAL_FAM_CACHED 0x006 /* .----.AC- 2345789 cached */ -/* For data load: */ -#define XTHAL_LAM_EXCEPTION 0x001 /* ........E 2345789 exception */ -#define XTHAL_LAM_ISOLATE 0x012 /* .---I.-C- 2345789 isolate */ -#define XTHAL_LAM_BYPASS 0x000 /* .O---.--- 2...... bypass speculative */ -#define XTHAL_LAM_BYPASSG 0x020 /* .O-G-.--- .345789 bypass guarded */ -#define XTHAL_LAM_CACHED_NOALLOC 0x002 /* .O---.-C- 2345789 cached no-allocate speculative */ -#define XTHAL_LAM_NACACHED XTHAL_LAM_CACHED_NOALLOC -#define XTHAL_LAM_NACACHEDG 0x022 /* .O-G-.-C- .?..... cached no-allocate guarded */ -#define XTHAL_LAM_CACHED 0x006 /* .----.AC- 2345789 cached speculative */ -#define XTHAL_LAM_COHCACHED 0x046 /* .-M--.AC- ....*89 cached speculative MP-coherent */ -/* For data store: */ -#define XTHAL_SAM_EXCEPTION 0x001 /* ........E 2345789 exception */ -#define XTHAL_SAM_ISOLATE 0x032 /* .--GI--C- 2345789 isolate */ -#define XTHAL_SAM_BYPASS 0x028 /* -O-G-W--- 2345789 bypass */ -#define XTHAL_SAM_WRITETHRU 0x02A /* -O-G-W-C- 2345789 writethrough */ -/*efine XTHAL_SAM_WRITETHRU_ALLOC*/ /*0x02E*/ /* -O-G-WAC- ....... writethrough allocate */ -#define XTHAL_SAM_WRITEBACK 0x026 /* F--G--AC- ...5789 writeback */ -#define XTHAL_SAM_WRITEBACK_NOALLOC 0x022 /* ?--G---C- .....89 writeback no-allocate */ -#define XTHAL_SAM_COHWRITEBACK 0x066 /* F-MG--AC- ....*89 writeback MP-coherent */ -/* For PIF attributes: */ /* -PIwrWCBUUUU ...9 */ -#define XTHAL_PAM_BYPASS 0x000 /* xxx00000xxxx ...9 bypass non-bufferable */ -#define XTHAL_PAM_BYPASS_BUF 0x010 /* xxx0000bxxxx ...9 bypass */ -#define XTHAL_PAM_CACHED_NOALLOC 0x030 /* xxx0001bxxxx ...9 cached no-allocate */ -#define XTHAL_PAM_WRITETHRU 0x0B0 /* xxx0101bxxxx ...9 writethrough (WT) */ -#define XTHAL_PAM_WRITEBACK_NOALLOC 0x0F0 /* xxx0111bxxxx ...9 writeback no-alloc (WBNA) */ -#define XTHAL_PAM_WRITEBACK 0x1F0 /* xxx1111bxxxx ...9 writeback (WB) */ -/*efine XTHAL_PAM_NORMAL*/ /*0x050*/ /* xxx0010bxxxx .... (unimplemented) */ -/*efine XTHAL_PAM_WRITETHRU_WA*/ /*0x130*/ /* xxx1001bxxxx .... (unimplemented, less likely) */ -/*efine XTHAL_PAM_WRITETHRU_RWA*/ /*0x1B0*/ /* xxx1101bxxxx .... (unimplemented, less likely) */ -/*efine XTHAL_PAM_WRITEBACK_WA*/ /*0x170*/ /* xxx1011bxxxx .... (unimplemented, less likely) */ - - -#if 0 -/* - Cache attribute encoding for CACHEATTR (per ISA): - (Note: if this differs from ISA Ref Manual, ISA has precedence) - - Inst-fetches Loads Stores - ------------- ------------ ------------- -0x0 FCA_EXCEPTION LCA_NACACHED SCA_WRITETHRU cached no-allocate (previously misnamed "uncached") -0x1 FCA_CACHED LCA_CACHED SCA_WRITETHRU cached -0x2 FCA_BYPASS LCA_BYPASS_G* SCA_BYPASS bypass cache (what most people call uncached) -0x3 FCA_CACHED LCA_CACHED SCA_WRITEALLOCF write-allocate - or LCA_EXCEPTION SCA_EXCEPTION (if unimplemented) -0x4 FCA_CACHED LCA_CACHED SCA_WRITEBACK[M] write-back [MP-coherent] - or LCA_EXCEPTION SCA_EXCEPTION (if unimplemented) -0x5 FCA_CACHED LCA_CACHED SCA_WRITEBACK_NOALLOC write-back no-allocate - or FCA_EXCEPTION LCA_EXCEPTION SCA_EXCEPTION (if unimplemented) -0x6..D FCA_EXCEPTION LCA_EXCEPTION SCA_EXCEPTION (reserved) -0xE FCA_EXCEPTION LCA_ISOLATE SCA_ISOLATE isolate -0xF FCA_EXCEPTION LCA_EXCEPTION SCA_EXCEPTION illegal - * Prior to T1020.2?, guard feature not supported, this defaulted to speculative (no _G) -*/ -#endif /*0*/ - - -#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__) -#ifdef __cplusplus -extern "C" { -#endif - - -/*---------------------------------------------------------------------- - Register Windows - ----------------------------------------------------------------------*/ - -/* This spill any live register windows (other than the caller's): - * (NOTE: current implementation require privileged code, but - * a user-callable implementation is possible.) */ -extern void xthal_window_spill( void ); - - -/*---------------------------------------------------------------------- - Optional/Custom Processor State - ----------------------------------------------------------------------*/ - -/* validate & invalidate the TIE register file */ -extern void xthal_validate_cp(int); -extern void xthal_invalidate_cp(int); - -/* read and write cpenable register */ -extern void xthal_set_cpenable(unsigned); -extern unsigned xthal_get_cpenable(void); - - -/*---------------------------------------------------------------------- - Interrupts - ----------------------------------------------------------------------*/ - -/* the number of interrupt levels */ -extern const unsigned char Xthal_num_intlevels; -/* the number of interrupts */ -extern const unsigned char Xthal_num_interrupts; -/* the highest level of interrupts masked by PS.EXCM */ -extern const unsigned char Xthal_excm_level; - -/* mask for level of interrupts */ -extern const unsigned int Xthal_intlevel_mask[XTHAL_MAX_INTLEVELS]; -/* mask for level 0 to N interrupts */ -extern const unsigned int Xthal_intlevel_andbelow_mask[XTHAL_MAX_INTLEVELS]; - -/* level of each interrupt */ -extern const unsigned char Xthal_intlevel[XTHAL_MAX_INTERRUPTS]; - -/* type per interrupt */ -extern const unsigned char Xthal_inttype[XTHAL_MAX_INTERRUPTS]; - -/* masks of each type of interrupt */ -extern const unsigned int Xthal_inttype_mask[XTHAL_MAX_INTTYPES]; - -/* interrupt numbers assigned to each timer interrupt */ -extern const int Xthal_timer_interrupt[XTHAL_MAX_TIMERS]; - -/* INTENABLE,INTERRUPT,INTSET,INTCLEAR register access functions: */ -extern unsigned xthal_get_intenable( void ); -extern void xthal_set_intenable( unsigned ); -extern unsigned xthal_get_interrupt( void ); -#define xthal_get_intread xthal_get_interrupt /* backward compatibility */ - -/* These two functions are deprecated. Use the newer functions - xthal_interrupt_trigger and xthal_interrupt_clear instead. */ -extern void xthal_set_intset( unsigned ); -extern void xthal_set_intclear( unsigned ); - - -/*---------------------------------------------------------------------- - Debug - ----------------------------------------------------------------------*/ - -/* Number of instruction and data break registers: */ -extern const int Xthal_num_ibreak; -extern const int Xthal_num_dbreak; - - -/*---------------------------------------------------------------------- - Core Counter - ----------------------------------------------------------------------*/ - -/* counter info */ -extern const unsigned char Xthal_have_ccount; /* set if CCOUNT register present */ -extern const unsigned char Xthal_num_ccompare; /* number of CCOMPAREn registers */ - -/* get CCOUNT register (if not present return 0) */ -extern unsigned xthal_get_ccount(void); - -/* set and get CCOMPAREn registers (if not present, get returns 0) */ -extern void xthal_set_ccompare(int, unsigned); -extern unsigned xthal_get_ccompare(int); - - -/*---------------------------------------------------------------------- - Miscellaneous - ----------------------------------------------------------------------*/ - -extern const unsigned char Xthal_have_prid; -extern const unsigned char Xthal_have_exceptions; -extern const unsigned char Xthal_xea_version; -extern const unsigned char Xthal_have_interrupts; -extern const unsigned char Xthal_have_highlevel_interrupts; -extern const unsigned char Xthal_have_nmi; - -extern unsigned xthal_get_prid( void ); - - -/*---------------------------------------------------------------------- - Virtual interrupt prioritization (DEPRECATED) - ----------------------------------------------------------------------*/ - -/* Convert between interrupt levels (as per PS.INTLEVEL) and virtual interrupt priorities: */ -extern unsigned xthal_vpri_to_intlevel(unsigned vpri); -extern unsigned xthal_intlevel_to_vpri(unsigned intlevel); - -/* Enables/disables given set (mask) of interrupts; returns previous enabled-mask of all ints: */ -/* These functions are deprecated. Use xthal_interrupt_enable and xthal_interrupt_disable instead. */ -extern unsigned xthal_int_enable(unsigned); -extern unsigned xthal_int_disable(unsigned); - -/* Set/get virtual priority of an interrupt: */ -extern int xthal_set_int_vpri(int intnum, int vpri); -extern int xthal_get_int_vpri(int intnum); - -/* Set/get interrupt lockout level for exclusive access to virtual priority data structures: */ -extern void xthal_set_vpri_locklevel(unsigned intlevel); -extern unsigned xthal_get_vpri_locklevel(void); - -/* Set/get current virtual interrupt priority: */ -extern unsigned xthal_set_vpri(unsigned vpri); -extern unsigned xthal_get_vpri(void); -extern unsigned xthal_set_vpri_intlevel(unsigned intlevel); -extern unsigned xthal_set_vpri_lock(void); - - -/*---------------------------------------------------------------------- - Generic Interrupt Trampolining Support (DEPRECATED) - ----------------------------------------------------------------------*/ - -typedef void (XtHalVoidFunc)(void); - -/* Bitmask of interrupts currently trampolining down: */ -extern unsigned Xthal_tram_pending; - -/* - * Bitmask of which interrupts currently trampolining down synchronously are - * actually enabled; this bitmask is necessary because INTENABLE cannot hold - * that state (sync-trampolining interrupts must be kept disabled while - * trampolining); in the current implementation, any bit set here is not set - * in INTENABLE, and vice-versa; once a sync-trampoline is handled (at level - * one), its enable bit must be moved from here to INTENABLE: - */ -extern unsigned Xthal_tram_enabled; - -/* Bitmask of interrupts configured for sync trampolining: */ -extern unsigned Xthal_tram_sync; - -/* Trampoline support functions: */ -extern unsigned xthal_tram_pending_to_service( void ); -extern void xthal_tram_done( unsigned serviced_mask ); -extern int xthal_tram_set_sync( int intnum, int sync ); -extern XtHalVoidFunc* xthal_set_tram_trigger_func( XtHalVoidFunc *trigger_fn ); - - -/*---------------------------------------------------------------------- - Internal Memories - ----------------------------------------------------------------------*/ - -extern const unsigned char Xthal_num_instrom; -extern const unsigned char Xthal_num_instram; -extern const unsigned char Xthal_num_datarom; -extern const unsigned char Xthal_num_dataram; -extern const unsigned char Xthal_num_xlmi; - -/* Each of the following arrays contains at least one entry, - * or as many entries as needed if more than one: */ -extern const unsigned int Xthal_instrom_vaddr[]; -extern const unsigned int Xthal_instrom_paddr[]; -extern const unsigned int Xthal_instrom_size []; -extern const unsigned int Xthal_instram_vaddr[]; -extern const unsigned int Xthal_instram_paddr[]; -extern const unsigned int Xthal_instram_size []; -extern const unsigned int Xthal_datarom_vaddr[]; -extern const unsigned int Xthal_datarom_paddr[]; -extern const unsigned int Xthal_datarom_size []; -extern const unsigned int Xthal_dataram_vaddr[]; -extern const unsigned int Xthal_dataram_paddr[]; -extern const unsigned int Xthal_dataram_size []; -extern const unsigned int Xthal_xlmi_vaddr[]; -extern const unsigned int Xthal_xlmi_paddr[]; -extern const unsigned int Xthal_xlmi_size []; - - -/*---------------------------------------------------------------------- - Cache - ----------------------------------------------------------------------*/ - -/* number of cache sets in log2(lines per way) */ -extern const unsigned char Xthal_icache_setwidth; -extern const unsigned char Xthal_dcache_setwidth; -/* cache set associativity (number of ways) */ -extern const unsigned int Xthal_icache_ways; -extern const unsigned int Xthal_dcache_ways; -/* cache features */ -extern const unsigned char Xthal_icache_line_lockable; -extern const unsigned char Xthal_dcache_line_lockable; - -/* cache attribute register control (used by other HAL routines) */ -extern unsigned xthal_get_cacheattr( void ); -extern unsigned xthal_get_icacheattr( void ); -extern unsigned xthal_get_dcacheattr( void ); -extern void xthal_set_cacheattr( unsigned ); -extern void xthal_set_icacheattr( unsigned ); -extern void xthal_set_dcacheattr( unsigned ); -/* set cache attribute (access modes) for a range of memory */ -extern int xthal_set_region_attribute( void *addr, unsigned size, - unsigned cattr, unsigned flags ); -/* Bits of flags parameter to xthal_set_region_attribute(): */ -#define XTHAL_CAFLAG_EXPAND 0x000100 /* only expand allowed access to range, don't reduce it */ -#define XTHAL_CAFLAG_EXACT 0x000200 /* return error if can't apply change to exact range specified */ -#define XTHAL_CAFLAG_NO_PARTIAL 0x000400 /* don't apply change to regions partially covered by range */ -#define XTHAL_CAFLAG_NO_AUTO_WB 0x000800 /* don't writeback data after leaving writeback attribute */ -#define XTHAL_CAFLAG_NO_AUTO_INV 0x001000 /* don't invalidate after disabling cache (entering bypass) */ - -/* enable caches */ -extern void xthal_icache_enable( void ); /* DEPRECATED */ -extern void xthal_dcache_enable( void ); /* DEPRECATED */ -/* disable caches */ -extern void xthal_icache_disable( void ); /* DEPRECATED */ -extern void xthal_dcache_disable( void ); /* DEPRECATED */ - -/* whole cache operations (privileged) */ -extern void xthal_icache_all_invalidate( void ); -extern void xthal_dcache_all_invalidate( void ); -extern void xthal_dcache_all_writeback( void ); -extern void xthal_dcache_all_writeback_inv( void ); -extern void xthal_icache_all_unlock( void ); -extern void xthal_dcache_all_unlock( void ); - -/* address-range cache operations (privileged) */ -/* prefetch and lock specified memory range into cache */ -extern void xthal_icache_region_lock( void *addr, unsigned size ); -extern void xthal_dcache_region_lock( void *addr, unsigned size ); -/* unlock from cache */ -extern void xthal_icache_region_unlock( void *addr, unsigned size ); -extern void xthal_dcache_region_unlock( void *addr, unsigned size ); - -/* huge-range cache operations (privileged) (EXPERIMENTAL) */ -extern void xthal_icache_hugerange_invalidate( void *addr, unsigned size ); -extern void xthal_icache_hugerange_unlock( void *addr, unsigned size ); -extern void xthal_dcache_hugerange_invalidate( void *addr, unsigned size ); -extern void xthal_dcache_hugerange_unlock( void *addr, unsigned size ); -extern void xthal_dcache_hugerange_writeback( void *addr, unsigned size ); -extern void xthal_dcache_hugerange_writeback_inv( void *addr, unsigned size ); - -# ifndef XTHAL_USE_CACHE_MACROS -/* cache line operations (privileged) */ -extern void xthal_icache_line_lock(void *addr); -extern void xthal_dcache_line_lock(void *addr); -extern void xthal_icache_line_unlock(void *addr); -extern void xthal_dcache_line_unlock(void *addr); -# endif - - - -/*---------------------------------------------------------------------- - Local Memory ECC/Parity - ----------------------------------------------------------------------*/ - -/* Inject memory errors; flags is bit combination of XTHAL_MEMEP_F_xxx: */ -extern void xthal_memep_inject_error(void *addr, int size, int flags); - - - -/*---------------------------------------------------------------------- - Memory Management Unit - ----------------------------------------------------------------------*/ - -extern const unsigned char Xthal_have_spanning_way; -extern const unsigned char Xthal_have_identity_map; -extern const unsigned char Xthal_have_mimic_cacheattr; -extern const unsigned char Xthal_have_xlt_cacheattr; -extern const unsigned char Xthal_have_cacheattr; -extern const unsigned char Xthal_have_tlbs; - -extern const unsigned char Xthal_mmu_asid_bits; /* 0 .. 8 */ -extern const unsigned char Xthal_mmu_asid_kernel; -extern const unsigned char Xthal_mmu_rings; /* 1 .. 4 (perhaps 0 if no MMU and/or no protection?) */ -extern const unsigned char Xthal_mmu_ring_bits; -extern const unsigned char Xthal_mmu_sr_bits; -extern const unsigned char Xthal_mmu_ca_bits; -extern const unsigned int Xthal_mmu_max_pte_page_size; -extern const unsigned int Xthal_mmu_min_pte_page_size; - -extern const unsigned char Xthal_itlb_way_bits; -extern const unsigned char Xthal_itlb_ways; -extern const unsigned char Xthal_itlb_arf_ways; -extern const unsigned char Xthal_dtlb_way_bits; -extern const unsigned char Xthal_dtlb_ways; -extern const unsigned char Xthal_dtlb_arf_ways; - -/* Return error codes for hal functions */ - -/* function sucessful, operation completed as expected */ -#define XTHAL_SUCCESS 0 -/* XTHAL_CAFLAGS_NO_PARTIAL was specified, and no full region is - * covered by the address range. */ -#define XTHAL_NO_REGIONS_COVERED -1 -/* The XTHAL_CAFLAGS_EXACT flag was given, but no exact mapping is possible. */ -#define XTHAL_INEXACT -2 -/* The supplied address doesn't correspond to the start of a region. */ -#define XTHAL_INVALID_ADDRESS -3 -/* This functionality is not available on this architecture. */ -#define XTHAL_UNSUPPORTED -4 -/* Translation failed because vaddr and paddr were not aligned. */ -#define XTHAL_ADDRESS_MISALIGNED -5 -/* There is mapping for the supplied address. */ -#define XTHAL_NO_MAPPING -6 -/* The requested access rights are not supported */ -#define XTHAL_BAD_ACCESS_RIGHTS -7 -/* The requested memory type is not supported */ -#define XTHAL_BAD_MEMORY_TYPE -8 -/* The entries supplied are not properly aligned to the MPU's background map. */ -#define XTHAL_MAP_NOT_ALIGNED -9 -/* There are not enough MPU entries available to do the requeste mapping. */ -#define XTHAL_OUT_OF_ENTRIES -10 -/* The entries supplied are not properly ordered for the MPU. */ -#define XTHAL_OUT_OF_ORDER_MAP -11 -/* an invalid argument such as a null pointer was supplied to the function */ -#define XTHAL_INVALID -12 -/* specified region is of zero size, therefore no mapping is done. */ -#define XTHAL_ZERO_SIZED_REGION -13 -/* specified range wraps around '0' */ -#define XTHAL_INVALID_ADDRESS_RANGE -14 - -/* - For backward compatibility we retain the following inconsistenly named - constants. Do not use them as they may be removed in a future release. - */ -#define XCHAL_SUCCESS XTHAL_SUCCESS -#define XCHAL_ADDRESS_MISALIGNED XTHAL_ADDRESS_MISALIGNED -#define XCHAL_INEXACT XTHAL_INEXACT -#define XCHAL_INVALID_ADDRESS XTHAL_INVALID_ADDRESS -#define XCHAL_UNSUPPORTED_ON_THIS_ARCH XTHAL_UNSUPPORTED -#define XCHAL_NO_PAGES_MAPPED XTHAL_NO_REGIONS_COVERED - - -/* Convert between virtual and physical addresses (through static maps only) - * WARNING: these two functions may go away in a future release; - * don't depend on them! -*/ -extern int xthal_static_v2p( unsigned vaddr, unsigned *paddrp ); -extern int xthal_static_p2v( unsigned paddr, unsigned *vaddrp, unsigned cached ); - -extern int xthal_set_region_translation(void* vaddr, void* paddr, - unsigned size, unsigned cache_atr, unsigned flags); -extern int xthal_v2p(void*, void**, unsigned*, unsigned*); -extern int xthal_invalidate_region(void* addr); -extern int xthal_set_region_translation_raw(void *vaddr, void *paddr, unsigned cattr); - -/*------------------------------------------------------------------------ - MPU (Memory Protection Unit) --------------------------------------------------------------------------*/ - -/* - * General notes on MPU (Memory Protection Unit): - * - * The MPU supports setting the access rights (read, write, execute) as - * well as the memory type (cacheablity, ...) - * for regions of memory. The granularity can be as small as 32 bytes. - * (XCHAL_MPU_ALIGN specifies the granularity for any specific MPU config) - * - * The MPU doesn't support mapping between virtual and physical addresses. - * - * The MPU contains a fixed number of map changeable forground map entries, - * and a background map which is fixed at configuration time. - * - * Each entry has a start address (up to 27 bits), valid flag, - * access rights (4 bits), and memory type (9 bits); - * - */ - - -/* - MPU access rights constants: - Only the combinations listed below are supported by the MPU. -*/ - -#define XTHAL_AR_NONE 0 /* no access */ -#define XTHAL_AR_R 4 /* Kernel read, User no access*/ -#define XTHAL_AR_RX 5 /* Kernel read/execute, User no access */ -#define XTHAL_AR_RW 6 /* Kernel read/write, User no access */ -#define XTHAL_AR_RWX 7 /* Kernel read/write/execute, User no access */ -#define XTHAL_AR_Ww 8 /* Kernel write, User write */ -#define XTHAL_AR_RWrwx 9 /* Kernel read/write , User read/write/execute */ -#define XTHAL_AR_RWr 10 /* Kernel read/write, User read */ -#define XTHAL_AR_RWXrx 11 /* Kernel read/write/execute, User read/execute */ -#define XTHAL_AR_Rr 12 /* Kernel read, User read */ -#define XTHAL_AR_RXrx 13 /* Kernel read/execute, User read/execute */ -#define XTHAL_AR_RWrw 14 /* Kernel read/write, User read/write */ -#define XTHAL_AR_RWXrwx 15 /* Kernel read/write/execute, - User read/write/execute */ - -#define XTHAL_AR_WIDTH 4 /* # bits used to encode access rights */ - -/* If the bit XTHAL_MPU_USE_EXISTING_ACCESS_RIGHTS is set in the accessRights - * argument to xthal_mpu_set_region_attribute(), or to the cattr argument of - * xthal_set_region_attribute() then the existing access rights for the first - * byte of the region will be used as the access rights of the new region. - */ -#define XTHAL_MPU_USE_EXISTING_ACCESS_RIGHTS 0x00002000 - -/* If the bit XTHAL_MPU_USE_EXISTING_MEMORY_TYPE is set in the memoryType - * argument to xthal_mpu_set_region_attribute(), or to the cattr argument of - * xthal_set_region_attribute() then the existing memory type for the first - * byte of the region will be used as the memory type of the new region. - */ -#define XTHAL_MPU_USE_EXISTING_MEMORY_TYPE 0x00004000 - -/* The following groups of constants are bit-wise or'd together to specify - * the memory type as input to the macros and functions that accept an - * unencoded memory type specifier: - * XTHAL_ENCODE_MEMORY_TYPE, xthal_encode_memory_type, - * xthal_mpu_set_region_attribute(), and xthal_set_region_attribute(). - * - * example: - * XTHAL_MEM_DEVICE | XTHAL_MEM_INTERRUPTIBLE | XTHAL_MEM_SYSTEM_SHARABLE - * - * or - * XTHAL_MEM_WRITEBACK | XTHAL_MEM_INNER_SHAREABLE - * - * If it is desired to specify different attributes for the system and - * local cache, then macro XTHAL_MEM_PROC_CACHE is used: - * - * XTHAL_MEM_PROC_CACHE(XTHAL_MEM_WRITEBACK, XTHAL_MEM_WRITETHRU) - * - * indicates the shared cache is writeback, but the processor's local cache - * is writethrough. - * - */ - -/* The following group of constants are used to specify cache attributes of - * an MPU entry. If the processors local cache and the system's shared cache - * have the same attributes (or if there aren't distinct local and shared - * caches) then the constant can be used directly. If different attributes - * for the shared and local caches, then use these constants as the parameters - * to the XTHAL_MEM_PROC_CACHE() macro. - */ -#define XTHAL_MEM_DEVICE 0x00008000 -#define XTHAL_MEM_NON_CACHEABLE 0x00090000 -#define XTHAL_MEM_WRITETHRU_NOALLOC 0x00080000 -#define XTHAL_MEM_WRITETHRU 0x00040000 -#define XTHAL_MEM_WRITETHRU_WRITEALLOC 0x00060000 -#define XTHAL_MEM_WRITEBACK_NOALLOC 0x00050000 -#define XTHAL_MEM_WRITEBACK 0x00070000 - -/* Indicates a read is interruptible. Only applicable to devices */ -#define XTHAL_MEM_INTERRUPTIBLE 0x08000000 - -/* Indicates if writes to this memory are bufferable ... only applicable - * to devices, and non-cacheable memory. - */ -#define XTHAL_MEM_BUFFERABLE 0x01000000 - -/* The following group of constants indicates the scope of the sharing of - * the memory region. XTHAL_MEM_INNER_SHAREABLE and XTHAL_MEM_OUTER_SHARABLE are - * only applicable to cacheable regions. XTHAL_MEM_SYSTEM_SHAREABLE is only - * applicable to devices and non-cacheable regions. - */ -#define XTHAL_MEM_NON_SHAREABLE 0x00000000 -#define XTHAL_MEM_INNER_SHAREABLE 0x02000000 -#define XTHAL_MEM_OUTER_SHAREABLE 0x04000000 -#define XTHAL_MEM_SYSTEM_SHAREABLE 0x06000000 - - -/* - * This macro is needed when the cache attributes are different for the shared - * and processor's local caches. For example: - * - * XTHAL_MEM_PROC_CACHE(XTHAL_MEM_WRITEBACK, XTHAL_MEM_NON_CACHEABLE) - * creates a memory type that is writeback cacheable in the system cache, and not - * cacheable in the processor's local cache. - */ -#define XTHAL_MEM_PROC_CACHE(system, processor) \ - (((system) & 0x000f0000) | (((processor) & 0x000f0000 ) << 4) | \ - (((system) & XTHAL_MEM_DEVICE) | ((processor) & XTHAL_MEM_DEVICE))) - -/* - * This macro converts a bit-wise combination of the XTHAL_MEM_... constants - * to the corresponding MPU memory type (9-bits). - * - * Unsupported combinations are mapped to the best available substitute. - * - * The same functionality plus error checking is available from - * xthal_encode_memory_type(). - */ -#define XTHAL_ENCODE_MEMORY_TYPE(x) \ - (((x) & 0xffffe000) ? \ - (_XTHAL_MEM_IS_DEVICE((x)) ? _XTHAL_ENCODE_DEVICE((x)) : \ - (_XTHAL_IS_SYSTEM_NONCACHEABLE((x)) ? \ - _XTHAL_ENCODE_SYSTEM_NONCACHEABLE((x)) : \ - _XTHAL_ENCODE_SYSTEM_CACHEABLE((x)))) : (x)) - -/* - * This structure is used to represent each MPU entry (both foreground and - * background). The internal representation of the structure is subject to - * change, so it should only be accessed by the XTHAL_MPU_ENTRY_... macros - * below. - */ -typedef struct xthal_MPU_entry -{ - unsigned as; /* virtual start address, and valid bit */ - unsigned at; /* access rights, and memory type (and space for entry index) */ -} xthal_MPU_entry; - -extern const xthal_MPU_entry Xthal_mpu_bgmap[]; - - - - -/* - * XTHAL_MPU_ENTRY creates an MPU entry from its component values. It is - * intended for initializing an MPU map. Example: - * const struct xthal_MPU_entry mpumap[] = - { XTHAL_MPU_ENTRY( 0x00000000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_WRITEBACK), - XTHAL_MPU_ENTRY( 0xE0000000, 1, XTHAL_AR_RWXrwx, - XTHAL_MEM_NON_CACHEABLE | XTHAL_MEM_BUFFERABLE), - XTHAL_MPU_ENTRY( 0xF0000000, 1, XTHAL_AR_RWX, - XTHAL_MEM_NON_CACHEABLE | XTHAL_MEM_BUFFERABLE) }; - xthal_write_map(mpumap, sizeof(mpumap) / sizeof(struct xthal_MPU_entry)); - * - */ -#define XTHAL_MPU_ENTRY(vaddr, valid, access, memtype) \ - { (((vaddr) & 0xffffffe0) | ((valid & 0x1))), \ - (((XTHAL_ENCODE_MEMORY_TYPE(memtype)) << 12) | (((access) & 0xf) << 8)) } - -/* - * These macros get (or set) the specified field of the MPU entry. - */ -#define XTHAL_MPU_ENTRY_GET_VSTARTADDR(x) ((x).as & 0xffffffe0) - -#define XTHAL_MPU_ENTRY_SET_VSTARTADDR(x, vaddr) (x).as = \ - (((x).as) & 0x1) | ((vaddr) & 0xffffffe0) - -#define XTHAL_MPU_ENTRY_GET_VALID(x) (((x).as & 0x1)) - -#define XTHAL_MPU_ENTRY_SET_VALID(x, valid) (x).as = \ - (((x).as & 0xfffffffe) | ((valid) & 0x1)) -#define XTHAL_MPU_ENTRY_GET_ACCESS(x) ((((x).at) >> 8) & 0xf) - -#define XTHAL_MPU_ENTRY_SET_ACCESS(x, accessRights) ((x).at = \ - ((x).at & 0xfffff0ff) | (((accessRights) & 0xf) << 8)) - -#define XTHAL_MPU_ENTRY_GET_MEMORY_TYPE(x) ((((x).at) >> 12) & 0x1ff) - -#define XTHAL_MPU_ENTRY_SET_MEMORY_TYPE(x, memtype) ((x).at = \ - ((x).at & 0xffe00fff) | (((XTHAL_ENCODE_MEMORY_TYPE(memtype)) & 0x1ff) << 12)) - -/* - * These functions accept encoded access rights, and return 1 if the - * supplied memory type has the property specified by the function name, - * otherwise they return 0. - */ -extern int xthal_is_kernel_readable(int accessRights); -extern int xthal_is_kernel_writeable(int accessRights); -extern int xthal_is_kernel_executable(int accessRights); -extern int xthal_is_user_readable(int accessRights); -extern int xthal_is_user_writeable (int accessRights); -extern int xthal_is_user_executable(int accessRights); - - -/* - * This function converts a bit-wise combination of the XTHAL_MEM_.. constants - * to the corresponding MPU memory type (9-bits). - * - * If none of the XTHAL_MEM_.. bits are present in the argument, then - * bits 4-12 (9-bits) are returned ... this supports using an already encoded - * memoryType (perhaps obtained from an xthal_MPU_entry structure) as input - * to xthal_set_region_attribute(). - * - * This function first checks that the supplied constants are a valid and - * supported combination. If not, it returns XTHAL_BAD_MEMORY_TYPE. - */ -extern int xthal_encode_memory_type(unsigned int x); - -/* - * This function accepts a 9-bit memory type value (such as returned by - * XTHAL_MEM_ENTRY_GET_MEMORY_TYPE() or xthal_encode_memory_type(). They - * return 1 if the memoryType has the property specified in the function - * name and 0 otherwise. - */ -extern int xthal_is_cacheable(unsigned int memoryType); -extern int xthal_is_writeback(unsigned int memoryType); -extern int xthal_is_device(unsigned int memoryType); - -/* - * Copies the current MPU entry list into 'entries' which - * must point to available memory of at least - * sizeof(struct xthal_MPU_entry) * XCHAL_MPU_ENTRIES. - * - * This function returns XTHAL_SUCCESS. - * XTHAL_INVALID, or - * XTHAL_UNSUPPORTED. - */ -extern int xthal_read_map(struct xthal_MPU_entry* entries); - -/* - * Writes the map pointed to by 'entries' to the MPU. Before updating - * the map, it commits any uncommitted - * cache writes, and invalidates the cache if necessary. - * - * This function does not check for the correctness of the map. Generally - * xthal_check_map() should be called first to check the map. - * - * If n == 0 then the existing map is cleared, and no new map is written - * (useful for returning to reset state) - * - * If (n > 0 && n < XCHAL_MPU_ENTRIES) then a new map is written with - * (XCHAL_MPU_ENTRIES-n) padding entries added to ensure a properly ordered - * map. The resulting foreground map will be equivalent to the map vector - * fg, but the position of the padding entries should not be relied upon. - * - * If n == XCHAL_MPU_ENTRIES then the complete map as specified by fg is - * written. - * - * The CACHEADRDIS register will be set to enable caching any 512MB region - * that is overlapped by an MPU region with a cacheable memory type. - * Caching will be disabled if none of the 512 MB region is cacheable. - * - * xthal_write_map() disables the MPU foreground map during the MPU - * update and relies on the background map. - * - * As a result any interrupt that does not meet the following conditions - * must be disabled before calling xthal_write_map(): - * 1) All code and data needed for the interrupt must be - * mapped by the background map with sufficient access rights. - * 2) The interrupt code must not access the MPU. - * - */ -extern void xthal_write_map(const struct xthal_MPU_entry* entries, unsigned n); - -/* - * Checks if entry vector 'entries' of length 'n' is a valid MPU access map. - * Returns: - * XTHAL_SUCCESS if valid, - * XTHAL_OUT_OF_ENTRIES - * XTHAL_MAP_NOT_ALIGNED, - * XTHAL_BAD_ACCESS_RIGHTS, - * XTHAL_OUT_OF_ORDER_MAP, or - * XTHAL_UNSUPPORTED if config doesn't have an MPU. - */ -extern int xthal_check_map(const struct xthal_MPU_entry* entries, unsigned n); - -/* - * Returns the MPU entry that maps 'vaddr'. If 'infgmap' is non-NULL then - * *infgmap is set to 1 if 'vaddr' is mapped by the foreground map, and - * *infgmap is set to 0 if 'vaddr' is mapped by the background map. - */ -extern struct xthal_MPU_entry xthal_get_entry_for_address(void* vaddr, - int* infgmap); - -/* - * Scans the supplied MPU map and returns a value suitable for writing to - * the CACHEADRDIS register: - * Bits 0-7 -> 1 if there are no cacheable areas in the corresponding 512MB - * region and 0 otherwise. - * Bits 8-31 -> undefined. - * This function can accept a partial memory map in the same manner - * xthal_write_map() does, */ -extern unsigned int -xthal_calc_cacheadrdis(const struct xthal_MPU_entry* e, unsigned n); - -/* - * This function is intended as an MPU specific version of - * xthal_set_region_attributes(). xthal_set_region_attributes() calls - * this function for MPU configurations. - * - * This function sets the attributes for the region [vaddr, vaddr+size) - * in the MPU. - * - * Depending on the state of the MPU this function will require from - * 0 to 3 unused MPU entries. - * - * This function typically will move, add, and subtract entries from - * the MPU map during execution, so that the resulting map may - * be quite different than when the function was called. - * - * This function does make the following guarantees: - * 1) The MPU access map remains in a valid state at all times - * during its execution. - * 2) At all points during (and after) completion the memoryType - * and accessRights remain the same for all addresses - * that are not in the range [vaddr, vaddr+size). - * 3) If XTHAL_SUCCESS is returned, then the range - * [vaddr, vaddr+size) will have the accessRights and memoryType - * specified. - * 4) The CACHEADRDIS register will be set to enable caching any 512MB region - * that is overlapped by an MPU region with a cacheable memory type. - * Caching will be disabled if none of the 512 MB region is cacheable. - * - * The accessRights parameter should be either a 4-bit value corresponding - * to an MPU access mode (as defined by the XTHAL_AR_.. constants), or - * XTHAL_MPU_USE_EXISTING_ACCESS_RIGHTS. - * - * The memoryType parameter should be either a bit-wise or-ing of XTHAL_MEM_.. - * constants that represent a valid MPU memoryType, a 9-bit MPU memoryType - * value, or XTHAL_MPU_USE_EXISTING_MEMORY_TYPE. - * - * In addition to the error codes that xthal_set_region_attribute() - * returns, this function can also return: XTHAL_BAD_ACCESS_RIGHTS - * (if the access rights bits map to an unsupported combination), or - * XTHAL_OUT_OF_MAP_ENTRIES (if there are not enough unused MPU entries) - * - * If this function is called with an invalid MPU map, then this function - * will return one of the codes that is returned by xthal_check_map(). - * - * The flag, XTHAL_CAFLAG_EXPAND, is not supported - * - */ - -extern int xthal_mpu_set_region_attribute(void* vaddr, unsigned size, - int accessRights, int memoryType, unsigned flags); - -/* The following are internal implementation macros. These should not - * be directly used except by the hal code and headers. -*/ - -/* - * Layout of the MPU specifier for: XTHAL_ENCODE_MEMORY_TYPE(), - * xthal_encode_memory_type(), xthal_set_region_attribute(), - * and xthal_mpu_set_region_attribute(). THIS IS SUBJECT TO CHANGE: - * - * Bits 0-3 - reserved for pass through of accessRights - * Bits 4-12 - reserved for pass through of memoryType bits - * Bit 13 - indicates to use existing access rights of region - * Bit 14 - indicates to use existing memory type of region - * Bit 15 - indicates device - * Bit 16-19- system cache properties - * Bit 20-23- local cache properties - * Bit 24 - indicates bufferable - * Bit 25-26- encodes shareability (1=inner, 2=outer, 3=system) - * Bit 27 - indicates interruptible - * Bits 28-31- reserved for future use - */ -#define _XTHAL_SYSTEM_CACHE_BITS 0x000f0000 -#define _XTHAL_LOCAL_CACHE_BITS 0x00f00000 -#define _XTHAL_MEM_SYSTEM_RWC_MASK 0x00070000 -#define _XTHAL_MEM_LOCAL_RWC_MASK 0x00700000 -#define _XTHAL_SHIFT_RWC 16 - -#define _XTHAL_MEM_ANY_SHAREABLE(x) (((x) & XTHAL_MEM_SYSTEM_SHAREABLE) ? 1 : 0) - -#define _XTHAL_MEM_INNER_SHAREABLE(x) ((((x) & XTHAL_MEM_SYSTEM_SHAREABLE) \ - == XTHAL_MEM_INNER_SHAREABLE) ? 1 : 0) - -#define _XTHAL_MEM_IS_BUFFERABLE(x) (((x) & XTHAL_MEM_BUFFERABLE) ? 1 : 0) - -#define _XTHAL_MEM_IS_DEVICE(x) (((x) & XTHAL_MEM_DEVICE) ? 1 : 0) - -#define _XTHAL_NON_CACHEABLE_DOMAIN(x) \ - (_XTHAL_MEM_IS_DEVICE(x) || _XTHAL_MEM_ANY_SHAREABLE(x)? 0x3 : 0) - -#define _XTHAL_CACHEABLE_DOMAIN(x) (_XTHAL_MEM_ANY_SHAREABLE(x) ? \ - 0x3 : 0x1) - -#define _XTHAL_MEM_CACHE_MASK(x) ((x) & _XTHAL_SYSTEM_CACHE_BITS) - -#define _XTHAL_IS_SYSTEM_NONCACHEABLE(x) \ - (((_XTHAL_MEM_CACHE_MASK(x) & XTHAL_MEM_NON_CACHEABLE) == \ - XTHAL_MEM_NON_CACHEABLE) ? 1 : 0) - -#define _XTHAL_ENCODE_DEVICE(x) \ - (((((x) & XTHAL_MEM_INTERRUPTIBLE) ? 1 : 0) << 3) | \ - (_XTHAL_NON_CACHEABLE_DOMAIN(x) << 1) | _XTHAL_MEM_IS_BUFFERABLE(x)) - -#define _XTHAL_ENCODE_SYSTEM_NONCACHEABLE(x) \ - (0x18 | (_XTHAL_NON_CACHEABLE_DOMAIN(x) << 1) \ - | _XTHAL_MEM_IS_BUFFERABLE(x)) - -#define _XTHAL_ENCODE_SYSTEM_CACHEABLE(x) \ - (((((((x) & _XTHAL_LOCAL_CACHE_BITS) >> 4) & XTHAL_MEM_NON_CACHEABLE) == \ - XTHAL_MEM_NON_CACHEABLE) ? 1 : 0) ? \ - (_XTHAL_CACHEABLE_DOMAIN(x) << 4) : \ - _XTHAL_ENCODE_SYSTEM_CACHEABLE_LOCAL_CACHEABLE(x)) | \ - ((_XTHAL_MEM_INNER_SHAREABLE(x) << 3) | \ - (_XTHAL_MEM_CACHE_MASK(x) & _XTHAL_MEM_SYSTEM_RWC_MASK) \ - >> _XTHAL_SHIFT_RWC) - -#define _XTHAL_ENCODE_SYSTEM_CACHEABLE_LOCAL_CACHEABLE(x) \ - ((_XTHAL_CACHEABLE_DOMAIN(x) << 7) | (((((x) & _XTHAL_LOCAL_CACHE_BITS) ? \ - ((x) & _XTHAL_LOCAL_CACHE_BITS) : \ - (_XTHAL_MEM_CACHE_MASK(x) << 4)) \ - & (_XTHAL_MEM_LOCAL_RWC_MASK)) >> _XTHAL_SHIFT_RWC )) - -/* End of internal macros */ - -/* The functions and constants below here have been deprecated.*/ -#define XTHAL_MEM_NON_CACHED XTHAL_MEM_NON_CACHEABLE -#define XTHAL_MEM_NON_SHARED XTHAL_MEM_NON_SHAREABLE -#define XTHAL_MEM_INNER_SHARED XTHAL_MEM_INNER_SHAREABLE -#define XTHAL_MEM_OUTER_SHARED XTHAL_MEM_OUTER_SHAREABLE -#define XTHAL_MEM_SYSTEM_SHARED XTHAL_MEM_SYSTEM_SHAREABLE -#define XTHAL_MEM_SW_SHAREABLE 0 - -#define xthal_is_cached(memoryType) (xthal_is_cacheable((memoryType))) -extern int xthal_read_background_map(struct xthal_MPU_entry* entries); - -/* end deprecated functions and constants */ - -#ifdef __cplusplus -} -#endif -#endif /*!_ASMLANGUAGE && !_NOCLANGUAGE && !__ASSEMBLER__ */ - -#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ - - - - -/**************************************************************************** - EXPERIMENTAL and DEPRECATED Definitions - ****************************************************************************/ - - -#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__) -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef INCLUDE_DEPRECATED_HAL_CODE -extern const unsigned char Xthal_have_old_exc_arch; -extern const unsigned char Xthal_have_mmu; -extern const unsigned int Xthal_num_regs; -extern const unsigned char Xthal_num_iroms; -extern const unsigned char Xthal_num_irams; -extern const unsigned char Xthal_num_droms; -extern const unsigned char Xthal_num_drams; -extern const unsigned int Xthal_configid0; -extern const unsigned int Xthal_configid1; -#endif - -#ifdef INCLUDE_DEPRECATED_HAL_DEBUG_CODE -#define XTHAL_24_BIT_BREAK 0x80000000 -#define XTHAL_16_BIT_BREAK 0x40000000 -extern const unsigned short Xthal_ill_inst_16[16]; -#define XTHAL_DEST_REG 0xf0000000 /* Mask for destination register */ -#define XTHAL_DEST_REG_INST 0x08000000 /* Branch address is in register */ -#define XTHAL_DEST_REL_INST 0x04000000 /* Branch address is relative */ -#define XTHAL_RFW_INST 0x00000800 -#define XTHAL_RFUE_INST 0x00000400 -#define XTHAL_RFI_INST 0x00000200 -#define XTHAL_RFE_INST 0x00000100 -#define XTHAL_RET_INST 0x00000080 -#define XTHAL_BREAK_INST 0x00000040 -#define XTHAL_SYSCALL_INST 0x00000020 -#define XTHAL_LOOP_END 0x00000010 /* Not set by xthal_inst_type */ -#define XTHAL_JUMP_INST 0x00000008 /* Call or jump instruction */ -#define XTHAL_BRANCH_INST 0x00000004 /* Branch instruction */ -#define XTHAL_24_BIT_INST 0x00000002 -#define XTHAL_16_BIT_INST 0x00000001 -typedef struct xthal_state { - unsigned pc; - unsigned ar[16]; - unsigned lbeg; - unsigned lend; - unsigned lcount; - unsigned extra_ptr; - unsigned cpregs_ptr[XTHAL_MAX_CPS]; -} XTHAL_STATE; -extern unsigned int xthal_inst_type(void *addr); -extern unsigned int xthal_branch_addr(void *addr); -extern unsigned int xthal_get_npc(XTHAL_STATE *user_state); -#endif /* INCLUDE_DEPRECATED_HAL_DEBUG_CODE */ - -#ifdef __cplusplus -} -#endif -#endif /*!_ASMLANGUAGE && !_NOCLANGUAGE && !__ASSEMBLER__ */ - -#endif /*XTENSA_HAL_H*/ - diff --git a/src/arch/xtensa/include/xtensa/idmaasm.h b/src/arch/xtensa/include/xtensa/idmaasm.h deleted file mode 100755 index 2669ff064ffd..000000000000 --- a/src/arch/xtensa/include/xtensa/idmaasm.h +++ /dev/null @@ -1,72 +0,0 @@ -/* $Id: //depot/dev/Foxhill/Xtensa/OS/include/xtensa/mpuasm.h#5 $ */ - -/* - * Copyright (c) 2016 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. - */ - -#ifndef _IDMAASM_H_ -#define _IDMAASM_H_ - -#if XCHAL_HAVE_IDMA -#include <xtensa/idma.h> -#endif - -/* - * Macro for restore IDMA regs - * - * Parameters: - * a_save => address register containing pointer to IDMA save area - * a_temp1, a_temp2, a_temp3. => address register temporaries - */ -// IDMA_REG_SETTINGS, -// IDMA_REG_TIMEOUT, -// IDMA_REG_DESC_START, -// IDMA_REG_CONTROL, -// IDMA_REG_USERPRIV, - -.macro _idma_restore a_save, a_temp1, a_temp2, a_temp3 -#if XCHAL_HAVE_IDMA - l32i \a_temp1, \a_save, 0 - movi \a_temp3, idmareg_base - movi \a_temp2, IDMA_REG_SETTINGS - add \a_temp2, \a_temp2, \a_temp3 - wer \a_temp1, \a_temp2 - l32i \a_temp1, \a_save, 4 - movi \a_temp2, IDMA_REG_TIMEOUT - add \a_temp2, \a_temp2, \a_temp3 - wer \a_temp1, \a_temp2 - l32i \a_temp1, \a_save, 8 - movi \a_temp2, IDMA_REG_DESC_START - add \a_temp2, \a_temp2, \a_temp3 - wer \a_temp1, \a_temp2 - l32i \a_temp1, \a_save, 12 - movi \a_temp2, IDMA_REG_CONTROL - add \a_temp2, \a_temp2, \a_temp3 - wer \a_temp1, \a_temp2 - l32i \a_temp1, \a_save, 16 - movi \a_temp2, IDMA_REG_USERPRIV - add \a_temp2, \a_temp2, \a_temp3 - wer \a_temp1, \a_temp2 -#endif -.endm - -#endif //_IDMAASM_H_ diff --git a/src/arch/xtensa/include/xtensa/mpuasm.h b/src/arch/xtensa/include/xtensa/mpuasm.h deleted file mode 100644 index f14dacc0b044..000000000000 --- a/src/arch/xtensa/include/xtensa/mpuasm.h +++ /dev/null @@ -1,111 +0,0 @@ -/* $Id: //depot/dev/Foxhill/Xtensa/OS/include/xtensa/mpuasm.h#5 $ */ - -/* - * Copyright (c) 2016 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. - */ - -#ifndef _MPUASM_H_ -#define _MPUASM_H_ -#include <xtensa/config/core.h> - -/* - * Macro for writing MPU map. - * - * Parameters: - * a_map => address register containing pointer to MPU map - * a_num_entries => number of entries in the forementioned map - * a_temp1, a_temp2. => address register temporaries - * a_temp3, a_temp4 - */ - -.macro mpu_write_map a_map, a_num_entries, a_temp1, a_temp2, a_temp3, a_temp4 -#if XCHAL_HAVE_MPU - movi \a_temp1, 0 - wsr.cacheadrdis \a_temp1 // enable the cache in all regions - wsr.mpuenb \a_temp1 // disable all foreground entries - - // Clear out the unused entries. - // - // Currently we are clearing out all the entries because currently - // the entries must be ordered even if they are all disabled. - // If out of order entries were permitted when all are disabled, - // performance could be improved by clearing XCHAL_MPU_ENTRIES - n - // (n = number of entries) rather than XCHAL_MPU_ENTRIES - 1 entries. - // - movi \a_temp2, 0 - movi \a_temp3, XCHAL_MPU_ENTRIES - 1 - j 1f - .align 16 // this alignment is done to ensure that -1: - memw // todo currently wptlb must be preceeded by a memw. The instructions must - // be aligned to ensure that both are in the same cache line. These statements should be - // properly conditionalized when that restriction is removed from the HW - wptlb \a_temp2, \a_temp1 - addi \a_temp2, \a_temp2, 1 - bltu \a_temp2, \a_temp3, 1b - - // Write the new entries. - // - beqz \a_num_entries, 4f // if no entries, skip loop - addx8 \a_map, \a_num_entries, \a_map // compute end of provided map - j 3f - .align 16 -2: memw // todo currently wptlb must be preceeded by a memw. The instructions must - // be aligned to ensure that both are in the same cache line. These statements should be - // properly conditionalized when that restriction is removed from the HW - wptlb \a_temp2, \a_temp4 - addi \a_temp3, \a_temp3, -1 - beqz \a_num_entries, 4f // loop until done -3: addi \a_map, \a_map, -8 - l32i \a_temp2, \a_map, 4 // get at (acc.rights, memtype) - l32i \a_temp4, \a_map, 0 // get as (vstart, valid) - addi \a_num_entries, \a_num_entries, -1 - extui \a_temp1, \a_temp2, 0, 5 // entry index portion - xor \a_temp2, \a_temp2, \a_temp1 // zero it - or \a_temp2, \a_temp2, \a_temp3 // set index = \a_temp3 - j 2b -4: -#endif -.endm - -/* - * Macro for reading MPU map - * - * Parameters: - * a_map_ptr => address register pointing to memory where map is written - * a_temp1, a_temp2 => address register temporaries - */ -.macro mpu_read_map a_map_ptr, a_temp1, a_temp2 -#if XCHAL_HAVE_MPU - movi \a_temp1, XCHAL_MPU_ENTRIES // set index to last entry + 1 - addx8 \a_map_ptr, \a_temp1, \a_map_ptr // set map ptr to last entry + 1 -1: addi \a_temp1, \a_temp1, -1 // decrement index - addi \a_map_ptr, \a_map_ptr, -8 // decrement index - rptlb0 \a_temp2, \a_temp1 // read 1/2 of entry - s32i \a_temp2, \a_map_ptr, 0 // write 1/2 of entry - rptlb1 \a_temp2, \a_temp1 - s32i \a_temp2, \a_map_ptr, 4 - bnez \a_temp1, 1b // loop until done -#endif - .endm - -#endif diff --git a/src/arch/xtensa/include/xtensa/overlay.h b/src/arch/xtensa/include/xtensa/overlay.h deleted file mode 100644 index 9e41cd2ebc2d..000000000000 --- a/src/arch/xtensa/include/xtensa/overlay.h +++ /dev/null @@ -1,190 +0,0 @@ -// overlay.h -- Overlay manager header file -// $Id$ - -// Copyright (c) 2013 Tensilica 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. - - -#ifndef OVERLAY_H -#define OVERLAY_H - - -#include <xtensa/xtruntime.h> - - -#ifdef __cplusplus -extern "C" { -#endif - - -// Overlays not supported for CALL0 ABI -#if defined (__XTENSA_CALL0_ABI__) -#undef XT_DISABLE_OVERLAYS -#define XT_DISABLE_OVERLAYS 1 -#endif - -// Define this to turn off overlay support -#ifdef XT_DISABLE_OVERLAYS - -#define OVERLAY(n) -#define DECLARE_OVERLAY(n) - -#define xt_overlay_map(ov_id) -#define xt_overlay_map_async(ov_id) 0 -#define xt_overlay_map_in_progress() 0 -#define xt_overlay_get_id() 0 -#define xt_overlay_get_state(pc) 0 -#define xt_overlay_check_map(pc,ps,ovstate,sp) 0 - -#else - -// Shorthand for convenience and portability. -#define OVERLAY(n) __attribute__((overlay(n))) - -// Structure of the overlay table required by gdb and the overlay -// manager. Should not be accessed by user code unless overriding -// the load process. -struct ovly_table { - void * vma; // The overlay's mapped address. - unsigned int size; // The size of the overlay, in bytes. - void * lma; // The overlay's load address. - unsigned int mapped; // Non-zero if overlay is currently mapped; zero otherwise. -}; - -// Constructed by the linker. Required for gdb and for the overlay -// manager. Should not be accessed by user code unless overriding -// the load process. -extern struct ovly_table _ovly_table[]; - -// Functions. -void xt_overlay_map(int ov_id); -int xt_overlay_map_async(int ov_id); -int xt_overlay_map_in_progress(void); -unsigned int xt_overlay_get_state(unsigned int pc); -unsigned int xt_overlay_check_map(unsigned int * pc, unsigned int * ps, - unsigned int ovstate, unsigned int sp); -int xt_overlay_start_map(void * dst, void * src, unsigned int len, int ov_id); -int xt_overlay_is_mapping(int ov_id); -void xt_overlay_fatal_error(int ov_id); - - -// Returns the current overlay ID. If no overlay is mapped or an overlay -// is in the middle of being mapped, returns -1. Inlined to avoid calling -// out of overlay (wastes cycles, can end up reading wrong ID on interrupt -// activity). -// -static inline int __attribute__((always_inline)) xt_overlay_get_id(void) -{ -extern short _mapping_id; -extern short _ovly_id; - - int ret; - unsigned int flags = XTOS_SET_INTLEVEL(15); - - if (_mapping_id >= 0) { - ret = -1; - } - else { - ret = _ovly_id; - } - - XTOS_RESTORE_INTLEVEL(flags); - return ret; -} - - -// The following macros are used to declare numbered overlays and generate -// the corresponding call stubs. Use as follows: -// -// DECLARE_OVERLAY(n) -// -// See documentation for more details. - -//#include <xtensa/config/core-isa.h> - -// At this time overlays are not supported without windowing. -#if defined(__XTENSA_WINDOWED_ABI__) - -#define xstr(x) str(x) -#define str(x) #x - -// At entry, register a8 holds the return address and a9 holds the target -// function address. This stub saves a8 on the stack at (SP - 20) which -// is the only location that is safe for us to use. Then it allocates 32 -// bytes on the stack for working storage, loads the overlay number into -// a8, and jumps to the common handler. The common handler will make sure -// that the called function is loaded into memory before calling it. -// NOTE: we are using the stack area normally reserved for nested functions. -// This means nested functions cannot be used when overlays are in use. - -#define CALL_IN(num) \ - asm(".section .gnu.linkonce.t.overlay.call." xstr(num) ".text, \"ax\"\n" \ - ".global _overlay_call_in_" xstr(num) "_\n" \ - ".align 4\n" \ - "_overlay_call_in_" xstr(num) "_:\n" \ - "s32e a8, a1, -20\n" \ - "addi a8, a1, -32\n" \ - "movsp a1, a8\n" \ - "movi a8, " xstr(num) "\n" \ - "j _overlay_call_in_common\n" \ - ".size _overlay_call_in_" xstr(num) "_, . - _overlay_call_in_" xstr(num) "_\n"); - -// The call-out stub first calls the target function, then loads the overlay -// number into register a14 and jumps to the common handler. The handler will -// make sure that the caller function is present in memory before returning. -// Note that registers a10-a13 may contain return values so must be preserved. -// -// Because we came here via a call4, the return address is in a4, and the top -// 2 bits are set to the window increment. We'll restore the top 2 bits of -// the return address from the called function's address, assuming that both -// are in the same 1 GB segment. For now this is always true. - -#define CALL_OUT(num) \ - asm(".section .gnu.linkonce.t.overlay.call." xstr(num) ".text, \"ax\"\n" \ - ".global _overlay_call_out_" xstr(num) "_\n" \ - ".align 4\n" \ - "_overlay_call_out_" xstr(num) "_:\n" \ - "slli a4, a4, 2\n" \ - "srli a4, a4, 2\n" \ - "extui a8, a9, 30, 2\n" \ - "slli a8, a8, 30\n" \ - "or a4, a4, a8\n" \ - "callx8 a9\n" \ - "movi a14, " xstr(num) "\n" \ - "j _overlay_call_out_common\n" \ - ".size _overlay_call_out_" xstr(num) "_, . - _overlay_call_out_" xstr(num) "_\n"); - -// Generate a call-in and a call-out stub for each overlay. - -#define DECLARE_OVERLAY(num) \ - CALL_IN(num) \ - CALL_OUT(num) - -#endif // defined(__XTENSA_WINDOWED_ABI__) - -#endif // XT_DISABLE_OVERLAYS - -#ifdef __cplusplus -} -#endif - -#endif // OVERLAY_H - diff --git a/src/arch/xtensa/include/xtensa/overlay_os_asm.h b/src/arch/xtensa/include/xtensa/overlay_os_asm.h deleted file mode 100644 index 4adc044e6a6c..000000000000 --- a/src/arch/xtensa/include/xtensa/overlay_os_asm.h +++ /dev/null @@ -1,140 +0,0 @@ -// overlay_os_asm.h -- Overlay manager assembly macros for OS use. -// $Id$ - -// Copyright (c) 2013 Tensilica 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. - - -#ifndef OVERLAY_OS_ASM_H -#define OVERLAY_OS_ASM_H - -// The macros in here are intended to be used by RTOS task switch code -// to check overlay status. Such code is usually in assembly and cannot -// call C code without penalty. For C code usage, it is best to use the -// corresponding C functions from the library. - - -// Inline assembly version of xt_overlay_get_state(). The arguments are -// three AR registers (a0-a15): -// -// "pcreg" - should contain the outgoing task's PC, i.e. the point at -// which the task got interrupted. The return value is also -// returned in this register. -// "sr1/2" - Scratch registers. These must be distinct from "pcreg". -// -// The return value is a 32-bit result that should be saved with the -// task context and passed as-is to xt_overlay_check_map. - - .macro _xt_overlay_get_state pcreg sr1 sr2 - - movi \sr1, _mapping_id - movi \sr2, _ovly_id - l16si \sr1, \sr1, 0 - l16ui \sr2, \sr2, 0 - slli \sr1, \sr1, 16 - or \pcreg, \sr1, \sr2 - - .endm - - -// Inline assembly version of xt_overlay_check_map(). It requires 5 AR -// registers (a0-a15) as arguments. -// -// "pcreg" - should contain the interrupted task's PC, i.e. the point -// at which the task got interrupted. This will be adjusted -// if required. -// "psreg" - should contain the interrupted task's PS. This will be -// adjusted if required. -// "ovreg" - should contain the overlay state on entry. Contents may -// be clobbered. -// "spreg" - should contain the tasks stack pointer on entry. -// "sr1" - Scratch register. Must be distinct from any of the above. -// -// The return values are "pcreg" and "psreg" and these must be used -// to update the task's PC and PS. -// Note that this macro may store data below the "spreg" pointer. If -// it does, then it will also disable interrupts via the PS, so that -// the task resumes with all interrupts disabled (to avoid corrupting -// this data). -// -// (SP - 24) Overlay ID to restore -// (SP - 28) Task PC -// (SP - 32) Task PS - - .macro _xt_overlay_check_map pcreg psreg ovreg spreg sr1 - -// There are four cases to deal with: -// -// _ovly_id = -1, _mapping_id = -1 -// No overlay is mapped or mapping, nothing to do. -// -// _ovly_id >= 0, _mapping_id = -1 -// An overlay was mapped, check PC to see if we need a restore. -// -// _ovly_id = -1, _mapping_id >= 0 -// An overlay is being mapped. Either it belongs to this task, which -// implies that the PC is in the mapping function, or it does not -// belong to this task. Either way there is nothing to do. -// -// _ovly_id >= 0, _mapping_id >= 0 -// Illegal, cannot happen by design. Don't need to handle this. -// -// So, the logic is to check _ovly_id first. If this is >= 0, then -// we check the task PC. If the PC is in the regions of interest then -// we'll patch the return PC to invoke xt_overlay_restore. - -.L1: - extui \sr1, \ovreg, 0, 16 // Extract _ovly_id - bbsi.l \sr1, 15, .Lno // If -1 then we're done - mov \ovreg, \sr1 // Restore this one - -// Next check the PC to see if it falls within the ranges of interest. - -.L2: - movi \sr1, _overlay_vma // Is PC < VMA range ? - bltu \pcreg, \sr1, .L3 - movi \sr1, _overlay_vma_end // Is PC > VMA range ? - bgeu \pcreg, \sr1, .L3 - j .L4 // PC is in VMA range -.L3: - movi \sr1, _overlay_call_stubs_start // Is PC < call stubs range ? - bltu \pcreg, \sr1, .Lno - movi \sr1, _overlay_call_stubs_end // Is PC > call stubs range ? - bgeu \pcreg, \sr1, .Lno - -// If we get here then a restore is needed. Save the overlay ID, PC and PS. -// Return modified PC and PS so that xt_overlay_restore() will execute in -// the context of the task when resumed. Note that the OS resumption code -// may expect PS.EXCM to be set so we leave it as is in the return value. - -.L4: - s32e \ovreg, \spreg, -24 // Save overlay ID - s32e \pcreg, \spreg, -28 // Save task PC - s32e \psreg, \spreg, -32 // Save task PS - movi \pcreg, xt_overlay_restore // Adjust resumption PC - movi \sr1, 15 - or \psreg, \psreg, \sr1 // Set intlevel to highest -.Lno: - - .endm - -#endif // OVERLAY_OS_ASM_H - diff --git a/src/arch/xtensa/include/xtensa/simboard.h b/src/arch/xtensa/include/xtensa/simboard.h deleted file mode 100644 index 980b0b759635..000000000000 --- a/src/arch/xtensa/include/xtensa/simboard.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2001 Tensilica 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. - */ - -/* simboard.h - Xtensa ISS "Board" specific definitions */ - -#ifndef _INC_SIMBOARD_H_ -#define _INC_SIMBOARD_H_ - -#include <xtensa/config/core.h> -#include <xtensa/config/system.h> - - -/* - * Device addresses. - */ - -/* System ROM: */ -#define XTBOARD_ROM_SIZE XSHAL_ROM_SIZE -#ifdef XSHAL_ROM_VADDR -#define XTBOARD_ROM_VADDR XSHAL_ROM_VADDR -#endif -#ifdef XSHAL_ROM_PADDR -#define XTBOARD_ROM_PADDR XSHAL_ROM_PADDR -#endif - -/* System RAM: */ -#define XTBOARD_RAM_SIZE XSHAL_RAM_SIZE -#ifdef XSHAL_RAM_VADDR -#define XTBOARD_RAM_VADDR XSHAL_RAM_VADDR -#endif -#ifdef XSHAL_RAM_PADDR -#define XTBOARD_RAM_PADDR XSHAL_RAM_PADDR -#endif - - -/* - * Things that depend on device addresses. - */ - -#define XTBOARD_CACHEATTR_WRITEBACK XSHAL_ISS_CACHEATTR_WRITEBACK -#define XTBOARD_CACHEATTR_WRITEALLOC XSHAL_ISS_CACHEATTR_WRITEALLOC -#define XTBOARD_CACHEATTR_WRITETHRU XSHAL_ISS_CACHEATTR_WRITETHRU -#define XTBOARD_CACHEATTR_BYPASS XSHAL_ISS_CACHEATTR_BYPASS -#define XTBOARD_CACHEATTR_DEFAULT XSHAL_ISS_CACHEATTR_DEFAULT - -#define XTBOARD_BUSINT_PIPE_REGIONS 0 -#define XTBOARD_BUSINT_SDRAM_REGIONS 0 - - -#endif /*_INC_SIMBOARD_H_*/ - diff --git a/src/arch/xtensa/include/xtensa/specreg.h b/src/arch/xtensa/include/xtensa/specreg.h deleted file mode 100644 index 1805811c28eb..000000000000 --- a/src/arch/xtensa/include/xtensa/specreg.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Xtensa Special Register symbolic names - */ - -/* $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/include/xtensa/specreg.h#1 $ */ - -/* - * Copyright (c) 2005-2011 Tensilica 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. - */ - -#ifndef XTENSA_SPECREG_H -#define XTENSA_SPECREG_H - -/* Special registers: */ -#define LBEG 0 -#define LEND 1 -#define LCOUNT 2 -#define SAR 3 -#define BR 4 -#define LITBASE 5 -#define SCOMPARE1 12 -#define ACCLO 16 -#define ACCHI 17 -#define MR_0 32 -#define MR_1 33 -#define MR_2 34 -#define MR_3 35 -#define PREFCTL 40 -#define WINDOWBASE 72 -#define WINDOWSTART 73 -#define PTEVADDR 83 -#define RASID 90 -#define ITLBCFG 91 -#define DTLBCFG 92 -#define IBREAKENABLE 96 -#define MEMCTL 97 -#define CACHEATTR 98 /* until T1050, XEA1 */ -#define CACHEADRDIS 98 /* LX7+ */ -#define ATOMCTL 99 -#define DDR 104 -#define MECR 110 -#define IBREAKA_0 128 -#define IBREAKA_1 129 -#define DBREAKA_0 144 -#define DBREAKA_1 145 -#define DBREAKC_0 160 -#define DBREAKC_1 161 -#define CONFIGID0 176 -#define EPC_1 177 -#define EPC_2 178 -#define EPC_3 179 -#define EPC_4 180 -#define EPC_5 181 -#define EPC_6 182 -#define EPC_7 183 -#define DEPC 192 -#define EPS_2 194 -#define EPS_3 195 -#define EPS_4 196 -#define EPS_5 197 -#define EPS_6 198 -#define EPS_7 199 -#define CONFIGID1 208 -#define EXCSAVE_1 209 -#define EXCSAVE_2 210 -#define EXCSAVE_3 211 -#define EXCSAVE_4 212 -#define EXCSAVE_5 213 -#define EXCSAVE_6 214 -#define EXCSAVE_7 215 -#define CPENABLE 224 -#define INTERRUPT 226 -#define INTREAD INTERRUPT /* alternate name for backward compatibility */ -#define INTSET INTERRUPT /* alternate name for backward compatibility */ -#define INTCLEAR 227 -#define INTENABLE 228 -#define PS 230 -#define VECBASE 231 -#define EXCCAUSE 232 -#define DEBUGCAUSE 233 -#define CCOUNT 234 -#define PRID 235 -#define ICOUNT 236 -#define ICOUNTLEVEL 237 -#define EXCVADDR 238 -#define CCOMPARE_0 240 -#define CCOMPARE_1 241 -#define CCOMPARE_2 242 -#define MISC_REG_0 244 -#define MISC_REG_1 245 -#define MISC_REG_2 246 -#define MISC_REG_3 247 - -/* Special cases (bases of special register series): */ -#define MR 32 -#define IBREAKA 128 -#define DBREAKA 144 -#define DBREAKC 160 -#define EPC 176 -#define EPS 192 -#define EXCSAVE 208 -#define CCOMPARE 240 -#define MISC_REG 244 - -/* Tensilica-defined user registers: */ -#if 0 -/*#define ... 21..24 */ /* (545CK) */ -/*#define ... 140..143 */ /* (545CK) */ -#define EXPSTATE 230 /* Diamond */ -#define THREADPTR 231 /* threadptr option */ -#define FCR 232 /* FPU */ -#define FSR 233 /* FPU */ -#define AE_OVF_SAR 240 /* HiFi2 */ -#define AE_BITHEAD 241 /* HiFi2 */ -#define AE_TS_FTS_BU_BP 242 /* HiFi2 */ -#define AE_SD_NO 243 /* HiFi2 */ -#define VSAR 240 /* VectraLX */ -#define ROUND_LO 242 /* VectraLX */ -#define ROUND_HI 243 /* VectraLX */ -#define CBEGIN 246 /* VectraLX */ -#define CEND 247 /* VectraLX */ -#endif - -#endif /* XTENSA_SPECREG_H */ - diff --git a/src/arch/xtensa/include/xtensa/tie/xt_virtualops.h b/src/arch/xtensa/include/xtensa/tie/xt_virtualops.h deleted file mode 100644 index 45ff64f29791..000000000000 --- a/src/arch/xtensa/include/xtensa/tie/xt_virtualops.h +++ /dev/null @@ -1,37 +0,0 @@ -// Customer ID=10631; Build=0x90af6; Copyright (c) 2017-2019 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. - -/* Do not modify. This is automatically generated.*/ - -/* parasoft-begin-suppress ALL "This file not MISRA checked." */ - -#ifndef _XTENSA_xt_virtualops_h_HEADER -#define _XTENSA_xt_virtualops_h_HEADER - - -/* Header includes start */ - - -/* Header includes end */ - -#endif /* !_XTENSA_xt_virtualops_h_HEADER */ - -/* parasoft-end-suppress ALL "This file not MISRA checked." */ diff --git a/src/arch/xtensa/include/xtensa/trax-api.h b/src/arch/xtensa/include/xtensa/trax-api.h deleted file mode 100644 index aa1584359bc4..000000000000 --- a/src/arch/xtensa/include/xtensa/trax-api.h +++ /dev/null @@ -1,93 +0,0 @@ -/* Misc TRAX API function definitions. - - Copyright (c) 2007-2012 Tensilica 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. */ - -#ifndef _TRAX_API_H_ -#define _TRAX_API_H_ - -#include <xtensa-isa.h> -#include <xtensa-params.h> -#include "tpack.h" -#include "traxreg.h" - -#include "xdm-regs.h" - -/* Flags for trax_stop(): */ -#define TRAX_STOP_HALT 0x0001 /* halt immediately, don't wait for post-stop-trigger capture */ -#define TRAX_STOP_QUIET 0x0002 /* don't display informative messages */ - - -/* - * Describes a TRAX channel (based on tpack). - */ -typedef struct { - tpack_channel chan; /* channel structure header */ - /* Per TRAX unit information: */ - int trax_version; /* TRAX_ID_VER(id), one of TRAX_VER_xxx macros */ - unsigned long trax_tram_size; /* size of trace RAM in bytes */ - int trax_erratum10; /* set if TRAX 1.0 erratum workarounds needed */ - int trax_erratum20; /* set if TRAX 2.0 erratum workaround needed (PR 22161)*/ - int trax_erratum20_size; - int trax_has_busy; /* has trace-busy feature */ - int trax_has_atb; /* has ATB feature */ - /*FIXME: add various features: coresight regs (don't call it that), APB, ATB, TRAM, ... */ -} trax_channel; - - -/* Prototypes: */ - -/* TRAX Protocol API: */ -extern int trax_read_register(tpack_channel *tchan, int regno, unsigned *value); -extern int trax_write_register(tpack_channel *tchan, int regno, unsigned value); -extern int trax_read_memory(tpack_channel *tchan, int address, int size, unsigned char *pdata); -extern int trax_fill_memory(tpack_channel *tchan, int address, int size, tpack_u32 pattern); -extern int trax_enumerate_devices(tpack_channel *tchan, int * buf, int * size); - -/* TRAX Network API: */ -extern unsigned long trax_ram_size(tpack_channel *traxchan); -extern unsigned long trax_ram_size_addr(tpack_channel *traxchan); -extern int trax_create_tracefile(tpack_channel *traxchan, int size, unsigned char * data, - char *filename, int hflags, const char *toolver); -extern int trax_memaccess_safe(tpack_channel *traxchan, const char *what); -extern int trax_start(tpack_channel *traxchan, int flags); -extern int trax_stop(tpack_channel *traxchan, int flags); -extern int trax_halt(tpack_channel *traxchan, int flags); -extern int trax_save(tpack_channel *traxchan, char *filename, int flags, const char *toolver, int erratum); - -/* TRAX Misc API (no network dependencies): */ -int trax_fixed_hw(unsigned * regs); -extern int trax_display_id(unsigned id, const char *prefix); -extern int trax_display_summary(unsigned id, - unsigned status, - unsigned control, - unsigned address, - unsigned delay, - unsigned trigger, - unsigned match, - unsigned startaddr, - unsigned endaddr, - const char *prefix); - -/* Other: */ - -#endif /* _TRAX_API_H_ */ - diff --git a/src/arch/xtensa/include/xtensa/trax-core-config.h b/src/arch/xtensa/include/xtensa/trax-core-config.h deleted file mode 100644 index 42a03334aa17..000000000000 --- a/src/arch/xtensa/include/xtensa/trax-core-config.h +++ /dev/null @@ -1,144 +0,0 @@ -/* Definitions for Xtensa processor config info needed for TRAX. - - Copyright (c) 2005-2011 Tensilica 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. */ - -#ifndef TRAX_CORE_CONFIG_H -#define TRAX_CORE_CONFIG_H - -#include "xtensa-params.h" - -/* - * Vector Enumerations. - */ - -/* These must match the LX2.0 and later traceport spec: */ -#define VEC_NO_VECTOR 0 -#define VEC_FIRST VEC_RESET /* first valid vector */ -#define VEC_RESET 1 -#define VEC_DEBUG 2 -#define VEC_NMI 3 -#define VEC_USER 4 -#define VEC_KERNEL 5 -#define VEC_DOUBLE 6 -#define VEC_MEMERR 7 -#define VEC_RESERVED8 8 -#define VEC_RESERVED9 9 -#define VEC_WINO4 10 -#define VEC_WINU4 11 -#define VEC_WINO8 12 -#define VEC_WINU8 13 -#define VEC_WINO12 14 -#define VEC_WINU12 15 -#define VEC_INTLEVEL2 16 -#define VEC_INTLEVEL3 17 -#define VEC_INTLEVEL4 18 -#define VEC_INTLEVEL5 19 -#define VEC_INTLEVEL6 20 -/* These are internal, i.e. don't appear like this on traceport: */ -#define VEC_DEBUG_OCD 21 -#define VEC_UNKNOWN 22 -/* Enumerations 23 through 31 are also reserved, but putting */ -/* placeholders here seems wasteful and unnecessary. */ -#define VEC_COUNT 23 - -/* Other branch (change-of-PC-flow) type encodings; - * if PC changes due to an exception or interrupt vector, - * one of the VEC_* values above is used, otherwise - * (or if it's unknown whether it's due to an exception/interrupt) - * one of the following is used: */ - -#define BRANCH_IS_VEC(n) ((n) < VEC_COUNT) /* is known to be except/interrupt? */ -#define BRANCH_OR_VEC 24 /* unknown type of branch (branch/exception/interrupt/etc) */ -#define BRANCH_UNKNOWN 25 /* unknown type of branch (anything but except/interrupt) */ -#define BRANCH_UNKNOWN_ERR 26 /* like BRANCH_UNKNOWN with known error (non-branch instr) */ -#define BRANCH_LOOPBACK 28 /* zero-overhead loopback (from LEND to LBEG) */ -#define BRANCH_CONDTAKEN 29 /* conditional branch taken (or LOOP{NEZ,GTZ} loop skip) */ -#define BRANCH_JUMP 30 /* jump (unconditional branch, i.e. J or JX) */ -#define BRANCH_IS_CALL(n) (((n) & ~3) == 32) /* is a function call? */ -#define BRANCH_CALL0 32 /* non-windowed function call (CALL0, CALLX0) */ -#define BRANCH_CALL4 33 /* windowed function call (CALL4, CALLX4) */ -#define BRANCH_CALL8 34 /* windowed function call (CALL8, CALLX8) */ -#define BRANCH_CALL12 35 /* windowed function call (CALL12, CALLX12) */ -#define BRANCH_IS_RETURN(n) ((n) >= 36) /* is any kind of return? */ -#define BRANCH_IS_CALLRETURN(n) (((n) & ~1) == 36) /* is a function return? */ -#define BRANCH_RET 36 /* non-windowed function return (RET or RET.N) */ -#define BRANCH_RETW 37 /* windowed function return (RETW or RETW.N) */ -#define BRANCH_IS_EIRETURN(n) ((n) >= 38) /* is an except/inter. return? */ -#define BRANCH_RFE 38 /* RFE or RFUE */ -#define BRANCH_RFDE 39 /* RFDE */ -#define BRANCH_RFWO 40 /* RFWO */ -#define BRANCH_RFWU 41 /* RFWU */ -#define BRANCH_RFI_2 42 /* RFI 2 */ -#define BRANCH_RFI_3 43 /* RFI 3 */ -#define BRANCH_RFI_4 44 /* RFI 4 */ -#define BRANCH_RFI_5 45 /* RFI 5 */ -#define BRANCH_RFI_6 46 /* RFI 6 */ -#define BRANCH_RFI_NMI 47 /* RFI NMILEVEL */ -#define BRANCH_RFI_DEBUG 48 /* RFI DEBUGLEVEL */ -#define BRANCH_RFME 49 /* RFME */ -#define BRANCH_COUNT 50 /* (number of defined BRANCH_xxx values) */ - - - -typedef struct { - unsigned vaddr; - unsigned vaddr2; /* for static vectors only (reloc vectors option) */ - int is_configured; -} trax_vector_t; - - -/* - * This structure describes those portion of a Tensilica processor's - * configuration that are useful for trace. - */ -typedef struct { - char ** isa_dlls; - char * core_name; /* (XPG core name, not necessarily same as XTENSA_CORE) */ - int big_endian; /* 0 = little-endian, 1 = big-endian */ - int has_loops; /* 1 = zero overhead loops configured */ - int has_autorefill; /* 1 = TLB autorefill (MMU) configured */ - unsigned max_instr_size; /* in bytes (eg. 3, 4, 8, ...) */ - unsigned int_level_max; /* number of interrupt levels configured (without NMI) */ - int debug_level; /* debug intlevel, 0 if debug not configured */ - int nmi_level; /* NMI intlevel, 0 if NMI not configured */ - unsigned targethw_min; /* min. targeted hardware version (XTENSA_HWVERSION_<rel>) */ - unsigned targethw_max; /* max. targeted hardware version (XTENSA_HWVERSION_<rel>) */ - int reloc_vectors; /* 0 = fixed vectors, 1 = relocatable vectors */ - int statvec_select; /* 0 = stat vec base 0, 1 = stat vec base 1 (SW default) */ - int vecbase_align; /* number of bits to align VECBASE (32 - bits in VECBASE) */ - unsigned statvec_base0; /* static vector base 0 */ - unsigned statvec_base1; /* static vector base 1 */ - unsigned vecbase_reset; /* reset value of VECBASE */ - trax_vector_t vectors[VEC_COUNT]; /* all vectors... */ -} trax_core_config_t; - - -/* Globals: */ -//extern const char * const trax_vector_short_names[/*VEC_COUNT*/]; // nobody uses this one -extern const char * const trax_vector_names[/*VEC_COUNT*/]; - -/* Prototypes: */ -extern int trax_read_params (trax_core_config_t *c, xtensa_params p); -extern int trax_vector_from_address(trax_core_config_t *config, unsigned long vaddr, unsigned long *vecbases); - -#endif /* TRAX_CORE_CONFIG_H */ - diff --git a/src/arch/xtensa/include/xtensa/trax-proto.h b/src/arch/xtensa/include/xtensa/trax-proto.h deleted file mode 100644 index 41d5c9fd769d..000000000000 --- a/src/arch/xtensa/include/xtensa/trax-proto.h +++ /dev/null @@ -1,91 +0,0 @@ -/* This file contains functions that are hidden from the user. These are - * protocol specific functions used to read and write TRAX registers - * and the trace memory - */ - -/* - * Copyright (c) 2012-2013 Tensilica 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. - */ -#ifndef _TRAX_PROTO_H -#define _TRAX_PROTO_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Function to read register - * - * regno : The register number to be read (not ERI addressed) - * data : Location where the read value is kept - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_read_register_eri (int regno, unsigned *data); - -/* Function to write a value into a register - * - * regno : The register number to be written (not ERI addressed) - * value : The value to be written at that register location - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_write_register_eri (int regno, unsigned value); - -/* Function to read memory - * - * address : Address of the TraceRAM memory, each location has a word - * len : Amount of memory in bytes, to be read - * data : buffer in which the read memory is stored - * final_address: Next address to be read in the following call to this - * function (trace save mechanism) - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_read_memory_eri (unsigned address, int len, int *data, - unsigned *final_address); - -/* Function to write a value to the memory address - * - * address : Address of the TraceRAM memory - * value : The value to be written inside that location - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_write_memory_eri (int address, unsigned value); - -/* Function to write to a subfield of the register. - * Called by set and show parameter functions. - * - * regno : Register number - * regmask : Mask in order to toggle appropriate bits - * value : Value to be written in the masked location - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_write_register_field_eri (int regno, unsigned regmask, - unsigned value); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/arch/xtensa/include/xtensa/trax-util.h b/src/arch/xtensa/include/xtensa/trax-util.h deleted file mode 100644 index 123ac366dfb4..000000000000 --- a/src/arch/xtensa/include/xtensa/trax-util.h +++ /dev/null @@ -1,63 +0,0 @@ -/* This file contains utility functions that can be used for polling TRAX - * or executing higher level save functionality - * It assumes that print subroutines and file I/O routines are available - * on the system - */ - -/* - * Copyright (c) 2012-2013 Tensilica 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. - */ - -#ifndef _TRAX_UTIL_H -#define _TRAX_UTIL_H - - -#ifdef __cplusplus -extern "C" { -#endif - -/* User can use this function if he wants to generate a tracefile output. - * Internally it calls trax_get_trace in a loop until it realizes that - * the entire trace has been read. - * - * context : pointer to structure which contains information about the - * current TRAX session - * filename : user specified output trace file name. If the file does not - * exist, it would create the new file, else would append to it - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_save (trax_context *context, char *filename); - -/* Displays a brief machine readable status. - * - * context : pointer to structure which contains information about the - * current TRAX session - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_poll (trax_context *context); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/arch/xtensa/include/xtensa/trax.h b/src/arch/xtensa/include/xtensa/trax.h deleted file mode 100644 index 47049c51d215..000000000000 --- a/src/arch/xtensa/include/xtensa/trax.h +++ /dev/null @@ -1,409 +0,0 @@ -/* Header file for TRAX control Library */ - -/* - * Copyright (c) 2012-2013 Tensilica 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. - */ - -#ifndef _TRAX_H -#define _TRAX_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define TRAX_STOP_HALT 0x0001 -#define TRAX_STOP_QUIET 0x0002 - -/* Flag values to indicate if the user wanted to reverse the pcstop - * parameters */ -#define TRAX_PCSTOP_REVERSE 0x0001 -#define TRAX_PCSTOP_NO_REVERSE 0x0000 - -/* Indicating whether postsize should be in terms of bytes, instructions - * or percentage of trace size captured */ -#define TRAX_POSTSIZE_BYTES 0x0000 -#define TRAX_POSTSIZE_INSTR 0x0001 -#define TRAX_POSTSIZE_PERCENT 0x0002 - -/* Size of the header inside the trace file */ -#define TRAX_HEADER_SIZE 256 - -/* Minimum size between start and end addresses */ -#define TRAX_MIN_TRACEMEM 64 - -/* For basic debugging */ -#define DEBUG 0 - -#include <stdbool.h> - -#define ffs(i) __builtin_ffs(i) - -/* Data structures */ - -/* Represents the context of the TRAX unit and the current TRAX session. - * To be used by set and show function calls to set and show appropriate - * parameters of appropriate TRAX unit. - */ - -typedef struct { - int trax_version; /* TRAX PC version information */ - unsigned long trax_tram_size; /* If trace RAM is present,size of it */ - int hflags; /* Flags that can be used to debug, - print info, etc. */ - int address_read_last; /* During saving of the trace, this - indicates the address from which - the current trace reading must - resume */ - unsigned long bytes_read; /* bytes read uptil now */ - unsigned long total_memlen; /* Total bytes to be read based on the - trace collected in the trace RAM */ - bool get_trace_started; /* indicates that the first chunk of - bytes (which include the header) has - been read */ -} trax_context; - - -/* -----------------------TRAX Initialization ------------------------------*/ - -/* Initializing the trax context. Reads registers and sets values for version, - * trace RAM size, total memory length, etc. Most of the other values are - * initialized to their default case. - * - * context : pointer to structure which contains information about the - * current TRAX session - * - * returns : 0 if successful, -1 if unsuccessful, -2 if ram_size if - * incorrect - */ -int trax_context_init_eri (trax_context *context); - -/* -----------------Starting/Stopping TRAX session -------------------------*/ - -/* Start tracing with current parameter setting. If tracing is already in - * progress, an error is reported. Otherwise, tracing starts and any unsaved - * contents of the TraceRAM is discarded - * - * context : pointer to structure which contains information about the - * current TRAX session - * returns : 0 if successful, 1 if trace is already active, - * -1 if unsuccessful - */ -int trax_start (trax_context *context); - -/* This command initiates a stop trigger or halts a trace session based of the - * value of the flag parameter passed. In case stop trigger is initiated, any - * selected post-stop-trigger capture proceeds normally. - * If trace capture was not in progress, or a stop was already triggered, the - * return value indicates appropriately. - * - * context : pointer to structure which contains information about the - * current TRAX session - * flags : To differentiate between stopping trace without any - * post-size-trigger capture (trax_halt) or with that. - * A zero value would stop the trace based on trigger and a - * value of one would halt it - * - * returns : 0 if successful, 1 if already stopped, -1 if unsuccessful - */ -int trax_stop_halt (trax_context *context, int flags); - -/* Resets the TRAX parameters to their default values which would internally - * involve resetting the TRAX registers. To invoke another trace session or - * reset the current tracing mechanism, this function needs to be called as - * it resets parameters of the context that deal with tracing information - * - * context : pointer to structure which contains information about the - * current TRAX session - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_reset (trax_context *context); - -/* ---------------Set/Get several TRAX parameters --------------------------*/ - -/* Sets the start address and end address (word aligned) of the trace in the - * TraceRAM. Care must be taken to ensure that the difference between the - * start and the end addresses is atleast TRAX_MIN_TRACEMEM bytes. If not, - * the values are reset to default, which is 0 for startaddr and - * traceRAM_words -1 for endaddr - * - * context : pointer to structure which contains information about the - * current TRAX session - * startaddr : value to which the start address must be set. Can be - * any value between 0 - (traceRAM_words - 1) - * endaddr : value to which the end address must be set. Can be any value - * between 0 - (traceRAM_words - 1) - * - * returns : 0 if successful, -1 if unsuccessful, -2 if the difference - * between the start and end addresses is less than - * TRAX_MIN_TRACEMEM bytes or if they are passed incorrect - * values, -3 if memory shared option is not configured, in - * which case, start and end addresses are set to default - * values instead of those passed by the user - */ -int trax_set_ram_boundaries (trax_context *context, unsigned startaddr, - unsigned endaddr); - -/* Shows the start address and end address(word aligned) of the trace in the - * TraceRAM. If incorrect, the startaddress and the endaddress values are - * set to default, i.e. 0 for startaddr and traceRAM_words - 1 for endaddr - * - * context : pointer to structure which contains information about the - * current TRAX session - * startaddr : pointer to value which will contain the start address - * endaddr : pointer to value which will contain the end address - * - * returns : 0 if successful, -1 if unsuccessful - * - */ -int trax_get_ram_boundaries (trax_context *context, unsigned *startaddr, - unsigned *endaddr); - -/* Selects stop trigger via cross-trigger input - * - * context : pointer to structure which contains information about the - * current TRAX session - * value : 0 = off (reset value), 1 = on - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_set_ctistop (trax_context *context, unsigned value); - -/* Shows if stop-trigger via cross-trigger input is off or on - * - * context : pointer to structure which contains information about the - * current TRAX session - * returns : 0 if off, 1 if on, -1 if unsuccessful - */ -int trax_get_ctistop (trax_context *context); - -/* Selects stop trigger via processor-trigger input - * - * context : pointer to structure which contains information about the - * current TRAX session - * value : 0 = off (reset value), 1 = on - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_set_ptistop (trax_context *context, unsigned value); - -/* Shows if stop trigger visa processor-trigger input is off or on - * - * context : pointer to structure which contains information about the - * current TRAX session - * returns : 0 if off, 1 if on, -1 if unsuccessful - */ -int trax_get_ptistop (trax_context *context); - -/* Reports cross trigger output state - * - * context : pointer to structure which contains information about the - * current TRAX session - * returns : 0 if CTO bit is reset, 1 if CTO bit is set - */ -int trax_get_cto (trax_context *context); - -/* Reports processor trigger output state - * - * context : pointer to structure which contains information about the - * current TRAX session - * returns : 0 if PTO bit is reset, 1 if PTO bit is set - */ -int trax_get_pto (trax_context *context); - -/* Selects condition that asserts cross trigger output - * - * context : pointer to structure which contains information about the - * current TRAX session - * option : 0 = off(reset value)/1 = ontrig/2 = onhalt - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_set_ctowhen (trax_context *context, int option); - -/* Shows condition that asserted cross trigger output. It can be - * any of: ontrig or onhalt or even off - * - * context : pointer to structure which contains information about the - * current TRAX session - * - * returns : 0 if off, 1 if ontrig, 2 if onhalt, -1 if unsuccessful - */ -int trax_get_ctowhen (trax_context *context); - -/* Selects condition that asserts processor trigger output - * - * context : pointer to structure which contains information about the - * current TRAX session - * option : 0 = off(reset value)/1 = ontrig/2 = onhalt - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_set_ptowhen (trax_context *context, int option); - - -/* Shows condition that asserted processor trigger output. It can be - * any of: ontrig or onhalt or even off - * - * context : pointer to structure which contains information about the - * current TRAX session - * returns : 0 if off, 1 if ontrig, 2 if onhalt, -1 if unsuccessful - */ -int trax_get_ptowhen (trax_context *context); - -/* Selects the trace synchronization message period. - * If ATEN enabled, we cannot allow syncper to be off, set it to reset value. - * Also, if no trace RAM, and ATEN enabled, set syncper to be reset value - * i.e. 256. A value of 1 i.e. on indicates that internally the message - * frequency is set to an optimal value. This option should be preferred - * if the user is not sure what message frequency option to set for the - * trace session. - * - * context : pointer to structure which contains information about the - * current TRAX session - * option : 0 = off, 1 = on, -1 = auto, 8, 16, 32, 64, 128, - * 256 (reset value) - * - * returns : 0 if successful, -1 if unsuccessful, -2 if incorrect - * arguments - */ -int trax_set_syncper (trax_context *context, int option); - -/* Shows trace synchronization message period. Can be one of: - * off, on, auto, 8, 16, 32, 64, 128, 256 (reset value) - * - * context : pointer to structure which contains information about the - * current TRAX session - * returns : value of sync period, 0 if off, -1 if unsuccessful - */ -int trax_get_syncper (trax_context *context); - -/* Selects stop trigger via PC match. Specifies the address or - * address range to match against program counter. Trace stops when the - * processor executes an instruction matching the specified address - * or range. - * - * context : pointer to structure which contains information about the - * current TRAX session - * index : indicates the number of stop trigger (currently there is - * only one i.e. index = 0) - * startaddress : start range of the address at which the stop trigger - * should be activated - * enaddress : end range of the address at which the stop trigger should - * be activated - * flags : If non-zero, this inverts the range. i.e. trace stops - * when the processor executes an instruction that does not - * match the specified address or range - * - * returns : 0 if successful, -1 if unsuccessful, -2 if incorrect - * arguments (unaligned) - * - * Note : For the current version of TRAX library, the endaddress and - * startaddress can differ by at most 31 bytes and the total - * range i.e. (endaddress - startaddress + 1) has to be a power - * of two - */ -int trax_set_pcstop (trax_context *context, int index, unsigned long startaddress, - unsigned long endaddress, int flags); - -/* Shows the stop trigger via PC match - * - * context : pointer to structure which contains information about the - * current TRAX session - * index : container of information about the number of stop triggers - * startaddress : container of start range of stop trigger - * endaddress : container of end range of stop trigger - * flags : container of information whcih indicates whether the - * pc stop range is inverted or not. - * - * returns : 0 if successful, -1 if unsuccessful - */ -int trax_get_pcstop (trax_context *context, int *index, - unsigned long *startaddress, - unsigned long *endaddress, int *flags); - -/* This function is used to set the amount of trace to be captured past - * the stop trigger. - * - * context : pointer to structure which contains information about the - * current TRAX session - * count_unit : contains the count of units (instructions or bytes) to be - * captured post trigger. If 0, it implies that this is off - * unit : unit of measuring the count. 0 is bytes, 1 is instructions - * 2 is percentage of trace - * - * returns : 0 if successful, -1 if unsuccessful, -2 if incorrect - * arguments - * - */ -int trax_set_postsize (trax_context *context, int count_unit, int unit); - -/* This function shows the amount of TraceRAM in terms of the number of - * instructions or bytes, captured post the stop trigger - * - * context : pointer to structure which contains information about the - * current TRAX session - * count_unit : will contain the count of units(instructions or bytes) post - * trigger - * unit : will contain information about the events that are counted - * 0 implies that the traceRAM words consumed are counted and - * 1 implies that the target processor instructions executed and - * excpetions/interrupts taken are counted - * - * returns : 0 if postsize was got successfully, -1 if unsuccessful - */ -int trax_get_postsize (trax_context *context, int *count_unit, int *unit); - -/* -------------------------- TRAX save routines ---------------------------*/ - -/* This function should be called by the user to return a chunk of - * bytes in buf. It can be a lower layer function of save, or can be - * called by the user explicitly. If bytes_actually_read contains a 0 - * after a call to this function has been made, it implies that the entire - * trace has been read successfully. - * - * context : pointer to structure which contains information about - * the current TRAX session - * buf : Buffer that is allocated by the user, all the trace - * data read would be put in this buffer, which can then - * be used to generate a tracefile. - * The first TRAX_HEADER_SIZE of the buffer will always - * contain the header information. - * bytes_to_be_read : Indicates the bytes the user wants to read. The first - * invocation would need this parameter to be - * TRAX_HEADER_SIZE at least. - * - * returns : bytes actually read during the call to this function. - * 0 implies that all the bytes in the trace have been - * read, -1 if unsuccessful read/write of - * registers or memory, -2 if trace was active while - * this function was called, -3 if user enters - * bytes_to_be_read < TRAX_HEADER_SIZE in the first - * pass - */ -int trax_get_trace (trax_context *context, void *buf, - int bytes_to_be_read); -#ifdef __cplusplus -} -#endif - -#endif /* _TRAX_H */ diff --git a/src/arch/xtensa/include/xtensa/traxfile.h b/src/arch/xtensa/include/xtensa/traxfile.h deleted file mode 100644 index 4afc926a5076..000000000000 --- a/src/arch/xtensa/include/xtensa/traxfile.h +++ /dev/null @@ -1,62 +0,0 @@ -/* TRAX file header definition. - - Copyright (c) 2007-2012 Tensilica 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. */ - - -#define TRAX_FHEAD_MAGIC "TRAXdmp" -#define TRAX_FHEAD_VERSION 1 - -/* Header flags: */ -#define TRAX_FHEADF_OCD_ENABLED 0x00000001 /* set if OCD was enabled while capturing trace */ -#define TRAX_FHEADF_TESTDUMP 0x00000002 /* set if is a test file - (from 'memsave' instead of 'save') */ -#define TRAX_FHEADF_OCD_ENABLED_WHILE_EXIT 0x00000004 /* set if OCD was enabled while capturing trace and - we were exiting the OCD mode */ - -/* Header at the start of a TRAX dump file. */ -typedef struct { - char magic[8]; /* 00: "TRAXdmp\0" (TRAX_FHEAD_MAGIC) */ - char endianness; /* 08: 0=little-endian, 1=big-endian */ - char version; /* 09: TRAX_FHEAD_VERSION */ - char reserved0[2]; /* 0A: ... */ - unsigned filesize; /* 0C: size of the trace file, including this header */ - unsigned trace_ofs; /* 10: start of trace output, byte offset from start of header */ - unsigned trace_size; /* 14: size of trace output in bytes */ - unsigned dumptime; /* 18: date/time of capture save (secs since 1970-01-01), 0 if unknown */ - unsigned flags; /* 1C: misc flags (TRAX_FHEAD_F_xxx) */ - char username[16]; /* 20: user doing the capture/save (up to 15 chars) */ - char toolver[24]; /* 30: tool + version used for capture/save (up to 23 chars) */ - char reserved2[40]; /* 48: (reserved - could be hostname used for dump (up to 39 chars)) */ - unsigned configid[2]; /* 70: processor ConfigID values, 0 if unknown */ - unsigned ts_freq; /* 78: timestamp frequency, 0 if not specified */ - unsigned reserved3; /* 7C: (reserved) */ - unsigned id; /* 80: TRAX registers at time of save (0 if not read) */ - unsigned control; - unsigned status; - unsigned reserved4; /* Data register (should not be read) */ - unsigned address; - unsigned trigger; - unsigned match; - unsigned delay; - unsigned trax_regs[24]; /*100: (total size) -- dummy allocation (FIXME) */ -} trax_file_header; - diff --git a/src/arch/xtensa/include/xtensa/traxreg.h b/src/arch/xtensa/include/xtensa/traxreg.h deleted file mode 100644 index 282ba1feef21..000000000000 --- a/src/arch/xtensa/include/xtensa/traxreg.h +++ /dev/null @@ -1,199 +0,0 @@ -/* TRAX register definitions - - Copyright (c) 2006-2012 Tensilica 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. */ - -#ifndef _TRAX_REGISTERS_H_ -#define _TRAX_REGISTERS_H_ - -#define SHOW 1 -#define HIDE 0 - -#define RO 0 -#define RW 1 - -/* TRAX Register Numbers (from possible range of 0..127) */ -#if 0 -#define TRAXREG_ID 0 -#define TRAXREG_CONTROL 1 -#define TRAXREG_STATUS 2 -#define TRAXREG_DATA 3 -#define TRAXREG_ADDRESS 4 -#define TRAXREG_TRIGGER 5 -#define TRAXREG_MATCH 6 -#define TRAXREG_DELAY 7 -#define TRAXREG_STARTADDR 8 -#define TRAXREG_ENDADDR 9 -/* Internal use only (unpublished): */ -#define TRAXREG_P4CHANGE 16 -#define TRAXREG_P4REV 17 -#define TRAXREG_P4DATE 18 -#define TRAXREG_P4TIME 19 -#define TRAXREG_PDSTATUS 20 -#define TRAXREG_PDDATA 21 -#define TRAXREG_STOP_PC 22 -#define TRAXREG_STOP_ICNT 23 -#define TRAXREG_MSG_STATUS 24 -#define TRAXREG_FSM_STATUS 25 -#define TRAXREG_IB_STATUS 26 -#define TRAXREG_MAX 27 -#define TRAXREG_ITCTRL 96 -#endif -/* The registers above match the NAR addresses. So, their values are used for NAR access */ - -/* TRAX Register Fields */ - -/* TRAX ID register fields: */ -#define TRAX_ID_PRODNO 0xf0000000 /* product number (0=TRAX) */ -#define TRAX_ID_PRODOPT 0x0f000000 /* product options */ -#define TRAX_ID_MIW64 0x08000000 /* opt: instruction width */ -#define TRAX_ID_AMTRAX 0x04000000 /* opt: collection of options, - internal (VER_2_0 or later)*/ -#define TRAX_ID_MAJVER(id) (((id) >> 20) & 0x0f) -#define TRAX_ID_MINVER(id) (((id) >> 17) & 0x07) -#define TRAX_ID_VER(id) ((TRAX_ID_MAJVER(id)<<4)|TRAX_ID_MINVER(id)) -#define TRAX_ID_STDCFG 0x00010000 /* standard config */ -#define TRAX_ID_CFGID 0x0000ffff /* TRAX configuration ID */ -#define TRAX_ID_MEMSHARED 0x00001000 /* Memshared option in TRAX */ -#define TRAX_ID_FROM_VER(ver) ((((ver) & 0xf0) << 16) | (((ver) & 0x7) << 17)) -/* Other TRAX ID register macros: */ -/* TRAX versions of interest (TRAX_ID_VER(), ie. MAJVER*16 + MINVER): */ -#define TRAX_VER_1_0 0x10 /* RA */ -#define TRAX_VER_1_1 0x11 /* RB thru RC-2010.1 */ -#define TRAX_VER_2_0 0x20 /* RC-2010.2, RD-2010.0, - RD-2011.1 */ -#define TRAX_VER_2_1 0x21 /* RC-2011.3 / RD-2011.2 and - later */ -#define TRAX_VER_3_0 0x30 /* RE-2012.0 */ -#define TRAX_VER_3_1 0x31 /* RE-2012.1 */ -#define TRAX_VER_HUAWEI_3 TRAX_VER_3_0 /* For Huawei, PRs: 25223, 25224 - , 24880 */ - - -/* TRAX version 1.0 requires a couple software workarounds: */ -#define TRAX_ID_1_0_ERRATUM(id) (TRAX_ID_VER(id) == TRAX_VER_1_0) -/* TRAX version 2.0 requires software workaround for PR 22161: */ -#define TRAX_ID_MEMSZ_ERRATUM(id) (TRAX_ID_VER(id) == TRAX_VER_2_0) - -/* TRAX Control register fields: */ -#define TRAX_CONTROL_TREN 0x00000001 -#define TRAX_CONTROL_TRSTP 0x00000002 -#define TRAX_CONTROL_PCMEN 0x00000004 -#define TRAX_CONTROL_PTIEN 0x00000010 -#define TRAX_CONTROL_CTIEN 0x00000020 -#define TRAX_CONTROL_TMEN 0x00000080 /* 2.0+ */ -#define TRAX_CONTROL_CNTU 0x00000200 -#define TRAX_CONTROL_BIEN 0x00000400 -#define TRAX_CONTROL_BOEN 0x00000800 -#define TRAX_CONTROL_TSEN 0x00000800 -#define TRAX_CONTROL_SMPER 0x00007000 -#define TRAX_CONTROL_SMPER_SHIFT 12 -#define TRAX_CONTROL_PTOWT 0x00010000 -#define TRAX_CONTROL_CTOWT 0x00020000 -#define TRAX_CONTROL_PTOWS 0x00100000 -#define TRAX_CONTROL_CTOWS 0x00200000 -#define TRAX_CONTROL_ATID 0x7F000000 /* 2.0+, amtrax */ -#define TRAX_CONTROL_ATID_SHIFT 24 -#define TRAX_CONTROL_ATEN 0x80000000 /* 2.0+, amtrax */ - -#define TRAX_CONTROL_PTOWS_ER 0x00020000 /* For 3.0 */ -#define TRAX_CONTROL_CTOWT_ER 0x00100000 /* For 3.0 */ - -#define TRAX_CONTROL_ITCTO 0x00400000 /* For 3.0 */ -#define TRAX_CONTROL_ITCTIA 0x00800000 /* For 3.0 */ -#define TRAX_CONTROL_ITATV 0x01000000 /* For 3.0 */ - - -/* TRAX Status register fields: */ -#define TRAX_STATUS_TRACT 0x00000001 -#define TRAX_STATUS_TRIG 0x00000002 -#define TRAX_STATUS_PCMTG 0x00000004 -#define TRAX_STATUS_BUSY 0x00000008 /* ER ??? */ -#define TRAX_STATUS_PTITG 0x00000010 -#define TRAX_STATUS_CTITG 0x00000020 -#define TRAX_STATUS_MEMSZ 0x00001F00 -#define TRAX_STATUS_MEMSZ_SHIFT 8 -#define TRAX_STATUS_PTO 0x00010000 -#define TRAX_STATUS_CTO 0x00020000 - -#define TRAX_STATUS_ITCTOA 0x00400000 /* For 3.0 */ -#define TRAX_STATUS_ITCTI 0x00800000 /* For 3.0 */ -#define TRAX_STATUS_ITATR 0x01000000 /* For 3.0 */ - - -/* TRAX Address register fields: */ -#define TRAX_ADDRESS_TWSAT 0x80000000 -#define TRAX_ADDRESS_TWSAT_SHIFT 31 -#define TRAX_ADDRESS_TOTALMASK 0x00FFFFFF -// !!! VUakiVU. added for new TRAX: -#define TRAX_ADDRESS_WRAPCNT 0x7FE00000 /* version ???... */ -#define TRAX_ADDRESS_WRAP_SHIFT 21 - -/* TRAX PCMatch register fields: */ -#define TRAX_PCMATCH_PCML 0x0000001F -#define TRAX_PCMATCH_PCML_SHIFT 0 -#define TRAX_PCMATCH_PCMS 0x80000000 - -/* Compute trace ram buffer size (in bytes) from status register: */ -#define TRAX_MEM_SIZE(status) (1L << (((status) & TRAX_STATUS_MEMSZ) >> TRAX_STATUS_MEMSZ_SHIFT)) - -#if 0 -/* Describes a field within a register: */ -typedef struct { - const char* name; -// unsigned width; -// unsigned shift; - char width; - char shift; - char visible; /* 0 = internal use only, 1 = shown */ - char reserved; -} trax_regfield_t; -#endif - -/* Describes a TRAX register: */ -typedef struct { - const char* name; - unsigned id; - char width; - char visible; - char writable; - char reserved; - //const trax_regfield_t * fieldset; -} trax_regdef_t; - - -extern const trax_regdef_t trax_reglist[]; -extern const signed char trax_readable_regs[]; - -#ifdef __cplusplus -extern "C" { -#endif - -/* Prototypes: */ -extern int trax_find_reg(char * regname, char **errmsg); -extern const char * trax_regname(int regno); - -#ifdef __cplusplus -} -#endif - -#endif /* _TRAX_REGISTERS_H_ */ - diff --git a/src/arch/xtensa/include/xtensa/uart-16550.h b/src/arch/xtensa/include/xtensa/uart-16550.h deleted file mode 100644 index c551c64c1375..000000000000 --- a/src/arch/xtensa/include/xtensa/uart-16550.h +++ /dev/null @@ -1,152 +0,0 @@ -/******************************************************************************* - - Copyright (c) 2006-2007 Tensilica 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. - --------------------------------------------------------------------------------- - -uart-16550.h Generic definitions for National Semiconductor 16550 UART - -This is used by board-support-packages with one or more 16550 compatible UARTs. -A BSP provides a base address for each instance of a 16550 UART on the board. - -Note that a 16552 DUART (Dual UART) is simply two instances of a 16550 UART. - -*******************************************************************************/ - -#ifndef _UART_16550_H_ -#define _UART_16550_H_ - -/* C interface to UART registers. */ -struct uart_dev_s { - union { - uart16550_reg_t rxb; /* DLAB=0: receive buffer, read-only */ - uart16550_reg_t txb; /* DLAB=0: transmit buffer, write-only */ - uart16550_reg_t dll; /* DLAB=1: divisor, LS byte latch */ - } w0; - union { - uart16550_reg_t ier; /* DLAB=0: interrupt-enable register */ - uart16550_reg_t dlm; /* DLAB=1: divisor, MS byte latch */ - } w1; - - union { - uart16550_reg_t isr; /* DLAB=0: interrupt status register, read-only */ - uart16550_reg_t fcr; /* DLAB=0: FIFO control register, write-only */ - uart16550_reg_t afr; /* DLAB=1: alternate function register */ - } w2; - - uart16550_reg_t lcr; /* line control-register, write-only */ - uart16550_reg_t mcr; /* modem control-regsiter, write-only */ - uart16550_reg_t lsr; /* line status register, read-only */ - uart16550_reg_t msr; /* modem status register, read-only */ - uart16550_reg_t scr; /* scratch regsiter, read/write */ -}; - - -#define _RXB(u) ((u)->w0.rxb) -#define _TXB(u) ((u)->w0.txb) -#define _DLL(u) ((u)->w0.dll) -#define _IER(u) ((u)->w1.ier) -#define _DLM(u) ((u)->w1.dlm) -#define _ISR(u) ((u)->w2.isr) -#define _FCR(u) ((u)->w2.fcr) -#define _AFR(u) ((u)->w2.afr) -#define _LCR(u) ((u)->lcr) -#define _MCR(u) ((u)->mcr) -#define _LSR(u) ((u)->lsr) -#define _MSR(u) ((u)->msr) -#define _SCR(u) ((u)->scr) - -typedef volatile struct uart_dev_s uart_dev_t; - -/* IER bits */ -#define RCVR_DATA_REG_INTENABLE 0x01 -#define XMIT_HOLD_REG_INTENABLE 0x02 -#define RCVR_STATUS_INTENABLE 0x04 -#define MODEM_STATUS_INTENABLE 0x08 - -/* FCR bits */ -#define _FIFO_ENABLE 0x01 -#define RCVR_FIFO_RESET 0x02 -#define XMIT_FIFO_RESET 0x04 -#define DMA_MODE_SELECT 0x08 -#define RCVR_TRIGGER_LSB 0x40 -#define RCVR_TRIGGER_MSB 0x80 - -/* AFR bits */ -#define AFR_CONC_WRITE 0x01 -#define AFR_BAUDOUT_SEL 0x02 -#define AFR_RXRDY_SEL 0x04 - -/* ISR bits */ -#define INT_STATUS(r) ((r)&1) -#define INT_PRIORITY(r) (((r)>>1)&0x7) - -/* LCR bits */ -#define WORD_LENGTH(n) (((n)-5)&0x3) -#define STOP_BIT_ENABLE 0x04 -#define PARITY_ENABLE 0x08 -#define EVEN_PARITY 0x10 -#define FORCE_PARITY 0x20 -#define XMIT_BREAK 0x40 -#define DLAB_ENABLE 0x80 - -/* MCR bits */ -#define _DTR 0x01 -#define _RTS 0x02 -#define _OP1 0x04 -#define _OP2 0x08 -#define LOOP_BACK 0x10 - -/* LSR Bits */ -#define RCVR_DATA_READY 0x01 -#define OVERRUN_ERROR 0x02 -#define PARITY_ERROR 0x04 -#define FRAMING_ERROR 0x08 -#define BREAK_INTERRUPT 0x10 -#define XMIT_HOLD_EMPTY 0x20 -#define XMIT_EMPTY 0x40 -#define FIFO_ERROR 0x80 -#define RCVR_READY(u) (_LSR(u)&RCVR_DATA_READY) -#define XMIT_READY(u) (_LSR(u)&XMIT_HOLD_EMPTY) - -/* MSR bits */ -#define _RDR 0x01 -#define DELTA_DSR 0x02 -#define DELTA_RI 0x04 -#define DELTA_CD 0x08 -#define _CTS 0x10 -#define _DSR 0x20 -#define _RI 0x40 -#define _CD 0x80 - - -/* Compute 16-bit divisor for baudrate generator, with rounding: */ -#define UART_DIVISOR(clock,baud) (((clock)/16 + (baud)/2)/(baud)) - -/* Prototypes of driver functions */ -extern void uart16550_init( uart_dev_t *u, unsigned baud, unsigned ndata, - unsigned parity, unsigned nstop ); -extern void uart16550_out( uart_dev_t *u, char c ); -extern char uart16550_in( uart_dev_t *u ); -extern unsigned uart16550_measure_sys_clk( uart_dev_t *u ); - -#endif /* _UART_16550_H_ */ diff --git a/src/arch/xtensa/include/xtensa/xdm-regs.h b/src/arch/xtensa/include/xtensa/xdm-regs.h deleted file mode 100644 index c220bc96ca65..000000000000 --- a/src/arch/xtensa/include/xtensa/xdm-regs.h +++ /dev/null @@ -1,534 +0,0 @@ -/* xdm-regs.h - Common register and related definitions for the XDM - (Xtensa Debug Module) */ - -/* Copyright (c) 2016 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. */ - - -#ifndef _XDM_REGS_H_ -#define _XDM_REGS_H_ - -/* NOTE: This header file is included by C, assembler, and other sources. - So any C-specific or asm-specific content must be appropriately #ifdef'd. */ - - -/* - * XDM registers can be accessed using APB, ERI, or JTAG (via NAR). - * Address offsets for APB and ERI are the same, and for JTAG - * is different (due to the limited 7-bit NAR addressing). - * - * Here, we first provide the constants as APB / ERI address offsets. - * This is necessary for assembler code (which accesses XDM via ERI), - * because complex conversion macros between the two address maps - * don't work in the assembler. - * Conversion macros are used to convert these to/from JTAG (NAR), - * addresses, for software using JTAG. - */ -/* FIXME: maybe provide only MISC+CS registers here, and leave specific - subsystem registers in separate headers? eg. for TRAX, PERF, OCD */ - -/* XDM_.... ERI addr [NAR addr] Description...... */ - -/* TRAX */ -#define XDM_TRAX_ID 0x100000 /*[0x00] ID */ -#define XDM_TRAX_CONTROL 0x100004 /*[0x01] Control */ -#define XDM_TRAX_STATUS 0x100008 /*[0x02] Status */ -#define XDM_TRAX_DATA 0x10000C /*[0x03] Data */ -#define XDM_TRAX_ADDRESS 0x100010 /*[0x04] Address */ -#define XDM_TRAX_TRIGGER 0x100014 /*[0x05] Stop PC */ -#define XDM_TRAX_MATCH 0x100018 /*[0x06] Stop PC Range */ -#define XDM_TRAX_DELAY 0x10001C /*[0x07] Post Stop Trigger Capture Size */ -#define XDM_TRAX_STARTADDR 0x100020 /*[0x08] Trace Memory Start */ -#define XDM_TRAX_ENDADDR 0x100024 /*[0x09] Trace Memory End */ -#define XDM_TRAX_DEBUGPC 0x10003C /*[0x0F] Debug PC */ -#define XDM_TRAX_P4CHANGE 0x100040 /*[0x10] X */ -#define XDM_TRAX_TIME0 0x100040 /*[0x10] First Time Register */ -#define XDM_TRAX_P4REV 0x100044 /*[0x11] X */ -#define XDM_TRAX_TIME1 0x100044 /*[0x11] Second Time Register */ -#define XDM_TRAX_P4DATE 0x100048 /*[0x12] X */ -#define XDM_TRAX_INTTIME_MAX 0x100048 /*[0x12] maximal Value of Timestamp IntTime */ -#define XDM_TRAX_P4TIME 0x10004C /*[0x13] X */ -#define XDM_TRAX_PDSTATUS 0x100050 /*[0x14] Sample of PDebugStatus */ -#define XDM_TRAX_PDDATA 0x100054 /*[0x15] Sample of PDebugData */ -#define XDM_TRAX_STOP_PC 0x100058 /*[0x16] X */ -#define XDM_TRAX_STOP_ICNT 0x10005C /*[0x16] X */ -#define XDM_TRAX_MSG_STATUS 0x100060 /*[0x17] X */ -#define XDM_TRAX_FSM_STATUS 0x100064 /*[0x18] X */ -#define XDM_TRAX_IB_STATUS 0x100068 /*[0x19] X */ -#define XDM_TRAX_STOPCNT 0x10006C /*[0x1A] X */ - -/* Performance Monitoring Counters */ -#define XDM_PERF_PMG 0x101000 /*[0x20] perf. mon. global control register */ -#define XDM_PERF_INTPC 0x101010 /*[0x24] perf. mon. interrupt PC */ -#define XDM_PERF_PM0 0x101080 /*[0x28] perf. mon. counter 0 value */ -#define XDM_PERF_PM1 0x101084 /*[0x29] perf. mon. counter 1 value */ -#define XDM_PERF_PM2 0x101088 /*[0x2A] perf. mon. counter 2 value */ -#define XDM_PERF_PM3 0x10108C /*[0x2B] perf. mon. counter 3 value */ -#define XDM_PERF_PM4 0x101090 /*[0x2C] perf. mon. counter 4 value */ -#define XDM_PERF_PM5 0x101094 /*[0x2D] perf. mon. counter 5 value */ -#define XDM_PERF_PM6 0x101098 /*[0x2E] perf. mon. counter 6 value */ -#define XDM_PERF_PM7 0x10109C /*[0x2F] perf. mon. counter 7 value */ -#define XDM_PERF_PM(n) (0x101080+((n)<<2)) /* perfmon cnt n=0..7 value */ -#define XDM_PERF_PMCTRL0 0x101100 /*[0x30] perf. mon. counter 0 control */ -#define XDM_PERF_PMCTRL1 0x101104 /*[0x31] perf. mon. counter 1 control */ -#define XDM_PERF_PMCTRL2 0x101108 /*[0x32] perf. mon. counter 2 control */ -#define XDM_PERF_PMCTRL3 0x10110C /*[0x33] perf. mon. counter 3 control */ -#define XDM_PERF_PMCTRL4 0x101110 /*[0x34] perf. mon. counter 4 control */ -#define XDM_PERF_PMCTRL5 0x101114 /*[0x35] perf. mon. counter 5 control */ -#define XDM_PERF_PMCTRL6 0x101118 /*[0x36] perf. mon. counter 6 control */ -#define XDM_PERF_PMCTRL7 0x10111C /*[0x37] perf. mon. counter 7 control */ -#define XDM_PERF_PMCTRL(n) (0x101100+((n)<<2)) /* perfmon cnt n=0..7 control */ -#define XDM_PERF_PMSTAT0 0x101180 /*[0x38] perf. mon. counter 0 status */ -#define XDM_PERF_PMSTAT1 0x101184 /*[0x39] perf. mon. counter 1 status */ -#define XDM_PERF_PMSTAT2 0x101188 /*[0x3A] perf. mon. counter 2 status */ -#define XDM_PERF_PMSTAT3 0x10118C /*[0x3B] perf. mon. counter 3 status */ -#define XDM_PERF_PMSTAT4 0x101190 /*[0x3C] perf. mon. counter 4 status */ -#define XDM_PERF_PMSTAT5 0x101194 /*[0x3D] perf. mon. counter 5 status */ -#define XDM_PERF_PMSTAT6 0x101198 /*[0x3E] perf. mon. counter 6 status */ -#define XDM_PERF_PMSTAT7 0x10119C /*[0x3F] perf. mon. counter 7 status */ -#define XDM_PERF_PMSTAT(n) (0x101180+((n)<<2)) /* perfmon cnt n=0..7 status */ - -/* On-Chip-Debug (OCD) */ -#define XDM_OCD_ID 0x102000 /*[0x40] ID register */ -#define XDM_OCD_DCR_CLR 0x102008 /*[0x42] Debug Control reg clear */ -#define XDM_OCD_DCR_SET 0x10200C /*[0x43] Debug Control reg set */ -#define XDM_OCD_DSR 0x102010 /*[0x44] Debug Status reg */ -#define XDM_OCD_DDR 0x102014 /*[0x45] Debug Data reg */ -#define XDM_OCD_DDREXEC 0x102018 /*[0x46] Debug Data reg + execute-DIR */ -#define XDM_OCD_DIR0EXEC 0x10201C /*[0x47] Debug Instruction reg, word 0 + execute-DIR */ -#define XDM_OCD_DIR0 0x102020 /*[0x48] Debug Instruction reg, word 1 */ -#define XDM_OCD_DIR1 0x102024 /*[0x49] Debug Instruction reg, word 2 */ -#define XDM_OCD_DIR2 0x102028 /*[0x4A] Debug Instruction reg, word 3 */ -#define XDM_OCD_DIR3 0x10202C /*[0x49] Debug Instruction reg, word 4 */ -#define XDM_OCD_DIR4 0x102030 /*[0x4C] Debug Instruction reg, word 5 */ -#define XDM_OCD_DIR5 0x102034 /*[0x4D] Debug Instruction reg, word 5 */ -#define XDM_OCD_DIR6 0x102038 /*[0x4E] Debug Instruction reg, word 6 */ -#define XDM_OCD_DIR7 0x10203C /*[0x4F] Debug Instruction reg, word 7 */ - -/* Miscellaneous Registers */ -#define XDM_MISC_PWRCTL 0x103020 /*[0x58] Power and Reset Control */ -#define XDM_MISC_PWRSTAT 0x103024 /*[0x59] Power and Reset Status */ -#define XDM_MISC_ERISTAT 0x103028 /*[0x5A] ERI Transaction Status */ -#define XDM_MISC_DATETIME 0x103034 -#define XDM_MISC_CONFIGID1_V0 0x103034 /*[0x5D] [INTERNAL] ConfigID1 in XDM v0/1 */ -#define XDM_MISC_CONFIGID1_V2 0x10007c /*[0x1F] [INTERNAL] ConfigID1 since XDM v2 */ -#define XDM_MISC_CONFIGID0_V2 0x100078 /*[0x1E] [INTERNAL] ConfigID0 since XDM v2 */ -#define XDM_MISC_UBID 0x103038 /*[0x5E] [INTERNAL] Build Unique ID */ -#define XDM_MISC_CID 0x10303C /*[0x5F] [INTERNAL] Customer ID */ - -/* CoreSight compatibility */ -#define XDM_CS_ITCTRL 0x103F00 /*[0x60] InTegration Mode control reg */ -#define XDM_CS_CLAIMSET 0x103FA0 /*[0x68] Claim Tag Set reg */ -#define XDM_CS_CLAIMCLR 0x103FA4 /*[0x69] Claim Tag Clear reg */ -#define XDM_CS_LOCK_ACCESS 0x103FB0 /*[0x6B] Lock Access (writing 0xC5ACCE55 unlocks) */ -#define XDM_CS_LOCK_STATUS 0x103FB4 /*[0x6D] Lock Status */ -#define XDM_CS_AUTH_STATUS 0x103FB8 /*[0x6E] Authentication Status */ -#define XDM_CS_DEV_ID 0x103FC8 /*[0x72] Device ID */ -#define XDM_CS_DEV_TYPE 0x103FCC /*[0x73] Device Type */ -#define XDM_CS_PER_ID4 0x103FD0 /*[0x74] Peripheral ID reg byte 4 */ -#define XDM_CS_PER_ID5 0x103FD4 /*[0x75] Peripheral ID reg byte 5 */ -#define XDM_CS_PER_ID6 0x103FD8 /*[0x76] Peripheral ID reg byte 6 */ -#define XDM_CS_PER_ID7 0x103FDC /*[0x77] Peripheral ID reg byte 7 */ -#define XDM_CS_PER_ID0 0x103FE0 /*[0x78] Peripheral ID reg byte 0 */ -#define XDM_CS_PER_ID1 0x103FE4 /*[0x79] Peripheral ID reg byte 1 */ -#define XDM_CS_PER_ID2 0x103FE8 /*[0x7A] Peripheral ID reg byte 2 */ -#define XDM_CS_PER_ID3 0x103FEC /*[0x7B] Peripheral ID reg byte 3 */ -#define XDM_CS_COMP_ID0 0x103FF0 /*[0x7C] Component ID reg byte 0 */ -#define XDM_CS_COMP_ID1 0x103FF4 /*[0x7D] Component ID reg byte 1 */ -#define XDM_CS_COMP_ID2 0x103FF8 /*[0x7E] Component ID reg byte 2 */ -#define XDM_CS_COMP_ID3 0x103FFC /*[0x7F] Component ID reg byte 3 */ - -#define CS_PER_ID0 0x00000003 -#define CS_PER_ID1 0x00000021 -#define CS_PER_ID2 0x0000000f -#define CS_PER_ID3 0x00000000 -#define CS_PER_ID4 0x00000024 - -#define CS_COMP_ID0 0x0000000d -#define CS_COMP_ID1 0x00000090 -#define CS_COMP_ID2 0x00000005 -#define CS_COMP_ID3 0x000000b1 - -#define CS_DEV_TYPE 0x00000015 - -#define XTENSA_IDCODE 0x120034e5 // FIXME (upper bits not spec. out but BE is !) -#define XTENSA_MFC_ID (XTENSA_IDCODE & 0xFFF) -#define CS_DEV_ID XTENSA_IDCODE //FIXME - for XDM v0 only, for v2 is the new ID, that includes vars like PRID but also can be custom -#define CS_DEV_ID_v0_MASK 0x00000FFF // can compare only the lower 12 bits -#define CS_DEV_ID_v2_MASK 0xF0000000 // can compare only the upper 4 bits - -#define NXS_OCD_REG(val) ((val >= 0x40) && (val <= 0x5F)) -#define NXS_TRAX_REG(val) val <= 0x3F - -#define ERI_TRAX_REG(val) ((val & 0xFFFF) < 0x1000) -#define ERI_OCD_REG(val) ((val & 0xFFFF) >= 0x2000) && ((val & 0xFFFF) < 0x4000)) - -/* Convert above 14-bit ERI/APB address/offset to 7-bit NAR address: */ -#define _XDM_ERI_TO_NAR(a) ( ((a)&0x3F80)==0x0000 ? (((a)>>2) & 0x1F) \ - : ((a)&0x3E00)==0x1000 ? (0x20 | (((a)>>2) & 7) | (((a)>>4) & 0x18)) \ - : ((a)&0x3FC0)==0x2000 ? (0x40 | (((a)>>2) & 0xF)) \ - : ((a)&0x3FE0)==0x3020 ? (0x50 | (((a)>>2) & 0xF)) \ - : ((a)&0x3FFC)==0x3F00 ? 0x60 \ - : ((a)&0x3F80)==0x3F80 ? (0x60 | (((a)>>2) & 0x1F)) \ - : -1 ) - -#define XDM_ERI_TO_NAR(a) _XDM_ERI_TO_NAR(a & 0xFFFF) - -/* Convert 7-bit NAR address back to ERI/APB address/offset: */ -#define _XDM_NAR_TO_APB(a) ((a) <= 0x1f ? ((a) << 2) \ - :(a) >= 0x20 && (a) <= 0x3F ? (0x1000 | (((a)& 7) << 2) | (((a)&0x18)<<4)) \ - :(a) >= 0x40 && (a) <= 0x4F ? (0x2000 | (((a)&0xF) << 2)) \ - :(a) >= 0x58 && (a) <= 0x5F ? (0x3000 | (((a)&0xF) << 2)) \ - :(a) == 0x60 ? (0x3F00) \ - :(a) >= 0x68 && (a) <= 0x7F ? (0x3F80 | (((a)&0x1F) << 2)) \ - : -1) - -#define XDM_NAR_TO_APB(a) _XDM_NAR_TO_APB((a & 0xFFFF)) -#define XDM_NAR_TO_ERI(a) _XDM_NAR_TO_APB((a & 0xFFFF)) | 0x100000 - -/* Convert APB to ERI address */ -#define XDM_APB_TO_ERI(a) ((a) | (0x100000)) -#define XDM_ERI_TO_APB(a) ((a) & (0x0FFFFF)) - -/*********** Bit definitions within some of the above registers ***********/ -#define OCD_ID_LSDDRP 0x01000000 -#define OCD_ID_LSDDRP_SHIFT 24 -#define OCD_ID_ENDIANESS 0x00000001 -#define OCD_ID_ENDIANESS_SHIFT 0 -#define OCD_ID_PSO 0x0000000C -#define OCD_ID_PSO_SHIFT 2 -#define OCD_ID_TRACEPORT 0x00000080 -#define OCD_ID_TRACEPORT_SHIFT 7 - -#define OCD_ID_LSDDRP_XEA3 0x00000400 - -/* Power Status register. NOTE: different bit positions in JTAG vs. ERI/APB !! */ -/* ERI/APB: */ -#define PWRSTAT_CORE_DOMAIN_ON 0x00000001 /* set if core is powered on */ -#define PWRSTAT_CORE_DOMAIN_ON_SHIFT 0 -#define PWRSTAT_WAKEUP_RESET 0x00000002 /* [ERI only] 0=cold start, 1=PSO wakeup */ -#define PWRSTAT_WAKEUP_RESET_SHIFT 1 -#define PWRSTAT_CACHES_LOST_POWER 0x00000004 /* [ERI only] set if caches (/localmems?) lost power */ - /* FIXME: does this include local memories? */ -#define PWRSTAT_CACHES_LOST_POWER_SHIFT 2 -#define PWRSTAT_CORE_STILL_NEEDED 0x00000010 /* set if others keeping core awake */ -#define PWRSTAT_CORE_STILL_NEEDED_SHIFT 4 -#define PWRSTAT_MEM_DOMAIN_ON 0x00000100 /* set if memory domain is powered on */ -#define PWRSTAT_MEM_DOMAIN_ON_SHIFT 8 -#define PWRSTAT_DEBUG_DOMAIN_ON 0x00001000 /* set if debug domain is powered on */ -#define PWRSTAT_DEBUG_DOMAIN_ON_SHIFT 12 -#define PWRSTAT_ALL_ON (PWRSTAT_CORE_DOMAIN_ON | PWRSTAT_MEM_DOMAIN_ON | PWRSTAT_DEBUG_DOMAIN_ON) -#define PWRSTAT_CORE_WAS_RESET 0x00010000 /* [APB only] set if core got reset */ -#define PWRSTAT_CORE_WAS_RESET_SHIFT 16 -#define PWRSTAT_DEBUG_WAS_RESET 0x10000000 /* set if debug module got reset */ -#define PWRSTAT_DEBUG_WAS_RESET_SHIFT 28 -/* JTAG: */ -#define J_PWRSTAT_CORE_DOMAIN_ON 0x01 /* set if core is powered on */ -#define J_PWRSTAT_MEM_DOMAIN_ON 0x02 /* set if memory domain is powered on */ -#define J_PWRSTAT_DEBUG_DOMAIN_ON 0x04 /* set if debug domain is powered on */ -#define J_PWRSTAT_ALL_ON (J_PWRSTAT_CORE_DOMAIN_ON | J_PWRSTAT_MEM_DOMAIN_ON | J_PWRSTAT_DEBUG_DOMAIN_ON) -#define J_PWRSTAT_CORE_STILL_NEEDED 0x08 /* set if others keeping core awake */ -#define J_PWRSTAT_CORE_WAS_RESET 0x10 /* set if core got reset */ -#define J_PWRSTAT_DEBUG_WAS_RESET 0x40 /* set if debug module got reset */ - -/* Power Control register. NOTE: different bit positions in JTAG vs. ERI/APB !! */ -/* ERI/APB: */ -#define PWRCTL_CORE_SHUTOFF 0x00000001 /* [ERI only] core wants to shut off on WAITI */ -#define PWRCTL_CORE_SHUTOFF_SHIFT 0 -#define PWRCTL_CORE_WAKEUP 0x00000001 /* [APB only] set to force core to stay powered on */ -#define PWRCTL_CORE_WAKEUP_SHIFT 0 -#define PWRCTL_MEM_WAKEUP 0x00000100 /* set to force memory domain to stay powered on */ -#define PWRCTL_MEM_WAKEUP_SHIFT 8 -#define PWRCTL_DEBUG_WAKEUP 0x00001000 /* set to force debug domain to stay powered on */ -#define PWRCTL_DEBUG_WAKEUP_SHIFT 12 -#define PWRCTL_ALL_ON (PWRCTL_CORE_WAKEUP | PWRCTL_MEM_WAKEUP | PWRCTL_DEBUG_WAKEUP) -#define PWRCTL_CORE_RESET 0x00010000 /* [APB only] set to assert core reset */ -#define PWRCTL_CORE_RESET_SHIFT 16 -#define PWRCTL_DEBUG_RESET 0x10000000 /* set to assert debug module reset */ -#define PWRCTL_DEBUG_RESET_SHIFT 28 -/* JTAG: */ -#define J_PWRCTL_CORE_WAKEUP 0x01 /* set to force core to stay powered on */ -#define J_PWRCTL_MEM_WAKEUP 0x02 /* set to force memory domain to stay powered on */ -#define J_PWRCTL_DEBUG_WAKEUP 0x04 /* set to force debug domain to stay powered on */ -#define J_DEBUG_USE 0x80 /* */ -#define J_PWRCTL_ALL_ON (J_DEBUG_USE | J_PWRCTL_CORE_WAKEUP | J_PWRCTL_MEM_WAKEUP | J_PWRCTL_DEBUG_WAKEUP) -#define J_PWRCTL_DEBUG_ON J_DEBUG_USE | J_PWRCTL_DEBUG_WAKEUP -#define J_PWRCTL_CORE_RESET 0x10 /* set to assert core reset */ -#define J_PWRCTL_DEBUG_RESET 0x40 /* set to assert debug module reset */ - -#define J_PWRCTL_WRITE_MASK 0xFF -#define J_PWRSTAT_WRITE_MASK 0xFF - -#define PWRCTL_WRITE_MASK ~0 -#define PWRSTAT_WRITE_MASK ~0 - -/************ The following are only relevant for JTAG, so perhaps belong in OCD only **************/ - -/* XDM 5-bit JTAG Instruction Register (IR) values: */ -#define XDM_IR_PWRCTL 0x08 /* select 8-bit Power/Reset Control (PRC) */ -#define XDM_IR_PWRSTAT 0x09 /* select 8-bit Power/Reset Status (PRS) */ -#define XDM_IR_NAR_SEL 0x1c /* select altern. 8-bit NAR / 32-bit NDR (Nexus-style) */ -#define XDM_IR_NDR_SEL 0x1d /* select altern. 32-bit NDR / 8-bit NAR - (FIXME - functionality not yet in HW) */ -#define XDM_IR_IDCODE 0x1e /* select 32-bit JTAG IDCODE */ -#define XDM_IR_BYPASS 0x1f /* select 1-bit bypass */ - -#define XDM_IR_WIDTH 5 /* width of IR for Xtensa TAP */ - -/* NAR register bits: */ -#define XDM_NAR_WRITE 0x01 -#define XDM_NAR_ADDR_MASK 0xFE -#define XDM_NAR_ADDR_SHIFT 1 - -#define XDM_NAR_BUSY 0x02 -#define XDM_NAR_ERROR 0x01 - -#define NEXUS_DIR_READ 0x00 -#define NEXUS_DIR_WRITE 0x01 - -/************ Define DCR register bits **************/ - -#define DCR_ENABLEOCD 0x0000001 -#define DCR_ENABLEOCD_SHIFT 0 -#define DCR_DEBUG_INT 0x0000002 -#define DCR_DEBUG_INT_SHIFT 1 -#define DCR_DEBUG_OVERRIDE 0x0000004 -#define DCR_DEBUG_OVERRIDE_SHIFT 2 -#define DCR_DEBUG_SS_REQ 0x0000008 -#define DCR_DEBUG_SS_REQ_SHIFT 3 -#define DCR_MASK_NMI 0x0000020 -#define DCR_MASK_NMI_SHIFT 5 -#define DCR_STEP_ENABLE 0x0000040 -#define DCR_STEP_ENABLE_SHIFT 6 -#define DCR_BREAK_IN_EN 0x0010000 -#define DCR_BREAK_IN_EN_SHIFT 16 -#define DCR_BREAK_OUT_EN 0x0020000 -#define DCR_BREAK_OUT_EN_SHIFT 17 -#define DCR_DEBUG_INT_EN 0x0040000 -#define DCR_DEBUG_INT_EN_SHIFT 18 -#define DCR_DBG_SW_ACTIVE 0x0100000 -#define DCR_DBG_SW_ACTIVE_SHIFT 20 -#define DCR_STALL_IN_EN 0x0200000 -#define DCR_STALL_IN_EN_SHIFT 21 -#define DCR_DEBUG_OUT_EN 0x0400000 -#define DCR_DEBUG_OUT_EN_SHIFT 22 -#define DCR_BREAK_OUT_ITO 0x1000000 -#define DCR_STALL_OUT_ITO 0x2000000 -#define DCR_STALL_OUT_ITO_SHIFT 25 - -/************ Define DSR register bits **************/ - -#define DOSR_STOP_CAUSE_SHIFT 5 -#define DOSR_STOP_CAUSE_MASK 0xF - -#define DOSR_EXECDONE_SHIFT 0 -#define DOSR_EXECDONE_ER 0x01 -#define DOSR_EXECDONE_SHIFT 0 -#define DOSR_EXCEPTION_ER 0x02 -#define DOSR_EXCEPTION_SHIFT 1 -#define DOSR_BUSY 0x04 -#define DOSR_BUSY_SHIFT 2 -#define DOSR_OVERRUN 0x08 -#define DOSR_OVERRUN_SHIFT 3 -#define DOSR_INOCDMODE_ER 0x10 -#define DOSR_INOCDMODE_SHIFT 4 -#define DOSR_CORE_WROTE_DDR_ER 0x400 -#define DOSR_CORE_WROTE_DDR_SHIFT 10 -#define DOSR_CORE_READ_DDR_ER 0x800 -#define DOSR_CORE_READ_DDR_SHIFT 11 -#define DOSR_HOST_WROTE_DDR_ER 0x4000 -#define DOSR_HOST_WROTE_DDR_SHIFT 14 -#define DOSR_HOST_READ_DDR_ER 0x8000 -#define DOSR_HOST_READ_DDR_SHIFT 15 - -#define DOSR_DEBUG_PEND_BIN 0x10000 -#define DOSR_DEBUG_PEND_HOST 0x20000 -#define DOSR_DEBUG_PEND_TRAX 0x40000 -#define DOSR_DEBUG_BIN 0x100000 -#define DOSR_DEBUG_HOST 0x200000 -#define DOSR_DEBUG_TRAX 0x400000 -#define DOSR_DEBUG_PEND_BIN_SHIFT 16 -#define DOSR_DEBUG_PEND_HOST_SHIFT 17 -#define DOSR_DEBUG_PEND_TRAX_SHIFT 18 -#define DOSR_DEBUG_BREAKIN 0x0100000 -#define DOSR_DEBUG_BREAKIN_SHIFT 20 -#define DOSR_DEBUG_HOST_SHIFT 21 -#define DOSR_DEBUG_TRAX_SHIFT 22 - -#define DOSR_DEBUG_STALL 0x1000000 -#define DOSR_DEBUG_STALL_SHIFT 24 - -#define DOSR_CORE_ON 0x40000000 -#define DOSR_CORE_ON_SHIFT 30 -#define DOSR_DEBUG_ON 0x80000000 -#define DOSR_DEBUG_ON_SHIFT 31 - -/********** Performance monitor registers bits **********/ - -#define PERF_PMG_ENABLE 0x00000001 /* global enable bit */ -#define PERF_PMG_ENABLE_SHIFT 0 - -#define PERF_PMCTRL_INT_ENABLE 0x00000001 /* assert interrupt on overflow */ -#define PERF_PMCTRL_INT_ENABLE_SHIFT 0 -#define PERF_PMCTRL_KRNLCNT 0x00000008 /* ignore TRACELEVEL */ -#define PERF_PMCTRL_KRNLCNT_SHIFT 3 -#define PERF_PMCTRL_TRACELEVEL 0x000000F0 /* count when CINTLEVEL <= TRACELEVEL */ -#define PERF_PMCTRL_TRACELEVEL_SHIFT 4 -#define PERF_PMCTRL_SELECT 0x00001F00 /* events group selector */ -#define PERF_PMCTRL_SELECT_SHIFT 8 -#define PERF_PMCTRL_MASK 0xFFFF0000 /* events mask */ -#define PERF_PMCTRL_MASK_SHIFT 16 - -#define PERF_PMSTAT_OVERFLOW 0x00000001 /* counter overflowed */ -#define PERF_PMSTAT_OVERFLOW_SHIFT 0 -#define PERF_PMSTAT_INT 0x00000010 /* interrupt asserted */ -#define PERF_PMSTAT_INT_SHIFT 4 - -#if defined (USE_XDM_REGNAME) || defined (USE_DAP_REGNAME) -/* Describes XDM register: */ -typedef struct { - int reg; - char* name; -} regdef_t; - -/* - * Returns the name of the specified XDM register number, - * or simply "???" if the register number is not recognized. - * FIXME - requires -1 as the last entry - change to compare the name to ??? - * or even better, make the code above to work. - */ -static char* -regname(regdef_t* list, int reg) -{ - int i = 0; - while (list[i].reg != -1) { - if (list[i].reg == reg) - break; - i++; - } - return list[i].name; -} - -#if defined (USE_XDM_REGNAME) -static regdef_t xdm_reglist[] = -{ - {XDM_OCD_DSR ,"DOSR" }, - {XDM_OCD_DDR ,"DDR" }, - {XDM_OCD_DDREXEC ,"DDREXEC" }, - {XDM_OCD_DIR0EXEC ,"DIR0EXEC"}, - {XDM_OCD_DCR_CLR ,"DCR_CLR" }, - {XDM_OCD_DCR_SET ,"DCR_SET" }, - {XDM_TRAX_CONTROL ,"CONTROL" }, - {XDM_TRAX_STATUS ,"STATUS" }, - {XDM_TRAX_DATA ,"DATA" }, - {XDM_TRAX_ADDRESS ,"ADDRESS" }, - - {XDM_TRAX_ID ,"TRAX_ID" }, - - {XDM_TRAX_TRIGGER ,"TRIGGER PC" }, - {XDM_TRAX_MATCH ,"PC MATCH" }, - {XDM_TRAX_DELAY ,"DELAY CNT." }, - {XDM_TRAX_STARTADDR ,"START ADDRESS"}, - {XDM_TRAX_ENDADDR ,"END ADDRESS" }, - {XDM_TRAX_DEBUGPC ,"DEBUG PC" }, - {XDM_TRAX_P4CHANGE ,"P4 CHANGE" }, - {XDM_TRAX_P4REV ,"P4 REV." }, - {XDM_TRAX_P4DATE ,"P4 DATE" }, - {XDM_TRAX_P4TIME ,"P4 TIME" }, - {XDM_TRAX_PDSTATUS ,"PD STATUS" }, - {XDM_TRAX_PDDATA ,"PD DATA" }, - {XDM_TRAX_STOP_PC ,"STOP PC" }, - {XDM_TRAX_STOP_ICNT ,"STOP ICNT" }, - {XDM_TRAX_MSG_STATUS,"MSG STAT." }, - {XDM_TRAX_FSM_STATUS,"FSM STAT." }, - {XDM_TRAX_IB_STATUS ,"IB STAT." }, - - {XDM_OCD_ID ,"OCD_ID" }, - {XDM_OCD_DIR0 ,"DIR0" }, - {XDM_OCD_DIR1 ,"DIR1" }, - {XDM_OCD_DIR2 ,"DIR2" }, - {XDM_OCD_DIR3 ,"DIR3" }, - {XDM_OCD_DIR4 ,"DIR4" }, - {XDM_OCD_DIR5 ,"DIR5" }, - {XDM_OCD_DIR6 ,"DIR6" }, - {XDM_OCD_DIR7 ,"DIR7" }, - - {XDM_PERF_PMG ,"PMG" }, - {XDM_PERF_INTPC ,"INTPC" }, - {XDM_PERF_PM0 ,"PM0 " }, - {XDM_PERF_PM1 ,"PM1 " }, - {XDM_PERF_PM2 ,"PM2 " }, - {XDM_PERF_PM3 ,"PM3 " }, - {XDM_PERF_PM4 ,"PM4 " }, - {XDM_PERF_PM5 ,"PM5 " }, - {XDM_PERF_PM6 ,"PM6 " }, - {XDM_PERF_PM7 ,"PM7 " }, - {XDM_PERF_PMCTRL0 ,"PMCTRL0"}, - {XDM_PERF_PMCTRL1 ,"PMCTRL1"}, - {XDM_PERF_PMCTRL2 ,"PMCTRL2"}, - {XDM_PERF_PMCTRL3 ,"PMCTRL3"}, - {XDM_PERF_PMCTRL4 ,"PMCTRL4"}, - {XDM_PERF_PMCTRL5 ,"PMCTRL5"}, - {XDM_PERF_PMCTRL6 ,"PMCTRL6"}, - {XDM_PERF_PMCTRL7 ,"PMCTRL7"}, - {XDM_PERF_PMSTAT0 ,"PMSTAT0"}, - {XDM_PERF_PMSTAT1 ,"PMSTAT1"}, - {XDM_PERF_PMSTAT2 ,"PMSTAT2"}, - {XDM_PERF_PMSTAT3 ,"PMSTAT3"}, - {XDM_PERF_PMSTAT4 ,"PMSTAT4"}, - {XDM_PERF_PMSTAT5 ,"PMSTAT5"}, - {XDM_PERF_PMSTAT6 ,"PMSTAT6"}, - {XDM_PERF_PMSTAT7 ,"PMSTAT7"}, - - {XDM_MISC_PWRCTL ,"PWRCTL" }, - {XDM_MISC_PWRSTAT ,"PWRSTAT" }, - {XDM_MISC_ERISTAT ,"ERISTAT" }, - {XDM_MISC_DATETIME ,"DATETIME"}, - {XDM_MISC_UBID ,"UBID" }, - {XDM_MISC_CID ,"CID" }, - - {XDM_CS_ITCTRL ,"ITCTRL" }, - {XDM_CS_CLAIMSET ,"CLAIMSET" }, - {XDM_CS_CLAIMCLR ,"CLAIMCLR" }, - {XDM_CS_LOCK_ACCESS ,"LOCK_ACCESS"}, - {XDM_CS_LOCK_STATUS ,"LOCK_STATUS"}, - {XDM_CS_AUTH_STATUS ,"AUTH_STATUS"}, - {XDM_CS_DEV_ID ,"DEV_ID" }, - {XDM_CS_DEV_TYPE ,"DEV_TYPE" }, - {XDM_CS_PER_ID4 ,"PER_ID4" }, - {XDM_CS_PER_ID5 ,"PER_ID5" }, - {XDM_CS_PER_ID6 ,"PER_ID6" }, - {XDM_CS_PER_ID7 ,"PER_ID7" }, - {XDM_CS_PER_ID0 ,"PER_ID0" }, - {XDM_CS_PER_ID1 ,"PER_ID1" }, - {XDM_CS_PER_ID2 ,"PER_ID2" }, - {XDM_CS_PER_ID3 ,"PER_ID3" }, - {XDM_CS_COMP_ID0 ,"COMP_ID0" }, - {XDM_CS_COMP_ID1 ,"COMP_ID1" }, - {XDM_CS_COMP_ID2 ,"COMP_ID2" }, - {XDM_CS_COMP_ID3 ,"COMP_ID3" }, - {-1 ,"???" }, -}; -#endif - -#endif - -#endif /* _XDM_REGS_H_ */ diff --git a/src/arch/xtensa/include/xtensa/xmon.h b/src/arch/xtensa/include/xtensa/xmon.h deleted file mode 100644 index 34c90dc92902..000000000000 --- a/src/arch/xtensa/include/xtensa/xmon.h +++ /dev/null @@ -1,156 +0,0 @@ -/* xmon.h - XMON definitions - * - * $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xmon/xmon.h#1 $ - * - * Copyright (c) 2001-2013 Tensilica 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. - */ - -#ifndef __H_XMON -#define __H_XMON - -#ifndef UCHAR -# define UCHAR unsigned char -#endif - -#ifndef C_UCHAR -# define C_UCHAR const unsigned char -#endif - -#ifndef UINT32 -# define UINT32 unsigned int -#endif - -/* Default GDB packet size */ -#define GDB_PKT_SIZE 4096 - -/*XMON signals */ -#define XMON_SIGINT 2 /*target was interrupted */ -#define XMON_SIGILL 4 /*illegal instruction */ -#define XMON_SIGTRAP 5 /*general exception */ -#define XMON_SIGSEGV 11 /*page faults */ - - -/* Type of log message from XMON to the application */ -typedef enum { - XMON_LOG, - XMON_TRACE, - XMON_ERR, -} xmon_log_t; - - -#ifdef _cplusplus -extern "C" { -#endif - -/* - * THE FOLLOWING ROUTINES ARE USED BY THE USER - */ - -/** - * Initialize XMON so GDB can attach. - * gdbBuf - pointer to a buffer XMON uses to comm. with GDB - * gdbPktSize - Size of the allocated buffer for GDB communication. - * xlog - log handler for XMON produced errors/logs/traces - - */ -extern int -_xmon_init(char* gdbBuf, int gdbPktSize, - void(*xlog)(xmon_log_t type, const char* str)); - -/** - * Detach from XMON. Can execute at any time - */ -extern void -_xmon_close(void); - -/** - * Print message to GDB - */ -extern void -_xmon_consoleString(const char* str); - -/** - * XMON version - */ -extern const char* -_xmon_version(); - -/** - * Enable disable various logging and tracing chains - * app_log_en - enable/disable logging to the app log handler. - * ENABLED BY DEFAULT. - * app_trace_en - enable/disable tracing to the app log handler. - * DISABLED BY DEFAULT. - * gdb_log_en - enable/disable log notifications to the GDB. - * ENABLED BY DEFAULT. - * gdb_trace_en - enable/disable tracing notifications to the GDB. - * DISABLED BY DEFAULT. - */ -extern void -_xmon_log(char app_log_en, char app_trace_en, - char gdb_log_en, char gdb_trace_en); - -//extern int -//_xmon_process_packet (int len, char* buf); - -//extern int -//_xmon_process_packet2 (void); - -/* - * THE FOLLOWING ROUTINES NEED TO BE PROVIDED BY USER - */ - -/* - * Receive remote packet bytes from GDB - * wait: If the function would block waiting for more - * characters from gdb, wait=0 instructs it to - * return 0 immediatelly. Otherwise, if wait=1, - * the function may or may not wait for GDB. - * NOTE: Current XMON version supports single char - * input only (return value is 1 always) - * buf: Pointer to the buffer for the received data. - * Returns: 0 - no data avaiable, - >0 - length of received array in buf. - */ -extern int -_xmon_in(int wait, UCHAR* buf); - -/* - * Output an array of chars to GDB - * len - number of chars in the array - */ -extern void -_xmon_out(int len, UCHAR*); - -/* - * Flush output characthers - * XMON invokes this one when a full response is ready - */ -extern int -_xmon_flush(void); // flush output characters - -#ifdef _cplusplus -} -#endif - - -#endif diff --git a/src/arch/xtensa/include/xtensa/xtbsp.h b/src/arch/xtensa/include/xtensa/xtbsp.h deleted file mode 100644 index 0781e4154f4f..000000000000 --- a/src/arch/xtensa/include/xtensa/xtbsp.h +++ /dev/null @@ -1,287 +0,0 @@ -/******************************************************************************* - - Copyright (c) 2006-2009 Tensilica 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. - --------------------------------------------------------------------------------- - -xtbsp.h Xtensa Board Support Package API - -This API defines a minimal set of board-support functions that every supported -Xtensa board is expected to provide in the board-support-package (BSP) library -associated with the board-specific LSP. Only basic board functions are provided -in this board-independent API. API functions not applicable to a board must be -stubbed in its BSP library. More complex operations must use a board-specific -interface. Functions are grouped by type of peripheral device. - -*******************************************************************************/ - -#ifndef _XTBSP_H_ -#define _XTBSP_H_ - - -#ifdef __cplusplus -extern "C" { -#endif - - -/******************************************************************************* -BOARD INITIALIZATION. -The board with all its devices is initialized by xtbsp_board_init(). -Individual devices represented by this API can be reinitialized at any -time by calling their inidividual device init functions (grouped with -other device functions). This might be useful to (say) change the baud -rate of the UART. -*/ - - -/* -Initialize the board. Must call before any other API function. -Iniitializes BSP, board in general, and all devices on the board. -*/ -extern void xtbsp_board_init(void); - - -/******************************************************************************* -BOARD CHARACTERISTICS and CONVENIENCE FUNCTIONS. -Board support functions not associated with a particular peripheral device. -*/ - -/* -Return a short string representing the type of board. -If the board has a display, the string must fit on a single line. -*/ -extern const char * xtbsp_board_name(void); - -/* -Hardware reset the entire board (if possible). Does not return if successful. -If this function returns, it is stubbed out or not possible with this board. -*/ -extern void xtbsp_board_reset(void); - -/* -Return the clock frequency in Hertz. May be constant or computed. -*/ -extern unsigned xtbsp_clock_freq_hz(void); - -/* -Return the clock period in picoseconds. May be constant or computed. -*/ -extern unsigned xtbsp_clock_period_ps(void); - -/* -Spin (at least) a number of cycles per the processor's CCOUNT register. -Unlike a s/w delay loop, the duration is not affected by compiler -optimization or interrupts completed within the delay period. -If the processor doesn't have CCOUNT, a s/w delay loop is used to obtain -a rough approximation of the cycle count. -*/ -extern void xtbsp_delay_cycles(unsigned cycles); - -/* -Spin at least a number of nanoseconds (approximate and err in the high side). -BSP implementation should do this efficiently, avoiding integer overflow or -excessive loss of precision, run-time division or floating point. -Function implementation (vs. macro) allows BSP to optimize for the clock -frequency by pre-computing (or using constant) scale factors. -*/ -extern void xtbsp_delay_ns(unsigned ns); - - -/******************************************************************************* -C LIBRARY SUPPORT. -These functions are called by the C library libgloss interface. -Their names are predetermined apart from this BSP API. -*/ - -/* -Initialize the board. Called by C library initialization code. -Usually simply calls xtbsp_board_init(). -*/ -extern void board_init(void); - -/* -(Wait for and) Input a single byte from the default character I/O -device. Return -1 if there is no input device. -This device is usually a UART and this function calls xtbsp_uart_getchar(). -On some boards (eg.) it might be a directly connected keyboard. -*/ -extern int inbyte(void); - -/* -Output a single char to the default character I/O device (and wait -until it's been taken). -This device is usually a UART and this function calls xtbsp_uart_putchar(). -On some boards (eg.) it might be a directly connected bit-mapped screen. -*/ -extern void outbyte(int c); - - -/******************************************************************************* -UART (SERIAL I/O). -Supports a single UART in a simple polling mode and provides control of -receiver and transmitter data interrupts (client must provide handler). -Provides a mapping to processor interrupt number which can be used with -the HAL to control processor interrupt enable (INTENABLE) etc. -*/ - -/* Bitmasks to identify UART interrupts. */ -typedef enum xtbsp_uart_int { - xtbsp_uart_int_rx = 1<<0, - xtbsp_uart_int_tx = 1<<1, - /* mask of all valid interrupt bits */ - xtbsp_uart_int_all = (1<<2)-1 -} xtbsp_uart_int; - -/* -Return non-zero if the board has a UART. -*/ -extern int xtbsp_uart_exists(void); - -/* -Initialize the UART: - parity = 0 (none), 1 (odd), or 2 (even). - nstop = 1 or 2 (stop bits). - ndata = 7 or 8 (data bits). -Disables all UART interrupts. -Returns non-zero if failed (perhaps due to unsupported parameter values). -Must call before any of the following functions. -*/ -extern int xtbsp_uart_init(unsigned baud, unsigned ndata, - unsigned parity, unsigned nstop); -#define xtbsp_uart_init_default() xtbsp_uart_init(38400, 8, 0, 1) - -/* - Extended init routine for 'portable' UART. Allows specifying the UART - base address and interrupt number (if interrupt operation desired). - Meant for use on platforms other than the FPGA boards (e.g. XTSC sim - or Palladium). - - NOTE: Using the 'portable' UART may require that you implement function - xtbsp_clock_freq_hz() if your target platform does not provide it. - We recommend you implement it as a weak function so that it can be - overridden by the target platform implementation if available. - */ -extern int xtbsp_uart_init_ex(unsigned uart_baseaddr, - unsigned uart_intnum, - unsigned baud, - unsigned ndata, - unsigned parity, - unsigned nstop); - -/* -(Wait for and) Input a single char from the UART. -Any pending xtbsp_uart_int_rx interrupt is cleared. -*/ -extern char xtbsp_uart_getchar(void); - -/* -(Wait for transmitter ready and) Output a single char to the UART. -Any pending xtbsp_uart_int_tx interrupt is cleared. -*/ -extern void xtbsp_uart_putchar(const char c); - -/* -Return true (non-zero) if a character has been received and is ready -to be input by xtbsp_uart_getchar() without waiting, else return 0. -*/ -extern int xtbsp_uart_get_isready(void); - -/* -Return non-zero if a character may be output by xtbsp_uart_putchar() -without waiting, else return 0. -Any pending xtbsp_uart_int_tx interrupt is cleared. -*/ -extern int xtbsp_uart_put_isready(void); - -/* -Return the enable status of all UART interrupts represented by this API, -that is those with bits defined in type xtbsp_uart_int (1 bit = enabled). -This is the enable status at the device, not the processor's INTENABLE. -*/ -extern xtbsp_uart_int xtbsp_uart_int_enable_status(void); - -/* -Enable selected UART interrupts at the device. -*/ -extern void xtbsp_uart_int_enable(const xtbsp_uart_int mask); - -/* -Disable selected UART interrupts at the device. -*/ -extern void xtbsp_uart_int_disable(const xtbsp_uart_int mask); - -/* -Return the interrupt number (0..31) to which the selected UART interrupt -is connected. May be used with the link-time HAL to obtain more information, -eg. Xthal_intlevel_mask[xtbsp_uart_int_number(xtbsp_uart_int_rx)] -This information can be used to control the processor's INTENABLE, etc. -Result is -1 if not connected, undefined if mask has more than 1 bit set. -*/ -extern int xtbsp_uart_int_number(const xtbsp_uart_int mask); - - -/******************************************************************************* -DISPLAY. -Supports a single display that can render a series of ASCII characters. -Functions are provided to perform generic display tasks such as display -a string, display character by character, or blank the display. -Chars are 7-bit printable ASCII. Strings are C style NUL \0 terminated. -These functions busy-wait for any required timing delays so the caller does -not have to deal with timing. Some displays require long delays which in -some client applications warrant a board and RTOS specific approach to -driving the display, however that is beyond the scope of this API. -*/ - -/* -Return non-zero if board has a display. -*/ -extern int xtbsp_display_exists(void); - -/* -Initialize the display. Must call before any of the following functions. -*/ -extern void xtbsp_display_init(void); - -/* -Display a single char at position pos (0 is leftmost). Other positions are -left untouched. Positions beyond the width of the display are ignored. -*/ -extern void xtbsp_display_char(unsigned pos, const char c); - -/* -Display a string. Blank-pad to or truncate at the end of the display -(overwrites any previous string so don't need to blank display first). -*/ -extern void xtbsp_display_string(const char *s); - -/* -Blank (clear) the entire display. -*/ -extern void xtbsp_display_blank(void); - - - -#ifdef __cplusplus -} -#endif - -#endif /* _XTBSP_H_ */ diff --git a/src/arch/xtensa/include/xtensa/xtensa-libdb-macros.h b/src/arch/xtensa/include/xtensa/xtensa-libdb-macros.h deleted file mode 100644 index 8f67184d3454..000000000000 --- a/src/arch/xtensa/include/xtensa/xtensa-libdb-macros.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * xtensa-libdb-macros.h - */ - -/* $Id: //depot/rel/Foxhill/dot.8/Xtensa/Software/libdb/xtensa-libdb-macros.h#1 $ */ - -/* Copyright (c) 2004-2008 Tensilica 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. */ - -#ifndef __H_LIBDB_MACROS -#define __H_LIBDB_MACROS - -/* - * This header file provides macros used to construct, identify and use - * "target numbers" that are assigned to various types of Xtensa processor - * registers and states. These target numbers are used by GDB in the remote - * protocol, and are thus used by all GDB debugger agents (targets). - * They are also used in ELF debugger information sections (stabs, dwarf, etc). - * - * These macros are separated from xtensa-libdb.h because they are needed - * by certain debugger agents that do not use or have access to libdb, - * e.g. the OCD daemon, RedBoot, XMON, etc. - * - * For the time being, for compatibility with certain 3rd party debugger - * software vendors, target numbers are limited to 16 bits. It is - * conceivable that this will be extended in the future to 32 bits. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef uint32 - #define uint32 unsigned int -#endif -#ifndef int32 - #define int32 int -#endif - - -/* - * Macros to form register "target numbers" for various standard registers/states: - */ -#define XTENSA_DBREGN_INVALID -1 /* not a valid target number */ -#define XTENSA_DBREGN_A(n) (0x0000+(n)) /* address registers a0..a15 */ -#define XTENSA_DBREGN_B(n) (0x0010+(n)) /* boolean bits b0..b15 */ -#define XTENSA_DBREGN_PC 0x0020 /* program counter */ - /* 0x0021 RESERVED for use by Tensilica */ -#define XTENSA_DBREGN_BO(n) (0x0022+(n)) /* boolean octuple-bits bo0..bo1 */ -#define XTENSA_DBREGN_BQ(n) (0x0024+(n)) /* boolean quadruple-bits bq0..bq3 */ -#define XTENSA_DBREGN_BD(n) (0x0028+(n)) /* boolean double-bits bd0..bd7 */ -#define XTENSA_DBREGN_F(n) (0x0030+(n)) /* floating point registers f0..f15 */ -#define XTENSA_DBREGN_VEC(n) (0x0040+(n)) /* Vectra vec regs v0..v15 */ -#define XTENSA_DBREGN_VSEL(n) (0x0050+(n)) /* Vectra sel s0..s3 (V1) ..s7 (V2) */ -#define XTENSA_DBREGN_VALIGN(n) (0x0058+(n)) /* Vectra valign regs u0..u3 */ -#define XTENSA_DBREGN_VCOEFF(n) (0x005C+(n)) /* Vectra I vcoeff regs c0..c1 */ - /* 0x005E..0x005F RESERVED for use by Tensilica */ -#define XTENSA_DBREGN_AEP(n) (0x0060+(n)) /* HiFi2 Audio Engine regs aep0..aep7 */ -#define XTENSA_DBREGN_AEQ(n) (0x0068+(n)) /* HiFi2 Audio Engine regs aeq0..aeq3 */ - /* 0x006C..0x00FF RESERVED for use by Tensilica */ -#define XTENSA_DBREGN_AR(n) (0x0100+(n)) /* physical address regs ar0..ar63 - (note: only with window option) */ - /* 0x0140..0x01FF RESERVED for use by Tensilica */ -#define XTENSA_DBREGN_SREG(n) (0x0200+(n)) /* special registers 0..255 (core) */ -#define XTENSA_DBREGN_BR XTENSA_DBREGN_SREG(0x04) /* all 16 boolean bits, BR */ -#define XTENSA_DBREGN_MR(n) XTENSA_DBREGN_SREG(0x20+(n)) /* MAC16 registers m0..m3 */ -#define XTENSA_DBREGN_UREG(n) (0x0300+(n)) /* user registers 0..255 (TIE) */ - /* 0x0400..0x0FFF RESERVED for use by Tensilica */ - /* 0x1000..0x1FFF user-defined regfiles */ - /* 0x2000..0xEFFF other states (and regfiles) */ -#define XTENSA_DBREGN_DBAGENT(n) (0xF000+(n)) /* non-processor "registers" 0..4095 for - 3rd-party debugger agent defined use */ - /* > 0xFFFF (32-bit) RESERVED for use by Tensilica */ -/*#define XTENSA_DBREGN_CONTEXT(n) (0x02000000+((n)<<20))*/ /* add this macro's value to a target - number to identify a specific context 0..31 - for context-replicated registers */ -#define XTENSA_DBREGN_MASK 0xFFFF /* mask of valid target_number bits */ -#define XTENSA_DBREGN_WRITE_SIDE 0x04000000 /* flag to request write half of a register - split into distinct read and write entries - with the same target number (currently only - valid in a couple of libdb API functions; - see xtensa-libdb.h for details) */ - -/* - * Macros to identify specific ranges of target numbers (formed above): - * NOTE: any context number (or other upper 12 bits) are considered - * modifiers and are thus stripped out for identification purposes. - */ -#define XTENSA_DBREGN_IS_VALID(tn) (((tn) & ~0xFFFF) == 0) /* just tests it's 16-bit unsigned */ -#define XTENSA_DBREGN_IS_A(tn) (((tn) & 0xFFF0)==0x0000) /* is a0..a15 */ -#define XTENSA_DBREGN_IS_B(tn) (((tn) & 0xFFF0)==0x0010) /* is b0..b15 */ -#define XTENSA_DBREGN_IS_PC(tn) (((tn) & 0xFFFF)==0x0020) /* is program counter */ -#define XTENSA_DBREGN_IS_BO(tn) (((tn) & 0xFFFE)==0x0022) /* is bo0..bo1 */ -#define XTENSA_DBREGN_IS_BQ(tn) (((tn) & 0xFFFC)==0x0024) /* is bq0..bq3 */ -#define XTENSA_DBREGN_IS_BD(tn) (((tn) & 0xFFF8)==0x0028) /* is bd0..bd7 */ -#define XTENSA_DBREGN_IS_F(tn) (((tn) & 0xFFF0)==0x0030) /* is f0..f15 */ -#define XTENSA_DBREGN_IS_VEC(tn) (((tn) & 0xFFF0)==0x0040) /* is v0..v15 */ -#define XTENSA_DBREGN_IS_VSEL(tn) (((tn) & 0xFFF8)==0x0050) /* is s0..s7 (s0..s3 in V1) */ -#define XTENSA_DBREGN_IS_VALIGN(tn) (((tn) & 0xFFFC)==0x0058) /* is u0..u3 */ -#define XTENSA_DBREGN_IS_VCOEFF(tn) (((tn) & 0xFFFE)==0x005C) /* is c0..c1 */ -#define XTENSA_DBREGN_IS_AEP(tn) (((tn) & 0xFFF8)==0x0060) /* is aep0..aep7 */ -#define XTENSA_DBREGN_IS_AEQ(tn) (((tn) & 0xFFFC)==0x0068) /* is aeq0..aeq3 */ -#define XTENSA_DBREGN_IS_AR(tn) (((tn) & 0xFFC0)==0x0100) /* is ar0..ar63 */ -#define XTENSA_DBREGN_IS_SREG(tn) (((tn) & 0xFF00)==0x0200) /* is special register */ -#define XTENSA_DBREGN_IS_BR(tn) (((tn) & 0xFFFF)==XTENSA_DBREGN_SREG(0x04)) /* is BR */ -#define XTENSA_DBREGN_IS_MR(tn) (((tn) & 0xFFFC)==XTENSA_DBREGN_SREG(0x20)) /* m0..m3 */ -#define XTENSA_DBREGN_IS_UREG(tn) (((tn) & 0xFF00)==0x0300) /* is user register */ -#define XTENSA_DBREGN_IS_DBAGENT(tn) (((tn) & 0xF000)==0xF000) /* is non-processor */ -/*#define XTENSA_DBREGN_IS_CONTEXT(tn) (((tn) & 0x02000000) != 0)*/ /* specifies context # */ - -/* - * Macros to extract register index from a register "target number" - * when a specific range has been identified using one of the _IS_ macros above. - * These macros only return a useful value if the corresponding _IS_ macro returns true. - */ -#define XTENSA_DBREGN_A_INDEX(tn) ((tn) & 0x0F) /* 0..15 for a0..a15 */ -#define XTENSA_DBREGN_B_INDEX(tn) ((tn) & 0x0F) /* 0..15 for b0..b15 */ -#define XTENSA_DBREGN_BO_INDEX(tn) ((tn) & 0x01) /* 0..1 for bo0..bo1 */ -#define XTENSA_DBREGN_BQ_INDEX(tn) ((tn) & 0x03) /* 0..3 for bq0..bq3 */ -#define XTENSA_DBREGN_BD_INDEX(tn) ((tn) & 0x07) /* 0..7 for bd0..bd7 */ -#define XTENSA_DBREGN_F_INDEX(tn) ((tn) & 0x0F) /* 0..15 for f0..f15 */ -#define XTENSA_DBREGN_VEC_INDEX(tn) ((tn) & 0x0F) /* 0..15 for v0..v15 */ -#define XTENSA_DBREGN_VSEL_INDEX(tn) ((tn) & 0x07) /* 0..7 for s0..s7 */ -#define XTENSA_DBREGN_VALIGN_INDEX(tn) ((tn) & 0x03) /* 0..3 for u0..u3 */ -#define XTENSA_DBREGN_VCOEFF_INDEX(tn) ((tn) & 0x01) /* 0..1 for c0..c1 */ -#define XTENSA_DBREGN_AEP_INDEX(tn) ((tn) & 0x07) /* 0..7 for aep0..aep7 */ -#define XTENSA_DBREGN_AEQ_INDEX(tn) ((tn) & 0x03) /* 0..3 for aeq0..aeq3 */ -#define XTENSA_DBREGN_AR_INDEX(tn) ((tn) & 0x3F) /* 0..63 for ar0..ar63 */ -#define XTENSA_DBREGN_SREG_INDEX(tn) ((tn) & 0xFF) /* 0..255 for special registers */ -#define XTENSA_DBREGN_MR_INDEX(tn) ((tn) & 0x03) /* 0..3 for m0..m3 */ -#define XTENSA_DBREGN_UREG_INDEX(tn) ((tn) & 0xFF) /* 0..255 for user registers */ -#define XTENSA_DBREGN_DBAGENT_INDEX(tn) ((tn) & 0xFFF) /* 0..4095 for non-processor */ -/*#define XTENSA_DBREGN_CONTEXT_INDEX(tn) (((tn) >> 20) & 0x1F)*/ /* 0..31 context numbers */ - - - - -#ifdef __cplusplus -} -#endif - -#endif /* __H_LIBDB_MACROS */ - diff --git a/src/arch/xtensa/include/xtensa/xtensa-versions.h b/src/arch/xtensa/include/xtensa/xtensa-versions.h deleted file mode 100644 index 30f318eb0e6b..000000000000 --- a/src/arch/xtensa/include/xtensa/xtensa-versions.h +++ /dev/null @@ -1,398 +0,0 @@ -/* - xtensa-versions.h -- definitions of Xtensa version and release numbers - - This file defines most Xtensa-related product versions and releases - that exist so far. - It also provides a bit of information about which ones are current. - This file changes every release, as versions/releases get added. - - - $Id: //depot/rel/Foxhill/dot.8/Xtensa/Software/misc/xtensa-versions.h.tpp#1 $ - - Copyright (c) 2006-2010 Tensilica 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. -*/ - -#ifndef XTENSA_VERSIONS_H -#define XTENSA_VERSIONS_H - - -/* - * NOTE: A "release" is a collection of product versions - * made available at once (together) to customers. - * In the past, release and version names all matched in T####.# form, - * making the distinction irrelevant. - * Starting with the RA-2004.1 release, this is no longer the case. - */ - - -/* Hardware (Xtensa/Diamond processor) versions: */ -#define XTENSA_HWVERSION_T1020_0 102000 /* versions T1020.0 */ -#define XTENSA_HWCIDSCHEME_T1020_0 10 -#define XTENSA_HWCIDVERS_T1020_0 2 -#define XTENSA_HWVERSION_T1020_1 102001 /* versions T1020.1 */ -#define XTENSA_HWCIDSCHEME_T1020_1 10 -#define XTENSA_HWCIDVERS_T1020_1 3 -#define XTENSA_HWVERSION_T1020_2 102002 /* versions T1020.2 */ -#define XTENSA_HWCIDSCHEME_T1020_2 10 -#define XTENSA_HWCIDVERS_T1020_2 4 -#define XTENSA_HWVERSION_T1020_2B 102002 /* versions T1020.2b */ -#define XTENSA_HWCIDSCHEME_T1020_2B 10 -#define XTENSA_HWCIDVERS_T1020_2B 5 -#define XTENSA_HWVERSION_T1020_3 102003 /* versions T1020.3 */ -#define XTENSA_HWCIDSCHEME_T1020_3 10 -#define XTENSA_HWCIDVERS_T1020_3 6 -#define XTENSA_HWVERSION_T1020_4 102004 /* versions T1020.4 */ -#define XTENSA_HWCIDSCHEME_T1020_4 10 -#define XTENSA_HWCIDVERS_T1020_4 7 -#define XTENSA_HWVERSION_T1030_0 103000 /* versions T1030.0 */ -#define XTENSA_HWCIDSCHEME_T1030_0 10 -#define XTENSA_HWCIDVERS_T1030_0 9 -#define XTENSA_HWVERSION_T1030_1 103001 /* versions T1030.1 */ -#define XTENSA_HWCIDSCHEME_T1030_1 10 -#define XTENSA_HWCIDVERS_T1030_1 10 -#define XTENSA_HWVERSION_T1030_2 103002 /* versions T1030.2 */ -#define XTENSA_HWCIDSCHEME_T1030_2 10 -#define XTENSA_HWCIDVERS_T1030_2 11 -#define XTENSA_HWVERSION_T1030_3 103003 /* versions T1030.3 */ -#define XTENSA_HWCIDSCHEME_T1030_3 10 -#define XTENSA_HWCIDVERS_T1030_3 12 -#define XTENSA_HWVERSION_T1040_0 104000 /* versions T1040.0 */ -#define XTENSA_HWCIDSCHEME_T1040_0 10 -#define XTENSA_HWCIDVERS_T1040_0 15 -#define XTENSA_HWVERSION_T1040_1 104001 /* versions T1040.1 */ -#define XTENSA_HWCIDSCHEME_T1040_1 01 -#define XTENSA_HWCIDVERS_T1040_1 32 -#define XTENSA_HWVERSION_T1040_1P 104001 /* versions T1040.1-prehotfix */ -#define XTENSA_HWCIDSCHEME_T1040_1P 10 -#define XTENSA_HWCIDVERS_T1040_1P 16 -#define XTENSA_HWVERSION_T1040_2 104002 /* versions T1040.2 */ -#define XTENSA_HWCIDSCHEME_T1040_2 01 -#define XTENSA_HWCIDVERS_T1040_2 33 -#define XTENSA_HWVERSION_T1040_3 104003 /* versions T1040.3 */ -#define XTENSA_HWCIDSCHEME_T1040_3 01 -#define XTENSA_HWCIDVERS_T1040_3 34 -#define XTENSA_HWVERSION_T1050_0 105000 /* versions T1050.0 */ -#define XTENSA_HWCIDSCHEME_T1050_0 1100 -#define XTENSA_HWCIDVERS_T1050_0 1 -#define XTENSA_HWVERSION_T1050_1 105001 /* versions T1050.1 */ -#define XTENSA_HWCIDSCHEME_T1050_1 1100 -#define XTENSA_HWCIDVERS_T1050_1 2 -#define XTENSA_HWVERSION_T1050_2 105002 /* versions T1050.2 */ -#define XTENSA_HWCIDSCHEME_T1050_2 1100 -#define XTENSA_HWCIDVERS_T1050_2 4 -#define XTENSA_HWVERSION_T1050_3 105003 /* versions T1050.3 */ -#define XTENSA_HWCIDSCHEME_T1050_3 1100 -#define XTENSA_HWCIDVERS_T1050_3 6 -#define XTENSA_HWVERSION_T1050_4 105004 /* versions T1050.4 */ -#define XTENSA_HWCIDSCHEME_T1050_4 1100 -#define XTENSA_HWCIDVERS_T1050_4 7 -#define XTENSA_HWVERSION_T1050_5 105005 /* versions T1050.5 */ -#define XTENSA_HWCIDSCHEME_T1050_5 1100 -#define XTENSA_HWCIDVERS_T1050_5 8 -#define XTENSA_HWVERSION_RA_2004_1 210000 /* versions LX1.0.0 */ -#define XTENSA_HWCIDSCHEME_RA_2004_1 1100 -#define XTENSA_HWCIDVERS_RA_2004_1 3 -#define XTENSA_HWVERSION_RA_2005_1 210001 /* versions LX1.0.1 */ -#define XTENSA_HWCIDSCHEME_RA_2005_1 1100 -#define XTENSA_HWCIDVERS_RA_2005_1 20 -#define XTENSA_HWVERSION_RA_2005_2 210002 /* versions LX1.0.2 */ -#define XTENSA_HWCIDSCHEME_RA_2005_2 1100 -#define XTENSA_HWCIDVERS_RA_2005_2 21 -#define XTENSA_HWVERSION_RA_2005_3 210003 /* versions LX1.0.3, X6.0.3 */ -#define XTENSA_HWCIDSCHEME_RA_2005_3 1100 -#define XTENSA_HWCIDVERS_RA_2005_3 22 -#define XTENSA_HWVERSION_RA_2006_4 210004 /* versions LX1.0.4, X6.0.4 */ -#define XTENSA_HWCIDSCHEME_RA_2006_4 1100 -#define XTENSA_HWCIDVERS_RA_2006_4 23 -#define XTENSA_HWVERSION_RA_2006_5 210005 /* versions LX1.0.5, X6.0.5 */ -#define XTENSA_HWCIDSCHEME_RA_2006_5 1100 -#define XTENSA_HWCIDVERS_RA_2006_5 24 -#define XTENSA_HWVERSION_RA_2006_6 210006 /* versions LX1.0.6, X6.0.6 */ -#define XTENSA_HWCIDSCHEME_RA_2006_6 1100 -#define XTENSA_HWCIDVERS_RA_2006_6 25 -#define XTENSA_HWVERSION_RA_2007_7 210007 /* versions LX1.0.7, X6.0.7 */ -#define XTENSA_HWCIDSCHEME_RA_2007_7 1100 -#define XTENSA_HWCIDVERS_RA_2007_7 26 -#define XTENSA_HWVERSION_RA_2008_8 210008 /* versions LX1.0.8, X6.0.8 */ -#define XTENSA_HWCIDSCHEME_RA_2008_8 1100 -#define XTENSA_HWCIDVERS_RA_2008_8 27 -#define XTENSA_HWVERSION_RB_2006_0 220000 /* versions LX2.0.0, X7.0.0 */ -#define XTENSA_HWCIDSCHEME_RB_2006_0 1100 -#define XTENSA_HWCIDVERS_RB_2006_0 48 -#define XTENSA_HWVERSION_RB_2007_1 220001 /* versions LX2.0.1, X7.0.1 */ -#define XTENSA_HWCIDSCHEME_RB_2007_1 1100 -#define XTENSA_HWCIDVERS_RB_2007_1 49 -#define XTENSA_HWVERSION_RB_2007_2 221000 /* versions LX2.1.0, X7.1.0 */ -#define XTENSA_HWCIDSCHEME_RB_2007_2 1100 -#define XTENSA_HWCIDVERS_RB_2007_2 52 -#define XTENSA_HWVERSION_RB_2008_3 221001 /* versions LX2.1.1, X7.1.1 */ -#define XTENSA_HWCIDSCHEME_RB_2008_3 1100 -#define XTENSA_HWCIDVERS_RB_2008_3 53 -#define XTENSA_HWVERSION_RB_2008_4 221002 /* versions LX2.1.2, X7.1.2 */ -#define XTENSA_HWCIDSCHEME_RB_2008_4 1100 -#define XTENSA_HWCIDVERS_RB_2008_4 54 -#define XTENSA_HWVERSION_RB_2009_5 221003 /* versions LX2.1.3, X7.1.3 */ -#define XTENSA_HWCIDSCHEME_RB_2009_5 1100 -#define XTENSA_HWCIDVERS_RB_2009_5 55 -#define XTENSA_HWVERSION_RB_2007_2_MP 221100 /* versions LX2.1.8-MP, X7.1.8-MP */ -#define XTENSA_HWCIDSCHEME_RB_2007_2_MP 1100 -#define XTENSA_HWCIDVERS_RB_2007_2_MP 64 -#define XTENSA_HWVERSION_RC_2009_0 230000 /* versions LX3.0.0, X8.0.0, MX1.0.0 */ -#define XTENSA_HWCIDSCHEME_RC_2009_0 1100 -#define XTENSA_HWCIDVERS_RC_2009_0 65 -#define XTENSA_HWVERSION_RC_2010_1 230001 /* versions LX3.0.1, X8.0.1, MX1.0.1 */ -#define XTENSA_HWCIDSCHEME_RC_2010_1 1100 -#define XTENSA_HWCIDVERS_RC_2010_1 66 -#define XTENSA_HWVERSION_RC_2010_2 230002 /* versions LX3.0.2, X8.0.2, MX1.0.2 */ -#define XTENSA_HWCIDSCHEME_RC_2010_2 1100 -#define XTENSA_HWCIDVERS_RC_2010_2 67 -#define XTENSA_HWVERSION_RC_2011_3 230003 /* versions LX3.0.3, X8.0.3, MX1.0.3 */ -#define XTENSA_HWCIDSCHEME_RC_2011_3 1100 -#define XTENSA_HWCIDVERS_RC_2011_3 68 -#define XTENSA_HWVERSION_RD_2010_0 240000 /* versions LX4.0.0, X9.0.0, MX1.1.0, TX1.0.0 */ -#define XTENSA_HWCIDSCHEME_RD_2010_0 1100 -#define XTENSA_HWCIDVERS_RD_2010_0 80 -#define XTENSA_HWVERSION_RD_2011_1 240001 /* versions LX4.0.1, X9.0.1, MX1.1.1, TX1.0.1 */ -#define XTENSA_HWCIDSCHEME_RD_2011_1 1100 -#define XTENSA_HWCIDVERS_RD_2011_1 81 -#define XTENSA_HWVERSION_RD_2011_2 240002 /* versions LX4.0.2, X9.0.2, MX1.1.2, TX1.0.2 */ -#define XTENSA_HWCIDSCHEME_RD_2011_2 1100 -#define XTENSA_HWCIDVERS_RD_2011_2 82 -#define XTENSA_HWVERSION_RD_2011_3 240003 /* versions LX4.0.3, X9.0.3, MX1.1.3, TX1.0.3 */ -#define XTENSA_HWCIDSCHEME_RD_2011_3 1100 -#define XTENSA_HWCIDVERS_RD_2011_3 83 -#define XTENSA_HWVERSION_RD_2012_4 240004 /* versions LX4.0.4, X9.0.4, MX1.1.4, TX1.0.4 */ -#define XTENSA_HWCIDSCHEME_RD_2012_4 1100 -#define XTENSA_HWCIDVERS_RD_2012_4 84 -#define XTENSA_HWVERSION_RD_2012_5 240005 /* versions LX4.0.5, X9.0.5, MX1.1.5, TX1.0.5 */ -#define XTENSA_HWCIDSCHEME_RD_2012_5 1100 -#define XTENSA_HWCIDVERS_RD_2012_5 85 -#define XTENSA_HWVERSION_RE_2012_0 250000 /* versions LX5.0.0, X10.0.0, MX1.2.0 */ -#define XTENSA_HWCIDSCHEME_RE_2012_0 1100 -#define XTENSA_HWCIDVERS_RE_2012_0 96 -#define XTENSA_HWVERSION_RE_2012_1 250001 /* versions LX5.0.1, X10.0.1, MX1.2.1 */ -#define XTENSA_HWCIDSCHEME_RE_2012_1 1100 -#define XTENSA_HWCIDVERS_RE_2012_1 97 -#define XTENSA_HWVERSION_RE_2013_2 250002 /* versions LX5.0.2, X10.0.2, MX1.2.2 */ -#define XTENSA_HWCIDSCHEME_RE_2013_2 1100 -#define XTENSA_HWCIDVERS_RE_2013_2 98 -#define XTENSA_HWVERSION_RE_2013_3 250003 /* versions LX5.0.3, X10.0.3, MX1.2.3 */ -#define XTENSA_HWCIDSCHEME_RE_2013_3 1100 -#define XTENSA_HWCIDVERS_RE_2013_3 99 -#define XTENSA_HWVERSION_RE_2013_4 250004 /* versions LX5.0.4, X10.0.4, MX1.2.4 */ -#define XTENSA_HWCIDSCHEME_RE_2013_4 1100 -#define XTENSA_HWCIDVERS_RE_2013_4 100 -#define XTENSA_HWVERSION_RE_2014_5 250005 /* versions LX5.0.5, X10.0.5, MX1.2.5 */ -#define XTENSA_HWCIDSCHEME_RE_2014_5 1100 -#define XTENSA_HWCIDVERS_RE_2014_5 101 -#define XTENSA_HWVERSION_RE_2015_6 250006 /* versions LX5.0.6, X10.0.6, MX1.2.6 */ -#define XTENSA_HWCIDSCHEME_RE_2015_6 1100 -#define XTENSA_HWCIDVERS_RE_2015_6 102 -#define XTENSA_HWVERSION_RF_2014_0 260000 /* versions LX6.0.0, X11.0.0, MX1.3.0 */ -#define XTENSA_HWCIDSCHEME_RF_2014_0 1100 -#define XTENSA_HWCIDVERS_RF_2014_0 112 -#define XTENSA_HWVERSION_RF_2014_1 260001 /* versions LX6.0.1, X11.0.1 */ -#define XTENSA_HWCIDSCHEME_RF_2014_1 1100 -#define XTENSA_HWCIDVERS_RF_2014_1 113 -#define XTENSA_HWVERSION_RF_2015_2 260002 /* versions LX6.0.2, X11.0.2 */ -#define XTENSA_HWCIDSCHEME_RF_2015_2 1100 -#define XTENSA_HWCIDVERS_RF_2015_2 114 -#define XTENSA_HWVERSION_RF_2015_3 260003 /* versions LX6.0.3, X11.0.3 */ -#define XTENSA_HWCIDSCHEME_RF_2015_3 1100 -#define XTENSA_HWCIDVERS_RF_2015_3 115 -#define XTENSA_HWVERSION_RF_2016_4 260004 /* versions LX6.0.4, X11.0.4 */ -#define XTENSA_HWCIDSCHEME_RF_2016_4 1100 -#define XTENSA_HWCIDVERS_RF_2016_4 116 -#define XTENSA_HWVERSION_RG_2015_0 270000 /* versions LX7.0.0 */ -#define XTENSA_HWCIDSCHEME_RG_2015_0 1100 -#define XTENSA_HWCIDVERS_RG_2015_0 128 -#define XTENSA_HWVERSION_RG_2015_1 270001 /* versions LX7.0.1 */ -#define XTENSA_HWCIDSCHEME_RG_2015_1 1100 -#define XTENSA_HWCIDVERS_RG_2015_1 129 -#define XTENSA_HWVERSION_RG_2015_2 270002 /* versions LX7.0.2 */ -#define XTENSA_HWCIDSCHEME_RG_2015_2 1100 -#define XTENSA_HWCIDVERS_RG_2015_2 130 -#define XTENSA_HWVERSION_RG_2016_3 270003 /* versions LX7.0.3 */ -#define XTENSA_HWCIDSCHEME_RG_2016_3 1100 -#define XTENSA_HWCIDVERS_RG_2016_3 131 -#define XTENSA_HWVERSION_RG_2016_4 270004 /* versions LX7.0.4 */ -#define XTENSA_HWCIDSCHEME_RG_2016_4 1100 -#define XTENSA_HWCIDVERS_RG_2016_4 132 -#define XTENSA_HWVERSION_RG_2017_5 270005 /* versions LX7.0.5 */ -#define XTENSA_HWCIDSCHEME_RG_2017_5 1100 -#define XTENSA_HWCIDVERS_RG_2017_5 133 -#define XTENSA_HWVERSION_RG_2017_6 270006 /* versions LX7.0.6 */ -#define XTENSA_HWCIDSCHEME_RG_2017_6 1100 -#define XTENSA_HWCIDVERS_RG_2017_6 134 -#define XTENSA_HWVERSION_RG_2017_7 270007 /* versions LX7.0.7 */ -#define XTENSA_HWCIDSCHEME_RG_2017_7 1100 -#define XTENSA_HWCIDVERS_RG_2017_7 135 -#define XTENSA_HWVERSION_RG_2017_8 270008 /* versions LX7.0.8 */ -#define XTENSA_HWCIDSCHEME_RG_2017_8 1100 -#define XTENSA_HWCIDVERS_RG_2017_8 136 -#define XTENSA_HWVERSION_RH_2016_0 280000 /* versions LX8.0.0, NX1.0.0, SX1.0.0 */ -#define XTENSA_HWCIDSCHEME_RH_2016_0 1100 -#define XTENSA_HWCIDVERS_RH_2016_0 144 - -/* Software (Xtensa Tools) versions: */ -#define XTENSA_SWVERSION_T1020_0 102000 /* versions T1020.0 */ -#define XTENSA_SWVERSION_T1020_1 102001 /* versions T1020.1 */ -#define XTENSA_SWVERSION_T1020_2 102002 /* versions T1020.2 */ -#define XTENSA_SWVERSION_T1020_2B 102002 /* versions T1020.2b */ -#define XTENSA_SWVERSION_T1020_3 102003 /* versions T1020.3 */ -#define XTENSA_SWVERSION_T1020_4 102004 /* versions T1020.4 */ -#define XTENSA_SWVERSION_T1030_0 103000 /* versions T1030.0 */ -#define XTENSA_SWVERSION_T1030_1 103001 /* versions T1030.1 */ -#define XTENSA_SWVERSION_T1030_2 103002 /* versions T1030.2 */ -#define XTENSA_SWVERSION_T1030_3 103003 /* versions T1030.3 */ -#define XTENSA_SWVERSION_T1040_0 104000 /* versions T1040.0 */ -#define XTENSA_SWVERSION_T1040_1 104001 /* versions T1040.1 */ -#define XTENSA_SWVERSION_T1040_1P 104001 /* versions T1040.1-prehotfix */ -#define XTENSA_SWVERSION_T1040_2 104002 /* versions T1040.2 */ -#define XTENSA_SWVERSION_T1040_3 104003 /* versions T1040.3 */ -#define XTENSA_SWVERSION_T1050_0 105000 /* versions T1050.0 */ -#define XTENSA_SWVERSION_T1050_1 105001 /* versions T1050.1 */ -#define XTENSA_SWVERSION_T1050_2 105002 /* versions T1050.2 */ -#define XTENSA_SWVERSION_T1050_3 105003 /* versions T1050.3 */ -#define XTENSA_SWVERSION_T1050_4 105004 /* versions T1050.4 */ -#define XTENSA_SWVERSION_T1050_5 105005 /* versions T1050.5 */ -#define XTENSA_SWVERSION_RA_2004_1 600000 /* versions 6.0.0 */ -#define XTENSA_SWVERSION_RA_2005_1 600001 /* versions 6.0.1 */ -#define XTENSA_SWVERSION_RA_2005_2 600002 /* versions 6.0.2 */ -#define XTENSA_SWVERSION_RA_2005_3 600003 /* versions 6.0.3 */ -#define XTENSA_SWVERSION_RA_2006_4 600004 /* versions 6.0.4 */ -#define XTENSA_SWVERSION_RA_2006_5 600005 /* versions 6.0.5 */ -#define XTENSA_SWVERSION_RA_2006_6 600006 /* versions 6.0.6 */ -#define XTENSA_SWVERSION_RA_2007_7 600007 /* versions 6.0.7 */ -#define XTENSA_SWVERSION_RA_2008_8 600008 /* versions 6.0.8 */ -#define XTENSA_SWVERSION_RB_2006_0 700000 /* versions 7.0.0 */ -#define XTENSA_SWVERSION_RB_2007_1 700001 /* versions 7.0.1 */ -#define XTENSA_SWVERSION_RB_2007_2 701000 /* versions 7.1.0 */ -#define XTENSA_SWVERSION_RB_2008_3 701001 /* versions 7.1.1 */ -#define XTENSA_SWVERSION_RB_2008_4 701002 /* versions 7.1.2 */ -#define XTENSA_SWVERSION_RB_2009_5 701003 /* versions 7.1.3 */ -#define XTENSA_SWVERSION_RB_2007_2_MP 701100 /* versions 7.1.8-MP */ -#define XTENSA_SWVERSION_RC_2009_0 800000 /* versions 8.0.0 */ -#define XTENSA_SWVERSION_RC_2010_1 800001 /* versions 8.0.1 */ -#define XTENSA_SWVERSION_RC_2010_2 800002 /* versions 8.0.2 */ -#define XTENSA_SWVERSION_RC_2011_3 800003 /* versions 8.0.3 */ -#define XTENSA_SWVERSION_RD_2010_0 900000 /* versions 9.0.0 */ -#define XTENSA_SWVERSION_RD_2011_1 900001 /* versions 9.0.1 */ -#define XTENSA_SWVERSION_RD_2011_2 900002 /* versions 9.0.2 */ -#define XTENSA_SWVERSION_RD_2011_3 900003 /* versions 9.0.3 */ -#define XTENSA_SWVERSION_RD_2012_4 900004 /* versions 9.0.4 */ -#define XTENSA_SWVERSION_RD_2012_5 900005 /* versions 9.0.5 */ -#define XTENSA_SWVERSION_RE_2012_0 1000000 /* versions 10.0.0 */ -#define XTENSA_SWVERSION_RE_2012_1 1000001 /* versions 10.0.1 */ -#define XTENSA_SWVERSION_RE_2013_2 1000002 /* versions 10.0.2 */ -#define XTENSA_SWVERSION_RE_2013_3 1000003 /* versions 10.0.3 */ -#define XTENSA_SWVERSION_RE_2013_4 1000004 /* versions 10.0.4 */ -#define XTENSA_SWVERSION_RE_2014_5 1000005 /* versions 10.0.5 */ -#define XTENSA_SWVERSION_RE_2015_6 1000006 /* versions 10.0.6 */ -#define XTENSA_SWVERSION_RF_2014_0 1100000 /* versions 11.0.0 */ -#define XTENSA_SWVERSION_RF_2014_1 1100001 /* versions 11.0.1 */ -#define XTENSA_SWVERSION_RF_2015_2 1100002 /* versions 11.0.2 */ -#define XTENSA_SWVERSION_RF_2015_3 1100003 /* versions 11.0.3 */ -#define XTENSA_SWVERSION_RF_2016_4 1100004 /* versions 11.0.4 */ -#define XTENSA_SWVERSION_RG_2015_0 1200000 /* versions 12.0.0 */ -#define XTENSA_SWVERSION_RG_2015_1 1200001 /* versions 12.0.1 */ -#define XTENSA_SWVERSION_RG_2015_2 1200002 /* versions 12.0.2 */ -#define XTENSA_SWVERSION_RG_2016_3 1200003 /* versions 12.0.3 */ -#define XTENSA_SWVERSION_RG_2016_4 1200004 /* versions 12.0.4 */ -#define XTENSA_SWVERSION_RG_2017_5 1200005 /* versions 12.0.5 */ -#define XTENSA_SWVERSION_RG_2017_6 1200006 /* versions 12.0.6 */ -#define XTENSA_SWVERSION_RG_2017_7 1200007 /* versions 12.0.7 */ -#define XTENSA_SWVERSION_RG_2017_8 1200008 /* versions 12.0.8 */ -#define XTENSA_SWVERSION_RH_2016_0 1300000 /* versions 13.0.0 */ -#define XTENSA_SWVERSION_T1040_1_PREHOTFIX XTENSA_SWVERSION_T1040_1P /* T1040.1-prehotfix */ -#define XTENSA_SWVERSION_6_0_0 XTENSA_SWVERSION_RA_2004_1 /* 6.0.0 */ -#define XTENSA_SWVERSION_6_0_1 XTENSA_SWVERSION_RA_2005_1 /* 6.0.1 */ -#define XTENSA_SWVERSION_6_0_2 XTENSA_SWVERSION_RA_2005_2 /* 6.0.2 */ -#define XTENSA_SWVERSION_6_0_3 XTENSA_SWVERSION_RA_2005_3 /* 6.0.3 */ -#define XTENSA_SWVERSION_6_0_4 XTENSA_SWVERSION_RA_2006_4 /* 6.0.4 */ -#define XTENSA_SWVERSION_6_0_5 XTENSA_SWVERSION_RA_2006_5 /* 6.0.5 */ -#define XTENSA_SWVERSION_6_0_6 XTENSA_SWVERSION_RA_2006_6 /* 6.0.6 */ -#define XTENSA_SWVERSION_6_0_7 XTENSA_SWVERSION_RA_2007_7 /* 6.0.7 */ -#define XTENSA_SWVERSION_6_0_8 XTENSA_SWVERSION_RA_2008_8 /* 6.0.8 */ -#define XTENSA_SWVERSION_7_0_0 XTENSA_SWVERSION_RB_2006_0 /* 7.0.0 */ -#define XTENSA_SWVERSION_7_0_1 XTENSA_SWVERSION_RB_2007_1 /* 7.0.1 */ -#define XTENSA_SWVERSION_7_1_0 XTENSA_SWVERSION_RB_2007_2 /* 7.1.0 */ -#define XTENSA_SWVERSION_7_1_1 XTENSA_SWVERSION_RB_2008_3 /* 7.1.1 */ -#define XTENSA_SWVERSION_7_1_2 XTENSA_SWVERSION_RB_2008_4 /* 7.1.2 */ -#define XTENSA_SWVERSION_7_1_3 XTENSA_SWVERSION_RB_2009_5 /* 7.1.3 */ -#define XTENSA_SWVERSION_7_1_8_MP XTENSA_SWVERSION_RB_2007_2_MP /* 7.1.8-MP */ -#define XTENSA_SWVERSION_8_0_0 XTENSA_SWVERSION_RC_2009_0 /* 8.0.0 */ -#define XTENSA_SWVERSION_8_0_1 XTENSA_SWVERSION_RC_2010_1 /* 8.0.1 */ -#define XTENSA_SWVERSION_8_0_2 XTENSA_SWVERSION_RC_2010_2 /* 8.0.2 */ -#define XTENSA_SWVERSION_8_0_3 XTENSA_SWVERSION_RC_2011_3 /* 8.0.3 */ -#define XTENSA_SWVERSION_9_0_0 XTENSA_SWVERSION_RD_2010_0 /* 9.0.0 */ -#define XTENSA_SWVERSION_9_0_1 XTENSA_SWVERSION_RD_2011_1 /* 9.0.1 */ -#define XTENSA_SWVERSION_9_0_2 XTENSA_SWVERSION_RD_2011_2 /* 9.0.2 */ -#define XTENSA_SWVERSION_9_0_3 XTENSA_SWVERSION_RD_2011_3 /* 9.0.3 */ -#define XTENSA_SWVERSION_9_0_4 XTENSA_SWVERSION_RD_2012_4 /* 9.0.4 */ -#define XTENSA_SWVERSION_9_0_5 XTENSA_SWVERSION_RD_2012_5 /* 9.0.5 */ -#define XTENSA_SWVERSION_10_0_0 XTENSA_SWVERSION_RE_2012_0 /* 10.0.0 */ -#define XTENSA_SWVERSION_10_0_1 XTENSA_SWVERSION_RE_2012_1 /* 10.0.1 */ -#define XTENSA_SWVERSION_10_0_2 XTENSA_SWVERSION_RE_2013_2 /* 10.0.2 */ -#define XTENSA_SWVERSION_10_0_3 XTENSA_SWVERSION_RE_2013_3 /* 10.0.3 */ -#define XTENSA_SWVERSION_10_0_4 XTENSA_SWVERSION_RE_2013_4 /* 10.0.4 */ -#define XTENSA_SWVERSION_10_0_5 XTENSA_SWVERSION_RE_2014_5 /* 10.0.5 */ -#define XTENSA_SWVERSION_10_0_6 XTENSA_SWVERSION_RE_2015_6 /* 10.0.6 */ -#define XTENSA_SWVERSION_11_0_0 XTENSA_SWVERSION_RF_2014_0 /* 11.0.0 */ -#define XTENSA_SWVERSION_11_0_1 XTENSA_SWVERSION_RF_2014_1 /* 11.0.1 */ -#define XTENSA_SWVERSION_11_0_2 XTENSA_SWVERSION_RF_2015_2 /* 11.0.2 */ -#define XTENSA_SWVERSION_11_0_3 XTENSA_SWVERSION_RF_2015_3 /* 11.0.3 */ -#define XTENSA_SWVERSION_11_0_4 XTENSA_SWVERSION_RF_2016_4 /* 11.0.4 */ -#define XTENSA_SWVERSION_12_0_0 XTENSA_SWVERSION_RG_2015_0 /* 12.0.0 */ -#define XTENSA_SWVERSION_12_0_1 XTENSA_SWVERSION_RG_2015_1 /* 12.0.1 */ -#define XTENSA_SWVERSION_12_0_2 XTENSA_SWVERSION_RG_2015_2 /* 12.0.2 */ -#define XTENSA_SWVERSION_12_0_3 XTENSA_SWVERSION_RG_2016_3 /* 12.0.3 */ -#define XTENSA_SWVERSION_12_0_4 XTENSA_SWVERSION_RG_2016_4 /* 12.0.4 */ -#define XTENSA_SWVERSION_12_0_5 XTENSA_SWVERSION_RG_2017_5 /* 12.0.5 */ -#define XTENSA_SWVERSION_12_0_6 XTENSA_SWVERSION_RG_2017_6 /* 12.0.6 */ -#define XTENSA_SWVERSION_12_0_7 XTENSA_SWVERSION_RG_2017_7 /* 12.0.7 */ -#define XTENSA_SWVERSION_12_0_8 XTENSA_SWVERSION_RG_2017_8 /* 12.0.8 */ -#define XTENSA_SWVERSION_13_0_0 XTENSA_SWVERSION_RH_2016_0 /* 13.0.0 */ - - -/* The current release: */ -#define XTENSA_RELEASE_NAME "RG-2017.8" -#define XTENSA_RELEASE_CANONICAL_NAME "RG-2017.8" - -/* The product versions within the current release: */ -#define XTENSA_SWVERSION XTENSA_SWVERSION_RG_2017_8 -#define XTENSA_SWVERSION_NAME "12.0.8" -#define XTENSA_SWVERSION_NAME_IDENT 12_0_8 -#define XTENSA_SWVERSION_CANONICAL_NAME "12.0.8" -#define XTENSA_SWVERSION_MAJORMID_NAME "12.0" -#define XTENSA_SWVERSION_MAJOR_NAME "12" -/* For product licensing (not necessarily same as *_MAJORMID_NAME): */ -#define XTENSA_SWVERSION_LICENSE_NAME "12.0" - -/* Note: there may be multiple hardware products in one release, - and software can target older hardware, so the notion of - "current" hardware versions is partially configuration dependent. - For now, "current" hardware product version info is left out - to avoid confusion. */ - -#endif /*XTENSA_VERSIONS_H*/ - diff --git a/src/arch/xtensa/include/xtensa/xtensa-xer.h b/src/arch/xtensa/include/xtensa/xtensa-xer.h deleted file mode 100644 index d1a200daf650..000000000000 --- a/src/arch/xtensa/include/xtensa/xtensa-xer.h +++ /dev/null @@ -1,149 +0,0 @@ -/* xer-constants.h -- various constants describing external registers accessed - via wer and rer. - - TODO: find a better prefix. Also conditionalize certain constants based - on number of cores and interrupts actually present. -*/ - -/* - * Copyright (c) 1999-2008 Tensilica 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. - */ - -#include <xtensa/config/core.h> - -#define NUM_INTERRUPTS 27 -#define NUM_CORES 4 - -/* Routing of NMI (BInterrupt2) and interrupts 0..n-1 (BInterrupt3+) - RER reads - WER writes - */ - -#define XER_MIROUT 0x0000 -#define XER_MIROUT_LAST (XER_MIROUT + NUM_INTERRUPTS) - - -/* IPI to core M (all 16 causes). - - RER reads - WER clears - */ -#define XER_MIPICAUSE 0x0100 -#define XER_MIPICAUSE_FIELD_A_FIRST 0x0 -#define XER_MIPICAUSE_FIELD_A_LAST 0x0 -#define XER_MIPICAUSE_FIELD_B_FIRST 0x1 -#define XER_MIPICAUSE_FIELD_B_LAST 0x3 -#define XER_MIPICAUSE_FIELD_C_FIRST 0x4 -#define XER_MIPICAUSE_FIELD_C_LAST 0x7 -#define XER_MIPICAUSE_FIELD_D_FIRST 0x8 -#define XER_MIPICAUSE_FIELD_D_LAST 0xF - - -/* IPI from cause bit 0..15 - - RER invalid - WER sets -*/ -#define XER_MIPISET 0x0140 -#define XER_MIPISET_LAST 0x014F - - -/* Global enable - - RER read - WER clear -*/ -#define XER_MIENG 0x0180 - - -/* Global enable - - RER invalid - WER set -*/ -#define XER_MIENG_SET 0x0184 - -/* Global assert - - RER read - WER clear -*/ -#define XER_MIASG 0x0188 - - -/* Global enable - - RER invalid - WER set -*/ -#define XER_MIASG_SET 0x018C - - -/* IPI partition register - - RER read - WER write -*/ -#define XER_PART 0x0190 -#define XER_IPI0 0x0 -#define XER_IPI1 0x1 -#define XER_IPI2 0x2 -#define XER_IPI3 0x3 - -#define XER_PART_ROUTE_IPI(NUM, FIELD) ((NUM) << ((FIELD) << 2)) - -#define XER_PART_ROUTE_IPI_CAUSE(TO_A, TO_B, TO_C, TO_D) \ - (XER_PART_ROUTE_IPI(TO_A, XER_IPI0) | \ - XER_PART_ROUTE_IPI(TO_B, XER_IPI1) | \ - XER_PART_ROUTE_IPI(TO_C, XER_IPI2) | \ - XER_PART_ROUTE_IPI(TO_D, XER_IPI3)) - -#define XER_IPI_WAKE_EXT_INTERRUPT XCHAL_EXTINT0_NUM -#define XER_IPI_WAKE_CAUSE XER_MIPICAUSE_FIELD_C_FIRST -#define XER_IPI_WAKE_ADDRESS (XER_MIPISET + XER_IPI_WAKE_CAUSE) -#define XER_DEFAULT_IPI_ROUTING XER_PART_ROUTE_IPI_CAUSE(XER_IPI1, XER_IPI0, XER_IPI2, XER_IPI3) - - -/* System configuration ID - - RER read - WER invalid -*/ -#define XER_SYSCFGID 0x01A0 - - -/* RunStall to secondary processors - - RER read - WER write -*/ -#define XER_MPSCORE 0x0200 - - -/* Cache coherency ON - - RER read - WER write -*/ -#define XER_CCON 0x0220 - - diff --git a/src/arch/xtensa/include/xtensa/xtruntime-core-state.h b/src/arch/xtensa/include/xtensa/xtruntime-core-state.h deleted file mode 100644 index 94cc719af822..000000000000 --- a/src/arch/xtensa/include/xtensa/xtruntime-core-state.h +++ /dev/null @@ -1,240 +0,0 @@ -/* xtruntime-core-state.h - core state save area (used eg. by PSO) */ -/* $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/include/xtensa/xtruntime-core-state.h#1 $ */ - -/* - * Copyright (c) 2012-2013 Tensilica 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. - */ - -#ifndef _XTOS_CORE_STATE_H_ -#define _XTOS_CORE_STATE_H_ - -/* Import STRUCT_xxx macros for defining structures: */ -#include <xtensa/xtruntime-frames.h> -#include <xtensa/config/core.h> -#include <xtensa/config/tie.h> -#if XCHAL_HAVE_IDMA -#include <xtensa/idma.h> -#endif - -//#define XTOS_PSO_TEST 1 // uncommented for internal PSO testing only - -#define CORE_STATE_SIGNATURE 0xB1C5AFED // pattern that indicates state was saved - - -/* - * Save area for saving entire core state, such as across Power Shut-Off (PSO). - */ - -STRUCT_BEGIN -STRUCT_FIELD (long,4,CS_SA_,signature) // for checking whether state was saved -STRUCT_FIELD (long,4,CS_SA_,restore_label) -STRUCT_FIELD (long,4,CS_SA_,aftersave_label) -STRUCT_AFIELD(long,4,CS_SA_,areg,XCHAL_NUM_AREGS) -#if XCHAL_HAVE_WINDOWED -STRUCT_AFIELD(long,4,CS_SA_,caller_regs,16) // save a max of 16 caller regs -STRUCT_FIELD (long,4,CS_SA_,caller_regs_saved) // flag to show if caller regs saved -#endif -#if XCHAL_HAVE_PSO_CDM -STRUCT_FIELD (long,4,CS_SA_,pwrctl) -#endif -#if XCHAL_HAVE_WINDOWED -STRUCT_FIELD (long,4,CS_SA_,windowbase) -STRUCT_FIELD (long,4,CS_SA_,windowstart) -#endif -STRUCT_FIELD (long,4,CS_SA_,sar) -#if XCHAL_HAVE_EXCEPTIONS -STRUCT_FIELD (long,4,CS_SA_,epc1) -STRUCT_FIELD (long,4,CS_SA_,ps) -STRUCT_FIELD (long,4,CS_SA_,excsave1) -# ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR -STRUCT_FIELD (long,4,CS_SA_,depc) -# endif -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 2 -STRUCT_AFIELD(long,4,CS_SA_,epc, XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI - 1) -STRUCT_AFIELD(long,4,CS_SA_,eps, XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI - 1) -STRUCT_AFIELD(long,4,CS_SA_,excsave,XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI - 1) -#endif -#if XCHAL_HAVE_LOOPS -STRUCT_FIELD (long,4,CS_SA_,lcount) -STRUCT_FIELD (long,4,CS_SA_,lbeg) -STRUCT_FIELD (long,4,CS_SA_,lend) -#endif -#if XCHAL_HAVE_ABSOLUTE_LITERALS -STRUCT_FIELD (long,4,CS_SA_,litbase) -#endif -#if XCHAL_HAVE_VECBASE -STRUCT_FIELD (long,4,CS_SA_,vecbase) -#endif -#if XCHAL_HAVE_S32C1I && (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RC_2009_0) /* have ATOMCTL ? */ -STRUCT_FIELD (long,4,CS_SA_,atomctl) -#endif -#if XCHAL_HAVE_PREFETCH -STRUCT_FIELD (long,4,CS_SA_,prefctl) -#endif -#if XCHAL_USE_MEMCTL -STRUCT_FIELD (long,4,CS_SA_,memctl) -#endif -#if XCHAL_HAVE_CCOUNT -STRUCT_FIELD (long,4,CS_SA_,ccount) -STRUCT_AFIELD(long,4,CS_SA_,ccompare, XCHAL_NUM_TIMERS) -#endif -#if XCHAL_HAVE_INTERRUPTS -STRUCT_FIELD (long,4,CS_SA_,intenable) -STRUCT_FIELD (long,4,CS_SA_,interrupt) -#endif -#if XCHAL_HAVE_DEBUG -STRUCT_FIELD (long,4,CS_SA_,icount) -STRUCT_FIELD (long,4,CS_SA_,icountlevel) -STRUCT_FIELD (long,4,CS_SA_,debugcause) -// DDR not saved -# if XCHAL_NUM_DBREAK -STRUCT_AFIELD(long,4,CS_SA_,dbreakc, XCHAL_NUM_DBREAK) -STRUCT_AFIELD(long,4,CS_SA_,dbreaka, XCHAL_NUM_DBREAK) -# endif -# if XCHAL_NUM_IBREAK -STRUCT_AFIELD(long,4,CS_SA_,ibreaka, XCHAL_NUM_IBREAK) -STRUCT_FIELD (long,4,CS_SA_,ibreakenable) -# endif -#endif -#if XCHAL_NUM_MISC_REGS -STRUCT_AFIELD(long,4,CS_SA_,misc,XCHAL_NUM_MISC_REGS) -#endif -#if XCHAL_HAVE_MEM_ECC_PARITY -STRUCT_FIELD (long,4,CS_SA_,mepc) -STRUCT_FIELD (long,4,CS_SA_,meps) -STRUCT_FIELD (long,4,CS_SA_,mesave) -STRUCT_FIELD (long,4,CS_SA_,mesr) -STRUCT_FIELD (long,4,CS_SA_,mecr) -STRUCT_FIELD (long,4,CS_SA_,mevaddr) -#endif - -/* We put this ahead of TLB and other TIE state, - to keep it within S32I/L32I offset range. */ -#if XCHAL_HAVE_CP -STRUCT_FIELD (long,4,CS_SA_,cpenable) -#endif - -/* TLB state */ -#if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR -STRUCT_AFIELD(long,4,CS_SA_,tlbs,8*2) -#endif -#if XCHAL_HAVE_PTP_MMU -/* Compute number of auto-refill (ARF) entries as max of I and D, - to simplify TLB save logic. On the unusual configs with - ITLB ARF != DTLB ARF entries, we'll just end up - saving/restoring some extra entries redundantly. */ -# if XCHAL_DTLB_ARF_ENTRIES_LOG2 + XCHAL_ITLB_ARF_ENTRIES_LOG2 > 4 -# define ARF_ENTRIES 8 -# else -# define ARF_ENTRIES 4 -# endif -STRUCT_FIELD (long,4,CS_SA_,ptevaddr) -STRUCT_FIELD (long,4,CS_SA_,rasid) -STRUCT_FIELD (long,4,CS_SA_,dtlbcfg) -STRUCT_FIELD (long,4,CS_SA_,itlbcfg) -/*** WARNING: past this point, field offsets may be larger than S32I/L32I range ***/ -STRUCT_AFIELD(long,4,CS_SA_,tlbs,((4*ARF_ENTRIES+4)*2+3)*2) -# if XCHAL_HAVE_SPANNING_WAY /* MMU v3 */ -STRUCT_AFIELD(long,4,CS_SA_,tlbs_ways56,(4+8)*2*2) -# endif -#endif -/* MPU state */ -#if XCHAL_HAVE_MPU -STRUCT_AFIELD(long,4,CS_SA_,mpuentry,8*XCHAL_MPU_ENTRIES) -STRUCT_FIELD (long,4,CS_SA_,cacheadrdis) -#endif - -#if XCHAL_HAVE_IDMA -STRUCT_AFIELD(long,4,CS_SA_,idmaregs, IDMA_PSO_SAVE_SIZE) -#endif - -/* TIE state */ -/* NOTE: NCP area is aligned to XCHAL_TOTAL_SA_ALIGN not XCHAL_NCP_SA_ALIGN, - because the offsets of all subsequent coprocessor save areas are relative - to the NCP save area. */ -STRUCT_AFIELD_A(char,1,XCHAL_TOTAL_SA_ALIGN,CS_SA_,ncp,XCHAL_NCP_SA_SIZE) -#if XCHAL_HAVE_CP -#if XCHAL_CP0_SA_SIZE > 0 -STRUCT_AFIELD_A(char,1,XCHAL_CP0_SA_ALIGN,CS_SA_,cp0,XCHAL_CP0_SA_SIZE) -#endif -#if XCHAL_CP1_SA_SIZE > 0 -STRUCT_AFIELD_A(char,1,XCHAL_CP1_SA_ALIGN,CS_SA_,cp1,XCHAL_CP1_SA_SIZE) -#endif -#if XCHAL_CP2_SA_SIZE > 0 -STRUCT_AFIELD_A(char,1,XCHAL_CP2_SA_ALIGN,CS_SA_,cp2,XCHAL_CP2_SA_SIZE) -#endif -#if XCHAL_CP3_SA_SIZE > 0 -STRUCT_AFIELD_A(char,1,XCHAL_CP3_SA_ALIGN,CS_SA_,cp3,XCHAL_CP3_SA_SIZE) -#endif -#if XCHAL_CP4_SA_SIZE > 0 -STRUCT_AFIELD_A(char,1,XCHAL_CP4_SA_ALIGN,CS_SA_,cp4,XCHAL_CP4_SA_SIZE) -#endif -#if XCHAL_CP5_SA_SIZE > 0 -STRUCT_AFIELD_A(char,1,XCHAL_CP5_SA_ALIGN,CS_SA_,cp5,XCHAL_CP5_SA_SIZE) -#endif -#if XCHAL_CP6_SA_SIZE > 0 -STRUCT_AFIELD_A(char,1,XCHAL_CP6_SA_ALIGN,CS_SA_,cp6,XCHAL_CP6_SA_SIZE) -#endif -#if XCHAL_CP7_SA_SIZE > 0 -STRUCT_AFIELD_A(char,1,XCHAL_CP7_SA_ALIGN,CS_SA_,cp7,XCHAL_CP7_SA_SIZE) -#endif -//STRUCT_AFIELD_A(char,1,XCHAL_CP8_SA_ALIGN,CS_SA_,cp8,XCHAL_CP8_SA_SIZE) -//STRUCT_AFIELD_A(char,1,XCHAL_CP9_SA_ALIGN,CS_SA_,cp9,XCHAL_CP9_SA_SIZE) -//STRUCT_AFIELD_A(char,1,XCHAL_CP10_SA_ALIGN,CS_SA_,cp10,XCHAL_CP10_SA_SIZE) -//STRUCT_AFIELD_A(char,1,XCHAL_CP11_SA_ALIGN,CS_SA_,cp11,XCHAL_CP11_SA_SIZE) -//STRUCT_AFIELD_A(char,1,XCHAL_CP12_SA_ALIGN,CS_SA_,cp12,XCHAL_CP12_SA_SIZE) -//STRUCT_AFIELD_A(char,1,XCHAL_CP13_SA_ALIGN,CS_SA_,cp13,XCHAL_CP13_SA_SIZE) -//STRUCT_AFIELD_A(char,1,XCHAL_CP14_SA_ALIGN,CS_SA_,cp14,XCHAL_CP14_SA_SIZE) -//STRUCT_AFIELD_A(char,1,XCHAL_CP15_SA_ALIGN,CS_SA_,cp15,XCHAL_CP15_SA_SIZE) -#endif - -STRUCT_END(XtosCoreState) - - - -// These are part of non-coprocessor state (ncp): -#if XCHAL_HAVE_MAC16 -//STRUCT_FIELD (long,4,CS_SA_,acclo) -//STRUCT_FIELD (long,4,CS_SA_,acchi) -//STRUCT_AFIELD(long,4,CS_SA_,mr, 4) -#endif -#if XCHAL_HAVE_THREADPTR -//STRUCT_FIELD (long,4,CS_SA_,threadptr) -#endif -#if XCHAL_HAVE_S32C1I -//STRUCT_FIELD (long,4,CS_SA_,scompare1) -#endif -#if XCHAL_HAVE_BOOLEANS -//STRUCT_FIELD (long,4,CS_SA_,br) -#endif - -// Not saved: -// EXCCAUSE ?? -// DEBUGCAUSE ?? -// EXCVADDR ?? -// DDR -// INTERRUPT -// ... locked cache lines ... - -#endif /* _XTOS_CORE_STATE_H_ */ - diff --git a/src/arch/xtensa/include/xtensa/xtruntime-frames.h b/src/arch/xtensa/include/xtensa/xtruntime-frames.h deleted file mode 100644 index 0b6e0d181821..000000000000 --- a/src/arch/xtensa/include/xtensa/xtruntime-frames.h +++ /dev/null @@ -1,202 +0,0 @@ -/* xtruntime-frames.h - exception stack frames for single-threaded run-time */ -/* $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/include/xtensa/xtruntime-frames.h#1 $ */ - -/* - * Copyright (c) 2002-2012 Tensilica 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. - */ - -#ifndef _XTRUNTIME_FRAMES_H_ -#define _XTRUNTIME_FRAMES_H_ - -#include <xtensa/config/core.h> - -/* Macros that help define structures for both C and assembler: */ -#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) -#define STRUCT_BEGIN .pushsection .text; .struct 0 -#define STRUCT_FIELD(ctype,size,pre,name) pre##name: .space size -#define STRUCT_AFIELD(ctype,size,pre,name,n) pre##name: .if n ; .space (size)*(n) ; .endif -#define STRUCT_AFIELD_A(ctype,size,align,pre,name,n) .balign align ; pre##name: .if n ; .space (size)*(n) ; .endif -#define STRUCT_END(sname) sname##Size:; .popsection -#else /*_ASMLANGUAGE||__ASSEMBLER__*/ -#define STRUCT_BEGIN typedef struct { -#define STRUCT_FIELD(ctype,size,pre,name) ctype name; -#define STRUCT_AFIELD(ctype,size,pre,name,n) ctype name[n]; -#define STRUCT_AFIELD_A(ctype,size,align,pre,name,n) ctype name[n] __attribute__((aligned(align))); -#define STRUCT_END(sname) } sname; -#endif /*_ASMLANGUAGE||__ASSEMBLER__*/ - -/* Coprocessors masks. - * NOTE: currently only 2 supported. - */ -#define CP0_MASK (1 << 0) -#define CP1_MASK (1 << 1) - -/* - * Kernel vector mode exception stack frame. - * - * NOTE: due to the limited range of addi used in the current - * kernel exception vector, and the fact that historically - * the vector is limited to 12 bytes, the size of this - * stack frame is limited to 128 bytes (currently at 64). - */ -STRUCT_BEGIN -STRUCT_FIELD (long,4,KEXC_,pc) /* "parm" */ -STRUCT_FIELD (long,4,KEXC_,ps) -STRUCT_AFIELD(long,4,KEXC_,areg, 4) /* a12 .. a15 */ -STRUCT_FIELD (long,4,KEXC_,sar) /* "save" */ -#if XCHAL_HAVE_LOOPS -STRUCT_FIELD (long,4,KEXC_,lcount) -STRUCT_FIELD (long,4,KEXC_,lbeg) -STRUCT_FIELD (long,4,KEXC_,lend) -#endif -#if XCHAL_HAVE_MAC16 -STRUCT_FIELD (long,4,KEXC_,acclo) -STRUCT_FIELD (long,4,KEXC_,acchi) -STRUCT_AFIELD(long,4,KEXC_,mr, 4) -#endif -STRUCT_END(KernelFrame) - - -/* - * User vector mode exception stack frame: - * - * WARNING: if you modify this structure, you MUST modify the - * computation of the pad size (ALIGNPAD) accordingly. - */ -STRUCT_BEGIN -STRUCT_FIELD (long,4,UEXC_,pc) -STRUCT_FIELD (long,4,UEXC_,ps) -STRUCT_FIELD (long,4,UEXC_,sar) -STRUCT_FIELD (long,4,UEXC_,vpri) -STRUCT_FIELD (long,4,UEXC_,a0) -STRUCT_FIELD (long,4,UEXC_,a1) -STRUCT_FIELD (long,4,UEXC_,a2) -STRUCT_FIELD (long,4,UEXC_,a3) -STRUCT_FIELD (long,4,UEXC_,a4) -STRUCT_FIELD (long,4,UEXC_,a5) -STRUCT_FIELD (long,4,UEXC_,a6) -STRUCT_FIELD (long,4,UEXC_,a7) -STRUCT_FIELD (long,4,UEXC_,a8) -STRUCT_FIELD (long,4,UEXC_,a9) -STRUCT_FIELD (long,4,UEXC_,a10) -STRUCT_FIELD (long,4,UEXC_,a11) -STRUCT_FIELD (long,4,UEXC_,a12) -STRUCT_FIELD (long,4,UEXC_,a13) -STRUCT_FIELD (long,4,UEXC_,a14) -STRUCT_FIELD (long,4,UEXC_,a15) -STRUCT_FIELD (long,4,UEXC_,exccause) /* NOTE: can probably rid of this one (pass direct) */ -STRUCT_FIELD (long,4,UEXC_,align1) /* alignment to 8 bytes */ -#if XCHAL_HAVE_LOOPS -STRUCT_FIELD (long,4,UEXC_,lcount) -STRUCT_FIELD (long,4,UEXC_,lbeg) -STRUCT_FIELD (long,4,UEXC_,lend) -STRUCT_FIELD (long,4,UEXC_,align2) /* alignment to 8 bytes */ -#endif -#if XCHAL_HAVE_MAC16 -STRUCT_FIELD (long,4,UEXC_,acclo) -STRUCT_FIELD (long,4,UEXC_,acchi) -STRUCT_AFIELD(long,4,UEXC_,mr, 4) -#endif -#if (XCHAL_CP_MASK & CP0_MASK) -STRUCT_AFIELD_A (long,4,XCHAL_TOTAL_SA_ALIGN,UEXC_,cp0, XCHAL_CP0_SA_SIZE / 4) -#endif -#if (XCHAL_CP_MASK & CP1_MASK) -STRUCT_AFIELD_A (long,4,XCHAL_TOTAL_SA_ALIGN,UEXC_,cp1, XCHAL_CP1_SA_SIZE / 4) -#endif -/* ALIGNPAD is the 16-byte alignment padding. */ -#define ALIGNPAD ((2 + XCHAL_HAVE_MAC16*2 + ((XCHAL_CP0_SA_SIZE%16)/4) + ((XCHAL_CP1_SA_SIZE%16)/4)) & 3) -#if ALIGNPAD -STRUCT_AFIELD(long,4,UEXC_,pad, ALIGNPAD) /* 16-byte alignment padding */ -#endif -/*STRUCT_AFIELD_A(char,1,XCHAL_CPEXTRA_SA_ALIGN,UEXC_,ureg, (XCHAL_CPEXTRA_SA_SIZE+3)&-4)*/ /* not used */ -STRUCT_END(UserFrame) - -/* - * xtos_structures_pointers contains ptrs to all structures created for - * each processor individually. - * - * To access the core specific structure from ASM (after threadptr is set): - * xtos_addr_percore a13, xtos_interrupt_table - */ -STRUCT_BEGIN -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_enabled) -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_intstruct) -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_interrupt_table) -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_interrupt_mask_table) -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_stack_for_interrupt_1) -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_stack_for_interrupt_2) -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_stack_for_interrupt_3) -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_stack_for_interrupt_4) -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_stack_for_interrupt_5) -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_interrupt_ctx) -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_saved_ctx) -STRUCT_FIELD(void*,4,XTOS_PTR_TO_,xtos_saved_sp) -STRUCT_END(xtos_structures_pointers) - -/* - * xtos_task_context contains information about currently - * executed task - */ - -#define XTOS_TASK_CONTEXT_OWN_STACK 1 - -STRUCT_BEGIN -STRUCT_FIELD (UserFrame*,4,TC_,stack_pointer) -STRUCT_FIELD (void*,4,TC_,stack_base) -STRUCT_FIELD (long,4,TC_,stack_size) -STRUCT_FIELD (long,4,TC_,flags) -STRUCT_END(xtos_task_context) - -#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) - - -/* Check for UserFrameSize small enough not to require rounding...: */ - /* Skip 16-byte save area, then 32-byte space for 8 regs of call12 - * (which overlaps with 16-byte GCC nested func chaining area), - * then exception stack frame: */ - .set UserFrameTotalSize, 16+32+UserFrameSize - /* Greater than 112 bytes? (max range of ADDI, both signs, when aligned to 16 bytes): */ - .ifgt UserFrameTotalSize-112 - /* Round up to 256-byte multiple to accelerate immediate adds: */ - .set UserFrameTotalSize, ((UserFrameTotalSize+255) & 0xFFFFFF00) - .endif -# define ESF_TOTALSIZE UserFrameTotalSize - -#endif /* _ASMLANGUAGE || __ASSEMBLER__ */ - - -#if XCHAL_NUM_CONTEXTS > 1 -/* Structure of info stored on new context's stack for setup: */ -STRUCT_BEGIN -STRUCT_FIELD (long,4,INFO_,sp) -STRUCT_FIELD (long,4,INFO_,arg1) -STRUCT_FIELD (long,4,INFO_,funcpc) -STRUCT_FIELD (long,4,INFO_,prevps) -STRUCT_END(SetupInfo) -#endif - - -#define KERNELSTACKSIZE 1024 - - -#endif /* _XTRUNTIME_FRAMES_H_ */ - diff --git a/src/arch/xtensa/include/xtensa/xtruntime.h b/src/arch/xtensa/include/xtensa/xtruntime.h deleted file mode 100644 index d5d1f1dd3ff2..000000000000 --- a/src/arch/xtensa/include/xtensa/xtruntime.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - * xtruntime.h -- general C definitions for single-threaded run-time - * - * Copyright (c) 2002-2013 Tensilica 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. - */ - -#ifndef XTRUNTIME_H -#define XTRUNTIME_H - -#include <xtensa/config/core.h> -#include <xtensa/config/specreg.h> -#include <xtensa/xtruntime-core-state.h> - -#ifndef XTSTR -#define _XTSTR(x) # x -#define XTSTR(x) _XTSTR(x) -#endif - -/* _xtos_core_shutoff() flags parameter values: */ -#define XTOS_KEEPON_MEM 0x00000100 /* ==PWRCTL_MEM_WAKEUP */ -#define XTOS_KEEPON_MEM_SHIFT 8 -#define XTOS_KEEPON_DEBUG 0x00001000 /* ==PWRCTL_DEBUG_WAKEUP */ -#define XTOS_KEEPON_DEBUG_SHIFT 12 - -#define XTOS_IDMA_NO_WAIT 0x00010000 /* Do not wait for idma to finish. Disable if necessary */ -#define XTOS_IDMA_WAIT_STANDBY 0x00020000 /* Also treat standby state as the end of wait */ - -#define XTOS_COREF_PSO 0x00000001 /* do power shutoff */ -#define XTOS_COREF_PSO_SHIFT 0 - -#define _xtos_set_execption_handler _xtos_set_exception_handler /* backward compatibility */ -#define _xtos_set_saved_intenable _xtos_ints_on /* backward compatibility */ -#define _xtos_clear_saved_intenable _xtos_ints_off /* backward compatibility */ - -#if !defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__) - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(XTOS_MISRA) -typedef void (_xtos_handler_func)(void *); -#elif defined(__cplusplus) -typedef void (_xtos_handler_func)(...); -#else -typedef void (_xtos_handler_func)(); -#endif -typedef _xtos_handler_func *_xtos_handler; - -/* - * unsigned XTOS_SET_INTLEVEL(int intlevel); - * This macro sets the current interrupt level. - * The 'intlevel' parameter must be a constant. - * This macro returns a 32-bit value that must be passed to - * XTOS_RESTORE_INTLEVEL() to restore the previous interrupt level. - * XTOS_RESTORE_JUST_INTLEVEL() also does this, but in XEA2 configs - * it restores only PS.INTLEVEL rather than the entire PS register - * and thus is slower. - */ -#if !XCHAL_HAVE_INTERRUPTS -# define XTOS_SET_INTLEVEL(intlevel) 0 -# define XTOS_SET_MIN_INTLEVEL(intlevel) 0 -# define XTOS_RESTORE_INTLEVEL(restoreval) -# define XTOS_RESTORE_JUST_INTLEVEL(restoreval) -#elif XCHAL_HAVE_XEA2 -/* In XEA2, we can simply safely set PS.INTLEVEL directly: */ -/* NOTE: these asm macros don't modify memory, but they are marked - * as such to act as memory access barriers to the compiler because - * these macros are sometimes used to delineate critical sections; - * function calls are natural barriers (the compiler does not know - * whether a function modifies memory) unless declared to be inlined. */ -# define XTOS_SET_INTLEVEL(intlevel) ({ unsigned __tmp; \ - __asm__ __volatile__( "rsil %0, " XTSTR(intlevel) "\n" \ - : "=a" (__tmp) : : "memory" ); \ - __tmp;}) -# define XTOS_SET_MIN_INTLEVEL(intlevel) ({ unsigned __tmp, __tmp2, __tmp3; \ - __asm__ __volatile__( "rsr.ps %0\n" /* get old (current) PS.INTLEVEL */ \ - "movi %2, " XTSTR(intlevel) "\n" \ - "extui %1, %0, 0, 4\n" /* keep only INTLEVEL bits of parameter */ \ - "blt %2, %1, 1f\n" \ - "rsil %0, " XTSTR(intlevel) "\n" \ - "1:\n" \ - : "=a" (__tmp), "=&a" (__tmp2), "=&a" (__tmp3) : : "memory" ); \ - __tmp;}) -# define XTOS_RESTORE_INTLEVEL(restoreval) do{ unsigned __tmp = (restoreval); \ - __asm__ __volatile__( "wsr.ps %0 ; rsync\n" \ - : : "a" (__tmp) : "memory" ); \ - }while(0) -# define XTOS_RESTORE_JUST_INTLEVEL(restoreval) _xtos_set_intlevel(restoreval) -#else -/* In XEA1, we have to rely on INTENABLE register virtualization: */ -extern unsigned _xtos_set_vpri( unsigned vpri ); -extern unsigned _xtos_vpri_enabled; /* current virtual priority */ -# define XTOS_SET_INTLEVEL(intlevel) _xtos_set_vpri(~XCHAL_INTLEVEL_ANDBELOW_MASK(intlevel)) -# define XTOS_SET_MIN_INTLEVEL(intlevel) _xtos_set_vpri(_xtos_vpri_enabled & ~XCHAL_INTLEVEL_ANDBELOW_MASK(intlevel)) -# define XTOS_RESTORE_INTLEVEL(restoreval) _xtos_set_vpri(restoreval) -# define XTOS_RESTORE_JUST_INTLEVEL(restoreval) _xtos_set_vpri(restoreval) -#endif - -/* - * The following macros build upon the above. They are generally used - * instead of invoking the SET_INTLEVEL and SET_MIN_INTLEVEL macros directly. - * They all return a value that can be used with XTOS_RESTORE_INTLEVEL() - * or _xtos_restore_intlevel() or _xtos_restore_just_intlevel() to restore - * the effective interrupt level to what it was before the macro was invoked. - * In XEA2, the DISABLE macros are much faster than the MASK macros - * (in all configs, DISABLE sets the effective interrupt level, whereas MASK - * makes ensures the effective interrupt level is at least the level given - * without lowering it; in XEA2 with INTENABLE virtualization, these macros - * affect PS.INTLEVEL only, not the virtual priority, so DISABLE has partial - * MASK semantics). - * - * A typical critical section sequence might be: - * unsigned rval = XTOS_DISABLE_EXCM_INTERRUPTS; - * ... critical section ... - * XTOS_RESTORE_INTLEVEL(rval); - */ -/* Enable all interrupts (those activated with _xtos_ints_on()): */ -#define XTOS_ENABLE_INTERRUPTS XTOS_SET_INTLEVEL(0) -/* Disable low priority level interrupts (they can interact with the OS): */ -#define XTOS_DISABLE_LOWPRI_INTERRUPTS XTOS_SET_INTLEVEL(XCHAL_NUM_LOWPRI_LEVELS) -#define XTOS_MASK_LOWPRI_INTERRUPTS XTOS_SET_MIN_INTLEVEL(XCHAL_NUM_LOWPRI_LEVELS) -/* Disable interrupts that can interact with the OS: */ -#define XTOS_DISABLE_EXCM_INTERRUPTS XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL) -#define XTOS_MASK_EXCM_INTERRUPTS XTOS_SET_MIN_INTLEVEL(XCHAL_EXCM_LEVEL) -#if 0 /* XTOS_LOCK_LEVEL is not exported to applications */ -/* Disable interrupts that can interact with the OS, or manipulate virtual INTENABLE: */ -#define XTOS_DISABLE_LOCK_INTERRUPTS XTOS_SET_INTLEVEL(XTOS_LOCK_LEVEL) -#define XTOS_MASK_LOCK_INTERRUPTS XTOS_SET_MIN_INTLEVEL(XTOS_LOCK_LEVEL) -#endif -/* Disable ALL interrupts (not for common use, particularly if one's processor - * configuration has high-level interrupts and one cares about their latency): */ -#define XTOS_DISABLE_ALL_INTERRUPTS XTOS_SET_INTLEVEL(15) - -/* These two are deprecated. Use the newer functions below. */ -extern unsigned int _xtos_ints_off( unsigned int mask ); -extern unsigned int _xtos_ints_on( unsigned int mask ); - -/* Newer functions to enable/disable the specified interrupt. */ -static inline void _xtos_interrupt_enable(unsigned int intnum) -{ - _xtos_ints_on(1 << intnum); -} - -static inline void _xtos_interrupt_disable(unsigned int intnum) -{ - _xtos_ints_off(1 << intnum); -} - -extern unsigned _xtos_set_intlevel( int intlevel ); -extern unsigned _xtos_set_min_intlevel( int intlevel ); -extern unsigned _xtos_restore_intlevel( unsigned restoreval ); -extern unsigned _xtos_restore_just_intlevel( unsigned restoreval ); -extern _xtos_handler _xtos_set_interrupt_handler( int n, _xtos_handler f ); -extern _xtos_handler _xtos_set_interrupt_handler_arg( int n, _xtos_handler f, void *arg ); -extern _xtos_handler _xtos_set_exception_handler( int n, _xtos_handler f ); - -extern void _xtos_memep_initrams( void ); -extern void _xtos_memep_enable( int flags ); - -/* For use with the tiny LSP (see LSP reference manual). */ -#if XCHAL_NUM_INTLEVELS >= 1 -extern void _xtos_dispatch_level1_interrupts( void ); -#endif -#if XCHAL_NUM_INTLEVELS >= 2 -extern void _xtos_dispatch_level2_interrupts( void ); -#endif -#if XCHAL_NUM_INTLEVELS >= 3 -extern void _xtos_dispatch_level3_interrupts( void ); -#endif -#if XCHAL_NUM_INTLEVELS >= 4 -extern void _xtos_dispatch_level4_interrupts( void ); -#endif -#if XCHAL_NUM_INTLEVELS >= 5 -extern void _xtos_dispatch_level5_interrupts( void ); -#endif -#if XCHAL_NUM_INTLEVELS >= 6 -extern void _xtos_dispatch_level6_interrupts( void ); -#endif - -/* Deprecated (but kept because they were documented): */ -extern unsigned int _xtos_read_ints( void ); -extern void _xtos_clear_ints( unsigned int mask ); - - -/* Power shut-off related routines. */ -extern int _xtos_core_shutoff(unsigned flags); -extern int _xtos_core_save(unsigned flags, XtosCoreState *savearea, void *code); -extern void _xtos_core_restore(unsigned retvalue, XtosCoreState *savearea); - - -#if XCHAL_NUM_CONTEXTS > 1 -extern unsigned _xtos_init_context(int context_num, int stack_size, - _xtos_handler_func *start_func, int arg1); -#endif - -/* Deprecated: */ -#if XCHAL_NUM_TIMERS > 0 -extern void _xtos_timer_0_delta( int cycles ); -#endif -#if XCHAL_NUM_TIMERS > 1 -extern void _xtos_timer_1_delta( int cycles ); -#endif -#if XCHAL_NUM_TIMERS > 2 -extern void _xtos_timer_2_delta( int cycles ); -#endif -#if XCHAL_NUM_TIMERS > 3 -extern void _xtos_timer_3_delta( int cycles ); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !_ASMLANGUAGE && !__ASSEMBLER__ */ - -#endif /* XTRUNTIME_H */ - diff --git a/src/arch/xtensa/init.c b/src/arch/xtensa/init.c deleted file mode 100644 index 2f15c4b67362..000000000000 --- a/src/arch/xtensa/init.c +++ /dev/null @@ -1,210 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2016 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - -/** - * \file arch/xtensa/init.c - * \brief Xtensa initialization functions - * \authors Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#include "xtos-internal.h" -#include <sof/common.h> -#include <rtos/panic.h> -#include <sof/init.h> -#include <sof/lib/cpu.h> -#include <rtos/sof.h> -#include <rtos/spinlock.h> - -#include <ipc/trace.h> - -#include <xtensa/xtruntime-frames.h> -#include <xtos-structs.h> -#include <stddef.h> -#include <stdint.h> - -/* UserFrame's size needs to be 16 bytes aligned */ -STATIC_ASSERT((sizeof(UserFrame) % 16) == 0, invalid_UserFrame_alignment); - -/* verify xtos_active_task offset */ -STATIC_ASSERT(offsetof(struct thread_data, xtos_active_task) == - XTOS_TASK_CONTEXT_OFFSET, invalid_xtos_active_task_offset); - -#if CONFIG_DEBUG_LOCKS -/** \brief Debug lock. */ -uint32_t lock_dbg_atomic; - -/** \brief Debug locks per user. */ -uint32_t lock_dbg_user[DBG_LOCK_USERS] = {0}; -#endif -#if CONFIG_NO_SECONDARY_CORE_ROM -void *shared_vecbase_ptr __aligned(PLATFORM_DCACHE_ALIGN); -#endif -/** \brief Core context for primary core. */ -static struct core_context primary_core_ctx; - -/** \brief Core context pointers for all the cores. */ -struct core_context *core_ctx_ptr[CONFIG_CORE_COUNT] = { 0 }; - -/** \brief Xtos core data for primary core. */ -struct xtos_core_data primary_core_data; - -/** \brief Xtos core data pointers for all the cores. */ -struct xtos_core_data *core_data_ptr[CONFIG_CORE_COUNT] = { 0 }; - -/** - * \brief Initializes core specific data. - */ -static void initialize_pointers_per_core(void) -{ - int core = cpu_get_id(); - struct xtos_core_data *core_data; - xtos_structures_pointers *p; - - if (core == PLATFORM_PRIMARY_CORE_ID) { - primary_core_data.thread_data_ptr = &primary_core_ctx.td; - core_ctx_ptr[PLATFORM_PRIMARY_CORE_ID] = &primary_core_ctx; - core_data_ptr[PLATFORM_PRIMARY_CORE_ID] = &primary_core_data; - } - - cpu_write_threadptr((int)core_ctx_ptr[core]); - - core_data = core_data_ptr[core]; - - p = &core_data->thread_data_ptr->xtos_ptrs; - p->xtos_interrupt_ctx = &core_data->xtos_interrupt_ctx; - p->xtos_saved_sp = &core_data->xtos_saved_sp; -#if CONFIG_XT_INTERRUPT_LEVEL_1 - p->xtos_stack_for_interrupt_1 = core_data->xtos_stack_for_interrupt_1; -#endif -#if CONFIG_XT_INTERRUPT_LEVEL_2 - p->xtos_stack_for_interrupt_2 = core_data->xtos_stack_for_interrupt_2; -#endif -#if CONFIG_XT_INTERRUPT_LEVEL_3 - p->xtos_stack_for_interrupt_3 = core_data->xtos_stack_for_interrupt_3; -#endif -#if CONFIG_XT_INTERRUPT_LEVEL_4 - p->xtos_stack_for_interrupt_4 = core_data->xtos_stack_for_interrupt_4; -#endif -#if CONFIG_XT_INTERRUPT_LEVEL_5 - p->xtos_stack_for_interrupt_5 = core_data->xtos_stack_for_interrupt_5; -#endif -#if CONFIG_MULTICORE - p->xtos_enabled = &core_data->xtos_int_data.xtos_enabled; - p->xtos_intstruct = &core_data->xtos_int_data; - p->xtos_interrupt_table = - &core_data->xtos_int_data.xtos_interrupt_table.array[0]; - p->xtos_interrupt_mask_table = - &core_data->xtos_int_data.xtos_interrupt_mask_table[0]; -#endif -} - -/** - * \brief Called in the case of exception. - */ -static void exception(void) -{ - uintptr_t epc1; - - __asm__ __volatile__("rsr %0, EPC1" : "=a" (epc1) : : "memory"); - - /* now save panic dump */ - /* TODO: we could invoke a GDB stub here */ - panic_dump(SOF_IPC_PANIC_EXCEPTION, NULL, &epc1); -} - -/** - * \brief Registers exception handlers. - */ -static void register_exceptions(void) -{ - - /* 0 - 9 */ - _xtos_set_exception_handler( - EXCCAUSE_ILLEGAL, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_SYSCALL, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_INSTR_ERROR, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_LOAD_STORE_ERROR, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_ALLOCA, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_DIVIDE_BY_ZERO, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_SPECULATION, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_PRIVILEGED, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_UNALIGNED, (void *)&exception); - - /* Reserved 10..11 */ - - _xtos_set_exception_handler( - EXCCAUSE_INSTR_DATA_ERROR, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_LOAD_STORE_DATA_ERROR, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_INSTR_ADDR_ERROR, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_LOAD_STORE_ADDR_ERROR, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_ITLB_MISS, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_ITLB_MULTIHIT, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_INSTR_RING, (void *)&exception); - - /* Reserved 19 */ - - _xtos_set_exception_handler( - EXCCAUSE_INSTR_PROHIBITED, (void *)&exception); - - /* Reserved 21..23 */ - _xtos_set_exception_handler( - EXCCAUSE_DTLB_MISS, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_DTLB_MULTIHIT, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_LOAD_STORE_RING, (void *)&exception); - - /* Reserved 27 */ - _xtos_set_exception_handler( - EXCCAUSE_LOAD_PROHIBITED, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_STORE_PROHIBITED, (void *)&exception); - - /* Reserved 30..31 */ - _xtos_set_exception_handler( - EXCCAUSE_CP0_DISABLED, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_CP1_DISABLED, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_CP2_DISABLED, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_CP3_DISABLED, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_CP4_DISABLED, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_CP5_DISABLED, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_CP6_DISABLED, (void *)&exception); - _xtos_set_exception_handler( - EXCCAUSE_CP7_DISABLED, (void *)&exception); - - /* Reserved 40..63 */ -} - -/** - * \brief Initializes architecture. - * \return Error status. - */ -int arch_init(void) -{ - initialize_pointers_per_core(); - register_exceptions(); - return 0; -} diff --git a/src/arch/xtensa/lib/CMakeLists.txt b/src/arch/xtensa/lib/CMakeLists.txt deleted file mode 100644 index f31326299f33..000000000000 --- a/src/arch/xtensa/lib/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -add_local_sources(sof notifier.c) - -if (CONFIG_AMS) - add_local_sources(sof ams.c) -endif() - -if (CONFIG_MULTICORE) - add_local_sources(sof cpu.c) -endif() diff --git a/src/arch/xtensa/lib/ams.c b/src/arch/xtensa/lib/ams.c deleted file mode 100644 index 87fc1f482f2f..000000000000 --- a/src/arch/xtensa/lib/ams.c +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2023 Intel Corporation. All rights reserved. -// -// Author: Krzysztof Frydryk <krzysztofx.frydryk@intel.com> - -/** - * \file - * \brief Xtensa Asynchronous Messaging Service implementation file - * \authors Krzysztof Frydryk <krzysztofx.frydryk@intel.com> - */ - -#include <sof/lib/cpu.h> -#include <sof/lib/ams.h> -#include <xtos-structs.h> - -struct async_message_service **arch_ams_get(void) -{ -#if CONFIG_AMS - struct core_context *ctx = (struct core_context *)cpu_read_threadptr(); - - return &ctx->ams; -#else - return NULL; -#endif -} diff --git a/src/arch/xtensa/lib/cpu.c b/src/arch/xtensa/lib/cpu.c deleted file mode 100644 index 7910a02eff83..000000000000 --- a/src/arch/xtensa/lib/cpu.c +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - -/** - * \file - * \brief Xtensa CPU implementation file - * \authors Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#include <sof/common.h> -#include <rtos/idc.h> -#include <rtos/interrupt.h> -#include <rtos/alloc.h> -#include <rtos/cache.h> -#include <sof/lib/cpu.h> -#include <sof/lib/memory.h> -#include <sof/lib/mm_heap.h> -#include <sof/lib/notifier.h> -#include <sof/lib/pm_runtime.h> -#include <rtos/wait.h> -#include <sof/schedule/schedule.h> -#include <rtos/sof.h> -#include <sof/trace/trace.h> -#include <ipc/trace.h> -#include <user/trace.h> -#include <xtos-structs.h> -#include <stdint.h> - -extern struct core_context *core_ctx_ptr[CONFIG_CORE_COUNT]; -extern struct xtos_core_data *core_data_ptr[CONFIG_CORE_COUNT]; - -static uint32_t active_cores_mask = BIT(PLATFORM_PRIMARY_CORE_ID); - -#if CONFIG_NO_SECONDARY_CORE_ROM -extern void *shared_vecbase_ptr; -extern uint8_t _WindowOverflow4[]; - -/** - * \brief This function will allocate memory for shared secondary cores - * dynamic vectors and set global pointer shared_vecbase_ptr - */ -static void alloc_shared_secondary_cores_objects(void) -{ - uint8_t *dynamic_vectors; - - dynamic_vectors = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, 0, SOF_DYNAMIC_VECTORS_SIZE); - if (dynamic_vectors == NULL) - sof_panic(SOF_IPC_PANIC_MEM); - - shared_vecbase_ptr = dynamic_vectors; - dcache_writeback_region(&shared_vecbase_ptr, - sizeof(shared_vecbase_ptr)); -} - -/** - * \brief This function will copy dynamic vectors from _WindowOverflow4 - * to shared shared_vecbase_ptr used in alternate reset vector - */ -static void unpack_dynamic_vectors(void) -{ - void *dyn_vec_start_addr = _WindowOverflow4; - - memcpy_s(shared_vecbase_ptr, SOF_DYNAMIC_VECTORS_SIZE, - dyn_vec_start_addr, SOF_DYNAMIC_VECTORS_SIZE); - dcache_writeback_invalidate_region(shared_vecbase_ptr, - SOF_DYNAMIC_VECTORS_SIZE); -} -#endif - -int arch_cpu_enable_core(int id) -{ - struct idc_msg power_up = { - IDC_MSG_POWER_UP, IDC_MSG_POWER_UP_EXT, id }; - int ret; - - if (!arch_cpu_is_core_enabled(id)) { - /* Turn on stack memory for core */ - pm_runtime_get(CORE_MEMORY_POW, id); - - /* Power up secondary core */ - pm_runtime_get(PM_RUNTIME_DSP, PWRD_BY_TPLG | id); - - /* allocate resources for core */ - cpu_alloc_core_context(id); - - /* enable IDC interrupt for the secondary core */ - idc_enable_interrupts(id, cpu_get_id()); - -#if CONFIG_NO_SECONDARY_CORE_ROM - /* unpack dynamic vectors if it is the first secondary core */ - if (active_cores_mask == BIT(PLATFORM_PRIMARY_CORE_ID)) { - alloc_shared_secondary_cores_objects(); - unpack_dynamic_vectors(); - } -#endif - /* send IDC power up message */ - ret = idc_send_msg(&power_up, IDC_POWER_UP); - if (ret < 0) - return ret; - - active_cores_mask |= (1 << id); - } - - return 0; -} - -void arch_cpu_disable_core(int id) -{ - struct idc_msg power_down = { - IDC_MSG_POWER_DOWN, IDC_MSG_POWER_DOWN_EXT, id }; - - if (arch_cpu_is_core_enabled(id)) { - idc_send_msg(&power_down, IDC_POWER_DOWN); - - active_cores_mask ^= (1 << id); -#if CONFIG_NO_SECONDARY_CORE_ROM - /* free shared dynamic vectors it was the last secondary core */ - if (active_cores_mask == BIT(PLATFORM_PRIMARY_CORE_ID)) { - rfree(shared_vecbase_ptr); - shared_vecbase_ptr = NULL; - } -#endif - } -} - -int arch_cpu_is_core_enabled(int id) -{ - return active_cores_mask & BIT(id); -} - -int arch_cpu_enabled_cores(void) -{ - return active_cores_mask; -} - -void cpu_alloc_core_context(int core) -{ - struct core_context *core_ctx; - - core_ctx = rzalloc_core_sys(core, sizeof(*core_ctx)); - dcache_writeback_invalidate_region(core_ctx, sizeof(*core_ctx)); - - core_data_ptr[core] = rzalloc_core_sys(core, - sizeof(*core_data_ptr[core])); - core_data_ptr[core]->thread_data_ptr = &core_ctx->td; - dcache_writeback_invalidate_region(core_data_ptr[core], - sizeof(*core_data_ptr[core])); - - dcache_writeback_invalidate_region(core_data_ptr, - sizeof(core_data_ptr)); - - core_ctx_ptr[core] = core_ctx; - dcache_writeback_invalidate_region(core_ctx_ptr, - sizeof(core_ctx_ptr)); - - /* share pointer to sof context */ - dcache_writeback_region(sof_get(), sizeof(*sof_get())); -} - -void cpu_power_down_core(uint32_t flags) -{ - arch_interrupt_global_disable(); - - /* Power down with memory on is performed by secondary cores during - * d0 -> d0ix before they are disabled by primary core. - */ - if (flags & CPU_POWER_DOWN_MEMORY_ON) { - /* disable idc interrupts */ - idc_free(IDC_FREE_IRQ_ONLY); - - /* disable scheduler interrupts */ - schedule_free(SOF_SCHEDULER_FREE_IRQ_ONLY); - - /* data writeback/invalidate */ - dcache_writeback_invalidate_all(); - - /* after writeback/invalidate secondary core is prepared for - * powered off - prepare_d0ix_core_mask flag can be disabled - */ - platform_pm_runtime_prepare_d0ix_dis(cpu_get_id()); - } else { - idc_free(0); - - schedule_free(0); - - free_system_notify(); - - /* free entire sys heap, an instance dedicated for this core */ - free_heap(SOF_MEM_ZONE_SYS); - - dcache_writeback_invalidate_all(); - - /* Turn off stack memory for core */ - pm_runtime_put(CORE_MEMORY_POW, cpu_get_id()); - - pm_runtime_put(PM_RUNTIME_DSP, PWRD_BY_TPLG | cpu_get_id()); - } - - trace_point(0); - - /* arch_wait_for_interrupt() not used, because it will cause panic. - * This code is executed on irq lvl > 0, which is expected. - * Core will be put into reset by host anyway. - */ - while (1) - arch_wait_for_interrupt(0); -} - -int arch_cpu_restore_secondary_cores(void) -{ - struct idc_msg power_up = { IDC_MSG_POWER_UP, IDC_MSG_POWER_UP_EXT }; - int ret, id; - - for (id = 0; id < CONFIG_CORE_COUNT; id++) { - if (arch_cpu_is_core_enabled(id) && id != PLATFORM_PRIMARY_CORE_ID) { - power_up.core = id; - - /* Power up secondary core */ - pm_runtime_get(PM_RUNTIME_DSP, id); - - /* enable IDC interrupt for the secondary core */ - idc_enable_interrupts(id, cpu_get_id()); - - /* send IDC power up message */ - ret = idc_send_msg(&power_up, IDC_POWER_UP); - if (ret < 0) - return ret; - } - } - - return 0; -} - -int arch_cpu_secondary_cores_prepare_d0ix(void) -{ - struct idc_msg prepare_msg = { IDC_MSG_PREPARE_D0ix, - IDC_MSG_PREPARE_D0ix_EXT }; - int ret, id; - - for (id = 0; id < CONFIG_CORE_COUNT; id++) { - if (arch_cpu_is_core_enabled(id) && id != PLATFORM_PRIMARY_CORE_ID) { - prepare_msg.core = id; - - /* send IDC prepare message to all enabled secondary - * cores. - */ - ret = idc_send_msg(&prepare_msg, IDC_BLOCKING); - if (ret < 0) - return ret; - } - } - - return 0; -} diff --git a/src/arch/xtensa/lib/notifier.c b/src/arch/xtensa/lib/notifier.c deleted file mode 100644 index 225fe1ba99c2..000000000000 --- a/src/arch/xtensa/lib/notifier.c +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - -/** - * \file - * \brief Xtensa notifier implementation file - * \authors Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#include <sof/lib/cpu.h> -#include <sof/lib/notifier.h> -#include <xtos-structs.h> - -struct notify **arch_notify_get(void) -{ - struct core_context *ctx = (struct core_context *)cpu_read_threadptr(); - - return &ctx->notify; -} diff --git a/src/arch/xtensa/main-entry.S b/src/arch/xtensa/main-entry.S deleted file mode 100644 index 1cfa36fa4136..000000000000 --- a/src/arch/xtensa/main-entry.S +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2017 Intel Corporation. All rights reserved. - * - * Author: Rander Wang <rander.wang@intel.com> - */ - -/* - * Entry point from boot loader. - * Fix link address of this entry to SOF_TEXT_START so that - * it is easy for boot loader to jump to the baseFW because - * the boot loader and baseFW are in different elf file. - */ - - -// Exports -.global _MainEntry - - -/**************************************************************************/ - - .begin literal_prefix .MainEntry - .section .MainEntry.text, "ax" - - .align 4 - .global _MainEntry - -_MainEntry: - - call0 _start - - .size _MainEntry, . - _MainEntry - - .end literal_prefix diff --git a/src/arch/xtensa/schedule/CMakeLists.txt b/src/arch/xtensa/schedule/CMakeLists.txt deleted file mode 100644 index d462729c7245..000000000000 --- a/src/arch/xtensa/schedule/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -add_local_sources(sof schedule.c task.c) diff --git a/src/arch/xtensa/schedule/schedule.c b/src/arch/xtensa/schedule/schedule.c deleted file mode 100644 index 8ed9ab811eb9..000000000000 --- a/src/arch/xtensa/schedule/schedule.c +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - -/** - * \file - * \brief Xtensa schedule implementation file - * \authors Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#include <sof/lib/cpu.h> -#include <sof/schedule/schedule.h> -#include <xtos-structs.h> - -struct schedulers **arch_schedulers_get(void) -{ - struct core_context *ctx = (struct core_context *)cpu_read_threadptr(); - - return &ctx->schedulers; -} diff --git a/src/arch/xtensa/schedule/task.c b/src/arch/xtensa/schedule/task.c deleted file mode 100644 index e7949152ff92..000000000000 --- a/src/arch/xtensa/schedule/task.c +++ /dev/null @@ -1,130 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2017 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> -// Tomasz Lauda <tomasz.lauda@linux.intel.com> - -/** - * \file - * \brief Arch task implementation file - * \authors Liam Girdwood <liam.r.girdwood@linux.intel.com> - * Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#include <rtos/alloc.h> -#include <rtos/cache.h> -#include <sof/lib/cpu.h> -#include <sof/lib/memory.h> -#include <rtos/wait.h> -#include <sof/schedule/edf_schedule.h> -#include <sof/schedule/schedule.h> -#include <rtos/task.h> -#include <ipc/topology.h> - -#include <xtensa/corebits.h> -#include <xtensa/xtruntime-frames.h> -#include <xtos-structs.h> -#include <errno.h> -#include <stddef.h> -#include <stdint.h> - -enum task_state task_main_secondary_core(void *data) -{ -#if CONFIG_MULTICORE - /* main audio processing loop */ - while (1) { - /* sleep until next IDC or DMA */ - wait_for_interrupt(0); - } -#endif - - return SOF_TASK_STATE_COMPLETED; -} - -struct task **task_main_get(void) -{ - struct core_context *ctx = (struct core_context *)cpu_read_threadptr(); - - return &ctx->main_task; -} - -volatile void *task_context_get(void) -{ - struct core_context *ctx = (struct core_context *)cpu_read_threadptr(); - - return ctx->td.xtos_active_task; -} - -void task_context_set(void *task_ctx) -{ - struct core_context *ctx = (struct core_context *)cpu_read_threadptr(); - - ctx->td.xtos_active_task = task_ctx; -} - -int task_context_alloc(void **task_ctx) -{ - *task_ctx = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(xtos_task_context)); - if (!*task_ctx) - return -ENOMEM; - return 0; -} - -int task_context_init(void *task_ctx, void *entry, void *arg0, void *arg1, - int task_core, void *stack, int stack_size) -{ - xtos_task_context *ctx = task_ctx; - UserFrame *sp; - - /* allocate stack if not provided */ - if (stack) { - ctx->stack_base = stack; - ctx->stack_size = stack_size; - } else { - ctx->stack_base = rballoc(0, SOF_MEM_CAPS_RAM, - PLATFORM_TASK_DEFAULT_STACK_SIZE); - if (!ctx->stack_base) - return -ENOMEM; - ctx->stack_size = PLATFORM_TASK_DEFAULT_STACK_SIZE; - ctx->flags |= XTOS_TASK_CONTEXT_OWN_STACK; - } - bzero(ctx->stack_base, ctx->stack_size); - - /* set initial stack pointer */ - sp = (UserFrame *)((char *)ctx->stack_base + ctx->stack_size - - sizeof(UserFrame)); - - /* entry point */ - sp->pc = (uint32_t)entry; - - /* a1 is pointer to stack */ - sp->a1 = (uint32_t)sp; - - /* PS_WOECALL4_ABI - window overflow and increment enable - * PS_UM - user vector mode enable - */ - sp->ps = PS_WOECALL4_ABI | PS_UM; - - /* a6 and a7 are the first parameters */ - sp->a6 = (uint32_t)arg0; - sp->a7 = (uint32_t)arg1; - - ctx->stack_pointer = sp; - - return 0; -} - -void task_context_free(void *task_ctx) -{ - xtos_task_context *ctx = task_ctx; - - if (ctx->flags & XTOS_TASK_CONTEXT_OWN_STACK) - rfree(ctx->stack_base); - - ctx->stack_size = 0; - ctx->stack_pointer = NULL; - - rfree(ctx); -} diff --git a/src/arch/xtensa/xtos/CMakeLists.txt b/src/arch/xtensa/xtos/CMakeLists.txt deleted file mode 100644 index 2377a7469428..000000000000 --- a/src/arch/xtensa/xtos/CMakeLists.txt +++ /dev/null @@ -1,96 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -set(VECTOR_DEFS - -D__SPLIT__vector - -D__SPLIT__handler - -D__SPLIT__user -) - -# Builds lib for each level from the same source files - -function(sof_xtos_add_level level) - set(lib_name "xlevel${level}") - add_library(${lib_name} STATIC "") - add_local_sources(${lib_name} - int-handler.S - int-vector.S - int-initlevel.S - ) - target_link_libraries(${lib_name} sof_options) - target_compile_definitions(${lib_name} PRIVATE - ${VECTOR_DEFS} - -D_INTERRUPT_LEVEL=${level} - ) -endfunction() - -if(CONFIG_XT_INTERRUPT_LEVEL_1) - list(APPEND VECTOR_DEFS -D__SPLIT__level1int) -endif() - -if(CONFIG_XT_INTERRUPT_LEVEL_2) - list(APPEND VECTOR_DEFS -D__SPLIT__level2) - list(APPEND levels 2) -endif() - -if(CONFIG_XT_INTERRUPT_LEVEL_3) - list(APPEND VECTOR_DEFS -D__SPLIT__level3) - list(APPEND levels 3) -endif() - -if(CONFIG_XT_INTERRUPT_LEVEL_4) - list(APPEND VECTOR_DEFS -D__SPLIT__level4) - list(APPEND levels 4) -endif() - -if(CONFIG_XT_INTERRUPT_LEVEL_5) - list(APPEND VECTOR_DEFS -D__SPLIT__level5) - list(APPEND levels 5) -endif() - -foreach(level ${levels}) - sof_xtos_add_level(${level}) -endforeach() - -add_library(xtos STATIC "") -add_local_sources(xtos - core-restore.S - core-save.S - core-shutoff.S - double-vector.S - debug-vector.S - xea1/exc-alloca-handler.S - xea1/exc-c-wrapper-handler.S - xea2/exc-c-wrapper-handler.S - xea1/exc-return.S - xea2/exc-return.S - exc-sethandler.c - exc-syscall-handler.S - exc-table.S - exc-unhandled.S - interrupt-table.S - int-sethandler.c - xea1/intlevel-restore.S - xea2/intlevel-restore.S - xea1/intlevel-setmin.S - xea2/intlevel-setmin.S - xea1/intlevel-set.S - xea2/intlevel-set.S - xea1/int-lowpri-dispatcher.S - xea2/int-lowpri-dispatcher.S - ints-off.S - ints-on.S - kernel-vector.S - memep-enable.S - memep-initrams.S - memerror-vector.S - nmi-vector.S - xea2/reloc-vectors.S - user-vector.S - xea1/window-vectors.S - xea2/window-vectors.S - stub.c -) -sof_append_relative_path_definitions(xtos) -target_link_libraries(xtos sof_options) -target_compile_definitions(xtos PRIVATE ${VECTOR_DEFS}) - diff --git a/src/arch/xtensa/xtos/_sharedvectors-for-reset.S b/src/arch/xtensa/xtos/_sharedvectors-for-reset.S deleted file mode 100644 index ef60901d53e8..000000000000 --- a/src/arch/xtensa/xtos/_sharedvectors-for-reset.S +++ /dev/null @@ -1,40 +0,0 @@ -// _sharedvectors-for-reset.S -- Reference to pull in a shared reset vector -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/_sharedvectors-for-reset.S#1 $ - -// Copyright (c) 2008 Tensilica 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. - -#include <xtensa/coreasm.h> - -/* Multicore build flows can use this file (_sharedvectors-for-reset.o) - by copying it to _sharedvectors.o early in the linker search path - (to override the default one), and updating the memory map or linker - scripts accordingly. - This file pulls in a sharable reset vector (typically - shared-reset-vector.S, which requires the PRID option). */ - -.global _SharedResetVector - -/* The following allows this object file to be pulled in by reference: */ -.text -.global _xtos_sharedvectors_ref_ -.set _xtos_sharedvectors_ref_, 0 - diff --git a/src/arch/xtensa/xtos/_sharedvectors.S b/src/arch/xtensa/xtos/_sharedvectors.S deleted file mode 100644 index def144132519..000000000000 --- a/src/arch/xtensa/xtos/_sharedvectors.S +++ /dev/null @@ -1,37 +0,0 @@ -// _sharedvectors.S -- Reference symbols to pull in any shared vectors -// (default version, used when not sharing any vector) -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/_sharedvectors.S#1 $ - -// Copyright (c) 2008 Tensilica 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. - -#include <xtensa/coreasm.h> - -/* Not present by default. Multicore build flows build/use a custom - version of _sharedvectors.o that may pull in shared vectors. */ - -/* .global _SharedResetVector */ - -/* The following allows this object file to be pulled in by reference: */ -.text -.global _xtos_sharedvectors_ref_ -.set _xtos_sharedvectors_ref_, 0 - diff --git a/src/arch/xtensa/xtos/_vectors.S b/src/arch/xtensa/xtos/_vectors.S deleted file mode 100644 index 8c70e3f2514f..000000000000 --- a/src/arch/xtensa/xtos/_vectors.S +++ /dev/null @@ -1,94 +0,0 @@ -// _vectors.S -- Reference symbols to pull in all required vectors -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/_vectors.S#1 $ - -// Copyright (c) 2004, 2006-2007 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/config/system.h> /* for XSHAL_VECTORS_PACKED */ - -.global _ResetVector - -#if XCHAL_HAVE_EXCEPTIONS - -# if XCHAL_HAVE_DEBUG -.global _DebugExceptionVector -# endif - -.global _KernelExceptionVector -.global _UserExceptionVector - -# ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR -.global _DoubleExceptionVector -# endif - -# if XCHAL_HAVE_NMI -.global _NMIExceptionVector -# endif - -# if XCHAL_HAVE_WINDOWED -.global _WindowOverflow4 -.global _WindowUnderflow4 -.global _WindowOverflow8 -.global _WindowUnderflow8 -.global _WindowOverflow12 -.global _WindowUnderflow12 -# endif - -# if XCHAL_HAVE_MEM_ECC_PARITY -.global _MemErrorVector -# endif - -#endif /* XCHAL_HAVE_EXCEPTIONS */ - - -#if (XCHAL_NUM_INTLEVELS >= 2) && (2 != XCHAL_DEBUGLEVEL) -.global _Level2Vector -#endif -#if (XCHAL_NUM_INTLEVELS >= 3) && (3 != XCHAL_DEBUGLEVEL) -.global _Level3Vector -#endif -#if (XCHAL_NUM_INTLEVELS >= 4) && (4 != XCHAL_DEBUGLEVEL) -.global _Level4Vector -#endif -#if (XCHAL_NUM_INTLEVELS >= 5) && (5 != XCHAL_DEBUGLEVEL) -.global _Level5Vector -#endif -#if (XCHAL_NUM_INTLEVELS >= 6) && (6 != XCHAL_DEBUGLEVEL) -.global _Level6Vector -#endif - -#if XCHAL_HAVE_VECBASE && XSHAL_VECTORS_PACKED -.global _RelocVectors -#endif - -/* These don't take up space: */ -.global xthals_hw_configid0 -.global xthals_hw_configid1 -.global xthals_release_major -.global xthals_release_minor - -/* The following allows this object file to be pulled in by reference: */ -.text -.global _xtos_vectors_ref_ -.set _xtos_vectors_ref_, 0 - - diff --git a/src/arch/xtensa/xtos/checkvecsize b/src/arch/xtensa/xtos/checkvecsize deleted file mode 100755 index 70789816de81..000000000000 --- a/src/arch/xtensa/xtos/checkvecsize +++ /dev/null @@ -1,71 +0,0 @@ -# Script to check that vector code is 16 bytes or less -# $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/checkvecsize#1 $ - -# Copyright (c) 2001 Tensilica 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. - -package Xtensa::checkvecsize; - -# Perl library modules -use strict; -use Getopt::Long; -use FileHandle; - -# Program - -use vars qw($objdump $maxsize); - -{ - $::myname = 'checkvecsize'; - - # command line - $maxsize = 16; - die("Usage is: $::myname -objdump prog [-maxsize n] files...\n") - unless &GetOptions("objdump=s" => \$objdump, - "maxsize=i" => \$maxsize) - && @ARGV > 0 && defined($objdump); - my $file; - foreach $file (@ARGV) { - checkvecsize ($file); - } -} - -sub checkvecsize { - my ($file) = @_; - my $od = new FileHandle "${objdump} -h $file|"; - die("$::myname: $!, opening pipe to $objdump -h $file.\n") - unless $od; - while (<$od>) { - if (/^\s*\d+\s+(\S+)\s+([0-9A-Fa-f]{8})\s/) { - my $size = hex($2); - die("$::myname: $file $1 section size is $size bytes.\n") - if $size > $maxsize; - } - } - $od->close(); -} - - -# Local Variables: -# mode:perl -# perl-indent-level:2 -# cperl-indent-level:2 -# End: diff --git a/src/arch/xtensa/xtos/core-restore.S b/src/arch/xtensa/xtos/core-restore.S deleted file mode 100644 index 25fa43f18afb..000000000000 --- a/src/arch/xtensa/xtos/core-restore.S +++ /dev/null @@ -1,607 +0,0 @@ -// core-restore.S -- core state restore routine (used by PSO) -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/core-restore.S#1 $ - -// Copyright (c) 2012-2013 Tensilica 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. - - -#include <xtensa/coreasm.h> -#include <xtensa/corebits.h> -#include <xtensa/cacheasm.h> -#include <xtensa/cacheattrasm.h> -#include <xtensa/xdm-regs.h> -#include <xtensa/config/core-isa.h> -#include <xtensa/mpuasm.h> -#include <xtensa/xtruntime-core-state.h> -#include "xtos-internal.h" -#include <xtensa/idmaasm.h> - - .text - - - - // void _xtos_core_restore(unsigned retvalue, XtosCoreState *savearea) - // - // Restore processor state. - // If save area signature is bad, function just returns. - // Else, processor state is restored, and execution resumes - // according to that saved processor state. - // - // On entry: - // Caches are ready to use (initialized or warm, as the case may be). - // - .align 4 - .global _xtos_core_restore - .type _xtos_core_restore,@function -_xtos_core_restore: - abi_entry - - // Check the save area's signature: - movi a5, CORE_STATE_SIGNATURE - l32i a4, a3, CS_SA_signature - movi a6, 0 - bne a4, a5, 1f // if bad, just return - -#if XCHAL_HAVE_INTERRUPTS - rsil a4, 15 // disable interrupts... - wsr.intenable a6 -#endif - - // Here, call0 is used as an unlimited range jump. It does not return. - call0 _xtos_core_restore_nw - -1: abi_return - - .size _xtos_core_restore, . - _xtos_core_restore - - - - // Restore processor state. - // On entry: - // Caches are ready to use (initialized or warm, as the case may be). - // a2 = return value passed to restored processor state - // a3 = pointer to save area to restore from - // INTENABLE = 0 (interrupts all disabled) - // LITBASE = initialized (per reset vector, not restored) - // touching a4..a7 won't overflow - // other registers are mostly undefined - // - .align 4 - .global _xtos_core_restore_nw - .type _xtos_core_restore_nw,@function -_xtos_core_restore_nw: - -#if XCHAL_HAVE_WINDOWED - s32i a2, a3, CS_SA_areg + 2*4 // save a2 thru rotation - wsr.excsave1 a3 // save a3 thru rotation - l32i a6, a3, CS_SA_windowstart // restore windowstart - l32i a5, a3, CS_SA_windowbase // restore windowbase - wsr.windowstart a6 - wsr.windowbase a5 - rsync - // a0-a15 have possibly all changed, so need to reload a3 - rsr.excsave1 a3 // restore a3 - l32i a2, a3, CS_SA_areg + 2*4 // restore a2 (return value) -#endif - - //movi a0, 0 - l32i a0, a3, CS_SA_restore_label // _xtos_core_save_common's return PC - - // Just for consistency... -#if XCHAL_HAVE_INTERRUPTS || XCHAL_HAVE_EXCEPTIONS - movi a4, 0x11 - wsr.ps a4 - rsync -#endif - - l32i a5, a3, CS_SA_sar // restore sar - wsr.sar a5 - -#if XCHAL_HAVE_PSO_CDM - // Restore PWRCTL (except ShutProcOffOnPWait, cleared when all is done). - movi a4, XDM_MISC_PWRCTL - movi a7, PWRCTL_CORE_SHUTOFF // aka ShutProcOffOnPWait - rer a6, a4 // read pwrctl - l32i a5, a3, CS_SA_pwrctl // get saved pwrctl - and a7, a7, a6 // keep just ShutProcOffOnPWait bit - or a5, a5, a7 // keep it set if already set (clear later) - wer a5, a4 // restore pwrctl (except ShutProcOffOnPWait) -#endif - - .set _idx, 2 - .rept XCHAL_NUM_INTLEVELS+XCHAL_HAVE_NMI-1 - l32i a5, a3, CS_SA_epc + 4*(_idx-2) - INDEX_SR wsr.epc a5 - l32i a5, a3, CS_SA_eps + 4*(_idx-2) - INDEX_SR wsr.eps a5 - l32i a5, a3, CS_SA_excsave + 4*(_idx-2) - INDEX_SR wsr.excsave a5 - .set _idx, _idx+1 - .endr - -#if XCHAL_HAVE_LOOPS - l32i a5, a3, CS_SA_lbeg - wsr.lbeg a5 - l32i a5, a3, CS_SA_lend - wsr.lend a5 - l32i a5, a3, CS_SA_lcount - wsr.lcount a5 -#endif -#if XCHAL_HAVE_ABSOLUTE_LITERALS - l32i a5, a3, CS_SA_litbase - wsr.litbase a5 -#endif -#if XCHAL_HAVE_VECBASE - l32i a5, a3, CS_SA_vecbase - wsr.vecbase a5 -#endif -#if XCHAL_HAVE_S32C1I && (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RC_2009_0) /* have ATOMCTL ? */ - l32i a5, a3, CS_SA_atomctl - wsr.atomctl a5 -#endif -#if XCHAL_HAVE_PREFETCH - l32i a5, a3, CS_SA_prefctl - wsr.prefctl a5 -#endif -#if XCHAL_USE_MEMCTL - l32i a5, a3, CS_SA_memctl - wsr.memctl a5 -#endif -#if XCHAL_HAVE_DEBUG - // NOTE: restore of debug state is conditional, - // as the power-down and wakeup code might be actively debugged. - rsr.icountlevel a5 - bnez a5, 1f // skip if being single-stepped (not failsafe!) - l32i a5, a3, CS_SA_icount - wsr.icount a5 - l32i a5, a3, CS_SA_icountlevel - wsr.icountlevel a5 -1: - //l32i a5, a3, CS_SA_debugcause // (won't get restored?) - //wsr.debugcause a5 - //l32i a5, a3, CS_SA_ddr - //wsr.ddr a5 -# if XCHAL_NUM_IBREAK - rsr.ibreakenable a6 - bnez a5, 1f // skip restore if already some ibreaks defined - - .set _idx, 0 - .rept XCHAL_NUM_IBREAK - l32i a5, a3, CS_SA_ibreaka + 4*_idx - INDEX_SR wsr.ibreaka a5 - .set _idx, _idx+1 - .endr - - l32i a5, a3, CS_SA_ibreakenable - wsr.ibreakenable a5 -1: -# endif - .set _idx, 0 - .rept XCHAL_NUM_DBREAK - INDEX_SR rsr.dbreakc a6 - bbsi.l a6, 30, 1f // skip restore of that dbreak if already active - bbsi.l a6, 31, 1f // ditto - l32i a5, a3, CS_SA_dbreaka + 4*_idx - INDEX_SR wsr.dbreaka a5 - l32i a5, a3, CS_SA_dbreakc + 4*_idx - INDEX_SR wsr.dbreakc a5 -1: - .set _idx, _idx+1 - .endr -#endif - - .set _idx, 0 - .rept XCHAL_NUM_MISC_REGS - l32i a5, a3, CS_SA_misc + 4*_idx - INDEX_SR wsr.misc a5 - .set _idx, _idx+1 - .endr - -#if XCHAL_HAVE_MEM_ECC_PARITY - l32i a5, a3, CS_SA_mepc - wsr.mepc a5 - l32i a5, a3, CS_SA_meps - wsr.meps a5 - l32i a5, a3, CS_SA_mesave - wsr.mesave a5 - l32i a5, a3, CS_SA_mesr - wsr.mesr a5 - l32i a5, a3, CS_SA_mecr - wsr.mecr a5 - l32i a5, a3, CS_SA_mevaddr - wsr.mevaddr a5 -#endif - - /* TIE state */ - addi a4, a3, CS_SA_ncp - xchal_ncp_load a4, a5,a6,a7,a8 // restore non-coprocessor state -#if XCHAL_HAVE_CP - movi a6, -1 - wsr.cpenable a6 // enable all coprocessors - rsync - xchal_cp0_load a4, a5,a6,a7,a8 continue=1 - xchal_cp1_load a4, a5,a6,a7,a8 continue=1 - xchal_cp2_load a4, a5,a6,a7,a8 continue=1 - xchal_cp3_load a4, a5,a6,a7,a8 continue=1 - xchal_cp4_load a4, a5,a6,a7,a8 continue=1 - xchal_cp5_load a4, a5,a6,a7,a8 continue=1 - xchal_cp6_load a4, a5,a6,a7,a8 continue=1 - xchal_cp7_load a4, a5,a6,a7,a8 continue=1 - //xchal_cp8_load a4, a5,a6,a7,a8 continue=1 - //xchal_cp9_load a4, a5,a6,a7,a8 continue=1 - //xchal_cp10_load a4, a5,a6,a7,a8 continue=1 - //xchal_cp11_load a4, a5,a6,a7,a8 continue=1 - //xchal_cp12_load a4, a5,a6,a7,a8 continue=1 - //xchal_cp13_load a4, a5,a6,a7,a8 continue=1 - //xchal_cp14_load a4, a5,a6,a7,a8 continue=1 - //xchal_cp15_load a4, a5,a6,a7,a8 continue=1 - l32i a5, a3, CS_SA_cpenable - wsr.cpenable a5 -#endif - - /* TLB state (for known MMU types only, not internal custom) */ - // FIXME FIXME FIXME TODO: - // This restore code does not work in the general case, - // for CaXLT or full MMU, in particular when any address mappings - // were active when saved, that don't match reset state and affect - // code and data currently being accessed for restore. -#if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR - addi a4, a3, CS_SA_tlbs // where to start loading TLB entry info - movi a5, 0x20000000 - movi a6, 0 -1: - l32i a7, a4, 0 - wdtlb a7, a6 // write DTLB entry PPN + CA - dsync - l32i a7, a4, 4 - j 2f - // Ensure WITLB and ISYNC are in same cache line, when writing ITLB - // entry that maps this currently running code - // (micro-architecture defined sequence): - .begin no-transform - .align 16 -2: witlb a7, a6 // write ITLB entry PPN + CA - isync - .end no-transform - nop - nop - addi a4, a4, 8 - add a6, a6, a5 - bnez a6, 1b - -#elif XCHAL_HAVE_PTP_MMU - addi a4, a3, CS_SA_tlbs // where to start storing TLB entry info - movi a10, _xtos_pso_tlbmap - movi a11, _xtos_pso_tlbmap_end - l32i a14, a3, CS_SA_dtlbcfg - l32i a15, a3, CS_SA_itlbcfg - wsr.dtlbcfg a14 // page size index (0..3) for each DTLB way - wsr.itlbcfg a15 // page size index (0..3) for each ITLB way - l32i a5, a3, CS_SA_ptevaddr - wsr.ptevaddr a5 - rsync - // Loop from last way to first (less register pressure that way). -.Loop_tlbmap_rest: - addi a11, a11, -8 // next way - l32i a8, a11, 0 // map of four (page size log2) per index for this way - // DTLB page size: - extui a12, a14, 0, 4 // page size index for this DTLB way - srli a14, a14, 4 // (for next way) - ssa8l a12 // prepare to shift right by 8*a12 - srl a12, a8 // page size log2 for this DTLB way - ssl a12 // prepare to shift left by a12 - movi a12, 1 // (to compute 1 << (page size log2)) - sll a12, a12 // page size for this DTLB way - - // Restore all entries of this DTLB way: - l32i a9, a11, 4 // number of entries for this way - sub a5, a11, a10 // way number * 8 - srli a5, a5, 3 // way number - extui a9, a9, 0, 8 -1: - l32i a6, a4, 0 // read entry VPN + ASID - extui a7, a6, 0, 8 // get ASID - bnez a7, 2f // if non-zero, need WDTLB - add a6, a6, a5 // zero, so need IDTLB - add way number - idtlb a6 // invalidate DTLB entry - j 5f -2: // Non-zero ASID. Put in RASID and adjust PS.RING accordingly. - bgeui a7, 5, 3f // branch if ASID >= 5 - addi a7, a7, -1 - slli a7, a7, 6 // PS.RING = ASID - 1 - addi a7, a7, 0x11 // PS.EXCM=1, PS.INTLEVEL=1 - movi a6, 0x04030201 // for ASID in {1 .. 4} - j 4f -3: // ASID >= 5, place it in RASID - movi a6, 0x00030201 - slli a7, a7, 24 - add a6, a7, a6 // RASID = 0x <ASID> 03 02 01 - movi a7, 0xd1 // PS.RING=3, PS.EXCM=1, PS.INTLEVEL=1 -4: wsr.rasid a6 - wsr.ps a7 - rsync - l32i a6, a4, 0 // read entry VPN + ASID - l32i a7, a4, 4 // read entry PPN + CA - srli a6, a6, 8 // replace ASID ... - slli a6, a6, 8 // ... - add a6, a6, a5 // ... with way number - wdtlb a7, a6 // write DTLB entry ... -5: dsync - addi a4, a4, 8 - add a5, a5, a12 // next entry of this DTLB way - addi a9, a9, -1 - bnez a9, 1b - - // ITLB page size: - extui a12, a15, 0, 4 // page size index for this ITLB way - srli a15, a15, 4 // (for next way) - ssa8l a12 // prepare to shift right by 8*a12 - srl a12, a8 // page size log2 for this ITLB way - ssl a12 // prepare to shift left by a12 - movi a12, 1 // (to compute 1 << (page size log2)) - sll a12, a12 // page size for this ITLB way - - // Restore all entries of this ITLB way: - l32i a9, a11, 4 // number of entries for this way - sub a5, a11, a10 // way number * 8 - srli a5, a5, 3 // way number - bbsi.l a9, 15, 6f // skip ITLB if is a DTLB-only way - extui a9, a9, 0, 8 -1: - l32i a6, a4, 0 // read entry VPN + ASID - extui a7, a6, 0, 8 // get ASID - bnez a7, 2f // if non-zero, need WITLB - add a6, a6, a5 // zero, so need IITLB - add way number - iitlb a6 // invalidate ITLB entry - j 5f -2: // Non-zero ASID. Put in RASID and adjust PS.RING accordingly. - bgeui a7, 5, 3f // branch if ASID >= 5 - addi a7, a7, -1 - slli a7, a7, 6 // PS.RING = ASID - 1 - addi a7, a7, 0x11 // PS.EXCM=1, PS.INTLEVEL=1 - movi a6, 0x04030201 // for ASID in {1 .. 4} - j 4f -3: // ASID >= 5, place it in RASID - movi a6, 0x00030201 - slli a7, a7, 24 - add a6, a7, a6 // RASID = 0x <ASID> 03 02 01 - movi a7, 0xd1 // PS.RING=3, PS.EXCM=1, PS.INTLEVEL=1 -4: wsr.rasid a6 - wsr.ps a7 - rsync - l32i a6, a4, 0 // read entry VPN + ASID - l32i a7, a4, 4 // read entry PPN + CA - srli a6, a6, 8 // replace ASID ... - slli a6, a6, 8 // ... - add a6, a6, a5 // ... with way number - j 8f - .align 16 // ensure WITLB and ISYNC in same cache line -8: witlb a7, a6 // write ITLB entry ... -5: isync - addi a4, a4, 8 - add a5, a5, a12 // next entry of this ITLB way - addi a9, a9, -1 - bnez a9, 1b -6: - - bne a11, a10, .Loop_tlbmap_rest // loop for next TLB way - l32i a5, a3, CS_SA_rasid - wsr.rasid a5 - movi a6, 0x11 - wsr.ps a6 - rsync - // Done saving TLBs. -#endif - -#if XCHAL_HAVE_MPU - addi a4, a3, CS_SA_mpuentry // MPU restore location - movi a5, XCHAL_MPU_ENTRIES - mpu_write_map a4, a5, a6, a7, a8, a9 - l32i a4, a3, CS_SA_cacheadrdis - wsr.cacheadrdis a4 -#endif - -#if XCHAL_HAVE_IDMA - addi a4, a3, CS_SA_idmaregs // IDMA regs restore location - _idma_restore a4, a5, a6, a7 -#endif - -#if XCHAL_HAVE_WINDOWED - // All the stack frames (except for our own) are supposed to be spilled - // into the stack. So now we restore the saved registers for our caller - // (and its caller) into the correct locations in the stack. See the - // comments in core-save.S and also the Xtensa Programmers Guide for - // more information. Of course we only restore if there is valid saved - // state. - - l32i a4, a3, CS_SA_caller_regs_saved // flag - beqz a4, .Lendcr // skip restore if 0 - - // Restore our caller's a0-a3 - - l32i a1, a3, CS_SA_areg + 1*4 // restore a1 - addi a4, a1, -16 - l32i a5, a3, CS_SA_caller_regs - l32i a6, a3, CS_SA_caller_regs + 4 - s32i a5, a4, 0 // caller a0 - s32i a6, a4, 4 // caller a1 - l32i a5, a3, CS_SA_caller_regs + 8 - l32i a6, a3, CS_SA_caller_regs + 12 - s32i a5, a4, 8 // caller a2 - s32i a6, a4, 12 // caller a3 - - // Now restore our callers caller's a0-a3 - - l32i a5, a3, CS_SA_caller_regs + 16 - l32i a6, a3, CS_SA_caller_regs + 20 - s32i a5, a1, 0 // caller caller a0 - s32i a6, a1, 4 // caller caller a1 - l32i a5, a3, CS_SA_caller_regs + 24 - l32i a6, a3, CS_SA_caller_regs + 28 - s32i a5, a1, 8 // caller caller a2 - s32i a6, a1, 12 // caller caller a3 - - // Now restore caller's a4-a11 as required - // NOTE a0 is pointing to _xtos_core_save() not the actual caller - - l32i a4, a3, CS_SA_areg // load actual return address - extui a4, a4, 30, 2 // top 2 bits of ret addr - blti a4, 2, .Lendcr - l32i a5, a1, 4 // a5 <- caller caller a1 - slli a4, a4, 4 - sub a4, a5, a4 // a4 <- bottom of extra save area - addi a5, a5, -16 // a5 <- top of extra save area - addi a6, a3, CS_SA_caller_regs + 32 // location to start restore from -.Lcrloop: - l32i a7, a6, 0 // Restore in groups of 4 registers - l32i a8, a6, 4 - s32i a7, a4, 0 - s32i a8, a4, 4 - l32i a7, a6, 8 - l32i a8, a6, 12 - s32i a7, a4, 8 - s32i a8, a4, 12 - addi a4, a4, 16 - addi a6, a6, 16 - blt a4, a5, .Lcrloop -.Lendcr: -#endif - - // Restore timers and CCOUNT right before enabling interrupts. We will - // try to restore any timer interrupts that were pending (as indicated - // by the INTERRUPT register) at the time of the state save. -#if XCHAL_HAVE_CCOUNT - .macro restore_timer num intr - l32i a5, a3, CS_SA_ccompare + 4*\num // Load CCOMPARE value - l32i a6, a3, CS_SA_interrupt // Load old INTERRUPT value - writesr ccompare \num a5 // Restore CCOMPARE - bbci.l a6, \intr, .Lrtdone\num // Intr not set for this timer - addi a5, a5, -1 // CCOUNT = CCOMPARE - 1 -.Lrttry\num: - wsr.ccount a5 // Set CCOUNT and wait - esync - nop - rsr.interrupt a6 - bbci.l a6, \intr, .Lrttry\num // If intr not set then retry -.Lrtdone\num: - .endm - -#if XCHAL_NUM_TIMERS > 0 - restore_timer 0 XCHAL_TIMER0_INTERRUPT -#endif -#if XCHAL_NUM_TIMERS > 1 - restore_timer 1 XCHAL_TIMER1_INTERRUPT -#endif -#if XCHAL_NUM_TIMERS > 2 - restore_timer 2 XCHAL_TIMER2_INTERRUPT -#endif -#if XCHAL_NUM_TIMERS > 3 - restore_timer 3 XCHAL_TIMER3_INTERRUPT -#endif - - // Attempt to clear any spurious timer interrupts caused by the CCOUNT - // dance above. -#if XCHAL_NUM_TIMERS > 0 - l32i a5, a3, CS_SA_ccount // Restore CCOUNT - wsr.ccount a5 - l32i a5, a3, CS_SA_interrupt // Load old intr value - bbsi.l a5, XCHAL_TIMER0_INTERRUPT, .Lx1 // Skip if timer0 intr set - rsr.ccompare0 a6 // Force timer0 intr clear - wsr.ccompare0 a6 -.Lx1: -#if XCHAL_NUM_TIMERS > 1 - bbsi.l a5, XCHAL_TIMER1_INTERRUPT, .Lx2 // Skip if timer1 intr set - rsr.ccompare1 a6 // Force timer1 intr clear - wsr.ccompare1 a6 -.Lx2: -#endif -#if XCHAL_NUM_TIMERS > 2 - bbsi.l a5, XCHAL_TIMER2_INTERRUPT, .Lx3 // Skip if timer2 intr set - rsr.ccompare2 a6 // Force timer2 intr clear - wsr.ccompare2 a6 -.Lx3: -#endif -#if XCHAL_NUM_TIMERS > 3 - bbsi.l a5, XCHAL_TIMER3_INTERRUPT, .Lx4 // Skip if timer3 intr set - rsr.ccompare3 a6 // Force timer3 intr clear - wsr.ccompare3 a6 -.Lx4: -#endif -#endif - - l32i a5, a3, CS_SA_ccount // Restore CCOUNT again - wsr.ccount a5 -#endif - -#if XCHAL_HAVE_INTERRUPTS - rsil a6, 15 // disable interrupts before enabling with INTENABLE - l32i a5, a3, CS_SA_intenable - wsr.intenable a5 - movi a4, XCHAL_INTTYPE_MASK_SOFTWARE // restore any pending software interrupts - l32i a5, a3, CS_SA_interrupt - and a5, a5, a4 - wsr.intset a5 - rsync -#endif - - //l32i a0, a3, CS_SA_restore_label // _xtos_core_save_common's return PC -#if XCHAL_HAVE_INTERRUPTS || XCHAL_HAVE_EXCEPTIONS - //l32i a4, a3, CS_SA_ps - l32i a5, a3, CS_SA_epc1 - wsr.epc1 a5 - l32i a5, a3, CS_SA_excsave1 - wsr.excsave1 a5 -# ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR - l32i a5, a3, CS_SA_depc - wsr.depc a5 -# endif - //wsr.ps a4 // PS restored by caller - //rsync -#endif - -#if XCHAL_HAVE_PSO_CDM - // As late as possible, wait for debug to wakeup, and clear PWRCTL.ShutProcOffOnPWait. - movi a4, XDM_MISC_PWRCTL - rer a5, a4 // read pwrctl - - // Wait for debug powerup to complete (if started): - bbci.l a5, PWRCTL_DEBUG_WAKEUP_SHIFT, 1f - movi a7, XDM_MISC_PWRSTAT -2: rer a6, a7 // read PWRSTAT - bbci.l a6, PWRSTAT_DEBUG_DOMAIN_ON_SHIFT, 2b // loop until debug is powered up -1: - - movi a7, ~PWRCTL_CORE_SHUTOFF // aka ShutProcOffOnPWait - and a5, a5, a7 // clear ShutProcOffOnPWait bit - wer a5, a4 // update pwrctl -#endif - - movi a4, 0 - s32i a4, a3, CS_SA_signature // make sure save area is marked as no longer valid -#if XCHAL_DCACHE_IS_WRITEBACK - dhwb a3, CS_SA_signature -#endif - ret // return from _xtos_core_save_common - // NOTE: a2 holds return value as specified to - // _xtos_core_restore() - - .size _xtos_core_restore_nw, . - _xtos_core_restore_nw - diff --git a/src/arch/xtensa/xtos/core-save.S b/src/arch/xtensa/xtos/core-save.S deleted file mode 100644 index 217d68c845d4..000000000000 --- a/src/arch/xtensa/xtos/core-save.S +++ /dev/null @@ -1,763 +0,0 @@ -// core-save.S -- core state save/restore routines (used by PSO) -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/core-save.S#1 $ - -// Copyright (c) 2012-2013 Tensilica 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. - - -#include <xtensa/coreasm.h> -#include <xtensa/corebits.h> -#include <xtensa/cacheasm.h> -#include <xtensa/cacheattrasm.h> -#include <xtensa/xdm-regs.h> -#include <xtensa/xtruntime-core-state.h> -#include <xtensa/mpuasm.h> -#include "xtos-internal.h" - -.weak _idma_pso_save -//.type xtos_C_core_save, @function - - - .text - - - // (Place this alternate entry symbol *outside* the _xtos_core_save() - // function, to avoid confusing debugging / profiling / etc.) - .align 4 - .global _xtos_core_save_entry - .type _xtos_core_save_entry,@function -_xtos_core_save_entry: - j .Lcore_save - .size _xtos_core_save_entry, . - _xtos_core_save_entry - - - // int _xtos_core_save(unsigned flags, XtosCoreState *savearea, void *code) - // - // Generic processor state save routine. - // - // On entry (after ENTRY if windowed): - // a0 = return PC - // a2 = flags argument - // a3 = ptr to save area - // a4 = ptr to code to jump to after save (just return if 0) - // Returns: - // 0 when first returning from this call (if a4 == 0) - // non-zero (passed from restore call) when returning from restore - // (if a4 != 0, return behavior if any depends on code at a4) - // - .align 4 - .global _xtos_core_save - .type _xtos_core_save,@function -_xtos_core_save: - abi_entry - -.Lcore_save: - s32i a0, a3, CS_SA_areg + 0*4 // save a0 (clobbered below) - s32i a1, a3, CS_SA_areg + 1*4 // save a1 - s32i a2, a3, CS_SA_areg + 2*4 // save a2 (flags arg, for debugging only) - s32i a4, a3, CS_SA_areg + 4*4 // save a4 (code to jump to after saving) -#ifdef __XTENSA_CALL0_ABI__ - // Callee-saved regs: - s32i a12, a3, CS_SA_areg + 12*4 // save a12 - s32i a13, a3, CS_SA_areg + 13*4 // save a13 - s32i a14, a3, CS_SA_areg + 14*4 // save a14 - s32i a15, a3, CS_SA_areg + 15*4 // save a15 -#else - call4 xthal_window_spill // spill live caller windows to stack -#endif - j .Ls1 - - .align 16 -.Ls1: -#if XCHAL_HAVE_INTERRUPTS - rsil a4, 15 // disable interrupts before clobbering a0 -#elif XCHAL_HAVE_EXCEPTIONS - rsr.ps a4 -#endif - -#if XCHAL_HAVE_EXCEPTIONS - s32i a4, a3, CS_SA_ps // save PS -#endif - -#if XCHAL_HAVE_IDMA - movi a4, _idma_pso_save - beqz a4, .LnoIDMA -# ifdef __XTENSA_CALL0_ABI__ - mov a13, a3 - mov a12, a2 - addi a3, a3, CS_SA_idmaregs // location for IDMA regs save - call0 _idma_pso_save - mov a3, a13 - mov a2, a12 -# else - mov a6, a2 - addi a7, a3, CS_SA_idmaregs // location for IDMA regs save - call4 _idma_pso_save -# endif -.LnoIDMA: -#endif - -// not yet implemented -//# ifdef __XTENSA_CALL0_ABI__ -// mov a13, a3 -// mov a12, a2 -// call0 xtos_C_core_save -// mov a3, a13 -// mov a2, a12 -//# else -// mov a6, a2 -// mov a7, a3 -// call4 xtos_C_core_save -//# endif -//#endif - -#if XCHAL_HAVE_CCOUNT - rsr.ccount a5 // save CCOUNT restore value -#endif -#if XCHAL_HAVE_INTERRUPTS - rsr.interrupt a6 // save pending interrupts - s32i a6, a3, CS_SA_interrupt -#endif -#if XCHAL_HAVE_CCOUNT - s32i a5, a3, CS_SA_ccount -#endif - - call0 _xtos_core_save_common // save and shutoff -- returns after wakeup - - // a2 now contains return value. - // a3 still points to save area. - // Interrupts still disabled. - - // Restore WINDOWSTART to single window. Leave WINDOWBASE wherever it is. - //rsr.windowbase a6 - //movi a5, 1 - //ssl a6 - //sll a5, a5 - //wsr.windowstart a5 - //rsync - - l32i a0, a3, CS_SA_areg + 0*4 // restore a0 - l32i a1, a3, CS_SA_areg + 1*4 // restore a1 -#ifdef __XTENSA_CALL0_ABI__ - // Callee-saved regs: - l32i a12, a3, CS_SA_areg + 12*4 // restore a12 - l32i a13, a3, CS_SA_areg + 13*4 // restore a13 - l32i a14, a3, CS_SA_areg + 14*4 // restore a14 - l32i a15, a3, CS_SA_areg + 15*4 // restore a15 -#endif - -#if XCHAL_HAVE_EXCEPTIONS - // Now that we've restored windowed state (a0,a1), we can restore interrupts. - l32i a4, a3, CS_SA_ps // restore ps - wsr.ps a4 - rsync -#endif - - abi_return - - - - // Generic processor state save routine, callable from assembly-level - // (Does not assume valid stack, saves all ARs, no window-spill etc.) - // - // On entry: - // a0 = return PC - // a2 = flags argument - // a3 = ptr to save area - // a4 = ptr to code to jump to after save (just return if 0) - // All other registers are saved. - // Returns: - // 0 when first returning from this call (if a4 == 0) - // non-zero (passed from restore call) when returning from restore - // (if a4 != 0, return behavior if any depends on code at a4) - // - .align 4 - .global _xtos_core_save_nw -_xtos_core_save_nw: - s32i a0, a3, CS_SA_areg + 0*4 // save a0 (clobbered below) - s32i a1, a3, CS_SA_areg + 1*4 // save a1 - s32i a2, a3, CS_SA_areg + 2*4 // save a2 (flags arg, for debugging only) - s32i a4, a3, CS_SA_areg + 4*4 // save a4 (code to jump to after saving) - s32i a5, a3, CS_SA_areg + 5*4 // save a5 - s32i a6, a3, CS_SA_areg + 6*4 // save a6 - s32i a7, a3, CS_SA_areg + 7*4 // save a7 - j .Ls2 - - .align 16 -.Ls2: -#if XCHAL_HAVE_INTERRUPTS - rsil a4, 15 // disable interrupts before rotating etc -#elif XCHAL_HAVE_EXCEPTIONS - rsr.ps a4 -#endif - -#if XCHAL_HAVE_EXCEPTIONS - s32i a4, a3, CS_SA_ps // save PS -#endif - -#if XCHAL_HAVE_CCOUNT - rsr.ccount a5 // save CCOUNT restore value -#endif -#if XCHAL_HAVE_INTERRUPTS - rsr.interrupt a6 // save pending interrupts - s32i a6, a3, CS_SA_interrupt -#endif -#if XCHAL_HAVE_CCOUNT - s32i a5, a3, CS_SA_ccount -#endif - -#if XCHAL_HAVE_WINDOWED - movi a5, XCHAL_NUM_AREGS / 8 - 1 // number of 8-reg chunks to save (a0-a7 already done) -#endif -1: s32i a8, a3, CS_SA_areg + 8*4 // save a8 - s32i a9, a3, CS_SA_areg + 9*4 // save a9 - s32i a10,a3, CS_SA_areg + 10*4 // save a10 - s32i a11,a3, CS_SA_areg + 11*4 // save a11 - s32i a12,a3, CS_SA_areg + 12*4 // save a12 - s32i a13,a3, CS_SA_areg + 13*4 // save a13 - s32i a14,a3, CS_SA_areg + 14*4 // save a14 - s32i a15,a3, CS_SA_areg + 15*4 // save a15 -#if XCHAL_HAVE_WINDOWED - addi a11, a3, 8*4 // next frame (a11 will become a3, a13 become a5) - addi a13, a5, -1 - rotw 2 - bnez a5, 1b // loop until all frames done - rotw 2 // back to starting windowbase -#endif - - movi a1, 0 // not to save any regs from stack - call0 _xtos_core_save_common - - // a2 now contains return value. - // a3 still points to save area. - // Interrupts still disabled. - -#if XCHAL_HAVE_WINDOWED - rotw -2 - movi a5, XCHAL_NUM_AREGS / 8 - 1 // 8-reg chunks to restore (a0-a7 already done) - addi a3, a11, XCHAL_NUM_AREGS * 4 -1: rotw -2 - addi a3, a11, -8*4 - addi a5, a13, -1 -#endif - l32i a8, a3, CS_SA_areg + 8*4 // restore a8 - l32i a9, a3, CS_SA_areg + 9*4 // restore a9 - l32i a10,a3, CS_SA_areg + 10*4 // restore a10 - l32i a11,a3, CS_SA_areg + 11*4 // restore a11 - l32i a12,a3, CS_SA_areg + 12*4 // restore a12 - l32i a13,a3, CS_SA_areg + 13*4 // restore a13 - l32i a14,a3, CS_SA_areg + 14*4 // restore a14 - l32i a15,a3, CS_SA_areg + 15*4 // restore a15 -#if XCHAL_HAVE_WINDOWED - bnez a5, 1b // loop until all frames done - // We're now back to starting windowbase, and original a3. -#endif - - l32i a0, a3, CS_SA_areg + 0*4 // restore a0 - l32i a1, a3, CS_SA_areg + 1*4 // restore a1 - // Don't clobber return value, so don't restore a2. - l32i a4, a3, CS_SA_areg + 4*4 // restore a4 - l32i a5, a3, CS_SA_areg + 5*4 // restore a5 - l32i a6, a3, CS_SA_areg + 6*4 // restore a6 -#if XCHAL_HAVE_EXCEPTIONS - // Now that we've restored windowed state (a0,a1,done rotating), we can restore interrupts. - l32i a7, a3, CS_SA_ps // restore ps - wsr.ps a7 - rsync -#endif - l32i a7, a3, CS_SA_areg + 7*4 // restore a7 - ret - - - - - // Common state save / shut-off code. - // - // a0 = return PC within caller shut-off routine - // a1 = stack if != 0 - // a2 = flags argument - // a3 = pointer to _xtos_pso_savearea - // a4 = PS to save/restore - // PS.INTLEVEL = 15 (interrupts disabled, except NMI) - // a5-a15 (and other ARs) are available. - // NOTE: CCOUNT and INTERRUPT have already been saved in save area. - // - .align 4 - //.global _xtos_core_save_common -_xtos_core_save_common: -//#if XCHAL_HAVE_EXCEPTIONS -// s32i a4, a3, CS_SA_ps // save PS -//#endif - -#if XCHAL_HAVE_CACHE_BLOCKOPS - pfend.o // terminate non-essential block-prefetch ops -#endif - -#if XCHAL_HAVE_WINDOWED - // The following discussion is valid if we have a stack: - // At this point, all non-live register windows have been spilled to the - // stack. However, we cannot leave any spilled registers in our stack frame - // or our caller's stack frame, since these frames could change after we - // return and before restore() is called. So all spilled registers in the - // current and previous stack frames must be saved to the save area. This - // means a max of 16 registers: 4 base save registers for our caller, upto - // 8 extra save registers for our caller, and 4 base save registers for the - // next function up from our caller. The stack looks like this: - // - // ------------------------------- <---- stack ptr of function (i - 2) - // Base save area i - 3 - // ------------------------------- - // Extra save area i - 1 - // (0-8 registers depending on call type) - // ------------------------------- - // Locals i - 1 - // ------------------------------- <---- stack ptr of function (i - 1) - // Base save area i - 2 (our caller) - // - // ------------------------------- <---- Our stack ptr (a1) - // Base save area i - 1 - // ------------------------------- - // - // We don't have any extra save area or locals in our frame. See the - // Xtensa Programmer's Guide for more details of the stack layout. - // - // NOTE that we are not counting the call0 to _xtos_core_save_common() since - // that does not result in any register window rotation nor stack ptr change. - - s32i a1, a3, CS_SA_caller_regs_saved // save flag - beqz a1, .Lendcr // skip if no stack - - // Save our caller's a0-a3 from the base save area (a1-16) - - addi a4, a1, -16 - l32i a5, a4, 0 - l32i a6, a4, 4 - s32i a5, a3, CS_SA_caller_regs // caller a0 - s32i a6, a3, CS_SA_caller_regs + 4 // caller a1 - l32i a5, a4, 8 - l32i a6, a4, 12 - s32i a5, a3, CS_SA_caller_regs + 8 // caller a2 - s32i a6, a3, CS_SA_caller_regs + 12 // caller a3 - - // Save our callers caller's a0-a3 from its base save area (a1+0) - - l32i a5, a1, 0 - l32i a6, a1, 4 - s32i a5, a3, CS_SA_caller_regs + 16 // caller caller a0 - s32i a6, a3, CS_SA_caller_regs + 20 // caller caller a1 - l32i a5, a1, 8 - l32i a6, a1, 12 - s32i a5, a3, CS_SA_caller_regs + 24 // caller caller a2 - s32i a6, a3, CS_SA_caller_regs + 28 // caller caller a3 - - // Now save 0-8 registers for our caller from its ext save area - // NOTE we can't use a0 directly because we are one level down - - l32i a4, a3, CS_SA_areg // pull in the return address - extui a4, a4, 30, 2 // Top 2 bits of ret addr - blti a4, 2, .Lendcr // No regs to save - l32i a5, a1, 4 // a5 <- caller caller a1 - slli a4, a4, 4 - sub a4, a5, a4 // a4 <- bottom of extra save area - addi a5, a5, -16 // a5 <- top of extra save area - addi a6, a3, CS_SA_caller_regs + 32 // location to start saving to -.Lcrloop: - l32i a7, a4, 0 // Save in groups of 4 registers - l32i a8, a4, 4 - s32i a7, a6, 0 - s32i a8, a6, 4 - l32i a7, a4, 8 - l32i a8, a4, 12 - s32i a7, a6, 8 - s32i a8, a6, 12 - addi a4, a4, 16 - addi a6, a6, 16 - blt a4, a5, .Lcrloop -.Lendcr: -#endif - - // We want to save the CCOUNT value as soon as feasible after disabling - // interrupts, so that the counter does not run past any CCOMPARE value - // and miss a timer interrupt. The callers of this function have saved - // the values of CCOUNT and INTERRUPT immediately after disabling interrupts. - -#if XCHAL_HAVE_CCOUNT - .set _idx, 0 - .rept XCHAL_NUM_TIMERS - INDEX_SR rsr.ccompare a5 - s32i a5, a3, CS_SA_ccompare + 4*_idx - .set _idx, _idx+1 - .endr -#endif - - s32i a0, a3, CS_SA_restore_label // where to return to, to return from function -#if XCHAL_HAVE_INTERRUPTS || XCHAL_HAVE_EXCEPTIONS - rsr.epc1 a5 - s32i a5, a3, CS_SA_epc1 - rsr.excsave1 a5 - s32i a5, a3, CS_SA_excsave1 -# ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR - rsr.depc a5 - s32i a5, a3, CS_SA_depc -# endif -#endif -#if XCHAL_HAVE_WINDOWED - rsr.windowbase a5 - s32i a5, a3, CS_SA_windowbase // save windowbase - rsr.windowstart a5 - s32i a5, a3, CS_SA_windowstart // save windowstart -#endif - rsr.sar a5 - s32i a5, a3, CS_SA_sar // save sar - -#if XCHAL_HAVE_PSO_CDM - // Save PWRCTL, and update according to flags argument. - movi a4, XDM_MISC_PWRCTL - movi a6, PWRCTL_MEM_WAKEUP - rer a7, a4 // get pwrctl - s32i a7, a3, CS_SA_pwrctl // save pwrctl - // Avoid setting power-control bits if not already set, i.e. clear them only. - bbci.l a2, XTOS_COREF_PSO_SHIFT, 1f // if not shutting off, don't touch power bits - - // Set PWRCTL MEM_WAKEUP bit according to flags (whether to let mem power off). - or a5, a7, a6 // set... - xor a5, a5, a6 // ... and clear MEM_WAKEUP bit to write - and a6, a2, a6 // isolate MEM_WAKEUP bit from flags - or a5, a5, a6 // set MEM_WAKEUP bit to write from flags - // Clear PWRCTL DEBUG_WAKEUP bit if cleared in flags (if letting debug power off). - movi a6, ~PWRCTL_DEBUG_WAKEUP - or a6, a2, a6 // isolate DEBUG_WAKEUP bit from flags - and a6, a5, a6 // clear it if was clear in flags - // Update PWRCTL - wer a6, a4 // write new pwrctl - //extw // let the new pwrctl value settle -1: -#endif - - .set _idx, 2 - .rept XCHAL_NUM_INTLEVELS+XCHAL_HAVE_NMI-1 - INDEX_SR rsr.epc a5 - s32i a5, a3, CS_SA_epc + 4*(_idx-2) - INDEX_SR rsr.eps a5 - s32i a5, a3, CS_SA_eps + 4*(_idx-2) - INDEX_SR rsr.excsave a5 - s32i a5, a3, CS_SA_excsave + 4*(_idx-2) - .set _idx, _idx+1 - .endr - -#if XCHAL_HAVE_LOOPS - rsr.lbeg a5 - s32i a5, a3, CS_SA_lbeg - rsr.lend a5 - s32i a5, a3, CS_SA_lend - rsr.lcount a5 - s32i a5, a3, CS_SA_lcount -#endif -#if XCHAL_HAVE_ABSOLUTE_LITERALS - rsr.litbase a5 - s32i a5, a3, CS_SA_litbase -#endif -#if XCHAL_HAVE_VECBASE - rsr.vecbase a5 - s32i a5, a3, CS_SA_vecbase -#endif -#if XCHAL_HAVE_S32C1I && (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RC_2009_0) /* have ATOMCTL ? */ - rsr.atomctl a5 - s32i a5, a3, CS_SA_atomctl -#endif -#if XCHAL_HAVE_PREFETCH - movi a5, 0 // disable prefetch during shutoff - xsr.prefctl a5 - s32i a5, a3, CS_SA_prefctl -#endif -#if XCHAL_USE_MEMCTL - rsr.memctl a5 - s32i a5, a3, CS_SA_memctl -#endif -#if XCHAL_HAVE_INTERRUPTS - rsr.intenable a5 - s32i a5, a3, CS_SA_intenable -#endif -#if XCHAL_HAVE_DEBUG - // NOTE: restore of debug state is conditional, - // as the power-down and wakeup code might be actively debugged. - rsr.icount a5 - s32i a5, a3, CS_SA_icount - rsr.icountlevel a5 - s32i a5, a3, CS_SA_icountlevel - rsr.debugcause a5 - s32i a5, a3, CS_SA_debugcause // (won't get restored?) - //rsr.ddr a5 - //s32i a5, a3, CS_SA_ddr -# if XCHAL_NUM_IBREAK - rsr.ibreakenable a5 - s32i a5, a3, CS_SA_ibreakenable -# endif - .set _idx, 0 - .rept XCHAL_NUM_IBREAK - INDEX_SR rsr.ibreaka a5 - s32i a5, a3, CS_SA_ibreaka + 4*_idx - .set _idx, _idx+1 - .endr - .set _idx, 0 - .rept XCHAL_NUM_DBREAK - INDEX_SR rsr.dbreakc a5 - s32i a5, a3, CS_SA_dbreakc + 4*_idx - INDEX_SR rsr.dbreaka a5 - s32i a5, a3, CS_SA_dbreaka + 4*_idx - .set _idx, _idx+1 - .endr -#endif - - .set _idx, 0 - .rept XCHAL_NUM_MISC_REGS - INDEX_SR rsr.misc a5 - s32i a5, a3, CS_SA_misc + 4*_idx - .set _idx, _idx+1 - .endr - -#if XCHAL_HAVE_MEM_ECC_PARITY - rsr.mepc a5 - s32i a5, a3, CS_SA_mepc - rsr.meps a5 - s32i a5, a3, CS_SA_meps - rsr.mesave a5 - s32i a5, a3, CS_SA_mesave - rsr.mesr a5 - s32i a5, a3, CS_SA_mesr - rsr.mecr a5 - s32i a5, a3, CS_SA_mecr - rsr.mevaddr a5 - s32i a5, a3, CS_SA_mevaddr -#endif - - /* TIE state */ - addi a4, a3, CS_SA_ncp - xchal_ncp_store a4, a5,a6,a7,a8 // save non-coprocessor state -#if XCHAL_HAVE_CP - rsr.cpenable a5 - s32i a5, a3, CS_SA_cpenable - movi a6, -1 - wsr.cpenable a6 // enable all coprocessors - rsync - xchal_cp0_store a4, a5,a6,a7,a8 continue=1 - xchal_cp1_store a4, a5,a6,a7,a8 continue=1 - xchal_cp2_store a4, a5,a6,a7,a8 continue=1 - xchal_cp3_store a4, a5,a6,a7,a8 continue=1 - xchal_cp4_store a4, a5,a6,a7,a8 continue=1 - xchal_cp5_store a4, a5,a6,a7,a8 continue=1 - xchal_cp6_store a4, a5,a6,a7,a8 continue=1 - xchal_cp7_store a4, a5,a6,a7,a8 continue=1 - //xchal_cp8_store a4, a5,a6,a7,a8 continue=1 - //xchal_cp9_store a4, a5,a6,a7,a8 continue=1 - //xchal_cp10_store a4, a5,a6,a7,a8 continue=1 - //xchal_cp11_store a4, a5,a6,a7,a8 continue=1 - //xchal_cp12_store a4, a5,a6,a7,a8 continue=1 - //xchal_cp13_store a4, a5,a6,a7,a8 continue=1 - //xchal_cp14_store a4, a5,a6,a7,a8 continue=1 - //xchal_cp15_store a4, a5,a6,a7,a8 continue=1 -#endif - - /* TLB state (for known MMU types only, not internal custom) */ -#if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR - addi a4, a3, CS_SA_tlbs // where to start storing TLB entry info - movi a5, 0x20000000 - movi a6, 0 -1: rdtlb1 a7, a6 // read DTLB entry PPN + CA - s32i a7, a4, 0 - ritlb1 a7, a6 // read ITLB entry PPN + CA - s32i a7, a4, 4 - addi a4, a4, 8 - add a6, a6, a5 - bnez a6, 1b - -#elif XCHAL_HAVE_PTP_MMU - // Declare a table of TLB entries to save/restore. - // Each entry is a 32-bit index to use directly with [rw][di]tlb[01]. - // Indices assume ITLBCFG == DTLBCFG == 0. - // Bit 4 means not-for-dtlb, and bit 5 means not-for-itlb - // (these bits aren't used by these instructions, so okay to use for this). - .section .rodata, "a" - .global _xtos_pso_tlbmap - .global _xtos_pso_tlbmap_end - .type _xtos_pso_tlbmap, @object -_xtos_pso_tlbmap: - .long 0x0C0C0C0C, ARF_ENTRIES // *TLB way 0, 4/8 entries of 4KB - .long 0x0C0C0C0C, ARF_ENTRIES // *TLB way 1, 4/8 entries of 4KB - .long 0x0C0C0C0C, ARF_ENTRIES // *TLB way 2, 4/8 entries of 4KB - .long 0x0C0C0C0C, ARF_ENTRIES // *TLB way 3, 4/8 entries of 4KB - .long 0x1A181614, 4 // *TLB way 4, 4 entries of 1MB/4MB/16MB/64MB -# if XCHAL_HAVE_SPANNING_WAY /* MMU v3 */ - .long 0x1C1B1C1B, 4 // *TLB way 5, 4 entries of 128MB/256MB - .long 0x1B1D1B1D, 8 // *TLB way 6, 8 entries of 512MB/128MB -# endif - .long 0x0C0C0C0C, 0x8001 // DTLB way 7, 1 entry of 4KB - .long 0x0C0C0C0C, 0x8001 // DTLB way 8, 1 entry of 4KB - .long 0x0C0C0C0C, 0x8001 // DTLB way 9, 1 entry of 4KB -_xtos_pso_tlbmap_end: - .size _xtos_pso_tlbmap, . - _xtos_pso_tlbmap - - .text - addi a4, a3, CS_SA_tlbs // where to start storing TLB entry info - movi a10, _xtos_pso_tlbmap - movi a11, _xtos_pso_tlbmap_end - rsr.dtlbcfg a14 // page size index (0..3) for each DTLB way - rsr.itlbcfg a15 // page size index (0..3) for each ITLB way - s32i a14, a3, CS_SA_dtlbcfg - s32i a15, a3, CS_SA_itlbcfg - rsr.ptevaddr a5 - s32i a5, a3, CS_SA_ptevaddr - rsr.rasid a5 - s32i a5, a3, CS_SA_rasid - // Loop from last way to first (less register pressure that way). -.Loop_tlbmap: - addi a11, a11, -8 // next way - l32i a8, a11, 0 // map of four (page size log2) per index for this way - // DTLB page size: - extui a12, a14, 0, 4 // page size index for this DTLB way - srli a14, a14, 4 // (for next way) - ssa8l a12 // prepare to shift right by 8*a12 - srl a12, a8 // page size log2 for this DTLB way - ssl a12 // prepare to shift left by a12 - movi a12, 1 // (to compute 1 << (page size log2)) - sll a12, a12 // page size for this DTLB way - - // Save all entries of this DTLB way: - l32i a9, a11, 4 // number of entries for this way - sub a5, a11, a10 // way number * 8 - srli a5, a5, 3 // way number - extui a9, a9, 0, 8 -1: rdtlb0 a6, a5 // read DTLB entry VPN + ASID ... - rdtlb1 a7, a5 // read DTLB entry PPN + CA ... - add a5, a5, a12 // next entry of this DTLB way - s32i a6, a4, 0 // save entry ... - s32i a7, a4, 4 - addi a4, a4, 8 - addi a9, a9, -1 - bnez a9, 1b - - // ITLB page size: - extui a12, a15, 0, 4 // page size index for this ITLB way - srli a15, a15, 4 // (for next way) - ssa8l a12 // prepare to shift right by 8*a12 - srl a12, a8 // page size log2 for this ITLB way - ssl a12 // prepare to shift left by a12 - movi a12, 1 // (to compute 1 << (page size log2)) - sll a12, a12 // page size for this ITLB way - - // Save all entries of this ITLB way: - l32i a9, a11, 4 // number of entries for this way - sub a5, a11, a10 // way number * 8 - srli a5, a5, 3 // way number - bbsi.l a9, 15, 2f // skip ITLB if is a DTLB-only way - extui a9, a9, 0, 8 -1: ritlb0 a6, a5 // read ITLB entry VPN + ASID ... - ritlb1 a7, a5 // read ITLB entry PPN + CA ... - add a5, a5, a12 // next entry of this ITLB way - s32i a6, a4, 0 // save entry ... - s32i a7, a4, 4 - addi a4, a4, 8 - addi a9, a9, -1 - bnez a9, 1b -2: - bne a11, a10, .Loop_tlbmap // loop for next TLB way - // Done saving TLBs. -#endif - -#if XCHAL_HAVE_CACHE_BLOCKOPS - pfwait.a // wait for any remaining block-prefetch ops -#endif - -#if XCHAL_HAVE_MPU - addi a4, a3, CS_SA_mpuentry // location for MPU save - mpu_read_map a4, a5, a6 - rsr.cacheadrdis a4 - addi a5, a3, CS_SA_cacheadrdis - s32i a4, a5, 0 - -#if XCHAL_DCACHE_IS_WRITEBACK - // Must write this piece back to memory, because if it stays - // in the cache and we try to restore with caches bypassed, - // the wrong values will be fetched from memory. - // TODO: See if possible to replace with call to xthal_dcache_region_writeback - // TODO: If going to write back full dcache below, skip this step - addi a4, a3, CS_SA_mpuentry - movi a5, CS_SA_ncp - CS_SA_mpuentry - dcache_writeback_region a4, a5, a7, a8 -#endif -#endif - - // With data cache coherency enabled, need a full data cache - // writeback and invalidate, then disable coherency, before shut-off. - // Otherwise, if we'll let dcache power off, writeback its contents. - // - // We make sure the signature only gets written after everything - // else is written back (if we writeback), and only gets written - // back if the rest gets written back. - movi a6, CORE_STATE_SIGNATURE -#if XCHAL_DCACHE_IS_WRITEBACK -# if XCHAL_HAVE_PSO_CDM && XCHAL_DCACHE_IS_COHERENT && XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RE_2012_0 - rsr.memctl a4 - bbci.l a2, XTOS_COREF_PSO_SHIFT, 1f // if not shutting off, leave snoops as is - bbci.l a4, MEMCTL_SNOOP_EN_SHIFT, 1f // snoops (coherence) enabled? - dcache_writeback_inv_all a4, a5, a7, 0 // yes: writeback-invalidate - memw // wait for writeback to complete - s32i a6, a3, CS_SA_signature - dhwbi a3, CS_SA_signature - // Now that dcache is empty, make sure snoops are off during shut-off. - addi a4, a4, -MEMCTL_SNOOP_EN - wsr.memctl a4 - j 9f -1: -# endif - bbsi.l a2, PWRCTL_MEM_WAKEUP_SHIFT, 7f // letting caches power off? - dcache_writeback_all a4, a5, a7, 0 // yes: writeback - memw // wait for writeback to complete - j 8f - - // The signature and the cache/TLB state must be written out to - // main memory even though the caches stay on, because on restart - // we will come up with caches bypassed and need to read the state - // back before the cache/TLB is set up. -7: - mov a4, a3 - movi a5, CS_SA_ncp - dcache_writeback_region a4, a5, a7, a8 - memw -8: - s32i a6, a3, CS_SA_signature - dhwb a3, CS_SA_signature // needed even if caches stay on -#else - s32i a6, a3, CS_SA_signature -#endif - -9: l32i a4, a3, CS_SA_areg + 4*4 // restore a4 (code to jump to after saving) - memw // wait for signature to be in memory - - beqz a4, 1f // code to jump to? - jx a4 // yes, jump to it -1: l32i a0, a3, CS_SA_restore_label // no, return: restore return PC - movi a2, 0 // return 0 - ret - - - .size _xtos_core_save, . - _xtos_core_save - diff --git a/src/arch/xtensa/xtos/core-shutoff.S b/src/arch/xtensa/xtos/core-shutoff.S deleted file mode 100644 index c848e38ca1ab..000000000000 --- a/src/arch/xtensa/xtos/core-shutoff.S +++ /dev/null @@ -1,425 +0,0 @@ -// reset-pso.S -- PSO restore routine, invoked from Reset Vector -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/core-shutoff.S#1 $ - -// Copyright (c) 2012-2013 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/corebits.h> -#include <xtensa/cacheasm.h> -#include <xtensa/cacheattrasm.h> -#include <xtensa/xdm-regs.h> -#include <xtensa/xtruntime-core-state.h> -#include "xtos-internal.h" - -#if XCHAL_HAVE_PSO - .macro simulate_reset - // Single or multiple power domains, no retention. - // Just simulate reset. Set PS: - movi a5, 0x1F - wsr.ps a5 - rsync - // Scramble things: - rotw 3 - // Jump to reset vector: - movi a5, _ResetVector - jx a5 - .endm -#endif - - -#if XCHAL_HAVE_PSO_CDM && ! XCHAL_HAVE_PSO_FULL_RETENTION - // PSO: core state save area. - // This could be pretty large (includes TIE state, TLB state, many regs). - // - .section .bss, "aw" - .align XCHAL_TOTAL_SA_ALIGN - .global _xtos_pso_savearea - .type _xtos_pso_savearea, @object - .size _xtos_pso_savearea, XtosCoreStateSize -_xtos_pso_savearea: - .space XtosCoreStateSize -#endif - - - .text - - - // This version of the _xtos_core_shutoff() function can be called from assembly-level, - // where the stack might not be defined/usable, so can't do window-spill - // etc. This saves address registers per call0 ABI (all except a0/a2..a11). - // - // On entry: a0 = return PC, a2 = flags argument, a3..a11 = undefined/available. - // All other registers are saved/restored. - // - .align 4 - .global _xtos_core_shutoff_nw - .type _xtos_core_shutoff_nw,@function -_xtos_core_shutoff_nw: -#if XCHAL_HAVE_PSO_CDM && ! XCHAL_HAVE_PSO_FULL_RETENTION - movi a5, _xtos_core_save_nw -#endif - mov a11, a0 // ABI-independent return PC - j .Lcommon_shutoff - .size _xtos_core_shutoff_nw, . - _xtos_core_shutoff_nw - - - - // int _xtos_core_shutoff(unsigned flags) - // - // Save all processor state and shut-off the core. - // Returns when the core wakes up, and all state was restored - // (except in single power domain case, see below). - // - // For more details see: System SW Ref Manual, XTOS Chapter. - // - // Possible return values: - // - // 0 core did shut-off (return via reset vector, - // or after waiti for full-retention case) - // - // 1,2 core did not shut-off (other requestors were already - // requesting this core to stay on at time of call) - // (1 == early, 2 == late) - // - // 3 core did not shut-off (multi-power-domains no retention, - // and waiti resumed; FIXME: can this happen?) - // - // -1 core does not have PSO feature - // - // NOTE: in the single power domain case, this function never returns. - // The external system must power the core off than back on, - // and execution resumes at the reset vector. - // - // The flags parameter indicates whether to request memory and/or debug domains - // to stay powered on while the core is shut-off. (This parameter is ignored - // for the single power domain case.) If 0, they are both allowed to - // shut-off (although other external requesters may keep them powered on). - // Otherwise, one or both of these bits may be specified (or'ed together): - // XTOS_KEEPON_MEM force memory domain on during core power shut-off - // XTOS_KEEPON_DEBUG force debug domain on during core power shut-off - // If XTOS_KEEPON_MEM is specified, dcache writeback is NOT done. - // - // Effectively, the flags parameter sets the value of these two PWRCTL register - // bits (over ERI) during core power shut-off. The value of these two bits - // (as they were prior to calling this function) are saved, and restored on wakeup. - // Thus, if the core was requesting that the debug domain be powered on, and - // _xtos_core_shutoff() lets it power-off, then upon wakeup, the software restore - // sequence restores debug domain power, and waits for debug power to be ON. - // - // - .align 4 - .global _xtos_core_shutoff - .type _xtos_core_shutoff,@function -_xtos_core_shutoff: - abi_entry - -#if XCHAL_HAVE_PSO_CDM && ! XCHAL_HAVE_PSO_FULL_RETENTION - movi a5, _xtos_core_save_entry -#endif - movi a11, 1f // ABI-independent return PC - j .Lcommon_shutoff - -1: abi_return - - - - - .align 4 -.Lcommon_shutoff: - - - -#if XCHAL_HAVE_PSO_CDM && XCHAL_HAVE_PSO_FULL_RETENTION - // Multiple power domains, full retention in HW. - // Do the minimum required (things that need to be changed during shutoff): - - // Check whether other agents are keeping this core powered on, - // and avoid going through save sequence if we're not going to - // power down anyway. - movi a3, XDM_MISC_PWRSTAT - rer a6, a3 - movi a5, 1 // indicates other agents want this core powered on - bbsi.l a6, PWRSTAT_CORE_STILL_NEEDED_SHIFT, 1f - - rsil a8, 15 // disable interrupts - -# if XCHAL_HAVE_PREFETCH - // Save prefetch control and disable prefetch. - movi a10, 0 - xsr.prefctl a10 -# endif - -# if XCHAL_DCACHE_IS_WRITEBACK - bbsi.l a2, PWRCTL_MEM_WAKEUP_SHIFT, 7f // letting caches power off? - dcache_writeback_all a4, a7, a9,0 // yes: writeback - memw // wait for writeback to complete -7: -# endif - - // Save PWRCTL, and set ShutProcOffOnPWait (for WAITI to shut-off the core). - // (With dcache coherence, can this be used as signal to system - // to turn off snoops to this core?) - // - movi a4, XDM_MISC_PWRCTL - rer a9, a4 // get pwrctl - movi a6, PWRCTL_CORE_SHUTOFF // aka ShutProcOffOnPWait - or a7, a9, a6 // indicate WAITI will shut-off - xor a9, a7, a6 // make sure it's clear in saved pwrctl - wer a7, a4 // write new pwrctl - - // Make sure everything stabilizes: - isync - extw - - // With ShutProcOffOnPWait set, external agents can't change their mind. - // So check again whether other agents are keeping this core powered on, - // and avoid going through save sequence if we're not going to - // power down anyway. - rer a6, a3 // read PWRSTAT - movi a5, 2 // if abort: external agent wants core powered on - bbsi.l a6, PWRSTAT_CORE_STILL_NEEDED_SHIFT, .Lshutoff_late_abort - - // Set PWRCTL MEM_WAKEUP bit according to flags (whether to let mem power off). - movi a6, PWRCTL_MEM_WAKEUP - or a5, a7, a6 // set... - xor a5, a5, a6 // ... and clear MEM_WAKEUP bit to write - and a6, a2, a6 // isolate MEM_WAKEUP bit from flags - or a5, a5, a6 // set MEM_WAKEUP bit to write from flags - // Clear PWRCTL DEBUG_WAKEUP bit if cleared in flags (if letting debug power off). - movi a6, ~PWRCTL_DEBUG_WAKEUP - or a6, a2, a6 // isolate DEBUG_WAKEUP bit from flags - and a6, a5, a6 // clear it if was clear in flags - // Update PWRCTL - wer a6, a4 // write new pwrctl - extw // let the new pwrctl value settle - - // Okay, go for it -- power down (shutoff). - -# if !XTOS_PSO_TEST - waiti 0 // now shut-off! (interrupts enabled for power-on) -# endif - // Resumes here after power comes back on, after some interrupt taken. - wsr.ps a8 // restore interrupts - movi a5, 0 // successful - rsync // ensure wsr.ps completes - - // FIXME: do we need to initialize caches? - -.Lshutoff_late_abort: - wer a7, a4 // restore pwrctl (except ShutProcOffOnPWait still set) - - // Wait for debug powerup to complete (if started): - bbci.l a7, PWRCTL_DEBUG_WAKEUP_SHIFT, 3f - movi a6, XDM_MISC_PWRSTAT -2: rer a6, a6 // read PWRSTAT - bbci.l a6, PWRSTAT_DEBUG_DOMAIN_ON_SHIFT, 2b // loop until powered up -3: - -# if XCHAL_HAVE_PREFETCH - wsr.prefctl a10 // restore prefetch control -# endif - - // If CachesLostPower bit set, is there need to initialize caches? - - wer a9, a4 // clear ShutProcOffOnPWait - - wsr.ps a8 // restore interrupts - rsync // ensure wsr.ps completes - -1: mov a2, a5 - jx a11 // return (to ABI-dependent code if C callable) - - - -#elif XCHAL_HAVE_PSO_CDM /*&& !XCHAL_HAVE_PSO_FULL_RETENTION*/ - // Multiple power domains, no hardware retention. - // Do full core state save/restore in software. - - // Check whether other agents are keeping this core powered on, - // and avoid going through save sequence if we're not going to - // power down anyway. - movi a3, XDM_MISC_PWRSTAT - rer a3, a3 - bbsi.l a3, PWRSTAT_CORE_STILL_NEEDED_SHIFT, 1f - - movi a3, XTOS_COREF_PSO - or a2, a2, a3 // indicate power shutoff in flags - - movi a3, _xtos_pso_savearea - movi a4, _xtos_core_shutoff_aftersave - jx a5 // continue in _xtos_core_save (past prologue) - // which saves processor state, powers down - // debug/mem per a2, shuts off prefetch and - // snooping, and jumps to a4 - -1: movi a2, 1 // other agents want this core powered on - jx a11 // return (to ABI-dependent code if C callable) - - .align 4 - //.global _xtos_core_shutoff_aftersave -_xtos_core_shutoff_aftersave: - - // Multiple power domains, no retention. - - // Set ShutProcOffOnPWait, for WAITI to shut-off the core. - // (With dcache coherence, can this be used as signal to system - // to turn off snoops to this core?) - // - movi a4, XDM_MISC_PWRCTL - rer a7, a4 // get pwrctl - movi a6, PWRCTL_CORE_SHUTOFF // aka ShutProcOffOnPWait - or a7, a7, a6 // indicate WAITI will shut-off - wer a7, a4 // write new pwrctl - - // Make sure everything stabilizes: - isync - extw - - // Check whether other agents are keeping this core powered on, - // and avoid going through save sequence if we're not going to - // power down anyway. - movi a4, XDM_MISC_PWRSTAT - movi a2, 2 // if abort: external agent wants core powered on - rer a6, a4 - bbsi.l a6, PWRSTAT_CORE_STILL_NEEDED_SHIFT, .Lshutoff_late_abort - - // Call system-specific function to wait for system specific - // transactions to quiesce before shutting down the processor. - // This function may also abort the shutdown, however whoever - // attempts it must do it carefully: the function must know - // that it's possible to abort, it must do whatever's needed - // in the system to resume normal execution (e.g. restart - // snoops, DMA, etc), and for power reasons the software must - // avoid calling this shutdown routine in the first place if - // it can know then that it would end up aborting here. - // - // This is always a call0 function. - // TBD: can it be a C function instead? - // TBD: describe exact calling conventions, if asm call0 - - .weak xtos_system_ready_for_core_shutoff - movi a2, xtos_system_ready_for_core_shutoff - //isync - beqz a2, 1f - callx0 a2 - bnez a2, .Lshutoff_late_abort // if function returns error, abort shutdown -1: - - // Okay, go for it -- power down (shutoff). - - -# if XTOS_PSO_TEST - // Test only -- weakly simulate shutoff in sw, don't actually do it. - simulate_reset -# elif XCHAL_HAVE_INTERRUPTS - waiti 15 // now shut-off! -# elif XCHAL_HAVE_HALT - halt -# else -# error "PSO assumes interrupts (for WAITI) or HALT architecture (for HALT)" -# endif - - // Execution should not proceed here. - // If we get here, some error has occurred [FIXME] - - movi a2, 3 // WAITI resumed - -.Lshutoff_late_abort: - // We end up here if returning from shutoff request. - // Here, a2 == return code. - // Restore what's been clobbered (and doesn't get restored by caller): - // PWRCTL, MEMCTL, return PC. - - l32i a0, a3, CS_SA_restore_label // restore return PC - - // Restore PWRCTL. - movi a4, XDM_MISC_PWRCTL - l32i a5, a3, CS_SA_pwrctl // get saved pwrctl - wer a5, a4 // restore pwrctl - // Wait for debug powerup to complete (if started): - bbci.l a5, PWRCTL_DEBUG_WAKEUP_SHIFT, 1f - movi a7, XDM_MISC_PWRSTAT -2: rer a6, a7 // read PWRSTAT - bbci.l a6, PWRSTAT_DEBUG_DOMAIN_ON_SHIFT, 2b // loop until powered up -1: - - // Restore MEMCTL. -# if XCHAL_USE_MEMCTL - l32i a5, a3, CS_SA_memctl - wsr.memctl a5 -# endif - - // Clear the signature, to mark save area as no longer valid. - s32i a2, a3, CS_SA_signature -# if XCHAL_DCACHE_IS_WRITEBACK - dhwb a3, CS_SA_signature -# endif - - ret // return from _xtos_core_save_common - - - -#elif XCHAL_HAVE_PSO - // Single power domain. (No retention.) - - rsil a8, 15 // disable interrupts - -# if XCHAL_HAVE_PREFETCH - // Disable prefetch. - movi a10, 0 - wsr.memctl a10 -# endif - -# if XCHAL_DCACHE_IS_WRITEBACK - bbsi.l a2, PWRCTL_MEM_WAKEUP_SHIFT, 7f // letting caches power off? - dcache_writeback_all a4, a5, a6, 0 // yes: writeback - memw // wait for writeback to complete -7: -# endif - -1: waiti 15 // wait for shut-off - j 1b // loop until we get powered off - - - -#else - // No PSO. - movi a2, -1 - jx a11 // return (to ABI-dependent code if C callable) - -#endif - - - - -#if XCHAL_HAVE_PSO_CDM -# if XCHAL_HAVE_PSO_FULL_RETENTION - -# else /* not full retention */ - - -# endif /* !retention */ -#endif /* multi power domains */ - - - .size _xtos_core_shutoff, . - _xtos_core_shutoff - diff --git a/src/arch/xtensa/xtos/crt0-app.S b/src/arch/xtensa/xtos/crt0-app.S deleted file mode 100644 index 7f12337fd535..000000000000 --- a/src/arch/xtensa/xtos/crt0-app.S +++ /dev/null @@ -1,174 +0,0 @@ -// crt0-app.S -// Applications downloaded in RAM using a debug monitor (eg. XMON, RedBoot) -// start here at _app_reset. Such applications don't have any vectors: -// all exceptions are handled by the debug monitor. -// Thus, this file essentially plays the role of the reset vector -// to setup a few things before jumping to _start (in crt1*.S). - -// Copyright (c) 2005-2013 Tensilica 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. - -#include <xtensa/cacheattrasm.h> -#include <xtensa/coreasm.h> - - -// Assumptions on entry to _app_reset: -// - debug monitor handles all exceptions, has setup all vectors -// - interrupt related state is initialized -// (interrupts disabled or enabled for debug monitor's purposes) -// - debug option related state is initialized (for debug monitor) -// - any MMU related state is initialized (all handled by debug monitor) -// - caches are initialized (cache attributes not necessarily correct) -// - entire application is loaded (no unpacking needed here) - -// Assumptions on exit from _app_reset, ie. when jumping to _start: -// - low (level-one) and medium priority interrupts are disabled -// - C calling context not initialized: -// - PS not fully initialized (eg. PS.WOE not set per ABI) -// - SP not initialized -// - the following are initialized: -// - LITBASE, WindowBase, WindowStart, LCOUNT, CPENABLE, FP's FCR and FSR, -// cache attributes - -/**************************************************************************/ - - .text - .global _app_reset -_app_reset: - /* _app_reset may be required to be located at the beginning of the text - segment. However, the constant pool for _app_reset must be placed - before the code. Jump over the constant pool to solve this. */ - j .LpastInitialConstants - - .literal_position // tells the assembler/linker to place literals here - -.LpastInitialConstants: - // Keep a0 zero. It is used to initialize a few things. - // It is also the return address, where zero indicates - // that the frame used by _start is the bottommost frame. - // - movi a0, 0 // keep this register zero. - -#if XCHAL_HAVE_LOOPS - wsr.lcount a0 // loop count = 0 -#endif /* XCHAL_HAVE_LOOPS */ - - // Interrupts might be enabled, make sure at least medium and low priority - // interrupts are disabled until WindowBase, WindowStart, SP, and the stack - // are all properly setup (which will happen outside this file, after the - // _start label). We leave loops enabled on new exception architecture. -#if XCHAL_HAVE_EXCEPTIONS - movi a2, XCHAL_EXCM_LEVEL - wsr.ps a2 // set PS.INTLEVEL=EXCM_LEVEL, PS.WOE=0, PS.EXCM=0 - rsync -#endif - - // DO THIS FIRST: initialize the window start and base - // before, so that windows don't move under us. -#if XCHAL_HAVE_WINDOWED - // We do this even if we are assembling for the - // call0 abi, but it's not really needed. - movi a2, 1 - wsr.windowstart a2 // window start = 1 - wsr.windowbase a0 // window base = 0 - rsync - - // NOTE: a0 may no longer be zero here, because - // we wrote to WindowBase. So clear it again. - movi a0, 0 -#endif - - // Now, BEFORE we do any L32R (or MOVI with non-immediate - // range which results in an L32R), ensure LITBASE is set - // correctly. This is necessary for RAM applications loaded - // using a target-side debug monitor -- such applications - // don't have a reset vector and start execution at _start. - // (This part is unnecessary if running from a reset vector.) - // The target-side debug monitor might have set LITBASE to - // anything at all, so we cannot rely on its value here. -#if XCHAL_HAVE_ABSOLUTE_LITERALS - wsr.litbase a0 // force PC-relative L32R - rsync -# if XSHAL_USE_ABSOLUTE_LITERALS - .begin no-absolute-literals // use PC-rel L32R to load - movi a2, _lit4_start + 0x40001 // address of absolute literals - .end no-absolute-literals // (see handlers/ResetVector.S - wsr.litbase a2 // for explanation) - rsync -# endif -#endif - - - /* - * Now "enable" the caches. - * - * NOTE: We don't *initialize* the caches here, because the loader - * (eg. target debugger agent / debug monitor, boot code, etc) - * is expected to have initialized them for us. - * - * The _memmap_cacheattr_reset symbol's value (address) is defined - * by the LSP's linker script, as generated by xt-genldscripts. - * - * (NOTE: for configs that don't have CACHEATTR or region protection, - * ie. for full MMUs, there is no equivalent cache attribute layout, - * and the following code has no effect. We assume for now that the - * application restricts itself to the static TLB entries, i.e. to - * virtual addresses 0xD0000000 thru 0xFFFFFFFF.) - */ -#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR \ - || (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY) - movi a2, _memmap_cacheattr_reset /* note: absolute symbol, not a ptr */ - cacheattr_set /* set CACHEATTR from a2 (clobbers a3-a8) */ -#endif - - - - // Coprocessor option initialization -#if XCHAL_HAVE_CP - //movi a2, XCHAL_CP_MASK // enable existing CPs - // To allow creating new coprocessors using TC that are not known - // at GUI build time without having to explicitly enable them, - // all CPENABLE bits must be set, even though they may not always - // correspond to a coprocessor. - movi a2, 0xFF // enable *all* bits, to allow dynamic TIE - wsr.cpenable a2 -#endif - - // Floating point coprocessor option initialization -#if XCHAL_HAVE_FP - rsync /* wait for WSR to CPENABLE to complete before accessing FP coproc state */ - wur.fcr a0 /* clear FCR (default rounding mode, round-nearest) */ - wur.fsr a0 /* clear FSR */ -#endif - - - /* NOTE: Future releases may clear BSS here rather than in the CRT1. */ - - - /* - * Now jump to the application. This is typically the - * C run-time initialization ("CRT") which in turn calls main(): - */ - movi a4, _start - jx a4 // jump to _start - - .size _app_reset, . - _app_reset - diff --git a/src/arch/xtensa/xtos/crt1-boards.S b/src/arch/xtensa/xtos/crt1-boards.S deleted file mode 100644 index 3e2ed583e8a3..000000000000 --- a/src/arch/xtensa/xtos/crt1-boards.S +++ /dev/null @@ -1,348 +0,0 @@ -// crt1-boards.S -// -// For most hardware / boards, this code sets up the C calling context -// (setting up stack, PS, and clearing BSS) and jumps to __clibrary_start -// which sets up the C library, calls constructors and registers destructors, -// and calls main(). -// -// Control arrives here at _start from the reset vector or from crt0-app.S. - -// Copyright (c) 1998-2017 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. - - -#if CONFIG_MULTICORE -#include <sof/lib/cpu.h> -#include <sof/lib/memory.h> -#endif -#include <xtensa/cacheasm.h> -#include <xtensa/cacheattrasm.h> -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -// Exports -.global _start - -// Imports -// __clibrary_init from C library (eg. newlib or uclibc) -// exit from C library -// main from user application -// board_init board-specific (uart/mingloss/tinygloss.c) -// xthal_dcache_all_writeback from HAL library -// __stack from linker script (see LSP Ref Manual) -// _bss_table_start from linker script (see LSP Ref Manual) -// _bss_table_end from linker script (see LSP Ref Manual) - -.type main, @function - -.type primary_core_data, @object -.type core_data_ptr, @object - -// Macros to abstract away ABI differences - -#if __XTENSA_CALL0_ABI__ -# define CALL call0 -# define CALLX callx0 -#else -# define CALL call4 -# define CALLX callx4 -#endif - -/**************************************************************************/ - - .text - .align 4 - -_start: -#if CONFIG_MULTICORE - // each core unpacks xtos structures for itself - // nevertheless core 0 initializes shared xtosstruct - get_prid a5 - movi a4, PLATFORM_PRIMARY_CORE_ID - bne a5, a4, xtos_per_core -#endif - - // _start is typically NOT at the beginning of the text segment -- - // it is always called from either the reset vector or other code - // that does equivalent initialization (such as crt0-app.S). - // - // Assumptions on entry to _start: - // - low (level-one) and medium priority interrupts are disabled - // via PS.INTLEVEL and/or INTENABLE (PS.INTLEVEL is expected to - // be zeroed, to potentially enable them, before calling main) - // - C calling context not initialized: - // - PS not initialized - // - SP not initialized - // - the following are initialized: - // - LITBASE, cache attributes, WindowBase, WindowStart, - // CPENABLE, FP's FCR and FSR, EXCSAVE[n] - - // Keep a0 zero. It is used to initialize a few things. - // It is also the return address, where zero indicates - // that the frame used by _start is the bottommost frame. - // -#if !XCHAL_HAVE_HALT || !XCHAL_HAVE_BOOTLOADER // not needed for Xtensa TX - movi a0, 0 // keep this register zero. -#endif - -#if XTOS_RESET_UNNEEDED && !XCHAL_HAVE_HALT -#include "reset-unneeded.S" -#endif - -#if !CONFIG_MULTICORE - // Init xtos struct ptr - movi a2, primary_core_data - movi a3, core_data_ptr - s32i a2, a3, 0 -#else - // Init xtos struct ptr - movi a2, 4 - mull a2, a2, a5 - movi a3, core_data_ptr - add a3, a3, a2 - movi a2, primary_core_data - s32i a2, a3, 0 - - // Initialize the stack pointer. - // See the "ABI and Software Conventions" chapter in the - // Xtensa ISA Reference manual for details. - - // NOTE: Because the _start routine does not use any memory in its - // stack frame, and because all of its CALL instructions use a - // window size of 4 (or zero), the stack frame for _start can be empty. - -// Common xtos structures used by all cores. -xtos_common: - // Unpack xtos_exc_handler_table from rodata. - movi a6, xtos_exc_handler_table - movi a9, xtos_exc_handler_table_r - movi a13, XCHAL_EXCCAUSE_NUM*4 -xtos_exc_handler_table_loop: - l32i a12, a9, 0 - s32i a12, a6, 0 - addi a13, a13, -4 - addi a6, a6, 4 - addi a9, a9, 4 - bnez a13, xtos_exc_handler_table_loop - -// Xtos structures initialized per core from rodata. -xtos_per_core: -#endif -#if CONFIG_XT_BOOT_LOADER - .weak _Level2FromVector - .weak _Level3FromVector - .weak _Level4FromVector - .weak _Level5FromVector - - movi a4, _Level2FromVector - writesr excsave 2 a4 - movi a4, _Level3FromVector - writesr excsave 3 a4 - movi a4, _Level4FromVector - writesr excsave 4 a4 -#if XCHAL_INTLEVEL5_MASK - movi a4, _Level5FromVector - writesr excsave 5 a4 -#endif -#endif - -#if CONFIG_MULTICORE - get_prid a5 - movi a4, PLATFORM_PRIMARY_CORE_ID - beq a5, a4, xtos_per_core_obtain_xtos_structs - -xtos_per_core_cacheattr: -#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || \ - XCHAL_HAVE_XLT_CACHEATTR || \ - (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY) - movi a2, _memmap_cacheattr_reset /* absolute symbol, not a ptr */ - cacheattr_set /* set CACHEATTR from a2 (clobbers a3-a8) */ -#endif - -xtos_per_core_vecbase: -#if XCHAL_HAVE_VECBASE - /* note: absolute symbol, not a ptr */ - movi a2, _memmap_vecbase_reset - wsr.vecbase a2 -#endif - -#if XCHAL_HAVE_S32C1I && (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RC_2009_0) /* have ATOMCTL ? */ -# if XCHAL_DCACHE_IS_COHERENT - movi a3, 0x25 /* MX -- internal for writeback, RCW otherwise */ -# else - movi a3, 0x15 /* non-MX -- always RCW */ -# endif - wsr.atomctl a3 -#endif - -// Obtain core structs from given address. -xtos_per_core_obtain_xtos_structs: - get_prid a5 - movi a2, 4 - mull a2, a2, a5 - movi a3, core_data_ptr - add a3, a3, a2 - l32i a3, a3, 0 - -xtos_per_core_init_intstruct: - movi a2, 0 - s32i a2, a3, 0 - movi a2, 0xFFFFFFFF - s32i a2, a3, 4 - addi a3, a3, XTOS_INTSTRUCT_SIZE_PER_CORE - -xtos_per_core_init_interrupt_table: - // Setup iterator. - movi a6, XCHAL_NUM_INTERRUPTS - - // Setup init constants. - movi a2, xtos_unhandled_interrupt - - 1: - addi a6, a6, -1 - s32i a2, a3, 0 - s32i a6, a3, 4 - // Int handler size should be 8. - addi a3, a3, 8 - bnez a6, 1b - -xtos_per_core_init_interrupt_mask: - movi a6, XCHAL_NUM_INTERRUPTS - movi a5, ~XCHAL_LOWPRI_MASK - movi a7, -2 - - 2: - // i <==> a6 - addi a6, a6, -1 - // a4 := 1 << i - movi a4, 1 - ssl a6 - sll a4, a4 - // a2 := (-2 * (1 << i) - 1) | ~XCHAL_LOWPRI_MASK - mull a2, a4, a7 - addi a2, a2, -1 - or a2, a2, a5 - - s32i a2, a3, 0 - s32i a4, a3, 4 - // Int handler size should be 8. - addi a3, a3, 8 - addi a4, a4, 1 - bnez a6, 2b - - // Assign stack ptr before PS is initialized to avoid any debugger - // side effects and prevent from double exception. - xtos_stack_addr_percore sp, a3, _stack_sentry, _sof_core_s_start, SOF_STACK_SIZE -#else /* CONFIG_MULTICORE */ - movi sp, __stack -#endif - - /* - * Now that sp (a1) is set, we can set PS as per the application - * (user vector mode, enable interrupts, enable window exceptions if applicable). - */ -#if XCHAL_HAVE_EXCEPTIONS - movi a3, PS_UM|PS_WOE_ABI // PS.WOE = 0|1, PS.UM = 1, PS.EXCM = 0, PS.INTLEVEL = 0 - wsr.ps a3 - rsync -#endif - - /* - * Do any initialization that affects the memory map, such as - * setting up TLB entries, that needs to be done before we can - * successfully clear BSS (e.g. if some BSS segments are in - * remapped areas). - * - * NOTE: This hook works where the reset vector does not unpack - * segments (see "ROM packing" in the LSP manual), or where - * unpacking of segments is not affected by memory remapping. - * If ROM unpacking is affected, TLB setup must be done in - * assembler from the reset vector. - * - * The __memmap_init() routine can be a C function, however it - * does not have BSS initialized! In particular, __memmap_init() - * cannot set BSS variables, i.e. uninitialized global variables - * (they'll be wiped out by the following BSS clear), nor can it - * assume they are yet initialized to zero. - * - * The __memmap_init() function is optional. It is marked as a - * weak symbol, so that it gets valued zero if not defined. - */ - .weak __memmap_init - movi a4, __memmap_init - beqz a4, 1f - CALLX a4 -1: - -/* bootloader takes care of zeroing BSS */ -#if !CONFIG_XT_BOOT_LOADER - /* - * Clear the BSS (uninitialized data) segments. - * This code supports multiple zeroed sections (*.bss). - * - * Register allocation: - * a0 = 0 - * a6 = pointer to start of table, and through table - * a7 = pointer to end of table - * a8 = start address of bytes to be zeroed - * a9 = end address of bytes to be zeroed - * a10 = length of bytes to be zeroed - */ - movi a0, 0 - movi a6, _bss_table_start - movi a7, _bss_table_end - bgeu a6, a7, .L3zte - -.L0zte: l32i a8, a6, 0 // get start address, assumed multiple of 4 - l32i a9, a6, 4 // get end address, assumed multiple of 4 - addi a6, a6, 8 // next entry - sub a10, a9, a8 // a10 = length, assumed a multiple of 4 - bbci.l a10, 2, .L1zte - s32i a0, a8, 0 // clear 4 bytes to make length multiple of 8 - addi a8, a8, 4 -.L1zte: bbci.l a10, 3, .L2zte - s32i a0, a8, 0 // clear 8 bytes to make length multiple of 16 - s32i a0, a8, 4 - addi a8, a8, 8 -.L2zte: srli a10, a10, 4 // length is now multiple of 16, divide by 16 - floopnez a10, clearzte - s32i a0, a8, 0 // clear 16 bytes at a time... - s32i a0, a8, 4 - s32i a0, a8, 8 - s32i a0, a8, 12 - addi a8, a8, 16 - floopend a10, clearzte - - bltu a6, a7, .L0zte // loop until end of table of *.bss sections -.L3zte: -#endif - - // Call: int main(int argc, char ** argv, char ** environ); - CALL main - // Does not return here. - - .data - // Mark argc/argv/envp parameters as weak so that an external - // object file can override them. - .text - - .size _start, . - _start diff --git a/src/arch/xtensa/xtos/crt1-sim.S b/src/arch/xtensa/xtos/crt1-sim.S deleted file mode 100644 index 90687927449f..000000000000 --- a/src/arch/xtensa/xtos/crt1-sim.S +++ /dev/null @@ -1,290 +0,0 @@ -// crt1-sim.S -// For the Xtensa simulator target, this code sets up the C calling context -// and calls main() (via __clibrary_start). -// Control arrives here at _start from the reset vector or from crt0-app.S. - -// Copyright (c) 1998-2017 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. - -#include <xtensa/simboard.h> -#include <xtensa/simcall.h> -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -// Exports -.global _start - -// Imports -// __clibrary_init from C library (eg. newlib or uclibc) -// exit from C library -// main from user application -// __stack from linker script (see LSP Ref Manual) - -.type __clibrary_init, @function -.type main, @function -.type exit, @function - - -// Macros to abstract away ABI differences - -#if __XTENSA_CALL0_ABI__ -# define CALL call0 -# define CALLX callx0 -# define ARG1 a2 /* 1st outgoing call argument */ -# define ARG2 a3 /* 2nd outgoing call argument */ -# define ARG3 a4 /* 3rd outgoing call argument */ -# define ARG4 a5 /* 4th outgoing call argument */ -# define ARG5 a6 /* 5th outgoing call argument */ -#else -# define CALL call4 -# define CALLX callx4 -# define ARG1 a6 /* 1st outgoing call argument */ -# define ARG2 a7 /* 2nd outgoing call argument */ -# define ARG3 a8 /* 3rd outgoing call argument */ -# define ARG4 a9 /* 4th outgoing call argument */ -# define ARG5 a10 /* 5th outgoing call argument */ -#endif - - .data - .weak _start_envp // allow overriding - .align 4 -_start_envp: .word 0 // empty environ - - - - .text - .align 4 - -_start: - // _start is typically NOT at the beginning of the text segment -- - // it is always called from either the reset vector or other code - // that does equivalent initialization (such as crt0-app.S). - // - // Assumptions on entry to _start: - // - low (level-one) and medium priority interrupts are disabled - // via PS.INTLEVEL and/or INTENABLE (PS.INTLEVEL is expected to - // be zeroed, to potentially enable them, before calling main) - // - C calling context not initialized: - // - PS not initialized - // - SP not initialized - // - the following are initialized: - // - LITBASE, cache attributes, WindowBase, WindowStart, - // CPENABLE, FP's FCR and FSR, EXCSAVE[n] - - // Keep a0 zero. It is used to initialize a few things. - // It is also the return address, where zero indicates - // that the frame used by _start is the bottommost frame. - // - movi a0, 0 // keep this register zero. - -#if XTOS_RESET_UNNEEDED -#include "reset-unneeded.S" -#endif - - - // Initialize the stack pointer. - // See the "ABI and Software Conventions" chapter in the - // Xtensa ISA Reference manual for details. - - // NOTE: Because the _start routine does not use any memory in its - // stack frame, and because all of its CALL instructions use a - // window size of 4, the stack frame for _start can be empty. - movi sp, __stack - - // reserve stack space for - // - argv array - // - argument strings - movi a2, SYS_iss_argv_size - simcall // returns size of argv[] + its strings in a2 -#if XCHAL_HAVE_PIF - // The stack only needs 16-byte alignment. - // However, here we round up the argv size further to 128 byte multiples - // so that in most cases, variations in argv[0]'s path do not result in - // different stack allocation. Otherwise, such variations can impact - // execution timing (eg. due to cache effects etc) for the same code and data. - // If we have a PIF, it's more likely the extra required space is okay. - addi a2, a2, 127 - srli a2, a2, 7 - slli a2, a2, 7 -#else - // Keep stack 16-byte aligned. - addi a2, a2, 15 - srli a2, a2, 4 - slli a2, a2, 4 -#endif - // No need to use MOVSP because we have no caller (we're the - // base caller); in fact it's better not to use MOVSP in this - // context, to avoid unnecessary ALLOCA exceptions and copying - // from undefined memory: - // sub a3, sp, a2 - // movsp sp, a3 - sub sp, sp, a2 - - - /* - * Now that sp (a1) is set, we can set PS as per the application - * (user vector mode, enable interrupts, enable window exceptions if applicable). - */ -#if XCHAL_HAVE_EXCEPTIONS - movi a3, PS_UM|PS_WOE_ABI // PS.WOE = 0|1, PS.UM = 1, PS.EXCM = 0, PS.INTLEVEL = 0 - wsr.ps a3 - rsync -#endif - - - /* - * Do any initialization that affects the memory map, such as - * setting up TLB entries, that needs to be done before we can - * successfully clear BSS (e.g. if some BSS segments are in - * remapped areas). - * - * NOTE: This hook works where the reset vector does not unpack - * segments (see "ROM packing" in the LSP manual), or where - * unpacking of segments is not affected by memory remapping. - * If ROM unpacking is affected, TLB setup must be done in - * assembler from the reset vector. - * - * The __memmap_init() routine can be a C function, however it - * does not have BSS initialized! In particular, __memmap_init() - * cannot set BSS variables, i.e. uninitialized global variables - * (they'll be wiped out by the following BSS clear), nor can it - * assume they are yet initialized to zero. - * - * The __memmap_init() function is optional. It is marked as a - * weak symbol, so that it gets valued zero if not defined. - */ - .weak __memmap_init - movi a4, __memmap_init - beqz a4, 1f - CALLX a4 -1: - -#if !XCHAL_HAVE_BOOTLOADER /* boot loader takes care of zeroing BSS */ - - /* If a system-specific BSS init routine is defined, call it. - * Such a routine must be named __bss_init(). It can be a C - * function, however it must be written to be able to work - * with BSS not yet initialized. This function is optional. - * It is marked as a weak symbol, so that it gets value zero - * if not defined. - */ - .weak __bss_init - movi a4, __bss_init - beqz a4, 2f - movi ARG1, _bss_table_start - movi ARG2, _bss_table_end - CALLX a4 - j .Lnobss // skip default BSS init code -2: - - /* The new ISS simcall only appeared after RB-2007.2: */ -#if (XCHAL_HW_MAX_VERSION > XTENSA_HWVERSION_RB_2007_2) - /* - * Clear the BSS (uninitialized data) segments. - * This code supports multiple zeroed sections (*.bss). - * For speed, we clear memory using an ISS simcall - * (see crt1-boards.S for more generic BSS clearing code). - */ - movi a6, _bss_table_start - movi a7, _bss_table_end - bgeu a6, a7, .Lnobss -.Lbssloop: - movi a2, SYS_memset - l32i a3, a6, 0 // arg1 = fill start address - movi a4, 0 // arg2 = fill pattern - l32i a5, a6, 4 // get end address - addi a6, a6, 8 // next bss table entry - sub a5, a5, a3 // arg3 = fill size in bytes - simcall // memset(a3,a4,a5) - bltu a6, a7, .Lbssloop // loop until end of bss table -#endif /* XCHAL_HW_MAX_VERSION */ -.Lnobss: -#endif /* XCHAL_HAVE_BOOTLOADER */ - - - /* - * Call __clibrary_init to initialize the C library: - * - * void __clibrary_init(int argc, char ** argv, char ** environ, - * void(*init_func)(void), void(*fini_func)(void)); - */ - - // Get argv with the arguments from the ISS - mov a3, sp // tell simcall where to write argv[] - movi a2, SYS_iss_set_argv - simcall // write argv[] array at a3 - - movi a2, SYS_iss_argc - simcall // put argc in a2 - - -// Alternative smaller code for Xtensa TX. -// Many starting with simulation assume a full C env, so NOT DONE FOR NOW. -// -//#if XCHAL_HAVE_HALT -// -// // Assume minimalist environment for memory-constrained TX cores. -// // No C library or board initialization, and no call to exit(). -// // However, in the interest of software regressions, for now we -// // still pass parameters to main (but not the rarely used envp). -// -// //mov ARG1, a2 // argc already in a2. -// mov ARG2, sp // argv -// CALL main -// halt -// -//#else /* !HALT */ -// ... - - -#if __XTENSA_CALL0_ABI__ - mov a12, a2 // save argc (a2 is ARG1) -#else - mov ARG1, a2 // argc -#endif - mov ARG2, sp // argv - movi ARG3, _start_envp // envp - movi ARG4, _init // _init - movi ARG5, _fini // _fini - CALL __clibrary_init - - // Call: int main(int argc, char ** argv, char ** environ); -#if __XTENSA_CALL0_ABI__ - mov ARG1, a12 // argc -#else - mov ARG1, a2 // argc -#endif - mov ARG2, sp // argv - movi ARG3, _start_envp // envp = [0] - CALL main - // The return value is the same register as the first outgoing argument. - CALL exit // exit with main's return value - // Does not return here. - - .size _start, . - _start - - -// Local Variables: -// mode:fundamental -// comment-start: "// " -// comment-start-skip: "// *" -// End: diff --git a/src/arch/xtensa/xtos/crt1-tiny.S b/src/arch/xtensa/xtos/crt1-tiny.S deleted file mode 100644 index d1684c5e76ad..000000000000 --- a/src/arch/xtensa/xtos/crt1-tiny.S +++ /dev/null @@ -1,127 +0,0 @@ -// crt1-tiny.S -// -// This is a reduced version of the code in crt1-boards.S . -// For most hardware / boards, this code sets up the C calling context -// (setting up stack, PS, and clearing BSS) and calls main(). -// It has some limitations (see LSP Ref Manual for details) such as: -// - does not setup the C library (...) -// - does not call C++ static constructors and destructors -// - only clears .bss , not other *.bss sections -// -// Control arrives here at _start from the reset vector or from crt0-app.S. - -// Copyright (c) 1998-2013 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/xtensa-versions.h> -#include <xtensa/simcall.h> - - -// Imports -// __stack from linker script (see LSP Ref Manual) -// _bss_start from linker script (see LSP Ref Manual) -// _bss_end from linker script (see LSP Ref Manual) -// main from user application - - - -#ifdef __XTENSA_CALL0_ABI__ -# define CALL call0 -#else -# define CALL call4 -#endif - - -/**************************************************************************/ - - .text - .align 4 - .global _start -_start: - // _start is typically NOT at the beginning of the text segment -- - // it is always called from either the reset vector or other code - // that does equivalent initialization (such as crt0-app.S). - // See crt1-boards.S for assumptions on entry to _start , - // and for comments on what is being done in this file. - -#if !XCHAL_HAVE_HALT || !XCHAL_HAVE_BOOTLOADER // not needed for Xtensa TX - movi a0, 0 // mark base of call stack -#endif - - movi sp, __stack // setup the stack - -#if XCHAL_HAVE_EXCEPTIONS - movi a3, PS_UM|PS_WOE_ABI // PS: WOE=0|1, UM=1, EXCM=0, INTLEVEL=0 - wsr.ps a3 // setup PS for the application - rsync -#endif - - - // Clear the BSS (uninitialized data) segment. - // - // This code only supports .bss, not multiple *.bss sections. - // Corresponding code in crt1-boards.S does, and is faster but bigger. - -#if !XCHAL_HAVE_BOOTLOADER - movi a6, _bss_start - movi a7, _bss_end - bgeu a6, a7, 2f -1: s32i a0, a6, 0 - addi a6, a6, 4 - bltu a6, a7, 1b -2: -#endif - - // We can now call C code, the C calling environment is initialized. - // This tiny C runtime assumes main is declared as "void main(void)" - // rather than with the usual argc,argv. So there are no arguments. - - CALL main - - // In this tiny C runtime, main() is not expected to return. - // If it does, just loop forever. - - //CALL xthal_dcache_all_writeback // sync dirty dcaches to memory - //extw // sync TIE queues/ports/etc (LX or later only) - -.L0: -#if XCHAL_HAVE_HALT - halt -#else -# if XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RE_2013_2 /* SIMCALL is NOP in hw? */ - movi a2, SYS_exit - simcall // exit if in simulator, else NOP -# endif -# if XCHAL_HAVE_DEBUG - break 1, 15 // give control to debugger -# endif -#endif - j .L0 - - .size _start, . - _start - - -// Local Variables: -// mode:fundamental -// comment-start: "// " -// comment-start-skip: "// *" -// End: diff --git a/src/arch/xtensa/xtos/debug-vector.S b/src/arch/xtensa/xtos/debug-vector.S deleted file mode 100644 index cf16dcecaec3..000000000000 --- a/src/arch/xtensa/xtos/debug-vector.S +++ /dev/null @@ -1,73 +0,0 @@ -// debug-vector.S -- Debug Exception Vector -// $Id: //depot/rel/Eaglenest/Xtensa/OS/xtos/debug-vector.S#2 $ - -// Copyright (c) 2003-2013 Tensilica 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. - -#include <arch/debug/gdb/xtensa-defs.h> - -#include <xtensa/xtensa-versions.h> -#include <xtensa/coreasm.h> -#include <xtensa/config/specreg.h> -#ifdef SIMULATOR -#include <xtensa/simcall.h> -#endif - -#if XCHAL_HAVE_DEBUG && XCHAL_HAVE_EXCEPTIONS - - // This code goes at the debug exception vector - - .begin literal_prefix .DebugExceptionVector - .section .DebugExceptionVector.text, "ax" - .align 4 - .global _DebugExceptionVector -_DebugExceptionVector: - - isync_erratum453 -#if ((defined(SIMULATOR) || \ - (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RE_2013_2)) \ - && !CONFIG_GDB_DEBUG) /* SIMCALL is NOP in hw? */ - // In the simulator (ISS), let the debugger (if any is attached) - // handle the debug exception, else simply stop the simulation: - // - simcall // have ISS handle the debug exception -# endif -# if (!defined(SIMULATOR) && !CONFIG_GDB_DEBUG) - // For hardware, this code does not handle debug exceptions. - // To implement a target-side debug monitor, replace this - // vector with a real one that uses target-specific facilities - // to communicate with the debugger. - // -1: - // unexpected debug exception, loop in low-power mode - //waiti XCHAL_DEBUGLEVEL - j 1b // infinite loop - unexpected debug exception -# endif /*!SIMULATOR && !CONFIG_GDB_DEBUG*/ - -#if CONFIG_GDB_DEBUG - xsr a2, DEBUG_EXCSAVE - jx a2 -#endif - - .end literal_prefix - .size _DebugExceptionVector, . - _DebugExceptionVector - -#endif /* XCHAL_HAVE_DEBUG && XCHAL_HAVE_EXCEPTIONS */ diff --git a/src/arch/xtensa/xtos/deprecated.S b/src/arch/xtensa/xtos/deprecated.S deleted file mode 100644 index db746dbfa3aa..000000000000 --- a/src/arch/xtensa/xtos/deprecated.S +++ /dev/null @@ -1,122 +0,0 @@ -// deprecated.S -- Deprecated assembler functions - -// Copyright (c) 2003-2015 Tensilica 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. - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -#if XCHAL_HAVE_XEA1 || XCHAL_HAVE_XEA2 - - .text - -/* - void _xtos_timer_<N>_delta(int cycles) - - Set the timer from the current ccount. - DEPRECATED. PLEASE USE xthal_set_ccompare() AND xthal_get_ccount() - INSTEAD, OR USE DIFFERENT ALGORITHM THAT UPDATES CCOMPAREn RELATIVE TO - LAST CCOMPAREn FOR DRIFT-FREE PERIODIC TIMER INTERRUPTS. -*/ - .macro define_timer_delta num, numtimers - .if ((\num-\numtimers) & ~0xFFF) // num < numtimers ? - .align 4 - .global _xtos_timer_&num&_delta - .type _xtos_timer_&num&_delta,@function -_xtos_timer_&num&_delta: - abi_entry - rsr.ccount a3 - add a3, a3, a2 - writesr ccompare \num a3 - abi_return - .size _xtos_timer_&num&_delta, . - _xtos_timer_&num&_delta - .endif - .endm - - - -#if defined(__SPLIT__t0_delta) - - define_timer_delta 0, XCHAL_NUM_TIMERS - -#elif defined(__SPLIT__t1_delta) - - define_timer_delta 1, XCHAL_NUM_TIMERS - -#elif defined(__SPLIT__t2_delta) - - define_timer_delta 2, XCHAL_NUM_TIMERS - -#elif defined(__SPLIT__t3_delta) - - define_timer_delta 3, XCHAL_NUM_TIMERS - - -#elif defined(__SPLIT__read_ints) - - // - // u32 _xtos_read_ints( void ) - // - // _xtos_read_ints() reads the INTERRUPT register and returns it. - // DEPRECATED. - // [Kept temporarily because it was documented in T1050 System SW Ref Manual.] - // - .text - .align 4 - .global _xtos_read_ints - .type _xtos_read_ints,@function -_xtos_read_ints: - abi_entry -#if XCHAL_HAVE_INTERRUPTS - rsr.interrupt a2 -#else /*XCHAL_HAVE_INTERRUPTS*/ - movi a2, 0 -#endif /*XCHAL_HAVE_INTERRUPTS*/ - abi_return - .size _xtos_read_ints, . - _xtos_read_ints - - -#elif defined(__SPLIT__clear_ints) - - // - // void _xtos_clear_ints( u32 mask ) - // - // _xtos_clear_ints() clears selected bits of the INTERRUPT register. - // DEPRECATED. - // [Kept temporarily because it was documented in T1050 System SW Ref Manual.] - // - .text - .align 4 - .global _xtos_clear_ints - .type _xtos_clear_ints,@function -_xtos_clear_ints: - abi_entry -#if XCHAL_HAVE_INTERRUPTS - wsr.intclear a2 -#endif /*XCHAL_HAVE_INTERRUPTS*/ - abi_return - .size _xtos_clear_ints, . - _xtos_clear_ints - -#endif /* splitting */ - -#endif /* XEA1 or XEA2 */ - diff --git a/src/arch/xtensa/xtos/double-vector.S b/src/arch/xtensa/xtos/double-vector.S deleted file mode 100644 index f52e38462e4f..000000000000 --- a/src/arch/xtensa/xtos/double-vector.S +++ /dev/null @@ -1,98 +0,0 @@ -// double-vector.S -- Double Exception Vector -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/double-vector.S#1 $ - -// Copyright (c) 2000-2004, 2006, 2010 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/config/system.h> -#ifdef SIMULATOR -#include <xtensa/simcall.h> -#endif - - -#if XCHAL_HAVE_EXCEPTIONS && defined(XCHAL_DOUBLEEXC_VECTOR_VADDR) - -/* - * This is a very minimalist implementation of the double - * exception vector. For XEA2 configurations without a - * full MMU, this vector is only expected to be executed - * upon fatal errors (exceptions that occur within critical - * sections of exception vectors and handlers). - * - * For configurations with a full MMU (ie. with TLBs and - * auto-refill) and the windowed address registers option, - * a more complete version of this handler is necessary if: - * dynamic page mapping is implemented, and the stack - * can ever point to a dynamically mapped area. - * In this case, a double exception is a normal occurrence - * when a stack access within a window handler causes - * a TLB miss exception or other expected MMU fault. - * XTOS does not support this scenario, hence a minimalist - * double exception vector is sufficient. - */ - - .begin literal_prefix .DoubleExceptionVector - .section .DoubleExceptionVector.text, "ax" - - .align 4 - .global _DoubleExceptionVector -_DoubleExceptionVector: - -# if XCHAL_HAVE_DEBUG -1: break 1,4 // unhandled double exception -# elif defined(SIMULATOR) - wsr.excsave1 a2 // save a2 where simulator expects it - movi a2, SYS_unhandled_double_exc -1: simcall // let simulator/debugger report unhandled exception -# else -1: -# endif - j 1b // infinite loop - - // NOTE: a non-minimalist vector may choose to - // process the double exception in the vector itself - // (by default, much more space is allocated to double - // exception vectors than to most other vectors); - // or, to jump to a double exception handler located - // elsewhere. If only the normal case of double - // exceptions occurring within a window handler is - // being handled, then it is safe to use EXCSAVE_1 to - // do this jump (window handlers don't use EXCSAVE_1). - // For example: - // - // wsr.excsave1 a0 - // movi a0, _DoubleExceptionFromVector - // jx a0 - // - // .text - // .align 4 - // .global _DoubleExceptionFromVector - //_DoubleExceptionFromVector: - // ... - - - .size _DoubleExceptionVector, . - _DoubleExceptionVector - .text - .end literal_prefix - -#endif /* have double exceptions */ - diff --git a/src/arch/xtensa/xtos/exc-sethandler.c b/src/arch/xtensa/xtos/exc-sethandler.c deleted file mode 100644 index 9df2eff8ea89..000000000000 --- a/src/arch/xtensa/xtos/exc-sethandler.c +++ /dev/null @@ -1,70 +0,0 @@ - -/* exc-sethandler.c - register an exception handler in XTOS */ - -/* - * Copyright (c) 1999-2017 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. - */ - -#include <xtensa/config/core.h> -#include "xtos-internal.h" - - -#if XCHAL_HAVE_EXCEPTIONS - -extern void xtos_c_wrapper_handler(void *arg); /* assembly-level wrapper for C handlers */ -extern void xtos_unhandled_exception(void *arg); /* assembly-level handler for exceptions - with no registered handler */ -extern void xtos_p_none(void *arg); /* default/empty C handler */ - - -extern _xtos_handler xtos_c_handler_table[XCHAL_EXCCAUSE_NUM]; -extern _xtos_handler xtos_exc_handler_table[XCHAL_EXCCAUSE_NUM]; - -/* - * Register a C handler for the specified general exception - * (specified EXCCAUSE value). - */ -_xtos_handler _xtos_set_exception_handler( int n, _xtos_handler f ) -{ - _xtos_handler ret = 0; - - if( n < XCHAL_EXCCAUSE_NUM ) { - _xtos_handler func = f; - - if( func == 0 ) { - func = &xtos_p_none; - } - ret = xtos_c_handler_table[n]; - xtos_exc_handler_table[n] = ( (func == &xtos_p_none) - ? &xtos_unhandled_exception - : &xtos_c_wrapper_handler ); - xtos_c_handler_table[n] = func; - if( ret == &xtos_p_none ) { - ret = 0; - } - } - - return ret; -} - -#endif /* XCHAL_HAVE_EXCEPTIONS */ - diff --git a/src/arch/xtensa/xtos/exc-syscall-handler.S b/src/arch/xtensa/xtos/exc-syscall-handler.S deleted file mode 100644 index 9c647ce22a32..000000000000 --- a/src/arch/xtensa/xtos/exc-syscall-handler.S +++ /dev/null @@ -1,192 +0,0 @@ -/* exc-syscall-handler.S - XTOS syscall instruction handler */ - -/* - * Copyright (c) 1999-2010 Tensilica 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. - */ - -/* - * The SYSCALL instruction is typically used to implement system calls. - * By convention, register a2 identifies the requested system call. - * Typically, other parameters are passed in registers a3 and up, - * and results are returned in a2. - * - * The Xtensa windowed ABI reserves the value zero of register a2 - * as a request to force register windows to the stack. The call0 ABI, - * which has no equivalent operation, reserves this value as a no-op. - * - * Generally, only code that traverses the stack in unusual ways needs - * to force (spill) register windows to the stack. In generic C or C++, - * there are four cases, and they all use the standard SYSCALL mechanism: - * - * 1. C++ exceptions - * 2. setjmp and longjmp - * 3. functions using the GNU extension "__builtin_return_address" - * 4. functions using the GNU extension "nonlocal goto" - * - * NOTE: Specific operating systems often need to spill register windows - * to the stack in other situations such as context-switching, passing - * Unix-like signals to threads, displaying stack tracebacks, etc. - * They may choose to use the SYSCALL mechanism to do so, or use other - * means such as calling xthal_window_spill() or other methods. - * - * If you want to handle other system calls, you can modify this file, or - * use the C version of it in exc-syscall-handler.c . The Xtensa ABIs only - * define system call zero; the behavior of other system calls is up to you. - */ - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -#if XCHAL_HAVE_EXCEPTIONS - -//Vector: -// addi a1, a1, -ESF_TOTALSIZE // allocate exception stack frame, etc. -// s32i a2, a1, UEXC_a2 -// s32i a3, a1, UEXC_a3 -// movi a3, xtos_exc_handler_table -// rsr.exccause a2 -// addx4 a2, a2, a3 -// l32i a2, a2, 0 -// s32i a4, a1, UEXC_a4 -// jx a2 // jump to cause-specific handler - - .global _need_user_vector_ // pull-in real user vector (tiny LSP) - - - /* - * The SYSCALL handler is entered when the processor - * executes the SYSCALL instruction. - * By convention, the system call to execute is specified in a2. - */ - .text - .align 4 - .global _xtos_syscall_handler -_xtos_syscall_handler: - // HERE: a2, a3, a4 have been saved to the exception stack frame allocated with a1 (sp). - // We ignore that a4 was saved, we don't clobber it. - - rsr.epc1 a3 -#if XCHAL_HAVE_LOOPS - // If the SYSCALL instruction was the last instruction in the body of - // a zero-overhead loop, and the loop will execute again, decrement - // the loop count and resume execution at the head of the loop: - // - rsr.lend a2 - addi a3, a3, 3 // increment EPC to skip the SYSCALL instruction - bne a2, a3, 1f - rsr.lcount a2 - beqz a2, 1f - addi a2, a2, -1 - wsr.lcount a2 - rsr.lbeg a3 -1: l32i a2, a1, UEXC_a2 // get the system call number -#else - // No loop registers. - l32i a2, a1, UEXC_a2 // get the system call number - addi a3, a3, 3 // increment EPC to skip the SYSCALL instruction -#endif - wsr.epc1 a3 // update EPC1 past SYSCALL - l32i a3, a1, UEXC_a3 // restore a3 - // If you want to handle other system calls, check a2 here. - -#ifdef __XTENSA_WINDOWED_ABI__ - bnez a2, .Lnotzero // is syscall number zero? - - /* Spill register windows to the stack. */ - - // Save a2 thru a5 in the nested-C-function area, where an interrupt - // won't clobber them. The pseudo-CALL's ENTRY below clobbers a4 and a5. - //s32i a2, a1, (ESF_TOTALSIZE - 32) + 0 // a2 is zero, no need to save - s32i a3, a1, (ESF_TOTALSIZE - 32) + 4 - s32i a4, a1, (ESF_TOTALSIZE - 32) + 8 - s32i a5, a1, (ESF_TOTALSIZE - 32) + 12 - - movi a3, PS_WOE|PS_CALLINC(1)|PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL) // CALL4 emulation - rsr.ps a2 // save PS in a2 - wsr.ps a3 // PS.INTLEVEL=EXCMLEVEL (1 for XEA1) - // HERE: window overflows enabled but NOT SAFE yet, touch only a0..a3 until it's safe. - rsr.epc1 a3 // save EPC1 in a3 - addi a1, a1, ESF_TOTALSIZE // restore sp (dealloc ESF) for sane stack again - rsync // wait for WSR to PS to complete - // HERE: Window overflows and interrupts are safe, we saved EPC1 and - // restored a1, and a4-a15 are unmodified. - // Pseudo-CALL: make it look as if the code that executed SYSCALL - // made a CALL4 to here. See user exc. handler comments for details. - // ENTRY cannot cause window overflow; touch a4 to ensure a4-a7 - // overflow if needed: - movi a4, 0 // clears pseudo-CALL's return PC - // NOTE: On XEA1 processors, return from window overflow re-enables - // interrupts (by clearing PS.INTLEVEL). This is okay even though SP - // is unallocated because we saved state safe from interrupt dispatch. - .global _SyscallException -_SyscallException: // label makes tracebacks look nicer - _entry a1, 64 // as if after a CALL4 (PS.CALLINC==1) - // Call deep enough to force spill of entire address register file. - _call12 __deep_call -1: movi a14, 0x80000000 + .Ldelta_done - add a0, a12, a14 // clear a0 msbit (per CALL4), offset -3: retw // return from pseudo-CALL4 - - // NOTE: a5 still contains the exception window's exception stack frame pointer. -.LMdon: wsr.ps a2 // for XEA2, this sets EXCM; for XEA1, this sets INTLEVEL to 1; ... - movi a2, 0 // indicate successful SYSCALL (?) - l32i a4, a5, 32 + 8 - rsync // complete WSR to PS for safe write to EPC1 - wsr.epc1 a3 - l32i a3, a5, 32 + 4 - l32i a5, a5, 32 + 12 - rfe_rfue - - .set .Ldelta_retw, (3b - 1b) - .set .Ldelta_done, (.LMdon - 1b) - - .align 4 - .local __deep_call -__deep_call: - entry a1, 48 -#if XCHAL_NUM_AREGS < 64 - mov a15, a15 // touch just far enough to overflow 32 -#else - movi a12, .Ldelta_retw // use movi/add because of relocation - add a12, a0, a12 // set return PC as per CALL12 - _entry a1, 48 // last call was call12 so PS.CALLINC==3 - mov a12, a0 // set return PC - _entry a1, 48 - mov a12, a0 // set return PC - _entry a1, 16 - mov a11, a11 // touch just far enough to overflow 64 -#endif - retw - -#endif /* __XTENSA_WINDOWED_ABI__ */ - -.Lnotzero: - movi a2, -1 /*ENOSYS*/ // system call not supported - addi a1, a1, ESF_TOTALSIZE - rfe_rfue - - .size _xtos_syscall_handler, . - _xtos_syscall_handler - - -#endif /* XCHAL_HAVE_EXCEPTIONS */ - diff --git a/src/arch/xtensa/xtos/exc-table.S b/src/arch/xtensa/xtos/exc-table.S deleted file mode 100644 index a1281332e930..000000000000 --- a/src/arch/xtensa/xtos/exc-table.S +++ /dev/null @@ -1,61 +0,0 @@ -// exc-table.S - general exception C handler table - -// Copyright (c) 1999-2010 Tensilica 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. - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -#if XCHAL_HAVE_EXCEPTIONS - - /* - * Table of exception handlers (in C) for user vectored exceptions. - * Provides entries for all possible 64 exception causes - * currently allowed for in the EXCCAUSE register. - */ - .data - .global xtos_c_handler_table - .align 4 -xtos_c_handler_table: - .rept XCHAL_EXCCAUSE_NUM - .word xtos_p_none - .endr - - /* - * Default/empty exception C handler. - * This is just a placeholder for exception causes with no registered - * handler; it normally never gets executed. - * NOTE: control goes first to the debugger if one is present; - * see xtos_unhandled_exception in exc-unhandled.S . - */ - .text - .align 4 - .global xtos_p_none - .type xtos_p_none,@function -xtos_p_none: - abi_entry - // Do nothing. - abi_return - .size xtos_p_none, . - xtos_p_none - -#endif /* XCHAL_HAVE_EXCEPTIONS */ - diff --git a/src/arch/xtensa/xtos/exc-unhandled.S b/src/arch/xtensa/xtos/exc-unhandled.S deleted file mode 100644 index 2f569c0c8e49..000000000000 --- a/src/arch/xtensa/xtos/exc-unhandled.S +++ /dev/null @@ -1,83 +0,0 @@ -// exc-unhandled.S - General Exception Handler for unhandled exceptions - -// Copyright (c) 2002-2004, 2006, 2010 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/corebits.h> -#include "xtos-internal.h" -#ifdef SIMULATOR -#include <xtensa/simcall.h> -#endif - -#if XCHAL_HAVE_EXCEPTIONS - -/* - * Assembly-level exception handler used when no handler was - * registered for the specific exception cause. - * - * The BREAK instruction is used to give control to the debugger, - * if one is present and active. (If none is present and active, - * the default debug exception handler will typically skip over - * this break instruction.) - * This code follows the convention documented in the ISA manual - * to use BREAK instructions to signal unhandled exceptions to the - * debugger. For the debugger to report or handle this condition - * in an OS-independent manner, all processor state (except PC) - * must be restored as it was when the unhandled exception just - * occurred (ie. as it was at the beginning of the vector). - * If execution continues after the BREAK instruction (in which - * case any register might have been modified by the debugger), - * just return. - */ - .text - .align 4 - - // If not pulled-in some other way, define it as unhandled: - .weak xtos_cause3_handler - .global xtos_cause3_handler -xtos_cause3_handler: - - .global xtos_unhandled_exception -xtos_unhandled_exception: -#if XCHAL_HAVE_DEBUG || defined(SIMULATOR) - l32i a2, a1, UEXC_a2 // restore a2 - l32i a3, a1, UEXC_a3 // restore a3 - // Note: a4-a5 not clobbered, no need to restore. - addi a1, a1, ESF_TOTALSIZE // restore sp -# if XCHAL_HAVE_DEBUG - break 1, 1 // give control to the debugger (if any present) -# else - wsr.excsave1 a2 // save a2 where simulator expects it - movi a2, SYS_unhandled_user_exc - simcall // let simulator/debugger report unhandled exception - rsr.excsave1 a2 // restore a2 -# endif - rfe_rfue // if sim/debug resume, just return -#else /* DEBUG or SIMULATOR */ - j xtos_unhandled_exception // just loop forever -#endif /* DEBUG or SIMULATOR */ - - .size xtos_unhandled_exception, . - xtos_unhandled_exception - - -#endif /* XCHAL_HAVE_EXCEPTIONS */ - diff --git a/src/arch/xtensa/xtos/exit.S b/src/arch/xtensa/xtos/exit.S deleted file mode 100644 index eaee4364312b..000000000000 --- a/src/arch/xtensa/xtos/exit.S +++ /dev/null @@ -1,93 +0,0 @@ -// exit.S -// -// For hardware / boards, this is the default _exit routine called by the -// C library exit() function. If the program ever exits, we eventually -// end up here after all C library cleanup (such as closing open files, -// calling exit callbacks and C++ destructors, etc) is complete. - -// Copyright (c) 1998-2013 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/config/core-isa.h> -#include <xtensa/simcall.h> -#include "xtos-internal.h" - -// Macros to abstract away ABI differences -#if __XTENSA_CALL0_ABI__ -# define CALL call0 -#else -# define CALL call4 -#endif - - - .text - .align 4 - .global _exit - .type _exit, @function -_exit: - abi_entry 0, 4 - -#if __XTENSA_CALL0_ABI__ - // save exit code as cache writeback will clobber a2 in call0 - mov a12, a2 -#endif - - // sync dirty data to memory before terminating -#if XCHAL_DCACHE_IS_COHERENT - CALL xthal_cache_coherence_optout -#elif XCHAL_DCACHE_IS_WRITEBACK - CALL xthal_dcache_all_writeback -#endif - - // sync queues (if any, only for LX and later): -#if XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RA_2004_1 /* LX or later? */ - extw -#endif - // can break to debug monitor, go to sleep with waiti, or just spin in a loop -.L0: -#if XCHAL_HAVE_HALT - halt -#else -# if XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RE_2013_2 /* SIMCALL is NOP in hw? */ - // ISS expects exit code in a3 -# if __XTENSA_CALL0_ABI__ - mov a3, a12 -# else - mov a3, a2 -# endif - mov a4, a3 // save exitcode for the debugger, as simcall will erase a3 - movi a2, SYS_exit - simcall // exit if in simulator, else NOP - mov a2, a4 -# endif -# if XCHAL_HAVE_DEBUG - break 1, 15 // back to debugger, if one is attached -# endif -# if XCHAL_HAVE_INTERRUPTS - waiti 15 -# endif -#endif - j .L0 - //abi_exit - - .size _exit, . - _exit - diff --git a/src/arch/xtensa/xtos/int-handler.S b/src/arch/xtensa/xtos/int-handler.S deleted file mode 100644 index 3c86252c9aa5..000000000000 --- a/src/arch/xtensa/xtos/int-handler.S +++ /dev/null @@ -1,59 +0,0 @@ -// int-handler.S - Interrupt Handler Template (for levels > 1) -// $Id: //depot/main/Xtensa/OS/xtos/inth-template.S#1 $ - -// Copyright (c) 2003-2004, 2006 Tensilica 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. - - -// To use this template file, define a macro called _INTERRUPT_LEVEL -// to be the interrupt priority level of the vector, then include this file. -// The default Makefile defines _INTERRUPT_LEVEL when assembling this file -// for each medium and high priority interrupt level. - - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -#if XCHAL_HAVE_INTERRUPTS - -# if INTERRUPT_IS_HI(_INTERRUPT_LEVEL) - -# if _INTERRUPT_LEVEL > XTOS_LOCKLEVEL - /* Not safe to dispatch interrupts in C above XTOS_LOCKLEVEL, - * so default to assembly high-priority interrupt handlers template - * in this case (with the default XTOS_LOCKLEVEL this never happens): - */ -# include "int-highpri-template.S" -# else - /* Dispatch high-priority interrupt handlers in C: */ -# include "int-highpri-dispatcher.S" -# endif - -# elif INTERRUPT_IS_MED(_INTERRUPT_LEVEL) - -# include "int-medpri-dispatcher.S" - -# elif (_INTERRUPT_LEVEL <= XCHAL_NUM_INTLEVELS) && (_INTERRUPT_LEVEL != XCHAL_DEBUGLEVEL) -# error INTERNAL ERROR: Interrupt priority levels > 1 must be either hi or medium priority! -# endif - -#endif /* XCHAL_HAVE_INTERRUPTS */ diff --git a/src/arch/xtensa/xtos/int-highpri-dispatcher.S b/src/arch/xtensa/xtos/int-highpri-dispatcher.S deleted file mode 100644 index a3c919bd47fd..000000000000 --- a/src/arch/xtensa/xtos/int-highpri-dispatcher.S +++ /dev/null @@ -1,514 +0,0 @@ -// High-Priority Interrupt Dispatcher Template -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/int-highpri-dispatcher.S#1 $ - -// Copyright (c) 2004-2015 Tensilica 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. - -// -// This file allows writing high-priority interrupt handlers in C, -// providing convenience at a significant cost in performance. -// -// By default, this file is included by inth-template.S . -// The default Makefile defines _INTERRUPT_LEVEL when assembling -// inth-template.S for each medium and high priority interrupt level. -// -// To use this template file, define a macro called _INTERRUPT_LEVEL -// to be the interrupt priority level of the vector, then include this file. - - -#if CONFIG_MULTICORE -#include <sof/lib/cpu.h> -#endif -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -#if XCHAL_HAVE_INTERRUPTS && (XCHAL_HAVE_XEA1 || XCHAL_HAVE_XEA2) - -#define INTERRUPT_MASK XCHAL_INTLEVEL_MASK(_INTERRUPT_LEVEL) -#define SINGLE_INTERRUPT ((INTERRUPT_MASK & (INTERRUPT_MASK - 1)) == 0) -#define SINGLE_INT_NUM XCHAL_INTLEVEL_NUM(_INTERRUPT_LEVEL) - - -#define INTLEVEL_N_MASK INTERRUPT_MASK // mask of interrupts at this priority -#define INTLEVEL_N_NUM SINGLE_INT_NUM // interrupt number if there is only one -#define INTLEVEL_N_BELOW_MASK XCHAL_INTLEVEL_ANDBELOW_MASK(_INTERRUPT_LEVEL) - -/* Indicates whether there are multiple interrupts at this interrupt - * priority, ie. mapped to this interrupt vector. - * If there is only one, its number is INTLEVEL_N_NUM - */ -#define MULTIPLE_INTERRUPTS (!SINGLE_INTERRUPT) - -/* - * High priority interrupt stack frame: - */ -STRUCT_BEGIN -STRUCT_FIELD (long,4,HESF_,SAR) -STRUCT_FIELD (long,4,HESF_,WINDOWSTART) -STRUCT_FIELD (long,4,HESF_,WINDOWBASE) -STRUCT_FIELD (long,4,HESF_,EPC1) -STRUCT_FIELD (long,4,HESF_,EXCCAUSE) -STRUCT_FIELD (long,4,HESF_,EXCVADDR) -STRUCT_FIELD (long,4,HESF_,EXCSAVE1) -STRUCT_FIELD (long,4,HESF_,VPRI) /* (XEA1 only) */ -#if XCHAL_HAVE_MAC16 -STRUCT_FIELD (long,4,HESF_,ACCLO) -STRUCT_FIELD (long,4,HESF_,ACCHI) -/*STRUCT_AFIELD(long,4,HESF_,MR, 4)*/ -#endif -#if XCHAL_HAVE_LOOPS -STRUCT_FIELD (long,4,HESF_,LCOUNT) -STRUCT_FIELD (long,4,HESF_,LBEG) -STRUCT_FIELD (long,4,HESF_,LEND) -#endif -STRUCT_AFIELD(long,4,HESF_,AREG, 64) /* address registers ar0..ar63 */ -#define HESF_AR(n) HESF_AREG+((n)*4) -STRUCT_END(HighPriFrame) -#define HESF_TOTALSIZE HighPriFrameSize+32 /* 32 bytes for interrupted code's save areas under SP */ - - -#if XCHAL_HAVE_XEA1 && HAVE_XSR /* could be made true for T1040 and T1050 */ -# error "high-priority interrupt stack frame needs adjustment if HAVE_XSR is allowed with XEA1" -#endif - - -#define PRI_N_STACK_SIZE 1024 /* default to 1 kB stack for each level-N handling */ - - - // Allocate save area and stack: - // (must use .bss, not .comm, because the subsequent .set does not work otherwise) -#if CONFIG_MULTICORE - .macro generate_stack_for_int core_id - .if GREATERTHAN(CONFIG_CORE_COUNT, \core_id) - .section .bss, "aw" - .align 16 -LABEL(_Pri_,_Stack&core_id): .space PRI_N_STACK_SIZE + HESF_TOTALSIZE - .endif - .endm - - generate_stack_for_int 0 - generate_stack_for_int 1 - generate_stack_for_int 2 - generate_stack_for_int 3 -#else - .section .bss, "aw" - .align 16 -LABEL(_Pri_,_Stack): .space PRI_N_STACK_SIZE + HESF_TOTALSIZE -#endif - -#if HAVE_XSR - .data - .global LABEL(_Pri_,_HandlerAddress) -LABEL(_Pri_,_HandlerAddress): .space 4 -#endif - - - .text - .align 4 - .global LABEL(_Level,FromVector) -LABEL(_Level,FromVector): -#if CONFIG_MULTICORE - xtos_stack_addr_percore_add a2, LABEL(_Pri_,_Stack), PRI_N_STACK_SIZE // get ptr to save area -#else - movi a2, LABEL(_Pri_,_Stack) + PRI_N_STACK_SIZE -#endif - // interlock - - // Save a few registers so we can do some work: - s32i a0, a2, HESF_AR(0) -#if HAVE_XSR - //movi a0, LABEL(_Level,FromVector) // this dispatcher's address - movi a0, LABEL(_Pri_,_HandlerAddress) // dispatcher address var. - s32i a1, a2, HESF_AR(1) - l32i a0, a0, 0 // get dispatcher address - s32i a3, a2, HESF_AR(3) - xchgsr excsave _INTERRUPT_LEVEL a0 // get saved a2, restore dispatcher address -#else - readsr excsave _INTERRUPT_LEVEL a0 // get saved a2 - s32i a1, a2, HESF_AR(1) - s32i a3, a2, HESF_AR(3) -#endif - s32i a4, a2, HESF_AR(4) - s32i a0, a2, HESF_AR(2) - - // Save/restore all exception state - // (IMPORTANT: this code assumes no general exceptions occur - // during the execution of this dispatcher until this state - // is completely saved and from the point it is restored.) - // - // Exceptions that may normally occur within the C handler - // include window exceptions (affecting EPC1), alloca exceptions - // (affecting EPC1/EXCCAUSE and its handling uses EXCSAVE1), - // and possibly others depending on the particular C handler - // (possibly needing save/restore of EXCVADDR; and EXCVADDR - // is also possibly corrupted by any access thru an auto-refill - // way on a processor with a full MMU). - // - rsr.epc1 a3 - rsr.exccause a4 - s32i a3, a2, HESF_EPC1 - s32i a4, a2, HESF_EXCCAUSE -#if !XCHAL_HAVE_XEA1 - rsr.excvaddr a3 - s32i a3, a2, HESF_EXCVADDR -#endif - rsr.excsave1 a4 - s32i a4, a2, HESF_EXCSAVE1 - -#ifdef __XTENSA_WINDOWED_ABI__ - // Save remainder of entire address register file (!): - movi a0, XCHAL_NUM_AREGS - 8 // how many saved so far -#endif - - s32i a5, a2, HESF_AR(5) - s32i a6, a2, HESF_AR(6) - s32i a7, a2, HESF_AR(7) - -1: s32i a8, a2, HESF_AR(8) - s32i a9, a2, HESF_AR(9) - s32i a10, a2, HESF_AR(10) - s32i a11, a2, HESF_AR(11) - s32i a12, a2, HESF_AR(12) - s32i a13, a2, HESF_AR(13) - s32i a14, a2, HESF_AR(14) - s32i a15, a2, HESF_AR(15) - -#ifdef __XTENSA_WINDOWED_ABI__ - addi a8, a0, -8 - addi a10, a2, 8*4 - rotw 2 - bnez a0, 1b // loop until done - - rotw 2 - // back to original a2 ... - - // Save a few other registers required for C: - rsr.windowstart a3 - rsr.windowbase a4 - s32i a3, a2, HESF_WINDOWSTART - s32i a4, a2, HESF_WINDOWBASE - - // Setup window registers for first caller: - movi a3, 1 - movi a4, 0 - wsr.windowstart a3 - wsr.windowbase a4 - rsync - - // Note: register window has rotated, ie. a0..a15 clobbered. - -#endif /* __XTENSA_WINDOWED_ABI__ */ - -#if CONFIG_MULTICORE - xtos_stack_addr_percore_add a1, LABEL(_Pri_,_Stack), PRI_N_STACK_SIZE // get ptr to save area -#else - movi a1, LABEL(_Pri_,_Stack) + PRI_N_STACK_SIZE // get ptr to save area -#endif - movi a0, 0 // mark start of call frames in stack - - // Critical state saved, a bit more to do to allow window exceptions... - - // We now have a C-coherent stack and window state. - // Still have to fix PS while making sure interrupts stay disabled - // at the appropriate level (ie. level 2 and below are disabled in this case). - -#if XCHAL_HAVE_XEA1 -#if CONFIG_MULTICORE - xtos_addr_percore a7, xtos_intstruct // address of interrupt management globals -#else - movi a7, _xtos_intstruct // address of interrupt management globals -#endif - rsilft a3, _INTERRUPT_LEVEL, XTOS_LOCKLEVEL // lockout - movi a4, ~INTLEVEL_N_BELOW_MASK // mask out all interrupts at this level or lower - l32i a3, a7, XTOS_VPRI_ENABLED_OFS // read previous _xtos_vpri_enabled - l32i a5, a7, XTOS_ENABLED_OFS // read _xtos_enabled - s32i a4, a7, XTOS_VPRI_ENABLED_OFS // set new _xtos_vpri_enabled (mask interrupts as if at _INTERRUPT_LEVEL) - s32i a3, a1, HESF_VPRI // save previous vpri - movi a2, PS_WOECALL4_ABI + PS_UM // UM=1, INTLEVEL=0 - and a3, a5, a4 // mask out selected interrupts - wsr.intenable a3 // disable all low-priority interrupts -#else - // Load PS for C code, clear EXCM (NOTE: this step is different for XEA1): - movi a2, PS_WOECALL4_ABI + PS_UM + _INTERRUPT_LEVEL // UM=1, INTLEVEL=N, EXCM=0, RING=0 -#endif - wsr.ps a2 // update PS to enable window exceptions, etc as per above - rsync - - // Okay, window exceptions can now happen (although we have to call - // deep before any will happen because we've reset WINDOWSTART). - - // Save other state that might get clobbered by C code: - -////////////////// COMMON DISPATCH CODE BEGIN - - rsr.sar a14 - s32i a14, a1, HESF_SAR -#if XCHAL_HAVE_LOOPS - rsr.lcount a14 - s32i a14, a1, HESF_LCOUNT - rsr.lbeg a14 - s32i a14, a1, HESF_LBEG - rsr.lend a14 - s32i a14, a1, HESF_LEND -#endif -#if XCHAL_HAVE_MAC16 - rsr.acclo a14 - s32i a14, a1, HESF_ACCLO - rsr.acchi a14 - s32i a14, a1, HESF_ACCHI -#endif - -#if MULTIPLE_INTERRUPTS /* > 1 interrupts at this priority */ // _split_ multi_setup -#define TABLE_OFS 0 - - rsr.interrupt a15 // mask of pending interrupts -# if XCHAL_HAVE_XEA1 - l32i a12, a7, XTOS_ENABLED_OFS // mask of enabled interrupts -# else - rsr.intenable a12 // mask of enabled interrupts -# endif - movi a13, INTLEVEL_N_MASK // mask of interrupts at this priority level - and a15, a15, a12 - and a15, a15, a13 // enabled & pending interrupts at this priority - _beqz a15, LABEL(Pri_,_spurious) // handle spurious interrupts (eg. level-trig.) -LABEL(Pri_,_loop): // handle all enabled & pending interrupts - neg a14, a15 - and a14, a14, a15 // single-out least-significant bit set in mask - wsr.intclear a14 // clear if edge-trig. or s/w or wr/err (else no effect) - - // Compute pointer to interrupt table entry, given mask a14 with single bit set: - -# if XCHAL_HAVE_NSA -#if CONFIG_MULTICORE - xtos_addr_percore_sub a12, xtos_interrupt_table, (32-XCHAL_NUM_INTERRUPTS)*8 -#else - movi a12, xtos_interrupt_table - (32-XCHAL_NUM_INTERRUPTS)*8 -#endif - nsau a14, a14 // get index of bit in a14, numbered from msbit - addx8 a12, a14, a12 -# else /* XCHAL_HAVE_NSA */ -#if CONFIG_MULTICORE - xtos_addr_percore a12, xtos_interrupt_table // pointer to interrupt table -#else - movi a12, xtos_interrupt_table // pointer to interrupt table -#endif - bltui a14, 0x10000, 1f // in 16 lsbits? (if so, check them) - addi a12, a12, 16*8 // no, index is at least 16 entries further - // (the above ADDI expands to an ADDI+ADDMI sequence, +128 is outside its range) - extui a14, a14, 16,16 // shift right upper 16 bits -1: bltui a14, 0x100, 1f // in 8 lsbits? (if so, check them) - addi a12, a12, 8*8 // no, index is at least 8 entries further - srli a14, a14, 8 // shift right upper 8 bits -1: bltui a14, 0x10, 1f // in 4 lsbits? (if so, check them) - addi a12, a12, 4*8 // no, index is at least 4 entries further - srli a14, a14, 4 // shift right 4 bits -1: bltui a14, 0x4, 1f // in 2 lsbits? (if so, check them) - addi a12, a12, 2*8 // no, index is at least 2 entries further - srli a14, a14, 2 // shift right 2 bits -1: bltui a14, 0x2, 1f // is it the lsbit? - addi a12, a12, 1*8 // no, index is one entry further -1: // done! a12 points to interrupt's table entry -# endif /* XCHAL_HAVE_NSA */ - -#else /* !MULTIPLE_INTERRUPTS */ - -# if XCHAL_HAVE_NSA -# define TABLE_OFS 8 * (XCHAL_NUM_INTERRUPTS - 1 - INTLEVEL_N_NUM) -# else -# define TABLE_OFS 8 * INTLEVEL_N_NUM -# endif - - movi a13, INTLEVEL_N_MASK // (if interrupt is s/w or edge-triggered or write/err only) -#if CONFIG_MULTICORE - xtos_addr_percore a12, xtos_interrupt_table // get pointer to its interrupt table entry -#else - movi a12, xtos_interrupt_table // get pointer to its interrupt table entry -#endif - wsr.intclear a13 // clear the interrupt (if s/w or edge or wr/err only) - -#endif /* ifdef MULTIPLE_INTERRUPTS */ - - l32i a13, a12, TABLE_OFS + 0 // get pointer to handler from table entry -#ifdef __XTENSA_CALL0_ABI__ - l32i a2, a12, TABLE_OFS + 4 // pass single argument to C handler - callx0 a13 // call interrupt's C handler -#else - l32i a6, a12, TABLE_OFS + 4 // pass single argument to C handler - callx4 a13 // call interrupt's C handler -#endif - -#if XCHAL_HAVE_XEA1 -#if CONFIG_MULTICORE - xtos_addr_percore a7, xtos_intstruct // address of interrupt management globals -#else - movi a7, _xtos_intstruct // address of interrupt management globals -#endif -#endif -#if MULTIPLE_INTERRUPTS /* > 1 interrupts at this priority */ - rsr.interrupt a15 // get pending interrupts -# if XCHAL_HAVE_XEA1 - l32i a12, a7, XTOS_ENABLED_OFS // get enabled interrupts -# else - rsr.intenable a12 // get enabled interrupts -# endif - movi a13, INTLEVEL_N_MASK // get mask of interrupts at this priority level - and a15, a15, a12 - and a15, a15, a13 // pending+enabled interrupts at this priority - _bnez a15, LABEL(Pri_,_loop) // if any remain, dispatch one -LABEL(Pri_,_spurious): -#endif /* MULTIPLE_INTERRUPTS */ - - // Restore everything, and return. - -#if XCHAL_HAVE_EXCLUSIVE - // Clear exclusive monitors. - clrex -#endif - - // Three temp registers are required for this code to be optimal (no interlocks) in - // T2xxx microarchitectures with 7-stage pipe; otherwise only two - // registers would be needed. - // -#if XCHAL_HAVE_LOOPS - l32i a13, a1, HESF_LCOUNT - l32i a14, a1, HESF_LBEG - l32i a15, a1, HESF_LEND - wsr.lcount a13 - wsr.lbeg a14 - wsr.lend a15 -#endif - -#if XCHAL_HAVE_MAC16 - l32i a13, a1, HESF_ACCLO - l32i a14, a1, HESF_ACCHI - wsr.acclo a13 - wsr.acchi a14 -#endif - l32i a15, a1, HESF_SAR - wsr.sar a15 - -////////////////// COMMON DISPATCH CODE END - -#if XCHAL_HAVE_XEA1 - // Here, a7 = address of interrupt management globals - l32i a4, a1, HESF_VPRI // restore previous vpri - rsil a3, XTOS_LOCKLEVEL // lockout - l32i a5, a7, XTOS_ENABLED_OFS // read _xtos_enabled - s32i a4, a7, XTOS_VPRI_ENABLED_OFS // set new _xtos_vpri_enabled - movi a2, 0x00020 + _INTERRUPT_LEVEL // WOE=0, UM=1, INTLEVEL=N - and a3, a5, a4 // mask out selected interrupts - wsr.intenable a3 // disable all low-priority interrupts -#else - // Load PS for interrupt exit, set EXCM: - movi a2, 0x00030 + _INTERRUPT_LEVEL // WOE=0, CALLINC=0, UM=1, INTLEVEL=N, EXCM=1, RING=0 -#endif - wsr.ps a2 // update PS to disable window exceptions, etc as per above - rsync - - // NOTE: here for XEA1, restore INTENABLE etc... - -#ifdef __XTENSA_WINDOWED_ABI__ - // Restore window registers: - l32i a2, a1, HESF_WINDOWSTART - l32i a3, a1, HESF_WINDOWBASE - wsr.windowstart a2 - wsr.windowbase a3 - rsync - // Note: register window has rotated, ie. a0..a15 clobbered. - - // Reload initial stack pointer: -#if CONFIG_MULTICORE - xtos_stack_addr_percore_add a1, LABEL(_Pri_,_Stack), PRI_N_STACK_SIZE // - 16 -#else - movi a1, LABEL(_Pri_,_Stack) + PRI_N_STACK_SIZE // - 16 -#endif - movi a6, XCHAL_NUM_AREGS - 8 // how many saved so far - addi a7, a1, -8*4 - - // Restore entire register file (!): - -1: - addi a14, a6, -8 - addi a15, a7, 8*4 - l32i a4, a15, HESF_AR(4) - l32i a5, a15, HESF_AR(5) - l32i a6, a15, HESF_AR(6) - l32i a7, a15, HESF_AR(7) - l32i a8, a15, HESF_AR(8) - l32i a9, a15, HESF_AR(9) - l32i a10,a15, HESF_AR(10) - l32i a11,a15, HESF_AR(11) - rotw 2 - bnez a6, 1b // loop until done - - l32i a4, a7, HESF_AR(12) - l32i a5, a7, HESF_AR(13) - l32i a6, a7, HESF_AR(14) - l32i a7, a7, HESF_AR(15) - rotw 2 - - // back to original a1 ... - -#else /* Call0 ABI: */ - - l32i a4, a1, HESF_AR(4) // restore general registers - l32i a5, a1, HESF_AR(5) - l32i a6, a1, HESF_AR(6) - l32i a7, a1, HESF_AR(7) - l32i a8, a1, HESF_AR(8) - l32i a9, a1, HESF_AR(9) - l32i a10, a1, HESF_AR(10) - l32i a11, a1, HESF_AR(11) - l32i a12, a1, HESF_AR(12) - l32i a13, a1, HESF_AR(13) - l32i a14, a1, HESF_AR(14) - l32i a15, a1, HESF_AR(15) - -#endif /* __XTENSA_WINDOWED_ABI__ */ - - // Restore exception state: - l32i a2, a1, HESF_EPC1 - l32i a3, a1, HESF_EXCCAUSE - wsr.epc1 a2 - wsr.exccause a3 -#if !XCHAL_HAVE_XEA1 - l32i a2, a1, HESF_EXCVADDR - wsr.excvaddr a2 -#endif - l32i a3, a1, HESF_EXCSAVE1 - wsr.excsave1 a3 - - l32i a0, a1, HESF_AR(0) - l32i a2, a1, HESF_AR(2) - l32i a3, a1, HESF_AR(3) - l32i a1, a1, HESF_AR(1) - rfi _INTERRUPT_LEVEL - - .size LABEL(_Level,FromVector), . - LABEL(_Level,FromVector) - - // This symbol exists solely for the purpose of being able to pull-in this - // dispatcher using _xtos_dispatch_level<n>() routines with the tiny-rt LSP: - .global LABEL(_Level,HandlerLabel) - .set LABEL(_Level,HandlerLabel), 0 - -#endif /* XCHAL_HAVE_INTERRUPTS */ - diff --git a/src/arch/xtensa/xtos/int-highpri-template.S b/src/arch/xtensa/xtos/int-highpri-template.S deleted file mode 100644 index e41cc846c0e6..000000000000 --- a/src/arch/xtensa/xtos/int-highpri-template.S +++ /dev/null @@ -1,160 +0,0 @@ -// High-Priority Interrupt Handler Template -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/int-highpri-template.S#1 $ - -// Copyright (c) 2004-2010 Tensilica 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. - -// -// This file provides skeleton code for writing high-priority interrupt -// handlers in assembler for performance. -// -// By default, this file is included by inth-template.S . -// The default Makefile defines _INTERRUPT_LEVEL when assembling -// inth-template.S for each medium and high priority interrupt level. -// -// To use this template file, define a macro called _INTERRUPT_LEVEL -// to be the interrupt priority level of the vector, then include this file. - - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -#if XCHAL_HAVE_INTERRUPTS - -#define INTERRUPT_MASK XCHAL_INTLEVEL_MASK(_INTERRUPT_LEVEL) -#define SINGLE_INTERRUPT (INTERRUPT_MASK & (INTERRUPT_MASK - 1) == 0) -#define SINGLE_INT_NUM XCHAL_INTLEVEL_NUM(_INTERRUPT_LEVEL) - - -// NOTE: It is strongly recommended that high-priority -// interrupt handlers be written in assembly. -// -// High-priority interrupt handlers can be written in C, -// but only at the cost of an unreasonable amount of state -// save and restore (including the entire physical address -// register file and others, see int-highpri-dispatcher.S) -// that makes high-priority interrupt dispatching much slower -// than for low and medium priority interrupts. -// (Low and medium priority interrupts are masked by atomic -// register window operations, so they take advantage of a -// coherent window state for fast entry. High priority -// interrupts are not masked by window operations so they -// can interrupt them, leading to a potentially incoherent -// window state at the time of the interrupt. Given that -// high priority handlers must save and restore everything -// they touch, they end up needing to save and restore the -// entire window state [physical address register file etc.] -// and all exception state which they can also interrupt.) -// See also the Microprocessor Programmer's Guide. - -// High-priority interrupts are designed to be very fast and with -// very low latency. -// Typical high-priority interrupt service routines are kept -// relatively small and fast. Either there is little to do, -// or the routine handles only the necessary high priority -// activities related to a device and leaves the rest -// (other more complex and time-consuming activities) -// to be scheduled later, eg. by triggering a level-one -// (low-priority) or medium-priority software interrupt whose -// handler can be written in C for the more extensive processing. - -// NOTE: The following handler is just skeleton example -// code. It is NOT a functional handler. For software, edge- -// triggered and write-error interrupts, it simply does nothing -// and return. For other types (timer and level-triggered), -// this code does not clear the source(s) of interrupt, -// hence if any interrupt at this priority level are both enabled -// and triggered, the processor repeatedly takes the interrupt -// in a loop. This is all okay as a default, because -// XTOS (and other operating systems) clears the INTENABLE -// register at startup, requiring the application to -// enable specific interrupts before they can be taken. -// So as long as you don't enable any interrupt of this -// priority level, this example handler will never execute. - -// Exports -.global LABEL(_Level,FromVector) - - .data - .align 4 -LABEL(int,save): - .space 4 // save area - - .text - .align 4 -LABEL(_Level,FromVector): - // The vectoring code has already saved a2 in EXCSAVEn. - // Save any other registers we'll use: - movi a2, LABEL(int,save) - s32i a1, a2, 0 - // ... add more as needed (increase save area accordingly) ... - - // WRITE YOUR INTERRUPT HANDLING CODE HERE... - - // If multiple interrupts are mapped to this priority level, - // you'll probably need to distinguish which interrupt(s) - // occurred by reading the INTERRUPT (INTREAD) and - // INTENABLE registers, and'ing them together, and - // looking at what bits are set in both. - // If any of the interrupts are level-triggered, be ready - // to handle the case where no interrupts are to be handled - // -- this is called a spurious interrupt, and can happen - // when the level-triggered interrupt line goes inactive - // after the interrupt is taken but before the INTERRUPT - // register is read. - - // You'll also normally want to clear the source of - // the interrupt before returning, to avoid getting - // the same interrupt again immediately. For illustration, - // this code clears all software, edge-triggered, and - // write-error interrupts at this priority level (if any). - // NOTE: Timer interrupts must be cleared by writing to - // the corresponding CCOMPAREn register; and level-sensitive - // interrupts can only be cleared externally, usually by - // requesting the associated device to do so (in a - // device-specific manner). - // - movi a1, INTERRUPT_MASK - wsr.intclear a1 - - // Restore registers: - l32i a1, a2, 0 -#if HAVE_XSR - movi a2, LABEL(_Level,FromVector) // restore handler address - xchgsr excsave _INTERRUPT_LEVEL a2 -#else - readsr excsave _INTERRUPT_LEVEL a2 -#endif - // ... add more if more are saved above ... - -#if XCHAL_HAVE_EXCLUSIVE - // If your code used L32EX/S32EX, then clear any active excl monitors. - // Uncomment the line below. - // clrex -#endif - - // Return: - rfi _INTERRUPT_LEVEL - - .size LABEL(_Level,FromVector), . - LABEL(_Level,FromVector) - -#endif /* XCHAL_HAVE_INTERRUPTS */ diff --git a/src/arch/xtensa/xtos/int-initlevel.S b/src/arch/xtensa/xtos/int-initlevel.S deleted file mode 100644 index 1b09f2597439..000000000000 --- a/src/arch/xtensa/xtos/int-initlevel.S +++ /dev/null @@ -1,59 +0,0 @@ -// int-initlevel.S - Routines used to pull-in interrupt dispatch code -// in the tiny-rt LSP. -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/int-initlevel.S#1 $ - -// Copyright (c) 2006-2010 Tensilica 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. - - -// To assemble this template file, define a macro called _INTERRUPT_LEVEL -// to be the interrupt level of the vector. We use the same template for both -// high-level and medium-level interrupts, but not debug level. - - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -#if XCHAL_HAVE_INTERRUPTS && (_INTERRUPT_LEVEL <= XCHAL_NUM_INTLEVELS) && (_INTERRUPT_LEVEL != XCHAL_DEBUGLEVEL) - - // Nothing to do at runtime. This function only has effect - // at link-time. - // - .text - .global LABEL(_xtos_dispatch_level,_interrupts) - .align 4 -LABEL(_xtos_dispatch_level,_interrupts): - abi_entry - abi_return - .size LABEL(_xtos_dispatch_level,_interrupts), . - LABEL(_xtos_dispatch_level,_interrupts) - - // This reference is what does the work of pulling-in the - // relevant interrupt vector at the specified level. - // This is only needed in the tiny-rt LSP. - // -# if _INTERRUPT_LEVEL == 1 - .global _need_level1int_ -# else - .global LABEL(_Level,Vector) -# endif - -#endif /* XCHAL_HAVE_INTERRUPTS */ diff --git a/src/arch/xtensa/xtos/int-medpri-dispatcher.S b/src/arch/xtensa/xtos/int-medpri-dispatcher.S deleted file mode 100644 index e5ea0e930604..000000000000 --- a/src/arch/xtensa/xtos/int-medpri-dispatcher.S +++ /dev/null @@ -1,401 +0,0 @@ -// Medium-Priority Interrupt Dispatcher Template -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/int-medpri-dispatcher.S#1 $ - -// Copyright (c) 2004-2010 Tensilica 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. - -// -// By default, this file is included by inth-template.S . -// The default Makefile defines _INTERRUPT_LEVEL when assembling -// inth-template.S for each medium and high priority interrupt level. -// -// To use this template file, define a macro called _INTERRUPT_LEVEL -// to be the interrupt priority level of the vector, then include this file. - -#include <sof/lib/memory.h> - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -#if XCHAL_HAVE_INTERRUPTS - -#define INTERRUPT_MASK XCHAL_INTLEVEL_MASK(_INTERRUPT_LEVEL) -#define SINGLE_INTERRUPT ((INTERRUPT_MASK & (INTERRUPT_MASK - 1)) == 0) -#define SINGLE_INT_NUM XCHAL_INTLEVEL_NUM(_INTERRUPT_LEVEL) - - -// Strict non-preemptive prioritization - - - .text - .align 4 - .global LABEL(_Level,FromVector) -LABEL(_Level,FromVector): - -/* Allocate an exception stack frame, save a2, a4, and a5, and fix PS as: - * - * if not Call0 ABI - * - enable windowing for 'entry' (ps.woe=1, ps.excm=0) - * - setup ps.callinc to simulate call4 - * endif - * - preserve user mode - * - mask all interrupts at EXCM_LEVEL and lower - * - * Then deallocate the stack, 'rsync' for the write to PS, then use - * 'entry' to re-allocate the stack frame and rotate the register - * window (like a call4, preserving a0..a3). */ - -#if HAVE_XSR - xchgsr excsave _INTERRUPT_LEVEL a2 -#else - readsr excsave _INTERRUPT_LEVEL a2 -#endif - addi a1, a1, -ESF_TOTALSIZE - s32i a2, a1, UEXC_a2 - movi a2, PS_WOECALL4_ABI|PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL) - s32i a4, a1, UEXC_a4 - s32i a5, a1, UEXC_a5 - wsr.ps a2 - rsync - - /* store ps and pc */ - readsr eps, _INTERRUPT_LEVEL a2 - s32i a2, a1, UEXC_ps - readsr epc, _INTERRUPT_LEVEL a2 - s32i a2, a1, UEXC_pc - - /* store rest of the registers */ - s32i a0, a1, UEXC_a0 - s32i a3, a1, UEXC_a3 - s32i a6, a1, UEXC_a6 - s32i a7, a1, UEXC_a7 - s32i a8, a1, UEXC_a8 - s32i a9, a1, UEXC_a9 - s32i a10, a1, UEXC_a10 - s32i a11, a1, UEXC_a11 - s32i a12, a1, UEXC_a12 - s32i a13, a1, UEXC_a13 - s32i a14, a1, UEXC_a14 - s32i a15, a1, UEXC_a15 - - /* store current sp */ - xtos_addr_percore a2, xtos_saved_sp - s32i a1, a2, 0 - - /* store current task sp if context exists (not first irq) */ - xtos_task_ctx_percore a2 - beqz a2, no_context - s32i a1, a2, TC_stack_pointer - -no_context: -# if XTOS_CNEST - l32i a2, a1, ESF_TOTALSIZE-20 // save nested-C-func call-chain ptr -# endif - addi a1, a1, ESF_TOTALSIZE -# if XTOS_DEBUG_PC - readsr epc _INTERRUPT_LEVEL a4 // [for debug] get return PC - movi a5, 0xC0000000 // [for debug] setup call size... - or a4, a5, a4 // [for debug] set upper two bits of return PC - addx2 a4, a5, a4 // [for debug] clear upper bit -# else - movi a4, 0 /* terminate stack frames, overflow check */ -# endif - _entry a1, ESF_TOTALSIZE - -/* Reset the interrupt level to xtos locklevel (lvl 6 on most systems) */ - - rsil a15, XTOS_LOCKLEVEL - -#if SINGLE_INTERRUPT /* if only one interrupt at this priority level... */ - -/* Preserve the SAR, loop, MAC16 regs and coprocessors. Also, clear the interrupt. */ - -#if __XCC__ -#if (XCHAL_CP_MASK & CP0_MASK) - mov a11, a1 - addi a11, a11, UEXC_cp0 - xchal_cp0_store a11, a12, a13, a14, a15 -#endif -#if (XCHAL_CP_MASK & CP1_MASK) - mov a11, a1 - addi a11, a11, UEXC_cp1 - xchal_cp1_store a11, a12, a13, a14, a15 -#endif -#endif - rsr.sar a14 - movi a12, INTERRUPT_MASK - s32i a14, a1, UEXC_sar - wsr.intclear a12 // clear if edge-trig or s/w or wr/err (else no effect) - save_loops_mac16 a1, a13, a14 - - /* switch to interrupt stack */ - xtos_int_stack_addr_percore a13, _INTERRUPT_LEVEL, xtos_stack_for_interrupt - s32i a1, a13, 0 - addi a1, a13, SOF_STACK_SIZE - - /* set stack base and size for interrupt context */ - xtos_addr_percore a11, xtos_interrupt_ctx - s32i a13, a11, TC_stack_base - movi a13, SOF_STACK_SIZE - s32i a13, a11, TC_stack_size - - /* save task context */ - xtos_task_ctx_percore a13 - xtos_store_percore a13, a14, xtos_saved_ctx - - /* set interrupt task context */ - xtos_task_ctx_store_percore a11, a14 - -/* Load the handler from the table, initialize two args (interrupt - * number and exception stack frame), then call the interrupt handler. - * Note: The callx12 preserves the original user task's a4..a15.*/ - - xtos_on_wakeup - -#if CONFIG_MULTICORE - xtos_addr_percore_add a12, xtos_interrupt_table, MAPINT(SINGLE_INT_NUM)*XIE_SIZE -#else - movi a12, xtos_interrupt_table + (MAPINT(SINGLE_INT_NUM) * XIE_SIZE) -#endif - l32i a13, a12, XIE_HANDLER - l32i a14, a12, XIE_ARG - mov a15, a1 - callx12 a13 - -#else /* > 1 interrupts at this priority level */ - -/* Get bit list of pending interrupts at the current interrupt priority level. - * If bit list is empty, interrupt is spurious (can happen if a - * genuine interrupt brings control this direction, but the interrupt - * goes away before we read the INTERRUPT register). Also save off - * sar, loops, mac16 registers and coprocessors. */ - -#if __XCC__ -#if (XCHAL_CP_MASK & CP0_MASK) - mov a11, a1 - addi a11, a11, UEXC_cp0 - xchal_cp0_store a11, a12, a13, a14, a15 -#endif -#if (XCHAL_CP_MASK & CP1_MASK) - mov a11, a1 - addi a11, a11, UEXC_cp1 - xchal_cp1_store a11, a12, a13, a14, a15 -#endif -#endif - rsr.interrupt a15 - rsr.intenable a12 - movi a13, INTERRUPT_MASK - and a15, a15, a12 - and a15, a15, a13 - rsr.sar a14 - s32i a14, a1, UEXC_sar - save_loops_mac16 a1, a13, a14 - - /* switch to interrupt stack */ - xtos_int_stack_addr_percore a13, _INTERRUPT_LEVEL, xtos_stack_for_interrupt - s32i a1, a13, 0 - addi a1, a13, SOF_STACK_SIZE - - _beqz a15, LABEL(spurious,int) - - /* set stack base and size for interrupt context */ - xtos_addr_percore a11, xtos_interrupt_ctx - s32i a13, a11, TC_stack_base - movi a13, SOF_STACK_SIZE - s32i a13, a11, TC_stack_size - - /* save task context */ - xtos_task_ctx_percore a13 - xtos_store_percore a13, a14, xtos_saved_ctx - - /* set interrupt task context */ - xtos_task_ctx_store_percore a11, a14 - - xtos_on_wakeup - -/* Loop to handle all pending interrupts. */ - -LABEL(.L1,_loop0): - neg a12, a15 - and a12, a12, a15 - wsr.intclear a12 // clear if edge-trig or s/w or wr/err (else no effect) -#if CONFIG_MULTICORE - xtos_addr_percore a13, xtos_interrupt_table -#else - movi a13, xtos_interrupt_table -#endif - find_ms_setbit a15, a12, a14, 0 - mapint a15 - addx8 a12, a15, a13 - l32i a13, a12, XIE_HANDLER - l32i a14, a12, XIE_ARG - mov a15, a1 - callx12 a13 - - rsr.interrupt a15 - rsr.intenable a12 - movi a13, INTERRUPT_MASK - and a15, a15, a12 - and a15, a15, a13 - _bnez a15, LABEL(.L1,_loop0) - -#endif /* SINGLE_INTERRUPT */ - -/* Restore everything, and return. */ - - /* restore task context if needed */ - xtos_task_ctx_percore a11 - xtos_addr_percore a12, xtos_interrupt_ctx - bne a11, a12, restore_cp - xtos_addr_percore a12, xtos_saved_ctx - xtos_task_ctx_store_percore a12, a11 - -restore_cp: -#if __XCC__ -#if (XCHAL_CP_MASK & CP0_MASK) - xtos_task_ctx_percore a11 - beqz a11, no_context_2 - l32i a11, a11, TC_stack_pointer - addi a11, a11, UEXC_cp0 - xchal_cp0_load a11, a12, a13, a14, a15 -#endif -#if (XCHAL_CP_MASK & CP1_MASK) - xtos_task_ctx_percore a11 - beqz a11, no_context_2 - l32i a11, a11, TC_stack_pointer - addi a11, a11, UEXC_cp1 - xchal_cp1_load a11, a12, a13, a14, a15 -#endif -#endif - -no_context_2: - restore_loops_mac16 a1, a13, a14, a15 - l32i a14, a1, UEXC_sar -LABEL(spurious,int): - -#if XCHAL_HAVE_EXCLUSIVE - // Clear exclusive monitors. - clrex -#endif - - movi a0, LABEL(return,from_exc) - movi a13, 0xC0000000 - wsr.sar a14 - or a0, a0, a13 - addx2 a0, a13, a0 -# if _INTERRUPT_LEVEL < XCHAL_EXCM_LEVEL -/* Raise the interrupt mask before - * returning to avoid a race condition where we deallocate the - * exception stack frame but still have more register values to - * restore from it. */ - rsil a14, XCHAL_EXCM_LEVEL -# endif - retw -LABEL(return,from_exc): - /* a5 contains interrupt stack pointer */ - addi a5, a5, -SOF_STACK_SIZE - l32i a5, a5, 0 - -# if XTOS_CNEST - s32i a2, a5, ESF_TOTALSIZE-20 // restore nested-C-func call-chain ptr -# endif - - /* store sp after returning from handler */ - s32i a1, a5, UEXC_a1 - -restore: - /* load registers for window spill */ - l32i a4, a5, UEXC_a4 - l32i a6, a5, UEXC_a6 - l32i a7, a5, UEXC_a7 - l32i a8, a5, UEXC_a8 - l32i a9, a5, UEXC_a9 - l32i a10, a5, UEXC_a10 - l32i a11, a5, UEXC_a11 - l32i a12, a5, UEXC_a12 - l32i a13, a5, UEXC_a13 - l32i a14, a5, UEXC_a14 - - /* check if switch is needed */ - xtos_addr_percore a2, xtos_saved_sp - xtos_task_ctx_percore a1 - beqz a1, noSwitch - l32i a1, a1, TC_stack_pointer - l32i a0, a2, 0 - beq a0, a1, noSwitch - -doSwitch: - /* store new task sp */ - s32i a1, a2, 0 - - /* restore sp of task being preempted */ - l32i a1, a5, UEXC_a1 - - /* spill register windows to the stack */ - rsr.ps a2 - movi a3, PS_WOE_MASK - xor a2, a2, a3 - wsr.ps a2 - - call0 xthal_window_spill_nw - - /* restore previous ps */ - rsr.ps a2 - movi a3, PS_WOE_MASK - or a2, a2, a3 - wsr.ps a2 - - /* change stack */ - xtos_addr_percore a5, xtos_saved_sp - l32i a5, a5, 0 - j restore - -noSwitch: - /* restore ps and pc */ - l32i a0, a5, UEXC_ps - writesr eps _INTERRUPT_LEVEL a0 - rsync - l32i a0, a5, UEXC_pc - writesr epc _INTERRUPT_LEVEL a0 - - /* restore sar, loops and mac16 registers */ - l32i a0, a5, UEXC_sar - wsr.sar a0 - restore_loops_mac16 a5, a0, a1, a2 - - /* restore rest of the registers */ - l32i a0, a5, UEXC_a0 - l32i a1, a5, UEXC_a1 - l32i a2, a5, UEXC_a2 - l32i a3, a5, UEXC_a3 - l32i a15, a5, UEXC_a15 - l32i a5, a5, UEXC_a5 - rfi _INTERRUPT_LEVEL - - .size LABEL(_Level,FromVector), . - LABEL(_Level,FromVector) - - // This symbol exists solely for the purpose of being able to pull-in this - // dispatcher using _xtos_dispatch_level<n>() routines with the tiny-rt LSP: - .global LABEL(_Level,HandlerLabel) - .set LABEL(_Level,HandlerLabel), 0 - -#endif /* XCHAL_HAVE_INTERRUPT */ diff --git a/src/arch/xtensa/xtos/int-sethandler.c b/src/arch/xtensa/xtos/int-sethandler.c deleted file mode 100644 index 22737981beea..000000000000 --- a/src/arch/xtensa/xtos/int-sethandler.c +++ /dev/null @@ -1,88 +0,0 @@ - -/* int-sethandler.c - register an interrupt handler in XTOS */ - -/* - * Copyright (c) 1999-2017 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. - */ - -#include "xtos-internal.h" -#include "xtos-structs.h" -#include <sof/lib/cpu.h> - - -#if XCHAL_HAVE_INTERRUPTS -#if CONFIG_MULTICORE -extern struct xtos_core_data *core_data_ptr[CONFIG_CORE_COUNT]; -#else -/* - * Table of interrupt handlers. - * NOTE: if the NSA/NSAU instructions are configured, then to save - * a few cycles in the interrupt dispatcher code, the - * xtos_interrupt_table[] array is filled in reverse. - * IMPORTANT: Use the MAPINT() macro defined in xtos-internal.h to index entries in this array. - */ -extern XtosIntHandlerEntry xtos_interrupt_table[XCHAL_NUM_INTERRUPTS]; -#endif -#endif - -_xtos_handler _xtos_set_interrupt_handler_arg( int n, _xtos_handler f, void *arg ) -{ -#if XCHAL_HAVE_INTERRUPTS - XtosIntHandlerEntry *entry; - _xtos_handler old; - _xtos_handler ret; - - if( (n < 0) || (n >= XCHAL_NUM_INTERRUPTS) ) { - ret = 0; /* invalid interrupt number */ - } - else if( (int) Xthal_intlevel[n] > XTOS_LOCKLEVEL ) { - ret = 0; /* priority level too high to safely handle in C */ - } - else { -#if CONFIG_MULTICORE - entry = &(core_data_ptr[cpu_get_id()]->xtos_int_data.xtos_interrupt_table.array[MAPINT(n)]); -#else - entry = xtos_interrupt_table + MAPINT(n); -#endif - old = entry->handler; - if (f) { - entry->handler = f; - entry->u.varg = arg; - } else { - entry->handler = &xtos_unhandled_interrupt; - entry->u.narg = n; - } - ret = (old == &xtos_unhandled_interrupt) ? 0 : old; - } - - return ret; -#else - return 0; -#endif -} - - -_xtos_handler _xtos_set_interrupt_handler( int n, _xtos_handler f ) -{ - return _xtos_set_interrupt_handler_arg( n, f, (void *) n ); -} - diff --git a/src/arch/xtensa/xtos/int-vector.S b/src/arch/xtensa/xtos/int-vector.S deleted file mode 100644 index f23ad50844b7..000000000000 --- a/src/arch/xtensa/xtos/int-vector.S +++ /dev/null @@ -1,70 +0,0 @@ -// int-vector.S - Interrupt Vector Template (for levels > 1) -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/int-vector.S#1 $ - -// Copyright (c) 2003-2017 Tensilica 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. - - -// To use this template file, define a macro called _INTERRUPT_LEVEL -// to be the interrupt level of the vector, include "xtos-internal.h", -// then include this file. We use the same template for both high-level -// and medium-level interrupts, but not debug level. - - -#define _ASMLANGUAGE -#include "xtos-internal.h" -#include <xtensa/coreasm.h> -#include <xtensa/config/system.h> - - -#if XCHAL_HAVE_INTERRUPTS && (_INTERRUPT_LEVEL <= XCHAL_NUM_INTLEVELS) && (_INTERRUPT_LEVEL != XCHAL_DEBUGLEVEL) - - .begin literal_prefix LABEL(.Level,InterruptVector) - .section LABEL(.Level,InterruptVector.text), "ax" - .align 4 - .global LABEL(_Level,Vector) -LABEL(_Level,Vector): - // Medium and high priority interrupt vector: - -# if HAVE_XSR - // With XSR, we can use this vector which has the advantage of being ROMable - // without requiring the handler to also be in ROM; however, it requires - // initializing the EXCSAVEn register (see reset-vector.S) and a slightly - // different save/restore sequence in the handler: - hw_erratum_487_fix - xchgsr excsave _INTERRUPT_LEVEL a2 - jx a2 - - // Pull-in the real handler by reference, to ensure the reset vector gets it: - .global LABEL(_Level,FromVector) - -# else - writesr excsave _INTERRUPT_LEVEL a2 - movi a2, LABEL(_Level,FromVector) - jx a2 -# endif - - .size LABEL(_Level,Vector), . - LABEL(_Level,Vector) - .text - .end literal_prefix - -#endif /* interrupt at that level */ - diff --git a/src/arch/xtensa/xtos/interrupt-pri.h b/src/arch/xtensa/xtos/interrupt-pri.h deleted file mode 100644 index ae22cd2b5761..000000000000 --- a/src/arch/xtensa/xtos/interrupt-pri.h +++ /dev/null @@ -1,177 +0,0 @@ -/* interrupt-pri.h - Definitions and macros related to interrupt prioritization */ -/* - * Copyright (c) 2002-2004, 2006 Tensilica 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. - */ - -#if !defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__) -# error "The interrupt-pri.h header file is meant for inclusion by assembly source code only." -#endif - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - -/* - * The following macros are used by int-lowpri-dispatcher.S to - * implement prioritized interrupt dispatching and fairness. - * The prioritization scheme is set by XTOS parameters in xtos-params.h . - */ - - -#if XCHAL_HAVE_INTERRUPTS - - // msindex_int - // - // Return in register \aindex the index of the first (most significant) bit set - // in register \amask. - // Register \amask is clobbered (modified) by this macro. - // - // Note: this code is similar to the find_ms_setbit macro in <xtensa/coreasm.h>. - // - .macro msindex_int aindex, amask -# if XCHAL_HAVE_NSA - nsau \aindex, \amask // \aindex = interrupt index, from 0 to 31, from left to right - //movi \amask, 31 - //sub \aindex, \amask, \aindex -# else - movi \aindex, 0 // start with result of 0 (point to lsbit of 32) -# if XCHAL_NUM_INTERRUPTS > 16 - bltui \amask, 0x10000, 2f // is it one of the 16 lsbits? (if so, check lower 16 bits) - addi \aindex, \aindex, 16 // no, increment result to upper 16 bits (of 32) - extui \amask, \amask, 16, 16 // check upper half (shift right 16 bits) -2: -# endif -# if XCHAL_NUM_INTERRUPTS > 8 - bltui \amask, 0x100, 2f // is it one of the 8 lsbits? (if so, check lower 8 bits) - addi \aindex, \aindex, 8 // no, increment result to upper 8 bits (of 16) - srli \amask, \amask, 8 // shift right to check upper 8 bits -2: -# endif -# if XCHAL_NUM_INTERRUPTS > 4 - bltui \amask, 0x10, 2f // is it one of the 4 lsbits? (if so, check lower 4 bits) - addi \aindex, \aindex, 4 // no, increment result to upper 4 bits (of 8) - srli \amask, \amask, 4 // shift right 4 bits to check upper half -2: -# endif - bltui \amask, 0x4, 2f // is it one of the 2 lsbits? (if so, check lower 2 bits) - addi \aindex, \aindex, 2 // no, increment result to upper 2 bits (of 4) - srli \amask, \amask, 2 // shift right 2 bits to check upper half -2: - bltui \amask, 0x2, 2f // is it the lsbit? - addi \aindex, \aindex, 1 // no, increment result to upper bit (of 2) -2: // done! -# endif /*!NSA*/ - // HERE: \aindex = index of interrupt to handle - // \amask is available - .endm - - - // msindex_int_nc - // - // Same as msindex_int, but does not clobber \amask. - // Uses extra register \atmp (a temporary register) if needed. - // - .macro msindex_int_nc aindex, amask, atmp -# if XCHAL_HAVE_NSA - msindex_int \aindex, \amask // does not clobber \amask in this case -# else - mov \atmp, \amask - msindex_int \aindex, \atmp -# endif - .endm - - - // indexmask_int - // - // Compute index of highest priority interrupt in given mask, - // and trim mask to single bit corresponding to that interrupt. - // This is used for interrupt dispatching. - // - // Entry: - // \index = (undefined) - // \mask = non-zero mask of interrupt bits to consider handling - // \intptr = &_xtos_intstruct if INTENABLE virtualized, else undefined - // \tmp = (undefined) - // Exit: - // \index = index of interrupt (reversed if NSA present) - // \mask = single bit corresponding to index - // \intptr = (preserved) - // \tmp = (clobbered) - // - .macro indexmask_int index, mask, intptr, tmp -# if XTOS_SUBPRI_ORDER == XTOS_SPO_ZERO_LO - - msindex_int \index, \mask // \index = index of msbit set in \mask (\tmp is tmp, \mask clobbered) - // \index now contains the index of the highest priority pending+enabled interrupt. -# if XCHAL_HAVE_NSA - movi \mask, 0x80000000 - ssr \index - srl \mask, \mask // \mask = single bit set corresponding to interrupt to be processed... -# else - movi \mask, 1 - ssl \index - sll \mask, \mask // \mask = single bit set corresponding to interrupt to be processed... -# endif - -# elif XTOS_SUBPRI_ORDER == XTOS_SPO_ZERO_HI - - neg \index, \mask // find lsbit in \mask ... - and \mask, \index, \mask // ... - msindex_int_nc \index, \mask, \tmp // \index = index of msbit set in \mask (\tmp is tmp, \mask not clobbered) - -# else -# error Unsupported priority ordering. -# endif /*SUBPRI_ORDER*/ - .endm - - - // index_int - // - // Compute index of highest priority interrupt in given mask. - // This is used for fairness computations. - // - // Entry: - // \index = (undefined) - // \mask = non-zero mask of interrupt bits to consider handling - // \intptr = &_xtos_intptr - // \tmp = (undefined) - // Exit: - // \index = index of interrupt (reversed if NSA present) - // \mask = (preserved) - // \intptr = (preserved) - // \tmp = (clobbered) - // - .macro index_int index, mask, intptr, tmp -# if XTOS_SUBPRI_ORDER == XTOS_SPO_ZERO_LO - msindex_int_nc \index, \mask, \tmp // \index = index of msbit set in \mask (\mask not clobbered) -# elif XTOS_SUBPRI_ORDER == XTOS_SPO_ZERO_HI - neg \tmp, \mask // find lsbit in \mask ... - and \tmp, \tmp, \mask // ... - msindex_int \index, \tmp // \index = index of msbit set in \tmp (\tmp is clobbered) -# else -# error oops -# endif - .endm // index_int - - -#endif /* XCHAL_HAVE_INTERRUPTS */ - - diff --git a/src/arch/xtensa/xtos/interrupt-table.S b/src/arch/xtensa/xtos/interrupt-table.S deleted file mode 100644 index 795a0a53cb04..000000000000 --- a/src/arch/xtensa/xtos/interrupt-table.S +++ /dev/null @@ -1,129 +0,0 @@ -// interrupt-table.S - Interrupt handler table and default handler - -// Copyright (c) 2004-2017 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. - - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - -#if !CONFIG_MULTICORE -#if XCHAL_HAVE_INTERRUPTS - - .data - - .global _xtos_intstruct - .align 8 -_xtos_intstruct: -# if XTOS_VIRTUAL_INTENABLE - .global _xtos_enabled - .type _xtos_enabled,@object - .size _xtos_enabled,4 - .global _xtos_vpri_enabled - .type _xtos_vpri_enabled,@object - .size _xtos_vpri_enabled,4 -_xtos_enabled: .word 0 -_xtos_vpri_enabled: .word 0xFFFFFFFF -# endif -# if XTOS_VIRTUAL_INTERRUPT -# error Virtualized INTERRUPT register not yet supported. - .global _xtos_pending - .type _xtos_pending,@object - .size _xtos_pending,4 -_xtos_pending: .word 0 -# endif - - /* - * Table of C-level interrupt handlers (and args, etc) for each interrupt. - * NOTE: if the NSA/NSAU instructions are configured, then to save a few - * cycles in the interrupt dispatcher code, this table is filled in reverse. - * C code uses the MAPINT() macro defined in xtos-internal.h to index entries. - * NOTE: Under some conditions (turned off by default in xtos-params.h), - * this table gets properly initialized by the _xtos_init() function in - * init.c . NOTA: A future enhancement may be to always configure - * and build this table at build-time rather than ever doing it at run-time. - */ -#define i .Li /* workaround a silly GDB testsuite regression */ - .data - .global xtos_interrupt_table - .align 8 -xtos_interrupt_table: - .set i, XCHAL_HAVE_NSA*(XCHAL_NUM_INTERRUPTS-1) - .rept XCHAL_NUM_INTERRUPTS - .word xtos_unhandled_interrupt - .word i // parameter: interrupt number - .set i, i+1-(XCHAL_HAVE_NSA*2) - .endr - -# if XIE_EXTEND - /* MUST *IMMEDIATELY* follow xtos_interrupt_table: */ - .global xtos_interrupt_mask_table -xtos_interrupt_mask_table: - .set i, XCHAL_HAVE_NSA*(XCHAL_NUM_INTERRUPTS-1) - .rept XCHAL_NUM_INTERRUPTS - /* Default to all low-priority (level-one) interrupts at their own virtual priority: */ -# if XTOS_SUBPRI_ORDER == XTOS_SPO_ZERO_HI - .word ((1<<i)-1) | ~XCHAL_LOWPRI_MASK // vpri_mask default - lower-numbered ints (and high/medium-pri ints) pre-empt other low-pri ints -# else - .word (-2*(1<<i)) | ~XCHAL_LOWPRI_MASK // vpri_mask default - higher-numbered ints (and high/medium-pri ints) pre-empt other low-pri ints -# endif - .word (1<<i) // level_mask default - each low-pri (level-one) interrupt at its own subpriority - .set i, i+1-(XCHAL_HAVE_NSA*2) - .endr -# endif /*XIE_EXTEND*/ - -#endif /* XCHAL_HAVE_INTERRUPTS */ - - .text -#endif /* CONFIG_MULTICORE */ - -#if XCHAL_HAVE_INTERRUPTS - - // - // void xtos_unhandled_interrupt( int n ); - // - // Default/empty interrupt handler. - // This is used for interrupts with no registered handler. - // Parameter n is the interrupt number (0 thru 31). - // - - .text - .align 4 - .global xtos_unhandled_interrupt - .type xtos_unhandled_interrupt,@function - -xtos_unhandled_interrupt: - abi_entry -# if XCHAL_HAVE_DEBUG - // Break into the debugger if one is present and active: -# if XCHAL_NUM_INTLEVELS > XCHAL_DEBUGLEVEL - rsil a3, XCHAL_DEBUGLEVEL-1 // ensure break takes effect -# endif - break 1, 15 // unhandled (unregistered) interrupt $a2 -# else -1: j 1b // unhandled interrupt - loop forever -# endif - abi_return - - .size xtos_unhandled_interrupt, . - xtos_unhandled_interrupt - -#endif /* XCHAL_HAVE_INTERRUPTS */ - diff --git a/src/arch/xtensa/xtos/ints-off.S b/src/arch/xtensa/xtos/ints-off.S deleted file mode 100644 index 66b851f58593..000000000000 --- a/src/arch/xtensa/xtos/ints-off.S +++ /dev/null @@ -1,78 +0,0 @@ -// ints-off.S - Interrupt related assembler code - _xtos_ints_off - -// Copyright (c) 2004-2015 Tensilica 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. - - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -/*************************************************************************** - * _xtos_ints_on() and _xtos_ints_off() are used - * to enable and disable interrupts from C code; - * they can be called from the application or from a C interrupt handler. - */ - -// u32 _xtos_ints_off( u32 mask ); [T1050.0 docs this as returning old INTENABLE value] -// Disables a set of interrupts. See _xtos_ints_on(). -// -// MUST NOT be called when PS.INTLEVEL > XTOS_LOCKLEVEL -// (otherwise PS.INTLEVEL gets lowered; and operation may be inconsistent -// if this is called in the handler of an interrupt of level > LOCKLEVEL). -// - .text - .align 4 - .global _xtos_ints_off - .type _xtos_ints_off,@function -_xtos_ints_off: - abi_entry -#if XCHAL_HAVE_INTERRUPTS && (XCHAL_HAVE_XEA1 || XCHAL_HAVE_XEA2) -# if XTOS_VIRTUAL_INTENABLE -#if CONFIG_MULTICORE - xtos_addr_percore a4, xtos_intstruct -#else - movi a4, _xtos_intstruct -#endif - xtos_lock a7 // MUST USE highest address register of function to avoid window overflows in critical section - l32i a3, a4, XTOS_ENABLED_OFS // a3 = xtos_enabled - l32i a6, a4, XTOS_VPRI_ENABLED_OFS // a6 = xtos_vpri_enabled - or a5, a3, a2 // a5 = xtos_enabled | mask - xor a5, a5, a2 // a5 = xtos_enabled & ~mask - s32i a5, a4, XTOS_ENABLED_OFS // xtos_enabled &= ~mask - and a5, a5, a6 // a5 = xtos_enabled & xtos_vpri_enabled -# else - xtos_lock a7 // MUST USE highest address register of function to avoid window overflows in critical section - rsr.intenable a3 - //interlock - or a5, a3, a2 // a5 = INTENABLE | mask - xor a5, a5, a2 // a5 = INTENABLE & ~mask -# endif - wsr.intenable a5 - xtos_unlock a7 - mov a2, a3 // return previous (virtual or real) INTENABLE value -#else /*XCHAL_HAVE_INTERRUPTS*/ - movi a2, 0 // this config does not have interrupts, so return 0 -#endif /*XCHAL_HAVE_INTERRUPTS*/ - abi_return - - .size _xtos_ints_off, . - _xtos_ints_off - diff --git a/src/arch/xtensa/xtos/ints-on.S b/src/arch/xtensa/xtos/ints-on.S deleted file mode 100644 index 0e6acc8deb64..000000000000 --- a/src/arch/xtensa/xtos/ints-on.S +++ /dev/null @@ -1,79 +0,0 @@ -// ints-on.S - Interrupt related assembler code - _xtos_ints_on - -// Copyright (c) 2004-2015 Tensilica 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. - - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - - -/*************************************************************************** - * _xtos_ints_on() and _xtos_ints_off() are used - * to enable and disable interrupts from C code; - * they can be called from the application or from a C interrupt handler. - */ - - -// u32 _xtos_ints_on( u32 mask ); -// Enables a set of interrupts. -// With INTENABLE virtualizing, does not simply set INTENABLE directly, but rather -// computes it as a function of the current virtual priority. -// -// MUST NOT be called when PS.INTLEVEL > XTOS_LOCKLEVEL -// (otherwise PS.INTLEVEL gets lowered; and operation may be inconsistent -// if this is called in the handler of an interrupt of level > LOCKLEVEL). -// - .text - .align 4 - .global _xtos_ints_on - .type _xtos_ints_on,@function -_xtos_ints_on: - abi_entry -#if XCHAL_HAVE_INTERRUPTS && (XCHAL_HAVE_XEA1 || XCHAL_HAVE_XEA2) -# if XTOS_VIRTUAL_INTENABLE -#if CONFIG_MULTICORE - xtos_addr_percore a4, xtos_intstruct -#else - movi a4, _xtos_intstruct -#endif - xtos_lock a7 // MUST USE highest address register of function to avoid window overflows in critical section - l32i a3, a4, XTOS_ENABLED_OFS // a3 = xtos_enabled - l32i a6, a4, XTOS_VPRI_ENABLED_OFS // a6 = xtos_vpri_enabled - or a5, a3, a2 // xtos_enabled | mask - s32i a5, a4, XTOS_ENABLED_OFS // xtos_enabled |= mask - and a5, a5, a6 // a5 = xtos_enabled & xtos_vpri_enabled -# else - xtos_lock a7 // MUST USE highest address register of function to avoid window overflows in critical section - rsr.intenable a3 - //interlock - or a5, a3, a2 // INTENABLE | mask -# endif - wsr.intenable a5 - xtos_unlock a7 - mov a2, a3 // return previous (virtual or real) INTENABLE value -#else /*XCHAL_HAVE_INTERRUPTS*/ - movi a2, 0 // this config does not have interrupts, so return 0 -#endif /*XCHAL_HAVE_INTERRUPTS*/ - abi_return - - .size _xtos_ints_on, . - _xtos_ints_on - diff --git a/src/arch/xtensa/xtos/kernel-vector.S b/src/arch/xtensa/xtos/kernel-vector.S deleted file mode 100644 index 3f86b0ea4857..000000000000 --- a/src/arch/xtensa/xtos/kernel-vector.S +++ /dev/null @@ -1,73 +0,0 @@ -// kernel-vector.S - Kernel Vector for General Exceptions -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/kernel-vector.S#1 $ - -// Copyright (c) 1999-2015 Tensilica 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. - -/* - * General exceptions in kernel vector mode (PS.UM==0) go to this kernel - * vector. This kernel vector does very little. - * Under normal operation of the single-threaded runtime ("XTOS"), kernel - * vectored general exceptions do not occur, so nothing needs to be done. - * However when debugging, such as when writing exception and - * interrupt handlers, kernel vectored exceptions may occur. - * They are usually the sign of a bug, so here we take a breakpoint - * (if debug option enabled) or take drastic action (infinite loop) - * otherwise. - * - * XTOS does not allow exceptions in interrupt or exception handlers. - * If it did, a more elaborate kernel vector handler would be needed. - * See the Xtensa Microprocessor Programmer's Guide for an - * example of how to implement such a kernel vector handler. - */ - -#include <xtensa/coreasm.h> -#include <xtensa/config/system.h> -#ifdef SIMULATOR -#include <xtensa/simcall.h> -#endif - -#if XCHAL_HAVE_EXCEPTIONS && (XCHAL_HAVE_XEA1 || XCHAL_HAVE_XEA2) - - .begin literal_prefix .KernelExceptionVector - .section .KernelExceptionVector.text, "ax" - - .align 4 - .global _KernelExceptionVector -_KernelExceptionVector: - -# if XCHAL_HAVE_DEBUG -1: break 1,0 // unexpected kernel exception -# elif defined(SIMULATOR) - wsr a2, EXCSAVE1 // save a2 where simulator expects it - movi a2, SYS_unhandled_kernel_exc -1: simcall // let simulator/debugger report unhandled exception -# else -1: -# endif - j 1b // infinite loop - unexpected kernel exception - - .size _KernelExceptionVector, . - _KernelExceptionVector - .text - .end literal_prefix - -#endif /* XCHAL_HAVE_EXCEPTIONS */ - diff --git a/src/arch/xtensa/xtos/memctl_default.S b/src/arch/xtensa/xtos/memctl_default.S deleted file mode 100644 index 164f2c2d2f58..000000000000 --- a/src/arch/xtensa/xtos/memctl_default.S +++ /dev/null @@ -1,42 +0,0 @@ -// memctl_default.S - Default startup value for MEMCTL register. - -// Copyright (c) 1998-2015 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. - - -#include <xtensa/coreasm.h> -#include <xtensa/config/system.h> - - -// This file just contains this one symbol, used by the reset code. -// It is here rather than in reset-vector.S because we want the symbol -// to be external, so resolution is delayed until link time. -// -// To define your own value to override this default, redefine the -// symbol __memctl_default to the desired value, e.g. - -// -// xt-xcc test.c -g -o test -Wl,--defsym=__memctl_default=0x08080808 -// - - .global __memctl_default - .weak __memctl_default - .equ __memctl_default, XCHAL_CACHE_MEMCTL_DEFAULT - diff --git a/src/arch/xtensa/xtos/memep-enable.S b/src/arch/xtensa/xtos/memep-enable.S deleted file mode 100644 index c3724204675c..000000000000 --- a/src/arch/xtensa/xtos/memep-enable.S +++ /dev/null @@ -1,63 +0,0 @@ -// memep-enable.S -- Turn on local memory ECC/parity checking -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/memep-enable.S#1 $ - -// Copyright (c) 2006-2010 Tensilica 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. - -#include <xtensa/coreasm.h> - - - /* - * void _xtos_memep_enable(int flags); - * - * Turn on local memory ECC/parity checking, for both - * data access and instruction fetch. - * - * For now, flags are ignored. Caller is expected to pass zero. - * - * _xtos_memep_initrams() must have already been called, if necessary, - * to ensure all ECC/parity bits are valid in any local instruction - * or data RAM. The normal reset vector sequence already takes care - * of initializing any local cache ECC/parity bits. - */ - .text - .align 4 - .global _xtos_memep_enable -_xtos_memep_enable: - abi_entry - -#if XCHAL_HAVE_MEM_ECC_PARITY - - // Local Memory ECC/Parity option initialization - // - // NOTE: We turn on exceptions on correctable errors and correct - // them in the memory error handler. - movi a2, MESR_ERRENAB | MESR_DATEXC | MESR_INSEXC - wsr a2, MESR - isync - -#endif /* XCHAL_HAVE_MEM_ECC_PARITY */ - - movi a2, 0 // successfully turned on what we could - abi_return - - .size _xtos_memep_enable, . - _xtos_memep_enable - diff --git a/src/arch/xtensa/xtos/memep-initrams.S b/src/arch/xtensa/xtos/memep-initrams.S deleted file mode 100644 index 8cc399e55c59..000000000000 --- a/src/arch/xtensa/xtos/memep-initrams.S +++ /dev/null @@ -1,91 +0,0 @@ -// memep-initrams.S -- Initialize local memory ECC/parity -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/memep-initrams.S#1 $ - -// Copyright (c) 2006-2010 Tensilica 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. - -#include <xtensa/coreasm.h> - - - /* - * void _xtos_memep_initrams(void); - * - * Most reset vectors initialize caches, leaving only the local memories - * (instruction and data RAMs) with potentially some words that have - * not been written to and thus have uninitialized ECC/parity bits. - * Loading such a word after enabling ECC/parity checking would result - * in an exception (or memory error reported in MESR). To avoid this, - * an application must either carefully avoid loading from uninitialized - * words, or ensure it writes to every instruction and data RAM word. - * The latter is what this function does. It reads and writes every - * word of every local instruction and data RAM. It should normally - * be called with interrupts disabled. An interrupt might come in - * between a load and store, in which case any modification made by the - * interrupt handler to that local memory location is lost when this - * function resumes and does the store. If no interrupt handler makes - * any persistent modification to local memories, disabling them around - * a call to this function may be unnecessary. - * - * On the simulator (ISS), everything comes up zeroed, so no there is - * no need for this initialization. - */ - .text - .align 4 - .global _xtos_memep_initrams -_xtos_memep_initrams: - abi_entry - - // Local Memory ECC/Parity option initialization -#if XCHAL_HAVE_MEM_ECC_PARITY && (XCHAL_NUM_DATARAM || XCHAL_NUM_INSTRAM /*|| XCHAL_NUM_URAM || XCHAL_NUM_XLMI*/) && !defined(SIMULATOR) - .section .rodata, "a" - .align 4 -.L_locmemep_start: -# if XCHAL_NUM_DATARAM >= 1 && XCHAL_DATARAM0_ECC_PARITY - .long XCHAL_DATARAM0_VADDR, XCHAL_DATARAM0_VADDR+XCHAL_DATARAM0_SIZE -# endif -# if XCHAL_NUM_DATARAM >= 2 && XCHAL_DATARAM1_ECC_PARITY - .long XCHAL_DATARAM1_VADDR, XCHAL_DATARAM1_VADDR+XCHAL_DATARAM1_SIZE -# endif -# if XCHAL_NUM_INSTRAM >= 1 && XCHAL_INSTRAM0_ECC_PARITY - .long XCHAL_INSTRAM0_VADDR, XCHAL_INSTRAM0_VADDR+XCHAL_INSTRAM0_SIZE -# endif -# if XCHAL_NUM_INSTRAM >= 2 && XCHAL_INSTRAM1_ECC_PARITY - .long XCHAL_INSTRAM1_VADDR, XCHAL_INSTRAM1_VADDR+XCHAL_INSTRAM1_SIZE -# endif -.L_locmemep_end: - .text - movi a5, .L_locmemep_start // start of table of local memory ranges - movi a6, .L_locmemep_end // end of table ... -2: l32i a3, a5, 0 // start of local memory - l32i a4, a5, 4 // end of local memory - addi a5, a5, 8 // (next entry in table) -1: l32i a2, a3, 0 // load and store every word of local memory... - s32i a2, a3, 0 // ... to initialize all parity and/or ECC bits - addi a3, a3, 4 - bltu a3, a4, 1b // loop until whole memory initialized - bltu a5, a6, 2b // loop until all memories initialized - // ECC/parity bits are now initialized, checking can be turned on. -#endif /* ECC/parity on instruction or data RAM(s) */ - - abi_return - - .size _xtos_memep_initrams, . - _xtos_memep_initrams - diff --git a/src/arch/xtensa/xtos/memerror-vector.S b/src/arch/xtensa/xtos/memerror-vector.S deleted file mode 100644 index 460b58ac997b..000000000000 --- a/src/arch/xtensa/xtos/memerror-vector.S +++ /dev/null @@ -1,581 +0,0 @@ -/* memerror-vector.S -- Memory Error Exception Vector and Handler */ - -/* $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/memerror-vector.S#1 $ */ - -/* - * Copyright (c) 2006-2013 Tensilica 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. - */ - - -/* - * This handler supports multiple user hooks to handle various cases. - * This is the list of available hooks: - * - * _xtos_merr_hook_fatal_dme -- fatal error, double memory exception - * _xtos_merr_hook_uncorrectable_local -- fatal error, uncorrectable error in IRAM/DRAM - * _xtos_merr_hook_uncor_dtag -- fatal error, uncorrectable error in dcache tag - * _xtos_merr_hook_uncor_dirty -- fatal error, uncorrectable error in dirty dcache data - * _xtos_merr_hook_icache_relock -- non-fatal, hook to relock icache - * _xtos_merr_hook_dcache_relock -- non-fatal, hook to relock dcache - * _xtos_merr_hook_nonfatal -- non-fatal, correctable error - */ - - -#include <xtensa/coreasm.h> -#include <xtensa/corebits.h> - -#if XCHAL_HAVE_MEM_ECC_PARITY -# if defined(__SPLIT__vector) - - // Place this code in the memory error exception vector: - .begin literal_prefix .MemoryExceptionVector - .section .MemoryExceptionVector.text, "ax" - - .global _MemErrorVector - .align 4 -_MemErrorVector: -# if 0 /* XCHAL_HAVE_DEBUG */ - // Memory errors raise PS.INTLEVEL above DEBUGLEVEL, so - // break instructions have no effect within them (debug - // exceptions are masked). So leave commented out for now. - break 1, 5 // unhandled memory error exception -# endif - xsr.mesave a0 - jx a0 - - .size _MemErrorVector, . - _MemErrorVector - .text - .end literal_prefix - - -# elif defined(__SPLIT__handler) - -/* - * Some rules and assumptions: - * - * Anything that can interrupt this handler (e.g. NMI): - * - must not lock or unlock cache lines - */ - - -#define ICACHE_WAYWIDTH (XCHAL_ICACHE_SETWIDTH + XCHAL_ICACHE_LINEWIDTH) /* LICT's "iis" */ -#define DCACHE_WAYWIDTH (XCHAL_DCACHE_SETWIDTH + XCHAL_DCACHE_LINEWIDTH) /* LDCT's "dis" */ -/* NOTE: Memory ECC/parity is not supported on XLMI or on local ROMs: */ -#define HAVE_LOCAL_RAM (XCHAL_NUM_DATARAM || XCHAL_NUM_INSTRAM /*|| XCHAL_NUM_URAM || XCHAL_NUM_XLMI*/) - - -#if XCHAL_DCACHE_LINE_LOCKABLE && XCHAL_DCACHE_WAYS > 1 && XCHAL_HAVE_PREFETCH - .comm _MemErrorSave, 12, 4 -#else - //.lcomm _MemErrorSave, 8 - .comm _MemErrorSave, 8, 4 -#endif - - .text - .align 4 - .global _MemErrorHandler -_MemErrorHandler: - hw_erratum_487_fix - rsr.mesr a0 - bbsi.l a0, MESR_DME_SHIFT, .L_fatal_dme -# if XCHAL_ICACHE_SIZE > 0 || XCHAL_DCACHE_SIZE > 0 - bbsi.l a0, MESR_MEMTYPE_SHIFT+1, .L_cache // branch if error on a cache -# endif - // Error in a local memory. -# if HAVE_LOCAL_RAM - bbsi.l a0, MESR_ERRTYPE_SHIFT, .L_uncorrectable_local - // Correctable error in a local memory (IRAM or DRAM). - // (MEVADDR has all 32 bits, so XSR preserves a register:) - xsr.mevaddr a2 - // Note: MEVADDR is always 4-byte aligned, - // so we can just do L32I/S32I to correct the error. - // However, that's not atomic, and NMI can store in between; - // that's usually a problem for D rather than I, avoid the - // issue using S32C1I if configured (else NMI must not write DataRAM!?!): -# if (XCHAL_HAVE_S32C1I && (XCHAL_NUM_DATARAM /*|| XCHAL_NUM_URAM || XCHAL_NUM_XLMI*/)) - bbci.l a0, MESR_MEMTYPE_SHIFT, .L_instram // branch if error on InstRAM - // Unfortunately we need 3 registers to do S32C1I (data,addr,SCOMPARE1) so - // we need to save to _MemErrorSave: - movi a0, _MemErrorSave - s32i a4, a0, 0 // save a4 - l32i a4, a2, 0 // load data (re-correct) - rsr.scompare1 a0 // save SCOMPARE1 - wsr.scompare1 a4 - s32c1i a4, a2, 0 // store if still contains same value (else other store corrected error) - movi a4, _MemErrorSave - wsr.scompare1 a0 // restore SCOMPARE1 - l32i a4, a4, 0 // restore a4 - j 2f -.L_instram: -# endif - l32i a0, a2, 0 // load data (re-correct) - s32i a0, a2, 0 // store data to correct ECC bits -2: xsr.mevaddr a2 -# endif /* HAVE_LOCAL_RAM */ - - - // Weak reference: if unresolved, links okay but with zero value: - // - // This hook must return using a RET instruction. It will receive - // the return address in a0, and the MESR register value in a2. - // The hook may use and trash a2 and a3, but all other registers - // must be preserved. - - .weak _xtos_merr_hook_nonfatal - -.L_done: - // Finished, now see if there is a user hook to call before returning - movi a0, _xtos_merr_hook_nonfatal // hook address - beqz a0, 1f // no hook, return - movi a0, _MemErrorSave // save area address - s32i a2, a0, 0 // save a2 - s32i a3, a0, 4 // save a3 - movi a0, _xtos_merr_hook_nonfatal // re-load hook address - rsr.mesr a2 // pass MESR value as arg - callx0 a0 // call user hook - movi a3, _MemErrorSave - l32i a2, a3, 0 // restore a2 - l32i a3, a3, 4 // restore a3 -1: movi a0, _MemErrorHandler // handler address - xsr.mesave a0 // restore a0 and MESAVE - rfme - - - // Weak reference: if unresolved, links okay but with zero value: - .weak _xtos_merr_hook_fatal_dme -.L_fatal_dme: - // Fatal (unrecoverable) error, double memory exception - movi a0, _xtos_merr_hook_fatal_dme -1: beqz a0, 1b // fatal double memory error, no hook, so infinite loop - jx a0 // jump to user hook, if present - - -# if HAVE_LOCAL_RAM - // Weak reference: if unresolved, links okay but with zero value: - .weak _xtos_merr_hook_uncorrectable_local -.L_uncorrectable_local: - // Fatal (unrecoverable) error in IRAM or DRAM: parity or uncorrectable ECC error - movi a0, _xtos_merr_hook_uncorrectable_local -1: beqz a0, 1b // fatal memory error, no hook provided, so infinite loop - jx a0 // jump to user hook, if present -# endif - - -# if XCHAL_ICACHE_SIZE > 0 || XCHAL_DCACHE_SIZE > 0 -.L_cache: - // Error in one of the caches. -# endif - -# if XCHAL_ICACHE_SIZE > 0 && XCHAL_HAVE_ICACHE_TEST -# if XCHAL_DCACHE_SIZE > 0 && XCHAL_HAVE_DCACHE_TEST - bbsi.l a0, MESR_MEMTYPE_SHIFT, .L_dcache // branch if data cache error -# endif - // Error in the instruction cache. - bbsi.l a0, MESR_ERRTYPE_SHIFT, .L_icache_noncorr // branch if uncorrectable - // Correctable error in the instruction cache. - xsr.mevaddr a2 - // TODO FIXME: remove these 5 lines if waynum is in MEVADDR!? by using III if tag and IHI otherwise!?!?!?: -# if XCHAL_ICACHE_WAYS > 1 - extui a0, a0, MESR_WAYNUM_SHIFT, 2 - slli a0, a0, ICACHE_WAYWIDTH - slli a2, a2, 32 - ICACHE_WAYWIDTH - srli a2, a2, 32 - ICACHE_WAYWIDTH - or a2, a2, a0 -# endif -# if XCHAL_ICACHE_LINE_LOCKABLE - // Preserve the lock bit. So check the tag... - lict a0, a2 // load i-cache tag - bbci.l a0, XCHAL_ICACHE_TAG_L_SHIFT, .L_icache_corr_unlocked // branch if unlocked - // Correctable error in a locked instruction cache line. - // Fix both tag and one word, quicker than figuring out whether error is in tag or data: - sict a0, a2 // fix tag - // TODO FIXME: on fetch wider than 32-bits, SICW might replicate its 32 bits to the - // whole fetch width rather than just write 32-bits, depending on how customer wires up - // I-cache RAMs. With ECC option and I-cache locking, they need 32-bit word write enables. - licw a0, a2 - sicw a0, a2 // fix data word - j .L_icache_done -.L_icache_corr_unlocked: - // We have to write the whole tag to avoid hitting an error here (if tag error). - // So use IIU (which also invalidates) not III (which reads L bit so can hit error). - iiu a2, 0 // unlock line ==> also invalidates! (I-side only) -# else - iii a2, 0 // invalidate line (whole set!) -# endif -.L_icache_done: - xsr.mevaddr a2 - j .L_done - -.L_icache_noncorr: - // Non-correctable error in the instruction cache. - bbsi.l a0, MESR_MEMTYPE_SHIFT+2, .L_icache_tag_noncorr // branch if tag error - // Non-correctable error in the instruction cache data. - // Just invalidate the line if we can. -# if XCHAL_ICACHE_LINE_LOCKABLE - // If locked, need a different fix sequence. - xsr.mevaddr a2 - -# if XCHAL_ICACHE_WAYS > 1 - // This sequence is shorter, but does not retain original MEVADDR so - // prevents subsequent use of instructions requiring a virtual address - // (such as LICW, IPFL, etc): -// extui a0, a0, MESR_WAYNUM_SHIFT, 2 -// slli a0, a0, ICACHE_WAYWIDTH -// slli a2, a2, 32 - ICACHE_WAYWIDTH -// srli a2, a2, 32 - ICACHE_WAYWIDTH -// or a2, a2, a0 - - extui a0, a0, MESR_WAYNUM_SHIFT, 2 // id of way with mem error - slli a0, a0, ICACHE_WAYWIDTH - xor a0, a2, a0 // xor corresponding bits of addr - extui a0, a0, ICACHE_WAYWIDTH, 2 // take 2 xor'ed way bits - or a2, a2, a0 // save them at bottom of addr - slli a0, a0, ICACHE_WAYWIDTH - xor a2, a2, a0 // and change 2 way bits of addr -# endif - lict a0, a2 - bbsi.l a0, XCHAL_ICACHE_TAG_L_SHIFT, .L_icache_locked_uncor // branch if locked - // Cache line is not locked, just invalidate: -# if XCHAL_ICACHE_WAYS > 1 - iii a2, 0 -# else - ihi a2, 0 -# endif - j .L_icache_done - - // NOTE: we don't use the LICW/SICW sequence below unless the line is locked, - // otherwise the i-cache line might get replaced between LICW and SICW - // (if we're not extremely careful), which would be disastrous. - // Also, for locked lines, LICW/SICW is much safer than IHU/IHI/IPFL - // because it doesn't leave a window where the line is unlocked; - // however, if the error is non-correctable, we have no choice. - -.L_icache_locked_uncor: - // If locked and uncorrectable however, the only recourse is relocking. - // So we need to recover the virtual address so we can do IPFL. - // Note: can't use MEPC instead of MEVADDR, because (a) it might not - // point to the correct cache line, and (b) it might be completely wrong - // in the case where the mem error happened e.g. during an LICW or IPFL. -# if XCHAL_ICACHE_WAYS > 1 - // Recover virtual address in a2: - extui a0, a2, 0, 2 // get saved xor'ed bits at bottom - slli a0, a0, ICACHE_WAYWIDTH // line them up - xor a2, a2, a0 // restore original MEVADDR -# endif - ihu a2, 0 // unlock line - ihi a2, 0 // invalidate line - ipfl a2, 0 // refetch-and-lock the line - j .L_icache_done -# else /* LOCKABLE */ - rsr.mevaddr a0 - ihi a0, 0 // invalidate that cache line - j .L_done -# endif /* LOCKABLE */ - -.L_icache_tag_noncorr: - // Non-correctable error in the instruction cache tag. - // Just invalidate the tag or the entire set. -# if XCHAL_ICACHE_LINE_LOCKABLE - // Note: - // With i-cache locking, IIU writes the entire tag without mem-error check, - // and III writes part of it (leaves lock bit alone) so can hit errors. - // Without i-cache locking, III writes the entire tag without mem-error check. - // (Original assumption was that SICT is needed.) -# if XCHAL_ICACHE_WAYS > 1 - // TODO FIXME: avoid this 8-line alternative if waynum is in MEVADDR!?: - xsr.mevaddr a2 - extui a0, a0, MESR_WAYNUM_SHIFT, 2 - slli a0, a0, ICACHE_WAYWIDTH - slli a2, a2, 32 - ICACHE_WAYWIDTH - srli a2, a2, 32 - ICACHE_WAYWIDTH - or a2, a2, a0 - iiu a2, 0 // unlock line ==> also invalidates! (I-side only) - xsr.mevaddr a2 -# else - rsr.mevaddr a0 - iiu a0, 0 // unlock line ==> also invalidates! (I-side only) -# endif - // If line was locked, can't recover lock state, need external info to recover. - // User can provide an assembler hook routine _xtos_merr_hook_icache_relock - // to relock the icache at the index in a2: - // - any number of lines might still be locked at that index, - // including all of them - // - no stack is provided, a0 must be used as starting point to - // load a save area and saved registers as necessary - // - unless routine just does ret (i.e. does not modify any - // register, only possible if it does nothing), it needs to - // return by restoring all registers it modified, ending with: - // movi a0, _MemErrorHandler - // xsr.mesave a0 - // rfme - // CAVEAT EMPTOR: this hook mechanism is subject to change. - .weak _xtos_merr_hook_icache_relock // if unresolved, links with zero value - movi a0, _xtos_merr_hook_icache_relock -1: beqz a0, 1b // if no hook to recover lock state on icache tag mem error, loop forever - callx0 a0 // invoke user hook to relock i-cache (index in MEVADDR) -# else - rsr.mevaddr a0 - iii a0, 0 // invalidate entire set -# endif - j .L_done -# endif /* have ICACHE */ - - -# if XCHAL_DCACHE_SIZE > 0 && XCHAL_HAVE_DCACHE_TEST -# if XCHAL_ICACHE_SIZE > 0 && XCHAL_HAVE_ICACHE_TEST -.L_dcache: -# endif - // Error in the data cache. -# if XCHAL_DCACHE_IS_WRITEBACK || XCHAL_DCACHE_LINE_LOCKABLE - bbsi.l a0, MESR_ERRTYPE_SHIFT, .L_dcache_noncorr // branch if uncorrectable - // Uncorrectable error on a writeback dcache might be unrecoverable: -# endif - bbsi.l a0, MESR_MEMTYPE_SHIFT+2, .L_dcache_tag // branch if tag error - // Error in the data cache data (correctable, or non-correctable in writethru+unlockable cache). - // MEVADDR always a real vaddr here; might point to cache-isolate mode area though. -# if XCHAL_DCACHE_LINE_LOCKABLE - // Correctable error on lockable dcache data. - // If locked, need to refetch the line (or load/store its contents, which is less safe): - xsr.mevaddr a2 -# if XCHAL_DCACHE_WAYS > 1 - // Need some extra computation to get the correct dcache way's tag: - movi a0, _MemErrorSave - s32i a4, a0, 0 // save a4 - s32i a5, a0, 4 // save a5 -# if XCHAL_HAVE_PREFETCH - s32i a6, a0, 8 // save a6 - movi a6, 0 - xsr.prefctl a6 // disable prefetch during LDCT (issue TENX-24760) -# endif - rsr.mesr a4 - extui a4, a4, MESR_WAYNUM_SHIFT, 2 - slli a4, a4, DCACHE_WAYWIDTH - slli a5, a2, 32 - DCACHE_WAYWIDTH - srli a5, a5, 32 - DCACHE_WAYWIDTH - add a4, a4, a5 - mov a5, a0 - ldct a0, a4 - l32i a4, a5, 0 // restore a4 -# if XCHAL_HAVE_PREFETCH - wsr.prefctl a6 // restore prefetch - l32i a6, a5, 8 // restore a6 -# endif - l32i a5, a5, 4 // restore a5 -# else -# if XCHAL_HAVE_PREFETCH - movi a0, _MemErrorSave - s32i a4, a0, 0 // save a4 - movi a4, 0 - xsr.prefctl a4 // disable prefetch during LDCT (issue TENX-24760) -# endif - ldct a0, a2 // invalidate and unlock that cache tag -# if XCHAL_HAVE_PREFETCH - wsr.prefctl a4 // restore prefetch - movi a4, _MemErrorSave - l32i a4, a4, 0 // restore a4 -# endif -# endif - // FIXME: if castout, a2 is a cache index (see PR 24103), from which - // we can construct a physical address! need that paddr reconstruction, - // and doesn't work with any address translation. -# if 0 /* translation */ - movi a4, _xtos_vmap_vaddr // FIXME: do we need two variables for full MMU? -1: beqz a4, 1b // if no vaddr to use, loop forever (FIXME: caxlt: could assume V==P) - rdtlb1 a5, a4 // save current contents - ... clear lower bits of a4 ... - xx = some function of a2 - wdtlb xx, a4 - a2 = virtual address, i.e. some function of a2 and a4 ... - ... do the sequence below ... - ... - wdtlb a5, a4 // restore TLB entry -# endif - // NOTE: the following sequence leaves the line temporarily unlocked, if locked. - // We assume NMI handlers don't lock lines or rely on their being locked. - // We could have used "l32i a0,a2,0; s32i a0,a2,0" but that's not atomic on the data. - dhu a2, 0 // unlock the cache line, if locked - dhwbi a2, 0 // writeback and invalidate cache line - bbci.l a0, XCHAL_DCACHE_TAG_L_SHIFT, 1f - dpfl a2, 0 // re-prefetch-and-lock the cache line -1: xsr.mevaddr a2 -# else /* LOCKABLE */ - // Error in unlockable data cache data (correctable, or non-correctable in writethru cache). - rsr.mevaddr a0 - // USELESS NOTE: if writethru dcache and NMI handlers don't store to this, we could use DHI instead: - // FIXME: if castout, a0 is a physical address! doesn't work with any address translation. - dhwbi a0, 0 // writeback (if correctable) and invalidate that cache line -# endif /* LOCKABLE */ - j .L_done - -.L_dcache_tag: - // Error in data cache tag (correctable, or non-correctable in writethru+unlockable cache). - // MEVADDR only contains cache index here (not waynum), don't expect a vaddr (the ISA - // says upper bits are undefined; actual hw does put a vaddr, but in future might not). - // Whether or not correctable, just invalidate the particular way's line: - xsr.mevaddr a2 - // NOTE: could remove these 5 lines if hw were designed with waynum in MEVADDR (but is not): -# if XCHAL_DCACHE_WAYS > 1 - extui a0, a0, MESR_WAYNUM_SHIFT, 2 - slli a0, a0, DCACHE_WAYWIDTH - slli a2, a2, 32 - DCACHE_WAYWIDTH - srli a2, a2, 32 - DCACHE_WAYWIDTH - or a2, a2, a0 -# endif -# if XCHAL_DCACHE_LINE_LOCKABLE -# if XCHAL_HAVE_PREFETCH - movi a0, _MemErrorSave - s32i a4, a0, 0 // save a4 - movi a4, 0 - xsr.prefctl a4 // disable prefetch during LDCT (issue TENX-24760) -# endif - ldct a0, a2 // invalidate and unlock that cache tag -# if XCHAL_HAVE_PREFETCH - wsr.prefctl a4 // restore prefetch - movi a4, _MemErrorSave - l32i a4, a4, 0 // restore a4 -# endif - bbci.l a0, XCHAL_DCACHE_TAG_L_SHIFT, 1f // branch if not locked - sdct a0, a2 // if locked, this safely writes whole tag -# endif -1: diwbi a2, 0 // writeback (if correctable) and invalidate the line - xsr.mevaddr a2 - j .L_done - - - -# if XCHAL_DCACHE_IS_WRITEBACK || XCHAL_DCACHE_LINE_LOCKABLE -.L_dcache_noncorr: - // Uncorrectable error on a (writeback and/or lockable) data cache. -# if XCHAL_DCACHE_IS_WRITEBACK - // On tag errors we don't know whether the line is dirty, so this is unrecoverable: - bbsi.l a0, MESR_MEMTYPE_SHIFT+2, .L_uncorrectable_dtag // branch if tag error - // Castouts are by definition dirty, uncorrectable errors on these are unrecoverable: - bbsi.l a0, MESR_ACCTYPE_SHIFT, .L_uncorrectable_dirty // branch if castout - // Note: could still be an error on dirty dcache data, also unrecoverable. -# else - bbsi.l a0, MESR_MEMTYPE_SHIFT+2, .L_dcache_tag_noncorr // branch if tag error -# endif - // Uncorrectable error in dcache data. - // May be dirty or locked, so get tag to find out. - xsr.mevaddr a2 -# if XCHAL_DCACHE_WAYS > 1 - extui a0, a0, MESR_WAYNUM_SHIFT, 2 // id of way with mem error - slli a0, a0, DCACHE_WAYWIDTH - xor a0, a2, a0 // xor corresponding bits of addr - extui a0, a0, DCACHE_WAYWIDTH, 2 // take 2 xor'ed way bits - or a2, a2, a0 // save them at bottom of addr - slli a0, a0, DCACHE_WAYWIDTH - xor a2, a2, a0 // and change 2 way bits of addr -# endif -# if XCHAL_HAVE_PREFETCH - movi a0, _MemErrorSave - s32i a4, a0, 0 // save a4 - movi a4, 0 - xsr.prefctl a4 // disable prefetch during LDCT (issue TENX-24760) -# endif - ldct a0, a2 // get dcache tag -# if XCHAL_HAVE_PREFETCH - wsr.prefctl a4 // restore prefetch - movi a4, _MemErrorSave - l32i a4, a4, 0 // restore a4 -# endif -# if XCHAL_DCACHE_IS_WRITEBACK - bbsi.l a0, XCHAL_DCACHE_TAG_D_SHIFT, .L_uncorrectable_dirty_2 // branch if dirty -# endif - // Data cache line is clean. -# if XCHAL_DCACHE_LINE_LOCKABLE - bbsi.l a0, XCHAL_DCACHE_TAG_L_SHIFT, .L_dcache_nc_locked -# endif - // Data cache line is clean and unlocked. Just invalidate it. - // FIXME: any stores to this line by an NMI handler will be lost. - // On the other hand, if we use DHWBI, any stores by an NMI handler - // that don't happen to fix the error result in an unrecoverable castout. - // -# if XCHAL_DCACHE_WAYS > 1 - // Recover virtual address in a2: - extui a0, a2, 0, 2 // get saved xor'ed bits at bottom - slli a0, a0, DCACHE_WAYWIDTH // line them up - xor a2, a2, a0 // restore original MEVADDR -# endif - dhi a2, 0 // invalidate that data cache line - xsr.mevaddr a2 - j .L_done - -# if XCHAL_DCACHE_LINE_LOCKABLE -.L_dcache_nc_locked: -# if XCHAL_DCACHE_WAYS > 1 - // Recover virtual address in a2: - extui a0, a2, 0, 2 // get saved xor'ed bits at bottom - slli a0, a0, DCACHE_WAYWIDTH // line them up - xor a2, a2, a0 // restore original MEVADDR -# endif - // Unlock, invalidate, and relock it: - dhu a2, 0 // unlock that data cache line - dhi a2, 0 // invalidate that data cache line - dpfl a2, 0 // prefetch-and-lock the line again - xsr.mevaddr a2 - j .L_done -# endif - -# if XCHAL_DCACHE_IS_WRITEBACK - // Weak reference: if unresolved, links okay but with zero value: - .weak _xtos_merr_hook_uncor_dtag -.L_uncorrectable_dtag: - // Fatal (unrecoverable) error in dcache tag (maybe dirty): parity or uncorrectable ECC error - movi a0, _xtos_merr_hook_uncor_dtag -1: beqz a0, 1b // fatal non-corr dcache tag, no hook, so infinite loop - jx a0 // jump to user hook, if present - - // Weak reference: if unresolved, links okay but with zero value: - .weak _xtos_merr_hook_uncor_dirty -.L_uncorrectable_dirty_2: - xsr.mevaddr a2 -.L_uncorrectable_dirty: - // Fatal (unrecoverable) error, parity or non-correctable ECC error on dirty cache data - movi a0, _xtos_merr_hook_uncor_dirty -1: beqz a0, 1b // fatal non-corr dirty cache line, no hook, so infinite loop - jx a0 // jump to user hook, if present -# else -.L_dcache_tag_noncorr: - // Uncorrectable error on a lockable writethru data cache tag. - // We have to invalidate the line, but that way we lose the lock bit. - // Provide a hook to relock if necessary (using knowledge outside this module - // about what needs to be locked). See _xtos_merr_hook_icache_relock for details. - // CAVEAT EMPTOR: this hook mechanism is subject to change. - .weak _xtos_merr_hook_dcache_relock // if unresolved, links with zero value - movi a0, _xtos_merr_hook_dcache_relock -1: beqz a0, 1b // if no hook to recover lock state on dcache tag mem error, loop forever - callx0 a0 // invoke user hook to relock d-cache (index in MEVADDR) - j .L_done -# endif - -# endif /* DCACHE IS WRITEBACK || LINE_LOCKABLE */ - -# endif /* have DCACHE */ - - .size _MemErrorHandler, . - _MemErrorHandler - - - -# endif /* splitting */ -#endif /* XCHAL_HAVE_MEM_ECC_PARITY */ - diff --git a/src/arch/xtensa/xtos/nmi-vector.S b/src/arch/xtensa/xtos/nmi-vector.S deleted file mode 100644 index 637dcda96940..000000000000 --- a/src/arch/xtensa/xtos/nmi-vector.S +++ /dev/null @@ -1,60 +0,0 @@ -// nmi-vector.S -- Standalone NMI Interrupt Vector/Handler -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/nmi-vector.S#1 $ - -// Copyright (c) 2003, 2006, 2010 Tensilica 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. - -// The NMI exception vector handles non-maskable interrupts. - -#include <xtensa/coreasm.h> -#include <xtensa/config/system.h> - -#if XCHAL_HAVE_NMI - - .begin literal_prefix .NMIExceptionVector - .section .NMIExceptionVector.text, "ax" - - .align 4 - .global _NMIExceptionVector -_NMIExceptionVector: - -// Insert any custom NMI handling code here. -// For example: -// writesr excsave XCHAL_NMILEVEL a0 -// movi a0, ...address of some save area specific to this code... -// s32i a1, a0, 0 // save whatever registers are needed -// : -// do something useful ... -// : -// l32i a1, a0, 0 // restore whatever registers were saved -// readsr excsave XCHAL_NMILEVEL a0 -// -// This default NMI handler does not do anything. It just returns -// immediately upon any occurrence of a non-maskable interrupt. - - rfi XCHAL_NMILEVEL - - .size _NMIExceptionVector, . - _NMIExceptionVector - .text - .end literal_prefix - -#endif /* XCHAL_HAVE_NMI */ - diff --git a/src/arch/xtensa/xtos/null-syscall.S b/src/arch/xtensa/xtos/null-syscall.S deleted file mode 100644 index fb53cf948865..000000000000 --- a/src/arch/xtensa/xtos/null-syscall.S +++ /dev/null @@ -1,38 +0,0 @@ -// null-syscall.S - Stub for Unused SYSCALL Handler -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/null-syscall.S#1 $ - -// Copyright (c) 2006-2010 Tensilica 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. - - - // Redirect SYSCALL exceptions as not handled, when - // that functionality is not needed. Done this way, a user can - // just specify this small handler to override the default one. - - .text - .weak xtos_unhandled_exception - .global _xtos_syscall_handler -_xtos_syscall_handler: - movi a3, xtos_unhandled_exception -1: beqz a3, 1b - jx a3 - .size _xtos_syscall_handler, . - _xtos_syscall_handler - diff --git a/src/arch/xtensa/xtos/null-vectors.S b/src/arch/xtensa/xtos/null-vectors.S deleted file mode 100644 index 0bb274d690c1..000000000000 --- a/src/arch/xtensa/xtos/null-vectors.S +++ /dev/null @@ -1,184 +0,0 @@ -// null-vectors.S - Stubs for Unused Vectors and Handlers -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/null-vectors.S#1 $ - -// Copyright (c) 2006-2010 Tensilica 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. - - -// NOTE: The simulator version of this file is currently not used, -// i.e. the SIMULATOR macro is never defined when assembling this file. -// The relevant simulator code is left here for illustrative purposes only. - - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" -#ifdef SIMULATOR -#include <xtensa/simcall.h> -#endif - - // These are just tiny non-functional vectors and handlers for when - // their functionality is not being used. They just try to signal - // the debugger that an unhandled exception or interrupt occurred, - // and otherwise just spin in a loop. - // - // For interrupts levels above DEBUGLEVEL, lowering PS.INTLEVEL - // for break to work is tricky, and not always possible in a - // generic fashion without interfering with normal program execution. - // So for now we don't do it. - - -#if defined(__SPLIT__user) - -# if XCHAL_HAVE_EXCEPTIONS - .begin literal_prefix .UserExceptionVector - .section .UserExceptionVector.text, "ax" - .align 4 - .global _UserExceptionVector -_UserExceptionVector: -# if XCHAL_HAVE_DEBUG - break 1, 1 // unexpected user-vectored general exception -# endif -1: j 1b // infinite loop - unexpected user-vectored exception - .size _UserExceptionVector, . - _UserExceptionVector - .end literal_prefix -# endif - -#elif defined(__SPLIT__level1int) - - .text - .global _xtos_l1int_handler -_xtos_l1int_handler: - movi a3, xtos_unhandled_exception - jx a3 - .size _xtos_l1int_handler, . - _xtos_l1int_handler - -#elif defined(__SPLIT__level2) - -# if (XCHAL_NUM_INTLEVELS >= 2) && (XCHAL_DEBUGLEVEL != 2) - .begin literal_prefix .Level2InterruptVector - .section .Level2InterruptVector.text, "ax" - .align 4 - .global _Level2Vector -_Level2Vector: -# if XCHAL_HAVE_DEBUG && (XCHAL_DEBUGLEVEL > 2) - break 1, 2 // unexpected high-priority interrupt -# elif defined(SIMULATOR) - wsr a2, EXCSAVE_2 - movi a2, SYS_unhandled_highpri_interrupt - simcall // let simulator/debugger report unhandled level-2 interrupt -# endif -1: j 1b // infinite loop - unexpected level-2 interrupt - .size _Level2Vector, . - _Level2Vector - .text - .end literal_prefix -# endif /* level 2 */ - - -#elif defined(__SPLIT__level3) - -# if (XCHAL_NUM_INTLEVELS >= 3) && (XCHAL_DEBUGLEVEL != 3) - .begin literal_prefix .Level3InterruptVector - .section .Level3InterruptVector.text, "ax" - .align 4 - .global _Level3Vector -_Level3Vector: -# if XCHAL_HAVE_DEBUG && (XCHAL_DEBUGLEVEL > 3) - break 1, 2 // unexpected high-priority interrupt -# elif defined(SIMULATOR) - wsr a2, EXCSAVE_3 - movi a2, SYS_unhandled_highpri_interrupt - simcall // let simulator/debugger report unhandled level-3 interrupt -# endif -1: j 1b // infinite loop - unexpected level-3 interrupt - .size _Level3Vector, . - _Level3Vector - .text - .end literal_prefix -# endif /* level 3 */ - - -#elif defined(__SPLIT__level4) - -# if (XCHAL_NUM_INTLEVELS >= 4) && (XCHAL_DEBUGLEVEL != 4) - .begin literal_prefix .Level4InterruptVector - .section .Level4InterruptVector.text, "ax" - .align 4 - .global _Level4Vector -_Level4Vector: -# if XCHAL_HAVE_DEBUG && (XCHAL_DEBUGLEVEL > 4) - break 1, 2 // unexpected high-priority interrupt -# elif defined(SIMULATOR) - wsr a2, EXCSAVE_4 - movi a2, SYS_unhandled_highpri_interrupt - simcall // let simulator/debugger report unhandled level-4 interrupt -# endif -1: j 1b // infinite loop - unexpected level-4 interrupt - .size _Level4Vector, . - _Level4Vector - .text - .end literal_prefix -# endif /* level 4 */ - - -#elif defined(__SPLIT__level5) - -# if (XCHAL_NUM_INTLEVELS >= 5) && (XCHAL_DEBUGLEVEL != 5) - .begin literal_prefix .Level5InterruptVector - .section .Level5InterruptVector.text, "ax" - .align 4 - .global _Level5Vector -_Level5Vector: -# if XCHAL_HAVE_DEBUG && (XCHAL_DEBUGLEVEL > 5) - break 1, 2 // unexpected high-priority interrupt -# elif defined(SIMULATOR) - wsr a2, EXCSAVE_5 - movi a2, SYS_unhandled_highpri_interrupt - simcall // let simulator/debugger report unhandled level-5 interrupt -# endif -1: j 1b // infinite loop - unexpected level-5 interrupt - .size _Level5Vector, . - _Level5Vector - .text - .end literal_prefix -# endif /* level 5 */ - - -#elif defined(__SPLIT__level6) - -# if (XCHAL_NUM_INTLEVELS >= 6) && (XCHAL_DEBUGLEVEL != 6) - .begin literal_prefix .Level6InterruptVector - .section .Level6InterruptVector.text, "ax" - .align 4 - .global _Level6Vector -_Level6Vector: -# if XCHAL_HAVE_DEBUG && (XCHAL_DEBUGLEVEL > 6) - break 1, 2 // unexpected high-priority interrupt -# elif defined(SIMULATOR) - wsr a2, EXCSAVE_6 - movi a2, SYS_unhandled_highpri_interrupt - simcall // let simulator/debugger report unhandled level-6 interrupt -# endif -1: j 1b // infinite loop - unexpected level-6 interrupt - .size _Level6Vector, . - _Level6Vector - .text - .end literal_prefix -# endif /* level 6 */ - - -#endif /* split */ - diff --git a/src/arch/xtensa/xtos/reset-unneeded.S b/src/arch/xtensa/xtos/reset-unneeded.S deleted file mode 100644 index e662a5856a75..000000000000 --- a/src/arch/xtensa/xtos/reset-unneeded.S +++ /dev/null @@ -1,156 +0,0 @@ -// reset-unneeded.S -- Optional Extraneous Reset Code -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/reset-unneeded.S#1 $ - -// Copyright (c) 2002-2006 Tensilica 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. - -// This file is meant to be included by another, e.g. crt1-***.S . -// The code it contains is generally not needed, so is kept in a -// separate file for clarity of other code. - -#if XTOS_RESET_UNNEEDED - /* - * Reset registers that don't really need to be reset, - * but may provide more predictability when buggy code - * relies on uninitialized state. It might also clear - * "X"s a bit earlier in hardware simulations. - * - * NOTE: This code is by no means exhaustive. - * More processor registers/states could be reset if desired. - * This is just an example. - * - * ASSUMPTION: a0 is still zero at this point. - */ - - // Interrupt initialization. - // Because INTENABLE is cleared by the reset vector, clearing the - // interrupt-pending register should not be needed. This assumes - // that any application setting up an interrupt will register and - // clear it before enabling it, which is the recommended sequence. - // -#if XCHAL_HAVE_INTERRUPTS && (XCHAL_INTCLEARABLE_MASK != 0) && !XCHAL_HAVE_FULL_RESET - movi a2, XCHAL_INTCLEARABLE_MASK - wsr a2, INTCLEAR // clear software and edge-trig ints -#endif - - // Timer initialization (not strictly required, but sometimes helpful) - .macro reset_timer num - wsr a0, CCOMPARE_0 + \num - .endm - iterate 0, XCHAL_NUM_TIMERS-1, reset_timer - -# if XCHAL_HAVE_WINDOWED - // Windowed address register init -- initialize entire physical AR file - movi a0, XCHAL_NUM_AREGS/8 // number of 8-register chunks -arloop: - addi a8, a0, -1 // countdown into next chunk's a0 - movi a0, 0 - movi a1, 0 - movi a2, 0 - movi a3, 0 - movi a4, 0 - movi a5, 0 - movi a6, 0 - movi a7, 0 - rotw 2 // rotate to next chunk - bnez a0, arloop - // NOTE: WINDOWBASE is back to zero at this point. -# else /* XCHAL_HAVE_WINDOWED */ - // Non-windowed address register init - movi a1, 0 - movi a2, 0 - movi a3, 0 - movi a4, 0 - movi a5, 0 - movi a6, 0 - movi a7, 0 - movi a8, 0 - movi a9, 0 - movi a10, 0 - movi a11, 0 - movi a12, 0 - movi a13, 0 - movi a14, 0 - movi a15, 0 -# endif /* XCHAL_HAVE_WINDOWED */ - // Now all address registers are zero. - - // Initialize LBEG, LEND, and LCOUNT. -# if XCHAL_HAVE_LOOPS - wsr a0, LCOUNT // note: LCOUNT gets cleared by processor reset - wsr a0, LBEG - wsr a0, LEND -# endif - -# if XCHAL_HAVE_DEBUG - .macro reset_dbreaka num - wsr a0, DBREAKA + \num - .endm - .macro reset_ibreaka num - wsr a0, IBREAKA + \num - .endm - iterate 0, XCHAL_NUM_DBREAK-1, reset_dbreaka - iterate 0, XCHAL_NUM_IBREAK-1, reset_ibreaka -# endif - - // SAR initialization - ssai 0 - - // Exception initialization -# if XCHAL_HAVE_EXCEPTIONS - wsr a0, EPC+1 - wsr a0, EXCSAVE+1 - wsr a0, EXCCAUSE -# endif - -# if XCHAL_HAVE_HIGHLEVEL_INTERRUPTS - .macro reset_int num - wsr a0, EPC + \num - wsr a0, EPS + \num - wsr a0, EXCSAVE + \num - .endm - iterate 2, XCHAL_NUM_INTLEVELS, reset_int -# endif - - // Booleans initialization -# if XCHAL_HAVE_BOOLEANS - wsr a0, BR -# endif - - // MAC16 initialization -# if XCHAL_HAVE_MAC16 - wsr a0, ACCLO - wsr a0, ACCHI - wsr a0, M0 - wsr a0, M1 - wsr a0, M2 - wsr a0, M3 -# endif - - // OCD initialization -# if XCHAL_HAVE_OCD - wsr a0, DDR -# endif - - isync // wait for all the above to take effect - -#endif /* XTOS_RESET_UNNEEDED */ - diff --git a/src/arch/xtensa/xtos/reset-vector.S b/src/arch/xtensa/xtos/reset-vector.S deleted file mode 100644 index 7848a79b748f..000000000000 --- a/src/arch/xtensa/xtos/reset-vector.S +++ /dev/null @@ -1,678 +0,0 @@ -// reset-vector.S -- Xtensa Reset Vector -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/reset-vector.S#1 $ - -// Copyright (c) 1999-2013 Tensilica 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. - - -#include <sof/common.h> -#if CONFIG_XT_BOOT_LOADER && !CONFIG_VM_ROM -#include <sof/lib/memory.h> -#endif -#include <xtensa/coreasm.h> -#include <xtensa/corebits.h> -#include <xtensa/cacheasm.h> -#include <xtensa/cacheattrasm.h> -#include <xtensa/xtensa-xer.h> -#include <xtensa/xdm-regs.h> -#include <xtensa/config/system.h> /* for XSHAL_USE_ABSOLUTE_LITERALS only */ -#include <xtensa/xtruntime-core-state.h> -#include "xtos-internal.h" - -#if XCHAL_HAVE_MPU -/* for mpu_write_map opcode */ -#include <xtensa/mpuasm.h> -#endif - -// The following reset vector avoids initializing certain registers already -// initialized by processor reset. But it does initialize some of them -// anyway, for minimal support of warm restart (restarting in software by -// jumping to the reset vector rather than asserting hardware reset). - - - .begin literal_prefix .ResetVector - .section .ResetVector.text, "ax" - - .align 4 - .global _ResetVector -_ResetVector: - -#if (!XCHAL_HAVE_HALT || defined(XTOS_UNPACK)) && XCHAL_HAVE_IMEM_LOADSTORE - // NOTE: - // - // IMPORTANT: If you move the _ResetHandler portion to a section - // other than .ResetVector.text that is outside the range of - // the reset vector's 'j' instruction, the _ResetHandler symbol - // and a more elaborate j/movi/jx sequence are needed in - // .ResetVector.text to dispatch to the new location. - -#if CONFIG_XT_HAVE_RESET_VECTOR_ROM - j _ResetHandler -#else - // This is our VM ROM, it simply jumps to the reset handler. - j .sram_jump // jump over the literals - - .align 4 - .literal_position // tells the assembler/linker to place literals here - -_reset_sram: - .word _ResetHandler - .align 4 -.sram_jump: - l32r a0, _reset_sram // load SRAM reset handler address - jx a0 // jump to the handler -#endif - .size _ResetVector, . - _ResetVector - -# if XCHAL_HAVE_HALT - // Xtensa TX: reset vector segment is only 4 bytes, so must place the - // unpacker code elsewhere in the memory that contains the reset vector. -# if XCHAL_RESET_VECTOR_VADDR == XCHAL_INSTRAM0_VADDR - .section .iram0.text, "ax" -# elif XCHAL_RESET_VECTOR_VADDR == XCHAL_INSTROM0_VADDR - .section .irom0.text, "ax" -# elif XCHAL_RESET_VECTOR_VADDR == XCHAL_URAM0_VADDR - .section .uram0.text, "ax" -# else -# warning "Xtensa TX reset vector not at start of iram0, irom0, or uram0 -- ROMing LSPs may not work" - .text -# endif -# endif - - .extern __memctl_default - -#if CONFIG_XT_BOOT_LOADER || CONFIG_VM_ROM - .section .ResetHandler.text, "ax" - j _ResetHandler -#endif - .align 4 - .literal_position // tells the assembler/linker to place literals here - - // For MPU empty background map -- see XCHAL_HAVE_MPU code further below. - // Cannot put this in .rodata (not unpacked before MPU init). -# if XCHAL_HAVE_MPU && XCHAL_MPU_ENTRIES >= 8 && XCHAL_MPU_BACKGROUND_ENTRIES <= 2 - .global _xtos_mpu_attribs - .align 4 -_xtos_mpu_attribs: - .word 0x00006000+XCHAL_MPU_ENTRIES-8 // Illegal (---) - .word 0x000F7700+XCHAL_MPU_ENTRIES-8 // Writeback (rwx Cacheable Non-shareable wb rd-alloc wr-alloc) - .word 0x000D5700+XCHAL_MPU_ENTRIES-8 // WBNA (rwx Cacheable Non-shareable wb rd-alloc) - .word 0x000C4700+XCHAL_MPU_ENTRIES-8 // Writethru (rwx Cacheable Non-shareable wt rd-alloc) - .word 0x00006700+XCHAL_MPU_ENTRIES-8 // Bypass (rwx Device non-interruptible system-shareable) -# endif - - .align 4 - .global _ResetHandler -_ResetHandler: -#endif - -#if !XCHAL_HAVE_HALT - - /* - * Even if the processor supports the non-PC-relative L32R option, - * it will always start up in PC-relative mode. We take advantage of - * this, and use PC-relative mode at least until we're sure the .lit4 - * section is in place (which is sometimes only after unpacking). - */ - .begin no-absolute-literals - - // If we have dynamic cache way support, init the caches as soon - // as we can, which is now. Except, if we are waking up from a - // PSO event, then we need to do this slightly later. - -#if XCHAL_HAVE_ICACHE_DYN_WAYS || XCHAL_HAVE_DCACHE_DYN_WAYS -# if XCHAL_HAVE_PSO_CDM && !XCHAL_HAVE_PSO_FULL_RETENTION - // Do this later on in the code -- see below -# else - movi a0, __memctl_default - wsr.memctl a0 -# endif -#endif - - // If we have PSO support, then we must check for a warm start with - // caches left powered on. If the caches had been left powered on, - // we must restore the state of MEMCTL to the saved state if any. - // Note that MEMCTL may not be present depending on config. - -#if XCHAL_HAVE_PSO_CDM && !XCHAL_HAVE_PSO_FULL_RETENTION - movi a2, XDM_MISC_PWRSTAT // Read PWRSTAT - movi a3, _xtos_pso_savearea // Save area address - retained for later - movi a5, CORE_STATE_SIGNATURE // Signature for compare - retained for later - rer a7, a2 // PWRSTAT value - retained for later - extui a4, a7, 1, 2 // Now bottom 2 bits are core wakeup and cache power lost - bnei a4, 1, .Lcold_start // a4==1 means PSO wakeup, caches did not lose power - l32i a4, a3, CS_SA_signature // Load save area signature field - sub a4, a4, a5 - bnez a4, .Lcold_start // If signature mismatch then do cold start -#if XCHAL_USE_MEMCTL - l32i a4, a3, CS_SA_memctl // Load saved MEMCTL value - movi a0, ~MEMCTL_INV_EN - and a0, a4, a0 // Clear invalidate bit - wsr.memctl a0 -#endif - j .Lwarm_start - -.Lcold_start: - -#if XCHAL_HAVE_ICACHE_DYN_WAYS || XCHAL_HAVE_DCACHE_DYN_WAYS - // Enable and invalidate all ways of both caches. If there is no - // dynamic way support then this write will have no effect. - - movi a0, __memctl_default - wsr.memctl a0 -#endif - -.Lwarm_start: - -#endif - - movi a0, 0 // a0 is always 0 in this code, used to initialize lots of things - -#if XCHAL_HAVE_INTERRUPTS // technically this should be under !FULL_RESET, assuming hard reset - wsr.intenable a0 // make sure that interrupts are shut off (*before* we lower PS.INTLEVEL and PS.EXCM!) -#endif - -#if !XCHAL_HAVE_FULL_RESET - -#if XCHAL_HAVE_CCOUNT && (XCHAL_HW_MIN_VERSION < XTENSA_HWVERSION_RB_2006_0) /* pre-LX2 cores only */ - wsr.ccount a0 // not really necessary, but nice; best done very early -#endif - - // For full MMU configs, put page table at an unmapped virtual address. - // This ensures that accesses outside the static maps result - // in miss exceptions rather than random behaviour. - // Assumes XCHAL_SEG_MAPPABLE_VADDR == 0 (true in released MMU). -#if XCHAL_ITLB_ARF_WAYS > 0 || XCHAL_DTLB_ARF_WAYS > 0 - wsr.ptevaddr a0 -#endif - - // Debug initialization - // - // NOTE: DBREAKCn must be initialized before the combination of these two things: - // any load/store, and a lowering of PS.INTLEVEL below DEBUG_LEVEL. - // The processor already resets IBREAKENABLE appropriately. - // -#if XCHAL_HAVE_DEBUG -# if XCHAL_NUM_DBREAK -# if XCHAL_NUM_DBREAK >= 2 - wsr.dbreakc1 a0 -# endif - wsr.dbreakc0 a0 - dsync // wait for WSRs to DBREAKCn to complete -# endif - -# if XCHAL_HW_MIN_VERSION < XTENSA_HWVERSION_RA_2004_1 /* pre-LX cores only */ - // Starting in Xtensa LX, ICOUNTLEVEL resets to zero (not 15), so no need to initialize it. - // Prior to that we do, otherwise we get an ICOUNT exception, 2^32 instructions after reset. - rsr.icountlevel a2 // are we being debugged? (detected by ICOUNTLEVEL not 15, or dropped below 12) - bltui a2, 12, 1f // if so, avoid initializing ICOUNTLEVEL which drops single-steps through here - wsr.icountlevel a0 // avoid ICOUNT exceptions - isync // wait for WSR to ICOUNTLEVEL to complete -1: -# endif -#endif - -#endif /* !XCHAL_HAVE_FULL_RESET */ - -#if XCHAL_HAVE_ABSOLUTE_LITERALS - // Technically, this only needs to be done under !FULL_RESET, assuming hard reset: - wsr.litbase a0 - rsync -#endif - -#if XCHAL_HAVE_PSO_CDM && ! XCHAL_HAVE_PSO_FULL_RETENTION - // If we're powering up from a temporary power shut-off (PSO), - // restore state saved just prior to shut-off. Note that the - // MEMCTL register was already restored earlier, and as a side - // effect, registers a3, a5, a7 are now preloaded with values - // that we will use here. - // a3 - pointer to save area base address (_xtos_pso_savearea) - // a5 - saved state signature (CORE_STATE_SIGNATURE) - // a7 - contents of PWRSTAT register - - l32i a4, a3, CS_SA_signature // load save area signature - sub a4, a4, a5 // compare signature with expected one -# if XTOS_PSO_TEST - movi a7, PWRSTAT_WAKEUP_RESET // pretend PSO warm start with warm caches -# endif - bbci.l a7, PWRSTAT_WAKEUP_RESET_SHIFT, 1f // wakeup from PSO? (branch if not) - // Yes, wakeup from PSO. Check whether state was properly saved. - addi a5, a7, - PWRSTAT_WAKEUP_RESET // speculatively clear PSO-wakeup bit - movnez a7, a5, a4 // if state not saved (corrupted?), mark as cold start - bnez a4, 1f // if state not saved, just continue with reset - // Wakeup from PSO with good signature. Now check cache status: - bbci.l a7, PWRSTAT_CACHES_LOST_POWER_SHIFT, .Lpso_restore // if caches warm, restore now - // Caches got shutoff. Continue reset, we'll end up initializing caches, and check again later for PSO. -# if XCHAL_HAVE_PRID && XCHAL_HAVE_S32C1I - j .Ldonesync // skip reset sync, only done for cold start -# endif -1: // Cold start. (Not PSO wakeup.) Proceed with normal full reset. -#endif - -#if XCHAL_HAVE_PRID && XCHAL_HAVE_S32C1I - /* Core 0 initializes the XMP synchronization variable, if present. This operation needs to - happen as early as possible in the startup sequence so that the other cores can be released - from reset. */ - .weak _ResetSync - movi a2, _ResetSync // address of sync variable - rsr.prid a3 // core and multiprocessor ID - extui a3, a3, 0, 8 // extract core ID (FIXME: need proper constants for PRID bits to extract) - beqz a2, .Ldonesync // skip if no sync variable - bnez a3, .Ldonesync // only do this on core 0 - s32i a0, a2, 0 // clear sync variable -.Ldonesync: -#endif -#if XCHAL_HAVE_EXTERN_REGS && XCHAL_HAVE_MP_RUNSTALL - /* On core 0, this releases other cores. On other cores this has no effect, because - runstall control is unconnected. */ - movi a2, XER_MPSCORE - wer a0, a2 -#endif - - /* - * For processors with relocatable vectors, apply any alternate - * vector base given to xt-genldscripts, which sets the - * _memmap_vecbase_reset symbol accordingly. - */ -#if XCHAL_HAVE_VECBASE - movi a2, _memmap_vecbase_reset /* note: absolute symbol, not a ptr */ - wsr.vecbase a2 -#endif - -#if XCHAL_HAVE_S32C1I && (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RC_2009_0) /* have ATOMCTL ? */ -# if XCHAL_DCACHE_IS_COHERENT - movi a3, 0x25 /* MX -- internal for writeback, RCW otherwise */ -# else - movi a3, 0x15 /* non-MX -- always RCW */ -# endif - wsr.atomctl a3 -#endif - -#if XCHAL_HAVE_INTERRUPTS && XCHAL_HAVE_DEBUG - rsil a2, 1 // lower PS.INTLEVEL here to make reset vector easier to debug -#endif - - /* If either of the caches does not have dynamic way support, then - * use the old (slow) method to init them. If the cache is absent - * the macros will expand to empty. - */ -#if ! XCHAL_HAVE_ICACHE_DYN_WAYS - icache_reset a2, a3 -#endif -#if ! XCHAL_HAVE_DCACHE_DYN_WAYS - dcache_reset a2, a3 -#endif - -#if XCHAL_HAVE_PSO_CDM && ! XCHAL_HAVE_PSO_FULL_RETENTION - // Here, a7 still contains status from the power status register, - // or zero if signature check failed. - bbci.l a7, PWRSTAT_WAKEUP_RESET_SHIFT, .Lcoldstart // wakeup from PSO with good signature? - // Yes, wakeup from PSO. Caches had been powered down, now are initialized. -.Lpso_restore: - // Assume memory still initialized, so all code still unpacked etc. - // So we can just jump/call to relevant state restore code (wherever located). - movi a2, 0 // make shutoff routine return zero - movi a3, _xtos_pso_savearea - // Here, as below for _start, call0 is used as an unlimited-range jump. - call0 _xtos_core_restore_nw - // (does not return) -.Lcoldstart: -#endif - -#if XCHAL_HAVE_PREFETCH - /* Enable cache prefetch if present. */ - movi.n a2, 68 - wsr a2, PREFCTL -#endif - - /* - * Now setup the memory attributes. On some cores this "enables" caches. - * We do this ahead of unpacking, so it can proceed more efficiently. - * - * The _memmap_cacheattr_reset symbol's value (address) is defined - * by the LSP's linker script, as generated by xt-genldscripts. - * If defines 4-bit attributes for eight 512MB regions. - * - * (NOTE: for cores with the older MMU v1 or v2, or without any memory - * protection mechanism, the following code has no effect.) - */ -#if XCHAL_HAVE_MPU - // If there is a user-provided MPU table, then we will program the MPU - // with it now. Can't call xthal_write_map_raw() because code sections - // haven't been unpacked yet. For romable images, the MPU table values - // and the table size must reside in a section that does not need to be - // unpacked (.ResetHandler.text or .srom.text). - // NOTE: This will set CACHEADRDIS to all zeros, because computing a - // useful nonzero value from the user settings is too complex and slow - // to implement here. - - .weak __xt_mpu_init_table // Table of MPU entries - .weak __xt_mpu_init_table_size // Number of entries in table - - movi a2, __xt_mpu_init_table // non-zero if user defined - movi a3, __xt_mpu_init_table_size // non-zero if user defined - beqz a2, .Lno_user_mpu - beqz a3, .Lno_user_mpu - l32i a3, a3, 0 - beqz a3, .Lno_user_mpu // skip if size = 0 - mpu_write_map a2, a3, a12, a13, a14, a15 - j .Lno_default_mpu - -.Lno_user_mpu: - // If there's an empty background map, setup foreground maps to mimic - // region protection. - - /* If there's an empty background map, setup foreground maps to mimic region protection: */ -# if XCHAL_MPU_ENTRIES >= 8 && XCHAL_MPU_BACKGROUND_ENTRIES <= 2 - // We assume reset state: all MPU entries zeroed and disabled. - // Otherwise we'd need a loop to zero everything. - - movi a2, _memmap_cacheattr_reset // note: absolute symbol, not a ptr - movi a3, _xtos_mpu_attribs // see literal area at start of reset vector - movi a4, 0x20000000 // 512 MB delta - movi a6, 8 - movi a7, 1 // MPU entry vaddr 0, with valid bit set - movi a9, 0 // cacheadrdis value - wsr.cacheadrdis a9 // enable everything temporarily while MPU updates - - // Write eight MPU entries, from the last one going backwards (entries n-1 thru n-8) - // -2: extui a8, a2, 28, 4 // get next attribute nibble (msb first) - extui a5, a8, 0, 2 // lower two bit indicate whether cached - slli a9, a9, 1 // add a bit to cacheadrdis... - addi a10, a9, 1 // set that new bit if... - moveqz a9, a10, a5 // ... that region is non-cacheable - addx4 a5, a8, a3 // index into _xtos_mpu_attribs table - addi a8, a8, -5 // make valid attrib indices negative - movgez a5, a3, a8 // if not valid attrib, use Illegal - l32i a5, a5, 0 // load access rights, memtype from table entry - slli a2, a2, 4 - sub a7, a7, a4 // next 512MB region (last to first) - addi a6, a6, -1 - add a5, a5, a6 // add the index - wptlb a5, a7 // write the MPU entry - bnez a6, 2b // loop until done -# else - movi a9, XCHAL_MPU_BG_CACHEADRDIS // default value of CACHEADRDIS for bgnd map -# endif - wsr.cacheadrdis a9 // update cacheadrdis -.Lno_default_mpu: -#elif XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR \ - || (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY) - movi a2, _memmap_cacheattr_reset /* note: absolute symbol, not a ptr */ - cacheattr_set /* set CACHEATTR from a2 (clobbers a3-a8) */ -#endif - - /* Now that caches are initialized, cache coherency can be enabled. */ -#if XCHAL_DCACHE_IS_COHERENT -# if XCHAL_HAVE_EXTERN_REGS && XCHAL_HAVE_MX && (XCHAL_HW_MIN_VERSION < XTENSA_HWVERSION_RE_2012_0) - /* Opt into coherence for MX (for backward compatibility / testing). */ - movi a3, 1 - movi a2, XER_CCON - wer a3, a2 -# endif -#endif - - /* Enable zero-overhead loop instr buffer and snoop responses if configured. */ - /* If HW erratum 453 fix is to be applied then disable loop instr buffer. */ -#if XCHAL_USE_MEMCTL && (XCHAL_SNOOP_LB_MEMCTL_DEFAULT || XCHAL_ERRATUM_453) - rsr.memctl a2 -#if XCHAL_SNOOP_LB_MEMCTL_DEFAULT - movi a3, XCHAL_SNOOP_LB_MEMCTL_DEFAULT - or a2, a2, a3 -#endif -#if XCHAL_ERRATUM_453 - srli a2, a2, 1 /* clear bit 0 (ZOL buffer enable) */ - slli a2, a2, 1 -#endif - wsr.memctl a2 -#endif - - /* Caches are all up and running, clear PWRCTL.ShutProcOffOnPWait. */ -#if XCHAL_HAVE_PSO_CDM - movi a2, XDM_MISC_PWRCTL - movi a4, ~PWRCTL_CORE_SHUTOFF - rer a3, a2 - and a3, a3, a4 - wer a3, a2 -#endif - -#endif /* !XCHAL_HAVE_HALT */ - - /* - * At this point we can unpack code and data (e.g. copy segments from - * ROM to RAM, vectors into their proper location, etc.). However, - * - * 1) the destination of the unpack may require some setup, - * for instance a DDR controller may need to be initialized - * and enabled before anything is unpacked into DDR. - * 2) users may wish to provide their own unpack code which works - * faster or in a different way than the default unpack code. - * - * To support such uses, we provide a user hook at this point. - * If the user hook function is defined, then it is called from - * here, and its return value (in a2) is checked. If the return - * value is non-zero, then we assume that code unpacking has been - * completed. The user hook function must be written in assembly - * and should make minimal assumptions about system state. - */ - - .weak __reset_user_init - - movi a2, __reset_user_init - beqz a2, 1f // no user hook - callx0 a2 // execute user hook - movi a0, 0 // ensure a0 continues to hold 0 - bnez a2, unpackdone // if a2 != 0 then unpack is done -1: - -#if defined(XTOS_UNPACK) - movi a2, _rom_store_table - beqz a2, unpackdone -unpack: l32i a3, a2, 0 // start vaddr - l32i a4, a2, 4 // end vaddr - l32i a5, a2, 8 // store vaddr - addi a2, a2, 12 - bgeu a3, a4, upnext // skip unless start < end -uploop: l32i a6, a5, 0 - addi a5, a5, 4 - s32i a6, a3, 0 - addi a3, a3, 4 - bltu a3, a4, uploop - j unpack -upnext: bnez a3, unpack - bnez a5, unpack -#endif /* XTOS_UNPACK */ - -unpackdone: - -#if defined(XTOS_UNPACK) || defined(XTOS_MP) - /* - * If writeback caches are configured and enabled, unpacked data must be - * written out to memory before trying to execute it: - */ - dcache_writeback_all a2, a3, a4, 0 - icache_sync a2 // ensure data written back is visible to i-fetch - /* - * Note: no need to invalidate the i-cache after the above, because we - * already invalidated it further above and did not execute anything within - * unpacked regions afterwards. [Strictly speaking, if an unpacked region - * follows this code very closely, it's possible for cache-ahead to have - * cached a bit of that unpacked region, so in the future we may need to - * invalidate the entire i-cache here again anyway.] - */ -#endif - - -#if !XCHAL_HAVE_HALT /* skip for TX */ - - /* - * Now that we know the .lit4 section is present (if got unpacked) - * (and if absolute literals are used), initialize LITBASE to use it. - */ -#if XCHAL_HAVE_ABSOLUTE_LITERALS && XSHAL_USE_ABSOLUTE_LITERALS - /* - * Switch from PC-relative to absolute (litbase-relative) L32R mode. - * Set LITBASE to 256 kB beyond the start of the literals in .lit4 - * (aligns to the nearest 4 kB boundary, LITBASE does not have bits 1..11) - * and set the enable bit (_lit4_start is assumed 4-byte aligned). - */ - movi a2, _lit4_start + 0x40001 - wsr.litbase a2 - rsync -#endif /* have and use absolute literals */ - .end no-absolute-literals // we can now start using absolute literals - - -// Technically, this only needs to be done pre-LX2, assuming hard reset: -# if XCHAL_HAVE_WINDOWED && defined(__XTENSA_WINDOWED_ABI__) - // Windowed register init, so we can call windowed code (eg. C code). - movi a1, 1 - wsr.windowstart a1 - // The processor always clears WINDOWBASE at reset, so no need to clear it here. - // It resets WINDOWSTART to 1 starting with LX2.0/X7.0 (RB-2006.0). - // However, assuming hard reset is not yet always practical, so do this anyway: - wsr.windowbase a0 - rsync - movi a0, 0 // possibly a different a0, clear it -# endif - -#if XCHAL_HW_MIN_VERSION < XTENSA_HWVERSION_RB_2006_0 /* only pre-LX2 needs this */ - // Coprocessor option initialization -# if XCHAL_HAVE_CP - //movi a2, XCHAL_CP_MASK // enable existing CPs - // To allow creating new coprocessors using TC that are not known - // at GUI build time without having to explicitly enable them, - // all CPENABLE bits must be set, even though they may not always - // correspond to a coprocessor. - movi a2, 0xFF // enable *all* bits, to allow dynamic TIE - wsr.cpenable a2 -# endif - - // Floating point coprocessor option initialization (at least - // rounding mode, so that floating point ops give predictable results) -# if XCHAL_HAVE_FP && !XCHAL_HAVE_VECTORFPU2005 - rsync /* wait for WSR to CPENABLE to complete before accessing FP coproc state */ - wur.fcr a0 /* clear FCR (default rounding mode, round-nearest) */ - wur.fsr a0 /* clear FSR */ -# endif -#endif /* pre-LX2 */ - - - // Initialize memory error handler address. - // Putting this address in a register allows multiple instances of - // the same configured core (with separate program images but shared - // code memory, thus forcing memory error vector to be shared given - // it is not VECBASE relative) to have the same memory error vector, - // yet each have their own handler and associated data save area. -#if XCHAL_HAVE_MEM_ECC_PARITY_IGNORE - movi a4, _MemErrorHandler - wsr.mesave a4 -#endif - - - /* - * Initialize medium and high priority interrupt dispatchers: - */ -#if HAVE_XSR && (XCHAL_HAVE_XEA1 || XCHAL_HAVE_XEA2) - -#if !CONFIG_XT_BOOT_LOADER || CONFIG_VM_ROM -# ifndef XCHAL_DEBUGLEVEL /* debug option not selected? */ -# define XCHAL_DEBUGLEVEL 99 /* bogus value outside 2..6 */ -# endif - - .macro init_vector level - .if GREATERTHAN(XCHAL_NUM_INTLEVELS+1,\level) - .if XCHAL_DEBUGLEVEL-\level - .weak _Level&level&FromVector - movi a4, _Level&level&FromVector - writesr excsave \level a4 - .if GREATERTHAN(\level,XCHAL_EXCM_LEVEL) - movi a5, _Pri_&level&_HandlerAddress - s32i a4, a5, 0 - /* If user provides their own handler, that handler might - * not provide its own _Pri_<n>_HandlerAddress variable for - * linking handlers. In that case, the reference below - * would pull in the XTOS handler anyway, causing a conflict. - * To avoid that, provide a weak version of it here: - */ - .pushsection .data, "aw" - .global _Pri_&level&_HandlerAddress - .weak _Pri_&level&_HandlerAddress - .align 4 - _Pri_&level&_HandlerAddress: .space 4 - .popsection - .endif - .endif - .endif - .endm - - init_vector 2 - init_vector 3 - init_vector 4 - init_vector 5 - init_vector 6 -#endif -#endif /*HAVE_XSR*/ - - - /* - * Complete reset initialization outside the vector, - * to avoid requiring a vector that is larger than necessary. - * This 2nd-stage startup code sets up the C Run-Time (CRT) and calls main(). - * - * Here we use call0 not because we expect any return, but - * because the assembler/linker dynamically sizes call0 as - * needed (with -mlongcalls) which it doesn't with j or jx. - * Note: This needs to be call0 regardless of the selected ABI. - */ - -#if CONFIG_XT_BOOT_LOADER && !CONFIG_VM_ROM - movi a0, SOF_TEXT_BASE - callx0 a0 -#else - call0 _start // jump to _start (in crt1-*.S) -#endif - /* does not return */ - -#else /* XCHAL_HAVE_HALT */ - - j _start // jump to _start (in crt1-*.S) - // (TX has max 64kB IRAM, so J always in range) - - // Paranoia -- double-check requirements / assumptions of this Xtensa TX code: -# if !defined(__XTENSA_CALL0_ABI__) || !XCHAL_HAVE_FULL_RESET || XCHAL_HAVE_INTERRUPTS || XCHAL_HAVE_CCOUNT || XCHAL_DTLB_ARF_WAYS || XCHAL_HAVE_DEBUG || XCHAL_HAVE_S32C1I || XCHAL_HAVE_ABSOLUTE_LITERALS || XCHAL_DCACHE_SIZE || XCHAL_ICACHE_SIZE || XCHAL_HAVE_PIF || XCHAL_HAVE_WINDOWED -# error "Halt architecture (Xtensa TX) requires: call0 ABI, all flops reset, no exceptions or interrupts, no TLBs, no debug, no S32C1I, no LITBASE, no cache, no PIF, no windowed regs" -# endif - -#endif /* XCHAL_HAVE_HALT */ - - -#if (!XCHAL_HAVE_HALT || defined(XTOS_UNPACK)) && XCHAL_HAVE_IMEM_LOADSTORE - .size _ResetHandler, . - _ResetHandler -#else - .size _ResetVector, . - _ResetVector -#endif - - .text - .global xthals_hw_configid0, xthals_hw_configid1 - .global xthals_release_major, xthals_release_minor - .end literal_prefix diff --git a/src/arch/xtensa/xtos/shared-reset-vector.S b/src/arch/xtensa/xtos/shared-reset-vector.S deleted file mode 100644 index ae457f9507d3..000000000000 --- a/src/arch/xtensa/xtos/shared-reset-vector.S +++ /dev/null @@ -1,73 +0,0 @@ -// shared-reset-vector.S -- Sharable Reset Vector (requires PRID option) - -// Copyright (c) 1999-2010 Tensilica 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. - -#include <xtensa/coreasm.h> - - // Populate this processor's entry in the reset table. - // The core instance specific LSP should put this section - // in the correct location within the table. - // - .section .ResetTable.rodata, "a" - .word _ResetHandler - - // This sharable reset code assumes RC-2009.0 or later hardware, - // to guarantee that no processor state initialization is required - // prior to doing loads etc. - // Total size is 28 bytes (or 27 with density option). - // By necessity, none of these bytes vary by core instance; - // the appropriate reset table entry is selected using PRID. - // -#if XCHAL_HAVE_PRID - .section .SharedResetVector.text, "ax" - .begin no-absolute-literals - - .align 4 - .global _SharedResetVector -_SharedResetVector: - j .LSharedResetHandler - - .align 4 - .literal_position - - // Use L32R if available -#if XCHAL_HAVE_L32R - .literal rtbase, _ResetTable_base -#endif - - .align 4 -.LSharedResetHandler: - rsr.prid a0 // get processor ID (16 bits) -#if XCHAL_HAVE_L32R - l32r a1, rtbase // force use of L32R -#else - movi a1, _ResetTable_base // No L32R, will likely become CONST16 -#endif - extui a0, a0, 0, 4 // ID of core within the multiprocessor (FIXME: need proper constant...) - addx4 a1, a0, a1 - l32i a1, a1, 0 - jx a1 // jump to core-specific initialization - - .size _SharedResetVector, . - _SharedResetVector - .end no-absolute-literals -#endif - diff --git a/src/arch/xtensa/xtos/stub.c b/src/arch/xtensa/xtos/stub.c deleted file mode 100644 index 8a6dc8359f3d..000000000000 --- a/src/arch/xtensa/xtos/stub.c +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Those functions are stubs and implemented to ease linking libraries relying on -// certain operating system symbols to be present at link time. -// Those stub are not meant to be called at runtime and will panic if called. - -#include <stddef.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <rtos/panic.h> -#include <ipc/trace.h> - -struct _reent; - -ssize_t _write_r(struct _reent *ptr, - int fd, - const void *buf, - size_t cnt); -ssize_t _write_r(struct _reent *ptr, - int fd, - const void *buf, - size_t cnt) -{ - sof_panic(SOF_IPC_PANIC_ARCH); - return 0; -} - -off_t _lseek_r(struct _reent *ptr, - int fd, - off_t pos, - int whence); -off_t _lseek_r(struct _reent *ptr, - int fd, - off_t pos, - int whence) -{ - off_t ret; - - sof_panic(SOF_IPC_PANIC_ARCH); - return ret; -} - -int _kill_r(struct _reent *ptr, - int pid, - int sig); -int _kill_r(struct _reent *ptr, - int pid, - int sig) -{ - sof_panic(SOF_IPC_PANIC_ARCH); - return 0; -} - -void *_sbrk_r(struct _reent *ptr, - ptrdiff_t incr); -void *_sbrk_r(struct _reent *ptr, - ptrdiff_t incr) -{ - sof_panic(SOF_IPC_PANIC_ARCH); - return NULL; -} - -void _exit(int __status); -void _exit(int __status) -{ - sof_panic(SOF_IPC_PANIC_ARCH); -} - - -ssize_t _read_r(struct _reent *ptr, - int fd, - void *buf, - size_t cnt); -ssize_t _read_r(struct _reent *ptr, - int fd, - void *buf, - size_t cnt) -{ - sof_panic(SOF_IPC_PANIC_ARCH); - return 0; -} - -int _close_r(struct _reent *ptr, int fd); -int _close_r(struct _reent *ptr, int fd) -{ - sof_panic(SOF_IPC_PANIC_ARCH); - return 0; -} - - -int _getpid_r(struct _reent *ptr); -int _getpid_r(struct _reent *ptr) -{ - sof_panic(SOF_IPC_PANIC_ARCH); - return 0; -} - -int _fstat_r(struct _reent *ptr, - int fd, struct stat *pstat); -int _fstat_r(struct _reent *ptr, - int fd, struct stat *pstat) -{ - sof_panic(SOF_IPC_PANIC_ARCH); - return -1; -} - diff --git a/src/arch/xtensa/xtos/textaddr b/src/arch/xtensa/xtos/textaddr deleted file mode 100755 index 4355facf1b4e..000000000000 --- a/src/arch/xtensa/xtos/textaddr +++ /dev/null @@ -1,59 +0,0 @@ -# Program to determine -Ttext parameter for ld -# $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/textaddr#1 $ - -# Copyright (c) 2001 Tensilica 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. - -package textaddr; - -use strict; -use FileHandle; - -{ - $::myname = 'textaddr'; - - die("Usage is: $::myname objfile label address\n") - unless @ARGV == 3; - my($objfile, $label, $address) = @ARGV; - - - my $nm = new FileHandle "xt-nm $objfile|"; - die("$::myname: $!, opening pipe to xt-nm $objfile.\n") - unless $nm; - while (<$nm>) { - if (/^([0-9a-f]{8}) . (\w+)$/) { - my $oaddress = $1; - my $olabel = $2; - if ($olabel eq $label) { - printf ("0x%x\n", hex($address) - hex($oaddress)); - exit(0); - } - } - } - die ("$::myname: $label not found in $objfile.\n"); -} - -# -# Local Variables: -# mode:perl -# perl-indent-level:2 -# cperl-indent-level:2 -# End: diff --git a/src/arch/xtensa/xtos/tiny-refs-min.S b/src/arch/xtensa/xtos/tiny-refs-min.S deleted file mode 100644 index 453001cb7294..000000000000 --- a/src/arch/xtensa/xtos/tiny-refs-min.S +++ /dev/null @@ -1,28 +0,0 @@ -// tiny-refs-min.S - References to pull-in selected modules into tiny LSPs - -// Copyright (c) 2006 Tensilica 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. - - - .global _need_user_vector_ - .set _need_user_vector_, 0 // define this, so if referenced... - .global _UserExceptionVector // ... we pull-in this - diff --git a/src/arch/xtensa/xtos/tiny-refs.S b/src/arch/xtensa/xtos/tiny-refs.S deleted file mode 100644 index d89407e0eed9..000000000000 --- a/src/arch/xtensa/xtos/tiny-refs.S +++ /dev/null @@ -1,33 +0,0 @@ -// tiny-refs.S - References to pull-in selected modules into tiny LSPs - -// Copyright (c) 2006 Tensilica 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. - -#if defined(__SPLIT__level1int) - - .global _need_level1int_ - .set _need_level1int_, 0 // define this, so if referenced... - .global _need_user_vector_ // ... we pull-in this - .global _xtos_l1int_handler // and this - -#endif - - diff --git a/src/arch/xtensa/xtos/user-vector-min.S b/src/arch/xtensa/xtos/user-vector-min.S deleted file mode 100644 index d8f19ea5c1cd..000000000000 --- a/src/arch/xtensa/xtos/user-vector-min.S +++ /dev/null @@ -1,110 +0,0 @@ -// user-vector-min.S - Minimal User Vector for General Exceptions -// Takes less table space, but does not allow registering new handlers. -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/user-vector-min.S#1 $ - -// Copyright (c) 2003-2015 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/config/system.h> -#include "xtos-internal.h" - -#if XCHAL_HAVE_EXCEPTIONS && (XCHAL_HAVE_XEA1 || XCHAL_HAVE_XEA2) - - // Vector code - .begin literal_prefix .UserExceptionVector - .section .UserExceptionVector.text, "ax" - .align 4 - .global _UserExceptionVector -_UserExceptionVector: -# if (((XSHAL_USER_VECTOR_SIZE >= 28) && XCHAL_HAVE_ADDX && XCHAL_HAVE_DENSITY && XCHAL_HAVE_L32R) || (XSHAL_USER_VECTOR_SIZE >= 36) || XSHAL_VECTORS_PACKED) && !defined(XSHAL_ERRATUM_487_FIX) - - addi a1, a1, -ESF_TOTALSIZE // allocate exception stack frame, etc. - s32i a2, a1, UEXC_a2 - s32i a3, a1, UEXC_a3 - rsr.exccause a2 // get exception cause - movi a3, _xtos_min_handler_table - bgeui a2, 6, 1f // causes 6 and above map to zero - addx4 a3, a2, a3 // index by cause if 1 .. 5 -1: l32i a3, a3, 0 - s32i a4, a1, UEXC_a4 - jx a3 // jump to cause-specific handler - - .size _UserExceptionVector, . - _UserExceptionVector - .end literal_prefix - -# else /*vector as small as 12 bytes:*/ - - addi a1, a1, -ESF_TOTALSIZE // allocate exception stack frame, etc. - s32i a2, a1, UEXC_a2 - movi a2, _UserExceptionFromVector // load user exception handler address - //interlock - jx a2 // jump to handler - - .size _UserExceptionVector, . - _UserExceptionVector - .end literal_prefix - - // Dispatch outside vector: - .text - .align 4 - .global _UserExceptionFromVector -_UserExceptionFromVector: - hw_erratum_487_fix - rsr.exccause a2 // get exception cause - s32i a3, a1, UEXC_a3 - movi a3, _xtos_min_handler_table - bgeui a2, 6, 1f // causes 6 and above map to zero - addx4 a3, a2, a3 // index by cause if 1 .. 5 -1: l32i a3, a3, 0 - s32i a4, a1, UEXC_a4 - jx a3 // jump to cause-specific handler - .size _UserExceptionFromVector, . - _UserExceptionFromVector - -# endif - - - /* - * Read-only minimal table of assembly-level exception handlers - * for user vectored exceptions. - * Only provides entries for SYSCALL, MOVSP, and level-1 interrupt causes. - */ - .section .rodata, "a" - .global _xtos_min_handler_table - .align 4 -_xtos_min_handler_table: - .word xtos_unhandled_exception // 0 Illegal Instruction, and causes > 5 - .word _xtos_syscall_handler // 1 SYSCALL Instruction - .word xtos_unhandled_exception // 2 Instruction Fetch Error - .word xtos_unhandled_exception // 3 Load/Store Error -# if XCHAL_HAVE_INTERRUPTS - .word _xtos_l1int_handler // 4 Level-1 Interrupt -# else - .word xtos_unhandled_exception // 4 Level-1 Interrupt (not configured) -# endif -# if XCHAL_HAVE_WINDOWED && !defined(__XTENSA_CALL0_ABI__) - .word _xtos_alloca_handler // 5 Alloca (MOVSP Instruction) -# else - .word xtos_unhandled_exception // 5 Alloca (MOVSP Instruction) (not configured) -# endif - .text - -#endif /* XCHAL_HAVE_EXCEPTIONS */ - diff --git a/src/arch/xtensa/xtos/user-vector.S b/src/arch/xtensa/xtos/user-vector.S deleted file mode 100644 index 0f17d8300486..000000000000 --- a/src/arch/xtensa/xtos/user-vector.S +++ /dev/null @@ -1,200 +0,0 @@ -// user-vector.S - User Vector for General Exceptions -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/user-vector.S#1 $ - -// Copyright (c) 1998-2015 Tensilica 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. - - -#include <xtensa/coreasm.h> -#include <xtensa/config/system.h> -#include "xtos-internal.h" - -#if XCHAL_HAVE_EXCEPTIONS && (XCHAL_HAVE_XEA1 || XCHAL_HAVE_XEA2) - - // Vector code - .section .UserExceptionVector.text, "ax" - .align 4 - .global _UserExceptionVector -_UserExceptionVector: -# if (((XSHAL_USER_VECTOR_SIZE >= 28) && XCHAL_HAVE_ADDX && XCHAL_HAVE_DENSITY && XCHAL_HAVE_L32R) || (XSHAL_USER_VECTOR_SIZE >= 36) || XSHAL_VECTORS_PACKED) && !defined (XSHAL_ERRATUM_487_FIX) - // There is space to dispatch right at the vector: - - addi a1, a1, -ESF_TOTALSIZE // allocate exception stack frame, etc. - s32i a2, a1, UEXC_a2 - s32i a3, a1, UEXC_a3 - movi a3, xtos_exc_handler_table - rsr.exccause a2 // get exception cause - //interlock - addx4 a3, a2, a3 - l32i a3, a3, 0 - s32i a4, a1, UEXC_a4 - jx a3 // jump to cause-specific handler - - .size _UserExceptionVector, . - _UserExceptionVector - -# else - // The vector may be as small as 12 bytes: - - addi a1, a1, -ESF_TOTALSIZE // allocate exception stack frame, etc. - s32i a2, a1, UEXC_a2 - movi a2, _UserExceptionFromVector // load user exception handler address - //interlock - jx a2 // jump to handler - - .size _UserExceptionVector, . - _UserExceptionVector - - // Dispatch outside vector: - .text - //.subsection 2 - .align 4 - .global _UserExceptionFromVector -_UserExceptionFromVector: - hw_erratum_487_fix - s32i a3, a1, UEXC_a3 - movi a3, xtos_exc_handler_table - rsr.exccause a2 // get exception cause - s32i a4, a1, UEXC_a4 - addx4 a3, a2, a3 - l32i a3, a3, 0 - jx a3 // jump to cause-specific handler - - .size _UserExceptionFromVector, . - _UserExceptionFromVector - -# endif - - - .weak xtos_cause3_handler - - /* - * Table of assembly-level general-exception handlers - * (quickly entered) for user vectored exceptions. - * Provides entries for all possible 64 exception causes - * currently allowed for in the EXCCAUSE register. - * - * NOTE: entries that have a corresponding C handler - * (registered at run-time) point to xtos_c_wrapper_handler; - * entries that have no handler point to xtos_unhandled_exception. - */ - .data -#if CONFIG_MULTICORE - .global xtos_exc_handler_table_r -#else - .global xtos_exc_handler_table -#endif - .align 4 -#if CONFIG_MULTICORE -xtos_exc_handler_table_r: -#else -xtos_exc_handler_table: -#endif - .word xtos_unhandled_exception // 0 IllegalInstruction - .word _xtos_syscall_handler // 1 Syscall - .word xtos_unhandled_exception // 2 InstructionFetchError - .word xtos_unhandled_exception // 3 LoadStoreError -# if XCHAL_HAVE_INTERRUPTS - .word _xtos_l1int_handler // 4 Level1Interrupt -# else - .word xtos_unhandled_exception // 4 Level1Interrupt (not configured) -# endif -# if XCHAL_HAVE_WINDOWED && !defined(__XTENSA_CALL0_ABI__) - .word _xtos_alloca_handler // 5 Alloca (MOVSP) -# else - .word xtos_unhandled_exception // 5 Alloca (MOVSP) (not configured) -# endif - .word xtos_unhandled_exception // 6 IntegerDivideByZero - .word xtos_unhandled_exception // 7 Speculation - .word xtos_unhandled_exception // 8 Privileged - .word xtos_unhandled_exception // 9 Unaligned - .word xtos_unhandled_exception //10 (reserved for Tensilica) - .word xtos_unhandled_exception //11 (reserved for Tensilica) - .word xtos_cause3_handler //12 PIF data error on fetch - .word xtos_cause3_handler //13 PIF data error on ld/st - .word xtos_cause3_handler //14 PIF address error on fetch - .word xtos_cause3_handler //15 PIF address error on ld/st - .word xtos_unhandled_exception //16 InstTLBMiss - .word xtos_unhandled_exception //17 InstTLBMultiHit - .word xtos_unhandled_exception //18 InstFetchPrivilege - .word xtos_unhandled_exception //19 (reserved for Tensilica) - .word xtos_unhandled_exception //20 InstFetchProhibited - .word xtos_unhandled_exception //21 (reserved for Tensilica) - .word xtos_unhandled_exception //22 (reserved for Tensilica) - .word xtos_unhandled_exception //23 (reserved for Tensilica) - .word xtos_unhandled_exception //24 LoadStoreTLBMiss - .word xtos_unhandled_exception //25 LoadStoreTLBMultiHit - .word xtos_unhandled_exception //26 LoadStorePrivilege - .word xtos_unhandled_exception //27 (reserved for Tensilica) - .word xtos_unhandled_exception //28 LoadProhibited - .word xtos_unhandled_exception //29 StoreProhibited - .word xtos_unhandled_exception //30 (reserved for Tensilica) - .word xtos_unhandled_exception //31 (reserved for Tensilica) - .rept 8 - .word xtos_unhandled_exception //32-39 Coprocessor<n>Disabled (n = 0..7) - .endr - - .rept XCHAL_EXCCAUSE_NUM-40 - .word xtos_unhandled_exception //40-63 (reserved for TIE) - .endr -#if CONFIG_MULTICORE - .section .bss - .global xtos_exc_handler_table - .align 4 -xtos_exc_handler_table: - .space XCHAL_EXCCAUSE_NUM*4 -#endif - .text - - - // NOTES: - // - // Here are alternative vectors. They will NOT work with - // the handlers currently provided with XTOS. However they - // might be useful to someone writing their own handlers - // from scratch. Note that XSR is only available on T1040 - // and later hardware. - // -//*** The typical tiny 9-byte vector: *** -// wsr.excsave1 a3 // save user a3 -// movi a3, _UserExceptionFromVector // load user exception handler address -// jx a3 -// -//*** Minimizing EXCCAUSE-dispatch delay, not assuming valid SP: *** -// wsr.depc a0 // save a0 (double exceptions fatal here, so not expected) -// rsr.exccause a0 -// xsr.excsave1 a1 // EXCSAVE_1 always contains &exception_handlers[0] -// //interlock -// addx4 a0, a0, a1 -// l32i a0, a0, TABLE_OFS + EXC_CODE_KERNEL*4 -// xsr.excsave1 a1 // restore a1 (DEPC contains original a0) -// jx a0 // jump to cause-specific handler -// -//*** Doing EXCCAUSE-dispatch with table in EXCSAVE_1: *** -// addi a1, a1, -ESF_TOTALSIZE // allocate exception stack frame, etc. -// s32i a2, a1, UEXC_a2 -// rsr.exccause a2 -// xsr.excsave1 a4 // EXCSAVE_1 always contains &exception_handlers[0] -// s32i a3, a1, UEXC_a3 -// addx4 a2, a2, a4 -// l32i a2, a2, TABLE_OFS + EXC_CODE_KERNEL*4 -// xsr.excsave1 a4 // restore a1 (DEPC contains original a0) -// jx a2 // jump to cause-specific handler - -#endif /* XCHAL_HAVE_EXCEPTIONS */ - diff --git a/src/arch/xtensa/xtos/xea1/exc-alloca-handler.S b/src/arch/xtensa/xtos/xea1/exc-alloca-handler.S deleted file mode 100644 index c3b63fb0b377..000000000000 --- a/src/arch/xtensa/xtos/xea1/exc-alloca-handler.S +++ /dev/null @@ -1,275 +0,0 @@ -// exc-alloca-handler.S - OBSOLETE - ALLOCA cause exception assembly-level handler - -#if 0 /* This handler is OBSOLETE - now part of window-vectors.S */ - -// Copyright (c) 2002-2010 Tensilica 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. - -/* - * Code written to the windowed ABI must use the MOVSP instruction to modify - * the stack pointer (except for startup code, which doesn't have a caller). - * The compiler uses MOVSP to allocate very large or variable size stack frames. - * MOVSP guarantees that the caller frame's a0-a3 registers, stored below the - * stack pointer, are moved atomically with respect to interrupts and exceptions - * to satisfy windowed ABI requirements. When user code executes the MOVSP - * instruction and the caller frame is on the stack rather than in the register - * file, the processor takes an ALLOCA exception. The ALLOCA exception handler - * moves the caller frame's a0-a3 registers to follow the stack pointer. - * This file implements this ALLOCA exception handler. - * - * Code written in C can generate a MOVSP in four situations: - * - * 1. By calling "alloca": - * - * void foo(int array_size) { - * char * bar = alloca(array_size); - * ... - * - * 2. By using variable sized arrays (a GNU C extension): - * - * void foo(int array_size) { - * char bar[array_size]; - * ... - * - * 3. By using nested C functions (also a GNU C extension): - * - * void afunction(void) { - * ... - * int anotherfunction(void) { - * } - * ... - * - * 4. By using very large amounts of stack space in a single function. The exact - * limit is 32,760 bytes (including 16-48 bytes of caller frame overhead). - * Typically, users don't encounter this limit unless they have functions - * that locally declare large arrays, for example: - * - * void foo(void) { - * int an_array[8192]; // 32,768 bytes - * int another_array[100]; // 400 bytes - * ... - * - * - * NOTE: This handler only works when MOVSP's destination register is the stack - * pointer "a1" (synonym with "sp"), i.e. "MOVSP a1, <as>". This is the only - * meaningful form of MOVSP in the windowed ABI, and the only form generated - * by the compiler and used in assembly. The code below does not check the - * destination register, so other forms of MOVSP cause unexpected behaviour. - */ - -#include <xtensa/coreasm.h> -#include "xtos-internal.h" - -#define ERROR_CHECKING 1 // define as 0 to save a few bytes - - -#if XCHAL_HAVE_EXCEPTIONS - -//Vector: -// addi a1, a1, -ESF_TOTALSIZE // allocate exception stack frame, etc. -// s32i a2, a1, UEXC_a2 -// s32i a3, a1, UEXC_a3 -// movi a3, xtos_exc_handler_table -// rsr.exccause a2 -// addx4 a2, a2, a3 -// l32i a2, a2, 0 -// s32i a4, a1, UEXC_a4 -// jx a2 // jump to cause-specific handler - - .global _need_user_vector_ // pull-in real user vector (tiny LSP) - - .text - .align 4 - .global _xtos_alloca_handler -_xtos_alloca_handler: -#if !XCHAL_HAVE_WINDOWED || defined(__XTENSA_CALL0_ABI__) - rfe_rfue -#else /* we have windows w/o call0 abi */ - // HERE: a2, a3, a4 have been saved to - // exception stack frame allocated with a1 (sp). - // a2 contains EXCCAUSE. - // (12 cycles from vector to here, assuming cache hits, 5-stage pipe, etc) - - /* - * Skip the MOVSP instruction so we don't execute it again on return: - */ - - rsr.epc1 a3 // load instruction address (PC) - s32i a5, a1, UEXC_a5 // save a5 - addi a2, a3, 3 // increment PC to skip MOVSP instruction -#if XCHAL_HAVE_LOOPS - /* - * If the MOVSP instruction is the last instruction in the body of - * a zero-overhead loop that must be executed again, then decrement - * the loop count and resume execution at the head of the loop. - */ - rsr.lend a4 - rsr.lcount a5 - bne a4, a2, 1f // done unless next-PC matches LEND - beqz a5, 1f // if LCOUNT zero, not in loop - addi a5, a5, -1 // z.o. loopback! decrement LCOUNT... - wsr.lcount a5 - rsr.lbeg a2 // PC back to start of loop -#endif /*XCHAL_HAVE_LOOPS*/ -1: wsr.epc1 a2 // update return PC past MOVSP - - /* - * Figure out what register MOVSP is moving from ('s' field, 2nd byte). - * If MOVSP is in an instruction RAM or ROM, we can only access it with - * 32-bit loads. So use shifts to read the byte from a 32-bit load. - */ - - addi a3, a3, 1 // advance to byte containing 's' field - extui a2, a3, 0, 2 // get bits 0 and 1 of address of this byte - sub a3, a3, a2 // put address on 32-bit boundary - l32i a3, a3, 0 // get word containing byte (can't use l8ui on IRAM/IROM) - rsr.sar a4 // save SAR - // NOTE: possible addition here: verify destination register is indeed a1. -# if XCHAL_HAVE_BE - ssa8b a2 - sll a3, a3 - extui a3, a3, 28, 4 // extract source register number -# else - ssa8l a2 - srl a3, a3 - extui a3, a3, 0, 4 // extract source register number -# endif - wsr.sar a4 // restore SAR - // (+?? cycles max above = ?? cycles, assuming cache hits, 5-stage pipe, no zoloops, etc) - - movi a4, .Ljmptable // jump table - mov a5, a1 // save the exception stack frame ptr in a5 - addi a1, a1, ESF_TOTALSIZE // restore a1 (in case of MOVSP a1,a1) - -# if XCHAL_HAVE_DENSITY - addx4 a4, a3, a4 // index by src reg number * 4 -# define ALIGN .align 4 // 4-byte jmptable entries -# define MOV _mov.n -# define L32I _l32i.n -# define DONE _bnez.n a4, .Lmove_save_area // a4 known non-zero -# else - addx8 a4, a3, a4 // index by src reg number * 8 -# define ALIGN .align 8 // 8-byte jmptable entries -# define MOV mov -# define L32I l32i -# define DONE j .Lmove_save_area -# endif - - jx a4 // jump into the following table - - ALIGN -.Ljmptable: MOV a1, a0 ; DONE // MOVSP a1, a0 - ALIGN ; DONE // MOVSP a1, a1 - ALIGN ; L32I a1, a5, UEXC_a2 ; DONE // MOVSP a1, a2 - ALIGN ; L32I a1, a5, UEXC_a3 ; DONE // MOVSP a1, a3 - ALIGN ; L32I a1, a5, UEXC_a4 ; DONE // MOVSP a1, a4 - ALIGN ; L32I a1, a5, UEXC_a5 ; DONE // MOVSP a1, a5 - ALIGN ; MOV a1, a6 ; DONE // MOVSP a1, a6 - ALIGN ; MOV a1, a7 ; DONE // MOVSP a1, a7 - ALIGN ; MOV a1, a8 ; DONE // MOVSP a1, a8 - ALIGN ; MOV a1, a9 ; DONE // MOVSP a1, a9 - ALIGN ; MOV a1, a10 ; DONE // MOVSP a1, a10 - ALIGN ; MOV a1, a11 ; DONE // MOVSP a1, a11 - ALIGN ; MOV a1, a12 ; DONE // MOVSP a1, a12 - ALIGN ; MOV a1, a13 ; DONE // MOVSP a1, a13 - ALIGN ; MOV a1, a14 ; DONE // MOVSP a1, a14 - ALIGN ; MOV a1, a15 // MOVSP a1, a15 - -.Lmove_save_area: - // Okay. a1 now contains the new SP value. - -# if ERROR_CHECKING - // Verify it is sensible: - extui a3, a1, 0, 2 // verify that new SP is 4-byte aligned - beqz a3, 1f // if so, skip fixup - -// .global _xtos_misaligned_movsp // make label visible for debugging -//_xtos_misaligned_movsp: -# if XCHAL_HAVE_DEBUG - break 1, 15 // break into debugger (if any) -# endif - sub a1, a1, a3 // FORCE alignment of the new pointer (!) -1: -# endif - -# if XCHAL_HAVE_XEA2 - addi a2, a5, ESF_TOTALSIZE // compute a2 = old SP -# else /*XEA1:*/ - addi a2, a5, ESF_TOTALSIZE-16 // compute a2 = old SP's save area -# endif - // Does new SP (in a1) overlap with exception stack frame (in a5)?: - movi a4, ESF_TOTALSIZE // size of exception stack frame - sub a3, a1, a5 // distance from ESF ptr to new SP - bgeu a3, a4, 1f // does new SP overlap ESF? branch if not - // Move ESF down so it doesn't overlap with the new register save area: - // (a1 = current ESF, a2 = new SP, a4 = ESF_TOTALSIZE) - sub a5, a5, a4 // shift down ESF (by ESF size) - l32i a3, a5, UEXC_a2+ESF_TOTALSIZE - l32i a4, a5, UEXC_a3+ESF_TOTALSIZE - s32i a3, a5, UEXC_a2 - s32i a4, a5, UEXC_a3 - l32i a3, a5, UEXC_a4+ESF_TOTALSIZE - l32i a4, a5, UEXC_a5+ESF_TOTALSIZE - s32i a3, a5, UEXC_a4 - s32i a4, a5, UEXC_a5 -1: - - // Move the register save area (from old SP to new SP): -# if XCHAL_HAVE_XEA2 - l32e a3, a2, -16 - l32e a4, a2, -12 - s32e a3, a1, -16 - s32e a4, a1, -12 - l32e a3, a2, -8 - l32e a4, a2, -4 - s32e a3, a1, -8 - s32e a4, a1, -4 -# else /*XEA1:*/ - addi a1, a1, -16 // point to new save area - l32i a3, a2, 0 - l32i a4, a2, 4 - s32i a3, a1, 0 - s32i a4, a1, 4 - l32i a3, a2, 8 - l32i a4, a2, 12 - s32i a3, a1, 8 - s32i a4, a1, 12 - addi a1, a1, 16 // back to correct new SP -# endif /*XEA1*/ - // (+?? cycles max above = ?? cycles, assuming cache hits, 5-stage pipe, etc) - - // Restore a2, a3, a4, a5, and return: - l32i a2, a5, UEXC_a2 - l32i a3, a5, UEXC_a3 - l32i a4, a5, UEXC_a4 - l32i a5, a5, UEXC_a5 - rfe_rfue - // (+?? cycles max above = ?? cycles, assuming cache hits, 5-stage pipe, etc) - - -#endif /* !XCHAL_HAVE_WINDOWED || __XTENSA_CALL0_ABI */ - - .size _xtos_alloca_handler, . - _xtos_alloca_handler - -#endif /* XCHAL_HAVE_EXCEPTIONS */ - -#endif /* 0 */ - diff --git a/src/arch/xtensa/xtos/xea1/exc-c-wrapper-handler.S b/src/arch/xtensa/xtos/xea1/exc-c-wrapper-handler.S deleted file mode 100644 index 9937e8f7208a..000000000000 --- a/src/arch/xtensa/xtos/xea1/exc-c-wrapper-handler.S +++ /dev/null @@ -1,374 +0,0 @@ -// xea1/exc-c-wrapper-handler.S - General Exception Handler that Dispatches C Handlers - -// Copyright (c) 2002-2016 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/corebits.h> -#include <xtensa/config/specreg.h> -#include "../xtos-internal.h" -#ifdef SIMULATOR -#include <xtensa/simcall.h> -#endif - -#if XCHAL_HAVE_XEA1 && XCHAL_HAVE_EXCEPTIONS /* note - XEA1 always has exceptions */ - - -/* - * This assembly-level handler causes the associated exception (usually causes 12-15) - * to be handled as if it were exception cause 3 (load/store error exception). - * This provides forward-compatibility with a possible future split of the - * load/store error cause into multiple more specific causes. - */ - .align 4 - .global xtos_cause3_handler -xtos_cause3_handler: - movi a2, EXCCAUSE_LOAD_STORE_ERROR - j xtos_c_wrapper_handler - .size xtos_cause3_handler, . - xtos_cause3_handler - - -/* - * This is the general exception assembly-level handler that dispatches C handlers. - */ - .align 4 - .global xtos_c_wrapper_handler -xtos_c_wrapper_handler: -#ifdef __XTENSA_CALL0_ABI__ - // Redundantly de-allocate and re-allocate stack, so that GDB prologue - // analysis picks up the allocate part, and figures out how to traceback - // through the call stack through the exception. - addi a1, a1, ESF_TOTALSIZE // de-allocate stack frame (FIXME is it safe) -.global xtos_c_wrapper_dispatch -xtos_c_wrapper_dispatch: - // GDB starts analyzing prologue after most recent global symbol, so here: - addi a1, a1, -ESF_TOTALSIZE // re-allocate stack frame -#endif - - // HERE: a2, a3, a4 have been saved to exception stack frame allocated with a1 (sp). - // a2 contains EXCCAUSE. - s32i a5, a1, UEXC_a5 // a5 will get clobbered by ENTRY after the pseudo-CALL4 - // (a4..a15 spilled as needed; save if modified) - - //NOTA: Possible future improvement: - // keep interrupts disabled until we get into the handler, such that - // we don't have to save other critical state such as EXCVADDR here. - //rsr.excvaddr a3 - s32i a2, a1, UEXC_exccause - //s32i a3, a1, UEXC_excvaddr - -#if XCHAL_HAVE_INTERRUPTS - rsilft a3, 1, XTOS_LOCKLEVEL // lockout - rsr.intenable a2 - //movi a3, ~XCHAL_EXCM_MASK - movi a3, ~XTOS_LOCKOUT_MASK // mask out low and medium priority levels, and high priority levels covered by - // XTOS_LOCKLEVEL if any, so we can run at PS.INTLEVEL=0 while manipulating INTENABLE - s32i a2, a1, UEXC_sar // (temporary holding place for INTENABLE value to restore after pseudo-CALL4 below) - and a3, a2, a3 // mask out selected interrupts - wsr.intenable a3 // disable all interrupts up to and including XTOS_LOCKLEVEL -#endif - movi a3, PS_WOECALL4_ABI|PS_UM // WOE=0|1, UM=1, INTLEVEL=0, CALLINC=0|1 (call4 emul), OWB=(dontcare)=0 - - // NOTE: could use XSR here if targeting T1040 or T1050 hardware (requiring slight sequence adjustment as for XEA2): - rsr.ps a2 - rsync //NOT-ISA-DEFINED // wait for WSR to INTENABLE to complete before clearing PS.INTLEVEL - wsr.ps a3 // PS.INTLEVEL=0, effective INTLEVEL (via INTENABLE) is XTOS_LOCKLEVEL - - // HERE: window overflows enabled, but NOT SAFE because we're not quite - // in a valid windowed context (haven't restored a1 yet...); - // so don't cause any (keep to a0..a3) until we've saved critical state and restored a1: - - // NOTE: MUST SAVE EPC1 before causing any overflows, because overflows corrupt EPC1. - rsr.epc1 a3 - s32i a2, a1, UEXC_ps - s32i a3, a1, UEXC_pc - - -#ifdef __XTENSA_CALL0_ABI__ - - s32i a0, a1, UEXC_a0 // save the rest of the registers - s32i a6, a1, UEXC_a6 - s32i a7, a1, UEXC_a7 - s32i a8, a1, UEXC_a8 - s32i a9, a1, UEXC_a9 - s32i a10, a1, UEXC_a10 - s32i a11, a1, UEXC_a11 - s32i a12, a1, UEXC_a12 - s32i a13, a1, UEXC_a13 - s32i a14, a1, UEXC_a14 - s32i a15, a1, UEXC_a15 -# if XTOS_DEBUG_PC - // TODO: setup return PC for call traceback through interrupt dispatch -# endif - - rsync // wait for WSR to PS to complete - -#else /* ! __XTENSA_CALL0_ABI__ */ - -# if XTOS_CNEST - l32i a2, a1, ESF_TOTALSIZE-20 // save nested-C-func call-chain ptr -# endif - addi a1, a1, ESF_TOTALSIZE // restore sp (dealloc ESF) for sane stack again - rsync // wait for WSR to PS to complete - - /* HERE: we can SAFELY get window overflows. - * - * From here, registers a4..a15 automatically get spilled if needed. - * They become a0..a11 after the ENTRY instruction. - * Currently, we don't check whether or not these registers - * get spilled, so we must save and restore any that we - * modify. We've already saved a4 and a5 - * which we modify as part of the pseudo-CALL. - * - * IMPLEMENTATION NOTE: - * - * The pseudo-CALL below effectively saves registers a2..a3 so - * that they are available again after the corresponding - * RETW when returning from the exception handling. We - * could choose to put something like EPC1 or PS in - * there, so they're available more quickly when - * restoring. HOWEVER, exception handlers may wish to - * change such values, or anything on the exception stack - * frame, and expect these to be restored as modified. - * - * NOTA: future: figure out what's the best thing to put - * in a2 and a3. (candidate: a4 and a5 below; but what - * if exception handler manipulates ARs, as in a syscall - * handler.... oh well) - * - * - * Now do the pseudo-CALL. - * Make it look as if the code that got the exception made a - * CALL4 to the exception handling code. (We call - * this the "pseudo-CALL".) - * - * This pseudo-CALL is important and done this way: - * - * 1. There are only three ways to safely update the stack pointer - * in the windowed ABI, such that window exceptions work correctly: - * (a) spill all live windows to stack then switch to a new stack - * (or, save the entire address register file and window - * registers, which is likely even more expensive) - * (b) use MOVSP (or equivalent) - * (c) use ENTRY/RETW - * Doing (a) is excessively expensive, and doing (b) here requires - * copying 16 bytes back and forth which is also time-consuming; - * whereas (c) is very efficient, so that's what we do here. - * - * 2. Normally we cannot do a pseudo-CALL8 or CALL12 here. - * According to the - * windowed ABI, a function must allocate enough space - * for the largest call that it makes. However, the - * pseudo-CALL is executed in the context of the - * function that happened to be executing at the time - * the interrupt was taken, and that function might or - * might not have allocated enough stack space for a - * CALL8 or a CALL12. If we try doing a pseudo-CALL8 - * or -CALL12 here, we corrupt the stack if the - * interrupted function happened to not have allocated - * space for such a call. - * - * 3. We set the return PC, but it's not strictly - * necessary for proper operation. It does make - * debugging, ie. stack tracebacks, much nicer if it - * can point to the interrupted code (not always - * possible, eg. if interrupted code is in a different - * GB than the interrupt handling code, which is - * unlikely in a system without protection where - * interrupt handlers and general application code are - * typically linked together). - * - * IMPORTANT: Interrupts must stay disabled while doing the pseudo-CALL, - * or at least until after the ENTRY instruction, because SP has been - * restored to its original value that does not reflect the exception - * stack frame's allocation. An interrupt taken here would - * corrupt the exception stack frame (ie. allocate another over it). - * (High priority interrupts can remain enabled, they save and restore - * all of their state and use their own stack or save area.) - * For the same reason, we mustn't get any exceptions in this code - * (other than window exceptions where noted) until ENTRY is done. - */ - - // HERE: may get a single window overflow (caused by the following instruction). - -# if XTOS_DEBUG_PC - movi a4, 0xC0000000 // [for debug] for return PC computation below - or a3, a4, a3 // [for debug] set upper two bits of return PC - addx2 a4, a4, a3 // [for debug] clear upper bit -# else - movi a4, 0 // entry cannot cause overflow, cause it here -# endif - - .global _GeneralException -_GeneralException: // this label makes tracebacks through exceptions look nicer - - _entry a1, ESF_TOTALSIZE // as if after a CALL4 (PS.CALLINC set to 1 above) - - /* - * The above ENTRY instruction does a number of things: - * - * 1. Because we're emulating CALL4, the ENTRY rotates windows - * forward by 4 registers (as per 'ROTW +1'), so that - * a4-a15 became a0-a11. So now: a0-a11 are part of - * the interrupted context to be preserved. a0-a1 - * were already saved above when they were a4-a5. - * a12-a15 are free to use as they're NOT part of the - * interrupted context. We don't need to save/restore - * them, and they will get spilled if needed. - * - * 2. Updates SP (new a1), allocating the exception stack - * frame in the new window, preserving the old a1 in - * the previous window. - * - * 3. The underscore prefix prevents the assembler from - * automatically aligning the ENTRY instruction on a - * 4-byte boundary, which could create a fatal gap in - * the instruction stream. - * - * At this point, ie. before we re-enable interrupts, we know the caller is - * always live so we can safely modify a1 without using MOVSP (we can use MOVSP - * but it will never cause an ALLOCA or underflow exception here). - * So this is a good point to modify the stack pointer if we want eg. to - * switch to an interrupt stack (if we do, we need to save the current SP - * because certain things have been saved to that exception stack frame). - * We couldn't do this easily before ENTRY, where the caller wasn't - * necessarily live. - * - * NOTE: We don't switch to an interrupt stack here, because exceptions - * are generally caused by executing code -- so we handle exceptions in - * the context of the thread that cause them, and thus remain on the same - * stack. This means a thread's stack must be large enough to handle - * the maximum level of nesting of exceptions that the thread can cause. - */ - - // NOTA: exception handlers for certain causes may need interrupts to be kept - // disabled through their dispatch, so they can turn them off themselves at - // the right point (if at all), eg. to save critical state unknown to this - // code here, or for some recovery action that must be atomic with respect - // to interrupts.... - // - // Perhaps two versions of this assembly-level handler are needed, one that restores - // interrupts to what they were before the exception was taken (as here) - // and one that ensures at least low-priority interrupts are kept disabled? - // NOTA: For now, always enable interrupts here. - - /* - * Now we can enable interrupts. - * (Pseudo-CALL is complete, and SP reflects allocation of exception stack frame.) - */ - -#endif /* __XTENSA_CALL0_ABI__ */ - - -#if XCHAL_HAVE_INTERRUPTS - //... recompute and set INTENABLE ... - l32i a13, a1, UEXC_sar // (temporary holding place for INTENABLE value saved before pseudo-CALL4 above) - rsr.sar a12 - wsr.intenable a13 // restore INTENABLE as it was on entry -#else - rsr.sar a12 -#endif - - movi a13, xtos_c_handler_table // &table - l32i a15, a1, UEXC_exccause // arg2: exccause - - s32i a12, a1, UEXC_sar - save_loops_mac16 a1, a12, a14 // save LOOP & MAC16 regs, if configured - - addx4 a12, a15, a13 // a12 = table[exccause] - l32i a12, a12, 0 // ... -#ifdef __XTENSA_CALL0_ABI__ - mov a2, a1 // arg1: exception parameters - mov a3, a15 // arg2: exccause - beqz a12, 1f // null handler => skip call - callx0 a12 // call C exception handler for this exception -#else - mov a14, a1 // arg1: exception parameters - // mov a15, a15 // arg2: exccause, already in a15 - beqz a12, 1f // null handler => skip call - callx12 a12 // call C exception handler for this exception -#endif -1: - // Now exit the handler. - - - // Restore special registers - - restore_loops_mac16 a1, a13, a14, a15 // restore LOOP & MAC16 regs, if configured - l32i a14, a1, UEXC_sar - - /* - * Disable interrupts while returning from the pseudo-CALL setup above, - * for the same reason they were disabled while doing the pseudo-CALL: - * this sequence restores SP such that it doesn't reflect the allocation - * of the exception stack frame, which we still need to return from - * the exception. - */ - -#if XCHAL_HAVE_INTERRUPTS - // Must disable interrupts via INTENABLE, because PS.INTLEVEL gets zeroed - // by any window exception exit, eg. the window underflow that may happen - // upon executing the RETW instruction. - // Also, must disable at XTOS_LOCKLEVEL, not just EXCM_LEVEL, because this - // code effectively manipulates virtual INTENABLE state up to the point - // INTENABLE is written in _xtos_return_from_exc. - // - rsilft a12, 1, XTOS_LOCKLEVEL // lockout - rsr.intenable a12 - //movi a13, ~XCHAL_EXCM_MASK - movi a13, ~XTOS_LOCKOUT_MASK // mask out low and medium priority levels, and high priority levels covered by - // XTOS_LOCKLEVEL if any, so we can run at PS.INTLEVEL=0 while manipulating INTENABLE - s32i a12, a1, UEXC_sar // (temporary holding place for INTENABLE value to restore after pseudo-CALL4 below) - and a13, a12, a13 // mask out selected interrupts - wsr.intenable a13 // disable all interrupts up to and including XTOS_LOCKLEVEL -#endif - wsr.sar a14 - - movi a0, _xtos_return_from_exc -#ifdef __XTENSA_CALL0_ABI__ - jx a0 -#else /* ! __XTENSA_CALL0_ABI__ */ - /* Now return from the pseudo-CALL from the interrupted code, to rotate - * our windows back... */ - - movi a13, 0xC0000000 - //movi a13, 3 - //slli a13, a13, 30 -# if XCHAL_HAVE_INTERRUPTS - rsync //NOT-ISA-DEFINED // wait for WSR to INTENABLE to complete before doing RETW - // (ie. before underflow exception exit) - // (not needed, because underflow exception entry does implicit ISYNC ?? - // but in case underflow not taken, WSR must complete before wsr to PS that lowers PS.INTLEVEL - // possibly below XTOS_LOCKLEVEL, in which RETW's jump is not sufficient sync, so a sync - // is needed but it can be placed just before WSR to PS -- but here is fine) -# endif - or a0, a0, a13 // set upper two bits - addx2 a0, a13, a0 // clear upper bit - retw -#endif /* ! __XTENSA_CALL0_ABI__ */ - - /* FIXME: what about _GeneralException ? */ - - .size xtos_c_wrapper_handler, . - xtos_c_wrapper_handler - - -#endif /* XCHAL_HAVE_XEA1 && XCHAL_HAVE_EXCEPTIONS */ - diff --git a/src/arch/xtensa/xtos/xea1/exc-return.S b/src/arch/xtensa/xtos/xea1/exc-return.S deleted file mode 100644 index 25bfa32b71ab..000000000000 --- a/src/arch/xtensa/xtos/xea1/exc-return.S +++ /dev/null @@ -1,123 +0,0 @@ -// xea1/exc-return.S - Shared exception/interrupt return code - -// Copyright (c) 2002-2016 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/corebits.h> -#include <xtensa/config/specreg.h> -#include "../xtos-internal.h" - -#if XCHAL_HAVE_XEA1 && XCHAL_HAVE_EXCEPTIONS /* XEA1 always has exceptions */ - - .text - .align 4 - .global _xtos_return_from_exc -_xtos_return_from_exc: - -#ifdef __XTENSA_CALL0_ABI__ - - l32i a0, a1, UEXC_a0 // restore general registers, pc, ps - l32i a4, a1, UEXC_a4 - l32i a5, a1, UEXC_a5 - l32i a6, a1, UEXC_a6 - l32i a7, a1, UEXC_a7 - l32i a8, a1, UEXC_a8 - l32i a9, a1, UEXC_a9 - l32i a10, a1, UEXC_a10 - l32i a11, a1, UEXC_a11 - l32i a12, a1, UEXC_a12 - l32i a13, a1, UEXC_a13 - l32i a14, a1, UEXC_a14 - l32i a15, a1, UEXC_a15 - - l32i a2, a1, UEXC_pc - l32i a3, a1, UEXC_ps - wsr.epc1 a2 - wsr.ps a3 - - l32i a2, a1, UEXC_a2 - l32i a3, a1, UEXC_a3 - - rsync // wait for WSR to PS to complete - - addi a1, a1, ESF_TOTALSIZE // restore sp - - rfe - -#else /* ! __XTENSA_CALL0_ABI__ */ - - - // Here we rotated back by N registers, to the interrupted code's register window. - // NOTA: a2 and a3 might contain something useful, but we haven't determined - // what that might be yet (for now, a2 contains nested-C-func call-chain ptr). - - // NOTE: a5 still contains the exception window's exception stack frame pointer. - -# if XTOS_CNEST - s32i a2, a5, ESF_TOTALSIZE-20 // restore nested-C-func call-chain ptr -# endif - l32i a2, a5, UEXC_ps - l32i a3, a5, UEXC_pc - wsr.ps a2 // this sets INTLEVEL to 1; ... - -# if XCHAL_HAVE_INTERRUPTS - l32i a4, a5, UEXC_sar // load INTENABLE value that restores original vpri - l32i a2, a5, UEXC_a2 - rsync // wait for WSR to PS to complete - wsr.intenable a4 // update INTENABLE to restore original vpri (PS.INTLEVEL=1 here) - l32i a4, a5, UEXC_a4 -# else - l32i a2, a5, UEXC_a2 - l32i a4, a5, UEXC_a4 - rsync // wait for WSR to PS to complete -# endif - - /* FIXME: Enabling this here may break task-engine builds - * because task engines have exceptions (sort of), but they do - * not have the EPC_1 special register. XCHAL_HAVE_INTERRUPTS - * is incorrect for normal configs without interrupts but with - * exceptions (we still need to restore EPC_1). The correct - * solution is to define XCHAL_HAVE_EXCEPTIONS more strictly - * to mean something like "Have exceptions with - * user/kernel/double vectors" so that task engines are - * excluded. This would be a change to - * <xtensa/config/core.h>. */ - - wsr.epc1 a3 - // HERE: - // - we cannot get window overflows anymore -- we're NOT in a valid windowed context - // - low-priority interrupts are still disabled - - // NOTE: we don't restore EXCCAUSE or EXCVADDR, not needed. - - // Restore a3, a5: - l32i a3, a5, UEXC_a3 - l32i a5, a5, UEXC_a5 - - rfe_rfue - -#endif /* __XTENSA_CALL0_ABI__ */ - - .size _xtos_return_from_exc, . - _xtos_return_from_exc - -#endif /* XCHAL_HAVE_XEA1 && XCHAL_HAVE_EXCEPTIONS */ - diff --git a/src/arch/xtensa/xtos/xea1/int-lowpri-dispatcher.S b/src/arch/xtensa/xtos/xea1/int-lowpri-dispatcher.S deleted file mode 100644 index 500a2036e3bb..000000000000 --- a/src/arch/xtensa/xtos/xea1/int-lowpri-dispatcher.S +++ /dev/null @@ -1,324 +0,0 @@ -// XEA1 - Level-one interrupt dispatcher (user vectored handler) - -// Copyright (c) 1999-2016 Tensilica 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. - -#include <sof/lib/memory.h> - -#include <xtensa/coreasm.h> -#include "../xtos-internal.h" - -#if XCHAL_HAVE_XEA1 && XCHAL_HAVE_EXCEPTIONS && XCHAL_HAVE_INTERRUPTS - -#define _INTERRUPT_LEVEL 1 - - - // NOTE: something equivalent to the following vector is executed - // before entering this handler (see user-vector.S). -//_UserExceptionVector: -// addi a1, a1, -ESF_TOTALSIZE // allocate exception stack frame, etc. -// s32i a2, a1, UEXC_a2 -// s32i a3, a1, UEXC_a3 -// movi a3, xtos_exc_handler_table -// rsr.exccause a2 -// addx4 a2, a2, a3 -// l32i a2, a2, 0 -// s32i a4, a1, UEXC_a4 -// jx a2 // jump to cause-specific handler - - .global _need_user_vector_ // pull-in real user vector (tiny LSP) - - .text - .align 4 - .global _xtos_l1int_handler -_xtos_l1int_handler: - // HERE: a2, a3, a4 have been saved to exception stack frame allocated with a1 (sp). - - s32i a5, a1, UEXC_a5 // a5 will get clobbered by ENTRY after pseudo-CALL4 - // (a4..a15 spilled as needed; save if modified) - -#if HAVE_XSR - movi a2, PS_WOECALL4_ABI|PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL) - xsr.ps a2 - s32i a2, a1, UEXC_ps -#else - rsr.ps a2 - s32i a2, a1, UEXC_ps - movi a2, PS_WOECALL4_ABI|PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL) - wsr.ps a2 -#endif - rsync - - /* store pc */ - rsr.epc1 a2 - s32i a2, a1, UEXC_pc - - /* store rest of the registers */ - s32i a0, a1, UEXC_a0 - s32i a6, a1, UEXC_a6 - s32i a7, a1, UEXC_a7 - s32i a8, a1, UEXC_a8 - s32i a9, a1, UEXC_a9 - s32i a10, a1, UEXC_a10 - s32i a11, a1, UEXC_a11 - s32i a12, a1, UEXC_a12 - s32i a13, a1, UEXC_a13 - s32i a14, a1, UEXC_a14 - s32i a15, a1, UEXC_a15 - - /* store current sp */ - xtos_addr_percore a2, xtos_saved_sp - s32i a1, a2, 0 - - /* store current task sp */ - xtos_task_ctx_percore a2 - beqz a2, no_context - s32i a1, a2, TC_stack_pointer - -no_context: -# if XTOS_CNEST - l32i a2, a1, ESF_TOTALSIZE-20 // save nested-C-func call-chain ptr -# endif - addi a1, a1, ESF_TOTALSIZE -# if XTOS_DEBUG_PC - rsr.epc1 a4 // [for debug] get return PC - movi a5, 0xC0000000 // [for debug] setup call size... - or a4, a5, a4 // [for debug] set upper two bits of return PC - addx2 a4, a5, a4 // [for debug] clear upper bit -# else - movi a4, 0 /* terminate stack frames, overflow check */ -# endif - _entry a1, ESF_TOTALSIZE - -/* Reset the interrupt level to xtos locklevel (lvl 6 on most systems) */ - - rsil a15, XTOS_LOCKLEVEL - -/* Get bit list of pending interrupts at the current interrupt priority level. - * If bit list is empty, interrupt is spurious (can happen if a - * genuine interrupt brings control this direction, but the interrupt - * goes away before we read the INTERRUPT register). Also save off - * sar, loops, mac16 registers and coprocessors. */ - -#if __XCC__ -#if (XCHAL_CP_MASK & CP0_MASK) - mov a11, a1 - addi a11, a11, UEXC_cp0 - xchal_cp0_store a11, a12, a13, a14, a15 -#endif -#if (XCHAL_CP_MASK & CP1_MASK) - mov a11, a1 - addi a11, a11, UEXC_cp1 - xchal_cp1_store a11, a12, a13, a14, a15 -#endif -#endif - rsr.interrupt a15 - rsr.intenable a12 - movi a13, XCHAL_INTLEVEL1_MASK - and a15, a15, a12 - and a15, a15, a13 - rsr.sar a14 - s32i a14, a1, UEXC_sar - save_loops_mac16 a1, a13, a14 - - /* switch to interrupt stack */ - xtos_int_stack_addr_percore a13, _INTERRUPT_LEVEL, xtos_stack_for_interrupt - s32i a1, a13, 0 - addi a1, a13, SOF_STACK_SIZE - - _beqz a15, LABEL(spurious,int) - - /* set stack base and size for interrupt context */ - xtos_addr_percore a11, xtos_interrupt_ctx - s32i a13, a11, TC_stack_base - movi a13, SOF_STACK_SIZE - s32i a13, a11, TC_stack_size - - /* save task context */ - xtos_task_ctx_percore a13 - xtos_store_percore a13, a14, xtos_saved_ctx - - /* set interrupt task context */ - xtos_task_ctx_store_percore a11, a14 - - xtos_on_wakeup - -/* Loop to handle all pending interrupts. */ - -LABEL(.L1,_loop0): - neg a12, a15 - and a12, a12, a15 - wsr.intclear a12 // clear if edge-trig or s/w or wr/err (else no effect) -#if CONFIG_MULTICORE - xtos_addr_percore a13, xtos_interrupt_table -#else - movi a13, xtos_interrupt_table -#endif - find_ms_setbit a15, a12, a14, 0 - mapint a15 - addx8 a12, a15, a13 - l32i a13, a12, XIE_HANDLER - l32i a14, a12, XIE_ARG - mov a15, a1 - callx12 a13 - - rsr.interrupt a15 - rsr.intenable a12 - movi a13, XCHAL_INTLEVEL1_MASK - and a15, a15, a12 - and a15, a15, a13 - _bnez a15, LABEL(.L1,_loop0) - -/* Restore everything, and return. */ - - /* restore task context if needed */ - xtos_task_ctx_percore a11 - xtos_addr_percore a12, xtos_interrupt_ctx - bne a11, a12, restore_cp - xtos_addr_percore a12, xtos_saved_ctx - xtos_task_ctx_store_percore a12, a11 - -restore_cp: -#if __XCC__ -#if (XCHAL_CP_MASK & CP0_MASK) - xtos_task_ctx_percore a11 - beqz a11, no_context_2 - l32i a11, a11, TC_stack_pointer - addi a11, a11, UEXC_cp0 - xchal_cp0_load a11, a12, a13, a14, a15 -#endif -#if (XCHAL_CP_MASK & CP1_MASK) - xtos_task_ctx_percore a11 - beqz a11, no_context_2 - l32i a11, a11, TC_stack_pointer - addi a11, a11, UEXC_cp1 - xchal_cp1_load a11, a12, a13, a14, a15 -#endif -#endif - -no_context_2: - restore_loops_mac16 a1, a13, a14, a15 - l32i a14, a1, UEXC_sar -LABEL(spurious,int): - -#if XCHAL_HAVE_EXCLUSIVE - // Clear exclusive monitors. - clrex -#endif - - movi a0, LABEL(return,from_exc) - movi a13, 0xC0000000 - wsr.sar a14 - or a0, a0, a13 - addx2 a0, a13, a0 -# if _INTERRUPT_LEVEL < XCHAL_EXCM_LEVEL -/* Raise the interrupt mask before - * returning to avoid a race condition where we deallocate the - * exception stack frame but still have more register values to - * restore from it. */ - rsil a14, XCHAL_EXCM_LEVEL -# endif - retw -LABEL(return,from_exc): - /* a5 contains interrupt stack pointer */ - addi a5, a5, -SOF_STACK_SIZE - l32i a5, a5, 0 - -# if XTOS_CNEST - s32i a2, a5, ESF_TOTALSIZE-20 // restore nested-C-func call-chain ptr -# endif - - /* store sp after returning from handler */ - s32i a1, a5, UEXC_a1 - -restore: - /* load registers for window spill */ - l32i a4, a5, UEXC_a4 - l32i a6, a5, UEXC_a6 - l32i a7, a5, UEXC_a7 - l32i a8, a5, UEXC_a8 - l32i a9, a5, UEXC_a9 - l32i a10, a5, UEXC_a10 - l32i a11, a5, UEXC_a11 - l32i a12, a5, UEXC_a12 - l32i a13, a5, UEXC_a13 - l32i a14, a5, UEXC_a14 - - /* check if switch is needed */ - xtos_addr_percore a2, xtos_saved_sp - xtos_task_ctx_percore a1 - beqz a1, noSwitch - l32i a1, a1, TC_stack_pointer - l32i a0, a2, 0 - beq a0, a1, noSwitch - -doSwitch: - /* store new task sp */ - s32i a1, a2, 0 - - /* restore sp of task being preempted */ - l32i a1, a5, UEXC_a1 - - /* spill register windows to the stack */ - rsr.ps a2 - movi a3, PS_WOE_MASK - xor a2, a2, a3 - wsr.ps a2 - - call0 xthal_window_spill_nw - - /* restore previous ps */ - rsr.ps a2 - movi a3, PS_WOE_MASK - or a2, a2, a3 - wsr.ps a2 - - /* change stack */ - xtos_addr_percore a5, xtos_saved_sp - l32i a5, a5, 0 - j restore - -noSwitch: - /* restore ps and pc */ - l32i a0, a5, UEXC_ps - wsr.ps a0 - rsync - l32i a0, a5, UEXC_pc - wsr.epc1 a0 - - /* restore sar, loops and mac16 registers */ - l32i a0, a5, UEXC_sar - wsr.sar a0 - restore_loops_mac16 a5, a0, a1, a2 - - /* restore rest of the registers */ - l32i a0, a5, UEXC_a0 - l32i a1, a5, UEXC_a1 - l32i a2, a5, UEXC_a2 - l32i a3, a5, UEXC_a3 - l32i a15, a5, UEXC_a15 - l32i a5, a5, UEXC_a5 - rfe - - /* FIXME: what about _LevelOneInterrupt ? */ - .size _xtos_l1int_handler, . - _xtos_l1int_handler - -#endif /* XCHAL_HAVE_XEA1 && XCHAL_HAVE_EXCEPTIONS && XCHAL_HAVE_INTERRUPTS */ diff --git a/src/arch/xtensa/xtos/xea1/intlevel-restore.S b/src/arch/xtensa/xtos/xea1/intlevel-restore.S deleted file mode 100644 index 40b91dc1e6be..000000000000 --- a/src/arch/xtensa/xtos/xea1/intlevel-restore.S +++ /dev/null @@ -1,75 +0,0 @@ -// xea1/intlevel-restore.S - Interrupt related assembler code - _xtos_restore_intlevel - -// Copyright (c) 2004-2016 Tensilica 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. - - -#include <xtensa/coreasm.h> -#include <xtensa/config/specreg.h> -#include "../xtos-internal.h" - -#if XCHAL_HAVE_XEA1 - -/*************************************************************************** - * void _xtos_restore_intlevel(unsigned restoreval); - * - * _xtos_restore_intlevel() restores the current interrupt level - * according to a value returned by _xtos_set_intlevel() or - * _xtos_set_min_intlevel() (or one of the corresponding macros). - * - * NOTE: In XEA1, this function is implemented identically - * to _xtos_set_vpri(). - */ - -/*************************************************************************** - * _xtos_set_vpri() is used to set the current virtual priority from C code; - * it can be called from the application or from a C interrupt handler. - */ - - .text - .global _xtos_restore_intlevel - .type _xtos_restore_intlevel,@function - .global _xtos_set_vpri - .type _xtos_set_vpri,@function - .align 4 -_xtos_set_vpri: -_xtos_restore_intlevel: - abi_entry -#if XCHAL_HAVE_INTERRUPTS && XTOS_VIRTUAL_INTENABLE - mov a3, a2 -#if CONFIG_MULTICORE - xtos_addr_percore a4, xtos_intstruct -#else - movi a4, _xtos_intstruct -#endif - xtos_lock a7 // MUST USE highest address register of function to avoid window overflows in critical section - l32i a2, a4, XTOS_VPRI_ENABLED_OFS // return old xtos_vpri_enabled (current vpri) - l32i a5, a4, XTOS_ENABLED_OFS // a3 = xtos_enabled - s32i a3, a4, XTOS_VPRI_ENABLED_OFS // set new xtos_vpri_enabled (current vpri) - and a5, a5, a3 // a5 = xtos_enabled & xtos_vpri_enabled - wsr.intenable a5 - xtos_unlock a7 -#endif /*XCHAL_HAVE_INTERRUPTS*/ - abi_return - .size _xtos_set_vpri, . - _xtos_set_vpri - -#endif /* XEA1 */ - diff --git a/src/arch/xtensa/xtos/xea1/intlevel-set.S b/src/arch/xtensa/xtos/xea1/intlevel-set.S deleted file mode 100644 index b06736e7c2ed..000000000000 --- a/src/arch/xtensa/xtos/xea1/intlevel-set.S +++ /dev/null @@ -1,76 +0,0 @@ -// xea1/intlevel-set.S - Interrupt related assembler code - _xtos_set_intlevel - -// Copyright (c) 2004-2016 Tensilica 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. - - -#include <xtensa/coreasm.h> -#include <xtensa/config/specreg.h> -#include "../xtos-internal.h" - -#if XCHAL_HAVE_XEA1 - - -/*************************************************************************** - * unsigned _xtos_set_intlevel(int intlevel); - * - * _xtos_set_intlevel() is used to set the current priority from C code; - * it can be called from the application or from a C interrupt handler. - * - * NOTE: This version allows the 'intlevel' parameter to be computed - * at run-time, and thus is longer. It is much more efficient, and - * highly recommented, to use the XTOS_SET_INTLEVEL(intlevel) macro instead - * (which requires a constant intlevel). - */ - - .text - .align 4 - .global _xtos_set_intlevel - .type _xtos_set_intlevel,@function -_xtos_set_intlevel: - abi_entry -#if XCHAL_HAVE_INTERRUPTS - /* In XEA1, we have to rely on INTENABLE register virtualization: */ - movi a4, Xthal_intlevel_andbelow_mask - extui a3, a2, 0, 4 // keep only INTLEVEL bits of parameter - addx4 a5, a3, a4 // index mask to use - l32i a3, a5, 0 // get mask of interrupts at requested intlevel and below - movi a5, -1 // all 1's -#if CONFIG_MULTICORE - xtos_addr_percore a4, xtos_intstruct -#else - movi a4, _xtos_intstruct -#endif - xor a3, a3, a5 // mask of interrupts at intlevels above the requested one (to enable) - xtos_lock a7 // MUST USE highest address register of function to avoid window overflows in critical section - l32i a2, a4, XTOS_VPRI_ENABLED_OFS // return old xtos_vpri_enabled (current vpri) - l32i a5, a4, XTOS_ENABLED_OFS // a5 = xtos_enabled - s32i a3, a4, XTOS_VPRI_ENABLED_OFS // set new xtos_vpri_enabled (current vpri) - and a5, a5, a3 // a5 = xtos_enabled & xtos_vpri_enabled - wsr.intenable a5 - xtos_unlock a7 -#endif /*XCHAL_HAVE_INTERRUPTS*/ - abi_return - - .size _xtos_set_intlevel, . - _xtos_set_intlevel - -#endif /* XEA1 */ - diff --git a/src/arch/xtensa/xtos/xea1/intlevel-setmin.S b/src/arch/xtensa/xtos/xea1/intlevel-setmin.S deleted file mode 100644 index 051415d626ce..000000000000 --- a/src/arch/xtensa/xtos/xea1/intlevel-setmin.S +++ /dev/null @@ -1,79 +0,0 @@ -// xea1/intlevel-setmin.S - Interrupt related assembler code - _xtos_set_min_intlevel - -// Copyright (c) 2004-2016 Tensilica 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. - - -#include <xtensa/coreasm.h> -#include <xtensa/config/specreg.h> -#include "../xtos-internal.h" - -#if XCHAL_HAVE_XEA1 - - -/*************************************************************************** - * unsigned _xtos_set_min_intlevel(int intlevel); - * - * _xtos_set_min_intlevel() is identical to _xtos_set_intlevel() except - * that it will not lower the current interrupt level. Instead, - * it ensures that the current interrupt level is at least as high - * as specified. - * - * NOTE: This version allows the 'intlevel' parameter to be computed - * at run-time, and thus is longer. It is much more efficient, and - * highly recommented, to use the XTOS_SET_MIN_INTLEVEL(intlevel) macro instead - * (which requires a constant intlevel). - */ - - .text - .align 4 - .global _xtos_set_min_intlevel - .type _xtos_set_min_intlevel,@function -_xtos_set_min_intlevel: - abi_entry -#if XCHAL_HAVE_INTERRUPTS - /* In XEA1, we have to rely on INTENABLE register virtualization: */ - movi a4, Xthal_intlevel_andbelow_mask - extui a3, a2, 0, 4 // keep only INTLEVEL bits of parameter - addx4 a5, a3, a4 // index mask to use - l32i a3, a5, 0 // get mask of interrupts at requested intlevel and below - movi a5, -1 // all 1's -#if CONFIG_MULTICORE - xtos_addr_percore a4, xtos_intstruct -#else - movi a4, _xtos_intstruct -#endif - xor a3, a3, a5 // mask of interrupts at intlevels above the requested one (to enable) - xtos_lock a7 // MUST USE highest address register of function to avoid window overflows in critical section - l32i a2, a4, XTOS_VPRI_ENABLED_OFS // return old xtos_vpri_enabled (current vpri) - l32i a5, a4, XTOS_ENABLED_OFS // a5 = xtos_enabled - and a3, a3, a2 // make sure we don't enable any new interrupts - s32i a3, a4, XTOS_VPRI_ENABLED_OFS // set new xtos_vpri_enabled (current vpri) - and a5, a5, a3 // a5 = xtos_enabled & xtos_vpri_enabled - wsr.intenable a5 - xtos_unlock a7 -#endif /*XCHAL_HAVE_INTERRUPTS*/ - abi_return - - .size _xtos_set_min_intlevel, . - _xtos_set_min_intlevel - -#endif /* XEA1 */ - diff --git a/src/arch/xtensa/xtos/xea1/window-vectors.S b/src/arch/xtensa/xtos/xea1/window-vectors.S deleted file mode 100644 index 1670ed988429..000000000000 --- a/src/arch/xtensa/xtos/xea1/window-vectors.S +++ /dev/null @@ -1,355 +0,0 @@ -// window-vectors-xea1.S - Register Window Overflow/Underflow Handlers for XEA1 -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/xea1/window-vectors.S#1 $ - -// Copyright (c) 1999-2013 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/xtruntime-frames.h> - -#if XCHAL_HAVE_XEA1 -#if XCHAL_HAVE_WINDOWED && !defined(__XTENSA_CALL0_ABI__) - -# ifndef NO_SECTION_DIRECTIVES -// Exports -.global _WindowOverflow4 -.global _WindowUnderflow4 -.global _WindowOverflow8 -.global _WindowUnderflow8 -.global _WindowOverflow12 -.global _WindowUnderflow12 -.global _xtos_alloca_handler - - // Note: the current window exception vectors do not generate any - // literals. Hence the literal_prefix directive is not necessary. - // Specifying it "just in case" creates an empty section (named - // ".WindowVectors.literal") which can in some cases cause linking - // problems (the linker scripts don't place it anywhere). - // So leave it commented out: - // - //.begin literal_prefix .WindowVectors - - .section .WindowVectors.text, "ax" -# endif - - -// -// GENERAL NOTES: -// -// These window exception handlers need not be modified. -// They are specific to the windowed call ABI only. -// -// Underflow Handlers: -// -// The underflow handler for returning from call[i+1] to call[i] -// must preserve all the registers from call[i+1]'s window. -// In particular, a0 and a1 must be preserved because the RETW instruction -// will be reexecuted (and may even underflow again if an intervening -// exception has flushed call[i]'s registers). -// Registers a2 and up may contain return values. -// -// The caller could also potentially assume that the callee's a0 and a1 -// (its own a4&a5 if call4, a8&a9 if call8, a12&a13 if call12) -// are correct for whatever reason (not a clean thing to do in general, -// but if it's possible, unless the ABI explicitly prohibits it, -// it will eventually be done :) -- whether the the ABI needs to -// prohibit this is a different question). -// -// Timing of Handlers: -// -// Here is an overview of the overhead of taking a window exception, -// ie. the number of additional cycles taken relative to case where -// an exception is not taken. -// NOTE: these numbers do not take into account any cache misses, -// write buffer stalls, or other external stalls, if they occur. -// The totals consist of 5 cycles to enter the handler (or 6 or 7 -// for optional longer pipelines in Xtensa LX), the number of instructions -// and interlocks (2nd and 3rd columns below), and 2 cycles jump delay -// on return (3 cycles for optional longer I-side pipeline in Xtensa LX): -// -// Instruction+bubbles Totals (5-stage) -// XEA1 XEA2 XEA1 XEA2 -// Overflow-4 7 5 14 12 -// Overflow-8 14 10 21 17 -// Overflow-12 18 14 25 21 -// Underflow-4 6 5 13 12 -// Underflow-8 14 10 21 17 -// Underflow-12 18 14 25 21 -// -// Underflow-8 15 12 25 22 (7-stage; could be made 1 less) -// Underflow-12 19 16 29 26 (7-stage; could be made 1 less) - -#ifndef WINDOW_BASE_VECOFS -#define WINDOW_BASE_VECOFS XCHAL_WINDOW_OF4_VECOFS -#endif - - -// 4-Register Window Overflow Vector (Handler) -// -// Invoked if a call[i] referenced a register (a4-a15) -// that contains data from ancestor call[j]; -// call[j] had done a call4 to call[j+1]. -// On entry here: -// window rotated to call[j] start point; -// a0-a3 are registers to be saved; -// a4-a15 must be preserved; -// a5 is call[j+1]'s stack pointer. - - .org XCHAL_WINDOW_OF4_VECOFS - WINDOW_BASE_VECOFS -_WindowOverflow4: - addi a5, a5, -16 // to make store offsets positive - s32i a0, a5, 0 // save a0 to call[j+1]'s stack frame - s32i a1, a5, 4 // save a1 to call[j+1]'s stack frame - s32i a2, a5, 8 // save a2 to call[j+1]'s stack frame - s32i a3, a5, 12 // save a3 to call[j+1]'s stack frame - addi a5, a5, 16 // restore a5 - rfwo // rotates back to call[i] position - - .size _WindowOverflow4, . - _WindowOverflow4 - - -// ALLOCA exception handler -// -// NOTE: The alloca exception handler is squeezed in between the window exception -// handlers in order to save space, and also to allow short-range jumps to the -// window underflow handlers (see below for why). Because of the limited space in -// between the window handlers, this function is split into two to fit. -// -// Code written to the windowed ABI must use the MOVSP instruction to modify -// the stack pointer (except for startup code, which doesn't have a caller). -// The compiler uses MOVSP to allocate very large or variable size stack frames. -// MOVSP guarantees that the caller frame's a0-a3 registers, stored below the -// stack pointer, are moved atomically with respect to interrupts and exceptions -// to satisfy windowed ABI requirements. When user code executes the MOVSP -// instruction and the caller frame is on the stack rather than in the register -// file, the processor takes an ALLOCA exception. -// -// The XTOS user exception dispatcher allocates an exception frame on the -// stack and saves a2-a4 into that frame before calling us. So we need to -// restore those registers and deallocate the stack frame before jumping -// to the window underflow handler - which will restore the spilled registers -// back into the register file. -// The fact the alloca exception was taken means the registers associated with -// the base-save area have been spilled and will be restored by the underflow -// handler, so those 4 registers are available for scratch. - - .align 4 - -_xtos_alloca_handler: - - l32i a2, a1, UEXC_a2 // restore a2-a4 and deallocate frame - l32i a3, a1, UEXC_a3 - l32i a4, a1, UEXC_a4 - addi a1, a1, ESF_TOTALSIZE - wsr.excsave1 a0 // save a0 - rsr.windowbase a0 // grab WINDOWBASE before rotw changes it - rotw -1 // WINDOWBASE goes to a4, new a0-a3 are scratch - rsr.ps a2 - extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS - xor a3, a3, a4 // bits changed from old to current windowbase - j _xtos_alloca_2 // not enough room here... - - .size _xtos_alloca_handler, . - _xtos_alloca_handler - - -// 4-Register Window Underflow Vector (Handler) -// -// Invoked by RETW returning from call[i+1] to call[i] -// where call[i]'s registers must be reloaded (not live in ARs); -// call[i] had done a call4 to call[i+1]. -// On entry here: -// window rotated to call[i] start point; -// a0-a3 are undefined, must be reloaded with call[i].reg[0..3]; -// a4-a15 must be preserved (they are call[i+1].reg[0..11]); -// a5 is call[i+1]'s stack pointer. - - .org XCHAL_WINDOW_UF4_VECOFS - WINDOW_BASE_VECOFS -_WindowUnderflow4: - addi a3, a5, -16 // to make load offsets positive - l32i a0, a3, 0 // restore a0 from call[i+1]'s stack frame - l32i a1, a3, 4 // restore a1 from call[i+1]'s stack frame - l32i a2, a3, 8 // restore a2 from call[i+1]'s stack frame - l32i a3, a3, 12 // restore a3 from call[i+1]'s stack frame - rfwu - - .size _WindowUnderflow4, . - _WindowUnderflow4 - - -// This is the second part of the alloca handler. - - .align 4 - -_xtos_alloca_2: - - rsr.excsave1 a4 // restore original a0 (now in a4) - slli a3, a3, XCHAL_PS_OWB_SHIFT - xor a2, a2, a3 // flip changed bits in old window base - wsr.ps a2 // update PS.OWB to new window base - rsync - _bbci.l a4, 31, _WindowUnderflow4 - rotw -1 // original a0 goes to a8 - _bbci.l a8, 30, _WindowUnderflow8 - rotw -1 - j _WindowUnderflow12 - - .size _xtos_alloca_2, . - _xtos_alloca_2 - -// 8-Register Window Overflow Vector (Handler) -// -// Invoked if a call[i] referenced a register (a4-a15) -// that contains data from ancestor call[j]; -// call[j] had done a call8 to call[j+1]. -// On entry here: -// window rotated to call[j] start point; -// a0-a7 are registers to be saved; -// a8-a15 must be preserved; -// a9 is call[j+1]'s stack pointer. - - .org XCHAL_WINDOW_OF8_VECOFS - WINDOW_BASE_VECOFS -_WindowOverflow8: - addi a9, a9, -16 // to make store offsets positive - s32i a0, a9, 0 // save a0 to call[j+1]'s stack frame - addi a0, a1, -16 // a0 <- call[j-1]'s sp - s32i a1, a9, 4 // save a1 to call[j+1]'s stack frame - l32i a0, a0, 4 // (used to find end of call[j]'s frame) - s32i a2, a9, 8 // save a2 to call[j+1]'s stack frame - s32i a3, a9, 12 // save a3 to call[j+1]'s stack frame - addi a9, a9, 16 // restore a9 - addi a0, a0, -32 // to make load offsets positive - s32i a4, a0, 0 // save a4 to call[j]'s stack frame - s32i a5, a0, 4 // save a5 to call[j]'s stack frame - s32i a6, a0, 8 // save a6 to call[j]'s stack frame - s32i a7, a0, 12 // save a7 to call[j]'s stack frame - rfwo // rotates back to call[i] position - - .size _WindowOverflow8, . - _WindowOverflow8 - - -// 8-Register Window Underflow Vector (Handler) -// -// Invoked by RETW returning from call[i+1] to call[i] -// where call[i]'s registers must be reloaded (not live in ARs); -// call[i] had done a call8 to call[i+1]. -// On entry here: -// window rotated to call[i] start point; -// a0-a7 are undefined, must be reloaded with call[i].reg[0..7]; -// a8-a15 must be preserved (they are call[i+1].reg[0..7]); -// a9 is call[i+1]'s stack pointer. - - .org XCHAL_WINDOW_UF8_VECOFS - WINDOW_BASE_VECOFS -_WindowUnderflow8: - addi a9, a9, -16 // to make load offsets positive - l32i a0, a9, 0 // restore a0 from call[i+1]'s stack frame - l32i a1, a9, 4 // restore a1 from call[i+1]'s stack frame - l32i a2, a9, 8 // restore a2 from call[i+1]'s stack frame - addi a7, a1, -16 // a7 <- call[i-1]'s sp - l32i a7, a7, 4 // (used to find end of call[i]'s frame) - l32i a3, a9, 12 // restore a3 from call[i+1]'s stack frame - addi a9, a9, 16 // restore a9 - addi a7, a7, -32 // to make load offsets positive - l32i a4, a7, 0 // restore a4 from call[i]'s stack frame - l32i a5, a7, 4 // restore a5 from call[i]'s stack frame - l32i a6, a7, 8 // restore a6 from call[i]'s stack frame - l32i a7, a7, 12 // restore a7 from call[i]'s stack frame - rfwu - - .size _WindowUnderflow8, . - _WindowUnderflow8 - - -// 12-Register Window Overflow Vector (Handler) -// -// Invoked if a call[i] referenced a register (a4-a15) -// that contains data from ancestor call[j]; -// call[j] had done a call12 to call[j+1]. -// On entry here: -// window rotated to call[j] start point; -// a0-a11 are registers to be saved; -// a12-a15 must be preserved; -// a13 is call[j+1]'s stack pointer. - - .org XCHAL_WINDOW_OF12_VECOFS - WINDOW_BASE_VECOFS -_WindowOverflow12: - addi a13, a13, -16 // to make store offsets positive - s32i a0, a13, 0 // save a0 to call[j+1]'s stack frame - addi a0, a1, -16 // a0 <- call[j-1]'s sp - s32i a1, a13, 4 // save a1 to call[j+1]'s stack frame - l32i a0, a0, 4 // (used to find end of call[j]'s frame) - s32i a2, a13, 8 // save a2 to call[j+1]'s stack frame - s32i a3, a13, 12 // save a3 to call[j+1]'s stack frame - addi a13, a13, 16 // restore a13 - addi a0, a0, -48 // to make load offsets positive - s32i a4, a0, 0 // save a4 to end of call[j]'s stack frame - s32i a5, a0, 4 // save a5 to end of call[j]'s stack frame - s32i a6, a0, 8 // save a6 to end of call[j]'s stack frame - s32i a7, a0, 12 // save a7 to end of call[j]'s stack frame - s32i a8, a0, 16 // save a8 to end of call[j]'s stack frame - s32i a9, a0, 20 // save a9 to end of call[j]'s stack frame - s32i a10, a0, 24 // save a10 to end of call[j]'s stack frame - s32i a11, a0, 28 // save a11 to end of call[j]'s stack frame - rfwo // rotates back to call[i] position - - .size _WindowOverflow12, . - _WindowOverflow12 - - -// 12-Register Window Underflow Vector (Handler) -// -// Invoked by RETW returning from call[i+1] to call[i] -// where call[i]'s registers must be reloaded (not live in ARs); -// call[i] had done a call12 to call[i+1]. -// On entry here: -// window rotated to call[i] start point; -// a0-a11 are undefined, must be reloaded with call[i].reg[0..11]; -// a12-a15 must be preserved (they are call[i+1].reg[0..3]); -// a13 is call[i+1]'s stack pointer. - - .org XCHAL_WINDOW_UF12_VECOFS - WINDOW_BASE_VECOFS -_WindowUnderflow12: - addi a13, a13, -16 // to make load offsets positive - l32i a0, a13, 0 // restore a0 from call[i+1]'s stack frame - l32i a1, a13, 4 // restore a1 from call[i+1]'s stack frame - l32i a2, a13, 8 // restore a2 from call[i+1]'s stack frame - addi a11, a1, -16 // a11 <- call[i-1]'s sp - l32i a11, a11, 4 // (used to find end of call[i]'s frame) - l32i a3, a13, 12 // restore a3 from call[i+1]'s stack frame - addi a13, a13, 16 // restore a13 - addi a11, a11, -48 // to make load offsets positive - l32i a4, a11, 0 // restore a4 from end of call[i]'s stack frame - l32i a5, a11, 4 // restore a5 from end of call[i]'s stack frame - l32i a6, a11, 8 // restore a6 from end of call[i]'s stack frame - l32i a7, a11, 12 // restore a7 from end of call[i]'s stack frame - l32i a8, a11, 16 // restore a8 from end of call[i]'s stack frame - l32i a9, a11, 20 // restore a9 from end of call[i]'s stack frame - l32i a10, a11, 24 // restore a10 from end of call[i]'s stack frame - l32i a11, a11, 28 // restore a11 from end of call[i]'s stack frame - rfwu - - .size _WindowUnderflow12, . - _WindowUnderflow12 - - -# ifndef NO_SECTION_DIRECTIVES - //.end literal_prefix - .text -# endif - - -#endif /* XCHAL_HAVE_WINDOWED && !defined(__XTENSA_CALL0_ABI__) */ -#endif /* XCHAL_HAVE_XEA1 */ - diff --git a/src/arch/xtensa/xtos/xea2/exc-c-wrapper-handler.S b/src/arch/xtensa/xtos/xea2/exc-c-wrapper-handler.S deleted file mode 100644 index 08beb65b6b3a..000000000000 --- a/src/arch/xtensa/xtos/xea2/exc-c-wrapper-handler.S +++ /dev/null @@ -1,361 +0,0 @@ -// exc-c-wrapper-handler.S - General Exception Handler that Dispatches C Handlers - -// Copyright (c) 2002-2017 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. - -#include <xtensa/coreasm.h> -#include <xtensa/corebits.h> -#include "../xtos-internal.h" - -#if XCHAL_HAVE_XEA2 && XCHAL_HAVE_EXCEPTIONS - - -/* - * This assembly-level handler causes the associated exception (usually causes 12-15) - * to be handled as if it were exception cause 3 (load/store error exception). - * This provides forward-compatibility with a possible future split of the - * load/store error cause into multiple more specific causes. - */ - .align 4 - .global xtos_cause3_handler -xtos_cause3_handler: - movi a2, EXCCAUSE_LOAD_STORE_ERROR - j xtos_c_wrapper_handler - .size xtos_cause3_handler, . - xtos_cause3_handler - - - .align 4 -.Lhi: addi a2, a2, -XCHAL_EXCM_LEVEL - add a2, a2, a3 - j .Lps - - -/* - * This is the general exception assembly-level handler that dispatches C handlers. - */ - .align 4 - .global xtos_c_wrapper_handler -xtos_c_wrapper_handler: -#ifdef __XTENSA_CALL0_ABI__ - // Redundantly de-allocate and re-allocate stack, so that GDB prologue - // analysis picks up the allocate part, and figures out how to traceback - // through the call stack through the exception. - addi a1, a1, ESF_TOTALSIZE // de-allocate stack frame (FIXME is it safe) -.global xtos_c_wrapper_dispatch -xtos_c_wrapper_dispatch: - // GDB starts analyzing prologue after most recent global symbol, so here: - addi a1, a1, -ESF_TOTALSIZE // re-allocate stack frame -#endif - - // HERE: a2, a3, a4 have been saved to exception stack frame allocated with a1 (sp). - // a2 contains EXCCAUSE. - s32i a5, a1, UEXC_a5 // a5 will get clobbered by ENTRY after the pseudo-CALL4 - // (a4..a15 spilled as needed; save if modified) - - //NOTA: Possible future improvement: - // keep interrupts disabled until we get into the handler, such that - // we don't have to save other critical state such as EXCVADDR here. - //rsr.excvaddr a3 - s32i a2, a1, UEXC_exccause - //s32i a3, a1, UEXC_excvaddr - - // Set PS fields: - // EXCM = 0 - // WOE = __XTENSA_CALL0_ABI__ ? 0 : 1 - // UM = 1 - // INTLEVEL = MIN(INTLEVEL,EXCM_LEVEL) - // CALLINC = __XTENSA_CALL0_ABI__ ? 0 : 1 - // OWB = 0 (really, a dont care if !__XTENSA_CALL0_ABI__) - - rsr.ps a3 - movi a2, PS_WOECALL4_ABI|PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL) // CALL4 emulation - s32i a3, a1, UEXC_ps - extui a3, a3, 0, 4 // extract PS.INTLEVEL - bgeui a3, XCHAL_EXCM_LEVEL+1, .Lhi // at PS.INTLEVEL > EXCM_LEVEL ? -.Lps: rsr.epc1 a3 - wsr.ps a2 - - // HERE: window overflows enabled, but NOT SAFE because we're not quite - // in a valid windowed context (haven't restored a1 yet...); - // so don't cause any (keep to a0..a3) until we've saved critical state and restored a1: - - // NOTE: MUST SAVE EPC1 before causing any overflows, because overflows corrupt EPC1. - s32i a3, a1, UEXC_pc - -#ifdef __XTENSA_CALL0_ABI__ - - s32i a0, a1, UEXC_a0 // save the rest of the registers - s32i a6, a1, UEXC_a6 - s32i a7, a1, UEXC_a7 - s32i a8, a1, UEXC_a8 - s32i a9, a1, UEXC_a9 - s32i a10, a1, UEXC_a10 - s32i a11, a1, UEXC_a11 - s32i a12, a1, UEXC_a12 - s32i a13, a1, UEXC_a13 - s32i a14, a1, UEXC_a14 - s32i a15, a1, UEXC_a15 -# if XTOS_DEBUG_PC - // TODO: setup return PC for call traceback through interrupt dispatch -# endif - - rsync // wait for WSR to PS to complete - -#else /* ! __XTENSA_CALL0_ABI__ */ - -# if XTOS_CNEST - l32i a2, a1, ESF_TOTALSIZE-20 // save nested-C-func call-chain ptr -# endif - addi a1, a1, ESF_TOTALSIZE // restore sp (dealloc ESF) for sane stack again - rsync // wait for WSR to PS to complete - - /* HERE: we can SAFELY get window overflows. - * - * From here, registers a4..a15 automatically get spilled if needed. - * They become a0..a11 after the ENTRY instruction. - * Currently, we don't check whether or not these registers - * get spilled, so we must save and restore any that we - * modify. We've already saved a4 and a5 - * which we modify as part of the pseudo-CALL. - * - * IMPLEMENTATION NOTE: - * - * The pseudo-CALL below effectively saves registers a2..a3 so - * that they are available again after the corresponding - * RETW when returning from the exception handling. We - * could choose to put something like EPC1 or PS in - * there, so they're available more quickly when - * restoring. HOWEVER, exception handlers may wish to - * change such values, or anything on the exception stack - * frame, and expect these to be restored as modified. - * - * NOTA: future: figure out what's the best thing to put - * in a2 and a3. (candidate: a4 and a5 below; but what - * if exception handler manipulates ARs, as in a syscall - * handler.... oh well) - * - * - * Now do the pseudo-CALL. - * Make it look as if the code that got the exception made a - * CALL4 to the exception handling code. (We call - * this the "pseudo-CALL".) - * - * This pseudo-CALL is important and done this way: - * - * 1. There are only three ways to safely update the stack pointer - * in the windowed ABI, such that window exceptions work correctly: - * (a) spill all live windows to stack then switch to a new stack - * (or, save the entire address register file and window - * registers, which is likely even more expensive) - * (b) use MOVSP (or equivalent) - * (c) use ENTRY/RETW - * Doing (a) is excessively expensive, and doing (b) here requires - * copying 16 bytes back and forth which is also time-consuming; - * whereas (c) is very efficient, so that's what we do here. - * - * 2. Normally we cannot do a pseudo-CALL8 or CALL12 here. - * According to the - * windowed ABI, a function must allocate enough space - * for the largest call that it makes. However, the - * pseudo-CALL is executed in the context of the - * function that happened to be executing at the time - * the interrupt was taken, and that function might or - * might not have allocated enough stack space for a - * CALL8 or a CALL12. If we try doing a pseudo-CALL8 - * or -CALL12 here, we corrupt the stack if the - * interrupted function happened to not have allocated - * space for such a call. - * - * 3. We set the return PC, but it's not strictly - * necessary for proper operation. It does make - * debugging, ie. stack tracebacks, much nicer if it - * can point to the interrupted code (not always - * possible, eg. if interrupted code is in a different - * GB than the interrupt handling code, which is - * unlikely in a system without protection where - * interrupt handlers and general application code are - * typically linked together). - * - * IMPORTANT: Interrupts must stay disabled while doing the pseudo-CALL, - * or at least until after the ENTRY instruction, because SP has been - * restored to its original value that does not reflect the exception - * stack frame's allocation. An interrupt taken here would - * corrupt the exception stack frame (ie. allocate another over it). - * (High priority interrupts can remain enabled, they save and restore - * all of their state and use their own stack or save area.) - * For the same reason, we mustn't get any exceptions in this code - * (other than window exceptions where noted) until ENTRY is done. - */ - - // HERE: may get a single window overflow (caused by the following instruction). - -# if XTOS_DEBUG_PC - movi a4, 0xC0000000 // [for debug] for return PC computation below - or a3, a4, a3 // [for debug] set upper two bits of return PC - addx2 a4, a4, a3 // [for debug] clear upper bit -# else - movi a4, 0 // entry cannot cause overflow, cause it here -# endif - - _entry a1, ESF_TOTALSIZE // as if after a CALL4 (PS.CALLINC set to 1 above) - - /* - * The above ENTRY instruction does a number of things: - * - * 1. Because we're emulating CALL4, the ENTRY rotates windows - * forward by 4 registers (as per 'ROTW +1'), so that - * a4-a15 became a0-a11. So now: a0-a11 are part of - * the interrupted context to be preserved. a0-a1 - * were already saved above when they were a4-a5. - * a12-a15 are free to use as they're NOT part of the - * interrupted context. We don't need to save/restore - * them, and they will get spilled if needed. - * - * 2. Updates SP (new a1), allocating the exception stack - * frame in the new window, preserving the old a1 in - * the previous window. - * - * 3. The underscore prefix prevents the assembler from - * automatically aligning the ENTRY instruction on a - * 4-byte boundary, which could create a fatal gap in - * the instruction stream. - * - * At this point, ie. before we re-enable interrupts, we know the caller is - * always live so we can safely modify a1 without using MOVSP (we can use MOVSP - * but it will never cause an ALLOCA or underflow exception here). - * So this is a good point to modify the stack pointer if we want eg. to - * switch to an interrupt stack (if we do, we need to save the current SP - * because certain things have been saved to that exception stack frame). - * We couldn't do this easily before ENTRY, where the caller wasn't - * necessarily live. - * - * NOTE: We don't switch to an interrupt stack here, because exceptions - * are generally caused by executing code -- so we handle exceptions in - * the context of the thread that cause them, and thus remain on the same - * stack. This means a thread's stack must be large enough to handle - * the maximum level of nesting of exceptions that the thread can cause. - */ - - // NOTA: exception handlers for certain causes may need interrupts to be kept - // disabled through their dispatch, so they can turn them off themselves at - // the right point (if at all), eg. to save critical state unknown to this - // code here, or for some recovery action that must be atomic with respect - // to interrupts.... - // - // Perhaps two versions of this assembly-level handler are needed, one that restores - // interrupts to what they were before the exception was taken (as here) - // and one that ensures at least low-priority interrupts are kept disabled? - // NOTA: For now, always enable interrupts here. - - /* - * Now we can enable interrupts. - * (Pseudo-CALL is complete, and SP reflects allocation of exception stack frame.) - */ - -#endif /* __XTENSA_CALL0_ABI__ */ - - -#if XCHAL_HAVE_INTERRUPTS - rsr.sar a12 - // Restore PS.INTLEVEL to its saved value (re-enables interrupts - // if they were enabled before taking the exception): - l32i a13, a1, UEXC_ps - rsr.ps a14 - extui a13, a13, 0, 4 // extract saved PS.INTLEVEL - extui a15, a14, 0, 4 // extract current PS.INTLEVEL - xor a14, a14, a15 // clear a14.INTLEVEL - xor a14, a14, a13 // replace with saved PS.INTLEVEL - wsr.ps a14 // restore PS.INTLEVEL -#else - rsr.sar a12 -#endif - - movi a13, xtos_c_handler_table // &table - l32i a15, a1, UEXC_exccause // arg2: exccause - - s32i a12, a1, UEXC_sar - save_loops_mac16 a1, a12, a14 // save LOOP & MAC16 regs, if configured - - addx4 a12, a15, a13 // a12 = table[exccause] - l32i a12, a12, 0 // ... - .global _GeneralException -_GeneralException: // this label makes tracebacks through exceptions look nicer - -#ifdef __XTENSA_CALL0_ABI__ - .global _GeneralExceptionFrameSize - .set _GeneralExceptionFrameSize, ESF_TOTALSIZE - .global _GeneralExceptionRegisterSaveOffset - .set _GeneralExceptionRegisterSaveOffset, UEXC_a0 - mov a2, a1 // arg1: exception parameters - mov a3, a15 // arg2: exccause - beqz a12, 1f // null handler => skip call - callx0 a12 // call C exception handler for this exception -#else - mov a14, a1 // arg1: exception parameters - // mov a15, a15 // arg2: exccause, already in a15 - beqz a12, 1f // null handler => skip call - callx12 a12 // call C exception handler for this exception -#endif - .size _GeneralException, . - _GeneralException -1: - // Now exit the handler. - - - // Restore special registers - - restore_loops_mac16 a1, a13, a14, a15 // restore LOOP & MAC16 regs, if configured - l32i a14, a1, UEXC_sar - - /* - * Disable interrupts while returning from the pseudo-CALL setup above, - * for the same reason they were disabled while doing the pseudo-CALL: - * this sequence restores SP such that it doesn't reflect the allocation - * of the exception stack frame, which we still need to return from - * the exception. - */ - -#if XCHAL_HAVE_INTERRUPTS - rsil a12, XCHAL_EXCM_LEVEL -#endif - wsr.sar a14 - - movi a0, _xtos_return_from_exc -#ifdef __XTENSA_CALL0_ABI__ - jx a0 -#else /* ! __XTENSA_CALL0_ABI__ */ - /* Now return from the pseudo-CALL from the interrupted code, to rotate - * our windows back... */ - - movi a13, 0xC0000000 - //movi a13, 3 - //slli a13, a13, 30 - or a0, a0, a13 // set upper two bits - addx2 a0, a13, a0 // clear upper bit - retw -#endif /* ! __XTENSA_CALL0_ABI__ */ - - /* FIXME: what about _GeneralException ? */ - - .size xtos_c_wrapper_handler, . - xtos_c_wrapper_handler - - -#endif /* XCHAL_HAVE_XEA2 && XCHAL_HAVE_EXCEPTIONS */ - diff --git a/src/arch/xtensa/xtos/xea2/exc-return.S b/src/arch/xtensa/xtos/xea2/exc-return.S deleted file mode 100644 index 083d78206905..000000000000 --- a/src/arch/xtensa/xtos/xea2/exc-return.S +++ /dev/null @@ -1,114 +0,0 @@ -// exc-return.S - Shared exception/interrupt return code - -// Copyright (c) 2002-2015 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/corebits.h> -#include "../xtos-internal.h" - -#if XCHAL_HAVE_XEA2 && XCHAL_HAVE_EXCEPTIONS - - .text - .align 4 - .global _xtos_return_from_exc -_xtos_return_from_exc: - -#ifdef __XTENSA_CALL0_ABI__ - - l32i a0, a1, UEXC_a0 // restore general registers, pc, ps - l32i a4, a1, UEXC_a4 - l32i a5, a1, UEXC_a5 - l32i a6, a1, UEXC_a6 - l32i a7, a1, UEXC_a7 - l32i a8, a1, UEXC_a8 - l32i a9, a1, UEXC_a9 - l32i a10, a1, UEXC_a10 - l32i a11, a1, UEXC_a11 - l32i a12, a1, UEXC_a12 - l32i a13, a1, UEXC_a13 - l32i a14, a1, UEXC_a14 - l32i a15, a1, UEXC_a15 - - l32i a2, a1, UEXC_pc - l32i a3, a1, UEXC_ps - wsr.epc1 a2 - wsr.ps a3 - - l32i a2, a1, UEXC_a2 - l32i a3, a1, UEXC_a3 - - rsync // wait for WSR to PS to complete - - addi a1, a1, ESF_TOTALSIZE // restore sp - - rfe - -#else /* ! __XTENSA_CALL0_ABI__ */ - - - // Here we rotated back by N registers, to the interrupted code's register window. - // NOTA: a2 and a3 might contain something useful, but we haven't determined - // what that might be yet (for now, a2 contains nested-C-func call-chain ptr). - - // NOTE: a5 still contains the exception window's exception stack frame pointer. - -# if XTOS_CNEST - s32i a2, a5, ESF_TOTALSIZE-20 // restore nested-C-func call-chain ptr -# endif - l32i a2, a5, UEXC_ps - l32i a3, a5, UEXC_pc - wsr.ps a2 // this sets PS.EXCM - - l32i a2, a5, UEXC_a2 - l32i a4, a5, UEXC_a4 - rsync // wait for WSR to PS to complete - - /* FIXME: Enabling this here may break task-engine builds - * because task engines have exceptions (sort of), but they do - * not have the EPC_1 special register. XCHAL_HAVE_INTERRUPTS - * is incorrect for normal configs without interrupts but with - * exceptions (we still need to restore EPC_1). The correct - * solution is to define XCHAL_HAVE_EXCEPTIONS more strictly - * to mean something like "Have exceptions with - * user/kernel/double vectors" so that task engines are - * excluded. This would be a change to - * <xtensa/config/core.h>. */ - - wsr.epc1 a3 - // HERE: - // - we cannot get window overflows anymore -- we're NOT in a valid windowed context - // - low-priority interrupts are still disabled - - // NOTE: we don't restore EXCCAUSE or EXCVADDR, not needed. - - // Restore a3, a5: - l32i a3, a5, UEXC_a3 - l32i a5, a5, UEXC_a5 - - rfe_rfue - -#endif /* __XTENSA_CALL0_ABI__ */ - - .size _xtos_return_from_exc, . - _xtos_return_from_exc - -#endif /* XCHAL_HAVE_XEA2 && XCHAL_HAVE_EXCEPTIONS */ - diff --git a/src/arch/xtensa/xtos/xea2/int-lowpri-dispatcher.S b/src/arch/xtensa/xtos/xea2/int-lowpri-dispatcher.S deleted file mode 100644 index 02453b5c5a4d..000000000000 --- a/src/arch/xtensa/xtos/xea2/int-lowpri-dispatcher.S +++ /dev/null @@ -1,324 +0,0 @@ -// Level-one interrupt dispatcher (user vectored handler) - -// Copyright (c) 1999-2015 Tensilica 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. - -#include <sof/lib/memory.h> - -#include <xtensa/coreasm.h> -#include "../xtos-internal.h" - -#if XCHAL_HAVE_XEA2 && XCHAL_HAVE_EXCEPTIONS && XCHAL_HAVE_INTERRUPTS - -#define _INTERRUPT_LEVEL 1 - - - // NOTE: something equivalent to the following vector is executed - // before entering this handler (see user-vector.S). -//_UserExceptionVector: -// addi a1, a1, -ESF_TOTALSIZE // allocate exception stack frame, etc. -// s32i a2, a1, UEXC_a2 -// s32i a3, a1, UEXC_a3 -// movi a3, xtos_exc_handler_table -// rsr.exccause a2 -// addx4 a2, a2, a3 -// l32i a2, a2, 0 -// s32i a4, a1, UEXC_a4 -// jx a2 // jump to cause-specific handler - - .global _need_user_vector_ // pull-in real user vector (tiny LSP) - - .text - .align 4 - .global _xtos_l1int_handler -_xtos_l1int_handler: - // HERE: a2, a3, a4 have been saved to exception stack frame allocated with a1 (sp). - - s32i a5, a1, UEXC_a5 // a5 will get clobbered by ENTRY after pseudo-CALL4 - // (a4..a15 spilled as needed; save if modified) - -#if HAVE_XSR - movi a2, PS_WOECALL4_ABI|PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL) - xsr.ps a2 - s32i a2, a1, UEXC_ps -#else - rsr.ps a2 - s32i a2, a1, UEXC_ps - movi a2, PS_WOECALL4_ABI|PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL) - wsr.ps a2 -#endif - rsync - - /* store pc */ - rsr.epc1 a2 - s32i a2, a1, UEXC_pc - - /* store rest of the registers */ - s32i a0, a1, UEXC_a0 - s32i a6, a1, UEXC_a6 - s32i a7, a1, UEXC_a7 - s32i a8, a1, UEXC_a8 - s32i a9, a1, UEXC_a9 - s32i a10, a1, UEXC_a10 - s32i a11, a1, UEXC_a11 - s32i a12, a1, UEXC_a12 - s32i a13, a1, UEXC_a13 - s32i a14, a1, UEXC_a14 - s32i a15, a1, UEXC_a15 - - /* store current sp */ - xtos_addr_percore a2, xtos_saved_sp - s32i a1, a2, 0 - - /* store current task sp */ - xtos_task_ctx_percore a2 - beqz a2, no_context - s32i a1, a2, TC_stack_pointer - -no_context: -# if XTOS_CNEST - l32i a2, a1, ESF_TOTALSIZE-20 // save nested-C-func call-chain ptr -# endif - addi a1, a1, ESF_TOTALSIZE -# if XTOS_DEBUG_PC - rsr.epc1 a4 // [for debug] get return PC - movi a5, 0xC0000000 // [for debug] setup call size... - or a4, a5, a4 // [for debug] set upper two bits of return PC - addx2 a4, a5, a4 // [for debug] clear upper bit -# else - movi a4, 0 /* terminate stack frames, overflow check */ -# endif - _entry a1, ESF_TOTALSIZE - -/* Reset the interrupt level to xtos locklevel (lvl 6 on most systems) */ - - rsil a15, XTOS_LOCKLEVEL - -/* Get bit list of pending interrupts at the current interrupt priority level. - * If bit list is empty, interrupt is spurious (can happen if a - * genuine interrupt brings control this direction, but the interrupt - * goes away before we read the INTERRUPT register). Also save off - * sar, loops, mac16 registers and coprocessors. */ - -#if __XCC__ -#if (XCHAL_CP_MASK & CP0_MASK) - mov a11, a1 - addi a11, a11, UEXC_cp0 - xchal_cp0_store a11, a12, a13, a14, a15 -#endif -#if (XCHAL_CP_MASK & CP1_MASK) - mov a11, a1 - addi a11, a11, UEXC_cp1 - xchal_cp1_store a11, a12, a13, a14, a15 -#endif -#endif - rsr.interrupt a15 - rsr.intenable a12 - movi a13, XCHAL_INTLEVEL1_MASK - and a15, a15, a12 - and a15, a15, a13 - rsr.sar a14 - s32i a14, a1, UEXC_sar - save_loops_mac16 a1, a13, a14 - - /* switch to interrupt stack */ - xtos_int_stack_addr_percore a13, _INTERRUPT_LEVEL, xtos_stack_for_interrupt - s32i a1, a13, 0 - addi a1, a13, SOF_STACK_SIZE - - _beqz a15, LABEL(spurious,int) - - /* set stack base and size for interrupt context */ - xtos_addr_percore a11, xtos_interrupt_ctx - s32i a13, a11, TC_stack_base - movi a13, SOF_STACK_SIZE - s32i a13, a11, TC_stack_size - - /* save task context */ - xtos_task_ctx_percore a13 - xtos_store_percore a13, a14, xtos_saved_ctx - - /* set interrupt task context */ - xtos_task_ctx_store_percore a11, a14 - - xtos_on_wakeup - -/* Loop to handle all pending interrupts. */ - -LABEL(.L1,_loop0): - neg a12, a15 - and a12, a12, a15 - wsr.intclear a12 // clear if edge-trig or s/w or wr/err (else no effect) -#if CONFIG_MULTICORE - xtos_addr_percore a13, xtos_interrupt_table -#else - movi a13, xtos_interrupt_table -#endif - find_ms_setbit a15, a12, a14, 0 - mapint a15 - addx8 a12, a15, a13 - l32i a13, a12, XIE_HANDLER - l32i a14, a12, XIE_ARG - mov a15, a1 - callx12 a13 - - rsr.interrupt a15 - rsr.intenable a12 - movi a13, XCHAL_INTLEVEL1_MASK - and a15, a15, a12 - and a15, a15, a13 - _bnez a15, LABEL(.L1,_loop0) - -/* Restore everything, and return. */ - - /* restore task context if needed */ - xtos_task_ctx_percore a11 - xtos_addr_percore a12, xtos_interrupt_ctx - bne a11, a12, restore_cp - xtos_addr_percore a12, xtos_saved_ctx - xtos_task_ctx_store_percore a12, a11 - -restore_cp: -#if __XCC__ -#if (XCHAL_CP_MASK & CP0_MASK) - xtos_task_ctx_percore a11 - beqz a11, no_context_2 - l32i a11, a11, TC_stack_pointer - addi a11, a11, UEXC_cp0 - xchal_cp0_load a11, a12, a13, a14, a15 -#endif -#if (XCHAL_CP_MASK & CP1_MASK) - xtos_task_ctx_percore a11 - beqz a11, no_context_2 - l32i a11, a11, TC_stack_pointer - addi a11, a11, UEXC_cp1 - xchal_cp1_load a11, a12, a13, a14, a15 -#endif -#endif - -no_context_2: - restore_loops_mac16 a1, a13, a14, a15 - l32i a14, a1, UEXC_sar -LABEL(spurious,int): - -#if XCHAL_HAVE_EXCLUSIVE - // Clear exclusive monitors. - clrex -#endif - - movi a0, LABEL(return,from_exc) - movi a13, 0xC0000000 - wsr.sar a14 - or a0, a0, a13 - addx2 a0, a13, a0 -# if _INTERRUPT_LEVEL < XCHAL_EXCM_LEVEL -/* Raise the interrupt mask before - * returning to avoid a race condition where we deallocate the - * exception stack frame but still have more register values to - * restore from it. */ - rsil a14, XCHAL_EXCM_LEVEL -# endif - retw -LABEL(return,from_exc): - /* a5 contains interrupt stack pointer */ - addi a5, a5, -SOF_STACK_SIZE - l32i a5, a5, 0 - -# if XTOS_CNEST - s32i a2, a5, ESF_TOTALSIZE-20 // restore nested-C-func call-chain ptr -# endif - - /* store sp after returning from handler */ - s32i a1, a5, UEXC_a1 - -restore: - /* load registers for window spill */ - l32i a4, a5, UEXC_a4 - l32i a6, a5, UEXC_a6 - l32i a7, a5, UEXC_a7 - l32i a8, a5, UEXC_a8 - l32i a9, a5, UEXC_a9 - l32i a10, a5, UEXC_a10 - l32i a11, a5, UEXC_a11 - l32i a12, a5, UEXC_a12 - l32i a13, a5, UEXC_a13 - l32i a14, a5, UEXC_a14 - - /* check if switch is needed */ - xtos_addr_percore a2, xtos_saved_sp - xtos_task_ctx_percore a1 - beqz a1, noSwitch - l32i a1, a1, TC_stack_pointer - l32i a0, a2, 0 - beq a0, a1, noSwitch - -doSwitch: - /* store new task sp */ - s32i a1, a2, 0 - - /* restore sp of task being preempted */ - l32i a1, a5, UEXC_a1 - - /* spill register windows to the stack */ - rsr.ps a2 - movi a3, PS_WOE_MASK - xor a2, a2, a3 - wsr.ps a2 - - call0 xthal_window_spill_nw - - /* restore previous ps */ - rsr.ps a2 - movi a3, PS_WOE_MASK - or a2, a2, a3 - wsr.ps a2 - - /* change stack */ - xtos_addr_percore a5, xtos_saved_sp - l32i a5, a5, 0 - j restore - -noSwitch: - /* restore ps and pc */ - l32i a0, a5, UEXC_ps - wsr.ps a0 - rsync - l32i a0, a5, UEXC_pc - wsr.epc1 a0 - - /* restore sar, loops and mac16 registers */ - l32i a0, a5, UEXC_sar - wsr.sar a0 - restore_loops_mac16 a5, a0, a1, a2 - - /* restore rest of the registers */ - l32i a0, a5, UEXC_a0 - l32i a1, a5, UEXC_a1 - l32i a2, a5, UEXC_a2 - l32i a3, a5, UEXC_a3 - l32i a15, a5, UEXC_a15 - l32i a5, a5, UEXC_a5 - rfe - - /* FIXME: what about _LevelOneInterrupt ? */ - .size _xtos_l1int_handler, . - _xtos_l1int_handler - -#endif /* XCHAL_HAVE_XEA2 && XCHAL_HAVE_EXCEPTIONS && XCHAL_HAVE_INTERRUPTS */ diff --git a/src/arch/xtensa/xtos/xea2/intlevel-restore.S b/src/arch/xtensa/xtos/xea2/intlevel-restore.S deleted file mode 100644 index 9c4f4b0b65fd..000000000000 --- a/src/arch/xtensa/xtos/xea2/intlevel-restore.S +++ /dev/null @@ -1,91 +0,0 @@ -// intlevel-restore.S - Interrupt related assembler code - _xtos_restore_intlevel - -// Copyright (c) 2004-2015 Tensilica 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. - - -#include <xtensa/coreasm.h> -#include "../xtos-internal.h" - -#if XCHAL_HAVE_XEA2 - -/*************************************************************************** - * void _xtos_restore_intlevel(unsigned restoreval); - * - * _xtos_restore_intlevel() restores the current interrupt level - * according to a value returned by _xtos_set_intlevel() or - * _xtos_set_min_intlevel() (or one of the corresponding macros). - * - * NOTE: In XEA2, this function may restore the entire PS register, not - * just the PS.INTLEVEL field. If some other PS field(s) must be changed - * and kept intact across restoring PS.INTLEVEL (this is generally unlikely), - * use the XTOS_RESTORE_JUST_INTLEVEL() macro instead (which is slower). - * - * NOTE: The macro form of this function (XTOS_RESTORE_INTLEVEL()) - * is recommended (for XEA2 configs or where the config is unknown) - * because it may be more efficient. - */ - - .text - .global _xtos_restore_intlevel - .type _xtos_restore_intlevel,@function - .align 4 -_xtos_restore_intlevel: - abi_entry -# if XCHAL_HAVE_INTERRUPTS - wsr a2, PS // restore PS - rsync // wait for WSR to PS to complete -# endif - abi_return - .size _xtos_restore_intlevel, . - _xtos_restore_intlevel - - - -/*************************************************************************** - * _xtos_set_vpri() is used to set the current virtual priority from C code; - * it can be called from the application or from a C interrupt handler. - */ - - .global _xtos_set_vpri - .type _xtos_set_vpri,@function - .align 4 -_xtos_set_vpri: - abi_entry -#if XCHAL_HAVE_INTERRUPTS && XTOS_VIRTUAL_INTENABLE - mov a3, a2 -#if CONFIG_MULTICORE - xtos_addr_percore a4, xtos_intstruct -#else - movi a4, _xtos_intstruct -#endif - xtos_lock a7 // MUST USE highest address register of function to avoid window overflows in critical section - l32i a2, a4, XTOS_VPRI_ENABLED_OFS // return old xtos_vpri_enabled (current vpri) - l32i a5, a4, XTOS_ENABLED_OFS // a3 = xtos_enabled - s32i a3, a4, XTOS_VPRI_ENABLED_OFS // set new xtos_vpri_enabled (current vpri) - and a5, a5, a3 // a5 = xtos_enabled & xtos_vpri_enabled - wsr a5, INTENABLE - xtos_unlock a7 -#endif /*XCHAL_HAVE_INTERRUPTS*/ - abi_return - .size _xtos_set_vpri, . - _xtos_set_vpri - -#endif /* XEA2 */ - diff --git a/src/arch/xtensa/xtos/xea2/intlevel-set.S b/src/arch/xtensa/xtos/xea2/intlevel-set.S deleted file mode 100644 index 30a82c336fb0..000000000000 --- a/src/arch/xtensa/xtos/xea2/intlevel-set.S +++ /dev/null @@ -1,63 +0,0 @@ -// intlevel-set.S - Interrupt related assembler code - _xtos_set_intlevel - -// Copyright (c) 2004-2015 Tensilica 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. - -#include <xtensa/coreasm.h> -#include "../xtos-internal.h" - -#if XCHAL_HAVE_XEA2 - - -/*************************************************************************** - * unsigned _xtos_set_intlevel(int intlevel); - * - * _xtos_set_intlevel() is used to set the current priority from C code; - * it can be called from the application or from a C interrupt handler. - * - * NOTE: This version allows the 'intlevel' parameter to be computed - * at run-time, and thus is longer. It is much more efficient, and - * highly recommented, to use the XTOS_SET_INTLEVEL(intlevel) macro instead - * (which requires a constant intlevel). - */ - - .text - .align 4 - .global _xtos_set_intlevel - .type _xtos_set_intlevel,@function -_xtos_set_intlevel: - abi_entry -#if XCHAL_HAVE_INTERRUPTS - /* In XEA2, we can simply safely set PS.INTLEVEL directly: */ - extui a3, a2, 0, 4 // keep only INTLEVEL bits of parameter - rsr.ps a2 // get old (current) PS.INTLEVEL - movi a4, ~0xF - and a4, a4, a2 // mask out PS.INTLEVEL - or a4, a4, a3 // insert requested INTLEVEL - wsr.ps a4 // update PS.INTLEVEL - rsync // wait for WSR to PS to complete -#endif /*XCHAL_HAVE_INTERRUPTS*/ - abi_return - - .size _xtos_set_intlevel, . - _xtos_set_intlevel - -#endif /* XEA2 */ - diff --git a/src/arch/xtensa/xtos/xea2/intlevel-setmin.S b/src/arch/xtensa/xtos/xea2/intlevel-setmin.S deleted file mode 100644 index 0d9f70e18b96..000000000000 --- a/src/arch/xtensa/xtos/xea2/intlevel-setmin.S +++ /dev/null @@ -1,68 +0,0 @@ -// intlevel-setmin.S - Interrupt related assembler code - _xtos_set_min_intlevel - -// Copyright (c) 2004-2015 Tensilica 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. - -#include <xtensa/coreasm.h> -#include "../xtos-internal.h" - -#if XCHAL_HAVE_XEA2 - - -/*************************************************************************** - * unsigned _xtos_set_min_intlevel(int intlevel); - * - * _xtos_set_min_intlevel() is identical to _xtos_set_intlevel() except - * that it will not lower the current interrupt level. Instead, - * it ensures that the current interrupt level is at least as high - * as specified. - * - * NOTE: This version allows the 'intlevel' parameter to be computed - * at run-time, and thus is longer. It is much more efficient, and - * highly recommented, to use the XTOS_SET_MIN_INTLEVEL(intlevel) macro instead - * (which requires a constant intlevel). - */ - - .text - .align 4 - .global _xtos_set_min_intlevel - .type _xtos_set_min_intlevel,@function -_xtos_set_min_intlevel: - abi_entry -#if XCHAL_HAVE_INTERRUPTS - /* In XEA2, we can simply safely set PS.INTLEVEL directly: */ - extui a3, a2, 0, 4 // keep only INTLEVEL bits of parameter - rsr.ps a2 // get old (current) PS.INTLEVEL - movi a4, ~0xF - extui a5, a2, 0, 4 // look at old PS.INTLEVEL - sub a5, a3, a5 // new.intlevel - old.intlevel - and a4, a4, a2 // mask out PS.INTLEVEL - or a4, a4, a3 // insert requested INTLEVEL - movltz a4, a2, a5 // keep same PS if already higher than requested - wsr.ps a4 // update PS.INTLEVEL - rsync // wait for WSR to PS to complete -#endif /*XCHAL_HAVE_INTERRUPTS*/ - abi_return - - .size _xtos_set_min_intlevel, . - _xtos_set_min_intlevel - -#endif /* XEA2 */ - diff --git a/src/arch/xtensa/xtos/xea2/reloc-vectors.S b/src/arch/xtensa/xtos/xea2/reloc-vectors.S deleted file mode 100644 index 7e9c1760495b..000000000000 --- a/src/arch/xtensa/xtos/xea2/reloc-vectors.S +++ /dev/null @@ -1,120 +0,0 @@ -// reloc-vector.S - Relocatable Vectors section -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/xea2/reloc-vectors.S#1 $ - -// Copyright (c) 2007-2017 Tensilica 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. - -/* - * This file is only used if the relocatable vectors option is enabled. - */ - - -#include <xtensa/coreasm.h> -#include <xtensa/config/system.h> - -#if XCHAL_HAVE_VECBASE - - .section .RelocatableVectors.text, "ax" - - .global _RelocVectors -_RelocVectors: - -//if XCHAL_RESET_VECBASE_OVERLAP ... -# if XSHAL_VECTORS_PACKED \ - && (XCHAL_RESET_VECTOR0_VADDR == XCHAL_VECBASE_RESET_VADDR \ - || XCHAL_RESET_VECTOR1_VADDR == XCHAL_VECBASE_RESET_VADDR) -# define JUMP_TO_RESET 1 - j .Ljump_to_reset -# endif - -# if XCHAL_HAVE_WINDOWED -# define NO_SECTION_DIRECTIVES 1 -# define WINDOW_BASE_VECOFS 0 -# include "window-vectors.S" -# endif - -#if XCHAL_HAVE_DEBUG && XCHAL_HAVE_EXCEPTIONS -# if XCHAL_DEBUGLEVEL == 2 -# define _Level2Vector _DebugExceptionVector -# elif XCHAL_DEBUGLEVEL == 3 -# define _Level3Vector _DebugExceptionVector -# elif XCHAL_DEBUGLEVEL == 4 -# define _Level4Vector _DebugExceptionVector -# elif XCHAL_DEBUGLEVEL == 5 -# define _Level5Vector _DebugExceptionVector -# elif XCHAL_DEBUGLEVEL == 6 -# define _Level6Vector _DebugExceptionVector -# endif -#endif - -# if XCHAL_HAVE_INTERRUPTS -# if XCHAL_NUM_INTLEVELS >= 2 - .org XCHAL_INTLEVEL2_VECOFS - j _Level2Vector -# endif -# if XCHAL_NUM_INTLEVELS >= 3 - .org XCHAL_INTLEVEL3_VECOFS - j _Level3Vector -# endif -# if XCHAL_NUM_INTLEVELS >= 4 - .org XCHAL_INTLEVEL4_VECOFS - j _Level4Vector -# endif -# if XCHAL_NUM_INTLEVELS >= 5 - .org XCHAL_INTLEVEL5_VECOFS - j _Level5Vector -# endif -# if XCHAL_NUM_INTLEVELS >= 6 - .org XCHAL_INTLEVEL6_VECOFS - j _Level6Vector -# endif -# if XCHAL_HAVE_NMI - .org XCHAL_NMI_VECOFS - j _NMIExceptionVector -# endif -# endif -# if XCHAL_HAVE_EXCEPTIONS - .org XCHAL_KERNEL_VECOFS - j _KernelExceptionVector - .org XCHAL_USER_VECOFS - j _UserExceptionVector - .org XCHAL_DOUBLEEXC_VECOFS - j _DoubleExceptionVector -# endif - -// Put literals here. - -// Put actual handlers here. - -# if JUMP_TO_RESET - .align 4 - .literal rvec, _ResetVector -.Ljump_to_reset: - l32r a2, rvec - jx a2 -# endif - - .size _RelocVectors, . - _RelocVectors - - .text - -#endif /* XCHAL_HAVE_VECBASE */ - diff --git a/src/arch/xtensa/xtos/xea2/switch_context.S b/src/arch/xtensa/xtos/xea2/switch_context.S deleted file mode 100644 index b4ed2fafe2af..000000000000 --- a/src/arch/xtensa/xtos/xea2/switch_context.S +++ /dev/null @@ -1,94 +0,0 @@ -/* switch_contexts.S - setup for multiple contexts */ - -/* - * Copyright (c) 2003-2010 Tensilica 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. - */ - -#include <xtensa/coreasm.h> -#include <xtensa/xtruntime-frames.h> - -#if XCHAL_NUM_CONTEXTS > 1 - - -/* - * void _xtos_setup_context(int context_num, StartInfo *info); - */ - .align 4 - .global _xtos_setup_context - .type _xtos_setup_context,@function -_xtos_setup_context: - abi_entry -#if XCHAL_HAVE_INTERRUPTS - rsil a5, 15 /* disable interrupts so we can use EXCSAVE_1 */ -#else - rsr.ps a5 /* just read PS */ -#endif - wsr.excsave1 a3 /* save pointer to new context info */ - s32i a5, a3, INFO_prevps /* save previous PS */ - movi a4, ~0x01F00000 /* mask out PS.CTXT */ - slli a2, a2, 20 /* shift up new PS.CTXT value */ - and a4, a5, a4 - or a4, a4, a2 /* new PS value */ - wsr.ps a4 - rsync - /* We're now in the new context! */ - movi a0, 0 - movi a1, 1 - wsr.windowstart a1 - wsr.windowbase a0 - rsync - rsr.excsave1 a9 /* get pointer to context info */ - movi a0, 0 /* terminate call frames */ - l32i a1, a9, INFO_sp /* get stack pointer */ - l32i a10, a9, INFO_arg1 /* get start function's arguments... */ - l32i a8, a9, INFO_funcpc /* get start function's address */ - /* Okay, now switch back to context zero: */ - l32i a9, a9, INFO_prevps /* retrieve previous PS */ - wsr.ps a9 - rsync - /* Back to original context! */ - abi_return - - .size _xtos_setup_context, . - _xtos_setup_context - - - - /* - * This is the first thing to be executed in the new context - * by explicit setting of PC: - */ - .align 4 - .global _xtos_start_context -_xtos_start_context: -#ifdef __XTENSA_CALL0_ABI__ - Crash the assembler here: I think this is wrong. - callx0 a8 -#else - callx8 a8 -#endif -1: nop - j 1b /* do nothing until context 0 exits */ - .size _xtos_start_context, . - _xtos_start_context - - -#endif /* XCHAL_NUM_CONTEXTS > 1 */ - diff --git a/src/arch/xtensa/xtos/xea2/window-vectors.S b/src/arch/xtensa/xtos/xea2/window-vectors.S deleted file mode 100644 index b6bd0f0974dd..000000000000 --- a/src/arch/xtensa/xtos/xea2/window-vectors.S +++ /dev/null @@ -1,338 +0,0 @@ -// window-vectors-xea2.S - Register Window Overflow/Underflow Handlers for XEA2 -// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/xtos/xea2/window-vectors.S#1 $ - -// Copyright (c) 1999-2016 Tensilica 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. - -#include <xtensa/coreasm.h> -#include <xtensa/xtruntime-frames.h> - -#if XCHAL_HAVE_XEA2 && XCHAL_HAVE_WINDOWED && !defined(__XTENSA_CALL0_ABI__) - -# ifndef NO_SECTION_DIRECTIVES -// Exports -.global _WindowOverflow4 -.global _WindowUnderflow4 -.global _WindowOverflow8 -.global _WindowUnderflow8 -.global _WindowOverflow12 -.global _WindowUnderflow12 -.global _xtos_alloca_handler - - // Note: the current window exception vectors do not generate any - // literals. Hence the literal_prefix directive is not necessary. - // Specifying it "just in case" creates an empty section (named - // ".WindowVectors.literal") which can in some cases cause linking - // problems (the linker scripts don't place it anywhere). - // So leave it commented out: - // - //.begin literal_prefix .WindowVectors - - .section .WindowVectors.text, "ax" -# endif - - -// -// GENERAL NOTES: -// -// These window exception handlers need not be modified. -// They are specific to the windowed call ABI only. -// -// Underflow Handlers: -// -// The underflow handler for returning from call[i+1] to call[i] -// must preserve all the registers from call[i+1]'s window. -// In particular, a0 and a1 must be preserved because the RETW instruction -// will be reexecuted (and may even underflow again if an intervening -// exception has flushed call[i]'s registers). -// Registers a2 and up may contain return values. -// -// The caller could also potentially assume that the callee's a0 and a1 -// (its own a4&a5 if call4, a8&a9 if call8, a12&a13 if call12) -// are correct for whatever reason (not a clean thing to do in general, -// but if it's possible, unless the ABI explicitly prohibits it, -// it will eventually be done :) -- whether the the ABI needs to -// prohibit this is a different question). -// -// Timing of Handlers: -// -// Here is an overview of the overhead of taking a window exception, -// ie. the number of additional cycles taken relative to case where -// an exception is not taken. -// NOTE: these numbers do not take into account any cache misses, -// write buffer stalls, or other external stalls, if they occur. -// The totals consist of 5 cycles to enter the handler (or 6 or 7 -// for optional longer pipelines in Xtensa LX), the number of instructions -// and interlocks (2nd and 3rd columns below), and 2 cycles jump delay -// on return (3 cycles for optional longer I-side pipeline in Xtensa LX): -// -// Instruction+bubbles Totals (5-stage) -// XEA1 XEA2 XEA1 XEA2 -// Overflow-4 7 5 14 12 -// Overflow-8 14 10 21 17 -// Overflow-12 18 14 25 21 -// Underflow-4 6 5 13 12 -// Underflow-8 14 10 21 17 -// Underflow-12 18 14 25 21 -// -// Underflow-8 15 12 25 22 (7-stage; could be made 1 less) -// Underflow-12 19 16 29 26 (7-stage; could be made 1 less) - -#ifndef WINDOW_BASE_VECOFS -#define WINDOW_BASE_VECOFS XCHAL_WINDOW_OF4_VECOFS -#endif - - -// 4-Register Window Overflow Vector (Handler) -// -// Invoked if a call[i] referenced a register (a4-a15) -// that contains data from ancestor call[j]; -// call[j] had done a call4 to call[j+1]. -// On entry here: -// window rotated to call[j] start point; -// a0-a3 are registers to be saved; -// a4-a15 must be preserved; -// a5 is call[j+1]'s stack pointer. - - .org XCHAL_WINDOW_OF4_VECOFS - WINDOW_BASE_VECOFS -_WindowOverflow4: - hw_erratum_487_fix - s32e a0, a5, -16 // save a0 to call[j+1]'s stack frame - s32e a1, a5, -12 // save a1 to call[j+1]'s stack frame - s32e a2, a5, -8 // save a2 to call[j+1]'s stack frame - s32e a3, a5, -4 // save a3 to call[j+1]'s stack frame - rfwo // rotates back to call[i] position - - .size _WindowOverflow4, . - _WindowOverflow4 - - -// ALLOCA exception handler -// -// NOTE: The alloca exception handler is squeezed in between the window exception -// handlers in order to save space, and also to allow short-range jumps to the -// window underflow handlers (see below for why). Because of the limited space in -// between the window handlers, this function is split into two to fit. -// -// Code written to the windowed ABI must use the MOVSP instruction to modify -// the stack pointer (except for startup code, which doesn't have a caller). -// The compiler uses MOVSP to allocate very large or variable size stack frames. -// MOVSP guarantees that the caller frame's a0-a3 registers, stored below the -// stack pointer, are moved atomically with respect to interrupts and exceptions -// to satisfy windowed ABI requirements. When user code executes the MOVSP -// instruction and the caller frame is on the stack rather than in the register -// file, the processor takes an ALLOCA exception. -// -// The XTOS user exception dispatcher allocates an exception frame on the -// stack and saves a2-a4 into that frame before calling us. So we need to -// restore those registers and deallocate the stack frame before jumping -// to the window underflow handler - which will restore the spilled registers -// back into the register file. -// The fact the alloca exception was taken means the registers associated with -// the base-save area have been spilled and will be restored by the underflow -// handler, so those 4 registers are available for scratch. - - .align 4 - -_xtos_alloca_handler: - - l32i a2, a1, UEXC_a2 // restore a2-a4 and deallocate frame - l32i a3, a1, UEXC_a3 - l32i a4, a1, UEXC_a4 - addi a1, a1, ESF_TOTALSIZE - wsr.excsave1 a0 // save a0 - rsr.windowbase a0 // grab WINDOWBASE before rotw changes it - rotw -1 // WINDOWBASE goes to a4, new a0-a3 are scratch - rsr.ps a2 - extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS - xor a3, a3, a4 // bits changed from old to current windowbase - j _xtos_alloca_2 // not enough room here... - - .size _xtos_alloca_handler, . - _xtos_alloca_handler - - -// 4-Register Window Underflow Vector (Handler) -// -// Invoked by RETW returning from call[i+1] to call[i] -// where call[i]'s registers must be reloaded (not live in ARs); -// call[i] had done a call4 to call[i+1]. -// On entry here: -// window rotated to call[i] start point; -// a0-a3 are undefined, must be reloaded with call[i].reg[0..3]; -// a4-a15 must be preserved (they are call[i+1].reg[0..11]); -// a5 is call[i+1]'s stack pointer. - - .org XCHAL_WINDOW_UF4_VECOFS - WINDOW_BASE_VECOFS -_WindowUnderflow4: - l32e a0, a5, -16 // restore a0 from call[i+1]'s stack frame - l32e a1, a5, -12 // restore a1 from call[i+1]'s stack frame - l32e a2, a5, -8 // restore a2 from call[i+1]'s stack frame - l32e a3, a5, -4 // restore a3 from call[i+1]'s stack frame - rfwu - - .size _WindowUnderflow4, . - _WindowUnderflow4 - - -// This is the second part of the alloca handler. - - .align 4 - -_xtos_alloca_2: - - rsr.excsave1 a4 // restore original a0 (now in a4) - slli a3, a3, XCHAL_PS_OWB_SHIFT - xor a2, a2, a3 // flip changed bits in old window base - wsr.ps a2 // update PS.OWB to new window base - rsync - _bbci.l a4, 31, _WindowUnderflow4 - rotw -1 // original a0 goes to a8 - _bbci.l a8, 30, _WindowUnderflow8 - rotw -1 - j _WindowUnderflow12 - - .size _xtos_alloca_2, . - _xtos_alloca_2 - - -// 8-Register Window Overflow Vector (Handler) -// -// Invoked if a call[i] referenced a register (a4-a15) -// that contains data from ancestor call[j]; -// call[j] had done a call8 to call[j+1]. -// On entry here: -// window rotated to call[j] start point; -// a0-a7 are registers to be saved; -// a8-a15 must be preserved; -// a9 is call[j+1]'s stack pointer. - - .org XCHAL_WINDOW_OF8_VECOFS - WINDOW_BASE_VECOFS -_WindowOverflow8: - hw_erratum_487_fix - s32e a0, a9, -16 // save a0 to call[j+1]'s stack frame - l32e a0, a1, -12 // a0 <- call[j-1]'s sp (used to find end of call[j]'s frame) - s32e a1, a9, -12 // save a1 to call[j+1]'s stack frame - s32e a2, a9, -8 // save a2 to call[j+1]'s stack frame - s32e a3, a9, -4 // save a3 to call[j+1]'s stack frame - s32e a4, a0, -32 // save a4 to call[j]'s stack frame - s32e a5, a0, -28 // save a5 to call[j]'s stack frame - s32e a6, a0, -24 // save a6 to call[j]'s stack frame - s32e a7, a0, -20 // save a7 to call[j]'s stack frame - rfwo // rotates back to call[i] position - - .size _WindowOverflow8, . - _WindowOverflow8 - - -// 8-Register Window Underflow Vector (Handler) -// -// Invoked by RETW returning from call[i+1] to call[i] -// where call[i]'s registers must be reloaded (not live in ARs); -// call[i] had done a call8 to call[i+1]. -// On entry here: -// window rotated to call[i] start point; -// a0-a7 are undefined, must be reloaded with call[i].reg[0..7]; -// a8-a15 must be preserved (they are call[i+1].reg[0..7]); -// a9 is call[i+1]'s stack pointer. - - .org XCHAL_WINDOW_UF8_VECOFS - WINDOW_BASE_VECOFS -_WindowUnderflow8: - l32e a0, a9, -16 // restore a0 from call[i+1]'s stack frame - l32e a1, a9, -12 // restore a1 from call[i+1]'s stack frame - l32e a2, a9, -8 // restore a2 from call[i+1]'s stack frame - l32e a7, a1, -12 // a7 <- call[i-1]'s sp (used to find end of call[i]'s frame) - l32e a3, a9, -4 // restore a3 from call[i+1]'s stack frame - l32e a4, a7, -32 // restore a4 from call[i]'s stack frame - l32e a5, a7, -28 // restore a5 from call[i]'s stack frame - l32e a6, a7, -24 // restore a6 from call[i]'s stack frame - l32e a7, a7, -20 // restore a7 from call[i]'s stack frame - rfwu - - .size _WindowUnderflow8, . - _WindowUnderflow8 - - -// 12-Register Window Overflow Vector (Handler) -// -// Invoked if a call[i] referenced a register (a4-a15) -// that contains data from ancestor call[j]; -// call[j] had done a call12 to call[j+1]. -// On entry here: -// window rotated to call[j] start point; -// a0-a11 are registers to be saved; -// a12-a15 must be preserved; -// a13 is call[j+1]'s stack pointer. - - .org XCHAL_WINDOW_OF12_VECOFS - WINDOW_BASE_VECOFS -_WindowOverflow12: - hw_erratum_487_fix - s32e a0, a13, -16 // save a0 to call[j+1]'s stack frame - l32e a0, a1, -12 // a0 <- call[j-1]'s sp (used to find end of call[j]'s frame) - s32e a1, a13, -12 // save a1 to call[j+1]'s stack frame - s32e a2, a13, -8 // save a2 to call[j+1]'s stack frame - s32e a3, a13, -4 // save a3 to call[j+1]'s stack frame - s32e a4, a0, -48 // save a4 to end of call[j]'s stack frame - s32e a5, a0, -44 // save a5 to end of call[j]'s stack frame - s32e a6, a0, -40 // save a6 to end of call[j]'s stack frame - s32e a7, a0, -36 // save a7 to end of call[j]'s stack frame - s32e a8, a0, -32 // save a8 to end of call[j]'s stack frame - s32e a9, a0, -28 // save a9 to end of call[j]'s stack frame - s32e a10, a0, -24 // save a10 to end of call[j]'s stack frame - s32e a11, a0, -20 // save a11 to end of call[j]'s stack frame - rfwo // rotates back to call[i] position - - .size _WindowOverflow12, . - _WindowOverflow12 - - -// 12-Register Window Underflow Vector (Handler) -// -// Invoked by RETW returning from call[i+1] to call[i] -// where call[i]'s registers must be reloaded (not live in ARs); -// call[i] had done a call12 to call[i+1]. -// On entry here: -// window rotated to call[i] start point; -// a0-a11 are undefined, must be reloaded with call[i].reg[0..11]; -// a12-a15 must be preserved (they are call[i+1].reg[0..3]); -// a13 is call[i+1]'s stack pointer. - - .org XCHAL_WINDOW_UF12_VECOFS - WINDOW_BASE_VECOFS -_WindowUnderflow12: - l32e a0, a13, -16 // restore a0 from call[i+1]'s stack frame - l32e a1, a13, -12 // restore a1 from call[i+1]'s stack frame - l32e a2, a13, -8 // restore a2 from call[i+1]'s stack frame - l32e a11, a1, -12 // a11 <- call[i-1]'s sp (used to find end of call[i]'s frame) - l32e a3, a13, -4 // restore a3 from call[i+1]'s stack frame - l32e a4, a11, -48 // restore a4 from end of call[i]'s stack frame - l32e a5, a11, -44 // restore a5 from end of call[i]'s stack frame - l32e a6, a11, -40 // restore a6 from end of call[i]'s stack frame - l32e a7, a11, -36 // restore a7 from end of call[i]'s stack frame - l32e a8, a11, -32 // restore a8 from end of call[i]'s stack frame - l32e a9, a11, -28 // restore a9 from end of call[i]'s stack frame - l32e a10, a11, -24 // restore a10 from end of call[i]'s stack frame - l32e a11, a11, -20 // restore a11 from end of call[i]'s stack frame - rfwu - - .size _WindowUnderflow12, . - _WindowUnderflow12 - - -# ifndef NO_SECTION_DIRECTIVES - //.end literal_prefix - .text -# endif - - -#endif /* XCHAL_HAVE_XEA2 && XCHAL_HAVE_WINDOWED && !defined(__XTENSA_CALL0_ABI__) */ - diff --git a/src/arch/xtensa/xtos/xtos-internal.h b/src/arch/xtensa/xtos/xtos-internal.h deleted file mode 100644 index d7b4dc8dd772..000000000000 --- a/src/arch/xtensa/xtos/xtos-internal.h +++ /dev/null @@ -1,622 +0,0 @@ -/* - * xtos-internal.h -- internal definitions for single-threaded run-time - * - * Copyright (c) 2003-2010 Tensilica Inc. - * Copyright (c) 2019 Intel Corporation. All rights reserved. - * - * 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. - */ - -#ifndef XTOS_INTERNAL_H -#define XTOS_INTERNAL_H - - -#if CONFIG_MULTICORE -#include <sof/lib/cpu.h> -#endif -#include <sof/lib/memory.h> -#include <xtensa/config/core.h> -#include <xtensa/xtruntime.h> -#include <xtensa/xtruntime-frames.h> -#include <xtensa/xtensa-versions.h> -#ifndef XTOS_PARAMS_H /* this to allow indirect inclusion of this header from the outside */ -#include "xtos-params.h" -#endif - -/* Relative ordering of subpriorities within an interrupt level (or vector): */ -#define XTOS_SPO_ZERO_LO 0 /* lower (eg. zero) numbered interrupts are lower priority than higher numbered interrupts */ -#define XTOS_SPO_ZERO_HI 1 /* lower (eg. zero) numbered interrupts are higher priority than higher numbered interrupts */ - - -/* Sanity check some parameters from xtos-params.h: */ -#if XTOS_LOCKLEVEL < XCHAL_EXCM_LEVEL || XTOS_LOCKLEVEL > 15 -# error Invalid XTOS_LOCKLEVEL value, must be >= EXCM_LEVEL and <= 15, please fix xtos-params.h -#endif - -/* Mask of interrupts locked out at XTOS_LOCKLEVEL: */ -#define XTOS_LOCKOUT_MASK XCHAL_INTLEVEL_ANDBELOW_MASK(XTOS_LOCKLEVEL) -/* Mask of interrupts that can still be enabled at XTOS_LOCKLEVEL: */ -#define XTOS_UNLOCKABLE_MASK (0xFFFFFFFF-XTOS_LOCKOUT_MASK) - -/* Don't set this: */ -#define XTOS_HIGHINT_TRAMP 0 /* mapping high-pri ints to low-pri not auto-supported */ -#define XTOS_VIRTUAL_INTERRUPT XTOS_HIGHINT_TRAMP /* partially-virtualized INTERRUPT register not currently supported */ -#if XTOS_HIGHINT_TRAMP -# error Automatically-generated high-level interrupt trampolines are not presently supported. -#endif - -/* - * If single interrupt at level-one, sub-prioritization is irrelevant: - */ -#if defined(XCHAL_INTLEVEL1_NUM) -# undef XTOS_SUBPRI -# define XTOS_SUBPRI 0 /* override - only one interrupt */ -#endif - -/* - * In XEA1, the INTENABLE special register must be virtualized to provide - * standard XTOS functionality. - * In XEA2, this is only needed for software interrupt prioritization. - */ -#if XTOS_SUBPRI || XCHAL_HAVE_XEA1 -#define XTOS_VIRTUAL_INTENABLE 1 -#else -#define XTOS_VIRTUAL_INTENABLE 0 -#endif - -/* - * If single interrupt per priority, then fairness is irrelevant: - */ -#if (XTOS_SUBPRI && !XTOS_SUBPRI_GROUPS) || defined(XCHAL_INTLEVEL1_NUM) -# undef XTOS_INT_FAIRNESS -# define XTOS_INT_FAIRNESS 0 -#endif - -/* Identify special case interrupt handling code in int-lowpri-dispatcher.S: */ -#define XTOS_INT_SPECIALCASE (XTOS_SUBPRI_ORDER == XTOS_SPO_ZERO_HI && XTOS_INT_FAIRNESS == 0 && XTOS_SUBPRI_GROUPS == 0) - -/* - * Determine whether to extend the interrupt entry array: - */ -#define XIE_EXTEND (XTOS_VIRTUAL_INTENABLE && !XTOS_INT_SPECIALCASE) - -/* If we have the NSAU instruction, ordering of interrupts is reversed in xtos_interrupt_table[]: */ -#if XCHAL_HAVE_NSA -# define MAPINT(n) ((XCHAL_NUM_INTERRUPTS-1)-(n)) -# ifdef _ASMLANGUAGE - .macro mapint an - neg \an, \an - addi \an, \an, XCHAL_NUM_INTERRUPTS-1 - .endm -# endif -#else /* no NSA */ -# define MAPINT(n) (n) -# ifdef _ASMLANGUAGE - .macro mapint an - .endm -# endif -#endif - -#define XTOS_TASK_CONTEXT_OFFSET 48 - -#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) -/*********** Useful macros ***********/ - -/* - * A useful looping macro: - * 'iterate' invokes 'what' (an instruction, pseudo-op or other macro) - * multiple times, passing it a numbered parameter from 'from' to 'to' - * inclusively. Does not invoke 'what' at all if from > to. - * Maximum difference between 'from' and 'to' is 99 minus nesting depth - * (GNU 'as' doesn't allow nesting deeper than 100). - */ - .macro iterate from, to, what - .ifeq ((\to-\from) & ~0xFFF) - \what \from - iterate "(\from+1)", \to, \what - .endif - .endm // iterate - - - - // rsilft - // - // Execute RSIL \ar, \tolevel if \tolevel is different than \fromlevel. - // This way the RSIL is avoided if we know at assembly time that - // it will not change the level. Typically, this means the \ar register - // is ignored, ie. RSIL is used only to change PS.INTLEVEL. - // - .macro rsilft ar, fromlevel, tolevel -#if XCHAL_HAVE_INTERRUPTS - .if \fromlevel - \tolevel - rsil \ar, \tolevel - .endif -#endif - .endm - - - // Save LOOP and MAC16 registers, if configured, to the exception stack - // frame pointed to by address register \esf, using \aa and \ab as temporaries. - // - // This macro essentially saves optional registers that the compiler uses by - // default when present. - // Note that the acclo/acchi subset of MAC16 may be used even if others - // multipliers are present (e.g. mul16, mul32). - // - // Only two temp registers required for this code to be optimal (no interlocks) in both - // T10xx (Athens) and Xtensa LX microarchitectures (both 5 and 7 stage pipes): - // - .macro save_loops_mac16 esf, aa, ab -#if XCHAL_HAVE_LOOPS - rsr.lcount \aa - rsr.lbeg \ab - s32i \aa, \esf, UEXC_lcount - rsr.lend \aa - s32i \ab, \esf, UEXC_lbeg - s32i \aa, \esf, UEXC_lend -#endif -#if XCHAL_HAVE_MAC16 - rsr.acclo \aa - rsr.acchi \ab - s32i \aa, \esf, UEXC_acclo - s32i \ab, \esf, UEXC_acchi -# if XTOS_SAVE_ALL_MAC16 - rsr.m0 \aa - rsr.m1 \ab - s32i \aa, \esf, UEXC_mr + 0 - s32i \ab, \esf, UEXC_mr + 4 - rsr.m2 \aa - rsr.m3 \ab - s32i \aa, \esf, UEXC_mr + 8 - s32i \ab, \esf, UEXC_mr + 12 -# endif -#endif - .endm - - // Restore LOOP and MAC16 registers, if configured, from the exception stack - // frame pointed to by address register \esf, using \aa, \ab and \ac as temporaries. - // - // Three temp registers are required for this code to be optimal (no interlocks) in - // Xtensa LX microarchitectures with 7-stage pipe; otherwise only two - // registers would be needed. - // - .macro restore_loops_mac16 esf, aa, ab, ac -#if XCHAL_HAVE_LOOPS - l32i \aa, \esf, UEXC_lcount - l32i \ab, \esf, UEXC_lbeg - l32i \ac, \esf, UEXC_lend - wsr.lcount \aa - wsr.lbeg \ab - wsr.lend \ac -#endif -#if XCHAL_HAVE_MAC16 - l32i \aa, \esf, UEXC_acclo - l32i \ab, \esf, UEXC_acchi -# if XTOS_SAVE_ALL_MAC16 - l32i \ac, \esf, UEXC_mr + 0 - wsr.acclo \aa - wsr.acchi \ab - wsr.m0 \ac - l32i \aa, \esf, UEXC_mr + 4 - l32i \ab, \esf, UEXC_mr + 8 - l32i \ac, \esf, UEXC_mr + 12 - wsr.m1 \aa - wsr.m2 \ab - wsr.m3 \ac -# else - wsr.acclo \aa - wsr.acchi \ab -# endif -#endif - .endm - - -/* Offsets from _xtos_intstruct structure: */ - .struct 0 -#if XTOS_VIRTUAL_INTENABLE -XTOS_ENABLED_OFS: .space 4 /* _xtos_enabled variable */ -XTOS_VPRI_ENABLED_OFS: .space 4 /* _xtos_vpri_enabled variable */ -#endif -#if XTOS_VIRTUAL_INTERRUPT -XTOS_PENDING_OFS: .space 4 /* _xtos_pending variable */ -#endif - .text - - -#if XTOS_VIRTUAL_INTENABLE - // Update INTENABLE register, computing it as follows: - // INTENABLE = _xtos_enabled & _xtos_vpri_enabled - // [ & ~_xtos_pending ] - // - // Entry: - // register ax = &_xtos_intstruct - // register ay, az undefined (temporaries) - // PS.INTLEVEL set to XTOS_LOCKLEVEL or higher (eg. via xtos_lock) - // window overflows prevented (PS.WOE=0, PS.EXCM=1, or overflows - // already done for registers ax, ay, az) - // - // Exit: - // registers ax, ay, az clobbered - // PS unchanged - // caller needs to SYNC (?) for INTENABLE changes to take effect - // - // Note: in other software prioritization schemes/implementations, - // the term <_xtos_vpri_enabled> in the above expression is often - // replaced with another expression that computes the set of - // interrupts allowed to be enabled at the current software virtualized - // interrupt priority. - // - // For example, a simple alternative implementation of software - // prioritization for XTOS might have been the following: - // INTENABLE = _xtos_enabled & (vpri_enabled | UNLOCKABLE_MASK) - // which removes the need for the interrupt dispatcher to 'or' the - // UNLOCKABLE_MASK bits into _xtos_vpri_enabled, and lets other code - // disable all lockout level interrupts by just clearing _xtos_vpri_enabled - // rather than setting it to UNLOCKABLE_MASK. - // Other implementations sometimes use a table, eg: - // INTENABLE = _xtos_enabled & enable_table[current_vpri] - // The HAL (used by some 3rd party OSes) uses essentially a table-driven - // version, with other tables enabling run-time changing of priorities. - // - .macro xtos_update_intenable ax, ay, az - //movi \ax, _xtos_intstruct - l32i \ay, \ax, XTOS_VPRI_ENABLED_OFS // ay = _xtos_vpri_enabled - l32i \az, \ax, XTOS_ENABLED_OFS // az = _xtos_enabled - //interlock - and \az, \az, \ay // az = _xtos_enabled & _xtos_vpri_enabled -# if XTOS_VIRTUAL_INTERRUPT - l32i \ay, \ax, XTOS_PENDING_OFS // ay = _xtos_pending - movi \ax, -1 - xor \ay, \ay, \ax // ay = ~_xtos_pending - and \az, \az, \ay // az &= ~_xtos_pending -# endif - wsr.intenable \az - .endm -#endif /* VIRTUAL_INTENABLE */ - - .macro xtos_lock ax - rsil \ax, XTOS_LOCKLEVEL // lockout - .endm - - .macro xtos_unlock ax - wsr.ps \ax // unlock - rsync - .endm - -/* Offsets to XtosIntHandlerEntry structure fields (see below): */ -# define XIE_HANDLER 0 -# define XIE_ARG 4 -# define XIE_SIZE 8 -# if XIE_EXTEND -# define XIE_VPRIMASK (XIE_SIZE*XCHAL_NUM_INTERRUPTS+0) /* if VIRTUAL_INTENABLE [SUBPRI||XEA1] && !SPECIALCASE */ -# define XIE_LEVELMASK (XIE_SIZE*XCHAL_NUM_INTERRUPTS+4) /* [fairness preloop] if FAIRNESS && SUBPRI [&& SUBPRI_GROUPS] */ -# endif - -/* To simplify code: */ -# if XCHAL_HAVE_NSA -# define IFNSA(a,b) a -# else -# define IFNSA(a,b) b -# endif - - // get_prid ax - // Extracts core id. - .macro get_prid ax -#if XCHAL_HAVE_PRID - rsr.prid \ax - extui \ax, \ax, 0, 8 -#else - movi \ax, PLATFORM_PRIMARY_CORE_ID -#endif - .endm - -#if CONFIG_MULTICORE - // xtos_stack_addr_percore ax, ay, stack_primary, stack_secondary, stack_size - // Retrieves address of end of stack buffer for certain core to register ax. - .macro xtos_stack_addr_percore ax, ay, stack_primary_addr, mem_blk_secondary_addr, stack_size - get_prid \ax - bnei \ax, PLATFORM_PRIMARY_CORE_ID, core_s - movi \ax, \stack_primary_addr - j exit -core_s: - addi \ax, \ax, -1 - movi \ay, _core_s_size - mull \ax, \ax, \ay - movi \ay, (HEAP_SYSTEM_S_SIZE + HEAP_SYS_RUNTIME_S_SIZE) - add \ax, \ax, \ay - movi \ay, \mem_blk_secondary_addr - add \ax, \ax, \ay - j exit -exit: - movi \ay, \stack_size - add \ax, \ax, \ay - .endm - - // xtos_stack_addr_percore_add ax, stack_name, offset - // Pointer to dedicated interrupt stack + offset. - .macro xtos_stack_addr_percore_add ax, stack_name, offset - get_prid \ax - beqz \ax, core_0 - beqi \ax, 1, core_1 - beqi \ax, 2, core_2 - beqi \ax, 3, core_3 - j exit -core_0: - movi \ax, \stack_name\()0 + (\offset) - j exit -core_1: - movi \ax, \stack_name\()1 + (\offset) - j exit -core_2: - movi \ax, \stack_name\()2 + (\offset) - j exit -core_3: - movi \ax, \stack_name\()3 + (\offset) - j exit -exit: - .endm - - // xtos_addr_percore_add ax, symbol, offset - // Pointer to structure per core + offset. - .macro xtos_addr_percore_add ax, symbol, offset - xtos_addr_percore \ax, \symbol - addi \ax, \ax, \offset - .endm - - // xtos_addr_percore_sub ax, symbol, offset - // Pointer to structure per core - offset. - .macro xtos_addr_percore_sub ax, symbol, offset - xtos_addr_percore \ax, \symbol - addi \ax, \ax, -\offset - .endm -#endif /* CONFIG_MULTICORE */ - - // xtos_addr_percore ax, structure_name - // Pointer to structure per core. - .macro xtos_addr_percore ax, structure_name -#if XCHAL_HAVE_THREADPTR - rur.threadptr \ax -#else - j 1f - .align 4 - .literal_position -2: - .word SOF_VIRTUAL_THREAD_BASE -1: - .align 4 - l32r \ax, 2b - l32i \ax, \ax, 0 -#endif - l32i \ax, \ax, XTOS_PTR_TO_\structure_name - .endm - - // xtos_store_percore ax, ay, structure_name - // Stores register value under the selected structure per core. - .macro xtos_store_percore ax, ay, structure_name -#if XCHAL_HAVE_THREADPTR - rur.threadptr \ay -#else - j 1f - .align 4 - .literal_position -2: - .word SOF_VIRTUAL_THREAD_BASE -1: - .align 4 - l32r \ay, 2b - l32i \ay, \ay, 0 -#endif - s32i \ax, \ay, XTOS_PTR_TO_\structure_name - .endm - - // xtos_int_stack_addr_percore ax, int_level, stack_name - // Pointer to dedicated interrupt stack. - .macro xtos_int_stack_addr_percore ax, int_level, stack_name -#if XCHAL_HAVE_THREADPTR - rur.threadptr \ax -#else - j 1f - .align 4 - .literal_position -2: - .word SOF_VIRTUAL_THREAD_BASE -1: - .align 4 - l32r \ax, 2b - l32i \ax, \ax, 0 -#endif - l32i \ax, \ax, XTOS_PTR_TO_\stack_name\()_&int_level - .endm - - // xtos_task_ctx_percore ax - // Pointer to structure per core. - .macro xtos_task_ctx_percore ax -#if XCHAL_HAVE_THREADPTR - rur.threadptr \ax -#else - j 1f - .align 4 - .literal_position -2: - .word SOF_VIRTUAL_THREAD_BASE -1: - .align 4 - l32r \ax, 2b - l32i \ax, \ax, 0 -#endif - l32i \ax, \ax, XTOS_TASK_CONTEXT_OFFSET - .endm - - // xtos_task_ctx_store_percore ax, ay - // Changes task context to point to the selected address. - .macro xtos_task_ctx_store_percore ax, ay -#if XCHAL_HAVE_THREADPTR - rur.threadptr \ay -#else - j 1f - .align 4 - .literal_position -2: - .word SOF_VIRTUAL_THREAD_BASE -1: - .align 4 - l32r \ay, 2b - l32i \ay, \ay, 0 -#endif - s32i \ax, \ay, XTOS_TASK_CONTEXT_OFFSET - .endm - - // Executes optional callback on wake up - .macro xtos_on_wakeup -#if CONFIG_WAKEUP_HOOK - call12 arch_interrupt_on_wakeup -#endif - .endm - -#else /* !_ASMLANGUAGE && !__ASSEMBLER__ */ - -/* - * Interrupt handler table entry. - * Unregistered entries have 'handler' point to xtos_unhandled_interrupt(). - */ -typedef struct XtosIntHandlerEntry { - _xtos_handler handler; - union { - void * varg; - int narg; - } u; -} XtosIntHandlerEntry; -# if XIE_EXTEND -typedef struct XtosIntMaskEntry { - unsigned vpri_mask; /* mask of interrupts enabled when this interrupt is taken */ - unsigned level_mask; /* mask of interrupts at this interrupt's level */ -} XtosIntMaskEntry; -# endif - -#if CONFIG_MULTICORE -struct XtosIntStruct -{ - unsigned xtos_enabled; - unsigned vpri_enabled; -}; - -// XtosIntInterruptTable holds array of interrupt handler descriptors. -struct XtosIntInterruptTable -{ - struct XtosIntHandlerEntry array[XCHAL_NUM_INTERRUPTS]; -}; - -// XtosInterruptStructure describes layout of xtos interrupt structures per core -// generated for certain platform in file interrupt-table.S. -struct XtosInterruptStructure -{ - struct XtosIntStruct xtos_enabled; - struct XtosIntInterruptTable xtos_interrupt_table; - struct XtosIntMaskEntry xtos_interrupt_mask_table[XCHAL_NUM_INTERRUPTS]; - __attribute__((aligned(XCHAL_DCACHE_LINESIZE))) int al[0]; -}; -#endif - -extern void xtos_unhandled_interrupt(); - -#endif /* !_ASMLANGUAGE && !__ASSEMBLER__ */ - -/* - * Notes... - * - * XEA1 and interrupt-SUBPRIoritization both imply virtualization of INTENABLE. - * Synchronous trampoloines imply partial virtualization of the INTERRUPT - * register, which in turn also implies virtualization of INTENABLE register. - * High-level interrupts manipulating the set of enabled interrupts implies - * at least a high XTOS_LOCK_LEVEL, although not necessarily INTENABLE virtualization. - * - * With INTENABLE register virtualization, at all times the INTENABLE - * register reflects the expression: - * (set of interrupts enabled) & (set of interrupts enabled by current - * virtual priority) - * - * Unrelated (DBREAK semantics): - * - * A[31-6] = DBA[3-6] - * --------------------- - * A[5-0] & DBC[5-C] & szmask - * - * = DBA[5-0] & szmask - * ^___ ??? - */ - - -/* Report whether the XSR instruction is available (conservative): */ -#define HAVE_XSR (XCHAL_HAVE_XEA2 || !XCHAL_HAVE_EXCEPTIONS) -/* - * This is more accurate, but not a reliable test in software releases prior to 6.0 - * (where the targeted hardware parameter was not explicit in the XPG): - * - *#define HAVE_XSR (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_T1040_0) - */ - - - -/* Macros for supporting hi-level and medium-level interrupt handling. */ - -#if XCHAL_NUM_INTLEVELS > 6 -#error Template files (*-template.S) limit support to interrupt levels <= 6 -#endif - -#if defined(__XTENSA_WINDOWED_ABI__) && XCHAL_HAVE_CALL4AND12 == 0 -#error CALL8-only is not supported! -#endif - -#define INTERRUPT_IS_HI(level) \ - ( XCHAL_HAVE_INTERRUPTS && \ - (XCHAL_EXCM_LEVEL < level) && \ - (XCHAL_NUM_INTLEVELS >= level) && \ - (XCHAL_HAVE_DEBUG ? XCHAL_DEBUGLEVEL != level : 1)) - -#define INTERRUPT_IS_MED(level) \ - (XCHAL_HAVE_INTERRUPTS && (XCHAL_EXCM_LEVEL >= level)) - - -#define _JOIN(x,y) x ## y -#define JOIN(x,y) _JOIN(x,y) - -#define _JOIN3(a,b,c) a ## b ## c -#define JOIN3(a,b,c) _JOIN3(a,b,c) - -#define LABEL(x,y) JOIN3(x,_INTERRUPT_LEVEL,y) -#define EXCSAVE_LEVEL JOIN(EXCSAVE_,_INTERRUPT_LEVEL) -#define INTLEVEL_VSIZE JOIN3(XSHAL_INTLEVEL,_INTERRUPT_LEVEL,_VECTOR_SIZE) - -/* For asm macros; works for positive a,b smaller than 1000: */ -#define GREATERTHAN(a, b) (((b) - (a)) & ~0xFFF) -#define EQUAL(a, b) ((1 << (a)) & (1 << (b))) - -#if CONFIG_MULTICORE -// sizeof(xtos_enabled) -#define XTOS_ENABLED_SIZE_PER_CORE (4) -// sizeof(vpri_enabled) -#define XTOS_VPRI_ENABLED_SIZE_PER_CORE (4) -// sizeof(XtosIntStruct) -#define XTOS_INTSTRUCT_SIZE_PER_CORE (XTOS_ENABLED_SIZE_PER_CORE + \ - XTOS_VPRI_ENABLED_SIZE_PER_CORE) -#endif - -#endif /* XTOS_INTERNAL_H */ - diff --git a/src/arch/xtensa/xtos/xtos-params.h b/src/arch/xtensa/xtos/xtos-params.h deleted file mode 100644 index 334aba76d504..000000000000 --- a/src/arch/xtensa/xtos/xtos-params.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * xtos-params.h -- user-settable parameters for XTOS single-threaded run-time - * - * Copyright (c) 2002, 2004, 2006-2007 Tensilica 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. - */ - -#ifndef XTOS_PARAMS_H -#define XTOS_PARAMS_H - -/* - * IMPORTANT NOTE. - * This file contains XTOS parameters that may be modified - * according to needs. HOWEVER, any modifications are NOT - * supported. Handling of parameters other than the defaults - * provided in the original version of this file are for - * illustrative and educational purposes only. If you do - * change the parameters here-in (which requires rebuilding - * XTOS), please verify the resulting code extensively - * before even considering its use in production code. - * - * To rebuild XTOS, see instructions in the Xtensa System Software - * Reference Manual. The following sequence is no longer supported. - * - * cd <config_dir>/xtensa-elf/src/handlers - * xt-make clean - * xt-make - * xt-make install - * - * (Note: the last step installs the modified XTOS in *ALL* - * LSPs that normally include XTOS. You may prefer copying - * the generated files to your own custom LSP instead. Or - * better yet, also make a copy of all source files and maintain - * them somewhere completely separate -- which may require - * minor adjustments to the makefile.) - * - * PERFORMANCE TUNING: - * To slightly improve performance of interrupt dispatching, - * you can do some combination of the following: - * - change XTOS_SUBPRI to zero - * - change XTOS_SUBPRI_GROUPS to zero - * - change XTOS_SUBPRI_ORDER to XTOS_SPO_ZERO_HI - * - change XTOS_DEBUG_PC to zero - * - change XTOS_INT_FAIRNESS to zero - * - change XTOS_CNEST to zero - * There are non-trivial trade-offs in making such changes however, - * such as loss of support (see important note above), loss of - * interrupt scheduling fairness, loss of ability to traceback - * interrupt handlers across interrupted code when debugging them, - * loss of supported for nested C functions, etc. - */ - - -/* - * Lower LOCKLEVEL to XCHAL_EXCM_LEVEL for improved interrupt latency - * if you don't register C handlers for high-priority interrupts and your - * high-priority handlers don't touch INTENABLE nor virtual priorities. - * - * XTOS_LOCKLEVEL is less meaningful but still relevant if XEA2 and SUBPRI is zero, - * ie. if INTENABLE doesn't get virtualized (XTOS_VIRTUAL_INTENABLE not set); - * in this case, it is the interrupt level at which INTENABLE accesses are guarded, - * so that interrupt handlers up to this level can safely manipulate INTENABLE. - */ -#define XTOS_LOCKLEVEL XCHAL_NUM_INTLEVELS /* intlevel of INTENABLE register virtualization - (minimum is EXCM_LEVEL) */ - -/* - * NOTE: the following four parameters (SUBPRI, SUBPRI_GROUPS, SUBPRI_ORDER, INT_FAIRNESS) - * are irrelevant and ignored for interrupt vectors to which only one interrupt is mapped. - */ - -#define XTOS_SUBPRI 1 /* set to 0 if you don't need sub-prioritization - within level-one interrupts via software; - for XEA2 configs, this might improve performance of - certain sections of code, because INTENABLE register - virtualization becomes unnecessary in this case */ - -/* Ignored unless SUBPRI set: */ -#define XTOS_SUBPRI_GROUPS 1 /* 1 = support selective grouping of interrupts at the same priority */ - -#define XTOS_SUBPRI_ORDER XTOS_SPO_ZERO_LO /* one of XTOS_SPO_ZERO_LO, XTOS_SPO_ZERO_HI */ - -/* Ignored if SUBPRI set but SUBPRI_GROUPS is not (single interrupt per subpri), - * or if single interrupt configured at level/vector: */ -#define XTOS_INT_FAIRNESS 1 /* 1 = enable round-robin/fifo scheduling of interrupt - handlers of a given level or sub-priority */ - - -#define XTOS_DEBUG_PC 1 /* 1 = enable nice stack traceback showing interrupted code - when debugging interrupt or exception handler; - not implemented for high-priority handlers, or - for call0 ABI */ - -#define XTOS_CNEST 1 /* 1 = enable support for nested C functions - (save/restore nested C function call-chain pointer) */ - -/* Current compilers only use ACC (not MRn) when MAC16 is enabled, so you can leave this 0 for performance: */ -#define XTOS_SAVE_ALL_MAC16 0 /* set to save/restore MAC16 MRn registers */ - -/* Setting this might be useful to clear X's in hardware simulation a bit earlier, but - * should not be needed in production code: */ -#define XTOS_RESET_UNNEEDED 0 /* set to reset more registers than are really needed */ - -#endif /* XTOS_PARAMS_H */ - diff --git a/src/arch/xtensa/xtos/xtos-structs.h b/src/arch/xtensa/xtos/xtos-structs.h deleted file mode 100644 index 90f7410f0983..000000000000 --- a/src/arch/xtensa/xtos/xtos-structs.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#ifndef __XTOS_XTOS_STRUCTS_H__ -#define __XTOS_XTOS_STRUCTS_H__ - -#include "xtos-internal.h" -#include <sof/common.h> -#include <sof/lib/memory.h> - -#include <xtensa/xtruntime-frames.h> -#include <stdint.h> - -struct idc; -struct notify; -struct schedulers; -struct task; - -struct thread_data { - xtos_structures_pointers xtos_ptrs; - volatile xtos_task_context *xtos_active_task; -}; - -struct xtos_core_data { -#if CONFIG_MULTICORE - struct XtosInterruptStructure xtos_int_data; -#endif -#if CONFIG_XT_INTERRUPT_LEVEL_1 - uint8_t xtos_stack_for_interrupt_1[SOF_STACK_SIZE] __aligned(16); -#endif -#if CONFIG_XT_INTERRUPT_LEVEL_2 - uint8_t xtos_stack_for_interrupt_2[SOF_STACK_SIZE] __aligned(16); -#endif -#if CONFIG_XT_INTERRUPT_LEVEL_3 - uint8_t xtos_stack_for_interrupt_3[SOF_STACK_SIZE] __aligned(16); -#endif -#if CONFIG_XT_INTERRUPT_LEVEL_4 - uint8_t xtos_stack_for_interrupt_4[SOF_STACK_SIZE] __aligned(16); -#endif -#if CONFIG_XT_INTERRUPT_LEVEL_5 - uint8_t xtos_stack_for_interrupt_5[SOF_STACK_SIZE] __aligned(16); -#endif - xtos_task_context xtos_interrupt_ctx; - uintptr_t xtos_saved_sp; - struct thread_data *thread_data_ptr; -}; - -struct core_context { - struct thread_data td; - struct task *main_task; - struct schedulers *schedulers; - struct notify *notify; -#ifdef CONFIG_AMS - struct async_message_service *ams; -#endif - struct idc *idc; -}; - -#endif /* __XTOS_XTOS_STRUCTS_H__ */ diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index bd43559aaa80..92002c8b7c1c 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -1,68 +1,81 @@ # SPDX-License-Identifier: BSD-3-Clause -if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) - add_local_sources(sof - host-legacy.c - component.c - source_api_helper.c - sink_api_helper.c - sink_source_utils.c - audio_stream.c - channel_map.c - ) +set(base_files + channel_map.c + component.c + source_api_helper.c + sink_api_helper.c + sink_source_utils.c + audio_stream.c + channel_map.c +) +### Common actions for Zephyr/XTOS ### +if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) + # directories included unconditionally (alphabetical order) add_subdirectory(buffers) + add_subdirectory(pcm_converter) + add_subdirectory(pipeline) - if(CONFIG_COMP_BLOB) - add_local_sources(sof data_blob.c) - endif() - if(CONFIG_COMP_SRC) - add_subdirectory(src) + if(CONFIG_COMP_BASEFW_IPC4 AND NOT CONFIG_LIBRARY) + add_local_sources(sof base_fw.c) endif() - if(CONFIG_COMP_FIR) - add_subdirectory(eq_fir) + add_local_sources_ifdef(CONFIG_IPC4_BASE_FW_INTEL sof base_fw_intel.c) + + # directories and files included conditionally (alphabetical order) + if(CONFIG_COMP_ARIA) + add_subdirectory(aria) endif() - if(CONFIG_COMP_IIR) - add_subdirectory(eq_iir) + if(CONFIG_COMP_ASRC) + add_subdirectory(asrc) endif() - if(CONFIG_COMP_DCBLOCK) - add_subdirectory(dcblock) + if(CONFIG_COMP_COPIER) + add_subdirectory(copier) endif() if(CONFIG_COMP_CROSSOVER) add_subdirectory(crossover) endif() - if(CONFIG_COMP_TDFB) - add_subdirectory(tdfb) + if(CONFIG_COMP_DCBLOCK) + add_subdirectory(dcblock) endif() if(CONFIG_COMP_DRC) add_subdirectory(drc) endif() - if(CONFIG_COMP_MULTIBAND_DRC) - add_subdirectory(multiband_drc) + if(CONFIG_COMP_FIR) + add_subdirectory(eq_fir) endif() - if(CONFIG_COMP_TONE) - add_local_sources(sof - tone.c - ) + if(CONFIG_COMP_IGO_NR) + add_subdirectory(igo_nr) + endif() + if(CONFIG_COMP_IIR) + add_subdirectory(eq_iir) + endif() + if(CONFIG_COMP_LEVEL_MULTIPLIER) + add_subdirectory(level_multiplier) + endif() + if(CONFIG_COMP_MFCC) + add_subdirectory(mfcc) endif() if(CONFIG_COMP_MIXER) - add_subdirectory(mixer) + add_subdirectory(mixer) endif() if(CONFIG_COMP_MIXIN_MIXOUT) - add_subdirectory(mixin_mixout) + add_subdirectory(mixin_mixout) + endif() + if(CONFIG_COMP_MODULE_ADAPTER) + add_subdirectory(module_adapter) + endif() + if(CONFIG_COMP_MULTIBAND_DRC) + add_subdirectory(multiband_drc) endif() if(CONFIG_COMP_MUX) add_subdirectory(mux) endif() - if(CONFIG_COMP_DAI) - add_local_sources(sof - dai-legacy.c - ) + if(CONFIG_COMP_PHASE_VOCODER) + add_subdirectory(phase_vocoder) endif() - if(CONFIG_COMP_KPB AND NOT CONFIG_LIBRARY_STATIC) - add_local_sources(sof - kpb.c - ) + if(CONFIG_COMP_RTNR) + add_subdirectory(rtnr) endif() if(CONFIG_COMP_SEL) add_subdirectory(selector) @@ -70,51 +83,97 @@ if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) if(CONFIG_COMP_SMART_AMP) add_subdirectory(smart_amp) endif() - add_subdirectory(pcm_converter) - if(CONFIG_COMP_ASRC) - add_subdirectory(asrc) + if(CONFIG_COMP_SOUND_DOSE) + add_subdirectory(sound_dose) endif() - if(CONFIG_COMP_MODULE_ADAPTER) - add_subdirectory(module_adapter) + if(CONFIG_COMP_SRC) + add_subdirectory(src) endif() - if(CONFIG_COMP_IGO_NR) - add_subdirectory(igo_nr) + if(CONFIG_COMP_STFT_PROCESS) + add_subdirectory(stft_process) endif() - if(CONFIG_COMP_COPIER) - add_subdirectory(copier) + if(CONFIG_COMP_TDFB) + add_subdirectory(tdfb) endif() - if(CONFIG_COMP_RTNR) - add_subdirectory(rtnr) + if(CONFIG_COMP_TEMPLATE) + add_subdirectory(template) endif() - if(CONFIG_COMP_BASEFW_IPC4 AND NOT CONFIG_LIBRARY) - add_local_sources(sof - base_fw.c - ) - endif() - if(CONFIG_COMP_ARIA) - add_subdirectory(aria) + if(CONFIG_COMP_TENSORFLOW) + add_subdirectory(tensorflow) endif() if(CONFIG_COMP_UP_DOWN_MIXER) add_subdirectory(up_down_mixer) endif() - if(CONFIG_COMP_MFCC) - add_subdirectory(mfcc) - endif() if(CONFIG_COMP_VOLUME) add_subdirectory(volume) endif() - subdirs(pipeline) + if(CONFIG_DTS_CODEC) + add_subdirectory(codec) + endif() + # end of directories and files included conditionally (alphabetical order) + add_subdirectory(google) + add_subdirectory(nxp) + if(CONFIG_COMP_CHAIN_DMA) add_local_sources(sof chain_dma.c) endif() - if(CONFIG_DTS_CODEC) - add_subdirectory(codec) + if(CONFIG_COMP_KPB AND NOT CONFIG_LIBRARY_STATIC) + add_local_sources(sof + kpb.c + ) + endif() + if(CONFIG_INTEL_ADSP_MIC_PRIVACY) + add_subdirectory(mic_privacy_manager) + endif() + if(CONFIG_COMP_TONE) + add_subdirectory(tone) + endif() + if(CONFIG_UAOL_INTEL_ADSP) + add_local_sources(sof intel_uaol.c) + endif() + if(CONFIG_ZEPHYR_NATIVE_DRIVERS) + list(APPEND base_files host-zephyr.c) + sof_list_append_ifdef(CONFIG_COMP_DAI base_files dai-zephyr.c) + else() + list(APPEND base_files host-legacy.c) + sof_list_append_ifdef(CONFIG_COMP_DAI base_files dai-legacy.c) + endif() +endif() + +### Common files (also used in shared library build) + +sof_list_append_ifdef(CONFIG_COMP_BLOB base_files data_blob.c) + +### (end of common files) + +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + zephyr_library_sources( + ${base_files} + ) + + return() +elseif(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) + ### not shared library, e.g. testbench ### + + add_local_sources(sof + host-legacy.c + ${base_files} + ) + + if(CONFIG_COMP_DAI) + add_local_sources(sof + dai-legacy.c + ) endif() return() endif() +### Shared library build (CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) ### + subdirs(pipeline) if(CONFIG_COMP_MODULE_ADAPTER) @@ -122,15 +181,10 @@ if(CONFIG_COMP_MODULE_ADAPTER) endif() add_local_sources(sof - component.c data_blob.c buffers/comp_buffer.c buffers/audio_buffer.c - source_api_helper.c - sink_api_helper.c - sink_source_utils.c - audio_stream.c - channel_map.c + ${base_files} ) # Audio Modules with various optimizaitons diff --git a/src/audio/Kconfig b/src/audio/Kconfig index d0be938077df..8accb25738a2 100644 --- a/src/audio/Kconfig +++ b/src/audio/Kconfig @@ -2,9 +2,6 @@ menu "Audio components" -rsource "volume/Kconfig" -rsource "aria/Kconfig" - config COMP_BASEFW_IPC4 bool "BASEFW component" default y @@ -20,8 +17,6 @@ config IPC4_BASE_FW_INTEL This implements a set of additional IPC4 properties that extend the base spec. -rsource "copier/Kconfig" - config HOST_DMA_RELOAD_DELAY_ENABLE bool "Delay reloading DMA for host interfaces" default y @@ -41,16 +36,23 @@ config HOST_DMA_RELOAD_THRESHOLD config HOST_DMA_STREAM_SYNCHRONIZATION bool "Stream DMA Transfers Synchronization" default y if ACE - default n help Enable synchronized Firmware Pointer Increment (FPI) register updates of HD-A gateways belonging to a group defined by the driver. The driver may also specify an update period for each group, different than the default one determined by the system tick frequency. This feature will allow host lower power consumption in scenarios with deep buffering. +config HOST_DMA_IPC_POSITION_UPDATES + bool "Support for stream position updates via IPC messages" + depends on IPC_MAJOR_3 + default y + help + Support firmware functionality to report stream position updates + by sending an IPC message whenever one period of audio is transferred. + Most platforms provide more efficient ways to query the DMA status. + config COMP_CHAIN_DMA bool "Chain DMA component" - default n depends on IPC_MAJOR_4 depends on DMA_INTEL_ADSP_HDA help @@ -58,7 +60,7 @@ config COMP_CHAIN_DMA config XRUN_NOTIFICATIONS_ENABLE bool "Enable xrun notification" - default n + default y depends on IPC_MAJOR_4 help Enable xrun notifications sending to host @@ -72,7 +74,12 @@ config IPC4_GATEWAY host and DSP without using DMA: via memory window (audio payload) and IPC4 messages (set/get/flush commands). -rsource "up_down_mixer/Kconfig" +config MODULE_MAX_CONNECTIONS + int "Module maximum number of connected sink/source modules" + default 8 + help + Specifies the maximum number of sink and source connections a module + may have to other modules. config COMP_BLOB bool "Large IPC data as compound message blobs" @@ -82,33 +89,19 @@ config COMP_BLOB multiple IPC messages. Not all components or modules need this. If unsure, say yes. -rsource "src/Kconfig" +config MODULE_MAX_BLOB_SIZE + int "Maximum IPC blob size in bytes" + default 8192 + help + Specify the maximum size of IPC4 module blob data that can be + appended to each message. config COMP_STUBS bool "Build all selected third-party (3P) components with stubs" - default n help Select to force all 3P blocks to link against stubs rather than their libraries. This should only be used in testing environments like fuzzers or CI. -rsource "eq_fir/Kconfig" - -rsource "eq_iir/Kconfig" - -config COMP_TONE - bool "Tone component" - default n - select CORDIC_FIXED - help - Select for Tone component. - Warning: This component is deprecated and will be removed from SOF v2.8. - -rsource "mixer/Kconfig" - -rsource "mixin_mixout/Kconfig" - -rsource "mux/Kconfig" - config COMP_KPB bool "KPB component" default y @@ -125,24 +118,6 @@ config KPB_FORCE_COPY_TYPE_NORMAL endif # COMP_KPB -rsource "google/Kconfig" - -rsource "selector/Kconfig" - -rsource "crossover/Kconfig" - -rsource "drc/Kconfig" - -rsource "multiband_drc/Kconfig" - -rsource "dcblock/Kconfig" - -rsource "smart_amp/Kconfig" - -rsource "asrc/Kconfig" - -rsource "tdfb/Kconfig" - config COMP_MODULE_ADAPTER bool "Module adapter" default y @@ -154,15 +129,41 @@ config COMP_MODULE_ADAPTER "src\include\sof\audio\module_adapter\interfaces.h". It is possible to link several different codecs and use them in parallel. -rsource "module_adapter/Kconfig" - +# --- Kconfig Sources (alphabetical order) --- +rsource "aria/Kconfig" +rsource "asrc/Kconfig" +rsource "codec/Kconfig" +rsource "copier/Kconfig" +rsource "crossover/Kconfig" +rsource "dcblock/Kconfig" +rsource "drc/Kconfig" +rsource "eq_fir/Kconfig" +rsource "eq_iir/Kconfig" +rsource "google/Kconfig" rsource "igo_nr/Kconfig" - -rsource "rtnr/Kconfig" - rsource "mfcc/Kconfig" +rsource "mixer/Kconfig" +rsource "mixin_mixout/Kconfig" +rsource "module_adapter/Kconfig" +rsource "multiband_drc/Kconfig" +rsource "mux/Kconfig" +rsource "nxp/Kconfig" +rsource "phase_vocoder/Kconfig" +rsource "rtnr/Kconfig" +rsource "selector/Kconfig" +rsource "smart_amp/Kconfig" +rsource "sound_dose/Kconfig" +rsource "src/Kconfig" +rsource "stft_process/Kconfig" +rsource "tdfb/Kconfig" +rsource "template/Kconfig" +rsource "tensorflow/Kconfig" +rsource "tone/Kconfig" +rsource "up_down_mixer/Kconfig" +rsource "volume/Kconfig" +# --- End Kconfig Sources (alphabetical order) --- -rsource "codec/Kconfig" +rsource "level_multiplier/Kconfig" endmenu # "Audio components" @@ -170,10 +171,19 @@ menu "Data formats" config FORMAT_U8 bool "Support U8" - default n help Support unsigned 8 bit processing data format +config FORMAT_A_LAW + bool "Support A-law" + help + Support 8 bit A-law processing data format. + +config FORMAT_MU_LAW + bool "Support mu-law" + help + Support 8 bit mu-law processing data format. + config FORMAT_S16LE bool "Support S16LE" default y @@ -188,7 +198,6 @@ config FORMAT_S24LE config FORMAT_S24_3LE bool "Support S24_3LE" - default n help Support packed 24 bit processing data format with sign and in little endian format @@ -218,10 +227,21 @@ config FORMAT_CONVERT_HIFI3 config PCM_CONVERTER_FORMAT_U8 bool "Support U8" - default n help Support 8 bit processing data format without sign +config PCM_CONVERTER_FORMAT_A_LAW + bool "Support A-law" + select MATH_A_LAW_CODEC + help + Support 8 bit A-law data format. + +config PCM_CONVERTER_FORMAT_MU_LAW + bool "Support mu-law" + select MATH_MU_LAW_CODEC + help + Support 8 bit mu-law data format. + config PCM_CONVERTER_FORMAT_S16LE bool "Support S16LE" default y @@ -242,7 +262,6 @@ config PCM_CONVERTER_FORMAT_S24_4LE_MSB config PCM_CONVERTER_FORMAT_S24_3LE bool "Support S24_3LE" - default n help Support packed 24 bit processing data format with sign and in little endian format @@ -267,42 +286,36 @@ config PCM_CONVERTER_FORMAT_FLOAT config PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32 bool "Support S16C16 <-> S16C32" - default n help Support conversion between 16 bit valid sample size in 16 bit container and 16 bit valid sample size in 32 bit container config PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32 bool "Support S16C32 <-> S32C32" - default n help Support conversion between 16 bit valid sample size in 32 bit container and 32 bit valid sample size in 32 bit container config PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32 bool "Support S16C32 <-> S24C32" - default n help Support conversion between 16 bit valid sample size in 32 bit container and 24 bit valid sample size in 32 bit container config PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 bool "Support S24C24 <-> S24C32" - default n help Support conversion between 24 bit valid sample size in 24 bit container and 24 bit valid sample size in 32 bit container config PCM_CONVERTER_FORMAT_S24_C32_AND_S24_C24 bool "Support S24C32 <-> S24C24" - default n help Support conversion between 24 bit valid sample size in 32 bit container and 24 bit valid sample size in 24 bit container config PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32 bool "Support S16C32 <-> S16C32" - default n help Support one-to-one copying conversion for 16 bit valid sample size in 32 bit container @@ -331,7 +344,6 @@ config TRACE_CHANNEL config WRAP_ACTUAL_POSITION bool "Buffer wrapping" - default n help This option is to update the actual position information on wrap of buffer. It is not necessary that on wrap, the buffer position would be zero.At wrap, @@ -340,20 +352,17 @@ config WRAP_ACTUAL_POSITION 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. config DISABLE_DESCRIPTOR_SPLIT bool "Disable descriptor split" - default n help This option disbale the descriptor split for host p-table. config DAI_VERBOSE_GLITCH_WARNINGS bool "Enable additional checks and warnings for DAI data flow" - default n help Select if you want to enable additional checks and warning logs for DAI data flow. If DAI copy is called with no data to process, diff --git a/src/audio/aria/CMakeLists.txt b/src/audio/aria/CMakeLists.txt index 36af35cc76fd..f967fbbea895 100644 --- a/src/audio/aria/CMakeLists.txt +++ b/src/audio/aria/CMakeLists.txt @@ -1,3 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof aria.c aria_hifi5.c aria_hifi3.c aria_generic.c) +if(CONFIG_COMP_ARIA STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/aria_llext) + add_dependencies(app aria) +else() + add_local_sources(sof aria.c aria_hifi5.c aria_hifi3.c aria_generic.c) +endif() diff --git a/src/audio/aria/Kconfig b/src/audio/aria/Kconfig index 74a344588667..51b9cfa3381d 100644 --- a/src/audio/aria/Kconfig +++ b/src/audio/aria/Kconfig @@ -2,7 +2,7 @@ config COMP_ARIA tristate "ARIA component" - default n + default m if LIBRARY_DEFAULT_MODULAR depends on IPC_MAJOR_4 help Select for Automatic Regressive Input Amplifier Module component diff --git a/src/audio/aria/README.md b/src/audio/aria/README.md new file mode 100644 index 000000000000..99dcc595ac6d --- /dev/null +++ b/src/audio/aria/README.md @@ -0,0 +1,23 @@ +# Aria Audio Component Architecture + +This directory contains the implementation of the Aria audio component. + +## Overview + +The Aria component implements an automatic regressive input amplifier that applies variable input gain, reducing gain for high-level signals to prevent clipping while introducing about 1 ms of processing latency. + +## Architecture Diagram + +```mermaid +graph LR + In[Input Data] --> Aria[Aria Core Processing] + Aria --> Out[Output Data] +``` + +## Configuration and Scripts + +- **Kconfig**: Enables the ARIA (Automatic Regressive Input Amplifier Module) component. It applies a variable gain (target: 0, 6, 12, 18 dB) that is reduced for high-level signals to prevent clipping, introducing a 1ms latency. Users can choose HIFI optimization levels (HIFI3, HIFI4, Max, Generic). +- **CMakeLists.txt**: Handles the build integration. Depends on `IPC_MAJOR_4`. If built modularly (`CONFIG_COMP_ARIA="m"`), it uses a loadable extension (`llext`); otherwise, it compiles `aria.c` and HIFI-specific files locally. +- **aria.toml**: Defines the topology parameters for the module (UUID, affinity, pin configuration) and an array of `mod_cfg` configurations defining processing constraints for various setups. +- **Topology (.conf)**: Derived from `tools/topology/topology2/include/components/aria.conf`, it defines the `aria` widget object for topology generation. It exposes attributes like `cpc` (cycles per chunk) and `is_pages`. It sets up an `extctl` byte control with a maximum payload of 4096 bytes and defaults to UUID `6d:16:f7:99:2c:37:ef:43:81:f6:22:00:7a:a1:5f:03` (type `effect`). +- **MATLAB Tuning (`tune/`)**: Contains `.m` scripts (e.g., `sof_aria_blobs.m`) which generate ALSA control binary blobs, text formats, and M4 configuration fragments used at topology creation or runtime to supply operational parameters like attenuation settings (e.g., `param_1.conf`, `param_2.conf`). diff --git a/src/audio/aria/aria.c b/src/audio/aria/aria.c index 7fe6e319e79a..ef7285d2f564 100644 --- a/src/audio/aria/aria.c +++ b/src/audio/aria/aria.c @@ -9,7 +9,6 @@ #include <sof/audio/pipeline.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/cache.h> #include <rtos/init.h> #include <sof/lib/notifier.h> @@ -33,8 +32,6 @@ LOG_MODULE_REGISTER(aria, CONFIG_SOF_LOG_LEVEL); /* these ids aligns windows driver requirement to support windows driver */ SOF_DEFINE_REG_UUID(aria); -DECLARE_TR_CTX(aria_comp_tr, SOF_UUID(aria_uuid), LOG_LEVEL_INFO); - /** * \brief Aria gain index mapping table */ @@ -121,12 +118,19 @@ static int aria_init(struct processing_module *mod) size_t ibs, chc, sgs, sgc, req_mem, att; void *buf; - comp_info(dev, "aria_init()"); + comp_info(dev, "entry"); list_init(&dev->bsource_list); list_init(&dev->bsink_list); - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + /* sample group size is used as a divisor below, reject configs that make it zero */ + if (!base_cfg->audio_fmt.channels_count || base_cfg->audio_fmt.depth < 8) { + comp_err(dev, "invalid channels:%u depth:%d", + base_cfg->audio_fmt.channels_count, base_cfg->audio_fmt.depth); + return -EINVAL; + } + + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) { return -ENOMEM; } @@ -139,17 +143,17 @@ static int aria_init(struct processing_module *mod) att = aria->attenuation; if (aria->attenuation > ARIA_MAX_ATT) { - comp_warn(dev, "init_aria(): Attenuation value %d must not be greater than %d", + comp_warn(dev, "Attenuation value %d must not be greater than %d", att, ARIA_MAX_ATT); att = ARIA_MAX_ATT; } mod_data->private = cd; - buf = rballoc(0, SOF_MEM_CAPS_RAM, req_mem); + buf = mod_balloc(mod, req_mem); if (!buf) { - rfree(cd); - comp_err(dev, "init_aria(): allocation failed for size %d", req_mem); + mod_free(mod, cd); + comp_err(dev, "allocation failed for size %d", req_mem); return -ENOMEM; } @@ -160,8 +164,8 @@ static int aria_free(struct processing_module *mod) { struct aria_data *cd = module_get_private_data(mod); - rfree(cd->data_addr); - rfree(cd); + mod_free(mod, cd->data_addr); + mod_free(mod, cd); return 0; } @@ -171,11 +175,6 @@ static void aria_set_stream_params(struct comp_buffer *buffer, const struct ipc4_audio_format *audio_fmt = &mod->priv.cfg.base_cfg.audio_fmt; ipc4_update_buffer_format(buffer, audio_fmt); -#if SOF_USE_HIFI(3, ARIA) || SOF_USE_HIFI(4, ARIA) - audio_stream_set_align(8, 1, &buffer->stream); -#elif SOF_USE_HIFI(5, ARIA) - audio_stream_set_align(16, 1, &buffer->stream); -#endif } static int aria_prepare(struct processing_module *mod, @@ -187,22 +186,27 @@ static int aria_prepare(struct processing_module *mod, struct comp_dev *dev = mod->dev; struct aria_data *cd = module_get_private_data(mod); - comp_info(dev, "aria_prepare()"); + comp_info(dev, "entry"); source = comp_dev_get_first_data_producer(dev); - aria_set_stream_params(source, mod); - sink = comp_dev_get_first_data_consumer(dev); + if (!source || !sink) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } + + aria_set_stream_params(source, mod); aria_set_stream_params(sink, mod); + audio_stream_set_align(SOF_FRAME_BYTE_ALIGN, SOF_FRAME_COUNT_ALIGN, &source->stream); if (audio_stream_get_valid_fmt(&source->stream) != SOF_IPC_FRAME_S24_4LE || audio_stream_get_valid_fmt(&sink->stream) != SOF_IPC_FRAME_S24_4LE) { - comp_err(dev, "aria_prepare(): format is not supported"); + comp_err(dev, "format is not supported"); return -EINVAL; } if (dev->state == COMP_STATE_ACTIVE) { - comp_info(dev, "aria_prepare(): Component is in active state."); + comp_info(dev, "Component is in active state."); return 0; } @@ -224,7 +228,7 @@ static int aria_reset(struct processing_module *mod) struct aria_data *cd = module_get_private_data(mod); int idx; - comp_info(dev, "aria_reset()"); + comp_info(dev, "entry"); if (dev->state == COMP_STATE_ACTIVE) { comp_info(dev, "aria module is in active state. Ignore resetting"); @@ -251,7 +255,7 @@ static int aria_process(struct processing_module *mod, uint32_t copy_bytes; uint32_t frames = input_buffers[0].size; - comp_dbg(dev, "aria_copy()"); + comp_dbg(dev, "entry"); frames = MIN(frames, cd->smpl_group_cnt); @@ -278,7 +282,7 @@ static int aria_set_config(struct processing_module *mod, uint32_t param_id, struct aria_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - comp_info(dev, "aria_set_config()"); + comp_info(dev, "entry"); if (param_id == ARIA_SET_ATTENUATION) { if (fragment_size != sizeof(uint32_t)) { comp_err(dev, "Illegal fragment_size = %d", fragment_size); @@ -287,7 +291,7 @@ static int aria_set_config(struct processing_module *mod, uint32_t param_id, memcpy_s(&cd->att, sizeof(uint32_t), fragment, sizeof(uint32_t)); if (cd->att > ARIA_MAX_ATT) { comp_warn(dev, - "aria_set_config(): Attenuation parameter %d is limited to %d", + "Attenuation parameter %d is limited to %d", cd->att, ARIA_MAX_ATT); cd->att = ARIA_MAX_ATT; } @@ -309,9 +313,6 @@ static const struct module_interface aria_interface = { .set_configuration = aria_set_config, }; -DECLARE_MODULE_ADAPTER(aria_interface, aria_uuid, aria_comp_tr); -SOF_MODULE_INIT(aria, sys_comp_module_aria_interface_init); - #if CONFIG_COMP_ARIA_MODULE /* modular: llext dynamic link */ @@ -319,14 +320,15 @@ SOF_MODULE_INIT(aria, sys_comp_module_aria_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_ARIA 0x6D, 0x16, 0xF7, 0x99, 0x2C, 0x37, 0xEF, 0x43, 0xF6, 0x81, \ - 0x22, 0x00, 0x7A, 0xA1, 0x5F, 0x03 - -SOF_LLEXT_MOD_ENTRY(aria, &aria_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("ARIA", aria_llext_entry, 1, UUID_ARIA, 8); + SOF_LLEXT_MODULE_MANIFEST("ARIA", &aria_interface, 1, SOF_REG_UUID(aria), 8); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(aria_comp_tr, SOF_UUID(aria_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(aria_interface, aria_uuid, aria_comp_tr); +SOF_MODULE_INIT(aria, sys_comp_module_aria_interface_init); + #endif diff --git a/src/audio/aria/aria.toml b/src/audio/aria/aria.toml index fa97abcc7bcf..f40ac691d3aa 100644 --- a/src/audio/aria/aria.toml +++ b/src/audio/aria/aria.toml @@ -5,7 +5,7 @@ REM # Aria module config [[module.entry]] name = "ARIA" - uuid = "99F7166D-372C-43EF-81F6-22007AA15F03" + uuid = UUIDREG_STR_ARIA affinity_mask = "0x1" instance_count = "8" domain_types = "0" diff --git a/src/audio/aria/tune/sof_aria_blobs.m b/src/audio/aria/tune/sof_aria_blobs.m index 212a4d83b480..a3adaa8c668e 100644 --- a/src/audio/aria/tune/sof_aria_blobs.m +++ b/src/audio/aria/tune/sof_aria_blobs.m @@ -20,17 +20,17 @@ function sof_aria_blobs() blob8 = sof_aria_build_blob(0); tplg2_fn = sprintf("%s/passthrough.conf", sof_tplg_aria); - check_create_dir(tplg2_fn); - tplg2_write(tplg2_fn, blob8, "aria_config", ... - "Exported with script sof_aria_blobs.m" , ... - "cd tools/tune/aria; octave sof_aria_blobs.m"); + sof_check_create_dir(tplg2_fn); + sof_tplg2_write(tplg2_fn, blob8, "aria_config", ... + "Exported with script sof_aria_blobs.m" , ... + "cd tools/tune/aria; octave sof_aria_blobs.m"); for param = 1:3 blob8 = sof_aria_build_blob(param); tplg2_fn = sprintf("%s/param_%d.conf", sof_tplg_aria, param); - tplg2_write(tplg2_fn, blob8, "aria_config", ... - "Exported with script sof_aria_blobs.m" , ... - "cd tools/tune/aria; octave sof_aria_blobs.m"); + sof_tplg2_write(tplg2_fn, blob8, "aria_config", ... + "Exported with script sof_aria_blobs.m" , ... + "cd tools/tune/aria; octave sof_aria_blobs.m"); end sof_aria_paths(false); @@ -53,7 +53,7 @@ function sof_aria_paths(enable) data_length = length(param_values); data_size = 4 * data_length; ipc_ver = 4; - [abi_bytes, abi_size] = get_abi(data_size, ipc_ver, blob_type, blob_param_id); + [abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver, blob_type, blob_param_id); blob_size = data_size + abi_size; blob8 = uint8(zeros(1, blob_size)); blob8(1:abi_size) = abi_bytes; diff --git a/src/audio/asrc/CMakeLists.txt b/src/audio/asrc/CMakeLists.txt index e87e2b1202d2..696549090f55 100644 --- a/src/audio/asrc/CMakeLists.txt +++ b/src/audio/asrc/CMakeLists.txt @@ -1,10 +1,16 @@ # SPDX-License-Identifier: BSD-3-Clause +if(CONFIG_COMP_ASRC STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/asrc_llext) + add_dependencies(app asrc) + return() +endif() + add_local_sources(sof asrc.c asrc_farrow.c asrc_farrow_generic.c - asrc_farrow_hifi3.c) + asrc_farrow_hifi3.c asrc_farrow_hifi5.c) if(CONFIG_IPC_MAJOR_3) - add_local_sources(sof asrc_ipc3.c) + add_local_sources(sof asrc_ipc3.c) elseif(CONFIG_IPC_MAJOR_4) - add_local_sources(sof asrc_ipc4.c) + add_local_sources(sof asrc_ipc4.c) endif() diff --git a/src/audio/asrc/Kconfig b/src/audio/asrc/Kconfig index b9b8604e667e..1ee458363c75 100644 --- a/src/audio/asrc/Kconfig +++ b/src/audio/asrc/Kconfig @@ -64,70 +64,60 @@ menu "Supported downsampling conversions" config ASRC_SUPPORT_CONVERSION_24000_TO_08000 bool "Downsample 24 kHz to 8 kHz" - default n help This option enables downsampling from 24 kHz to 8 kHz into the build. The consumption of memory is 2.1 kB. config ASRC_SUPPORT_CONVERSION_24000_TO_16000 bool "Downsample 24 kHz to 16 kHz" - default n help This option enables downsampling from 24 kHz to 16 kHz into the build. The consumption of memory is 1.9 kB. config ASRC_SUPPORT_CONVERSION_48000_TO_08000 bool "Downsample 48 kHz to 8 kHz" - default n help This option enables downsampling from 48 kHz to 8 kHz into the build. The consumption of memory is 2.1 kB. config ASRC_SUPPORT_CONVERSION_48000_TO_11025 bool "Downsample 48 kHz to 11.025 kHz" - default n help This option enables downsampling from 48 kHz to 11.025 kHz into the build. The consumption of memory is 1.5 kB. config ASRC_SUPPORT_CONVERSION_48000_TO_12000 bool "Downsample 48 kHz to 12 kHz" - default n help This option enables downsampling from 48 kHz to 12 kHz into the build. The consumption of memory is 1.5 kB. config ASRC_SUPPORT_CONVERSION_48000_TO_16000 bool "Downsample 48 kHz to 16 kHz" - default n help This option enables downsampling from 48 kHz to 16 kHz into the build. The consumption of memory is 1.9 kB. config ASRC_SUPPORT_CONVERSION_48000_TO_22050 bool "Downsample 48 kHz to 22.05 kHz" - default n help This option enables downsampling from 48 kHz to 22.05 kHz into the build. The consumption of memory is 1.6 kB. config ASRC_SUPPORT_CONVERSION_48000_TO_24000 bool "Downsample 48 kHz to 24 kHz" - default n help This option enables downsampling from 48 kHz to 24 kHz into the build. The consumption of memory is 1.6 kB. config ASRC_SUPPORT_CONVERSION_48000_TO_32000 bool "Downsample 48 kHz to 32 kHz" - default n help This option enables downsampling from 48 kHz to 32 kHz into the build. The consumption of memory is 1.9 kB. config ASRC_SUPPORT_CONVERSION_48000_TO_44100 bool "Downsample 48 kHz to 44.1 kHz" - default n help This option enables downsampling from 48 kHz to 44.1 kHz into the build. The consumption of memory is 1.8 kB. diff --git a/src/audio/asrc/README.md b/src/audio/asrc/README.md new file mode 100644 index 000000000000..0ed94f83f8dc --- /dev/null +++ b/src/audio/asrc/README.md @@ -0,0 +1,23 @@ +# Asynchronous Sample Rate Converter (ASRC) Architecture + +This directory contains the ASRC component implementation. + +## Overview + +The ASRC component converts the sample rate of an incoming audio stream to a different outgoing sample rate, independently of any synchronous clocks. This is commonly used when crossing clock domains. + +## Architecture Diagram + +```mermaid +graph LR + In[Input Buffer Rate A] --> ASRC[ASRC Core Engine] + ASRC --> Out[Output Buffer Rate B] + Clock[Target Clock Domain] -.-> ASRC +``` + +## Configuration and Scripts + +- **Kconfig**: Controls the ASRC component. ASRC tracks a slave DAI out of sync with firmware timers and uses less RAM than synchronous SRC. It also supports granular configuration of downsampling ratios (from 24kHz/48kHz to lower rates) to optimize memory footprint (about 1.5-2.1 kB per conversion ratio). +- **CMakeLists.txt**: Manages source inclusion (`asrc.c`, `asrc_farrow.c`, etc.). Handles modular builds (`llext`) and chooses IPC abstraction (`asrc_ipc3.c` vs `asrc_ipc4.c`) based on the active IPC major version. +- **asrc.toml**: Holds topology module entry parameters. Features pre-defined `mod_cfg` parameter arrays specifically tailored for `CONFIG_METEORLAKE`, `CONFIG_LUNARLAKE`, and `CONFIG_SOC_ACE30`/`40` SOC platforms. +- **Topology (.conf)**: Derived from `tools/topology/topology2/include/components/asrc.conf`, defining the `asrc` widget object. It introduces parameters like `rate_out` (target sample rate) and `operation_mode`. Defaults to UUID `2d:40:b4:66:68:b4:f2:42:81:a7:b3:71:21:86:3d:d4` and type `asrc`. diff --git a/src/audio/asrc/asrc.c b/src/audio/asrc/asrc.c index 45a0acc81bfb..b070d3b1c251 100644 --- a/src/audio/asrc/asrc.c +++ b/src/audio/asrc/asrc.c @@ -11,7 +11,6 @@ #include <sof/audio/ipc-config.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> #include <sof/math/numbers.h> @@ -101,7 +100,7 @@ static void src_copy_s32(struct processing_module *mod, in_frames, &idx); if (ret) - comp_err(dev, "src_copy_s32(), error %d", ret); + comp_err(dev, "error %d", ret); buf = (int32_t *)cd->obuf[0]; n = out_frames * audio_stream_get_channels(sink); @@ -177,7 +176,7 @@ static void src_copy_s16(struct processing_module *mod, in_frames, &idx); if (ret) - comp_err(dev, "src_copy_s16(), error %d", ret); + comp_err(dev, "error %d", ret); buf = (int16_t *)cd->obuf[0]; n = out_frames * audio_stream_get_channels(sink); @@ -207,17 +206,17 @@ static int asrc_init(struct processing_module *mod) const ipc_asrc_cfg *ipc_asrc = (const ipc_asrc_cfg *)mod_data->cfg.init_data; struct comp_data *cd; - comp_info(dev, "asrc_init(), source_rate=%d, sink_rate=%d, asynchronous_mode=%d, operation_mode=%d", + comp_info(dev, "source_rate=%d, sink_rate=%d, asynchronous_mode=%d, operation_mode=%d", asrc_get_source_rate(ipc_asrc), asrc_get_sink_rate(ipc_asrc), asrc_get_asynchronous_mode(ipc_asrc), asrc_get_operation_mode(ipc_asrc)); /* validate init data - either SRC sink or source rate must be set */ if (asrc_get_source_rate(ipc_asrc) == 0 || asrc_get_sink_rate(ipc_asrc) == 0) { - comp_err(dev, "asrc_init(), sink or source rates are not set"); + comp_err(dev, "sink or source rates are not set"); return -EINVAL; } - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -242,7 +241,7 @@ static int asrc_init(struct processing_module *mod) return 0; } -static int asrc_initialize_buffers(struct asrc_farrow *src_obj) +static int asrc_initialize_buffers(struct processing_module *mod, struct asrc_farrow *src_obj) { int32_t *buf_32; int16_t *buf_16; @@ -251,16 +250,17 @@ static int asrc_initialize_buffers(struct asrc_farrow *src_obj) /* Set buffer_length to filter_length * 2 to compensate for * missing element wise wrap around while loading but allowing - * aligned loads. + * aligned loads. FIR delay line write is initialized to last + * position of first copy block for reverse direction write. */ src_obj->buffer_length = src_obj->filter_length * 2; - src_obj->buffer_write_position = src_obj->filter_length; + src_obj->buffer_write_position = src_obj->filter_length - 1; if (src_obj->bit_depth == 32) { buffer_size = src_obj->buffer_length * sizeof(int32_t); for (ch = 0; ch < src_obj->num_channels; ch++) { - buf_32 = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, buffer_size); + buf_32 = mod_zalloc(mod, buffer_size); if (!buf_32) return -ENOMEM; @@ -271,7 +271,7 @@ static int asrc_initialize_buffers(struct asrc_farrow *src_obj) buffer_size = src_obj->buffer_length * sizeof(int16_t); for (ch = 0; ch < src_obj->num_channels; ch++) { - buf_16 = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, buffer_size); + buf_16 = mod_zalloc(mod, buffer_size); if (!buf_16) return -ENOMEM; @@ -283,7 +283,7 @@ static int asrc_initialize_buffers(struct asrc_farrow *src_obj) return 0; } -static void asrc_release_buffers(struct asrc_farrow *src_obj) +static void asrc_release_buffers(struct processing_module *mod, struct asrc_farrow *src_obj) { int32_t *buf_32; int16_t *buf_16; @@ -298,7 +298,7 @@ static void asrc_release_buffers(struct asrc_farrow *src_obj) if (buf_32) { src_obj->ring_buffers32[ch] = NULL; - rfree(buf_32); + mod_free(mod, buf_32); } } else @@ -307,7 +307,7 @@ static void asrc_release_buffers(struct asrc_farrow *src_obj) if (buf_16) { src_obj->ring_buffers16[ch] = NULL; - rfree(buf_16); + mod_free(mod, buf_16); } } } @@ -317,12 +317,13 @@ static int asrc_free(struct processing_module *mod) struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - comp_dbg(dev, "asrc_free()"); + comp_dbg(dev, "entry"); - rfree(cd->buf); - asrc_release_buffers(cd->asrc_obj); - rfree(cd->asrc_obj); - rfree(cd); + mod_free(mod, cd->buf); + asrc_release_buffers(mod, cd->asrc_obj); + asrc_free_polyphase_filter(mod, cd->asrc_obj); + mod_free(mod, cd->asrc_obj); + mod_free(mod, cd); return 0; } @@ -331,51 +332,10 @@ static int asrc_set_config(struct processing_module *mod, uint32_t config_id, const uint8_t *fragment, size_t fragment_size, uint8_t *response, size_t response_size) { - comp_err(mod->dev, "asrc_set_config()"); + comp_err(mod->dev, "entry"); return -EINVAL; } -static int asrc_verify_params(struct processing_module *mod, - struct sof_ipc_stream_params *params) -{ - struct comp_data *cd = module_get_private_data(mod); - struct comp_dev *dev = mod->dev; - int ret; - - comp_dbg(dev, "asrc_verify_params()"); - - /* check whether params->rate (received from driver) are equal - * to asrc->source_rate (PLAYBACK) or asrc->sink_rate (CAPTURE) set - * during creating src component in asrc_new(). - * src->source/sink_rate = 0 means that source/sink rate can vary. - */ - if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { - if (asrc_get_source_rate(&cd->ipc_config) && - params->rate != asrc_get_source_rate(&cd->ipc_config)) { - comp_err(dev, "asrc_verify_params(): runtime stream pcm rate %u does not match rate %u fetched from ipc.", - params->rate, asrc_get_source_rate(&cd->ipc_config)); - return -EINVAL; - } - } else { - if (asrc_get_sink_rate(&cd->ipc_config) && - params->rate != asrc_get_sink_rate(&cd->ipc_config)) { - comp_err(dev, "asrc_verify_params(): runtime stream pcm rate %u does not match rate %u fetched from ipc.", - params->rate, asrc_get_sink_rate(&cd->ipc_config)); - return -EINVAL; - } - } - - /* update downstream (playback) or upstream (capture) buffer parameters - */ - ret = comp_verify_params(dev, BUFF_PARAMS_RATE, params); - if (ret < 0) { - comp_err(dev, "asrc_verify_params(): comp_verify_params() failed."); - return ret; - } - - return 0; -} - /* set component audio stream parameters */ static int asrc_params(struct processing_module *mod) { @@ -385,18 +345,26 @@ static int asrc_params(struct processing_module *mod) struct comp_buffer *sourceb, *sinkb; int err; - comp_info(dev, "asrc_params()"); + comp_info(dev, "entry"); asrc_set_stream_params(cd, pcm_params); - err = asrc_verify_params(mod, pcm_params); + err = asrc_verify_stream_params(mod, pcm_params); + if (err < 0) + return -EINVAL; + + err = comp_verify_params(dev, BUFF_PARAMS_RATE, pcm_params); if (err < 0) { - comp_err(dev, "asrc_params(): pcm params verification failed."); + comp_err(dev, "comp_verify_params() failed."); return -EINVAL; } sourceb = comp_dev_get_first_data_producer(dev); sinkb = comp_dev_get_first_data_consumer(dev); + if (!sourceb || !sinkb) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } /* update the source/sink buffer formats. Sink rate will be modified below */ asrc_update_buffer_format(sourceb, cd); @@ -411,7 +379,7 @@ static int asrc_params(struct processing_module *mod) cd->sink_rate = audio_stream_get_rate(&sinkb->stream); if (!cd->sink_rate) { - comp_err(dev, "asrc_params(), zero sink rate"); + comp_err(dev, "zero sink rate"); return -EINVAL; } @@ -430,7 +398,7 @@ static int asrc_params(struct processing_module *mod) cd->sink_frames_max = cd->sink_frames + 10; cd->frames = MAX(cd->source_frames_max, cd->sink_frames_max); - comp_info(dev, "asrc_params(), source_rate=%u, sink_rate=%u, source_frames_max=%d, sink_frames_max=%d", + comp_info(dev, "source_rate=%u, sink_rate=%u, source_frames_max=%d, sink_frames_max=%d", cd->source_rate, cd->sink_rate, cd->source_frames_max, cd->sink_frames_max); @@ -450,11 +418,14 @@ static int asrc_dai_find(struct comp_dev *dev, struct comp_data *cd) /* In push mode check if sink component is DAI */ do { sinkb = comp_dev_get_first_data_consumer(dev); + if (!sinkb) { + comp_err(asrc_dev, "At end: NULL buffer, no DAI found."); + return -EINVAL; + } dev = comp_buffer_get_sink_component(sinkb); - if (!dev) { - comp_err(asrc_dev, "At end, no DAI found."); + comp_err(asrc_dev, "At end: NULL device, no DAI found."); return -EINVAL; } @@ -468,11 +439,14 @@ static int asrc_dai_find(struct comp_dev *dev, struct comp_data *cd) /* In pull mode check if source component is DAI */ do { sourceb = comp_dev_get_first_data_producer(dev); + if (!sourceb) { + comp_err(asrc_dev, "At beginning: NULL buffer, no DAI found."); + return -EINVAL; + } dev = comp_buffer_get_source_component(sourceb); - if (!dev) { - comp_err(asrc_dev, "At beginning, no DAI found."); + comp_err(asrc_dev, "At beginning: NULL device, no DAI found."); return -EINVAL; } @@ -495,7 +469,7 @@ static int asrc_trigger(struct processing_module *mod, int cmd) struct comp_dev *dev = mod->dev; int ret; - comp_info(dev, "asrc_trigger()"); + comp_info(dev, "entry"); /* Enable timestamping in pipeline DAI */ if (cmd == COMP_TRIGGER_START && cd->track_drift) { @@ -535,13 +509,16 @@ static int asrc_prepare(struct processing_module *mod, int ret; int i; - comp_info(dev, "asrc_prepare()"); + comp_info(dev, "entry"); ret = asrc_params(mod); if (ret < 0) return ret; - /* SRC component will only ever have 1 source and 1 sink buffer */ + /* + * SRC component will only ever have 1 source and 1 sink buffer, + * asrc_params() has checked their validity already + */ sourceb = comp_dev_get_first_data_producer(dev); sinkb = comp_dev_get_first_data_consumer(dev); @@ -557,7 +534,7 @@ static int asrc_prepare(struct processing_module *mod, 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", + comp_err(dev, "sink buffer size %d is insufficient < %d * %d", audio_stream_get_size(&sinkb->stream), dev->ipc_config.periods_sink, sink_period_bytes); ret = -ENOMEM; @@ -566,12 +543,12 @@ static int asrc_prepare(struct processing_module *mod, /* validate */ if (!sink_period_bytes) { - comp_err(dev, "asrc_prepare(), sink_period_bytes = 0"); + comp_err(dev, "sink_period_bytes = 0"); ret = -EINVAL; goto err; } if (!source_period_bytes) { - comp_err(dev, "asrc_prepare(), source_period_bytes = 0"); + comp_err(dev, "source_period_bytes = 0"); ret = -EINVAL; goto err; } @@ -590,7 +567,7 @@ static int asrc_prepare(struct processing_module *mod, cd->asrc_func = src_copy_s32; break; default: - comp_err(dev, "asrc_prepare(), invalid frame format"); + comp_err(dev, "invalid frame format"); return -EINVAL; } @@ -599,11 +576,10 @@ static int asrc_prepare(struct processing_module *mod, cd->buf_size = (cd->source_frames_max + cd->sink_frames_max) * frame_bytes; - cd->buf = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - cd->buf_size); + cd->buf = mod_zalloc(mod, cd->buf_size); if (!cd->buf) { cd->buf_size = 0; - comp_err(dev, "asrc_prepare(), allocation fail for size %d", + comp_err(dev, "allocation fail for size %d", cd->buf_size); ret = -ENOMEM; goto err; @@ -617,18 +593,17 @@ static int asrc_prepare(struct processing_module *mod, /* Get required size and allocate memory for ASRC */ sample_bits = sample_bytes * 8; - ret = asrc_get_required_size(dev, &cd->asrc_size, + ret = asrc_get_required_size(mod, &cd->asrc_size, audio_stream_get_channels(&sourceb->stream), sample_bits); if (ret) { - comp_err(dev, "asrc_prepare(), get_required_size_bytes failed"); + comp_err(dev, "get_required_size_bytes failed"); goto err_free_buf; } - cd->asrc_obj = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - cd->asrc_size); + cd->asrc_obj = mod_zalloc(mod, cd->asrc_size); if (!cd->asrc_obj) { - comp_err(dev, "asrc_prepare(), allocation fail for size %d", + comp_err(dev, "allocation fail for size %d", cd->asrc_size); cd->asrc_size = 0; ret = -ENOMEM; @@ -644,7 +619,7 @@ static int asrc_prepare(struct processing_module *mod, fs_sec = cd->source_rate; } - ret = asrc_initialise(dev, cd->asrc_obj, audio_stream_get_channels(&sourceb->stream), + ret = asrc_initialise(mod, 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, @@ -655,7 +630,7 @@ static int asrc_prepare(struct processing_module *mod, } /* Allocate ring buffers */ - ret = asrc_initialize_buffers(cd->asrc_obj); + ret = asrc_initialize_buffers(mod, cd->asrc_obj); /* check for errors */ if (ret) { @@ -673,7 +648,7 @@ static int asrc_prepare(struct processing_module *mod, cd->skew_min = cd->skew; cd->skew_max = cd->skew; - comp_info(dev, "asrc_prepare(), skew = %d", cd->skew); + comp_info(dev, "skew = %d", cd->skew); ret = asrc_update_drift(dev, cd->asrc_obj, cd->skew); if (ret) { comp_err(dev, "asrc_update_drift(), error %d", ret); @@ -683,12 +658,12 @@ static int asrc_prepare(struct processing_module *mod, return 0; err_free_asrc: - asrc_release_buffers(cd->asrc_obj); - rfree(cd->asrc_obj); + asrc_release_buffers(mod, cd->asrc_obj); + mod_free(mod, cd->asrc_obj); cd->asrc_obj = NULL; err_free_buf: - rfree(cd->buf); + mod_free(mod, cd->buf); cd->buf = NULL; err: @@ -744,7 +719,7 @@ static int asrc_control_loop(struct comp_dev *dev, struct comp_data *cd) /* Prevent divide by zero */ if (delta_sample == 0 || tsd.walclk_rate == 0) { - comp_err(dev, "asrc_control_loop(), DAI timestamp failed"); + comp_err(dev, "DAI timestamp failed"); return -EINVAL; } @@ -784,7 +759,7 @@ static int asrc_process(struct processing_module *mod, int frames_snk; int ret; - comp_dbg(dev, "asrc_process()"); + comp_dbg(dev, "entry"); ret = asrc_control_loop(dev, cd); if (ret) @@ -829,7 +804,7 @@ static int asrc_process(struct processing_module *mod, cd->asrc_func(mod, source_s, sink_s, &consumed, &produced); buffer_stream_writeback(sink, produced * audio_stream_frame_bytes(sink_s)); - comp_dbg(dev, "asrc_process(), consumed = %u, produced = %u", consumed, produced); + comp_dbg(dev, "consumed = %u, produced = %u", consumed, produced); output_buffers[0].size = produced * audio_stream_frame_bytes(sink_s); input_buffers[0].consumed = consumed * audio_stream_frame_bytes(source_s); @@ -843,16 +818,17 @@ static int asrc_reset(struct processing_module *mod) struct comp_dev *dev = mod->dev; struct comp_data *cd = module_get_private_data(mod); - comp_dbg(dev, "asrc_reset(), skew_min=%d, skew_max=%d", cd->skew_min, cd->skew_max); + comp_dbg(dev, "skew_min=%d, skew_max=%d", cd->skew_min, cd->skew_max); /* If any resources feasible to stop */ if (cd->track_drift) asrc_dai_stop_timestamp(cd); /* Free the allocations those were done in prepare() */ - asrc_release_buffers(cd->asrc_obj); - rfree(cd->asrc_obj); - rfree(cd->buf); + asrc_release_buffers(mod, cd->asrc_obj); + asrc_free_polyphase_filter(mod, cd->asrc_obj); + mod_free(mod, cd->asrc_obj); + mod_free(mod, cd->buf); cd->asrc_obj = NULL; cd->buf = NULL; @@ -869,9 +845,6 @@ static const struct module_interface asrc_interface = { .free = asrc_free, }; -DECLARE_MODULE_ADAPTER(asrc_interface, ASRC_UUID, asrc_tr); -SOF_MODULE_INIT(asrc, sys_comp_module_asrc_interface_init); - #if CONFIG_COMP_ASRC_MODULE /* modular: llext dynamic link */ @@ -879,13 +852,15 @@ SOF_MODULE_INIT(asrc, sys_comp_module_asrc_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_ASRC 0x2d, 0x40, 0xb4, 0x66, 0x68, 0xb4, 0xf2, 0x42, \ - 0x81, 0xa7, 0xb3, 0x71, 0x21, 0x86, 0x3d, 0xd4 -SOF_LLEXT_MOD_ENTRY(asrc, &asrc_interface); - static const struct sof_man_module_manifest mod_manifest[] __section(".module") __used = { - SOF_LLEXT_MODULE_MANIFEST("ASRC", asrc_llext_entry, 1, UUID_ASRC, 2), + SOF_LLEXT_MODULE_MANIFEST("ASRC", &asrc_interface, 1, SOF_REG_UUID(asrc4), 2), }; SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_MODULE_ADAPTER(asrc_interface, ASRC_UUID, asrc_tr); +SOF_MODULE_INIT(asrc, sys_comp_module_asrc_interface_init); + #endif diff --git a/src/audio/asrc/asrc.h b/src/audio/asrc/asrc.h index 1c86a2cf757e..4d7a902a0c9d 100644 --- a/src/audio/asrc/asrc.h +++ b/src/audio/asrc/asrc.h @@ -124,6 +124,7 @@ int asrc_dai_start_timestamp(struct comp_data *cd); int asrc_dai_stop_timestamp(struct comp_data *cd); void asrc_update_buffer_format(struct comp_buffer *buf_c, struct comp_data *cd); void asrc_set_stream_params(struct comp_data *cd, struct sof_ipc_stream_params *params); +int asrc_verify_stream_params(struct processing_module *mod, struct sof_ipc_stream_params *params); extern struct tr_ctx asrc_tr; /* Different UUID names for different build configurations... */ diff --git a/src/audio/asrc/asrc.toml b/src/audio/asrc/asrc.toml index ace84d85e733..2e8f8eac837e 100644 --- a/src/audio/asrc/asrc.toml +++ b/src/audio/asrc/asrc.toml @@ -4,7 +4,7 @@ [[module.entry]] name = "ASRC" - uuid = "66B4402D-B468-42F2-81A7-B37121863DD4" + uuid = UUIDREG_STR_ASRC4 affinity_mask = "0x3" instance_count = "2" domain_types = "0" @@ -18,38 +18,53 @@ 1, 0, 0xfeef, 0xc, 0x8, 0x45ff] #if CONFIG_METEORLAKE - 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] -#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_PANTHERLAKE) - 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] + mod_cfg = [0, 0, 0, 0, 20480, 21808000, 64, 192, 0, 21808, 0, + 1, 0, 0, 0, 20480, 45820000, 64, 384, 0, 45820, 0, + 2, 0, 0, 0, 20480, 75236000, 512, 1440, 0, 75236, 0, + 3, 0, 0, 0, 20480, 79732000, 512, 1536, 0, 79732, 0, + 4, 0, 0, 0, 20480, 50411000, 184, 384, 0, 50411, 0, + 5, 0, 0, 0, 20480, 24236000, 192, 128, 0, 24236, 0, + 6, 0, 0, 0, 20480, 46753000, 192, 384, 0, 46753, 0, + 7, 0, 0, 0, 20480, 30032000, 256, 256, 0, 30032, 0, + 8, 0, 0, 0, 20480, 48676000, 256, 384, 0, 48676, 0, + 9, 0, 0, 0, 20480, 46548000, 360, 360, 0, 46548, 0, + 10, 0, 0, 0, 20480, 94372000, 1440, 1536, 0, 94372, 0, + 11, 0, 0, 0, 20480, 42912000, 1536, 512, 0, 42912, 0, + 12, 0, 0, 0, 20480, 31871000, 384, 192, 0, 31871, 0, + 13, 0, 0, 0, 20480, 34216000, 384, 256, 0, 34216, 0, + 14, 0, 0, 0, 20480, 83448000, 1536, 1440, 0, 83448, 0] +#elif CONFIG_LUNARLAKE + mod_cfg = [0, 0, 0, 0, 20480, 22736000, 64, 192, 0, 22736, 0, + 1, 0, 0, 0, 20480, 44703000, 64, 384, 0, 44703, 0, + 2, 0, 0, 0, 20480, 73092000, 512, 1440, 0, 73092, 0, + 3, 0, 0, 0, 20480, 78604000, 512, 1536, 0, 78604, 0, + 4, 0, 0, 0, 20480, 47674000, 184, 384, 0, 47674, 0, + 5, 0, 0, 0, 20480, 19524000, 192, 128, 0, 19524, 0, + 6, 0, 0, 0, 20480, 45942000, 192, 384, 0, 45942, 0, + 7, 0, 0, 0, 20480, 31244000, 256, 256, 0, 31244, 0, + 8, 0, 0, 0, 20480, 46978000, 256, 384, 0, 46978, 0, + 9, 0, 0, 0, 20480, 45016000, 360, 360, 0, 45016, 0, + 10, 0, 0, 0, 20480, 92684000, 1440, 1536, 0, 92684, 0, + 11, 0, 0, 0, 20480, 44535000, 1536, 512, 0, 44535, 0, + 12, 0, 0, 0, 20480, 30050000, 384, 192, 0, 30050, 0, + 13, 0, 0, 0, 20480, 35152000, 384, 256, 0, 35152, 0, + 14, 0, 0, 0, 20480, 81647000, 1536, 1440, 0, 81647, 0] +#elif CONFIG_SOC_ACE30 || CONFIG_SOC_ACE40 + mod_cfg = [0, 0, 0, 0, 20480, 29755000, 64, 192, 0, 29755, 0, + 1, 0, 0, 0, 20480, 58017000, 64, 384, 0, 58017, 0, + 2, 0, 0, 0, 20480, 103471000, 512, 1440, 0, 103471, 0, + 3, 0, 0, 0, 20480, 111431000, 512, 1536, 0, 111431, 0, + 4, 0, 0, 0, 20480, 59433000, 184, 384, 0, 59433, 0, + 5, 0, 0, 0, 20480, 25771000, 192, 128, 0, 25771, 0, + 6, 0, 0, 0, 20480, 54923000, 192, 384, 0, 54923, 0, + 7, 0, 0, 0, 20480, 42727000, 256, 256, 0, 42727, 0, + 8, 0, 0, 0, 20480, 55791000, 256, 384, 0, 55791, 0, + 9, 0, 0, 0, 20480, 57647000, 360, 360, 0, 57647, 0, + 10, 0, 0, 0, 20480, 129703000, 1440, 1536, 0, 129703, 0, + 11, 0, 0, 0, 20480, 60467000, 1536, 512, 0, 60467, 0, + 12, 0, 0, 0, 20480, 34239000, 384, 192, 0, 34239, 0, + 13, 0, 0, 0, 20480, 45743000, 384, 256, 0, 45743, 0, + 14, 0, 0, 0, 20480, 113667000, 1536, 1440, 0, 113667, 0] #endif index = __COUNTER__ diff --git a/src/audio/asrc/asrc_farrow.c b/src/audio/asrc/asrc_farrow.c index dbe1edbe2aaa..dcd58fad22bf 100644 --- a/src/audio/asrc/asrc_farrow.c +++ b/src/audio/asrc/asrc_farrow.c @@ -11,7 +11,9 @@ #include <rtos/string.h> #include <sof/trace/trace.h> #include <sof/audio/format.h> +#include <sof/lib/memory.h> #include <user/trace.h> +#include <sof/audio/module_adapter/module/generic.h> #include "asrc_farrow.h" LOG_MODULE_DECLARE(asrc, CONFIG_SOF_LOG_LEVEL); @@ -143,6 +145,51 @@ static const struct asrc_filter_params c_filter_params[CR_NUM] = { * coefficients will be attached to the _Src_farrow struct via the * initialise_filter function. */ + +#if SOF_USE_MIN_HIFI(5, ASRC) +#include "coef/asrc_farrow_coeff_4x_44100Hz_to_48000Hz.h" +#include "coef/asrc_farrow_coeff_4x_48000Hz_to_48000Hz.h" + +#if (CONFIG_ASRC_SUPPORT_CONVERSION_24000_TO_08000) +#include "coef/asrc_farrow_coeff_4x_24000Hz_to_08000Hz.h" +#endif + +#if (CONFIG_ASRC_SUPPORT_CONVERSION_24000_TO_16000) +#include "coef/asrc_farrow_coeff_4x_24000Hz_to_16000Hz.h" +#endif + +#if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_08000) +#include "coef/asrc_farrow_coeff_4x_48000Hz_to_08000Hz.h" +#endif + +#if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_11025) +#include "coef/asrc_farrow_coeff_4x_48000Hz_to_11025Hz.h" +#endif + +#if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_12000) +#include "coef/asrc_farrow_coeff_4x_48000Hz_to_12000Hz.h" +#endif + +#if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_16000) +#include "coef/asrc_farrow_coeff_4x_48000Hz_to_16000Hz.h" +#endif + +#if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_22050) +#include "coef/asrc_farrow_coeff_4x_48000Hz_to_22050Hz.h" +#endif + +#if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_24000) +#include "coef/asrc_farrow_coeff_4x_48000Hz_to_24000Hz.h" +#endif + +#if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_32000) +#include "coef/asrc_farrow_coeff_4x_48000Hz_to_32000Hz.h" +#endif + +#if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_44100) +#include "coef/asrc_farrow_coeff_4x_48000Hz_to_44100Hz.h" +#endif +#else #include "coef/asrc_farrow_coeff_44100Hz_to_48000Hz.h" #include "coef/asrc_farrow_coeff_48000Hz_to_48000Hz.h" @@ -186,6 +233,7 @@ static const struct asrc_filter_params c_filter_params[CR_NUM] = { #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_44100) #include "coef/asrc_farrow_coeff_48000Hz_to_44100Hz.h" #endif +#endif /* * FUNCTION DECLARATIONS @@ -195,7 +243,7 @@ static const struct asrc_filter_params c_filter_params[CR_NUM] = { * Initialise the pointers to the filters, set the number of filters * and their length */ -static enum asrc_error_code initialise_filter(struct comp_dev *dev, +static enum asrc_error_code initialise_filter(struct processing_module *mod, struct asrc_farrow *src_obj); /* @@ -220,27 +268,28 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, * Pointers to each channels data. Buffers are allocated externally. */ -enum asrc_error_code asrc_get_required_size(struct comp_dev *dev, +enum asrc_error_code asrc_get_required_size(struct processing_module *mod, int *required_size, int num_channels, int bit_depth) { + struct comp_dev *dev = mod->dev; int size; /* check for parameter errors */ if (!required_size) { - comp_err(dev, "asrc_get_required_size(), invalid required_size"); + comp_err(dev, "invalid required_size"); return ASRC_EC_INVALID_POINTER; } if (num_channels < 1) { - comp_err(dev, "asrc_get_required_size(), invalid num_channels = %d", + comp_err(dev, "invalid num_channels = %d", num_channels); return ASRC_EC_INVALID_NUM_CHANNELS; } if (bit_depth != 16 && bit_depth != 32) { - comp_err(dev, "asrc_get_required_size_bytes(), invalid bit_depth = %d", + comp_err(dev, "invalid bit_depth = %d", bit_depth); return ASRC_EC_INVALID_BIT_DEPTH; } @@ -270,7 +319,7 @@ enum asrc_error_code asrc_get_required_size(struct comp_dev *dev, return ASRC_EC_OK; } -enum asrc_error_code asrc_initialise(struct comp_dev *dev, +enum asrc_error_code asrc_initialise(struct processing_module *mod, struct asrc_farrow *src_obj, int num_channels, int32_t fs_prim, @@ -283,38 +332,39 @@ enum asrc_error_code asrc_initialise(struct comp_dev *dev, enum asrc_control_mode control_mode, enum asrc_operation_mode operation_mode) { + struct comp_dev *dev = mod->dev; enum asrc_error_code error_code; /* check for parameter errors */ if (!src_obj) { - comp_err(dev, "asrc_initialise(), null src_obj"); + comp_err(dev, "null src_obj"); return ASRC_EC_INVALID_POINTER; } if (num_channels < 1) { - comp_err(dev, "asrc_initialise(), num_channels = %d", + comp_err(dev, "num_channels = %d", num_channels); return ASRC_EC_INVALID_NUM_CHANNELS; } if (fs_prim < 8000 || fs_prim > 192000) { - comp_err(dev, "asrc_initialise(), fs_prim = %d", fs_prim); + comp_err(dev, "fs_prim = %d", fs_prim); return ASRC_EC_INVALID_SAMPLE_RATE; } if (fs_sec < 8000 || fs_sec > 192000) { - comp_err(dev, "asrc_initialise(), fs_src = %d", fs_sec); + comp_err(dev, "fs_src = %d", fs_sec); return ASRC_EC_INVALID_SAMPLE_RATE; } if (buffer_length < 2) { - comp_err(dev, "asrc_initialise(), buffer_length = %d", + comp_err(dev, "buffer_length = %d", buffer_length); return ASRC_EC_INVALID_BUFFER_LENGTH; } if (bit_depth != 16 && bit_depth != 32) { - comp_err(dev, "asrc_initialise(), bit_depth = %d", + comp_err(dev, "bit_depth = %d", bit_depth); return ASRC_EC_INVALID_BIT_DEPTH; } @@ -347,7 +397,7 @@ enum asrc_error_code asrc_initialise(struct comp_dev *dev, /* check conversion ratios */ if (src_obj->fs_ratio == 0 || src_obj->fs_ratio_inv == 0) { - comp_err(dev, "asrc_initialise(), fail to calculate ratios"); + comp_err(dev, "fail to calculate ratios"); return ASRC_EC_INVALID_CONVERSION_RATIO; } @@ -362,11 +412,11 @@ enum asrc_error_code asrc_initialise(struct comp_dev *dev, * also sets the pointer to the corresponding * calc_impulse_response_nX function. */ - error_code = initialise_filter(dev, src_obj); + error_code = initialise_filter(mod, src_obj); /* check for errors */ if (error_code != ASRC_EC_OK) { - comp_err(dev, "asrc_initialise(), failed filter initialise"); + comp_err(dev, "failed filter initialise"); return error_code; } @@ -390,28 +440,30 @@ enum asrc_error_code asrc_initialise(struct comp_dev *dev, return ASRC_EC_OK; } -enum asrc_error_code asrc_set_fs_ratio(struct comp_dev *dev, +enum asrc_error_code asrc_set_fs_ratio(struct processing_module *mod, struct asrc_farrow *src_obj, int32_t fs_prim, int32_t fs_sec) { + struct comp_dev *dev = mod->dev; + /* Check for parameter errors */ if (!src_obj) { - comp_err(dev, "asrc_set_fs_ratio(), null src_obj"); + comp_err(dev, "null src_obj"); return ASRC_EC_INVALID_POINTER; } if (!src_obj->is_initialised) { - comp_err(dev, "asrc_set_fs_ratio(), not initialised"); + comp_err(dev, "not initialised"); return ASRC_EC_INIT_FAILED; } if (fs_prim < 8000 || fs_prim > 192000) { - comp_err(dev, "asrc_set_fs_ratio(), fs_prim = %d", fs_prim); + comp_err(dev, "fs_prim = %d", fs_prim); return ASRC_EC_INVALID_SAMPLE_RATE; } if (fs_sec < 8000 || fs_sec > 192000) { - comp_err(dev, "asrc_set_fs_ratio(), fs_sec = %d", fs_sec); + comp_err(dev, "fs_sec = %d", fs_sec); return ASRC_EC_INVALID_SAMPLE_RATE; } @@ -431,7 +483,7 @@ enum asrc_error_code asrc_set_fs_ratio(struct comp_dev *dev, /* check conversion ratios */ if (src_obj->fs_ratio == 0 || src_obj->fs_ratio_inv == 0) { - comp_err(dev, "asrc_set_fs_ratio(), failed to calculate ratios"); + comp_err(dev, "failed to calculate ratios"); return ASRC_EC_INVALID_CONVERSION_RATIO; } @@ -442,10 +494,10 @@ enum asrc_error_code asrc_set_fs_ratio(struct comp_dev *dev, /* See initialise_asrc(...) for further information * Update the filters accordingly */ - enum asrc_error_code error_code = initialise_filter(dev, src_obj); + enum asrc_error_code error_code = initialise_filter(mod, src_obj); /* check for errors */ if (error_code != ASRC_EC_OK) { - comp_err(dev, "asrc_set_fs_ratio(), failed filter initialise"); + comp_err(dev, "failed filter initialise"); return error_code; } @@ -472,12 +524,12 @@ enum asrc_error_code asrc_set_input_format(struct comp_dev *dev, { /* check for parameter errors */ if (!src_obj) { - comp_err(dev, "asrc_set_input_format(), null src_obj"); + comp_err(dev, "null src_obj"); return ASRC_EC_INVALID_POINTER; } if (!src_obj->is_initialised) { - comp_err(dev, "asrc_set_input_format(), not initialised"); + comp_err(dev, "not initialised"); return ASRC_EC_INIT_FAILED; } @@ -492,12 +544,12 @@ enum asrc_error_code asrc_set_output_format(struct comp_dev *dev, { /* check for parameter errors */ if (!src_obj) { - comp_err(dev, "asrc_set_output_format(), null src_obj"); + comp_err(dev, "null src_obj"); return ASRC_EC_INVALID_POINTER; } if (!src_obj->is_initialised) { - comp_err(dev, "asrc_set_output_format(), not initialised"); + comp_err(dev, "not initialised"); return ASRC_EC_INIT_FAILED; } @@ -506,13 +558,40 @@ enum asrc_error_code asrc_set_output_format(struct comp_dev *dev, return ASRC_EC_OK; } +static const int32_t *__get_polyphase_filter(struct processing_module *mod, + const int32_t *filter, size_t size) +{ +#if CONFIG_FAST_GET + return mod_fast_get(mod, filter, size); +#else + return filter; +#endif +} + +#define get_polyphase_filter(m, f) __get_polyphase_filter(m, f, sizeof(f)) + +static void put_polyphase_filter(struct processing_module *mod, const int32_t *filter) +{ +#if CONFIG_FAST_GET + mod_fast_put(mod, filter); +#endif +} + +void asrc_free_polyphase_filter(struct processing_module *mod, struct asrc_farrow *src_obj) +{ + if (src_obj && src_obj->polyphase_filters) { + put_polyphase_filter(mod, src_obj->polyphase_filters); + src_obj->polyphase_filters = NULL; + } +} /* * FILTER FUNCTIONS */ -static enum asrc_error_code initialise_filter(struct comp_dev *dev, +static enum asrc_error_code initialise_filter(struct processing_module *mod, struct asrc_farrow *src_obj) { + struct comp_dev *dev = mod->dev; int fs_in; int fs_out; @@ -533,11 +612,11 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, /* Reset coefficients for possible exit with error. */ src_obj->filter_length = 0; src_obj->num_filters = 0; - src_obj->polyphase_filters = NULL; + asrc_free_polyphase_filter(mod, src_obj); if (fs_in == 0 || fs_out == 0) { /* Avoid possible divisions by zero. */ - comp_err(dev, "initialise_filter(), fs_in = %d, fs_out = %d", + comp_err(dev, "fs_in = %d, fs_out = %d", fs_in, fs_out); return ASRC_EC_INVALID_SAMPLE_RATE; } else if (fs_in == 48000 && fs_out >= 48000) { @@ -549,7 +628,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO48000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO48000].num_filters; - src_obj->polyphase_filters = &coeff48000to48000[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to48000); } else if (fs_in <= fs_out) { /* All upsampling use cases can share the same set of * filter coefficients. @@ -558,7 +637,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_44100TO48000].filter_length; src_obj->num_filters = c_filter_params[CR_44100TO48000].num_filters; - src_obj->polyphase_filters = &coeff44100to48000[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff44100to48000); } else if (fs_in == 48000) { switch (fs_out) { #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_08000) @@ -567,7 +646,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO08000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO08000].num_filters; - src_obj->polyphase_filters = &coeff48000to08000[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to08000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_11025) @@ -576,7 +655,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO11025].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO11025].num_filters; - src_obj->polyphase_filters = &coeff48000to11025[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to11025); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_12000) @@ -585,7 +664,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO12000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO12000].num_filters; - src_obj->polyphase_filters = &coeff48000to12000[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to12000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_16000) @@ -594,7 +673,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO16000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO16000].num_filters; - src_obj->polyphase_filters = &coeff48000to16000[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to16000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_22050) @@ -603,7 +682,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO22050].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO22050].num_filters; - src_obj->polyphase_filters = &coeff48000to22050[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to22050); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_24000) @@ -612,7 +691,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO24000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO24000].num_filters; - src_obj->polyphase_filters = &coeff48000to24000[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to24000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_32000) @@ -621,7 +700,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO32000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO32000].num_filters; - src_obj->polyphase_filters = &coeff48000to32000[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to32000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_44100) @@ -630,11 +709,11 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO44100].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO44100].num_filters; - src_obj->polyphase_filters = &coeff48000to44100[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to44100); break; #endif default: - comp_err(dev, "initialise_filter(), fs_out = %d", + comp_err(dev, "fs_out = %d", fs_out); return ASRC_EC_INVALID_SAMPLE_RATE; } @@ -646,7 +725,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_24000TO08000].filter_length; src_obj->num_filters = c_filter_params[CR_24000TO08000].num_filters; - src_obj->polyphase_filters = &coeff24000to08000[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff24000to08000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_24000_TO_16000) @@ -655,23 +734,23 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_24000TO16000].filter_length; src_obj->num_filters = c_filter_params[CR_24000TO16000].num_filters; - src_obj->polyphase_filters = &coeff24000to16000[0]; + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff24000to16000); break; #endif default: - comp_err(dev, "initialise_filter(), fs_out = %d", + comp_err(dev, "fs_out = %d", fs_out); return ASRC_EC_INVALID_SAMPLE_RATE; } } else { /* Conversion ratio is not supported. */ - comp_err(dev, "initialise_filter(), fs_in = %d", fs_in); + comp_err(dev, "fs_in = %d", fs_in); return ASRC_EC_INVALID_SAMPLE_RATE; } /* Check that filter length does not exceed allocated */ if (src_obj->filter_length > ASRC_MAX_FILTER_LENGTH) { - comp_err(dev, "initialise_filter(), filter_length %d exceeds max", + comp_err(dev, "filter_length %d exceeds max", src_obj->filter_length); return ASRC_EC_INVALID_FILTER_LENGTH; } @@ -693,7 +772,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, src_obj->calc_ir = &asrc_calc_impulse_response_n7; break; default: - comp_err(dev, "initialise_filter(), num_filters = %d", + comp_err(dev, "num_filters = %d", src_obj->num_filters); return ASRC_EC_INVALID_CONVERSION_RATIO; } @@ -710,12 +789,12 @@ enum asrc_error_code asrc_update_drift(struct comp_dev *dev, /* check for parameter errors */ if (!src_obj) { - comp_err(dev, "asrc_update_drift(), null src_obj"); + comp_err(dev, "null src_obj"); return ASRC_EC_INVALID_POINTER; } if (!src_obj->is_initialised) { - comp_err(dev, "asrc_update_drift(), not initialised"); + comp_err(dev, "not initialised"); return ASRC_EC_INIT_FAILED; } @@ -726,7 +805,7 @@ enum asrc_error_code asrc_update_drift(struct comp_dev *dev, /* Skew is Q2.30 */ if (clock_skew < SKEW_MIN || clock_skew > SKEW_MAX) { - comp_err(dev, "asrc_update_drift(), clock_skew = %d", + comp_err(dev, "clock_skew = %d", clock_skew); return ASRC_EC_INVALID_CLOCK_SKEW; } @@ -758,12 +837,12 @@ enum asrc_error_code asrc_update_fs_ratio(struct comp_dev *dev, /* Check input for errors */ if (!src_obj) { - comp_err(dev, "asrc_update_fs_ratio(), null src_obj"); + comp_err(dev, "null src_obj"); return ASRC_EC_INVALID_POINTER; } if (!src_obj->is_initialised) { - comp_err(dev, "asrc_update_fs_ratio(), not initialized"); + comp_err(dev, "not initialized"); return ASRC_EC_INIT_FAILED; } @@ -809,11 +888,11 @@ void asrc_write_to_ring_buffer16(struct asrc_farrow *src_obj, int m; /* update the buffer_write_position */ - (src_obj->buffer_write_position)++; + (src_obj->buffer_write_position)--; /* since it's a ring buffer we need a wrap around */ - if (src_obj->buffer_write_position >= src_obj->buffer_length) - src_obj->buffer_write_position -= (src_obj->buffer_length >> 1); + if (src_obj->buffer_write_position < 0) + src_obj->buffer_write_position += (src_obj->buffer_length >> 1); /* handle input format */ if (src_obj->input_format == ASRC_IOF_INTERLEAVED) @@ -823,7 +902,7 @@ void asrc_write_to_ring_buffer16(struct asrc_farrow *src_obj, /* write data to each channel */ j = src_obj->buffer_write_position; - k = j - (src_obj->buffer_length >> 1); + k = j + (src_obj->buffer_length >> 1); for (ch = 0; ch < src_obj->num_channels; ch++) { /* * Since we want the filter function to load 64 bit of @@ -851,11 +930,11 @@ void asrc_write_to_ring_buffer32(struct asrc_farrow *src_obj, int m; /* update the buffer_write_position */ - (src_obj->buffer_write_position)++; + (src_obj->buffer_write_position)--; /* since it's a ring buffer we need a wrap around */ - if (src_obj->buffer_write_position >= src_obj->buffer_length) - src_obj->buffer_write_position -= (src_obj->buffer_length >> 1); + if (src_obj->buffer_write_position < 0) + src_obj->buffer_write_position += (src_obj->buffer_length >> 1); /* handle input format */ if (src_obj->input_format == ASRC_IOF_INTERLEAVED) @@ -865,7 +944,7 @@ void asrc_write_to_ring_buffer32(struct asrc_farrow *src_obj, /* write data to each channel */ j = src_obj->buffer_write_position; - k = j - (src_obj->buffer_length >> 1); + k = j + (src_obj->buffer_length >> 1); for (ch = 0; ch < src_obj->num_channels; ch++) { /* * Since we want the filter function to load 64 bit of @@ -1294,7 +1373,7 @@ enum asrc_error_code asrc_process_pull32(struct comp_dev *dev, } if (src_obj->time_value_pull > TIME_VALUE_LIMIT) { - comp_err(dev, "process_pull32(): Time value = %d", + comp_err(dev, "Time value = %d", src_obj->time_value_pull); return ASRC_EC_FAILED_PULL_MODE; } diff --git a/src/audio/asrc/asrc_farrow.h b/src/audio/asrc/asrc_farrow.h index 4a7eca8bf480..48e564c2d1e1 100644 --- a/src/audio/asrc/asrc_farrow.h +++ b/src/audio/asrc/asrc_farrow.h @@ -231,7 +231,7 @@ struct asrc_farrow { * @param[in] bit_depth The wordlength that will be used for representing * the PCM samples, must be 16 or 32. */ -enum asrc_error_code asrc_get_required_size(struct comp_dev *dev, +enum asrc_error_code asrc_get_required_size(struct processing_module *mod, int *required_size, int num_channels, int bit_depth); @@ -268,7 +268,7 @@ enum asrc_error_code asrc_get_required_size(struct comp_dev *dev, * @param[in] operation_mode Choose 'push' or 'pull', depending on the mode * you want your ASRC to operate in. */ -enum asrc_error_code asrc_initialise(struct comp_dev *dev, +enum asrc_error_code asrc_initialise(struct processing_module *mod, struct asrc_farrow *src_obj, int num_channels, int32_t fs_prim, @@ -281,6 +281,13 @@ enum asrc_error_code asrc_initialise(struct comp_dev *dev, enum asrc_control_mode control_mode, enum asrc_operation_mode operation_mode); +/* + * @brief Free polyphase filters + * + * @param[in] src_obj Pointer to the ias_src_farrow. + */ +void asrc_free_polyphase_filter(struct processing_module *mod, struct asrc_farrow *src_obj); + /* * @brief Process the sample rate converter for one frame; the frame * consists of @p input_num_frames samples within @p num_channels @@ -584,7 +591,7 @@ enum asrc_error_code asrc_update_fs_ratio(struct comp_dev *dev, * @param[in] fs_prim Primary sampling rate. * @param[in] fs_sec Secondary sampling rate. */ -enum asrc_error_code asrc_set_fs_ratio(struct comp_dev *dev, +enum asrc_error_code asrc_set_fs_ratio(struct processing_module *mod, struct asrc_farrow *src_obj, int32_t fs_prim, int32_t fs_sec); diff --git a/src/audio/asrc/asrc_farrow_generic.c b/src/audio/asrc/asrc_farrow_generic.c index 65c073ac02f7..b2decc07db23 100644 --- a/src/audio/asrc/asrc_farrow_generic.c +++ b/src/audio/asrc/asrc_farrow_generic.c @@ -44,7 +44,7 @@ void asrc_fir_filter16(struct asrc_farrow *src_obj, int16_t **output_buffers, * Data is Q1.15, coefficients are Q1.30. Prod will be Qx.45. */ for (n = 0; n < src_obj->filter_length; n++) - prod += (int64_t)(*buffer_p--) * (*filter_p++); + prod += (int64_t)(*buffer_p++) * (*filter_p++); /* Shift left after accumulation, because interim * results might saturate during filtering prod = prod @@ -96,7 +96,7 @@ void asrc_fir_filter32(struct asrc_farrow *src_obj, int32_t **output_buffers, * quality. The product is Qx.54. */ for (n = 0; n < src_obj->filter_length; n++) - prod += (int64_t)(*buffer_p--) * (*filter_p++ >> 8); + prod += (int64_t)(*buffer_p++) * (*filter_p++ >> 8); /* Shift left after accumulation, because interim * results might saturate during filtering prod = prod diff --git a/src/audio/asrc/asrc_farrow_hifi3.c b/src/audio/asrc/asrc_farrow_hifi3.c index 0220804f696d..d6175ac03b4c 100644 --- a/src/audio/asrc/asrc_farrow_hifi3.c +++ b/src/audio/asrc/asrc_farrow_hifi3.c @@ -1,10 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2012-2019 Intel Corporation. All rights reserved. +// Copyright(c) 2012-2025 Intel Corporation. #include <sof/common.h> -#if SOF_USE_HIFI(3, ASRC) || SOF_USE_HIFI(4, ASRC) || SOF_USE_HIFI(5, ASRC) +#if SOF_USE_HIFI(3, ASRC) || SOF_USE_HIFI(4, ASRC) #include "asrc_farrow.h" #include <xtensa/tie/xt_hifi3.h> @@ -56,7 +56,7 @@ void asrc_fir_filter16(struct asrc_farrow *src_obj, int16_t **output_buffers, /* Iterate over the filter bins */ for (n = 0; n < n_limit; n++) { /* Read four buffered samples at once */ - AE_LA16X4_RIP(buffer0123, align_buffer, buffer_p); + AE_LA16X4_IP(buffer0123, align_buffer, buffer_p); /* Store four bins of the impulse response */ AE_LA32X2_IP(filter01, align_filter, filter_p); @@ -141,7 +141,7 @@ void asrc_fir_filter32(struct asrc_farrow *src_obj, int32_t **output_buffers, /* Iterate over the filter bins */ for (n = 0; n < n_limit; n++) { /* Read two buffered samples at once */ - AE_LA32X2_RIP(buffer01, align_buffer, buffer_p); + AE_LA32X2_IP(buffer01, align_buffer, buffer_p); /* Store two bins of the impulse response */ AE_LA32X2_IP(filter01, align_filter, filter_p); diff --git a/src/audio/asrc/asrc_farrow_hifi5.c b/src/audio/asrc/asrc_farrow_hifi5.c new file mode 100644 index 000000000000..29961e8d5d4c --- /dev/null +++ b/src/audio/asrc/asrc_farrow_hifi5.c @@ -0,0 +1,403 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2012-2025 Intel Corporation. + +#include <sof/common.h> + +#if SOF_USE_MIN_HIFI(5, ASRC) + +#include "asrc_farrow.h" +#include <xtensa/tie/xt_hifi5.h> + +LOG_MODULE_DECLARE(asrc, CONFIG_SOF_LOG_LEVEL); + +void asrc_fir_filter16(struct asrc_farrow *src_obj, int16_t **output_buffers, + int index_output_frame) +{ + ae_valignx2 align_filter; + ae_valign align_buffer; + ae_int64 prod; + ae_f32x2 filter01; + ae_f32x2 filter23; + ae_f16x4 buffer0123; + ae_int32x4 *filter_p; + ae_f16x4 *buffer_p; + int n_limit; + int ch; + int n; + int i; + + /* + * Four filter bins are accumulated per iteration. + * 'n_limit' is therefore stored to reduce redundant + * calculations. Also handle possible interleaved output. + */ + n_limit = src_obj->filter_length >> 2; + if (src_obj->output_format == ASRC_IOF_INTERLEAVED) + i = src_obj->num_channels * index_output_frame; + else + i = index_output_frame; + + /* Iterate over each channel */ + for (ch = 0; ch < src_obj->num_channels; ch++) { + /* Pointer to the beginning of the impulse response */ + filter_p = (ae_int32x4 *)&src_obj->impulse_response[0]; + + /* Pointer to the buffered input data */ + buffer_p = + (ae_f16x4 *)&src_obj->ring_buffers16[ch] + [src_obj->buffer_write_position]; + + /* Allows unaligned load of 64 bit per cycle */ + align_filter = AE_LA128_PP(filter_p); + align_buffer = AE_LA64_PP(buffer_p); + + /* Initialise the accumulator */ + prod = AE_ZERO64(); + + /* Iterate over the filter bins */ + for (n = 0; n < n_limit; n++) { + /* Read four buffered samples at once */ + AE_LA16X4_IP(buffer0123, align_buffer, buffer_p); + + /* Store four bins of the impulse response */ + AE_LA32X2X2_IP(filter01, filter23, align_filter, filter_p); + + /* Multiply and accumulate */ + AE_MULAAAAFQ32X16(prod, filter01, filter23, buffer0123); + } + + /* Shift with saturation, use filter01 as scratch */ + filter01 = AE_SLAI32S(AE_ROUND32F48SASYM(prod), 1); + + /* Round 'prod' to 16 bit and store it in + * (de-)interleaved format in the output buffers + */ + AE_S16_0_X(AE_ROUND16X4F32SSYM(filter01, filter01), + (ae_f16 *)&output_buffers[ch][i], 0); + } +} + +void asrc_fir_filter32(struct asrc_farrow *src_obj, int32_t **output_buffers, + int index_output_frame) +{ + ae_valignx2 align_filter; + ae_valignx2 align_buffer; + ae_f64 prod0; + ae_f64 prod1; + ae_f32x2 buffer23; + ae_f32x2 buffer01; + ae_f32x2 filter01; + ae_f32x2 filter23; + const ae_int32x4 *filter_p; + const ae_int32x4 *buffer_p; + int n_limit; + int ch; + int n; + int i; + + /* + * Two filter bins are accumulated per iteration. + * 'n_limit' is therefore stored to reduce redundant + * calculations. Also handle possible interleaved output. + */ + n_limit = src_obj->filter_length >> 2; + if (src_obj->output_format == ASRC_IOF_INTERLEAVED) + i = src_obj->num_channels * index_output_frame; + else + i = index_output_frame; + + /* Iterate over each channel */ + for (ch = 0; ch < src_obj->num_channels; ch++) { + /* Pointer to the beginning of the impulse response */ + filter_p = (ae_int32x4 *)&src_obj->impulse_response[0]; + + /* Pointer to the buffered input data */ + buffer_p = + (ae_int32x4 *)&src_obj->ring_buffers32[ch] + [src_obj->buffer_write_position]; + + /* Allows unaligned load of 64 bit per cycle */ + align_filter = AE_LA128_PP(filter_p); + align_buffer = AE_LA128_PP(buffer_p); + + /* Initialise the accumulators */ + prod0 = AE_ZERO64(); + prod1 = AE_ZERO64(); + + /* Iterate over the filter bins */ + for (n = 0; n < n_limit; n++) { + /* Read four buffered samples */ + AE_LA32X2X2_IP(buffer01, buffer23, align_buffer, buffer_p); + + /* Load four coefficients of the impulse response */ + AE_LA32X2X2_IP(filter01, filter23, align_filter, filter_p); + + /* Multiply and accumulate */ + AE_MULAAF2D32RA_HH_LL(prod0, prod1, buffer01, buffer23, filter01, filter23); + } + + /* Add up the two accumulators */ + prod0 = AE_ADD64S(prod0, prod1); + + /* Shift with saturation */ + buffer01 = AE_SLAI32S(AE_ROUND32F48SASYM(prod0), 1); + + /* Store 'buffer01' in (de-)interleaved format in the output buffers */ + AE_S32_L_X(buffer01, (ae_f32 *)&output_buffers[ch][i], 0); + } +} + +/* + ALGORITHM SPECIFIC FUNCTIONS */ + +void asrc_calc_impulse_response_n4(struct asrc_farrow *src_obj) +{ + ae_f32x2 time_x2; + ae_f32x2 a10; + ae_f32x2 a32; + ae_f32x2 b10; + ae_f32x2 b32; + ae_int32x4 *filter_P; + ae_int32x4 *result_P; + ae_valignx2 align_f; + ae_valignx2 align_out; + int i; + int n; + + /* Set the pointer tot the polyphase filters */ + filter_P = (ae_int32x4 *)&src_obj->polyphase_filters[0]; + + /* + * Set the pointer to the impulse response. + * This is where the result is stored. + */ + result_P = (ae_int32x4 *)&src_obj->impulse_response[0]; + + /* allow unaligned load of 64 bit of polyphase filter coefficients */ + align_f = AE_LA128_PP(filter_P); + align_out = AE_ZALIGN128(); + + /* Get the current fractional time */ + time_x2 = AE_L32_X((ae_f32 *)&src_obj->time_value, 0); + time_x2 = AE_SLAI32S(time_x2, 4); + + /* + * Generates two impulse response bins per iterations. + * 'index_limit' is therefore stored to reduce redundant + * calculations. + */ + n = src_obj->filter_length >> 2; + for (i = 0; i < n; i++) { + /* + * The polyphase filters lie in storage as follows + * (For N = 4, M = 64): + * [g3,0][g3,1][g3,2][g3,3][g2,0][g2,1][g2,2][g2,3]... + * [g0,0][g0,1][g0,2][g0,3][g3,4][g3,5][g3,6][g3,7]... + * [g0,60][g0,61][g0,62][g0,63] + * + * Since the polyphase filter coefficients are stored + * in an appropriate order, we can just load them up, + * one after another. + */ + + /* Load coefficients g3,4*i g3,4*i+1 g3,4*i+2, g3,4*i+3 */ + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + + /* Load coefficients g2,4*i g2,4*i+1 g2,4*i+2, g2,4*i+3 */ + AE_LA32X2X2_IP(a10, a32, align_f, filter_P); + + /* + * Use the 'Horner's Method' to calculate the result + * in a numerically stable and efficient way: + * + * Example for one coefficient (N = 4): + * g_out,m = ((g3,m*t + g2,m)*t + g1,m)*t + g0,m + */ + AE_MULAFP32X2RS(a10, b10, time_x2); /* Dual-MAC, could not find */ + AE_MULAFP32X2RS(a32, b32, time_x2); /* suitable HiFi5 quad-MAC */ + + /* Load coefficients g1,4*i g1,4*i+1 g1,4*i+2, g1,4*i+3 */ + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + AE_MULAFP32X2RS(b10, a10, time_x2); + AE_MULAFP32X2RS(b32, a32, time_x2); + + /* Load coefficients g0,4*i g0,4*i+1 g0,4*i+2, g0,4*i+3 */ + AE_LA32X2X2_IP(a10, a32, align_f, filter_P); + AE_MULAFP32X2RS(a10, b10, time_x2); + AE_MULAFP32X2RS(a32, b32, time_x2); + + /* Store the result */ + AE_SA32X2X2_IP(a10, a32, align_out, result_P); + } + + AE_SA128POS_FP(align_out, result_P); +} + +void asrc_calc_impulse_response_n5(struct asrc_farrow *src_obj) +{ + /* + * See 'calc_impulse_response_n4' for a detailed description + * of the algorithm and data handling + */ + ae_f32x2 time_x2; + ae_f32x2 a10; + ae_f32x2 a32; + ae_f32x2 b10; + ae_f32x2 b32; + ae_int32x4 *filter_P; + ae_int32x4 *result_P; + ae_valignx2 align_f; + ae_valignx2 align_out; + int i; + int n; + + filter_P = (ae_int32x4 *)&src_obj->polyphase_filters[0]; + result_P = (ae_int32x4 *)&src_obj->impulse_response[0]; + + align_f = AE_LA128_PP(filter_P); + align_out = AE_ZALIGN128(); + + time_x2 = AE_L32_X((ae_f32 *)&src_obj->time_value, 0); + time_x2 = AE_SLAI32S(time_x2, 4); + + n = src_obj->filter_length >> 2; + for (i = 0; i < n; i++) { + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + AE_LA32X2X2_IP(a10, a32, align_f, filter_P); + AE_MULAFP32X2RS(a10, b10, time_x2); + AE_MULAFP32X2RS(a32, b32, time_x2); + + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + AE_MULAFP32X2RS(b10, a10, time_x2); + AE_MULAFP32X2RS(b32, a32, time_x2); + + AE_LA32X2X2_IP(a10, a32, align_f, filter_P); + AE_MULAFP32X2RS(a10, b10, time_x2); + AE_MULAFP32X2RS(a32, b32, time_x2); + + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + AE_MULAFP32X2RS(b10, a10, time_x2); + AE_MULAFP32X2RS(b32, a32, time_x2); + + AE_SA32X2X2_IP(b10, b32, align_out, result_P); + + } + AE_SA128POS_FP(align_out, result_P); +} + +void asrc_calc_impulse_response_n6(struct asrc_farrow *src_obj) +{ + /* + * See 'calc_impulse_response_n4' for a detailed description + * of the algorithm and data handling + */ + ae_f32x2 time_x2; + ae_f32x2 a10; + ae_f32x2 a32; + ae_f32x2 b10; + ae_f32x2 b32; + ae_int32x4 *filter_P; + ae_int32x4 *result_P; + ae_valignx2 align_f; + ae_valignx2 align_out; + int i; + int n; + + filter_P = (ae_int32x4 *)&src_obj->polyphase_filters[0]; + result_P = (ae_int32x4 *)&src_obj->impulse_response[0]; + + align_f = AE_LA128_PP(filter_P); + align_out = AE_ZALIGN128(); + + time_x2 = AE_L32_X((ae_f32 *)&src_obj->time_value, 0); + time_x2 = AE_SLAI32S(time_x2, 4); + + n = src_obj->filter_length >> 2; + for (i = 0; i < n; i++) { + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + AE_LA32X2X2_IP(a10, a32, align_f, filter_P); + AE_MULAFP32X2RS(a10, b10, time_x2); + AE_MULAFP32X2RS(a32, b32, time_x2); + + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + AE_MULAFP32X2RS(b10, a10, time_x2); + AE_MULAFP32X2RS(b32, a32, time_x2); + + AE_LA32X2X2_IP(a10, a32, align_f, filter_P); + AE_MULAFP32X2RS(a10, b10, time_x2); + AE_MULAFP32X2RS(a32, b32, time_x2); + + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + AE_MULAFP32X2RS(b10, a10, time_x2); + AE_MULAFP32X2RS(b32, a32, time_x2); + + AE_LA32X2X2_IP(a10, a32, align_f, filter_P); + AE_MULAFP32X2RS(a10, b10, time_x2); + AE_MULAFP32X2RS(a32, b32, time_x2); + + AE_SA32X2X2_IP(a10, a32, align_out, result_P); + + } + AE_SA128POS_FP(align_out, result_P); +} + +void asrc_calc_impulse_response_n7(struct asrc_farrow *src_obj) +{ + /* + * See 'calc_impulse_response_n4' for a detailed description + * of the algorithm and data handling + */ + ae_f32x2 time_x2; + ae_f32x2 a10; + ae_f32x2 a32; + ae_f32x2 b10; + ae_f32x2 b32; + ae_int32x4 *filter_P; + ae_int32x4 *result_P; + ae_valignx2 align_f; + ae_valignx2 align_out; + int i; + int n; + + filter_P = (ae_int32x4 *)&src_obj->polyphase_filters[0]; + result_P = (ae_int32x4 *)&src_obj->impulse_response[0]; + + align_f = AE_LA128_PP(filter_P); + align_out = AE_ZALIGN128(); + + time_x2 = AE_L32_X((ae_f32 *)&src_obj->time_value, 0); + time_x2 = AE_SLAI32S(time_x2, 4); + + n = src_obj->filter_length >> 2; + for (i = 0; i < n; i++) { + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + AE_LA32X2X2_IP(a10, a32, align_f, filter_P); + AE_MULAFP32X2RS(a10, b10, time_x2); + AE_MULAFP32X2RS(a32, b32, time_x2); + + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + AE_MULAFP32X2RS(b10, a10, time_x2); + AE_MULAFP32X2RS(b32, a32, time_x2); + + AE_LA32X2X2_IP(a10, a32, align_f, filter_P); + AE_MULAFP32X2RS(a10, b10, time_x2); + AE_MULAFP32X2RS(a32, b32, time_x2); + + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + AE_MULAFP32X2RS(b10, a10, time_x2); + AE_MULAFP32X2RS(b32, a32, time_x2); + + AE_LA32X2X2_IP(a10, a32, align_f, filter_P); + AE_MULAFP32X2RS(a10, b10, time_x2); + AE_MULAFP32X2RS(a32, b32, time_x2); + + AE_LA32X2X2_IP(b10, b32, align_f, filter_P); + AE_MULAFP32X2RS(b10, a10, time_x2); + AE_MULAFP32X2RS(b32, a32, time_x2); + + AE_SA32X2X2_IP(b10, b32, align_out, result_P); + } + AE_SA128POS_FP(align_out, result_P); +} + +#endif /* ASRC_HIFI_5 */ diff --git a/src/audio/asrc/asrc_ipc3.c b/src/audio/asrc/asrc_ipc3.c index 30dfbecddc6b..07cdb33f14f2 100644 --- a/src/audio/asrc/asrc_ipc3.c +++ b/src/audio/asrc/asrc_ipc3.c @@ -4,7 +4,6 @@ #include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/ipc-config.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> #include <sof/trace/trace.h> @@ -18,6 +17,7 @@ SOF_DEFINE_REG_UUID(asrc); DECLARE_TR_CTX(asrc_tr, SOF_UUID(asrc_uuid), LOG_LEVEL_INFO); +LOG_MODULE_DECLARE(asrc, CONFIG_SOF_LOG_LEVEL); int asrc_dai_configure_timestamp(struct comp_data *cd) { @@ -64,3 +64,31 @@ void asrc_set_stream_params(struct comp_data *cd, struct sof_ipc_stream_params * { /* IPC3 don't need to update audio stream format here. */ } + +int asrc_verify_stream_params(struct processing_module *mod, struct sof_ipc_stream_params *params) +{ + struct comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + + /* PCM sampling rate received in params is dynamically selected based on the mode + * (PULL/PUSH). Need to validate it against the initial fixed ASRC configuration + * src->source/sink_rate = 0 means that source/sink rate can vary. + */ + if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { + if (asrc_get_source_rate(&cd->ipc_config) && + params->rate != asrc_get_source_rate(&cd->ipc_config)) { + comp_err(dev, "runtime stream pcm rate %u does not match rate %u fetched from ipc.", + params->rate, asrc_get_source_rate(&cd->ipc_config)); + return -EINVAL; + } + } else { + if (asrc_get_sink_rate(&cd->ipc_config) && + params->rate != asrc_get_sink_rate(&cd->ipc_config)) { + comp_err(dev, "runtime stream pcm rate %u does not match rate %u fetched from ipc.", + params->rate, asrc_get_sink_rate(&cd->ipc_config)); + return -EINVAL; + } + } + + return 0; +} diff --git a/src/audio/asrc/asrc_ipc4.c b/src/audio/asrc/asrc_ipc4.c index 3e5d8bf7818f..cba17aeee410 100644 --- a/src/audio/asrc/asrc_ipc4.c +++ b/src/audio/asrc/asrc_ipc4.c @@ -4,7 +4,6 @@ #include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/ipc-config.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> #include <sof/trace/trace.h> @@ -76,3 +75,15 @@ void asrc_set_stream_params(struct comp_data *cd, struct sof_ipc_stream_params * { ipc4_base_module_cfg_to_stream_params(&cd->ipc_config.base, params); } + +int asrc_verify_stream_params(struct processing_module *mod, struct sof_ipc_stream_params *params) +{ + /* IPC4 params contain the same fixed sampling rate that is already stored in + * ipc4_asrc_module_cfg, rather than a PCM sampling rate that is dynamically selected + * based on the mode (PULL/PUSH) as in IPC3. For now leave the function empty. + */ + (void)mod; + (void)params; + + return 0; +} diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_24000Hz_to_08000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_24000Hz_to_08000Hz.h index fe089c50c082..149fd5669778 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_24000Hz_to_08000Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_24000Hz_to_08000Hz.h @@ -6,7 +6,7 @@ /* Conversion from 24000 Hz to 8000 Hz */ /* NUM_FILTERS=4, FILTER_LENGTH=128, alpha=6.200000, gamma=0.454000 */ -static const int32_t coeff24000to08000[] = { +__cold_rodata static const int32_t coeff24000to08000[] = { /* Filter #4, conversion from 24000 Hz to 8000 Hz */ CONVERT_COEFF(-10830), /* Filter:4, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_24000Hz_to_16000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_24000Hz_to_16000Hz.h index 351c238d5dac..9f0070a48928 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_24000Hz_to_16000Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_24000Hz_to_16000Hz.h @@ -6,7 +6,7 @@ /* Conversion from 24000 Hz to 16000 Hz */ /* NUM_FILTERS=6, FILTER_LENGTH=80, alpha=6.800000, gamma=0.460000 */ -static const int32_t coeff24000to16000[] = { +__cold_rodata static const int32_t coeff24000to16000[] = { /* Filter #6, conversion from 24000 Hz to 16000 Hz */ CONVERT_COEFF(-26295), /* Filter:6, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_44100Hz_to_48000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_44100Hz_to_48000Hz.h index 28ff9ae7834d..fca60d5d6b2c 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_44100Hz_to_48000Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_44100Hz_to_48000Hz.h @@ -6,7 +6,7 @@ /* Conversion from 44100 Hz to 48000 Hz */ /* NUM_FILTERS=7, FILTER_LENGTH=64, alpha=7.800000, gamma=0.459000 */ -static const int32_t coeff44100to48000[] = { +__cold_rodata static const int32_t coeff44100to48000[] = { /* Filter #7, conversion from 44100 Hz to 48000 Hz */ CONVERT_COEFF(-36104), /* Filter:7, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_08000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_08000Hz.h index c4affd499b39..8db0161ae75d 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_08000Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_08000Hz.h @@ -6,7 +6,7 @@ /* Conversion from 48000 Hz to 8000 Hz */ /* NUM_FILTERS=4, FILTER_LENGTH=128, alpha=5.600000, gamma=0.415500 */ -static const int32_t coeff48000to08000[] = { +__cold_rodata static const int32_t coeff48000to08000[] = { /* Filter #4, conversion from 48000 Hz to 8000 Hz */ CONVERT_COEFF(-3301), /* Filter:4, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_11025Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_11025Hz.h index 0488065745d3..50c25bd2490d 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_11025Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_11025Hz.h @@ -6,7 +6,7 @@ /* Conversion from 48000 Hz to 11025 Hz */ /* NUM_FILTERS=4, FILTER_LENGTH=96, alpha=5.700000, gamma=0.417000 */ -static const int32_t coeff48000to11025[] = { +__cold_rodata static const int32_t coeff48000to11025[] = { /* Filter #4, conversion from 48000 Hz to 11025 Hz */ CONVERT_COEFF(-5276), /* Filter:4, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_12000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_12000Hz.h index b527b30a982d..69ae4fbd550d 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_12000Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_12000Hz.h @@ -6,7 +6,7 @@ /* Conversion from 48000 Hz to 12000 Hz */ /* NUM_FILTERS=4, FILTER_LENGTH=96, alpha=5.700000, gamma=0.424000 */ -static const int32_t coeff48000to12000[] = { +__cold_rodata static const int32_t coeff48000to12000[] = { /* Filter #4, conversion from 48000 Hz to 12000 Hz */ CONVERT_COEFF(9466), /* Filter:4, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_16000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_16000Hz.h index e085df9d34c5..a26687c4afd0 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_16000Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_16000Hz.h @@ -6,7 +6,7 @@ /* Conversion from 48000 Hz to 16000 Hz */ /* NUM_FILTERS=5, FILTER_LENGTH=96, alpha=5.700000, gamma=0.443000 */ -static const int32_t coeff48000to16000[] = { +__cold_rodata static const int32_t coeff48000to16000[] = { /* Filter #5, conversion from 48000 Hz to 16000 Hz */ CONVERT_COEFF(6003), /* Filter:5, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_22050Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_22050Hz.h index 71daa2c2adae..3ab3c3fc2605 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_22050Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_22050Hz.h @@ -6,7 +6,7 @@ /* Conversion from 48000 Hz to 22050 Hz */ /* NUM_FILTERS=5, FILTER_LENGTH=80, alpha=6.900000, gamma=0.440000 */ -static const int32_t coeff48000to22050[] = { +__cold_rodata static const int32_t coeff48000to22050[] = { /* Filter #5, conversion from 48000 Hz to 22050 Hz */ CONVERT_COEFF(7662), /* Filter:5, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_24000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_24000Hz.h index 2d075beb243f..9eed3d92451a 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_24000Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_24000Hz.h @@ -6,7 +6,7 @@ /* Conversion from 48000 Hz to 24000 Hz */ /* NUM_FILTERS=5, FILTER_LENGTH=80, alpha=7.500000, gamma=0.440000 */ -static const int32_t coeff48000to24000[] = { +__cold_rodata static const int32_t coeff48000to24000[] = { /* Filter #5, conversion from 48000 Hz to 24000 Hz */ CONVERT_COEFF(-13838), /* Filter:5, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_32000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_32000Hz.h index 7dfe46d76bcf..7f798a829ae7 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_32000Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_32000Hz.h @@ -6,7 +6,7 @@ /* Conversion from 48000 Hz to 32000 Hz */ /* NUM_FILTERS=6, FILTER_LENGTH=80, alpha=8.000000, gamma=0.452000 */ -static const int32_t coeff48000to32000[] = { +__cold_rodata static const int32_t coeff48000to32000[] = { /* Filter #6, conversion from 48000 Hz to 32000 Hz */ CONVERT_COEFF(-11561), /* Filter:6, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_44100Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_44100Hz.h index ef40e3bf690f..505708746f60 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_44100Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_44100Hz.h @@ -6,7 +6,7 @@ /* Conversion from 48000 Hz to 44100 Hz */ /* NUM_FILTERS=7, FILTER_LENGTH=64, alpha=8.150000, gamma=0.456000 */ -static const int32_t coeff48000to44100[] = { +__cold_rodata static const int32_t coeff48000to44100[] = { /* Filter #7, conversion from 48000 Hz to 44100 Hz */ CONVERT_COEFF(-34608), /* Filter:7, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_48000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_48000Hz.h index c9e0d9b2f671..953a9adbdab3 100644 --- a/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_48000Hz.h +++ b/src/audio/asrc/coef/asrc_farrow_coeff_48000Hz_to_48000Hz.h @@ -6,7 +6,7 @@ /* Conversion from 48000 Hz to 48000 Hz */ /* NUM_FILTERS=7, FILTER_LENGTH=48, alpha=7.150000, gamma=0.458000 */ -static const int32_t coeff48000to48000[] = { +__cold_rodata static const int32_t coeff48000to48000[] = { /* Filter #7, conversion from 48000 Hz to 48000 Hz */ CONVERT_COEFF(201584), /* Filter:7, Coefficient: 1 */ diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_24000Hz_to_08000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_24000Hz_to_08000Hz.h new file mode 100644 index 000000000000..778de8dfa56e --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_24000Hz_to_08000Hz.h @@ -0,0 +1,618 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 24000 Hz to 8000 Hz */ +/* NUM_FILTERS=4, FILTER_LENGTH=128, alpha=6.200000, gamma=0.454000 */ + +__cold_rodata static const int32_t coeff24000to08000[] = { + + /* Filter #1, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-10830), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(-19325), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(-8706), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(17158), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(41187), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(5433), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(-57507), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(-85177), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(53742), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(102764), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(56825), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(-81566), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(-40910), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(43191), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(132068), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(122684), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(35023), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(21531), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(-20607), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(-56412), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(-28687), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(84875), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(153388), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(85079), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(-198613), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(-152429), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(77423), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(318659), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(-26903), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(-219188), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(-265221), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(-55019), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-45627), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(16004), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(80964), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(83822), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(-97650), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(-243132), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(-188414), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(74163), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(320857), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(-4716), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(-436161), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(-569989), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(292318), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(469916), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(238081), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(-305542), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(3428), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(-103074), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(-136759), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(-45156), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(342026), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(348018), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(12595), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(-425480), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(-178871), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(504223), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(887721), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(512609), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(-717573), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(-551012), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(198162), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(961755), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(113706), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(201400), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(115814), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(-100685), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(-563391), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(-190843), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(456045), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(818713), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(-456956), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(-1233622), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(-1020591), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(215831), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(1003766), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(97129), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(-1125979), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(-1574771), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-269690), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(-219149), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(49817), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(327706), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(483675), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(-385406), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(-1078344), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(-901092), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(1533583), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(1697790), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(298404), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(-1679597), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(-640937), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(1106673), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(2199991), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(1469926), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(353713), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(53122), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(-355599), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(-510586), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(159521), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(1284520), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(1431454), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(273189), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(-2496622), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(-1148947), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(1536178), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(3316675), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(-783087), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(-2766581), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(-2577984), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(34050), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-219636), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(328523), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(671539), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(455239), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(-1358235), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(-2033639), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(-951202), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(1203809), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(2363113), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(-953893), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(-4000055), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(-3912103), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(3113447), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(3898837), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(1239875), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(-3039958), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-218603), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(-807891), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(-756009), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(-2224), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(2631188), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(1887961), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(-716945), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(-3109267), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(-210918), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(4333834), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(5693246), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(2072560), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(-5293214), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(-3091666), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(2322327), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(6542868), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(880151), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(1105224), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(358874), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(-838150), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(-3059949), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(-204798), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(3314225), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(4395729), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(-4059383), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(-7516860), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(-4691958), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(2885839), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(5504147), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(-735062), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(-7351776), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(-8370954), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-1470082), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(-869768), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(620664), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(1797644), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(1651041), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(-3053727), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(-5765452), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(-3689804), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(9097774), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(8056110), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(-501272), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(-10047020), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(-1927609), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(7351404), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(11484456), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(5838619), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(1543877), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(-152285), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(-2007072), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(-2377760), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(2092009), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(6966627), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(6364024), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(-127424), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(-12064250), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(-3431170), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(9849385), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(16521192), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(-6100793), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(-14529711), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(-11146964), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(3059490), /* Filter:1, Coefficient: 48 */ + + /* Filter #13, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-667626), /* Filter:4, Coefficient: 49 */ + CONVERT_COEFF(1968948), /* Filter:4, Coefficient: 50 */ + CONVERT_COEFF(3348219), /* Filter:4, Coefficient: 51 */ + CONVERT_COEFF(1996625), /* Filter:4, Coefficient: 52 */ + CONVERT_COEFF(-7691699), /* Filter:3, Coefficient: 49 */ + CONVERT_COEFF(-9695566), /* Filter:3, Coefficient: 50 */ + CONVERT_COEFF(-3280325), /* Filter:3, Coefficient: 51 */ + CONVERT_COEFF(7429429), /* Filter:3, Coefficient: 52 */ + CONVERT_COEFF(9318936), /* Filter:2, Coefficient: 49 */ + CONVERT_COEFF(-7786997), /* Filter:2, Coefficient: 50 */ + CONVERT_COEFF(-21129476), /* Filter:2, Coefficient: 51 */ + CONVERT_COEFF(-17795597), /* Filter:2, Coefficient: 52 */ + CONVERT_COEFF(17076149), /* Filter:1, Coefficient: 49 */ + CONVERT_COEFF(18036447), /* Filter:1, Coefficient: 50 */ + CONVERT_COEFF(2522929), /* Filter:1, Coefficient: 51 */ + CONVERT_COEFF(-18539360), /* Filter:1, Coefficient: 52 */ + + /* Filter #14, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-1439811), /* Filter:4, Coefficient: 53 */ + CONVERT_COEFF(-4374392), /* Filter:4, Coefficient: 54 */ + CONVERT_COEFF(-4134491), /* Filter:4, Coefficient: 55 */ + CONVERT_COEFF(-185988), /* Filter:4, Coefficient: 56 */ + CONVERT_COEFF(13688967), /* Filter:3, Coefficient: 53 */ + CONVERT_COEFF(8930617), /* Filter:3, Coefficient: 54 */ + CONVERT_COEFF(-5110430), /* Filter:3, Coefficient: 55 */ + CONVERT_COEFF(-18240532), /* Filter:3, Coefficient: 56 */ + CONVERT_COEFF(2685075), /* Filter:2, Coefficient: 53 */ + CONVERT_COEFF(25435789), /* Filter:2, Coefficient: 54 */ + CONVERT_COEFF(30208500), /* Filter:2, Coefficient: 55 */ + CONVERT_COEFF(8011608), /* Filter:2, Coefficient: 56 */ + CONVERT_COEFF(-26909927), /* Filter:1, Coefficient: 53 */ + CONVERT_COEFF(-11976152), /* Filter:1, Coefficient: 54 */ + CONVERT_COEFF(18016549), /* Filter:1, Coefficient: 55 */ + CONVERT_COEFF(38981614), /* Filter:1, Coefficient: 56 */ + + /* Filter #15, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(5056345), /* Filter:4, Coefficient: 57 */ + CONVERT_COEFF(7681958), /* Filter:4, Coefficient: 58 */ + CONVERT_COEFF(5124031), /* Filter:4, Coefficient: 59 */ + CONVERT_COEFF(-1687599), /* Filter:4, Coefficient: 60 */ + CONVERT_COEFF(-18700492), /* Filter:3, Coefficient: 57 */ + CONVERT_COEFF(-2525039), /* Filter:3, Coefficient: 58 */ + CONVERT_COEFF(21825461), /* Filter:3, Coefficient: 59 */ + CONVERT_COEFF(37870743), /* Filter:3, Coefficient: 60 */ + CONVERT_COEFF(-28470273), /* Filter:2, Coefficient: 57 */ + CONVERT_COEFF(-50432144), /* Filter:2, Coefficient: 58 */ + CONVERT_COEFF(-32720110), /* Filter:2, Coefficient: 59 */ + CONVERT_COEFF(25573931), /* Filter:2, Coefficient: 60 */ + CONVERT_COEFF(28567790), /* Filter:1, Coefficient: 57 */ + CONVERT_COEFF(-13547145), /* Filter:1, Coefficient: 58 */ + CONVERT_COEFF(-58824612), /* Filter:1, Coefficient: 59 */ + CONVERT_COEFF(-64597690), /* Filter:1, Coefficient: 60 */ + + /* Filter #16, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-8594673), /* Filter:4, Coefficient: 61 */ + CONVERT_COEFF(-10910995), /* Filter:4, Coefficient: 62 */ + CONVERT_COEFF(-6715326), /* Filter:4, Coefficient: 63 */ + CONVERT_COEFF(1653573), /* Filter:4, Coefficient: 64 */ + CONVERT_COEFF(32251799), /* Filter:3, Coefficient: 61 */ + CONVERT_COEFF(4871577), /* Filter:3, Coefficient: 62 */ + CONVERT_COEFF(-29612069), /* Filter:3, Coefficient: 63 */ + CONVERT_COEFF(-50673264), /* Filter:3, Coefficient: 64 */ + CONVERT_COEFF(95527010), /* Filter:2, Coefficient: 61 */ + CONVERT_COEFF(134020246), /* Filter:2, Coefficient: 62 */ + CONVERT_COEFF(111496535), /* Filter:2, Coefficient: 63 */ + CONVERT_COEFF(33022726), /* Filter:2, Coefficient: 64 */ + CONVERT_COEFF(-2840724), /* Filter:1, Coefficient: 61 */ + CONVERT_COEFF(116347844), /* Filter:1, Coefficient: 62 */ + CONVERT_COEFF(244337981), /* Filter:1, Coefficient: 63 */ + CONVERT_COEFF(319519294), /* Filter:1, Coefficient: 64 */ + + /* Filter #17, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(9058182), /* Filter:4, Coefficient: 65 */ + CONVERT_COEFF(11001115), /* Filter:4, Coefficient: 66 */ + CONVERT_COEFF(6613114), /* Filter:4, Coefficient: 67 */ + CONVERT_COEFF(-908182), /* Filter:4, Coefficient: 68 */ + CONVERT_COEFF(-45371944), /* Filter:3, Coefficient: 65 */ + CONVERT_COEFF(-17020199), /* Filter:3, Coefficient: 66 */ + CONVERT_COEFF(17061394), /* Filter:3, Coefficient: 67 */ + CONVERT_COEFF(37099013), /* Filter:3, Coefficient: 68 */ + CONVERT_COEFF(-62590522), /* Filter:2, Coefficient: 65 */ + CONVERT_COEFF(-125985859), /* Filter:2, Coefficient: 66 */ + CONVERT_COEFF(-127527137), /* Filter:2, Coefficient: 67 */ + CONVERT_COEFF(-74392732), /* Filter:2, Coefficient: 68 */ + CONVERT_COEFF(303533893), /* Filter:1, Coefficient: 65 */ + CONVERT_COEFF(204637406), /* Filter:1, Coefficient: 66 */ + CONVERT_COEFF(72635229), /* Filter:1, Coefficient: 67 */ + CONVERT_COEFF(-31218589), /* Filter:1, Coefficient: 68 */ + + /* Filter #18, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-6645584), /* Filter:4, Coefficient: 69 */ + CONVERT_COEFF(-7338726), /* Filter:4, Coefficient: 70 */ + CONVERT_COEFF(-3379574), /* Filter:4, Coefficient: 71 */ + CONVERT_COEFF(1862507), /* Filter:4, Coefficient: 72 */ + CONVERT_COEFF(33592635), /* Filter:3, Coefficient: 69 */ + CONVERT_COEFF(12488167), /* Filter:3, Coefficient: 70 */ + CONVERT_COEFF(-10270513), /* Filter:3, Coefficient: 71 */ + CONVERT_COEFF(-20289677), /* Filter:3, Coefficient: 72 */ + CONVERT_COEFF(-3539197), /* Filter:2, Coefficient: 69 */ + CONVERT_COEFF(43642084), /* Filter:2, Coefficient: 70 */ + CONVERT_COEFF(47036638), /* Filter:2, Coefficient: 71 */ + CONVERT_COEFF(16924310), /* Filter:2, Coefficient: 72 */ + CONVERT_COEFF(-69423135), /* Filter:1, Coefficient: 69 */ + CONVERT_COEFF(-46017033), /* Filter:1, Coefficient: 70 */ + CONVERT_COEFF(2774597), /* Filter:1, Coefficient: 71 */ + CONVERT_COEFF(36162526), /* Filter:1, Coefficient: 72 */ + + /* Filter #19, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(4687214), /* Filter:4, Coefficient: 73 */ + CONVERT_COEFF(3633943), /* Filter:4, Coefficient: 74 */ + CONVERT_COEFF(169088), /* Filter:4, Coefficient: 75 */ + CONVERT_COEFF(-2783863), /* Filter:4, Coefficient: 76 */ + CONVERT_COEFF(-13928301), /* Filter:3, Coefficient: 73 */ + CONVERT_COEFF(926804), /* Filter:3, Coefficient: 74 */ + CONVERT_COEFF(12081784), /* Filter:3, Coefficient: 75 */ + CONVERT_COEFF(12208082), /* Filter:3, Coefficient: 76 */ + CONVERT_COEFF(-17765712), /* Filter:2, Coefficient: 73 */ + CONVERT_COEFF(-31677983), /* Filter:2, Coefficient: 74 */ + CONVERT_COEFF(-19297249), /* Filter:2, Coefficient: 75 */ + CONVERT_COEFF(5057264), /* Filter:2, Coefficient: 76 */ + CONVERT_COEFF(34660987), /* Filter:1, Coefficient: 73 */ + CONVERT_COEFF(7654480), /* Filter:1, Coefficient: 74 */ + CONVERT_COEFF(-19463498), /* Filter:1, Coefficient: 75 */ + CONVERT_COEFF(-26510886), /* Filter:1, Coefficient: 76 */ + + /* Filter #20, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-3155209), /* Filter:4, Coefficient: 77 */ + CONVERT_COEFF(-1100082), /* Filter:4, Coefficient: 78 */ + CONVERT_COEFF(1452075), /* Filter:4, Coefficient: 79 */ + CONVERT_COEFF(2496940), /* Filter:4, Coefficient: 80 */ + CONVERT_COEFF(3219751), /* Filter:3, Coefficient: 77 */ + CONVERT_COEFF(-6628589), /* Filter:3, Coefficient: 78 */ + CONVERT_COEFF(-9810802), /* Filter:3, Coefficient: 79 */ + CONVERT_COEFF(-4999762), /* Filter:3, Coefficient: 80 */ + CONVERT_COEFF(21084806), /* Filter:2, Coefficient: 77 */ + CONVERT_COEFF(18281519), /* Filter:2, Coefficient: 78 */ + CONVERT_COEFF(1997933), /* Filter:2, Coefficient: 79 */ + CONVERT_COEFF(-13157294), /* Filter:2, Coefficient: 80 */ + CONVERT_COEFF(-12029861), /* Filter:1, Coefficient: 77 */ + CONVERT_COEFF(9119834), /* Filter:1, Coefficient: 78 */ + CONVERT_COEFF(19673432), /* Filter:1, Coefficient: 79 */ + CONVERT_COEFF(13313145), /* Filter:1, Coefficient: 80 */ + + /* Filter #21, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(1470988), /* Filter:4, Coefficient: 81 */ + CONVERT_COEFF(-530883), /* Filter:4, Coefficient: 82 */ + CONVERT_COEFF(-1826789), /* Filter:4, Coefficient: 83 */ + CONVERT_COEFF(-1519560), /* Filter:4, Coefficient: 84 */ + CONVERT_COEFF(2887991), /* Filter:3, Coefficient: 81 */ + CONVERT_COEFF(7345400), /* Filter:3, Coefficient: 82 */ + CONVERT_COEFF(5461142), /* Filter:3, Coefficient: 83 */ + CONVERT_COEFF(-374397), /* Filter:3, Coefficient: 84 */ + CONVERT_COEFF(-15778100), /* Filter:2, Coefficient: 81 */ + CONVERT_COEFF(-5804379), /* Filter:2, Coefficient: 82 */ + CONVERT_COEFF(7156002), /* Filter:2, Coefficient: 83 */ + CONVERT_COEFF(12632597), /* Filter:2, Coefficient: 84 */ + CONVERT_COEFF(-2347060), /* Filter:1, Coefficient: 81 */ + CONVERT_COEFF(-13766705), /* Filter:1, Coefficient: 82 */ + CONVERT_COEFF(-12757053), /* Filter:1, Coefficient: 83 */ + CONVERT_COEFF(-1966773), /* Filter:1, Coefficient: 84 */ + + /* Filter #22, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-77386), /* Filter:4, Coefficient: 85 */ + CONVERT_COEFF(1218353), /* Filter:4, Coefficient: 86 */ + CONVERT_COEFF(1379966), /* Filter:4, Coefficient: 87 */ + CONVERT_COEFF(441511), /* Filter:4, Coefficient: 88 */ + CONVERT_COEFF(-5068027), /* Filter:3, Coefficient: 85 */ + CONVERT_COEFF(-5140982), /* Filter:3, Coefficient: 86 */ + CONVERT_COEFF(-1197542), /* Filter:3, Coefficient: 87 */ + CONVERT_COEFF(3116904), /* Filter:3, Coefficient: 88 */ + CONVERT_COEFF(7480579), /* Filter:2, Coefficient: 85 */ + CONVERT_COEFF(-2749314), /* Filter:2, Coefficient: 86 */ + CONVERT_COEFF(-9360248), /* Filter:2, Coefficient: 87 */ + CONVERT_COEFF(-7716970), /* Filter:2, Coefficient: 88 */ + CONVERT_COEFF(8772201), /* Filter:1, Coefficient: 85 */ + CONVERT_COEFF(11107791), /* Filter:1, Coefficient: 86 */ + CONVERT_COEFF(4436017), /* Filter:1, Coefficient: 87 */ + CONVERT_COEFF(-4741987), /* Filter:1, Coefficient: 88 */ + + /* Filter #23, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-708796), /* Filter:4, Coefficient: 89 */ + CONVERT_COEFF(-1141122), /* Filter:4, Coefficient: 90 */ + CONVERT_COEFF(-618337), /* Filter:4, Coefficient: 91 */ + CONVERT_COEFF(314070), /* Filter:4, Coefficient: 92 */ + CONVERT_COEFF(4381539), /* Filter:3, Coefficient: 89 */ + CONVERT_COEFF(2040448), /* Filter:3, Coefficient: 90 */ + CONVERT_COEFF(-1562338), /* Filter:3, Coefficient: 91 */ + CONVERT_COEFF(-3425561), /* Filter:3, Coefficient: 92 */ + CONVERT_COEFF(-281783), /* Filter:2, Coefficient: 89 */ + CONVERT_COEFF(6309527), /* Filter:2, Coefficient: 90 */ + CONVERT_COEFF(7023993), /* Filter:2, Coefficient: 91 */ + CONVERT_COEFF(2144389), /* Filter:2, Coefficient: 92 */ + CONVERT_COEFF(-8900882), /* Filter:1, Coefficient: 89 */ + CONVERT_COEFF(-5510132), /* Filter:1, Coefficient: 90 */ + CONVERT_COEFF(1698787), /* Filter:1, Coefficient: 91 */ + CONVERT_COEFF(6542354), /* Filter:1, Coefficient: 92 */ + + /* Filter #24, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(865964), /* Filter:4, Coefficient: 93 */ + CONVERT_COEFF(658712), /* Filter:4, Coefficient: 94 */ + CONVERT_COEFF(-34808), /* Filter:4, Coefficient: 95 */ + CONVERT_COEFF(-598408), /* Filter:4, Coefficient: 96 */ + CONVERT_COEFF(-2338169), /* Filter:3, Coefficient: 93 */ + CONVERT_COEFF(422162), /* Filter:3, Coefficient: 94 */ + CONVERT_COEFF(2447614), /* Filter:3, Coefficient: 95 */ + CONVERT_COEFF(2257011), /* Filter:3, Coefficient: 96 */ + CONVERT_COEFF(-3705979), /* Filter:2, Coefficient: 93 */ + CONVERT_COEFF(-5807407), /* Filter:2, Coefficient: 94 */ + CONVERT_COEFF(-3061584), /* Filter:2, Coefficient: 95 */ + CONVERT_COEFF(1669136), /* Filter:2, Coefficient: 96 */ + CONVERT_COEFF(5575464), /* Filter:1, Coefficient: 93 */ + CONVERT_COEFF(397296), /* Filter:1, Coefficient: 94 */ + CONVERT_COEFF(-4329403), /* Filter:1, Coefficient: 95 */ + CONVERT_COEFF(-4978370), /* Filter:1, Coefficient: 96 */ + + /* Filter #25, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-608313), /* Filter:4, Coefficient: 97 */ + CONVERT_COEFF(-139661), /* Filter:4, Coefficient: 98 */ + CONVERT_COEFF(366507), /* Filter:4, Coefficient: 99 */ + CONVERT_COEFF(506515), /* Filter:4, Coefficient: 100 */ + CONVERT_COEFF(327984), /* Filter:3, Coefficient: 97 */ + CONVERT_COEFF(-1565787), /* Filter:3, Coefficient: 98 */ + CONVERT_COEFF(-1944169), /* Filter:3, Coefficient: 99 */ + CONVERT_COEFF(-743409), /* Filter:3, Coefficient: 100 */ + CONVERT_COEFF(4387464), /* Filter:2, Coefficient: 97 */ + CONVERT_COEFF(3269084), /* Filter:2, Coefficient: 98 */ + CONVERT_COEFF(-227334), /* Filter:2, Coefficient: 99 */ + CONVERT_COEFF(-3001559), /* Filter:2, Coefficient: 100 */ + CONVERT_COEFF(-1650694), /* Filter:1, Coefficient: 97 */ + CONVERT_COEFF(2456535), /* Filter:1, Coefficient: 98 */ + CONVERT_COEFF(4020324), /* Filter:1, Coefficient: 99 */ + CONVERT_COEFF(2215413), /* Filter:1, Coefficient: 100 */ + + /* Filter #26, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(227496), /* Filter:4, Coefficient: 101 */ + CONVERT_COEFF(-184800), /* Filter:4, Coefficient: 102 */ + CONVERT_COEFF(-384947), /* Filter:4, Coefficient: 103 */ + CONVERT_COEFF(-250573), /* Filter:4, Coefficient: 104 */ + CONVERT_COEFF(848717), /* Filter:3, Coefficient: 101 */ + CONVERT_COEFF(1522401), /* Filter:3, Coefficient: 102 */ + CONVERT_COEFF(897837), /* Filter:3, Coefficient: 103 */ + CONVERT_COEFF(-323140), /* Filter:3, Coefficient: 104 */ + CONVERT_COEFF(-2999081), /* Filter:2, Coefficient: 101 */ + CONVERT_COEFF(-663371), /* Filter:2, Coefficient: 102 */ + CONVERT_COEFF(1805833), /* Filter:2, Coefficient: 103 */ + CONVERT_COEFF(2461354), /* Filter:2, Coefficient: 104 */ + CONVERT_COEFF(-1023079), /* Filter:1, Coefficient: 101 */ + CONVERT_COEFF(-2946059), /* Filter:1, Coefficient: 102 */ + CONVERT_COEFF(-2271916), /* Filter:1, Coefficient: 103 */ + CONVERT_COEFF(46810), /* Filter:1, Coefficient: 104 */ + + /* Filter #27, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(56883), /* Filter:4, Coefficient: 105 */ + CONVERT_COEFF(266613), /* Filter:4, Coefficient: 106 */ + CONVERT_COEFF(231070), /* Filter:4, Coefficient: 107 */ + CONVERT_COEFF(21669), /* Filter:4, Coefficient: 108 */ + CONVERT_COEFF(-1085470), /* Filter:3, Coefficient: 105 */ + CONVERT_COEFF(-870963), /* Filter:3, Coefficient: 106 */ + CONVERT_COEFF(-16819), /* Filter:3, Coefficient: 107 */ + CONVERT_COEFF(696469), /* Filter:3, Coefficient: 108 */ + CONVERT_COEFF(1096398), /* Filter:2, Coefficient: 105 */ + CONVERT_COEFF(-881544), /* Filter:2, Coefficient: 106 */ + CONVERT_COEFF(-1827647), /* Filter:2, Coefficient: 107 */ + CONVERT_COEFF(-1190629), /* Filter:2, Coefficient: 108 */ + CONVERT_COEFF(1934524), /* Filter:1, Coefficient: 105 */ + CONVERT_COEFF(2002411), /* Filter:1, Coefficient: 106 */ + CONVERT_COEFF(516537), /* Filter:1, Coefficient: 107 */ + CONVERT_COEFF(-1096900), /* Filter:1, Coefficient: 108 */ + + /* Filter #28, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-165914), /* Filter:4, Coefficient: 109 */ + CONVERT_COEFF(-188751), /* Filter:4, Coefficient: 110 */ + CONVERT_COEFF(-60237), /* Filter:4, Coefficient: 111 */ + CONVERT_COEFF(89578), /* Filter:4, Coefficient: 112 */ + CONVERT_COEFF(737670), /* Filter:3, Coefficient: 109 */ + CONVERT_COEFF(199113), /* Filter:3, Coefficient: 110 */ + CONVERT_COEFF(-389567), /* Filter:3, Coefficient: 111 */ + CONVERT_COEFF(-560182), /* Filter:3, Coefficient: 112 */ + CONVERT_COEFF(247255), /* Filter:2, Coefficient: 109 */ + CONVERT_COEFF(1222537), /* Filter:2, Coefficient: 110 */ + CONVERT_COEFF(1068384), /* Filter:2, Coefficient: 111 */ + CONVERT_COEFF(124598), /* Filter:2, Coefficient: 112 */ + CONVERT_COEFF(-1569451), /* Filter:1, Coefficient: 109 */ + CONVERT_COEFF(-750469), /* Filter:1, Coefficient: 110 */ + CONVERT_COEFF(482448), /* Filter:1, Coefficient: 111 */ + CONVERT_COEFF(1101069), /* Filter:1, Coefficient: 112 */ + + /* Filter #29, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(139197), /* Filter:4, Coefficient: 113 */ + CONVERT_COEFF(70304), /* Filter:4, Coefficient: 114 */ + CONVERT_COEFF(-38289), /* Filter:4, Coefficient: 115 */ + CONVERT_COEFF(-93047), /* Filter:4, Coefficient: 116 */ + CONVERT_COEFF(-263233), /* Filter:3, Coefficient: 113 */ + CONVERT_COEFF(174746), /* Filter:3, Coefficient: 114 */ + CONVERT_COEFF(383750), /* Filter:3, Coefficient: 115 */ + CONVERT_COEFF(250958), /* Filter:3, Coefficient: 116 */ + CONVERT_COEFF(-721785), /* Filter:2, Coefficient: 113 */ + CONVERT_COEFF(-838118), /* Filter:2, Coefficient: 114 */ + CONVERT_COEFF(-289378), /* Filter:2, Coefficient: 115 */ + CONVERT_COEFF(357413), /* Filter:2, Coefficient: 116 */ + CONVERT_COEFF(755091), /* Filter:1, Coefficient: 113 */ + CONVERT_COEFF(-90734), /* Filter:1, Coefficient: 114 */ + CONVERT_COEFF(-683828), /* Filter:1, Coefficient: 115 */ + CONVERT_COEFF(-627769), /* Filter:1, Coefficient: 116 */ + + /* Filter #30, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(-63107), /* Filter:4, Coefficient: 117 */ + CONVERT_COEFF(8665), /* Filter:4, Coefficient: 118 */ + CONVERT_COEFF(56144), /* Filter:4, Coefficient: 119 */ + CONVERT_COEFF(48031), /* Filter:4, Coefficient: 120 */ + CONVERT_COEFF(-44424), /* Filter:3, Coefficient: 117 */ + CONVERT_COEFF(-235818), /* Filter:3, Coefficient: 118 */ + CONVERT_COEFF(-199384), /* Filter:3, Coefficient: 119 */ + CONVERT_COEFF(-19310), /* Filter:3, Coefficient: 120 */ + CONVERT_COEFF(583440), /* Filter:2, Coefficient: 117 */ + CONVERT_COEFF(312988), /* Filter:2, Coefficient: 118 */ + CONVERT_COEFF(-127566), /* Filter:2, Coefficient: 119 */ + CONVERT_COEFF(-358789), /* Filter:2, Coefficient: 120 */ + CONVERT_COEFF(-112449), /* Filter:1, Coefficient: 117 */ + CONVERT_COEFF(363474), /* Filter:1, Coefficient: 118 */ + CONVERT_COEFF(449326), /* Filter:1, Coefficient: 119 */ + CONVERT_COEFF(178527), /* Filter:1, Coefficient: 120 */ + + /* Filter #31, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(4767), /* Filter:4, Coefficient: 121 */ + CONVERT_COEFF(-30353), /* Filter:4, Coefficient: 122 */ + CONVERT_COEFF(-31778), /* Filter:4, Coefficient: 123 */ + CONVERT_COEFF(-7893), /* Filter:4, Coefficient: 124 */ + CONVERT_COEFF(128040), /* Filter:3, Coefficient: 121 */ + CONVERT_COEFF(136746), /* Filter:3, Coefficient: 122 */ + CONVERT_COEFF(38083), /* Filter:3, Coefficient: 123 */ + CONVERT_COEFF(-60147), /* Filter:3, Coefficient: 124 */ + CONVERT_COEFF(-257969), /* Filter:2, Coefficient: 121 */ + CONVERT_COEFF(8641), /* Filter:2, Coefficient: 122 */ + CONVERT_COEFF(190921), /* Filter:2, Coefficient: 123 */ + CONVERT_COEFF(174318), /* Filter:2, Coefficient: 124 */ + CONVERT_COEFF(-151547), /* Filter:1, Coefficient: 121 */ + CONVERT_COEFF(-276720), /* Filter:1, Coefficient: 122 */ + CONVERT_COEFF(-161692), /* Filter:1, Coefficient: 123 */ + CONVERT_COEFF(35536), /* Filter:1, Coefficient: 124 */ + + /* Filter #32, conversion from 24000 Hz to 8000 Hz */ + + CONVERT_COEFF(14756), /* Filter:4, Coefficient: 125 */ + CONVERT_COEFF(18247), /* Filter:4, Coefficient: 126 */ + CONVERT_COEFF(5816), /* Filter:4, Coefficient: 127 */ + CONVERT_COEFF(-573080), /* Filter:4, Coefficient: 128 */ + CONVERT_COEFF(-80967), /* Filter:3, Coefficient: 125 */ + CONVERT_COEFF(-32124), /* Filter:3, Coefficient: 126 */ + CONVERT_COEFF(24552), /* Filter:3, Coefficient: 127 */ + CONVERT_COEFF(872700), /* Filter:3, Coefficient: 128 */ + CONVERT_COEFF(32782), /* Filter:2, Coefficient: 125 */ + CONVERT_COEFF(-84503), /* Filter:2, Coefficient: 126 */ + CONVERT_COEFF(-95337), /* Filter:2, Coefficient: 127 */ + CONVERT_COEFF(-244664), /* Filter:2, Coefficient: 128 */ + CONVERT_COEFF(141820), /* Filter:1, Coefficient: 125 */ + CONVERT_COEFF(108395), /* Filter:1, Coefficient: 126 */ + CONVERT_COEFF(10015), /* Filter:1, Coefficient: 127 */ + CONVERT_COEFF(-54956), /* Filter:1, Coefficient: 128 */ +}; diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_24000Hz_to_16000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_24000Hz_to_16000Hz.h new file mode 100644 index 000000000000..c6cb368ffef1 --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_24000Hz_to_16000Hz.h @@ -0,0 +1,550 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 24000 Hz to 16000 Hz */ +/* NUM_FILTERS=6, FILTER_LENGTH=80, alpha=6.800000, gamma=0.460000 */ + +__cold_rodata static const int32_t coeff24000to16000[] = { + + /* Filter #1, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(-26295), /* Filter:6, Coefficient: 1 */ + CONVERT_COEFF(-6174), /* Filter:6, Coefficient: 2 */ + CONVERT_COEFF(59137), /* Filter:6, Coefficient: 3 */ + CONVERT_COEFF(-55792), /* Filter:6, Coefficient: 4 */ + CONVERT_COEFF(95136), /* Filter:5, Coefficient: 1 */ + CONVERT_COEFF(-90674), /* Filter:5, Coefficient: 2 */ + CONVERT_COEFF(-78081), /* Filter:5, Coefficient: 3 */ + CONVERT_COEFF(262291), /* Filter:5, Coefficient: 4 */ + CONVERT_COEFF(20739), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(149775), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(-239278), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(-22446), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(-144563), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(217789), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(67657), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(-521235), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(-120977), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(-98594), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(393503), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(-206930), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(42248), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(-133707), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(38413), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(241342), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(-44498), /* Filter:6, Coefficient: 5 */ + CONVERT_COEFF(140021), /* Filter:6, Coefficient: 6 */ + CONVERT_COEFF(-65538), /* Filter:6, Coefficient: 7 */ + CONVERT_COEFF(-159309), /* Filter:6, Coefficient: 8 */ + CONVERT_COEFF(-143888), /* Filter:5, Coefficient: 5 */ + CONVERT_COEFF(-302689), /* Filter:5, Coefficient: 6 */ + CONVERT_COEFF(539007), /* Filter:5, Coefficient: 7 */ + CONVERT_COEFF(-33282), /* Filter:5, Coefficient: 8 */ + CONVERT_COEFF(472981), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(-445555), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(-364304), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(1077686), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(409104), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(529589), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(-1203596), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(246572), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(-546538), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(894742), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(104473), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(-1568720), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(-302760), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(-155593), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(660489), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(-329457), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(250380), /* Filter:6, Coefficient: 9 */ + CONVERT_COEFF(11147), /* Filter:6, Coefficient: 10 */ + CONVERT_COEFF(-380641), /* Filter:6, Coefficient: 11 */ + CONVERT_COEFF(321305), /* Filter:6, Coefficient: 12 */ + CONVERT_COEFF(-810002), /* Filter:5, Coefficient: 9 */ + CONVERT_COEFF(794826), /* Filter:5, Coefficient: 10 */ + CONVERT_COEFF(490903), /* Filter:5, Coefficient: 11 */ + CONVERT_COEFF(-1598783), /* Filter:5, Coefficient: 12 */ + CONVERT_COEFF(-425238), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(-1277747), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(1786094), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(314731), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(1691746), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(-1890565), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(-897425), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(3576853), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(1232437), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(1350041), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(-3034301), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(596978), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(-766480), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(1172797), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(160492), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(-1874803), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(263297), /* Filter:6, Coefficient: 13 */ + CONVERT_COEFF(-680359), /* Filter:6, Coefficient: 14 */ + CONVERT_COEFF(215469), /* Filter:6, Coefficient: 15 */ + CONVERT_COEFF(752593), /* Filter:6, Coefficient: 16 */ + CONVERT_COEFF(693774), /* Filter:5, Coefficient: 13 */ + CONVERT_COEFF(1664970), /* Filter:5, Coefficient: 14 */ + CONVERT_COEFF(-2393909), /* Filter:5, Coefficient: 15 */ + CONVERT_COEFF(-270022), /* Filter:5, Coefficient: 16 */ + CONVERT_COEFF(-2867333), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(2015640), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(2321674), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(-4757264), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(-1759642), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(-3621615), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(5521571), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(433087), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(3906959), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(-4133829), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(-2063561), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(7454382), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(1336229), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(1573222), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(-3181847), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(419381), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(-924495), /* Filter:6, Coefficient: 17 */ + CONVERT_COEFF(-243808), /* Filter:6, Coefficient: 18 */ + CONVERT_COEFF(1435511), /* Filter:6, Coefficient: 19 */ + CONVERT_COEFF(-854950), /* Filter:6, Coefficient: 20 */ + CONVERT_COEFF(3494050), /* Filter:5, Coefficient: 17 */ + CONVERT_COEFF(-2545027), /* Filter:5, Coefficient: 18 */ + CONVERT_COEFF(-2574960), /* Filter:5, Coefficient: 19 */ + CONVERT_COEFF(5494742), /* Filter:5, Coefficient: 20 */ + CONVERT_COEFF(788251), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(5808654), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(-5844798), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(-2965912), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(-7943091), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(5939150), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(5840605), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(-12672998), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(-3286678), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(-7450030), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(10475967), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(1477617), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(4031999), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(-3839814), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(-2330782), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(7001267), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(-1191753), /* Filter:6, Coefficient: 21 */ + CONVERT_COEFF(2084337), /* Filter:6, Coefficient: 22 */ + CONVERT_COEFF(-128069), /* Filter:6, Coefficient: 23 */ + CONVERT_COEFF(-2601191), /* Filter:6, Coefficient: 24 */ + CONVERT_COEFF(-1086047), /* Filter:5, Coefficient: 21 */ + CONVERT_COEFF(-6323279), /* Filter:5, Coefficient: 22 */ + CONVERT_COEFF(6516645), /* Filter:5, Coefficient: 23 */ + CONVERT_COEFF(2986602), /* Filter:5, Coefficient: 24 */ + CONVERT_COEFF(10152857), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(-4315876), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(-9807613), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(13486977), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(2509829), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(14660956), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(-15044393), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(-7085983), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(-15070746), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(10141650), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(11626122), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(-22492705), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(-2520134), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(-7205710), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(9041722), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(2204328), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(2240070), /* Filter:6, Coefficient: 25 */ + CONVERT_COEFF(1583859), /* Filter:6, Coefficient: 26 */ + CONVERT_COEFF(-4145189), /* Filter:6, Coefficient: 27 */ + CONVERT_COEFF(1204705), /* Filter:6, Coefficient: 28 */ + CONVERT_COEFF(-10826352), /* Filter:5, Coefficient: 25 */ + CONVERT_COEFF(4740217), /* Filter:5, Coefficient: 26 */ + CONVERT_COEFF(10247700), /* Filter:5, Coefficient: 27 */ + CONVERT_COEFF(-14202210), /* Filter:5, Coefficient: 28 */ + CONVERT_COEFF(1961386), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(-19034008), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(12554808), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(14736870), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(25196436), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(-10843609), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(-24055393), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(33134987), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(2787191), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(26962307), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(-25014527), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(-15146780), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(-13501440), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(7856982), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(11265305), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(-19146543), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(4445165), /* Filter:6, Coefficient: 29 */ + CONVERT_COEFF(-5022270), /* Filter:6, Coefficient: 30 */ + CONVERT_COEFF(-1998803), /* Filter:6, Coefficient: 31 */ + CONVERT_COEFF(8226514), /* Filter:6, Coefficient: 32 */ + CONVERT_COEFF(-2184106), /* Filter:5, Coefficient: 29 */ + CONVERT_COEFF(20242040), /* Filter:5, Coefficient: 30 */ + CONVERT_COEFF(-12782630), /* Filter:5, Coefficient: 31 */ + CONVERT_COEFF(-17153461), /* Filter:5, Coefficient: 32 */ + CONVERT_COEFF(-27924414), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(2706581), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(34610785), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(-30620463), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(5074883), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(-47384059), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(30833566), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(38864431), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(44598021), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(-15639102), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(-46416323), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(58085501), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(581006), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(24589586), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(-20506417), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(-16259182), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(-3439899), /* Filter:6, Coefficient: 33 */ + CONVERT_COEFF(-8925448), /* Filter:6, Coefficient: 34 */ + CONVERT_COEFF(11104297), /* Filter:6, Coefficient: 35 */ + CONVERT_COEFF(6265801), /* Filter:6, Coefficient: 36 */ + CONVERT_COEFF(30279913), /* Filter:5, Coefficient: 33 */ + CONVERT_COEFF(1264181), /* Filter:5, Coefficient: 34 */ + CONVERT_COEFF(-44000805), /* Filter:5, Coefficient: 35 */ + CONVERT_COEFF(27404677), /* Filter:5, Coefficient: 36 */ + CONVERT_COEFF(-22972428), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(60020710), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(-13003893), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(-79732586), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(-72814450), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(3812134), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(102230911), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(-87524750), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(16356030), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(-94361261), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(53986557), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(98938922), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(41141721), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(-11448663), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(-49636394), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(60678285), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(-19358245), /* Filter:6, Coefficient: 37 */ + CONVERT_COEFF(-1448253), /* Filter:6, Coefficient: 38 */ + CONVERT_COEFF(26658987), /* Filter:6, Coefficient: 39 */ + CONVERT_COEFF(1437558), /* Filter:6, Coefficient: 40 */ + CONVERT_COEFF(51523005), /* Filter:5, Coefficient: 37 */ + CONVERT_COEFF(-60986563), /* Filter:5, Coefficient: 38 */ + CONVERT_COEFF(-58253729), /* Filter:5, Coefficient: 39 */ + CONVERT_COEFF(69683724), /* Filter:5, Coefficient: 40 */ + CONVERT_COEFF(76987483), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(99162074), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(-138037476), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(-114554861), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(-100746036), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(243760389), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(161666543), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(-338656732), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(-174705650), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(-35750635), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(498608183), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(308015331), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(26029323), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(-140264601), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(104468300), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(595087393), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(-20425535), /* Filter:6, Coefficient: 41 */ + CONVERT_COEFF(6567320), /* Filter:6, Coefficient: 42 */ + CONVERT_COEFF(15743139), /* Filter:6, Coefficient: 43 */ + CONVERT_COEFF(-9427264), /* Filter:6, Coefficient: 44 */ + CONVERT_COEFF(36693971), /* Filter:5, Coefficient: 41 */ + CONVERT_COEFF(-76752453), /* Filter:5, Coefficient: 42 */ + CONVERT_COEFF(-18978257), /* Filter:5, Coefficient: 43 */ + CONVERT_COEFF(58790681), /* Filter:5, Coefficient: 44 */ + CONVERT_COEFF(160865448), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(112183817), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(-122474297), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(-52614939), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(-258230261), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(238070373), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(183898488), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(-140152136), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(-427437883), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(-416558699), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(122106215), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(125076115), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(520991913), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(12457163), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(-124027598), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(56265475), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(-7663681), /* Filter:6, Coefficient: 45 */ + CONVERT_COEFF(9874963), /* Filter:6, Coefficient: 46 */ + CONVERT_COEFF(564421), /* Filter:6, Coefficient: 47 */ + CONVERT_COEFF(-7491119), /* Filter:6, Coefficient: 48 */ + CONVERT_COEFF(-6293486), /* Filter:5, Coefficient: 45 */ + CONVERT_COEFF(-36428312), /* Filter:5, Coefficient: 46 */ + CONVERT_COEFF(22206365), /* Filter:5, Coefficient: 47 */ + CONVERT_COEFF(14384112), /* Filter:5, Coefficient: 48 */ + CONVERT_COEFF(87304224), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(-5399444), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(-55884369), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(33711827), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(-42369119), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(106491355), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(-28115935), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(-58576468), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(-125087622), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(-11228768), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(89164835), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(-43176336), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(37936440), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(-56171034), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(7138480), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(35072417), /* Filter:1, Coefficient: 48 */ + + /* Filter #13, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(3743976), /* Filter:6, Coefficient: 49 */ + CONVERT_COEFF(3498372), /* Filter:6, Coefficient: 50 */ + CONVERT_COEFF(-4901576), /* Filter:6, Coefficient: 51 */ + CONVERT_COEFF(234077), /* Filter:6, Coefficient: 52 */ + CONVERT_COEFF(-24281078), /* Filter:5, Coefficient: 49 */ + CONVERT_COEFF(3132387), /* Filter:5, Coefficient: 50 */ + CONVERT_COEFF(16560249), /* Filter:5, Coefficient: 51 */ + CONVERT_COEFF(-12239715), /* Filter:5, Coefficient: 52 */ + CONVERT_COEFF(21599169), /* Filter:4, Coefficient: 49 */ + CONVERT_COEFF(-37380560), /* Filter:4, Coefficient: 50 */ + CONVERT_COEFF(5717759), /* Filter:4, Coefficient: 51 */ + CONVERT_COEFF(25010112), /* Filter:4, Coefficient: 52 */ + CONVERT_COEFF(53813676), /* Filter:3, Coefficient: 49 */ + CONVERT_COEFF(11709605), /* Filter:3, Coefficient: 50 */ + CONVERT_COEFF(-47320948), /* Filter:3, Coefficient: 51 */ + CONVERT_COEFF(19538940), /* Filter:3, Coefficient: 52 */ + CONVERT_COEFF(-39017312), /* Filter:2, Coefficient: 49 */ + CONVERT_COEFF(55027501), /* Filter:2, Coefficient: 50 */ + CONVERT_COEFF(-3760701), /* Filter:2, Coefficient: 51 */ + CONVERT_COEFF(-39483388), /* Filter:2, Coefficient: 52 */ + CONVERT_COEFF(-26074542), /* Filter:1, Coefficient: 49 */ + CONVERT_COEFF(-10215709), /* Filter:1, Coefficient: 50 */ + CONVERT_COEFF(25770583), /* Filter:1, Coefficient: 51 */ + CONVERT_COEFF(-7934321), /* Filter:1, Coefficient: 52 */ + + /* Filter #14, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(3638857), /* Filter:6, Coefficient: 53 */ + CONVERT_COEFF(-2392834), /* Filter:6, Coefficient: 54 */ + CONVERT_COEFF(-1352878), /* Filter:6, Coefficient: 55 */ + CONVERT_COEFF(2683085), /* Filter:6, Coefficient: 56 */ + CONVERT_COEFF(-5372325), /* Filter:5, Coefficient: 53 */ + CONVERT_COEFF(12708978), /* Filter:5, Coefficient: 54 */ + CONVERT_COEFF(-3609816), /* Filter:5, Coefficient: 55 */ + CONVERT_COEFF(-7612571), /* Filter:5, Coefficient: 56 */ + CONVERT_COEFF(-19441937), /* Filter:4, Coefficient: 53 */ + CONVERT_COEFF(-7452690), /* Filter:4, Coefficient: 54 */ + CONVERT_COEFF(19552722), /* Filter:4, Coefficient: 55 */ + CONVERT_COEFF(-6222289), /* Filter:4, Coefficient: 56 */ + CONVERT_COEFF(24367027), /* Filter:3, Coefficient: 53 */ + CONVERT_COEFF(-29849864), /* Filter:3, Coefficient: 54 */ + CONVERT_COEFF(-549202), /* Filter:3, Coefficient: 55 */ + CONVERT_COEFF(23365978), /* Filter:3, Coefficient: 56 */ + CONVERT_COEFF(26883932), /* Filter:2, Coefficient: 53 */ + CONVERT_COEFF(13942943), /* Filter:2, Coefficient: 54 */ + CONVERT_COEFF(-29246879), /* Filter:2, Coefficient: 55 */ + CONVERT_COEFF(7153500), /* Filter:2, Coefficient: 56 */ + CONVERT_COEFF(-14873710), /* Filter:1, Coefficient: 53 */ + CONVERT_COEFF(15201245), /* Filter:1, Coefficient: 54 */ + CONVERT_COEFF(2157693), /* Filter:1, Coefficient: 55 */ + CONVERT_COEFF(-13047847), /* Filter:1, Coefficient: 56 */ + + /* Filter #15, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(-610388), /* Filter:6, Coefficient: 57 */ + CONVERT_COEFF(-1688412), /* Filter:6, Coefficient: 58 */ + CONVERT_COEFF(1513662), /* Filter:6, Coefficient: 59 */ + CONVERT_COEFF(349912), /* Filter:6, Coefficient: 60 */ + CONVERT_COEFF(7476439), /* Filter:5, Coefficient: 57 */ + CONVERT_COEFF(1248705), /* Filter:5, Coefficient: 58 */ + CONVERT_COEFF(-6509356), /* Filter:5, Coefficient: 59 */ + CONVERT_COEFF(3072466), /* Filter:5, Coefficient: 60 */ + CONVERT_COEFF(-11268706), /* Filter:4, Coefficient: 57 */ + CONVERT_COEFF(11724570), /* Filter:4, Coefficient: 58 */ + CONVERT_COEFF(1431814), /* Filter:4, Coefficient: 59 */ + CONVERT_COEFF(-9841071), /* Filter:4, Coefficient: 60 */ + CONVERT_COEFF(-13902547), /* Filter:3, Coefficient: 57 */ + CONVERT_COEFF(-9448707), /* Filter:3, Coefficient: 58 */ + CONVERT_COEFF(16453057), /* Filter:3, Coefficient: 59 */ + CONVERT_COEFF(-2865391), /* Filter:3, Coefficient: 60 */ + CONVERT_COEFF(18159363), /* Filter:2, Coefficient: 57 */ + CONVERT_COEFF(-16617074), /* Filter:2, Coefficient: 58 */ + CONVERT_COEFF(-3757540), /* Filter:2, Coefficient: 59 */ + CONVERT_COEFF(14970543), /* Filter:2, Coefficient: 60 */ + CONVERT_COEFF(6319609), /* Filter:1, Coefficient: 57 */ + CONVERT_COEFF(6173527), /* Filter:1, Coefficient: 58 */ + CONVERT_COEFF(-8607053), /* Filter:1, Coefficient: 59 */ + CONVERT_COEFF(524563), /* Filter:1, Coefficient: 60 */ + + /* Filter #16, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(-1364557), /* Filter:6, Coefficient: 61 */ + CONVERT_COEFF(582053), /* Filter:6, Coefficient: 62 */ + CONVERT_COEFF(658744), /* Filter:6, Coefficient: 63 */ + CONVERT_COEFF(-838099), /* Filter:6, Coefficient: 64 */ + CONVERT_COEFF(3042256), /* Filter:5, Coefficient: 61 */ + CONVERT_COEFF(-4197678), /* Filter:5, Coefficient: 62 */ + CONVERT_COEFF(315404), /* Filter:5, Coefficient: 63 */ + CONVERT_COEFF(2919373), /* Filter:5, Coefficient: 64 */ + CONVERT_COEFF(4965896), /* Filter:4, Coefficient: 61 */ + CONVERT_COEFF(4379351), /* Filter:4, Coefficient: 62 */ + CONVERT_COEFF(-6407530), /* Filter:4, Coefficient: 63 */ + CONVERT_COEFF(667422), /* Filter:4, Coefficient: 64 */ + CONVERT_COEFF(-10736941), /* Filter:3, Coefficient: 61 */ + CONVERT_COEFF(8712511), /* Filter:3, Coefficient: 62 */ + CONVERT_COEFF(2733105), /* Filter:3, Coefficient: 63 */ + CONVERT_COEFF(-8122284), /* Filter:3, Coefficient: 64 */ + CONVERT_COEFF(-6264447), /* Filter:2, Coefficient: 61 */ + CONVERT_COEFF(-7478462), /* Filter:2, Coefficient: 62 */ + CONVERT_COEFF(9209549), /* Filter:2, Coefficient: 63 */ + CONVERT_COEFF(-6635), /* Filter:2, Coefficient: 64 */ + CONVERT_COEFF(6210778), /* Filter:1, Coefficient: 61 */ + CONVERT_COEFF(-4146852), /* Filter:1, Coefficient: 62 */ + CONVERT_COEFF(-2148993), /* Filter:1, Coefficient: 63 */ + CONVERT_COEFF(4360107), /* Filter:1, Coefficient: 64 */ + + /* Filter #17, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(34742), /* Filter:6, Coefficient: 65 */ + CONVERT_COEFF(585847), /* Filter:6, Coefficient: 66 */ + CONVERT_COEFF(-385112), /* Filter:6, Coefficient: 67 */ + CONVERT_COEFF(-177297), /* Filter:6, Coefficient: 68 */ + CONVERT_COEFF(-2028360), /* Filter:5, Coefficient: 65 */ + CONVERT_COEFF(-875673), /* Filter:5, Coefficient: 66 */ + CONVERT_COEFF(1992549), /* Filter:5, Coefficient: 67 */ + CONVERT_COEFF(-596942), /* Filter:5, Coefficient: 68 */ + CONVERT_COEFF(4308258), /* Filter:4, Coefficient: 65 */ + CONVERT_COEFF(-3107701), /* Filter:4, Coefficient: 66 */ + CONVERT_COEFF(-1215261), /* Filter:4, Coefficient: 67 */ + CONVERT_COEFF(2940913), /* Filter:4, Coefficient: 68 */ + CONVERT_COEFF(2901374), /* Filter:3, Coefficient: 65 */ + CONVERT_COEFF(4157080), /* Filter:3, Coefficient: 66 */ + CONVERT_COEFF(-4574441), /* Filter:3, Coefficient: 67 */ + CONVERT_COEFF(-218386), /* Filter:3, Coefficient: 68 */ + CONVERT_COEFF(-6756530), /* Filter:2, Coefficient: 65 */ + CONVERT_COEFF(4038899), /* Filter:2, Coefficient: 66 */ + CONVERT_COEFF(2447917), /* Filter:2, Coefficient: 67 */ + CONVERT_COEFF(-4302235), /* Filter:2, Coefficient: 68 */ + CONVERT_COEFF(-1020076), /* Filter:1, Coefficient: 65 */ + CONVERT_COEFF(-2560492), /* Filter:1, Coefficient: 66 */ + CONVERT_COEFF(2237872), /* Filter:1, Coefficient: 67 */ + CONVERT_COEFF(503503), /* Filter:1, Coefficient: 68 */ + + /* Filter #18, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(376287), /* Filter:6, Coefficient: 69 */ + CONVERT_COEFF(-108531), /* Filter:6, Coefficient: 70 */ + CONVERT_COEFF(-186360), /* Filter:6, Coefficient: 71 */ + CONVERT_COEFF(184575), /* Filter:6, Coefficient: 72 */ + CONVERT_COEFF(-1027019), /* Filter:5, Coefficient: 69 */ + CONVERT_COEFF(1033388), /* Filter:5, Coefficient: 70 */ + CONVERT_COEFF(66645), /* Filter:5, Coefficient: 71 */ + CONVERT_COEFF(-722338), /* Filter:5, Coefficient: 72 */ + CONVERT_COEFF(-918864), /* Filter:4, Coefficient: 69 */ + CONVERT_COEFF(-1474180), /* Filter:4, Coefficient: 70 */ + CONVERT_COEFF(1499478), /* Filter:4, Coefficient: 71 */ + CONVERT_COEFF(87118), /* Filter:4, Coefficient: 72 */ + CONVERT_COEFF(3322300), /* Filter:3, Coefficient: 69 */ + CONVERT_COEFF(-1807064), /* Filter:3, Coefficient: 70 */ + CONVERT_COEFF(-1180769), /* Filter:3, Coefficient: 71 */ + CONVERT_COEFF(1876974), /* Filter:3, Coefficient: 72 */ + CONVERT_COEFF(815530), /* Filter:2, Coefficient: 69 */ + CONVERT_COEFF(2473272), /* Filter:2, Coefficient: 70 */ + CONVERT_COEFF(-1974352), /* Filter:2, Coefficient: 71 */ + CONVERT_COEFF(-499153), /* Filter:2, Coefficient: 72 */ + CONVERT_COEFF(-1850371), /* Filter:1, Coefficient: 69 */ + CONVERT_COEFF(717835), /* Filter:1, Coefficient: 70 */ + CONVERT_COEFF(834686), /* Filter:1, Coefficient: 71 */ + CONVERT_COEFF(-940634), /* Filter:1, Coefficient: 72 */ + + /* Filter #19, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(7527), /* Filter:6, Coefficient: 73 */ + CONVERT_COEFF(-119787), /* Filter:6, Coefficient: 74 */ + CONVERT_COEFF(68147), /* Filter:6, Coefficient: 75 */ + CONVERT_COEFF(28404), /* Filter:6, Coefficient: 76 */ + CONVERT_COEFF(391591), /* Filter:5, Coefficient: 73 */ + CONVERT_COEFF(218433), /* Filter:5, Coefficient: 74 */ + CONVERT_COEFF(-369238), /* Filter:5, Coefficient: 75 */ + CONVERT_COEFF(93076), /* Filter:5, Coefficient: 76 */ + CONVERT_COEFF(-1021014), /* Filter:4, Coefficient: 73 */ + CONVERT_COEFF(543575), /* Filter:4, Coefficient: 74 */ + CONVERT_COEFF(306112), /* Filter:4, Coefficient: 75 */ + CONVERT_COEFF(-496977), /* Filter:4, Coefficient: 76 */ + CONVERT_COEFF(-320463), /* Filter:3, Coefficient: 73 */ + CONVERT_COEFF(-991740), /* Filter:3, Coefficient: 74 */ + CONVERT_COEFF(753601), /* Filter:3, Coefficient: 75 */ + CONVERT_COEFF(156968), /* Filter:3, Coefficient: 76 */ + CONVERT_COEFF(1548719), /* Filter:2, Coefficient: 73 */ + CONVERT_COEFF(-552872), /* Filter:2, Coefficient: 74 */ + CONVERT_COEFF(-629254), /* Filter:2, Coefficient: 75 */ + CONVERT_COEFF(660050), /* Filter:2, Coefficient: 76 */ + CONVERT_COEFF(-13456), /* Filter:1, Coefficient: 73 */ + CONVERT_COEFF(592881), /* Filter:1, Coefficient: 74 */ + CONVERT_COEFF(-309498), /* Filter:1, Coefficient: 75 */ + CONVERT_COEFF(-180123), /* Filter:1, Coefficient: 76 */ + + /* Filter #20, conversion from 24000 Hz to 16000 Hz */ + + CONVERT_COEFF(-55547), /* Filter:6, Coefficient: 77 */ + CONVERT_COEFF(19487), /* Filter:6, Coefficient: 78 */ + CONVERT_COEFF(15420), /* Filter:6, Coefficient: 79 */ + CONVERT_COEFF(-8783213), /* Filter:6, Coefficient: 80 */ + CONVERT_COEFF(151753), /* Filter:5, Coefficient: 77 */ + CONVERT_COEFF(-141825), /* Filter:5, Coefficient: 78 */ + CONVERT_COEFF(11411), /* Filter:5, Coefficient: 79 */ + CONVERT_COEFF(21748306), /* Filter:5, Coefficient: 80 */ + CONVERT_COEFF(114656), /* Filter:4, Coefficient: 77 */ + CONVERT_COEFF(198467), /* Filter:4, Coefficient: 78 */ + CONVERT_COEFF(-171608), /* Filter:4, Coefficient: 79 */ + CONVERT_COEFF(-18242535), /* Filter:4, Coefficient: 80 */ + CONVERT_COEFF(-504421), /* Filter:3, Coefficient: 77 */ + CONVERT_COEFF(191996), /* Filter:3, Coefficient: 78 */ + CONVERT_COEFF(140005), /* Filter:3, Coefficient: 79 */ + CONVERT_COEFF(5774023), /* Filter:3, Coefficient: 80 */ + CONVERT_COEFF(-3503), /* Filter:2, Coefficient: 77 */ + CONVERT_COEFF(-338534), /* Filter:2, Coefficient: 78 */ + CONVERT_COEFF(171077), /* Filter:2, Coefficient: 79 */ + CONVERT_COEFF(-556806), /* Filter:2, Coefficient: 80 */ + CONVERT_COEFF(261387), /* Filter:1, Coefficient: 77 */ + CONVERT_COEFF(-35673), /* Filter:1, Coefficient: 78 */ + CONVERT_COEFF(-106078), /* Filter:1, Coefficient: 79 */ + CONVERT_COEFF(60225), /* Filter:1, Coefficient: 80 */ +}; diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_44100Hz_to_48000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_44100Hz_to_48000Hz.h new file mode 100644 index 000000000000..ba4434e92866 --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_44100Hz_to_48000Hz.h @@ -0,0 +1,506 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 44100 Hz to 48000 Hz */ +/* NUM_FILTERS=7, FILTER_LENGTH=64, alpha=7.800000, gamma=0.459000 */ + +__cold_rodata static const int32_t coeff44100to48000[] = { + + /* Filter #1, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(-36104), /* Filter:7, Coefficient: 1 */ + CONVERT_COEFF(50872), /* Filter:7, Coefficient: 2 */ + CONVERT_COEFF(-56564), /* Filter:7, Coefficient: 3 */ + CONVERT_COEFF(40229), /* Filter:7, Coefficient: 4 */ + CONVERT_COEFF(215090), /* Filter:6, Coefficient: 1 */ + CONVERT_COEFF(-343808), /* Filter:6, Coefficient: 2 */ + CONVERT_COEFF(497081), /* Filter:6, Coefficient: 3 */ + CONVERT_COEFF(-646143), /* Filter:6, Coefficient: 4 */ + CONVERT_COEFF(-224265), /* Filter:5, Coefficient: 1 */ + CONVERT_COEFF(396780), /* Filter:5, Coefficient: 2 */ + CONVERT_COEFF(-680396), /* Filter:5, Coefficient: 3 */ + CONVERT_COEFF(1099778), /* Filter:5, Coefficient: 4 */ + CONVERT_COEFF(-156406), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(276746), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(-402187), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(483398), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(48725), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(-150519), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(376286), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(-778623), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(140598), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(-270647), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(433819), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(-598685), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(12068), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(-294), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(-40869), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(127167), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(15714), /* Filter:7, Coefficient: 5 */ + CONVERT_COEFF(-132261), /* Filter:7, Coefficient: 6 */ + CONVERT_COEFF(331265), /* Filter:7, Coefficient: 7 */ + CONVERT_COEFF(-631432), /* Filter:7, Coefficient: 8 */ + CONVERT_COEFF(739353), /* Filter:6, Coefficient: 5 */ + CONVERT_COEFF(-699893), /* Filter:6, Coefficient: 6 */ + CONVERT_COEFF(427714), /* Filter:6, Coefficient: 7 */ + CONVERT_COEFF(192832), /* Filter:6, Coefficient: 8 */ + CONVERT_COEFF(-1660521), /* Filter:5, Coefficient: 5 */ + CONVERT_COEFF(2335311), /* Filter:5, Coefficient: 6 */ + CONVERT_COEFF(-3050136), /* Filter:5, Coefficient: 7 */ + CONVERT_COEFF(3673357), /* Filter:5, Coefficient: 8 */ + CONVERT_COEFF(-443096), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(177837), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(433397), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(-1512737), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(1399489), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(-2253057), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(3306250), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(-4459986), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(708253), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(-678784), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(404012), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(233922), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(-272876), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(486311), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(-764527), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(1087962), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(1043073), /* Filter:7, Coefficient: 9 */ + CONVERT_COEFF(-1562022), /* Filter:7, Coefficient: 10 */ + CONVERT_COEFF(2163475), /* Filter:7, Coefficient: 11 */ + CONVERT_COEFF(-2796684), /* Filter:7, Coefficient: 12 */ + CONVERT_COEFF(-1278823), /* Filter:6, Coefficient: 9 */ + CONVERT_COEFF(2928044), /* Filter:6, Coefficient: 10 */ + CONVERT_COEFF(-5192839), /* Filter:6, Coefficient: 11 */ + CONVERT_COEFF(8050849), /* Filter:6, Coefficient: 12 */ + CONVERT_COEFF(-4010927), /* Filter:5, Coefficient: 9 */ + CONVERT_COEFF(3811024), /* Filter:5, Coefficient: 10 */ + CONVERT_COEFF(-2780782), /* Filter:5, Coefficient: 11 */ + CONVERT_COEFF(616611), /* Filter:5, Coefficient: 12 */ + CONVERT_COEFF(3159157), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(-5417939), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(8246975), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(-11484454), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(5535069), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(-6267047), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(6314112), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(-5281074), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(-1346387), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(3013765), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(-5256640), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(8006079), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(-1416065), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(1685077), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(-1809078), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(1685203), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(3381591), /* Filter:7, Coefficient: 13 */ + CONVERT_COEFF(-3808499), /* Filter:7, Coefficient: 14 */ + CONVERT_COEFF(3941685), /* Filter:7, Coefficient: 15 */ + CONVERT_COEFF(-3627554), /* Filter:7, Coefficient: 16 */ + CONVERT_COEFF(-11376082), /* Filter:6, Coefficient: 13 */ + CONVERT_COEFF(14914588), /* Filter:6, Coefficient: 14 */ + CONVERT_COEFF(-18269373), /* Filter:6, Coefficient: 15 */ + CONVERT_COEFF(20898922), /* Filter:6, Coefficient: 16 */ + CONVERT_COEFF(2952090), /* Filter:5, Coefficient: 13 */ + CONVERT_COEFF(-8108091), /* Filter:5, Coefficient: 14 */ + CONVERT_COEFF(14884712), /* Filter:5, Coefficient: 15 */ + CONVERT_COEFF(-23103615), /* Filter:5, Coefficient: 16 */ + CONVERT_COEFF(14823547), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(-17800007), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(19798175), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(-20079410), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(2760719), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(1608543), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(-8072426), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(16684120), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(-11077473), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(14152940), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(-16777161), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(18370557), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(-1203455), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(260933), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(1220394), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(-3273956), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(2707504), /* Filter:7, Coefficient: 17 */ + CONVERT_COEFF(-1035138), /* Filter:7, Coefficient: 18 */ + CONVERT_COEFF(-1502971), /* Filter:7, Coefficient: 19 */ + CONVERT_COEFF(4964055), /* Filter:7, Coefficient: 20 */ + CONVERT_COEFF(-22132797), /* Filter:6, Coefficient: 17 */ + CONVERT_COEFF(21206202), /* Filter:6, Coefficient: 18 */ + CONVERT_COEFF(-17313533), /* Filter:6, Coefficient: 19 */ + CONVERT_COEFF(9678851), /* Filter:6, Coefficient: 20 */ + CONVERT_COEFF(32319346), /* Filter:5, Coefficient: 17 */ + CONVERT_COEFF(-41778175), /* Filter:5, Coefficient: 18 */ + CONVERT_COEFF(50397724), /* Filter:5, Coefficient: 19 */ + CONVERT_COEFF(-56771470), /* Filter:5, Coefficient: 20 */ + CONVERT_COEFF(17834747), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(-12260704), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(2654160), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(11480470), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(-27229456), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(39162945), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(-51563303), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(63114743), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(-18262033), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(15741168), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(-10127070), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(848490), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(5868998), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(-8893591), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(12142571), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(-15312249), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(-9324436), /* Filter:7, Coefficient: 21 */ + CONVERT_COEFF(14453459), /* Filter:7, Coefficient: 22 */ + CONVERT_COEFF(-20084074), /* Filter:7, Coefficient: 23 */ + CONVERT_COEFF(25773112), /* Filter:7, Coefficient: 24 */ + CONVERT_COEFF(2360201), /* Filter:6, Coefficient: 21 */ + CONVERT_COEFF(-19258639), /* Filter:6, Coefficient: 22 */ + CONVERT_COEFF(41160997), /* Filter:6, Coefficient: 23 */ + CONVERT_COEFF(-67779055), /* Filter:6, Coefficient: 24 */ + CONVERT_COEFF(59198429), /* Filter:5, Coefficient: 21 */ + CONVERT_COEFF(-55733258), /* Filter:5, Coefficient: 22 */ + CONVERT_COEFF(44245892), /* Filter:5, Coefficient: 23 */ + CONVERT_COEFF(-22473133), /* Filter:5, Coefficient: 24 */ + CONVERT_COEFF(-30320143), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(53616304), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(-80596906), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(109873203), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(-72116055), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(76512776), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(-73937881), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(61731000), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(12472346), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(-29940877), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(51324643), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(-76006737), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(18002687), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(-19726749), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(19922792), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(-17964334), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(-30833137), /* Filter:7, Coefficient: 25 */ + CONVERT_COEFF(34190653), /* Filter:7, Coefficient: 26 */ + CONVERT_COEFF(-34055766), /* Filter:7, Coefficient: 27 */ + CONVERT_COEFF(27111184), /* Filter:7, Coefficient: 28 */ + CONVERT_COEFF(98212836), /* Filter:6, Coefficient: 25 */ + CONVERT_COEFF(-130600585), /* Filter:6, Coefficient: 26 */ + CONVERT_COEFF(161254866), /* Filter:6, Coefficient: 27 */ + CONVERT_COEFF(-182201584), /* Filter:6, Coefficient: 28 */ + CONVERT_COEFF(-11960805), /* Filter:5, Coefficient: 25 */ + CONVERT_COEFF(61573102), /* Filter:5, Coefficient: 26 */ + CONVERT_COEFF(-129062026), /* Filter:5, Coefficient: 27 */ + CONVERT_COEFF(217007008), /* Filter:5, Coefficient: 28 */ + CONVERT_COEFF(-139327475), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(165912061), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(-185169687), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(189903320), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(-36878749), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(-4239017), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(66555533), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(-158147683), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(102957685), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(-130710897), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(157290278), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(-179922417), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(13153909), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(-4675683), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(-8550270), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(28262612), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(-6732875), /* Filter:7, Coefficient: 29 */ + CONVERT_COEFF(-33513548), /* Filter:7, Coefficient: 30 */ + CONVERT_COEFF(81968959), /* Filter:7, Coefficient: 31 */ + CONVERT_COEFF(-126044370), /* Filter:7, Coefficient: 32 */ + CONVERT_COEFF(173711794), /* Filter:6, Coefficient: 29 */ + CONVERT_COEFF(-91263367), /* Filter:6, Coefficient: 30 */ + CONVERT_COEFF(-97880606), /* Filter:6, Coefficient: 31 */ + CONVERT_COEFF(376032608), /* Filter:6, Coefficient: 32 */ + CONVERT_COEFF(-325394901), /* Filter:5, Coefficient: 29 */ + CONVERT_COEFF(443482836), /* Filter:5, Coefficient: 30 */ + CONVERT_COEFF(-458466415), /* Filter:5, Coefficient: 31 */ + CONVERT_COEFF(111467000), /* Filter:5, Coefficient: 32 */ + CONVERT_COEFF(-165805866), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(69571438), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(317915452), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(-847016031), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(295236856), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(-517257770), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(938951919), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(-618933202), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(193893264), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(-187311577), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(104180214), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(1104501607), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(-57986908), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(106920163), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(-209369472), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(677292439), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(86233108), /* Filter:7, Coefficient: 33 */ + CONVERT_COEFF(-35501375), /* Filter:7, Coefficient: 34 */ + CONVERT_COEFF(-5636059), /* Filter:7, Coefficient: 35 */ + CONVERT_COEFF(26510404), /* Filter:7, Coefficient: 36 */ + CONVERT_COEFF(-406938858), /* Filter:6, Coefficient: 33 */ + CONVERT_COEFF(298668575), /* Filter:6, Coefficient: 34 */ + CONVERT_COEFF(-136959173), /* Filter:6, Coefficient: 35 */ + CONVERT_COEFF(21661015), /* Filter:6, Coefficient: 36 */ + CONVERT_COEFF(296331993), /* Filter:5, Coefficient: 33 */ + CONVERT_COEFF(-523052704), /* Filter:5, Coefficient: 34 */ + CONVERT_COEFF(446708617), /* Filter:5, Coefficient: 35 */ + CONVERT_COEFF(-290145245), /* Filter:5, Coefficient: 36 */ + CONVERT_COEFF(848040024), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(-256558412), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(-137639539), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(223543416), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(-605929650), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(936110335), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(-517814517), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(297832194), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(-1104400882), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(-103375582), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(186432948), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(-193151946), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(677292439), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(-209369472), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(106920163), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(-57986908), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(-33774390), /* Filter:7, Coefficient: 37 */ + CONVERT_COEFF(34125210), /* Filter:7, Coefficient: 38 */ + CONVERT_COEFF(-30912242), /* Filter:7, Coefficient: 39 */ + CONVERT_COEFF(25943030), /* Filter:7, Coefficient: 40 */ + CONVERT_COEFF(41951855), /* Filter:6, Coefficient: 37 */ + CONVERT_COEFF(-74109079), /* Filter:6, Coefficient: 38 */ + CONVERT_COEFF(86833071), /* Filter:6, Coefficient: 39 */ + CONVERT_COEFF(-87225838), /* Filter:6, Coefficient: 40 */ + CONVERT_COEFF(168023601), /* Filter:5, Coefficient: 37 */ + CONVERT_COEFF(-79384353), /* Filter:5, Coefficient: 38 */ + CONVERT_COEFF(16820075), /* Filter:5, Coefficient: 39 */ + CONVERT_COEFF(25433754), /* Filter:5, Coefficient: 40 */ + CONVERT_COEFF(-231084433), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(210602792), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(-178568996), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(142372278), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(-161325042), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(69605744), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(-6892281), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(-34721861), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(179395431), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(-156965780), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(130550114), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(-102919808), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(28262612), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(-8550270), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(-4675683), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(13153909), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(-20303032), /* Filter:7, Coefficient: 41 */ + CONVERT_COEFF(14689217), /* Filter:7, Coefficient: 42 */ + CONVERT_COEFF(-9553062), /* Filter:7, Coefficient: 43 */ + CONVERT_COEFF(5169062), /* Filter:7, Coefficient: 44 */ + CONVERT_COEFF(79900129), /* Filter:6, Coefficient: 41 */ + CONVERT_COEFF(-68107389), /* Filter:6, Coefficient: 42 */ + CONVERT_COEFF(54242139), /* Filter:6, Coefficient: 43 */ + CONVERT_COEFF(-40072964), /* Filter:6, Coefficient: 44 */ + CONVERT_COEFF(-51687526), /* Filter:5, Coefficient: 41 */ + CONVERT_COEFF(65404355), /* Filter:5, Coefficient: 42 */ + CONVERT_COEFF(-69552118), /* Filter:5, Coefficient: 43 */ + CONVERT_COEFF(66752497), /* Filter:5, Coefficient: 44 */ + CONVERT_COEFF(-106166575), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(72576377), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(-43273377), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(19208349), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(60089315), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(-72784419), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(75792430), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(-71757314), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(76055038), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(-51427903), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(30073627), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(-12614739), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(-17964334), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(19922792), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(-19726749), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(18002687), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(-1674444), /* Filter:7, Coefficient: 45 */ + CONVERT_COEFF(-901531), /* Filter:7, Coefficient: 46 */ + CONVERT_COEFF(2611633), /* Filter:7, Coefficient: 47 */ + CONVERT_COEFF(-3566019), /* Filter:7, Coefficient: 48 */ + CONVERT_COEFF(26858516), /* Filter:6, Coefficient: 45 */ + CONVERT_COEFF(-15420460), /* Filter:6, Coefficient: 46 */ + CONVERT_COEFF(6205578), /* Filter:6, Coefficient: 47 */ + CONVERT_COEFF(650178), /* Filter:6, Coefficient: 48 */ + CONVERT_COEFF(-59316886), /* Filter:5, Coefficient: 45 */ + CONVERT_COEFF(49231067), /* Filter:5, Coefficient: 46 */ + CONVERT_COEFF(-38126705), /* Filter:5, Coefficient: 47 */ + CONVERT_COEFF(27261665), /* Filter:5, Coefficient: 48 */ + CONVERT_COEFF(-740031), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(-12258104), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(20288296), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(-24113150), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(63038805), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(-51691475), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(39422440), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(-27557546), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(-711004), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(10004241), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(-15638587), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(18181880), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(-15312249), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(12142571), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(-8893591), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(5868998), /* Filter:1, Coefficient: 48 */ + + /* Filter #13, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(3908988), /* Filter:7, Coefficient: 49 */ + CONVERT_COEFF(-3798121), /* Filter:7, Coefficient: 50 */ + CONVERT_COEFF(3386896), /* Filter:7, Coefficient: 51 */ + CONVERT_COEFF(-2811604), /* Filter:7, Coefficient: 52 */ + CONVERT_COEFF(-5252911), /* Filter:6, Coefficient: 49 */ + CONVERT_COEFF(7879560), /* Filter:6, Coefficient: 50 */ + CONVERT_COEFF(-8908772), /* Filter:6, Coefficient: 51 */ + CONVERT_COEFF(8758751), /* Filter:6, Coefficient: 52 */ + CONVERT_COEFF(-17520204), /* Filter:5, Coefficient: 49 */ + CONVERT_COEFF(9436366), /* Filter:5, Coefficient: 50 */ + CONVERT_COEFF(-3238487), /* Filter:5, Coefficient: 51 */ + CONVERT_COEFF(-1090753), /* Filter:5, Coefficient: 52 */ + CONVERT_COEFF(24640267), /* Filter:4, Coefficient: 49 */ + CONVERT_COEFF(-22815396), /* Filter:4, Coefficient: 50 */ + CONVERT_COEFF(19532216), /* Filter:4, Coefficient: 51 */ + CONVERT_COEFF(-15564685), /* Filter:4, Coefficient: 52 */ + CONVERT_COEFF(17030626), /* Filter:3, Coefficient: 49 */ + CONVERT_COEFF(-8400622), /* Filter:3, Coefficient: 50 */ + CONVERT_COEFF(1894708), /* Filter:3, Coefficient: 51 */ + CONVERT_COEFF(2528815), /* Filter:3, Coefficient: 52 */ + CONVERT_COEFF(-18312401), /* Filter:2, Coefficient: 49 */ + CONVERT_COEFF(16738756), /* Filter:2, Coefficient: 50 */ + CONVERT_COEFF(-14130963), /* Filter:2, Coefficient: 51 */ + CONVERT_COEFF(11068153), /* Filter:2, Coefficient: 52 */ + CONVERT_COEFF(-3273956), /* Filter:1, Coefficient: 49 */ + CONVERT_COEFF(1220394), /* Filter:1, Coefficient: 50 */ + CONVERT_COEFF(260933), /* Filter:1, Coefficient: 51 */ + CONVERT_COEFF(-1203455), /* Filter:1, Coefficient: 52 */ + + /* Filter #14, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(2182958), /* Filter:7, Coefficient: 53 */ + CONVERT_COEFF(-1582255), /* Filter:7, Coefficient: 54 */ + CONVERT_COEFF(1061509), /* Filter:7, Coefficient: 55 */ + CONVERT_COEFF(-646664), /* Filter:7, Coefficient: 56 */ + CONVERT_COEFF(-7836150), /* Filter:6, Coefficient: 53 */ + CONVERT_COEFF(6498637), /* Filter:6, Coefficient: 54 */ + CONVERT_COEFF(-5031961), /* Filter:6, Coefficient: 55 */ + CONVERT_COEFF(3640700), /* Filter:6, Coefficient: 56 */ + CONVERT_COEFF(3746098), /* Filter:5, Coefficient: 53 */ + CONVERT_COEFF(-5030962), /* Filter:5, Coefficient: 54 */ + CONVERT_COEFF(5294951), /* Filter:5, Coefficient: 55 */ + CONVERT_COEFF(-4882739), /* Filter:5, Coefficient: 56 */ + CONVERT_COEFF(11524851), /* Filter:4, Coefficient: 53 */ + CONVERT_COEFF(-7845878), /* Filter:4, Coefficient: 54 */ + CONVERT_COEFF(4787215), /* Filter:4, Coefficient: 55 */ + CONVERT_COEFF(-2456850), /* Filter:4, Coefficient: 56 */ + CONVERT_COEFF(-5106362), /* Filter:3, Coefficient: 53 */ + CONVERT_COEFF(6192755), /* Filter:3, Coefficient: 54 */ + CONVERT_COEFF(-6190960), /* Filter:3, Coefficient: 55 */ + CONVERT_COEFF(5494166), /* Filter:3, Coefficient: 56 */ + CONVERT_COEFF(-8005697), /* Filter:2, Coefficient: 53 */ + CONVERT_COEFF(5261877), /* Filter:2, Coefficient: 54 */ + CONVERT_COEFF(-3021912), /* Filter:2, Coefficient: 55 */ + CONVERT_COEFF(1355425), /* Filter:2, Coefficient: 56 */ + CONVERT_COEFF(1685203), /* Filter:1, Coefficient: 53 */ + CONVERT_COEFF(-1809078), /* Filter:1, Coefficient: 54 */ + CONVERT_COEFF(1685077), /* Filter:1, Coefficient: 55 */ + CONVERT_COEFF(-1416065), /* Filter:1, Coefficient: 56 */ + + /* Filter #15, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(342806), /* Filter:7, Coefficient: 57 */ + CONVERT_COEFF(-140284), /* Filter:7, Coefficient: 58 */ + CONVERT_COEFF(20786), /* Filter:7, Coefficient: 59 */ + CONVERT_COEFF(37371), /* Filter:7, Coefficient: 60 */ + CONVERT_COEFF(-2450499), /* Filter:6, Coefficient: 57 */ + CONVERT_COEFF(1518734), /* Filter:6, Coefficient: 58 */ + CONVERT_COEFF(-850198), /* Filter:6, Coefficient: 59 */ + CONVERT_COEFF(414533), /* Filter:6, Coefficient: 60 */ + CONVERT_COEFF(4097237), /* Filter:5, Coefficient: 57 */ + CONVERT_COEFF(-3177789), /* Filter:5, Coefficient: 58 */ + CONVERT_COEFF(2292208), /* Filter:5, Coefficient: 59 */ + CONVERT_COEFF(-1540003), /* Filter:5, Coefficient: 60 */ + CONVERT_COEFF(844451), /* Filter:4, Coefficient: 57 */ + CONVERT_COEFF(140882), /* Filter:4, Coefficient: 58 */ + CONVERT_COEFF(-633875), /* Filter:4, Coefficient: 59 */ + CONVERT_COEFF(781606), /* Filter:4, Coefficient: 60 */ + CONVERT_COEFF(-4443987), /* Filter:3, Coefficient: 57 */ + CONVERT_COEFF(3305948), /* Filter:3, Coefficient: 58 */ + CONVERT_COEFF(-2261053), /* Filter:3, Coefficient: 59 */ + CONVERT_COEFF(1410461), /* Filter:3, Coefficient: 60 */ + CONVERT_COEFF(-242505), /* Filter:2, Coefficient: 57 */ + CONVERT_COEFF(-396647), /* Filter:2, Coefficient: 58 */ + CONVERT_COEFF(672943), /* Filter:2, Coefficient: 59 */ + CONVERT_COEFF(-703923), /* Filter:2, Coefficient: 60 */ + CONVERT_COEFF(1087962), /* Filter:1, Coefficient: 57 */ + CONVERT_COEFF(-764527), /* Filter:1, Coefficient: 58 */ + CONVERT_COEFF(486311), /* Filter:1, Coefficient: 59 */ + CONVERT_COEFF(-272876), /* Filter:1, Coefficient: 60 */ + + /* Filter #16, conversion from 44100 Hz to 48000 Hz */ + + CONVERT_COEFF(-55188), /* Filter:7, Coefficient: 61 */ + CONVERT_COEFF(50357), /* Filter:7, Coefficient: 62 */ + CONVERT_COEFF(-35994), /* Filter:7, Coefficient: 63 */ + CONVERT_COEFF(18259534), /* Filter:7, Coefficient: 64 */ + CONVERT_COEFF(-162721), /* Filter:6, Coefficient: 61 */ + CONVERT_COEFF(40706), /* Filter:6, Coefficient: 62 */ + CONVERT_COEFF(881), /* Filter:6, Coefficient: 63 */ + CONVERT_COEFF(-52642287), /* Filter:6, Coefficient: 64 */ + CONVERT_COEFF(963380), /* Filter:5, Coefficient: 61 */ + CONVERT_COEFF(-562368), /* Filter:5, Coefficient: 62 */ + CONVERT_COEFF(310806), /* Filter:5, Coefficient: 63 */ + CONVERT_COEFF(55998086), /* Filter:5, Coefficient: 64 */ + CONVERT_COEFF(-719947), /* Filter:4, Coefficient: 61 */ + CONVERT_COEFF(558884), /* Filter:4, Coefficient: 62 */ + CONVERT_COEFF(-376234), /* Filter:4, Coefficient: 63 */ + CONVERT_COEFF(-26993761), /* Filter:4, Coefficient: 64 */ + CONVERT_COEFF(-789225), /* Filter:3, Coefficient: 61 */ + CONVERT_COEFF(384817), /* Filter:3, Coefficient: 62 */ + CONVERT_COEFF(-156478), /* Filter:3, Coefficient: 63 */ + CONVERT_COEFF(5955995), /* Filter:3, Coefficient: 64 */ + CONVERT_COEFF(595664), /* Filter:2, Coefficient: 61 */ + CONVERT_COEFF(-431821), /* Filter:2, Coefficient: 62 */ + CONVERT_COEFF(269381), /* Filter:2, Coefficient: 63 */ + CONVERT_COEFF(-589635), /* Filter:2, Coefficient: 64 */ + CONVERT_COEFF(127167), /* Filter:1, Coefficient: 61 */ + CONVERT_COEFF(-40869), /* Filter:1, Coefficient: 62 */ + CONVERT_COEFF(-294), /* Filter:1, Coefficient: 63 */ + CONVERT_COEFF(12068), /* Filter:1, Coefficient: 64 */ +}; diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_08000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_08000Hz.h new file mode 100644 index 000000000000..bb0cdb8cd0d9 --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_08000Hz.h @@ -0,0 +1,618 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 48000 Hz to 8000 Hz */ +/* NUM_FILTERS=4, FILTER_LENGTH=128, alpha=5.600000, gamma=0.415500 */ + +__cold_rodata static const int32_t coeff48000to08000[] = { + + /* Filter #1, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-3301), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(-3924), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(-3547), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(-2001), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(3989), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(-5958), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(-17787), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(-28475), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(65517), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(63506), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(39846), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(-6206), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(88725), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(154917), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(208524), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(227017), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(592), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(3785), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(6857), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(8947), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(-34495), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(-32695), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(-21285), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(-655), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(-68868), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(-135707), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(-189365), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(-211084), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(190319), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(87541), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(-77070), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(-280839), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(9255), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(7264), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(2938), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(-3172), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(26209), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(53920), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(75559), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(84121), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(-185467), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(-105464), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(23711), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(182957), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(-483590), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(-633541), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(-677765), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(-575509), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-9948), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(-15871), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(-19318), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(-18942), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(74293), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(44149), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(-3655), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(-61592), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(340885), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(458887), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(499081), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(433742), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(-311577), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(93646), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(580763), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(1056783), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-14049), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(-4887), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(7242), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(20103), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(-118123), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(-159680), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(-173513), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(-150856), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(254175), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(-23258), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(-355924), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(-679709), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(1409874), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(1531750), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(1343813), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(821550), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(30884), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(36752), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(35500), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(26152), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(-89716), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(3439), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(113663), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(219469), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(-919754), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(-1005668), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(-888441), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(-555451), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(11087), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(-967418), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(-1932735), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(-2671792), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(9393), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(-12331), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(-35074), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(-54036), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(296574), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(322901), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(283864), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(176829), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(-39793), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(579126), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(1185270), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(1645395), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(-2981375), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(-2714977), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(-1825131), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(-391039), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-64488), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(-62823), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(-47496), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(-19664), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(13593), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(-179927), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(-367152), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(-507125), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(1835407), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(1668894), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(1121896), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(247943), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(1377035), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(3161285), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(4587051), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(5293861), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(16678), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(55149), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(87997), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(107539), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(-562646), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(-508764), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(-339863), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(-73626), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(-821316), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(-1892108), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(-2740106), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(-3153045), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(5014601), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(3647017), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(1301187), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(-1690645), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(107770), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(85829), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(42999), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(-15023), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(249339), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(570716), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(824034), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(947166), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(-2976939), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(-2156713), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(-762064), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(1008723), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(-4809380), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(-7428596), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(-8928025), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(-8822328), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-78706), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(-136113), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(-174958), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(-184971), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(895533), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(653455), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(241140), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(-284575), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(2850676), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(4398591), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(5291841), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(5246926), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(-6880893), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(-3213125), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(1702668), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(7060108), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-160114), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(-100215), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(-11645), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(93176), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(-836548), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(-1310257), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(-1601506), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(-1625994), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(4124428), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(1976711), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(-935042), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(-4161104), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(11836509), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(14963038), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(15527995), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(12978729), /* Filter:1, Coefficient: 48 */ + + /* Filter #13, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(197453), /* Filter:4, Coefficient: 49 */ + CONVERT_COEFF(282648), /* Filter:4, Coefficient: 50 */ + CONVERT_COEFF(331646), /* Filter:4, Coefficient: 51 */ + CONVERT_COEFF(331926), /* Filter:4, Coefficient: 52 */ + CONVERT_COEFF(-1337215), /* Filter:3, Coefficient: 49 */ + CONVERT_COEFF(-739195), /* Filter:3, Coefficient: 50 */ + CONVERT_COEFF(108785), /* Filter:3, Coefficient: 51 */ + CONVERT_COEFF(1096994), /* Filter:3, Coefficient: 52 */ + CONVERT_COEFF(-7120987), /* Filter:2, Coefficient: 49 */ + CONVERT_COEFF(-9191912), /* Filter:2, Coefficient: 50 */ + CONVERT_COEFF(-9814753), /* Filter:2, Coefficient: 51 */ + CONVERT_COEFF(-8599910), /* Filter:2, Coefficient: 52 */ + CONVERT_COEFF(7284205), /* Filter:1, Coefficient: 49 */ + CONVERT_COEFF(-976463), /* Filter:1, Coefficient: 50 */ + CONVERT_COEFF(-10624045), /* Filter:1, Coefficient: 51 */ + CONVERT_COEFF(-19996714), /* Filter:1, Coefficient: 52 */ + + /* Filter #14, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(278128), /* Filter:4, Coefficient: 53 */ + CONVERT_COEFF(173526), /* Filter:4, Coefficient: 54 */ + CONVERT_COEFF(30081), /* Filter:4, Coefficient: 55 */ + CONVERT_COEFF(-133038), /* Filter:4, Coefficient: 56 */ + CONVERT_COEFF(2079471), /* Filter:3, Coefficient: 53 */ + CONVERT_COEFF(2895796), /* Filter:3, Coefficient: 54 */ + CONVERT_COEFF(3397039), /* Filter:3, Coefficient: 55 */ + CONVERT_COEFF(3471563), /* Filter:3, Coefficient: 56 */ + CONVERT_COEFF(-5414116), /* Filter:2, Coefficient: 53 */ + CONVERT_COEFF(-431194), /* Filter:2, Coefficient: 54 */ + CONVERT_COEFF(5865019), /* Filter:2, Coefficient: 55 */ + CONVERT_COEFF(12729600), /* Filter:2, Coefficient: 56 */ + CONVERT_COEFF(-27165458), /* Filter:1, Coefficient: 53 */ + CONVERT_COEFF(-30219478), /* Filter:1, Coefficient: 54 */ + CONVERT_COEFF(-27579070), /* Filter:1, Coefficient: 55 */ + CONVERT_COEFF(-18285419), /* Filter:1, Coefficient: 56 */ + + /* Filter #15, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-292255), /* Filter:4, Coefficient: 57 */ + CONVERT_COEFF(-423276), /* Filter:4, Coefficient: 58 */ + CONVERT_COEFF(-505071), /* Filter:4, Coefficient: 59 */ + CONVERT_COEFF(-523436), /* Filter:4, Coefficient: 60 */ + CONVERT_COEFF(3066123), /* Filter:3, Coefficient: 57 */ + CONVERT_COEFF(2198356), /* Filter:3, Coefficient: 58 */ + CONVERT_COEFF(958050), /* Filter:3, Coefficient: 59 */ + CONVERT_COEFF(-503489), /* Filter:3, Coefficient: 60 */ + CONVERT_COEFF(19252509), /* Filter:2, Coefficient: 57 */ + CONVERT_COEFF(24488239), /* Filter:2, Coefficient: 58 */ + CONVERT_COEFF(27599287), /* Filter:2, Coefficient: 59 */ + CONVERT_COEFF(27990266), /* Filter:2, Coefficient: 60 */ + CONVERT_COEFF(-2217112), /* Filter:1, Coefficient: 57 */ + CONVERT_COEFF(19807628), /* Filter:1, Coefficient: 58 */ + CONVERT_COEFF(46067140), /* Filter:1, Coefficient: 59 */ + CONVERT_COEFF(74113281), /* Filter:1, Coefficient: 60 */ + + /* Filter #16, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-473520), /* Filter:4, Coefficient: 61 */ + CONVERT_COEFF(-360852), /* Filter:4, Coefficient: 62 */ + CONVERT_COEFF(-200645), /* Filter:4, Coefficient: 63 */ + CONVERT_COEFF(-15496), /* Filter:4, Coefficient: 64 */ + CONVERT_COEFF(-1994632), /* Filter:3, Coefficient: 61 */ + CONVERT_COEFF(-3311919), /* Filter:3, Coefficient: 62 */ + CONVERT_COEFF(-4271266), /* Filter:3, Coefficient: 63 */ + CONVERT_COEFF(-4736706), /* Filter:3, Coefficient: 64 */ + CONVERT_COEFF(25410130), /* Filter:2, Coefficient: 61 */ + CONVERT_COEFF(20004573), /* Filter:2, Coefficient: 62 */ + CONVERT_COEFF(12308550), /* Filter:2, Coefficient: 63 */ + CONVERT_COEFF(3178633), /* Filter:2, Coefficient: 64 */ + CONVERT_COEFF(101068271), /* Filter:1, Coefficient: 61 */ + CONVERT_COEFF(124000002), /* Filter:1, Coefficient: 62 */ + CONVERT_COEFF(140320208), /* Filter:1, Coefficient: 63 */ + CONVERT_COEFF(148144605), /* Filter:1, Coefficient: 64 */ + + /* Filter #17, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(168169), /* Filter:4, Coefficient: 65 */ + CONVERT_COEFF(324285), /* Filter:4, Coefficient: 66 */ + CONVERT_COEFF(431264), /* Filter:4, Coefficient: 67 */ + CONVERT_COEFF(475348), /* Filter:4, Coefficient: 68 */ + CONVERT_COEFF(-4641842), /* Filter:3, Coefficient: 65 */ + CONVERT_COEFF(-4000373), /* Filter:3, Coefficient: 66 */ + CONVERT_COEFF(-2903906), /* Filter:3, Coefficient: 67 */ + CONVERT_COEFF(-1507432), /* Filter:3, Coefficient: 68 */ + CONVERT_COEFF(-6325048), /* Filter:2, Coefficient: 65 */ + CONVERT_COEFF(-15089017), /* Filter:2, Coefficient: 66 */ + CONVERT_COEFF(-22105139), /* Filter:2, Coefficient: 67 */ + CONVERT_COEFF(-26612611), /* Filter:2, Coefficient: 68 */ + CONVERT_COEFF(146558923), /* Filter:1, Coefficient: 65 */ + CONVERT_COEFF(135748984), /* Filter:1, Coefficient: 66 */ + CONVERT_COEFF(116974214), /* Filter:1, Coefficient: 67 */ + CONVERT_COEFF(92388797), /* Filter:1, Coefficient: 68 */ + + /* Filter #18, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(452628), /* Filter:4, Coefficient: 69 */ + CONVERT_COEFF(369409), /* Filter:4, Coefficient: 70 */ + CONVERT_COEFF(240897), /* Filter:4, Coefficient: 71 */ + CONVERT_COEFF(88460), /* Filter:4, Coefficient: 72 */ + CONVERT_COEFF(-4920), /* Filter:3, Coefficient: 69 */ + CONVERT_COEFF(1400822), /* Filter:3, Coefficient: 70 */ + CONVERT_COEFF(2528987), /* Filter:3, Coefficient: 71 */ + CONVERT_COEFF(3247243), /* Filter:3, Coefficient: 72 */ + CONVERT_COEFF(-28200972), /* Filter:2, Coefficient: 69 */ + CONVERT_COEFF(-26858406), /* Filter:2, Coefficient: 70 */ + CONVERT_COEFF(-22958846), /* Filter:2, Coefficient: 71 */ + CONVERT_COEFF(-17191493), /* Filter:2, Coefficient: 72 */ + CONVERT_COEFF(64738752), /* Filter:1, Coefficient: 69 */ + CONVERT_COEFF(36982432), /* Filter:1, Coefficient: 70 */ + CONVERT_COEFF(11893275), /* Filter:1, Coefficient: 71 */ + CONVERT_COEFF(-8295001), /* Filter:1, Coefficient: 72 */ + + /* Filter #19, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-64023), /* Filter:4, Coefficient: 73 */ + CONVERT_COEFF(-194079), /* Filter:4, Coefficient: 74 */ + CONVERT_COEFF(-284155), /* Filter:4, Coefficient: 75 */ + CONVERT_COEFF(-324136), /* Filter:4, Coefficient: 76 */ + CONVERT_COEFF(3489610), /* Filter:3, Coefficient: 73 */ + CONVERT_COEFF(3263104), /* Filter:3, Coefficient: 74 */ + CONVERT_COEFF(2642488), /* Filter:3, Coefficient: 75 */ + CONVERT_COEFF(1754510), /* Filter:3, Coefficient: 76 */ + CONVERT_COEFF(-10445713), /* Filter:2, Coefficient: 73 */ + CONVERT_COEFF(-3671194), /* Filter:2, Coefficient: 74 */ + CONVERT_COEFF(2263465), /* Filter:2, Coefficient: 75 */ + CONVERT_COEFF(6691197), /* Filter:2, Coefficient: 76 */ + CONVERT_COEFF(-22148960), /* Filter:1, Coefficient: 73 */ + CONVERT_COEFF(-29166675), /* Filter:1, Coefficient: 74 */ + CONVERT_COEFF(-29766384), /* Filter:1, Coefficient: 75 */ + CONVERT_COEFF(-25142508), /* Filter:1, Coefficient: 76 */ + + /* Filter #20, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-312505), /* Filter:4, Coefficient: 77 */ + CONVERT_COEFF(-255992), /* Filter:4, Coefficient: 78 */ + CONVERT_COEFF(-167880), /* Filter:4, Coefficient: 79 */ + CONVERT_COEFF(-65312), /* Filter:4, Coefficient: 80 */ + CONVERT_COEFF(754742), /* Filter:3, Coefficient: 77 */ + CONVERT_COEFF(-198757), /* Filter:3, Coefficient: 78 */ + CONVERT_COEFF(-970391), /* Filter:3, Coefficient: 79 */ + CONVERT_COEFF(-1466526), /* Filter:3, Coefficient: 80 */ + CONVERT_COEFF(9227960), /* Filter:2, Coefficient: 77 */ + CONVERT_COEFF(9804583), /* Filter:2, Coefficient: 78 */ + CONVERT_COEFF(8647121), /* Filter:2, Coefficient: 79 */ + CONVERT_COEFF(6212516), /* Filter:2, Coefficient: 80 */ + CONVERT_COEFF(-17019531), /* Filter:1, Coefficient: 77 */ + CONVERT_COEFF(-7348727), /* Filter:1, Coefficient: 78 */ + CONVERT_COEFF(2000942), /* Filter:1, Coefficient: 79 */ + CONVERT_COEFF(9509007), /* Filter:1, Coefficient: 80 */ + + /* Filter #21, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(33847), /* Filter:4, Coefficient: 81 */ + CONVERT_COEFF(114046), /* Filter:4, Coefficient: 82 */ + CONVERT_COEFF(164441), /* Filter:4, Coefficient: 83 */ + CONVERT_COEFF(180290), /* Filter:4, Coefficient: 84 */ + CONVERT_COEFF(-1646620), /* Filter:3, Coefficient: 81 */ + CONVERT_COEFF(-1524717), /* Filter:3, Coefficient: 82 */ + CONVERT_COEFF(-1161761), /* Filter:3, Coefficient: 83 */ + CONVERT_COEFF(-650773), /* Filter:3, Coefficient: 84 */ + CONVERT_COEFF(3093389), /* Filter:2, Coefficient: 81 */ + CONVERT_COEFF(-89994), /* Filter:2, Coefficient: 82 */ + CONVERT_COEFF(-2791699), /* Filter:2, Coefficient: 83 */ + CONVERT_COEFF(-4619639), /* Filter:2, Coefficient: 84 */ + CONVERT_COEFF(14188512), /* Filter:1, Coefficient: 81 */ + CONVERT_COEFF(15667833), /* Filter:1, Coefficient: 82 */ + CONVERT_COEFF(14165998), /* Filter:1, Coefficient: 83 */ + CONVERT_COEFF(10376123), /* Filter:1, Coefficient: 84 */ + + /* Filter #22, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(163170), /* Filter:4, Coefficient: 85 */ + CONVERT_COEFF(120081), /* Filter:4, Coefficient: 86 */ + CONVERT_COEFF(61686), /* Filter:4, Coefficient: 87 */ + CONVERT_COEFF(66), /* Filter:4, Coefficient: 88 */ + CONVERT_COEFF(-98000), /* Filter:3, Coefficient: 85 */ + CONVERT_COEFF(396363), /* Filter:3, Coefficient: 86 */ + CONVERT_COEFF(754499), /* Filter:3, Coefficient: 87 */ + CONVERT_COEFF(931769), /* Filter:3, Coefficient: 88 */ + CONVERT_COEFF(-5381371), /* Filter:2, Coefficient: 85 */ + CONVERT_COEFF(-5091650), /* Filter:2, Coefficient: 86 */ + CONVERT_COEFF(-3944213), /* Filter:2, Coefficient: 87 */ + CONVERT_COEFF(-2256257), /* Filter:2, Coefficient: 88 */ + CONVERT_COEFF(5285564), /* Filter:1, Coefficient: 85 */ + CONVERT_COEFF(-30634), /* Filter:1, Coefficient: 86 */ + CONVERT_COEFF(-4605459), /* Filter:1, Coefficient: 87 */ + CONVERT_COEFF(-7732849), /* Filter:1, Coefficient: 88 */ + + /* Filter #23, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-53544), /* Filter:4, Coefficient: 89 */ + CONVERT_COEFF(-90654), /* Filter:4, Coefficient: 90 */ + CONVERT_COEFF(-106725), /* Filter:4, Coefficient: 91 */ + CONVERT_COEFF(-101537), /* Filter:4, Coefficient: 92 */ + CONVERT_COEFF(920613), /* Filter:3, Coefficient: 89 */ + CONVERT_COEFF(747526), /* Filter:3, Coefficient: 90 */ + CONVERT_COEFF(464354), /* Filter:3, Coefficient: 91 */ + CONVERT_COEFF(136043), /* Filter:3, Coefficient: 92 */ + CONVERT_COEFF(-398040), /* Filter:2, Coefficient: 89 */ + CONVERT_COEFF(1278522), /* Filter:2, Coefficient: 90 */ + CONVERT_COEFF(2499600), /* Filter:2, Coefficient: 91 */ + CONVERT_COEFF(3108250), /* Filter:2, Coefficient: 92 */ + CONVERT_COEFF(-9056522), /* Filter:1, Coefficient: 89 */ + CONVERT_COEFF(-8586783), /* Filter:1, Coefficient: 90 */ + CONVERT_COEFF(-6650839), /* Filter:1, Coefficient: 91 */ + CONVERT_COEFF(-3793297), /* Filter:1, Coefficient: 92 */ + + /* Filter #24, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-78733), /* Filter:4, Coefficient: 93 */ + CONVERT_COEFF(-44705), /* Filter:4, Coefficient: 94 */ + CONVERT_COEFF(-7104), /* Filter:4, Coefficient: 95 */ + CONVERT_COEFF(26726), /* Filter:4, Coefficient: 96 */ + CONVERT_COEFF(-172582), /* Filter:3, Coefficient: 93 */ + CONVERT_COEFF(-408494), /* Filter:3, Coefficient: 94 */ + CONVERT_COEFF(-538640), /* Filter:3, Coefficient: 95 */ + CONVERT_COEFF(-553497), /* Filter:3, Coefficient: 96 */ + CONVERT_COEFF(3077680), /* Filter:2, Coefficient: 93 */ + CONVERT_COEFF(2499519), /* Filter:2, Coefficient: 94 */ + CONVERT_COEFF(1552119), /* Filter:2, Coefficient: 95 */ + CONVERT_COEFF(456990), /* Filter:2, Coefficient: 96 */ + CONVERT_COEFF(-650487), /* Filter:1, Coefficient: 93 */ + CONVERT_COEFF(2175698), /* Filter:1, Coefficient: 94 */ + CONVERT_COEFF(4221669), /* Filter:1, Coefficient: 95 */ + CONVERT_COEFF(5227614), /* Filter:1, Coefficient: 96 */ + + /* Filter #25, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(51065), /* Filter:4, Coefficient: 97 */ + CONVERT_COEFF(62685), /* Filter:4, Coefficient: 98 */ + CONVERT_COEFF(61148), /* Filter:4, Coefficient: 99 */ + CONVERT_COEFF(48532), /* Filter:4, Coefficient: 100 */ + CONVERT_COEFF(-465874), /* Filter:3, Coefficient: 97 */ + CONVERT_COEFF(-305721), /* Filter:3, Coefficient: 98 */ + CONVERT_COEFF(-112385), /* Filter:3, Coefficient: 99 */ + CONVERT_COEFF(73933), /* Filter:3, Coefficient: 100 */ + CONVERT_COEFF(-567215), /* Filter:2, Coefficient: 97 */ + CONVERT_COEFF(-1344377), /* Filter:2, Coefficient: 98 */ + CONVERT_COEFF(-1767688), /* Filter:2, Coefficient: 99 */ + CONVERT_COEFF(-1810088), /* Filter:2, Coefficient: 100 */ + CONVERT_COEFF(5157406), /* Filter:1, Coefficient: 97 */ + CONVERT_COEFF(4175038), /* Filter:1, Coefficient: 98 */ + CONVERT_COEFF(2587411), /* Filter:1, Coefficient: 99 */ + CONVERT_COEFF(768423), /* Filter:1, Coefficient: 100 */ + + /* Filter #26, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(28723), /* Filter:4, Coefficient: 101 */ + CONVERT_COEFF(6440), /* Filter:4, Coefficient: 102 */ + CONVERT_COEFF(-13774), /* Filter:4, Coefficient: 103 */ + CONVERT_COEFF(-28398), /* Filter:4, Coefficient: 104 */ + CONVERT_COEFF(219811), /* Filter:3, Coefficient: 101 */ + CONVERT_COEFF(303981), /* Filter:3, Coefficient: 102 */ + CONVERT_COEFF(319710), /* Filter:3, Coefficient: 103 */ + CONVERT_COEFF(274094), /* Filter:3, Coefficient: 104 */ + CONVERT_COEFF(-1518489), /* Filter:2, Coefficient: 101 */ + CONVERT_COEFF(-994890), /* Filter:2, Coefficient: 102 */ + CONVERT_COEFF(-369667), /* Filter:2, Coefficient: 103 */ + CONVERT_COEFF(226880), /* Filter:2, Coefficient: 104 */ + CONVERT_COEFF(-919124), /* Filter:1, Coefficient: 101 */ + CONVERT_COEFF(-2188898), /* Filter:1, Coefficient: 102 */ + CONVERT_COEFF(-2873130), /* Filter:1, Coefficient: 103 */ + CONVERT_COEFF(-2936618), /* Filter:1, Coefficient: 104 */ + + /* Filter #27, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-35477), /* Filter:4, Coefficient: 105 */ + CONVERT_COEFF(-34783), /* Filter:4, Coefficient: 106 */ + CONVERT_COEFF(-27623), /* Filter:4, Coefficient: 107 */ + CONVERT_COEFF(-16364), /* Filter:4, Coefficient: 108 */ + CONVERT_COEFF(184790), /* Filter:3, Coefficient: 105 */ + CONVERT_COEFF(75160), /* Filter:3, Coefficient: 106 */ + CONVERT_COEFF(-31027), /* Filter:3, Coefficient: 107 */ + CONVERT_COEFF(-114243), /* Filter:3, Coefficient: 108 */ + CONVERT_COEFF(689048), /* Filter:2, Coefficient: 105 */ + CONVERT_COEFF(952149), /* Filter:2, Coefficient: 106 */ + CONVERT_COEFF(998741), /* Filter:2, Coefficient: 107 */ + CONVERT_COEFF(854886), /* Filter:2, Coefficient: 108 */ + CONVERT_COEFF(-2463839), /* Filter:1, Coefficient: 105 */ + CONVERT_COEFF(-1625344), /* Filter:1, Coefficient: 106 */ + CONVERT_COEFF(-632765), /* Filter:1, Coefficient: 107 */ + CONVERT_COEFF(307301), /* Filter:1, Coefficient: 108 */ + + /* Filter #28, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-3819), /* Filter:4, Coefficient: 109 */ + CONVERT_COEFF(7377), /* Filter:4, Coefficient: 110 */ + CONVERT_COEFF(15261), /* Filter:4, Coefficient: 111 */ + CONVERT_COEFF(18835), /* Filter:4, Coefficient: 112 */ + CONVERT_COEFF(-162364), /* Filter:3, Coefficient: 109 */ + CONVERT_COEFF(-171920), /* Filter:3, Coefficient: 110 */ + CONVERT_COEFF(-147466), /* Filter:3, Coefficient: 111 */ + CONVERT_COEFF(-99442), /* Filter:3, Coefficient: 112 */ + CONVERT_COEFF(578544), /* Filter:2, Coefficient: 109 */ + CONVERT_COEFF(243498), /* Filter:2, Coefficient: 110 */ + CONVERT_COEFF(-77378), /* Filter:2, Coefficient: 111 */ + CONVERT_COEFF(-326115), /* Filter:2, Coefficient: 112 */ + CONVERT_COEFF(1031494), /* Filter:1, Coefficient: 109 */ + CONVERT_COEFF(1443736), /* Filter:1, Coefficient: 110 */ + CONVERT_COEFF(1522566), /* Filter:1, Coefficient: 111 */ + CONVERT_COEFF(1312875), /* Filter:1, Coefficient: 112 */ + + /* Filter #29, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(18119), /* Filter:4, Coefficient: 113 */ + CONVERT_COEFF(13991), /* Filter:4, Coefficient: 114 */ + CONVERT_COEFF(7872), /* Filter:4, Coefficient: 115 */ + CONVERT_COEFF(1348), /* Filter:4, Coefficient: 116 */ + CONVERT_COEFF(-41184), /* Filter:3, Coefficient: 113 */ + CONVERT_COEFF(14196), /* Filter:3, Coefficient: 114 */ + CONVERT_COEFF(56400), /* Filter:3, Coefficient: 115 */ + CONVERT_COEFF(79557), /* Filter:3, Coefficient: 116 */ + CONVERT_COEFF(-468515), /* Filter:2, Coefficient: 113 */ + CONVERT_COEFF(-496901), /* Filter:2, Coefficient: 114 */ + CONVERT_COEFF(-427126), /* Filter:2, Coefficient: 115 */ + CONVERT_COEFF(-291358), /* Filter:2, Coefficient: 116 */ + CONVERT_COEFF(906078), /* Filter:1, Coefficient: 113 */ + CONVERT_COEFF(414464), /* Filter:1, Coefficient: 114 */ + CONVERT_COEFF(-54245), /* Filter:1, Coefficient: 115 */ + CONVERT_COEFF(-417064), /* Filter:1, Coefficient: 116 */ + + /* Filter #30, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-4186), /* Filter:4, Coefficient: 117 */ + CONVERT_COEFF(-7781), /* Filter:4, Coefficient: 118 */ + CONVERT_COEFF(-9064), /* Filter:4, Coefficient: 119 */ + CONVERT_COEFF(-8214), /* Filter:4, Coefficient: 120 */ + CONVERT_COEFF(82669), /* Filter:3, Coefficient: 117 */ + CONVERT_COEFF(68978), /* Filter:3, Coefficient: 118 */ + CONVERT_COEFF(44558), /* Filter:3, Coefficient: 119 */ + CONVERT_COEFF(16546), /* Filter:3, Coefficient: 120 */ + CONVERT_COEFF(-128765), /* Filter:2, Coefficient: 117 */ + CONVERT_COEFF(23638), /* Filter:2, Coefficient: 118 */ + CONVERT_COEFF(138103), /* Filter:2, Coefficient: 119 */ + CONVERT_COEFF(200098), /* Filter:2, Coefficient: 120 */ + CONVERT_COEFF(-627465), /* Filter:1, Coefficient: 117 */ + CONVERT_COEFF(-677691), /* Filter:1, Coefficient: 118 */ + CONVERT_COEFF(-592807), /* Filter:1, Coefficient: 119 */ + CONVERT_COEFF(-419175), /* Filter:1, Coefficient: 120 */ + + /* Filter #31, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(-5833), /* Filter:4, Coefficient: 121 */ + CONVERT_COEFF(-2739), /* Filter:4, Coefficient: 122 */ + CONVERT_COEFF(251), /* Filter:4, Coefficient: 123 */ + CONVERT_COEFF(2500), /* Filter:4, Coefficient: 124 */ + CONVERT_COEFF(-8556), /* Filter:3, Coefficient: 121 */ + CONVERT_COEFF(-26141), /* Filter:3, Coefficient: 122 */ + CONVERT_COEFF(-34137), /* Filter:3, Coefficient: 123 */ + CONVERT_COEFF(-32972), /* Filter:3, Coefficient: 124 */ + CONVERT_COEFF(208777), /* Filter:2, Coefficient: 121 */ + CONVERT_COEFF(174473), /* Filter:2, Coefficient: 122 */ + CONVERT_COEFF(114277), /* Filter:2, Coefficient: 123 */ + CONVERT_COEFF(46990), /* Filter:2, Coefficient: 124 */ + CONVERT_COEFF(-210728), /* Filter:1, Coefficient: 121 */ + CONVERT_COEFF(-16339), /* Filter:1, Coefficient: 122 */ + CONVERT_COEFF(129243), /* Filter:1, Coefficient: 123 */ + CONVERT_COEFF(209618), /* Filter:1, Coefficient: 124 */ + + /* Filter #32, conversion from 48000 Hz to 8000 Hz */ + + CONVERT_COEFF(3662), /* Filter:4, Coefficient: 125 */ + CONVERT_COEFF(3707), /* Filter:4, Coefficient: 126 */ + CONVERT_COEFF(2870), /* Filter:4, Coefficient: 127 */ + CONVERT_COEFF(335927), /* Filter:4, Coefficient: 128 */ + CONVERT_COEFF(-25001), /* Filter:3, Coefficient: 125 */ + CONVERT_COEFF(-13600), /* Filter:3, Coefficient: 126 */ + CONVERT_COEFF(-2195), /* Filter:3, Coefficient: 127 */ + CONVERT_COEFF(-458842), /* Filter:3, Coefficient: 128 */ + CONVERT_COEFF(-11331), /* Filter:2, Coefficient: 125 */ + CONVERT_COEFF(-50338), /* Filter:2, Coefficient: 126 */ + CONVERT_COEFF(-66501), /* Filter:2, Coefficient: 127 */ + CONVERT_COEFF(55557), /* Filter:2, Coefficient: 128 */ + CONVERT_COEFF(226117), /* Filter:1, Coefficient: 125 */ + CONVERT_COEFF(193432), /* Filter:1, Coefficient: 126 */ + CONVERT_COEFF(133189), /* Filter:1, Coefficient: 127 */ + CONVERT_COEFF(67358), /* Filter:1, Coefficient: 128 */ +}; diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_11025Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_11025Hz.h new file mode 100644 index 000000000000..3ab1223bc68a --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_11025Hz.h @@ -0,0 +1,466 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 48000 Hz to 11025 Hz */ +/* NUM_FILTERS=4, FILTER_LENGTH=96, alpha=5.700000, gamma=0.417000 */ + +__cold_rodata static const int32_t coeff48000to11025[] = { + + /* Filter #1, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(-5276), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(-12951), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(-16487), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(-12216), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(41170), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(24714), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(-16130), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(-68429), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(90439), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(156156), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(166381), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(85133), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(-36529), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(89808), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(257736), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(391514), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(540), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(18145), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(33188), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(37139), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(-107599), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(-106756), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(-50319), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(54036), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(-87027), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(-298777), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(-456335), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(-457073), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(396015), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(201937), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(-185458), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(-658946), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(24307), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(-4499), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(-40503), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(-68959), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(171682), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(249813), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(237789), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(112225), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(-238997), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(174254), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(656680), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(1007920), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(-1024879), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(-1067924), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(-648377), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(205595), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(-74494), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(-48117), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(7013), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(73976), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(-104001), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(-339463), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(-493890), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(-476173), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(1025112), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(596557), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(-220901), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(-1180767), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(1256824), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(2103513), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(2312568), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(1604844), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(126345), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(137657), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(93034), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(-1731), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(-247687), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(147413), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(581451), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(878980), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(-1906017), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(-2021581), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(-1318811), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(113142), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(21881), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(-2005545), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(-3742184), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(-4386660), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(-118109), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(-212105), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(-239586), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(-174729), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(881333), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(518154), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(-143352), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(-896882), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(1853939), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(3252995), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(3650862), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(2652871), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(-3396385), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(-779248), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(2779889), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(6048018), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(-24432), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(168052), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(333676), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(400546), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(-1453384), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(-1543048), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(-1029512), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(8151), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(350965), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(-2609224), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(-5174708), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(-6226971), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(7629537), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(6502907), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(2518773), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(-3351884), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(322102), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(100162), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(-207102), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(-497722), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(1264729), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(2286428), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(2621280), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(1995783), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(-5018466), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(-1546610), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(3294826), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(7886940), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(-9170470), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(-12602533), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(-11762954), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(-6054156), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(-657260), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(-599700), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(-303789), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(169268), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(453662), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(-1602376), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(-3496605), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(-4480875), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(10370645), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(9314284), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(4342738), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(-3512410), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(3330959), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(13498465), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(20611375), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(21154438), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(685660), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(1076048), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(1189612), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(947693), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(-3992362), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(-1882814), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(1466176), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(5196025), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(-11914041), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(-17803913), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(-18332740), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(-11858951), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(13330874), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(-1889934), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(-20501310), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(-36179493), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(378181), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(-382925), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(-1125926), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(-1628684), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(8192385), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(9416173), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(8242832), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(4697569), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(1316974), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(18760292), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(36372844), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(49436642), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(-41896152), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(-32009702), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(-4216305), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(39274782), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(-1725846), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(-1363486), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(-620573), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(310846), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(-498294), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(-6096589), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(-10663877), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(-12993683), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(53943647), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(47812424), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(31605996), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(8506473), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(91783432), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(143507821), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(183866425), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(204194917), /* Filter:1, Coefficient: 48 */ + + /* Filter #13, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(1181314), /* Filter:4, Coefficient: 49 */ + CONVERT_COEFF(1758112), /* Filter:4, Coefficient: 50 */ + CONVERT_COEFF(1894276), /* Filter:4, Coefficient: 51 */ + CONVERT_COEFF(1570552), /* Filter:4, Coefficient: 52 */ + CONVERT_COEFF(-12461531), /* Filter:3, Coefficient: 49 */ + CONVERT_COEFF(-9210650), /* Filter:3, Coefficient: 50 */ + CONVERT_COEFF(-4109186), /* Filter:3, Coefficient: 51 */ + CONVERT_COEFF(1507388), /* Filter:3, Coefficient: 52 */ + CONVERT_COEFF(-16471793), /* Filter:2, Coefficient: 49 */ + CONVERT_COEFF(-37810559), /* Filter:2, Coefficient: 50 */ + CONVERT_COEFF(-50965956), /* Filter:2, Coefficient: 51 */ + CONVERT_COEFF(-53557320), /* Filter:2, Coefficient: 52 */ + CONVERT_COEFF(200025358), /* Filter:1, Coefficient: 49 */ + CONVERT_COEFF(172279208), /* Filter:1, Coefficient: 50 */ + CONVERT_COEFF(127020431), /* Filter:1, Coefficient: 51 */ + CONVERT_COEFF(73842077), /* Filter:1, Coefficient: 52 */ + + /* Filter #14, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(897380), /* Filter:4, Coefficient: 53 */ + CONVERT_COEFF(77192), /* Filter:4, Coefficient: 54 */ + CONVERT_COEFF(-659808), /* Filter:4, Coefficient: 55 */ + CONVERT_COEFF(-1125092), /* Filter:4, Coefficient: 56 */ + CONVERT_COEFF(6226751), /* Filter:3, Coefficient: 53 */ + CONVERT_COEFF(8960398), /* Filter:3, Coefficient: 54 */ + CONVERT_COEFF(9231586), /* Filter:3, Coefficient: 55 */ + CONVERT_COEFF(7267416), /* Filter:3, Coefficient: 56 */ + CONVERT_COEFF(-45919329), /* Filter:2, Coefficient: 53 */ + CONVERT_COEFF(-30871316), /* Filter:2, Coefficient: 54 */ + CONVERT_COEFF(-12800875), /* Filter:2, Coefficient: 55 */ + CONVERT_COEFF(3635617), /* Filter:2, Coefficient: 56 */ + CONVERT_COEFF(23363491), /* Filter:1, Coefficient: 53 */ + CONVERT_COEFF(-15432232), /* Filter:1, Coefficient: 54 */ + CONVERT_COEFF(-37267226), /* Filter:1, Coefficient: 55 */ + CONVERT_COEFF(-41497734), /* Filter:1, Coefficient: 56 */ + + /* Filter #15, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(-1224338), /* Filter:4, Coefficient: 57 */ + CONVERT_COEFF(-977499), /* Filter:4, Coefficient: 58 */ + CONVERT_COEFF(-502204), /* Filter:4, Coefficient: 59 */ + CONVERT_COEFF(31518), /* Filter:4, Coefficient: 60 */ + CONVERT_COEFF(3877187), /* Filter:3, Coefficient: 57 */ + CONVERT_COEFF(167487), /* Filter:3, Coefficient: 58 */ + CONVERT_COEFF(-2806990), /* Filter:3, Coefficient: 59 */ + CONVERT_COEFF(-4344247), /* Filter:3, Coefficient: 60 */ + CONVERT_COEFF(14790492), /* Filter:2, Coefficient: 57 */ + CONVERT_COEFF(18905076), /* Filter:2, Coefficient: 58 */ + CONVERT_COEFF(16363909), /* Filter:2, Coefficient: 59 */ + CONVERT_COEFF(9303267), /* Filter:2, Coefficient: 60 */ + CONVERT_COEFF(-31720872), /* Filter:1, Coefficient: 57 */ + CONVERT_COEFF(-14278017), /* Filter:1, Coefficient: 58 */ + CONVERT_COEFF(3817177), /* Filter:1, Coefficient: 59 */ + CONVERT_COEFF(16872467), /* Filter:1, Coefficient: 60 */ + + /* Filter #16, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(458491), /* Filter:4, Coefficient: 61 */ + CONVERT_COEFF(668294), /* Filter:4, Coefficient: 62 */ + CONVERT_COEFF(632521), /* Filter:4, Coefficient: 63 */ + CONVERT_COEFF(402936), /* Filter:4, Coefficient: 64 */ + CONVERT_COEFF(-4258557), /* Filter:3, Coefficient: 61 */ + CONVERT_COEFF(-2868976), /* Filter:3, Coefficient: 62 */ + CONVERT_COEFF(-834307), /* Filter:3, Coefficient: 63 */ + CONVERT_COEFF(1096696), /* Filter:3, Coefficient: 64 */ + CONVERT_COEFF(754906), /* Filter:2, Coefficient: 61 */ + CONVERT_COEFF(-6366692), /* Filter:2, Coefficient: 62 */ + CONVERT_COEFF(-10107072), /* Filter:2, Coefficient: 63 */ + CONVERT_COEFF(-9905933), /* Filter:2, Coefficient: 64 */ + CONVERT_COEFF(21863748), /* Filter:1, Coefficient: 61 */ + CONVERT_COEFF(18819227), /* Filter:1, Coefficient: 62 */ + CONVERT_COEFF(10252203), /* Filter:1, Coefficient: 63 */ + CONVERT_COEFF(-56657), /* Filter:1, Coefficient: 64 */ + + /* Filter #17, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(84254), /* Filter:4, Coefficient: 65 */ + CONVERT_COEFF(-206679), /* Filter:4, Coefficient: 66 */ + CONVERT_COEFF(-380298), /* Filter:4, Coefficient: 67 */ + CONVERT_COEFF(-399448), /* Filter:4, Coefficient: 68 */ + CONVERT_COEFF(2330787), /* Filter:3, Coefficient: 65 */ + CONVERT_COEFF(2593273), /* Filter:3, Coefficient: 66 */ + CONVERT_COEFF(1966425), /* Filter:3, Coefficient: 67 */ + CONVERT_COEFF(807090), /* Filter:3, Coefficient: 68 */ + CONVERT_COEFF(-6539839), /* Filter:2, Coefficient: 65 */ + CONVERT_COEFF(-1656983), /* Filter:2, Coefficient: 66 */ + CONVERT_COEFF(2892064), /* Filter:2, Coefficient: 67 */ + CONVERT_COEFF(5683926), /* Filter:2, Coefficient: 68 */ + CONVERT_COEFF(-8463246), /* Filter:1, Coefficient: 65 */ + CONVERT_COEFF(-12588471), /* Filter:1, Coefficient: 66 */ + CONVERT_COEFF(-11859264), /* Filter:1, Coefficient: 67 */ + CONVERT_COEFF(-7381325), /* Filter:1, Coefficient: 68 */ + + /* Filter #18, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(-283699), /* Filter:4, Coefficient: 69 */ + CONVERT_COEFF(-94156), /* Filter:4, Coefficient: 70 */ + CONVERT_COEFF(93448), /* Filter:4, Coefficient: 71 */ + CONVERT_COEFF(216583), /* Filter:4, Coefficient: 72 */ + CONVERT_COEFF(-413134), /* Filter:3, Coefficient: 69 */ + CONVERT_COEFF(-1281462), /* Filter:3, Coefficient: 70 */ + CONVERT_COEFF(-1571374), /* Filter:3, Coefficient: 71 */ + CONVERT_COEFF(-1287849), /* Filter:3, Coefficient: 72 */ + CONVERT_COEFF(6114153), /* Filter:2, Coefficient: 69 */ + CONVERT_COEFF(4458459), /* Filter:2, Coefficient: 70 */ + CONVERT_COEFF(1633571), /* Filter:2, Coefficient: 71 */ + CONVERT_COEFF(-1216156), /* Filter:2, Coefficient: 72 */ + CONVERT_COEFF(-1289801), /* Filter:1, Coefficient: 69 */ + CONVERT_COEFF(4127659), /* Filter:1, Coefficient: 70 */ + CONVERT_COEFF(7210746), /* Filter:1, Coefficient: 71 */ + CONVERT_COEFF(7366642), /* Filter:1, Coefficient: 72 */ + + /* Filter #19, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(245013), /* Filter:4, Coefficient: 73 */ + CONVERT_COEFF(185843), /* Filter:4, Coefficient: 74 */ + CONVERT_COEFF(74882), /* Filter:4, Coefficient: 75 */ + CONVERT_COEFF(-40571), /* Filter:4, Coefficient: 76 */ + CONVERT_COEFF(-627349), /* Filter:3, Coefficient: 73 */ + CONVERT_COEFF(120817), /* Filter:3, Coefficient: 74 */ + CONVERT_COEFF(688759), /* Filter:3, Coefficient: 75 */ + CONVERT_COEFF(917942), /* Filter:3, Coefficient: 76 */ + CONVERT_COEFF(-3140159), /* Filter:2, Coefficient: 73 */ + CONVERT_COEFF(-3667371), /* Filter:2, Coefficient: 74 */ + CONVERT_COEFF(-2881001), /* Filter:2, Coefficient: 75 */ + CONVERT_COEFF(-1291563), /* Filter:2, Coefficient: 76 */ + CONVERT_COEFF(5079392), /* Filter:1, Coefficient: 73 */ + CONVERT_COEFF(1556950), /* Filter:1, Coefficient: 74 */ + CONVERT_COEFF(-1803822), /* Filter:1, Coefficient: 75 */ + CONVERT_COEFF(-3921315), /* Filter:1, Coefficient: 76 */ + + /* Filter #20, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(-120129), /* Filter:4, Coefficient: 77 */ + CONVERT_COEFF(-143205), /* Filter:4, Coefficient: 78 */ + CONVERT_COEFF(-112715), /* Filter:4, Coefficient: 79 */ + CONVERT_COEFF(-49779), /* Filter:4, Coefficient: 80 */ + CONVERT_COEFF(794458), /* Filter:3, Coefficient: 77 */ + CONVERT_COEFF(427950), /* Filter:3, Coefficient: 78 */ + CONVERT_COEFF(-8978), /* Filter:3, Coefficient: 79 */ + CONVERT_COEFF(-352674), /* Filter:3, Coefficient: 80 */ + CONVERT_COEFF(414286), /* Filter:2, Coefficient: 77 */ + CONVERT_COEFF(1640931), /* Filter:2, Coefficient: 78 */ + CONVERT_COEFF(2071182), /* Filter:2, Coefficient: 79 */ + CONVERT_COEFF(1722382), /* Filter:2, Coefficient: 80 */ + CONVERT_COEFF(-4335656), /* Filter:1, Coefficient: 77 */ + CONVERT_COEFF(-3247151), /* Filter:1, Coefficient: 78 */ + CONVERT_COEFF(-1321521), /* Filter:1, Coefficient: 79 */ + CONVERT_COEFF(627989), /* Filter:1, Coefficient: 80 */ + + /* Filter #21, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(17150), /* Filter:4, Coefficient: 81 */ + CONVERT_COEFF(63819), /* Filter:4, Coefficient: 82 */ + CONVERT_COEFF(78078), /* Filter:4, Coefficient: 83 */ + CONVERT_COEFF(61882), /* Filter:4, Coefficient: 84 */ + CONVERT_COEFF(-504123), /* Filter:3, Coefficient: 81 */ + CONVERT_COEFF(-451338), /* Filter:3, Coefficient: 82 */ + CONVERT_COEFF(-256412), /* Filter:3, Coefficient: 83 */ + CONVERT_COEFF(-18431), /* Filter:3, Coefficient: 84 */ + CONVERT_COEFF(875132), /* Filter:2, Coefficient: 81 */ + CONVERT_COEFF(-76722), /* Filter:2, Coefficient: 82 */ + CONVERT_COEFF(-786703), /* Filter:2, Coefficient: 83 */ + CONVERT_COEFF(-1067401), /* Filter:2, Coefficient: 84 */ + CONVERT_COEFF(1947985), /* Filter:1, Coefficient: 81 */ + CONVERT_COEFF(2336224), /* Filter:1, Coefficient: 82 */ + CONVERT_COEFF(1872047), /* Filter:1, Coefficient: 83 */ + CONVERT_COEFF(907040), /* Filter:1, Coefficient: 84 */ + + /* Filter #22, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(27740), /* Filter:4, Coefficient: 85 */ + CONVERT_COEFF(-8034), /* Filter:4, Coefficient: 86 */ + CONVERT_COEFF(-32141), /* Filter:4, Coefficient: 87 */ + CONVERT_COEFF(-38602), /* Filter:4, Coefficient: 88 */ + CONVERT_COEFF(169685), /* Filter:3, Coefficient: 85 */ + CONVERT_COEFF(253408), /* Filter:3, Coefficient: 86 */ + CONVERT_COEFF(228111), /* Filter:3, Coefficient: 87 */ + CONVERT_COEFF(129707), /* Filter:3, Coefficient: 88 */ + CONVERT_COEFF(-922590), /* Filter:2, Coefficient: 85 */ + CONVERT_COEFF(-503998), /* Filter:2, Coefficient: 86 */ + CONVERT_COEFF(-23864), /* Filter:2, Coefficient: 87 */ + CONVERT_COEFF(335367), /* Filter:2, Coefficient: 88 */ + CONVERT_COEFF(-116914), /* Filter:1, Coefficient: 85 */ + CONVERT_COEFF(-842108), /* Filter:1, Coefficient: 86 */ + CONVERT_COEFF(-1100770), /* Filter:1, Coefficient: 87 */ + CONVERT_COEFF(-928696), /* Filter:1, Coefficient: 88 */ + + /* Filter #23, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(-29393), /* Filter:4, Coefficient: 89 */ + CONVERT_COEFF(-11914), /* Filter:4, Coefficient: 90 */ + CONVERT_COEFF(5087), /* Filter:4, Coefficient: 91 */ + CONVERT_COEFF(15234), /* Filter:4, Coefficient: 92 */ + CONVERT_COEFF(12179), /* Filter:3, Coefficient: 89 */ + CONVERT_COEFF(-76760), /* Filter:3, Coefficient: 90 */ + CONVERT_COEFF(-112173), /* Filter:3, Coefficient: 91 */ + CONVERT_COEFF(-95873), /* Filter:3, Coefficient: 92 */ + CONVERT_COEFF(480135), /* Filter:2, Coefficient: 89 */ + CONVERT_COEFF(418338), /* Filter:2, Coefficient: 90 */ + CONVERT_COEFF(230980), /* Filter:2, Coefficient: 91 */ + CONVERT_COEFF(22991), /* Filter:2, Coefficient: 92 */ + CONVERT_COEFF(-502241), /* Filter:1, Coefficient: 89 */ + CONVERT_COEFF(-39321), /* Filter:1, Coefficient: 90 */ + CONVERT_COEFF(290352), /* Filter:1, Coefficient: 91 */ + CONVERT_COEFF(414260), /* Filter:1, Coefficient: 92 */ + + /* Filter #24, conversion from 48000 Hz to 11025 Hz */ + + CONVERT_COEFF(16461), /* Filter:4, Coefficient: 93 */ + CONVERT_COEFF(10800), /* Filter:4, Coefficient: 94 */ + CONVERT_COEFF(2550), /* Filter:4, Coefficient: 95 */ + CONVERT_COEFF(-797683), /* Filter:4, Coefficient: 96 */ + CONVERT_COEFF(-49051), /* Filter:3, Coefficient: 93 */ + CONVERT_COEFF(991), /* Filter:3, Coefficient: 94 */ + CONVERT_COEFF(33364), /* Filter:3, Coefficient: 95 */ + CONVERT_COEFF(1235716), /* Filter:3, Coefficient: 96 */ + CONVERT_COEFF(-122969), /* Filter:2, Coefficient: 93 */ + CONVERT_COEFF(-172363), /* Filter:2, Coefficient: 94 */ + CONVERT_COEFF(-138918), /* Filter:2, Coefficient: 95 */ + CONVERT_COEFF(-375528), /* Filter:2, Coefficient: 96 */ + CONVERT_COEFF(356624), /* Filter:1, Coefficient: 93 */ + CONVERT_COEFF(201071), /* Filter:1, Coefficient: 94 */ + CONVERT_COEFF(40502), /* Filter:1, Coefficient: 95 */ + CONVERT_COEFF(-62504), /* Filter:1, Coefficient: 96 */ +}; diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_12000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_12000Hz.h new file mode 100644 index 000000000000..89a08f8e1506 --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_12000Hz.h @@ -0,0 +1,466 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 48000 Hz to 12000 Hz */ +/* NUM_FILTERS=4, FILTER_LENGTH=96, alpha=5.700000, gamma=0.424000 */ + +__cold_rodata static const int32_t coeff48000to12000[] = { + + /* Filter #1, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(9466), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(18324), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(18675), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(6681), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(-44320), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(-15044), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(41846), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(99856), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(-108866), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(-168122), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(-143205), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(-4840), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(18979), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(-124739), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(-289576), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(-372252), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(-14873), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(-36092), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(-43775), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(-28417), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(120645), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(74642), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(-36940), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(-172008), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(212485), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(406758), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(446885), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(243397), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(-270550), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(47706), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(493005), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(859159), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(8921), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(53986), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(83668), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(76633), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(-259236), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(-230916), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(-63713), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(194231), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(-181655), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(-668246), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(-964705), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(-841844), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(902116), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(470138), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(-375031), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(-1319757), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(25833), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(-53679), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(-127150), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(-153896), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(429216), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(506489), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(338544), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(-54472), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(-229172), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(697753), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(1541275), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(1833706), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(-1890703), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(-1664796), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(-514224), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(1238423), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(-107640), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(6019), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(144977), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(244094), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(-527257), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(-854646), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(-830345), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(-379134), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(1268127), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(-96526), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(-1771933), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(-2986182), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(2863711), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(3496880), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(2551682), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(94379), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(243618), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(120959), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(-89812), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(-303143), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(373317), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(1118639), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(1481524), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(1194410), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(-3011832), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(-1547918), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(1028425), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(3697569), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(-3026789), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(-5421590), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(-5729809), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(-3309613), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(-414069), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(-346290), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(-95407), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(254838), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(254718), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(-1017842), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(-2072112), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(-2348186), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(5163786), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(4438011), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(1391449), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(-2999213), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(1279200), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(6283525), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(9357238), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(8581017), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(556057), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(654070), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(461041), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(8985), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(-1547890), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(169371), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(2173059), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(3569126), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(-6896234), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(-8311637), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(-6031532), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(-353097), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(3488394), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(-4399594), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(-11887580), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(-15284742), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(-543384), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(-960956), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(-1025319), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(-634838), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(3569496), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(1878806), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(-1076651), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(-4206990), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(6748994), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(12209118), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(13074826), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(7888560), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(-12059514), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(-2284367), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(10842409), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(21814880), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(131905), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(1022024), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(1689633), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(1826448), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(-6121966), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(-5683979), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(-2536796), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(2619817), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(-2343046), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(-14088848), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(-22312461), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(-22299178), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(24861172), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(16527773), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(-2222990), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(-25382165), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(1291803), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(187823), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(-1156014), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(-2289689), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(8156827), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(12037112), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(12558708), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(9041064), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(-11640045), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(8421631), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(32901411), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(54414451), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(-43234314), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(-45424925), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(-24777921), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(19525839), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(-2804099), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(-2486101), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(-1405857), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(99935), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(2176743), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(-6112957), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(-13291600), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(-17077204), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(65561608), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(61534767), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(41975533), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(11356417), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(80690239), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(145621917), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(198554116), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(225828200), /* Filter:1, Coefficient: 48 */ + + /* Filter #13, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(1544944), /* Filter:4, Coefficient: 49 */ + CONVERT_COEFF(2466704), /* Filter:4, Coefficient: 50 */ + CONVERT_COEFF(2590632), /* Filter:4, Coefficient: 51 */ + CONVERT_COEFF(1922395), /* Filter:4, Coefficient: 52 */ + CONVERT_COEFF(-16247012), /* Filter:3, Coefficient: 49 */ + CONVERT_COEFF(-11073761), /* Filter:3, Coefficient: 50 */ + CONVERT_COEFF(-3227323), /* Filter:3, Coefficient: 51 */ + CONVERT_COEFF(4820544), /* Filter:3, Coefficient: 52 */ + CONVERT_COEFF(-22315217), /* Filter:2, Coefficient: 49 */ + CONVERT_COEFF(-50044994), /* Filter:2, Coefficient: 50 */ + CONVERT_COEFF(-64751780), /* Filter:2, Coefficient: 51 */ + CONVERT_COEFF(-63486697), /* Filter:2, Coefficient: 52 */ + CONVERT_COEFF(220203456), /* Filter:1, Coefficient: 49 */ + CONVERT_COEFF(183182934), /* Filter:1, Coefficient: 50 */ + CONVERT_COEFF(124528682), /* Filter:1, Coefficient: 51 */ + CONVERT_COEFF(59139166), /* Filter:1, Coefficient: 52 */ + + /* Filter #14, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(735067), /* Filter:4, Coefficient: 53 */ + CONVERT_COEFF(-540990), /* Filter:4, Coefficient: 54 */ + CONVERT_COEFF(-1480192), /* Filter:4, Coefficient: 55 */ + CONVERT_COEFF(-1812185), /* Filter:4, Coefficient: 56 */ + CONVERT_COEFF(10661840), /* Filter:3, Coefficient: 53 */ + CONVERT_COEFF(12763578), /* Filter:3, Coefficient: 54 */ + CONVERT_COEFF(10929621), /* Filter:3, Coefficient: 55 */ + CONVERT_COEFF(6261251), /* Filter:3, Coefficient: 56 */ + CONVERT_COEFF(-48196279), /* Filter:2, Coefficient: 53 */ + CONVERT_COEFF(-24804128), /* Filter:2, Coefficient: 54 */ + CONVERT_COEFF(-1006930), /* Filter:2, Coefficient: 55 */ + CONVERT_COEFF(16367589), /* Filter:2, Coefficient: 56 */ + CONVERT_COEFF(2395365), /* Filter:1, Coefficient: 53 */ + CONVERT_COEFF(-34403398), /* Filter:1, Coefficient: 54 */ + CONVERT_COEFF(-46984107), /* Filter:1, Coefficient: 55 */ + CONVERT_COEFF(-38540927), /* Filter:1, Coefficient: 56 */ + + /* Filter #15, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(-1504699), /* Filter:4, Coefficient: 57 */ + CONVERT_COEFF(-752135), /* Filter:4, Coefficient: 58 */ + CONVERT_COEFF(118595), /* Filter:4, Coefficient: 59 */ + CONVERT_COEFF(782220), /* Filter:4, Coefficient: 60 */ + CONVERT_COEFF(660837), /* Filter:3, Coefficient: 57 */ + CONVERT_COEFF(-3907345), /* Filter:3, Coefficient: 58 */ + CONVERT_COEFF(-6107752), /* Filter:3, Coefficient: 59 */ + CONVERT_COEFF(-5624729), /* Filter:3, Coefficient: 60 */ + CONVERT_COEFF(23479491), /* Filter:2, Coefficient: 57 */ + CONVERT_COEFF(20364635), /* Filter:2, Coefficient: 58 */ + CONVERT_COEFF(10388086), /* Filter:2, Coefficient: 59 */ + CONVERT_COEFF(-1396259), /* Filter:2, Coefficient: 60 */ + CONVERT_COEFF(-17723958), /* Filter:1, Coefficient: 57 */ + CONVERT_COEFF(4911585), /* Filter:1, Coefficient: 58 */ + CONVERT_COEFF(20616375), /* Filter:1, Coefficient: 59 */ + CONVERT_COEFF(25014862), /* Filter:1, Coefficient: 60 */ + + /* Filter #16, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(1034412), /* Filter:4, Coefficient: 61 */ + CONVERT_COEFF(852013), /* Filter:4, Coefficient: 62 */ + CONVERT_COEFF(377238), /* Filter:4, Coefficient: 63 */ + CONVERT_COEFF(-159449), /* Filter:4, Coefficient: 64 */ + CONVERT_COEFF(-3138072), /* Filter:3, Coefficient: 61 */ + CONVERT_COEFF(63987), /* Filter:3, Coefficient: 62 */ + CONVERT_COEFF(2647613), /* Filter:3, Coefficient: 63 */ + CONVERT_COEFF(3737272), /* Filter:3, Coefficient: 64 */ + CONVERT_COEFF(-10266950), /* Filter:2, Coefficient: 61 */ + CONVERT_COEFF(-13455602), /* Filter:2, Coefficient: 62 */ + CONVERT_COEFF(-10821182), /* Filter:2, Coefficient: 63 */ + CONVERT_COEFF(-4453036), /* Filter:2, Coefficient: 64 */ + CONVERT_COEFF(18775762), /* Filter:1, Coefficient: 61 */ + CONVERT_COEFF(6405039), /* Filter:1, Coefficient: 62 */ + CONVERT_COEFF(-6134454), /* Filter:1, Coefficient: 63 */ + CONVERT_COEFF(-13930540), /* Filter:1, Coefficient: 64 */ + + /* Filter #17, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(-540437), /* Filter:4, Coefficient: 65 */ + CONVERT_COEFF(-643355), /* Filter:4, Coefficient: 66 */ + CONVERT_COEFF(-474537), /* Filter:4, Coefficient: 67 */ + CONVERT_COEFF(-146712), /* Filter:4, Coefficient: 68 */ + CONVERT_COEFF(3175158), /* Filter:3, Coefficient: 65 */ + CONVERT_COEFF(1467919), /* Filter:3, Coefficient: 66 */ + CONVERT_COEFF(-516205), /* Filter:3, Coefficient: 67 */ + CONVERT_COEFF(-1946005), /* Filter:3, Coefficient: 68 */ + CONVERT_COEFF(2499446), /* Filter:2, Coefficient: 65 */ + CONVERT_COEFF(7214349), /* Filter:2, Coefficient: 66 */ + CONVERT_COEFF(8236197), /* Filter:2, Coefficient: 67 */ + CONVERT_COEFF(5814958), /* Filter:2, Coefficient: 68 */ + CONVERT_COEFF(-14805492), /* Filter:1, Coefficient: 65 */ + CONVERT_COEFF(-9671153), /* Filter:1, Coefficient: 66 */ + CONVERT_COEFF(-1632211), /* Filter:1, Coefficient: 67 */ + CONVERT_COEFF(5613145), /* Filter:1, Coefficient: 68 */ + + /* Filter #18, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(182504), /* Filter:4, Coefficient: 69 */ + CONVERT_COEFF(380962), /* Filter:4, Coefficient: 70 */ + CONVERT_COEFF(391293), /* Filter:4, Coefficient: 71 */ + CONVERT_COEFF(242079), /* Filter:4, Coefficient: 72 */ + CONVERT_COEFF(-2350019), /* Filter:3, Coefficient: 69 */ + CONVERT_COEFF(-1745607), /* Filter:3, Coefficient: 70 */ + CONVERT_COEFF(-551374), /* Filter:3, Coefficient: 71 */ + CONVERT_COEFF(648570), /* Filter:3, Coefficient: 72 */ + CONVERT_COEFF(1519255), /* Filter:2, Coefficient: 69 */ + CONVERT_COEFF(-2610059), /* Filter:2, Coefficient: 70 */ + CONVERT_COEFF(-4955468), /* Filter:2, Coefficient: 71 */ + CONVERT_COEFF(-4899346), /* Filter:2, Coefficient: 72 */ + CONVERT_COEFF(9335222), /* Filter:1, Coefficient: 69 */ + CONVERT_COEFF(8686809), /* Filter:1, Coefficient: 70 */ + CONVERT_COEFF(4712022), /* Filter:1, Coefficient: 71 */ + CONVERT_COEFF(-403519), /* Filter:1, Coefficient: 72 */ + + /* Filter #19, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(22015), /* Filter:4, Coefficient: 73 */ + CONVERT_COEFF(-166585), /* Filter:4, Coefficient: 74 */ + CONVERT_COEFF(-252342), /* Filter:4, Coefficient: 75 */ + CONVERT_COEFF(-219066), /* Filter:4, Coefficient: 76 */ + CONVERT_COEFF(1369416), /* Filter:3, Coefficient: 73 */ + CONVERT_COEFF(1406290), /* Filter:3, Coefficient: 74 */ + CONVERT_COEFF(869654), /* Filter:3, Coefficient: 75 */ + CONVERT_COEFF(84471), /* Filter:3, Coefficient: 76 */ + CONVERT_COEFF(-2899640), /* Filter:2, Coefficient: 73 */ + CONVERT_COEFF(-115895), /* Filter:2, Coefficient: 74 */ + CONVERT_COEFF(2186507), /* Filter:2, Coefficient: 75 */ + CONVERT_COEFF(3171366), /* Filter:2, Coefficient: 76 */ + CONVERT_COEFF(-4412139), /* Filter:1, Coefficient: 73 */ + CONVERT_COEFF(-5920243), /* Filter:1, Coefficient: 74 */ + CONVERT_COEFF(-4796349), /* Filter:1, Coefficient: 75 */ + CONVERT_COEFF(-1992494), /* Filter:1, Coefficient: 76 */ + + /* Filter #20, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(-102810), /* Filter:4, Coefficient: 77 */ + CONVERT_COEFF(32566), /* Filter:4, Coefficient: 78 */ + CONVERT_COEFF(127289), /* Filter:4, Coefficient: 79 */ + CONVERT_COEFF(150143), /* Filter:4, Coefficient: 80 */ + CONVERT_COEFF(-582238), /* Filter:3, Coefficient: 77 */ + CONVERT_COEFF(-881098), /* Filter:3, Coefficient: 78 */ + CONVERT_COEFF(-762309), /* Filter:3, Coefficient: 79 */ + CONVERT_COEFF(-358757), /* Filter:3, Coefficient: 80 */ + CONVERT_COEFF(2695169), /* Filter:2, Coefficient: 77 */ + CONVERT_COEFF(1237005), /* Filter:2, Coefficient: 78 */ + CONVERT_COEFF(-416702), /* Filter:2, Coefficient: 79 */ + CONVERT_COEFF(-1556295), /* Filter:2, Coefficient: 80 */ + CONVERT_COEFF(1044258), /* Filter:1, Coefficient: 77 */ + CONVERT_COEFF(3054325), /* Filter:1, Coefficient: 78 */ + CONVERT_COEFF(3442737), /* Filter:1, Coefficient: 79 */ + CONVERT_COEFF(2390972), /* Filter:1, Coefficient: 80 */ + + /* Filter #21, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(106283), /* Filter:4, Coefficient: 81 */ + CONVERT_COEFF(27996), /* Filter:4, Coefficient: 82 */ + CONVERT_COEFF(-44477), /* Filter:4, Coefficient: 83 */ + CONVERT_COEFF(-81857), /* Filter:4, Coefficient: 84 */ + CONVERT_COEFF(104868), /* Filter:3, Coefficient: 81 */ + CONVERT_COEFF(424671), /* Filter:3, Coefficient: 82 */ + CONVERT_COEFF(499517), /* Filter:3, Coefficient: 83 */ + CONVERT_COEFF(352818), /* Filter:3, Coefficient: 84 */ + CONVERT_COEFF(-1827601), /* Filter:2, Coefficient: 81 */ + CONVERT_COEFF(-1307300), /* Filter:2, Coefficient: 82 */ + CONVERT_COEFF(-381962), /* Filter:2, Coefficient: 83 */ + CONVERT_COEFF(479247), /* Filter:2, Coefficient: 84 */ + CONVERT_COEFF(626053), /* Filter:1, Coefficient: 81 */ + CONVERT_COEFF(-990379), /* Filter:1, Coefficient: 82 */ + CONVERT_COEFF(-1844980), /* Filter:1, Coefficient: 83 */ + CONVERT_COEFF(-1771871), /* Filter:1, Coefficient: 84 */ + + /* Filter #22, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(-76222), /* Filter:4, Coefficient: 85 */ + CONVERT_COEFF(-39943), /* Filter:4, Coefficient: 86 */ + CONVERT_COEFF(4124), /* Filter:4, Coefficient: 87 */ + CONVERT_COEFF(35042), /* Filter:4, Coefficient: 88 */ + CONVERT_COEFF(96315), /* Filter:3, Coefficient: 85 */ + CONVERT_COEFF(-136873), /* Filter:3, Coefficient: 86 */ + CONVERT_COEFF(-254389), /* Filter:3, Coefficient: 87 */ + CONVERT_COEFF(-235483), /* Filter:3, Coefficient: 88 */ + CONVERT_COEFF(939561), /* Filter:2, Coefficient: 85 */ + CONVERT_COEFF(907226), /* Filter:2, Coefficient: 86 */ + CONVERT_COEFF(518385), /* Filter:2, Coefficient: 87 */ + CONVERT_COEFF(25446), /* Filter:2, Coefficient: 88 */ + CONVERT_COEFF(-1021645), /* Filter:1, Coefficient: 85 */ + CONVERT_COEFF(-61990), /* Filter:1, Coefficient: 86 */ + CONVERT_COEFF(668408), /* Filter:1, Coefficient: 87 */ + CONVERT_COEFF(936512), /* Filter:1, Coefficient: 88 */ + + /* Filter #23, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(42668), /* Filter:4, Coefficient: 89 */ + CONVERT_COEFF(29706), /* Filter:4, Coefficient: 90 */ + CONVERT_COEFF(7441), /* Filter:4, Coefficient: 91 */ + CONVERT_COEFF(-11516), /* Filter:4, Coefficient: 92 */ + CONVERT_COEFF(-123440), /* Filter:3, Coefficient: 89 */ + CONVERT_COEFF(8781), /* Filter:3, Coefficient: 90 */ + CONVERT_COEFF(98290), /* Filter:3, Coefficient: 91 */ + CONVERT_COEFF(118044), /* Filter:3, Coefficient: 92 */ + CONVERT_COEFF(-339383), /* Filter:2, Coefficient: 89 */ + CONVERT_COEFF(-459507), /* Filter:2, Coefficient: 90 */ + CONVERT_COEFF(-355164), /* Filter:2, Coefficient: 91 */ + CONVERT_COEFF(-138328), /* Filter:2, Coefficient: 92 */ + CONVERT_COEFF(761504), /* Filter:1, Coefficient: 89 */ + CONVERT_COEFF(341342), /* Filter:1, Coefficient: 90 */ + CONVERT_COEFF(-79676), /* Filter:1, Coefficient: 91 */ + CONVERT_COEFF(-329103), /* Filter:1, Coefficient: 92 */ + + /* Filter #24, conversion from 48000 Hz to 12000 Hz */ + + CONVERT_COEFF(-19411), /* Filter:4, Coefficient: 93 */ + CONVERT_COEFF(-15780), /* Filter:4, Coefficient: 94 */ + CONVERT_COEFF(-5811), /* Filter:4, Coefficient: 95 */ + CONVERT_COEFF(758261), /* Filter:4, Coefficient: 96 */ + CONVERT_COEFF(79948), /* Filter:3, Coefficient: 93 */ + CONVERT_COEFF(19085), /* Filter:3, Coefficient: 94 */ + CONVERT_COEFF(-29023), /* Filter:3, Coefficient: 95 */ + CONVERT_COEFF(-1187553), /* Filter:3, Coefficient: 96 */ + CONVERT_COEFF(62290), /* Filter:2, Coefficient: 93 */ + CONVERT_COEFF(164272), /* Filter:2, Coefficient: 94 */ + CONVERT_COEFF(156134), /* Filter:2, Coefficient: 95 */ + CONVERT_COEFF(378483), /* Filter:2, Coefficient: 96 */ + CONVERT_COEFF(-360897), /* Filter:1, Coefficient: 93 */ + CONVERT_COEFF(-238066), /* Filter:1, Coefficient: 94 */ + CONVERT_COEFF(-70489), /* Filter:1, Coefficient: 95 */ + CONVERT_COEFF(50810), /* Filter:1, Coefficient: 96 */ +}; diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_16000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_16000Hz.h new file mode 100644 index 000000000000..7f972f251991 --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_16000Hz.h @@ -0,0 +1,562 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 48000 Hz to 16000 Hz */ +/* NUM_FILTERS=5, FILTER_LENGTH=96, alpha=5.700000, gamma=0.443000 */ + +__cold_rodata static const int32_t coeff48000to16000[] = { + + /* Filter #1, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(6003), /* Filter:5, Coefficient: 1 */ + CONVERT_COEFF(-2286), /* Filter:5, Coefficient: 2 */ + CONVERT_COEFF(-11917), /* Filter:5, Coefficient: 3 */ + CONVERT_COEFF(-12263), /* Filter:5, Coefficient: 4 */ + CONVERT_COEFF(16701), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(40694), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(27405), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(-25736), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(-56844), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(26944), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(132074), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(141901), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(-147894), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(-187545), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(-21075), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(277248), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(14698), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(-167333), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(-289523), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(-163034), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(1010), /* Filter:5, Coefficient: 5 */ + CONVERT_COEFF(18750), /* Filter:5, Coefficient: 6 */ + CONVERT_COEFF(23487), /* Filter:5, Coefficient: 7 */ + CONVERT_COEFF(5356), /* Filter:5, Coefficient: 8 */ + CONVERT_COEFF(-75665), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(-64460), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(21621), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(120266), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(-5491), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(-220739), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(-298783), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(-96954), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(434836), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(201545), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(-357476), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(-796006), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(218113), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(572796), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(507886), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(-103264), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-24865), /* Filter:5, Coefficient: 9 */ + CONVERT_COEFF(-40246), /* Filter:5, Coefficient: 10 */ + CONVERT_COEFF(-20333), /* Filter:5, Coefficient: 11 */ + CONVERT_COEFF(26070), /* Filter:5, Coefficient: 12 */ + CONVERT_COEFF(132288), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(13456), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(-160847), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(-233861), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(286982), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(528042), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(330026), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(-261850), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(-608575), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(261248), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(1195810), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(1292859), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(-870589), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(-1084744), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(-322241), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(1022402), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(61074), /* Filter:5, Coefficient: 13 */ + CONVERT_COEFF(47049), /* Filter:5, Coefficient: 14 */ + CONVERT_COEFF(-16265), /* Filter:5, Coefficient: 15 */ + CONVERT_COEFF(-81433), /* Filter:5, Coefficient: 16 */ + CONVERT_COEFF(-100488), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(171929), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(359676), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(257462), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(-794371), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(-728986), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(53574), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(1014174), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(174255), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(-1469546), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(-2223834), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(-1105863), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(1845595), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(1186048), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(-793496), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(-2620309), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-86732), /* Filter:5, Coefficient: 17 */ + CONVERT_COEFF(-11725), /* Filter:5, Coefficient: 18 */ + CONVERT_COEFF(93077), /* Filter:5, Coefficient: 19 */ + CONVERT_COEFF(136905), /* Filter:5, Coefficient: 20 */ + CONVERT_COEFF(-117314), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(-482097), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(-490512), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(-44622), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(1290134), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(433539), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(-1052827), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(-1945766), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(1365285), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(3245541), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(2622791), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(-576159), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(-2535935), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(-84562), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(3100653), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(4273125), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(64518), /* Filter:5, Coefficient: 21 */ + CONVERT_COEFF(-84123), /* Filter:5, Coefficient: 22 */ + CONVERT_COEFF(-189618), /* Filter:5, Coefficient: 23 */ + CONVERT_COEFF(-145818), /* Filter:5, Coefficient: 24 */ + CONVERT_COEFF(552271), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(783867), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(351343), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(-501169), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(-1269113), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(735909), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(2545279), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(2459933), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(-4050257), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(-4676104), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(-1197064), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(4181701), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(1843458), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(-2859084), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(-6099452), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(-4589449), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(40024), /* Filter:5, Coefficient: 25 */ + CONVERT_COEFF(229992), /* Filter:5, Coefficient: 26 */ + CONVERT_COEFF(253530), /* Filter:5, Coefficient: 27 */ + CONVERT_COEFF(54594), /* Filter:5, Coefficient: 28 */ + CONVERT_COEFF(-1090434), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(-823146), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(245247), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(1324309), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(124819), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(-2847668), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(-3912612), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(-1694303), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(7014764), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(4162168), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(-3070757), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(-9141382), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(1405180), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(7494249), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(8215482), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(1730865), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-235096), /* Filter:5, Coefficient: 29 */ + CONVERT_COEFF(-376320), /* Filter:5, Coefficient: 30 */ + CONVERT_COEFF(-213387), /* Filter:5, Coefficient: 31 */ + CONVERT_COEFF(172458), /* Filter:5, Coefficient: 32 */ + CONVERT_COEFF(1448025), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(304353), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(-1354202), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(-2164152), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(2525824), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(5399928), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(4073459), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(-1173325), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(-8346879), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(91892), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(10287607), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(13522720), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(-7725810), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(-12333767), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(-6913819), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(5879577), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(488565), /* Filter:5, Coefficient: 33 */ + CONVERT_COEFF(444779), /* Filter:5, Coefficient: 34 */ + CONVERT_COEFF(3934), /* Filter:5, Coefficient: 35 */ + CONVERT_COEFF(-538903), /* Filter:5, Coefficient: 36 */ + CONVERT_COEFF(-1231572), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(991042), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(2832294), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(2605690), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(-6524989), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(-7262601), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(-1715100), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(6645311), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(5393659), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(-9375299), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(-19144348), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(-14082933), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(16237057), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(14362523), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(-839543), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(-18862506), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-743652), /* Filter:5, Coefficient: 37 */ + CONVERT_COEFF(-364983), /* Filter:5, Coefficient: 38 */ + CONVERT_COEFF(412423), /* Filter:5, Coefficient: 39 */ + CONVERT_COEFF(1049680), /* Filter:5, Coefficient: 40 */ + CONVERT_COEFF(51807), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(-3160575), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(-4453939), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(-2290054), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(11124179), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(6869327), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(-4598379), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(-15255006), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(4836350), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(24247448), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(27060755), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(6196430), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(-24233009), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(-8964202), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(18626760), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(37047113), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(1021779), /* Filter:5, Coefficient: 41 */ + CONVERT_COEFF(223192), /* Filter:5, Coefficient: 42 */ + CONVERT_COEFF(-900926), /* Filter:5, Coefficient: 43 */ + CONVERT_COEFF(-1626034), /* Filter:5, Coefficient: 44 */ + CONVERT_COEFF(2394425), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(6494128), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(6785094), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(2350160), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(-15741799), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(-2587077), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(17884441), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(32479337), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(-26945239), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(-47161583), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(-32017732), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(20427044), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(26747798), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(-12522864), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(-55553443), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(-63801692), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-1450725), /* Filter:5, Coefficient: 45 */ + CONVERT_COEFF(-470498), /* Filter:5, Coefficient: 46 */ + CONVERT_COEFF(661749), /* Filter:5, Coefficient: 47 */ + CONVERT_COEFF(1177778), /* Filter:5, Coefficient: 48 */ + CONVERT_COEFF(-4430794), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(-9217671), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(-8589764), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(-2482951), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(29620390), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(7771362), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(-22319484), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(-43669888), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(85909205), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(126153193), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(112402280), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(44979247), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(-10171046), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(99475669), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(223708992), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(305859586), /* Filter:1, Coefficient: 48 */ + + /* Filter #13, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(729289), /* Filter:5, Coefficient: 49 */ + CONVERT_COEFF(-368490), /* Filter:5, Coefficient: 50 */ + CONVERT_COEFF(-1360978), /* Filter:5, Coefficient: 51 */ + CONVERT_COEFF(-1582611), /* Filter:5, Coefficient: 52 */ + CONVERT_COEFF(5588041), /* Filter:4, Coefficient: 49 */ + CONVERT_COEFF(10764075), /* Filter:4, Coefficient: 50 */ + CONVERT_COEFF(10021818), /* Filter:4, Coefficient: 51 */ + CONVERT_COEFF(4102867), /* Filter:4, Coefficient: 52 */ + CONVERT_COEFF(-43706637), /* Filter:3, Coefficient: 49 */ + CONVERT_COEFF(-22383172), /* Filter:3, Coefficient: 50 */ + CONVERT_COEFF(7781413), /* Filter:3, Coefficient: 51 */ + CONVERT_COEFF(29772819), /* Filter:3, Coefficient: 52 */ + CONVERT_COEFF(-44758225), /* Filter:2, Coefficient: 49 */ + CONVERT_COEFF(-112244374), /* Filter:2, Coefficient: 50 */ + CONVERT_COEFF(-126089107), /* Filter:2, Coefficient: 51 */ + CONVERT_COEFF(-85924595), /* Filter:2, Coefficient: 52 */ + CONVERT_COEFF(305859586), /* Filter:1, Coefficient: 49 */ + CONVERT_COEFF(223708992), /* Filter:1, Coefficient: 50 */ + CONVERT_COEFF(99475669), /* Filter:1, Coefficient: 51 */ + CONVERT_COEFF(-10171046), /* Filter:1, Coefficient: 52 */ + + /* Filter #14, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-908464), /* Filter:5, Coefficient: 53 */ + CONVERT_COEFF(187247), /* Filter:5, Coefficient: 54 */ + CONVERT_COEFF(989311), /* Filter:5, Coefficient: 55 */ + CONVERT_COEFF(1041404), /* Filter:5, Coefficient: 56 */ + CONVERT_COEFF(-3113458), /* Filter:4, Coefficient: 53 */ + CONVERT_COEFF(-7286202), /* Filter:4, Coefficient: 54 */ + CONVERT_COEFF(-6424181), /* Filter:4, Coefficient: 55 */ + CONVERT_COEFF(-1920843), /* Filter:4, Coefficient: 56 */ + CONVERT_COEFF(32745687), /* Filter:3, Coefficient: 53 */ + CONVERT_COEFF(18147500), /* Filter:3, Coefficient: 54 */ + CONVERT_COEFF(-2455994), /* Filter:3, Coefficient: 55 */ + CONVERT_COEFF(-15794058), /* Filter:3, Coefficient: 56 */ + CONVERT_COEFF(-20476276), /* Filter:2, Coefficient: 53 */ + CONVERT_COEFF(31981862), /* Filter:2, Coefficient: 54 */ + CONVERT_COEFF(47161892), /* Filter:2, Coefficient: 55 */ + CONVERT_COEFF(26973318), /* Filter:2, Coefficient: 56 */ + CONVERT_COEFF(-63801692), /* Filter:1, Coefficient: 53 */ + CONVERT_COEFF(-55553443), /* Filter:1, Coefficient: 54 */ + CONVERT_COEFF(-12522864), /* Filter:1, Coefficient: 55 */ + CONVERT_COEFF(26747798), /* Filter:1, Coefficient: 56 */ + + /* Filter #15, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(427927), /* Filter:5, Coefficient: 57 */ + CONVERT_COEFF(-342034), /* Filter:5, Coefficient: 58 */ + CONVERT_COEFF(-731079), /* Filter:5, Coefficient: 59 */ + CONVERT_COEFF(-543506), /* Filter:5, Coefficient: 60 */ + CONVERT_COEFF(2748904), /* Filter:4, Coefficient: 57 */ + CONVERT_COEFF(4570973), /* Filter:4, Coefficient: 58 */ + CONVERT_COEFF(2912804), /* Filter:4, Coefficient: 59 */ + CONVERT_COEFF(-421780), /* Filter:4, Coefficient: 60 */ + CONVERT_COEFF(-15430280), /* Filter:3, Coefficient: 57 */ + CONVERT_COEFF(-4768911), /* Filter:3, Coefficient: 58 */ + CONVERT_COEFF(6810261), /* Filter:3, Coefficient: 59 */ + CONVERT_COEFF(11194720), /* Filter:3, Coefficient: 60 */ + CONVERT_COEFF(-6166649), /* Filter:2, Coefficient: 57 */ + CONVERT_COEFF(-27051114), /* Filter:2, Coefficient: 58 */ + CONVERT_COEFF(-24261125), /* Filter:2, Coefficient: 59 */ + CONVERT_COEFF(-4859188), /* Filter:2, Coefficient: 60 */ + CONVERT_COEFF(37047113), /* Filter:1, Coefficient: 57 */ + CONVERT_COEFF(18626760), /* Filter:1, Coefficient: 58 */ + CONVERT_COEFF(-8964202), /* Filter:1, Coefficient: 59 */ + CONVERT_COEFF(-24233009), /* Filter:1, Coefficient: 60 */ + + /* Filter #16, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-11110), /* Filter:5, Coefficient: 61 */ + CONVERT_COEFF(432181), /* Filter:5, Coefficient: 62 */ + CONVERT_COEFF(487097), /* Filter:5, Coefficient: 63 */ + CONVERT_COEFF(181137), /* Filter:5, Coefficient: 64 */ + CONVERT_COEFF(-2809542), /* Filter:4, Coefficient: 61 */ + CONVERT_COEFF(-2751305), /* Filter:4, Coefficient: 62 */ + CONVERT_COEFF(-733429), /* Filter:4, Coefficient: 63 */ + CONVERT_COEFF(1447308), /* Filter:4, Coefficient: 64 */ + CONVERT_COEFF(6774473), /* Filter:3, Coefficient: 61 */ + CONVERT_COEFF(-1626617), /* Filter:3, Coefficient: 62 */ + CONVERT_COEFF(-7269584), /* Filter:3, Coefficient: 63 */ + CONVERT_COEFF(-6605985), /* Filter:3, Coefficient: 64 */ + CONVERT_COEFF(14069130), /* Filter:2, Coefficient: 61 */ + CONVERT_COEFF(19148004), /* Filter:2, Coefficient: 62 */ + CONVERT_COEFF(9390672), /* Filter:2, Coefficient: 63 */ + CONVERT_COEFF(-5379859), /* Filter:2, Coefficient: 64 */ + CONVERT_COEFF(-18862506), /* Filter:1, Coefficient: 61 */ + CONVERT_COEFF(-839543), /* Filter:1, Coefficient: 62 */ + CONVERT_COEFF(14362523), /* Filter:1, Coefficient: 63 */ + CONVERT_COEFF(16237057), /* Filter:1, Coefficient: 64 */ + + /* Filter #17, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-202750), /* Filter:5, Coefficient: 65 */ + CONVERT_COEFF(-371867), /* Filter:5, Coefficient: 66 */ + CONVERT_COEFF(-238987), /* Filter:5, Coefficient: 67 */ + CONVERT_COEFF(46710), /* Filter:5, Coefficient: 68 */ + CONVERT_COEFF(2187189), /* Filter:4, Coefficient: 65 */ + CONVERT_COEFF(1200707), /* Filter:4, Coefficient: 66 */ + CONVERT_COEFF(-491006), /* Filter:4, Coefficient: 67 */ + CONVERT_COEFF(-1524430), /* Filter:4, Coefficient: 68 */ + CONVERT_COEFF(-1257592), /* Filter:3, Coefficient: 65 */ + CONVERT_COEFF(4047456), /* Filter:3, Coefficient: 66 */ + CONVERT_COEFF(5441306), /* Filter:3, Coefficient: 67 */ + CONVERT_COEFF(2592862), /* Filter:3, Coefficient: 68 */ + CONVERT_COEFF(-13520338), /* Filter:2, Coefficient: 65 */ + CONVERT_COEFF(-10296413), /* Filter:2, Coefficient: 66 */ + CONVERT_COEFF(-103461), /* Filter:2, Coefficient: 67 */ + CONVERT_COEFF(8341557), /* Filter:2, Coefficient: 68 */ + CONVERT_COEFF(5879577), /* Filter:1, Coefficient: 65 */ + CONVERT_COEFF(-6913819), /* Filter:1, Coefficient: 66 */ + CONVERT_COEFF(-12333767), /* Filter:1, Coefficient: 67 */ + CONVERT_COEFF(-7725810), /* Filter:1, Coefficient: 68 */ + + /* Filter #18, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(248164), /* Filter:5, Coefficient: 69 */ + CONVERT_COEFF(230638), /* Filter:5, Coefficient: 70 */ + CONVERT_COEFF(45115), /* Filter:5, Coefficient: 71 */ + CONVERT_COEFF(-140841), /* Filter:5, Coefficient: 72 */ + CONVERT_COEFF(-1253197), /* Filter:4, Coefficient: 69 */ + CONVERT_COEFF(-105103), /* Filter:4, Coefficient: 70 */ + CONVERT_COEFF(916311), /* Filter:4, Coefficient: 71 */ + CONVERT_COEFF(1076028), /* Filter:4, Coefficient: 72 */ + CONVERT_COEFF(-1655380), /* Filter:3, Coefficient: 69 */ + CONVERT_COEFF(-3925882), /* Filter:3, Coefficient: 70 */ + CONVERT_COEFF(-2894376), /* Filter:3, Coefficient: 71 */ + CONVERT_COEFF(85264), /* Filter:3, Coefficient: 72 */ + CONVERT_COEFF(9145142), /* Filter:2, Coefficient: 69 */ + CONVERT_COEFF(3079217), /* Filter:2, Coefficient: 70 */ + CONVERT_COEFF(-4156100), /* Filter:2, Coefficient: 71 */ + CONVERT_COEFF(-7015142), /* Filter:2, Coefficient: 72 */ + CONVERT_COEFF(1730865), /* Filter:1, Coefficient: 69 */ + CONVERT_COEFF(8215482), /* Filter:1, Coefficient: 70 */ + CONVERT_COEFF(7494249), /* Filter:1, Coefficient: 71 */ + CONVERT_COEFF(1405180), /* Filter:1, Coefficient: 72 */ + + /* Filter #19, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-188394), /* Filter:5, Coefficient: 73 */ + CONVERT_COEFF(-86846), /* Filter:5, Coefficient: 74 */ + CONVERT_COEFF(60603), /* Filter:5, Coefficient: 75 */ + CONVERT_COEFF(134904), /* Filter:5, Coefficient: 76 */ + CONVERT_COEFF(409479), /* Filter:4, Coefficient: 73 */ + CONVERT_COEFF(-438001), /* Filter:4, Coefficient: 74 */ + CONVERT_COEFF(-802163), /* Filter:4, Coefficient: 75 */ + CONVERT_COEFF(-501779), /* Filter:4, Coefficient: 76 */ + CONVERT_COEFF(2455894), /* Filter:3, Coefficient: 73 */ + CONVERT_COEFF(2573565), /* Filter:3, Coefficient: 74 */ + CONVERT_COEFF(769517), /* Filter:3, Coefficient: 75 */ + CONVERT_COEFF(-1256461), /* Filter:3, Coefficient: 76 */ + CONVERT_COEFF(-4187065), /* Filter:2, Coefficient: 73 */ + CONVERT_COEFF(1191611), /* Filter:2, Coefficient: 74 */ + CONVERT_COEFF(4674610), /* Filter:2, Coefficient: 75 */ + CONVERT_COEFF(4053062), /* Filter:2, Coefficient: 76 */ + CONVERT_COEFF(-4589449), /* Filter:1, Coefficient: 73 */ + CONVERT_COEFF(-6099452), /* Filter:1, Coefficient: 74 */ + CONVERT_COEFF(-2859084), /* Filter:1, Coefficient: 75 */ + CONVERT_COEFF(1843458), /* Filter:1, Coefficient: 76 */ + + /* Filter #20, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(94077), /* Filter:5, Coefficient: 77 */ + CONVERT_COEFF(-9066), /* Filter:5, Coefficient: 78 */ + CONVERT_COEFF(-84702), /* Filter:5, Coefficient: 79 */ + CONVERT_COEFF(-81382), /* Filter:5, Coefficient: 80 */ + CONVERT_COEFF(112941), /* Filter:4, Coefficient: 77 */ + CONVERT_COEFF(522408), /* Filter:4, Coefficient: 78 */ + CONVERT_COEFF(461411), /* Filter:4, Coefficient: 79 */ + CONVERT_COEFF(70472), /* Filter:4, Coefficient: 80 */ + CONVERT_COEFF(-1959787), /* Filter:3, Coefficient: 77 */ + CONVERT_COEFF(-1077960), /* Filter:3, Coefficient: 78 */ + CONVERT_COEFF(418428), /* Filter:3, Coefficient: 79 */ + CONVERT_COEFF(1294567), /* Filter:3, Coefficient: 80 */ + CONVERT_COEFF(580341), /* Filter:2, Coefficient: 77 */ + CONVERT_COEFF(-2620598), /* Filter:2, Coefficient: 78 */ + CONVERT_COEFF(-3246544), /* Filter:2, Coefficient: 79 */ + CONVERT_COEFF(-1368066), /* Filter:2, Coefficient: 80 */ + CONVERT_COEFF(4273125), /* Filter:1, Coefficient: 77 */ + CONVERT_COEFF(3100653), /* Filter:1, Coefficient: 78 */ + CONVERT_COEFF(-84562), /* Filter:1, Coefficient: 79 */ + CONVERT_COEFF(-2535935), /* Filter:1, Coefficient: 80 */ + + /* Filter #21, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-17797), /* Filter:5, Coefficient: 81 */ + CONVERT_COEFF(45404), /* Filter:5, Coefficient: 82 */ + CONVERT_COEFF(60538), /* Filter:5, Coefficient: 83 */ + CONVERT_COEFF(26766), /* Filter:5, Coefficient: 84 */ + CONVERT_COEFF(-290075), /* Filter:4, Coefficient: 81 */ + CONVERT_COEFF(-357062), /* Filter:4, Coefficient: 82 */ + CONVERT_COEFF(-144107), /* Filter:4, Coefficient: 83 */ + CONVERT_COEFF(126933), /* Filter:4, Coefficient: 84 */ + CONVERT_COEFF(1030932), /* Filter:3, Coefficient: 81 */ + CONVERT_COEFF(67431), /* Filter:3, Coefficient: 82 */ + CONVERT_COEFF(-727987), /* Filter:3, Coefficient: 83 */ + CONVERT_COEFF(-804281), /* Filter:3, Coefficient: 84 */ + CONVERT_COEFF(1103742), /* Filter:2, Coefficient: 81 */ + CONVERT_COEFF(2223786), /* Filter:2, Coefficient: 82 */ + CONVERT_COEFF(1471128), /* Filter:2, Coefficient: 83 */ + CONVERT_COEFF(-172596), /* Filter:2, Coefficient: 84 */ + CONVERT_COEFF(-2620309), /* Filter:1, Coefficient: 81 */ + CONVERT_COEFF(-793496), /* Filter:1, Coefficient: 82 */ + CONVERT_COEFF(1186048), /* Filter:1, Coefficient: 83 */ + CONVERT_COEFF(1845595), /* Filter:1, Coefficient: 84 */ + + /* Filter #22, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-19212), /* Filter:5, Coefficient: 85 */ + CONVERT_COEFF(-39619), /* Filter:5, Coefficient: 86 */ + CONVERT_COEFF(-25052), /* Filter:5, Coefficient: 87 */ + CONVERT_COEFF(4714), /* Filter:5, Coefficient: 88 */ + CONVERT_COEFF(239663), /* Filter:4, Coefficient: 85 */ + CONVERT_COEFF(146928), /* Filter:4, Coefficient: 86 */ + CONVERT_COEFF(-31586), /* Filter:4, Coefficient: 87 */ + CONVERT_COEFF(-139998), /* Filter:4, Coefficient: 88 */ + CONVERT_COEFF(-272737), /* Filter:3, Coefficient: 85 */ + CONVERT_COEFF(326716), /* Filter:3, Coefficient: 86 */ + CONVERT_COEFF(533127), /* Filter:3, Coefficient: 87 */ + CONVERT_COEFF(294587), /* Filter:3, Coefficient: 88 */ + CONVERT_COEFF(-1292361), /* Filter:2, Coefficient: 85 */ + CONVERT_COEFF(-1196542), /* Filter:2, Coefficient: 86 */ + CONVERT_COEFF(-262345), /* Filter:2, Coefficient: 87 */ + CONVERT_COEFF(608020), /* Filter:2, Coefficient: 88 */ + CONVERT_COEFF(1022402), /* Filter:1, Coefficient: 85 */ + CONVERT_COEFF(-322241), /* Filter:1, Coefficient: 86 */ + CONVERT_COEFF(-1084744), /* Filter:1, Coefficient: 87 */ + CONVERT_COEFF(-870589), /* Filter:1, Coefficient: 88 */ + + /* Filter #23, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(22982), /* Filter:5, Coefficient: 89 */ + CONVERT_COEFF(18703), /* Filter:5, Coefficient: 90 */ + CONVERT_COEFF(1310), /* Filter:5, Coefficient: 91 */ + CONVERT_COEFF(-11946), /* Filter:5, Coefficient: 92 */ + CONVERT_COEFF(-114763), /* Filter:4, Coefficient: 89 */ + CONVERT_COEFF(-10932), /* Filter:4, Coefficient: 90 */ + CONVERT_COEFF(70685), /* Filter:4, Coefficient: 91 */ + CONVERT_COEFF(74147), /* Filter:4, Coefficient: 92 */ + CONVERT_COEFF(-93308), /* Filter:3, Coefficient: 89 */ + CONVERT_COEFF(-300945), /* Filter:3, Coefficient: 90 */ + CONVERT_COEFF(-225549), /* Filter:3, Coefficient: 91 */ + CONVERT_COEFF(-8488), /* Filter:3, Coefficient: 92 */ + CONVERT_COEFF(796245), /* Filter:2, Coefficient: 89 */ + CONVERT_COEFF(358093), /* Filter:2, Coefficient: 90 */ + CONVERT_COEFF(-201126), /* Filter:2, Coefficient: 91 */ + CONVERT_COEFF(-434862), /* Filter:2, Coefficient: 92 */ + CONVERT_COEFF(-103264), /* Filter:1, Coefficient: 89 */ + CONVERT_COEFF(507886), /* Filter:1, Coefficient: 90 */ + CONVERT_COEFF(572796), /* Filter:1, Coefficient: 91 */ + CONVERT_COEFF(218113), /* Filter:1, Coefficient: 92 */ + + /* Filter #24, conversion from 48000 Hz to 16000 Hz */ + + CONVERT_COEFF(-11816), /* Filter:5, Coefficient: 93 */ + CONVERT_COEFF(-2391), /* Filter:5, Coefficient: 94 */ + CONVERT_COEFF(5852), /* Filter:5, Coefficient: 95 */ + CONVERT_COEFF(2789237), /* Filter:5, Coefficient: 96 */ + CONVERT_COEFF(20271), /* Filter:4, Coefficient: 93 */ + CONVERT_COEFF(-31141), /* Filter:4, Coefficient: 94 */ + CONVERT_COEFF(-40353), /* Filter:4, Coefficient: 95 */ + CONVERT_COEFF(-5145454), /* Filter:4, Coefficient: 96 */ + CONVERT_COEFF(142594), /* Filter:3, Coefficient: 93 */ + CONVERT_COEFF(134883), /* Filter:3, Coefficient: 94 */ + CONVERT_COEFF(29007), /* Filter:3, Coefficient: 95 */ + CONVERT_COEFF(2574030), /* Filter:3, Coefficient: 96 */ + CONVERT_COEFF(-277542), /* Filter:2, Coefficient: 93 */ + CONVERT_COEFF(20836), /* Filter:2, Coefficient: 94 */ + CONVERT_COEFF(187526), /* Filter:2, Coefficient: 95 */ + CONVERT_COEFF(-232512), /* Filter:2, Coefficient: 96 */ + CONVERT_COEFF(-163034), /* Filter:1, Coefficient: 93 */ + CONVERT_COEFF(-289523), /* Filter:1, Coefficient: 94 */ + CONVERT_COEFF(-167333), /* Filter:1, Coefficient: 95 */ + CONVERT_COEFF(14698), /* Filter:1, Coefficient: 96 */ +}; diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_22050Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_22050Hz.h new file mode 100644 index 000000000000..a367a5aaeb12 --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_22050Hz.h @@ -0,0 +1,470 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 48000 Hz to 22050 Hz */ +/* NUM_FILTERS=5, FILTER_LENGTH=80, alpha=6.900000, gamma=0.440000 */ + +__cold_rodata static const int32_t coeff48000to22050[] = { + + /* Filter #1, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(7662), /* Filter:5, Coefficient: 1 */ + CONVERT_COEFF(-17184), /* Filter:5, Coefficient: 2 */ + CONVERT_COEFF(-22717), /* Filter:5, Coefficient: 3 */ + CONVERT_COEFF(18493), /* Filter:5, Coefficient: 4 */ + CONVERT_COEFF(26582), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(59229), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(-23847), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(-124610), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(-47392), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(71132), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(144232), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(-51617), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(-97554), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(-81873), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(168609), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(294217), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(-7478), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(-118181), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(-86878), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(179401), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(50021), /* Filter:5, Coefficient: 5 */ + CONVERT_COEFF(-716), /* Filter:5, Coefficient: 6 */ + CONVERT_COEFF(-81566), /* Filter:5, Coefficient: 7 */ + CONVERT_COEFF(-50232), /* Filter:5, Coefficient: 8 */ + CONVERT_COEFF(-31457), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(195123), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(176350), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(-200655), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(-305430), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(-114428), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(443237), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(491935), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(-107851), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(-611698), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(-258982), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(827677), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(315885), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(-78832), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(-610555), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(-331518), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(93705), /* Filter:5, Coefficient: 9 */ + CONVERT_COEFF(135899), /* Filter:5, Coefficient: 10 */ + CONVERT_COEFF(-50936), /* Filter:5, Coefficient: 11 */ + CONVERT_COEFF(-230545), /* Filter:5, Coefficient: 12 */ + CONVERT_COEFF(-407292), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(40422), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(637092), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(360246), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(-369778), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(-1017042), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(-134226), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(1419254), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(1008537), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(-574204), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(-1940858), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(-505832), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(737212), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(1062392), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(-352536), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(-1841477), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(-76801), /* Filter:5, Coefficient: 13 */ + CONVERT_COEFF(275249), /* Filter:5, Coefficient: 14 */ + CONVERT_COEFF(286242), /* Filter:5, Coefficient: 15 */ + CONVERT_COEFF(-192062), /* Filter:5, Coefficient: 16 */ + CONVERT_COEFF(-683487), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(-963806), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(323515), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(1549537), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(1160591), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(-1248908), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(-2484661), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(65823), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(2484992), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(2450305), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(-1828062), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(-4678056), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(-798359), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(2086950), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(2599807), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(-1103167), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(-515072), /* Filter:5, Coefficient: 17 */ + CONVERT_COEFF(-77740), /* Filter:5, Coefficient: 18 */ + CONVERT_COEFF(637488), /* Filter:5, Coefficient: 19 */ + CONVERT_COEFF(520979), /* Filter:5, Coefficient: 20 */ + CONVERT_COEFF(579066), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(-1719643), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(-1913093), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(1028444), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(3467676), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(2238991), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(-3179440), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(-5124630), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(-677091), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(5922919), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(4937918), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(-4589554), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(-4357955), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(-1503387), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(4861173), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(5344084), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(-497338), /* Filter:5, Coefficient: 21 */ + CONVERT_COEFF(-1009488), /* Filter:5, Coefficient: 22 */ + CONVERT_COEFF(-19056), /* Filter:5, Coefficient: 23 */ + CONVERT_COEFF(1296890), /* Filter:5, Coefficient: 24 */ + CONVERT_COEFF(3210464), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(772866), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(-3684403), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(-3455526), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(793879), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(7290357), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(3834155), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(-6951870), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(-9665238), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(-459773), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(12380065), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(8936328), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(-2820697), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(-8978993), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(-2385048), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(10125784), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(889191), /* Filter:5, Coefficient: 25 */ + CONVERT_COEFF(-1077548), /* Filter:5, Coefficient: 26 */ + CONVERT_COEFF(-1876055), /* Filter:5, Coefficient: 27 */ + CONVERT_COEFF(109024), /* Filter:5, Coefficient: 28 */ + CONVERT_COEFF(2472912), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(6129880), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(938394), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(-7290689), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(-9648642), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(2539229), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(14225977), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(6351241), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(-10107211), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(-18425284), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(684847), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(24410695), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(9951675), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(-6442120), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(-17275963), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(-3302824), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(2503811), /* Filter:5, Coefficient: 29 */ + CONVERT_COEFF(1622255), /* Filter:5, Coefficient: 30 */ + CONVERT_COEFF(-2108058), /* Filter:5, Coefficient: 31 */ + CONVERT_COEFF(-3706384), /* Filter:5, Coefficient: 32 */ + CONVERT_COEFF(-6226493), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(5152980), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(11810681), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(1756465), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(-14169848), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(-18068824), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(6045860), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(28349964), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(15712903), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(-21218811), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(-35403029), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(3599978), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(20277588), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(18098088), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(-14414412), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(-34069195), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(-43231), /* Filter:5, Coefficient: 33 */ + CONVERT_COEFF(4988198), /* Filter:5, Coefficient: 34 */ + CONVERT_COEFF(4446245), /* Filter:5, Coefficient: 35 */ + CONVERT_COEFF(-2462458), /* Filter:5, Coefficient: 36 */ + CONVERT_COEFF(-14505985), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(-13737342), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(8767251), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(27475802), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(12429936), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(-29867986), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(-41267927), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(9703094), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(50670832), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(31896562), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(-48962542), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(-87373984), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(-4069199), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(44482662), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(37762356), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(-39254890), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(-8050820), /* Filter:5, Coefficient: 37 */ + CONVERT_COEFF(-4999058), /* Filter:5, Coefficient: 38 */ + CONVERT_COEFF(4105217), /* Filter:5, Coefficient: 39 */ + CONVERT_COEFF(9073725), /* Filter:5, Coefficient: 40 */ + CONVERT_COEFF(15338177), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(-19743794), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(-39156404), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(-18221320), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(75644534), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(74121388), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(-12477230), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(-103703844), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(4474816), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(169430567), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(238526201), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(112848617), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(-91913076), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(-4506400), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(214304195), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(405304801), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(4173646), /* Filter:5, Coefficient: 41 */ + CONVERT_COEFF(-4920958), /* Filter:5, Coefficient: 42 */ + CONVERT_COEFF(-8020196), /* Filter:5, Coefficient: 43 */ + CONVERT_COEFF(-2482049), /* Filter:5, Coefficient: 44 */ + CONVERT_COEFF(22486980), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(39548952), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(16825069), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(-17561438), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(-105059398), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(-14951358), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(73361822), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(77292504), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(-112603327), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(-238487201), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(-169572730), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(-4590557), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(405304801), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(214304195), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(-4506400), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(-91913076), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(4418383), /* Filter:5, Coefficient: 45 */ + CONVERT_COEFF(4986040), /* Filter:5, Coefficient: 46 */ + CONVERT_COEFF(-25488), /* Filter:5, Coefficient: 47 */ + CONVERT_COEFF(-3695594), /* Filter:5, Coefficient: 48 */ + CONVERT_COEFF(-26497283), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(-6227664), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(14635866), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(13055417), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(11676560), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(-41128822), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(-31313215), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(11383073), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(87419323), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(49090442), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(-31848996), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(-50742654), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(-39254890), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(37762356), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(44482662), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(-4069199), /* Filter:1, Coefficient: 48 */ + + /* Filter #13, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(-2115328), /* Filter:5, Coefficient: 49 */ + CONVERT_COEFF(1610445), /* Filter:5, Coefficient: 50 */ + CONVERT_COEFF(2503111), /* Filter:5, Coefficient: 51 */ + CONVERT_COEFF(117640), /* Filter:5, Coefficient: 52 */ + CONVERT_COEFF(-3354395), /* Filter:4, Coefficient: 49 */ + CONVERT_COEFF(-11619407), /* Filter:4, Coefficient: 50 */ + CONVERT_COEFF(-3795045), /* Filter:4, Coefficient: 51 */ + CONVERT_COEFF(6834164), /* Filter:4, Coefficient: 52 */ + CONVERT_COEFF(28805923), /* Filter:3, Coefficient: 49 */ + CONVERT_COEFF(7109971), /* Filter:3, Coefficient: 50 */ + CONVERT_COEFF(-17815824), /* Filter:3, Coefficient: 51 */ + CONVERT_COEFF(-14850789), /* Filter:3, Coefficient: 52 */ + CONVERT_COEFF(-3681316), /* Filter:2, Coefficient: 49 */ + CONVERT_COEFF(35411365), /* Filter:2, Coefficient: 50 */ + CONVERT_COEFF(21287118), /* Filter:2, Coefficient: 51 */ + CONVERT_COEFF(-15681405), /* Filter:2, Coefficient: 52 */ + CONVERT_COEFF(-34069195), /* Filter:1, Coefficient: 49 */ + CONVERT_COEFF(-14414412), /* Filter:1, Coefficient: 50 */ + CONVERT_COEFF(18098088), /* Filter:1, Coefficient: 51 */ + CONVERT_COEFF(20277588), /* Filter:1, Coefficient: 52 */ + + /* Filter #14, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(-1871020), /* Filter:5, Coefficient: 53 */ + CONVERT_COEFF(-1081544), /* Filter:5, Coefficient: 54 */ + CONVERT_COEFF(883235), /* Filter:5, Coefficient: 55 */ + CONVERT_COEFF(1296873), /* Filter:5, Coefficient: 56 */ + CONVERT_COEFF(6559989), /* Filter:4, Coefficient: 53 */ + CONVERT_COEFF(-1807040), /* Filter:4, Coefficient: 54 */ + CONVERT_COEFF(-6018602), /* Filter:4, Coefficient: 55 */ + CONVERT_COEFF(-1736019), /* Filter:4, Coefficient: 56 */ + CONVERT_COEFF(5784968), /* Filter:3, Coefficient: 53 */ + CONVERT_COEFF(14451451), /* Filter:3, Coefficient: 54 */ + CONVERT_COEFF(3098823), /* Filter:3, Coefficient: 55 */ + CONVERT_COEFF(-9531104), /* Filter:3, Coefficient: 56 */ + CONVERT_COEFF(-24446956), /* Filter:2, Coefficient: 53 */ + CONVERT_COEFF(-728979), /* Filter:2, Coefficient: 54 */ + CONVERT_COEFF(18430270), /* Filter:2, Coefficient: 55 */ + CONVERT_COEFF(10144287), /* Filter:2, Coefficient: 56 */ + CONVERT_COEFF(-3302824), /* Filter:1, Coefficient: 53 */ + CONVERT_COEFF(-17275963), /* Filter:1, Coefficient: 54 */ + CONVERT_COEFF(-6442120), /* Filter:1, Coefficient: 55 */ + CONVERT_COEFF(9951675), /* Filter:1, Coefficient: 56 */ + + /* Filter #15, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(-14486), /* Filter:5, Coefficient: 57 */ + CONVERT_COEFF(-1007116), /* Filter:5, Coefficient: 58 */ + CONVERT_COEFF(-499607), /* Filter:5, Coefficient: 59 */ + CONVERT_COEFF(518015), /* Filter:5, Coefficient: 60 */ + CONVERT_COEFF(3750042), /* Filter:4, Coefficient: 57 */ + CONVERT_COEFF(3262673), /* Filter:4, Coefficient: 58 */ + CONVERT_COEFF(-1214266), /* Filter:4, Coefficient: 59 */ + CONVERT_COEFF(-3107008), /* Filter:4, Coefficient: 60 */ + CONVERT_COEFF(-7325337), /* Filter:3, Coefficient: 57 */ + CONVERT_COEFF(3551588), /* Filter:3, Coefficient: 58 */ + CONVERT_COEFF(7434859), /* Filter:3, Coefficient: 59 */ + CONVERT_COEFF(1083621), /* Filter:3, Coefficient: 60 */ + CONVERT_COEFF(-8921035), /* Filter:2, Coefficient: 57 */ + CONVERT_COEFF(-12401028), /* Filter:2, Coefficient: 58 */ + CONVERT_COEFF(437331), /* Filter:2, Coefficient: 59 */ + CONVERT_COEFF(9670117), /* Filter:2, Coefficient: 60 */ + CONVERT_COEFF(10125784), /* Filter:1, Coefficient: 57 */ + CONVERT_COEFF(-2385048), /* Filter:1, Coefficient: 58 */ + CONVERT_COEFF(-8978993), /* Filter:1, Coefficient: 59 */ + CONVERT_COEFF(-2820697), /* Filter:1, Coefficient: 60 */ + + /* Filter #16, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(637690), /* Filter:5, Coefficient: 61 */ + CONVERT_COEFF(-75416), /* Filter:5, Coefficient: 62 */ + CONVERT_COEFF(-514050), /* Filter:5, Coefficient: 63 */ + CONVERT_COEFF(-193261), /* Filter:5, Coefficient: 64 */ + CONVERT_COEFF(-639301), /* Filter:4, Coefficient: 61 */ + CONVERT_COEFF(2025342), /* Filter:4, Coefficient: 62 */ + CONVERT_COEFF(1480378), /* Filter:4, Coefficient: 63 */ + CONVERT_COEFF(-777830), /* Filter:4, Coefficient: 64 */ + CONVERT_COEFF(-5090473), /* Filter:3, Coefficient: 61 */ + CONVERT_COEFF(-3382465), /* Filter:3, Coefficient: 62 */ + CONVERT_COEFF(2113958), /* Filter:3, Coefficient: 63 */ + CONVERT_COEFF(3558926), /* Filter:3, Coefficient: 64 */ + CONVERT_COEFF(4609140), /* Filter:2, Coefficient: 61 */ + CONVERT_COEFF(-4932011), /* Filter:2, Coefficient: 62 */ + CONVERT_COEFF(-5934824), /* Filter:2, Coefficient: 63 */ + CONVERT_COEFF(666961), /* Filter:2, Coefficient: 64 */ + CONVERT_COEFF(5344084), /* Filter:1, Coefficient: 61 */ + CONVERT_COEFF(4861173), /* Filter:1, Coefficient: 62 */ + CONVERT_COEFF(-1503387), /* Filter:1, Coefficient: 63 */ + CONVERT_COEFF(-4357955), /* Filter:1, Coefficient: 64 */ + + /* Filter #17, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(284900), /* Filter:5, Coefficient: 65 */ + CONVERT_COEFF(275450), /* Filter:5, Coefficient: 66 */ + CONVERT_COEFF(-75748), /* Filter:5, Coefficient: 67 */ + CONVERT_COEFF(-230175), /* Filter:5, Coefficient: 68 */ + CONVERT_COEFF(-1466138), /* Filter:4, Coefficient: 65 */ + CONVERT_COEFF(-138526), /* Filter:4, Coefficient: 66 */ + CONVERT_COEFF(988361), /* Filter:4, Coefficient: 67 */ + CONVERT_COEFF(561735), /* Filter:4, Coefficient: 68 */ + CONVERT_COEFF(202115), /* Filter:3, Coefficient: 65 */ + CONVERT_COEFF(-2487174), /* Filter:3, Coefficient: 66 */ + CONVERT_COEFF(-1348983), /* Filter:3, Coefficient: 67 */ + CONVERT_COEFF(1116387), /* Filter:3, Coefficient: 68 */ + CONVERT_COEFF(4682079), /* Filter:2, Coefficient: 65 */ + CONVERT_COEFF(1837378), /* Filter:2, Coefficient: 66 */ + CONVERT_COEFF(-2448933), /* Filter:2, Coefficient: 67 */ + CONVERT_COEFF(-2491052), /* Filter:2, Coefficient: 68 */ + CONVERT_COEFF(-1103167), /* Filter:1, Coefficient: 65 */ + CONVERT_COEFF(2599807), /* Filter:1, Coefficient: 66 */ + CONVERT_COEFF(2086950), /* Filter:1, Coefficient: 67 */ + CONVERT_COEFF(-798359), /* Filter:1, Coefficient: 68 */ + + /* Filter #18, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(-51484), /* Filter:5, Coefficient: 69 */ + CONVERT_COEFF(135388), /* Filter:5, Coefficient: 70 */ + CONVERT_COEFF(93830), /* Filter:5, Coefficient: 71 */ + CONVERT_COEFF(-49843), /* Filter:5, Coefficient: 72 */ + CONVERT_COEFF(-431830), /* Filter:4, Coefficient: 69 */ + CONVERT_COEFF(-583157), /* Filter:4, Coefficient: 70 */ + CONVERT_COEFF(31866), /* Filter:4, Coefficient: 71 */ + CONVERT_COEFF(400739), /* Filter:4, Coefficient: 72 */ + CONVERT_COEFF(1470096), /* Filter:3, Coefficient: 69 */ + CONVERT_COEFF(-80799), /* Filter:3, Coefficient: 70 */ + CONVERT_COEFF(-1028729), /* Filter:3, Coefficient: 71 */ + CONVERT_COEFF(-410822), /* Filter:3, Coefficient: 72 */ + CONVERT_COEFF(502162), /* Filter:2, Coefficient: 69 */ + CONVERT_COEFF(1943488), /* Filter:2, Coefficient: 70 */ + CONVERT_COEFF(577848), /* Filter:2, Coefficient: 71 */ + CONVERT_COEFF(-1008802), /* Filter:2, Coefficient: 72 */ + CONVERT_COEFF(-1841477), /* Filter:1, Coefficient: 69 */ + CONVERT_COEFF(-352536), /* Filter:1, Coefficient: 70 */ + CONVERT_COEFF(1062392), /* Filter:1, Coefficient: 71 */ + CONVERT_COEFF(737212), /* Filter:1, Coefficient: 72 */ + + /* Filter #19, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(-81469), /* Filter:5, Coefficient: 73 */ + CONVERT_COEFF(-912), /* Filter:5, Coefficient: 74 */ + CONVERT_COEFF(49880), /* Filter:5, Coefficient: 75 */ + CONVERT_COEFF(18545), /* Filter:5, Coefficient: 76 */ + CONVERT_COEFF(149914), /* Filter:4, Coefficient: 73 */ + CONVERT_COEFF(-191736), /* Filter:4, Coefficient: 74 */ + CONVERT_COEFF(-168399), /* Filter:4, Coefficient: 75 */ + CONVERT_COEFF(50437), /* Filter:4, Coefficient: 76 */ + CONVERT_COEFF(482726), /* Filter:3, Coefficient: 73 */ + CONVERT_COEFF(466197), /* Filter:3, Coefficient: 74 */ + CONVERT_COEFF(-99774), /* Filter:3, Coefficient: 75 */ + CONVERT_COEFF(-314278), /* Filter:3, Coefficient: 76 */ + CONVERT_COEFF(-830203), /* Filter:2, Coefficient: 73 */ + CONVERT_COEFF(258176), /* Filter:2, Coefficient: 74 */ + CONVERT_COEFF(613009), /* Filter:2, Coefficient: 75 */ + CONVERT_COEFF(108811), /* Filter:2, Coefficient: 76 */ + CONVERT_COEFF(-331518), /* Filter:1, Coefficient: 73 */ + CONVERT_COEFF(-610555), /* Filter:1, Coefficient: 74 */ + CONVERT_COEFF(-78832), /* Filter:1, Coefficient: 75 */ + CONVERT_COEFF(315885), /* Filter:1, Coefficient: 76 */ + + /* Filter #20, conversion from 48000 Hz to 22050 Hz */ + + CONVERT_COEFF(-22620), /* Filter:5, Coefficient: 77 */ + CONVERT_COEFF(-17175), /* Filter:5, Coefficient: 78 */ + CONVERT_COEFF(7621), /* Filter:5, Coefficient: 79 */ + CONVERT_COEFF(1139618), /* Filter:5, Coefficient: 80 */ + CONVERT_COEFF(114508), /* Filter:4, Coefficient: 77 */ + CONVERT_COEFF(9531), /* Filter:4, Coefficient: 78 */ + CONVERT_COEFF(-57126), /* Filter:4, Coefficient: 79 */ + CONVERT_COEFF(-2091381), /* Filter:4, Coefficient: 80 */ + CONVERT_COEFF(-63466), /* Filter:3, Coefficient: 77 */ + CONVERT_COEFF(145663), /* Filter:3, Coefficient: 78 */ + CONVERT_COEFF(78240), /* Filter:3, Coefficient: 79 */ + CONVERT_COEFF(1014579), /* Filter:3, Coefficient: 80 */ + CONVERT_COEFF(-294701), /* Filter:2, Coefficient: 77 */ + CONVERT_COEFF(-169322), /* Filter:2, Coefficient: 78 */ + CONVERT_COEFF(81968), /* Filter:2, Coefficient: 79 */ + CONVERT_COEFF(-55338), /* Filter:2, Coefficient: 80 */ + CONVERT_COEFF(179401), /* Filter:1, Coefficient: 77 */ + CONVERT_COEFF(-86878), /* Filter:1, Coefficient: 78 */ + CONVERT_COEFF(-118181), /* Filter:1, Coefficient: 79 */ + CONVERT_COEFF(-7478), /* Filter:1, Coefficient: 80 */ +}; diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_24000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_24000Hz.h new file mode 100644 index 000000000000..e74514d294ae --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_24000Hz.h @@ -0,0 +1,470 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 48000 Hz to 24000 Hz */ +/* NUM_FILTERS=5, FILTER_LENGTH=80, alpha=7.500000, gamma=0.440000 */ + +__cold_rodata static const int32_t coeff48000to24000[] = { + + /* Filter #1, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(-13838), /* Filter:5, Coefficient: 1 */ + CONVERT_COEFF(-4878), /* Filter:5, Coefficient: 2 */ + CONVERT_COEFF(27346), /* Filter:5, Coefficient: 3 */ + CONVERT_COEFF(15920), /* Filter:5, Coefficient: 4 */ + CONVERT_COEFF(25265), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(-42584), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(-60777), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(71524), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(47328), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(43014), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(-104992), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(-127217), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(-2834), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(111653), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(50477), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(-231338), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(-41434), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(14488), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(121697), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(33752), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(-45854), /* Filter:5, Coefficient: 5 */ + CONVERT_COEFF(-42865), /* Filter:5, Coefficient: 6 */ + CONVERT_COEFF(63570), /* Filter:5, Coefficient: 7 */ + CONVERT_COEFF(93651), /* Filter:5, Coefficient: 8 */ + CONVERT_COEFF(137676), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(-84397), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(-270825), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(41689), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(165291), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(305244), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(-174342), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(-598509), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(-207390), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(350931), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(536033), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(-368031), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(-237368), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(-187652), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(341275), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(495730), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(-67575), /* Filter:5, Coefficient: 9 */ + CONVERT_COEFF(-172357), /* Filter:5, Coefficient: 10 */ + CONVERT_COEFF(37425), /* Filter:5, Coefficient: 11 */ + CONVERT_COEFF(273544), /* Filter:5, Coefficient: 12 */ + CONVERT_COEFF(458722), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(112302), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(-667913), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(-436742), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(41098), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(983891), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(349373), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(-1364077), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(-1063316), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(121078), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(1731952), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(580588), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(-335483), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(-966591), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(78327), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(1529224), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(52090), /* Filter:5, Coefficient: 13 */ + CONVERT_COEFF(-376509), /* Filter:5, Coefficient: 14 */ + CONVERT_COEFF(-224228), /* Filter:5, Coefficient: 15 */ + CONVERT_COEFF(441602), /* Filter:5, Coefficient: 16 */ + CONVERT_COEFF(820085), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(970404), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(-788941), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(-1699573), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(-1101019), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(1549721), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(2252110), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(-1267504), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(-2355777), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(-1892010), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(2600412), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(3840272), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(582559), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(-2002140), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(-1750602), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(2088832), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(489839), /* Filter:5, Coefficient: 17 */ + CONVERT_COEFF(-411054), /* Filter:5, Coefficient: 18 */ + CONVERT_COEFF(-834753), /* Filter:5, Coefficient: 19 */ + CONVERT_COEFF(216224), /* Filter:5, Coefficient: 20 */ + CONVERT_COEFF(413580), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(2524893), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(467752), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(-3237432), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(-3710975), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(204721), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(5200041), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(1907427), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(-2010349), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(-6224958), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(95035), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(8541845), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(3403760), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(-1414199), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(-5320802), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(-392742), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(1207772), /* Filter:5, Coefficient: 21 */ + CONVERT_COEFF(208047), /* Filter:5, Coefficient: 22 */ + CONVERT_COEFF(-1512464), /* Filter:5, Coefficient: 23 */ + CONVERT_COEFF(-902856), /* Filter:5, Coefficient: 24 */ + CONVERT_COEFF(-1964673), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(3514611), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(4069138), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(-2943356), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(-6229468), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(-5181060), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(6118238), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(9448813), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(3529031), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(-9961767), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(-8961434), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(9386380), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(7035593), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(3578394), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(-7842078), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(-8128913), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(1605200), /* Filter:5, Coefficient: 25 */ + CONVERT_COEFF(1860328), /* Filter:5, Coefficient: 26 */ + CONVERT_COEFF(-1299691), /* Filter:5, Coefficient: 27 */ + CONVERT_COEFF(-2995019), /* Filter:5, Coefficient: 28 */ + CONVERT_COEFF(-6587556), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(1071316), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(9078533), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(2520726), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(-4069677), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(-14153956), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(-708399), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(18265964), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(15841264), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(-5580394), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(-23206259), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(-2651769), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(6860332), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(13650089), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(-3152739), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(-19289299), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(374618), /* Filter:5, Coefficient: 29 */ + CONVERT_COEFF(4104773), /* Filter:5, Coefficient: 30 */ + CONVERT_COEFF(1423065), /* Filter:5, Coefficient: 31 */ + CONVERT_COEFF(-4786018), /* Filter:5, Coefficient: 32 */ + CONVERT_COEFF(-10790451), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(-8135144), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(10552917), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(15849886), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(8867184), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(-20196992), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(-20805992), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(17591439), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(29398714), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(16316208), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(-31955417), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(-36235851), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(-4149557), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(23701422), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(15790875), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(-24995516), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(-4380083), /* Filter:5, Coefficient: 33 */ + CONVERT_COEFF(4154074), /* Filter:5, Coefficient: 34 */ + CONVERT_COEFF(8675375), /* Filter:5, Coefficient: 35 */ + CONVERT_COEFF(314997), /* Filter:5, Coefficient: 36 */ + CONVERT_COEFF(-6457951), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(-25205239), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(-5222436), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(33153210), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(36619130), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(-6512823), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(-55966649), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(-22123969), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(27200860), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(63486136), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(-8378210), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(-101100781), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(-32577317), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(20405426), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(56329747), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(-4562349), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(-11223389), /* Filter:5, Coefficient: 37 */ + CONVERT_COEFF(-9182954), /* Filter:5, Coefficient: 38 */ + CONVERT_COEFF(5881106), /* Filter:5, Coefficient: 39 */ + CONVERT_COEFF(14830455), /* Filter:5, Coefficient: 40 */ + CONVERT_COEFF(32686336), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(-17828627), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(-56842565), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(-29576137), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(75895153), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(107387729), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(3315284), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(-129456983), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(-44707785), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(159981825), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(284418268), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(144185861), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(-94322531), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(-41673825), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(198691815), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(435480713), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(5793826), /* Filter:5, Coefficient: 41 */ + CONVERT_COEFF(-9270194), /* Filter:5, Coefficient: 42 */ + CONVERT_COEFF(-11239929), /* Filter:5, Coefficient: 43 */ + CONVERT_COEFF(350438), /* Filter:5, Coefficient: 44 */ + CONVERT_COEFF(33611108), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(54752705), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(12202297), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(-34504953), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(-132194211), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(-1313049), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(106654220), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(79294325), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(-144007288), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(-284533495), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(-160261654), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(44620548), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(435480713), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(198691815), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(-41673825), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(-94322531), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(8697892), /* Filter:5, Coefficient: 45 */ + CONVERT_COEFF(4139411), /* Filter:5, Coefficient: 46 */ + CONVERT_COEFF(-4400335), /* Filter:5, Coefficient: 47 */ + CONVERT_COEFF(-4782540), /* Filter:5, Coefficient: 48 */ + CONVERT_COEFF(-29508465), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(8636575), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(24014024), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(3272779), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(-19581710), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(-57247113), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(-9049303), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(36450428), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(101282205), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(8546018), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(-63545873), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(-27357901), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(-4562349), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(56329747), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(20405426), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(-32577317), /* Filter:1, Coefficient: 48 */ + + /* Filter #13, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(1438893), /* Filter:5, Coefficient: 49 */ + CONVERT_COEFF(4107485), /* Filter:5, Coefficient: 50 */ + CONVERT_COEFF(363683), /* Filter:5, Coefficient: 51 */ + CONVERT_COEFF(-3000681), /* Filter:5, Coefficient: 52 */ + CONVERT_COEFF(-16278067), /* Filter:4, Coefficient: 49 */ + CONVERT_COEFF(-8279099), /* Filter:4, Coefficient: 50 */ + CONVERT_COEFF(9318126), /* Filter:4, Coefficient: 51 */ + CONVERT_COEFF(9464322), /* Filter:4, Coefficient: 52 */ + CONVERT_COEFF(19409638), /* Filter:3, Coefficient: 49 */ + CONVERT_COEFF(-19986418), /* Filter:3, Coefficient: 50 */ + CONVERT_COEFF(-21274397), /* Filter:3, Coefficient: 51 */ + CONVERT_COEFF(7861648), /* Filter:3, Coefficient: 52 */ + CONVERT_COEFF(36215318), /* Filter:2, Coefficient: 49 */ + CONVERT_COEFF(32067664), /* Filter:2, Coefficient: 50 */ + CONVERT_COEFF(-16258232), /* Filter:2, Coefficient: 51 */ + CONVERT_COEFF(-29464286), /* Filter:2, Coefficient: 52 */ + CONVERT_COEFF(-24995516), /* Filter:1, Coefficient: 49 */ + CONVERT_COEFF(15790875), /* Filter:1, Coefficient: 50 */ + CONVERT_COEFF(23701422), /* Filter:1, Coefficient: 51 */ + CONVERT_COEFF(-4149557), /* Filter:1, Coefficient: 52 */ + + /* Filter #14, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(-1293262), /* Filter:5, Coefficient: 53 */ + CONVERT_COEFF(1866746), /* Filter:5, Coefficient: 54 */ + CONVERT_COEFF(1602403), /* Filter:5, Coefficient: 55 */ + CONVERT_COEFF(-908649), /* Filter:5, Coefficient: 56 */ + CONVERT_COEFF(-3897952), /* Filter:4, Coefficient: 53 */ + CONVERT_COEFF(-8522376), /* Filter:4, Coefficient: 54 */ + CONVERT_COEFF(177415), /* Filter:4, Coefficient: 55 */ + CONVERT_COEFF(6565670), /* Filter:4, Coefficient: 56 */ + CONVERT_COEFF(18743832), /* Filter:3, Coefficient: 53 */ + CONVERT_COEFF(224054), /* Filter:3, Coefficient: 54 */ + CONVERT_COEFF(-14211714), /* Filter:3, Coefficient: 55 */ + CONVERT_COEFF(-4803433), /* Filter:3, Coefficient: 56 */ + CONVERT_COEFF(2584064), /* Filter:2, Coefficient: 53 */ + CONVERT_COEFF(23233877), /* Filter:2, Coefficient: 54 */ + CONVERT_COEFF(5641875), /* Filter:2, Coefficient: 55 */ + CONVERT_COEFF(-15842519), /* Filter:2, Coefficient: 56 */ + CONVERT_COEFF(-19289299), /* Filter:1, Coefficient: 53 */ + CONVERT_COEFF(-3152739), /* Filter:1, Coefficient: 54 */ + CONVERT_COEFF(13650089), /* Filter:1, Coefficient: 55 */ + CONVERT_COEFF(6860332), /* Filter:1, Coefficient: 56 */ + + /* Filter #15, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(-1512218), /* Filter:5, Coefficient: 57 */ + CONVERT_COEFF(212504), /* Filter:5, Coefficient: 58 */ + CONVERT_COEFF(1209017), /* Filter:5, Coefficient: 59 */ + CONVERT_COEFF(213290), /* Filter:5, Coefficient: 60 */ + CONVERT_COEFF(1976159), /* Filter:4, Coefficient: 57 */ + CONVERT_COEFF(-4356506), /* Filter:4, Coefficient: 58 */ + CONVERT_COEFF(-2866105), /* Filter:4, Coefficient: 59 */ + CONVERT_COEFF(2379900), /* Filter:4, Coefficient: 60 */ + CONVERT_COEFF(9257256), /* Filter:3, Coefficient: 57 */ + CONVERT_COEFF(6616934), /* Filter:3, Coefficient: 58 */ + CONVERT_COEFF(-4879764), /* Filter:3, Coefficient: 59 */ + CONVERT_COEFF(-6512863), /* Filter:3, Coefficient: 60 */ + CONVERT_COEFF(-9434058), /* Filter:2, Coefficient: 57 */ + CONVERT_COEFF(8947402), /* Filter:2, Coefficient: 58 */ + CONVERT_COEFF(9993781), /* Filter:2, Coefficient: 59 */ + CONVERT_COEFF(-3508647), /* Filter:2, Coefficient: 60 */ + CONVERT_COEFF(-8128913), /* Filter:1, Coefficient: 57 */ + CONVERT_COEFF(-7842078), /* Filter:1, Coefficient: 58 */ + CONVERT_COEFF(3578394), /* Filter:1, Coefficient: 59 */ + CONVERT_COEFF(7035593), /* Filter:1, Coefficient: 60 */ + + /* Filter #16, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(-836606), /* Filter:5, Coefficient: 61 */ + CONVERT_COEFF(-409479), /* Filter:5, Coefficient: 62 */ + CONVERT_COEFF(491682), /* Filter:5, Coefficient: 63 */ + CONVERT_COEFF(441038), /* Filter:5, Coefficient: 64 */ + CONVERT_COEFF(2873370), /* Filter:4, Coefficient: 61 */ + CONVERT_COEFF(-885436), /* Filter:4, Coefficient: 62 */ + CONVERT_COEFF(-2375971), /* Filter:4, Coefficient: 63 */ + CONVERT_COEFF(-64342), /* Filter:4, Coefficient: 64 */ + CONVERT_COEFF(1595238), /* Filter:3, Coefficient: 61 */ + CONVERT_COEFF(5317156), /* Filter:3, Coefficient: 62 */ + CONVERT_COEFF(469755), /* Filter:3, Coefficient: 63 */ + CONVERT_COEFF(-3719261), /* Filter:3, Coefficient: 64 */ + CONVERT_COEFF(-8559856), /* Filter:2, Coefficient: 61 */ + CONVERT_COEFF(-115583), /* Filter:2, Coefficient: 62 */ + CONVERT_COEFF(6232362), /* Filter:2, Coefficient: 63 */ + CONVERT_COEFF(2027557), /* Filter:2, Coefficient: 64 */ + CONVERT_COEFF(-392742), /* Filter:1, Coefficient: 61 */ + CONVERT_COEFF(-5320802), /* Filter:1, Coefficient: 62 */ + CONVERT_COEFF(-1414199), /* Filter:1, Coefficient: 63 */ + CONVERT_COEFF(3403760), /* Filter:1, Coefficient: 64 */ + + /* Filter #17, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(-225715), /* Filter:5, Coefficient: 65 */ + CONVERT_COEFF(-376564), /* Filter:5, Coefficient: 66 */ + CONVERT_COEFF(53103), /* Filter:5, Coefficient: 67 */ + CONVERT_COEFF(273883), /* Filter:5, Coefficient: 68 */ + CONVERT_COEFF(1688791), /* Filter:4, Coefficient: 65 */ + CONVERT_COEFF(534773), /* Filter:4, Coefficient: 66 */ + CONVERT_COEFF(-1030744), /* Filter:4, Coefficient: 67 */ + CONVERT_COEFF(-657535), /* Filter:4, Coefficient: 68 */ + CONVERT_COEFF(-1461589), /* Filter:3, Coefficient: 65 */ + CONVERT_COEFF(2203284), /* Filter:3, Coefficient: 66 */ + CONVERT_COEFF(1673250), /* Filter:3, Coefficient: 67 */ + CONVERT_COEFF(-1033553), /* Filter:3, Coefficient: 68 */ + CONVERT_COEFF(-3840853), /* Filter:2, Coefficient: 65 */ + CONVERT_COEFF(-2612954), /* Filter:2, Coefficient: 66 */ + CONVERT_COEFF(1889068), /* Filter:2, Coefficient: 67 */ + CONVERT_COEFF(2363811), /* Filter:2, Coefficient: 68 */ + CONVERT_COEFF(2088832), /* Filter:1, Coefficient: 65 */ + CONVERT_COEFF(-1750602), /* Filter:1, Coefficient: 66 */ + CONVERT_COEFF(-2002140), /* Filter:1, Coefficient: 67 */ + CONVERT_COEFF(582559), /* Filter:1, Coefficient: 68 */ + + /* Filter #18, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(36846), /* Filter:5, Coefficient: 69 */ + CONVERT_COEFF(-172746), /* Filter:5, Coefficient: 70 */ + CONVERT_COEFF(-67313), /* Filter:5, Coefficient: 71 */ + CONVERT_COEFF(93968), /* Filter:5, Coefficient: 72 */ + CONVERT_COEFF(519728), /* Filter:4, Coefficient: 69 */ + CONVERT_COEFF(577634), /* Filter:4, Coefficient: 70 */ + CONVERT_COEFF(-189254), /* Filter:4, Coefficient: 71 */ + CONVERT_COEFF(-416848), /* Filter:4, Coefficient: 72 */ + CONVERT_COEFF(-1430962), /* Filter:3, Coefficient: 69 */ + CONVERT_COEFF(286656), /* Filter:3, Coefficient: 70 */ + CONVERT_COEFF(1012557), /* Filter:3, Coefficient: 71 */ + CONVERT_COEFF(88679), /* Filter:3, Coefficient: 72 */ + CONVERT_COEFF(-576512), /* Filter:2, Coefficient: 69 */ + CONVERT_COEFF(-1736423), /* Filter:2, Coefficient: 70 */ + CONVERT_COEFF(-124869), /* Filter:2, Coefficient: 71 */ + CONVERT_COEFF(1065395), /* Filter:2, Coefficient: 72 */ + CONVERT_COEFF(1529224), /* Filter:1, Coefficient: 69 */ + CONVERT_COEFF(78327), /* Filter:1, Coefficient: 70 */ + CONVERT_COEFF(-966591), /* Filter:1, Coefficient: 71 */ + CONVERT_COEFF(-335483), /* Filter:1, Coefficient: 72 */ + + /* Filter #19, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(63497), /* Filter:5, Coefficient: 73 */ + CONVERT_COEFF(-43069), /* Filter:5, Coefficient: 74 */ + CONVERT_COEFF(-45864), /* Filter:5, Coefficient: 75 */ + CONVERT_COEFF(16027), /* Filter:5, Coefficient: 76 */ + CONVERT_COEFF(16898), /* Filter:4, Coefficient: 73 */ + CONVERT_COEFF(256277), /* Filter:4, Coefficient: 74 */ + CONVERT_COEFF(45646), /* Filter:4, Coefficient: 75 */ + CONVERT_COEFF(-135456), /* Filter:4, Coefficient: 76 */ + CONVERT_COEFF(-605787), /* Filter:3, Coefficient: 73 */ + CONVERT_COEFF(-205368), /* Filter:3, Coefficient: 74 */ + CONVERT_COEFF(303359), /* Filter:3, Coefficient: 75 */ + CONVERT_COEFF(183044), /* Filter:3, Coefficient: 76 */ + CONVERT_COEFF(370923), /* Filter:2, Coefficient: 73 */ + CONVERT_COEFF(-536759), /* Filter:2, Coefficient: 74 */ + CONVERT_COEFF(-352848), /* Filter:2, Coefficient: 75 */ + CONVERT_COEFF(207503), /* Filter:2, Coefficient: 76 */ + CONVERT_COEFF(495730), /* Filter:1, Coefficient: 73 */ + CONVERT_COEFF(341275), /* Filter:1, Coefficient: 74 */ + CONVERT_COEFF(-187652), /* Filter:1, Coefficient: 75 */ + CONVERT_COEFF(-237368), /* Filter:1, Coefficient: 76 */ + + /* Filter #20, conversion from 48000 Hz to 24000 Hz */ + + CONVERT_COEFF(27375), /* Filter:5, Coefficient: 77 */ + CONVERT_COEFF(-4922), /* Filter:5, Coefficient: 78 */ + CONVERT_COEFF(-13857), /* Filter:5, Coefficient: 79 */ + CONVERT_COEFF(-763703), /* Filter:5, Coefficient: 80 */ + CONVERT_COEFF(-48618), /* Filter:4, Coefficient: 77 */ + CONVERT_COEFF(62211), /* Filter:4, Coefficient: 78 */ + CONVERT_COEFF(30113), /* Filter:4, Coefficient: 79 */ + CONVERT_COEFF(1343965), /* Filter:4, Coefficient: 80 */ + CONVERT_COEFF(-123289), /* Filter:3, Coefficient: 77 */ + CONVERT_COEFF(-114093), /* Filter:3, Coefficient: 78 */ + CONVERT_COEFF(40096), /* Filter:3, Coefficient: 79 */ + CONVERT_COEFF(-641120), /* Filter:3, Coefficient: 80 */ + CONVERT_COEFF(232473), /* Filter:2, Coefficient: 77 */ + CONVERT_COEFF(-50406), /* Filter:2, Coefficient: 78 */ + CONVERT_COEFF(-112271), /* Filter:2, Coefficient: 79 */ + CONVERT_COEFF(102292), /* Filter:2, Coefficient: 80 */ + CONVERT_COEFF(33752), /* Filter:1, Coefficient: 77 */ + CONVERT_COEFF(121697), /* Filter:1, Coefficient: 78 */ + CONVERT_COEFF(14488), /* Filter:1, Coefficient: 79 */ + CONVERT_COEFF(-41434), /* Filter:1, Coefficient: 80 */ +}; diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_32000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_32000Hz.h new file mode 100644 index 000000000000..1d02d5885466 --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_32000Hz.h @@ -0,0 +1,550 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 48000 Hz to 32000 Hz */ +/* NUM_FILTERS=6, FILTER_LENGTH=80, alpha=8.000000, gamma=0.452000 */ + +__cold_rodata static const int32_t coeff48000to32000[] = { + + /* Filter #1, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(-11561), /* Filter:6, Coefficient: 1 */ + CONVERT_COEFF(15747), /* Filter:6, Coefficient: 2 */ + CONVERT_COEFF(5105), /* Filter:6, Coefficient: 3 */ + CONVERT_COEFF(-38743), /* Filter:6, Coefficient: 4 */ + CONVERT_COEFF(9801), /* Filter:5, Coefficient: 1 */ + CONVERT_COEFF(-57987), /* Filter:5, Coefficient: 2 */ + CONVERT_COEFF(55855), /* Filter:5, Coefficient: 3 */ + CONVERT_COEFF(57347), /* Filter:5, Coefficient: 4 */ + CONVERT_COEFF(46237), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(-16129), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(-97341), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(155756), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(9592), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(90049), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(-143614), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(-53049), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(-56068), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(83510), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(61872), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(-268865), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(-22379), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(-24379), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(90814), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(-27309), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(32278), /* Filter:6, Coefficient: 5 */ + CONVERT_COEFF(39046), /* Filter:6, Coefficient: 6 */ + CONVERT_COEFF(-95870), /* Filter:6, Coefficient: 7 */ + CONVERT_COEFF(23105), /* Filter:6, Coefficient: 8 */ + CONVERT_COEFF(-175841), /* Filter:5, Coefficient: 5 */ + CONVERT_COEFF(72860), /* Filter:5, Coefficient: 6 */ + CONVERT_COEFF(247915), /* Filter:5, Coefficient: 7 */ + CONVERT_COEFF(-361409), /* Filter:5, Coefficient: 8 */ + CONVERT_COEFF(35097), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(-344433), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(268897), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(365707), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(365130), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(-248936), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(-457784), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(858658), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(128732), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(422344), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(-623551), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(-218850), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(-174868), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(210533), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(151417), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(-508987), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(138684), /* Filter:6, Coefficient: 9 */ + CONVERT_COEFF(-160549), /* Filter:6, Coefficient: 10 */ + CONVERT_COEFF(-79806), /* Filter:6, Coefficient: 11 */ + CONVERT_COEFF(315837), /* Filter:6, Coefficient: 12 */ + CONVERT_COEFF(-88230), /* Filter:5, Coefficient: 9 */ + CONVERT_COEFF(670200), /* Filter:5, Coefficient: 10 */ + CONVERT_COEFF(-440690), /* Filter:5, Coefficient: 11 */ + CONVERT_COEFF(-669306), /* Filter:5, Coefficient: 12 */ + CONVERT_COEFF(-792638), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(86409), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(1208069), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(-1151663), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(41857), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(-1469440), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(1160033), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(1367901), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(1266645), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(-690167), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(-1490906), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(2295682), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(158227), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(724561), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(-839003), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(-482312), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(-143037), /* Filter:6, Coefficient: 13 */ + CONVERT_COEFF(-351812), /* Filter:6, Coefficient: 14 */ + CONVERT_COEFF(494431), /* Filter:6, Coefficient: 15 */ + CONVERT_COEFF(110738), /* Filter:6, Coefficient: 16 */ + CONVERT_COEFF(1230829), /* Filter:5, Coefficient: 13 */ + CONVERT_COEFF(-10053), /* Filter:5, Coefficient: 14 */ + CONVERT_COEFF(-1802066), /* Filter:5, Coefficient: 15 */ + CONVERT_COEFF(1456443), /* Filter:5, Coefficient: 16 */ + CONVERT_COEFF(-910652), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(2480789), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(-641633), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(-3110197), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(-2897785), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(246665), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(4107125), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(-3569996), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(473707), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(-3847887), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(2297303), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(3846674), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(1676174), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(-570776), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(-2053116), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(2402095), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(-790086), /* Filter:6, Coefficient: 17 */ + CONVERT_COEFF(463549), /* Filter:6, Coefficient: 18 */ + CONVERT_COEFF(736606), /* Filter:6, Coefficient: 19 */ + CONVERT_COEFF(-1203048), /* Filter:6, Coefficient: 20 */ + CONVERT_COEFF(1420579), /* Filter:5, Coefficient: 17 */ + CONVERT_COEFF(-3164667), /* Filter:5, Coefficient: 18 */ + CONVERT_COEFF(474626), /* Filter:5, Coefficient: 19 */ + CONVERT_COEFF(3997758), /* Filter:5, Coefficient: 20 */ + CONVERT_COEFF(3363870), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(1795377), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(-6095509), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(2170913), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(-3143459), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(7478803), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(-1291163), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(-9390934), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(-6253867), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(-704435), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(9301477), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(-6005932), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(1135780), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(-4267272), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(1601388), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(4727524), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(-85369), /* Filter:6, Coefficient: 21 */ + CONVERT_COEFF(1689090), /* Filter:6, Coefficient: 22 */ + CONVERT_COEFF(-1153692), /* Filter:6, Coefficient: 23 */ + CONVERT_COEFF(-1392092), /* Filter:6, Coefficient: 24 */ + CONVERT_COEFF(-3695078), /* Filter:5, Coefficient: 21 */ + CONVERT_COEFF(-2619412), /* Filter:5, Coefficient: 22 */ + CONVERT_COEFF(6934895), /* Filter:5, Coefficient: 23 */ + CONVERT_COEFF(-1671143), /* Filter:5, Coefficient: 24 */ + CONVERT_COEFF(6715445), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(-8010806), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(-3066771), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(13022550), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(8830976), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(6179129), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(-16519290), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(3931355), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(-8288130), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(14331732), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(596302), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(-19674765), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(-5703839), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(-2226042), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(9343886), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(-3864751), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(2561676), /* Filter:6, Coefficient: 25 */ + CONVERT_COEFF(-41718), /* Filter:6, Coefficient: 26 */ + CONVERT_COEFF(-3351923), /* Filter:6, Coefficient: 27 */ + CONVERT_COEFF(2484217), /* Filter:6, Coefficient: 28 */ + CONVERT_COEFF(-7983534), /* Filter:5, Coefficient: 25 */ + CONVERT_COEFF(8090613), /* Filter:5, Coefficient: 26 */ + CONVERT_COEFF(4635953), /* Filter:5, Coefficient: 27 */ + CONVERT_COEFF(-14057177), /* Filter:5, Coefficient: 28 */ + CONVERT_COEFF(-5546048), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(-13215426), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(17029298), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(5073548), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(19154324), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(-19288118), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(-11295504), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(33812123), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(13651643), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(16170479), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(-29933479), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(407469), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(-9649047), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(12189269), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(3905181), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(-19010870), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(2646463), /* Filter:6, Coefficient: 29 */ + CONVERT_COEFF(-5183436), /* Filter:6, Coefficient: 30 */ + CONVERT_COEFF(113142), /* Filter:6, Coefficient: 31 */ + CONVERT_COEFF(6922098), /* Filter:6, Coefficient: 32 */ + CONVERT_COEFF(4012768), /* Filter:5, Coefficient: 29 */ + CONVERT_COEFF(15785061), /* Filter:5, Coefficient: 30 */ + CONVERT_COEFF(-16561721), /* Filter:5, Coefficient: 31 */ + CONVERT_COEFF(-9670889), /* Filter:5, Coefficient: 32 */ + CONVERT_COEFF(-26242846), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(12222374), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(26293489), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(-35302032), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(-9629387), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(-38047097), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(40551122), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(22142931), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(39448271), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(-29337586), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(-31488442), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(62886474), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(8709491), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(18945155), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(-25616062), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(-6708613), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(-4854058), /* Filter:6, Coefficient: 33 */ + CONVERT_COEFF(-6493349), /* Filter:6, Coefficient: 34 */ + CONVERT_COEFF(10955382), /* Filter:6, Coefficient: 35 */ + CONVERT_COEFF(3639331), /* Filter:6, Coefficient: 36 */ + CONVERT_COEFF(29320297), /* Filter:5, Coefficient: 33 */ + CONVERT_COEFF(-6238872), /* Filter:5, Coefficient: 34 */ + CONVERT_COEFF(-37929537), /* Filter:5, Coefficient: 35 */ + CONVERT_COEFF(31607052), /* Filter:5, Coefficient: 36 */ + CONVERT_COEFF(-10922848), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(57004450), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(-23682378), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(-69775212), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(-71937950), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(20998625), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(89787906), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(-97112393), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(-2929444), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(-86584128), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(69191980), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(80706313), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(40270809), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(-21053631), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(-42367788), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(65956939), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(-17266601), /* Filter:6, Coefficient: 37 */ + CONVERT_COEFF(231253), /* Filter:6, Coefficient: 38 */ + CONVERT_COEFF(21704927), /* Filter:6, Coefficient: 39 */ + CONVERT_COEFF(-2600806), /* Filter:6, Coefficient: 40 */ + CONVERT_COEFF(41975839), /* Filter:5, Coefficient: 37 */ + CONVERT_COEFF(-59844606), /* Filter:5, Coefficient: 38 */ + CONVERT_COEFF(-44992655), /* Filter:5, Coefficient: 39 */ + CONVERT_COEFF(73711853), /* Filter:5, Coefficient: 40 */ + CONVERT_COEFF(81790468), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(86455952), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(-138195163), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(-113308335), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(-81580682), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(240735052), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(145279809), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(-321141069), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(-178457029), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(-14491810), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(488414096), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(292747412), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(15022342), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(-138518549), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(114569679), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(586792923), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(-20066125), /* Filter:6, Coefficient: 41 */ + CONVERT_COEFF(5767713), /* Filter:6, Coefficient: 42 */ + CONVERT_COEFF(15089402), /* Filter:6, Coefficient: 43 */ + CONVERT_COEFF(-7757981), /* Filter:6, Coefficient: 44 */ + CONVERT_COEFF(38637120), /* Filter:5, Coefficient: 41 */ + CONVERT_COEFF(-70881813), /* Filter:5, Coefficient: 42 */ + CONVERT_COEFF(-22766795), /* Filter:5, Coefficient: 43 */ + CONVERT_COEFF(54397391), /* Filter:5, Coefficient: 44 */ + CONVERT_COEFF(145358829), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(111916983), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(-108596377), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(-60427595), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(-248537116), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(217233738), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(188328936), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(-122913915), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(-407818384), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(-414365665), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(101272401), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(136295795), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(516212737), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(23787556), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(-126544125), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(46784418), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(-8119365), /* Filter:6, Coefficient: 45 */ + CONVERT_COEFF(8416921), /* Filter:6, Coefficient: 46 */ + CONVERT_COEFF(2011547), /* Filter:6, Coefficient: 47 */ + CONVERT_COEFF(-7011741), /* Filter:6, Coefficient: 48 */ + CONVERT_COEFF(239202), /* Filter:5, Coefficient: 45 */ + CONVERT_COEFF(-36066145), /* Filter:5, Coefficient: 46 */ + CONVERT_COEFF(15579621), /* Filter:5, Coefficient: 47 */ + CONVERT_COEFF(18206458), /* Filter:5, Coefficient: 48 */ + CONVERT_COEFF(78881593), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(7227261), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(-55803497), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(21803835), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(-57723218), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(99822925), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(-9284004), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(-64228804), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(-112035461), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(-30308183), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(88786923), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(-24912829), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(46379080), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(-52379260), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(-3286550), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(38004833), /* Filter:1, Coefficient: 48 */ + + /* Filter #13, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(2029399), /* Filter:6, Coefficient: 49 */ + CONVERT_COEFF(4158325), /* Filter:6, Coefficient: 50 */ + CONVERT_COEFF(-3721541), /* Filter:6, Coefficient: 51 */ + CONVERT_COEFF(-1133029), /* Filter:6, Coefficient: 52 */ + CONVERT_COEFF(-20392589), /* Filter:5, Coefficient: 49 */ + CONVERT_COEFF(-2906434), /* Filter:5, Coefficient: 50 */ + CONVERT_COEFF(16751891), /* Filter:5, Coefficient: 51 */ + CONVERT_COEFF(-6818425), /* Filter:5, Coefficient: 52 */ + CONVERT_COEFF(28980439), /* Filter:4, Coefficient: 49 */ + CONVERT_COEFF(-30983025), /* Filter:4, Coefficient: 50 */ + CONVERT_COEFF(-5048118), /* Filter:4, Coefficient: 51 */ + CONVERT_COEFF(25896772), /* Filter:4, Coefficient: 52 */ + CONVERT_COEFF(39777989), /* Filter:3, Coefficient: 49 */ + CONVERT_COEFF(25764575), /* Filter:3, Coefficient: 50 */ + CONVERT_COEFF(-43217126), /* Filter:3, Coefficient: 51 */ + CONVERT_COEFF(4190043), /* Filter:3, Coefficient: 52 */ + CONVERT_COEFF(-50106572), /* Filter:2, Coefficient: 49 */ + CONVERT_COEFF(44996435), /* Filter:2, Coefficient: 50 */ + CONVERT_COEFF(12663590), /* Filter:2, Coefficient: 51 */ + CONVERT_COEFF(-40495107), /* Filter:2, Coefficient: 52 */ + CONVERT_COEFF(-18138626), /* Filter:1, Coefficient: 49 */ + CONVERT_COEFF(-17850332), /* Filter:1, Coefficient: 50 */ + CONVERT_COEFF(23180027), /* Filter:1, Coefficient: 51 */ + CONVERT_COEFF(608735), /* Filter:1, Coefficient: 52 */ + + /* Filter #14, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(3433587), /* Filter:6, Coefficient: 53 */ + CONVERT_COEFF(-1029758), /* Filter:6, Coefficient: 54 */ + CONVERT_COEFF(-2029714), /* Filter:6, Coefficient: 55 */ + CONVERT_COEFF(1907010), /* Filter:6, Coefficient: 56 */ + CONVERT_COEFF(-8939750), /* Filter:5, Coefficient: 53 */ + CONVERT_COEFF(10066060), /* Filter:5, Coefficient: 54 */ + CONVERT_COEFF(1203126), /* Filter:5, Coefficient: 55 */ + CONVERT_COEFF(-8271006), /* Filter:5, Coefficient: 56 */ + CONVERT_COEFF(-10289050), /* Filter:4, Coefficient: 53 */ + CONVERT_COEFF(-13908366), /* Filter:4, Coefficient: 54 */ + CONVERT_COEFF(15437261), /* Filter:4, Coefficient: 55 */ + CONVERT_COEFF(1959317), /* Filter:4, Coefficient: 56 */ + CONVERT_COEFF(30176511), /* Filter:3, Coefficient: 53 */ + CONVERT_COEFF(-19720665), /* Filter:3, Coefficient: 54 */ + CONVERT_COEFF(-11906392), /* Filter:3, Coefficient: 55 */ + CONVERT_COEFF(21431694), /* Filter:3, Coefficient: 56 */ + CONVERT_COEFF(12685188), /* Filter:2, Coefficient: 53 */ + CONVERT_COEFF(23538156), /* Filter:2, Coefficient: 54 */ + CONVERT_COEFF(-22526671), /* Filter:2, Coefficient: 55 */ + CONVERT_COEFF(-5324400), /* Filter:2, Coefficient: 56 */ + CONVERT_COEFF(-17751380), /* Filter:1, Coefficient: 53 */ + CONVERT_COEFF(9315300), /* Filter:1, Coefficient: 54 */ + CONVERT_COEFF(8260899), /* Filter:1, Coefficient: 55 */ + CONVERT_COEFF(-11561731), /* Filter:1, Coefficient: 56 */ + + /* Filter #15, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(463533), /* Filter:6, Coefficient: 57 */ + CONVERT_COEFF(-1687787), /* Filter:6, Coefficient: 58 */ + CONVERT_COEFF(600074), /* Filter:6, Coefficient: 59 */ + CONVERT_COEFF(911501), /* Filter:6, Coefficient: 60 */ + CONVERT_COEFF(3698444), /* Filter:5, Coefficient: 57 */ + CONVERT_COEFF(4136678), /* Filter:5, Coefficient: 58 */ + CONVERT_COEFF(-5065760), /* Filter:5, Coefficient: 59 */ + CONVERT_COEFF(-233174), /* Filter:5, Coefficient: 60 */ + CONVERT_COEFF(-12705057), /* Filter:4, Coefficient: 57 */ + CONVERT_COEFF(5580298), /* Filter:4, Coefficient: 58 */ + CONVERT_COEFF(6376293), /* Filter:4, Coefficient: 59 */ + CONVERT_COEFF(-7669533), /* Filter:4, Coefficient: 60 */ + CONVERT_COEFF(-2881357), /* Filter:3, Coefficient: 57 */ + CONVERT_COEFF(-14454865), /* Filter:3, Coefficient: 58 */ + CONVERT_COEFF(10115126), /* Filter:3, Coefficient: 59 */ + CONVERT_COEFF(5126005), /* Filter:3, Coefficient: 60 */ + CONVERT_COEFF(19856482), /* Filter:2, Coefficient: 57 */ + CONVERT_COEFF(-6933075), /* Filter:2, Coefficient: 58 */ + CONVERT_COEFF(-10972601), /* Filter:2, Coefficient: 59 */ + CONVERT_COEFF(11128930), /* Filter:2, Coefficient: 60 */ + CONVERT_COEFF(140888), /* Filter:1, Coefficient: 57 */ + CONVERT_COEFF(8573112), /* Filter:1, Coefficient: 58 */ + CONVERT_COEFF(-4785738), /* Filter:1, Coefficient: 59 */ + CONVERT_COEFF(-3732684), /* Filter:1, Coefficient: 60 */ + + /* Filter #16, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(-950577), /* Filter:6, Coefficient: 61 */ + CONVERT_COEFF(-130034), /* Filter:6, Coefficient: 62 */ + CONVERT_COEFF(756094), /* Filter:6, Coefficient: 63 */ + CONVERT_COEFF(-329642), /* Filter:6, Coefficient: 64 */ + CONVERT_COEFF(3849839), /* Filter:5, Coefficient: 61 */ + CONVERT_COEFF(-1976633), /* Filter:5, Coefficient: 62 */ + CONVERT_COEFF(-1672857), /* Filter:5, Coefficient: 63 */ + CONVERT_COEFF(2337162), /* Filter:5, Coefficient: 64 */ + CONVERT_COEFF(-439082), /* Filter:4, Coefficient: 61 */ + CONVERT_COEFF(5830744), /* Filter:4, Coefficient: 62 */ + CONVERT_COEFF(-2898810), /* Filter:4, Coefficient: 63 */ + CONVERT_COEFF(-2565926), /* Filter:4, Coefficient: 64 */ + CONVERT_COEFF(-10239291), /* Filter:3, Coefficient: 61 */ + CONVERT_COEFF(1875733), /* Filter:3, Coefficient: 62 */ + CONVERT_COEFF(6351912), /* Filter:3, Coefficient: 63 */ + CONVERT_COEFF(-4786768), /* Filter:3, Coefficient: 64 */ + CONVERT_COEFF(1978448), /* Filter:2, Coefficient: 61 */ + CONVERT_COEFF(-9164115), /* Filter:2, Coefficient: 62 */ + CONVERT_COEFF(3532591), /* Filter:2, Coefficient: 63 */ + CONVERT_COEFF(4618733), /* Filter:2, Coefficient: 64 */ + CONVERT_COEFF(5531160), /* Filter:1, Coefficient: 61 */ + CONVERT_COEFF(-269508), /* Filter:1, Coefficient: 62 */ + CONVERT_COEFF(-3833892), /* Filter:1, Coefficient: 63 */ + CONVERT_COEFF(2235084), /* Filter:1, Coefficient: 64 */ + + /* Filter #17, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(-346938), /* Filter:6, Coefficient: 65 */ + CONVERT_COEFF(420998), /* Filter:6, Coefficient: 66 */ + CONVERT_COEFF(2948), /* Filter:6, Coefficient: 67 */ + CONVERT_COEFF(-283734), /* Filter:6, Coefficient: 68 */ + CONVERT_COEFF(-118556), /* Filter:5, Coefficient: 65 */ + CONVERT_COEFF(-1556054), /* Filter:5, Coefficient: 66 */ + CONVERT_COEFF(938534), /* Filter:5, Coefficient: 67 */ + CONVERT_COEFF(530259), /* Filter:5, Coefficient: 68 */ + CONVERT_COEFF(3449180), /* Filter:4, Coefficient: 65 */ + CONVERT_COEFF(-99308), /* Filter:4, Coefficient: 66 */ + CONVERT_COEFF(-2308321), /* Filter:4, Coefficient: 67 */ + CONVERT_COEFF(1316267), /* Filter:4, Coefficient: 68 */ + CONVERT_COEFF(-1879552), /* Filter:3, Coefficient: 65 */ + CONVERT_COEFF(4332349), /* Filter:3, Coefficient: 66 */ + CONVERT_COEFF(-1033406), /* Filter:3, Coefficient: 67 */ + CONVERT_COEFF(-2361476), /* Filter:3, Coefficient: 68 */ + CONVERT_COEFF(-4953240), /* Filter:2, Coefficient: 65 */ + CONVERT_COEFF(-565926), /* Filter:2, Coefficient: 66 */ + CONVERT_COEFF(3678031), /* Filter:2, Coefficient: 67 */ + CONVERT_COEFF(-1548139), /* Filter:2, Coefficient: 68 */ + CONVERT_COEFF(1508675), /* Filter:1, Coefficient: 65 */ + CONVERT_COEFF(-2340479), /* Filter:1, Coefficient: 66 */ + CONVERT_COEFF(191583), /* Filter:1, Coefficient: 67 */ + CONVERT_COEFF(1469400), /* Filter:1, Coefficient: 68 */ + + /* Filter #18, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(154632), /* Filter:6, Coefficient: 69 */ + CONVERT_COEFF(97677), /* Filter:6, Coefficient: 70 */ + CONVERT_COEFF(-151006), /* Filter:6, Coefficient: 71 */ + CONVERT_COEFF(22864), /* Filter:6, Coefficient: 72 */ + CONVERT_COEFF(-909572), /* Filter:5, Coefficient: 69 */ + CONVERT_COEFF(153482), /* Filter:5, Coefficient: 70 */ + CONVERT_COEFF(491289), /* Filter:5, Coefficient: 71 */ + CONVERT_COEFF(-360835), /* Filter:5, Coefficient: 72 */ + CONVERT_COEFF(817805), /* Filter:4, Coefficient: 69 */ + CONVERT_COEFF(-1291146), /* Filter:4, Coefficient: 70 */ + CONVERT_COEFF(169841), /* Filter:4, Coefficient: 71 */ + CONVERT_COEFF(707188), /* Filter:4, Coefficient: 72 */ + CONVERT_COEFF(1928437), /* Filter:3, Coefficient: 69 */ + CONVERT_COEFF(514414), /* Filter:3, Coefficient: 70 */ + CONVERT_COEFF(-1484055), /* Filter:3, Coefficient: 71 */ + CONVERT_COEFF(448482), /* Filter:3, Coefficient: 72 */ + CONVERT_COEFF(-1615722), /* Filter:2, Coefficient: 69 */ + CONVERT_COEFF(1829243), /* Filter:2, Coefficient: 70 */ + CONVERT_COEFF(84371), /* Filter:2, Coefficient: 71 */ + CONVERT_COEFF(-1162547), /* Filter:2, Coefficient: 72 */ + CONVERT_COEFF(-877441), /* Filter:1, Coefficient: 69 */ + CONVERT_COEFF(-501872), /* Filter:1, Coefficient: 70 */ + CONVERT_COEFF(801814), /* Filter:1, Coefficient: 71 */ + CONVERT_COEFF(-87747), /* Filter:1, Coefficient: 72 */ + + /* Filter #19, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(77476), /* Filter:6, Coefficient: 73 */ + CONVERT_COEFF(-55647), /* Filter:6, Coefficient: 74 */ + CONVERT_COEFF(-12425), /* Filter:6, Coefficient: 75 */ + CONVERT_COEFF(36432), /* Filter:6, Coefficient: 76 */ + CONVERT_COEFF(-98904), /* Filter:5, Coefficient: 73 */ + CONVERT_COEFF(262255), /* Filter:5, Coefficient: 74 */ + CONVERT_COEFF(-86370), /* Filter:5, Coefficient: 75 */ + CONVERT_COEFF(-93036), /* Filter:5, Coefficient: 76 */ + CONVERT_COEFF(-474181), /* Filter:4, Coefficient: 73 */ + CONVERT_COEFF(-161908), /* Filter:4, Coefficient: 74 */ + CONVERT_COEFF(348709), /* Filter:4, Coefficient: 75 */ + CONVERT_COEFF(-94475), /* Filter:4, Coefficient: 76 */ + CONVERT_COEFF(655915), /* Filter:3, Coefficient: 73 */ + CONVERT_COEFF(-589182), /* Filter:3, Coefficient: 74 */ + CONVERT_COEFF(-68486), /* Filter:3, Coefficient: 75 */ + CONVERT_COEFF(343484), /* Filter:3, Coefficient: 76 */ + CONVERT_COEFF(527672), /* Filter:2, Coefficient: 73 */ + CONVERT_COEFF(407424), /* Filter:2, Coefficient: 74 */ + CONVERT_COEFF(-485562), /* Filter:2, Coefficient: 75 */ + CONVERT_COEFF(16521), /* Filter:2, Coefficient: 76 */ + CONVERT_COEFF(-432603), /* Filter:1, Coefficient: 73 */ + CONVERT_COEFF(255380), /* Filter:1, Coefficient: 74 */ + CONVERT_COEFF(118325), /* Filter:1, Coefficient: 75 */ + CONVERT_COEFF(-185814), /* Filter:1, Coefficient: 76 */ + + /* Filter #20, conversion from 48000 Hz to 32000 Hz */ + + CONVERT_COEFF(-14137), /* Filter:6, Coefficient: 77 */ + CONVERT_COEFF(-9206), /* Filter:6, Coefficient: 78 */ + CONVERT_COEFF(11763), /* Filter:6, Coefficient: 79 */ + CONVERT_COEFF(-1554661), /* Filter:6, Coefficient: 80 */ + CONVERT_COEFF(94324), /* Filter:5, Coefficient: 77 */ + CONVERT_COEFF(-8059), /* Filter:5, Coefficient: 78 */ + CONVERT_COEFF(-36850), /* Filter:5, Coefficient: 79 */ + CONVERT_COEFF(3952809), /* Filter:5, Coefficient: 80 */ + CONVERT_COEFF(-126700), /* Filter:4, Coefficient: 77 */ + CONVERT_COEFF(110024), /* Filter:4, Coefficient: 78 */ + CONVERT_COEFF(-3318), /* Filter:4, Coefficient: 79 */ + CONVERT_COEFF(-3431485), /* Filter:4, Coefficient: 80 */ + CONVERT_COEFF(-132999), /* Filter:3, Coefficient: 77 */ + CONVERT_COEFF(-93296), /* Filter:3, Coefficient: 78 */ + CONVERT_COEFF(98915), /* Filter:3, Coefficient: 79 */ + CONVERT_COEFF(1107272), /* Filter:3, Coefficient: 80 */ + CONVERT_COEFF(229610), /* Filter:2, Coefficient: 77 */ + CONVERT_COEFF(-109871), /* Filter:2, Coefficient: 78 */ + CONVERT_COEFF(-44438), /* Filter:2, Coefficient: 79 */ + CONVERT_COEFF(-62812), /* Filter:2, Coefficient: 80 */ + CONVERT_COEFF(23112), /* Filter:1, Coefficient: 77 */ + CONVERT_COEFF(73212), /* Filter:1, Coefficient: 78 */ + CONVERT_COEFF(-37195), /* Filter:1, Coefficient: 79 */ + CONVERT_COEFF(-11124), /* Filter:1, Coefficient: 80 */ +}; diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_44100Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_44100Hz.h new file mode 100644 index 000000000000..ad487d58af14 --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_44100Hz.h @@ -0,0 +1,506 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 48000 Hz to 44100 Hz */ +/* NUM_FILTERS=7, FILTER_LENGTH=64, alpha=8.150000, gamma=0.456000 */ + +__cold_rodata static const int32_t coeff48000to44100[] = { + + /* Filter #1, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(-34608), /* Filter:7, Coefficient: 1 */ + CONVERT_COEFF(58942), /* Filter:7, Coefficient: 2 */ + CONVERT_COEFF(-85115), /* Filter:7, Coefficient: 3 */ + CONVERT_COEFF(96633), /* Filter:7, Coefficient: 4 */ + CONVERT_COEFF(69866), /* Filter:6, Coefficient: 1 */ + CONVERT_COEFF(-157606), /* Filter:6, Coefficient: 2 */ + CONVERT_COEFF(299637), /* Filter:6, Coefficient: 3 */ + CONVERT_COEFF(-469979), /* Filter:6, Coefficient: 4 */ + CONVERT_COEFF(61623), /* Filter:5, Coefficient: 1 */ + CONVERT_COEFF(-49681), /* Filter:5, Coefficient: 2 */ + CONVERT_COEFF(-50870), /* Filter:5, Coefficient: 3 */ + CONVERT_COEFF(302189), /* Filter:5, Coefficient: 4 */ + CONVERT_COEFF(-66312), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(181693), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(-384955), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(630700), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(-133695), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(219785), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(-230581), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(36535), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(-1792), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(-79997), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(271909), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(-561039), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(33030), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(-71885), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(101248), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(-78725), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(-67867), /* Filter:7, Coefficient: 5 */ + CONVERT_COEFF(-28521), /* Filter:7, Coefficient: 6 */ + CONVERT_COEFF(207221), /* Filter:7, Coefficient: 7 */ + CONVERT_COEFF(-452333), /* Filter:7, Coefficient: 8 */ + CONVERT_COEFF(592244), /* Filter:6, Coefficient: 5 */ + CONVERT_COEFF(-540223), /* Filter:6, Coefficient: 6 */ + CONVERT_COEFF(168968), /* Filter:6, Coefficient: 7 */ + CONVERT_COEFF(620325), /* Filter:6, Coefficient: 8 */ + CONVERT_COEFF(-730836), /* Filter:5, Coefficient: 5 */ + CONVERT_COEFF(1274818), /* Filter:5, Coefficient: 6 */ + CONVERT_COEFF(-1742595), /* Filter:5, Coefficient: 7 */ + CONVERT_COEFF(1816487), /* Filter:5, Coefficient: 8 */ + CONVERT_COEFF(-786525), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(641498), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(29205), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(-1344095), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(483560), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(-1352248), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(2396129), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(-3194402), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(844568), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(-919927), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(530444), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(525026), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(-43685), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(291450), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(-633133), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(956210), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(703127), /* Filter:7, Coefficient: 9 */ + CONVERT_COEFF(-853001), /* Filter:7, Coefficient: 10 */ + CONVERT_COEFF(769748), /* Filter:7, Coefficient: 11 */ + CONVERT_COEFF(-339193), /* Filter:7, Coefficient: 12 */ + CONVERT_COEFF(-1794792), /* Filter:6, Coefficient: 9 */ + CONVERT_COEFF(3115259), /* Filter:6, Coefficient: 10 */ + CONVERT_COEFF(-4115635), /* Filter:6, Coefficient: 11 */ + CONVERT_COEFF(4175773), /* Filter:6, Coefficient: 12 */ + CONVERT_COEFF(-1127711), /* Filter:5, Coefficient: 9 */ + CONVERT_COEFF(-592357), /* Filter:5, Coefficient: 10 */ + CONVERT_COEFF(3316547), /* Filter:5, Coefficient: 11 */ + CONVERT_COEFF(-6552082), /* Filter:5, Coefficient: 12 */ + CONVERT_COEFF(3171756), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(-5026421), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(6078263), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(-5335178), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(3130331), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(-1578560), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(-1791676), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(6684486), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(-2241194), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(4271071), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(-5884188), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(6087444), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(-1072749), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(768744), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(104733), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(-1522163), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(-475432), /* Filter:7, Coefficient: 13 */ + CONVERT_COEFF(1576583), /* Filter:7, Coefficient: 14 */ + CONVERT_COEFF(-2703138), /* Filter:7, Coefficient: 15 */ + CONVERT_COEFF(3453146), /* Filter:7, Coefficient: 16 */ + CONVERT_COEFF(-2703131), /* Filter:6, Coefficient: 13 */ + CONVERT_COEFF(-602943), /* Filter:6, Coefficient: 14 */ + CONVERT_COEFF(5477993), /* Filter:6, Coefficient: 15 */ + CONVERT_COEFF(-10918971), /* Filter:6, Coefficient: 16 */ + CONVERT_COEFF(9289206), /* Filter:5, Coefficient: 13 */ + CONVERT_COEFF(-10150369), /* Filter:5, Coefficient: 14 */ + CONVERT_COEFF(7770551), /* Filter:5, Coefficient: 15 */ + CONVERT_COEFF(-1353879), /* Filter:5, Coefficient: 16 */ + CONVERT_COEFF(1998375), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(4084791), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(-12023857), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(19736881), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(-11958163), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(15672295), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(-15501757), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(9501580), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(-3932030), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(-1045712), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(8383285), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(-16438405), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(3198988), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(-4582047), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(4952446), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(-3644365), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(-3371842), /* Filter:7, Coefficient: 17 */ + CONVERT_COEFF(2097989), /* Filter:7, Coefficient: 18 */ + CONVERT_COEFF(462769), /* Filter:7, Coefficient: 19 */ + CONVERT_COEFF(-3989397), /* Filter:7, Coefficient: 20 */ + CONVERT_COEFF(15222797), /* Filter:6, Coefficient: 17 */ + CONVERT_COEFF(-16309530), /* Filter:6, Coefficient: 18 */ + CONVERT_COEFF(12321848), /* Filter:6, Coefficient: 19 */ + CONVERT_COEFF(-2389147), /* Filter:6, Coefficient: 20 */ + CONVERT_COEFF(-8743201), /* Filter:5, Coefficient: 17 */ + CONVERT_COEFF(20620478), /* Filter:5, Coefficient: 18 */ + CONVERT_COEFF(-30859164), /* Filter:5, Coefficient: 19 */ + CONVERT_COEFF(35112554), /* Filter:5, Coefficient: 20 */ + CONVERT_COEFF(-24216328), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(22270762), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(-11641126), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(-7783920), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(2945332), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(-20300949), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(38527510), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(-51525628), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(22503598), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(-23386679), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(16406368), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(-579401), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(335976), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(4676188), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(-10331423), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(14886324), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(7681853), /* Filter:7, Coefficient: 21 */ + CONVERT_COEFF(-10332684), /* Filter:7, Coefficient: 22 */ + CONVERT_COEFF(10556529), /* Filter:7, Coefficient: 23 */ + CONVERT_COEFF(-7162197), /* Filter:7, Coefficient: 24 */ + CONVERT_COEFF(-12649004), /* Filter:6, Coefficient: 21 */ + CONVERT_COEFF(29813575), /* Filter:6, Coefficient: 22 */ + CONVERT_COEFF(-44081375), /* Filter:6, Coefficient: 23 */ + CONVERT_COEFF(49138162), /* Filter:6, Coefficient: 24 */ + CONVERT_COEFF(-29258606), /* Filter:5, Coefficient: 21 */ + CONVERT_COEFF(10919084), /* Filter:5, Coefficient: 22 */ + CONVERT_COEFF(19020907), /* Filter:5, Coefficient: 23 */ + CONVERT_COEFF(-55343811), /* Filter:5, Coefficient: 24 */ + CONVERT_COEFF(33051579), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(-57937612), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(73731473), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(-71049212), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(52464541), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(-35835631), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(-221654), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(51953451), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(-22361334), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(47518499), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(-67260276), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(72617965), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(-16268114), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(12660525), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(-3194146), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(-11448189), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(-380917), /* Filter:7, Coefficient: 25 */ + CONVERT_COEFF(11434339), /* Filter:7, Coefficient: 26 */ + CONVERT_COEFF(-23628219), /* Filter:7, Coefficient: 27 */ + CONVERT_COEFF(32030513), /* Filter:7, Coefficient: 28 */ + CONVERT_COEFF(-38782554), /* Filter:6, Coefficient: 25 */ + CONVERT_COEFF(8866692), /* Filter:6, Coefficient: 26 */ + CONVERT_COEFF(40253511), /* Filter:6, Coefficient: 27 */ + CONVERT_COEFF(-100091024), /* Filter:6, Coefficient: 28 */ + CONVERT_COEFF(88284037), /* Filter:5, Coefficient: 25 */ + CONVERT_COEFF(-104388358), /* Filter:5, Coefficient: 26 */ + CONVERT_COEFF(88441513), /* Filter:5, Coefficient: 27 */ + CONVERT_COEFF(-26445221), /* Filter:5, Coefficient: 28 */ + CONVERT_COEFF(42410154), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(14925059), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(-96386403), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(187893880), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(-109003806), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(154763074), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(-167878153), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(123866455), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(-55449878), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(10901411), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(60443544), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(-151195441), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(28705285), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(-44216319), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(52284288), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(-46468489), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(-27579775), /* Filter:7, Coefficient: 29 */ + CONVERT_COEFF(944226), /* Filter:7, Coefficient: 30 */ + CONVERT_COEFF(39504750), /* Filter:7, Coefficient: 31 */ + CONVERT_COEFF(-55450763), /* Filter:7, Coefficient: 32 */ + CONVERT_COEFF(146139326), /* Filter:6, Coefficient: 29 */ + CONVERT_COEFF(-125193602), /* Filter:6, Coefficient: 30 */ + CONVERT_COEFF(-8119725), /* Filter:6, Coefficient: 31 */ + CONVERT_COEFF(167052942), /* Filter:6, Coefficient: 32 */ + CONVERT_COEFF(-89102768), /* Filter:5, Coefficient: 29 */ + CONVERT_COEFF(248694534), /* Filter:5, Coefficient: 30 */ + CONVERT_COEFF(-331843959), /* Filter:5, Coefficient: 31 */ + CONVERT_COEFF(152869295), /* Filter:5, Coefficient: 32 */ + CONVERT_COEFF(-262248494), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(259694722), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(54567300), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(-585088494), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(6010978), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(-266538025), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(769027860), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(-550799263), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(246363387), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(-319948913), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(300954467), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(871436613), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(19590070), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(39171518), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(-163170521), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(660899842), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(38104285), /* Filter:7, Coefficient: 33 */ + CONVERT_COEFF(1432784), /* Filter:7, Coefficient: 34 */ + CONVERT_COEFF(-27672195), /* Filter:7, Coefficient: 35 */ + CONVERT_COEFF(31921116), /* Filter:7, Coefficient: 36 */ + CONVERT_COEFF(-224528201), /* Filter:6, Coefficient: 33 */ + CONVERT_COEFF(117817853), /* Filter:6, Coefficient: 34 */ + CONVERT_COEFF(19821501), /* Filter:6, Coefficient: 35 */ + CONVERT_COEFF(-91903193), /* Filter:6, Coefficient: 36 */ + CONVERT_COEFF(215108034), /* Filter:5, Coefficient: 33 */ + CONVERT_COEFF(-360908796), /* Filter:5, Coefficient: 34 */ + CONVERT_COEFF(227085039), /* Filter:5, Coefficient: 35 */ + CONVERT_COEFF(-46451389), /* Filter:5, Coefficient: 36 */ + CONVERT_COEFF(566423159), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(-22644330), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(-290592428), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(278076526), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(-547493323), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(767195769), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(-267778001), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(8458989), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(-871689336), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(-300550035), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(319555239), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(-246162036), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(660899842), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(-163170521), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(39171518), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(19590070), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(-23433614), /* Filter:7, Coefficient: 37 */ + CONVERT_COEFF(11233560), /* Filter:7, Coefficient: 38 */ + CONVERT_COEFF(-223441), /* Filter:7, Coefficient: 39 */ + CONVERT_COEFF(-7253420), /* Filter:7, Coefficient: 40 */ + CONVERT_COEFF(101002885), /* Filter:6, Coefficient: 37 */ + CONVERT_COEFF(-76882874), /* Filter:6, Coefficient: 38 */ + CONVERT_COEFF(40567202), /* Filter:6, Coefficient: 39 */ + CONVERT_COEFF(-5841992), /* Filter:6, Coefficient: 40 */ + CONVERT_COEFF(-64257112), /* Filter:5, Coefficient: 37 */ + CONVERT_COEFF(110837148), /* Filter:5, Coefficient: 38 */ + CONVERT_COEFF(-110758392), /* Filter:5, Coefficient: 39 */ + CONVERT_COEFF(82493642), /* Filter:5, Coefficient: 40 */ + CONVERT_COEFF(-187504747), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(85554391), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(-397767), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(-55476805), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(121745909), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(-166662052), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(154450910), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(-109358640), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(151201064), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(-60582140), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(-10716025), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(55283389), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(-46468489), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(52284288), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(-44216319), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(28705285), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(10580704), /* Filter:7, Coefficient: 41 */ + CONVERT_COEFF(-10304561), /* Filter:7, Coefficient: 42 */ + CONVERT_COEFF(7623908), /* Filter:7, Coefficient: 43 */ + CONVERT_COEFF(-3924457), /* Filter:7, Coefficient: 44 */ + CONVERT_COEFF(-19382377), /* Filter:6, Coefficient: 41 */ + CONVERT_COEFF(32139774), /* Filter:6, Coefficient: 42 */ + CONVERT_COEFF(-33292678), /* Filter:6, Coefficient: 43 */ + CONVERT_COEFF(26137219), /* Filter:6, Coefficient: 44 */ + CONVERT_COEFF(-42829268), /* Filter:5, Coefficient: 41 */ + CONVERT_COEFF(4984408), /* Filter:5, Coefficient: 42 */ + CONVERT_COEFF(22596297), /* Filter:5, Coefficient: 43 */ + CONVERT_COEFF(-36478796), /* Filter:5, Coefficient: 44 */ + CONVERT_COEFF(79727899), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(-77180699), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(56875188), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(-29072432), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(52664560), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(-1000453), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(-35199577), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(52081162), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(-72507573), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(67216590), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(-47532278), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(22412200), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(-11448189), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(-3194146), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(12660525), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(-16268114), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(408527), /* Filter:7, Coefficient: 45 */ + CONVERT_COEFF(2131760), /* Filter:7, Coefficient: 46 */ + CONVERT_COEFF(-3383382), /* Filter:7, Coefficient: 47 */ + CONVERT_COEFF(3446766), /* Filter:7, Coefficient: 48 */ + CONVERT_COEFF(-14928192), /* Filter:6, Coefficient: 45 */ + CONVERT_COEFF(3604808), /* Filter:6, Coefficient: 46 */ + CONVERT_COEFF(5060056), /* Filter:6, Coefficient: 47 */ + CONVERT_COEFF(-9794928), /* Filter:6, Coefficient: 48 */ + CONVERT_COEFF(37496027), /* Filter:5, Coefficient: 45 */ + CONVERT_COEFF(-29308651), /* Filter:5, Coefficient: 46 */ + CONVERT_COEFF(16712649), /* Filter:5, Coefficient: 47 */ + CONVERT_COEFF(-4136967), /* Filter:5, Coefficient: 48 */ + CONVERT_COEFF(2701198), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(16300851), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(-25550339), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(25786949), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(-51410197), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(38626003), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(-20524157), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(3201416), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(514571), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(-16347016), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(23344971), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(-22483689), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(14886324), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(-10331423), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(4676188), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(335976), /* Filter:1, Coefficient: 48 */ + + /* Filter #13, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(-2686276), /* Filter:7, Coefficient: 49 */ + CONVERT_COEFF(1556907), /* Filter:7, Coefficient: 50 */ + CONVERT_COEFF(-458759), /* Filter:7, Coefficient: 51 */ + CONVERT_COEFF(-349838), /* Filter:7, Coefficient: 52 */ + CONVERT_COEFF(10698922), /* Filter:6, Coefficient: 49 */ + CONVERT_COEFF(-8800439), /* Filter:6, Coefficient: 50 */ + CONVERT_COEFF(5504157), /* Filter:6, Coefficient: 51 */ + CONVERT_COEFF(-2104680), /* Filter:6, Coefficient: 52 */ + CONVERT_COEFF(-5353271), /* Filter:5, Coefficient: 49 */ + CONVERT_COEFF(10426821), /* Filter:5, Coefficient: 50 */ + CONVERT_COEFF(-11299744), /* Filter:5, Coefficient: 51 */ + CONVERT_COEFF(9194215), /* Filter:5, Coefficient: 52 */ + CONVERT_COEFF(-19783847), /* Filter:4, Coefficient: 49 */ + CONVERT_COEFF(11038509), /* Filter:4, Coefficient: 50 */ + CONVERT_COEFF(-2643603), /* Filter:4, Coefficient: 51 */ + CONVERT_COEFF(-3406265), /* Filter:4, Coefficient: 52 */ + CONVERT_COEFF(9283532), /* Filter:3, Coefficient: 49 */ + CONVERT_COEFF(-15360523), /* Filter:3, Coefficient: 50 */ + CONVERT_COEFF(15614973), /* Filter:3, Coefficient: 51 */ + CONVERT_COEFF(-11968720), /* Filter:3, Coefficient: 52 */ + CONVERT_COEFF(16437903), /* Filter:2, Coefficient: 49 */ + CONVERT_COEFF(-8395909), /* Filter:2, Coefficient: 50 */ + CONVERT_COEFF(1064109), /* Filter:2, Coefficient: 51 */ + CONVERT_COEFF(3914091), /* Filter:2, Coefficient: 52 */ + CONVERT_COEFF(-3644365), /* Filter:1, Coefficient: 49 */ + CONVERT_COEFF(4952446), /* Filter:1, Coefficient: 50 */ + CONVERT_COEFF(-4582047), /* Filter:1, Coefficient: 51 */ + CONVERT_COEFF(3198988), /* Filter:1, Coefficient: 52 */ + + /* Filter #14, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(773994), /* Filter:7, Coefficient: 53 */ + CONVERT_COEFF(-852306), /* Filter:7, Coefficient: 54 */ + CONVERT_COEFF(699704), /* Filter:7, Coefficient: 55 */ + CONVERT_COEFF(-448245), /* Filter:7, Coefficient: 56 */ + CONVERT_COEFF(-520111), /* Filter:6, Coefficient: 53 */ + CONVERT_COEFF(2004349), /* Filter:6, Coefficient: 54 */ + CONVERT_COEFF(-2415951), /* Filter:6, Coefficient: 55 */ + CONVERT_COEFF(2082258), /* Filter:6, Coefficient: 56 */ + CONVERT_COEFF(-5690292), /* Filter:5, Coefficient: 53 */ + CONVERT_COEFF(2181982), /* Filter:5, Coefficient: 54 */ + CONVERT_COEFF(439695), /* Filter:5, Coefficient: 55 */ + CONVERT_COEFF(-1855684), /* Filter:5, Coefficient: 56 */ + CONVERT_COEFF(6401526), /* Filter:4, Coefficient: 53 */ + CONVERT_COEFF(-6690447), /* Filter:4, Coefficient: 54 */ + CONVERT_COEFF(5225196), /* Filter:4, Coefficient: 55 */ + CONVERT_COEFF(-3082950), /* Filter:4, Coefficient: 56 */ + CONVERT_COEFF(6735661), /* Filter:3, Coefficient: 53 */ + CONVERT_COEFF(-1855964), /* Filter:3, Coefficient: 54 */ + CONVERT_COEFF(-1521598), /* Filter:3, Coefficient: 55 */ + CONVERT_COEFF(3091258), /* Filter:3, Coefficient: 56 */ + CONVERT_COEFF(-6073880), /* Filter:2, Coefficient: 53 */ + CONVERT_COEFF(5876421), /* Filter:2, Coefficient: 54 */ + CONVERT_COEFF(-4268572), /* Filter:2, Coefficient: 55 */ + CONVERT_COEFF(2242351), /* Filter:2, Coefficient: 56 */ + CONVERT_COEFF(-1522163), /* Filter:1, Coefficient: 53 */ + CONVERT_COEFF(104733), /* Filter:1, Coefficient: 54 */ + CONVERT_COEFF(768744), /* Filter:1, Coefficient: 55 */ + CONVERT_COEFF(-1072749), /* Filter:1, Coefficient: 56 */ + + /* Filter #15, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(203843), /* Filter:7, Coefficient: 57 */ + CONVERT_COEFF(-26420), /* Filter:7, Coefficient: 58 */ + CONVERT_COEFF(-68761), /* Filter:7, Coefficient: 59 */ + CONVERT_COEFF(96718), /* Filter:7, Coefficient: 60 */ + CONVERT_COEFF(-1402019), /* Filter:6, Coefficient: 57 */ + CONVERT_COEFF(704429), /* Filter:6, Coefficient: 58 */ + CONVERT_COEFF(-181684), /* Filter:6, Coefficient: 59 */ + CONVERT_COEFF(-110580), /* Filter:6, Coefficient: 60 */ + CONVERT_COEFF(2199202), /* Filter:5, Coefficient: 57 */ + CONVERT_COEFF(-1845730), /* Filter:5, Coefficient: 58 */ + CONVERT_COEFF(1207778), /* Filter:5, Coefficient: 59 */ + CONVERT_COEFF(-596672), /* Filter:5, Coefficient: 60 */ + CONVERT_COEFF(1112474), /* Filter:4, Coefficient: 57 */ + CONVERT_COEFF(227477), /* Filter:4, Coefficient: 58 */ + CONVERT_COEFF(-852533), /* Filter:4, Coefficient: 59 */ + CONVERT_COEFF(926541), /* Filter:4, Coefficient: 60 */ + CONVERT_COEFF(-3174871), /* Filter:3, Coefficient: 57 */ + CONVERT_COEFF(2392005), /* Filter:3, Coefficient: 58 */ + CONVERT_COEFF(-1357177), /* Filter:3, Coefficient: 59 */ + CONVERT_COEFF(491739), /* Filter:3, Coefficient: 60 */ + CONVERT_COEFF(-527993), /* Filter:2, Coefficient: 57 */ + CONVERT_COEFF(-527169), /* Filter:2, Coefficient: 58 */ + CONVERT_COEFF(917240), /* Filter:2, Coefficient: 59 */ + CONVERT_COEFF(-842790), /* Filter:2, Coefficient: 60 */ + CONVERT_COEFF(956210), /* Filter:1, Coefficient: 57 */ + CONVERT_COEFF(-633133), /* Filter:1, Coefficient: 58 */ + CONVERT_COEFF(291450), /* Filter:1, Coefficient: 59 */ + CONVERT_COEFF(-43685), /* Filter:1, Coefficient: 60 */ + + /* Filter #16, conversion from 48000 Hz to 44100 Hz */ + + CONVERT_COEFF(-84837), /* Filter:7, Coefficient: 61 */ + CONVERT_COEFF(58623), /* Filter:7, Coefficient: 62 */ + CONVERT_COEFF(-34394), /* Filter:7, Coefficient: 63 */ + CONVERT_COEFF(-3711660), /* Filter:7, Coefficient: 64 */ + CONVERT_COEFF(210495), /* Filter:6, Coefficient: 61 */ + CONVERT_COEFF(-195186), /* Filter:6, Coefficient: 62 */ + CONVERT_COEFF(137148), /* Filter:6, Coefficient: 63 */ + CONVERT_COEFF(10382357), /* Filter:6, Coefficient: 64 */ + CONVERT_COEFF(170808), /* Filter:5, Coefficient: 61 */ + CONVERT_COEFF(45623), /* Filter:5, Coefficient: 62 */ + CONVERT_COEFF(-107490), /* Filter:5, Coefficient: 63 */ + CONVERT_COEFF(-10759470), /* Filter:5, Coefficient: 64 */ + CONVERT_COEFF(-705509), /* Filter:4, Coefficient: 61 */ + CONVERT_COEFF(414544), /* Filter:4, Coefficient: 62 */ + CONVERT_COEFF(-186990), /* Filter:4, Coefficient: 63 */ + CONVERT_COEFF(5200106), /* Filter:4, Coefficient: 64 */ + CONVERT_COEFF(28928), /* Filter:3, Coefficient: 61 */ + CONVERT_COEFF(-225201), /* Filter:3, Coefficient: 62 */ + CONVERT_COEFF(216708), /* Filter:3, Coefficient: 63 */ + CONVERT_COEFF(-1228780), /* Filter:3, Coefficient: 64 */ + CONVERT_COEFF(560092), /* Filter:2, Coefficient: 61 */ + CONVERT_COEFF(-271537), /* Filter:2, Coefficient: 62 */ + CONVERT_COEFF(79933), /* Filter:2, Coefficient: 63 */ + CONVERT_COEFF(84418), /* Filter:2, Coefficient: 64 */ + CONVERT_COEFF(-78725), /* Filter:1, Coefficient: 61 */ + CONVERT_COEFF(101248), /* Filter:1, Coefficient: 62 */ + CONVERT_COEFF(-71885), /* Filter:1, Coefficient: 63 */ + CONVERT_COEFF(33030), /* Filter:1, Coefficient: 64 */ +}; diff --git a/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_48000Hz.h b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_48000Hz.h new file mode 100644 index 000000000000..af6e1137500f --- /dev/null +++ b/src/audio/asrc/coef/asrc_farrow_coeff_4x_48000Hz_to_48000Hz.h @@ -0,0 +1,382 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2012-2025 Intel Corporation. + */ + +/* Conversion from 48000 Hz to 48000 Hz */ +/* NUM_FILTERS=7, FILTER_LENGTH=48, alpha=7.150000, gamma=0.458000 */ + +__cold_rodata static const int32_t coeff48000to48000[] = { + + /* Filter #1, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(201584), /* Filter:7, Coefficient: 1 */ + CONVERT_COEFF(-337772), /* Filter:7, Coefficient: 2 */ + CONVERT_COEFF(532323), /* Filter:7, Coefficient: 3 */ + CONVERT_COEFF(-781809), /* Filter:7, Coefficient: 4 */ + CONVERT_COEFF(-509717), /* Filter:6, Coefficient: 1 */ + CONVERT_COEFF(901735), /* Filter:6, Coefficient: 2 */ + CONVERT_COEFF(-1563722), /* Filter:6, Coefficient: 3 */ + CONVERT_COEFF(2576238), /* Filter:6, Coefficient: 4 */ + CONVERT_COEFF(-76220), /* Filter:5, Coefficient: 1 */ + CONVERT_COEFF(108575), /* Filter:5, Coefficient: 2 */ + CONVERT_COEFF(38232), /* Filter:5, Coefficient: 3 */ + CONVERT_COEFF(-557092), /* Filter:5, Coefficient: 4 */ + CONVERT_COEFF(427848), /* Filter:4, Coefficient: 1 */ + CONVERT_COEFF(-890617), /* Filter:4, Coefficient: 2 */ + CONVERT_COEFF(1688361), /* Filter:4, Coefficient: 3 */ + CONVERT_COEFF(-2889171), /* Filter:4, Coefficient: 4 */ + CONVERT_COEFF(450982), /* Filter:3, Coefficient: 1 */ + CONVERT_COEFF(-810046), /* Filter:3, Coefficient: 2 */ + CONVERT_COEFF(1143995), /* Filter:3, Coefficient: 3 */ + CONVERT_COEFF(-1251295), /* Filter:3, Coefficient: 4 */ + CONVERT_COEFF(-134205), /* Filter:2, Coefficient: 1 */ + CONVERT_COEFF(408052), /* Filter:2, Coefficient: 2 */ + CONVERT_COEFF(-969157), /* Filter:2, Coefficient: 3 */ + CONVERT_COEFF(1915703), /* Filter:2, Coefficient: 4 */ + CONVERT_COEFF(-119772), /* Filter:1, Coefficient: 1 */ + CONVERT_COEFF(240527), /* Filter:1, Coefficient: 2 */ + CONVERT_COEFF(-379589), /* Filter:1, Coefficient: 3 */ + CONVERT_COEFF(490498), /* Filter:1, Coefficient: 4 */ + + /* Filter #2, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(1063090), /* Filter:7, Coefficient: 5 */ + CONVERT_COEFF(-1325755), /* Filter:7, Coefficient: 6 */ + CONVERT_COEFF(1486665), /* Filter:7, Coefficient: 7 */ + CONVERT_COEFF(-1428619), /* Filter:7, Coefficient: 8 */ + CONVERT_COEFF(-3983820), /* Filter:6, Coefficient: 5 */ + CONVERT_COEFF(5758133), /* Filter:6, Coefficient: 6 */ + CONVERT_COEFF(-7757839), /* Filter:6, Coefficient: 7 */ + CONVERT_COEFF(9692081), /* Filter:6, Coefficient: 8 */ + CONVERT_COEFF(1699253), /* Filter:5, Coefficient: 5 */ + CONVERT_COEFF(-3746237), /* Filter:5, Coefficient: 6 */ + CONVERT_COEFF(6958850), /* Filter:5, Coefficient: 7 */ + CONVERT_COEFF(-11504364), /* Filter:5, Coefficient: 8 */ + CONVERT_COEFF(4484829), /* Filter:4, Coefficient: 5 */ + CONVERT_COEFF(-6340864), /* Filter:4, Coefficient: 6 */ + CONVERT_COEFF(8150817), /* Filter:4, Coefficient: 7 */ + CONVERT_COEFF(-9406444), /* Filter:4, Coefficient: 8 */ + CONVERT_COEFF(828449), /* Filter:3, Coefficient: 5 */ + CONVERT_COEFF(513188), /* Filter:3, Coefficient: 6 */ + CONVERT_COEFF(-3201273), /* Filter:3, Coefficient: 7 */ + CONVERT_COEFF(7625293), /* Filter:3, Coefficient: 8 */ + CONVERT_COEFF(-3299444), /* Filter:2, Coefficient: 5 */ + CONVERT_COEFF(5081025), /* Filter:2, Coefficient: 6 */ + CONVERT_COEFF(-7084841), /* Filter:2, Coefficient: 7 */ + CONVERT_COEFF(8963125), /* Filter:2, Coefficient: 8 */ + CONVERT_COEFF(-496983), /* Filter:1, Coefficient: 5 */ + CONVERT_COEFF(295408), /* Filter:1, Coefficient: 6 */ + CONVERT_COEFF(234925), /* Filter:1, Coefficient: 7 */ + CONVERT_COEFF(-1212831), /* Filter:1, Coefficient: 8 */ + + /* Filter #3, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(1005001), /* Filter:7, Coefficient: 9 */ + CONVERT_COEFF(-51772), /* Filter:7, Coefficient: 10 */ + CONVERT_COEFF(-1592653), /* Filter:7, Coefficient: 11 */ + CONVERT_COEFF(4060025), /* Filter:7, Coefficient: 12 */ + CONVERT_COEFF(-11095974), /* Filter:6, Coefficient: 9 */ + CONVERT_COEFF(11326651), /* Filter:6, Coefficient: 10 */ + CONVERT_COEFF(-9587117), /* Filter:6, Coefficient: 11 */ + CONVERT_COEFF(4982353), /* Filter:6, Coefficient: 12 */ + CONVERT_COEFF(17367482), /* Filter:5, Coefficient: 9 */ + CONVERT_COEFF(-24255226), /* Filter:5, Coefficient: 10 */ + CONVERT_COEFF(31509193), /* Filter:5, Coefficient: 11 */ + CONVERT_COEFF(-38039723), /* Filter:5, Coefficient: 12 */ + CONVERT_COEFF(9395942), /* Filter:4, Coefficient: 9 */ + CONVERT_COEFF(-7240294), /* Filter:4, Coefficient: 10 */ + CONVERT_COEFF(1973428), /* Filter:4, Coefficient: 11 */ + CONVERT_COEFF(7334367), /* Filter:4, Coefficient: 12 */ + CONVERT_COEFF(-14032432), /* Filter:3, Coefficient: 9 */ + CONVERT_COEFF(22406684), /* Filter:3, Coefficient: 10 */ + CONVERT_COEFF(-32346679), /* Filter:3, Coefficient: 11 */ + CONVERT_COEFF(42960394), /* Filter:3, Coefficient: 12 */ + CONVERT_COEFF(-10179847), /* Filter:2, Coefficient: 9 */ + CONVERT_COEFF(10023910), /* Filter:2, Coefficient: 10 */ + CONVERT_COEFF(-7657809), /* Filter:2, Coefficient: 11 */ + CONVERT_COEFF(2202705), /* Filter:2, Coefficient: 12 */ + CONVERT_COEFF(2728545), /* Filter:1, Coefficient: 9 */ + CONVERT_COEFF(-4811819), /* Filter:1, Coefficient: 10 */ + CONVERT_COEFF(7398958), /* Filter:1, Coefficient: 11 */ + CONVERT_COEFF(-10303827), /* Filter:1, Coefficient: 12 */ + + /* Filter #4, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(-7418549), /* Filter:7, Coefficient: 13 */ + CONVERT_COEFF(11634082), /* Filter:7, Coefficient: 14 */ + CONVERT_COEFF(-16526119), /* Filter:7, Coefficient: 15 */ + CONVERT_COEFF(21713991), /* Filter:7, Coefficient: 16 */ + CONVERT_COEFF(3391495), /* Filter:6, Coefficient: 13 */ + CONVERT_COEFF(-16327279), /* Filter:6, Coefficient: 14 */ + CONVERT_COEFF(34359416), /* Filter:6, Coefficient: 15 */ + CONVERT_COEFF(-57585131), /* Filter:6, Coefficient: 16 */ + CONVERT_COEFF(42294622), /* Filter:5, Coefficient: 13 */ + CONVERT_COEFF(-42269640), /* Filter:5, Coefficient: 14 */ + CONVERT_COEFF(35559100), /* Filter:5, Coefficient: 15 */ + CONVERT_COEFF(-19433648), /* Filter:5, Coefficient: 16 */ + CONVERT_COEFF(-21417196), /* Filter:4, Coefficient: 13 */ + CONVERT_COEFF(40631722), /* Filter:4, Coefficient: 14 */ + CONVERT_COEFF(-64768213), /* Filter:4, Coefficient: 15 */ + CONVERT_COEFF(92865281), /* Filter:4, Coefficient: 16 */ + CONVERT_COEFF(-52793804), /* Filter:3, Coefficient: 13 */ + CONVERT_COEFF(59804363), /* Filter:3, Coefficient: 14 */ + CONVERT_COEFF(-61377672), /* Filter:3, Coefficient: 15 */ + CONVERT_COEFF(54364939), /* Filter:3, Coefficient: 16 */ + CONVERT_COEFF(7145457), /* Filter:2, Coefficient: 13 */ + CONVERT_COEFF(-20980397), /* Filter:2, Coefficient: 14 */ + CONVERT_COEFF(39546773), /* Filter:2, Coefficient: 15 */ + CONVERT_COEFF(-62615800), /* Filter:2, Coefficient: 16 */ + CONVERT_COEFF(13197765), /* Filter:1, Coefficient: 13 */ + CONVERT_COEFF(-15601953), /* Filter:1, Coefficient: 14 */ + CONVERT_COEFF(16892782), /* Filter:1, Coefficient: 15 */ + CONVERT_COEFF(-16315753), /* Filter:1, Coefficient: 16 */ + + /* Filter #5, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(-26537520), /* Filter:7, Coefficient: 17 */ + CONVERT_COEFF(29908749), /* Filter:7, Coefficient: 18 */ + CONVERT_COEFF(-29980490), /* Filter:7, Coefficient: 19 */ + CONVERT_COEFF(23337872), /* Filter:7, Coefficient: 20 */ + CONVERT_COEFF(85425357), /* Filter:6, Coefficient: 17 */ + CONVERT_COEFF(-116220246), /* Filter:6, Coefficient: 18 */ + CONVERT_COEFF(146323990), /* Filter:6, Coefficient: 19 */ + CONVERT_COEFF(-167617073), /* Filter:6, Coefficient: 20 */ + CONVERT_COEFF(-9079150), /* Filter:5, Coefficient: 17 */ + CONVERT_COEFF(53136657), /* Filter:5, Coefficient: 18 */ + CONVERT_COEFF(-116017890), /* Filter:5, Coefficient: 19 */ + CONVERT_COEFF(200714461), /* Filter:5, Coefficient: 20 */ + CONVERT_COEFF(-123020997), /* Filter:4, Coefficient: 17 */ + CONVERT_COEFF(152146065), /* Filter:4, Coefficient: 18 */ + CONVERT_COEFF(-175480494), /* Filter:4, Coefficient: 19 */ + CONVERT_COEFF(185308827), /* Filter:4, Coefficient: 20 */ + CONVERT_COEFF(-35083980), /* Filter:3, Coefficient: 17 */ + CONVERT_COEFF(-839184), /* Filter:3, Coefficient: 18 */ + CONVERT_COEFF(59061656), /* Filter:3, Coefficient: 19 */ + CONVERT_COEFF(-148239694), /* Filter:3, Coefficient: 20 */ + CONVERT_COEFF(89388345), /* Filter:2, Coefficient: 17 */ + CONVERT_COEFF(-118423648), /* Filter:2, Coefficient: 18 */ + CONVERT_COEFF(147552056), /* Filter:2, Coefficient: 19 */ + CONVERT_COEFF(-173608580), /* Filter:2, Coefficient: 20 */ + CONVERT_COEFF(12995329), /* Filter:1, Coefficient: 17 */ + CONVERT_COEFF(-5913276), /* Filter:1, Coefficient: 18 */ + CONVERT_COEFF(-6205575), /* Filter:1, Coefficient: 19 */ + CONVERT_COEFF(25256070), /* Filter:1, Coefficient: 20 */ + + /* Filter #6, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(-3217307), /* Filter:7, Coefficient: 21 */ + CONVERT_COEFF(-37038723), /* Filter:7, Coefficient: 22 */ + CONVERT_COEFF(86353009), /* Filter:7, Coefficient: 23 */ + CONVERT_COEFF(-97721939), /* Filter:7, Coefficient: 24 */ + CONVERT_COEFF(160008482), /* Filter:6, Coefficient: 21 */ + CONVERT_COEFF(-78261417), /* Filter:6, Coefficient: 22 */ + CONVERT_COEFF(-112362175), /* Filter:6, Coefficient: 23 */ + CONVERT_COEFF(293242487), /* Filter:6, Coefficient: 24 */ + CONVERT_COEFF(-307335294), /* Filter:5, Coefficient: 21 */ + CONVERT_COEFF(424736994), /* Filter:5, Coefficient: 22 */ + CONVERT_COEFF(-438040128), /* Filter:5, Coefficient: 23 */ + CONVERT_COEFF(198203604), /* Filter:5, Coefficient: 24 */ + CONVERT_COEFF(-166691617), /* Filter:4, Coefficient: 21 */ + CONVERT_COEFF(75780494), /* Filter:4, Coefficient: 22 */ + CONVERT_COEFF(306273762), /* Filter:4, Coefficient: 23 */ + CONVERT_COEFF(-885042156), /* Filter:4, Coefficient: 24 */ + CONVERT_COEFF(284938963), /* Filter:3, Coefficient: 21 */ + CONVERT_COEFF(-508669005), /* Filter:3, Coefficient: 22 */ + CONVERT_COEFF(934119707), /* Filter:3, Coefficient: 23 */ + CONVERT_COEFF(-607381991), /* Filter:3, Coefficient: 24 */ + CONVERT_COEFF(191344927), /* Filter:2, Coefficient: 21 */ + CONVERT_COEFF(-188272598), /* Filter:2, Coefficient: 22 */ + CONVERT_COEFF(107814255), /* Filter:2, Coefficient: 23 */ + CONVERT_COEFF(1098624520), /* Filter:2, Coefficient: 24 */ + CONVERT_COEFF(-54854236), /* Filter:1, Coefficient: 21 */ + CONVERT_COEFF(104205542), /* Filter:1, Coefficient: 22 */ + CONVERT_COEFF(-207541862), /* Filter:1, Coefficient: 23 */ + CONVERT_COEFF(676692041), /* Filter:1, Coefficient: 24 */ + + /* Filter #7, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(85978275), /* Filter:7, Coefficient: 25 */ + CONVERT_COEFF(-36956143), /* Filter:7, Coefficient: 26 */ + CONVERT_COEFF(-3244216), /* Filter:7, Coefficient: 27 */ + CONVERT_COEFF(23345067), /* Filter:7, Coefficient: 28 */ + CONVERT_COEFF(-404403423), /* Filter:6, Coefficient: 25 */ + CONVERT_COEFF(300207629), /* Filter:6, Coefficient: 26 */ + CONVERT_COEFF(-140639902), /* Filter:6, Coefficient: 27 */ + CONVERT_COEFF(27599531), /* Filter:6, Coefficient: 28 */ + CONVERT_COEFF(293327128), /* Filter:5, Coefficient: 25 */ + CONVERT_COEFF(-521588890), /* Filter:5, Coefficient: 26 */ + CONVERT_COEFF(444290293), /* Filter:5, Coefficient: 27 */ + CONVERT_COEFF(-287297861), /* Filter:5, Coefficient: 28 */ + CONVERT_COEFF(844058593), /* Filter:4, Coefficient: 25 */ + CONVERT_COEFF(-251982826), /* Filter:4, Coefficient: 26 */ + CONVERT_COEFF(-139427582), /* Filter:4, Coefficient: 27 */ + CONVERT_COEFF(221132516), /* Filter:4, Coefficient: 28 */ + CONVERT_COEFF(-603949609), /* Filter:3, Coefficient: 25 */ + CONVERT_COEFF(929187271), /* Filter:3, Coefficient: 26 */ + CONVERT_COEFF(-507498526), /* Filter:3, Coefficient: 27 */ + CONVERT_COEFF(285983393), /* Filter:3, Coefficient: 28 */ + CONVERT_COEFF(-1099221720), /* Filter:2, Coefficient: 25 */ + CONVERT_COEFF(-107131260), /* Filter:2, Coefficient: 26 */ + CONVERT_COEFF(187466276), /* Filter:2, Coefficient: 27 */ + CONVERT_COEFF(-190655157), /* Filter:2, Coefficient: 28 */ + CONVERT_COEFF(676692041), /* Filter:1, Coefficient: 25 */ + CONVERT_COEFF(-207541862), /* Filter:1, Coefficient: 26 */ + CONVERT_COEFF(104205542), /* Filter:1, Coefficient: 27 */ + CONVERT_COEFF(-54854236), /* Filter:1, Coefficient: 28 */ + + /* Filter #8, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(-29977934), /* Filter:7, Coefficient: 29 */ + CONVERT_COEFF(29900921), /* Filter:7, Coefficient: 30 */ + CONVERT_COEFF(-26527103), /* Filter:7, Coefficient: 31 */ + CONVERT_COEFF(21702815), /* Filter:7, Coefficient: 32 */ + CONVERT_COEFF(33517333), /* Filter:6, Coefficient: 29 */ + CONVERT_COEFF(-63177333), /* Filter:6, Coefficient: 30 */ + CONVERT_COEFF(73741881), /* Filter:6, Coefficient: 31 */ + CONVERT_COEFF(-72644258), /* Filter:6, Coefficient: 32 */ + CONVERT_COEFF(165959941), /* Filter:5, Coefficient: 29 */ + CONVERT_COEFF(-79430320), /* Filter:5, Coefficient: 30 */ + CONVERT_COEFF(20091574), /* Filter:5, Coefficient: 31 */ + CONVERT_COEFF(18247620), /* Filter:5, Coefficient: 32 */ + CONVERT_COEFF(-224053962), /* Filter:4, Coefficient: 29 */ + CONVERT_COEFF(199362700), /* Filter:4, Coefficient: 30 */ + CONVERT_COEFF(-164221867), /* Filter:4, Coefficient: 31 */ + CONVERT_COEFF(126509506), /* Filter:4, Coefficient: 32 */ + CONVERT_COEFF(-150024800), /* Filter:3, Coefficient: 29 */ + CONVERT_COEFF(60887712), /* Filter:3, Coefficient: 30 */ + CONVERT_COEFF(-2449324), /* Filter:3, Coefficient: 31 */ + CONVERT_COEFF(-33779561), /* Filter:3, Coefficient: 32 */ + CONVERT_COEFF(173118469), /* Filter:2, Coefficient: 29 */ + CONVERT_COEFF(-147250722), /* Filter:2, Coefficient: 30 */ + CONVERT_COEFF(118271995), /* Filter:2, Coefficient: 31 */ + CONVERT_COEFF(-89345383), /* Filter:2, Coefficient: 32 */ + CONVERT_COEFF(25256070), /* Filter:1, Coefficient: 29 */ + CONVERT_COEFF(-6205575), /* Filter:1, Coefficient: 30 */ + CONVERT_COEFF(-5913276), /* Filter:1, Coefficient: 31 */ + CONVERT_COEFF(12995329), /* Filter:1, Coefficient: 32 */ + + /* Filter #9, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(-16515450), /* Filter:7, Coefficient: 33 */ + CONVERT_COEFF(11624746), /* Filter:7, Coefficient: 34 */ + CONVERT_COEFF(-7410994), /* Filter:7, Coefficient: 35 */ + CONVERT_COEFF(4054390), /* Filter:7, Coefficient: 36 */ + CONVERT_COEFF(64749828), /* Filter:6, Coefficient: 33 */ + CONVERT_COEFF(-53438753), /* Filter:6, Coefficient: 34 */ + CONVERT_COEFF(41090862), /* Filter:6, Coefficient: 35 */ + CONVERT_COEFF(-29322557), /* Filter:6, Coefficient: 36 */ + CONVERT_COEFF(-40444649), /* Filter:5, Coefficient: 33 */ + CONVERT_COEFF(50530543), /* Filter:5, Coefficient: 34 */ + CONVERT_COEFF(-51969177), /* Filter:5, Coefficient: 35 */ + CONVERT_COEFF(47732391), /* Filter:5, Coefficient: 36 */ + CONVERT_COEFF(-90610096), /* Filter:4, Coefficient: 33 */ + CONVERT_COEFF(59102310), /* Filter:4, Coefficient: 34 */ + CONVERT_COEFF(-33359574), /* Filter:4, Coefficient: 35 */ + CONVERT_COEFF(13843008), /* Filter:4, Coefficient: 36 */ + CONVERT_COEFF(53381614), /* Filter:3, Coefficient: 33 */ + CONVERT_COEFF(-60692487), /* Filter:3, Coefficient: 34 */ + CONVERT_COEFF(59374033), /* Filter:3, Coefficient: 35 */ + CONVERT_COEFF(-52565904), /* Filter:3, Coefficient: 36 */ + CONVERT_COEFF(62645405), /* Filter:2, Coefficient: 33 */ + CONVERT_COEFF(-39619353), /* Filter:2, Coefficient: 34 */ + CONVERT_COEFF(21073095), /* Filter:2, Coefficient: 35 */ + CONVERT_COEFF(-7241772), /* Filter:2, Coefficient: 36 */ + CONVERT_COEFF(-16315753), /* Filter:1, Coefficient: 33 */ + CONVERT_COEFF(16892782), /* Filter:1, Coefficient: 34 */ + CONVERT_COEFF(-15601953), /* Filter:1, Coefficient: 35 */ + CONVERT_COEFF(13197765), /* Filter:1, Coefficient: 36 */ + + /* Filter #10, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(-1588840), /* Filter:7, Coefficient: 37 */ + CONVERT_COEFF(-54023), /* Filter:7, Coefficient: 38 */ + CONVERT_COEFF(1006037), /* Filter:7, Coefficient: 39 */ + CONVERT_COEFF(-1428806), /* Filter:7, Coefficient: 40 */ + CONVERT_COEFF(19130847), /* Filter:6, Coefficient: 37 */ + CONVERT_COEFF(-11009977), /* Filter:6, Coefficient: 38 */ + CONVERT_COEFF(5064348), /* Filter:6, Coefficient: 39 */ + CONVERT_COEFF(-1121566), /* Filter:6, Coefficient: 40 */ + CONVERT_COEFF(-40290924), /* Filter:5, Coefficient: 37 */ + CONVERT_COEFF(31587996), /* Filter:5, Coefficient: 38 */ + CONVERT_COEFF(-23032529), /* Filter:5, Coefficient: 39 */ + CONVERT_COEFF(15527527), /* Filter:5, Coefficient: 40 */ + CONVERT_COEFF(-316683), /* Filter:4, Coefficient: 37 */ + CONVERT_COEFF(-7949710), /* Filter:4, Coefficient: 38 */ + CONVERT_COEFF(11982264), /* Filter:4, Coefficient: 39 */ + CONVERT_COEFF(-12919307), /* Filter:4, Coefficient: 40 */ + CONVERT_COEFF(42881174), /* Filter:3, Coefficient: 37 */ + CONVERT_COEFF(-32366569), /* Filter:3, Coefficient: 38 */ + CONVERT_COEFF(22483813), /* Filter:3, Coefficient: 39 */ + CONVERT_COEFF(-14134393), /* Filter:3, Coefficient: 40 */ + CONVERT_COEFF(-2113613), /* Filter:2, Coefficient: 37 */ + CONVERT_COEFF(7582042), /* Filter:2, Coefficient: 38 */ + CONVERT_COEFF(-9963872), /* Filter:2, Coefficient: 39 */ + CONVERT_COEFF(10135303), /* Filter:2, Coefficient: 40 */ + CONVERT_COEFF(-10303827), /* Filter:1, Coefficient: 37 */ + CONVERT_COEFF(7398958), /* Filter:1, Coefficient: 38 */ + CONVERT_COEFF(-4811819), /* Filter:1, Coefficient: 39 */ + CONVERT_COEFF(2728545), /* Filter:1, Coefficient: 40 */ + + /* Filter #11, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(1486340), /* Filter:7, Coefficient: 41 */ + CONVERT_COEFF(-1325194), /* Filter:7, Coefficient: 42 */ + CONVERT_COEFF(1062490), /* Filter:7, Coefficient: 43 */ + CONVERT_COEFF(-781289), /* Filter:7, Coefficient: 44 */ + CONVERT_COEFF(-1159486), /* Filter:6, Coefficient: 41 */ + CONVERT_COEFF(2193279), /* Filter:6, Coefficient: 42 */ + CONVERT_COEFF(-2391815), /* Filter:6, Coefficient: 43 */ + CONVERT_COEFF(2112274), /* Filter:6, Coefficient: 44 */ + CONVERT_COEFF(-9534209), /* Filter:5, Coefficient: 41 */ + CONVERT_COEFF(5163088), /* Filter:5, Coefficient: 42 */ + CONVERT_COEFF(-2278340), /* Filter:5, Coefficient: 43 */ + CONVERT_COEFF(600969), /* Filter:5, Coefficient: 44 */ + CONVERT_COEFF(11857857), /* Filter:4, Coefficient: 41 */ + CONVERT_COEFF(-9741790), /* Filter:4, Coefficient: 42 */ + CONVERT_COEFF(7296922), /* Filter:4, Coefficient: 43 */ + CONVERT_COEFF(-5011117), /* Filter:4, Coefficient: 44 */ + CONVERT_COEFF(7729413), /* Filter:3, Coefficient: 41 */ + CONVERT_COEFF(-3293739), /* Filter:3, Coefficient: 42 */ + CONVERT_COEFF(587429), /* Filter:3, Coefficient: 43 */ + CONVERT_COEFF(773723), /* Filter:3, Coefficient: 44 */ + CONVERT_COEFF(-8932187), /* Filter:2, Coefficient: 41 */ + CONVERT_COEFF(7064806), /* Filter:2, Coefficient: 42 */ + CONVERT_COEFF(-5069022), /* Filter:2, Coefficient: 43 */ + CONVERT_COEFF(3292866), /* Filter:2, Coefficient: 44 */ + CONVERT_COEFF(-1212831), /* Filter:1, Coefficient: 41 */ + CONVERT_COEFF(234925), /* Filter:1, Coefficient: 42 */ + CONVERT_COEFF(295408), /* Filter:1, Coefficient: 43 */ + CONVERT_COEFF(-496983), /* Filter:1, Coefficient: 44 */ + + /* Filter #12, conversion from 48000 Hz to 48000 Hz */ + + CONVERT_COEFF(531937), /* Filter:7, Coefficient: 45 */ + CONVERT_COEFF(-337523), /* Filter:7, Coefficient: 46 */ + CONVERT_COEFF(201449), /* Filter:7, Coefficient: 47 */ + CONVERT_COEFF(-12084314), /* Filter:7, Coefficient: 48 */ + CONVERT_COEFF(-1628548), /* Filter:6, Coefficient: 45 */ + CONVERT_COEFF(1123843), /* Filter:6, Coefficient: 46 */ + CONVERT_COEFF(-699211), /* Filter:6, Coefficient: 47 */ + CONVERT_COEFF(35988267), /* Filter:6, Coefficient: 48 */ + CONVERT_COEFF(201557), /* Filter:5, Coefficient: 45 */ + CONVERT_COEFF(-447451), /* Filter:5, Coefficient: 46 */ + CONVERT_COEFF(397902), /* Filter:5, Coefficient: 47 */ + CONVERT_COEFF(-39316590), /* Filter:5, Coefficient: 48 */ + CONVERT_COEFF(3151503), /* Filter:4, Coefficient: 45 */ + CONVERT_COEFF(-1807037), /* Filter:4, Coefficient: 46 */ + CONVERT_COEFF(943390), /* Filter:4, Coefficient: 47 */ + CONVERT_COEFF(18887301), /* Filter:4, Coefficient: 48 */ + CONVERT_COEFF(-1214047), /* Filter:3, Coefficient: 45 */ + CONVERT_COEFF(1120557), /* Filter:3, Coefficient: 46 */ + CONVERT_COEFF(-796401), /* Filter:3, Coefficient: 47 */ + CONVERT_COEFF(-3816331), /* Filter:3, Coefficient: 48 */ + CONVERT_COEFF(-1912448), /* Filter:2, Coefficient: 45 */ + CONVERT_COEFF(967701), /* Filter:2, Coefficient: 46 */ + CONVERT_COEFF(-407415), /* Filter:2, Coefficient: 47 */ + CONVERT_COEFF(461439), /* Filter:2, Coefficient: 48 */ + CONVERT_COEFF(490498), /* Filter:1, Coefficient: 45 */ + CONVERT_COEFF(-379589), /* Filter:1, Coefficient: 46 */ + CONVERT_COEFF(240527), /* Filter:1, Coefficient: 47 */ + CONVERT_COEFF(-119772), /* Filter:1, Coefficient: 48 */ +}; diff --git a/src/audio/asrc/llext/CMakeLists.txt b/src/audio/asrc/llext/CMakeLists.txt index 8ef1d2e26fa6..27d5889d166a 100644 --- a/src/audio/asrc/llext/CMakeLists.txt +++ b/src/audio/asrc/llext/CMakeLists.txt @@ -4,6 +4,7 @@ sof_llext_build("asrc" SOURCES ../asrc.c ../asrc_farrow_hifi3.c + ../asrc_farrow_hifi5.c ../asrc_farrow.c ../asrc_farrow_generic.c ../asrc_ipc4.c diff --git a/src/audio/audio_stream.c b/src/audio/audio_stream.c index ede9f7922a8a..aa16617f066c 100644 --- a/src/audio/audio_stream.c +++ b/src/audio/audio_stream.c @@ -20,7 +20,6 @@ static uint32_t audio_stream_frame_align_get(const uint32_t byte_align, return frame_align_req * frame_num / gcd(frame_num, frame_align_req); } - void audio_stream_recalc_align(struct audio_stream *stream) { const uint32_t byte_align = stream->byte_align_req; @@ -34,6 +33,7 @@ void audio_stream_recalc_align(struct audio_stream *stream) stream->runtime_stream_params.align_shift_idx = (is_power_of_2(process_size) ? 31 : 32) - clz(process_size); } +EXPORT_SYMBOL(audio_stream_recalc_align); void audio_stream_set_align(const uint32_t byte_align, const uint32_t frame_align_req, @@ -44,12 +44,13 @@ void audio_stream_set_align(const uint32_t byte_align, audio_stream_recalc_align(stream); } EXPORT_SYMBOL(audio_stream_set_align); + void audio_stream_init(struct audio_stream *audio_stream, void *buff_addr, uint32_t size) { audio_stream->size = size; audio_stream->addr = buff_addr; audio_stream->end_addr = (char *)audio_stream->addr + size; - audio_stream_set_align(1, 1, audio_stream); + audio_stream_set_align(SOF_FRAME_BYTE_ALIGN, SOF_FRAME_COUNT_ALIGN, audio_stream); audio_stream_reset(audio_stream); } diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index ea495a433a0e..b03b97ad998e 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -11,7 +11,9 @@ #include <ipc4/base_fw_vendor.h> #include <ipc4/pipeline.h> #include <ipc4/logging.h> +#include <ipc4/notification.h> #include <ipc/topology.h> +#include <ipc/compress_params.h> #include <sof_versions.h> #include <sof/lib/cpu-clk-manager.h> #include <sof/lib/cpu.h> @@ -44,7 +46,95 @@ DECLARE_TR_CTX(basefw_comp_tr, SOF_UUID(basefw_uuid), LOG_LEVEL_INFO); static struct ipc4_system_time_info global_system_time_info; static uint64_t global_cycle_delta; -static int basefw_config(uint32_t *data_offset, char *data) +__cold static uint32_t get_host_buffer_size(void) +{ + struct sof_dma *dma_host; + uint32_t periods; + + assert_can_be_cold(); + + dma_host = sof_dma_get(SOF_DMA_DIR_HMEM_TO_LMEM, 0, SOF_DMA_DEV_HOST, + SOF_DMA_ACCESS_SHARED); + if (!dma_host) { + LOG_WRN("Failed to get host DMA channel"); + return 0; + } + + periods = dma_host->plat_data.period_count; + + sof_dma_put(dma_host); + + return periods; +} + +struct sof_ipc4_codec_info_data { + uint32_t count; + uint32_t items[32]; +} __packed __aligned(4); + +/** + * Encodes codec and direction information into a single 32-bit value. + * @param codec Codec type (bits 0-7) + * @param dir Stream direction (bits 8-11) + * @return Encoded 32-bit value + */ +#define SET_CODEC_INFO_ITEM(codec, dir) (((codec) & 0xff) | (((dir) & 0xf) << 8)) + +static void get_codec_info(struct sof_tlv **tuple) +{ + struct sof_ipc4_codec_info_data codec_info = { 0 }; + +#ifdef CONFIG_CADENCE_CODEC_AAC_DEC + codec_info.items[codec_info.count++] = + SET_CODEC_INFO_ITEM(SND_AUDIOCODEC_AAC, SOF_IPC_STREAM_PLAYBACK); +#endif +#ifdef CONFIG_CADENCE_CODEC_MP3_DEC + codec_info.items[codec_info.count++] = + SET_CODEC_INFO_ITEM(SND_AUDIOCODEC_MP3, SOF_IPC_STREAM_PLAYBACK); +#endif +#ifdef CONFIG_CADENCE_CODEC_MP3_ENC + codec_info.items[codec_info.count++] = + SET_CODEC_INFO_ITEM(SND_AUDIOCODEC_MP3, SOF_IPC_STREAM_CAPTURE); +#endif +#ifdef CONFIG_CADENCE_CODEC_VORBIS_DEC + codec_info.items[codec_info.count++] = + SET_CODEC_INFO_ITEM(SND_AUDIOCODEC_VORBIS, SOF_IPC_STREAM_PLAYBACK); +#endif +#ifdef CONFIG_COMP_MFCC + codec_info.items[codec_info.count++] = + SET_CODEC_INFO_ITEM(SND_AUDIOCODEC_BESPOKE, SOF_IPC_STREAM_CAPTURE); +#endif + + if (!codec_info.count) + return; + + tlv_value_set(*tuple, IPC4_SOF_CODEC_INFO, sizeof(codec_info.count) + + sizeof(codec_info.items[0]) * codec_info.count, &codec_info); + + *tuple = tlv_next(*tuple); +} + +#define SOF_CONFIG_MEMBER_SIZE(struct_name) (sizeof(struct sof_tlv) + \ + sizeof(struct struct_name)) +#define SOF_CONFIG_SIZE_MAX (SOF_CONFIG_MEMBER_SIZE(sof_ipc4_codec_info_data)) + +static void base_fw_sof_config(struct sof_tlv **tuple) +{ + char sof_config_data[SOF_CONFIG_SIZE_MAX] = { 0 }; + struct sof_tlv *sof_config_tuple = (struct sof_tlv *)sof_config_data; + uint32_t sof_config_size; + + get_codec_info(&sof_config_tuple); + sof_config_size = (uint32_t)((char *)sof_config_tuple - sof_config_data); + if (sof_config_size == 0) + return; + + tlv_value_set(*tuple, IPC4_FW_SOF_INFO, sof_config_size, sof_config_data); + + *tuple = tlv_next(*tuple); +} + +__cold static int basefw_config(uint32_t *data_offset, char *data) { uint16_t version[4] = {SOF_MAJOR, SOF_MINOR, SOF_MICRO, SOF_BUILD}; struct sof_tlv *tuple = (struct sof_tlv *)data; @@ -52,6 +142,8 @@ static int basefw_config(uint32_t *data_offset, char *data) uint32_t plat_data_offset = 0; uint32_t log_bytes_size = 0; + assert_can_be_cold(); + tlv_value_set(tuple, IPC4_FW_VERSION_FW_CFG, sizeof(version), version); tuple = tlv_next(tuple); @@ -122,6 +214,13 @@ static int basefw_config(uint32_t *data_offset, char *data) tuple = tlv_next(tuple); + tlv_value_uint32_set(tuple, IPC4_FW_MIN_HOST_BUFFER_PERIODS, + get_host_buffer_size()); + + tuple = tlv_next(tuple); + + base_fw_sof_config(&tuple); + /* add platform specific tuples */ basefw_vendor_fw_config(&plat_data_offset, (char *)tuple); @@ -130,11 +229,13 @@ static int basefw_config(uint32_t *data_offset, char *data) return IPC4_SUCCESS; } -static int basefw_hw_config(uint32_t *data_offset, char *data) +__cold static int basefw_hw_config(uint32_t *data_offset, char *data) { struct sof_tlv *tuple = (struct sof_tlv *)data; uint32_t plat_data_offset = 0; + assert_can_be_cold(); + tlv_value_uint32_set(tuple, IPC4_CAVS_VER_HW_CFG, HW_CFG_VERSION); tuple = tlv_next(tuple); @@ -154,30 +255,35 @@ static int basefw_hw_config(uint32_t *data_offset, char *data) return IPC4_SUCCESS; } -struct ipc4_system_time_info *basefw_get_system_time_info(void) +__cold struct ipc4_system_time_info *basefw_get_system_time_info(void) { + assert_can_be_cold(); + return &global_system_time_info; } +/* Cannot be cold - this function is called from the logger per log_set_timestamp_func() below */ static log_timestamp_t basefw_get_timestamp(void) { return sof_cycle_get_64() + global_cycle_delta; } -static uint32_t basefw_set_system_time(uint32_t param_id, - bool first_block, - bool last_block, - uint32_t data_offset, - const char *data) +__cold static uint32_t basefw_set_system_time(uint32_t param_id, bool first_block, bool last_block, + uint32_t data_offset, const char *data) { uint64_t dsp_time; uint64_t dsp_cycle; uint64_t host_time; uint64_t host_cycle; + assert_can_be_cold(); + if (!(first_block && last_block)) return IPC4_INVALID_REQUEST; + if (data_offset < sizeof(struct ipc4_system_time)) + return IPC4_ERROR_INVALID_PARAM; + global_system_time_info.host_time.val_l = ((const struct ipc4_system_time *)data)->val_l; global_system_time_info.host_time.val_u = ((const struct ipc4_system_time *)data)->val_u; @@ -203,25 +309,32 @@ static uint32_t basefw_set_system_time(uint32_t param_id, return IPC4_SUCCESS; } -static uint32_t basefw_get_system_time(uint32_t *data_offset, char *data) +__cold static uint32_t basefw_get_system_time(uint32_t *data_offset, char *data) { struct ipc4_system_time *system_time = (struct ipc4_system_time *)data; + assert_can_be_cold(); + system_time->val_l = global_system_time_info.host_time.val_l; system_time->val_u = global_system_time_info.host_time.val_u; *data_offset = sizeof(struct ipc4_system_time); return IPC4_SUCCESS; } -static int basefw_register_kcps(bool first_block, - bool last_block, - uint32_t data_offset_or_size, - const char *data) +__cold static int basefw_register_kcps(bool first_block, bool last_block, + uint32_t data_offset_or_size, const char *data) { + assert_can_be_cold(); + if (!(first_block && last_block)) return IPC4_ERROR_INVALID_PARAM; #if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL + if (data_offset_or_size < sizeof(int32_t)) { + tr_err(&ipc_tr, "basefw_register_kcps: payload too small: %u", data_offset_or_size); + return IPC4_ERROR_INVALID_PARAM; + } + /* value of kcps to request on core 0. Can be negative */ if (core_kcps_adjust(0, *(int32_t *)data)) return IPC4_ERROR_INVALID_PARAM; @@ -230,9 +343,17 @@ static int basefw_register_kcps(bool first_block, return IPC4_SUCCESS; } -static int basefw_kcps_allocation_request(struct ipc4_resource_kcps *request) +__cold static int basefw_kcps_allocation_request(struct ipc4_resource_kcps *request) { + assert_can_be_cold(); + #if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL + if (request->core_id >= CONFIG_CORE_COUNT) { + tr_err(&ipc_tr, "invalid core_id %u", + request->core_id); + return IPC4_ERROR_INVALID_PARAM; + } + if (core_kcps_adjust(request->core_id, request->kcps)) return IPC4_ERROR_INVALID_PARAM; #endif @@ -240,16 +361,22 @@ static int basefw_kcps_allocation_request(struct ipc4_resource_kcps *request) return IPC4_SUCCESS; } -static int basefw_resource_allocation_request(bool first_block, - bool last_block, - uint32_t data_offset_or_size, - const char *data) +__cold static int basefw_resource_allocation_request(bool first_block, bool last_block, + uint32_t data_offset_or_size, const char *data) { struct ipc4_resource_request *request; + assert_can_be_cold(); + if (!(first_block && last_block)) return IPC4_ERROR_INVALID_PARAM; + if (data_offset_or_size < sizeof(struct ipc4_resource_request)) { + tr_err(&ipc_tr, "basefw_resource_allocation_request: payload too small: %u < %zu", + data_offset_or_size, sizeof(struct ipc4_resource_request)); + return IPC4_ERROR_INVALID_PARAM; + } + request = (struct ipc4_resource_request *)data; switch (request->ra_type) { @@ -262,8 +389,10 @@ static int basefw_resource_allocation_request(bool first_block, } } -static int basefw_power_state_info_get(uint32_t *data_offset, char *data) +__cold static int basefw_power_state_info_get(uint32_t *data_offset, char *data) { + assert_can_be_cold(); + #if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL struct sof_tlv *tuple = (struct sof_tlv *)data; uint32_t core_kcps[CONFIG_CORE_COUNT] = {0}; @@ -286,8 +415,10 @@ static int basefw_power_state_info_get(uint32_t *data_offset, char *data) #endif } -static int basefw_libraries_info_get(uint32_t *data_offset, char *data) +__cold static int basefw_libraries_info_get(uint32_t *data_offset, char *data) { + assert_can_be_cold(); + if (sizeof(struct ipc4_libraries_info) + LIB_MANAGER_MAX_LIBS * sizeof(struct ipc4_library_props) > SOF_IPC_MSG_MAX_SIZE) { @@ -304,7 +435,7 @@ static int basefw_libraries_info_get(uint32_t *data_offset, char *data) desc = basefw_vendor_get_manifest(); } else { #if CONFIG_LIBRARY_MANAGER - desc = (struct sof_man_fw_desc *)lib_manager_get_library_manifest(lib_id); + desc = lib_manager_get_library_manifest(LIB_MANAGER_PACK_LIB_ID(lib_id)); #else desc = NULL; #endif @@ -313,7 +444,7 @@ static int basefw_libraries_info_get(uint32_t *data_offset, char *data) if (!desc) continue; - libs_info->libraries[lib_id].id = lib_id; + libs_info->libraries[lib_counter].id = lib_id; memcpy_s(libs_info->libraries[lib_counter].name, SOF_MAN_FW_HDR_FW_NAME_LEN, desc->header.name, sizeof(desc->header.name)); libs_info->libraries[lib_counter].major_version = @@ -332,20 +463,22 @@ static int basefw_libraries_info_get(uint32_t *data_offset, char *data) libs_info->library_count = lib_counter; *data_offset = - sizeof(libs_info) + libs_info->library_count * sizeof(libs_info->libraries[0]); + sizeof(*libs_info) + libs_info->library_count * sizeof(libs_info->libraries[0]); return IPC4_SUCCESS; } -static int basefw_modules_info_get(uint32_t *data_offset, char *data) +__cold static int basefw_modules_info_get(uint32_t *data_offset, char *data) { + assert_can_be_cold(); + return basefw_vendor_modules_info_get(data_offset, data); } -int schedulers_info_get(uint32_t *data_off_size, - char *data, - uint32_t core_id) +__cold int schedulers_info_get(uint32_t *data_off_size, char *data, uint32_t core_id) { + assert_can_be_cold(); + /* Check if the requested core_id is valid and within the number of configured cores */ if (core_id >= CONFIG_CORE_COUNT) return IPC4_ERROR_INVALID_PARAM; @@ -382,7 +515,7 @@ int schedulers_info_get(uint32_t *data_off_size, return IPC4_SUCCESS; } -static int basefw_pipeline_list_info_get(uint32_t *data_offset, char *data) +__cold static int basefw_pipeline_list_info_get(uint32_t *data_offset, char *data) { struct ipc4_pipeline_set_state_data *ppl_data = (struct ipc4_pipeline_set_state_data *)data; @@ -390,6 +523,8 @@ static int basefw_pipeline_list_info_get(uint32_t *data_offset, char *data) struct ipc_comp_dev *ipc_pipe; const struct ipc4_pipeline_set_state_data *pipeline_data; + assert_can_be_cold(); + pipeline_data = ipc4_get_pipeline_data_wrapper(); ppl_data->pipelines_count = 0; @@ -407,10 +542,17 @@ static int basefw_pipeline_list_info_get(uint32_t *data_offset, char *data) return IPC4_SUCCESS; } -int set_perf_meas_state(const char *data) +__cold int set_perf_meas_state(uint32_t data_size, const uint8_t *data) { + assert_can_be_cold(); + #ifdef CONFIG_SOF_TELEMETRY - enum ipc4_perf_measurements_state_set state = *data; + if (data_size < sizeof(*data)) { + tr_err(&ipc_tr, "set_perf_meas_state: payload too small: %u", data_size); + return IPC4_ERROR_INVALID_PARAM; + } + + uint8_t state = *data; switch (state) { case IPC4_PERF_MEASUREMENTS_DISABLED: @@ -419,8 +561,8 @@ int set_perf_meas_state(const char *data) break; case IPC4_PERF_MEASUREMENTS_STOPPED: enable_performance_counters(); - reset_performance_counters(); perf_meas_set_state(IPC4_PERF_MEASUREMENTS_STOPPED); + reset_performance_counters(); break; case IPC4_PERF_MEASUREMENTS_STARTED: enable_performance_counters(); @@ -437,8 +579,10 @@ int set_perf_meas_state(const char *data) return IPC4_SUCCESS; } -static int extended_global_perf_data_get(uint32_t *data_off_size, char *data) +__cold static int extended_global_perf_data_get(uint32_t *data_off_size, char *data) { + assert_can_be_cold(); + #ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS int ret; struct extended_global_perf_data *perf_data = (struct extended_global_perf_data *)data; @@ -455,8 +599,10 @@ static int extended_global_perf_data_get(uint32_t *data_off_size, char *data) #endif } -static int global_perf_data_get(uint32_t *data_off_size, char *data) +__cold static int global_perf_data_get(uint32_t *data_off_size, char *data) { + assert_can_be_cold(); + #ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS int ret; struct global_perf_data *perf_data = (struct global_perf_data *)data; @@ -473,8 +619,10 @@ static int global_perf_data_get(uint32_t *data_off_size, char *data) #endif } -static int io_global_perf_state_get(uint32_t *data_off_size, char *data) +__cold static int io_global_perf_state_get(uint32_t *data_off_size, char *data) { + assert_can_be_cold(); + #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS *data = io_perf_monitor_get_state(); *data_off_size = sizeof(enum ipc4_perf_measurements_state_set); @@ -485,8 +633,10 @@ static int io_global_perf_state_get(uint32_t *data_off_size, char *data) #endif } -static int io_global_perf_data_get(uint32_t *data_off_size, char *data) +__cold static int io_global_perf_data_get(uint32_t *data_off_size, char *data) { + assert_can_be_cold(); + #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS int ret; struct io_global_perf_data *perf_data = (struct io_global_perf_data *)data; @@ -503,25 +653,31 @@ static int io_global_perf_data_get(uint32_t *data_off_size, char *data) #endif } -static int io_perf_monitor_state_set(const char *data) +__cold static int io_perf_monitor_state_set(uint32_t data_size, const uint8_t *data) { + assert_can_be_cold(); + #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS - return io_perf_monitor_set_state((enum ipc4_perf_measurements_state_set)*data); + if (data_size < sizeof(*data)) { + tr_err(&ipc_tr, "io_perf_monitor_state_set: payload too small: %u", data_size); + return IPC4_ERROR_INVALID_PARAM; + } + + return io_perf_monitor_set_state(*data); #else return IPC4_UNAVAILABLE; #endif } -static int basefw_get_large_config(struct comp_dev *dev, - uint32_t param_id, - bool first_block, - bool last_block, - uint32_t *data_offset, - char *data) +__cold static int basefw_get_large_config(struct comp_dev *dev, uint32_t param_id, + bool first_block, bool last_block, + uint32_t *data_offset, char *data) { /* We can use extended param id for both extended and standard param id */ union ipc4_extended_param_id extended_param_id; + assert_can_be_cold(); + extended_param_id.full = param_id; switch (extended_param_id.part.parameter_type) { @@ -575,6 +731,33 @@ static int basefw_get_large_config(struct comp_dev *dev, data_offset, data); }; +__cold static int basefw_notification_mask_info(uint32_t data_size, const void *data) +{ + const struct ipc4_notification_mask_info *mask_info = data; + + assert_can_be_cold(); + + if (data_size < sizeof(struct ipc4_notification_mask_info)) { + tr_err(&ipc_tr, "basefw_notification_mask_info: payload too small: %u < %zu", + data_size, sizeof(struct ipc4_notification_mask_info)); + return IPC4_ERROR_INVALID_PARAM; + } + + ipc4_update_notification_mask(mask_info->ntfy_mask, mask_info->enabled_mask); + + return IPC4_SUCCESS; +} + +__cold static int basefw_astate_table(void) +{ + assert_can_be_cold(); + + /* Trivial handler possible due to an empty Astate Table requested in get_large_config */ + STATIC_ASSERT(IPC4_MAX_CLK_STATES == 0, IPC4_NON_ZERO_ASTATE_UNSUPPORTED); + + return IPC4_SUCCESS; +} + /** * Handles the DMA Control IPC message to initialize or modify DMA gateway configuration. * @@ -584,15 +767,15 @@ static int basefw_get_large_config(struct comp_dev *dev, * @param data Pointer to the data buffer containing the DMA Control message. * @return 0 on success, error code on failure. */ -static int basefw_dma_control(bool first_block, - bool last_block, - uint32_t data_offset, - const char *data) +__cold static int basefw_dma_control(bool first_block, bool last_block, uint32_t data_offset, + const char *data) { struct ipc4_dma_control *dma_control; size_t data_size; int ret; + assert_can_be_cold(); + /* Ensure that the message is atomic and contains all necessary information */ if (!first_block || !last_block) { tr_err(&ipc_tr, "Non-atomic DMA Control message received"); @@ -600,6 +783,13 @@ static int basefw_dma_control(bool first_block, } dma_control = (struct ipc4_dma_control *)data; + + /* data_offset must cover the fixed header before computing the payload size */ + if (data_offset < sizeof(struct ipc4_dma_control)) { + tr_err(&ipc_tr, "DMA Control message too short: %u", data_offset); + return IPC4_ERROR_INVALID_PARAM; + } + data_size = data_offset - sizeof(struct ipc4_dma_control); if (data_size < (dma_control->config_length * sizeof(uint32_t))) { @@ -619,20 +809,23 @@ static int basefw_dma_control(bool first_block, return IPC4_SUCCESS; } -static int basefw_set_large_config(struct comp_dev *dev, - uint32_t param_id, - bool first_block, - bool last_block, - uint32_t data_offset, - const char *data) +__cold static int basefw_set_large_config(struct comp_dev *dev, uint32_t param_id, + bool first_block, bool last_block, + uint32_t data_offset, const char *data) { + assert_can_be_cold(); + switch (param_id) { + case IPC4_NOTIFICATION_MASK: + return basefw_notification_mask_info(data_offset, data); + case IPC4_ASTATE_TABLE: + return basefw_astate_table(); case IPC4_DMA_CONTROL: return basefw_dma_control(first_block, last_block, data_offset, data); case IPC4_PERF_MEASUREMENTS_STATE: - return set_perf_meas_state(data); + return set_perf_meas_state(data_offset, (const uint8_t *)data); case IPC4_IO_PERF_MEASUREMENTS_STATE: - return io_perf_monitor_state_set(data); + return io_perf_monitor_state_set(data_offset, (const uint8_t *)data); case IPC4_SYSTEM_TIME: return basefw_set_system_time(param_id, first_block, last_block, data_offset, data); @@ -666,8 +859,7 @@ static SHARED_DATA struct comp_driver_info comp_basefw_info = { UT_STATIC void sys_comp_basefw_init(void) { - comp_register(platform_shared_get(&comp_basefw_info, - sizeof(comp_basefw_info))); + comp_register(&comp_basefw_info); } DECLARE_MODULE(sys_comp_basefw_init); diff --git a/src/audio/base_fw_intel.c b/src/audio/base_fw_intel.c index 5c38d07960cc..bcb9fca8e1f2 100644 --- a/src/audio/base_fw_intel.c +++ b/src/audio/base_fw_intel.c @@ -22,17 +22,30 @@ #include <zephyr/pm/device_runtime.h> #include <sof/lib/memory.h> +#include <sof/lib_manager.h> #include <ipc4/base_fw.h> #include <ipc4/alh.h> #include <rimage/sof/user/manifest.h> #include "copier/copier_gain.h" +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include <sof/audio/mic_privacy_manager.h> +#endif + +#if CONFIG_UAOL_INTEL_ADSP +#include <sof/audio/intel_uaol.h> +#endif + struct ipc4_modules_info { uint32_t modules_count; struct sof_man_module modules[0]; } __packed __aligned(4); +/* Sanity check because a subtraction of those sizes is performed later on */ +STATIC_ASSERT(sizeof(struct ipc4_modules_info) < SOF_IPC_MSG_MAX_SIZE, + invalid_modules_info_struct_size); + /* * TODO: default to value of ACE1.x platforms. This is defined * in multiple places in Zephyr, mm_drv_intel_adsp.h and @@ -54,14 +67,16 @@ struct ipc4_modules_info { LOG_MODULE_REGISTER(basefw_intel, CONFIG_SOF_LOG_LEVEL); -int basefw_vendor_fw_config(uint32_t *data_offset, char *data) +__cold int basefw_vendor_fw_config(uint32_t *data_offset, char *data) { struct sof_tlv *tuple = (struct sof_tlv *)data; + assert_can_be_cold(); + tlv_value_uint32_set(tuple, IPC4_SLOW_CLOCK_FREQ_HZ_FW_CFG, IPC4_ALH_CAVS_1_8); tuple = tlv_next(tuple); - tlv_value_uint32_set(tuple, IPC4_UAOL_SUPPORT, 0); + tlv_value_uint32_set(tuple, IPC4_UAOL_SUPPORT, IS_ENABLED(CONFIG_UAOL_INTEL_ADSP)); tuple = tlv_next(tuple); tlv_value_uint32_set(tuple, IPC4_ALH_SUPPORT_LEVEL_FW_CFG, IPC4_ALH_CAVS_1_8); @@ -72,11 +87,13 @@ int basefw_vendor_fw_config(uint32_t *data_offset, char *data) return 0; } -int basefw_vendor_hw_config(uint32_t *data_offset, char *data) +__cold int basefw_vendor_hw_config(uint32_t *data_offset, char *data) { struct sof_tlv *tuple = (struct sof_tlv *)data; uint32_t value; + assert_can_be_cold(); + tlv_value_uint32_set(tuple, IPC4_HP_EBB_COUNT_HW_CFG, PLATFORM_HPSRAM_EBB_COUNT); tuple = tlv_next(tuple); @@ -95,53 +112,104 @@ int basefw_vendor_hw_config(uint32_t *data_offset, char *data) tuple = tlv_next(tuple); tlv_value_uint32_set(tuple, IPC4_LP_EBB_COUNT_HW_CFG, PLATFORM_LPSRAM_EBB_COUNT); -#ifdef CONFIG_SOC_INTEL_ACE30 +#if defined(CONFIG_SOC_ACE30) || defined(CONFIG_SOC_ACE40) tuple = tlv_next(tuple); tlv_value_uint32_set(tuple, IPC4_I2S_CAPS_HW_CFG, I2S_VER_30_PTL); #endif +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + struct privacy_capabilities priv_caps; + + tuple = tlv_next(tuple); + + priv_caps.privacy_version = 1; + priv_caps.capabilities_length = 1; + priv_caps.capabilities[0] = mic_privacy_get_policy_register(); + + tlv_value_set(tuple, IPC4_INTEL_MIC_PRIVACY_CAPS_HW_CFG, sizeof(priv_caps), &priv_caps); +#endif + + /* Linux 7.0 and older do not enable UAOL for any Intel + * hardware, so below capability check will lead to a DSP + * panic. In strict compatibility mode, bypass the capability + * check. */ +#if !defined(CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY) && defined(CONFIG_UAOL_INTEL_ADSP) + tuple = tlv_next(tuple); + tlv_value_set_uaol_caps(tuple, IPC4_UAOL_CAPS_HW_CFG); +#endif + tuple = tlv_next(tuple); *data_offset = (int)((char *)tuple - data); return 0; } -struct sof_man_fw_desc *basefw_vendor_get_manifest(void) +__cold struct sof_man_fw_desc *basefw_vendor_get_manifest(void) { - struct sof_man_fw_desc *desc; - - desc = (struct sof_man_fw_desc *)IMR_BOOT_LDR_MANIFEST_BASE; + assert_can_be_cold(); - return desc; + return (struct sof_man_fw_desc *)IMR_BOOT_LDR_MANIFEST_BASE; } -int basefw_vendor_modules_info_get(uint32_t *data_offset, char *data) +__cold int basefw_vendor_modules_info_get(uint32_t *data_offset, char *data) { + assert_can_be_cold(); + struct ipc4_modules_info *const module_info = (struct ipc4_modules_info *)data; - struct sof_man_fw_desc *desc = basefw_vendor_get_manifest(); + const struct sof_man_fw_desc *desc; + uint32_t curr_mod_cnt, curr_cpy_size, total_mod_cnt = 0; + uint32_t total_size_left = SOF_IPC_MSG_MAX_SIZE - sizeof(struct ipc4_modules_info); + int ret; + + for (int lib_id = 0; lib_id < LIB_MANAGER_MAX_LIBS; ++lib_id) { + if (lib_id == 0) { + desc = basefw_vendor_get_manifest(); + } else { +#if CONFIG_LIBRARY_MANAGER + desc = lib_manager_get_library_manifest(LIB_MANAGER_PACK_LIB_ID(lib_id)); +#else + desc = NULL; +#endif + } + + if (!desc) + continue; + + curr_mod_cnt = desc->header.num_module_entries; + curr_cpy_size = sizeof(struct sof_man_module) * curr_mod_cnt; - if (!desc) - return -EINVAL; + ret = memcpy_s(&module_info->modules[total_mod_cnt], total_size_left, + (char *)desc + SOF_MAN_MODULE_OFFSET(0), curr_cpy_size); + if (ret) { + tr_err(&basefw_comp_tr, "Couldn't copy module info for %d lib", lib_id); + return IPC4_OUT_OF_MEMORY; + } - module_info->modules_count = desc->header.num_module_entries; + /* replace structure id ("$AME" tag) with runtime info */ + for (uint32_t idx = 0; idx < curr_mod_cnt; ++idx) { + uint32_t mod_id = LIB_MANAGER_PACK_MODULE_ID(lib_id, idx); - for (int idx = 0; idx < module_info->modules_count; ++idx) { - struct sof_man_module *module_entry = - (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(idx)); - memcpy_s(&module_info->modules[idx], sizeof(module_info->modules[idx]), - module_entry, sizeof(struct sof_man_module)); + module_info->modules[total_mod_cnt + idx].runtime_info.module_id = mod_id; + /* TODO: set bit[0] for modules loaded into ADSP memory */ + module_info->modules[total_mod_cnt + idx].runtime_info.state_flags = 0x0; + } + + total_mod_cnt += curr_mod_cnt; + total_size_left -= curr_cpy_size; } + module_info->modules_count = total_mod_cnt; + *data_offset = sizeof(*module_info) + module_info->modules_count * sizeof(module_info->modules[0]); - return 0; + return IPC4_SUCCESS; } /* There are two types of sram memory : high power mode sram and * low power mode sram. This function retures memory size in page * , memory bank power and usage status of each sram to host driver */ -static int basefw_mem_state_info(uint32_t *data_offset, char *data) +__cold static int basefw_mem_state_info(uint32_t *data_offset, char *data) { struct sof_tlv *tuple = (struct sof_tlv *)data; struct ipc4_sram_state_info info; @@ -151,6 +219,8 @@ static int basefw_mem_state_info(uint32_t *data_offset, char *data) uint16_t *ptr; int i; + assert_can_be_cold(); + /* set hpsram */ info.free_phys_mem_pages = SRAM_BANK_SIZE * PLATFORM_HPSRAM_EBB_COUNT / HOST_PAGE_SIZE; info.ebb_state_dword_count = SOF_DIV_ROUND_UP(PLATFORM_HPSRAM_EBB_COUNT, 32); @@ -159,7 +229,11 @@ static int basefw_mem_state_info(uint32_t *data_offset, char *data) info.page_alloc_struct.page_alloc_count * sizeof(uint32_t); size = ALIGN(size, 4); /* size is also saved as tuple length */ - tuple_data = rballoc(0, SOF_MEM_CAPS_RAM, size); + tuple_data = rballoc(SOF_MEM_FLAG_USER, size); + if (!tuple_data) { + LOG_ERR("allocation failed"); + return IPC4_ERROR_INVALID_PARAM; + } /* save memory info in data array since info length is variable */ index = 0; @@ -205,11 +279,13 @@ static int basefw_mem_state_info(uint32_t *data_offset, char *data) *data_offset = (int)((char *)tuple - data); rfree(tuple_data); - return 0; + return IPC4_SUCCESS; } -static uint32_t basefw_get_ext_system_time(uint32_t *data_offset, char *data) +__cold static uint32_t basefw_get_ext_system_time(uint32_t *data_offset, char *data) { + assert_can_be_cold(); + #if CONFIG_ACE_V1X_ART_COUNTER && CONFIG_ACE_V1X_RTC_COUNTER struct ipc4_ext_system_time *ext_system_time = (struct ipc4_ext_system_time *)(data); struct ipc4_ext_system_time ext_system_time_data = {0}; @@ -261,23 +337,23 @@ static uint32_t basefw_get_ext_system_time(uint32_t *data_offset, char *data) *data_offset = sizeof(struct ipc4_ext_system_time); return IPC4_SUCCESS; -#endif +#else return IPC4_UNAVAILABLE; +#endif } -int basefw_vendor_get_large_config(struct comp_dev *dev, - uint32_t param_id, - bool first_block, - bool last_block, - uint32_t *data_offset, - char *data) +__cold int basefw_vendor_get_large_config(struct comp_dev *dev, uint32_t param_id, + bool first_block, bool last_block, + uint32_t *data_offset, char *data) { + assert_can_be_cold(); + /* We can use extended param id for both extended and standard param id */ union ipc4_extended_param_id extended_param_id; extended_param_id.full = param_id; - uint32_t ret = -EINVAL; + uint32_t ret = IPC4_INVALID_REQUEST; switch (extended_param_id.part.parameter_type) { case IPC4_MEMORY_STATE_INFO_GET: @@ -287,7 +363,7 @@ int basefw_vendor_get_large_config(struct comp_dev *dev, if (ret == IPC4_UNAVAILABLE) { tr_warn(&basefw_comp_tr, "returning success for get host EXTENDED_SYSTEM_TIME without handling it"); - return 0; + return IPC4_SUCCESS; } else { return ret; } @@ -299,8 +375,10 @@ int basefw_vendor_get_large_config(struct comp_dev *dev, return ret; } -static int fw_config_set_force_l1_exit(const struct sof_tlv *tlv) +__cold static int fw_config_set_force_l1_exit(const struct sof_tlv *tlv) { + assert_can_be_cold(); + #if defined(CONFIG_SOC_SERIES_INTEL_ADSP_ACE) const uint32_t force = tlv->value[0]; @@ -318,45 +396,110 @@ static int fw_config_set_force_l1_exit(const struct sof_tlv *tlv) #endif } -static int basefw_set_fw_config(bool first_block, - bool last_block, - uint32_t data_offset, - const char *data) +__cold static int basefw_set_fw_config(bool first_block, bool last_block, + uint32_t data_offset, const char *data) { + assert_can_be_cold(); + + /* Validate minimum TLV header (type + length fields) is present */ + if (data_offset < sizeof(struct sof_tlv)) { + tr_err(&basefw_comp_tr, "FW_CONFIG payload too small: %u < %zu", + data_offset, sizeof(struct sof_tlv)); + return IPC4_INVALID_CONFIG_DATA_LEN; + } + const struct sof_tlv *tlv = (const struct sof_tlv *)data; + /* Validate the TLV value payload fits within the reported buffer size */ + if (tlv->length > data_offset - sizeof(struct sof_tlv)) { + tr_err(&basefw_comp_tr, + "FW_CONFIG TLV value truncated: len %u exceeds payload %u", + tlv->length, data_offset); + return IPC4_INVALID_CONFIG_DATA_LEN; + } + switch (tlv->type) { case IPC4_DMI_FORCE_L1_EXIT: + if (tlv->length < sizeof(uint32_t)) { + tr_err(&basefw_comp_tr, "DMI_FORCE_L1_EXIT value too small: %u", + tlv->length); + return IPC4_INVALID_CONFIG_DATA_LEN; + } return fw_config_set_force_l1_exit(tlv); default: break; } - tr_warn(&basefw_comp_tr, "returning success for Set FW_CONFIG without handling it"); + + tr_warn(&basefw_comp_tr, "Set FW_CONFIG: no handler for type %u", tlv->type); + return 0; +} + +static int basefw_set_mic_priv_policy(bool first_block, + bool last_block, + uint32_t data_offset_or_size, + const char *data) +{ +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + return 0; +#else + return IPC4_UNAVAILABLE; +#endif +} + +static int basefw_mic_priv_state_changed(bool first_block, + bool last_block, + uint32_t data_offset_or_size, + const char *data) +{ +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + if (data_offset_or_size < sizeof(uint8_t)) { + tr_err(&basefw_comp_tr, "mic_priv_state_changed: payload too small: %u", + data_offset_or_size); + return IPC4_ERROR_INVALID_PARAM; + } + + uint32_t mic_disable_status = (uint32_t)(uint8_t)(*data); + + tr_info(&basefw_comp_tr, "state changed to %u", mic_disable_status); + struct mic_privacy_settings settings; + + mic_privacy_fill_settings(&settings, mic_disable_status); + mic_privacy_propagate_settings(&settings); + return 0; +#else + return IPC4_UNAVAILABLE; +#endif } -int basefw_vendor_set_large_config(struct comp_dev *dev, - uint32_t param_id, - bool first_block, - bool last_block, - uint32_t data_offset, - const char *data) +__cold int basefw_vendor_set_large_config(struct comp_dev *dev, uint32_t param_id, + bool first_block, bool last_block, + uint32_t data_offset, const char *data) { + assert_can_be_cold(); + switch (param_id) { case IPC4_FW_CONFIG: return basefw_set_fw_config(first_block, last_block, data_offset, data); + case IPC4_SET_MIC_PRIVACY_FW_MANAGED_POLICY_MASK: + return basefw_set_mic_priv_policy(first_block, last_block, data_offset, data); + case IPC4_MIC_PRIVACY_HW_MANAGED_STATE_CHANGE: + return basefw_mic_priv_state_changed(first_block, last_block, data_offset, data); default: break; } - return IPC4_UNKNOWN_MESSAGE_TYPE; + return IPC4_INVALID_REQUEST; } -int basefw_vendor_dma_control(uint32_t node_id, const char *config_data, size_t data_size) +__cold int basefw_vendor_dma_control(uint32_t node_id, const char *config_data, size_t data_size) { union ipc4_connector_node_id node = (union ipc4_connector_node_id)node_id; + int dai_index = node.f.v_index; int ret, result; - enum dai_type type; + enum sof_ipc_dai_type type; + + assert_can_be_cold(); tr_info(&basefw_comp_tr, "node_id 0x%x, config_data 0x%x, data_size %u", node_id, (uint32_t)config_data, data_size); @@ -374,13 +517,27 @@ int basefw_vendor_dma_control(uint32_t node_id, const char *config_data, size_t return IPC4_SUCCESS; case ipc4_i2s_link_output_class: case ipc4_i2s_link_input_class: - type = DAI_INTEL_SSP; + type = SOF_DAI_INTEL_SSP; break; + +#if CONFIG_UAOL_INTEL_ADSP + case ipc4_alh_uaol_stream_link_output_class: + case ipc4_alh_uaol_stream_link_input_class: + type = SOF_DAI_INTEL_UAOL; + dai_index = uaol_stream_id_to_hda_link_stream_id(node.f.v_index); + if (dai_index < 0) { + tr_err(&basefw_comp_tr, + "HDA link stream not found! UAOL node ID: 0x%x", node_id); + return IPC4_INVALID_RESOURCE_ID; + } + break; +#endif + default: return IPC4_INVALID_RESOURCE_ID; } - const struct device *dev = dai_get_device(type, node.f.v_index); + const struct device *dev = dai_get_device(type, dai_index); if (!dev) { tr_err(&basefw_comp_tr, diff --git a/src/audio/buffers/CMakeLists.txt b/src/audio/buffers/CMakeLists.txt index 944a84dedb7e..b035b055b449 100644 --- a/src/audio/buffers/CMakeLists.txt +++ b/src/audio/buffers/CMakeLists.txt @@ -1,8 +1,5 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof audio_buffer.c) -add_local_sources(sof comp_buffer.c) +add_local_sources(sof audio_buffer.c comp_buffer.c) -if(CONFIG_PIPELINE_2_0) - add_local_sources(sof ring_buffer.c) -endif() +add_local_sources_ifdef(CONFIG_PIPELINE_2_0 sof ring_buffer.c) diff --git a/src/audio/buffers/README.md b/src/audio/buffers/README.md new file mode 100644 index 000000000000..fcd4516dd4ab --- /dev/null +++ b/src/audio/buffers/README.md @@ -0,0 +1,20 @@ +# Audio Buffers Architecture + +This directory contains the core audio buffer management. + +## Overview + +Buffers connect the output of one component to the input of the next in an audio pipeline graph. They implement circular (ring) buffer semantics and handle cache coherency for DSP memory. + +## Architecture Diagram + +```mermaid +graph LR + CompA[Component A / Producer] -->|Write| Buf[Ring Buffer] + Buf -->|Read| CompB[Component B / Consumer] +``` + +## Configuration and Scripts + +- **CMakeLists.txt**: Includes the base core buffer source files (`audio_buffer.c`, `comp_buffer.c`). When the `CONFIG_PIPELINE_2_0` feature flag is enabled, it additionally compiles `ring_buffer.c`. +- **Topology (.conf)**: Derived from `tools/topology/topology2/include/components/buffer.conf`, defining the `buffer` widget object. Key parameters include `size` (automatically computed), `periods`, `channels`, and `caps` (capabilities like `dai`, `host`, `pass`, `comp`). Defaults to UUID `92:4c:54:42:92:8e:41:4e:b6:79:34:51:9f:1c:1d:28`. diff --git a/src/audio/buffers/audio_buffer.c b/src/audio/buffers/audio_buffer.c index af882accaae8..1ecf8472dd65 100644 --- a/src/audio/buffers/audio_buffer.c +++ b/src/audio/buffers/audio_buffer.c @@ -7,8 +7,13 @@ #include <stdint.h> #include <stddef.h> #include <errno.h> +#include <rtos/panic.h> #include <rtos/alloc.h> #include <ipc/stream.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <module/ipc4/base-config.h> +#include <sof/audio/component.h> +#include <module/module/base.h> #include <sof/audio/audio_buffer.h> #include <sof/audio/sink_api.h> #include <sof/audio/source_api.h> @@ -92,9 +97,8 @@ void audio_buffer_free(struct sof_audio_buffer *buffer) audio_buffer_free(buffer->secondary_buffer_sink); audio_buffer_free(buffer->secondary_buffer_source); #endif /* CONFIG_PIPELINE_2_0 */ - if (buffer->ops->free) - buffer->ops->free(buffer); - rfree(buffer); + /* "virtual destructor": free the buffer internals and buffer memory */ + buffer->ops->free(buffer); } static @@ -122,7 +126,6 @@ int audio_buffer_source_set_ipc_params_default(struct sof_audio_buffer *buffer, return 0; } -static int audio_buffer_sink_set_ipc_params(struct sof_sink *sink, struct sof_ipc_stream_params *params, bool force_update) { @@ -133,7 +136,6 @@ int audio_buffer_sink_set_ipc_params(struct sof_sink *sink, struct sof_ipc_strea return audio_buffer_source_set_ipc_params_default(buffer, params, force_update); } -static int audio_buffer_sink_on_audio_format_set(struct sof_sink *sink) { struct sof_audio_buffer *buffer = sof_audio_buffer_from_sink(sink); @@ -143,7 +145,6 @@ int audio_buffer_sink_on_audio_format_set(struct sof_sink *sink) return 0; } -static int audio_buffer_sink_set_alignment_constants(struct sof_sink *sink, const uint32_t byte_align, const uint32_t frame_align_req) @@ -155,7 +156,6 @@ int audio_buffer_sink_set_alignment_constants(struct sof_sink *sink, return 0; } -static int audio_buffer_source_set_ipc_params(struct sof_source *source, struct sof_ipc_stream_params *params, bool force_update) { @@ -166,7 +166,6 @@ int audio_buffer_source_set_ipc_params(struct sof_source *source, return audio_buffer_source_set_ipc_params_default(buffer, params, force_update); } -static int audio_buffer_source_on_audio_format_set(struct sof_source *source) { struct sof_audio_buffer *buffer = sof_audio_buffer_from_source(source); @@ -176,7 +175,6 @@ int audio_buffer_source_on_audio_format_set(struct sof_source *source) return 0; } -static int audio_buffer_source_set_alignment_constants(struct sof_source *source, const uint32_t byte_align, const uint32_t frame_align_req) @@ -188,34 +186,50 @@ int audio_buffer_source_set_alignment_constants(struct sof_source *source, return 0; } +uint32_t audio_buffer_sink_get_lft(struct sof_sink *sink) +{ + struct sof_audio_buffer *buffer = sof_audio_buffer_from_sink(sink); + /* get number of ms in the buffer */ + size_t bytes_per_sec = sink_get_frame_bytes(&buffer->_sink_api) * + sink_get_rate(&buffer->_sink_api); + size_t bytes_per_ms = bytes_per_sec / 1000; + + /* round up for frequencies like 44100 */ + if (bytes_per_ms * 1000 != bytes_per_sec) + bytes_per_ms++; + uint32_t us_in_buffer = + 1000 * source_get_data_available(&buffer->_source_api) / bytes_per_ms; + + return us_in_buffer; + + /* + * TODO, Currently there's no DP to DP connection + * >>> the code below is never accessible and won't work because of cache incoherence <<< + * + * to make DP to DP connection possible: + * + * 1) module data must be ALWAYS located in non cached memory alias, allowing + * cross core access to params like period (needed below) and calling + * module_get_deadline for the next module, regardless of cores the modules are + * running on + * 2) comp_buffer must be removed from all pipeline code, replaced with a generic abstract + * class audio_buffer - allowing using comp_buffer and ring_buffer without current + * "hybrid buffer" solution + */ +} + void audio_buffer_init(struct sof_audio_buffer *buffer, uint32_t buffer_type, bool is_shared, - struct source_ops *source_ops, struct sink_ops *sink_ops, + const struct source_ops *source_ops, const struct sink_ops *sink_ops, const struct audio_buffer_ops *audio_buffer_ops, struct sof_audio_stream_params *audio_stream_params) { - CORE_CHECK_STRUCT_INIT(&buffer, is_shared); + CORE_CHECK_STRUCT_INIT(buffer, is_shared); buffer->buffer_type = buffer_type; buffer->ops = audio_buffer_ops; + assert(audio_buffer_ops->free); buffer->audio_stream_params = audio_stream_params; buffer->is_shared = is_shared; - /* set default implementations of sink/source methods, if there's no - * specific implementation provided - */ - if (!sink_ops->audio_set_ipc_params) - sink_ops->audio_set_ipc_params = audio_buffer_sink_set_ipc_params; - if (!sink_ops->on_audio_format_set && buffer->ops->on_audio_format_set) - sink_ops->on_audio_format_set = audio_buffer_sink_on_audio_format_set; - if (!sink_ops->set_alignment_constants && buffer->ops->set_alignment_constants) - sink_ops->set_alignment_constants = audio_buffer_sink_set_alignment_constants; - - if (!source_ops->audio_set_ipc_params) - source_ops->audio_set_ipc_params = audio_buffer_source_set_ipc_params; - if (!source_ops->on_audio_format_set && buffer->ops->on_audio_format_set) - source_ops->on_audio_format_set = audio_buffer_source_on_audio_format_set; - if (!source_ops->set_alignment_constants && buffer->ops->set_alignment_constants) - source_ops->set_alignment_constants = audio_buffer_source_set_alignment_constants; - source_init(audio_buffer_get_source(buffer), source_ops, audio_buffer_get_stream_params(buffer)); sink_init(audio_buffer_get_sink(buffer), sink_ops, diff --git a/src/audio/buffers/comp_buffer.c b/src/audio/buffers/comp_buffer.c index 62f90bd2b5c9..8a3d44133d4b 100644 --- a/src/audio/buffers/comp_buffer.c +++ b/src/audio/buffers/comp_buffer.c @@ -11,12 +11,14 @@ #include <sof/audio/sink_api.h> #include <sof/audio/source_api.h> #include <sof/audio/sink_source_utils.h> +#include <rtos/userspace_helper.h> #include <sof/common.h> #include <rtos/interrupt.h> #include <rtos/alloc.h> #include <rtos/cache.h> -#include <sof/lib/notifier.h> +#include <sof/lib/vregion.h> #include <sof/list.h> +#include <sof/schedule/dp_schedule.h> #include <rtos/spinlock.h> #include <rtos/symbol.h> #include <ipc/topology.h> @@ -145,31 +147,48 @@ static void comp_buffer_free(struct sof_audio_buffer *audio_buffer) struct comp_buffer *buffer = container_of(audio_buffer, struct comp_buffer, audio_buffer); - struct buffer_cb_free cb_data = { - .buffer = buffer, - }; + buf_dbg(buffer, "entry"); - buf_dbg(buffer, "buffer_free()"); +#if CONFIG_PROBE + if (buffer->probe_cb_free) + buffer->probe_cb_free(buffer->probe_cb_arg); +#endif + + struct mod_alloc_ctx *alloc = buffer->audio_buffer.alloc; - notifier_event(buffer, NOTIFIER_ID_BUFFER_FREE, - NOTIFIER_TARGET_CORE_LOCAL, &cb_data, sizeof(cb_data)); + assert(!IS_ENABLED(CONFIG_SOF_USERSPACE_LL) || alloc); - /* In case some listeners didn't unregister from buffer's callbacks */ - notifier_unregister_all(NULL, buffer); + if (alloc) + sof_ctx_free(alloc, buffer->stream.addr); + else + sof_heap_free(sof_sys_user_heap_get(), buffer->stream.addr); - rfree(buffer->stream.addr); + if (alloc && alloc->vreg) { + vregion_free(alloc->vreg, buffer); + if (!vregion_put(alloc->vreg)) + rfree(alloc); + } else { + sof_heap_free(alloc ? alloc->heap : NULL, buffer); + } } -static struct source_ops comp_buffer_source_ops = { +APP_TASK_DATA static const struct source_ops comp_buffer_source_ops = { .get_data_available = comp_buffer_get_data_available, .get_data = comp_buffer_get_data, .release_data = comp_buffer_release_data, + .audio_set_ipc_params = audio_buffer_source_set_ipc_params, + .on_audio_format_set = audio_buffer_source_on_audio_format_set, + .set_alignment_constants = audio_buffer_source_set_alignment_constants, }; -static struct sink_ops comp_buffer_sink_ops = { +APP_TASK_DATA static const struct sink_ops comp_buffer_sink_ops = { .get_free_size = comp_buffer_get_free_size, .get_buffer = comp_buffer_get_buffer, .commit_buffer = comp_buffer_commit_buffer, + .audio_set_ipc_params = audio_buffer_sink_set_ipc_params, + .on_audio_format_set = audio_buffer_sink_on_audio_format_set, + .set_alignment_constants = audio_buffer_sink_set_alignment_constants, + .get_lft = audio_buffer_sink_get_lft, }; static const struct audio_buffer_ops audio_buffer_ops = { @@ -177,27 +196,30 @@ static const struct audio_buffer_ops audio_buffer_ops = { .reset = comp_buffer_reset, .audio_set_ipc_params = comp_buffer_set_ipc_params, .on_audio_format_set = comp_buffer_format_set, - .set_alignment_constants = comp_buffer_set_alignment_constants + .set_alignment_constants = comp_buffer_set_alignment_constants, }; -static struct comp_buffer *buffer_alloc_struct(void *stream_addr, size_t size, uint32_t caps, +static struct comp_buffer *buffer_alloc_struct(struct mod_alloc_ctx *alloc, + void *stream_addr, size_t size, uint32_t flags, bool is_shared) { struct comp_buffer *buffer; - tr_dbg(&buffer_tr, "buffer_alloc_struct()"); + tr_dbg(&buffer_tr, "entry"); - /* 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)); + /* allocate new buffer, but add coherent if shared with other cores */ + if (is_shared) + flags |= SOF_MEM_FLAG_COHERENT; + buffer = sof_ctx_alloc(alloc, flags, sizeof(*buffer), 0); if (!buffer) { - tr_err(&buffer_tr, "buffer_alloc_struct(): could not alloc structure"); + tr_err(&buffer_tr, "could not alloc structure"); return NULL; } - buffer->caps = caps; + memset(buffer, 0, sizeof(*buffer)); + + buffer->flags = flags; /* Force channels to 2 for init to prevent bad call to clz in buffer_init_stream */ buffer->stream.runtime_stream_params.channels = 2; @@ -211,55 +233,68 @@ static struct comp_buffer *buffer_alloc_struct(void *stream_addr, size_t size, u audio_stream_set_underrun(&buffer->stream, !!(flags & SOF_BUF_UNDERRUN_PERMITTED)); audio_stream_set_overrun(&buffer->stream, !!(flags & SOF_BUF_OVERRUN_PERMITTED)); + buffer->audio_buffer.alloc = alloc; - list_init(&buffer->source_list); - list_init(&buffer->sink_list); + comp_buffer_reset_source_list(buffer); + comp_buffer_reset_sink_list(buffer); return buffer; } -struct comp_buffer *buffer_alloc(size_t size, uint32_t caps, uint32_t flags, uint32_t align, - bool is_shared) +struct comp_buffer *buffer_alloc(struct mod_alloc_ctx *alloc, size_t size, uint32_t flags, + uint32_t align, bool is_shared) { struct comp_buffer *buffer; void *stream_addr; - tr_dbg(&buffer_tr, "buffer_alloc()"); + tr_dbg(&buffer_tr, "entry"); /* validate request */ if (size == 0) { - tr_err(&buffer_tr, "buffer_alloc(): new size = %zu is invalid", size); + tr_err(&buffer_tr, "new size = %zu is invalid", size); return NULL; } - stream_addr = rballoc_align(0, caps, size, align); + assert(!IS_ENABLED(CONFIG_SOF_USERSPACE_LL) || alloc); + + if (alloc) + stream_addr = sof_ctx_alloc(alloc, flags, size, align); + else + stream_addr = sof_heap_alloc(sof_sys_user_heap_get(), + flags | SOF_MEM_FLAG_LARGE_BUFFER, size, align); + if (!stream_addr) { - tr_err(&buffer_tr, "buffer_alloc(): could not alloc size = %zu bytes of type = %u", - size, caps); + tr_err(&buffer_tr, "could not alloc size = %zu bytes of flags = 0x%x", + size, flags); return NULL; } - buffer = buffer_alloc_struct(stream_addr, size, caps, flags, is_shared); + buffer = buffer_alloc_struct(alloc, stream_addr, size, flags, is_shared); if (!buffer) { - tr_err(&buffer_tr, "buffer_alloc(): could not alloc buffer structure"); - rfree(stream_addr); + tr_err(&buffer_tr, "could not alloc buffer structure"); + + if (alloc) + sof_ctx_free(alloc, stream_addr); + else + sof_heap_free(sof_sys_user_heap_get(), stream_addr); } return buffer; } -struct comp_buffer *buffer_alloc_range(size_t preferred_size, size_t minimum_size, uint32_t caps, +struct comp_buffer *buffer_alloc_range(struct mod_alloc_ctx *alloc, size_t preferred_size, + size_t minimum_size, uint32_t flags, uint32_t align, bool is_shared) { struct comp_buffer *buffer; size_t size; void *stream_addr = NULL; - tr_dbg(&buffer_tr, "buffer_alloc_range(): %zu -- %zu bytes", minimum_size, preferred_size); + tr_dbg(&buffer_tr, "%zu -- %zu bytes", minimum_size, preferred_size); /* validate request */ if (minimum_size == 0 || preferred_size < minimum_size) { - tr_err(&buffer_tr, "buffer_alloc_range(): new size range %zu -- %zu is invalid", + tr_err(&buffer_tr, "new size range %zu -- %zu is invalid", minimum_size, preferred_size); return NULL; } @@ -268,24 +303,36 @@ struct comp_buffer *buffer_alloc_range(size_t preferred_size, size_t minimum_siz if (preferred_size % minimum_size) preferred_size += minimum_size - preferred_size % minimum_size; + assert(!IS_ENABLED(CONFIG_SOF_USERSPACE_LL) || alloc); + for (size = preferred_size; size >= minimum_size; size -= minimum_size) { - stream_addr = rballoc_align(0, caps, size, align); + if (alloc) + stream_addr = sof_ctx_alloc(alloc, flags, size, align); + else + stream_addr = sof_heap_alloc(sof_sys_user_heap_get(), + flags | SOF_MEM_FLAG_LARGE_BUFFER, size, + align); + if (stream_addr) break; } - tr_dbg(&buffer_tr, "buffer_alloc_range(): allocated %zu bytes", size); + tr_dbg(&buffer_tr, "allocated %zu bytes", size); if (!stream_addr) { - tr_err(&buffer_tr, "buffer_alloc_range(): could not alloc size = %zu bytes of type = %u", - minimum_size, caps); + tr_err(&buffer_tr, "could not alloc size = %zu bytes of type = 0x%x", + minimum_size, flags); return NULL; } - buffer = buffer_alloc_struct(stream_addr, size, caps, flags, is_shared); + buffer = buffer_alloc_struct(alloc, stream_addr, size, flags, is_shared); if (!buffer) { - tr_err(&buffer_tr, "buffer_alloc_range(): could not alloc buffer structure"); - rfree(stream_addr); + tr_err(&buffer_tr, "could not alloc buffer structure"); + + if (alloc) + sof_ctx_free(alloc, stream_addr); + else + sof_heap_free(sof_sys_user_heap_get(), stream_addr); } return buffer; @@ -293,11 +340,11 @@ struct comp_buffer *buffer_alloc_range(size_t preferred_size, size_t minimum_siz void buffer_zero(struct comp_buffer *buffer) { - buf_dbg(buffer, "stream_zero()"); + buf_dbg(buffer, "entry"); CORE_CHECK_STRUCT(&buffer->audio_buffer); bzero(audio_stream_get_addr(&buffer->stream), audio_stream_get_size(&buffer->stream)); - if (buffer->caps & SOF_MEM_CAPS_DMA) + if (buffer->flags & SOF_MEM_FLAG_DMA) dcache_writeback_region((__sparse_force void __sparse_cache *) audio_stream_get_addr(&buffer->stream), audio_stream_get_size(&buffer->stream)); @@ -306,6 +353,7 @@ void buffer_zero(struct comp_buffer *buffer) int buffer_set_size(struct comp_buffer *buffer, uint32_t size, uint32_t alignment) { void *new_ptr = NULL; + struct mod_alloc_ctx *alloc = buffer->audio_buffer.alloc; CORE_CHECK_STRUCT(&buffer->audio_buffer); @@ -318,23 +366,31 @@ int buffer_set_size(struct comp_buffer *buffer, uint32_t size, uint32_t alignmen if (size == audio_stream_get_size(&buffer->stream)) return 0; - if (!alignment) - new_ptr = rbrealloc(audio_stream_get_addr(&buffer->stream), SOF_MEM_FLAG_NO_COPY, - buffer->caps, size, audio_stream_get_size(&buffer->stream)); + assert(!IS_ENABLED(CONFIG_SOF_USERSPACE_LL) || alloc); + + if (alloc) + new_ptr = sof_ctx_alloc(alloc, buffer->flags, size, alignment); else - new_ptr = rbrealloc_align(audio_stream_get_addr(&buffer->stream), - SOF_MEM_FLAG_NO_COPY, buffer->caps, size, - audio_stream_get_size(&buffer->stream), alignment); + new_ptr = sof_heap_alloc(sof_sys_user_heap_get(), + buffer->flags | SOF_MEM_FLAG_LARGE_BUFFER, size, + alignment); + /* we couldn't allocate bigger chunk */ if (!new_ptr && size > audio_stream_get_size(&buffer->stream)) { - buf_err(buffer, "resize can't alloc %u bytes type %u", - audio_stream_get_size(&buffer->stream), buffer->caps); + buf_err(buffer, "resize can't alloc %u bytes of flags 0x%x", + audio_stream_get_size(&buffer->stream), buffer->flags); return -ENOMEM; } /* use bigger chunk, else just use the old chunk but set smaller */ - if (new_ptr) - buffer->stream.addr = new_ptr; + if (new_ptr) { + if (alloc) + sof_ctx_free(alloc, audio_stream_get_addr(&buffer->stream)); + else + sof_heap_free(sof_sys_user_heap_get(), audio_stream_get_addr(&buffer->stream)); + + audio_stream_set_addr(&buffer->stream, new_ptr); + } buffer_init_stream(buffer, size); @@ -344,10 +400,10 @@ int buffer_set_size(struct comp_buffer *buffer, uint32_t size, uint32_t alignmen int buffer_set_size_range(struct comp_buffer *buffer, size_t preferred_size, size_t minimum_size, uint32_t alignment) { - void *ptr = audio_stream_get_addr(&buffer->stream); const size_t actual_size = audio_stream_get_size(&buffer->stream); void *new_ptr = NULL; size_t new_size; + struct mod_alloc_ctx *alloc = buffer->audio_buffer.alloc; CORE_CHECK_STRUCT(&buffer->audio_buffer); @@ -365,33 +421,37 @@ int buffer_set_size_range(struct comp_buffer *buffer, size_t preferred_size, siz if (preferred_size == actual_size) return 0; - if (!alignment) { - for (new_size = preferred_size; new_size >= minimum_size; - new_size -= minimum_size) { - new_ptr = rbrealloc(ptr, SOF_MEM_FLAG_NO_COPY, buffer->caps, new_size, - actual_size); - if (new_ptr) - break; - } - } else { - for (new_size = preferred_size; new_size >= minimum_size; - new_size -= minimum_size) { - new_ptr = rbrealloc_align(ptr, SOF_MEM_FLAG_NO_COPY, buffer->caps, new_size, - actual_size, alignment); - if (new_ptr) - break; - } + assert(!IS_ENABLED(CONFIG_SOF_USERSPACE_LL) || alloc); + + for (new_size = preferred_size; new_size >= minimum_size; + new_size -= minimum_size) { + if (alloc) + new_ptr = sof_ctx_alloc(alloc, buffer->flags, new_size, alignment); + else + new_ptr = sof_heap_alloc(sof_sys_user_heap_get(), + buffer->flags | SOF_MEM_FLAG_LARGE_BUFFER, + new_size, alignment); + + if (new_ptr) + break; } /* we couldn't allocate bigger chunk */ if (!new_ptr && new_size > actual_size) { - buf_err(buffer, "resize can't alloc %zu bytes type %u", new_size, buffer->caps); + buf_err(buffer, "resize can't alloc %zu bytes of flags 0x%x", new_size, + buffer->flags); return -ENOMEM; } /* use bigger chunk, else just use the old chunk but set smaller */ - if (new_ptr) - buffer->stream.addr = new_ptr; + if (new_ptr) { + if (alloc) + sof_ctx_free(alloc, audio_stream_get_addr(&buffer->stream)); + else + sof_heap_free(sof_sys_user_heap_get(), audio_stream_get_addr(&buffer->stream)); + + audio_stream_set_addr(&buffer->stream, new_ptr); + } buffer_init_stream(buffer, new_size); @@ -407,7 +467,7 @@ int buffer_set_params(struct comp_buffer *buffer, CORE_CHECK_STRUCT(&buffer->audio_buffer); if (!params) { - buf_err(buffer, "buffer_set_params(): !params"); + buf_err(buffer, "!params"); return -EINVAL; } @@ -416,7 +476,7 @@ int buffer_set_params(struct comp_buffer *buffer, ret = audio_stream_set_params(&buffer->stream, params); if (ret < 0) { - buf_err(buffer, "buffer_set_params(): audio_stream_set_params failed"); + buf_err(buffer, "audio_stream_set_params failed"); return -EINVAL; } @@ -453,19 +513,13 @@ bool buffer_params_match(struct comp_buffer *buffer, void comp_update_buffer_produce(struct comp_buffer *buffer, uint32_t bytes) { - struct buffer_cb_transact cb_data = { - .buffer = buffer, - .transaction_amount = bytes, - .transaction_begin_address = audio_stream_get_wptr(&buffer->stream), - }; - /* return if no bytes */ if (!bytes) { #if CONFIG_SOF_LOG_DBG_BUFFER struct comp_dev *src_component = comp_buffer_get_source_component(buffer); struct comp_dev *sink_component = comp_buffer_get_sink_component(buffer); - buf_dbg(buffer, "comp_update_buffer_produce(), no bytes to produce, source->comp.id = %u, source->comp.type = %u, sink->comp.id = %u, sink->comp.type = %u", + buf_dbg(buffer, "no bytes to produce, source->comp.id = %u, source->comp.type = %u, sink->comp.id = %u, sink->comp.type = %u", src_component ? dev_comp_id(src_component) : (unsigned int)UINT32_MAX, src_component ? dev_comp_type(src_component) : (unsigned int)UINT32_MAX, sink_component ? dev_comp_id(sink_component) : (unsigned int)UINT32_MAX, @@ -474,17 +528,30 @@ void comp_update_buffer_produce(struct comp_buffer *buffer, uint32_t bytes) return; } +#if CONFIG_PROBE + void *produce_begin = audio_stream_get_wptr(&buffer->stream); +#endif + audio_stream_produce(&buffer->stream, bytes); - notifier_event(buffer, NOTIFIER_ID_BUFFER_PRODUCE, - NOTIFIER_TARGET_CORE_LOCAL, &cb_data, sizeof(cb_data)); +#if CONFIG_PROBE + if (buffer->probe_cb_produce) { + struct buffer_cb_transact cb_data = { + .buffer = buffer, + .transaction_amount = bytes, + .transaction_begin_address = produce_begin, + }; + + buffer->probe_cb_produce(buffer->probe_cb_arg, &cb_data); + } +#endif #if CONFIG_SOF_LOG_DBG_BUFFER - buf_dbg(buffer, "comp_update_buffer_produce(), ((buffer->avail << 16) | buffer->free) = %08x, ((buffer->id << 16) | buffer->size) = %08x", + buf_dbg(buffer, "((buffer->avail << 16) | buffer->free) = %08x, ((buffer->id << 16) | buffer->size) = %08x", (audio_stream_get_avail_bytes(&buffer->stream) << 16) | audio_stream_get_free_bytes(&buffer->stream), (buffer->id << 16) | audio_stream_get_size(&buffer->stream)); - buf_dbg(buffer, "comp_update_buffer_produce(), ((buffer->r_ptr - buffer->addr) << 16 | (buffer->w_ptr - buffer->addr)) = %08x", + buf_dbg(buffer, "((buffer->r_ptr - buffer->addr) << 16 | (buffer->w_ptr - buffer->addr)) = %08x", ((char *)audio_stream_get_rptr(&buffer->stream) - (char *)audio_stream_get_addr(&buffer->stream)) << 16 | ((char *)audio_stream_get_wptr(&buffer->stream) - @@ -494,12 +561,6 @@ void comp_update_buffer_produce(struct comp_buffer *buffer, uint32_t bytes) void comp_update_buffer_consume(struct comp_buffer *buffer, uint32_t bytes) { - struct buffer_cb_transact cb_data = { - .buffer = buffer, - .transaction_amount = bytes, - .transaction_begin_address = audio_stream_get_rptr(&buffer->stream), - }; - CORE_CHECK_STRUCT(&buffer->audio_buffer); /* return if no bytes */ @@ -508,7 +569,7 @@ void comp_update_buffer_consume(struct comp_buffer *buffer, uint32_t bytes) struct comp_dev *src_component = comp_buffer_get_source_component(buffer); struct comp_dev *sink_component = comp_buffer_get_sink_component(buffer); - buf_dbg(buffer, "comp_update_buffer_consume(), no bytes to consume, source->comp.id = %u, source->comp.type = %u, sink->comp.id = %u, sink->comp.type = %u", + buf_dbg(buffer, "no bytes to consume, source->comp.id = %u, source->comp.type = %u, sink->comp.id = %u, sink->comp.type = %u", src_component ? dev_comp_id(src_component) : (unsigned int)UINT32_MAX, src_component ? dev_comp_type(src_component) : (unsigned int)UINT32_MAX, sink_component ? dev_comp_id(sink_component) : (unsigned int)UINT32_MAX, @@ -519,11 +580,8 @@ void comp_update_buffer_consume(struct comp_buffer *buffer, uint32_t bytes) audio_stream_consume(&buffer->stream, bytes); - notifier_event(buffer, NOTIFIER_ID_BUFFER_CONSUME, - NOTIFIER_TARGET_CORE_LOCAL, &cb_data, sizeof(cb_data)); - #if CONFIG_SOF_LOG_DBG_BUFFER - buf_dbg(buffer, "comp_update_buffer_consume(), (buffer->avail << 16) | buffer->free = %08x, (buffer->id << 16) | buffer->size = %08x, (buffer->r_ptr - buffer->addr) << 16 | (buffer->w_ptr - buffer->addr)) = %08x", + buf_dbg(buffer, "(buffer->avail << 16) | buffer->free = %08x, (buffer->id << 16) | buffer->size = %08x, (buffer->r_ptr - buffer->addr) << 16 | (buffer->w_ptr - buffer->addr)) = %08x", (audio_stream_get_avail_bytes(&buffer->stream) << 16) | audio_stream_get_free_bytes(&buffer->stream), (buffer->id << 16) | audio_stream_get_size(&buffer->stream), @@ -534,21 +592,38 @@ void comp_update_buffer_consume(struct comp_buffer *buffer, uint32_t bytes) #endif } +static inline struct list_item *buffer_comp_list(struct comp_buffer *buffer, + int dir) +{ + return dir == PPL_DIR_DOWNSTREAM ? + &buffer->source_list : &buffer->sink_list; +} + /* - * Locking: must be called with interrupts disabled! Serialized IPCs protect us + * Locking: must be called with interrupts disabled (or sys_mutex held for + * userspace LL builds)! Serialized IPCs protect us * from racing attach / detach calls, but the scheduler can interrupt the IPC * thread and begin using the buffer for streaming. FIXME: this is still a * problem with different cores. + * + * Returns -EALREADY if the buffer is already attached in this direction. + * Attaching the same buffer twice would corrupt the list (list_item_prepend + * on an already-linked node creates a self-loop), so callers must propagate + * the error. */ -void buffer_attach(struct comp_buffer *buffer, struct list_item *head, int dir) +int buffer_attach(struct comp_buffer *buffer, struct list_item *head, int dir) { struct list_item *list = buffer_comp_list(buffer, dir); CORE_CHECK_STRUCT(&buffer->audio_buffer); + if (!list_is_empty(list)) + return -EALREADY; list_item_prepend(list, head); + return 0; } /* - * Locking: must be called with interrupts disabled! See buffer_attach() above + * Locking: must be called with interrupts disabled (or sys_mutex held for + * userspace LL builds)! See buffer_attach() above * for details */ void buffer_detach(struct comp_buffer *buffer, struct list_item *head, int dir) diff --git a/src/audio/buffers/ring_buffer.c b/src/audio/buffers/ring_buffer.c index 52acc91a11f4..51245e91ca40 100644 --- a/src/audio/buffers/ring_buffer.c +++ b/src/audio/buffers/ring_buffer.c @@ -6,8 +6,11 @@ #include <sof/common.h> #include <sof/trace/trace.h> #include <sof/lib/uuid.h> +#include <sof/lib/vregion.h> +#include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/ring_buffer.h> +#include <sof/audio/component.h> #include <rtos/alloc.h> #include <ipc/topology.h> @@ -92,10 +95,12 @@ static void ring_buffer_free(struct sof_audio_buffer *audio_buffer) if (!audio_buffer) return; - struct ring_buffer *ring_buffer = - container_of(audio_buffer, struct ring_buffer, audio_buffer); + struct ring_buffer *ring_buffer = container_of(audio_buffer, + struct ring_buffer, audio_buffer); + struct mod_alloc_ctx *alloc = audio_buffer->alloc; - rfree((__sparse_force void *)ring_buffer->_data_buffer); + sof_ctx_free(alloc, (__sparse_force void *)ring_buffer->_data_buffer); + sof_ctx_free(alloc, ring_buffer); } static void ring_buffer_reset(struct sof_audio_buffer *audio_buffer) @@ -239,38 +244,63 @@ static int ring_buffer_release_data(struct sof_source *source, size_t free_size) return 0; } -static struct source_ops ring_buffer_source_ops = { +int ring_buffer_module_unbind(struct sof_sink *sink) +{ + struct ring_buffer *ring_buffer = ring_buffer_from_sink(sink); + + CORE_CHECK_STRUCT(&ring_buffer->audio_buffer); + + /* in case of disconnection, invalidate all cache. This method is guaranteed be called on + * core that have been using sink API + */ + ring_buffer_invalidate_shared(ring_buffer, ring_buffer->_data_buffer, + ring_buffer->data_buffer_size); + + return 0; +} + +static const struct source_ops ring_buffer_source_ops = { .get_data_available = ring_buffer_get_data_available, .get_data = ring_buffer_get_data, .release_data = ring_buffer_release_data, + .audio_set_ipc_params = audio_buffer_source_set_ipc_params, + .on_audio_format_set = audio_buffer_source_on_audio_format_set, + .set_alignment_constants = audio_buffer_source_set_alignment_constants, }; -static struct sink_ops ring_buffer_sink_ops = { +static const struct sink_ops ring_buffer_sink_ops = { .get_free_size = ring_buffer_get_free_size, .get_buffer = ring_buffer_get_buffer, .commit_buffer = ring_buffer_commit_buffer, + .on_unbind = ring_buffer_module_unbind, + .audio_set_ipc_params = audio_buffer_sink_set_ipc_params, + .on_audio_format_set = audio_buffer_sink_on_audio_format_set, + .set_alignment_constants = audio_buffer_sink_set_alignment_constants, + .get_lft = audio_buffer_sink_get_lft, }; static const struct audio_buffer_ops audio_buffer_ops = { .free = ring_buffer_free, - .reset = ring_buffer_reset + .reset = ring_buffer_reset, }; -struct ring_buffer *ring_buffer_create(size_t min_available, size_t min_free_space, bool is_shared, +struct ring_buffer *ring_buffer_create(struct comp_dev *dev, size_t min_available, + size_t min_free_space, bool is_shared, uint32_t id) { struct ring_buffer *ring_buffer; + struct mod_alloc_ctx *alloc = dev->mod->priv.resources.alloc; + struct k_heap *heap = alloc->heap; + int memory_flags = (is_shared ? SOF_MEM_FLAG_COHERENT : 0) | + user_get_buffer_memory_region(dev->drv); /* allocate ring_buffer structure */ - if (is_shared) - ring_buffer = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, - sizeof(*ring_buffer)); - else - ring_buffer = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(*ring_buffer)); + ring_buffer = sof_ctx_alloc(alloc, memory_flags, sizeof(*ring_buffer), 0); if (!ring_buffer) return NULL; + memset(ring_buffer, 0, sizeof(*ring_buffer)); + /* init base structure. The audio_stream_params is NULL because ring_buffer * is currently used as a secondary buffer for DP only * @@ -280,6 +310,8 @@ struct ring_buffer *ring_buffer_create(size_t min_available, size_t min_free_spa audio_buffer_init(&ring_buffer->audio_buffer, BUFFER_TYPE_RING_BUFFER, is_shared, &ring_buffer_source_ops, &ring_buffer_sink_ops, &audio_buffer_ops, NULL); + ring_buffer->audio_buffer.alloc = alloc; + ring_buffer->audio_buffer.alloc->heap = heap; /* set obs/ibs in sink/source interfaces */ sink_set_min_free_space(audio_buffer_get_sink(&ring_buffer->audio_buffer), @@ -334,13 +366,19 @@ struct ring_buffer *ring_buffer_create(size_t min_available, size_t min_free_spa ring_buffer->data_buffer_size = 3 * max_ibs_obs; /* allocate data buffer - always in cached memory alias */ - ring_buffer->data_buffer_size = - ALIGN_UP(ring_buffer->data_buffer_size, PLATFORM_DCACHE_ALIGN); - ring_buffer->_data_buffer = (__sparse_force __sparse_cache void *) - rballoc_align(0, 0, ring_buffer->data_buffer_size, PLATFORM_DCACHE_ALIGN); - if (!ring_buffer->_data_buffer) + ring_buffer->data_buffer_size = ALIGN_UP(ring_buffer->data_buffer_size, + PLATFORM_DCACHE_ALIGN); + + void *data_buf; + + data_buf = sof_ctx_alloc(alloc, user_get_buffer_memory_region(dev->drv), + ring_buffer->data_buffer_size, PLATFORM_DCACHE_ALIGN); + + if (!data_buf) goto err; + ring_buffer->_data_buffer = (__sparse_force __sparse_cache void *)data_buf; + tr_info(&ring_buffer_tr, "Ring buffer created, id: %u shared: %u min_available: %u min_free_space %u, size %u", id, ring_buffer_is_shared(ring_buffer), min_available, min_free_space, ring_buffer->data_buffer_size); @@ -349,6 +387,6 @@ struct ring_buffer *ring_buffer_create(size_t min_available, size_t min_free_spa return ring_buffer; err: tr_err(&ring_buffer_tr, "Ring buffer creation failure"); - rfree(ring_buffer); + sof_ctx_free(alloc, ring_buffer); return NULL; } diff --git a/src/audio/chain_dma.c b/src/audio/chain_dma.c index 41282fd24eeb..257dead39b52 100644 --- a/src/audio/chain_dma.c +++ b/src/audio/chain_dma.c @@ -18,6 +18,7 @@ #include <sof/schedule/schedule.h> #include <rtos/task.h> #include <sof/lib/dma.h> +#include <sof/lib/memory.h> #include <ipc4/error_status.h> #include <ipc4/module.h> #include <ipc4/pipeline.h> @@ -26,15 +27,16 @@ #include <rtos/init.h> #if CONFIG_XRUN_NOTIFICATIONS_ENABLE #include <ipc4/notification.h> -#include <sof/ipc/msg.h> -#include <ipc/header.h> #endif -#define DT_NUM_HDA_IN DT_PROP(DT_INST(0, intel_adsp_hda_link_in), dma_channels) -#define DT_NUM_HDA_OUT DT_PROP(DT_INST(0, intel_adsp_hda_link_out), dma_channels) +#define DT_NUM_HDA_HOST_IN DT_PROP(DT_INST(0, intel_adsp_hda_host_in), dma_channels) +#define DT_NUM_HDA_HOST_OUT DT_PROP(DT_INST(0, intel_adsp_hda_host_out), dma_channels) + +#define DT_NUM_HDA_LINK_IN DT_PROP(DT_INST(0, intel_adsp_hda_link_in), dma_channels) +#define DT_NUM_HDA_LINK_OUT DT_PROP(DT_INST(0, intel_adsp_hda_link_out), dma_channels) static const struct comp_driver comp_chain_dma; -static const uint32_t max_chain_number = DT_NUM_HDA_OUT + DT_NUM_HDA_IN; +static const uint32_t max_chain_number = DT_NUM_HDA_HOST_OUT + DT_NUM_HDA_HOST_IN; LOG_MODULE_REGISTER(chain_dma, CONFIG_SOF_LOG_LEVEL); @@ -55,17 +57,16 @@ struct chain_dma_data { uint8_t cs; #if CONFIG_XRUN_NOTIFICATIONS_ENABLE bool xrun_notification_sent; - struct ipc_msg *msg_xrun; #endif /* local host DMA config */ - struct dma *dma_host; + struct sof_dma *dma_host; struct dma_chan_data *chan_host; struct dma_config z_config_host; struct dma_block_config dma_block_cfg_host; /* local link DMA config */ - struct dma *dma_link; + struct sof_dma *dma_link; struct dma_chan_data *chan_link; struct dma_config z_config_link; struct dma_block_config dma_block_cfg_link; @@ -82,7 +83,7 @@ static int chain_host_start(struct comp_dev *dev) if (err < 0) return err; - comp_info(dev, "chain_host_start(): dma_start() host chan_index = %u", + comp_info(dev, "dma_start() host chan_index = %u", cd->chan_host->index); return 0; } @@ -96,7 +97,7 @@ static int chain_link_start(struct comp_dev *dev) if (err < 0) return err; - comp_info(dev, "chain_link_start(): dma_start() link chan_index = %u", + comp_info(dev, "dma_start() link chan_index = %u", cd->chan_link->index); return 0; } @@ -110,7 +111,7 @@ static int chain_link_stop(struct comp_dev *dev) if (err < 0) return err; - comp_info(dev, "chain_link_stop(): dma_stop() link chan_index = %u", + comp_info(dev, "dma_stop() link chan_index = %u", cd->chan_link->index); return 0; @@ -125,7 +126,7 @@ static int chain_host_stop(struct comp_dev *dev) if (err < 0) return err; - comp_info(dev, "chain_host_stop(): dma_stop() host chan_index = %u", + comp_info(dev, "dma_stop() host chan_index = %u", cd->chan_host->index); return 0; @@ -142,30 +143,13 @@ static size_t chain_get_transferred_data_size(const uint32_t out_read_pos, const } #if CONFIG_XRUN_NOTIFICATIONS_ENABLE -static void handle_xrun(struct chain_dma_data *cd) +static void chain_dma_send_xrun_notif(struct chain_dma_data *cd) { - int ret; + uint32_t resource_id = cd->link_connector_node_id.dw; + enum sof_ipc_stream_direction dir = cd->stream_direction; - if (cd->link_connector_node_id.f.dma_type == ipc4_hda_link_output_class && - !cd->xrun_notification_sent) { - tr_warn(&chain_dma_tr, "handle_xrun(): underrun detected"); - xrun_notif_msg_init(cd->msg_xrun, cd->link_connector_node_id.dw, - SOF_IPC4_GATEWAY_UNDERRUN_DETECTED); - ipc_msg_send(cd->msg_xrun, NULL, true); - cd->xrun_notification_sent = true; - } else if (cd->link_connector_node_id.f.dma_type == ipc4_hda_link_input_class && - !cd->xrun_notification_sent) { - tr_warn(&chain_dma_tr, "handle_xrun(): overrun detected"); - xrun_notif_msg_init(cd->msg_xrun, cd->link_connector_node_id.dw, - SOF_IPC4_GATEWAY_OVERRUN_DETECTED); - ipc_msg_send(cd->msg_xrun, NULL, true); - cd->xrun_notification_sent = true; - } else { - /* if xrun_notification_sent is already set, then it means that link was - * able to reach stability therefore next underrun/overrun should be reported. - */ - cd->xrun_notification_sent = false; - } + if (!cd->xrun_notification_sent) + cd->xrun_notification_sent = send_gateway_xrun_notif_msg(resource_id, dir); } #endif @@ -184,16 +168,19 @@ static enum task_state chain_task_run(void *data) ret = dma_get_status(cd->chan_link->dma->z_dev, cd->chan_link->index, &stat); switch (ret) { case 0: +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE + cd->xrun_notification_sent = false; +#endif break; case -EPIPE: - tr_warn(&chain_dma_tr, "chain_task_run(): dma_get_status() link xrun occurred," - " ret = %u", ret); #if CONFIG_XRUN_NOTIFICATIONS_ENABLE - handle_xrun(cd); + chain_dma_send_xrun_notif(cd); #endif + tr_warn(&chain_dma_tr, "dma_get_status() link xrun occurred," + " ret = %d", ret); break; default: - tr_err(&chain_dma_tr, "chain_task_run(): dma_get_status() error, ret = %u", ret); + tr_err(&chain_dma_tr, "dma_get_status() error, ret = %d", ret); return SOF_TASK_STATE_COMPLETED; } @@ -204,7 +191,7 @@ static enum task_state chain_task_run(void *data) /* Host DMA does not report xruns. All error values will be treated as critical. */ ret = dma_get_status(cd->chan_host->dma->z_dev, cd->chan_host->index, &stat); if (ret < 0) { - tr_err(&chain_dma_tr, "chain_task_run(): dma_get_status() error, ret = %u", ret); + tr_err(&chain_dma_tr, "dma_get_status() error, ret = %d", ret); return SOF_TASK_STATE_COMPLETED; } @@ -223,14 +210,14 @@ static enum task_state chain_task_run(void *data) ret = dma_reload(cd->chan_host->dma->z_dev, cd->chan_host->index, 0, 0, increment); if (ret < 0) { tr_err(&chain_dma_tr, - "chain_task_run(): dma_reload() host error, ret = %u", ret); + "dma_reload() host error, ret = %d", ret); return SOF_TASK_STATE_COMPLETED; } ret = dma_reload(cd->chan_link->dma->z_dev, cd->chan_link->index, 0, 0, increment); if (ret < 0) { tr_err(&chain_dma_tr, - "chain_task_run(): dma_reload() link error, ret = %u", ret); + "dma_reload() link error, ret = %d", ret); return SOF_TASK_STATE_COMPLETED; } } else { @@ -245,11 +232,10 @@ static enum task_state chain_task_run(void *data) 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, - half_buff_size); + MIN(host_avail_bytes, link_free_bytes)); if (ret < 0) { tr_err(&chain_dma_tr, - "chain_task_run(): dma_reload() link error, ret = %u", - ret); + "dma_reload() link error, ret = %d", ret); return SOF_TASK_STATE_COMPLETED; } cd->first_data_received = true; @@ -264,7 +250,7 @@ static enum task_state chain_task_run(void *data) 0, 0, transferred); if (ret < 0) { tr_err(&chain_dma_tr, - "chain_task_run(): dma_reload() host error, ret = %u", ret); + "dma_reload() host error, ret = %d", ret); return SOF_TASK_STATE_COMPLETED; } @@ -273,8 +259,8 @@ static enum task_state chain_task_run(void *data) ret = dma_reload(cd->chan_link->dma->z_dev, cd->chan_link->index, 0, 0, half_buff_size); if (ret < 0) { - tr_err(&chain_dma_tr, "chain_task_run(): dma_reload() " - "link error, ret = %u", ret); + tr_err(&chain_dma_tr, + "dma_reload() link error, ret = %d", ret); return SOF_TASK_STATE_COMPLETED; } } @@ -285,17 +271,13 @@ static enum task_state chain_task_run(void *data) static int chain_task_start(struct comp_dev *dev) { - struct comp_driver_list *drivers = comp_drivers_get(); struct chain_dma_data *cd = comp_get_drvdata(dev); - k_spinlock_key_t key; int ret; - comp_info(dev, "chain_task_start(), host_dma_id = 0x%08x", cd->host_connector_node_id.dw); + comp_info(dev, "host_dma_id = 0x%08x", cd->host_connector_node_id.dw); - key = k_spin_lock(&drivers->lock); switch (cd->chain_task.state) { case SOF_TASK_STATE_QUEUED: - k_spin_unlock(&drivers->lock, key); return 0; case SOF_TASK_STATE_COMPLETED: break; @@ -304,28 +286,27 @@ static int chain_task_start(struct comp_dev *dev) case SOF_TASK_STATE_FREE: break; default: - comp_err(dev, "chain_task_start(), bad state transition"); - ret = -EINVAL; - goto error; + comp_err(dev, "bad state transition"); + return -EINVAL; } if (cd->stream_direction == SOF_IPC_STREAM_PLAYBACK) { ret = chain_host_start(dev); if (ret) - goto error; + return ret; ret = chain_link_start(dev); if (ret) { chain_host_stop(dev); - goto error; + return ret; } } else { ret = chain_link_start(dev); if (ret) - goto error; + return ret; ret = chain_host_start(dev); if (ret) { chain_link_stop(dev); - goto error; + return ret; } } @@ -333,41 +314,36 @@ static int chain_task_start(struct comp_dev *dev) SOF_SCHEDULE_LL_TIMER, SOF_TASK_PRI_HIGH, chain_task_run, cd, 0, 0); if (ret < 0) { - comp_err(dev, "chain_task_start(), ll task initialization failed"); + comp_err(dev, "ll task initialization failed"); goto error_task; } ret = schedule_task(&cd->chain_task, 0, 0); if (ret < 0) { - comp_err(dev, "chain_task_start(), ll schedule task failed"); + comp_err(dev, "ll schedule task failed"); schedule_task_free(&cd->chain_task); goto error_task; } pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); - k_spin_unlock(&drivers->lock, key); return 0; error_task: chain_host_stop(dev); chain_link_stop(dev); -error: - k_spin_unlock(&drivers->lock, key); + return ret; } static int chain_task_pause(struct comp_dev *dev) { - struct comp_driver_list *drivers = comp_drivers_get(); struct chain_dma_data *cd = comp_get_drvdata(dev); - k_spinlock_key_t key; int ret, ret2; if (cd->chain_task.state == SOF_TASK_STATE_FREE) return 0; - key = k_spin_lock(&drivers->lock); cd->first_data_received = false; if (cd->stream_direction == SOF_IPC_STREAM_PLAYBACK) { ret = chain_host_stop(dev); @@ -379,18 +355,18 @@ static int chain_task_pause(struct comp_dev *dev) if (!ret) ret = ret2; - k_spin_unlock(&drivers->lock, key); - schedule_task_free(&cd->chain_task); pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); return ret; } -static void chain_release(struct comp_dev *dev) +__cold static void chain_release(struct comp_dev *dev) { struct chain_dma_data *cd = comp_get_drvdata(dev); + assert_can_be_cold(); + dma_release_channel(cd->chan_host->dma->z_dev, cd->chan_host->index); sof_dma_put(cd->dma_host); dma_release_channel(cd->chan_link->dma->z_dev, cd->chan_link->index); @@ -403,15 +379,30 @@ static void chain_release(struct comp_dev *dev) } /* Retrieves host connector node id from dma id */ -static int get_connector_node_id(uint32_t dma_id, bool host_type, - union ipc4_connector_node_id *connector_node_id) +__cold static int get_connector_node_id(uint32_t dma_id, bool host_type, + union ipc4_connector_node_id *connector_node_id) { - uint8_t type = host_type ? ipc4_hda_host_output_class : ipc4_hda_link_output_class; + uint32_t max_out, max_in; + uint8_t type, type2; - if (dma_id >= DT_NUM_HDA_OUT) { - type = host_type ? ipc4_hda_host_input_class : ipc4_hda_link_input_class; - dma_id -= DT_NUM_HDA_OUT; - if (dma_id >= DT_NUM_HDA_IN) + assert_can_be_cold(); + + if (host_type) { + type = ipc4_hda_host_output_class; + type2 = ipc4_hda_host_input_class; + max_out = DT_NUM_HDA_HOST_OUT; + max_in = DT_NUM_HDA_HOST_IN; + } else { + type = ipc4_hda_link_output_class; + type2 = ipc4_hda_link_input_class; + max_out = DT_NUM_HDA_LINK_OUT; + max_in = DT_NUM_HDA_LINK_IN; + } + + if (dma_id >= max_out) { + type = type2; + dma_id -= max_out; + if (dma_id >= max_in) return -EINVAL; } connector_node_id->dw = 0; @@ -421,7 +412,7 @@ static int get_connector_node_id(uint32_t dma_id, bool host_type, return 0; } -static int chain_init(struct comp_dev *dev, void *addr, size_t length) +__cold static int chain_init(struct comp_dev *dev, void *addr, size_t length) { struct chain_dma_data *cd = comp_get_drvdata(dev); struct dma_block_config *dma_block_cfg_host = &cd->dma_block_cfg_host; @@ -431,6 +422,8 @@ static int chain_init(struct comp_dev *dev, void *addr, size_t length) int channel; int err; + assert_can_be_cold(); + memset(dma_cfg_host, 0, sizeof(*dma_cfg_host)); memset(dma_block_cfg_host, 0, sizeof(*dma_block_cfg_host)); dma_cfg_host->block_count = 1; @@ -466,15 +459,16 @@ static int chain_init(struct comp_dev *dev, void *addr, size_t length) channel = cd->host_connector_node_id.f.v_index; channel = dma_request_channel(cd->dma_host->z_dev, &channel); if (channel < 0) { - comp_err(dev, "chain_init(): dma_request_channel() failed"); - return -EINVAL; + comp_err(dev, "host dma_request_channel() failed for %u", + cd->host_connector_node_id.f.v_index); + return channel; } cd->chan_host = &cd->dma_host->chan[channel]; err = dma_config(cd->dma_host->z_dev, cd->chan_host->index, dma_cfg_host); if (err < 0) { - comp_err(dev, "chain_init(): dma_config() failed"); + comp_err(dev, "host dma_config() failed for %d", channel); goto error_host; } @@ -482,7 +476,9 @@ static int chain_init(struct comp_dev *dev, void *addr, size_t length) channel = cd->link_connector_node_id.f.v_index; channel = dma_request_channel(cd->dma_link->z_dev, &channel); if (channel < 0) { - comp_err(dev, "chain_init(): dma_request_channel() failed"); + comp_err(dev, "link dma_request_channel() failed for %u", + cd->link_connector_node_id.f.v_index); + err = channel; goto error_host; } @@ -490,7 +486,7 @@ static int chain_init(struct comp_dev *dev, void *addr, size_t length) err = dma_config(cd->dma_link->z_dev, cd->chan_link->index, dma_cfg_link); if (err < 0) { - comp_err(dev, "chain_init(): dma_config() failed"); + comp_err(dev, "link dma_config() failed for %d", channel); goto error_link; } return 0; @@ -504,8 +500,8 @@ static int chain_init(struct comp_dev *dev, void *addr, size_t length) return err; } -static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uint8_t link_dma_id, - uint32_t fifo_size) +__cold static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uint8_t link_dma_id, + uint32_t fifo_size) { struct chain_dma_data *cd = comp_get_drvdata(dev); uint32_t addr_align; @@ -514,6 +510,8 @@ static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uint8_t li uint32_t dir; int ret; + assert_can_be_cold(); + ret = get_connector_node_id(host_dma_id, true, &cd->host_connector_node_id); if (ret < 0) return ret; @@ -540,7 +538,7 @@ static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uint8_t li cd->dma_host = sof_dma_get(dir, 0, SOF_DMA_DEV_HOST, SOF_DMA_ACCESS_SHARED); if (!cd->dma_host) { - comp_err(dev, "chain_task_init(): dma_get() returned NULL"); + comp_err(dev, "dma_get() returned NULL"); return -EINVAL; } @@ -550,7 +548,7 @@ static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uint8_t li cd->dma_link = sof_dma_get(dir, SOF_DMA_CAP_HDA, SOF_DMA_DEV_HDA, SOF_DMA_ACCESS_SHARED); if (!cd->dma_link) { sof_dma_put(cd->dma_host); - comp_err(dev, "chain_task_init(): dma_get() returned NULL"); + comp_err(dev, "dma_get() returned NULL"); return -EINVAL; } @@ -559,8 +557,7 @@ static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uint8_t li &addr_align); if (ret < 0) { comp_err(dev, - "chain_task_init(): could not get dma buffer address alignment, err = %d", - ret); + "could not get dma buffer address alignment, err = %d", ret); goto error; } @@ -586,10 +583,11 @@ 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); /* allocate not shared buffer */ - cd->dma_buffer = buffer_alloc(fifo_size, SOF_MEM_CAPS_DMA, 0, addr_align, false); + cd->dma_buffer = buffer_alloc(NULL, fifo_size, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA, + addr_align, BUFFER_USAGE_NOT_SHARED); if (!cd->dma_buffer) { - comp_err(dev, "chain_task_init(): failed to alloc dma buffer"); + comp_err(dev, "failed to alloc dma buffer"); ret = -EINVAL; goto error; } @@ -627,9 +625,9 @@ static int chain_task_trigger(struct comp_dev *dev, int cmd) } } -static struct comp_dev *chain_task_create(const struct comp_driver *drv, - const struct comp_ipc_config *ipc_config, - const void *ipc_specific_config) +__cold static struct comp_dev *chain_task_create(const struct comp_driver *drv, + const struct comp_ipc_config *ipc_config, + const void *ipc_specific_config) { const struct ipc4_chain_dma *cdma = (struct ipc4_chain_dma *)ipc_specific_config; const uint32_t host_dma_id = cdma->primary.r.host_dma_id; @@ -640,6 +638,8 @@ static struct comp_dev *chain_task_create(const struct comp_driver *drv, struct comp_dev *dev; int ret; + assert_can_be_cold(); + if (host_dma_id >= max_chain_number) return NULL; @@ -647,7 +647,7 @@ static struct comp_dev *chain_task_create(const struct comp_driver *drv, if (!dev) return NULL; - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); if (!cd) goto error; @@ -658,37 +658,24 @@ static struct comp_dev *chain_task_create(const struct comp_driver *drv, comp_set_drvdata(dev, cd); ret = chain_task_init(dev, host_dma_id, link_dma_id, fifo_size); - if (ret) - goto error_cd; - -#if CONFIG_XRUN_NOTIFICATIONS_ENABLE - cd->msg_xrun = ipc_msg_init(header.dat, - sizeof(struct ipc4_resource_event_data_notification)); - if (!cd->msg_xrun) - goto error_cd; - cd->xrun_notification_sent = false; -#endif - - return dev; + if (!ret) + return dev; -error_cd: rfree(cd); error: - rfree(dev); + comp_free_device(dev); return NULL; } -static void chain_task_free(struct comp_dev *dev) +__cold static void chain_task_free(struct comp_dev *dev) { struct chain_dma_data *cd = comp_get_drvdata(dev); -#if CONFIG_XRUN_NOTIFICATIONS_ENABLE - ipc_msg_free(cd->msg_xrun); -#endif + assert_can_be_cold(); chain_release(dev); rfree(cd); - rfree(dev); + comp_free_device(dev); } static const struct comp_driver comp_chain_dma = { @@ -707,8 +694,7 @@ static SHARED_DATA struct comp_driver_info comp_chain_dma_info = { UT_STATIC void sys_comp_chain_dma_init(void) { - comp_register(platform_shared_get(&comp_chain_dma_info, - sizeof(comp_chain_dma_info))); + comp_register(&comp_chain_dma_info); } DECLARE_MODULE(sys_comp_chain_dma_init); diff --git a/src/audio/channel_map.c b/src/audio/channel_map.c index a2ef0a5528dc..b743fdacb0cd 100644 --- a/src/audio/channel_map.c +++ b/src/audio/channel_map.c @@ -28,7 +28,7 @@ struct sof_ipc_channel_map *chmap_get(struct sof_ipc_stream_map *smap, uint32_t byte = 0; if (index >= smap->num_ch_map) { - tr_err(&chmap_tr, "chmap_get(): index %d out of bounds %d", + tr_err(&chmap_tr, "index %d out of bounds %d", index, smap->num_ch_map); return NULL; diff --git a/src/audio/codec/CMakeLists.txt b/src/audio/codec/CMakeLists.txt index d32c421ad997..5212a3631daf 100644 --- a/src/audio/codec/CMakeLists.txt +++ b/src/audio/codec/CMakeLists.txt @@ -1,12 +1,21 @@ # SPDX-License-Identifier: BSD-3-Clause -if(CONFIG_DTS_CODEC) - add_local_sources(sof dts/dts.c) - target_compile_definitions(sof PRIVATE -DDTS_MATH_INT32 -DDTS_XTENSA) - if (CONFIG_DTS_CODEC_STUB) - add_local_sources(sof dts/dts_stub.c) - else() - sof_add_static_library(DtsCodec - ${SOF_ROOT_SOURCE_DIRECTORY}/third_party/lib/libdts-sof-interface-i32.a) - endif() +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + if(CONFIG_DTS_CODEC STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(dts/llext ${PROJECT_BINARY_DIR}/dts_llext) + add_dependencies(app dts) + + elseif(CONFIG_DTS_CODEC) + zephyr_library_sources(dts/dts.c) + if (CONFIG_DTS_CODEC_STUB) + zephyr_library_sources(dts/dts_stub.c) + else() + zephyr_library_import(DtsCodec + ${sof_top_dir}/third_party/lib/libdts-sof-interface-i32.a) + endif() + endif() + + return() endif() diff --git a/src/audio/codec/Kconfig b/src/audio/codec/Kconfig index 59eaef67e1b7..0f089e3a7c54 100644 --- a/src/audio/codec/Kconfig +++ b/src/audio/codec/Kconfig @@ -2,7 +2,6 @@ config DTS_CODEC tristate "DTS codec" - default n select DTS_CODEC_STUB if COMP_STUBS help Select to include DTS codec. @@ -14,7 +13,6 @@ config DTS_CODEC config DTS_CODEC_STUB bool "DTS codec stub" depends on DTS_CODEC - default n help Select to include DTS codec stub library. This is meant for testing and CI purposes only. diff --git a/src/audio/codec/README.md b/src/audio/codec/README.md new file mode 100644 index 000000000000..76a27e696d1a --- /dev/null +++ b/src/audio/codec/README.md @@ -0,0 +1,13 @@ +# Codec Abstraction Architecture + +This directory contains abstractions and adapters for various hardware and software audio codecs. + +## Overview + +Provides a unified interface to initialize, configure, and stream data to/from codec dependencies. + +## Configuration and Scripts + +- **Kconfig**: Specifically manages configurations for external codecs. For example, it defines options for the `DTS_CODEC`, including a testing/CI stub `DTS_CODEC_STUB` when `COMP_STUBS` is enabled. Use of the actual DTS codec requires a pre-compiled static library from Xperi. +- **CMakeLists.txt**: Specifies Zephyr build integration. For the DTS codec, it checks for modular builds (`llext`). If built statically, it either links the stub source or imports the pre-compiled `libdts-sof-interface-i32.a` library depending on configuration. +- **Topology (.conf)**: `tools/topology/topology2/include/components/dts.conf` defines the `dts` widget. It exposes `cpc` (cycles per chunk) and configures a byte control of size 2048 with `extctl` operations. Defaults to UUID `4f:c3:5f:d9:0f:37:c7:4a:bc:86:bf:dc:5b:e2:41:e6`. diff --git a/src/audio/codec/dts/dts.c b/src/audio/codec/dts/dts.c index c61ac2b8ef00..bc4795055576 100644 --- a/src/audio/codec/dts/dts.c +++ b/src/audio/codec/dts/dts.c @@ -8,11 +8,9 @@ #include <sof/audio/module_adapter/module/generic.h> #include "DtsSofInterface.h" - LOG_MODULE_REGISTER(dts, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(dts); -DECLARE_TR_CTX(dts_tr, SOF_UUID(dts_uuid), LOG_LEVEL_INFO); #define MAX_EXPECTED_DTS_CONFIG_DATA_SIZE 8192 @@ -25,7 +23,7 @@ static void *dts_effect_allocate_codec_memory(void *mod_void, unsigned int lengt comp_dbg(dev, "dts_effect_allocate_codec_memory() start"); - pMem = module_allocate_memory(mod, (uint32_t)length, (uint32_t)alignment); + pMem = mod_alloc_align(mod, (uint32_t)length, (uint32_t)alignment); if (pMem == NULL) comp_err(dev, @@ -40,14 +38,14 @@ static void dts_effect_free_codec_memory(void *mod_void, void *pMem) struct processing_module *mod = mod_void; struct comp_dev *dev = mod->dev; - comp_dbg(dev, "dts_effect_free_codec_memory() start"); + comp_dbg(dev, "start"); - int ret = module_free_memory(mod, pMem); + int ret = mod_free(mod, pMem); if (ret) - comp_err(dev, "dts_effect_free_codec_memory() module_free_memory failed %d", ret); + comp_err(dev, "mod_free failed %d", ret); - comp_dbg(dev, "dts_effect_free_codec_memory() done"); + comp_dbg(dev, "done"); } static int dts_effect_convert_sof_interface_result(struct comp_dev *dev, @@ -82,7 +80,7 @@ static int dts_effect_populate_buffer_configuration(struct comp_dev *dev, DtsSofInterfaceBufferFormat buffer_format; unsigned int buffer_fmt, frame_fmt, rate, channels; - comp_dbg(dev, "dts_effect_populate_buffer_configuration() start"); + comp_dbg(dev, "start"); if (!source) return -EINVAL; @@ -127,7 +125,7 @@ static int dts_effect_populate_buffer_configuration(struct comp_dev *dev, buffer_config->numChannels = channels; buffer_config->periodInFrames = dev->frames; - comp_dbg(dev, "dts_effect_populate_buffer_configuration() done"); + comp_dbg(dev, "done"); return 0; } @@ -141,14 +139,14 @@ static int dts_codec_init(struct processing_module *mod) DtsSofInterfaceVersionInfo interface_version; DtsSofInterfaceVersionInfo sdk_version; - comp_dbg(dev, "dts_codec_init() start"); + comp_dbg(dev, "start"); dts_result = dtsSofInterfaceInit((DtsSofInterfaceInst **)&(codec->private), dts_effect_allocate_codec_memory, dts_effect_free_codec_memory, mod); ret = dts_effect_convert_sof_interface_result(dev, dts_result); if (ret) - comp_err(dev, "dts_codec_init() dtsSofInterfaceInit failed %d %d", ret, dts_result); + comp_err(dev, "dtsSofInterfaceInit failed %d %d", ret, dts_result); /* Obtain the current versions of DTS interface and SDK */ dts_result = dtsSofInterfaceGetVersion(&interface_version, &sdk_version); @@ -156,13 +154,13 @@ static int dts_codec_init(struct processing_module *mod) /* Not necessary to fail initialisation if only get version failed */ if (dts_result == DTS_SOF_INTERFACE_RESULT_SUCCESS) { comp_info(dev, - "dts_codec_init() DTS SOF Interface version %d.%d.%d.%d", + "DTS SOF Interface version %d.%d.%d.%d", interface_version.major, interface_version.minor, interface_version.patch, interface_version.build); comp_info(dev, - "dts_codec_init() DTS SDK version %d.%d.%d.%d", + "DTS SDK version %d.%d.%d.%d", sdk_version.major, sdk_version.minor, sdk_version.patch, @@ -170,9 +168,9 @@ static int dts_codec_init(struct processing_module *mod) } if (ret) - comp_err(dev, "dts_codec_init() failed %d %d", ret, dts_result); + comp_err(dev, "failed %d %d", ret, dts_result); - comp_dbg(dev, "dts_codec_init() done"); + comp_dbg(dev, "done"); return ret; } @@ -187,12 +185,12 @@ static int dts_codec_prepare(struct processing_module *mod, DtsSofInterfaceBufferConfiguration buffer_configuration; DtsSofInterfaceResult dts_result; - comp_dbg(dev, "dts_codec_prepare() start"); + comp_dbg(dev, "start"); ret = dts_effect_populate_buffer_configuration(dev, &buffer_configuration); if (ret) { comp_err(dev, - "dts_codec_prepare() dts_effect_populate_buffer_configuration failed %d", + "dts_effect_populate_buffer_configuration failed %d", ret); return ret; } @@ -207,9 +205,9 @@ static int dts_codec_prepare(struct processing_module *mod, ret = dts_effect_convert_sof_interface_result(dev, dts_result); if (ret) - comp_err(dev, "dts_codec_prepare() failed %d", ret); + comp_err(dev, "failed %d", ret); - comp_dbg(dev, "dts_codec_prepare() done"); + comp_dbg(dev, "done"); return ret; } @@ -221,7 +219,7 @@ static int dts_codec_init_process(struct processing_module *mod) struct module_data *codec = &mod->priv; DtsSofInterfaceResult dts_result; - comp_dbg(dev, "dts_codec_init_process() start"); + comp_dbg(dev, "start"); dts_result = dtsSofInterfaceInitProcess(codec->private); ret = dts_effect_convert_sof_interface_result(dev, dts_result); @@ -231,9 +229,9 @@ static int dts_codec_init_process(struct processing_module *mod) codec->mpd.init_done = 1; if (ret) - comp_err(dev, "dts_codec_init_process() failed %d %d", ret, dts_result); + comp_err(dev, "failed %d %d", ret, dts_result); - comp_dbg(dev, "dts_codec_init_process() done"); + comp_dbg(dev, "done"); return ret; } @@ -251,7 +249,7 @@ dts_codec_process(struct processing_module *mod, /* Proceed only if we have enough data to fill the module buffer completely */ if (input_buffers[0].size < codec->mpd.in_buff_size) { - comp_dbg(dev, "dts_codec_process(): not enough data to process"); + comp_dbg(dev, "not enough data to process"); return -ENODATA; } @@ -265,7 +263,7 @@ dts_codec_process(struct processing_module *mod, input_buffers[0].data, codec->mpd.in_buff_size); codec->mpd.avail = codec->mpd.in_buff_size; - comp_dbg(dev, "dts_codec_process() start"); + comp_dbg(dev, "start"); dts_result = dtsSofInterfaceProcess(codec->private, &bytes_processed); ret = dts_effect_convert_sof_interface_result(dev, dts_result); @@ -275,7 +273,7 @@ dts_codec_process(struct processing_module *mod, input_buffers[0].consumed = codec->mpd.consumed; if (ret) { - comp_err(dev, "dts_codec_process() failed %d %d", ret, dts_result); + comp_err(dev, "failed %d %d", ret, dts_result); return ret; } @@ -284,7 +282,7 @@ dts_codec_process(struct processing_module *mod, codec->mpd.produced); output_buffers[0].size = codec->mpd.produced; - comp_dbg(dev, "dts_codec_process() done"); + comp_dbg(dev, "done"); return ret; } @@ -304,17 +302,17 @@ static int dts_codec_apply_config(struct processing_module *mod) uint32_t param_number = 0; DtsSofInterfaceResult dts_result; - comp_dbg(dev, "dts_codec_apply_config() start"); + comp_dbg(dev, "start"); config = &codec->cfg; /* Check that config->data isn't invalid and has size greater than 0 */ config_header_size = sizeof(config->size) + sizeof(config->avail); if (config->size < config_header_size) { - comp_warn(dev, "dts_codec_apply_config() config->data is invalid"); + comp_warn(dev, "config->data is invalid"); return 0; } else if (config->size == config_header_size) { - comp_warn(dev, "dts_codec_apply_config() size of config->data is 0"); + comp_warn(dev, "size of config->data is 0"); return 0; } @@ -324,19 +322,32 @@ static int dts_codec_apply_config(struct processing_module *mod) /* Check that config->data is not greater than the max expected for DTS data */ if (config_data_size > MAX_EXPECTED_DTS_CONFIG_DATA_SIZE) { comp_err(dev, - "dts_codec_apply_config() size of config->data is larger than max for DTS data"); + "size of config->data is larger than max for DTS data"); return -EINVAL; } /* Allow for multiple module_params to be packed into the data pointed to by config */ + param_header_size = sizeof(param->id) + sizeof(param->size); for (i = 0; i < config_data_size; param_number++) { + /* Need at least a param header in the remaining bytes to read id/size */ + if (config_data_size - i < param_header_size) { + comp_err(dev, "param header truncated"); + return -EINVAL; + } + param = (struct module_param *)((char *)config->data + i); - param_header_size = sizeof(param->id) + sizeof(param->size); /* If param->size is less than param_header_size, then this param is not valid */ if (param->size < param_header_size) { - comp_err(dev, "dts_codec_apply_config() param is invalid"); + comp_err(dev, "param is invalid"); + return -EINVAL; + } + + /* The whole param (header + data) must fit in the remaining config data */ + if (param->size > config_data_size - i) { + comp_err(dev, "param size %u exceeds remaining %u", + param->size, config_data_size - i); return -EINVAL; } @@ -345,7 +356,7 @@ static int dts_codec_apply_config(struct processing_module *mod) /* Calculate size of param->data */ param_data_size = param->size - param_header_size; - comp_dbg(dev, "dts_codec_apply_config() id %d size %d", + comp_dbg(dev, "id %d size %d", param->id, param_data_size); if (param_data_size) { @@ -354,7 +365,7 @@ static int dts_codec_apply_config(struct processing_module *mod) ret = dts_effect_convert_sof_interface_result(dev, dts_result); if (ret) { comp_err(dev, - "dts_codec_apply_config() dtsSofInterfaceApplyConfig failed %d", + "dtsSofInterfaceApplyConfig failed %d", dts_result); return ret; } @@ -365,7 +376,7 @@ static int dts_codec_apply_config(struct processing_module *mod) i += param->size; } - comp_dbg(dev, "dts_codec_apply_config() done"); + comp_dbg(dev, "done"); return ret; } @@ -377,15 +388,15 @@ static int dts_codec_reset(struct processing_module *mod) struct module_data *codec = &mod->priv; DtsSofInterfaceResult dts_result; - comp_dbg(dev, "dts_codec_reset() start"); + comp_dbg(dev, "start"); dts_result = dtsSofInterfaceReset(codec->private); ret = dts_effect_convert_sof_interface_result(dev, dts_result); if (ret) - comp_err(dev, "dts_codec_reset() failed %d %d", ret, dts_result); + comp_err(dev, "failed %d %d", ret, dts_result); - comp_dbg(dev, "dts_codec_reset() done"); + comp_dbg(dev, "done"); return ret; } @@ -397,17 +408,15 @@ static int dts_codec_free(struct processing_module *mod) struct module_data *codec = &mod->priv; DtsSofInterfaceResult dts_result; - comp_dbg(dev, "dts_codec_free() start"); + comp_dbg(dev, "start"); dts_result = dtsSofInterfaceFree(codec->private); ret = dts_effect_convert_sof_interface_result(dev, dts_result); if (ret) - comp_err(dev, "dts_codec_free() failed %d %d", ret, dts_result); + comp_err(dev, "failed %d %d", ret, dts_result); - module_free_all_memory(mod); - - comp_dbg(dev, "dts_codec_free() done"); + comp_dbg(dev, "done"); return ret; } @@ -427,21 +436,21 @@ dts_codec_set_configuration(struct processing_module *mod, uint32_t config_id, ret = module_set_configuration(mod, config_id, pos, data_offset_size, fragment, fragment_size, response, response_size); if (ret < 0) { - comp_err(dev, "dts_codec_set_configuration(): error %x from module_set_configuration()", + comp_err(dev, "error %x from module_set_configuration()", ret); return ret; } /* return if more fragments are expected */ if (pos != MODULE_CFG_FRAGMENT_LAST && pos != MODULE_CFG_FRAGMENT_SINGLE) { - comp_err(dev, "dts_codec_set_configuration(): pos %d error", pos); + comp_err(dev, "pos %d error", pos); return 0; } #if CONFIG_IPC_MAJOR_3 // return if the module is not prepared if (md->state < MODULE_INITIALIZED) { - comp_err(dev, "dts_codec_set_configuration(): state %d error", md->state); + comp_err(dev, "state %d error", md->state); return 0; } #endif @@ -449,12 +458,12 @@ dts_codec_set_configuration(struct processing_module *mod, uint32_t config_id, /* whole configuration received, apply it now */ ret = dts_codec_apply_config(mod); if (ret) { - comp_err(dev, "dts_codec_set_configuration(): error %x: runtime config apply failed", + comp_err(dev, "error %x: runtime config apply failed", ret); return ret; } - comp_dbg(dev, "dts_codec_set_configuration(): config applied"); + comp_dbg(dev, "config applied"); return 0; } @@ -468,9 +477,6 @@ static const struct module_interface dts_interface = { .free = dts_codec_free }; -DECLARE_MODULE_ADAPTER(dts_interface, dts_uuid, dts_tr); -SOF_MODULE_INIT(dts, sys_comp_module_dts_interface_init); - #if CONFIG_DTS_CODEC_MODULE /* modular: llext dynamic link */ @@ -478,14 +484,15 @@ SOF_MODULE_INIT(dts, sys_comp_module_dts_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_DTS 0x4F, 0xC3, 0x5F, 0xD9, 0x0F, 0x37, 0xC7, 0x4A, 0x86, 0xBC, \ - 0xBF, 0xDC, 0x5B, 0xE2, 0x41, 0xE6 - -SOF_LLEXT_MOD_ENTRY(dts, &dts_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("DTS", dts_llext_entry, 1, UUID_DTS, 40); + SOF_LLEXT_MODULE_MANIFEST("DTS", &dts_interface, 1, SOF_REG_UUID(dts), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(dts_tr, SOF_UUID(dts_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(dts_interface, dts_uuid, dts_tr); +SOF_MODULE_INIT(dts, sys_comp_module_dts_interface_init); + #endif diff --git a/src/audio/codec/dts/dts.toml b/src/audio/codec/dts/dts.toml index debbbd82b47f..12b8a4104ad5 100644 --- a/src/audio/codec/dts/dts.toml +++ b/src/audio/codec/dts/dts.toml @@ -5,7 +5,7 @@ REM # dts codec module config [[module.entry]] name = "DTS" - uuid = "D95FC34F-370F-4AC7-BC86-BFDC5BE241E6" + uuid = UUIDREG_STR_DTS affinity_mask = "0x1" instance_count = "40" domain_types = "0" @@ -19,6 +19,6 @@ 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] REM # 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] + mod_cfg = [0, 0, 0, 0, 2048, 5000000, 384, 384, 0, 5000, 0] index = __COUNTER__ diff --git a/src/audio/codec/dts/llext/CMakeLists.txt b/src/audio/codec/dts/llext/CMakeLists.txt index 23ace9bd95ac..da7043e10511 100644 --- a/src/audio/codec/dts/llext/CMakeLists.txt +++ b/src/audio/codec/dts/llext/CMakeLists.txt @@ -2,14 +2,21 @@ # SPDX-License-Identifier: Apache-2.0 if(CONFIG_DTS_CODEC_STUB) -sof_llext_build("dts" - SOURCES ../dts.c - ../dts_stub.c - LIB openmodules -) -target_include_directories(dts_llext_lib PRIVATE - "../../../../../third_party/include" -) + sof_llext_build("dts" + SOURCES ../dts.c + ../dts_stub.c + ) + target_include_directories(dts_llext_lib PRIVATE + "../../../../../third_party/include" + ) +elseif(CONFIG_DTS_CODEC STREQUAL "m") + sof_llext_build("dts" + SOURCES ../dts.c + INCLUDES "${sof_top_dir}/third_party/include" + LIBS_PATH "${sof_top_dir}/third_party/lib/" + LIBS dts-sof-interface-i32 m c gcc + ) + else() message(FATAL_ERROR "Add library linking support in src/audio/codec/dts/llext/CMakeLists.txt") endif() diff --git a/src/audio/component.c b/src/audio/component.c index 33ee3e6f0419..8a6d35776971 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -5,6 +5,7 @@ // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> #include <sof/audio/component_ext.h> +#include <sof/audio/sink_source_utils.h> #include <sof/common.h> #include <sof/debug/telemetry/performance_monitor.h> #include <rtos/panic.h> @@ -13,6 +14,7 @@ #include <rtos/alloc.h> #include <rtos/cache.h> #include <sof/lib/memory.h> /* for SHARED_DATA */ +#include <sof/lib/uuid.h> #include <sof/list.h> #include <rtos/sof.h> #include <rtos/string.h> @@ -34,7 +36,7 @@ LOG_MODULE_REGISTER(component, CONFIG_SOF_LOG_LEVEL); -static SHARED_DATA struct comp_driver_list cd; +static APP_SYSUSER_BSS SHARED_DATA struct comp_driver_list cd; SOF_DEFINE_REG_UUID(component); @@ -43,24 +45,52 @@ DECLARE_TR_CTX(comp_tr, SOF_UUID(component_uuid), LOG_LEVEL_INFO); int comp_register(struct comp_driver_info *drv) { struct comp_driver_list *drivers = comp_drivers_get(); - k_spinlock_key_t key; - key = k_spin_lock(&drivers->lock); + /* + * No locking needed: the driver list is only modified at FW boot, + * where module init runs serially on the primary core, and at + * runtime from the serialized IPC thread (library load). These + * never overlap, so concurrent modification is not possible. + */ list_item_prepend(&drv->list, &drivers->list); - k_spin_unlock(&drivers->lock, key); return 0; } -EXPORT_SYMBOL(comp_register); void comp_unregister(struct comp_driver_info *drv) +{ + /* see comp_register() on why no locking is needed */ + list_item_del(&drv->list); +} + +int comp_set_adapter_ops(const struct comp_driver *drv, const struct module_interface *ops) { struct comp_driver_list *drivers = comp_drivers_get(); - k_spinlock_key_t key; + struct list_item *clist; + + /* The list is only modified in IPC context, and we're in IPC context too */ + list_for_item(clist, &drivers->list) { + struct comp_driver_info *info = container_of(clist, struct comp_driver_info, list); + + if (!memcmp(info->drv->uid, drv->uid, UUID_SIZE)) { + /* + * This function should only be called for dynamically + * loaded component drivers and their driver info cannot + * be NULL. Do a sanity check. + */ + if (!info->adapter_ops) { + tr_err(&comp_tr, "NULL adapter ops ptr for %pU!", + info->drv->tctx->uuid_p); + return -EINVAL; + } - key = k_spin_lock(&drivers->lock); - list_item_del(&drv->list); - k_spin_unlock(&drivers->lock, key); + tr_dbg(&comp_tr, "update uuid %pU", info->drv->tctx->uuid_p); + *info->adapter_ops = ops; + return 0; + } + } + + return -ENODEV; } /* NOTE: Keep the component state diagram up to date: @@ -72,7 +102,7 @@ int comp_set_state(struct comp_dev *dev, int cmd) int requested_state = comp_get_requested_state(cmd); if (dev->state == requested_state) { - comp_info(dev, "comp_set_state(), state already set to %u", + comp_info(dev, "state already set to %u", dev->state); #ifdef CONFIG_IPC_MAJOR_4 return 0; @@ -84,14 +114,14 @@ int comp_set_state(struct comp_dev *dev, int cmd) switch (cmd) { case COMP_TRIGGER_START: if (dev->state != COMP_STATE_PRE_ACTIVE) { - comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_START", + comp_err(dev, "wrong state = %u, COMP_TRIGGER_START", dev->state); return -EINVAL; } break; case COMP_TRIGGER_RELEASE: if (dev->state != COMP_STATE_PRE_ACTIVE) { - comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_RELEASE", + comp_err(dev, "wrong state = %u, COMP_TRIGGER_RELEASE", dev->state); return -EINVAL; } @@ -99,7 +129,7 @@ int comp_set_state(struct comp_dev *dev, int cmd) case COMP_TRIGGER_STOP: if (dev->state != COMP_STATE_ACTIVE && dev->state != COMP_STATE_PAUSED) { - comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_STOP", + comp_err(dev, "wrong state = %u, COMP_TRIGGER_STOP", dev->state); return -EINVAL; } @@ -107,7 +137,7 @@ int comp_set_state(struct comp_dev *dev, int cmd) case COMP_TRIGGER_PAUSE: /* only support pausing for running */ if (dev->state != COMP_STATE_ACTIVE) { - comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_PAUSE", + comp_err(dev, "wrong state = %u, COMP_TRIGGER_PAUSE", dev->state); return -EINVAL; } @@ -115,15 +145,15 @@ int comp_set_state(struct comp_dev *dev, int cmd) case COMP_TRIGGER_RESET: /* reset always succeeds */ if (dev->state == COMP_STATE_ACTIVE) - comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_RESET", + comp_err(dev, "wrong state = %u, COMP_TRIGGER_RESET", dev->state); else if (dev->state == COMP_STATE_PAUSED) - comp_info(dev, "comp_set_state(): state = %u, COMP_TRIGGER_RESET", + comp_info(dev, "state = %u, COMP_TRIGGER_RESET", dev->state); break; case COMP_TRIGGER_PREPARE: if (dev->state != COMP_STATE_READY) { - comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_PREPARE", + comp_err(dev, "wrong state = %u, COMP_TRIGGER_PREPARE", dev->state); return -EINVAL; } @@ -131,7 +161,7 @@ int comp_set_state(struct comp_dev *dev, int cmd) case COMP_TRIGGER_PRE_START: if (dev->state != COMP_STATE_PREPARE) { comp_err(dev, - "comp_set_state(): wrong state = %u, COMP_TRIGGER_PRE_START", + "wrong state = %u, COMP_TRIGGER_PRE_START", dev->state); return -EINVAL; } @@ -139,7 +169,7 @@ int comp_set_state(struct comp_dev *dev, int cmd) case COMP_TRIGGER_PRE_RELEASE: if (dev->state != COMP_STATE_PAUSED) { comp_err(dev, - "comp_set_state(): wrong state = %u, COMP_TRIGGER_PRE_RELEASE", + "wrong state = %u, COMP_TRIGGER_PRE_RELEASE", dev->state); return -EINVAL; } @@ -156,10 +186,9 @@ EXPORT_SYMBOL(comp_set_state); void sys_comp_init(struct sof *sof) { - sof->comp_drivers = platform_shared_get(&cd, sizeof(cd)); + sof->comp_drivers = &cd; list_init(&sof->comp_drivers->list); - k_spinlock_init(&sof->comp_drivers->lock); } void comp_get_copy_limits(struct comp_buffer *source, @@ -420,6 +449,7 @@ void cir_buf_copy(void *src, void *src_addr, void *src_end, void *dst, #endif EXPORT_SYMBOL(audio_stream_copy); +EXPORT_SYMBOL(cir_buf_copy); void audio_stream_copy_from_linear(const void *linear_source, int ioffset, struct audio_stream *sink, int ooffset, @@ -464,6 +494,62 @@ void audio_stream_copy_to_linear(const struct audio_stream *source, int ioffset, } } +static bool comp_check_eos(struct comp_dev *dev) +{ + enum sof_audio_buffer_state sink_state = AUDIOBUF_STATE_INITIAL; + struct comp_buffer *buffer; + + if (!dev->pipeline->expect_eos) + return false; + + comp_dev_for_each_producer(dev, buffer) { + struct sof_source *source = audio_buffer_get_source(&buffer->audio_buffer); + enum sof_audio_buffer_state state = source_get_state(source); + + if (source_get_pipeline_id(source) != dev->pipeline->pipeline_id) + continue; + + if (state == AUDIOBUF_STATE_END_OF_STREAM_FLUSH) { + /* Earlier in the pipeline, there is a DP module that has reached + * the EOS state. However, silence is generated to flush its internal + * buffers, so pass this state to the output buffers. + */ + comp_dbg(dev, "- EOS flush detected"); + sink_state = AUDIOBUF_STATE_END_OF_STREAM_FLUSH; + break; + } else if (state == AUDIOBUF_STATE_END_OF_STREAM) { + /* EOS is detected, so we need to set the sink state to AUDIOBUF_STATE_EOS. */ + size_t min_avail = source_get_min_available(source); + + if (source_get_data_available(source) < min_avail) { + comp_dbg(dev, "- EOS detected"); + if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { + /* For DP modules, fill missing input data with silence to + * allow it to process the remaining data. + */ + struct sof_sink *previous_mod_data_sink = + audio_buffer_get_sink(&buffer->audio_buffer); + sink_fill_with_silence(previous_mod_data_sink, min_avail); + sink_state = AUDIOBUF_STATE_END_OF_STREAM_FLUSH; + } else { + sink_state = AUDIOBUF_STATE_END_OF_STREAM; + break; + } + } + } + } + + if (sink_state != AUDIOBUF_STATE_INITIAL) { + comp_dev_for_each_consumer(dev, buffer) + audio_buffer_set_state(&buffer->audio_buffer, sink_state); + + /* For AUDIOBUF_STATE_END_OF_STREAM_FLUSH process data normally. */ + return sink_state != AUDIOBUF_STATE_END_OF_STREAM_FLUSH; + } + + return false; +} + /** See comp_ops::copy */ int comp_copy(struct comp_dev *dev) { @@ -498,6 +584,9 @@ int comp_copy(struct comp_dev *dev) const uint32_t begin_stamp = (uint32_t)telemetry_timestamp(); #endif + if (comp_check_eos(dev)) + return 0; + ret = dev->drv->ops.copy(dev); #ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS diff --git a/src/audio/copier/README.md b/src/audio/copier/README.md new file mode 100644 index 000000000000..f120f9cd7a86 --- /dev/null +++ b/src/audio/copier/README.md @@ -0,0 +1,22 @@ +# Copier Architecture + +This directory contains the Copier component. + +## Overview + +The Copier is a versatile component responsible for moving data smoothly between hardware endpoints (DAIs, Host APIs) and internal buffers. It may also apply simple format conversions (e.g., 16-bit to 32-bit). + +## Architecture Diagram + +```mermaid +graph LR + DMA[DMA Engine] <--> Copier[Copier Component] + Copier <--> Buf[Internal Buffer] +``` + +## Configuration and Scripts + +- **Kconfig**: Enables the `COMP_COPIER` component (depends on IPC 4). Also defines `COMP_DAI`, options to reverse DMA/DAI trigger stop ordering (`COMP_DAI_STOP_TRIGGER_ORDER_REVERSE`), DAI grouping, and an optional copier gain feature (`COPIER_GAIN`) for static gain, mute, or transition gain (fade-in/fade-out). +- **CMakeLists.txt**: Includes base copier implementations (HIFI, generic, host, DAI). If `CONFIG_IPC4_GATEWAY` is enabled, it adds `copier_ipcgtw.c`, and if `CONFIG_COPIER_GAIN` is selected, includes `copier_gain.c`. +- **copier.toml**: Contains topology configurations, describing UUID, pins, and complex `mod_cfg` tuples tailored per platform (`CONFIG_METEORLAKE`, `CONFIG_LUNARLAKE`, or `CONFIG_SOC_ACE30`/`40`). +- **Topology (.conf)**: `tools/topology/topology2/include/components/dai-copier.conf` (among others like `host-copier`, `module-copier`) define copier widget objects. They configure connection-specific attributes like `copier_type` (e.g., `HDA`, `SSP`, `DMIC`, `SAI`), `direction` (`playback` or `capture`), `node_type`, and `cpc`. `dai-copier` defaults to UUID `83:0c:a0:9b:12:CA:83:4a:94:3c:1f:a2:e8:2f:9d:da`. diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 0fe324cb78f3..6e7b379a1f33 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -15,9 +15,10 @@ #include <sof/ipc/topology.h> #include <rtos/interrupt.h> #include <rtos/timer.h> -#include <rtos/alloc.h> #include <rtos/cache.h> #include <rtos/init.h> +#include <rtos/userspace_helper.h> +#include <sof/lib/memory.h> #include <sof/lib/uuid.h> #include <sof/list.h> #include <rtos/string.h> @@ -39,6 +40,9 @@ #include "host_copier.h" #include "dai_copier.h" #include "ipcgtw_copier.h" +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include <zephyr/drivers/mic_privacy/intel/mic_privacy.h> +#endif #if CONFIG_ZEPHYR_NATIVE_DRIVERS #include <zephyr/drivers/dai.h> @@ -49,75 +53,126 @@ LOG_MODULE_REGISTER(copier, CONFIG_SOF_LOG_LEVEL); /* this id aligns windows driver requirement to support windows driver */ SOF_DEFINE_REG_UUID(copier); -DECLARE_TR_CTX(copier_comp_tr, SOF_UUID(copier_uuid), LOG_LEVEL_INFO); +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +static void mic_privacy_event(void *arg, enum notify_id type, void *data) +{ + struct mic_privacy_data *mic_priv_data = arg; + struct mic_privacy_settings *mic_privacy_settings = data; + + if (type == NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE) { + LOG_INF("state1 = %d, state2 = %d ", + mic_privacy_settings->mic_privacy_state, mic_priv_data->mic_privacy_state); + + if (mic_privacy_settings->mic_privacy_state == MIC_PRIV_UNMUTED) { + if (mic_priv_data->mic_privacy_state == MIC_PRIV_MUTED) { + mic_priv_data->mic_privacy_state = MIC_PRIV_FADE_IN; + LOG_INF("switch to FADE_IN"); + } + } else { + /* In case when mute would be triggered before copier instantiation. */ + if (mic_priv_data->mic_privacy_state != MIC_PRIV_MUTED) { + mic_priv_data->mic_privacy_state = MIC_PRIV_FADE_OUT; + LOG_INF("switch to FADE_OUT"); + } + } + mic_priv_data->max_ramp_time_in_ms = (mic_privacy_settings->max_ramp_time * 1000) / + ADSP_RTC_FREQUENCY; + } +} -static int copier_init(struct processing_module *mod) +static int mic_privacy_configure(struct processing_module *mod, struct copier_data *cd) +{ + struct mic_privacy_data *mic_priv_data; + int ret; + + mic_priv_data = mod_zalloc(mod, sizeof(struct mic_privacy_data)); + if (!mic_priv_data) + return -ENOMEM; + + if (cd->gtw_type == ipc4_gtw_dmic) + mic_privacy_enable_dmic_irq(true); + + mic_priv_data->audio_freq = cd->config.base.audio_fmt.sampling_frequency; + + uint32_t zeroing_wait_time = (mic_privacy_get_dma_zeroing_wait_time() * 1000) / + ADSP_RTC_FREQUENCY; + + ret = copier_gain_set_params(mod->dev, &mic_priv_data->mic_priv_gain_params, + zeroing_wait_time, SOF_DAI_INTEL_NONE); + if (ret != 0) { + mod_free(mod, mic_priv_data); + return ret; + } + + cd->mic_priv = mic_priv_data; + + ret = notifier_register(cd->mic_priv, NULL, NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE, + mic_privacy_event, 0); + + if (ret != 0) + mod_free(mod, mic_priv_data); + + return ret; +} + +static void mic_privacy_free(struct processing_module *mod) +{ + struct copier_data *cd = module_get_private_data(mod); + + if (cd->gtw_type == ipc4_gtw_dmic) + mic_privacy_enable_dmic_irq(false); + + notifier_unregister(cd->mic_priv, NULL, NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE); + + mod_free(mod, cd->mic_priv); +} +#endif + +__cold static int copier_init(struct processing_module *mod) { union ipc4_connector_node_id node_id; - struct ipc_comp_dev *ipc_pipe; - struct ipc *ipc = ipc_get(); struct copier_data *cd; struct comp_dev *dev = mod->dev; struct module_data *md = &mod->priv; struct ipc4_copier_module_cfg *copier = (struct ipc4_copier_module_cfg *)md->cfg.init_data; - struct comp_ipc_config *config = &dev->ipc_config; - void *gtw_cfg = NULL; - size_t gtw_cfg_size; + size_t cfg_total_size = sizeof(*copier); + size_t gtw_cfg_var_size = 0; int i, ret = 0; - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); - if (!cd) - return -ENOMEM; + assert_can_be_cold(); + + if (copier->gtw_cfg.config_length > 1) { + /* one word already included in gateway_cfg struct hence subtraction */ + gtw_cfg_var_size += (copier->gtw_cfg.config_length - 1) << 2; + cfg_total_size += gtw_cfg_var_size; + } - md->private = cd; /* - * Don't copy the config_data[] variable size array, we don't need to - * store it, it's only used during IPC processing, besides we haven't - * allocated space for it, so don't "fix" this! + * gtw_cfg.config_length is host-controlled; make sure the resulting + * copy length does not read past the init payload in the mailbox. + * cfg_total_size is at least sizeof(*copier), so this also rejects an + * empty (md->cfg.size == 0) or otherwise too-small init payload. */ - if (memcpy_s(&cd->config, sizeof(cd->config), copier, sizeof(*copier)) < 0) { - ret = -EINVAL; - goto error_cd; + if (cfg_total_size > md->cfg.size) { + comp_err(dev, "copier_init(): cfg size %zu exceeds init payload %zu", + cfg_total_size, md->cfg.size); + return -EINVAL; } - /* Allocate memory and store gateway_cfg in runtime. Gateway cfg has to - * be kept even after copier is created e.g. during SET_PIPELINE_STATE - * IPC when dai_config_dma_channel() is called second time and DMA - * config is used to assign dma_channel_id value. - */ - if (copier->gtw_cfg.config_length) { - gtw_cfg_size = copier->gtw_cfg.config_length << 2; - gtw_cfg = rmalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - gtw_cfg_size); - if (!gtw_cfg) { - ret = -ENOMEM; - goto error_cd; - } + cd = mod_zalloc(mod, sizeof(*cd) + gtw_cfg_var_size); + if (!cd) + return -ENOMEM; - ret = memcpy_s(gtw_cfg, gtw_cfg_size, &copier->gtw_cfg.config_data, - gtw_cfg_size); - if (ret) { - comp_err(dev, "Unable to copy gateway config from copier blob"); - goto error; - } + md->private = cd; - cd->gtw_cfg = gtw_cfg; + if (memcpy_s(&cd->config, cfg_total_size, copier, cfg_total_size) < 0) { + ret = -EINVAL; + goto error; } for (i = 0; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT; i++) cd->out_fmt[i] = cd->config.out_fmt; - ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, - config->pipeline_id, - IPC_COMP_IGNORE_REMOTE); - if (!ipc_pipe) { - comp_err(dev, "pipeline %d is not existed", config->pipeline_id); - ret = -EPIPE; - goto error; - } - - dev->pipeline = ipc_pipe->pipeline; - node_id = copier->gtw_cfg.node_id; /* copier is linked to gateway */ if (node_id.dw != IPC4_INVALID_NODE_ID) { @@ -126,11 +181,21 @@ static int copier_init(struct processing_module *mod) switch (node_id.f.dma_type) { case ipc4_hda_host_output_class: case ipc4_hda_host_input_class: - ret = copier_host_create(dev, cd, copier, ipc_pipe->pipeline); + ret = copier_host_create(mod, copier, dev->pipeline); if (ret < 0) { comp_err(dev, "unable to create host"); goto error; } +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + if (cd->direction == SOF_IPC_STREAM_CAPTURE && + node_id.f.dma_type == ipc4_hda_host_output_class) { + ret = mic_privacy_configure(mod, cd); + if (ret < 0) { + comp_err(dev, "unable to configure mic privacy"); + goto error; + } + } +#endif break; case ipc4_hda_link_output_class: case ipc4_hda_link_input_class: @@ -139,16 +204,27 @@ static int copier_init(struct processing_module *mod) case ipc4_i2s_link_input_class: case ipc4_alh_link_output_class: case ipc4_alh_link_input_class: - ret = copier_dai_create(dev, cd, copier, ipc_pipe->pipeline); + case ipc4_alh_uaol_stream_link_output_class: + case ipc4_alh_uaol_stream_link_input_class: + ret = copier_dai_create(dev, cd, copier, dev->pipeline); if (ret < 0) { comp_err(dev, "unable to create dai"); goto error; } +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + if (cd->direction == SOF_IPC_STREAM_CAPTURE) { + ret = mic_privacy_configure(mod, cd); + if (ret < 0) { + comp_err(dev, "unable to configure mic privacy"); + goto error; + } + } +#endif break; #if CONFIG_IPC4_GATEWAY case ipc4_ipc_output_class: case ipc4_ipc_input_class: - ret = copier_ipcgtw_create(dev, cd, copier, ipc_pipe->pipeline); + ret = copier_ipcgtw_create(mod, copier, dev->pipeline); if (ret < 0) { comp_err(dev, "unable to create IPC gateway"); goto error; @@ -173,35 +249,37 @@ static int copier_init(struct processing_module *mod) dev->state = COMP_STATE_READY; return 0; error: - rfree(gtw_cfg); -error_cd: - rfree(cd); + mod_free(mod, cd); return ret; } -static int copier_free(struct processing_module *mod) +__cold static int copier_free(struct processing_module *mod) { struct copier_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; + assert_can_be_cold(); + +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + mic_privacy_free(mod); +#endif + switch (dev->ipc_config.type) { case SOF_COMP_HOST: if (!cd->ipc_gtw) - copier_host_free(cd); + copier_host_free(mod); else /* handle gtw case */ - copier_ipcgtw_free(cd); + copier_ipcgtw_free(mod); break; case SOF_COMP_DAI: - copier_dai_free(cd); + copier_dai_free(mod); break; default: break; } - if (cd) - rfree(cd->gtw_cfg); - rfree(cd); + mod_free(mod, cd); return 0; } @@ -220,7 +298,7 @@ static int copier_prepare(struct processing_module *mod, if (ret < 0) return ret; - comp_info(dev, "copier_prepare()"); + comp_info(dev, "entry"); switch (dev->ipc_config.type) { case SOF_COMP_HOST: @@ -262,7 +340,7 @@ static int copier_reset(struct processing_module *mod) struct ipc4_pipeline_registers pipe_reg; struct comp_dev *dev = mod->dev; - comp_dbg(dev, "copier_reset()"); + comp_dbg(dev, "entry"); cd->input_total_data_processed = 0; cd->output_total_data_processed = 0; @@ -294,13 +372,13 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) { struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); - struct sof_ipc_stream_posn posn; + struct sof_ipc_stream_posn posn = { 0 }; struct comp_dev *dai_copier; struct comp_buffer *buffer; uint32_t latency; int ret; - comp_dbg(dev, "copier_comp_trigger()"); + comp_dbg(dev, "entry"); ret = comp_set_state(dev, cmd); if (ret < 0) @@ -436,7 +514,12 @@ static int do_conversion_copy(struct comp_dev *dev, comp_get_copy_limits(src, sink, processed_data); - i = IPC4_SINK_QUEUE_ID(buf_get_id(sink)); + /* + * Buffer ID is constructed as IPC4_COMP_ID(src_queue, dst_queue). + * From the buffer's perspective, copier's sink is the source, + * so we use IPC4_SRC_QUEUE_ID() to get the correct copier sink index. + */ + i = IPC4_SRC_QUEUE_ID(buf_get_id(sink)); if (i >= IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT) return -EINVAL; buffer_stream_invalidate(src, processed_data->source_bytes); @@ -513,7 +596,12 @@ static int copier_module_copy(struct processing_module *mod, uint32_t source_samples; int sink_queue_id; - sink_queue_id = IPC4_SINK_QUEUE_ID(buf_get_id(sink_c)); + /* + * Buffer ID is constructed as IPC4_COMP_ID(src_queue, dst_queue). + * From the buffer's perspective, copier's sink is the source, + * so we use IPC4_SRC_QUEUE_ID() to get the correct copier sink index. + */ + sink_queue_id = IPC4_SRC_QUEUE_ID(buf_get_id(sink_c)); if (sink_queue_id >= IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT) return -EINVAL; @@ -596,7 +684,7 @@ static int copier_process(struct processing_module *mod, struct copier_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - comp_dbg(dev, "copier_process()"); + comp_dbg(dev, "entry"); switch (dev->ipc_config.type) { case SOF_COMP_HOST: @@ -626,7 +714,7 @@ static int copier_params(struct processing_module *mod) struct comp_dev *dev = mod->dev; int i, ret = 0; - comp_dbg(dev, "copier_params()"); + comp_dbg(dev, "entry"); copier_update_params(cd, dev, params); @@ -653,14 +741,16 @@ static int copier_params(struct processing_module *mod) return ret; } -static int copier_set_sink_fmt(struct comp_dev *dev, const void *data, - int max_data_size) +__cold static int copier_set_sink_fmt(struct comp_dev *dev, const void *data, + int max_data_size) { const struct ipc4_copier_config_set_sink_format *sink_fmt = data; struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); uint32_t chmap; + assert_can_be_cold(); + if (max_data_size < sizeof(*sink_fmt)) { comp_err(dev, "error: max_data_size %d should be bigger than %d", max_data_size, sizeof(*sink_fmt)); @@ -698,16 +788,20 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data, return 0; } -static int set_attenuation(struct comp_dev *dev, uint32_t data_offset, const char *data) +__cold static int set_attenuation(struct comp_dev *dev, uint32_t data_offset, const char *data) { struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); uint32_t attenuation; enum sof_ipc_frame valid_fmt, frame_fmt; - /* only support attenuation in format of 32bit */ - if (data_offset > sizeof(uint32_t)) { - comp_err(dev, "attenuation data size %d is incorrect", data_offset); + assert_can_be_cold(); + + /* only support attenuation in format of 32bit; the payload is + * dereferenced as a uint32_t below so it must be exactly that size + */ + if (data_offset != sizeof(uint32_t)) { + comp_err(dev, "attenuation data size %u is incorrect", data_offset); return -EINVAL; } @@ -733,7 +827,7 @@ static int set_attenuation(struct comp_dev *dev, uint32_t data_offset, const cha return 0; } -static int set_chmap(struct comp_dev *dev, const void *data, size_t data_size) +__cold static int set_chmap(struct comp_dev *dev, const void *data, size_t data_size) { const struct ipc4_copier_config_channel_map *chmap_cfg = data; struct processing_module *mod = comp_mod(dev); @@ -746,6 +840,8 @@ static int set_chmap(struct comp_dev *dev, const void *data, size_t data_size) int i; uint32_t irq_flags; + assert_can_be_cold(); + if (data_size < sizeof(*chmap_cfg)) { comp_err(dev, "Wrong payload size: %d", data_size); return -EINVAL; @@ -809,16 +905,18 @@ static int set_chmap(struct comp_dev *dev, const void *data, size_t data_size) return 0; } -static int copier_set_configuration(struct processing_module *mod, - uint32_t config_id, - enum module_cfg_fragment_position pos, - uint32_t data_offset_size, - const uint8_t *fragment, size_t fragment_size, - uint8_t *response, - size_t response_size) +__cold static int copier_set_configuration(struct processing_module *mod, + uint32_t config_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, + const uint8_t *fragment, size_t fragment_size, + uint8_t *response, + size_t response_size) { struct comp_dev *dev = mod->dev; + assert_can_be_cold(); + comp_dbg(dev, "copier_set_config()"); switch (config_id) { @@ -839,15 +937,18 @@ static inline void convert_u64_to_u32s(uint64_t val, uint32_t *val_l, uint32_t * *val_h = (uint32_t)((val >> 32) & 0xffffffff); } -static int copier_get_configuration(struct processing_module *mod, - uint32_t config_id, uint32_t *data_offset_size, - uint8_t *fragment, size_t fragment_size) +__cold static int copier_get_configuration(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) { struct copier_data *cd = module_get_private_data(mod); struct ipc4_llp_reading_extended llp_ext; struct comp_dev *dev = mod->dev; - struct sof_ipc_stream_posn posn; + struct sof_ipc_stream_posn posn = { 0 }; struct ipc4_llp_reading llp; + int ret; + + assert_can_be_cold(); if (cd->ipc_gtw) return 0; @@ -875,7 +976,9 @@ static int copier_get_configuration(struct processing_module *mod, } /* get llp from dai */ - comp_position(dev, &posn); + ret = comp_position(dev, &posn); + if (ret < 0) + return ret; convert_u64_to_u32s(posn.comp_posn, &llp.llp_l, &llp.llp_u); convert_u64_to_u32s(posn.wallclock, &llp.wclk_l, &llp.wclk_u); @@ -905,7 +1008,9 @@ static int copier_get_configuration(struct processing_module *mod, } /* get llp from dai */ - comp_position(dev, &posn); + ret = comp_position(dev, &posn); + if (ret < 0) + return ret; convert_u64_to_u32s(posn.comp_posn, &llp_ext.llp_reading.llp_l, &llp_ext.llp_reading.llp_u); @@ -1044,27 +1149,31 @@ static int copier_dai_ts_stop_op(struct comp_dev *dev) return dai_common_ts_stop(dd, dev); } -static int copier_get_hw_params(struct comp_dev *dev, struct sof_ipc_stream_params *params, - int dir) +__cold static int copier_get_hw_params(struct comp_dev *dev, struct sof_ipc_stream_params *params, + int dir) { struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); struct dai_data *dd = cd->dd[0]; + assert_can_be_cold(); + if (dev->ipc_config.type != SOF_COMP_DAI) return -EINVAL; return dai_common_get_hw_params(dd, dev, params, dir); } -static int copier_bind(struct processing_module *mod, void *data) +__cold static int copier_bind(struct processing_module *mod, struct bind_info *bind_data) { - const struct ipc4_module_bind_unbind *const bu = (struct ipc4_module_bind_unbind *)data; + const struct ipc4_module_bind_unbind *const bu = bind_data->ipc4_data; const uint32_t src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); const uint32_t src_queue_id = bu->extension.r.src_queue; struct copier_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; + assert_can_be_cold(); + if (dev->ipc_config.id != src_id) return 0; /* Another component is a data producer */ @@ -1084,21 +1193,23 @@ static int copier_bind(struct processing_module *mod, void *data) return -ENODEV; } -static int copier_unbind(struct processing_module *mod, void *data) +__cold static int copier_unbind(struct processing_module *mod, struct bind_info *unbind_data) { struct copier_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; + assert_can_be_cold(); + if (dev->ipc_config.type == SOF_COMP_DAI) { struct dai_data *dd = cd->dd[0]; - return dai_zephyr_unbind(dd, dev, data); + return dai_zephyr_unbind(dd, dev, unbind_data); } return 0; } -static struct module_endpoint_ops copier_endpoint_ops = { +static APP_SYSUSER_DATA const struct module_endpoint_ops copier_endpoint_ops = { .get_total_data_processed = copier_get_processed_data, .position = copier_position, .dai_ts_config = copier_dai_ts_config_op, @@ -1109,7 +1220,7 @@ static struct module_endpoint_ops copier_endpoint_ops = { .trigger = copier_comp_trigger }; -static const struct module_interface copier_interface = { +static APP_SYSUSER_DATA const struct module_interface copier_interface = { .init = copier_init, .prepare = copier_prepare, .process_audio_stream = copier_process, @@ -1122,5 +1233,7 @@ static const struct module_interface copier_interface = { .endpoint_ops = &copier_endpoint_ops, }; +DECLARE_TR_CTX(copier_comp_tr, SOF_UUID(copier_uuid), LOG_LEVEL_INFO); + DECLARE_MODULE_ADAPTER(copier_interface, copier_uuid, copier_comp_tr); SOF_MODULE_INIT(copier, sys_comp_module_copier_interface_init); diff --git a/src/audio/copier/copier.h b/src/audio/copier/copier.h index 43c125134f07..4e29e18d33a6 100644 --- a/src/audio/copier/copier.h +++ b/src/audio/copier/copier.h @@ -32,6 +32,10 @@ #include <sof/compiler_attributes.h> #include <sof/audio/buffer.h> #include <sof/audio/pcm_converter.h> +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include <sof/lib/notifier.h> +#include <sof/audio/mic_privacy_manager.h> +#endif static const uint32_t INVALID_QUEUE_ID = 0xFFFFFFFF; @@ -237,13 +241,6 @@ struct ipc4_data_segment_enabled { } __attribute__((packed, aligned(4))); struct copier_data { - /* - * struct ipc4_copier_module_cfg actually has variable size, but we - * don't need the variable size array at the end, we won't be copying it - * from the IPC data. - */ - struct ipc4_copier_module_cfg config; - void *gtw_cfg; enum ipc4_gateway_type gtw_type; uint32_t endpoint_num; @@ -270,6 +267,11 @@ struct copier_data { uint32_t channels[IPC4_ALH_MAX_NUMBER_OF_GTW]; uint32_t chan_map[IPC4_ALH_MAX_NUMBER_OF_GTW]; struct ipcgtw_data *ipcgtw_data; +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + struct mic_privacy_data *mic_priv; +#endif + /* Has to be at the end due to variable size array */ + struct ipc4_copier_module_cfg config; }; int apply_attenuation(struct comp_dev *dev, struct copier_data *cd, diff --git a/src/audio/copier/copier.toml b/src/audio/copier/copier.toml index e7cd23f5154b..acb2a5f8876f 100644 --- a/src/audio/copier/copier.toml +++ b/src/audio/copier/copier.toml @@ -1,6 +1,6 @@ [[module.entry]] name = "COPIER" - uuid = "9BA00C83-CA12-4A83-943C-1FA2E82F9DDA" + uuid = UUIDREG_STR_COPIER affinity_mask = "0x1" instance_count = "32" domain_types = "0" @@ -18,59 +18,114 @@ REM # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] #if CONFIG_METEORLAKE - 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, + mod_cfg = [0, 0, 0, 0, 280, 4918000, 768, 768, 0, 4918, 0, + 1, 0, 0, 0, 280, 6526000, 768, 768, 0, 6526, 0, + 2, 0, 0, 0, 280, 6388000, 384, 384, 0, 6388, 0, + 3, 0, 0, 0, 280, 4682000, 512, 512, 0, 4682, 0, + 4, 0, 0, 0, 280, 5738000, 512, 512, 0, 5738, 0, + 5, 0, 0, 0, 280, 6250000, 256, 256, 0, 6250, 0, + 6, 0, 0, 0, 280, 6460000, 768, 768, 0, 6460, 0, + 7, 0, 0, 0, 280, 7116000, 768, 768, 0, 7116, 0, + 8, 0, 0, 0, 280, 6008000, 384, 384, 0, 6008, 0, + 9, 0, 0, 0, 280, 6258000, 512, 512, 0, 6258, 0, + 10, 0, 0, 0, 280, 7188000, 1024, 1024, 0, 7188, 0, + 11, 0, 0, 0, 280, 7272000, 1536, 1536, 0, 7272, 0, + 12, 0, 0, 0, 280, 6290000, 768, 768, 0, 6290, 0, + 13, 0, 0, 0, 280, 6604000, 1024, 1024, 0, 6604, 0, + 14, 0, 0, 0, 280, 6198000, 384, 384, 0, 6198, 0, + 15, 0, 0, 0, 280, 6250000, 384, 384, 0, 6250, 0, + 16, 0, 0, 0, 280, 6258000, 256, 256, 0, 6258, 0, + 17, 0, 0, 0, 280, 4354000, 256, 256, 0, 4354, 0, + 18, 0, 0, 0, 280, 6198000, 256, 256, 0, 6198, 0, + 19, 0, 0, 0, 280, 6250000, 128, 128, 0, 6250, 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, - 42, 0, 0, 0, 280, 5350000, 384, 192, 0, 5350, 0] -#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_PANTHERLAKE) - 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] + 21, 0, 0, 0, 280, 6206000, 128, 128, 0, 6206, 0, + 22, 0, 0, 0, 280, 4170000, 64, 64, 0, 4170, 0, + 23, 0, 0, 0, 280, 4234000, 96, 96, 0, 4234, 0, + 24, 0, 0, 0, 280, 6198000, 96, 96, 0, 6198, 0, + 25, 0, 0, 0, 280, 6250000, 96, 96, 0, 6250, 0, + 26, 0, 0, 0, 280, 6198000, 192, 192, 0, 6198, 0, + 27, 0, 0, 0, 280, 6258000, 192, 192, 0, 6258, 0, + 28, 0, 0, 0, 280, 6392000, 720, 720, 0, 6392, 0, + 29, 0, 0, 0, 280, 6250000, 360, 360, 0, 6250, 0, + 30, 0, 0, 0, 280, 5326000, 360, 360, 0, 5326, 0, + 31, 0, 0, 0, 280, 6258000, 180, 180, 0, 6258, 0, + 32, 0, 0, 0, 280, 4354000, 256, 256, 0, 4354, 0, + 33, 0, 0, 0, 280, 4898000, 256, 256, 0, 4898, 0, + 34, 0, 0, 0, 280, 6246000, 128, 128, 0, 6246, 0, + 35, 0, 0, 0, 280, 6250000, 192, 192, 0, 6250, 0, + 36, 0, 0, 0, 280, 6250000, 48, 48, 0, 6250, 0, + 37, 0, 0, 0, 280, 4170000, 64, 64, 0, 4170, 0, + 38, 0, 0, 0, 280, 6198000, 64, 64, 0, 6198, 0, + 39, 0, 0, 0, 280, 6246000, 32, 32, 0, 6246, 0, + 40, 0, 0, 0, 280, 5272000, 192, 384, 0, 5272, 0, + 41, 0, 0, 0, 280, 5350000, 384, 192, 0, 5350, 0] +#elif CONFIG_LUNARLAKE + mod_cfg = [0, 0, 0, 0, 280, 6057000, 768, 768, 0, 6057, 0, + 1, 0, 0, 0, 280, 8062000, 768, 768, 0, 8062, 0, + 2, 0, 0, 0, 280, 6250000, 384, 384, 0, 6250, 0, + 3, 0, 0, 0, 280, 6290000, 512, 512, 0, 6290, 0, + 4, 0, 0, 0, 280, 7254000, 512, 512, 0, 7254, 0, + 5, 0, 0, 0, 280, 5607000, 256, 256, 0, 5607, 0, + 6, 0, 0, 0, 280, 6514000, 768, 768, 0, 6514, 0, + 7, 0, 0, 0, 280, 7974000, 768, 768, 0, 7974, 0, + 8, 0, 0, 0, 280, 6242000, 384, 384, 0, 6242, 0, + 9, 0, 0, 0, 280, 6294000, 512, 512, 0, 6294, 0, + 10, 0, 0, 0, 280, 8704000, 1024, 1024, 0, 8704, 0, + 11, 0, 0, 0, 280, 6165000, 1536, 1536, 0, 6165, 0, + 12, 0, 0, 0, 280, 5775000, 768, 768, 0, 5775, 0, + 13, 0, 0, 0, 280, 6610000, 1024, 1024, 0, 6610, 0, + 14, 0, 0, 0, 280, 6457000, 384, 384, 0, 6457, 0, + 15, 0, 0, 0, 280, 7442000, 384, 384, 0, 7442, 0, + 16, 0, 0, 0, 280, 6618000, 256, 256, 0, 6618, 0, + 17, 0, 0, 0, 280, 9104000, 128, 128, 0, 9104, 0, + 18, 0, 0, 0, 280, 6098000, 128, 128, 0, 6098, 0, + 19, 0, 0, 0, 280, 10360000, 128, 128, 0, 10360, 0, + 20, 0, 0, 0, 280, 6046000, 64, 64, 0, 6046, 0, + 21, 0, 0, 0, 280, 6026000, 96, 96, 0, 6026, 0, + 22, 0, 0, 0, 280, 10928000, 96, 96, 0, 10928, 0, + 23, 0, 0, 0, 280, 6688000, 192, 192, 0, 6688, 0, + 24, 0, 0, 0, 280, 8054000, 720, 720, 0, 8054, 0, + 25, 0, 0, 0, 280, 6978000, 360, 360, 0, 6978, 0, + 26, 0, 0, 0, 280, 6118000, 180, 180, 0, 6118, 0, + 27, 0, 0, 0, 280, 6046000, 48, 48, 0, 6046, 0, + 28, 0, 0, 0, 280, 6058000, 64, 64, 0, 6058, 0, + 29, 0, 0, 0, 280, 6198000, 64, 64, 0, 6198, 0, + 30, 0, 0, 0, 280, 6034000, 32, 32, 0, 6034, 0] +#elif CONFIG_SOC_ACE30 || CONFIG_SOC_ACE40 + mod_cfg = [0, 0, 0, 0, 280, 7915000, 768, 768, 0, 7915, 0, + 1, 0, 0, 0, 280, 9487000, 768, 768, 0, 9487, 0, + 2, 0, 0, 0, 280, 7363000, 384, 384, 0, 7363, 0, + 3, 0, 0, 0, 280, 7731000, 512, 512, 0, 7731, 0, + 4, 0, 0, 0, 280, 8459000, 512, 512, 0, 8459, 0, + 5, 0, 0, 0, 280, 7523000, 256, 256, 0, 7523, 0, + 6, 0, 0, 0, 280, 7927000, 768, 768, 0, 7927, 0, + 7, 0, 0, 0, 280, 9507000, 768, 768, 0, 9507, 0, + 8, 0, 0, 0, 280, 7639000, 384, 384, 0, 7639, 0, + 9, 0, 0, 0, 280, 7787000, 512, 512, 0, 7787, 0, + 10, 0, 0, 0, 280, 10211000, 1024, 1024, 0, 10211, 0, + 11, 0, 0, 0, 280, 8387000, 1536, 1536, 0, 8387, 0, + 12, 0, 0, 0, 280, 7923000, 768, 768, 0, 7923, 0, + 13, 0, 0, 0, 280, 8075000, 1024, 1024, 0, 8075, 0, + 14, 0, 0, 0, 280, 8103000, 384, 384, 0, 8103, 0, + 15, 0, 0, 0, 280, 9431000, 2304, 2304, 0, 9431, 0, + 16, 0, 0, 0, 280, 7523000, 256, 256, 0, 7523, 0, + 17, 0, 0, 0, 280, 7479000, 256, 256, 0, 7479, 0, + 18, 0, 0, 0, 280, 7791000, 256, 256, 0, 7791, 0, + 19, 0, 0, 0, 280, 9987000, 3072, 3072, 0, 9987, 0, + 20, 0, 0, 0, 280, 7451000, 128, 128, 0, 7451, 0, + 21, 0, 0, 0, 280, 11495000, 4608, 4608, 0, 11495, 0, + 22, 0, 0, 0, 280, 7627000, 64, 64, 0, 7627, 0, + 23, 0, 0, 0, 280, 7407000, 96, 96, 0, 7407, 0, + 24, 0, 0, 0, 280, 12879000, 6144, 6144, 0, 12879, 0, + 25, 0, 0, 0, 280, 7431000, 192, 192, 0, 7431, 0, + 26, 0, 0, 0, 280, 8580000, 720, 720, 0, 8580, 0, + 27, 0, 0, 0, 280, 7935000, 360, 360, 0, 7935, 0, + 28, 0, 0, 0, 280, 7487000, 180, 180, 0, 7487, 0, + 29, 0, 0, 0, 280, 7623000, 48, 48, 0, 7623, 0, + 30, 0, 0, 0, 280, 7647000, 64, 64, 0, 7647, 0, + 31, 0, 0, 0, 280, 7103000, 32, 32, 0, 7103, 0, +] #endif index = __COUNTER__ diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index 587a133ebd75..109bc2a4a6b2 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -4,6 +4,7 @@ // // Author: Baofeng Tian <baofeng.tian@intel.com> +#include <sof/lib/memory.h> #include <sof/trace/trace.h> #include <sof/audio/component_ext.h> #include <ipc/dai.h> @@ -87,6 +88,16 @@ static int copier_alh_assign_dai_index(struct comp_dev *dev, switch (dai->type) { case SOF_DAI_INTEL_HDA: /* We use DAI_INTEL_HDA for ACE 2.0 platforms */ + /* + * alh_cfg.count is host-controlled and scales the config size + * and mapping[] walk below; bound it before any arithmetic so a + * crafted blob cannot read past the gateway config. + */ + if (alh_blob->alh_cfg.count > IPC4_ALH_MAX_NUMBER_OF_GTW) { + comp_err(mod->dev, "Invalid ALH count: %u", + alh_blob->alh_cfg.count); + return -EINVAL; + } alh_cfg_size = get_alh_config_size(alh_blob); dma_config = (uint8_t *)gtw_cfg_data + alh_cfg_size; dma_config_length = (cd->config.gtw_cfg.config_length << 2) - alh_cfg_size; @@ -107,7 +118,7 @@ static int copier_alh_assign_dai_index(struct comp_dev *dev, } dai_num = alh_blob->alh_cfg.count; - if (dai_num > IPC4_ALH_MAX_NUMBER_OF_GTW || dai_num < 0) { + if (dai_num > IPC4_ALH_MAX_NUMBER_OF_GTW || dai_num <= 0) { comp_err(mod->dev, "Invalid dai_count: %d", dai_num); return -EINVAL; } @@ -137,7 +148,7 @@ static int copier_alh_assign_dai_index(struct comp_dev *dev, } dai_num = alh_blob->alh_cfg.count; - if (dai_num > IPC4_ALH_MAX_NUMBER_OF_GTW || dai_num < 0) { + if (dai_num > IPC4_ALH_MAX_NUMBER_OF_GTW || dai_num <= 0) { comp_err(mod->dev, "Invalid dai_count: %d", dai_num); return -EINVAL; } @@ -155,13 +166,13 @@ static int copier_alh_assign_dai_index(struct comp_dev *dev, return 0; } -static int copier_dai_init(struct comp_dev *dev, - struct comp_ipc_config *config, - const struct ipc4_copier_module_cfg *copier, - struct pipeline *pipeline, - struct ipc_config_dai *dai, - enum ipc4_gateway_type type, - int index, int dai_count) +__cold static int copier_dai_init(struct comp_dev *dev, + struct comp_ipc_config *config, + const struct ipc4_copier_module_cfg *copier, + struct pipeline *pipeline, + struct ipc_config_dai *dai, + enum ipc4_gateway_type type, + int index, int dai_count) { struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); @@ -169,6 +180,8 @@ static int copier_dai_init(struct comp_dev *dev, struct dai_data *dd; int ret; + assert_can_be_cold(); + if (cd->direction == SOF_IPC_STREAM_PLAYBACK) { enum sof_ipc_frame out_frame_fmt, out_valid_fmt; @@ -201,9 +214,10 @@ static int copier_dai_init(struct comp_dev *dev, return ret; } - dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); + dd = mod_alloc_ext(mod, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*dd), 0); if (!dd) return -ENOMEM; + memset(dd, 0, sizeof(*dd)); ret = dai_common_new(dd, dev, dai); if (ret < 0) @@ -220,16 +234,19 @@ static int copier_dai_init(struct comp_dev *dev, /* Allocate gain data if selected for this dai type and set basic params */ if (dai->apply_gain) { - struct copier_gain_params *gain_data = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, - 0, SOF_MEM_CAPS_RAM, - sizeof(*gain_data)); + struct copier_gain_params *gain_data = + mod_alloc_ext(mod, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*gain_data), 0); if (!gain_data) { ret = -ENOMEM; goto e_zephyr_free; } + memset(gain_data, 0, sizeof(*gain_data)); cd->dd[index]->gain_data = gain_data; - ret = copier_gain_set_params(dev, cd->dd[index]); + ret = copier_gain_set_params(dev, cd->dd[index]->gain_data, + GAIN_DEFAULT_FADE_PERIOD, + cd->dd[index]->dai->type); if (ret < 0) { comp_err(dev, "Failed to set gain params!"); goto gain_free; @@ -240,11 +257,11 @@ static int copier_dai_init(struct comp_dev *dev, return 0; gain_free: - rfree(dd->gain_data); + mod_free(mod, dd->gain_data); e_zephyr_free: dai_common_free(dd); free_dd: - rfree(dd); + mod_free(mod, dd); return ret; } @@ -252,9 +269,9 @@ static int copier_dai_init(struct comp_dev *dev, * ssp, dmic or alh. Sof dai component can support this case so copier * reuses dai component to support non-host gateway. */ -int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, - const struct ipc4_copier_module_cfg *copier, - struct pipeline *pipeline) +__cold int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, + const struct ipc4_copier_module_cfg *copier, + struct pipeline *pipeline) { struct processing_module *mod = comp_mod(dev); struct comp_ipc_config *config = &dev->ipc_config; @@ -263,6 +280,10 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, struct ipc_config_dai dai; int dai_count; int i, ret; + uint8_t *gtw_cfg_data = (uint8_t *)cd->config.gtw_cfg.config_data; + size_t gtw_cfg_size = cd->config.gtw_cfg.config_length * 4; + + assert_can_be_cold(); config->type = SOF_COMP_DAI; @@ -274,6 +295,8 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, dai.is_config_blob = true; dai.sampling_frequency = copier->out_fmt.sampling_frequency; dai.feature_mask = copier->copier_feature_mask; + dai.gtw_fmt = (dai.direction == SOF_IPC_STREAM_PLAYBACK) ? + &cd->config.out_fmt : &cd->config.base.audio_fmt; switch (node_id.f.dma_type) { case ipc4_hda_link_output_class: @@ -287,13 +310,11 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, dai.type = SOF_DAI_INTEL_SSP; dai.is_config_blob = true; cd->gtw_type = ipc4_gtw_ssp; - ret = ipc4_find_dma_config(&dai, (uint8_t *)cd->gtw_cfg, - copier->gtw_cfg.config_length * 4); + ret = ipc4_find_dma_config(&dai, gtw_cfg_data, gtw_cfg_size); if (ret != 0) { comp_err(dev, "No ssp dma_config found in blob!"); return -EINVAL; } - dai.out_fmt = &copier->out_fmt; break; case ipc4_alh_link_output_class: case ipc4_alh_link_input_class: @@ -306,22 +327,31 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, dai.is_config_blob = true; cd->gtw_type = ipc4_gtw_alh; #endif /* ACE_VERSION > ACE_VERSION_1_5 */ - ret = copier_alh_assign_dai_index(dev, cd->gtw_cfg, node_id, - &dai, dai_index, &dai_count); + ret = copier_alh_assign_dai_index(dev, gtw_cfg_data, node_id, &dai, dai_index, + &dai_count); if (ret) return ret; break; + case ipc4_alh_uaol_stream_link_output_class: + case ipc4_alh_uaol_stream_link_input_class: + dai.type = SOF_DAI_INTEL_UAOL; + dai.is_config_blob = true; + cd->gtw_type = ipc4_gtw_alh; + ret = ipc4_find_all_dma_configs_tlvs_only(&dai, gtw_cfg_data, gtw_cfg_size); + if (ret != IPC4_SUCCESS) { + comp_err(dev, "No uaol dma_config found in blob!"); + return -EINVAL; + } + break; case ipc4_dmic_link_input_class: dai.type = SOF_DAI_INTEL_DMIC; dai.is_config_blob = true; cd->gtw_type = ipc4_gtw_dmic; - ret = ipc4_find_dma_config(&dai, (uint8_t *)cd->gtw_cfg, - copier->gtw_cfg.config_length * 4); + ret = ipc4_find_dma_config(&dai, gtw_cfg_data, gtw_cfg_size); if (ret != 0) { comp_err(dev, "No dmic dma_config found in blob!"); return -EINVAL; } - dai.out_fmt = &copier->out_fmt; #if CONFIG_COPIER_GAIN dai.apply_gain = true; #endif @@ -368,12 +398,16 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, return 0; } -void copier_dai_free(struct copier_data *cd) +__cold void copier_dai_free(struct processing_module *mod) { + struct copier_data *cd = module_get_private_data(mod); + + assert_can_be_cold(); + for (int i = 0; i < cd->endpoint_num; i++) { dai_common_free(cd->dd[i]); - rfree(cd->dd[i]->gain_data); - rfree(cd->dd[i]); + mod_free(mod, cd->dd[i]->gain_data); + mod_free(mod, cd->dd[i]); } /* only dai have multi endpoint case */ if (cd->multi_endpoint_buffer) diff --git a/src/audio/copier/copier_gain.c b/src/audio/copier/copier_gain.c index f7e2f24fdb8d..842f92997108 100644 --- a/src/audio/copier/copier_gain.c +++ b/src/audio/copier/copier_gain.c @@ -4,6 +4,7 @@ // // Author: Ievgen Ganakov <ievgen.ganakov@intel.com> +#include <sof/lib/memory.h> #include <sof/trace/trace.h> #include <ipc4/base-config.h> #include <sof/audio/component_ext.h> @@ -15,46 +16,44 @@ LOG_MODULE_DECLARE(copier, CONFIG_SOF_LOG_LEVEL); -int copier_gain_set_params(struct comp_dev *dev, struct dai_data *dd) +__cold int copier_gain_set_params(struct comp_dev *dev, struct copier_gain_params *gain_params, + uint32_t fade_period, enum sof_ipc_dai_type dai_type) { struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); struct ipc4_base_module_cfg *ipc4_cfg = &cd->config.base; uint32_t sampling_freq = ipc4_cfg->audio_fmt.sampling_frequency; uint32_t frames = sampling_freq / dev->pipeline->period; - uint32_t fade_period = GAIN_DEFAULT_FADE_PERIOD; int ret; + assert_can_be_cold(); + /* Set basic gain parameters */ - copier_gain_set_basic_params(dev, dd, ipc4_cfg); + copier_gain_set_basic_params(dev, gain_params, ipc4_cfg); - switch (dd->dai->type) { + switch (dai_type) { case SOF_DAI_INTEL_DMIC: { - struct dmic_config_data *dmic_cfg = cd->gtw_cfg; - - if (!dmic_cfg) { - comp_err(dev, "No dmic config found"); - return -EINVAL; - } + struct dmic_config_data *dmic_cfg = + (void *)cd->config.gtw_cfg.config_data; union dmic_global_cfg *dmic_glb_cfg = &dmic_cfg->dmic_blob.global_cfg; /* Get fade period from DMIC blob */ fade_period = dmic_glb_cfg->ext_global_cfg.fade_in_period; /* Convert and assign silence and fade length values */ - dd->gain_data->silence_sg_length = + gain_params->silence_sg_length = frames * dmic_glb_cfg->ext_global_cfg.silence_period; - dd->gain_data->fade_sg_length = frames * fade_period; + gain_params->fade_sg_length = frames * fade_period; } break; default: - comp_info(dev, "Apply default fade period for dai type %d", dd->dai->type); + comp_info(dev, "Apply default fade period for dai type %d", dai_type); break; } /* Set fade parameters */ - ret = copier_gain_set_fade_params(dev, dd, ipc4_cfg, fade_period, frames); + ret = copier_gain_set_fade_params(dev, gain_params, ipc4_cfg, fade_period, frames); if (ret) comp_err(dev, "Failed to set fade params"); @@ -150,7 +149,10 @@ int copier_gain_dma_control(union ipc4_connector_node_id node, const char *confi break; } - ret = copier_set_gain(dev, cd->dd[0], gain_data); + struct ipc4_copier_module_cfg *copier_cfg = cd->dd[0]->dai_spec_config; + const uint32_t channels = copier_cfg->base.audio_fmt.channels_count; + + ret = copier_set_gain(dev, cd->dd[0]->gain_data, gain_data, channels); if (ret) comp_err(dev, "Gain DMA control: failed to set gain"); return ret; @@ -159,12 +161,9 @@ int copier_gain_dma_control(union ipc4_connector_node_id node, const char *confi return -ENODEV; } -int copier_set_gain(struct comp_dev *dev, struct dai_data *dd, - struct gain_dma_control_data *gain_data) +int copier_set_gain(struct comp_dev *dev, struct copier_gain_params *gain_params, + struct gain_dma_control_data *gain_data, uint32_t channels) { - struct copier_gain_params *gain_params = dd->gain_data; - struct ipc4_copier_module_cfg *copier_cfg = dd->dai_spec_config; - const int channels = copier_cfg->base.audio_fmt.channels_count; uint16_t static_gain[MAX_GAIN_COEFFS_CNT]; int ret; @@ -173,12 +172,17 @@ int copier_set_gain(struct comp_dev *dev, struct dai_data *dd, return -EINVAL; } + if (channels == 0 || channels > MAX_GAIN_COEFFS_CNT) { + comp_err(dev, "invalid channels count %u", channels); + return -EINVAL; + } + /* Set gain coefficients */ comp_info(dev, "Update gain coefficients from DMA_CONTROL ipc"); size_t gain_coef_size = channels * sizeof(uint16_t); - ret = memcpy_s(static_gain, gain_coef_size, gain_data->gain_coeffs, + ret = memcpy_s(static_gain, sizeof(static_gain), gain_data->gain_coeffs, gain_coef_size); if (ret) { comp_err(dev, "memcpy_s failed with error %d", ret); diff --git a/src/audio/copier/copier_gain.h b/src/audio/copier/copier_gain.h index 077a47f468c3..bd7cc5719f5b 100644 --- a/src/audio/copier/copier_gain.h +++ b/src/audio/copier/copier_gain.h @@ -8,8 +8,10 @@ #ifndef __SOF_COPIER_GAIN_H__ #define __SOF_COPIER_GAIN_H__ +#include <stdint.h> #include <sof/audio/buffer.h> #include <ipc4/base_fw.h> +#include <ipc4/gateway.h> #include <ipc/dai.h> #if SOF_USE_HIFI(3, COPIER) || SOF_USE_HIFI(4, COPIER) || SOF_USE_HIFI(5, COPIER) #include <xtensa/tie/xt_hifi3.h> @@ -117,10 +119,13 @@ struct gain_dma_control_data { * the given device and DAI data. * * @param dev The pointer to the component device structure. - * @param dd The pointer to the DAI data structure. + * @param gain_params The pointer to gain params structure. + * @param fade_period The fade period in milliseconds. + * @param dai_type DAI type * @return 0 on success, negative error code on failure. */ -int copier_gain_set_params(struct comp_dev *dev, struct dai_data *dd); +int copier_gain_set_params(struct comp_dev *dev, struct copier_gain_params *gain_params, + uint32_t fade_period, enum sof_ipc_dai_type dai_type); /** * @brief Sets the basic gain parameters. @@ -129,10 +134,10 @@ int copier_gain_set_params(struct comp_dev *dev, struct dai_data *dd); * by the given device and DAI data. * * @param dev The pointer to the component device structure. - * @param dd The pointer to the DAI data structure. + * @param gain_params The pointer to gain params structure. * @param ipc4_cfg The pointer to the IPC4 base module config. */ -void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, +void copier_gain_set_basic_params(struct comp_dev *dev, struct copier_gain_params *gain_params, struct ipc4_base_module_cfg *ipc4_cfg); /** @@ -142,13 +147,13 @@ void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, * by the given device and DAI data. * * @param dev The pointer to the component device structure. - * @param dd The pointer to the DAI data structure. + * @param gain_params The pointer to gain params structure. * @param ipc4_cfg The pointer to the IPC4 base module config. * @param fade_period The fade period in milliseconds. * @param frames The number of frames to fade. * @return 0 on success, negative error code on failure. */ -int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd, +int copier_gain_set_fade_params(struct comp_dev *dev, struct copier_gain_params *gain_params, struct ipc4_base_module_cfg *ipc4_cfg, uint32_t fade_period, uint32_t frames); @@ -209,12 +214,13 @@ enum copier_gain_state copier_gain_eval_state(struct copier_gain_params *gain_pa * Sets/modify gain for a copier module in runtime. * * @param dev The copier device structure. - * @param dd The DAI data structure. + * @param gain_params The pointer to the copier_gain_params structure. * @param gain_data The gain control data structure. + * @param channels Number of audio channels. * @return 0 on success, otherwise a negative error code. */ -int copier_set_gain(struct comp_dev *dev, struct dai_data *dd, - struct gain_dma_control_data *gain_data); +int copier_set_gain(struct comp_dev *dev, struct copier_gain_params *gain_params, + struct gain_dma_control_data *gain_data, uint32_t channels); /** * Checks for unity gain mode. diff --git a/src/audio/copier/copier_generic.c b/src/audio/copier/copier_generic.c index a4fc8ca6c9a1..bb5918819e5b 100644 --- a/src/audio/copier/copier_generic.c +++ b/src/audio/copier/copier_generic.c @@ -6,6 +6,7 @@ #include <ipc4/base-config.h> #include <sof/audio/component_ext.h> +#include <sof/lib/memory.h> #include <module/module/base.h> #include <sof/common.h> #include <ipc/dai.h> @@ -60,10 +61,11 @@ int apply_attenuation(struct comp_dev *dev, struct copier_data *cd, } } -void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, - struct ipc4_base_module_cfg *ipc4_cfg) +__cold void copier_gain_set_basic_params(struct comp_dev *dev, + struct copier_gain_params *gain_params, + struct ipc4_base_module_cfg *ipc4_cfg) { - struct copier_gain_params *gain_params = dd->gain_data; + assert_can_be_cold(); gain_params->channels_count = ipc4_cfg->audio_fmt.channels_count; @@ -71,13 +73,14 @@ void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, gain_params->gain_coeffs[i] = UNITY_GAIN_GENERIC; } -int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd, - struct ipc4_base_module_cfg *ipc4_cfg, - uint32_t fade_period, uint32_t frames) +__cold int copier_gain_set_fade_params(struct comp_dev *dev, struct copier_gain_params *gain_params, + struct ipc4_base_module_cfg *ipc4_cfg, + uint32_t fade_period, uint32_t frames) { - struct copier_gain_params *gain_params = dd->gain_data; uint16_t step_i64_to_i16; + assert_can_be_cold(); + if (fade_period == GAIN_DEFAULT_FADE_PERIOD) { /* Set fade transition delay to default value*/ if (ipc4_cfg->audio_fmt.sampling_frequency > IPC4_FS_16000HZ) @@ -88,6 +91,8 @@ int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd, /* Special case for GAIN_ZERO_TRANS_MS to support zero fade-in transition time */ gain_params->fade_sg_length = 0; return 0; + } else { + gain_params->fade_sg_length = frames * fade_period; } /* High precision step for fade-in calculation, keeps accurate precision */ @@ -164,7 +169,7 @@ int copier_gain_input16(struct comp_buffer *buff, enum copier_gain_state state, /* Apply fade */ for (j = 0; j < nch; j++) { - dst += j; + dst_tmp = dst + j; /* Quadratic fade part in Q15 format*/ gain_env_sq = q_multsr_16x16(gain_env[j], gain_env[j], 15); @@ -175,8 +180,8 @@ int copier_gain_input16(struct comp_buffer *buff, enum copier_gain_state state, gain_env_sq, 15); for (i = 0; i < nmax; i += nch) - dst[i] = q_multsr_sat_16x16(dst[i], gain, - GAIN_Q10_INT_SHIFT); + dst_tmp[i] = q_multsr_sat_16x16(dst_tmp[i], gain, + GAIN_Q10_INT_SHIFT); } samples -= nmax; dst = audio_stream_wrap(&buff->stream, dst + nmax); @@ -255,7 +260,7 @@ int copier_gain_input32(struct comp_buffer *buff, enum copier_gain_state state, /* Apply fade */ for (j = 0; j < nch; j++) { - dst += j; + dst_tmp = dst + j; /* Quadratic fade part in Q15 format*/ gain_env_sq = q_multsr_16x16(gain_env[j], gain_env[j], 15); @@ -266,8 +271,8 @@ int copier_gain_input32(struct comp_buffer *buff, enum copier_gain_state state, gain_env_sq, 15); for (i = 0; i < nmax; i += nch) - dst[i] = q_multsr_sat_32x32(dst[i], gain, - GAIN_Q10_INT_SHIFT); + dst_tmp[i] = q_multsr_sat_32x32(dst_tmp[i], gain, + GAIN_Q10_INT_SHIFT); } samples -= nmax; dst = audio_stream_wrap(&buff->stream, dst + nmax); @@ -323,7 +328,13 @@ void copier_update_params(struct copier_data *cd, struct comp_dev *dev, /* update each sink format */ comp_dev_for_each_consumer(dev, sink) { int j; - j = IPC4_SINK_QUEUE_ID(buf_get_id(sink)); + j = IPC4_SRC_QUEUE_ID(buf_get_id(sink)); + + /* src_queue id is host-controlled; bound it before indexing out_fmt[] */ + if (j >= IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT) { + comp_err(dev, "invalid src_queue id %d", j); + continue; + } ipc4_update_buffer_format(sink, &cd->out_fmt[j]); } @@ -347,9 +358,9 @@ void copier_update_params(struct copier_data *cd, struct comp_dev *dev, } } -int create_multi_endpoint_buffer(struct comp_dev *dev, - struct copier_data *cd, - const struct ipc4_copier_module_cfg *copier_cfg) +__cold int create_multi_endpoint_buffer(struct comp_dev *dev, + struct copier_data *cd, + const struct ipc4_copier_module_cfg *copier_cfg) { struct comp_ipc_config *config = &dev->ipc_config; enum sof_ipc_frame in_frame_fmt, out_frame_fmt; @@ -361,6 +372,8 @@ int create_multi_endpoint_buffer(struct comp_dev *dev, uint32_t chan_map; int i; + assert_can_be_cold(); + audio_stream_fmt_conversion(copier_cfg->base.audio_fmt.depth, copier_cfg->base.audio_fmt.valid_bit_depth, &in_frame_fmt, &in_valid_fmt, @@ -420,8 +433,7 @@ int create_multi_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; - /* allocate not shared buffer */ - buffer = buffer_new(&ipc_buf, false); + buffer = buffer_new(NULL, &ipc_buf, BUFFER_USAGE_NOT_SHARED); if (!buffer) return -ENOMEM; @@ -442,9 +454,11 @@ int create_multi_endpoint_buffer(struct comp_dev *dev, return 0; } -enum sof_ipc_stream_direction +__cold enum sof_ipc_stream_direction get_gateway_direction(enum ipc4_connector_node_id_type node_id_type) { + assert_can_be_cold(); + /* WARNING: simple "% 2" formula that was used before does not work for all * interfaces: at least it does not work for IPC gateway. But it may also * does not work for other not yet supported interfaces. And so additional @@ -558,6 +572,11 @@ pcm_converter_func get_converter_func(const struct ipc4_audio_format *in_fmt, if (out_valid == SOF_IPC_FRAME_S16_LE && out == SOF_IPC_FRAME_S32_LE) out = SOF_IPC_FRAME_S16_4LE; + if (in_valid == SOF_IPC_FRAME_S24_4LE && in == SOF_IPC_FRAME_S32_LE) + in = in_valid; + if (out_valid == SOF_IPC_FRAME_S24_4LE && out == SOF_IPC_FRAME_S32_LE) + out = out_valid; + return pcm_get_remap_function(in, out); } diff --git a/src/audio/copier/copier_hifi.c b/src/audio/copier/copier_hifi.c index 0d0d454f2c41..14c91b632f5b 100644 --- a/src/audio/copier/copier_hifi.c +++ b/src/audio/copier/copier_hifi.c @@ -13,6 +13,7 @@ #include <sof/audio/format.h> #include <sof/audio/pipeline.h> #include <sof/audio/component.h> +#include <sof/lib/memory.h> #include <module/module/base.h> #include <stddef.h> #include <errno.h> @@ -75,10 +76,11 @@ int apply_attenuation(struct comp_dev *dev, struct copier_data *cd, } } -void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, - struct ipc4_base_module_cfg *ipc4_cfg) +__cold void copier_gain_set_basic_params(struct comp_dev *dev, + struct copier_gain_params *gain_params, + struct ipc4_base_module_cfg *ipc4_cfg) { - struct copier_gain_params *gain_params = dd->gain_data; + assert_can_be_cold(); /* Set default gain coefficients */ for (int i = 0; i < ARRAY_SIZE(gain_params->gain_coeffs); ++i) @@ -91,15 +93,16 @@ void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, gain_params->channels_count = ipc4_cfg->audio_fmt.channels_count; } -int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd, - struct ipc4_base_module_cfg *ipc4_cfg, - uint32_t fade_period, uint32_t frames) +__cold int copier_gain_set_fade_params(struct comp_dev *dev, struct copier_gain_params *gain_params, + struct ipc4_base_module_cfg *ipc4_cfg, + uint32_t fade_period, uint32_t frames) { - struct copier_gain_params *gain_params = dd->gain_data; uint16_t init_gain[MAX_GAIN_COEFFS_CNT]; uint16_t step_i64_to_i16; ae_f16 step_f16; + assert_can_be_cold(); + /* For backward compatibility add a case with default fade transition. * Backward compatibility is referring to clock_on_delay in DMIC blob. */ @@ -113,6 +116,8 @@ int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd, /* Special case for GAIN_ZERO_TRANS_MS to support zero fade in transition time */ gain_params->fade_sg_length = 0; return 0; + } else { + gain_params->fade_sg_length = frames * fade_period; } /* High precision step for fade-in calculation, keeps accurate precision */ diff --git a/src/audio/copier/copier_host.c b/src/audio/copier/copier_host.c index b61af44bfe0e..3e704b2b1163 100644 --- a/src/audio/copier/copier_host.c +++ b/src/audio/copier/copier_host.c @@ -5,9 +5,11 @@ // Author: Baofeng Tian <baofeng.tian@intel.com> #include <sof/audio/component_ext.h> +#include <sof/lib/memory.h> #include <sof/tlv.h> #include <sof/trace/trace.h> #include <sof/audio/module_adapter/module/generic.h> +#include <rtos/userspace_helper.h> #include "copier.h" #include "host_copier.h" @@ -26,12 +28,14 @@ struct fpi_sync_group { struct list_item item; }; -static struct list_item group_list_head = LIST_INIT(group_list_head); +static APP_SYSUSER_DATA struct list_item group_list_head = LIST_INIT(group_list_head); -static struct fpi_sync_group *find_group_by_id(uint32_t id) +__cold static struct fpi_sync_group *find_group_by_id(uint32_t id) { struct list_item *item; + assert_can_be_cold(); + list_for_item(item, &group_list_head) { struct fpi_sync_group *group = list_item(item, struct fpi_sync_group, item); @@ -42,11 +46,14 @@ static struct fpi_sync_group *find_group_by_id(uint32_t id) return NULL; } -int add_to_fpi_sync_group(struct comp_dev *parent_dev, - struct host_data *hd, - struct ipc4_copier_sync_group *sync_group) +__cold static int add_to_fpi_sync_group(struct comp_dev *parent_dev, + struct host_data *hd, + struct ipc4_copier_sync_group *sync_group) { struct fpi_sync_group *group = find_group_by_id(sync_group->group_id); + struct processing_module *mod = comp_mod(parent_dev); + + assert_can_be_cold(); if (group) { if (group->period != sync_group->fpi_update_period_usec) { @@ -57,11 +64,13 @@ int add_to_fpi_sync_group(struct comp_dev *parent_dev, group->ref_count++; } else { - group = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*group)); + group = mod_alloc_ext(mod, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*group), 0); if (!group) { comp_err(parent_dev, "Failed to alloc memory for new group"); return -ENOMEM; } + memset(group, 0, sizeof(*group)); group->id = sync_group->group_id; group->period = sync_group->fpi_update_period_usec; @@ -76,9 +85,12 @@ int add_to_fpi_sync_group(struct comp_dev *parent_dev, return 0; } -void delete_from_fpi_sync_group(struct host_data *hd) +__cold static void delete_from_fpi_sync_group(struct processing_module *mod) { - struct fpi_sync_group *group = find_group_by_id(hd->group_id); + struct copier_data *cd = module_get_private_data(mod); + struct fpi_sync_group *group = find_group_by_id(cd->hd->group_id); + + assert_can_be_cold(); if (!group) return; @@ -86,19 +98,21 @@ void delete_from_fpi_sync_group(struct host_data *hd) group->ref_count--; if (group->ref_count == 0) { list_item_del(&group->item); - rfree(group); + mod_free(mod, group); } } #endif /* Playback only */ -static int init_pipeline_reg(struct comp_dev *dev) +__cold static int init_pipeline_reg(struct comp_dev *dev) { struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); struct ipc4_pipeline_registers pipe_reg; uint32_t gateway_id; + assert_can_be_cold(); + gateway_id = cd->config.gtw_cfg.node_id.f.v_index; if (gateway_id >= IPC4_MAX_PIPELINE_REG_SLOTS) { comp_err(dev, "gateway_id %u out of array bounds.", gateway_id); @@ -122,11 +136,12 @@ static int init_pipeline_reg(struct comp_dev *dev) * Sof host component can support this case so copier reuses host * component to support host gateway. */ -int copier_host_create(struct comp_dev *dev, struct copier_data *cd, - const struct ipc4_copier_module_cfg *copier_cfg, - struct pipeline *pipeline) +__cold int copier_host_create(struct processing_module *mod, + const struct ipc4_copier_module_cfg *copier_cfg, + struct pipeline *pipeline) { - struct processing_module *mod = comp_mod(dev); + struct copier_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; struct comp_ipc_config *config = &dev->ipc_config; struct ipc_config_host ipc_host; struct host_data *hd; @@ -135,25 +150,40 @@ int copier_host_create(struct comp_dev *dev, struct copier_data *cd, enum sof_ipc_frame in_frame_fmt, out_frame_fmt; enum sof_ipc_frame in_valid_fmt, out_valid_fmt; + assert_can_be_cold(); + config->type = SOF_COMP_HOST; cd->gtw_type = ipc4_gtw_host; - audio_stream_fmt_conversion(copier_cfg->base.audio_fmt.depth, - copier_cfg->base.audio_fmt.valid_bit_depth, - &in_frame_fmt, &in_valid_fmt, - copier_cfg->base.audio_fmt.s_type); + ret = audio_stream_fmt_conversion(copier_cfg->base.audio_fmt.depth, + copier_cfg->base.audio_fmt.valid_bit_depth, + &in_frame_fmt, &in_valid_fmt, + copier_cfg->base.audio_fmt.s_type); + if (ret) { + comp_err(dev, "failed with input format: depth %d, valid %d, type %d", + copier_cfg->base.audio_fmt.depth, + copier_cfg->base.audio_fmt.valid_bit_depth, + copier_cfg->base.audio_fmt.s_type); + return ret; + } - audio_stream_fmt_conversion(copier_cfg->out_fmt.depth, - copier_cfg->out_fmt.valid_bit_depth, - &out_frame_fmt, &out_valid_fmt, - copier_cfg->out_fmt.s_type); + ret = audio_stream_fmt_conversion(copier_cfg->out_fmt.depth, + copier_cfg->out_fmt.valid_bit_depth, + &out_frame_fmt, &out_valid_fmt, + copier_cfg->out_fmt.s_type); + if (ret) { + comp_err(dev, "failed with output format: depth %d, valid %d, type %d", + copier_cfg->out_fmt.depth, copier_cfg->out_fmt.valid_bit_depth, + copier_cfg->out_fmt.s_type); + return ret; + } memset(&ipc_host, 0, sizeof(ipc_host)); ipc_host.direction = dir; ipc_host.dma_buffer_size = copier_cfg->gtw_cfg.dma_buffer_size; ipc_host.feature_mask = copier_cfg->copier_feature_mask; - hd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*hd)); + hd = mod_zalloc(mod, sizeof(*hd)); if (!hd) return -ENOMEM; @@ -181,14 +211,16 @@ int copier_host_create(struct comp_dev *dev, struct copier_data *cd, if (value_ptr) { struct ipc4_copier_sync_group *sync_group; - if (value_size != sizeof(struct ipc4_copier_sync_group)) - return -EINVAL; + if (value_size != sizeof(struct ipc4_copier_sync_group)) { + ret = -EINVAL; + goto e_conv; + } sync_group = (struct ipc4_copier_sync_group *)((void *)value_ptr); ret = add_to_fpi_sync_group(dev, hd, sync_group); if (ret < 0) - return ret; + goto e_conv; } } #endif @@ -225,19 +257,23 @@ int copier_host_create(struct comp_dev *dev, struct copier_data *cd, e_conv: host_common_free(hd); e_data: - rfree(hd); + mod_free(mod, hd); return ret; } -void copier_host_free(struct copier_data *cd) +__cold void copier_host_free(struct processing_module *mod) { + struct copier_data *cd = module_get_private_data(mod); + + assert_can_be_cold(); + #if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION if (cd->hd->is_grouped) - delete_from_fpi_sync_group(cd->hd); + delete_from_fpi_sync_group(mod); #endif host_common_free(cd->hd); - rfree(cd->hd); + mod_free(mod, cd->hd); } /* This is called by DMA driver every time when DMA completes its current @@ -249,7 +285,7 @@ void copier_host_dma_cb(struct comp_dev *dev, size_t bytes) struct copier_data *cd = module_get_private_data(mod); int ret, frames; - comp_dbg(dev, "copier_host_dma_cb() %p", dev); + comp_dbg(dev, "%p", dev); /* update position */ host_common_update(cd->hd, dev, bytes); @@ -267,10 +303,14 @@ void copier_host_dma_cb(struct comp_dev *dev, size_t bytes) 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); + comp_dbg(dev, "apply attenuation failed! %d", ret); buffer_stream_writeback(cd->hd->local_buffer, bytes); } +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + if (cd->mic_priv) + mic_privacy_process(dev, cd->mic_priv, cd->hd->local_buffer, bytes); +#endif } static void copier_notifier_cb(void *arg, enum notify_id type, void *data) diff --git a/src/audio/copier/copier_ipcgtw.c b/src/audio/copier/copier_ipcgtw.c index f31da128a368..115c9a4a7e2d 100644 --- a/src/audio/copier/copier_ipcgtw.c +++ b/src/audio/copier/copier_ipcgtw.c @@ -2,9 +2,10 @@ // // Copyright 2023 Intel Corporation. All rights reserved. +#include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/component_ext.h> #include <sof/trace/trace.h> -#include <sof/lib/uuid.h> +#include <sof/lib/memory.h> #include <sof/ut.h> #include <rtos/init.h> #include "copier.h" @@ -12,10 +13,6 @@ LOG_MODULE_REGISTER(ipcgtw, CONFIG_SOF_LOG_LEVEL); -SOF_DEFINE_REG_UUID(ipcgw); - -DECLARE_TR_CTX(ipcgtw_comp_tr, SOF_UUID(ipcgw_uuid), LOG_LEVEL_INFO); - /* List of existing IPC gateways */ static struct list_item ipcgtw_list_head = LIST_INIT(ipcgtw_list_head); @@ -101,7 +98,7 @@ int copier_ipcgtw_process(const struct ipc4_ipcgtw_cmd *cmd, if (!dev) return -ENODEV; - comp_dbg(dev, "copier_ipcgtw_process(): %x %x", + comp_dbg(dev, "%x %x", cmd->primary.dat, cmd->extension.dat); buf = get_buffer(dev); @@ -112,7 +109,7 @@ int copier_ipcgtw_process(const struct ipc4_ipcgtw_cmd *cmd, * case do not report error but return 0 bytes available for GET_DATA and * 0 bytes free for SET_DATA. */ - comp_warn(dev, "copier_ipcgtw_process(): no buffer found"); + comp_warn(dev, "no buffer found"); } out = (struct ipc4_ipc_gateway_cmd_data_reply *)reply_payload; @@ -161,7 +158,7 @@ int copier_ipcgtw_process(const struct ipc4_ipcgtw_cmd *cmd, break; default: - comp_err(dev, "copier_ipcgtw_process(): unexpected cmd: %u", + comp_err(dev, "unexpected cmd: %u", (unsigned int)cmd->primary.r.cmd); return -EINVAL; } @@ -179,7 +176,7 @@ int copier_ipcgtw_params(struct ipcgtw_data *ipcgtw_data, struct comp_dev *dev, buf = get_buffer(dev); if (!buf) { - comp_err(dev, "ipcgtw_params(): no buffer found"); + comp_err(dev, "no buffer found"); return -EINVAL; } @@ -187,7 +184,7 @@ int copier_ipcgtw_params(struct ipcgtw_data *ipcgtw_data, struct comp_dev *dev, 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", + comp_err(dev, "failed to resize buffer to %u bytes", ipcgtw_data->buf_size); return err; } @@ -202,22 +199,41 @@ void copier_ipcgtw_reset(struct comp_dev *dev) if (buf) { audio_stream_reset(&buf->stream); } else { - comp_warn(dev, "ipcgtw_reset(): no buffer found"); + comp_warn(dev, "no buffer found"); } } -int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, - const struct ipc4_copier_module_cfg *copier, struct pipeline *pipeline) +__cold int copier_ipcgtw_create(struct processing_module *mod, + const struct ipc4_copier_module_cfg *copier, + struct pipeline *pipeline) { + struct copier_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; struct comp_ipc_config *config = &dev->ipc_config; struct ipcgtw_data *ipcgtw_data; const struct ipc4_copier_gateway_cfg *gtw_cfg; const struct ipc4_ipc_gateway_config_blob *blob; int ret; + assert_can_be_cold(); + gtw_cfg = &copier->gtw_cfg; if (!gtw_cfg->config_length) { - comp_err(dev, "ipcgtw_create(): empty ipc4_gateway_config_data"); + comp_err(dev, "empty ipc4_gateway_config_data"); + return -EINVAL; + } + + /* config_length is in dwords; require enough dwords to cover the + * gateway config header and the blob read below. Compare dword counts + * (rather than scaling config_length by 4) so a large host-supplied + * value cannot overflow the multiplication on 32-bit size_t. + */ + if (gtw_cfg->config_length < + SOF_DIV_ROUND_UP(sizeof(struct ipc4_gateway_config_data) + + sizeof(struct ipc4_ipc_gateway_config_blob), + sizeof(uint32_t))) { + comp_err(dev, "ipc4_gateway_config_data too small: %u", + gtw_cfg->config_length); return -EINVAL; } @@ -227,7 +243,7 @@ int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, config->type = SOF_COMP_HOST; cd->gtw_type = ipc4_gtw_host; - ipcgtw_data = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*ipcgtw_data)); + ipcgtw_data = mod_zalloc(mod, sizeof(*ipcgtw_data)); if (!ipcgtw_data) return -ENOMEM; @@ -240,7 +256,7 @@ int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, /* The buffer connected to the IPC gateway will be resized later in ipcgtw_params() * to the size specified in the IPC gateway blob. */ - comp_dbg(dev, "ipcgtw_create(): buffer_size: %u", blob->buffer_size); + comp_dbg(dev, "buffer_size: %u", blob->buffer_size); ipcgtw_data->buf_size = blob->buffer_size; cd->converter[IPC4_COPIER_GATEWAY_PIN] = @@ -269,12 +285,16 @@ int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, return 0; e_ipcgtw: - rfree(ipcgtw_data); + mod_free(mod, ipcgtw_data); return ret; } -void copier_ipcgtw_free(struct copier_data *cd) +__cold void copier_ipcgtw_free(struct processing_module *mod) { + struct copier_data *cd = module_get_private_data(mod); + + assert_can_be_cold(); + list_item_del(&cd->ipcgtw_data->item); - rfree(cd->ipcgtw_data); + mod_free(mod, cd->ipcgtw_data); } diff --git a/src/audio/copier/dai_copier.h b/src/audio/copier/dai_copier.h index a03970288b1b..481b06b4bc58 100644 --- a/src/audio/copier/dai_copier.h +++ b/src/audio/copier/dai_copier.h @@ -69,7 +69,7 @@ static inline int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, v int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, struct comp_buffer *multi_endpoint_buffer, int num_endpoints); -int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, void *data); +int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, struct bind_info *unbind_data); #endif @@ -79,7 +79,7 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, const struct ipc4_copier_module_cfg *copier, struct pipeline *pipeline); -void copier_dai_free(struct copier_data *cd); +void copier_dai_free(struct processing_module *mod); int copier_dai_prepare(struct comp_dev *dev, struct copier_data *cd); diff --git a/src/audio/copier/host_copier.h b/src/audio/copier/host_copier.h index 08cbba43be27..d00907959e8f 100644 --- a/src/audio/copier/host_copier.h +++ b/src/audio/copier/host_copier.h @@ -22,6 +22,10 @@ #include <sof/lib/notifier.h> #include "copier.h" +#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS +struct io_perf_data_item; +#endif + typedef void (*copy_callback_t)(struct comp_dev *dev, size_t bytes); struct host_data; @@ -48,8 +52,13 @@ struct hc_buf { */ struct host_data { /* local DMA config */ +#if CONFIG_ZEPHYR_NATIVE_DRIVERS + struct sof_dma *dma; + int chan_index; +#else struct dma *dma; struct dma_chan_data *chan; +#endif struct dma_sg_config config; #ifdef __ZEPHYR__ struct dma_config z_config; @@ -61,13 +70,14 @@ struct host_data { /* host position reporting related */ uint32_t host_size; /**< Host buffer size (in bytes) */ - uint32_t report_pos; /**< Position in current report period */ uint32_t local_pos; /**< Local position in host buffer */ uint32_t host_period_bytes; uint16_t stream_tag; uint16_t no_stream_position; /**< 1 means don't send stream position */ uint64_t total_data_processed; - uint8_t cont_update_posn; /**< 1 means continuous update stream position */ + uint64_t nobytes_last_logged; /**< uptime, when "no bytes" was last logged */ + unsigned int n_skipped; /**< number of "no bytes" skipped */ + uint8_t cont_update_posn; /**< 1 means continuous update stream position */ /* host component attributes */ enum comp_copy_type copy_type; /**< Current host copy type */ @@ -95,7 +105,13 @@ struct host_data { /* stream info */ struct sof_ipc_stream_posn posn; /* TODO: update this */ +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES + uint32_t report_pos; /**< Position in current report period */ struct ipc_msg *msg; /**< host notification */ +#endif +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE + bool xrun_notification_sent; +#endif uint32_t dma_buffer_size; /* dma buffer size */ #if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION bool is_grouped; @@ -103,6 +119,11 @@ struct host_data { uint64_t next_sync; uint64_t period_in_cycles; #endif +#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS + struct io_perf_data_item *io_perf_host_byte_count; +#endif + + struct mod_alloc_ctx alloc_ctx; }; int host_common_new(struct host_data *hd, struct comp_dev *dev, @@ -120,10 +141,10 @@ static inline int host_common_copy(struct host_data *hd, struct comp_dev *dev, c } void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t bytes); void host_common_one_shot(struct host_data *hd, uint32_t bytes); -int copier_host_create(struct comp_dev *dev, struct copier_data *cd, +int copier_host_create(struct processing_module *mod, const struct ipc4_copier_module_cfg *copier_cfg, struct pipeline *pipeline); -void copier_host_free(struct copier_data *cd); +void copier_host_free(struct processing_module *mod); int copier_host_params(struct copier_data *cd, struct comp_dev *dev, struct sof_ipc_stream_params *params); void copier_host_dma_cb(struct comp_dev *dev, size_t bytes); diff --git a/src/audio/copier/ipcgtw_copier.h b/src/audio/copier/ipcgtw_copier.h index ef42ede75ddd..a9ea82914d4e 100644 --- a/src/audio/copier/ipcgtw_copier.h +++ b/src/audio/copier/ipcgtw_copier.h @@ -95,17 +95,17 @@ struct ipc4_ipc_gateway_cmd_data_reply { int copier_ipcgtw_process(const struct ipc4_ipcgtw_cmd *cmd, void *reply_payload, uint32_t *reply_payload_size); -int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, +int copier_ipcgtw_create(struct processing_module *mod, const struct ipc4_copier_module_cfg *copier, struct pipeline *pipeline); #if CONFIG_IPC4_GATEWAY -void copier_ipcgtw_free(struct copier_data *cd); +void copier_ipcgtw_free(struct processing_module *mod); int copier_ipcgtw_params(struct ipcgtw_data *ipcgtw_data, struct comp_dev *dev, struct sof_ipc_stream_params *params); void copier_ipcgtw_reset(struct comp_dev *dev); #else -static inline void copier_ipcgtw_free(struct copier_data *cd) {} +static inline void copier_ipcgtw_free(struct processing_module *mod) {} static inline void copier_ipcgtw_reset(struct comp_dev *dev) {} static inline int copier_ipcgtw_params(struct ipcgtw_data *ipcgtw_data, struct comp_dev *dev, struct sof_ipc_stream_params *params) diff --git a/src/audio/crossover/CMakeLists.txt b/src/audio/crossover/CMakeLists.txt index c58c01460cd7..cd24cc33eb27 100644 --- a/src/audio/crossover/CMakeLists.txt +++ b/src/audio/crossover/CMakeLists.txt @@ -1,3 +1,11 @@ +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_COMP_CROSSOVER STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/crossover_llext) + add_dependencies(app crossover) + return() +endif() + add_local_sources(sof crossover.c) add_local_sources(sof crossover_generic.c) if(CONFIG_IPC_MAJOR_3) diff --git a/src/audio/crossover/Kconfig b/src/audio/crossover/Kconfig index 8044d300f6e1..9e56fa3ab6d7 100644 --- a/src/audio/crossover/Kconfig +++ b/src/audio/crossover/Kconfig @@ -4,7 +4,7 @@ config COMP_CROSSOVER tristate "Crossover Filter component" select COMP_BLOB select MATH_IIR_DF2T - default n + default m if LIBRARY_DEFAULT_MODULAR help Select for Crossover Filter component. A crossover can be used to split a signal into two or more frequency ranges, so that the outputs diff --git a/src/audio/crossover/README.md b/src/audio/crossover/README.md new file mode 100644 index 000000000000..1e0e180178a9 --- /dev/null +++ b/src/audio/crossover/README.md @@ -0,0 +1,24 @@ +# Crossover Architecture + +This directory contains the Crossover filter component. + +## Overview + +The Crossover splits an audio signal into multiple frequency bands (e.g., Low, Mid, High) so they can be processed or routed independently (like to a woofer and a tweeter). + +## Architecture Diagram + +```mermaid +graph LR + In[Wideband Audio In] --> Cross[Crossover Split] + Cross --> OutLow[Low Frequency Out] + Cross --> OutHigh[High Frequency Out] +``` + +## Configuration and Scripts + +- **Kconfig**: Selects the Crossover Filter (`COMP_CROSSOVER`), which splits signals into driver-specific frequencies. Also automatically selects `COMP_BLOB` and `MATH_IIR_DF2T` math functions for its internal filters. +- **CMakeLists.txt**: Handles modular builds (`llext`). Selects `crossover.c` and generic implementations, and chooses the correct IPC file (`crossover_ipc3.c` or `crossover_ipc4.c`) based on the active IPC major version. +- **crossover.toml**: Topology parameters for the Crossover module. For IPC4, it sets `init_config = 1` so that `base_cfg_ext` is appended to the IPC payload, which is required up-front to identify output pin indices. Defines UUID, pins, and memory requirements. +- **Topology (.conf)**: `tools/topology/topology2/include/components/crossover.conf` defines the `crossover` widget object. It sets basic widget requirements and defaults to type `effect` with UUID `d1:9a:8c:94:6a:80:31:41:ad:6c:b2:bd:a9:e3:5a:9f`. +- **MATLAB Tuning (`tune/`)**: The `tune` directory holds MATLAB/Octave scripts (like `sof_example_crossover.m`) that convert mathematical frequency split parameters (e.g., 200 Hz, 1000 Hz, 3000 Hz cutoffs) into binary, ALSA, and `.conf` payloads suitable for 2-way, 3-way, or 4-way driver crossover configurations. diff --git a/src/audio/crossover/crossover.c b/src/audio/crossover/crossover.c index dae27ff12b56..cbc45a04ec50 100644 --- a/src/audio/crossover/crossover.c +++ b/src/audio/crossover/crossover.c @@ -15,10 +15,9 @@ #include <sof/common.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> -#include <sof/math/iir_df2t.h> +#include <sof/math/iir_df1.h> #include <sof/list.h> #include <sof/platform.h> #include <rtos/string.h> @@ -41,18 +40,17 @@ LOG_MODULE_REGISTER(crossover, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(crossover); -DECLARE_TR_CTX(crossover_tr, SOF_UUID(crossover_uuid), LOG_LEVEL_INFO); - /** * \brief Reset the state (coefficients and delay) of the crossover filter * across all channels */ -static void crossover_reset_state(struct comp_data *cd) +static void crossover_reset_state(struct processing_module *mod) { + struct comp_data *cd = module_get_private_data(mod); int i; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) - crossover_reset_state_ch(&cd->state[i]); + crossover_reset_state_ch(mod, &cd->state[i]); } /** @@ -73,7 +71,7 @@ int crossover_get_stream_index(struct processing_module *mod, if (assign_sink[i] == pipe_id) return i; - comp_err(mod->dev, "crossover_get_stream_index() error: couldn't find any assignment for connected pipeline %u", + comp_err(mod->dev, "error: couldn't find any assignment for connected pipeline %u", pipe_id); return -EINVAL; @@ -127,14 +125,14 @@ static int crossover_assign_sinks(struct processing_module *mod, */ if (i < 0) { comp_err(dev, - "crossover_assign_sinks(), could not find sink %d in config", + "could not find sink %d in config", sink_id); break; } if (assigned_obufs[i]) { comp_err(dev, - "crossover_assign_sinks(), multiple sinks with id %d are assigned", + "multiple sinks with id %d are assigned", sink_id); break; } @@ -156,17 +154,21 @@ static int crossover_assign_sinks(struct processing_module *mod, * high/low pass filter. * \param[out] lr4 initialized struct */ -static int crossover_init_coef_lr4(struct sof_eq_iir_biquad *coef, - struct iir_state_df2t *lr4) +static int crossover_init_coef_lr4(struct processing_module *mod, + struct sof_eq_iir_biquad *coef, + struct iir_state_df1 *lr4) { int ret; + /* Ensure the LR4 can be processed with the simplified 4th order IIR */ + if (CROSSOVER_LR4_NUM_BIQUADS != SOF_IIR_DF1_4TH_NUM_BIQUADS) + return -EINVAL; + /* Only one set of coefficients is stored in config for both biquads * in series due to identity. To maintain the structure of - * iir_state_df2t, it requires two copies of coefficients in a row. + * iir_state_df1, it requires two copies of coefficients in a row. */ - lr4->coef = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(struct sof_eq_iir_biquad) * 2); + lr4->coef = mod_zalloc(mod, sizeof(struct sof_eq_iir_biquad) * 2); if (!lr4->coef) return -ENOMEM; @@ -185,13 +187,12 @@ static int crossover_init_coef_lr4(struct sof_eq_iir_biquad *coef, * delay[0..1] -> state for first biquad * delay[2..3] -> state for second biquad */ - lr4->delay = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(uint64_t) * CROSSOVER_NUM_DELAYS_LR4); + lr4->delay = mod_zalloc(mod, sizeof(uint64_t) * CROSSOVER_NUM_DELAYS_LR4); if (!lr4->delay) return -ENOMEM; - lr4->biquads = 2; - lr4->biquads_in_series = 2; + lr4->biquads = CROSSOVER_LR4_NUM_BIQUADS; + lr4->biquads_in_series = CROSSOVER_LR4_NUM_BIQUADS; return 0; } @@ -199,7 +200,8 @@ static int crossover_init_coef_lr4(struct sof_eq_iir_biquad *coef, /** * \brief Initializes the crossover coefficients for one channel */ -int crossover_init_coef_ch(struct sof_eq_iir_biquad *coef, +int crossover_init_coef_ch(struct processing_module *mod, + struct sof_eq_iir_biquad *coef, struct crossover_state *ch_state, int32_t num_sinks) { @@ -210,12 +212,12 @@ int crossover_init_coef_ch(struct sof_eq_iir_biquad *coef, for (i = 0; i < num_lr4s; i++) { /* Get the low pass coefficients */ - err = crossover_init_coef_lr4(&coef[j], + err = crossover_init_coef_lr4(mod, &coef[j], &ch_state->lowpass[i]); if (err < 0) return -EINVAL; /* Get the high pass coefficients */ - err = crossover_init_coef_lr4(&coef[j + 1], + err = crossover_init_coef_lr4(mod, &coef[j + 1], &ch_state->highpass[i]); if (err < 0) return -EINVAL; @@ -239,29 +241,29 @@ static int crossover_init_coef(struct processing_module *mod, int nch) int ch, err; if (!config) { - comp_err(mod->dev, "crossover_init_coef(), no config is set"); + comp_err(mod->dev, "no config is set"); return -EINVAL; } /* Sanity checks */ if (nch > PLATFORM_MAX_CHANNELS) { - comp_err(mod->dev, "crossover_init_coef(), invalid channels count (%i)", nch); + comp_err(mod->dev, "invalid channels count (%i)", nch); return -EINVAL; } - comp_info(mod->dev, "crossover_init_coef(), initializing %i-way crossover", + comp_info(mod->dev, "initializing %i-way crossover", config->num_sinks); /* Collect the coef array and assign it to every channel */ crossover = config->coef; for (ch = 0; ch < nch; ch++) { - err = crossover_init_coef_ch(crossover, &cd->state[ch], + err = crossover_init_coef_ch(mod, crossover, &cd->state[ch], config->num_sinks); /* Free all previously allocated blocks in case of an error */ if (err < 0) { - comp_err(mod->dev, "crossover_init_coef(), could not assign coefficients to ch %d", + comp_err(mod->dev, "could not assign coefficients to ch %d", ch); - crossover_reset_state(cd); + crossover_reset_state(mod); return err; } } @@ -274,11 +276,10 @@ static int crossover_init_coef(struct processing_module *mod, int nch) */ static int crossover_setup(struct processing_module *mod, int nch) { - struct comp_data *cd = module_get_private_data(mod); int ret = 0; /* Reset any previous state */ - crossover_reset_state(cd); + crossover_reset_state(mod); /* Assign LR4 coefficients from config */ ret = crossover_init_coef(mod, nch); @@ -295,52 +296,36 @@ static int crossover_init(struct processing_module *mod) struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; struct comp_data *cd; - const struct module_config *ipc_crossover = &md->cfg; - size_t bs = ipc_crossover->size; int ret; - comp_info(dev, "crossover_init()"); - - /* Check that the coefficients blob size is sane */ - if (bs > SOF_CROSSOVER_MAX_SIZE) { - comp_err(dev, "crossover_init(), blob size (%d) exceeds maximum allowed size (%i)", - bs, SOF_CROSSOVER_MAX_SIZE); - return -ENOMEM; - } + comp_info(dev, "entry"); - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; md->private = cd; /* Handler for configuration data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "crossover_init(): comp_data_blob_handler_new() failed."); + comp_err(dev, "comp_data_blob_handler_new() failed."); ret = -ENOMEM; goto cd_fail; } - /* Get configuration data and reset Crossover state */ - ret = comp_init_data_blob(cd->model_handler, bs, ipc_crossover->data); - if (ret < 0) { - comp_err(dev, "crossover_init(): comp_init_data_blob() failed."); - goto cd_fail; - } - ret = crossover_output_pin_init(mod); if (ret < 0) { - comp_err(dev, "crossover_init(): crossover_init_output_pins() failed."); + comp_err(dev, "failed."); goto cd_fail; } - crossover_reset_state(cd); + crossover_reset_state(mod); return 0; cd_fail: - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); + mod_data_blob_handler_free(mod, cd->model_handler); + mod_free(mod, cd); return ret; } @@ -351,13 +336,13 @@ static int crossover_free(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "crossover_free()"); + comp_info(mod->dev, "entry"); - comp_data_blob_handler_free(cd->model_handler); + mod_data_blob_handler_free(mod, cd->model_handler); - crossover_reset_state(cd); + crossover_reset_state(mod); - rfree(cd); + mod_free(mod, cd); return 0; } @@ -365,26 +350,61 @@ static int crossover_free(struct processing_module *mod) * \brief Verifies that the config is formatted correctly. * * The function can only be called after the buffers have been initialized. + * + * \param[in] mod Processing module owning the configuration. The blob + * under validation is read from the module's private data + * (\c cd->config); callers must store it there beforehand. + * \param[in] new_size Size in bytes reported by the framework for the blob; + * must match the size field embedded in the blob header. + * \return 0 on success, negative errno on invalid configuration. */ -static int crossover_validate_config(struct processing_module *mod, - struct sof_crossover_config *config) +static int crossover_validate_config(struct processing_module *mod, size_t new_size) { + struct comp_data *cd = module_get_private_data(mod); + struct sof_crossover_config *config = cd->config; struct comp_dev *dev = mod->dev; - uint32_t size = config->size; + size_t required_size; int32_t num_assigned_sinks; + int32_t num_lr4s; + uint32_t size; - if (size > SOF_CROSSOVER_MAX_SIZE || !size) { - comp_err(dev, "crossover_validate_config(), size %d is invalid", size); + if (!config) { + comp_err(dev, "NULL config blob"); + return -EINVAL; + } + + /* Reject truncated blobs before touching config->size: the framework- + * reported new_size must cover at least the fixed header. + */ + if (new_size < sizeof(*config)) { + comp_err(dev, "size %u is smaller than header", (uint32_t)new_size); + return -EINVAL; + } + + size = config->size; + if (size > SOF_CROSSOVER_MAX_SIZE || size != new_size) { + comp_err(dev, "size %u is invalid", size); return -EINVAL; } if (config->num_sinks > SOF_CROSSOVER_MAX_STREAMS || config->num_sinks < 2) { - comp_err(dev, "crossover_validate_config(), invalid num_sinks %i, expected number between 2 and %i", + comp_err(dev, "invalid num_sinks %i, expected number between 2 and %i", config->num_sinks, SOF_CROSSOVER_MAX_STREAMS); return -EINVAL; } + /* Each channel reads 2 * num_lr4s biquads from config->coef[]; the + * runtime uses 1 LR4 pair for 2-way and 3 LR4 pairs otherwise. + * See tune/sof_crossover_generate_config.m script. + */ + num_lr4s = (config->num_sinks == CROSSOVER_2WAY_NUM_SINKS) ? 1 : 3; + required_size = sizeof(*config) + (size_t)num_lr4s * 2 * sizeof(struct sof_eq_iir_biquad); + if (size < required_size) { + comp_err(dev, "size %u too small for num_sinks %u", size, config->num_sinks); + return -EINVAL; + } + /* Align the crossover's sinks, to their respective configuration in * the config. */ @@ -394,7 +414,7 @@ static int crossover_validate_config(struct processing_module *mod, * is different than what is configured. */ if (num_assigned_sinks != config->num_sinks) { - comp_err(dev, "crossover_validate_config(), number of assigned sinks %d, expected from config %d", + comp_err(dev, "number of assigned sinks %d, expected from config %d", num_assigned_sinks, config->num_sinks); return -EINVAL; } @@ -411,7 +431,7 @@ static int crossover_set_config(struct processing_module *mod, uint32_t config_i struct comp_data *cd = module_get_private_data(mod); int ret; - comp_info(mod->dev, "crossover_set_config()"); + comp_info(mod->dev, "entry"); ret = crossover_check_config(mod, fragment); if (ret < 0) @@ -429,7 +449,7 @@ static int crossover_get_config(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; int ret; - comp_info(mod->dev, "crossover_get_config()"); + comp_info(mod->dev, "entry"); ret = crossover_check_config(mod, fragment); if (ret < 0) @@ -463,17 +483,39 @@ static int crossover_process_audio_stream(struct processing_module *mod, uint32_t frames = input_buffers[0].size; uint32_t frame_bytes = audio_stream_frame_bytes(input_buffers[0].data); uint32_t processed_bytes; + struct sof_crossover_config *prev_config; + uint32_t prev_num_sinks; + size_t cfg_size; int ret; int i; - comp_dbg(dev, "crossover_process_audio_stream()"); + comp_dbg(dev, "entry"); /* Check for changed configuration */ if (comp_is_new_data_blob_available(cd->model_handler)) { - cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); + prev_config = cd->config; + prev_num_sinks = prev_config ? prev_config->num_sinks : 0; + + cd->config = comp_get_data_blob(cd->model_handler, &cfg_size, NULL); + ret = crossover_validate_config(mod, cfg_size); + if (ret < 0) + return ret; + + /* num_sinks must not change at runtime: cd->crossover_split was + * selected for the previous count, and a smaller value would + * cause the split function to write past the sink array. + * Reject the blob; the previous config and split stay in use. + */ + if (prev_num_sinks && cd->config->num_sinks != prev_num_sinks) { + comp_err(dev, "runtime num_sinks change %u -> %u not supported", + prev_num_sinks, cd->config->num_sinks); + cd->config = prev_config; + return -EINVAL; + } + ret = crossover_setup(mod, audio_stream_get_channels(source)); if (ret < 0) { - comp_err(dev, "crossover_process_audio_stream(), failed Crossover setup"); + comp_err(dev, "failed Crossover setup"); return ret; } } @@ -526,16 +568,22 @@ static int crossover_prepare(struct processing_module *mod, struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; struct comp_buffer *source, *sink; + size_t data_size; int channels; - int ret = 0; + int ret; + + comp_info(dev, "entry"); - comp_info(dev, "crossover_prepare()"); + source = comp_dev_get_first_data_producer(dev); + if (!source) { + comp_err(dev, "no source buffer"); + return -ENOTCONN; + } crossover_params(mod); /* Crossover has a variable number of sinks */ mod->max_sinks = SOF_CROSSOVER_MAX_STREAMS; - source = comp_dev_get_first_data_producer(dev); /* Get source data format */ cd->source_format = audio_stream_get_frm_fmt(&source->stream); @@ -544,53 +592,51 @@ static int crossover_prepare(struct processing_module *mod, /* Validate frame format and buffer size of sinks */ comp_dev_for_each_consumer(dev, sink) { if (cd->source_format != audio_stream_get_frm_fmt(&sink->stream)) { - comp_err(dev, "crossover_prepare(): Source fmt %d and sink fmt %d are different.", + comp_err(dev, "Source fmt %d and sink fmt %d are different.", cd->source_format, audio_stream_get_frm_fmt(&sink->stream)); - ret = -EINVAL; + return -EINVAL; } - - if (ret < 0) - return ret; } - comp_info(dev, "crossover_prepare(), source_format=%d, sink_formats=%d, nch=%d", + comp_info(dev, "source_format=%d, sink_formats=%d, nch=%d", cd->source_format, cd->source_format, channels); - cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - - /* Initialize Crossover */ - if (cd->config && crossover_validate_config(mod, cd->config) < 0) { - /* If config is invalid then delete it */ - comp_err(dev, "crossover_prepare(), invalid binary config format"); - crossover_free_config(&cd->config); - } + cd->config = comp_get_data_blob(cd->model_handler, &data_size, NULL); + /* A NULL cd->config is a supported operating mode: the component runs + * in passthrough (see the else-branch below), so only validate when a + * blob is actually present. + */ if (cd->config) { + ret = crossover_validate_config(mod, data_size); + if (ret < 0) + return ret; + ret = crossover_setup(mod, channels); if (ret < 0) { - comp_err(dev, "crossover_prepare(), setup failed"); + comp_err(dev, "setup failed"); return ret; } cd->crossover_process = crossover_find_proc_func(cd->source_format); if (!cd->crossover_process) { - comp_err(dev, "crossover_prepare(), No processing function matching frame_fmt %i", + comp_err(dev, "No processing function matching frame_fmt %i", cd->source_format); return -EINVAL; } cd->crossover_split = crossover_find_split_func(cd->config->num_sinks); if (!cd->crossover_split) { - comp_err(dev, "crossover_prepare(), No split function matching num_sinks %i", + comp_err(dev, "No split function matching num_sinks %i", cd->config->num_sinks); return -EINVAL; } } else { - comp_info(dev, "crossover_prepare(), setting crossover to passthrough mode"); + comp_info(dev, "setting crossover to passthrough mode"); cd->crossover_process = crossover_find_proc_func_pass(cd->source_format); if (!cd->crossover_process) { - comp_err(dev, "crossover_prepare(), No passthrough function matching frame_fmt %i", + comp_err(dev, "No passthrough function matching frame_fmt %i", cd->source_format); return -EINVAL; } @@ -608,9 +654,9 @@ static int crossover_reset(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "crossover_reset()"); + comp_info(mod->dev, "entry"); - crossover_reset_state(cd); + crossover_reset_state(mod); cd->crossover_process = NULL; cd->crossover_split = NULL; @@ -629,9 +675,6 @@ static const struct module_interface crossover_interface = { .free = crossover_free }; -DECLARE_MODULE_ADAPTER(crossover_interface, crossover_uuid, crossover_tr); -SOF_MODULE_INIT(crossover, sys_comp_module_crossover_interface_init); - #if CONFIG_COMP_CROSSOVER_MODULE /* modular: llext dynamic link */ @@ -639,14 +682,15 @@ SOF_MODULE_INIT(crossover, sys_comp_module_crossover_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_CROSSOVER 0xD1, 0x9A, 0x8C, 0x94, 0x6A, 0x80, 0x31, 0x41, 0x6C, 0xAD, \ - 0xB2, 0xBD, 0xA9, 0xE3, 0x5A, 0x9F - -SOF_LLEXT_MOD_ENTRY(crossover, &crossover_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("XOVER", crossover_llext_entry, 1, UUID_CROSSOVER, 40); + SOF_LLEXT_MODULE_MANIFEST("XOVER", &crossover_interface, 1, SOF_REG_UUID(crossover), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(crossover_tr, SOF_UUID(crossover_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(crossover_interface, crossover_uuid, crossover_tr); +SOF_MODULE_INIT(crossover, sys_comp_module_crossover_interface_init); + #endif diff --git a/src/audio/crossover/crossover.h b/src/audio/crossover/crossover.h index f193c058a375..2312a1d53857 100644 --- a/src/audio/crossover/crossover.h +++ b/src/audio/crossover/crossover.h @@ -8,13 +8,15 @@ #define __SOF_AUDIO_CROSSOVER_CROSSOVER_H__ #include <sof/audio/module_adapter/module/module_interface.h> -#include <sof/math/iir_df2t.h> +#include <sof/math/iir_df1.h> #include <module/crossover/crossover_common.h> #include <sof/platform.h> #include <stdint.h> #include "crossover_user.h" +#define CROSSOVER_LR4_NUM_BIQUADS 2 + struct comp_buffer; struct comp_dev; @@ -119,10 +121,10 @@ extern const size_t crossover_split_fncount; * \brief Runs input in through the LR4 filter and returns it's output. */ static inline int32_t crossover_generic_process_lr4(int32_t in, - struct iir_state_df2t *lr4) + struct iir_state_df1 *lr4) { /* Cascade two biquads with same coefficients in series. */ - return iir_df2t(lr4, in); + return iir_df1_4th(lr4, in); } static inline void crossover_free_config(struct sof_crossover_config **config) diff --git a/src/audio/crossover/crossover.toml b/src/audio/crossover/crossover.toml index c27f14ce34e6..fead1e8e22d2 100644 --- a/src/audio/crossover/crossover.toml +++ b/src/audio/crossover/crossover.toml @@ -7,7 +7,7 @@ REM # 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" + uuid = UUIDREG_STR_CROSSOVER affinity_mask = "0x1" instance_count = "40" domain_types = "0" diff --git a/src/audio/crossover/crossover_generic.c b/src/audio/crossover/crossover_generic.c index e445777113d4..028018934816 100644 --- a/src/audio/crossover/crossover_generic.c +++ b/src/audio/crossover/crossover_generic.c @@ -8,7 +8,7 @@ #include <sof/audio/module_adapter/module/module_interface.h> #include <sof/audio/component.h> #include <sof/audio/format.h> -#include <sof/math/iir_df2t.h> +#include <sof/math/iir_df1.h> #include <stdint.h> #include "crossover.h" @@ -21,8 +21,8 @@ * As a side effect, this function mutates the delay values of both * filters. */ -static inline void crossover_generic_lr4_split(struct iir_state_df2t *lp, - struct iir_state_df2t *hp, +static inline void crossover_generic_lr4_split(struct iir_state_df1 *lp, + struct iir_state_df1 *hp, int32_t x, int32_t *y1, int32_t *y2) { @@ -39,8 +39,8 @@ static inline void crossover_generic_lr4_split(struct iir_state_df2t *lp, * to be out of phase. We need to pass the signal through another set of LR4 * filters to align back the phase. */ -static inline void crossover_generic_lr4_merge(struct iir_state_df2t *lp, - struct iir_state_df2t *hp, +static inline void crossover_generic_lr4_merge(struct iir_state_df1 *lp, + struct iir_state_df1 *hp, int32_t x, int32_t *y) { int32_t z1, z2; diff --git a/src/audio/crossover/crossover_ipc3.c b/src/audio/crossover/crossover_ipc3.c index 07eb39ebca95..48f56ac3cced 100644 --- a/src/audio/crossover/crossover_ipc3.c +++ b/src/audio/crossover/crossover_ipc3.c @@ -48,13 +48,13 @@ int crossover_check_sink_assign(struct processing_module *mod, i = crossover_get_stream_index(mod, config, pipeline_id); if (i < 0) { - comp_warn(dev, "crossover_check_sink_assign(), could not assign sink %d", + comp_warn(dev, "could not assign sink %d", pipeline_id); break; } if (assigned_sinks[i]) { - comp_warn(dev, "crossover_check_sink_assign(), multiple sinks from pipeline %d are assigned", + comp_warn(dev, "multiple sinks from pipeline %d are assigned", pipeline_id); break; } diff --git a/src/audio/crossover/crossover_ipc4.c b/src/audio/crossover/crossover_ipc4.c index 9fbe7730e53e..3e0beffeeeb1 100644 --- a/src/audio/crossover/crossover_ipc4.c +++ b/src/audio/crossover/crossover_ipc4.c @@ -81,13 +81,13 @@ int crossover_check_sink_assign(struct processing_module *mod, pin_index = cd->output_pin_index[j]; i = crossover_get_stream_index(mod, config, pin_index); if (i < 0) { - comp_warn(dev, "crossover_check_sink_assign(), could not assign sink %u", + comp_warn(dev, "could not assign sink %u", pin_index); break; } if (assigned_sinks[i]) { - comp_warn(dev, "crossover_check_sink_assign(), multiple sinks from pin %u are assigned", + comp_warn(dev, "multiple sinks from pin %u are assigned", pin_index); break; } @@ -113,11 +113,12 @@ void crossover_params(struct processing_module *mod) struct comp_buffer *sinkb, *sourceb; struct comp_dev *dev = mod->dev; - comp_dbg(dev, "crossover_params()"); + comp_dbg(dev, "entry"); ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); component_set_nearest_period_frames(dev, params->rate); + /* First producer verified by the caller */ sourceb = comp_dev_get_first_data_producer(dev); ipc4_update_buffer_format(sourceb, &mod->priv.cfg.base_cfg.audio_fmt); diff --git a/src/audio/crossover/tune/sof_crossover_build_blob.m b/src/audio/crossover/tune/sof_crossover_build_blob.m index e5f48fd61a13..17f1c2c60fc5 100644 --- a/src/audio/crossover/tune/sof_crossover_build_blob.m +++ b/src/audio/crossover/tune/sof_crossover_build_blob.m @@ -1,4 +1,4 @@ -function blob8 = crossover_build_blob(blob_struct, endian, ipc_ver) +function blob8 = sof_crossover_build_blob(blob_struct, endian, ipc_ver) if nargin < 2 endian = 'little'; @@ -21,7 +21,7 @@ %% Build Blob % refer to sof/src/include/user/crossover.h for the config struct. data_size = 4 * (2 + 4 + 4 + numel(blob_struct.all_coef)); -[abi_bytes, abi_size] = get_abi(data_size, ipc_ver); +[abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver); blob_size = data_size + abi_size; blob8 = uint8(zeros(1, blob_size)); diff --git a/src/audio/crossover/tune/sof_example_crossover.m b/src/audio/crossover/tune/sof_example_crossover.m index 297834ae03bf..6d642122aab6 100644 --- a/src/audio/crossover/tune/sof_example_crossover.m +++ b/src/audio/crossover/tune/sof_example_crossover.m @@ -49,9 +49,9 @@ function export_crossover(cr) tplg1_fn = sprintf('%s/coef_%s_%s_%s.m4', tpath1, str_way, str_freq, str_pid); % Control Bytes File tplg2_fn = sprintf('%s/coef_%s_%s_%s.conf', tpath2, str_way, str_freq, str_pid); % Use those files with sof-ctl to update the component's configuration -blob3_fn = sprintf('%s/coef_%dway.blob', ctlpath3, cr.num_sinks); % Blob binary file +blob3_fn = sprintf('%s/coef_%dway.bin', ctlpath3, cr.num_sinks); % Blob binary file alsa3_fn = sprintf('%s/coef_%dway.txt', ctlpath3, cr.num_sinks); % ALSA CSV format file -blob4_fn = sprintf('%s/coef_%dway.blob', ctlpath4, cr.num_sinks); % Blob binary file +blob4_fn = sprintf('%s/coef_%dway.bin', ctlpath4, cr.num_sinks); % Blob binary file alsa4_fn = sprintf('%s/coef_%dway.txt', ctlpath4, cr.num_sinks); % ALSA CSV format file % This array is an example on how to assign a buffer from pipeline 1 to output 0, @@ -85,16 +85,12 @@ function export_crossover(cr) % Generate output files -mkdir_check(tpath1); -mkdir_check(tpath2); -mkdir_check(ctlpath3); -mkdir_check(ctlpath4); -tplg_write(tplg1_fn, blob8, "CROSSOVER"); -tplg2_write(tplg2_fn, blob8_ipc4, "crossover_config", 'Exported Control Bytes'); +sof_tplg_write(tplg1_fn, blob8, "CROSSOVER"); +sof_tplg2_write(tplg2_fn, blob8_ipc4, "crossover_config", 'Exported Control Bytes'); sof_ucm_blob_write(blob3_fn, blob8); sof_ucm_blob_write(blob4_fn, blob8_ipc4); -alsactl_write(alsa3_fn, blob8); -alsactl_write(alsa4_fn, blob8_ipc4); +sof_alsactl_write(alsa3_fn, blob8); +sof_alsactl_write(alsa4_fn, blob8_ipc4); % Plot Magnitude and Phase Response of each sink sof_crossover_plot_freq(crossover.lp, crossover.hp, cr.fs, cr.num_sinks); @@ -125,12 +121,3 @@ function export_crossover(cr) end end - -% Check if directory exists, avoid warning print for existing -function mkdir_check(new_dir) - - if ~exist(new_dir, 'dir') - mkdir(new_dir); - end - -end diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index b212bb9ebdac..8a9496c49121 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -41,8 +41,6 @@ LOG_MODULE_REGISTER(dai_comp, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(dai); -DECLARE_TR_CTX(dai_comp_tr, SOF_UUID(dai_uuid), LOG_LEVEL_INFO); - #if CONFIG_COMP_DAI_GROUP static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, int cmd); @@ -62,7 +60,7 @@ int dai_assign_group(struct dai_data *dd, struct comp_dev *dev, uint32_t group_i { if (dd->group) { if (dd->group->group_id != group_id) { - comp_err(dev, "dai_assign_group(), DAI already in group %d, requested %d", + comp_err(dev, "DAI already in group %d, requested %d", dd->group->group_id, group_id); return -EINVAL; } @@ -73,12 +71,12 @@ int dai_assign_group(struct dai_data *dd, struct comp_dev *dev, uint32_t group_i dd->group = dai_group_get(group_id, DAI_CREAT); if (!dd->group) { - comp_err(dev, "dai_assign_group(), failed to assign group %d", + comp_err(dev, "failed to assign group %d", group_id); return -EINVAL; } - comp_dbg(dev, "dai_assign_group(), group %d num %d", + comp_dbg(dev, "group %d num %d", group_id, dd->group->num_dais); /* Register for the atomic trigger event */ @@ -97,7 +95,7 @@ static void dai_dma_cb(void *arg, enum notify_id type, void *data) uint32_t bytes = next->elem.size; int ret; - comp_dbg(dev, "dai_dma_cb()"); + comp_dbg(dev, "entry"); next->status = SOF_DMA_CB_STATUS_RELOAD; @@ -136,7 +134,7 @@ static void dai_dma_cb(void *arg, enum notify_id type, void *data) dd->local_buffer : dd->dma_buffer; sink_c = dev->direction == SOF_IPC_STREAM_PLAYBACK ? dd->dma_buffer : dd->local_buffer; - comp_err(dev, "dai_dma_cb() dma buffer copy failed, dir %d bytes %d avail %d free %d", + comp_err(dev, "dma buffer copy failed, dir %d bytes %d avail %d free %d", dev->direction, bytes, audio_stream_get_avail_samples(&source_c->stream) * audio_stream_frame_bytes(&source_c->stream), @@ -154,7 +152,7 @@ int dai_common_new(struct dai_data *dd, struct comp_dev *dev, const struct ipc_c dd->dai = dai_get(dai->type, dai->dai_index, DAI_CREAT); if (!dd->dai) { - comp_cl_err(&comp_dai, "dai_common_new(): dai_get() failed to create DAI."); + comp_cl_err(&comp_dai, "dai_get() failed to create DAI."); return -ENODEV; } dd->dai->dd = dd; @@ -169,7 +167,7 @@ int dai_common_new(struct dai_data *dd, struct comp_dev *dev, const struct ipc_c dd->dma = dma_get(dir, caps, dma_dev, DMA_ACCESS_SHARED); if (!dd->dma) { - comp_cl_err(&comp_dai, "dai_common_new(): dma_get() failed to get shared access to DMA."); + comp_cl_err(&comp_dai, "dma_get() failed to get shared access to DMA."); return -ENODEV; } @@ -196,9 +194,9 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, return NULL; dev->ipc_config = *config; - dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); + dd = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*dd)); if (!dd) { - rfree(dev); + comp_free_device(dev); return NULL; } @@ -213,7 +211,7 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, error: rfree(dd); - rfree(dev); + comp_free_device(dev); return NULL; } @@ -250,7 +248,7 @@ static void dai_free(struct comp_dev *dev) dai_common_free(dd); rfree(dd); - rfree(dev); + comp_free_device(dev); } int dai_common_get_hw_params(struct dai_data *dd, struct comp_dev *dev, @@ -263,7 +261,7 @@ int dai_common_get_hw_params(struct dai_data *dd, struct comp_dev *dev, /* fetching hw dai stream params */ ret = dai_get_hw_params(dd->dai, params, dir); if (ret < 0) { - comp_err(dev, "dai_comp_get_hw_params(): dai_get_hw_params failed ret %d", + comp_err(dev, "dai_get_hw_params failed ret %d", ret); return ret; } @@ -293,12 +291,12 @@ static int dai_comp_hw_params(struct comp_dev *dev, struct dai_data *dd = comp_get_drvdata(dev); int ret; - comp_dbg(dev, "dai_comp_hw_params()"); + comp_dbg(dev, "entry"); /* configure hw dai stream params */ ret = dai_hw_params(dd->dai, params); if (ret < 0) { - comp_err(dev, "dai_comp_hw_params(): dai_hw_params failed ret %d", + comp_err(dev, "dai_hw_params failed ret %d", ret); return ret; } @@ -323,13 +321,13 @@ static int dai_verify_params(struct dai_data *dd, struct comp_dev *dev, * pcm_converter functions. */ if (hw_params.rate && hw_params.rate != params->rate) { - comp_err(dev, "dai_verify_params(): pcm rate parameter %d does not match hardware rate %d", + comp_err(dev, "pcm rate parameter %d does not match hardware rate %d", params->rate, hw_params.rate); return -EINVAL; } if (hw_params.channels && hw_params.channels != params->channels) { - comp_err(dev, "dai_verify_params(): pcm channels parameter %d does not match hardware channels %d", + comp_err(dev, "pcm channels parameter %d does not match hardware channels %d", params->channels, hw_params.channels); return -EINVAL; } @@ -355,7 +353,7 @@ static int dai_playback_params(struct comp_dev *dev, uint32_t period_bytes, 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", + comp_err(dev, "converter function NULL: local fmt %d dma fmt %d\n", local_fmt, dma_fmt); return -EINVAL; } @@ -371,7 +369,7 @@ static int dai_playback_params(struct comp_dev *dev, uint32_t period_bytes, config->is_scheduling_source = comp_is_scheduling_source(dev); config->period = dev->pipeline->period; - comp_info(dev, "dai_playback_params() dest_dev = %d stream_id = %d src_width = %d dest_width = %d", + comp_info(dev, "dest_dev = %d stream_id = %d src_width = %d dest_width = %d", config->dest_dev, dd->stream_id, config->src_width, config->dest_width); @@ -379,16 +377,16 @@ static int dai_playback_params(struct comp_dev *dev, uint32_t period_bytes, fifo = dai_get_fifo(dd->dai, dev->direction, dd->stream_id); - comp_info(dev, "dai_playback_params() fifo 0x%x", fifo); + comp_info(dev, "fifo 0x%x", fifo); - err = dma_sg_alloc(&config->elem_array, SOF_MEM_ZONE_RUNTIME, + err = dma_sg_alloc(NULL, &config->elem_array, SOF_MEM_FLAG_USER, config->direction, period_count, period_bytes, (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", + comp_err(dev, "dma_sg_alloc() for period_count %d period_bytes %d failed with err = %d", period_count, period_bytes, err); } @@ -409,7 +407,7 @@ static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, 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", + comp_err(dev, "converter function NULL: local fmt %d dma fmt %d\n", local_fmt, dma_fmt); return -EINVAL; } @@ -436,7 +434,7 @@ static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, config->dest_width = config->src_width; } - comp_info(dev, "dai_capture_params() src_dev = %d stream_id = %d src_width = %d dest_width = %d", + comp_info(dev, "src_dev = %d stream_id = %d src_width = %d dest_width = %d", config->src_dev, dd->stream_id, config->src_width, config->dest_width); @@ -444,16 +442,16 @@ static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, fifo = dai_get_fifo(dd->dai, dev->direction, dd->stream_id); - comp_info(dev, "dai_capture_params() fifo 0x%x", fifo); + comp_info(dev, "fifo 0x%x", fifo); - err = dma_sg_alloc(&config->elem_array, SOF_MEM_ZONE_RUNTIME, + err = dma_sg_alloc(NULL, &config->elem_array, SOF_MEM_FLAG_USER, config->direction, period_count, period_bytes, (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", + comp_err(dev, "dma_sg_alloc() for period_count %d period_bytes %d failed with err = %d", period_count, period_bytes, err); } @@ -469,7 +467,7 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, uint32_t period_bytes; uint32_t buffer_size; uint32_t addr_align; - uint32_t align; + uint32_t align = 0; int err; comp_dbg(dev, "dai_params()"); @@ -481,14 +479,14 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, err = dai_verify_params(dd, dev, params); if (err < 0) { - comp_err(dev, "dai_params(): pcm params verification failed."); + comp_err(dev, "pcm params verification failed."); return -EINVAL; } /* params verification passed, so now configure hw dai stream params */ err = dai_comp_hw_params(dev, params); if (err < 0) { - comp_err(dev, "dai_params(): dai_comp_hw_params failed err %d", err); + comp_err(dev, "dai_comp_hw_params failed err %d", err); return err; } @@ -505,7 +503,7 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, /* can set params on only init state */ if (dev->state != COMP_STATE_READY) { - comp_err(dev, "dai_params(): Component is in state %d, expected COMP_STATE_READY.", + comp_err(dev, "Component is in state %d, expected COMP_STATE_READY.", dev->state); return -EINVAL; } @@ -513,14 +511,14 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, err = dma_get_attribute_legacy(dd->dma, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, &addr_align); if (err < 0) { - comp_err(dev, "dai_params(): could not get dma buffer address alignment, err = %d", + comp_err(dev, "could not get dma buffer address alignment, err = %d", err); return err; } err = dma_get_attribute_legacy(dd->dma, DMA_ATTR_BUFFER_ALIGNMENT, &align); if (err < 0 || !align) { - comp_err(dev, "dai_params(): could not get valid dma buffer alignment, err = %d, align = %u", + comp_err(dev, "could not get valid dma buffer alignment, err = %d, align = %u", err, align); return -EINVAL; } @@ -528,7 +526,7 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, err = dma_get_attribute_legacy(dd->dma, DMA_ATTR_BUFFER_PERIOD_COUNT, &period_count); if (err < 0 || !period_count) { - comp_err(dev, "dai_params(): could not get valid dma buffer period count, err = %d, period_count = %u", + comp_err(dev, "could not get valid dma buffer period count, err = %d, period_count = %u", err, period_count); return -EINVAL; } @@ -540,7 +538,7 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, /* calculate period size */ period_bytes = dev->frames * frame_size; if (!period_bytes) { - comp_err(dev, "dai_params(): invalid period_bytes."); + comp_err(dev, "invalid period_bytes."); return -EINVAL; } @@ -556,15 +554,16 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, 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", + comp_err(dev, "buffer_set_size() failed, buffer_size = %u", buffer_size); return err; } } else { - dd->dma_buffer = buffer_alloc(buffer_size, SOF_MEM_CAPS_DMA, 0, - addr_align, false); + dd->dma_buffer = buffer_alloc(NULL, buffer_size, + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA, + addr_align, BUFFER_USAGE_NOT_SHARED); if (!dd->dma_buffer) { - comp_err(dev, "dai_params(): failed to alloc dma buffer"); + comp_err(dev, "failed to alloc dma buffer"); return -ENOMEM; } @@ -588,7 +587,7 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params { struct dai_data *dd = comp_get_drvdata(dev); - comp_dbg(dev, "dai_params()"); + comp_dbg(dev, "entry"); return dai_common_params(dd, dev, params); } @@ -599,7 +598,7 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev) /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { - comp_info(dev, "dai_common_config_prepare(): Component is in active state."); + comp_info(dev, "Component is in active state."); return 0; } @@ -609,13 +608,13 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev) } if (dd->chan) { - comp_info(dev, "dai_common_config_prepare(): dma channel index %d already configured", + comp_info(dev, "dma channel index %d already configured", dd->chan->index); return 0; } channel = dai_config_dma_channel(dd, dev, dd->dai_spec_config); - comp_info(dev, "dai_common_config_prepare(), channel = %d", channel); + comp_info(dev, "channel = %d", channel); /* do nothing for asking for channel free, for compatibility. */ if (channel == DMA_CHAN_INVALID) { @@ -626,14 +625,14 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev) /* allocate DMA channel */ dd->chan = dma_channel_get_legacy(dd->dma, channel); if (!dd->chan) { - comp_err(dev, "dai_common_config_prepare(): dma_channel_get() failed"); + comp_err(dev, "dma_channel_get() failed"); dd->chan = NULL; return -EIO; } dd->chan->dev_data = dd; - comp_info(dev, "dai_common_config_prepare(): new configured dma channel index %d", + comp_info(dev, "new configured dma channel index %d", dd->chan->index); /* setup callback */ @@ -650,13 +649,13 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev) dd->total_data_processed = 0; if (!dd->chan) { - comp_err(dev, "dai_prepare(): Missing dd->chan."); + comp_err(dev, "Missing dd->chan."); comp_set_state(dev, COMP_TRIGGER_RESET); return -EINVAL; } if (!dd->config.elem_array.elems) { - comp_err(dev, "dai_prepare(): Missing dd->config.elem_array.elems."); + comp_err(dev, "Missing dd->config.elem_array.elems."); comp_set_state(dev, COMP_TRIGGER_RESET); return -EINVAL; } @@ -683,7 +682,7 @@ static int dai_prepare(struct comp_dev *dev) struct dai_data *dd = comp_get_drvdata(dev); int ret; - comp_info(dev, "dai_prepare()"); + comp_info(dev, "entry"); ret = dai_common_config_prepare(dd, dev); if (ret < 0) @@ -710,7 +709,7 @@ void dai_common_reset(struct dai_data *dd, struct comp_dev *dev) if (!dd->delayed_dma_stop) dai_dma_release(dd, dev); - dma_sg_free(&config->elem_array); + dma_sg_free(NULL, &config->elem_array); if (dd->dma_buffer) { buffer_free(dd->dma_buffer); @@ -726,7 +725,7 @@ static int dai_reset(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); - comp_info(dev, "dai_reset()"); + comp_info(dev, "entry"); dai_common_reset(dd, dev); @@ -740,7 +739,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, { int ret; - comp_dbg(dev, "dai_comp_trigger_internal(), command = %u", cmd); + comp_dbg(dev, "command = %u", cmd); ret = comp_set_state(dev, cmd); if (ret < 0) @@ -751,7 +750,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, switch (cmd) { case COMP_TRIGGER_START: - comp_dbg(dev, "dai_comp_trigger_internal(), START"); + comp_dbg(dev, "START"); /* only start the DAI if we are not XRUN handling */ if (dd->xrun == 0) { @@ -794,12 +793,12 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, platform_dai_wallclock(dev, &dd->wallclock); break; case COMP_TRIGGER_XRUN: - comp_info(dev, "dai_comp_trigger_internal(), XRUN"); + comp_info(dev, "XRUN"); dd->xrun = 1; COMPILER_FALLTHROUGH; case COMP_TRIGGER_STOP: - comp_dbg(dev, "dai_comp_trigger_internal(), STOP"); + comp_dbg(dev, "STOP"); /* * Some platforms cannot just simple disable * DMA channel during the transfer, @@ -817,7 +816,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, #endif break; case COMP_TRIGGER_PAUSE: - comp_dbg(dev, "dai_comp_trigger_internal(), PAUSE"); + comp_dbg(dev, "PAUSE"); ret = dma_pause_legacy(dd->chan); dai_trigger(dd->dai, cmd, dev->direction); break; @@ -842,7 +841,7 @@ int dai_common_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd) /* DAI not in a group, use normal trigger */ if (!group) { - comp_dbg(dev, "dai_common_trigger(), non-atomic trigger"); + comp_dbg(dev, "non-atomic trigger"); return dai_comp_trigger_internal(dd, dev, cmd); } @@ -852,13 +851,13 @@ int dai_common_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd) /* First DAI to receive the trigger command, * prepare for atomic trigger */ - comp_dbg(dev, "dai_common_trigger(), begin atomic trigger for group %d", + comp_dbg(dev, "begin atomic trigger for group %d", group->group_id); group->trigger_cmd = cmd; group->trigger_counter = group->num_dais - 1; } else if (group->trigger_cmd != cmd) { /* Already processing a different trigger command */ - comp_err(dev, "dai_common_trigger(), already processing atomic trigger"); + comp_err(dev, "already processing atomic trigger"); ret = -EAGAIN; } else { /* Count down the number of remaining DAIs required @@ -866,7 +865,7 @@ int dai_common_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd) * takes place */ group->trigger_counter--; - comp_dbg(dev, "dai_common_trigger(), trigger counter %d, group %d", + comp_dbg(dev, "trigger counter %d, group %d", group->trigger_counter, group->group_id); if (!group->trigger_counter) { @@ -902,10 +901,10 @@ static void dai_report_xrun(struct comp_dev *dev, uint32_t bytes) struct dai_data *dd = comp_get_drvdata(dev); if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { - comp_err(dev, "dai_report_xrun(): underrun due to no data available"); + comp_err(dev, "underrun due to no data available"); comp_underrun(dev, dd->local_buffer, bytes); } else { - comp_err(dev, "dai_report_xrun(): overrun due to no space available"); + comp_err(dev, "overrun due to no space available"); comp_overrun(dev, dd->local_buffer, bytes); } } @@ -951,23 +950,23 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun copy_bytes = samples * sampling; - comp_dbg(dev, "dai_common_copy(), dir: %d copy_bytes= 0x%x, frames= %d", + comp_dbg(dev, "dir: %d copy_bytes= 0x%x, frames= %d", dev->direction, copy_bytes, samples / audio_stream_get_channels(&dd->local_buffer->stream)); /* Check possibility of glitch occurrence */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK && copy_bytes + avail_bytes < dd->period_bytes) - comp_warn(dev, "dai_common_copy(): Copy_bytes %d + avail bytes %d < period bytes %d, possible glitch", + comp_warn(dev, "Copy_bytes %d + avail bytes %d < period bytes %d, possible glitch", copy_bytes, avail_bytes, dd->period_bytes); else if (dev->direction == SOF_IPC_STREAM_CAPTURE && copy_bytes + free_bytes < dd->period_bytes) - comp_warn(dev, "dai_common_copy(): Copy_bytes %d + free bytes %d < period bytes %d, possible glitch", + comp_warn(dev, "Copy_bytes %d + free bytes %d < period bytes %d, possible glitch", copy_bytes, free_bytes, dd->period_bytes); /* return if nothing to copy */ if (!copy_bytes) { - comp_warn(dev, "dai_common_copy(): nothing to copy"); + comp_warn(dev, "nothing to copy"); return 0; } @@ -989,7 +988,7 @@ static int dai_copy(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); - comp_dbg(dev, "dai_copy()"); + comp_dbg(dev, "entry"); /* * DAI devices will only ever have 1 sink, so no need to pass an array of PCM converter @@ -1050,7 +1049,7 @@ static int dai_ts_start(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); - comp_dbg(dev, "dai_ts_start()"); + comp_dbg(dev, "entry"); return dai_common_ts_start(dd, dev); } @@ -1067,7 +1066,7 @@ static int dai_ts_stop(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); - comp_dbg(dev, "dai_ts_stop()"); + comp_dbg(dev, "entry"); return dai_common_ts_stop(dd, dev); } @@ -1084,7 +1083,7 @@ static int dai_ts_get(struct comp_dev *dev, struct timestamp_data *tsd) { struct dai_data *dd = comp_get_drvdata(dev); - comp_dbg(dev, "dai_ts_get()"); + comp_dbg(dev, "entry"); return dai_common_ts_get(dd, dev, tsd); } @@ -1104,6 +1103,8 @@ static uint64_t dai_get_processed_data(struct comp_dev *dev, uint32_t stream_no, return ret; } +DECLARE_TR_CTX(dai_comp_tr, SOF_UUID(dai_uuid), LOG_LEVEL_INFO); + static const struct comp_driver comp_dai = { .type = SOF_COMP_DAI, .uid = SOF_RT_UUID(dai_uuid), @@ -1133,8 +1134,7 @@ static SHARED_DATA struct comp_driver_info comp_dai_info = { UT_STATIC void sys_comp_dai_init(void) { - comp_register(platform_shared_get(&comp_dai_info, - sizeof(comp_dai_info))); + comp_register(&comp_dai_info); } DECLARE_MODULE(sys_comp_dai_init); diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index c43d2f87332f..e0295526d054 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -36,6 +36,10 @@ #include <stddef.h> #include <stdint.h> +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE +#include <ipc4/notification.h> +#endif + #include "copier/copier.h" #include "copier/dai_copier.h" #include "copier/copier_gain.h" @@ -59,8 +63,6 @@ LOG_MODULE_REGISTER(dai_comp, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(dai); -DECLARE_TR_CTX(dai_comp_tr, SOF_UUID(dai_uuid), LOG_LEVEL_INFO); - #if CONFIG_COMP_DAI_GROUP static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, int cmd); @@ -76,8 +78,10 @@ static void dai_atomic_trigger(void *arg, enum notify_id type, void *data) } /* Assign DAI to a group */ -int dai_assign_group(struct dai_data *dd, struct comp_dev *dev, uint32_t group_id) +__cold int dai_assign_group(struct dai_data *dd, struct comp_dev *dev, uint32_t group_id) { + assert_can_be_cold(); + if (dd->group) { if (dd->group->group_id != group_id) { comp_err(dev, "DAI already in group %d, requested %d", @@ -135,19 +139,22 @@ static int dai_trigger_op(struct dai *dai, int cmd, int direction) } /* called from src/ipc/ipc3/handler.c and src/ipc/ipc4/dai.c */ -int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config, - const void *spec_config) +__cold int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config, + const void *spec_config, size_t size) { const struct device *dev = dai->dev; const struct sof_ipc_dai_config *sof_cfg = spec_config; - struct dai_config cfg; + struct dai_config cfg = {0}; const void *cfg_params; + size_t dai_cfg_size = size; bool is_blob; + assert_can_be_cold(); + cfg.dai_index = common_config->dai_index; is_blob = common_config->is_config_blob; - cfg.format = sof_cfg->format; - cfg.options = sof_cfg->flags; + cfg.format = common_config->format; + cfg.options = is_blob ? 0 : sof_cfg->flags; cfg.rate = common_config->sampling_frequency; switch (common_config->type) { @@ -181,11 +188,51 @@ int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config, cfg.type = DAI_IMX_ESAI; cfg_params = &sof_cfg->esai; break; + case SOF_DAI_IMX_MICFIL: + cfg.type = DAI_IMX_MICFIL; + cfg_params = &sof_cfg->micfil; + break; + case SOF_DAI_AMD_SDW: + cfg.type = DAI_AMD_SDW; + cfg_params = &sof_cfg->acpsdw; + break; + case SOF_DAI_AMD_HS: + case SOF_DAI_AMD_HS_VIRTUAL: + case SOF_DAI_AMD_SP: + case SOF_DAI_AMD_SP_VIRTUAL: + case SOF_DAI_AMD_BT: + case SOF_DAI_AMD_TDM: + cfg.type = DAI_AMD_TDM; + cfg_params = &sof_cfg->acptdm; + break; + case SOF_DAI_INTEL_UAOL: + cfg.type = DAI_INTEL_UAOL; + cfg.channels = common_config->gtw_fmt->channels_count; + /* + * FIXME: The spec says HW expects container size here, not valid_bit_depth. + * However, tests fail if container size is used and work fine with + * valid_bit_depth. Needs investigation. Perhaps tests have a bug? + */ + cfg.word_size = common_config->gtw_fmt->valid_bit_depth; + cfg_params = spec_config; + dai_set_link_hda_config(&cfg.link_config, common_config, spec_config); + break; + case SOF_DAI_MEDIATEK_AFE: + cfg.type = DAI_MEDIATEK_AFE; + cfg_params = &sof_cfg->afe; + break; default: return -EINVAL; } - return dai_config_set(dev, &cfg, cfg_params); + if (!is_blob) { + if (size < SOF_DAI_CONFIG_HW_SPEC_OFFSET) + return -EINVAL; + + dai_cfg_size -= SOF_DAI_CONFIG_HW_SPEC_OFFSET; + } + + return dai_config_set(dev, &cfg, cfg_params, dai_cfg_size); } /* called from ipc/ipc3/dai.c */ @@ -250,7 +297,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, enum sof_dma_cb_status dma_status = SOF_DMA_CB_STATUS_RELOAD; int ret; - comp_dbg(dev, "dai_dma_cb()"); + comp_dbg(dev, "entry"); /* stop dma copy for pause/stop/xrun */ if (dev->state != COMP_STATE_ACTIVE || dd->xrun) { @@ -276,37 +323,41 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, /* * copy from local buffer to all sinks that are not gateway buffers * using the right PCM converter function. + * Skip in case of endpoint DAI devices created by the copier. */ - struct comp_buffer *sink; + if (converter) { + struct comp_buffer *sink; - comp_dev_for_each_consumer(dev, sink) { - struct comp_dev *sink_dev; - int j; + comp_dev_for_each_consumer(dev, sink) { + struct comp_dev *sink_dev; + int j; - if (sink == dd->dma_buffer) - continue; + if (sink == dd->dma_buffer) + continue; - sink_dev = comp_buffer_get_sink_component(sink); + sink_dev = comp_buffer_get_sink_component(sink); - j = IPC4_SRC_QUEUE_ID(buf_get_id(sink)); + j = IPC4_SRC_QUEUE_ID(buf_get_id(sink)); - 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; - continue; - } + 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; + continue; + } - if (!converter[j]) { - comp_err(dev, "No PCM converter for sink queue %d\n", j); - ret = -EINVAL; - continue; - } + if (!converter[j]) { + comp_err(dev, "No PCM converter for sink queue %d\n", j); + ret = -EINVAL; + continue; + } - if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && - audio_buffer_hw_params_configured(&sink->audio_buffer)) { - ret = stream_copy_from_no_consume(dd->local_buffer, sink, - converter[j], bytes, dd->chmap); + if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && + audio_buffer_hw_params_configured(&sink->audio_buffer)) { + ret = stream_copy_from_no_consume(dev, dd->local_buffer, + sink, converter[j], + bytes, dd->chmap); + } } } #endif @@ -318,7 +369,8 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, * The PCM converter functions used during DMA buffer copy can never fail, * so no need to check the return value of stream_copy_from_no_consume(). */ - ret = stream_copy_from_no_consume(dd->dma_buffer, dd->local_buffer, + + ret = stream_copy_from_no_consume(dev, dd->dma_buffer, dd->local_buffer, dd->process, bytes, dd->chmap); #if CONFIG_IPC_MAJOR_4 /* Apply gain to the local buffer */ @@ -348,7 +400,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, sink_dev = comp_buffer_get_sink_component(sink); - j = IPC4_SINK_QUEUE_ID(buf_get_id(sink)); + j = IPC4_SRC_QUEUE_ID(buf_get_id(sink)); if (j >= IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT) { comp_err(dev, "Sink queue ID: %d >= max output pin count: %d\n", @@ -365,7 +417,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && audio_buffer_hw_params_configured(&sink->audio_buffer)) - ret = stream_copy_from_no_consume(dd->dma_buffer, + ret = stream_copy_from_no_consume(dev, dd->dma_buffer, sink, converter[j], bytes, dd->chmap); } @@ -394,7 +446,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, } #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS /* Increment performance counters */ - io_perf_monitor_update_data(dd->io_perf_bytes_count, bytes); + io_perf_monitor_update_data(dd->io_perf_dai_byte_count, bytes); #endif return dma_status; @@ -408,7 +460,7 @@ dai_dma_multi_endpoint_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t fr enum sof_dma_cb_status dma_status = SOF_DMA_CB_STATUS_RELOAD; uint32_t i, bytes; - comp_dbg(dev, "dai_dma_multi_endpoint_cb()"); + comp_dbg(dev, "entry"); /* stop dma copy for pause/stop/xrun */ if (dev->state != COMP_STATE_ACTIVE || dd->xrun) { @@ -462,11 +514,13 @@ dai_dma_multi_endpoint_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t fr return dma_status; } -int dai_common_new(struct dai_data *dd, struct comp_dev *dev, - const struct ipc_config_dai *dai_cfg) +__cold int dai_common_new(struct dai_data *dd, struct comp_dev *dev, + const struct ipc_config_dai *dai_cfg) { uint32_t dir; + assert_can_be_cold(); + dd->dai = dai_get(dai_cfg->type, dai_cfg->dai_index, DAI_CREAT); if (!dd->dai) { comp_err(dev, "dai_get() failed to create DAI."); @@ -479,6 +533,7 @@ int dai_common_new(struct dai_data *dd, struct comp_dev *dev, dir = dai_cfg->direction == SOF_IPC_STREAM_PLAYBACK ? SOF_DMA_DIR_MEM_TO_DEV : SOF_DMA_DIR_DEV_TO_MEM; + dd->chan_index = -EINVAL; dd->dma = sof_dma_get(dir, dd->dai->dma_caps, dd->dai->dma_dev, SOF_DMA_ACCESS_SHARED); if (!dd->dma) { dai_put(dd->dai); @@ -490,7 +545,17 @@ int dai_common_new(struct dai_data *dd, struct comp_dev *dev, dma_sg_init(&dd->config.elem_array); dd->xrun = 0; - dd->chan = NULL; + +#ifdef CONFIG_SOF_USERSPACE_LL + /* + * copier_dai_create() uses mod_zalloc() to allocate + * the 'dd' dai data object and does not set dd->alloc_ctx. + * If LL is run in user-space, assign the 'heap' here. + */ + dd->alloc_ctx.heap = sof_sys_user_heap_get(); +#else + dd->alloc_ctx.heap = NULL; +#endif /* I/O performance init, keep it last so the function does not reach this in case * of return on error, so that we do not waste a slot @@ -525,27 +590,30 @@ int dai_common_new(struct dai_data *dd, struct comp_dev *dev, /* ignore perf meas init on case of other dai types */ if (perf_type != IO_PERF_INVALID_ID) { struct io_perf_data_item init_data = {perf_type, - cpu_get_id(), + dai_cfg->dai_index, perf_dir, IO_PERF_POWERED_UP_ENABLED, IO_PERF_D0IX_POWER_MODE, 0, 0, 0 }; - io_perf_monitor_init_data(&dd->io_perf_bytes_count, &init_data); + io_perf_monitor_init_data(&dd->io_perf_dai_byte_count, &init_data); } #endif return 0; } -static struct comp_dev *dai_new(const struct comp_driver *drv, - const struct comp_ipc_config *config, - const void *spec) +__cold static struct comp_dev *dai_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec) { struct comp_dev *dev; const struct ipc_config_dai *dai_cfg = spec; struct dai_data *dd; + struct k_heap *heap = NULL; int ret; + assert_can_be_cold(); + comp_cl_dbg(&comp_dai, "dai_new()"); dev = comp_alloc(drv, sizeof(*dev)); @@ -554,10 +622,12 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, dev->ipc_config = *config; - dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); + dd = sof_heap_alloc(heap, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*dd), 0); if (!dd) goto e_data; + memset(dd, 0, sizeof(*dd)); + comp_set_drvdata(dev, dd); ret = dai_common_new(dd, dev, dai_cfg); @@ -571,24 +641,26 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, return dev; error: - rfree(dd); + sof_heap_free(heap, dd); e_data: - rfree(dev); + comp_free_device(dev); return NULL; } -void dai_common_free(struct dai_data *dd) +__cold void dai_common_free(struct dai_data *dd) { + assert_can_be_cold(); + #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS - io_perf_monitor_release_slot(dd->io_perf_bytes_count); + io_perf_monitor_release_slot(dd->io_perf_dai_byte_count); #endif if (dd->group) dai_group_put(dd->group); - if (dd->chan) { - dma_release_channel(dd->dma->z_dev, dd->chan->index); - dd->chan->dev_data = NULL; + if (dd->chan_index >= 0) { + sof_dma_release_channel(dd->dma, dd->chan_index); + dd->chan_index = -EINVAL; } sof_dma_put(dd->dma); @@ -597,29 +669,32 @@ void dai_common_free(struct dai_data *dd) dai_put(dd->dai); - rfree(dd->dai_spec_config); + sof_heap_free(dd->alloc_ctx.heap, dd->dai_spec_config); } -static void dai_free(struct comp_dev *dev) +__cold static void dai_free(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); + assert_can_be_cold(); + if (dd->group) notifier_unregister(dev, dd->group, NOTIFIER_ID_DAI_TRIGGER); dai_common_free(dd); - rfree(dd); - rfree(dev); + /* heap is NULL to match what is passed in dai_new() */ + sof_heap_free(NULL, dd); + comp_free_device(dev); } int dai_common_get_hw_params(struct dai_data *dd, struct comp_dev *dev, - struct sof_ipc_stream_params *params, int dir) + struct sof_ipc_stream_params *params, int dir) { struct dai_config cfg; int ret; - comp_dbg(dev, "dai_common_get_hw_params()"); + comp_dbg(dev, "entry"); ret = dai_config_get(dd->dai->dev, &cfg, dir); if (ret) @@ -640,12 +715,14 @@ int dai_common_get_hw_params(struct dai_data *dd, struct comp_dev *dev, return ret; } -static int dai_comp_get_hw_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params, - int dir) +__cold static int dai_comp_get_hw_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params, + int dir) { struct dai_data *dd = comp_get_drvdata(dev); + assert_can_be_cold(); + return dai_common_get_hw_params(dd, dev, params, dir); } @@ -659,7 +736,7 @@ static int dai_verify_params(struct dai_data *dd, struct comp_dev *dev, ret = dai_common_get_hw_params(dd, dev, &hw_params, params->direction); if (ret < 0) { - comp_err(dev, "dai_verify_params failed ret %d", ret); + comp_err(dev, "failed ret %d", ret); return ret; } @@ -708,6 +785,7 @@ static int dai_get_dma_slot(struct dai_data *dd, struct comp_dev *dev, uint32_t switch (cfg.type) { case DAI_IMX_SAI: case DAI_IMX_ESAI: + case DAI_IMX_MICFIL: *slot = (hs & GENMASK(15, 8)) >> 8; break; default: @@ -773,7 +851,7 @@ static int dai_set_sg_config(struct dai_data *dd, struct comp_dev *dev, uint32_t comp_dbg(dev, "fifo 0x%x", fifo); - err = dma_get_attribute(dd->dma->z_dev, DMA_ATTR_MAX_BLOCK_COUNT, &max_block_count); + err = sof_dma_get_attribute(dd->dma, DMA_ATTR_MAX_BLOCK_COUNT, &max_block_count); if (err < 0) { comp_err(dev, "can't get max block count, err = %d", err); @@ -801,7 +879,7 @@ static int dai_set_sg_config(struct dai_data *dd, struct comp_dev *dev, uint32_t } while (--max_block_count > 0); } - err = dma_sg_alloc(&config->elem_array, SOF_MEM_ZONE_RUNTIME, + err = dma_sg_alloc(dd->alloc_ctx.heap, &config->elem_array, SOF_MEM_FLAG_USER, config->direction, period_count, period_bytes, @@ -825,10 +903,11 @@ static int dai_set_dma_config(struct dai_data *dd, struct comp_dev *dev) struct dma_block_config *prev = NULL; int i; - comp_dbg(dev, "dai_set_dma_config()"); + comp_dbg(dev, "entry"); - dma_cfg = rballoc(SOF_MEM_FLAG_COHERENT, SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, - sizeof(struct dma_config)); + dma_cfg = sof_heap_alloc(dd->alloc_ctx.heap, + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT | SOF_MEM_FLAG_DMA, + sizeof(struct dma_config), 0); if (!dma_cfg) { comp_err(dev, "dma_cfg allocation failed"); return -ENOMEM; @@ -857,10 +936,11 @@ static int dai_set_dma_config(struct dai_data *dd, struct comp_dev *dev) else dma_cfg->dma_slot = config->src_dev; - dma_block_cfg = rballoc(SOF_MEM_FLAG_COHERENT, SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, - sizeof(struct dma_block_config) * dma_cfg->block_count); + dma_block_cfg = sof_heap_alloc(dd->alloc_ctx.heap, + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT | SOF_MEM_FLAG_DMA, + sizeof(struct dma_block_config) * dma_cfg->block_count, 0); if (!dma_block_cfg) { - rfree(dma_cfg); + sof_heap_free(dd->alloc_ctx.heap, dma_cfg); comp_err(dev, "dma_block_config allocation failed"); return -ENOMEM; } @@ -906,10 +986,10 @@ static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, uint32_t buffer_size; uint32_t buffer_size_preferred; uint32_t addr_align; - uint32_t align; + uint32_t align = 0; int err; - comp_dbg(dev, "dai_set_dma_buffer()"); + comp_dbg(dev, "entry"); if (dev->direction == SOF_IPC_STREAM_PLAYBACK) dd->local_buffer = comp_dev_get_first_data_producer(dev); @@ -929,14 +1009,14 @@ static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, return -EINVAL; } - err = dma_get_attribute(dd->dma->z_dev, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, &addr_align); + err = sof_dma_get_attribute(dd->dma, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, &addr_align); if (err < 0) { comp_err(dev, "can't get dma buffer addr align, err = %d", err); return err; } - err = dma_get_attribute(dd->dma->z_dev, DMA_ATTR_BUFFER_SIZE_ALIGNMENT, &align); + err = sof_dma_get_attribute(dd->dma, DMA_ATTR_BUFFER_SIZE_ALIGNMENT, &align); if (err < 0 || !align) { comp_err(dev, "no valid dma align, err = %d, align = %u", err, align); @@ -994,8 +1074,9 @@ static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, return err; } } else { - dd->dma_buffer = buffer_alloc_range(buffer_size_preferred, buffer_size, - SOF_MEM_CAPS_DMA, 0, addr_align, false); + dd->dma_buffer = buffer_alloc_range(&dd->alloc_ctx, buffer_size_preferred, buffer_size, + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA, + addr_align, BUFFER_USAGE_NOT_SHARED); if (!dd->dma_buffer) { comp_err(dev, "failed to alloc dma buffer"); return -ENOMEM; @@ -1081,8 +1162,8 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, if (err < 0) { buffer_free(dd->dma_buffer); dd->dma_buffer = NULL; - dma_sg_free(&config->elem_array); - rfree(dd->z_config); + dma_sg_free(dd->alloc_ctx.heap, &config->elem_array); + sof_heap_free(dd->alloc_ctx.heap, dd->z_config); dd->z_config = NULL; } @@ -1093,7 +1174,7 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params { struct dai_data *dd = comp_get_drvdata(dev); - comp_dbg(dev, "dai_params()"); + comp_dbg(dev, "entry"); return dai_common_params(dd, dev, params); } @@ -1113,9 +1194,9 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev) return -EINVAL; } - if (dd->chan) { + if (dd->chan_index >= 0) { comp_info(dev, "dma channel index %d already configured", - dd->chan->index); + dd->chan_index); return 0; } @@ -1129,18 +1210,14 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev) } /* get DMA channel */ - channel = dma_request_channel(dd->dma->z_dev, &channel); - if (channel < 0) { - comp_err(dev, "dma_request_channel() failed"); - dd->chan = NULL; - return -EIO; + dd->chan_index = sof_dma_request_channel(dd->dma, channel); + if (dd->chan_index < 0) { + comp_err(dev, "dma_request_channel() failed ch %d ret %d", channel, dd->chan_index); + return dd->chan_index; } - dd->chan = &dd->dma->chan[channel]; - dd->chan->dev_data = dd; - comp_dbg(dev, "new configured dma channel index %d", - dd->chan->index); + dd->chan_index); return 0; } @@ -1151,8 +1228,8 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev) dd->total_data_processed = 0; - if (!dd->chan) { - comp_err(dev, "Missing dd->chan."); + if (dd->chan_index < 0) { + comp_err(dev, "Missing dd->chan_index."); comp_set_state(dev, COMP_TRIGGER_RESET); return -EINVAL; } @@ -1173,7 +1250,7 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev) return 0; } - ret = dma_config(dd->chan->dma->z_dev, dd->chan->index, dd->z_config); + ret = sof_dma_config(dd->dma, dd->chan_index, dd->z_config); if (ret < 0) comp_set_state(dev, COMP_TRIGGER_RESET); @@ -1185,7 +1262,7 @@ static int dai_prepare(struct comp_dev *dev) struct dai_data *dd = comp_get_drvdata(dev); int ret; - comp_dbg(dev, "dai_prepare()"); + comp_dbg(dev, "entry"); ret = dai_common_config_prepare(dd, dev); if (ret < 0) @@ -1212,10 +1289,10 @@ void dai_common_reset(struct dai_data *dd, struct comp_dev *dev) if (!dd->delayed_dma_stop) dai_dma_release(dd, dev); - dma_sg_free(&config->elem_array); + dma_sg_free(dd->alloc_ctx.heap, &config->elem_array); if (dd->z_config) { - rfree(dd->z_config->head_block); - rfree(dd->z_config); + sof_heap_free(dd->alloc_ctx.heap, dd->z_config->head_block); + sof_heap_free(dd->alloc_ctx.heap, dd->z_config); dd->z_config = NULL; } @@ -1233,7 +1310,7 @@ static int dai_reset(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); - comp_dbg(dev, "dai_reset()"); + comp_dbg(dev, "entry"); dai_common_reset(dd, dev); @@ -1260,7 +1337,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, /* only start the DAI if we are not XRUN handling */ if (dd->xrun == 0) { - ret = dma_start(dd->chan->dma->z_dev, dd->chan->index); + ret = sof_dma_start(dd->dma, dd->chan_index); if (ret < 0) return ret; @@ -1298,16 +1375,16 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, /* only start the DAI if we are not XRUN handling */ if (dd->xrun == 0) { /* recover valid start position */ - ret = dma_stop(dd->chan->dma->z_dev, dd->chan->index); + ret = sof_dma_stop(dd->dma, dd->chan_index); if (ret < 0) return ret; /* dma_config needed after stop */ - ret = dma_config(dd->chan->dma->z_dev, dd->chan->index, dd->z_config); + ret = sof_dma_config(dd->dma, dd->chan_index, dd->z_config); if (ret < 0) return ret; - ret = dma_start(dd->chan->dma->z_dev, dd->chan->index); + ret = sof_dma_start(dd->dma, dd->chan_index); if (ret < 0) return ret; @@ -1335,11 +1412,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, * as soon as possible. */ #if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE - ret = dma_stop(dd->chan->dma->z_dev, dd->chan->index); + ret = sof_dma_stop(dd->dma, dd->chan_index); dai_trigger_op(dd->dai, cmd, dev->direction); #else dai_trigger_op(dd->dai, cmd, dev->direction); - ret = dma_stop(dd->chan->dma->z_dev, dd->chan->index); + ret = sof_dma_stop(dd->dma, dd->chan_index); if (ret) { comp_warn(dev, "dma was stopped earlier"); ret = 0; @@ -1349,11 +1426,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, case COMP_TRIGGER_PAUSE: comp_dbg(dev, "PAUSE"); #if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE - ret = dma_suspend(dd->chan->dma->z_dev, dd->chan->index); + ret = sof_dma_suspend(dd->dma, dd->chan_index); dai_trigger_op(dd->dai, cmd, dev->direction); #else dai_trigger_op(dd->dai, cmd, dev->direction); - ret = dma_suspend(dd->chan->dma->z_dev, dd->chan->index); + ret = sof_dma_suspend(dd->dma, dd->chan_index); #endif break; case COMP_TRIGGER_PRE_START: @@ -1424,7 +1501,7 @@ int dai_common_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd) irq_local_disable(irq_flags); notifier_event(group, NOTIFIER_ID_DAI_TRIGGER, - BIT(cpu_get_id()), NULL, 0); + NOTIFIER_TARGET_CORE_LOCAL, NULL, 0); irq_local_enable(irq_flags); /* return error of last trigger */ @@ -1442,8 +1519,34 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd) return dai_common_trigger(dd, dev, cmd); } -/* report xrun occurrence */ -static void dai_report_xrun(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes) +/** + * Get status from the DMA driver. + * + * After status call, a check for xrun condition is done and + * depending on configuration, a xrun report is optionally sent. + * See also xrun reporting done in dai_report_reload_xrun(). + */ +static int dai_get_status(struct comp_dev *dev, struct dai_data *dd, struct dma_status *stat) +{ + int ret = sof_dma_get_status(dd->dma, dd->chan_index, stat); +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE + if (ret == -EPIPE && !dd->xrun_notification_sent) { + dd->xrun_notification_sent = send_copier_gateway_xrun_notif_msg + (dev->pipeline->pipeline_id, dev->direction); + } else if (!ret) { + dd->xrun_notification_sent = false; + } +#endif + return ret; +} + +/** + * Report xrun occurrence after DAI DMA driver reports + * an error for a reload attempt of 'bytes' of data. + * + * See also xrun detection done in dai_get_status(). + */ +static void dai_report_reload_xrun(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes) { if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { comp_err(dev, "underrun due to no data available"); @@ -1479,7 +1582,7 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, struct dma_status stat; /* get data sizes from DMA */ - ret = dma_get_status(dd[i]->chan->dma->z_dev, dd[i]->chan->index, &stat); + ret = dai_get_status(dev, dd[i], &stat); switch (ret) { case 0: break; @@ -1496,6 +1599,9 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, return ret; } + if (dd[i]->dma->plat_data.caps & SOF_DMA_CAP_HDA) + audio_stream_sync_to_hw(&dd[i]->dma_buffer->stream, &stat); + avail_bytes = MIN(avail_bytes, stat.pending_length); free_bytes = MIN(free_bytes, stat.free); } @@ -1527,9 +1633,9 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, #endif for (i = 0; i < num_endpoints; i++) { - ret = dma_reload(dd[i]->chan->dma->z_dev, dd[i]->chan->index, 0, 0, 0); + ret = sof_dma_reload(dd[i]->dma, dd[i]->chan_index, 0); if (ret < 0) { - dai_report_xrun(dd[i], dev, 0); + dai_report_reload_xrun(dd[i], dev, 0); return ret; } } @@ -1553,12 +1659,12 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, status = dai_dma_multi_endpoint_cb(dd[i], dev, frames, multi_endpoint_buffer); if (status == SOF_DMA_CB_STATUS_END) - dma_stop(dd[i]->chan->dma->z_dev, dd[i]->chan->index); + sof_dma_stop(dd[i]->dma, dd[i]->chan_index); 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); + ret = sof_dma_reload(dd[i]->dma, dd[i]->chan_index, copy_bytes); if (ret < 0) { - dai_report_xrun(dd[i], dev, copy_bytes); + dai_report_reload_xrun(dd[i], dev, copy_bytes); return ret; } @@ -1610,23 +1716,35 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun int ret; /* get data sizes from DMA */ - ret = dma_get_status(dd->chan->dma->z_dev, dd->chan->index, &stat); + ret = dai_get_status(dev, dd, &stat); switch (ret) { case 0: break; case -EPIPE: /* DMA status can return -EPIPE and current status content if xrun occurs */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) - comp_dbg(dev, "dma_get_status() underrun occurred, ret = %u", + comp_dbg(dev, "dma_get_status() underrun occurred, ret = %d", ret); else - comp_dbg(dev, "dma_get_status() overrun occurred, ret = %u", + comp_dbg(dev, "dma_get_status() overrun occurred, ret = %d", ret); break; default: return ret; } + /* HDA DMA Write and Read Position registers are not cleared by hardware on + * dma_stop() or dma_start(). However, the dma_buffer is recreated after a reset + * with its w_ptr and r_ptr set to NULL. The w_ptr and r_ptr must be kept in sync + * with the hardware DMA Write and Read Positions. + * Other types of DMA clear their hardware Read/Write Positions upon dma_stop() + * or dma_start(). Additionally, some DMAs, such as GPDMA, do not populate + * dma_status::write_position and read_position. Therefore, synchronization is + * done here only for HDA DMA. + */ + if (dd->dma->plat_data.caps & SOF_DMA_CAP_HDA) + audio_stream_sync_to_hw(&dd->dma_buffer->stream, &stat); + avail_bytes = stat.pending_length; free_bytes = stat.free; @@ -1733,7 +1851,7 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun comp_warn(dev, "nothing to copy, src_frames: %u, sink_frames: %u", src_frames, sink_frames); #endif - dma_reload(dd->chan->dma->z_dev, dd->chan->index, 0, 0, 0); + sof_dma_reload(dd->dma, dd->chan_index, 0); return 0; } @@ -1743,11 +1861,11 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun comp_warn(dev, "dai trigger copy failed"); if (dai_dma_cb(dd, dev, copy_bytes, converter) == SOF_DMA_CB_STATUS_END) - dma_stop(dd->chan->dma->z_dev, dd->chan->index); + sof_dma_stop(dd->dma, dd->chan_index); - ret = dma_reload(dd->chan->dma->z_dev, dd->chan->index, 0, 0, copy_bytes); + ret = sof_dma_reload(dd->dma, dd->chan_index, copy_bytes); if (ret < 0) { - dai_report_xrun(dd, dev, copy_bytes); + dai_report_reload_xrun(dd, dev, copy_bytes); return ret; } @@ -1783,7 +1901,7 @@ int dai_common_ts_config_op(struct dai_data *dd, struct comp_dev *dev) struct dai_ts_cfg *cfg = &dd->ts_config; comp_dbg(dev, "dai_ts_config()"); - if (!dd->chan) { + if (dd->chan_index < 0) { comp_err(dev, "No DMA channel information"); return -EINVAL; } @@ -1806,7 +1924,7 @@ int dai_common_ts_config_op(struct dai_data *dd, struct comp_dev *dev) 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_index = dd->chan_index; cfg->dma_chan_count = dd->dma->plat_data.channels; return dai_ts_config(dd->dai->dev, cfg); @@ -1895,12 +2013,15 @@ 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) +__cold +int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, struct bind_info *unbind_data) { struct ipc4_module_bind_unbind *bu; int buf_id; - bu = (struct ipc4_module_bind_unbind *)data; + assert_can_be_cold(); + + bu = unbind_data->ipc4_data; buf_id = IPC4_COMP_ID(bu->extension.r.src_queue, bu->extension.r.dst_queue); if (dd && dd->local_buffer) { @@ -1914,6 +2035,8 @@ int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, void *data) } #endif /* CONFIG_IPC_MAJOR_4 */ +DECLARE_TR_CTX(dai_comp_tr, SOF_UUID(dai_uuid), LOG_LEVEL_INFO); + static const struct comp_driver comp_dai = { .type = SOF_COMP_DAI, .uid = SOF_RT_UUID(dai_uuid), @@ -1943,7 +2066,7 @@ static SHARED_DATA struct comp_driver_info comp_dai_info = { UT_STATIC void sys_comp_dai_init(void) { - comp_register(platform_shared_get(&comp_dai_info, sizeof(comp_dai_info))); + comp_register(&comp_dai_info); } DECLARE_MODULE(sys_comp_dai_init); diff --git a/src/audio/data_blob.c b/src/audio/data_blob.c index 7e1bc11f1f17..94ea19e829a7 100644 --- a/src/audio/data_blob.c +++ b/src/audio/data_blob.c @@ -72,7 +72,7 @@ void *comp_get_data_blob(struct comp_data_blob_handler *blob_handler, /* Function returns new data blob if available */ if (comp_is_new_data_blob_available(blob_handler)) { - comp_dbg(blob_handler->dev, "comp_get_data_blob(): new data available"); + comp_dbg(blob_handler->dev, "new data available"); /* Free "old" data blob and set data to data_new pointer */ blob_handler->free(blob_handler->data); @@ -95,7 +95,7 @@ void *comp_get_data_blob(struct comp_data_blob_handler *blob_handler, * data blob it means that component hasn't got any config yet. * Function returns NULL in that case. */ - comp_warn(blob_handler->dev, "comp_get_data_blob(): blob_handler->data is not set."); + comp_warn(blob_handler->dev, "blob_handler->data is not set."); } if (size) @@ -110,7 +110,7 @@ bool comp_is_new_data_blob_available(struct comp_data_blob_handler { assert(blob_handler); - comp_dbg(blob_handler->dev, "comp_is_new_data_blob_available()"); + comp_dbg(blob_handler->dev, "entry"); /* New data blob is available when new data blob is allocated (data_new * is not NULL), and the component has received all required chunks of data @@ -128,6 +128,7 @@ bool comp_is_current_data_blob_valid(struct comp_data_blob_handler { return !!blob_handler->data; } +EXPORT_SYMBOL(comp_is_current_data_blob_valid); int comp_init_data_blob(struct comp_data_blob_handler *blob_handler, uint32_t size, const void *init_data) @@ -144,7 +145,7 @@ int comp_init_data_blob(struct comp_data_blob_handler *blob_handler, /* Data blob allocation */ blob_handler->data = blob_handler->alloc(size); if (!blob_handler->data) { - comp_err(blob_handler->dev, "comp_init_data_blob(): model->data allocation failed"); + comp_err(blob_handler->dev, "model->data allocation failed"); return -ENOMEM; } @@ -184,25 +185,25 @@ int comp_data_blob_set(struct comp_data_blob_handler *blob_handler, #if CONFIG_IPC_MAJOR_3 if (cdata->cmd != SOF_CTRL_CMD_BINARY) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), illegal control command"); + comp_err(blob_handler->dev, "illegal control command"); return -EINVAL; } #endif - comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd() pos = %d, fragment size = %zu", + comp_dbg(blob_handler->dev, "pos = %d, fragment size = %zu", pos, fragment_size); /* Check that there is no work-in-progress previous request */ if (blob_handler->data_new && (pos == MODULE_CFG_FRAGMENT_FIRST || pos == MODULE_CFG_FRAGMENT_SINGLE)) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), busy with previous request"); + comp_err(blob_handler->dev, "busy with previous request"); return -EBUSY; } /* In single blob mode the component can not be reconfigured if the component is active. */ if (blob_handler->single_blob && blob_handler->dev->state == COMP_STATE_ACTIVE) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), on the fly updates forbidden in single blob mode"); + comp_err(blob_handler->dev, "on the fly updates forbidden in single blob mode"); return -EBUSY; } @@ -242,7 +243,7 @@ int comp_data_blob_set(struct comp_data_blob_handler *blob_handler, if (!blob_handler->data_new) { blob_handler->data_new = blob_handler->alloc(data_offset_size); if (!blob_handler->data_new) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): blob_handler->data_new allocation failed."); + comp_err(blob_handler->dev, "blob_handler->data_new allocation failed."); return -ENOMEM; } } @@ -254,7 +255,7 @@ int comp_data_blob_set(struct comp_data_blob_handler *blob_handler, /* return an error in case when we do not have allocated memory for model data */ if (!blob_handler->data_new) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): buffer not allocated"); + comp_err(blob_handler->dev, "buffer not allocated"); return -ENOMEM; } @@ -262,20 +263,20 @@ int comp_data_blob_set(struct comp_data_blob_handler *blob_handler, blob_handler->new_data_size - blob_handler->data_pos, fragment, fragment_size); if (ret) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): failed to copy fragment"); + comp_err(blob_handler->dev, "failed to copy fragment"); return ret; } blob_handler->data_pos += fragment_size; if (pos == MODULE_CFG_FRAGMENT_SINGLE || pos == MODULE_CFG_FRAGMENT_LAST) { - comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd(): final package received"); + comp_dbg(blob_handler->dev, "final package received"); if (blob_handler->validator) { - comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd(): validating new data..."); + comp_dbg(blob_handler->dev, "validating new data..."); ret = blob_handler->validator(blob_handler->dev, blob_handler->data_new, blob_handler->new_data_size); if (ret < 0) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): new data is invalid! discarding it..."); + comp_err(blob_handler->dev, "new data is invalid! discarding it..."); blob_handler->free(blob_handler->data_new); blob_handler->data_new = NULL; return ret; @@ -326,9 +327,17 @@ int ipc4_comp_data_blob_set(struct comp_data_blob_handler *blob_handler, assert(blob_handler); comp_dbg(blob_handler->dev, - "ipc4_comp_data_blob_set(): data_offset = %d", + "data_offset = %d", data_offset); + /* Reject a new first_block mid-transfer: reusing stale data_new while + * overwriting new_data_size defeats the memcpy_s bound (heap overflow). + */ + if (blob_handler->data_new && first_block) { + comp_err(blob_handler->dev, "busy with previous request"); + return -EBUSY; + } + /* in case when the current package is the first, we should allocate * memory for whole model data */ @@ -352,7 +361,7 @@ int ipc4_comp_data_blob_set(struct comp_data_blob_handler *blob_handler, if (!blob_handler->data_new) { comp_err(blob_handler->dev, - "ipc4_comp_data_blob_set(): blob_handler allocation failed!"); + "blob_handler allocation failed!"); return -ENOMEM; } } @@ -364,8 +373,16 @@ int ipc4_comp_data_blob_set(struct comp_data_blob_handler *blob_handler, valid_data_size = last_block ? data_offset : MAILBOX_DSPBOX_SIZE; ret = memcpy_s((char *)blob_handler->data_new, - valid_data_size, data, valid_data_size); - assert(!ret); + blob_handler->new_data_size, data, valid_data_size); + if (ret) { + comp_err(blob_handler->dev, "failed to copy fragment"); + blob_handler->free(blob_handler->data_new); + blob_handler->data_new = NULL; + blob_handler->new_data_size = 0; + blob_handler->data_pos = 0; + blob_handler->data_ready = false; + return ret; + } blob_handler->data_pos += valid_data_size; } else { @@ -374,13 +391,13 @@ int ipc4_comp_data_blob_set(struct comp_data_blob_handler *blob_handler, */ if (!blob_handler->data_new) { comp_err(blob_handler->dev, - "ipc4_comp_data_blob_set(): Buffer not allocated!"); + "Buffer not allocated!"); return -ENOMEM; } if (blob_handler->data_pos != data_offset) { comp_err(blob_handler->dev, - "ipc4_comp_data_blob_set(): Wrong data offset received!"); + "Wrong data offset received!"); return -EINVAL; } @@ -390,15 +407,24 @@ int ipc4_comp_data_blob_set(struct comp_data_blob_handler *blob_handler, valid_data_size = blob_handler->new_data_size - data_offset; ret = memcpy_s((char *)blob_handler->data_new + data_offset, - valid_data_size, data, valid_data_size); - assert(!ret); + blob_handler->new_data_size - data_offset, + data, valid_data_size); + if (ret) { + comp_err(blob_handler->dev, "failed to copy fragment"); + blob_handler->free(blob_handler->data_new); + blob_handler->data_new = NULL; + blob_handler->new_data_size = 0; + blob_handler->data_pos = 0; + blob_handler->data_ready = false; + return ret; + } blob_handler->data_pos += valid_data_size; } if (last_block) { comp_dbg(blob_handler->dev, - "ipc4_comp_data_blob_set(): final package received"); + "final package received"); /* If component state is READY we can omit old * configuration immediately. When in playback/capture @@ -440,13 +466,13 @@ int comp_data_blob_set_cmd(struct comp_data_blob_handler *blob_handler, assert(blob_handler); - comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd() msg_index = %d, num_elems = %d, remaining = %d ", + comp_dbg(blob_handler->dev, "msg_index = %d, num_elems = %d, remaining = %d ", cdata->msg_index, cdata->num_elems, cdata->elems_remaining); /* Check that there is no work-in-progress previous request */ if (blob_handler->data_new && cdata->msg_index == 0) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), busy with previous request"); + comp_err(blob_handler->dev, "busy with previous request"); return -EBUSY; } @@ -455,7 +481,7 @@ int comp_data_blob_set_cmd(struct comp_data_blob_handler *blob_handler, */ if (blob_handler->single_blob && blob_handler->dev->state == COMP_STATE_ACTIVE) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), on the fly updates forbidden in single blob mode"); + comp_err(blob_handler->dev, "on the fly updates forbidden in single blob mode"); return -EBUSY; } @@ -496,7 +522,7 @@ int comp_data_blob_set_cmd(struct comp_data_blob_handler *blob_handler, blob_handler->data_new = blob_handler->alloc(cdata->data->size); if (!blob_handler->data_new) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): blob_handler->data_new allocation failed."); + comp_err(blob_handler->dev, "blob_handler->data_new allocation failed."); return -ENOMEM; } } @@ -510,7 +536,7 @@ int comp_data_blob_set_cmd(struct comp_data_blob_handler *blob_handler, * model data */ if (!blob_handler->data_new) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): buffer not allocated"); + comp_err(blob_handler->dev, "buffer not allocated"); return -ENOMEM; } @@ -522,14 +548,14 @@ int comp_data_blob_set_cmd(struct comp_data_blob_handler *blob_handler, blob_handler->data_pos += cdata->num_elems; if (!cdata->elems_remaining) { - comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd(): final package received"); + comp_dbg(blob_handler->dev, "final package received"); if (blob_handler->validator) { - comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd(): validating new data blob"); + comp_dbg(blob_handler->dev, "validating new data blob"); ret = blob_handler->validator(blob_handler->dev, blob_handler->data_new, blob_handler->new_data_size); if (ret < 0) { - comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): new data blob invalid, discarding"); + comp_err(blob_handler->dev, "new data blob invalid, discarding"); blob_handler->free(blob_handler->data_new); blob_handler->data_new = NULL; return ret; @@ -580,7 +606,7 @@ int comp_data_blob_get_cmd(struct comp_data_blob_handler *blob_handler, return -EINVAL; } - comp_dbg(blob_handler->dev, "comp_data_blob_get_cmd() msg_index = %d, num_elems = %d, remaining = %d ", + comp_dbg(blob_handler->dev, "msg_index = %d, num_elems = %d, remaining = %d ", cdata->msg_index, cdata->num_elems, cdata->elems_remaining); @@ -589,7 +615,7 @@ int comp_data_blob_get_cmd(struct comp_data_blob_handler *blob_handler, /* reset data_pos variable in case of copying first element */ if (!cdata->msg_index) { blob_handler->data_pos = 0; - comp_dbg(blob_handler->dev, "comp_data_blob_get_cmd() model data_size = 0x%x", + comp_dbg(blob_handler->dev, "model data_size = 0x%x", blob_handler->data_size); } @@ -597,11 +623,23 @@ int comp_data_blob_get_cmd(struct comp_data_blob_handler *blob_handler, * required size */ if (cdata->num_elems > size) { - comp_err(blob_handler->dev, "comp_data_blob_get_cmd(): invalid cdata->num_elems %d", + comp_err(blob_handler->dev, "invalid cdata->num_elems %d", cdata->num_elems); return -EINVAL; } + /* Bound data_pos against data_size: host-controlled num_elems + * advances it per fragment and could leak adjacent heap. + */ + if (blob_handler->data_pos >= blob_handler->data_size || + cdata->num_elems > blob_handler->data_size - blob_handler->data_pos) { + comp_err(blob_handler->dev, + "out of bounds read: pos %u elems %u size %u", + blob_handler->data_pos, cdata->num_elems, + blob_handler->data_size); + return -EINVAL; + } + /* copy required size of data */ ret = memcpy_s(cdata->data->data, size, (char *)blob_handler->data + blob_handler->data_pos, @@ -612,7 +650,7 @@ int comp_data_blob_get_cmd(struct comp_data_blob_handler *blob_handler, cdata->data->size = blob_handler->data_size; blob_handler->data_pos += cdata->num_elems; } else { - comp_warn(blob_handler->dev, "comp_data_blob_get_cmd(): model->data not allocated yet."); + comp_warn(blob_handler->dev, "model->data not allocated yet."); cdata->data->abi = SOF_ABI_VERSION; cdata->data->size = 0; } @@ -623,12 +661,13 @@ EXPORT_SYMBOL(comp_data_blob_get_cmd); static void *default_alloc(size_t size) { - return rballoc(0, SOF_MEM_CAPS_RAM, size); + return sof_heap_alloc(sof_sys_user_heap_get(), + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_LARGE_BUFFER, size, 0); } static void default_free(void *buf) { - rfree(buf); + sof_heap_free(sof_sys_user_heap_get(), buf); } struct comp_data_blob_handler * @@ -638,12 +677,13 @@ comp_data_blob_handler_new_ext(struct comp_dev *dev, bool single_blob, { struct comp_data_blob_handler *handler; - comp_dbg(dev, "comp_data_blob_handler_new_ext()"); + comp_dbg(dev, "entry"); - handler = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(struct comp_data_blob_handler)); + handler = sof_heap_alloc(sof_sys_user_heap_get(), SOF_MEM_FLAG_USER, + sizeof(struct comp_data_blob_handler), 0); if (handler) { + memset(handler, 0, sizeof(*handler)); handler->dev = dev; handler->single_blob = single_blob; handler->alloc = alloc ? alloc : default_alloc; @@ -661,6 +701,6 @@ void comp_data_blob_handler_free(struct comp_data_blob_handler *blob_handler) comp_free_data_blob(blob_handler); - rfree(blob_handler); + sof_heap_free(sof_sys_user_heap_get(), blob_handler); } EXPORT_SYMBOL(comp_data_blob_handler_free); diff --git a/src/audio/dcblock/CMakeLists.txt b/src/audio/dcblock/CMakeLists.txt index a433b0629eeb..7927b6913a42 100644 --- a/src/audio/dcblock/CMakeLists.txt +++ b/src/audio/dcblock/CMakeLists.txt @@ -1,10 +1,16 @@ +if(CONFIG_COMP_DCBLOCK STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/dcblock_llext) + add_dependencies(app dcblock) + return() +endif() + add_local_sources(sof dcblock.c) add_local_sources(sof dcblock_generic.c) add_local_sources(sof dcblock_hifi3.c) add_local_sources(sof dcblock_hifi4.c) if(CONFIG_IPC_MAJOR_3) - add_local_sources(sof dcblock_ipc3.c) + add_local_sources(sof dcblock_ipc3.c) elseif(CONFIG_IPC_MAJOR_4) - add_local_sources(sof dcblock_ipc4.c) + add_local_sources(sof dcblock_ipc4.c) endif() diff --git a/src/audio/dcblock/Kconfig b/src/audio/dcblock/Kconfig index af6eae1c3c7e..e67708ed9ad1 100644 --- a/src/audio/dcblock/Kconfig +++ b/src/audio/dcblock/Kconfig @@ -2,6 +2,7 @@ config COMP_DCBLOCK tristate "DC Blocking Filter component" + default m if LIBRARY_DEFAULT_MODULAR default y help Select for DC Blocking Filter component. This component filters out diff --git a/src/audio/dcblock/README.md b/src/audio/dcblock/README.md new file mode 100644 index 000000000000..4cbae3402540 --- /dev/null +++ b/src/audio/dcblock/README.md @@ -0,0 +1,23 @@ +# DC Block Architecture + +This directory contains the DC Blocking filter. + +## Overview + +The DC Blocker removes the DC offset (0 Hz component) from an audio signal, avoiding speaker damage and maximizing dynamic range. + +## Architecture Diagram + +```mermaid +graph LR + In[Audio Input] --> IIR[High-pass IIR Filter] + IIR --> Out[DC-Free Audio Output] +``` + +## Configuration and Scripts + +- **Kconfig**: Enables the DC Blocking Filter component (`COMP_DCBLOCK`) which filters out DC offsets often from a microphone's output. Includes selectable HIFI optimization levels (Max, HIFI4, HIFI3, Generic). +- **CMakeLists.txt**: Manages local build sources including generic and HIFI optimized versions (`dcblock_generic.c`, `dcblock_hifi3.c`, etc.) and determines the valid IPC abstraction (`dcblock_ipc3.c` vs `dcblock_ipc4.c`). Supports loadable extension generation via `llext`. +- **dcblock.toml**: Topology parameters for the DCBlock module. Defines UUID, pins, and memory limits for IPC integration. +- **Topology (.conf)**: Derived from `tools/topology/topology2/include/components/dcblock.conf`, it defines the `dcblock` widget object for topology generation. It defaults to type `effect` with UUID `af:ef:09:b8:81:56:b1:42:9e:d6:04:bb:01:2d:d3:84` and enforces input/output pins configuration. +- **MATLAB Tuning (`tune/`)**: The included `.m` scripts (e.g., `sof_example_dcblock.m`) automatically determine the optimal R coefficients to achieve various high-pass cutoff frequencies (-3dB point) across supported sample rates (like 16kHz and 48kHz). These coefficients are then packed into configuration blobs. diff --git a/src/audio/dcblock/dcblock.c b/src/audio/dcblock/dcblock.c index 4d4888d8b4f8..15e6139b7a89 100644 --- a/src/audio/dcblock/dcblock.c +++ b/src/audio/dcblock/dcblock.c @@ -36,8 +36,6 @@ LOG_MODULE_REGISTER(dcblock, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(dcblock); -DECLARE_TR_CTX(dcblock_tr, SOF_UUID(dcblock_uuid), LOG_LEVEL_INFO); - /** * \brief Sets the DC Blocking filter in pass through mode. * The frequency response of a DCB filter is: @@ -48,7 +46,7 @@ static void dcblock_set_passthrough(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "dcblock_set_passthrough()"); + comp_info(mod->dev, "entry"); int i; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) @@ -82,14 +80,11 @@ static int dcblock_init(struct processing_module *mod) { struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; - struct module_config *ipc_dcblock = &md->cfg; struct comp_data *cd; - size_t bs = ipc_dcblock->size; - int ret; - comp_info(dev, "dcblock_init()"); + comp_info(dev, "entry"); - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -99,25 +94,12 @@ static int dcblock_init(struct processing_module *mod) /* component model data handler */ cd->model_handler = comp_data_blob_handler_new(dev); if (!cd->model_handler) { - comp_err(dev, "dcblock_init(): comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto err_cd; - } - - ret = comp_init_data_blob(cd->model_handler, bs, ipc_dcblock->data); - if (ret < 0) { - comp_err(dev, "dcblock_init(): comp_init_data_blob() failed with error: %d", ret); - goto err_model_cd; + comp_err(dev, "comp_data_blob_handler_new() failed."); + rfree(cd); + return -ENOMEM; } return 0; - -err_model_cd: - comp_data_blob_handler_free(cd->model_handler); - -err_cd: - rfree(cd); - return ret; } /** @@ -128,7 +110,7 @@ static int dcblock_free(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "dcblock_free()"); + comp_info(mod->dev, "entry"); comp_data_blob_handler_free(cd->model_handler); rfree(cd); return 0; @@ -172,7 +154,7 @@ static int dcblock_process(struct processing_module *mod, struct audio_stream *sink = output_buffers[0].data; uint32_t frames = input_buffers[0].size; - comp_dbg(mod->dev, "dcblock_process()"); + comp_dbg(mod->dev, "entry"); cd->dcblock_func(cd, source, sink, frames); @@ -192,14 +174,19 @@ static int dcblock_prepare(struct processing_module *mod, struct comp_data *cd = module_get_private_data(mod); struct comp_buffer *sourceb, *sinkb; struct comp_dev *dev = mod->dev; + size_t data_size; - comp_info(dev, "dcblock_prepare()"); - - dcblock_params(mod); + comp_info(dev, "entry"); /* DC Filter component will only ever have one source and sink buffer */ sourceb = comp_dev_get_first_data_producer(dev); sinkb = comp_dev_get_first_data_consumer(dev); + if (!sourceb || !sinkb) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } + + dcblock_params(mod); /* get source data format */ cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); @@ -210,15 +197,19 @@ static int dcblock_prepare(struct processing_module *mod, dcblock_init_state(cd); cd->dcblock_func = dcblock_find_func(cd->source_format); if (!cd->dcblock_func) { - comp_err(dev, "dcblock_prepare(), No processing function matching frames format"); + comp_err(dev, "No processing function matching frames format"); return -EINVAL; } - comp_info(mod->dev, "dcblock_prepare(), source_format=%d, sink_format=%d", + comp_info(mod->dev, "source_format=%d, sink_format=%d", cd->source_format, cd->sink_format); - cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - if (cd->config) + cd->config = comp_get_data_blob(cd->model_handler, &data_size, NULL); + /* dcblock_copy_coefficients() copies sizeof(R_coeffs) from the blob, so + * require the blob to actually hold that many bytes; fall back to + * passthrough otherwise instead of over-reading the blob + */ + if (cd->config && data_size >= sizeof(cd->R_coeffs)) dcblock_copy_coefficients(mod); else dcblock_set_passthrough(mod); @@ -235,7 +226,7 @@ static int dcblock_reset(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "dcblock_reset()"); + comp_info(mod->dev, "entry"); dcblock_init_state(cd); @@ -254,9 +245,6 @@ static const struct module_interface dcblock_interface = { .free = dcblock_free, }; -DECLARE_MODULE_ADAPTER(dcblock_interface, dcblock_uuid, dcblock_tr); -SOF_MODULE_INIT(dcblock, sys_comp_module_dcblock_interface_init); - #if CONFIG_COMP_DCBLOCK_MODULE /* modular: llext dynamic link */ @@ -264,14 +252,15 @@ SOF_MODULE_INIT(dcblock, sys_comp_module_dcblock_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_DCBLOCK 0xAF, 0xEF, 0x09, 0xB8, 0x81, 0x56, 0xB1, 0x42, 0xD6, 0x9E, \ - 0x04, 0xBB, 0x01, 0x2D, 0xD3, 0x84 - -SOF_LLEXT_MOD_ENTRY(dcblock, &dcblock_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("DCBLOCK", dcblock_llext_entry, 1, UUID_DCBLOCK, 40); + SOF_LLEXT_MODULE_MANIFEST("DCBLOCK", &dcblock_interface, 1, SOF_REG_UUID(dcblock), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(dcblock_tr, SOF_UUID(dcblock_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(dcblock_interface, dcblock_uuid, dcblock_tr); +SOF_MODULE_INIT(dcblock, sys_comp_module_dcblock_interface_init); + #endif diff --git a/src/audio/dcblock/dcblock.toml b/src/audio/dcblock/dcblock.toml index 8ad98ed54d5b..c752fd13a279 100644 --- a/src/audio/dcblock/dcblock.toml +++ b/src/audio/dcblock/dcblock.toml @@ -5,7 +5,7 @@ REM # DCblock module config [[module.entry]] name = "DCBLOCK" - uuid = "B809EFAF-5681-42B1-9ED6-04BB012DD384" + uuid = UUIDREG_STR_DCBLOCK affinity_mask = "0x1" instance_count = "40" domain_types = "0" diff --git a/src/audio/dcblock/dcblock_ipc4.c b/src/audio/dcblock/dcblock_ipc4.c index 534510841b85..c375d11ec042 100644 --- a/src/audio/dcblock/dcblock_ipc4.c +++ b/src/audio/dcblock/dcblock_ipc4.c @@ -30,7 +30,7 @@ int dcblock_get_ipc_config(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "dcblock_get_ipc_config()"); + comp_info(mod->dev, "entry"); return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); } @@ -44,7 +44,7 @@ int dcblock_set_ipc_config(struct processing_module *mod, { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "dcblock_set_ipc_config()"); + comp_info(mod->dev, "entry"); return comp_data_blob_set(cd->model_handler, pos, data_offset_size, fragment, fragment_size); @@ -56,11 +56,13 @@ void dcblock_params(struct processing_module *mod) struct comp_buffer *sinkb, *sourceb; struct comp_dev *dev = mod->dev; - comp_dbg(dev, "dcblock_params()"); + comp_dbg(dev, "entry"); ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); component_set_nearest_period_frames(dev, params->rate); + /* The caller has verified, that sink and source buffers are connected */ + sinkb = comp_dev_get_first_data_consumer(dev); ipc4_update_buffer_format(sinkb, &mod->priv.cfg.base_cfg.audio_fmt); diff --git a/src/audio/dcblock/tune/sof_dcblock_build_blob.m b/src/audio/dcblock/tune/sof_dcblock_build_blob.m index df4722cd8f10..41d0c1565ab3 100644 --- a/src/audio/dcblock/tune/sof_dcblock_build_blob.m +++ b/src/audio/dcblock/tune/sof_dcblock_build_blob.m @@ -27,7 +27,7 @@ %% Build Blob data_size = (num_of_coeffs)*4; -[abi_bytes, abi_size] = get_abi(data_size, ipc_ver); +[abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver); blob_size = data_size + abi_size; blob8 = uint8(zeros(1, blob_size)); diff --git a/src/audio/dcblock/tune/sof_example_dcblock.m b/src/audio/dcblock/tune/sof_example_dcblock.m index 139f812ee869..cf6d856656a3 100644 --- a/src/audio/dcblock/tune/sof_example_dcblock.m +++ b/src/audio/dcblock/tune/sof_example_dcblock.m @@ -37,9 +37,9 @@ function dcblock_blob_calculate(prm) tplg1_fn = sprintf("%s/topology1/m4/dcblock_coef_%s.m4", sof_tplg, prm.id); % Control Bytes File tplg2_fn = sprintf("%s/topology2/include/components/dcblock/%s.conf", sof_tplg, prm.id); % Use those files with sof-ctl to update the component's configuration -blob3_fn = sprintf("%s/ipc3/dcblock/coef_%s.blob", sof_ctl, prm.id); % Blob binary file +blob3_fn = sprintf("%s/ipc3/dcblock/coef_%s.bin", sof_ctl, prm.id); % Blob binary file alsa3_fn = sprintf("%s/ipc3/dcblock/coef_%s.txt", sof_ctl, prm.id); % ALSA CSV format file -blob4_fn = sprintf("%s/ipc4/dcblock/coef_%s.blob", sof_ctl, prm.id); % Blob binary file +blob4_fn = sprintf("%s/ipc4/dcblock/coef_%s.bin", sof_ctl, prm.id); % Blob binary file alsa4_fn = sprintf("%s/ipc4/dcblock/coef_%s.txt", sof_ctl, prm.id); % ALSA CSV format file endian = "little"; @@ -58,17 +58,17 @@ function dcblock_blob_calculate(prm) blob8_ipc4 = sof_dcblock_build_blob(R_coeffs, endian, 4); % Generate output files -tplg_write(tplg1_fn, blob8, "DCBLOCK", ... - "Exported with script sof_example_dcblock.m", ... - "cd tools/tune/dcblock; octave sof_example_dcblock.m"); +sof_tplg_write(tplg1_fn, blob8, "DCBLOCK", ... + "Exported with script sof_example_dcblock.m", ... + "cd tools/tune/dcblock; octave sof_example_dcblock.m"); sof_ucm_blob_write(blob3_fn, blob8); -alsactl_write(alsa3_fn, blob8); +sof_alsactl_write(alsa3_fn, blob8); -tplg2_write(tplg2_fn, blob8_ipc4, "dcblock_config", ... - "Exported with script sof_example_dcblock.m" , ... - "cd tools/tune/dcblock; octave sof_example_dcblock.m"); +sof_tplg2_write(tplg2_fn, blob8_ipc4, "dcblock_config", ... + "Exported with script sof_example_dcblock.m" , ... + "cd tools/tune/dcblock; octave sof_example_dcblock.m"); sof_ucm_blob_write(blob4_fn, blob8_ipc4); -alsactl_write(alsa4_fn, blob8_ipc4); +sof_alsactl_write(alsa4_fn, blob8_ipc4); % Plot Filter's Transfer Function and Step Response % As an example, plot the graphs of the first coefficient diff --git a/src/audio/drc/CMakeLists.txt b/src/audio/drc/CMakeLists.txt index 4e2751035ee5..883c32675b50 100644 --- a/src/audio/drc/CMakeLists.txt +++ b/src/audio/drc/CMakeLists.txt @@ -1,9 +1,19 @@ -add_local_sources(sof - drc.c - drc_generic.c - drc_hifi3.c - drc_hifi4.c - drc_math_generic.c - drc_math_hifi3.c - drc_log.c -) +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_COMP_DRC STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/drc_llext) + add_dependencies(app drc) +else() + add_local_sources(sof + drc.c + drc_generic.c + drc_hifi3.c + drc_hifi4.c + drc_math_generic.c + drc_math_hifi3.c + ) +endif() + +if(NOT CONFIG_COMP_DRC STREQUAL "n") + add_local_sources(sof drc_log.c) +endif() diff --git a/src/audio/drc/Kconfig b/src/audio/drc/Kconfig index 56e3c4d9e6fc..9d061c41ea67 100644 --- a/src/audio/drc/Kconfig +++ b/src/audio/drc/Kconfig @@ -9,7 +9,7 @@ config COMP_DRC select NUMBERS_NORM select MATH_EXP select COMP_BLOB - default n + default m if LIBRARY_DEFAULT_MODULAR help Select for Dynamic Range Compressor (DRC) component. A DRC can be used to reduce the volume of loud sounds and amplify silent sounds thus diff --git a/src/audio/drc/README.md b/src/audio/drc/README.md new file mode 100644 index 000000000000..a0a1eb8dd80a --- /dev/null +++ b/src/audio/drc/README.md @@ -0,0 +1,26 @@ +# Dynamic Range Compressor (DRC) Architecture + +This directory contains the DRC component. + +## Overview + +The Dynamic Range Compressor reduces the volume of loud sounds or amplifies quiet sounds by narrowing or "compressing" an audio signal's dynamic range. + +## Architecture Diagram + +```mermaid +graph TD + In[Audio Input] --> Det[Envelope Detector] + In --> Gain[Gain Element] + Det --> Calc[Gain Calculation] + Calc --> Gain + Gain --> Out[Audio Output] +``` + +## Configuration and Scripts + +- **Kconfig**: Enables the Dynamic Range Compressor component (`COMP_DRC`). It relies on various math features like `CORDIC_FIXED`, `MATH_LUT_SINE_FIXED`, and `MATH_EXP`. The maximum number of pre-delay frames is tunable via `DRC_MAX_PRE_DELAY_FRAMES` (defaults to 512). +- **CMakeLists.txt**: Manages local base sources and generic/HIFI specific files such as `drc_hifi4.c` and `drc_math_hifi3.c`. Adds logging capabilities if compiled in (`drc_log.c`). +- **drc.toml**: Topology parameters for the DRC module definition, exposing UUID and standard buffer sizes and processing capabilities. +- **Topology (.conf)**: `tools/topology/topology2/include/components/drc.conf` configures the `drc` widget object, providing switch controls by binding a mixer control to switch get/put handlers (`259`). Defaults to type `effect` with UUID `da:e4:6e:b3:6f:00:f9:47:a0:6d:fe:cb:e2:d8:b6:ce`. +- **MATLAB Tuning (`tune/`)**: Contains `.m` scripts (e.g., `sof_example_drc.m`) capable of tuning compressor parameters (threshold, knee, ratio, attack, release) and visualizing their gain reaction curves. The outputs are exported as `.conf` configurations, M4 macros, and ALSA `alsactl` payload blobs for preset instantiation defaults (e.g., speaker or DMIC presets). diff --git a/src/audio/drc/drc.c b/src/audio/drc/drc.c index 000e804cbd00..7fe86ce01c56 100644 --- a/src/audio/drc/drc.c +++ b/src/audio/drc/drc.c @@ -12,6 +12,7 @@ #include <sof/audio/ipc-config.h> #include <sof/audio/pipeline.h> #include <sof/ipc/msg.h> +#include <sof/lib/memory.h> #include <sof/lib/uuid.h> #include <sof/math/numbers.h> #include <sof/trace/trace.h> @@ -19,7 +20,6 @@ #include <ipc/stream.h> #include <ipc/topology.h> #include <module/module/llext.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <rtos/panic.h> #include <rtos/string.h> @@ -41,11 +41,12 @@ LOG_MODULE_DECLARE(drc, CONFIG_SOF_LOG_LEVEL); extern const struct sof_uuid drc_uuid; extern struct tr_ctx drc_tr; -void drc_reset_state(struct drc_state *state) +/* Called from drc_setup() from drc_process(), so cannot be __cold */ +void drc_reset_state(struct processing_module *mod, struct drc_state *state) { int i; - rfree(state->pre_delay_buffers[0]); + mod_free(mod, state->pre_delay_buffers[0]); for (i = 0; i < PLATFORM_MAX_CHANNELS; ++i) { state->pre_delay_buffers[i] = NULL; } @@ -65,7 +66,8 @@ void drc_reset_state(struct drc_state *state) state->max_attack_compression_diff_db = INT32_MIN; } -int drc_init_pre_delay_buffers(struct drc_state *state, +int drc_init_pre_delay_buffers(struct processing_module *mod, + struct drc_state *state, size_t sample_bytes, int channels) { @@ -74,7 +76,7 @@ int drc_init_pre_delay_buffers(struct drc_state *state, int i; /* Allocate pre-delay (lookahead) buffers */ - state->pre_delay_buffers[0] = rballoc(0, SOF_MEM_CAPS_RAM, bytes_total); + state->pre_delay_buffers[0] = mod_alloc(mod, bytes_total); if (!state->pre_delay_buffers[0]) return -ENOMEM; @@ -118,16 +120,18 @@ int drc_set_pre_delay_time(struct drc_state *state, return 0; } -static int drc_setup(struct drc_comp_data *cd, uint16_t channels, uint32_t rate) +/* Called from drc_process(), so cannot be __cold */ +static int drc_setup(struct processing_module *mod, uint16_t channels, uint32_t rate) { + struct drc_comp_data *cd = module_get_private_data(mod); uint32_t sample_bytes = get_sample_bytes(cd->source_format); int ret; /* Reset any previous state */ - drc_reset_state(&cd->state); + drc_reset_state(mod, &cd->state); /* Allocate pre-delay buffers */ - ret = drc_init_pre_delay_buffers(&cd->state, (size_t)sample_bytes, (int)channels); + ret = drc_init_pre_delay_buffers(mod, &cd->state, (size_t)sample_bytes, (int)channels); if (ret < 0) return ret; @@ -143,44 +147,28 @@ __cold static int drc_init(struct processing_module *mod) { struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; - struct module_config *cfg = &md->cfg; struct drc_comp_data *cd; - size_t bs = cfg->size; int ret; - comp_info(dev, "drc_init()"); + assert_can_be_cold(); - /* Check first before proceeding with dev and cd that coefficients - * blob size is sane. - */ - if (bs > SOF_DRC_MAX_SIZE) { - comp_err(dev, "drc_init(), error: configuration blob size = %u > %d", - bs, SOF_DRC_MAX_SIZE); - return -EINVAL; - } + comp_info(dev, "entry"); - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; md->private = cd; /* Handler for configuration data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "drc_init(): comp_data_blob_handler_new() failed."); + comp_err(dev, "mod_data_blob_handler_new() failed."); ret = -ENOMEM; goto cd_fail; } - /* Get configuration data and reset DRC state */ - ret = comp_init_data_blob(cd->model_handler, bs, cfg->data); - if (ret < 0) { - comp_err(dev, "drc_init(): comp_init_data_blob() failed."); - goto cd_fail; - } - - drc_reset_state(&cd->state); + drc_reset_state(mod, &cd->state); /* Initialize DRC to enabled. If defined by topology, a control may set * enabled to false before prepare() or during streaming with the switch @@ -191,8 +179,8 @@ __cold static int drc_init(struct processing_module *mod) return 0; cd_fail: - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); + mod_data_blob_handler_free(mod, cd->model_handler); + mod_free(mod, cd); return ret; } @@ -200,20 +188,24 @@ __cold static int drc_free(struct processing_module *mod) { struct drc_comp_data *cd = module_get_private_data(mod); - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); + assert_can_be_cold(); + + mod_data_blob_handler_free(mod, cd->model_handler); + mod_free(mod, cd); return 0; } -static int 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) +__cold static int 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 drc_comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - comp_dbg(dev, "drc_set_config()"); + assert_can_be_cold(); + + comp_dbg(dev, "entry"); #if CONFIG_IPC_MAJOR_4 struct sof_ipc4_control_msg_payload *ctl = (struct sof_ipc4_control_msg_payload *)fragment; @@ -223,7 +215,7 @@ static int drc_set_config(struct processing_module *mod, uint32_t param_id, if (ctl->id == SOF_DRC_CTRL_INDEX_ENABLE_SWITCH && ctl->num_elems == SOF_DRC_NUM_ELEMS_ENABLE_SWITCH) { cd->enable_switch = ctl->chanv[0].value; - comp_info(dev, "drc_set_config(), enable_switch = %d", cd->enable_switch); + comp_info(dev, "enable_switch = %d", cd->enable_switch); } else { comp_err(dev, "Illegal switch control id = %d, num_elems = %d", ctl->id, ctl->num_elems); @@ -233,24 +225,26 @@ static int drc_set_config(struct processing_module *mod, uint32_t param_id, return 0; case SOF_IPC4_ENUM_CONTROL_PARAM_ID: - comp_err(dev, "drc_set_config(), illegal control."); + comp_err(dev, "illegal control."); return -EINVAL; } #endif - comp_info(dev, "drc_set_config(), bytes control"); + comp_info(dev, "bytes control"); return comp_data_blob_set(cd->model_handler, pos, data_offset_size, fragment, fragment_size); } -static int drc_get_config(struct processing_module *mod, - uint32_t config_id, uint32_t *data_offset_size, - uint8_t *fragment, size_t fragment_size) +__cold static int drc_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) { struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; struct drc_comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "drc_get_config()"); + assert_can_be_cold(); + + comp_info(mod->dev, "entry"); return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); } @@ -268,12 +262,12 @@ static int drc_process(struct processing_module *mod, int frames = input_buffers[0].size; int ret; - comp_dbg(dev, "drc_process()"); + comp_dbg(dev, "entry"); /* Check for changed configuration */ if (comp_is_new_data_blob_available(cd->model_handler)) { cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - ret = drc_setup(cd, audio_stream_get_channels(source), + ret = drc_setup(mod, audio_stream_get_channels(source), audio_stream_get_rate(source)); if (ret < 0) { comp_err(dev, "drc_copy(), failed DRC setup"); @@ -310,11 +304,13 @@ static void drc_params(struct processing_module *mod) struct comp_buffer *sinkb, *sourceb; struct comp_dev *dev = mod->dev; - comp_dbg(dev, "drc_params()"); + comp_dbg(dev, "entry"); ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); component_set_nearest_period_frames(dev, params->rate); + /* The caller has verified, that sink and source buffers are connected */ + sinkb = comp_dev_get_first_data_consumer(dev); ipc4_update_buffer_format(sinkb, &mod->priv.cfg.base_cfg.audio_fmt); @@ -330,19 +326,24 @@ static int drc_prepare(struct processing_module *mod, struct drc_comp_data *cd = module_get_private_data(mod); struct comp_buffer *sourceb, *sinkb; struct comp_dev *dev = mod->dev; + size_t data_size; int channels; int rate; int ret; - comp_info(dev, "drc_prepare()"); - -#if CONFIG_IPC_MAJOR_4 - drc_params(mod); -#endif + comp_info(dev, "entry"); /* DRC component will only ever have 1 source and 1 sink buffer */ sourceb = comp_dev_get_first_data_producer(dev); sinkb = comp_dev_get_first_data_consumer(dev); + if (!sourceb || !sinkb) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } + +#if CONFIG_IPC_MAJOR_4 + drc_params(mod); +#endif /* get source data format */ cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); @@ -350,18 +351,21 @@ static int drc_prepare(struct processing_module *mod, rate = audio_stream_get_rate(&sinkb->stream); /* Initialize DRC */ - comp_info(dev, "drc_prepare(), source_format=%d", cd->source_format); - cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - if (cd->config) { - ret = drc_setup(cd, channels, rate); + comp_info(dev, "source_format=%d", cd->source_format); + cd->config = comp_get_data_blob(cd->model_handler, &data_size, NULL); + /* the blob is dereferenced as a struct sof_drc_config below and in + * drc_setup(), so require it to be at least that large + */ + if (cd->config && data_size >= sizeof(struct sof_drc_config)) { + ret = drc_setup(mod, channels, rate); if (ret < 0) { - comp_err(dev, "drc_prepare() error: drc_setup failed."); + comp_err(dev, "error: drc_setup failed."); return ret; } cd->drc_func = drc_find_proc_func(cd->source_format); if (!cd->drc_func) { - comp_err(dev, "drc_prepare(), No proc func"); + comp_err(dev, "No proc func"); return -EINVAL; } @@ -378,7 +382,7 @@ static int drc_prepare(struct processing_module *mod, cd->drc_func = drc_default_pass; } - comp_info(dev, "drc_prepare(), DRC is configured."); + comp_info(dev, "DRC is configured."); return 0; } @@ -386,7 +390,7 @@ static int drc_reset(struct processing_module *mod) { struct drc_comp_data *cd = module_get_private_data(mod); - drc_reset_state(&cd->state); + drc_reset_state(mod, &cd->state); return 0; } @@ -401,23 +405,20 @@ static const struct module_interface drc_interface = { .free = drc_free }; -DECLARE_MODULE_ADAPTER(drc_interface, drc_uuid, drc_tr); -SOF_MODULE_INIT(drc, sys_comp_module_drc_interface_init); - #if CONFIG_COMP_DRC_MODULE /* modular: llext dynamic link */ #include <module/module/api_ver.h> #include <rimage/sof/user/manifest.h> -#define UUID_DRC 0xda, 0xe4, 0x6e, 0xb3, 0x6f, 0x00, 0xf9, 0x47, \ - 0xa0, 0x6d, 0xfe, 0xcb, 0xe2, 0xd8, 0xb6, 0xce - -SOF_LLEXT_MOD_ENTRY(drc, &drc_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("DRC", drc_llext_entry, 1, UUID_DRC, 40); + SOF_LLEXT_MODULE_MANIFEST("DRC", &drc_interface, 1, SOF_REG_UUID(drc), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_MODULE_ADAPTER(drc_interface, drc_uuid, drc_tr); +SOF_MODULE_INIT(drc, sys_comp_module_drc_interface_init); + #endif diff --git a/src/audio/drc/drc.toml b/src/audio/drc/drc.toml index 4c0b25601425..a131c7b75451 100644 --- a/src/audio/drc/drc.toml +++ b/src/audio/drc/drc.toml @@ -5,7 +5,7 @@ REM # DRC module config [[module.entry]] name = "DRC" - uuid = "B36EE4DA-006F-47F9-A06D-FECBE2D8B6CE" + uuid = UUIDREG_STR_DRC affinity_mask = "0x1" instance_count = "40" domain_types = "0" diff --git a/src/audio/drc/drc_algorithm.h b/src/audio/drc/drc_algorithm.h index c0a942b09622..8d9d759eb3a8 100644 --- a/src/audio/drc/drc_algorithm.h +++ b/src/audio/drc/drc_algorithm.h @@ -14,10 +14,11 @@ #include "drc.h" /* drc reset function */ -void drc_reset_state(struct drc_state *state); +void drc_reset_state(struct processing_module *mod, struct drc_state *state); /* drc init functions */ -int drc_init_pre_delay_buffers(struct drc_state *state, +int drc_init_pre_delay_buffers(struct processing_module *mod, + struct drc_state *state, size_t sample_bytes, int channels); int drc_set_pre_delay_time(struct drc_state *state, diff --git a/src/audio/drc/drc_hifi4.c b/src/audio/drc/drc_hifi4.c index b2252058e885..a4c32c0deb15 100644 --- a/src/audio/drc/drc_hifi4.c +++ b/src/audio/drc/drc_hifi4.c @@ -116,7 +116,7 @@ void drc_update_detector_average(struct drc_state *state, int nch) { ae_f32 detector_average = state->detector_average; /* Q2.30 */ - ae_int32 abs_input_array[DRC_DIVISION_FRAMES]; /* Q1.31 */ + ae_int32 abs_input_array[DRC_DIVISION_FRAMES] __attribute__((aligned(8))); /* Q1.31 */ ae_int32 *abs_input_array_p; int div_start, i, ch; ae_int16 *sample16_p; /* for s16 format case */ diff --git a/src/audio/drc/drc_log.c b/src/audio/drc/drc_log.c index 63c88e65101a..d2e0f1efe7ea 100644 --- a/src/audio/drc/drc_log.c +++ b/src/audio/drc/drc_log.c @@ -10,6 +10,7 @@ SOF_DEFINE_REG_UUID(drc); LOG_MODULE_REGISTER(drc, CONFIG_SOF_LOG_LEVEL); DECLARE_TR_CTX(drc_tr, SOF_UUID(drc_uuid), LOG_LEVEL_INFO); -EXPORT_SYMBOL(drc_tr); -EXPORT_SYMBOL(drc_uuid); EXPORT_SYMBOL(log_const_drc); +#ifdef CONFIG_LOG_RUNTIME_FILTERING +EXPORT_SYMBOL(log_dynamic_drc); +#endif diff --git a/src/audio/drc/drc_math_generic.c b/src/audio/drc/drc_math_generic.c index 574a387bf70c..f4e1f115fcad 100644 --- a/src/audio/drc/drc_math_generic.c +++ b/src/audio/drc/drc_math_generic.c @@ -80,7 +80,7 @@ static inline int32_t log10_fixed(int32_t x) * Input is Q6.26: max 32.0 * Output range ~ (-inf, 30.1030); regulated to Q11.21: (-1024.0, 1024.0) */ -inline int32_t drc_lin2db_fixed(int32_t linear) +int32_t drc_lin2db_fixed(int32_t linear) { int32_t log10_linear; @@ -96,7 +96,7 @@ inline int32_t drc_lin2db_fixed(int32_t linear) * Input is Q6.26: max 32.0 * Output range ~ (-inf, 3.4657); regulated to Q6.26: (-32.0, 32.0) */ -inline int32_t drc_log_fixed(int32_t x) +int32_t drc_log_fixed(int32_t x) { const int32_t LOG10 = Q_CONVERT_FLOAT(2.3025850929940457f, 29); int32_t log10_x; @@ -114,7 +114,7 @@ inline int32_t drc_log_fixed(int32_t x) * Input is Q2.30; valid range: [-1.0, 1.0] * Output range: [-1.0, 1.0]; regulated to Q2.30: (-2.0, 2.0) */ -inline int32_t drc_asin_fixed(int32_t x) +int32_t drc_asin_fixed(int32_t x) { #define qcl 30 #define qch 26 @@ -174,7 +174,7 @@ inline int32_t drc_asin_fixed(int32_t x) * Input depends on precision_x * Output depends on precision_y */ -inline int32_t drc_inv_fixed(int32_t x, int32_t precision_x, int32_t precision_y) +int32_t drc_inv_fixed(int32_t x, int32_t precision_x, int32_t precision_y) { #define qc 25 /* Coefficients obtained from: @@ -229,7 +229,7 @@ inline int32_t drc_inv_fixed(int32_t x, int32_t precision_x, int32_t precision_y * y is Q2.30: (-2.0, 2.0) * Output is Q12.20: max 2048.0 */ -inline int32_t drc_pow_fixed(int32_t x, int32_t y) +int32_t drc_pow_fixed(int32_t x, int32_t y) { /* Negative or zero input x is not supported, just return 0. */ if (x <= 0) diff --git a/src/audio/drc/drc_math_hifi3.c b/src/audio/drc/drc_math_hifi3.c index aadad0151f56..700114188ec9 100644 --- a/src/audio/drc/drc_math_hifi3.c +++ b/src/audio/drc/drc_math_hifi3.c @@ -116,7 +116,7 @@ static inline ae_f32 log10_fixed(ae_f32 x) * Input is Q6.26: max 32.0 * Output range ~ (-inf, 30.1030); regulated to Q11.21: (-1024.0, 1024.0) */ -inline int32_t drc_lin2db_fixed(int32_t linear) +int32_t drc_lin2db_fixed(int32_t linear) { ae_f32 log10_linear; ae_f64 tmp; @@ -138,7 +138,7 @@ inline int32_t drc_lin2db_fixed(int32_t linear) * Input is Q6.26: max 32.0 * Output range ~ (-inf, 3.4657); regulated to Q6.26: (-32.0, 32.0) */ -inline int32_t drc_log_fixed(int32_t x) +int32_t drc_log_fixed(int32_t x) { ae_f32 log10_x; ae_f64 tmp; @@ -160,7 +160,7 @@ inline int32_t drc_log_fixed(int32_t x) * Input is Q2.30; valid range: [-1.0, 1.0] * Output range: [-1.0, 1.0]; regulated to Q2.30: (-2.0, 2.0) */ -inline int32_t drc_asin_fixed(int32_t x) +int32_t drc_asin_fixed(int32_t x) { /* Coefficients obtained from: * If x <= 1/sqrt(2), then @@ -224,7 +224,7 @@ inline int32_t drc_asin_fixed(int32_t x) * Input depends on precision_x * Output depends on precision_y */ -inline int32_t drc_inv_fixed(int32_t x, int32_t precision_x, int32_t precision_y) +int32_t drc_inv_fixed(int32_t x, int32_t precision_x, int32_t precision_y) { /* Coefficients obtained from: * fpminimax(1/x, 5, [|SG...|], [sqrt(2)/2;1], absolute); diff --git a/src/audio/drc/tune/sof_drc_build_blob.m b/src/audio/drc/tune/sof_drc_build_blob.m index 48ef29b31a65..72bd7288be16 100644 --- a/src/audio/drc/tune/sof_drc_build_blob.m +++ b/src/audio/drc/tune/sof_drc_build_blob.m @@ -22,7 +22,7 @@ % refer to sof/src/include/user/drc.h for the config struct. num_coefs = length(fieldnames(blob_struct)); data_size = 4 * (1 + 4 + num_coefs); -[abi_bytes, abi_size] = get_abi(data_size, ipc_ver); +[abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver); blob_size = data_size + abi_size; blob8 = uint8(zeros(1, blob_size)); diff --git a/src/audio/drc/tune/sof_example_drc.m b/src/audio/drc/tune/sof_example_drc.m index 896556e74f5b..febf320aad99 100644 --- a/src/audio/drc/tune/sof_example_drc.m +++ b/src/audio/drc/tune/sof_example_drc.m @@ -60,9 +60,9 @@ function drc_coefs_and_config_export(params, id) tplg1_fn = sprintf("%s/topology1/m4/drc_coef_%s.m4", sof_tplg, id); % Control Bytes File tplg2_fn = sprintf("%s/topology2/include/components/drc/%s.conf", sof_tplg, id); % Control Bytes File % Use those files with sof-ctl to update the component's configuration -blob3_fn = sprintf("%s/ipc3/drc_coef_%s.blob", sof_ctl, id); % Blob binary file +blob3_fn = sprintf("%s/ipc3/drc_coef_%s.bin", sof_ctl, id); % Blob binary file alsa3_fn = sprintf("%s/ipc3/drc_coef_%s.txt", sof_ctl, id); % ALSA CSV format file -blob4_fn = sprintf("%s/ipc4/drc/%s.blob", sof_ctl, id); % Blob binary file +blob4_fn = sprintf("%s/ipc4/drc/%s.bin", sof_ctl, id); % Blob binary file alsa4_fn = sprintf("%s/ipc4/drc/%s.txt", sof_ctl, id); % ALSA CSV format file endian = "little"; @@ -82,12 +82,12 @@ function drc_coefs_and_config_export(params, id) my_name = mfilename(); drc_note = sprintf("Exported with script %s.m", my_name); drc_howto = sprintf("cd tools/tune/drc; octave --no-window-system %s.m", my_name); -tplg_write(tplg1_fn, blob8, "DRC", drc_note, drc_howto); -tplg2_write(tplg2_fn, blob8_ipc4, "drc_config", drc_note, drc_howto); +sof_tplg_write(tplg1_fn, blob8, "DRC", drc_note, drc_howto); +sof_tplg2_write(tplg2_fn, blob8_ipc4, "drc_config", drc_note, drc_howto); sof_ucm_blob_write(blob3_fn, blob8); -alsactl_write(alsa3_fn, blob8); +sof_alsactl_write(alsa3_fn, blob8); sof_ucm_blob_write(blob4_fn, blob8_ipc4); -alsactl_write(alsa4_fn, blob8_ipc4); +sof_alsactl_write(alsa4_fn, blob8_ipc4); % Plot x-y response in dB sof_drc_plot_db_curve(coefs); diff --git a/src/audio/eq_fir/CMakeLists.txt b/src/audio/eq_fir/CMakeLists.txt index 250ca910658c..2c98126a1d86 100644 --- a/src/audio/eq_fir/CMakeLists.txt +++ b/src/audio/eq_fir/CMakeLists.txt @@ -1,9 +1,18 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof eq_fir.c eq_fir_generic.c eq_fir_hifi2ep.c eq_fir_hifi3.c) -if(CONFIG_IPC_MAJOR_3) - add_local_sources(sof eq_fir_ipc3.c) -elseif(CONFIG_IPC_MAJOR_4) - add_local_sources(sof eq_fir_ipc4.c) -endif() +if(CONFIG_COMP_FIR STREQUAL "m" AND DEFINED CONFIG_LLEXT) + + add_subdirectory(llext ${PROJECT_BINARY_DIR}/eq_fir_llext) + add_dependencies(app eq_fir) + +else() + add_local_sources(sof eq_fir.c eq_fir_generic.c eq_fir_hifi2ep.c eq_fir_hifi3.c) + + if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof eq_fir_ipc3.c) + elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof eq_fir_ipc4.c) + endif() + +endif() diff --git a/src/audio/eq_fir/README.md b/src/audio/eq_fir/README.md new file mode 100644 index 000000000000..24be526f6189 --- /dev/null +++ b/src/audio/eq_fir/README.md @@ -0,0 +1,24 @@ +# FIR Equalizer Architecture + +This directory contains the Finite Impulse Response (FIR) EQ component. + +## Overview + +FIR equalizers implement linear-phase (or minimal-phase) audio frequency shaping over a specified set of taps. + +## Architecture Diagram + +```mermaid +graph LR + In[Input Frame] --> FIR[FIR Filter Engine] + Coeffs[(Filter Coefficients)] --> FIR + FIR --> Out[Output Frame] +``` + +## Configuration and Scripts + +- **Kconfig**: Enables the FIR component (`COMP_FIR`), which automatically imports `MATH_FIR` and `COMP_BLOB`. Relies on compiler capabilities to leverage DSP MAC instructions for optimal performance. +- **CMakeLists.txt**: Integrates generic and architecture-specific (`eq_fir_hifi2ep.c`, `eq_fir_hifi3.c`) files into the build, picking the correct IPC wrapper (`ipc3` or `ipc4`), and supports `llext`. +- **eq_fir.toml**: Topology parameters for the EQFIR module, defining UUIDs, memory parameters (like 4096 bytes limits) and pin layouts. +- **Topology (.conf)**: Constrained by `tools/topology/topology2/include/components/eqfir.conf`, assigning it widget type `effect` and UUID `e7:0c:a9:43:a5:f3:df:41:ac:06:ba:98:65:1a:e6:a3`. +- **MATLAB Tuning (`tune/`)**: `sof_example_fir_eq.m` utilizes the Parks-McClellan (or related) algorithms to model loudness or mid-boost curves, iterating length variables to determine optimal FIR phase behaviors. It outputs quantized binary arrays containing the calculated taps necessary for topology population. diff --git a/src/audio/eq_fir/eq_fir.c b/src/audio/eq_fir/eq_fir.c index b02c104cdf89..6c4c3d630562 100644 --- a/src/audio/eq_fir/eq_fir.c +++ b/src/audio/eq_fir/eq_fir.c @@ -15,7 +15,6 @@ #include <sof/common.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> #include <sof/list.h> @@ -41,8 +40,6 @@ LOG_MODULE_REGISTER(eq_fir, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(eq_fir); -DECLARE_TR_CTX(eq_fir_tr, SOF_UUID(eq_fir_uuid), LOG_LEVEL_INFO); - /* Pass-through functions to replace FIR core while not configured for * response. */ @@ -58,15 +55,16 @@ static void eq_fir_passthrough(struct fir_state_32x16 fir[], audio_stream_copy(source, 0, sink, 0, frames * audio_stream_get_channels(source)); } -static void eq_fir_free_delaylines(struct comp_data *cd) +static void eq_fir_free_delaylines(struct processing_module *mod) { + struct comp_data *cd = module_get_private_data(mod); struct fir_state_32x16 *fir = cd->fir; int i = 0; /* Free the common buffer for all EQs and point then * each FIR channel delay line to NULL. */ - rfree(cd->fir_delay); + mod_free(mod, cd->fir_delay); cd->fir_delay = NULL; cd->fir_delay_size = 0; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) @@ -74,12 +72,13 @@ static void eq_fir_free_delaylines(struct comp_data *cd) } static int eq_fir_init_coef(struct comp_dev *dev, struct sof_eq_fir_config *config, - struct fir_state_32x16 *fir, int nch) + size_t config_size, struct fir_state_32x16 *fir, int nch) { struct sof_fir_coef_data *lookup[SOF_EQ_FIR_MAX_RESPONSES]; struct sof_fir_coef_data *eq; int16_t *assign_response; int16_t *coef_data; + size_t coef_words_max; size_t size_sum = 0; int resp = 0; int i; @@ -99,31 +98,74 @@ static int eq_fir_init_coef(struct comp_dev *dev, struct sof_eq_fir_config *conf nch = cd->nch; } - comp_info(dev, "eq_fir_init_coef(): %u responses, %u channels, stream %d channels", + comp_info(dev, "%u responses, %u channels, stream %d channels", config->number_of_responses, config->channels_in_config, nch); /* Sanity checks */ + if (config->size != config_size) { + comp_err(dev, "Incorrect configuration blob size"); + return -EINVAL; + } + if (nch > PLATFORM_MAX_CHANNELS || config->channels_in_config > PLATFORM_MAX_CHANNELS || !config->channels_in_config) { - comp_err(dev, "eq_fir_init_coef(), invalid channels count"); + comp_err(dev, "invalid channels count"); + return -EINVAL; + } + /* channels_in_config indexes into a int16_t array. An odd count would + * leave the coefficient area at a 2-byte alignment, breaking the + * 4-byte aligned int32_t loads in the optimized FIR kernels. + */ + if (config->channels_in_config & 0x1) { + comp_err(dev, "channels_in_config %u must be even", + config->channels_in_config); return -EINVAL; } if (config->number_of_responses > SOF_EQ_FIR_MAX_RESPONSES) { - comp_err(dev, "eq_fir_init_coef(), # of resp exceeds max"); + comp_err(dev, "# of resp exceeds max"); + return -EINVAL; + } + + /* Compute the size of the coefficient area in int16_t words from the + * blob's self-declared size. The blob layout is: + * sizeof(*config) header bytes + * channels_in_config int16_t assign_response[] + * coefficient data[] + */ + if (config->size < sizeof(*config) || + config->size - sizeof(*config) < + (size_t)config->channels_in_config * sizeof(int16_t)) { + comp_err(dev, "config size %u too small", config->size); return -EINVAL; } + coef_words_max = (config->size - sizeof(*config)) / sizeof(int16_t) - + config->channels_in_config; /* Collect index of response start positions in all_coefficients[] */ j = 0; assign_response = ASSUME_ALIGNED(&config->data[0], 4); - coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config], - 4); + coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config], 4); for (i = 0; i < SOF_EQ_FIR_MAX_RESPONSES; i++) { if (i < config->number_of_responses) { + /* Header must fit before reading length */ + if (j + SOF_FIR_COEF_NHEADER > coef_words_max) { + comp_err(dev, "response %d header out of bounds", i); + return -EINVAL; + } eq = (struct sof_fir_coef_data *)&coef_data[j]; + /* Bound length so it is valid and the coefficient data + * stays within the blob. + */ + if (eq->length <= 0 || eq->length > SOF_FIR_MAX_LENGTH || + (eq->length & 0x3) || + j + SOF_FIR_COEF_NHEADER + eq->length > coef_words_max) { + comp_err(dev, "response %d length %d out of bounds", + i, eq->length); + return -EINVAL; + } lookup[i] = eq; - j += SOF_FIR_COEF_NHEADER + coef_data[j]; + j += SOF_FIR_COEF_NHEADER + eq->length; } else { lookup[i] = NULL; } @@ -145,14 +187,14 @@ static int eq_fir_init_coef(struct comp_dev *dev, struct sof_eq_fir_config *conf * next channel response. */ if (fir) { - comp_info(dev, "eq_fir_init_coef(), ch %d is set to bypass", i); + comp_info(dev, "ch %d is set to bypass", i); fir_reset(&fir[i]); } continue; } if (resp >= config->number_of_responses) { - comp_err(dev, "eq_fir_init_coef(), requested response %d exceeds what has been defined", + comp_err(dev, "requested response %d exceeds what has been defined", resp); return -EINVAL; } @@ -163,7 +205,7 @@ static int eq_fir_init_coef(struct comp_dev *dev, struct sof_eq_fir_config *conf if (s > 0) { size_sum += s; } else { - comp_info(dev, "eq_fir_init_coef(), FIR length %d is invalid", eq->length); + comp_info(dev, "FIR length %d is invalid", eq->length); return -EINVAL; } @@ -177,7 +219,7 @@ static int eq_fir_init_coef(struct comp_dev *dev, struct sof_eq_fir_config *conf if (fir) { fir_init_coef(&fir[i], eq); - comp_info(dev, "eq_fir_init_coef(), ch %d is set to response = %d", + comp_info(dev, "ch %d is set to response = %d", i, resp); } } @@ -198,18 +240,20 @@ static void eq_fir_init_delay(struct fir_state_32x16 *fir, } } -static int eq_fir_setup(struct comp_dev *dev, struct comp_data *cd, int nch) +static int eq_fir_setup(struct processing_module *mod, int nch) { + struct comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; int delay_size; /* Free existing FIR channels data if it was allocated */ - eq_fir_free_delaylines(cd); + eq_fir_free_delaylines(mod); /* Update number of channels */ cd->nch = nch; /* Set coefficients for each channel EQ from coefficient blob */ - delay_size = eq_fir_init_coef(dev, cd->config, cd->fir, nch); + delay_size = eq_fir_init_coef(dev, cd->config, cd->config_size, cd->fir, nch); if (delay_size < 0) return delay_size; /* Contains error code */ @@ -220,9 +264,9 @@ static int eq_fir_setup(struct comp_dev *dev, struct comp_data *cd, int nch) return 0; /* Allocate all FIR channels data in a big chunk and clear it */ - cd->fir_delay = rballoc(0, SOF_MEM_CAPS_RAM, delay_size); + cd->fir_delay = mod_alloc(mod, delay_size); if (!cd->fir_delay) { - comp_err(dev, "eq_fir_setup(), delay allocation failed for size %d", delay_size); + comp_err(dev, "delay allocation failed for size %d", delay_size); return -ENOMEM; } @@ -234,9 +278,25 @@ static int eq_fir_setup(struct comp_dev *dev, struct comp_data *cd, int nch) return 0; } +static int eq_fir_check_blob_size(struct comp_dev *dev, size_t size) +{ + if (size < sizeof(struct sof_eq_fir_config) || size > SOF_EQ_FIR_MAX_SIZE) { + comp_err(dev, "invalid configuration blob, size %zu", size); + return -EINVAL; + } + + return 0; +} + static int eq_fir_validator(struct comp_dev *dev, void *new_data, uint32_t new_data_size) { - return eq_fir_init_coef(dev, new_data, NULL, -1); + int ret; + + ret = eq_fir_check_blob_size(dev, new_data_size); + if (ret < 0) + return ret; + + return eq_fir_init_coef(dev, new_data, new_data_size, NULL, -1); } /* @@ -247,24 +307,12 @@ static int eq_fir_init(struct processing_module *mod) { struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; - struct module_config *cfg = &md->cfg; struct comp_data *cd = NULL; - size_t bs = cfg->size; int i; - int ret; - comp_info(dev, "eq_fir_init()"); + comp_info(dev, "entry"); - /* Check first before proceeding with dev and cd that coefficients - * blob size is sane. - */ - if (bs > SOF_EQ_FIR_MAX_SIZE) { - comp_err(dev, "eq_fir_init(): coefficients blob size = %zu > SOF_EQ_FIR_MAX_SIZE", - bs); - return -EINVAL; - } - - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -274,46 +322,31 @@ static int eq_fir_init(struct processing_module *mod) cd->nch = -1; /* component model data handler */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "eq_fir_init(): comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto err; + comp_err(dev, "mod_data_blob_handler_new() failed."); + mod_free(mod, cd); + return -ENOMEM; } md->private = cd; - /* Allocate and make a copy of the coefficients blob and reset FIR. If - * the EQ is configured later in run-time the size is zero. - */ - ret = comp_init_data_blob(cd->model_handler, bs, cfg->init_data); - if (ret < 0) { - comp_err(dev, "eq_fir_init(): comp_init_data_blob() failed."); - goto err_init; - } - for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) fir_reset(&cd->fir[i]); return 0; - -err_init: - comp_data_blob_handler_free(cd->model_handler); -err: - rfree(cd); - return ret; } static int eq_fir_free(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "eq_fir_free()"); + comp_dbg(mod->dev, "entry"); - eq_fir_free_delaylines(cd); - comp_data_blob_handler_free(cd->model_handler); + eq_fir_free_delaylines(mod); + mod_data_blob_handler_free(mod, cd->model_handler); - rfree(cd); + mod_free(mod, cd); return 0; } @@ -325,7 +358,7 @@ static int eq_fir_get_config(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "eq_fir_get_config()"); + comp_info(mod->dev, "entry"); return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); } @@ -337,7 +370,7 @@ static int eq_fir_set_config(struct processing_module *mod, uint32_t config_id, { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "eq_fir_set_config()"); + comp_info(mod->dev, "entry"); return comp_data_blob_set(cd->model_handler, pos, data_offset_size, fragment, fragment_size); @@ -355,23 +388,25 @@ static int eq_fir_process(struct processing_module *mod, uint32_t frame_count = input_buffers[0].size; int ret; - comp_dbg(mod->dev, "eq_fir_process()"); + comp_dbg(mod->dev, "entry"); /* Check for changed configuration */ if (comp_is_new_data_blob_available(cd->model_handler)) { - cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - ret = eq_fir_setup(mod->dev, cd, audio_stream_get_channels(source)); + cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL); + if (!cd->config || eq_fir_check_blob_size(mod->dev, cd->config_size) < 0) + return -EINVAL; + ret = eq_fir_setup(mod, audio_stream_get_channels(source)); if (ret < 0) { - comp_err(mod->dev, "eq_fir_process(), failed FIR setup"); + comp_err(mod->dev, "failed FIR setup"); return ret; } else if (cd->fir_delay_size) { - comp_dbg(mod->dev, "eq_fir_process(), active"); + comp_dbg(mod->dev, "active"); ret = set_fir_func(mod, audio_stream_get_frm_fmt(source)); if (ret < 0) return ret; } else { cd->eq_fir_func = eq_fir_passthrough; - comp_dbg(mod->dev, "eq_fir_process(), pass-through"); + comp_dbg(mod->dev, "pass-through"); } } @@ -393,14 +428,12 @@ static int eq_fir_process(struct processing_module *mod, return 0; } -static void eq_fir_set_alignment(struct audio_stream *source, - struct audio_stream *sink) +static void eq_fir_set_alignment(struct audio_stream *source) { - const uint32_t byte_align = 1; + const uint32_t byte_align = SOF_FRAME_BYTE_ALIGN; const uint32_t frame_align_req = 2; /* Process multiples of 2 frames */ audio_stream_set_align(byte_align, frame_align_req, source); - audio_stream_set_align(byte_align, frame_align_req, sink); } static int eq_fir_prepare(struct processing_module *mod, @@ -414,7 +447,15 @@ static int eq_fir_prepare(struct processing_module *mod, enum sof_ipc_frame frame_fmt; int ret = 0; - comp_dbg(dev, "eq_fir_prepare()"); + comp_dbg(dev, "entry"); + + /* EQ component will only ever have 1 source and 1 sink buffer. */ + sourceb = comp_dev_get_first_data_producer(dev); + sinkb = comp_dev_get_first_data_consumer(dev); + if (!sourceb || !sinkb) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } ret = eq_fir_params(mod); if (ret < 0) { @@ -422,23 +463,23 @@ static int eq_fir_prepare(struct processing_module *mod, return ret; } - /* EQ component will only ever have 1 source and 1 sink buffer. */ - sourceb = comp_dev_get_first_data_producer(dev); - sinkb = comp_dev_get_first_data_consumer(dev); - eq_fir_set_alignment(&sourceb->stream, &sinkb->stream); + eq_fir_set_alignment(&sourceb->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); + cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL); if (cd->config) { - ret = eq_fir_setup(dev, cd, channels); + if (eq_fir_check_blob_size(dev, cd->config_size) < 0) + return -EINVAL; + + ret = eq_fir_setup(mod, channels); if (ret < 0) - comp_err(dev, "eq_fir_prepare(): eq_fir_setup failed."); + comp_err(dev, "eq_fir_setup failed."); else if (cd->fir_delay_size) ret = set_fir_func(mod, frame_fmt); else - comp_dbg(dev, "eq_fir_prepare(): pass-through"); + comp_dbg(dev, "pass-through"); } if (ret < 0) @@ -455,11 +496,11 @@ static int eq_fir_reset(struct processing_module *mod) int i; struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "eq_fir_reset()"); + comp_dbg(mod->dev, "entry"); comp_data_blob_set_validator(cd->model_handler, NULL); - eq_fir_free_delaylines(cd); + eq_fir_free_delaylines(mod); cd->eq_fir_func = NULL; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) @@ -478,9 +519,6 @@ static const struct module_interface eq_fir_interface = { .reset = eq_fir_reset, }; -DECLARE_MODULE_ADAPTER(eq_fir_interface, eq_fir_uuid, eq_fir_tr); -SOF_MODULE_INIT(eq_fir, sys_comp_module_eq_fir_interface_init); - #if CONFIG_COMP_FIR_MODULE /* modular: llext dynamic link */ @@ -488,14 +526,15 @@ SOF_MODULE_INIT(eq_fir, sys_comp_module_eq_fir_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_EQFIR 0xe7, 0x0c, 0xa9, 0x43, 0xa5, 0xf3, 0xdf, 0x41, \ - 0xac, 0x06, 0xba, 0x98, 0x65, 0x1a, 0xe6, 0xa3 - -SOF_LLEXT_MOD_ENTRY(eq_fir, &eq_fir_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("EQFIR", eq_fir_llext_entry, 1, UUID_EQFIR, 40); + SOF_LLEXT_MODULE_MANIFEST("EQFIR", &eq_fir_interface, 1, SOF_REG_UUID(eq_fir), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(eq_fir_tr, SOF_UUID(eq_fir_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(eq_fir_interface, eq_fir_uuid, eq_fir_tr); +SOF_MODULE_INIT(eq_fir, sys_comp_module_eq_fir_interface_init); + #endif diff --git a/src/audio/eq_fir/eq_fir.h b/src/audio/eq_fir/eq_fir.h index 921d39939d69..5af74dc5674a 100644 --- a/src/audio/eq_fir/eq_fir.h +++ b/src/audio/eq_fir/eq_fir.h @@ -36,6 +36,7 @@ struct comp_data { struct comp_data_blob_handler *model_handler; struct sof_eq_fir_config *config; int32_t *fir_delay; /**< pointer to allocated RAM */ + size_t config_size; /**< configuration size */ size_t fir_delay_size; /**< allocated size */ void (*eq_fir_func)(struct fir_state_32x16 fir[], struct input_stream_buffer *bsource, diff --git a/src/audio/eq_fir/eq_fir.toml b/src/audio/eq_fir/eq_fir.toml index 416c068e95ce..514a0804bba7 100644 --- a/src/audio/eq_fir/eq_fir.toml +++ b/src/audio/eq_fir/eq_fir.toml @@ -5,7 +5,7 @@ REM # eq fir module config [[module.entry]] name = "EQFIR" - uuid = "43A90CE7-F3A5-41DF-AC06-BA98651AE6A3" + uuid = UUIDREG_STR_EQ_FIR affinity_mask = "0x1" instance_count = "40" domain_types = "0" diff --git a/src/audio/eq_fir/eq_fir_hifi2ep.c b/src/audio/eq_fir/eq_fir_hifi2ep.c index 2a687623ea51..71b40edcee32 100644 --- a/src/audio/eq_fir/eq_fir_hifi2ep.c +++ b/src/audio/eq_fir/eq_fir_hifi2ep.c @@ -61,8 +61,7 @@ void eq_fir_2x_s32(struct fir_state_32x16 fir[], struct input_stream_buffer *bso for (i = 0; i < (frames >> 1); i++) { x1 = x0 + nch; y1 = y0 + nch; - fir_32x16_2x_hifiep(f, *x0, *x1, y0, y1, - lshift, rshift); + fir_32x16_2x(f, *x0, *x1, y0, y1, lshift, rshift); x0 += inc; y0 += inc; } @@ -107,8 +106,7 @@ void eq_fir_2x_s24(struct fir_state_32x16 fir[], struct input_stream_buffer *bso for (i = 0; i < (frames >> 1); i++) { x1 = x0 + nch; y1 = y0 + nch; - fir_32x16_2x_hifiep(f, *x0 << 8, *x1 << 8, &z0, &z1, - lshift, rshift); + fir_32x16_2x(f, *x0 << 8, *x1 << 8, &z0, &z1, lshift, rshift); *y0 = sat_int24(Q_SHIFT_RND(z0, 31, 23)); *y1 = sat_int24(Q_SHIFT_RND(z1, 31, 23)); x0 += inc; @@ -155,8 +153,7 @@ void eq_fir_2x_s16(struct fir_state_32x16 fir[], struct input_stream_buffer *bso for (i = 0; i < (frames >> 1); i++) { x1 = x0 + nch; y1 = y0 + nch; - fir_32x16_2x_hifiep(f, *x0 << 16, *x1 << 16, &z0, &z1, - lshift, rshift); + fir_32x16_2x(f, *x0 << 16, *x1 << 16, &z0, &z1, lshift, rshift); *y0 = sat_int16(Q_SHIFT_RND(z0, 31, 15)); *y1 = sat_int16(Q_SHIFT_RND(z1, 31, 15)); x0 += inc; diff --git a/src/audio/eq_fir/eq_fir_hifi3.c b/src/audio/eq_fir/eq_fir_hifi3.c index 638b296a74c4..0d25851ea447 100644 --- a/src/audio/eq_fir/eq_fir_hifi3.c +++ b/src/audio/eq_fir/eq_fir_hifi3.c @@ -70,7 +70,7 @@ void eq_fir_2x_s32(struct fir_state_32x16 fir[], struct input_stream_buffer *bso /* Load two input samples via input pointer x */ AE_L32_XP(d0, x, inc_nch_s); AE_L32_XP(d1, x, inc_nch_s); - fir_32x16_2x_hifi3(f, d0, d1, y0, y1, shift); + fir_32x16_2x(f, d0, d1, y0, y1, shift); AE_L32_XC(d0, y0, inc_2nch_s); AE_L32_XC(d1, y1, inc_2nch_s); } @@ -131,7 +131,7 @@ void eq_fir_2x_s24(struct fir_state_32x16 fir[], struct input_stream_buffer *bso d0 = AE_SLAA32(d0, 8); d1 = AE_SLAA32(d1, 8); - fir_32x16_2x_hifi3(f, d0, d1, &z0, &z1, shift); + fir_32x16_2x(f, d0, d1, &z0, &z1, shift); /* Shift and round to Q1.23 format */ d0 = AE_SRAI32R(z0, 8); @@ -205,7 +205,7 @@ void eq_fir_2x_s16(struct fir_state_32x16 fir[], struct input_stream_buffer *bso x0 = AE_CVT32X2F16_32(d0); x1 = AE_CVT32X2F16_32(d1); - fir_32x16_2x_hifi3(f, x0, x1, &z0, &z1, shift); + fir_32x16_2x(f, x0, x1, &z0, &z1, shift); /* Round to Q1.15 format */ d0 = AE_ROUND16X4F32SSYM(z0, z0); diff --git a/src/audio/eq_fir/eq_fir_ipc3.c b/src/audio/eq_fir/eq_fir_ipc3.c index 5b5c7e48c675..ecfd873ffd7f 100644 --- a/src/audio/eq_fir/eq_fir_ipc3.c +++ b/src/audio/eq_fir/eq_fir_ipc3.c @@ -23,24 +23,24 @@ int set_fir_func(struct processing_module *mod, enum sof_ipc_frame fmt) switch (fmt) { #if CONFIG_FORMAT_S16LE case SOF_IPC_FRAME_S16_LE: - comp_dbg(mod->dev, "set_fir_func(), SOF_IPC_FRAME_S16_LE"); + comp_dbg(mod->dev, "SOF_IPC_FRAME_S16_LE"); set_s16_fir(cd); break; #endif /* CONFIG_FORMAT_S16LE */ #if CONFIG_FORMAT_S24LE case SOF_IPC_FRAME_S24_4LE: - comp_dbg(mod->dev, "set_fir_func(), SOF_IPC_FRAME_S24_4LE"); + comp_dbg(mod->dev, "SOF_IPC_FRAME_S24_4LE"); set_s24_fir(cd); break; #endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE case SOF_IPC_FRAME_S32_LE: - comp_dbg(mod->dev, "set_fir_func(), SOF_IPC_FRAME_S32_LE"); + comp_dbg(mod->dev, "SOF_IPC_FRAME_S32_LE"); set_s32_fir(cd); break; #endif /* CONFIG_FORMAT_S32LE */ default: - comp_err(mod->dev, "set_fir_func(), invalid frame_fmt"); + comp_err(mod->dev, "invalid frame_fmt"); return -EINVAL; } return 0; diff --git a/src/audio/eq_fir/eq_fir_ipc4.c b/src/audio/eq_fir/eq_fir_ipc4.c index eec4165b748b..64ec2895e0dd 100644 --- a/src/audio/eq_fir/eq_fir_ipc4.c +++ b/src/audio/eq_fir/eq_fir_ipc4.c @@ -24,7 +24,7 @@ int set_fir_func(struct processing_module *mod, enum sof_ipc_frame fmt) struct comp_data *cd = module_get_private_data(mod); unsigned int valid_bit_depth = mod->priv.cfg.base_cfg.audio_fmt.valid_bit_depth; - comp_dbg(mod->dev, "set_fir_func(): valid_bit_depth %d", valid_bit_depth); + comp_dbg(mod->dev, "valid_bit_depth %d", valid_bit_depth); switch (valid_bit_depth) { #if CONFIG_FORMAT_S16LE case IPC4_DEPTH_16BIT: @@ -42,7 +42,7 @@ int set_fir_func(struct processing_module *mod, enum sof_ipc_frame fmt) break; #endif /* CONFIG_FORMAT_S32LE */ default: - comp_err(mod->dev, "set_fir_func(), invalid valid_bith_depth"); + comp_err(mod->dev, "invalid valid_bith_depth"); return -EINVAL; } return 0; @@ -54,11 +54,13 @@ int eq_fir_params(struct processing_module *mod) struct comp_buffer *sinkb, *sourceb; struct comp_dev *dev = mod->dev; - comp_dbg(dev, "eq_fir_params()"); + comp_dbg(dev, "entry"); ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); component_set_nearest_period_frames(dev, params->rate); + /* The caller has verified, that sink and source buffers are connected */ + sourceb = comp_dev_get_first_data_producer(dev); ipc4_update_buffer_format(sourceb, &mod->priv.cfg.base_cfg.audio_fmt); diff --git a/src/audio/eq_iir/CMakeLists.txt b/src/audio/eq_iir/CMakeLists.txt index 0c9853540ad5..33c50df17df8 100644 --- a/src/audio/eq_iir/CMakeLists.txt +++ b/src/audio/eq_iir/CMakeLists.txt @@ -1,8 +1,18 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof eq_iir.c eq_iir_generic.c) -if(CONFIG_IPC_MAJOR_3) - add_local_sources(sof eq_iir_ipc3.c) -elseif(CONFIG_IPC_MAJOR_4) - add_local_sources(sof eq_iir_ipc4.c) +if(CONFIG_COMP_IIR STREQUAL "m" AND DEFINED CONFIG_LLEXT) + + add_subdirectory(llext ${PROJECT_BINARY_DIR}/eq_iir_llext) + add_dependencies(app eq_iir) + +else() + + add_local_sources(sof eq_iir.c eq_iir_generic.c) + + if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof eq_iir_ipc3.c) + elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof eq_iir_ipc4.c) + endif() + endif() diff --git a/src/audio/eq_iir/README.md b/src/audio/eq_iir/README.md new file mode 100644 index 000000000000..6af07ceae354 --- /dev/null +++ b/src/audio/eq_iir/README.md @@ -0,0 +1,24 @@ +# IIR Equalizer Architecture + +This directory contains the Infinite Impulse Response (IIR) EQ component. + +## Overview + +IIR equalizers provide frequency shaping (like parametric EQs, shelves, high/low passes) typically using arrays of biquad filters. + +## Architecture Diagram + +```mermaid +graph LR + In[Input Frame] --> IIR[Biquad Cascade] + Coeffs[(Biquad Coefficients)] --> IIR + IIR --> Out[Output Frame] +``` + +## Configuration and Scripts + +- **Kconfig**: Activates the IIR component (`COMP_IIR`), selecting `MATH_IIR_DF1` and depending on the module adapter. +- **CMakeLists.txt**: Compiles generic logic (`eq_iir_generic.c`) and IPC-specific files depending on the Zephyr IPC configuration. +- **eq_iir.toml**: Topology parameters tailored by platform. Defines custom `mod_cfg` arrays with varying constraints based on `CONFIG_METEORLAKE` versus `CONFIG_LUNARLAKE` and ACE SOCs. +- **Topology (.conf)**: Dictated by `tools/topology/topology2/include/components/eqiir.conf`, representing an `effect` widget object with UUID `e6:c0:50:51:f9:27:c8:4e:83:51:c7:05:b6:42:d1:2f`. +- **MATLAB Tuning (`tune/`)**: `sof_example_iir_eq.m` and associated scripts can design parametric biquad presets (e.g., loudness, bass boost, bandpass, flat). These scripts compute the IIR coefficients, calculate precise scaling values, quantize mathematically, and bundle the permutations into binaries and configuration fragments suitable for SOF IPC messages. diff --git a/src/audio/eq_iir/eq_iir.c b/src/audio/eq_iir/eq_iir.c index e11d9454433b..2c90855ab061 100644 --- a/src/audio/eq_iir/eq_iir.c +++ b/src/audio/eq_iir/eq_iir.c @@ -17,7 +17,6 @@ #include <sof/common.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> #include <sof/list.h> @@ -38,8 +37,6 @@ LOG_MODULE_REGISTER(eq_iir, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(eq_iir); -DECLARE_TR_CTX(eq_iir_tr, SOF_UUID(eq_iir_uuid), LOG_LEVEL_INFO); - /* * End of EQ setup code. Next the standard component methods. */ @@ -47,60 +44,39 @@ static int eq_iir_init(struct processing_module *mod) { struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; - struct module_config *cfg = &md->cfg; struct comp_data *cd; - size_t bs = cfg->size; - int i, ret; + int i; - comp_info(dev, "eq_iir_init()"); + comp_info(dev, "entry"); - /* Check first before proceeding with dev and cd that coefficients blob size is sane */ - if (bs > SOF_EQ_IIR_MAX_SIZE) { - comp_err(dev, "eq_iir_init(), coefficients blob size %zu exceeds maximum", bs); - return -EINVAL; - } - - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; md->private = cd; /* component model data handler */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "eq_iir_init(): comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto err; - } - - /* Allocate and make a copy of the coefficients blob and reset IIR. If - * the EQ is configured later in run-time the size is zero. - */ - ret = comp_init_data_blob(cd->model_handler, bs, cfg->data); - if (ret < 0) { - comp_err(dev, "eq_iir_init(): comp_init_data_blob() failed with error: %d", ret); - comp_data_blob_handler_free(cd->model_handler); - goto err; + comp_err(dev, "mod_data_blob_handler_new() failed."); + mod_free(mod, cd); + return -ENOMEM; } for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) iir_reset_df1(&cd->iir[i]); return 0; -err: - rfree(cd); - return ret; } static int eq_iir_free(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - eq_iir_free_delaylines(cd); - comp_data_blob_handler_free(cd->model_handler); + eq_iir_free_delaylines(mod); + mod_data_blob_handler_free(mod, cd->model_handler); - rfree(cd); + mod_free(mod, cd); return 0; } @@ -113,7 +89,7 @@ static int eq_iir_set_config(struct processing_module *mod, uint32_t config_id, { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "eq_iir_set_config()"); + comp_info(mod->dev, "entry"); return comp_data_blob_set(cd->model_handler, pos, data_offset_size, fragment, fragment_size); @@ -126,11 +102,21 @@ static int eq_iir_get_config(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "eq_iir_get_config()"); + comp_info(mod->dev, "entry"); return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); } +static int eq_iir_check_blob_size(struct comp_dev *dev, size_t size) +{ + if (size < sizeof(struct sof_eq_iir_config) || size > SOF_EQ_IIR_MAX_SIZE) { + comp_err(dev, "invalid configuration blob, size %zu", size); + return -EINVAL; + } + + return 0; +} + static int eq_iir_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) @@ -143,8 +129,10 @@ static int eq_iir_process(struct processing_module *mod, /* Check for changed configuration */ if (comp_is_new_data_blob_available(cd->model_handler)) { - cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - ret = eq_iir_new_blob(mod, cd, audio_stream_get_frm_fmt(source), + cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL); + if (!cd->config || eq_iir_check_blob_size(mod->dev, cd->config_size) < 0) + return -EINVAL; + ret = eq_iir_new_blob(mod, audio_stream_get_frm_fmt(source), audio_stream_get_frm_fmt(sink), audio_stream_get_channels(source)); if (ret) @@ -166,7 +154,7 @@ static int eq_iir_process(struct processing_module *mod, static void eq_iir_set_alignment(struct audio_stream *source, struct audio_stream *sink) { - const uint32_t byte_align = 8; + const uint32_t byte_align = SOF_FRAME_BYTE_ALIGN; const uint32_t frame_align_req = 2; audio_stream_set_align(byte_align, frame_align_req, source); @@ -185,15 +173,20 @@ static int eq_iir_prepare(struct processing_module *mod, int channels; int ret = 0; - comp_dbg(dev, "eq_iir_prepare()"); + comp_dbg(dev, "entry"); + + /* EQ component will only ever have 1 source and 1 sink buffer */ + sourceb = comp_dev_get_first_data_producer(dev); + sinkb = comp_dev_get_first_data_consumer(dev); + if (!sourceb || !sinkb) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } ret = eq_iir_prepare_sub(mod); if (ret < 0) return ret; - /* EQ component will only ever have 1 source and 1 sink buffer */ - sourceb = comp_dev_get_first_data_producer(dev); - sinkb = comp_dev_get_first_data_consumer(dev); eq_iir_set_alignment(&sourceb->stream, &sinkb->stream); /* get source and sink data format */ @@ -201,23 +194,25 @@ static int eq_iir_prepare(struct processing_module *mod, 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); + cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL); /* Initialize EQ */ - comp_info(dev, "eq_iir_prepare(), source_format=%d, sink_format=%d", + comp_info(dev, "source_format=%d, sink_format=%d", source_format, sink_format); eq_iir_set_passthrough_func(cd, source_format, sink_format); /* Initialize EQ */ - if (cd->config) { - ret = eq_iir_new_blob(mod, cd, source_format, sink_format, channels); + if (cd->config && cd->config_size > 0) { + if (eq_iir_check_blob_size(dev, cd->config_size) < 0) + return -EINVAL; + ret = eq_iir_new_blob(mod, source_format, sink_format, channels); if (ret) return ret; } if (!cd->eq_iir_func) { - comp_err(dev, "eq_iir_prepare(), No processing function found"); + comp_err(dev, "No processing function found"); ret = -EINVAL; } @@ -229,7 +224,7 @@ static int eq_iir_reset(struct processing_module *mod) struct comp_data *cd = module_get_private_data(mod); int i; - eq_iir_free_delaylines(cd); + eq_iir_free_delaylines(mod); cd->eq_iir_func = NULL; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) @@ -248,9 +243,6 @@ static const struct module_interface eq_iir_interface = { .free = eq_iir_free }; -DECLARE_MODULE_ADAPTER(eq_iir_interface, eq_iir_uuid, eq_iir_tr); -SOF_MODULE_INIT(eq_iir, sys_comp_module_eq_iir_interface_init); - #if CONFIG_COMP_IIR_MODULE /* modular: llext dynamic link */ @@ -258,14 +250,15 @@ SOF_MODULE_INIT(eq_iir, sys_comp_module_eq_iir_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_EQIIR 0xE6, 0xC0, 0x50, 0x51, 0xF9, 0x27, 0xC8, 0x4E, \ - 0x83, 0x51, 0xC7, 0x05, 0xB6, 0x42, 0xD1, 0x2F - -SOF_LLEXT_MOD_ENTRY(eq_iir, &eq_iir_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("EQIIR", eq_iir_llext_entry, 1, UUID_EQIIR, 40); + SOF_LLEXT_MODULE_MANIFEST("EQIIR", &eq_iir_interface, 1, SOF_REG_UUID(eq_iir), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(eq_iir_tr, SOF_UUID(eq_iir_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(eq_iir_interface, eq_iir_uuid, eq_iir_tr); +SOF_MODULE_INIT(eq_iir, sys_comp_module_eq_iir_interface_init); + #endif diff --git a/src/audio/eq_iir/eq_iir.h b/src/audio/eq_iir/eq_iir.h index 7b6b6c247574..aa325a913005 100644 --- a/src/audio/eq_iir/eq_iir.h +++ b/src/audio/eq_iir/eq_iir.h @@ -39,6 +39,7 @@ struct comp_data { struct comp_data_blob_handler *model_handler; struct sof_eq_iir_config *config; int32_t *iir_delay; /**< pointer to allocated RAM */ + size_t config_size; /**< configuration size */ size_t iir_delay_size; /**< allocated size */ eq_iir_func eq_iir_func; /**< processing function */ }; @@ -56,9 +57,8 @@ void eq_iir_s24_default(struct processing_module *mod, struct input_stream_buffe void eq_iir_s32_default(struct processing_module *mod, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, uint32_t frames); -int eq_iir_new_blob(struct processing_module *mod, struct comp_data *cd, - enum sof_ipc_frame source_format, enum sof_ipc_frame sink_format, - int channels); +int eq_iir_new_blob(struct processing_module *mod, enum sof_ipc_frame source_format, + enum sof_ipc_frame sink_format, int channels); void eq_iir_set_passthrough_func(struct comp_data *cd, enum sof_ipc_frame source_format, @@ -71,5 +71,5 @@ void eq_iir_pass(struct processing_module *mod, struct input_stream_buffer *bsou int eq_iir_setup(struct processing_module *mod, int nch); -void eq_iir_free_delaylines(struct comp_data *cd); +void eq_iir_free_delaylines(struct processing_module *mod); #endif /* __SOF_AUDIO_EQ_IIR_EQ_IIR_H__ */ diff --git a/src/audio/eq_iir/eq_iir.toml b/src/audio/eq_iir/eq_iir.toml index ad369d38edce..a9933bffc9fb 100644 --- a/src/audio/eq_iir/eq_iir.toml +++ b/src/audio/eq_iir/eq_iir.toml @@ -5,7 +5,7 @@ REM # eq iir module config [[module.entry]] name = "EQIIR" - uuid = "5150C0E6-27F9-4EC8-8351-C705B642D12F" + uuid = UUIDREG_STR_EQ_IIR affinity_mask = "0x1" instance_count = "40" domain_types = "0" @@ -23,7 +23,8 @@ mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 1000, 0, 0, 0, 0, 0, 4096, 20663000, 768, 768, 0, 20663, 0, 0, 0, 0, 0, 4096, 11357000, 384, 384, 0, 11357, 0] -#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_PANTHERLAKE) +#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_SOC_ACE30) || \ + defined(CONFIG_SOC_ACE40) mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] #endif diff --git a/src/audio/eq_iir/eq_iir_generic.c b/src/audio/eq_iir/eq_iir_generic.c index 1941fbda3a8b..6eebcc4e0ed3 100644 --- a/src/audio/eq_iir/eq_iir_generic.c +++ b/src/audio/eq_iir/eq_iir_generic.c @@ -180,6 +180,65 @@ void eq_iir_s32_default(struct processing_module *mod, struct input_stream_buffe } #endif /* CONFIG_FORMAT_S32LE */ +static int eq_iir_blob_words_max(struct comp_dev *dev, + const struct sof_eq_iir_config *config, + size_t blob_size, + uint32_t *coef_words_max) +{ + size_t payload_bytes; + + /* Compute the size of the coefficient area in int32_t words from the + * framework-reported blob size. The blob layout is: + * sizeof(*config) header bytes + * channels_in_config int32_t assign_response[] + * coefficient data[] + * channels_in_config is bounded above, so the multiply fits in size_t. + * The blob's self-declared config->size is cross-checked against the + * authoritative blob_size so all later parsing stays within the buffer. + */ + if (blob_size < sizeof(*config) || config->size != blob_size) { + comp_err(dev, "blob size %zu / header size %u mismatch or too small", + blob_size, config->size); + return -EINVAL; + } + payload_bytes = blob_size - sizeof(*config); + if (payload_bytes % sizeof(int32_t) || + payload_bytes < (size_t)config->channels_in_config * sizeof(int32_t)) { + comp_err(dev, "blob size %zu misaligned or too small", blob_size); + return -EINVAL; + } + *coef_words_max = payload_bytes / sizeof(int32_t) - config->channels_in_config; + return 0; +} + +static int eq_iir_init_response(struct comp_dev *dev, int idx, + int32_t *coef_data, uint32_t coef_words_max, + uint32_t *j, struct sof_eq_iir_header **eq_out) +{ + struct sof_eq_iir_header *eq; + uint32_t header_end = *j + SOF_EQ_IIR_NHEADER; + uint32_t section_end; + + /* Header must fit before reading num_sections */ + if (header_end > coef_words_max) { + comp_err(dev, "response %d header out of bounds", idx); + return -EINVAL; + } + eq = (struct sof_eq_iir_header *)&coef_data[*j]; + /* Bound num_sections so the multiply cannot overflow and the section + * data stays within the blob. + */ + section_end = header_end + (uint32_t)SOF_EQ_IIR_NBIQUAD * eq->num_sections; + if (eq->num_sections > SOF_EQ_IIR_BIQUADS_MAX || section_end > coef_words_max) { + comp_err(dev, "response %d num_sections %u out of bounds", + idx, eq->num_sections); + return -EINVAL; + } + *eq_out = eq; + *j = section_end; + return 0; +} + static int eq_iir_init_coef(struct processing_module *mod, int nch) { struct comp_data *cd = module_get_private_data(mod); @@ -187,40 +246,46 @@ static int eq_iir_init_coef(struct processing_module *mod, int nch) struct iir_state_df1 *iir = cd->iir; struct sof_eq_iir_header *lookup[SOF_EQ_IIR_MAX_RESPONSES]; struct sof_eq_iir_header *eq; + uint32_t coef_words_max; int32_t *assign_response; int32_t *coef_data; int size_sum = 0; int resp = 0; int i; - int j; + uint32_t j; int s; + int ret; - comp_info(mod->dev, "eq_iir_init_coef(): %u responses, %u channels, stream %d channels", + comp_info(mod->dev, "%u responses, %u channels, stream %d channels", config->number_of_responses, config->channels_in_config, nch); /* Sanity checks */ if (nch > PLATFORM_MAX_CHANNELS || config->channels_in_config > PLATFORM_MAX_CHANNELS || !config->channels_in_config) { - comp_err(mod->dev, "eq_iir_init_coef(), invalid channels count"); + comp_err(mod->dev, "invalid channels count"); return -EINVAL; } if (config->number_of_responses > SOF_EQ_IIR_MAX_RESPONSES) { - comp_err(mod->dev, "eq_iir_init_coef(), # of resp exceeds max"); + comp_err(mod->dev, "# of resp exceeds max"); return -EINVAL; } + ret = eq_iir_blob_words_max(mod->dev, config, cd->config_size, &coef_words_max); + if (ret < 0) + return ret; + /* Collect index of response start positions in all_coefficients[] */ j = 0; assign_response = ASSUME_ALIGNED(&config->data[0], 4); - coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config], - 4); + coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config], 4); for (i = 0; i < SOF_EQ_IIR_MAX_RESPONSES; i++) { if (i < config->number_of_responses) { - eq = (struct sof_eq_iir_header *)&coef_data[j]; + ret = eq_iir_init_response(mod->dev, i, coef_data, + coef_words_max, &j, &eq); + if (ret < 0) + return ret; lookup[i] = eq; - j += SOF_EQ_IIR_NHEADER - + SOF_EQ_IIR_NBIQUAD * eq->num_sections; } else { lookup[i] = NULL; } @@ -241,13 +306,13 @@ static int eq_iir_init_coef(struct processing_module *mod, int nch) /* Initialize EQ channel to bypass and continue with * next channel response. */ - comp_info(mod->dev, "eq_iir_init_coef(), ch %d is set to bypass", i); + comp_info(mod->dev, "ch %d is set to bypass", i); iir_reset_df1(&iir[i]); continue; } if (resp >= config->number_of_responses) { - comp_err(mod->dev, "eq_iir_init_coef(), requested response %d exceeds defined", + comp_err(mod->dev, "requested response %d exceeds defined", resp); return -EINVAL; } @@ -258,13 +323,13 @@ static int eq_iir_init_coef(struct processing_module *mod, int nch) if (s > 0) { size_sum += s; } else { - comp_err(mod->dev, "eq_iir_init_coef(), sections count %d exceeds max", + comp_err(mod->dev, "sections count %d exceeds max", eq->num_sections); return -EINVAL; } iir_init_coef_df1(&iir[i], eq); - comp_info(mod->dev, "eq_iir_init_coef(), ch %d is set to response %d", i, resp); + comp_info(mod->dev, "ch %d is set to response %d", i, resp); } return size_sum; @@ -285,15 +350,16 @@ static void eq_iir_init_delay(struct iir_state_df1 *iir, } } -void eq_iir_free_delaylines(struct comp_data *cd) +void eq_iir_free_delaylines(struct processing_module *mod) { + struct comp_data *cd = module_get_private_data(mod); struct iir_state_df1 *iir = cd->iir; int i = 0; /* Free the common buffer for all EQs and point then * each IIR channel delay line to NULL. */ - rfree(cd->iir_delay); + mod_free(mod, cd->iir_delay); cd->iir_delay = NULL; cd->iir_delay_size = 0; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) @@ -315,9 +381,12 @@ int eq_iir_setup(struct processing_module *mod, int nch) int delay_size; /* Free existing IIR channels data if it was allocated */ - eq_iir_free_delaylines(cd); + eq_iir_free_delaylines(mod); - /* Set coefficients for each channel EQ from coefficient blob */ + /* Set coefficients for each channel EQ from coefficient blob. + * eq_iir_init_coef() / eq_iir_blob_words_max() perform all blob size + * sanity checks, including config->size vs cd->config_size. + */ delay_size = eq_iir_init_coef(mod, nch); if (delay_size < 0) return delay_size; /* Contains error code */ @@ -329,10 +398,9 @@ int eq_iir_setup(struct processing_module *mod, int nch) return 0; /* Allocate all IIR channels data in a big chunk and clear it */ - cd->iir_delay = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - delay_size); + cd->iir_delay = mod_zalloc(mod, delay_size); if (!cd->iir_delay) { - comp_err(mod->dev, "eq_iir_setup(), delay allocation fail"); + comp_err(mod->dev, "delay allocation fail"); return -ENOMEM; } diff --git a/src/audio/eq_iir/eq_iir_ipc3.c b/src/audio/eq_iir/eq_iir_ipc3.c index ca611bc8a819..69b27d64c3e7 100644 --- a/src/audio/eq_iir/eq_iir_ipc3.c +++ b/src/audio/eq_iir/eq_iir_ipc3.c @@ -17,7 +17,6 @@ #include <sof/common.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> #include <sof/list.h> @@ -270,7 +269,9 @@ static int eq_iir_verify_params(struct comp_dev *dev, uint32_t buffer_flag; int ret; - comp_dbg(dev, "eq_iir_verify_params()"); + comp_dbg(dev, "entry"); + + /* The caller has verified, that sink and source buffers are connected */ /* EQ component will only ever have 1 source and 1 sink buffer */ sourceb = comp_dev_get_first_data_producer(dev); @@ -289,29 +290,29 @@ static int eq_iir_verify_params(struct comp_dev *dev, ret = comp_verify_params(dev, buffer_flag, params); if (ret < 0) { - comp_err(dev, "eq_iir_verify_params(): comp_verify_params() failed."); + comp_err(dev, "comp_verify_params() failed."); return ret; } return 0; } -int eq_iir_new_blob(struct processing_module *mod, struct comp_data *cd, - enum sof_ipc_frame source_format, enum sof_ipc_frame sink_format, - int channels) +int eq_iir_new_blob(struct processing_module *mod, enum sof_ipc_frame source_format, + enum sof_ipc_frame sink_format, int channels) { + struct comp_data *cd = module_get_private_data(mod); int ret; ret = eq_iir_setup(mod, channels); if (ret < 0) { - comp_err(mod->dev, "eq_iir_new_blob(), failed IIR setup"); + comp_err(mod->dev, "failed IIR setup"); return ret; } else if (cd->iir_delay_size) { - comp_dbg(mod->dev, "eq_iir_new_blob(), active"); + comp_dbg(mod->dev, "active"); cd->eq_iir_func = eq_iir_find_func(source_format, sink_format, fm_configured, ARRAY_SIZE(fm_configured)); } else { - comp_dbg(mod->dev, "eq_iir_new_blob(), pass-through"); + comp_dbg(mod->dev, "pass-through"); cd->eq_iir_func = eq_iir_find_func(source_format, sink_format, fm_passthrough, ARRAY_SIZE(fm_passthrough)); } diff --git a/src/audio/eq_iir/eq_iir_ipc4.c b/src/audio/eq_iir/eq_iir_ipc4.c index 94e984e8a4ac..c19d7f2650fa 100644 --- a/src/audio/eq_iir/eq_iir_ipc4.c +++ b/src/audio/eq_iir/eq_iir_ipc4.c @@ -17,7 +17,6 @@ #include <sof/common.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> #include <sof/list.h> @@ -57,7 +56,7 @@ static eq_iir_func eq_iir_find_func(struct processing_module *mod) { unsigned int valid_bit_depth = mod->priv.cfg.base_cfg.audio_fmt.valid_bit_depth; - comp_dbg(mod->dev, "eq_iir_find_func(): valid_bit_depth %d", valid_bit_depth); + comp_dbg(mod->dev, "valid_bit_depth %d", valid_bit_depth); switch (valid_bit_depth) { #if CONFIG_FORMAT_S16LE case IPC4_DEPTH_16BIT: @@ -77,21 +76,21 @@ static eq_iir_func eq_iir_find_func(struct processing_module *mod) return NULL; } -int eq_iir_new_blob(struct processing_module *mod, struct comp_data *cd, - enum sof_ipc_frame source_format, enum sof_ipc_frame sink_format, - int channels) +int eq_iir_new_blob(struct processing_module *mod, enum sof_ipc_frame source_format, + enum sof_ipc_frame sink_format, int channels) { + struct comp_data *cd = module_get_private_data(mod); int ret; ret = eq_iir_setup(mod, channels); if (ret < 0) { - comp_err(mod->dev, "eq_iir_new_blob(), failed IIR setup"); + comp_err(mod->dev, "failed IIR setup"); return ret; } else if (cd->iir_delay_size) { - comp_dbg(mod->dev, "eq_iir_new_blob(), active"); + comp_dbg(mod->dev, "active"); cd->eq_iir_func = eq_iir_find_func(mod); } else { - comp_dbg(mod->dev, "eq_iir_new_blob(), pass-through"); + comp_dbg(mod->dev, "pass-through"); cd->eq_iir_func = eq_iir_pass; } @@ -105,9 +104,9 @@ static int eq_iir_params(struct processing_module *mod) struct comp_dev *dev = mod->dev; struct comp_buffer *sinkb; enum sof_ipc_frame valid_fmt, frame_fmt; - int i, ret; + int i; - comp_dbg(dev, "eq_iir_params()"); + comp_dbg(dev, "entry"); comp_params = *params; comp_params.channels = mod->priv.cfg.base_cfg.audio_fmt.channels_count; comp_params.rate = mod->priv.cfg.base_cfg.audio_fmt.sampling_frequency; @@ -124,9 +123,10 @@ static int eq_iir_params(struct processing_module *mod) comp_params.chmap[i] = (mod->priv.cfg.base_cfg.audio_fmt.ch_map >> i * 4) & 0xf; component_set_nearest_period_frames(dev, comp_params.rate); + + /* The caller has verified, that sink and source buffers are connected */ sinkb = comp_dev_get_first_data_consumer(dev); - ret = buffer_set_params(sinkb, &comp_params, true); - return ret; + return buffer_set_params(sinkb, &comp_params, true); } void eq_iir_set_passthrough_func(struct comp_data *cd, diff --git a/src/audio/eq_iir/tune/sof_cmocka_data_eq_fir.m b/src/audio/eq_iir/tune/sof_cmocka_data_eq_fir.m index 6fc47aee2f14..fd9e4a91f797 100644 --- a/src/audio/eq_iir/tune/sof_cmocka_data_eq_fir.m +++ b/src/audio/eq_iir/tune/sof_cmocka_data_eq_fir.m @@ -9,6 +9,8 @@ function sof_cmocka_data_eq_fir() +sof_eq_paths(true); + % Output files and paths sof_cmocka = '../../../../test/cmocka'; @@ -44,6 +46,8 @@ function sof_cmocka_data_eq_fir() plot(refi / scale) grid on; +sof_eq_paths(false); + end diff --git a/src/audio/eq_iir/tune/sof_cmocka_data_eq_iir.m b/src/audio/eq_iir/tune/sof_cmocka_data_eq_iir.m index 388a14039c48..6c9b3732f283 100644 --- a/src/audio/eq_iir/tune/sof_cmocka_data_eq_iir.m +++ b/src/audio/eq_iir/tune/sof_cmocka_data_eq_iir.m @@ -9,6 +9,8 @@ function sof_cmocka_data_eq_iir() +sof_eq_paths(true); + % Output files and paths sof_cmocka = '../../../../test/cmocka'; chirp_fn = fullfile(sof_cmocka, 'include/cmocka_chirp_2ch.h'); @@ -45,6 +47,8 @@ function sof_cmocka_data_eq_iir() plot(refi / scale) grid on; +sof_eq_paths(false); + end diff --git a/src/audio/eq_iir/tune/sof_eq_alsactl_write.m b/src/audio/eq_iir/tune/sof_eq_alsactl_write.m deleted file mode 100644 index f6c49128dbc6..000000000000 --- a/src/audio/eq_iir/tune/sof_eq_alsactl_write.m +++ /dev/null @@ -1,56 +0,0 @@ -function sof_eq_alsactl_write(fn, blob8) - -%% -% 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: -% * Redistributions of source code must retain the above copyright -% notice, this list of conditions and the following disclaimer. -% * 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. -% * Neither the name of the Intel Corporation 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 OWNER 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. -% -% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> -% - -%% Write blob -fh = fopen(fn, 'w'); - -%% Pad blob length to multiple of four bytes -n_orig = length(blob8); -n_new = ceil(n_orig/4); -blob8_new = zeros(1, n_new*4); -blob8_new(1:n_orig) = blob8; - -%% Convert to 32 bit -blob32 = zeros(1, n_new, 'uint32'); -k = 2.^[0 8 16 24]; -for i=1:n_new - j = (i-1)*4; - blob32(i) = blob8_new(j+1)*k(1) + blob8_new(j+2)*k(2) ... - + blob8_new(j+3)*k(3) + blob8_new(j+4)*k(4); -end -for i=1:n_new-1 - fprintf(fh, '%ld,', blob32(i)); -end -fprintf(fh, '%ld,\n', blob32(end)); -fclose(fh); - -end diff --git a/src/audio/eq_iir/tune/sof_eq_blob_plot.m b/src/audio/eq_iir/tune/sof_eq_blob_plot.m index cb096e863a6e..369c311fc96f 100644 --- a/src/audio/eq_iir/tune/sof_eq_blob_plot.m +++ b/src/audio/eq_iir/tune/sof_eq_blob_plot.m @@ -26,13 +26,13 @@ % SPDX-License-Identifier: BSD-3-Clause % -% Copyright (c) 2016-2022, Intel Corporation. All rights reserved. +% Copyright (c) 2016-2025, Intel Corporation. % % Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> %% Handle input parameters if nargin < 2 - if findstr(blobfn, '_fir_') + if strfind(blobfn, '_fir') eqtype = 'FIR'; else eqtype = 'IIR'; diff --git a/src/audio/eq_iir/tune/sof_eq_blob_read.m b/src/audio/eq_iir/tune/sof_eq_blob_read.m index d95613507c91..424e8c74ad93 100644 --- a/src/audio/eq_iir/tune/sof_eq_blob_read.m +++ b/src/audio/eq_iir/tune/sof_eq_blob_read.m @@ -2,17 +2,18 @@ % SPDX-License-Identifier: BSD-3-Clause % -% Copyright (c) 2020, Intel Corporation. All rights reserved. +% Copyright (c) 2020-2025, Intel Corporation. % % Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> %% Use file suffix as type if nargin < 2 - idx = findstr(blobfn, '.'); + idx = strfind(blobfn, '.'); fntype = blobfn(idx(end)+1:end); end %% Read the file +add_tlv_header = false; switch lower(fntype) case 'bin' fh = fopen(blobfn, 'rb'); @@ -23,13 +24,21 @@ tmp = fscanf(fh, '%u,', Inf); fclose(fh); case 'm4' + % The blobs in topology are without TLV header. For simplicity + % add to beginning two 32 bit words (zeros) to be compatible + % with other blob formats. tmp = get_parse_m4(blobfn); + add_tlv_header = true; otherwise error('Illegal file type, please give fntype argument'); end -blob = uint32(tmp); +if add_tlv_header + blob = uint32([0 0 tmp']'); +else + blob = uint32(tmp); +end end @@ -46,7 +55,7 @@ n = 1; ln = fgets(fh); while ln ~= -1 - idx = findstr(ln, '0x'); + idx = strfind(ln, '0x'); for i = 1:length(idx) bytes(n) = hex2dec(ln(idx(i)+2:idx(i)+3)); n = n + 1; diff --git a/src/audio/eq_iir/tune/sof_eq_fir_blob_decode.m b/src/audio/eq_iir/tune/sof_eq_fir_blob_decode.m index 5efa140b0f08..4d0ecbe52725 100644 --- a/src/audio/eq_iir/tune/sof_eq_fir_blob_decode.m +++ b/src/audio/eq_iir/tune/sof_eq_fir_blob_decode.m @@ -35,7 +35,7 @@ end %% Get ABI information -[abi_bytes, nbytes_abi] = sof_eq_get_abi(0); +[abi_bytes, nbytes_abi] = sof_get_abi(0); %% Defaults eq.b = []; diff --git a/src/audio/eq_iir/tune/sof_eq_fir_blob_pack.m b/src/audio/eq_iir/tune/sof_eq_fir_blob_pack.m index 9fd5f0aec8a5..66bd3142fc55 100644 --- a/src/audio/eq_iir/tune/sof_eq_fir_blob_pack.m +++ b/src/audio/eq_iir/tune/sof_eq_fir_blob_pack.m @@ -89,7 +89,7 @@ nbytes_data = nb16 * 2; %% Get ABI information -[abi_bytes, nbytes_abi] = sof_eq_get_abi(nbytes_data, ipc_ver); +[abi_bytes, nbytes_abi] = sof_get_abi(nbytes_data, ipc_ver); %% Initialize uint8 array with correct size nbytes = nbytes_abi + nbytes_data; diff --git a/src/audio/eq_iir/tune/sof_eq_get_abi.m b/src/audio/eq_iir/tune/sof_eq_get_abi.m deleted file mode 100644 index 6677af48c6ec..000000000000 --- a/src/audio/eq_iir/tune/sof_eq_get_abi.m +++ /dev/null @@ -1,73 +0,0 @@ -function [bytes, nbytes] = sof_eq_get_abi(setsize, ipc_ver, type, param_id) - -%% Return current SOF ABI header -% -% [bytes, nbytes] = sof_eq_get_abi(setsize, ipc_ver, type, param_id) -% Input -% setsize - size of the payload blob -% ipc_ver - 3 or 4, defaults to 3 -% type - for IPC3, normally 0, defaults to 0 -% param_id - for IPC4, 0 - 255, defaults to 0 -% -% Output -% bytes - returned uint8 type array -% nbytes - length of the array - -% SPDX-License-Identifier: BSD-3-Clause -% -% Copyright(c) 2018 Intel Corporation. All rights reserved. -% -% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> - -if nargin < 2 - ipc_ver = 3; -end -if nargin < 3 - type = 0; -end -if nargin < 4 - param_id = 0; -end - -abifn = 'eq_get_abi.bin'; -switch ipc_ver - case 3 - %% Use sof-ctl to write ABI header into a file - cmd = sprintf('sof-ctl -g %d -t %d -b -o %s', setsize, type, abifn); - [bytes, nbytes] = get_abi_with_sofctl(cmd, abifn); - case 4 - cmd = sprintf('sof-ctl -i 4 -g %d -p %d -b -o %s', setsize, param_id, abifn); - [bytes, nbytes] = get_abi_with_sofctl(cmd, abifn); - otherwise - fprintf(1, 'Illegal ipc_ver %d\n', ipc_ver); - error('Failed.'); -end - -end - -function [bytes, nbytes] = get_abi_with_sofctl(cmd, abifn) - -[ret, ~] = system(cmd); -if ret - error('Failed to run sof-ctl. Is it installed?'); -end -fh = fopen(abifn, 'r'); -if fh < 0 - error('Failed to read abi header produced by sof-ctl'); -end -[bytes, nbytes] = fread(fh, inf, 'uint8'); -fclose(fh); -delete(abifn); - -end - -function bytes = w32b(word) - -sh = [0 -8 -16 -24]; -bytes = uint8(zeros(1,4)); -bytes(1) = bitand(bitshift(word, sh(1)), 255); -bytes(2) = bitand(bitshift(word, sh(2)), 255); -bytes(3) = bitand(bitshift(word, sh(3)), 255); -bytes(4) = bitand(bitshift(word, sh(4)), 255); - -end diff --git a/src/audio/eq_iir/tune/sof_eq_iir_blob_decode.m b/src/audio/eq_iir/tune/sof_eq_iir_blob_decode.m index d721d9c34770..f54c88f63eb5 100644 --- a/src/audio/eq_iir/tune/sof_eq_iir_blob_decode.m +++ b/src/audio/eq_iir/tune/sof_eq_iir_blob_decode.m @@ -34,7 +34,7 @@ end %% Get ABI information -[abi_bytes, nbytes_abi] = get_abi(0); +[abi_bytes, nbytes_abi] = sof_get_abi(0); %% Defaults eq.b = []; diff --git a/src/audio/eq_iir/tune/sof_eq_iir_blob_pack.m b/src/audio/eq_iir/tune/sof_eq_iir_blob_pack.m index 35b9fffc0ed7..829a07e81843 100644 --- a/src/audio/eq_iir/tune/sof_eq_iir_blob_pack.m +++ b/src/audio/eq_iir/tune/sof_eq_iir_blob_pack.m @@ -43,7 +43,7 @@ nbytes_data = nbytes_head + nbytes_coef; %% Get ABI information -[abi_bytes, nbytes_abi] = sof_eq_get_abi(nbytes_data, ipc_ver); +[abi_bytes, nbytes_abi] = sof_get_abi(nbytes_data, ipc_ver); %% Initialize correct size uint8 array nbytes = nbytes_abi + nbytes_data; diff --git a/src/audio/eq_iir/tune/sof_eq_plot.m b/src/audio/eq_iir/tune/sof_eq_plot.m index 874bfe596c3e..4a11cf25c25f 100644 --- a/src/audio/eq_iir/tune/sof_eq_plot.m +++ b/src/audio/eq_iir/tune/sof_eq_plot.m @@ -75,14 +75,17 @@ function sof_eq_plot(eq, fn) eq.f, eq.iir_eq_db + offs_iir, '--',... eq.f, eq.fir_eq_db + offs_fir, '--'); legend('Target', 'Combined', 'IIR', 'FIR', 'Location', 'NorthWest'); + eq.diff_db = eq.tot_eq_db + offs_tot - eq.err_db_s; end if eq.enable_fir && eq.enable_iir == 0 semilogx(eq.f, eq.err_db_s, eq.f, eq.fir_eq_db + offs_fir); legend('Target', 'FIR', 'Location', 'NorthWest'); + eq.diff_db = eq.fir_eq_db + offs_fir - eq.err_db_s; end if eq.enable_fir == 0 && eq.enable_iir semilogx(eq.f, eq.err_db_s, eq.f, eq.iir_eq_db + offs_iir); legend('Target', 'IIR', 'Location', 'NorthWest'); + eq.diff_db = eq.iir_eq_db + offs_iir - eq.err_db_s; end grid on; ax=axis; axis([eq.p_fmin eq.p_fmax min(max(ax(3:4), -40), 40)]); @@ -91,6 +94,15 @@ function sof_eq_plot(eq, fn) tstr = sprintf('Filter target vs. achieved response: %s', eq.name); title(tstr); +fh=figure(fn); fn = fn+1; +semilogx(eq.f, eq.diff_db) +grid on; +ax=axis; axis([eq.p_fmin eq.p_fmax -5 5]); +xlabel('Frequency (Hz)'); +ylabel('Magnitude (dB)'); +tstr = sprintf('Response difference mean abs %.4f dB: %s', mean(abs(eq.diff_db)), eq.name); +title(tstr); + %% FIR filter if length(eq.b_fir) > 1 % Response diff --git a/src/audio/eq_iir/tune/sof_eq_tplg2_write.m b/src/audio/eq_iir/tune/sof_eq_tplg2_write.m deleted file mode 100644 index e3f28ddfa9a2..000000000000 --- a/src/audio/eq_iir/tune/sof_eq_tplg2_write.m +++ /dev/null @@ -1,45 +0,0 @@ -function sof_eq_tplg2_write(fn, blob8, component, comment) - -% SPDX-License-Identifier: BSD-3-Clause -% -% Copyright (c) 2023, Intel Corporation. All rights reserved. -% -% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> - -if nargin < 2 - comment = 'Exported EQ'; -end - -%% Check that blob length is multiple of 32 bits -n_blob = length(blob8); -n_test = ceil(n_blob/4)*4; -if (n_blob ~= n_test) - fprintf(1, 'Error: ´Blob length %d is not multiple of 32 bits\n', ... - n_blob); - error('Failed.'); -end - -%% Write blob -fh = fopen(fn, 'w'); -nl = 8; -fprintf(fh, '# %s %s\n', comment, date()); -fprintf(fh, 'Object.Base.data.\"%s\" {\n', component); -fprintf(fh, '\tbytes \"\n'); -for i = 1:nl:n_blob - fprintf(fh, '\t\t'); - for j = 0:nl-1 - n = i + j; - if n < n_blob - fprintf(fh, '0x%02x,', blob8(n)); - end - if n == n_blob - fprintf(fh, '0x%02x"', blob8(n)); - end - end - fprintf(fh, '\n'); -end -fprintf(fh, '}\n'); -fclose(fh); -fprintf('Blob size %d was written to file %s\n', n_blob, fn); - -end diff --git a/src/audio/eq_iir/tune/sof_eq_tplg_write.m b/src/audio/eq_iir/tune/sof_eq_tplg_write.m deleted file mode 100644 index f178be8ba215..000000000000 --- a/src/audio/eq_iir/tune/sof_eq_tplg_write.m +++ /dev/null @@ -1,47 +0,0 @@ -function sof_eq_tplg_write(fn, blob8, priv, comment) - -% SPDX-License-Identifier: BSD-3-Clause -% -% Copyright (c) 2018-2020, Intel Corporation. All rights reserved. -% -% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> - -if nargin < 4 - comment = 'Exported EQ'; -end - -%% Check that blob length is multiple of 32 bits -n_blob = length(blob8); -n_test = ceil(n_blob/4)*4; -if (n_blob ~= n_test) - fprintf(1, 'Error: ´Blob length %d is not multiple of 32 bits\n', ... - n_blob); - error('Failed.'); -end - -%% Write blob -fh = fopen(fn, 'w'); -nl = 8; -fprintf(fh, '# %s %s\n', comment, date()); -fprintf(fh, 'CONTROLBYTES_PRIV(%s,\n', priv); -fprintf(fh, '` bytes "'); -for i = 1:nl:n_blob - if i > 1 - fprintf(fh, '` '); - end - for j = 0:nl-1 - n = i + j; - if n < n_blob - fprintf(fh, '0x%02x,', blob8(n)); - end - if n == n_blob - fprintf(fh, '0x%02x"', blob8(n)); - end - end - fprintf(fh, '''\n'); -end -fprintf(fh, ')\n'); -fclose(fh); -fprintf('Blob size %d was written to file %s\n', n_blob, fn); - -end diff --git a/src/audio/eq_iir/tune/sof_example_fir_eq.m b/src/audio/eq_iir/tune/sof_example_fir_eq.m index a3d5fdbeadd6..a1e47396ce7e 100644 --- a/src/audio/eq_iir/tune/sof_example_fir_eq.m +++ b/src/audio/eq_iir/tune/sof_example_fir_eq.m @@ -24,7 +24,7 @@ function sof_example_fir_eq() %% ------------------- %% Example 1: Loudness %% ------------------- -fn.bin = 'loudness.blob'; +fn.bin = 'loudness.bin'; fn.txt = 'loudness.txt'; fn.tplg1 = 'eq_fir_coef_loudness.m4'; fn.tplg2 = 'loudness.conf'; @@ -55,7 +55,7 @@ function sof_example_fir_eq() %% ------------------- %% Example 2: Mid boost %% ------------------- -fn.bin = 'mid.blob'; +fn.bin = 'mid.bin'; fn.txt = 'mid.txt'; fn.tplg1 = 'eq_fir_coef_mid.m4'; fn.tplg2 = 'midboost.conf'; @@ -82,7 +82,7 @@ function sof_example_fir_eq() %% ------------------- %% Example 3: Flat EQ %% ------------------- -fn.bin = 'flat.blob'; +fn.bin = 'flat.bin'; fn.txt = 'flat.txt'; fn.tplg1 = 'eq_fir_coef_flat.m4'; fn.tplg2 = 'flat.conf'; @@ -109,7 +109,7 @@ function sof_example_fir_eq() %% -------------------------- %% Example 4: Pass-through EQ %% -------------------------- -fn.bin = 'pass.blob'; +fn.bin = 'pass.bin'; fn.txt = 'pass.txt'; fn.tplg1 = 'eq_fir_coef_pass.m4'; fn.tplg2 = 'passthrough.conf'; @@ -226,15 +226,16 @@ function sof_example_fir_eq() % Pack and write file common function for all exports function sof_eq_pack_export(bm, fn, note) +howto = 'cd src/audio/eq_iir/tune; octave --no-window-system sof_example_fir_eq.m'; bp = sof_eq_fir_blob_pack(bm, 3); % IPC3 if ~isempty(fn.bin) sof_ucm_blob_write(fullfile(fn.cpath3, fn.bin), bp); end if ~isempty(fn.txt) - sof_eq_alsactl_write(fullfile(fn.cpath3, fn.txt), bp); + sof_alsactl_write(fullfile(fn.cpath3, fn.txt), bp); end if ~isempty(fn.tplg1) - sof_eq_tplg_write(fullfile(fn.tpath1, fn.tplg1), bp, fn.priv, note); + sof_tplg_write(fullfile(fn.tpath1, fn.tplg1), bp, fn.priv, note, howto); end bp = sof_eq_fir_blob_pack(bm, 4); % IPC4 @@ -242,10 +243,10 @@ function sof_eq_pack_export(bm, fn, note) sof_ucm_blob_write(fullfile(fn.cpath4, fn.bin), bp); end if ~isempty(fn.txt) - sof_eq_alsactl_write(fullfile(fn.cpath4, fn.txt), bp); + sof_alsactl_write(fullfile(fn.cpath4, fn.txt), bp); end if ~isempty(fn.tplg2) - sof_eq_tplg2_write(fullfile(fn.tpath2, fn.tplg2), bp, 'fir_eq', note); + sof_tplg2_write(fullfile(fn.tpath2, fn.tplg2), bp, 'fir_eq', note, howto); end end diff --git a/src/audio/eq_iir/tune/sof_example_iir_bandsplit.m b/src/audio/eq_iir/tune/sof_example_iir_bandsplit.m index 23b96646d5cf..37a34342c678 100644 --- a/src/audio/eq_iir/tune/sof_example_iir_bandsplit.m +++ b/src/audio/eq_iir/tune/sof_example_iir_bandsplit.m @@ -20,7 +20,7 @@ function sof_example_iir_bandsplit() %% -------------------------------------------------- %% Example: Band-split 2ch to 4ch low and high bands %% -------------------------------------------------- -blob_fn = fullfile(cpath, 'bandsplit.blob'); +blob_fn = fullfile(cpath, 'bandsplit.bin'); alsa_fn = fullfile(cpath, 'bandsplit.txt'); tplg_fn = fullfile(tpath, 'eq_iir_bandsplit.m4'); comment = 'Bandsplit, created with example_iir_bandsplit.m'; @@ -133,11 +133,11 @@ function sof_eq_pack_export(bm, bin_fn, ascii_fn, tplg_fn, priv, note) end if ~isempty(ascii_fn) - sof_eq_alsactl_write(ascii_fn, bp); + sof_alsactl_write(ascii_fn, bp); end if ~isempty(tplg_fn) - sof_eq_tplg_write(tplg_fn, bp, priv, note); + sof_tplg_write(tplg_fn, bp, priv, note); end end diff --git a/src/audio/eq_iir/tune/sof_example_iir_eq.m b/src/audio/eq_iir/tune/sof_example_iir_eq.m index 50d966a17c41..eef0f2751300 100644 --- a/src/audio/eq_iir/tune/sof_example_iir_eq.m +++ b/src/audio/eq_iir/tune/sof_example_iir_eq.m @@ -2,7 +2,7 @@ % SPDX-License-Identifier: BSD-3-Clause % -% Copyright (c) 2016-2020, Intel Corporation. All rights reserved. +% Copyright (c) 2016-2026, Intel Corporation. % % Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> @@ -24,7 +24,7 @@ function sof_example_iir_eq() %% ------------------- %% Example 1: Loudness %% ------------------- -fn.bin = 'loudness.blob'; +fn.bin = 'loudness.bin'; fn.txt = 'loudness.txt'; fn.tplg1 = 'eq_iir_coef_loudness.m4'; fn.tplg2 = 'loudness.conf'; @@ -55,7 +55,7 @@ function sof_example_iir_eq() %% ------------------------------------ %% Example 2: Bass boost %% ------------------------------------ -fn.bin = 'bassboost.blob'; +fn.bin = 'bassboost.bin'; fn.txt = 'bassboost.txt'; fn.tplg1 = 'eq_iir_coef_bassboost.m4'; fn.tplg2 = 'bassboost.conf'; @@ -82,7 +82,7 @@ function sof_example_iir_eq() %% ------------------------------------ %% Example 3: Band-pass %% ------------------------------------ -fn.bin = 'bandpass.blob'; +fn.bin = 'bandpass.bin'; fn.txt = 'bandpass.txt'; fn.tplg1 = 'eq_iir_coef_bandpass.m4'; fn.tplg2 = 'bandpass.conf'; @@ -109,7 +109,7 @@ function sof_example_iir_eq() %% ------------------- %% Example 4: Flat IIR %% ------------------- -fn.bin = 'flat.blob'; +fn.bin = 'flat.bin'; fn.txt = 'flat.txt'; fn.tplg1 = 'eq_iir_coef_flat.m4'; fn.tplg2 = 'flat.conf'; @@ -136,7 +136,7 @@ function sof_example_iir_eq() %% --------------------------- %% Example 5: Pass-through IIR %% --------------------------- -fn.bin = 'pass.blob'; +fn.bin = 'pass.bin'; fn.txt = 'pass.txt'; fn.tplg1 = 'eq_iir_coef_pass.m4'; fn.tplg2 = 'passthrough.conf'; @@ -166,7 +166,7 @@ function sof_example_iir_eq() fs_list = [16e3 48e3]; fc_list = [20 30 40 50 100]; -g_list = [0 20]; +g_list = [0 16 20 30 40]; for i = 1:length(fs_list) for j = 1:length(fc_list); for k = 1:length(g_list); @@ -180,7 +180,7 @@ function sof_example_iir_eq() fn.txt = sprintf('highpass_%dhz_%ddb_%dkhz.txt', fc, g, fsk); comment = sprintf('%d Hz second order high-pass, gain %d dB, created with sof_example_iir_eq.m', ... fc, g); - fn.bin = sprintf('highpass_%dhz_%ddb_%dkhz.blob', fc, g, fsk); + fn.bin = sprintf('highpass_%dhz_%ddb_%dkhz.bin', fc, g, fsk); %% Design IIR high-pass eq_hp = hp_iir_eq(fs, fc, g); @@ -207,7 +207,7 @@ function sof_example_iir_eq() %% Example 7: Merge previous desigs to single blob for use as presets %% ------------------------------------------------------------------ -fn.bin = 'bundle.blob'; +fn.bin = 'bundle.bin'; fn.txt = 'bundle.txt'; fn.tplg1 = 'eq_iir_bundle.m4'; fn.tplg2 = 'bundle.conf'; @@ -354,15 +354,16 @@ function sof_example_iir_eq() % Pack and write file common function for all exports function sof_eq_pack_export(bm, fn, note) +howto = 'cd src/audio/eq_iir/tune; octave --no-window-system sof_example_iir_eq.m'; bp = sof_eq_iir_blob_pack(bm, 3); % IPC3 if ~isempty(fn.bin) sof_ucm_blob_write(fullfile(fn.cpath3, fn.bin), bp); end if ~isempty(fn.txt) - sof_eq_alsactl_write(fullfile(fn.cpath3, fn.txt), bp); + sof_alsactl_write(fullfile(fn.cpath3, fn.txt), bp); end if ~isempty(fn.tplg1) - sof_eq_tplg_write(fullfile(fn.tpath1, fn.tplg1), bp, fn.priv, note); + sof_tplg_write(fullfile(fn.tpath1, fn.tplg1), bp, fn.priv, note, howto); end bp = sof_eq_iir_blob_pack(bm, 4); % IPC4 @@ -370,10 +371,10 @@ function sof_eq_pack_export(bm, fn, note) sof_ucm_blob_write(fullfile(fn.cpath4, fn.bin), bp); end if ~isempty(fn.txt) - sof_eq_alsactl_write(fullfile(fn.cpath4, fn.txt), bp); + sof_alsactl_write(fullfile(fn.cpath4, fn.txt), bp); end if ~isempty(fn.tplg2) - sof_eq_tplg2_write(fullfile(fn.tpath2, fn.tplg2), bp, 'iir_eq', note); + sof_tplg2_write(fullfile(fn.tpath2, fn.tplg2), bp, 'iir_eq', note, howto); end end diff --git a/src/audio/eq_iir/tune/sof_example_lr4.m b/src/audio/eq_iir/tune/sof_example_lr4.m new file mode 100644 index 000000000000..d38111da6b98 --- /dev/null +++ b/src/audio/eq_iir/tune/sof_example_lr4.m @@ -0,0 +1,183 @@ +% sof_example_lr4 - Design 4th order Linkwitz–Riley filter bank +% +% This script is run without arguments. It creates IIR equalizer +% blobs for crossover filter bank for 2-way speaker and four +% channels stream. The exported configurations are Linkwitz-Riley +% 4th order with crossover frequency at 2 kHz. The filters are +% in order: +% - low, high, low, high +% - low, low, high, high +% - high, high, low, low +% + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2025, Intel Corporation. +% +% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +function sof_example_lr4() + +%% Common definitions +fs = 48e3; +fc = 2e3; +sof_tools = '../../../../tools'; +tpath = fullfile(sof_tools, 'topology/topology2/include/components/eqiir'); +cpath = fullfile(sof_tools, 'ctl/ipc4/eq_iir'); + +sof_eq_paths(1); + +%% -------------------------------------------------- +%% Example: Band-split 2ch to 4ch low and high bands +%% -------------------------------------------------- +design_name = sprintf('xover_lr4_%dhz_lhlh_%dkhz', fc, round(fs/1000)); +blob_fn = fullfile(cpath, [design_name '.bin']); +alsa_fn = fullfile(cpath, [design_name '.txt']); +tplg_fn = fullfile(tpath, [design_name '.conf']); +comment = 'LR4 filter bank coefficients'; +howto = 'cd src/audio/eq_iir/tune; octave sof_example_lr4.m'; + +% Design low-pass and high-pass filters +eq_lo = lo_band_iir(fs, fc); +eq_hi = hi_band_iir(fs, fc); + +% Quantize and pack filter coefficients plus shifts etc. +bq_lo = sof_eq_iir_blob_quant(eq_lo.p_z, eq_lo.p_p, eq_lo.p_k); +bq_hi = sof_eq_iir_blob_quant(eq_hi.p_z, eq_hi.p_p, eq_hi.p_k); + +% Build blob +channels_in_config = 4; % Setup max 4 channels EQ +assign_response = [0 1 0 1]; % Order: lo, hi, lo, hi +num_responses = 2; % Two responses: lo, hi +bm = sof_eq_iir_blob_merge(channels_in_config, ... + num_responses, ... + assign_response, ... + [bq_lo bq_hi]); + +% Pack and write file +sof_eq_pack_export(bm, blob_fn, alsa_fn, tplg_fn, comment, howto) + +%% -------------------------------------------------- +%% Example: Same but filters order is lo, lo, hi, hi +%% -------------------------------------------------- + +design_name = sprintf('xover_lr4_%dhz_llhh_%dkhz', fc, round(fs/1000)); +blob_fn = fullfile(cpath, [design_name '.bin']); +alsa_fn = fullfile(cpath, [design_name '.txt']); +tplg_fn = fullfile(tpath, [design_name '.conf']); + +assign_response = [0 0 1 1]; +num_responses = 2; +bm = sof_eq_iir_blob_merge(channels_in_config, ... + num_responses, ... + assign_response, ... + [bq_lo bq_hi]); + +% Pack and write file +sof_eq_pack_export(bm, blob_fn, alsa_fn, tplg_fn, comment, howto) + +%% -------------------------------------------------- +%% Example: Same but filters order is hi, hi, lo, lo +%% -------------------------------------------------- + +design_name = sprintf('xover_lr4_%dhz_hhll_%dkhz', fc, round(fs/1000)); +blob_fn = fullfile(cpath, [design_name '.bin']); +alsa_fn = fullfile(cpath, [design_name '.txt']); +tplg_fn = fullfile(tpath, [design_name '.conf']); + +assign_response = [1 1 0 0]; +num_responses = 2; +bm = sof_eq_iir_blob_merge(channels_in_config, ... + num_responses, ... + assign_response, ... + [bq_lo bq_hi]); + +% Pack and write file +sof_eq_pack_export(bm, blob_fn, alsa_fn, tplg_fn, comment, howto) + +%% ------------------------------------ +%% Done. +%% ------------------------------------ + +sof_eq_paths(0); +end + +%% ------------------- +%% EQ design functions +%% ------------------- + +function eq = lo_band_iir(fs, fc) + + +%% Get defaults for equalizer design +eq = sof_eq_defaults(); +eq.fs = fs; +eq.enable_iir = 1; +eq.iir_norm_type = 'peak'; +eq.iir_norm_offs_db = 0; + +% Parametric EQs are PEQ_HP1, PEQ_HP2, PEQ_LP1, PEQ_LP2, PEQ_LS1, +% PEQ_LS2, PEQ_HS1, PEQ_HS2 = 8, PEQ_PN2, PEQ_LP4, and PEQ_HP4. +% +% Parametric EQs take as second argument the cutoff frequency in Hz +% and as second argument a dB value (can use 0 for LP2). The +% Third argument is a Q-value (can use 0 for LP2). + +% Two 2nd order butterworth low-pass filters for 4th order Linkwitz–Riley +eq.peq = [ ... + eq.PEQ_LP2 fc 0 0 ; ... + eq.PEQ_LP2 fc 0 0 ; ... + ]; + +%% Design EQ +eq = sof_eq_compute(eq); + +%% Plot +sof_eq_plot(eq); + +end + +function eq = hi_band_iir(fs, fc) + + +%% Get defaults for equalizer design +eq = sof_eq_defaults(); +eq.fs = fs; +eq.enable_iir = 1; +eq.iir_norm_type = 'peak'; +eq.iir_norm_offs_db = 0; + +% Two 2nd order high-pass filters for 4th order Linkwitz–Riley +eq.peq = [ ... + eq.PEQ_HP2 fc 0 0 ; ... + eq.PEQ_HP2 fc 0 0 ; ... + ]; + +%% Design EQ +eq = sof_eq_compute(eq); + +%% Plot +sof_eq_plot(eq); + +end + + + +% Pack and write file common function for all exports +function sof_eq_pack_export(bm, bin_fn, ascii_fn, tplg_fn, note, howto) + +bp = sof_eq_iir_blob_pack(bm, 4); % IPC4 + +if ~isempty(bin_fn) + sof_ucm_blob_write(bin_fn, bp); +end + +if ~isempty(ascii_fn) + sof_alsactl_write(ascii_fn, bp); +end + +if ~isempty(tplg_fn) + sof_tplg2_write(tplg_fn, bp, 'IIR', note, howto); +end + +end diff --git a/src/audio/eq_iir/tune/sof_example_spk_eq.m b/src/audio/eq_iir/tune/sof_example_spk_eq.m index e7612796c393..3a91ae04db6a 100644 --- a/src/audio/eq_iir/tune/sof_example_spk_eq.m +++ b/src/audio/eq_iir/tune/sof_example_spk_eq.m @@ -30,14 +30,15 @@ function sof_example_spk_eq() fir.priv = 'DEF_EQFIR_PRIV'; iir.comment = 'Speaker FIR+IIR EQ created with example_spk_eq.m'; fir.comment = 'Speaker FIR+IIR EQ created with example_spk_eq.m'; +howto = 'cd src/audio/eq_iir/tune; octave --no-window-system sof_example_spk_eq.m'; %% File names fir.txt = 'spk.txt'; -fir.bin = 'spk.blob'; +fir.bin = 'spk.bin'; fir.tplg1 = 'eq_fir_coef_spk.m4'; fir.tplg2 = 'example_speaker.conf'; iir.txt = 'spk.txt'; -iir.bin = 'spk.blob'; +iir.bin = 'spk.bin'; iir.tplg1 = 'eq_iir_coef_spk.m4'; iir.tplg2 = 'example_speaker.conf'; @@ -142,13 +143,13 @@ function sof_example_spk_eq() assign_response, ... [ bq_fir ]); bp_fir = sof_eq_fir_blob_pack(bm_fir, 3); % IPC3 - sof_eq_alsactl_write(fullfile(fir.cpath3, fir.txt), bp_fir); + sof_alsactl_write(fullfile(fir.cpath3, fir.txt), bp_fir); sof_ucm_blob_write(fullfile(fir.cpath3, fir.bin), bp_fir); - sof_eq_tplg_write(fullfile(fn.tpath1, fir.tplg1), bp_fir, fir.priv, fir.comment); + sof_tplg_write(fullfile(fn.tpath1, fir.tplg1), bp_fir, fir.priv, fir.comment, howto); bp_fir = sof_eq_fir_blob_pack(bm_fir, 4); % IPC4 - sof_eq_alsactl_write(fullfile(fir.cpath4, fir.txt), bp_fir); + sof_alsactl_write(fullfile(fir.cpath4, fir.txt), bp_fir); sof_ucm_blob_write(fullfile(fir.cpath4, fir.bin), bp_fir); - sof_eq_tplg2_write(fullfile(fir.tpath2, fir.tplg2), bp_fir, 'eq_fir', fir.comment); + sof_tplg2_write(fullfile(fir.tpath2, fir.tplg2), bp_fir, 'eq_fir', fir.comment, howto); end %% Export IIR part @@ -159,13 +160,13 @@ function sof_example_spk_eq() assign_response, ... [ bq_iir ]); bp_iir = sof_eq_iir_blob_pack(bm_iir, 3); % IPC3 - sof_eq_alsactl_write(fullfile(iir.cpath3, iir.txt), bp_iir); + sof_alsactl_write(fullfile(iir.cpath3, iir.txt), bp_iir); sof_ucm_blob_write(fullfile(iir.cpath3, iir.bin), bp_iir); - sof_eq_tplg_write(fullfile(fn.tpath1, iir.tplg1), bp_iir, iir.priv, iir.comment); + sof_tplg_write(fullfile(fn.tpath1, iir.tplg1), bp_iir, iir.priv, iir.comment, howto); bp_iir = sof_eq_iir_blob_pack(bm_iir, 4); % IPC4 - sof_eq_alsactl_write(fullfile(iir.cpath4, iir.txt), bp_iir); + sof_alsactl_write(fullfile(iir.cpath4, iir.txt), bp_iir); sof_ucm_blob_write(fullfile(iir.cpath4, iir.bin), bp_iir); - sof_eq_tplg2_write(fullfile(iir.tpath2, iir.tplg2), bp_iir, 'eq_iir', iir.comment); + sof_tplg2_write(fullfile(iir.tpath2, iir.tplg2), bp_iir, 'eq_iir', iir.comment, howto); end sof_eq_paths(0); diff --git a/src/audio/eq_iir/tune/sof_export_c_eq_uint32t.m b/src/audio/eq_iir/tune/sof_export_c_eq_uint32t.m index 7c861a4d8bbb..c7c26437b458 100644 --- a/src/audio/eq_iir/tune/sof_export_c_eq_uint32t.m +++ b/src/audio/eq_iir/tune/sof_export_c_eq_uint32t.m @@ -1,4 +1,4 @@ -function sof_export_c_eq_uint32t(fn, blob8, vn, justeq) +function sof_export_c_eq_uint32t(fn, blob8, vn, justeq, howto) % sof_export_c_eq_uint32t(fn, blob8, vn) % @@ -8,10 +8,11 @@ function sof_export_c_eq_uint32t(fn, blob8, vn, justeq) % blob8 - blob data from EQ design % vn - variable name % justeq - export just the EQ wihtout ABI headers for direct use in FW +% howto - add a comment how the header file was created % SPDX-License-Identifier: BSD-3-Clause % -% Copyright (c) 2021, Intel Corporation. All rights reserved. +% Copyright (c) 2021-2025, Intel Corporation. % Write blob fh = fopen(fn, 'w'); @@ -23,10 +24,20 @@ function sof_export_c_eq_uint32t(fn, blob8, vn, justeq) year = datestr(now, 'yyyy'); fprintf(fh, '/* SPDX-License-Identifier: BSD-3-Clause\n'); fprintf(fh, ' *\n'); - fprintf(fh, ' * Copyright(c) %s Intel Corporation. All rights reserved.\n', year); + fprintf(fh, ' * Copyright(c) %s Intel Corporation.\n', year); fprintf(fh, ' */\n'); fprintf(fh, '\n'); + if nargin == 5 + fprintf(fh, '/* Created %s with command:\n', datestr(now, 'yyyy-mm-dd')); + fprintf(fh, ' * %s\n */\n\n', howto); + end + + fprintf(fh, '#include <stdint.h>\n\n'); + + % Drop 8 bytes TLV header + blob8 = blob8(9:end); + % Pad blob length to multiple of four bytes n_orig = length(blob8); n_new = ceil(n_orig/4); @@ -53,7 +64,7 @@ function sof_export_c_eq_uint32t(fn, blob8, vn, justeq) numbers_remain = n_new - numbers_in_line * full_lines; n = 1; - fprintf(fh, 'uint32_t %s[%d] = {\n', vn, n_new); + fprintf(fh, 'static const uint32_t %s[%d] = {\n', vn, n_new); for i = 1:full_lines fprintf(fh, '\t'); for j = 1:numbers_in_line diff --git a/src/audio/eq_iir/tune/sof_mls_freq_resp.m b/src/audio/eq_iir/tune/sof_mls_freq_resp.m index 8376325c69a1..a30864d93a3b 100644 --- a/src/audio/eq_iir/tune/sof_mls_freq_resp.m +++ b/src/audio/eq_iir/tune/sof_mls_freq_resp.m @@ -22,7 +22,7 @@ % SPDX-License-Identifier: BSD-3-Clause % -% Copyright (c) 2018-2020, Intel Corporation. All rights reserved. +% Copyright (c) 2018-2025, Intel Corporation. % % Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> @@ -332,12 +332,12 @@ function remote_capture(fn, cfg, t) sens =[]; desc = ''; str = fgets(fh); - idx = findstr(str, '"'); + idx = strfind(str, '"'); while length(idx) > 0 line = str(idx(1)+1:idx(2)-1); desc = sprintf('%s%s ', desc, line); str = fgets(fh); - idx = findstr(str, '"'); + idx = strfind(str, '"'); end if length(strfind(str, 'Sens')) desc = str; diff --git a/src/audio/google/CMakeLists.txt b/src/audio/google/CMakeLists.txt index a53374e3a95a..fa55c9f39a2e 100644 --- a/src/audio/google/CMakeLists.txt +++ b/src/audio/google/CMakeLists.txt @@ -1,6 +1,72 @@ # SPDX-License-Identifier: BSD-3-Clause -if((NOT CONFIG_LIBRARY) OR CONFIG_LIBRARY_STATIC) +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + set(THIRD_PARTY ${SOF_ROOT_SOURCE_DIRECTORY}/third_party) + if(CONFIG_IPC_MAJOR_3) + set(ipc_suffix ipc3) + elseif(CONFIG_IPC_MAJOR_4) + set(ipc_suffix ipc4) + endif() + + zephyr_library_sources_ifdef(CONFIG_COMP_GOOGLE_HOTWORD_DETECT + google_hotword_detect.c + ) + + if(CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext_rtc + ${PROJECT_BINARY_DIR}/google_rtc_audio_processing_llext) + add_dependencies(app google_rtc_audio_processing) + elseif(CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING) + zephyr_library_sources(google_rtc_audio_processing.c) + + zephyr_library_sources_ifdef(CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK + google_rtc_audio_processing_mock.c + ) + + if(NOT CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK) + zephyr_include_directories(${THIRD_PARTY}/include) + target_link_directories(SOF INTERFACE ${THIRD_PARTY}/lib) + target_link_libraries(SOF INTERFACE google_rtc_audio_processing) + target_link_libraries(SOF INTERFACE c++) + target_link_libraries(SOF INTERFACE c++abi) + target_link_libraries(SOF INTERFACE m) + target_link_libraries(SOF INTERFACE c) + target_link_libraries(SOF INTERFACE gcc) + endif() + endif() + + if(CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext_ctc + ${PROJECT_BINARY_DIR}/google_ctc_audio_processing_llext) + add_dependencies(app google_ctc_audio_processing) + elseif(CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING) + zephyr_library_sources( + google_ctc_audio_processing.c + google_ctc_audio_processing_${ipc_suffix}.c + ) + zephyr_library_sources_ifdef(CONFIG_GOOGLE_CTC_AUDIO_PROCESSING_MOCK + google_ctc_audio_processing_mock.c + ) + + if(NOT CONFIG_GOOGLE_CTC_AUDIO_PROCESSING_MOCK) + zephyr_include_directories(${THIRD_PARTY}/include) + target_link_directories(SOF INTERFACE ${THIRD_PARTY}/lib) + target_link_libraries(SOF INTERFACE google_ctc_audio_processing) + target_link_libraries(SOF INTERFACE c++) + target_link_libraries(SOF INTERFACE c++abi) + target_link_libraries(SOF INTERFACE m) + target_link_libraries(SOF INTERFACE c) + target_link_libraries(SOF INTERFACE gcc) + endif() + endif() + + return() +endif() + +### Library build rules ### +if(CONFIG_LIBRARY_STATIC) if(CONFIG_COMP_GOOGLE_HOTWORD_DETECT) add_local_sources(sof google_hotword_detect.c diff --git a/src/audio/google/Kconfig b/src/audio/google/Kconfig index 2f2f5693acc7..61d1608b6891 100644 --- a/src/audio/google/Kconfig +++ b/src/audio/google/Kconfig @@ -5,7 +5,6 @@ menu "Google components" config COMP_GOOGLE_HOTWORD_DETECT bool "Google hotword detector component" select COMP_BLOB - default n help Select for Google hotword detector component. It uses the Google hotword library to do keyword detection. A language model needs to @@ -15,7 +14,6 @@ config COMP_GOOGLE_HOTWORD_DETECT config COMP_GOOGLE_RTC_AUDIO_PROCESSING tristate "Google Real Time Communication Audio processing" select COMP_BLOB - default n help Select for Google real-time communication audio processing. It uses the Google real-time audio processing library to perform @@ -88,7 +86,6 @@ config COMP_GOOGLE_CTC_AUDIO_PROCESSING select COMP_BLOB select GOOGLE_CTC_AUDIO_PROCESSING_MOCK if COMP_STUBS select STATIC_INIT_GNU if ZEPHYR_SOF_MODULE - default n depends on ZEPHYR_SOF_MODULE help Select for Google crosstalk cancellation audio processing. It diff --git a/src/audio/google/README.md b/src/audio/google/README.md new file mode 100644 index 000000000000..feb5ce615b0a --- /dev/null +++ b/src/audio/google/README.md @@ -0,0 +1,10 @@ +# Google Custom Components Architecture + +This directory houses components specific to Google integrations, such as specialized wake-word or hotword engines. + +## Configuration and Scripts + +- **Kconfig**: Exposes menus for Google components, including `COMP_GOOGLE_HOTWORD_DETECT` (engine for hotword detection), `COMP_GOOGLE_RTC_AUDIO_PROCESSING` (acoustic echo cancellation with tunable memory size, sample rates, max channels, and reference max channels), and `COMP_GOOGLE_CTC_AUDIO_PROCESSING` (crosstalk cancellation). It also exposes mock definitions for CI testing (`COMP_STUBS`). +- **CMakeLists.txt**: Conditionally links external static libraries (`libhifi3_google_hotword_dsp_api.a`, `google_rtc_audio_processing`, `google_ctc_audio_processing`) from `third_party` tools. Defines Zephyr and non-Zephyr build pipelines. +- **google_rtc_audio_processing.toml / google_ctc_audio_processing.toml**: Specify topology module configurations for `RTC_AEC` and `CTC` models respectively with pinning mappings (like DMIC pins and playback references). +- **Topology (.conf)**: Incorporates `tools/topology/topology2/include/components/ctc.conf` (defaults to UUID `bc:1b:0e:bf:6a:dc:fe:45:bc:90:25:54:cb:13:7a:b4`) and `google-rtc-aec.conf` (defaults to UUID `a6:a0:80:b7:9f:26:6f:46:b4:77:23:df:a0:5a:f7:58`) with strict audio format channel maps (e.g. 2ch vs 4ch mappings). diff --git a/src/audio/google/google_ctc_audio_processing.c b/src/audio/google/google_ctc_audio_processing.c index 12ecac66f8a7..0ee37abd24d5 100644 --- a/src/audio/google/google_ctc_audio_processing.c +++ b/src/audio/google/google_ctc_audio_processing.c @@ -22,9 +22,6 @@ LOG_MODULE_REGISTER(google_ctc_audio_processing, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(google_ctc_audio_processing); -DECLARE_TR_CTX(google_ctc_audio_processing_tr, SOF_UUID(google_ctc_audio_processing_uuid), - LOG_LEVEL_INFO); - // TODO(eddyhsu): Share these utils function with RTC. static inline float clamp_rescale(float max_val, float x) { @@ -243,13 +240,14 @@ static int ctc_free(struct processing_module *mod) { struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "ctc_free()"); + comp_info(mod->dev, "entry"); if (cd) { - rfree(cd->input); - rfree(cd->output); + mod_free(mod, cd->input); + mod_free(mod, cd->output); GoogleCtcAudioProcessingFree(cd->state); - rfree(cd); + mod_data_blob_handler_free(mod, cd->tuning_handler); + mod_free(mod, cd); module_set_private_data(mod, NULL); } @@ -262,12 +260,12 @@ static int ctc_init(struct processing_module *mod) struct google_ctc_audio_processing_comp_data *cd; int buf_size; - comp_info(dev, "ctc_init()"); + comp_info(dev, "entry"); /* Create private component data */ - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) { - comp_err(dev, "ctc_init(): Failed to create component data"); + comp_err(dev, "Failed to create component data"); ctc_free(mod); return -ENOMEM; } @@ -277,29 +275,29 @@ static int ctc_init(struct processing_module *mod) cd->chunk_frames = kChunkFrames; buf_size = cd->chunk_frames * sizeof(cd->input[0]) * kMaxChannels; - cd->input = rballoc(0, SOF_MEM_CAPS_RAM, buf_size); + cd->input = mod_balloc(mod, buf_size); if (!cd->input) { - comp_err(dev, "ctc_init(): Failed to allocate input buffer"); + comp_err(dev, "Failed to allocate input buffer"); ctc_free(mod); return -ENOMEM; } - cd->output = rballoc(0, SOF_MEM_CAPS_RAM, buf_size); + cd->output = mod_balloc(mod, buf_size); if (!cd->output) { - comp_err(dev, "ctc_init(): Failed to allocate output buffer"); + comp_err(dev, "Failed to allocate output buffer"); ctc_free(mod); return -ENOMEM; } - cd->tuning_handler = comp_data_blob_handler_new(dev); + cd->tuning_handler = mod_data_blob_handler_new(mod); if (!cd->tuning_handler) { - comp_err(dev, "ctc_init(): Failed to create tuning handler"); + comp_err(dev, "Failed to create tuning handler"); ctc_free(mod); return -ENOMEM; } cd->enabled = true; - comp_dbg(dev, "ctc_init(): Ready"); + comp_dbg(dev, "Ready"); return 0; } @@ -312,7 +310,7 @@ static int google_ctc_audio_processing_reconfigure(struct processing_module *mod size_t size; int ret; - comp_dbg(dev, "google_ctc_audio_processing_reconfigure()"); + comp_dbg(dev, "entry"); config = comp_get_data_blob(cd->tuning_handler, &size, NULL); if (size == 0) { @@ -321,16 +319,16 @@ static int google_ctc_audio_processing_reconfigure(struct processing_module *mod } if (!config) { - comp_err(dev, "google_ctc_audio_processing_reconfigure(): Tuning config not set"); + comp_err(dev, "Tuning config not set"); return -EINVAL; } - comp_info(dev, "google_ctc_audio_processing_reconfigure(): New tuning config %p (%zu bytes)", + comp_info(dev, "New tuning config %p (%zu bytes)", config, size); cd->reconfigure = false; comp_info(dev, - "google_ctc_audio_processing_reconfigure(): Applying config of size %zu bytes", + "Applying config of size %zu bytes", size); ret = GoogleCtcAudioProcessingReconfigure(cd->state, config, size); if (ret) { @@ -352,9 +350,14 @@ static int ctc_prepare(struct processing_module *mod, uint8_t *config; int config_size; - comp_info(mod->dev, "ctc_prepare()"); + comp_info(mod->dev, "entry"); source = comp_dev_get_first_data_producer(dev); + if (!source) { + comp_err(dev, "no source buffer"); + return -ENOTCONN; + } + switch (audio_stream_get_frm_fmt(&source->stream)) { #if CONFIG_FORMAT_S16LE case SOF_IPC_FRAME_S16_LE: @@ -372,13 +375,13 @@ static int ctc_prepare(struct processing_module *mod, break; #endif default: - comp_err(mod->dev, "ctc_prepare(), invalid frame_fmt"); + comp_err(mod->dev, "invalid frame_fmt"); return -EINVAL; } num_channels = audio_stream_get_channels(&source->stream); if (num_channels > kMaxChannels) { - comp_err(mod->dev, "ctc_prepare(), invalid number of channels"); + comp_err(mod->dev, "invalid number of channels"); return -EINVAL; } cd->next_avail_output_samples = cd->chunk_frames * num_channels; @@ -386,7 +389,7 @@ static int ctc_prepare(struct processing_module *mod, config = comp_get_data_blob(cd->tuning_handler, &config_size, NULL); if (config_size != CTC_BLOB_CONFIG_SIZE) { - comp_info(mod->dev, "ctc_prepare(): config_size not expected: %d", config_size); + comp_info(mod->dev, "config_size not expected: %d", config_size); config = NULL; config_size = 0; } @@ -395,7 +398,7 @@ static int ctc_prepare(struct processing_module *mod, config, config_size); if (!cd->state) { - comp_err(mod->dev, "ctc_prepare(), failed to create CTC"); + comp_err(mod->dev, "failed to create CTC"); return -ENOMEM; } @@ -407,7 +410,7 @@ static int ctc_reset(struct processing_module *mod) struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); size_t buf_size = cd->chunk_frames * sizeof(cd->input[0]) * kMaxChannels; - comp_info(mod->dev, "ctc_reset()"); + comp_info(mod->dev, "entry"); GoogleCtcAudioProcessingFree(cd->state); cd->state = NULL; @@ -432,7 +435,7 @@ static int ctc_process(struct processing_module *mod, int ret; - comp_dbg(mod->dev, "ctc_process()"); + comp_dbg(mod->dev, "entry"); if (cd->reconfigure) { ret = google_ctc_audio_processing_reconfigure(mod); @@ -454,11 +457,6 @@ static const struct module_interface google_ctc_audio_processing_interface = { .reset = ctc_reset, }; -DECLARE_MODULE_ADAPTER(google_ctc_audio_processing_interface, - google_ctc_audio_processing_uuid, google_ctc_audio_processing_tr); -SOF_MODULE_INIT(google_ctc_audio_processing, - sys_comp_module_google_ctc_audio_processing_interface_init); - #if CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING_MODULE /* modular: llext dynamic link */ @@ -466,15 +464,19 @@ SOF_MODULE_INIT(google_ctc_audio_processing, #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_GOOGLE_CTC 0xBC, 0x1B, 0x0E, 0xBF, 0x6A, 0xDC, 0xFE, 0x45, 0x90, 0xBC, \ - 0x25, 0x54, 0xCB, 0x13, 0x7A, 0xB4 - -SOF_LLEXT_MOD_ENTRY(google_ctc_audio_processing, &google_ctc_audio_processing_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("CTC", google_ctc_audio_processing_llext_entry, - 1, UUID_GOOGLE_CTC, 40); + SOF_LLEXT_MODULE_MANIFEST("CTC", &google_ctc_audio_processing_interface, + 1, SOF_REG_UUID(google_ctc_audio_processing), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(google_ctc_audio_processing_tr, SOF_UUID(google_ctc_audio_processing_uuid), + LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(google_ctc_audio_processing_interface, + google_ctc_audio_processing_uuid, google_ctc_audio_processing_tr); +SOF_MODULE_INIT(google_ctc_audio_processing, + sys_comp_module_google_ctc_audio_processing_interface_init); + #endif diff --git a/src/audio/google/google_ctc_audio_processing.toml b/src/audio/google/google_ctc_audio_processing.toml index b136273f0362..4bea054225fc 100644 --- a/src/audio/google/google_ctc_audio_processing.toml +++ b/src/audio/google/google_ctc_audio_processing.toml @@ -5,7 +5,7 @@ REM # CTC module config [[module.entry]] name = "CTC" - uuid = "BF0E1BBC-DC6A-45FE-BC90-2554CB137AB4" + uuid = UUIDREG_STR_GOOGLE_CTC_AUDIO_PROCESSING affinity_mask = "0x1" instance_count = "40" domain_types = "0" diff --git a/src/audio/google/google_ctc_audio_processing_ipc3.c b/src/audio/google/google_ctc_audio_processing_ipc3.c index ccdceb1def95..8f6594203420 100644 --- a/src/audio/google/google_ctc_audio_processing_ipc3.c +++ b/src/audio/google/google_ctc_audio_processing_ipc3.c @@ -40,13 +40,13 @@ int ctc_set_config(struct processing_module *mod, uint32_t param_id, config = comp_get_data_blob(cd->tuning_handler, &size, NULL); if (size != CTC_BLOB_CONFIG_SIZE) { comp_err(mod->dev, - "ctc_set_config(): Invalid config size = %d", + "Invalid config size = %d", size); return -EINVAL; } if (config->size != CTC_BLOB_CONFIG_SIZE) { comp_err(mod->dev, - "ctc_set_config(): Invalid config->size = %d", + "Invalid config->size = %d", config->size); return -EINVAL; } @@ -56,17 +56,17 @@ int ctc_set_config(struct processing_module *mod, uint32_t param_id, case SOF_CTRL_CMD_SWITCH: if (cdata->num_elems == 1) { cd->enabled = cdata->chanv[0].value; - comp_info(dev, "ctc_set_config(), enabled = %d", + comp_info(mod->dev, "enabled = %d", cd->enabled); return 0; } comp_err(mod->dev, - "ctc_set_config(): Illegal num_elems = %d", + "Illegal num_elems = %d", cdata->num_elems); return -EINVAL; default: comp_err(mod->dev, - "ctc_set_config(): Only binary and switch controls supported %d", + "Only binary and switch controls supported %d", cdata->cmd); return -EINVAL; } @@ -79,7 +79,7 @@ int ctc_get_config(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "ctc_get_config(): %u", cdata->cmd); + comp_info(mod->dev, "%u", cdata->cmd); switch (cdata->cmd) { case SOF_CTRL_CMD_BINARY: diff --git a/src/audio/google/google_ctc_audio_processing_ipc4.c b/src/audio/google/google_ctc_audio_processing_ipc4.c index b57de9766d82..fa5f265e9d0f 100644 --- a/src/audio/google/google_ctc_audio_processing_ipc4.c +++ b/src/audio/google/google_ctc_audio_processing_ipc4.c @@ -37,15 +37,15 @@ int ctc_set_config(struct processing_module *mod, uint32_t param_id, case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: if (ctl->id == 0 && ctl->num_elems == 1) { cd->enabled = ctl->chanv[0].value; - comp_info(mod->dev, "ctc_set_config(): enabled = %d", cd->enabled); + comp_info(mod->dev, "enabled = %d", cd->enabled); return 0; } - comp_err(mod->dev, "ctc_set_config(): Illegal control id = %d, num_elems = %d", + comp_err(mod->dev, "Illegal control id = %d, num_elems = %d", ctl->id, ctl->num_elems); return -EINVAL; case SOF_IPC4_ENUM_CONTROL_PARAM_ID: default: - comp_err(mod->dev, "ctc_set_config(): Only binary and switch controls supported"); + comp_err(mod->dev, "Only binary and switch controls supported"); return -EINVAL; } @@ -58,13 +58,13 @@ int ctc_set_config(struct processing_module *mod, uint32_t param_id, config = comp_get_data_blob(cd->tuning_handler, &size, NULL); if (size != CTC_BLOB_CONFIG_SIZE) { comp_err(mod->dev, - "ctc_set_config(): Invalid config size = %d", + "Invalid config size = %d", size); return -EINVAL; } if (config->size != CTC_BLOB_CONFIG_SIZE) { comp_err(mod->dev, - "ctc_set_config(): Invalid config->size = %d", + "Invalid config->size = %d", config->size); return -EINVAL; } @@ -81,7 +81,7 @@ int ctc_get_config(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "ctc_get_config(): %u", cdata->cmd); + comp_info(mod->dev, "%u", cdata->cmd); return comp_data_blob_get_cmd(cd->tuning_handler, cdata, fragment_size); } diff --git a/src/audio/google/google_ctc_audio_processing_mock.c b/src/audio/google/google_ctc_audio_processing_mock.c index ea962aa3a774..f3f004d38ebb 100644 --- a/src/audio/google/google_ctc_audio_processing_mock.c +++ b/src/audio/google/google_ctc_audio_processing_mock.c @@ -18,7 +18,7 @@ struct GoogleCtcAudioProcessingState { GoogleCtcAudioProcessingState *GoogleCtcAudioProcessingCreate(void) { struct GoogleCtcAudioProcessingState *s = - rballoc(0, SOF_MEM_CAPS_RAM, sizeof(GoogleCtcAudioProcessingState)); + rballoc(SOF_MEM_FLAG_USER, sizeof(GoogleCtcAudioProcessingState)); if (!s) return NULL; @@ -31,7 +31,7 @@ GoogleCtcAudioProcessingState *GoogleCtcAudioProcessingCreateWithConfig(int chun int config_size) { struct GoogleCtcAudioProcessingState *s = - rballoc(0, SOF_MEM_CAPS_RAM, sizeof(GoogleCtcAudioProcessingState)); + rballoc(SOF_MEM_FLAG_USER, sizeof(GoogleCtcAudioProcessingState)); if (!s) return NULL; diff --git a/src/audio/google/google_hotword_detect.c b/src/audio/google/google_hotword_detect.c index 920945209dbf..1055f7914e1e 100644 --- a/src/audio/google/google_hotword_detect.c +++ b/src/audio/google/google_hotword_detect.c @@ -45,7 +45,6 @@ static const struct comp_driver ghd_driver; LOG_MODULE_REGISTER(google_hotword_detect, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(google_hotword); -DECLARE_TR_CTX(ghd_tr, SOF_UUID(ghd_uuid), LOG_LEVEL_INFO); struct comp_data { struct comp_data_blob_handler *model_handler; @@ -63,7 +62,7 @@ static void notify_host(const struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); - comp_dbg(dev, "notify_host()"); + comp_dbg(dev, "entry"); ipc_msg_send(cd->msg, &cd->event, true); } @@ -72,7 +71,7 @@ static void notify_kpb(const struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); - comp_dbg(dev, "notify_kpb()"); + comp_dbg(dev, "entry"); cd->client_data.r_ptr = NULL; cd->client_data.sink = NULL; @@ -102,7 +101,7 @@ static struct comp_dev *ghd_create(const struct comp_driver *drv, dev->ipc_config = *config; /* Create private component data */ - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); if (!cd) goto fail; @@ -115,19 +114,19 @@ static struct comp_dev *ghd_create(const struct comp_driver *drv, cd->msg = ipc_msg_init(cd->event.rhdr.hdr.cmd, cd->event.rhdr.hdr.size); if (!cd->msg) { - comp_err(dev, "ghd_create(): ipc_msg_init failed"); + comp_err(dev, "ipc_msg_init failed"); goto cd_fail; } /* Create component model data handler */ cd->model_handler = comp_data_blob_handler_new(dev); if (!cd->model_handler) { - comp_err(dev, "ghd_create(): comp_data_blob_handler_new failed"); + comp_err(dev, "comp_data_blob_handler_new failed"); goto cd_fail; } dev->state = COMP_STATE_READY; - comp_dbg(dev, "ghd_create(): Ready"); + comp_dbg(dev, "Ready"); return dev; cd_fail: @@ -135,7 +134,7 @@ static struct comp_dev *ghd_create(const struct comp_driver *drv, ipc_msg_free(cd->msg); rfree(cd); fail: - rfree(dev); + comp_free_device(dev); return NULL; } @@ -143,12 +142,12 @@ static void ghd_free(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); - comp_dbg(dev, "ghd_free()"); + comp_dbg(dev, "entry"); comp_data_blob_handler_free(cd->model_handler); ipc_msg_free(cd->msg); rfree(cd); - rfree(dev); + comp_free_device(dev); } static int ghd_params(struct comp_dev *dev, @@ -164,7 +163,7 @@ static int ghd_params(struct comp_dev *dev, ret = comp_verify_params(dev, 0, params); if (ret < 0) { - comp_err(dev, "ghd_params(): comp_verify_params failed."); + comp_err(dev, "comp_verify_params failed."); return -EINVAL; } @@ -172,13 +171,13 @@ static int ghd_params(struct comp_dev *dev, sourceb = comp_dev_get_first_data_producer(dev); if (audio_stream_get_channels(sourceb->stream) != 1) { - comp_err(dev, "ghd_params(): Only single-channel supported"); + comp_err(dev, "Only single-channel supported"); ret = -EINVAL; } else if (audio_stream_get_frm_fmt(&sourceb->stream) != SOF_IPC_FRAME_S16_LE) { - comp_err(dev, "ghd_params(): Only S16_LE supported"); + comp_err(dev, "Only S16_LE supported"); ret = -EINVAL; } else if (sourceb->stream.rate != KPB_SAMPLNG_FREQUENCY) { - comp_err(dev, "ghd_params(): Only 16KHz supported"); + comp_err(dev, "Only 16KHz supported"); ret = -EINVAL; } @@ -229,11 +228,11 @@ static int ghd_ctrl_set_bin_data(struct comp_dev *dev, switch (cdata->data->type) { case GOOGLE_HOTWORD_DETECT_MODEL: ret = comp_data_blob_set_cmd(cd->model_handler, cdata); - comp_dbg(dev, "ghd_ctrl_set_bin_data(): comp_data_blob_set_cmd=%d", + comp_dbg(dev, "comp_data_blob_set_cmd=%d", ret); return ret; default: - comp_err(dev, "ghd_ctrl_set_bin_data(): Unknown cdata->data->type %d", + comp_err(dev, "Unknown cdata->data->type %d", cdata->data->type); return -EINVAL; } @@ -246,7 +245,7 @@ static int ghd_ctrl_set_data(struct comp_dev *dev, case SOF_CTRL_CMD_BINARY: return ghd_ctrl_set_bin_data(dev, cdata); default: - comp_err(dev, "ghd_ctrl_set_data(): Only binary controls supported %d", + comp_err(dev, "Only binary controls supported %d", cdata->cmd); return -EINVAL; } @@ -264,11 +263,11 @@ static int ghd_ctrl_get_bin_data(struct comp_dev *dev, ret = comp_data_blob_get_cmd(cd->model_handler, cdata, max_data_size); - comp_dbg(dev, "ghd_ctrl_get_bin_data(): comp_data_blob_get_cmd=%d, size=%d", + comp_dbg(dev, "comp_data_blob_get_cmd=%d, size=%d", ret, max_data_size); return ret; default: - comp_err(dev, "ghd_ctrl_get_bin_data(): Unknown cdata->data->type %d", + comp_err(dev, "Unknown cdata->data->type %d", cdata->data->type); return -EINVAL; } @@ -282,7 +281,7 @@ static int ghd_ctrl_get_data(struct comp_dev *dev, case SOF_CTRL_CMD_BINARY: return ghd_ctrl_get_bin_data(dev, cdata, max_data_size); default: - comp_err(dev, "ghd_ctrl_get_data(): Only binary controls supported %d", + comp_err(dev, "Only binary controls supported %d", cdata->cmd); return -EINVAL; } @@ -293,7 +292,7 @@ static int ghd_cmd(struct comp_dev *dev, int cmd, void *data, { struct sof_ipc_ctrl_data *cdata = data; - comp_dbg(dev, "ghd_cmd(): %d", cmd); + comp_dbg(dev, "%d", cmd); switch (cmd) { case COMP_CMD_SET_DATA: @@ -301,7 +300,7 @@ static int ghd_cmd(struct comp_dev *dev, int cmd, void *data, case COMP_CMD_GET_DATA: return ghd_ctrl_get_data(dev, cdata, max_data_size); default: - comp_err(dev, "ghd_cmd(): Unknown cmd %d", cmd); + comp_err(dev, "Unknown cmd %d", cmd); return -EINVAL; } } @@ -311,7 +310,7 @@ static int ghd_trigger(struct comp_dev *dev, int cmd) { struct comp_data *cd = comp_get_drvdata(dev); - comp_dbg(dev, "ghd_trigger(): %d", cmd); + comp_dbg(dev, "%d", cmd); if (cmd == COMP_TRIGGER_START || cmd == COMP_TRIGGER_RELEASE) { cd->detected = 0; @@ -382,7 +381,7 @@ static int ghd_copy(struct comp_dev *dev) /* Check for new model */ if (comp_is_new_data_blob_available(cd->model_handler)) { - comp_dbg(dev, "ghd_copy(): Switch to new model"); + comp_dbg(dev, "Switch to new model"); ret = ghd_setup_model(dev); if (ret) return ret; @@ -394,7 +393,7 @@ static int ghd_copy(struct comp_dev *dev) bytes = audio_stream_get_avail_bytes(stream); - comp_dbg(dev, "ghd_copy() avail_bytes %u", bytes); + comp_dbg(dev, "avail_bytes %u", bytes); comp_dbg(dev, "buffer begin/r_ptr/end [0x%x 0x%x 0x%x]", (uint32_t)audio_stream_get_addr(stream), (uint32_t)audio_stream_get_rptr(stream), @@ -425,7 +424,7 @@ static int ghd_reset(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); - comp_dbg(dev, "ghd_reset()"); + comp_dbg(dev, "entry"); cd->detected = 0; cd->history_bytes = 0; @@ -438,7 +437,7 @@ static int ghd_prepare(struct comp_dev *dev) { int ret; - comp_dbg(dev, "ghd_prepare()"); + comp_dbg(dev, "entry"); ret = ghd_setup_model(dev); if (ret) @@ -447,6 +446,8 @@ static int ghd_prepare(struct comp_dev *dev) return comp_set_state(dev, COMP_TRIGGER_PREPARE); } +DECLARE_TR_CTX(ghd_tr, SOF_UUID(ghd_uuid), LOG_LEVEL_INFO); + static const struct comp_driver ghd_driver = { .type = SOF_COMP_KEYWORD_DETECT, .uid = SOF_RT_UUID(ghd_uuid), @@ -471,8 +472,7 @@ static SHARED_DATA struct comp_driver_info ghd_driver_info = { UT_STATIC void sys_comp_ghd_init(void) { - comp_register(platform_shared_get(&ghd_driver_info, - sizeof(ghd_driver_info))); + comp_register(&ghd_driver_info); } DECLARE_MODULE(sys_comp_ghd_init); diff --git a/src/audio/google/google_rtc_audio_processing.c b/src/audio/google/google_rtc_audio_processing.c index c84cadb4c5c8..7c50bca874c5 100644 --- a/src/audio/google/google_rtc_audio_processing.c +++ b/src/audio/google/google_rtc_audio_processing.c @@ -56,10 +56,6 @@ LOG_MODULE_REGISTER(google_rtc_audio_processing, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(google_rtc_audio_processing); -DECLARE_TR_CTX(google_rtc_audio_processing_tr, SOF_UUID(google_rtc_audio_processing_uuid), - LOG_LEVEL_INFO); - - static __aligned(PLATFORM_DCACHE_ALIGN) uint8_t aec_mem_blob[CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING_MEMORY_BUFFER_SIZE_KB * 1024]; @@ -107,7 +103,7 @@ static void *cached_ptr(void *p) void *GoogleRtcMalloc(size_t size) { - return rballoc(0, SOF_MEM_CAPS_RAM, size); + return rballoc(SOF_MEM_FLAG_USER, size); } void GoogleRtcFree(void *ptr) @@ -247,7 +243,7 @@ static int google_rtc_audio_processing_reconfigure(struct processing_module *mod size_t size; int ret; - comp_dbg(dev, "google_rtc_audio_processing_reconfigure()"); + comp_dbg(dev, "entry"); if (!comp_is_current_data_blob_valid(cd->tuning_handler) && !comp_is_new_data_blob_available(cd->tuning_handler)) { @@ -269,11 +265,11 @@ static int google_rtc_audio_processing_reconfigure(struct processing_module *mod } if (!config) { - comp_err(dev, "google_rtc_audio_processing_reconfigure(): Tuning config not set"); + comp_err(dev, "Tuning config not set"); return -EINVAL; } - comp_info(dev, "google_rtc_audio_processing_reconfigure(): New tuning config %p (%zu bytes)", + comp_info(dev, "New tuning config %p (%zu bytes)", config, size); cd->reconfigure = false; @@ -305,7 +301,7 @@ static int google_rtc_audio_processing_reconfigure(struct processing_module *mod if (google_rtc_audio_processing_config_present) { comp_info(dev, - "google_rtc_audio_processing_reconfigure(): Applying config of size %zu bytes", + "Applying config of size %zu bytes", google_rtc_audio_processing_config_size); ret = GoogleRtcAudioProcessingReconfigure(cd->state, @@ -331,7 +327,7 @@ static int google_rtc_audio_processing_reconfigure(struct processing_module *mod cd->num_capture_channels = num_capture_output_channels; } comp_info(dev, - "google_rtc_audio_processing_reconfigure(): Applying num capture channels %d", + "Applying num capture channels %d", cd->num_capture_channels); @@ -358,7 +354,7 @@ static int google_rtc_audio_processing_reconfigure(struct processing_module *mod /* Logging of linear headroom, using integer workaround to the broken printout of floats */ comp_info(dev, - "google_rtc_audio_processing_reconfigure(): Applying capture linear headroom: %d.%d", + "Applying capture linear headroom: %d.%d", (int)mic_gain, (int)(100 * mic_gain) - 100 * ((int)mic_gain)); } if (aec_reference_delay_present) { @@ -366,7 +362,7 @@ static int google_rtc_audio_processing_reconfigure(struct processing_module *mod /* Logging of delay, using integer workaround to the broken printout of floats */ comp_info(dev, - "google_rtc_audio_processing_reconfigure(): Applying aec reference delay: %d.%d", + "Applying aec reference delay: %d.%d", (int)aec_reference_delay, (int)(100 * aec_reference_delay) - 100 * ((int)aec_reference_delay)); @@ -414,7 +410,7 @@ static int google_rtc_audio_processing_cmd_set_data(struct processing_module *mo return 0; default: comp_err(mod->dev, - "google_rtc_audio_processing_ctrl_set_data(): Only binary controls supported %d", + "Only binary controls supported %d", cdata->cmd); return -EINVAL; } @@ -426,14 +422,14 @@ static int google_rtc_audio_processing_cmd_get_data(struct processing_module *mo { struct google_rtc_audio_processing_comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "google_rtc_audio_processing_ctrl_get_data(): %u", cdata->cmd); + comp_info(mod->dev, "%u", cdata->cmd); switch (cdata->cmd) { case SOF_CTRL_CMD_BINARY: return comp_data_blob_get_cmd(cd->tuning_handler, cdata, max_data_size); default: comp_err(mod->dev, - "google_rtc_audio_processing_ctrl_get_data(): Only binary controls supported %d", + "Only binary controls supported %d", cdata->cmd); return -EINVAL; } @@ -454,7 +450,7 @@ static int google_rtc_audio_processing_set_config(struct processing_module *mod, switch (param_id) { case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: case SOF_IPC4_ENUM_CONTROL_PARAM_ID: - comp_err(mod->dev, "google_rtc_audio_processing_ctrl_set_data(): Only binary controls supported"); + comp_err(mod->dev, "Only binary controls supported"); return -EINVAL; } @@ -493,7 +489,7 @@ static int google_rtc_audio_processing_get_config(struct processing_module *mod, uint8_t *fragment, size_t fragment_size) { #if CONFIG_IPC_MAJOR_4 - comp_err(mod->dev, "google_rtc_audio_processing_ctrl_get_config(): Not supported"); + comp_err(mod->dev, "Not supported"); return -EINVAL; #elif CONFIG_IPC_MAJOR_3 struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; @@ -509,10 +505,10 @@ static int google_rtc_audio_processing_init(struct processing_module *mod) struct google_rtc_audio_processing_comp_data *cd; int ret, i; - comp_info(dev, "google_rtc_audio_processing_init()"); + comp_info(dev, "entry"); /* Create private component data */ - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) { ret = -ENOMEM; goto fail; @@ -520,7 +516,7 @@ static int google_rtc_audio_processing_init(struct processing_module *mod) md->private = cd; - cd->tuning_handler = comp_data_blob_handler_new(dev); + cd->tuning_handler = mod_data_blob_handler_new(mod); if (!cd->tuning_handler) { ret = -ENOMEM; goto fail; @@ -575,18 +571,18 @@ static int google_rtc_audio_processing_init(struct processing_module *mod) /* Mic and reference, needed for audio stream type copy module client */ mod->max_sources = 2; - comp_dbg(dev, "google_rtc_audio_processing_init(): Ready"); + comp_dbg(dev, "Ready"); return 0; fail: - comp_err(dev, "google_rtc_audio_processing_init(): Failed"); + comp_err(dev, "Failed"); if (cd) { if (cd->state) { GoogleRtcAudioProcessingFree(cd->state); } GoogleRtcAudioProcessingDetachMemoryBuffer(); - comp_data_blob_handler_free(cd->tuning_handler); - rfree(cd); + mod_data_blob_handler_free(mod, cd->tuning_handler); + mod_free(mod, cd); } return ret; @@ -596,13 +592,13 @@ static int google_rtc_audio_processing_free(struct processing_module *mod) { struct google_rtc_audio_processing_comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "google_rtc_audio_processing_free()"); + comp_dbg(mod->dev, "entry"); GoogleRtcAudioProcessingFree(cd->state); cd->state = NULL; GoogleRtcAudioProcessingDetachMemoryBuffer(); - comp_data_blob_handler_free(cd->tuning_handler); - rfree(cd); + mod_data_blob_handler_free(mod, cd->tuning_handler); + mod_free(mod, cd); return 0; } @@ -616,7 +612,7 @@ static int google_rtc_audio_processing_prepare(struct processing_module *mod, struct google_rtc_audio_processing_comp_data *cd = module_get_private_data(mod); int ret = 0; - comp_info(dev, "google_rtc_audio_processing_prepare()"); + comp_info(dev, "entry"); if (num_of_sources != 2 || num_of_sinks != 1) { comp_err(dev, "Invalid source/sink count"); @@ -766,7 +762,7 @@ static int trigger_handler(struct processing_module *mod, int cmd) static int google_rtc_audio_processing_reset(struct processing_module *mod) { - comp_dbg(mod->dev, "google_rtc_audio_processing_reset()"); + comp_dbg(mod->dev, "entry"); return 0; } @@ -849,11 +845,6 @@ static const struct module_interface google_rtc_audio_processing_interface = { .reset = google_rtc_audio_processing_reset, }; -DECLARE_MODULE_ADAPTER(google_rtc_audio_processing_interface, - google_rtc_audio_processing_uuid, google_rtc_audio_processing_tr); -SOF_MODULE_INIT(google_rtc_audio_processing, - sys_comp_module_google_rtc_audio_processing_interface_init); - #if CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING_MODULE /* modular: llext dynamic link */ @@ -861,15 +852,19 @@ SOF_MODULE_INIT(google_rtc_audio_processing, #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_GOOGLE_RTC_AEC 0xA6, 0xA0, 0x80, 0xB7, 0x9F, 0x26, 0x6F, 0x46, 0x77, 0xB4, \ - 0x23, 0xDF, 0xA0, 0x5A, 0xF7, 0x58 - -SOF_LLEXT_MOD_ENTRY(google_rtc_audio_processing, &google_rtc_audio_processing_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("RTC_AEC", google_rtc_audio_processing_llext_entry, - 7, UUID_GOOGLE_RTC_AEC, 1); + SOF_LLEXT_MODULE_MANIFEST("RTC_AEC", &google_rtc_audio_processing_interface, + 7, SOF_REG_UUID(google_rtc_audio_processing), 1); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(google_rtc_audio_processing_tr, SOF_UUID(google_rtc_audio_processing_uuid), + LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(google_rtc_audio_processing_interface, + google_rtc_audio_processing_uuid, google_rtc_audio_processing_tr); +SOF_MODULE_INIT(google_rtc_audio_processing, + sys_comp_module_google_rtc_audio_processing_interface_init); + #endif diff --git a/src/audio/google/google_rtc_audio_processing.toml b/src/audio/google/google_rtc_audio_processing.toml index eab8e437f798..931452d0a7fc 100644 --- a/src/audio/google/google_rtc_audio_processing.toml +++ b/src/audio/google/google_rtc_audio_processing.toml @@ -4,7 +4,7 @@ [[module.entry]] name = "RTC_AEC" - uuid = "B780A0A6-269F-466F-B477-23DFA05AF758" + uuid = UUIDREG_STR_GOOGLE_RTC_AUDIO_PROCESSING REM # bit #i = 1 means core #i is allowed. affinity_mask = "0x7" instance_count = "1" @@ -19,5 +19,7 @@ pin = [0, 0, 0x8, 0x2, 0x2, 0x1, 0, 0, 0x8, 0x2, 0x2, 0x4, 1, 0, 0x8, 0x2, 0x2, 0x1] + REM # 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] index = __COUNTER__ diff --git a/src/audio/google/google_rtc_audio_processing_mock.c b/src/audio/google/google_rtc_audio_processing_mock.c index 7d5d12f5bd88..b931c3a85c7a 100644 --- a/src/audio/google/google_rtc_audio_processing_mock.c +++ b/src/audio/google/google_rtc_audio_processing_mock.c @@ -27,7 +27,7 @@ struct GoogleRtcAudioProcessingState { float *aec_reference; }; -static void SetFormats(GoogleRtcAudioProcessingState *const state, +static int SetFormats(GoogleRtcAudioProcessingState *const state, int capture_sample_rate_hz, int num_capture_input_channels, int num_capture_output_channels, @@ -41,11 +41,13 @@ static void SetFormats(GoogleRtcAudioProcessingState *const state, state->num_aec_reference_channels = num_render_channels; rfree(state->aec_reference); - state->aec_reference = rballoc(0, - SOF_MEM_CAPS_RAM, + state->aec_reference = rballoc(SOF_MEM_FLAG_USER, sizeof(state->aec_reference[0]) * state->num_frames * state->num_aec_reference_channels); + if (!state->aec_reference) + return -ENOMEM; + return 0; } void GoogleRtcAudioProcessingAttachMemoryBuffer(uint8_t *const buffer, @@ -65,20 +67,21 @@ GoogleRtcAudioProcessingState *GoogleRtcAudioProcessingCreateWithConfig(int capt const uint8_t *const config, int config_size) { + int err; struct GoogleRtcAudioProcessingState *s = - rballoc(0, SOF_MEM_CAPS_RAM, sizeof(GoogleRtcAudioProcessingState)); + rballoc(SOF_MEM_FLAG_USER, sizeof(GoogleRtcAudioProcessingState)); if (!s) return NULL; s->aec_reference = NULL; - SetFormats(s, + err = SetFormats(s, capture_sample_rate_hz, num_capture_input_channels, num_capture_output_channels, render_sample_rate_hz, num_render_channels); - if (!s->aec_reference) { + if (err) { rfree(s); return NULL; } diff --git a/src/audio/google/llext_ctc/CMakeLists.txt b/src/audio/google/llext_ctc/CMakeLists.txt index c04c9765bf1d..440e0fbe6ad2 100644 --- a/src/audio/google/llext_ctc/CMakeLists.txt +++ b/src/audio/google/llext_ctc/CMakeLists.txt @@ -6,7 +6,6 @@ sof_llext_build("google_ctc_audio_processing" SOURCES ../google_ctc_audio_processing.c ../google_ctc_audio_processing_ipc4.c ../google_ctc_audio_processing_mock.c - LIB openmodules ) target_include_directories(google_ctc_audio_processing_llext_lib PRIVATE "${sof_top_dir}/third_party/include" diff --git a/src/audio/google/llext_rtc/CMakeLists.txt b/src/audio/google/llext_rtc/CMakeLists.txt index 7cf47276d62e..0847fbc8bc57 100644 --- a/src/audio/google/llext_rtc/CMakeLists.txt +++ b/src/audio/google/llext_rtc/CMakeLists.txt @@ -2,7 +2,6 @@ if(CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK) sof_llext_build("google_rtc_audio_processing" SOURCES ../google_rtc_audio_processing.c ../google_rtc_audio_processing_mock.c - LIB openmodules ) target_include_directories(google_rtc_audio_processing_llext_lib PRIVATE "${sof_top_dir}/third_party/include" diff --git a/src/audio/host-legacy.c b/src/audio/host-legacy.c index e8d62e17301d..4560959bb044 100644 --- a/src/audio/host-legacy.c +++ b/src/audio/host-legacy.c @@ -25,6 +25,7 @@ #include <rtos/string.h> #include <sof/ut.h> #include <sof/trace/trace.h> +#include <sof/debug/telemetry/performance_monitor.h> #include <ipc/stream.h> #include <ipc/topology.h> #include <user/trace.h> @@ -40,8 +41,6 @@ LOG_MODULE_REGISTER(host, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(host); -DECLARE_TR_CTX(host_tr, SOF_UUID(host_uuid), LOG_LEVEL_INFO); - static inline struct dma_sg_elem *next_buffer(struct hc_buf *hc) { if (!hc->elem_array.elems || !hc->elem_array.count) @@ -81,14 +80,14 @@ static int host_dma_set_config_and_copy(struct host_data *hd, struct comp_dev *d /* reconfigure transfer */ ret = dma_set_config_legacy(hd->chan, &hd->config); if (ret < 0) { - comp_err(dev, "host_dma_set_config_and_copy(): dma_set_config() failed, ret = %d", + comp_err(dev, "dma_set_config() failed, ret = %d", ret); return ret; } ret = dma_copy_legacy(hd->chan, bytes, DMA_COPY_ONE_SHOT | DMA_COPY_BLOCKING); if (ret < 0) { - comp_err(dev, "host_dma_set_config_and_copy(): dma_copy() failed, ret = %d", + comp_err(dev, "dma_copy() failed, ret = %d", ret); return ret; } @@ -129,11 +128,11 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c uint32_t split_value = 0; int ret = 0; - comp_dbg(dev, "host_copy_one_shot()"); + comp_dbg(dev, "entry"); copy_bytes = host_get_copy_bytes_one_shot(hd, dev); if (!copy_bytes) { - comp_info(dev, "host_copy_one_shot(): no bytes to copy"); + comp_info(dev, "no bytes to copy"); return ret; } @@ -197,24 +196,24 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c uint32_t copy_bytes = 0; int ret = 0; - comp_dbg(dev, "host_copy_one_shot()"); + comp_dbg(dev, "entry"); copy_bytes = host_get_copy_bytes_one_shot(hd, dev); if (!copy_bytes) { - comp_info(dev, "host_copy_one_shot(): no bytes to copy"); + comp_info(dev, "no bytes to copy"); return ret; } /* reconfigure transfer */ ret = dma_set_config_legacy(hd->chan, &hd->config); if (ret < 0) { - comp_err(dev, "host_copy_one_shot(): dma_set_config() failed, ret = %u", ret); + comp_err(dev, "dma_set_config() failed, ret = %u", ret); return ret; } ret = dma_copy_legacy(hd->chan, copy_bytes, DMA_COPY_ONE_SHOT); if (ret < 0) { - comp_err(dev, "host_copy_one_shot(): dma_copy() failed, ret = %u", ret); + comp_err(dev, "dma_copy() failed, ret = %u", ret); return ret; } @@ -228,7 +227,9 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt struct comp_buffer *sink; int ret; bool update_mailbox = false; +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES bool send_ipc = false; +#endif if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { source = hd->dma_buffer; @@ -242,7 +243,7 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt /* 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", + comp_err(dev, "dma buffer copy failed, dir %d bytes %d avail %d free %d", dev->direction, bytes, audio_stream_get_avail_samples(&source->stream) * audio_stream_frame_bytes(&source->stream), @@ -252,6 +253,10 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt if (ret < 0) return; +#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS + io_perf_monitor_update_data(hd->io_perf_host_byte_count, bytes); +#endif + hd->total_data_processed += bytes; /* new local period, update host buffer position blks @@ -269,6 +274,7 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt if (hd->cont_update_posn) update_mailbox = true; +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES /* Don't send stream position if no_stream_position == 1 */ if (!hd->no_stream_position) { hd->report_pos += bytes; @@ -288,13 +294,16 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt send_ipc = true; } } +#endif if (update_mailbox) { pipeline_get_timestamp(dev->pipeline, dev, &hd->posn); mailbox_stream_write(dev->pipeline->posn_offset, &hd->posn, sizeof(hd->posn)); +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES if (send_ipc) ipc_msg_send(hd->msg, &hd->posn, false); +#endif } } @@ -344,7 +353,7 @@ static void host_dma_cb(void *arg, enum notify_id type, void *data) struct host_data *hd = comp_get_drvdata(dev); uint32_t bytes = next->elem.size; - comp_dbg(dev, "host_dma_cb() %p", &comp_host); + comp_dbg(dev, "%p", &comp_host); /* update position */ host_common_update(hd, dev, bytes); @@ -369,7 +378,7 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev /* get data sizes from DMA */ ret = dma_get_data_size_legacy(hd->chan, &avail_bytes, &free_bytes); if (ret < 0) { - comp_err(dev, "host_get_copy_bytes_normal(): dma_get_data_size() failed, ret = %u", + comp_err(dev, "dma_get_data_size() failed, ret = %u", ret); /* return 0 copy_bytes in case of error to skip DMA copy */ return 0; @@ -411,7 +420,7 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal uint32_t flags = 0; int ret; - comp_dbg(dev, "host_copy_normal()"); + comp_dbg(dev, "entry"); if (hd->copy_type == COMP_COPY_BLOCKING) flags |= DMA_COPY_BLOCKING; @@ -422,7 +431,7 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal ret = dma_copy_legacy(hd->chan, copy_bytes, flags); if (ret < 0) - comp_err(dev, "host_copy_normal(): dma_copy() failed, ret = %u", ret); + comp_err(dev, "dma_copy() failed, ret = %u", ret); return ret; } @@ -442,21 +451,21 @@ static int create_local_elems(struct host_data *hd, struct comp_dev *dev, uint32 elem_array = &hd->local.elem_array; /* config buffer will be used as proxy */ - err = dma_sg_alloc(&hd->config.elem_array, SOF_MEM_ZONE_RUNTIME, + err = dma_sg_alloc(NULL, &hd->config.elem_array, SOF_MEM_FLAG_USER, dir, 1, 0, 0, 0); if (err < 0) { - comp_err(dev, "create_local_elems(): dma_sg_alloc() failed"); + comp_err(dev, "dma_sg_alloc() failed"); return err; } } else { elem_array = &hd->config.elem_array; } - err = dma_sg_alloc(elem_array, SOF_MEM_ZONE_RUNTIME, dir, buffer_count, + err = dma_sg_alloc(NULL, elem_array, SOF_MEM_FLAG_USER, dir, buffer_count, buffer_bytes, (uintptr_t)(audio_stream_get_addr(&hd->dma_buffer->stream)), 0); if (err < 0) { - comp_err(dev, "create_local_elems(): dma_sg_alloc() failed"); + comp_err(dev, "dma_sg_alloc() failed"); return err; } @@ -484,7 +493,7 @@ int host_common_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) return 0; if (!hd->chan) { - comp_err(dev, "host_trigger(): no dma channel configured"); + comp_err(dev, "no dma channel configured"); return -EINVAL; } @@ -492,14 +501,14 @@ int host_common_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) case COMP_TRIGGER_START: ret = dma_start_legacy(hd->chan); if (ret < 0) - comp_err(dev, "host_trigger(): dma_start() failed, ret = %u", + comp_err(dev, "dma_start() failed, ret = %u", ret); break; case COMP_TRIGGER_STOP: case COMP_TRIGGER_XRUN: ret = dma_stop_legacy(hd->chan); if (ret < 0) - comp_err(dev, "host_trigger(): dma stop failed: %d", + comp_err(dev, "dma stop failed: %d", ret); break; default: @@ -515,7 +524,7 @@ static int host_trigger(struct comp_dev *dev, int cmd) struct host_data *hd = comp_get_drvdata(dev); int ret; - comp_dbg(dev, "host_trigger()"); + comp_dbg(dev, "entry"); ret = comp_set_state(dev, cmd); if (ret < 0) @@ -539,7 +548,7 @@ int host_common_new(struct host_data *hd, struct comp_dev *dev, hd->dma = dma_get(dir, 0, DMA_DEV_HOST, DMA_ACCESS_SHARED); if (!hd->dma) { - comp_err(dev, "host_common_new(): dma_get() returned NULL"); + comp_err(dev, "dma_get() returned NULL"); return -ENODEV; } @@ -550,12 +559,14 @@ int host_common_new(struct host_data *hd, struct comp_dev *dev, ipc_build_stream_posn(&hd->posn, SOF_IPC_STREAM_POSITION, config_id); +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES hd->msg = ipc_msg_init(hd->posn.rhdr.hdr.cmd, hd->posn.rhdr.hdr.size); if (!hd->msg) { - comp_err(dev, "host_common_new(): ipc_msg_init failed"); + comp_err(dev, "ipc_msg_init failed"); dma_put(hd->dma); return -ENOMEM; } +#endif hd->chan = NULL; hd->copy_type = COMP_COPY_NORMAL; @@ -578,7 +589,7 @@ static struct comp_dev *host_new(const struct comp_driver *drv, return NULL; dev->ipc_config = *config; - hd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*hd)); + hd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*hd)); if (!hd) goto e_data; @@ -595,26 +606,36 @@ static struct comp_dev *host_new(const struct comp_driver *drv, e_dev: rfree(hd); e_data: - rfree(dev); + comp_free_device(dev); return NULL; } void host_common_free(struct host_data *hd) { +#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS + /* Check for NULL just in case the params() step is omitted */ + if (hd->io_perf_host_byte_count) { + io_perf_monitor_release_slot(hd->io_perf_host_byte_count); + hd->io_perf_host_byte_count = NULL; + } +#endif + dma_put(hd->dma); +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES ipc_msg_free(hd->msg); - dma_sg_free(&hd->config.elem_array); +#endif + dma_sg_free(NULL, &hd->config.elem_array); } static void host_free(struct comp_dev *dev) { struct host_data *hd = comp_get_drvdata(dev); - comp_dbg(dev, "host_free()"); + comp_dbg(dev, "entry"); host_common_free(hd); rfree(hd); - rfree(dev); + comp_free_device(dev); } static int host_elements_reset(struct host_data *hd, struct comp_dev *dev) @@ -655,11 +676,11 @@ static int host_verify_params(struct comp_dev *dev, { int ret; - comp_dbg(dev, "host_verify_params()"); + comp_dbg(dev, "entry"); ret = comp_verify_params(dev, 0, params); if (ret < 0) { - comp_err(dev, "host_verify_params(): comp_verify_params() failed"); + comp_err(dev, "comp_verify_params() failed"); return ret; } @@ -675,7 +696,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, uint32_t period_bytes; uint32_t buffer_size; uint32_t addr_align; - uint32_t align; + uint32_t align = 0; int err; /* host params always installed by pipeline IPC */ @@ -689,7 +710,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, err = dma_get_attribute_legacy(hd->dma, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, &addr_align); if (err < 0) { - comp_err(dev, "host_params(): could not get dma buffer address alignment, err = %d", + comp_err(dev, "could not get dma buffer address alignment, err = %d", err); return err; } @@ -697,7 +718,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, /* retrieve DMA buffer size alignment */ err = dma_get_attribute_legacy(hd->dma, DMA_ATTR_BUFFER_ALIGNMENT, &align); if (err < 0 || !align) { - comp_err(dev, "host_params(): could not get valid dma buffer alignment, err = %d, align = %u", + comp_err(dev, "could not get valid dma buffer alignment, err = %d, align = %u", err, align); return -EINVAL; } @@ -706,7 +727,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, err = dma_get_attribute_legacy(hd->dma, DMA_ATTR_BUFFER_PERIOD_COUNT, &period_count); if (err < 0 || !period_count) { - comp_err(dev, "host_params(): could not get valid dma buffer period count, err = %d, period_count = %u", + comp_err(dev, "could not get valid dma buffer period count, err = %d, period_count = %u", err, period_count); return -EINVAL; } @@ -716,11 +737,16 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, else hd->local_buffer = comp_dev_get_first_data_producer(dev); + if (!hd->local_buffer) { + comp_err(dev, "no local buffer found"); + return -EINVAL; + } + period_bytes = dev->frames * audio_stream_frame_bytes(&hd->local_buffer->stream); if (!period_bytes) { - comp_err(dev, "host_params(): invalid period_bytes"); + comp_err(dev, "invalid period_bytes"); err = -EINVAL; goto out; } @@ -754,15 +780,16 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, if (hd->dma_buffer) { 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", + comp_err(dev, "buffer_set_size() failed, buffer_size = %u", buffer_size); goto out; } } else { - hd->dma_buffer = buffer_alloc(buffer_size, SOF_MEM_CAPS_DMA, 0, - addr_align, false); + hd->dma_buffer = buffer_alloc(NULL, buffer_size, + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA, + addr_align, BUFFER_USAGE_NOT_SHARED); if (!hd->dma_buffer) { - comp_err(dev, "host_params(): failed to alloc dma buffer"); + comp_err(dev, "failed to alloc dma buffer"); err = -ENOMEM; goto out; } @@ -791,14 +818,14 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, */ hd->chan = dma_channel_get_legacy(hd->dma, hd->stream_tag); if (!hd->chan) { - comp_err(dev, "host_params(): hd->chan is NULL"); + comp_err(dev, "hd->chan is NULL"); err = -ENODEV; goto out; } err = dma_set_config_legacy(hd->chan, &hd->config); if (err < 0) { - comp_err(dev, "host_params(): dma_set_config() failed"); + comp_err(dev, "dma_set_config() failed"); dma_channel_put_legacy(hd->chan); hd->chan = NULL; goto out; @@ -808,7 +835,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, &hd->dma_copy_align); if (err < 0) { - comp_err(dev, "host_params(): dma_get_attribute()"); + comp_err(dev, "dma_get_attribute()"); goto out; } @@ -825,6 +852,25 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, pcm_get_conversion_function(audio_stream_get_frm_fmt(&hd->local_buffer->stream), audio_stream_get_frm_fmt(&hd->local_buffer->stream)); +#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS + if (!hd->io_perf_host_byte_count) { + /* On the Host side, unlike the DAI side, the port direction values (INPUT/OUTPUT) + * match the stream direction enum values (CAPTURE/PLAYBACK), so we can directly + * use params->direction here. + */ + struct io_perf_data_item init_data = { + IO_PERF_HDA_ID, + hd->chan->index, + params->direction, + IO_PERF_POWERED_UP_ENABLED, + IO_PERF_D0IX_POWER_MODE, + 0, 0, 0 + }; + + io_perf_monitor_init_data(&hd->io_perf_host_byte_count, &init_data); + } +#endif + out: hd->cb_dev = dev; @@ -843,11 +889,11 @@ static int host_params(struct comp_dev *dev, struct host_data *hd = comp_get_drvdata(dev); int err; - comp_dbg(dev, "host_params()"); + comp_dbg(dev, "entry"); err = host_verify_params(dev, params); if (err < 0) { - comp_err(dev, "host_params(): pcm params verification failed."); + comp_err(dev, "pcm params verification failed."); return err; } @@ -865,7 +911,7 @@ static int host_prepare(struct comp_dev *dev) struct host_data *hd = comp_get_drvdata(dev); int ret; - comp_dbg(dev, "host_prepare()"); + comp_dbg(dev, "entry"); ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); if (ret < 0) @@ -901,9 +947,9 @@ void host_common_reset(struct host_data *hd, uint16_t state) } /* free all DMA elements */ - dma_sg_free(&hd->host.elem_array); - dma_sg_free(&hd->local.elem_array); - dma_sg_free(&hd->config.elem_array); + dma_sg_free(NULL, &hd->host.elem_array); + dma_sg_free(NULL, &hd->local.elem_array); + dma_sg_free(NULL, &hd->config.elem_array); /* It's safe that cleaning out `hd->config` after `dma_sg_free` for config.elem_array */ memset(&hd->config, 0, sizeof(hd->config)); @@ -916,7 +962,9 @@ void host_common_reset(struct host_data *hd, uint16_t state) /* reset buffer pointers */ hd->local_pos = 0; +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES hd->report_pos = 0; +#endif hd->total_data_processed = 0; hd->copy_type = COMP_COPY_NORMAL; @@ -928,7 +976,7 @@ static int host_reset(struct comp_dev *dev) { struct host_data *hd = comp_get_drvdata(dev); - comp_dbg(dev, "host_reset()"); + comp_dbg(dev, "entry"); host_common_reset(hd, dev->state); dev->state = COMP_STATE_READY; @@ -999,6 +1047,8 @@ static uint64_t host_get_processed_data(struct comp_dev *dev, uint32_t stream_no return ret; } +DECLARE_TR_CTX(host_tr, SOF_UUID(host_uuid), LOG_LEVEL_INFO); + static const struct comp_driver comp_host = { .type = SOF_COMP_HOST, .uid = SOF_RT_UUID(host_uuid), @@ -1024,8 +1074,7 @@ static SHARED_DATA struct comp_driver_info comp_host_info = { UT_STATIC void sys_comp_host_init(void) { - comp_register(platform_shared_get(&comp_host_info, - sizeof(comp_host_info))); + comp_register(&comp_host_info); } DECLARE_MODULE(sys_comp_host_init); diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index 43d8686db9f8..95f8f35a3736 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -24,6 +24,8 @@ #include <rtos/string.h> #include <sof/ut.h> #include <sof/trace/trace.h> +#include <sof/debug/telemetry/performance_monitor.h> +#include <sof/schedule/ll_schedule_domain.h> /* zephyr_ll_user_heap() */ #include <ipc/stream.h> #include <ipc/topology.h> #include <user/trace.h> @@ -32,6 +34,10 @@ #include <stddef.h> #include <stdint.h> +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE +#include <ipc4/notification.h> +#endif + #include "copier/copier.h" #include "copier/host_copier.h" @@ -41,8 +47,6 @@ LOG_MODULE_REGISTER(host_comp, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(host); -DECLARE_TR_CTX(host_tr, SOF_UUID(host_uuid), LOG_LEVEL_INFO); - static inline struct dma_sg_elem *next_buffer(struct hc_buf *hc) { if (!hc->elem_array.elems || !hc->elem_array.count) @@ -81,7 +85,7 @@ static int host_dma_set_config_and_copy(struct host_data *hd, struct comp_dev *d local_elem->size = bytes; /* reconfigure transfer */ - ret = dma_config(hd->chan->dma->z_dev, hd->chan->index, &hd->z_config); + ret = sof_dma_config(hd->dma, hd->chan_index, &hd->z_config); if (ret < 0) { comp_err(dev, "dma_config() failed, ret = %d", ret); @@ -90,9 +94,9 @@ static int host_dma_set_config_and_copy(struct host_data *hd, struct comp_dev *d cb(dev, bytes); - ret = dma_reload(hd->chan->dma->z_dev, hd->chan->index, 0, 0, bytes); + ret = sof_dma_reload(hd->dma, hd->chan_index, bytes); if (ret < 0) { - comp_err(dev, "dma_copy() failed, ret = %d", + comp_err(dev, "dma_reload() failed, ret = %d", ret); return ret; } @@ -134,7 +138,7 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c uint32_t split_value; int ret = 0; - comp_dbg(dev, "host_copy_one_shot()"); + comp_dbg(dev, "entry"); copy_bytes = host_get_copy_bytes_one_shot(hd); if (!copy_bytes) { @@ -204,7 +208,7 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c struct dma_sg_elem *local_elem = hd->config.elem_array.elems; int ret = 0; - comp_dbg(dev, "host_copy_one_shot()"); + comp_dbg(dev, "entry"); copy_bytes = host_get_copy_bytes_one_shot(hd); if (!copy_bytes) { @@ -220,17 +224,17 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c hd->z_config.head_block->block_size = local_elem->size; /* reconfigure transfer */ - ret = dma_config(hd->chan->dma->z_dev, hd->chan->index, &hd->z_config); + ret = sof_dma_config(hd->dma, hd->chan_index, &hd->z_config); if (ret < 0) { - comp_err(dev, "dma_config() failed, ret = %u", ret); + comp_err(dev, "dma_config() failed, ret = %d", ret); return ret; } cb(dev, copy_bytes); - ret = dma_reload(hd->chan->dma->z_dev, hd->chan->index, 0, 0, copy_bytes); + ret = sof_dma_reload(hd->dma, hd->chan_index, copy_bytes); if (ret < 0) - comp_err(dev, "dma_copy() failed, ret = %u", ret); + comp_err(dev, "dma_reload() failed, ret = %d", ret); return ret; } @@ -242,7 +246,9 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt struct comp_buffer *sink; int ret; bool update_mailbox = false; +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES bool send_ipc = false; +#endif if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { source = hd->dma_buffer; @@ -260,6 +266,10 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt return; } +#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS + io_perf_monitor_update_data(hd->io_perf_host_byte_count, bytes); +#endif + hd->total_data_processed += bytes; /* new local period, update host buffer position blks @@ -277,6 +287,7 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt if (hd->cont_update_posn) update_mailbox = true; +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES /* Don't send stream position if no_stream_position == 1 */ if (!hd->no_stream_position) { hd->report_pos += bytes; @@ -296,13 +307,16 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt send_ipc = true; } } +#endif if (update_mailbox) { pipeline_get_timestamp(dev->pipeline, dev, &hd->posn); mailbox_stream_write(dev->pipeline->posn_offset, &hd->posn, sizeof(hd->posn)); +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES if (send_ipc) ipc_msg_send(hd->msg, &hd->posn, false); +#endif } } @@ -349,7 +363,7 @@ static void host_dma_cb(struct comp_dev *dev, size_t bytes) { struct host_data *hd = comp_get_drvdata(dev); - comp_cl_dbg(&comp_host, "host_dma_cb() %p", &comp_host); + comp_cl_dbg(&comp_host, "%p", &comp_host); /* update position */ host_common_update(hd, dev, bytes); @@ -359,6 +373,50 @@ static void host_dma_cb(struct comp_dev *dev, size_t bytes) host_common_one_shot(hd, bytes); } +/* get status from dma and check for xrun */ +static int host_get_status(struct comp_dev *dev, struct host_data *hd, struct dma_status *stat) +{ + int ret = sof_dma_get_status(hd->dma, hd->chan_index, stat); +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE + if (ret == -EPIPE && !hd->xrun_notification_sent) { + hd->xrun_notification_sent = send_copier_gateway_xrun_notif_msg + (dev->pipeline->pipeline_id, dev->direction); + } else if (!ret) { + hd->xrun_notification_sent = false; + } +#endif + return ret; +} + +/* Minimum time between 2 consecutive "no bytes to copy" messages in milliseconds */ +#define SOF_MIN_NO_BYTES_INTERVAL_MS 20 + +static inline bool host_handle_eos(struct host_data *hd, struct comp_dev *dev, + uint32_t avail_samples) +{ + struct sof_audio_buffer *buffer = &hd->local_buffer->audio_buffer; + enum sof_audio_buffer_state state = audio_buffer_get_state(buffer); + + if (!dev->pipeline->expect_eos) + return false; + + if (!avail_samples) { + /* EOS is detected, so we need to set the sink + * state to AUDIOBUF_STATE_END_OF_STREAM. + */ + if (state != AUDIOBUF_STATE_END_OF_STREAM) { + audio_buffer_set_eos(buffer); + comp_info(dev, "- EOS detected"); + } + return true; + } + + if (state == AUDIOBUF_STATE_END_OF_STREAM) + comp_warn(dev, "Data available after reporting end of stream!"); + + return false; +} + /** * Calculates bytes to be copied in normal mode. * @param dev Host component device. @@ -375,20 +433,40 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev int ret; /* get data sizes from DMA */ - ret = dma_get_status(hd->chan->dma->z_dev, hd->chan->index, &dma_stat); + ret = host_get_status(dev, hd, &dma_stat); if (ret < 0) { - comp_err(dev, "dma_get_status() failed, ret = %u", + comp_err(dev, "dma_get_status() failed, ret = %d", ret); /* return 0 copy_bytes in case of error to skip DMA copy */ return 0; } + /* HDA DMA Write and Read Position registers are not cleared by hardware on + * dma_stop() or dma_start(). However, the dma_buffer is recreated after a reset + * with its w_ptr and r_ptr set to NULL. The w_ptr and r_ptr must be kept in sync + * with the hardware DMA Write and Read Positions. + * Other types of DMA clear their hardware Read/Write Positions upon dma_stop() + * or dma_start(). Additionally, some DMAs, such as GPDMA, do not populate + * dma_status::write_position and read_position. Therefore, synchronization is + * done here only for HDA DMA. + * + * For deep buffers, dma_reload() is called less frequently than consume/produce + * on dma_buffer. Replicate the hardware state of the DMA buffer to the dma_buffer + * struct only when no consume/produce operations on dma_buffer have been called + * since the last dma_reload() (hence hd->partial_size == 0 check here). + */ + if ((hd->dma->plat_data.caps & SOF_DMA_CAP_HDA) && hd->partial_size == 0) + audio_stream_sync_to_hw(&hd->dma_buffer->stream, &dma_stat); + 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->stream); + + if (host_handle_eos(hd, dev, avail_samples)) + return 0; } else { avail_samples = audio_stream_get_avail_samples(&buffer->stream); free_samples = (dma_stat.free - hd->partial_size) / dma_sample_bytes; @@ -400,12 +478,31 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev * in order to avoid high load spike * if FAST_MODE is enabled, then one period limitation is omitted */ - if (!(hd->ipc_host.feature_mask & BIT(IPC4_COPIER_FAST_MODE))) + if (!(hd->ipc_host.feature_mask & BIT(IPC4_COPIER_FAST_MODE))) { + const uint64_t now = k_uptime_get(); + const uint64_t delta = now - hd->nobytes_last_logged; + const bool reset_skipped = delta > SOF_MIN_NO_BYTES_INTERVAL_MS; + dma_copy_bytes = MIN(hd->period_bytes, dma_copy_bytes); - if (!dma_copy_bytes) - comp_info(dev, "no bytes to copy, available samples: %d, free_samples: %d", - avail_samples, free_samples); + if (hd->n_skipped > 1 && (dma_copy_bytes || reset_skipped)) { + comp_warn(dev, + "Skipped %u no-bytes events in last %llu ms, bytes %u", + hd->n_skipped - 1, delta, dma_copy_bytes); + hd->n_skipped = 0; + } + + if (!dma_copy_bytes) { + if (!hd->n_skipped || reset_skipped) { + hd->nobytes_last_logged = now; + hd->n_skipped = 0; + comp_warn(dev, + "no bytes to copy, available samples: %u, free_samples: %u", + avail_samples, free_samples); + } + hd->n_skipped++; + } + } /* dma_copy_bytes should be aligned to minimum possible chunk of * data to be copied by dma. @@ -460,16 +557,16 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal 0; int ret = 0; - comp_dbg(dev, "host_copy_normal()"); + comp_dbg(dev, "entry"); copy_bytes = host_get_copy_bytes_normal(hd, dev); if (!copy_bytes) { if (hd->partial_size != 0) { if (stream_sync(hd, dev)) { - ret = dma_reload(hd->chan->dma->z_dev, hd->chan->index, 0, 0, - hd->partial_size); + ret = sof_dma_reload(hd->dma, hd->chan_index, + hd->partial_size); if (ret < 0) - comp_err(dev, "dma_reload() failed, ret = %u", ret); + comp_err(dev, "dma_reload() failed, ret = %d", ret); hd->partial_size = 0; } @@ -493,10 +590,10 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal 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, - hd->partial_size); + ret = sof_dma_reload(hd->dma, hd->chan_index, + hd->partial_size); if (ret < 0) - comp_err(dev, "dma_reload() failed, ret = %u", ret); + comp_err(dev, "dma_reload() failed, ret = %d", ret); hd->partial_size = 0; } @@ -504,8 +601,9 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal 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) +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 dma_sg_elem_array *elem_array; uint32_t dir; @@ -519,7 +617,7 @@ static int create_local_elems(struct host_data *hd, struct comp_dev *dev, uint32 elem_array = &hd->local.elem_array; /* config buffer will be used as proxy */ - err = dma_sg_alloc(&hd->config.elem_array, SOF_MEM_ZONE_RUNTIME, + err = dma_sg_alloc(hd->alloc_ctx.heap, &hd->config.elem_array, SOF_MEM_FLAG_USER, dir, 1, 0, 0, 0); if (err < 0) { comp_err(dev, "dma_sg_alloc() failed"); @@ -529,7 +627,7 @@ static int create_local_elems(struct host_data *hd, struct comp_dev *dev, uint32 elem_array = &hd->config.elem_array; } - err = dma_sg_alloc(elem_array, SOF_MEM_ZONE_RUNTIME, dir, buffer_count, + err = dma_sg_alloc(hd->alloc_ctx.heap, elem_array, SOF_MEM_FLAG_USER, dir, buffer_count, buffer_bytes, (uintptr_t)audio_stream_get_addr(&hd->dma_buffer->stream), 0); if (err < 0) { @@ -560,7 +658,7 @@ int host_common_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) if (cmd != COMP_TRIGGER_START && hd->copy_type == COMP_COPY_ONE_SHOT) return ret; - if (!hd->chan) { + if (hd->chan_index < 0) { comp_err(dev, "no dma channel configured"); return -EINVAL; } @@ -568,14 +666,14 @@ int host_common_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) switch (cmd) { case COMP_TRIGGER_START: hd->partial_size = 0; - ret = dma_start(hd->chan->dma->z_dev, hd->chan->index); + ret = sof_dma_start(hd->dma, hd->chan_index); if (ret < 0) - comp_err(dev, "dma_start() failed, ret = %u", + comp_err(dev, "dma_start() failed, ret = %d", ret); break; case COMP_TRIGGER_STOP: case COMP_TRIGGER_XRUN: - ret = dma_stop(hd->chan->dma->z_dev, hd->chan->index); + ret = sof_dma_stop(hd->dma, hd->chan_index); if (ret < 0) comp_err(dev, "dma stop failed: %d", ret); @@ -592,7 +690,7 @@ static int host_trigger(struct comp_dev *dev, int cmd) struct host_data *hd = comp_get_drvdata(dev); int ret; - comp_dbg(dev, "host_trigger()"); + comp_dbg(dev, "entry"); ret = comp_set_state(dev, cmd); if (ret < 0) @@ -604,11 +702,13 @@ static int host_trigger(struct comp_dev *dev, int cmd) return host_common_trigger(hd, dev, cmd); } -int host_common_new(struct host_data *hd, struct comp_dev *dev, - const struct ipc_config_host *ipc_host, uint32_t config_id) +__cold int host_common_new(struct host_data *hd, struct comp_dev *dev, + const struct ipc_config_host *ipc_host, uint32_t config_id) { uint32_t dir; + assert_can_be_cold(); + hd->ipc_host = *ipc_host; /* request HDA DMA with shared access privilege */ dir = hd->ipc_host.direction == SOF_IPC_STREAM_PLAYBACK ? @@ -627,27 +727,43 @@ int host_common_new(struct host_data *hd, struct comp_dev *dev, ipc_build_stream_posn(&hd->posn, SOF_IPC_STREAM_POSITION, config_id); +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES hd->msg = ipc_msg_init(hd->posn.rhdr.hdr.cmd, sizeof(hd->posn)); if (!hd->msg) { comp_err(dev, "ipc_msg_init failed"); sof_dma_put(hd->dma); return -ENOMEM; } - hd->chan = NULL; +#endif + hd->chan_index = -EINVAL; hd->copy_type = COMP_COPY_NORMAL; +#ifdef CONFIG_SOF_USERSPACE_LL + /* + * copier_host_create() uses mod_zalloc() to allocate + * the 'hd' host data object and does not set hd->alloc_ctx. + * If LL is run in user-space, assign the 'heap' here. + */ + hd->alloc_ctx.heap = zephyr_ll_user_heap(); +#else + hd->alloc_ctx.heap = NULL; +#endif + return 0; } -static struct comp_dev *host_new(const struct comp_driver *drv, - const struct comp_ipc_config *config, - const void *spec) +__cold static struct comp_dev *host_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec) { struct comp_dev *dev; struct host_data *hd; const struct ipc_config_host *ipc_host = spec; + struct k_heap *heap = NULL; int ret; + assert_can_be_cold(); + comp_cl_dbg(&comp_host, "host_new()"); dev = comp_alloc(drv, sizeof(*dev)); @@ -655,10 +771,13 @@ static struct comp_dev *host_new(const struct comp_driver *drv, return NULL; dev->ipc_config = *config; - hd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*hd)); + hd = sof_heap_alloc(heap, SOF_MEM_FLAG_USER, sizeof(*hd), 0); if (!hd) goto e_data; + memset(hd, 0, sizeof(*hd)); + + hd->nobytes_last_logged = k_uptime_get(); comp_set_drvdata(dev, hd); ret = host_common_new(hd, dev, ipc_host, dev->ipc_config.id); @@ -670,28 +789,50 @@ static struct comp_dev *host_new(const struct comp_driver *drv, return dev; e_dev: - rfree(hd); + sof_heap_free(heap, hd); e_data: - rfree(dev); + comp_free_device(dev); return NULL; } -void host_common_free(struct host_data *hd) +__cold void host_common_free(struct host_data *hd) { + assert_can_be_cold(); + +#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS + /* Check for NULL just in case the params() step is omitted */ + if (hd->io_perf_host_byte_count) { + io_perf_monitor_release_slot(hd->io_perf_host_byte_count); + hd->io_perf_host_byte_count = NULL; + } +#endif + + /* release DMA channel if not already done by reset */ + if (hd->chan_index >= 0) { + sof_dma_stop(hd->dma, hd->chan_index); + sof_dma_release_channel(hd->dma, hd->chan_index); + hd->chan_index = -EINVAL; + } + sof_dma_put(hd->dma); +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES ipc_msg_free(hd->msg); - dma_sg_free(&hd->config.elem_array); +#endif + dma_sg_free(hd->alloc_ctx.heap, &hd->config.elem_array); } -static void host_free(struct comp_dev *dev) +__cold static void host_free(struct comp_dev *dev) { struct host_data *hd = comp_get_drvdata(dev); - comp_dbg(dev, "host_free()"); + assert_can_be_cold(); + + comp_dbg(dev, "entry"); host_common_free(hd); - rfree(hd); - rfree(dev); + /* NULL heap passed in host_new(), must match! */ + sof_heap_free(NULL, hd); + comp_free_device(dev); } static int host_elements_reset(struct host_data *hd, int direction) @@ -732,7 +873,7 @@ static int host_verify_params(struct comp_dev *dev, { int ret; - comp_dbg(dev, "host_verify_params()"); + comp_dbg(dev, "entry"); ret = comp_verify_params(dev, 0, params); if (ret < 0) { @@ -756,8 +897,8 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, uint32_t buffer_size; uint32_t buffer_size_preferred; uint32_t addr_align; - uint32_t align; - int i, channel, err; + uint32_t align = 0; + int i, err; bool is_scheduling_source = dev == dev->pipeline->sched_comp; uint32_t round_up_size; @@ -769,8 +910,8 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, hd->cont_update_posn = params->cont_update_posn; /* retrieve DMA buffer address alignment */ - err = dma_get_attribute(hd->dma->z_dev, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, - &addr_align); + err = sof_dma_get_attribute(hd->dma, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, + &addr_align); if (err < 0) { comp_err(dev, "could not get dma buffer address alignment, err = %d", err); @@ -778,7 +919,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, } /* retrieve DMA buffer size alignment */ - err = dma_get_attribute(hd->dma->z_dev, DMA_ATTR_BUFFER_SIZE_ALIGNMENT, &align); + err = sof_dma_get_attribute(hd->dma, DMA_ATTR_BUFFER_SIZE_ALIGNMENT, &align); if (err < 0 || !align) { comp_err(dev, "could not get valid dma buffer alignment, err = %d, align = %u", err, align); @@ -797,6 +938,11 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, else hd->local_buffer = comp_dev_get_first_data_producer(dev); + if (!hd->local_buffer) { + comp_err(dev, "no local buffer found"); + return -EINVAL; + } + period_bytes = dev->frames * get_frame_bytes(params->frame_fmt, params->channels); if (!period_bytes) { @@ -843,8 +989,9 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, } } else { /* allocate not shared buffer */ - hd->dma_buffer = buffer_alloc_range(buffer_size_preferred, buffer_size, - SOF_MEM_CAPS_DMA, 0, addr_align, false); + hd->dma_buffer = buffer_alloc_range(&hd->alloc_ctx, buffer_size_preferred, buffer_size, + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA, + addr_align, BUFFER_USAGE_NOT_SHARED); if (!hd->dma_buffer) { comp_err(dev, "failed to alloc dma buffer"); return -ENOMEM; @@ -887,27 +1034,20 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, /* get DMA channel from DMAC * note: stream_tag is ignored by dw-dma */ - channel = dma_request_channel(hd->dma->z_dev, &hda_chan); - if (channel < 0) { + hd->chan_index = sof_dma_request_channel(hd->dma, hda_chan); + if (hd->chan_index < 0) { comp_err(dev, "requested channel %d is busy", hda_chan); return -ENODEV; } - hd->chan = &hd->dma->chan[channel]; uint32_t buffer_addr = 0; uint32_t buffer_bytes = 0; uint32_t addr; - hd->chan->direction = config->direction; - hd->chan->desc_count = config->elem_array.count; - hd->chan->is_scheduling_source = config->is_scheduling_source; - hd->chan->period = config->period; - memset(dma_cfg, 0, sizeof(*dma_cfg)); - dma_block_cfg = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, - SOF_MEM_CAPS_RAM, - sizeof(*dma_block_cfg)); + dma_block_cfg = sof_heap_alloc(hd->alloc_ctx.heap, SOF_MEM_FLAG_USER, + sizeof(*dma_block_cfg), 0); if (!dma_block_cfg) { comp_err(dev, "dma_block_config allocation failed"); @@ -915,6 +1055,8 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, goto err_release_channel; } + memset(dma_block_cfg, 0, sizeof(*dma_block_cfg)); + dma_cfg->block_count = 1; dma_cfg->source_data_size = config->src_width; dma_cfg->dest_data_size = config->dest_width; @@ -950,14 +1092,14 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, break; } - err = dma_config(hd->chan->dma->z_dev, hd->chan->index, dma_cfg); + err = sof_dma_config(hd->dma, hd->chan_index, dma_cfg); if (err < 0) { comp_err(dev, "dma_config() failed"); goto err_free_block_cfg; } - err = dma_get_attribute(hd->dma->z_dev, DMA_ATTR_COPY_ALIGNMENT, - &hd->dma_copy_align); + err = sof_dma_get_attribute(hd->dma, DMA_ATTR_COPY_ALIGNMENT, + &hd->dma_copy_align); if (err < 0) { comp_err(dev, "dma_get_attribute() failed"); @@ -974,14 +1116,32 @@ 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; +#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS + if (!hd->io_perf_host_byte_count) { + /* On the Host side, unlike the DAI side, the port direction values (INPUT/OUTPUT) + * match the stream direction enum values (CAPTURE/PLAYBACK), so we can directly + * use params->direction here. + */ + struct io_perf_data_item init_data = { + IO_PERF_HDA_ID, + hd->chan_index, + params->direction, + IO_PERF_POWERED_UP_ENABLED, + IO_PERF_D0IX_POWER_MODE, + 0, 0, 0 + }; + io_perf_monitor_init_data(&hd->io_perf_host_byte_count, &init_data); + } +#endif + return 0; err_free_block_cfg: dma_cfg->head_block = NULL; - rfree(dma_block_cfg); + sof_heap_free(hd->alloc_ctx.heap, dma_block_cfg); err_release_channel: - dma_release_channel(hd->dma->z_dev, hd->chan->index); - hd->chan = NULL; + sof_dma_release_channel(hd->dma, hd->chan_index); + hd->chan_index = -EINVAL; return err; } @@ -992,7 +1152,7 @@ static int host_params(struct comp_dev *dev, struct host_data *hd = comp_get_drvdata(dev); int err; - comp_dbg(dev, "host_params()"); + comp_dbg(dev, "entry"); err = host_verify_params(dev, params); if (err < 0) { @@ -1014,7 +1174,7 @@ static int host_prepare(struct comp_dev *dev) struct host_data *hd = comp_get_drvdata(dev); int ret; - comp_dbg(dev, "host_prepare()"); + comp_dbg(dev, "entry"); ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); if (ret < 0) @@ -1039,16 +1199,16 @@ static int host_position(struct comp_dev *dev, void host_common_reset(struct host_data *hd, uint16_t state) { - if (hd->chan) { - dma_stop(hd->chan->dma->z_dev, hd->chan->index); - dma_release_channel(hd->dma->z_dev, hd->chan->index); - hd->chan = NULL; + if (hd->chan_index >= 0) { + sof_dma_stop(hd->dma, hd->chan_index); + sof_dma_release_channel(hd->dma, hd->chan_index); + hd->chan_index = -EINVAL; } /* free all DMA elements */ - dma_sg_free(&hd->host.elem_array); - dma_sg_free(&hd->local.elem_array); - dma_sg_free(&hd->config.elem_array); + dma_sg_free(hd->alloc_ctx.heap, &hd->host.elem_array); + dma_sg_free(hd->alloc_ctx.heap, &hd->local.elem_array); + dma_sg_free(hd->alloc_ctx.heap, &hd->config.elem_array); /* free DMA buffer */ if (hd->dma_buffer) { @@ -1058,11 +1218,13 @@ void host_common_reset(struct host_data *hd, uint16_t state) /* free DMA block configuration */ if (hd->z_config.head_block) - rfree(hd->z_config.head_block); + sof_heap_free(hd->alloc_ctx.heap, hd->z_config.head_block); /* reset buffer pointers */ hd->local_pos = 0; +#if CONFIG_HOST_DMA_IPC_POSITION_UPDATES hd->report_pos = 0; +#endif hd->total_data_processed = 0; hd->copy_type = COMP_COPY_NORMAL; @@ -1074,7 +1236,7 @@ static int host_reset(struct comp_dev *dev) { struct host_data *hd = comp_get_drvdata(dev); - comp_dbg(dev, "host_reset()"); + comp_dbg(dev, "entry"); host_common_reset(hd, dev->state); dev->state = COMP_STATE_READY; @@ -1092,11 +1254,13 @@ static int host_copy(struct comp_dev *dev) return host_common_copy(hd, dev, host_dma_cb); } -static int host_get_attribute(struct comp_dev *dev, uint32_t type, - void *value) +__cold static int host_get_attribute(struct comp_dev *dev, uint32_t type, + void *value) { struct host_data *hd = comp_get_drvdata(dev); + assert_can_be_cold(); + switch (type) { case COMP_ATTR_COPY_TYPE: *(enum comp_copy_type *)value = hd->copy_type; @@ -1111,11 +1275,13 @@ static int host_get_attribute(struct comp_dev *dev, uint32_t type, return 0; } -static int host_set_attribute(struct comp_dev *dev, uint32_t type, - void *value) +__cold static int host_set_attribute(struct comp_dev *dev, uint32_t type, + void *value) { struct host_data *hd = comp_get_drvdata(dev); + assert_can_be_cold(); + switch (type) { case COMP_ATTR_COPY_TYPE: hd->copy_type = *(enum comp_copy_type *)value; @@ -1145,6 +1311,8 @@ static uint64_t host_get_processed_data(struct comp_dev *dev, uint32_t stream_no return ret; } +DECLARE_TR_CTX(host_tr, SOF_UUID(host_uuid), LOG_LEVEL_INFO); + static const struct comp_driver comp_host = { .type = SOF_COMP_HOST, .uid = SOF_RT_UUID(host_uuid), @@ -1170,8 +1338,7 @@ static SHARED_DATA struct comp_driver_info comp_host_info = { UT_STATIC void sys_comp_host_init(void) { - comp_register(platform_shared_get(&comp_host_info, - sizeof(comp_host_info))); + comp_register(&comp_host_info); } DECLARE_MODULE(sys_comp_host_init); diff --git a/src/audio/igo_nr/CMakeLists.txt b/src/audio/igo_nr/CMakeLists.txt index 49f9af9a2003..f0fee994d82f 100644 --- a/src/audio/igo_nr/CMakeLists.txt +++ b/src/audio/igo_nr/CMakeLists.txt @@ -1,8 +1,22 @@ # SPDX-License-Identifier: BSD-3-Clause +if(CONFIG_COMP_IGO_NR STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/igo_nr_llext) + add_dependencies(app igo_nr) + return() +endif() + add_local_sources(sof igo_nr.c) + if (CONFIG_COMP_IGO_NR_STUB) -add_local_sources(sof igo_nr_stub.c) -else () -sof_add_static_library(IGOChrome ${CMAKE_CURRENT_LIST_DIR}/libigonr.a) -endif () + add_local_sources(sof igo_nr_stub.c) + +else() + is_zephyr(zephyr) + if(zephyr) ### Zephyr ### + zephyr_library_import(IGOChrome ${CMAKE_CURRENT_LIST_DIR}/libigonr.a) + else() + sof_add_static_library(IGOChrome ${CMAKE_CURRENT_LIST_DIR}/libigonr.a) + endif() + +endif() diff --git a/src/audio/igo_nr/Kconfig b/src/audio/igo_nr/Kconfig index be987594f4ee..d584df40cb67 100644 --- a/src/audio/igo_nr/Kconfig +++ b/src/audio/igo_nr/Kconfig @@ -4,7 +4,6 @@ config COMP_IGO_NR tristate "IGO NR component" select COMP_BLOB select COMP_IGO_NR_STUB if COMP_STUBS - default n help This option enables Intelligo non-speech noise reduction. The feature links to a proprietary binary libigonr.a that currently is supported on different Xtensa DSP platforms. Please email @@ -14,7 +13,6 @@ config COMP_IGO_NR_STUB bool "IGO NR component" select COMP_BLOB depends on COMP_IGO_NR - default n help This option builds the IGO adapter with a stub library, it should only be used for testing or CI purposes. diff --git a/src/audio/igo_nr/README.md b/src/audio/igo_nr/README.md new file mode 100644 index 000000000000..3ab01a6a9cbc --- /dev/null +++ b/src/audio/igo_nr/README.md @@ -0,0 +1,14 @@ +# Intelligo Noise Reduction (IGO NR) Architecture + +This directory contains integration for the Intelligo Noise Reduction algorithms. + +## Overview + +IGO NR is an advanced noise suppression engine targeting microphone input paths to improve speech intelligibility. + +## Configuration and Scripts + +- **Kconfig**: Enables the Intelligo non-speech noise reduction component (`COMP_IGO_NR`), which utilizes a proprietary binary `libigonr.a`. Also provides a `COMP_IGO_NR_STUB` option for testing/CI environments that links a stub library instead of the proprietary binary. +- **CMakeLists.txt**: Handles the build integration. It either links the stub (`igo_nr_stub.c`) or the actual binary (`libigonr.a`) based on the Kconfig selection. Supports Zephyr integration module loading and standard external library compilation (`llext`). +- **igo_nr.toml**: Defines the topology parameters for the module (UUID, module_type, pin configuration, and processing constraints configured under `mod_cfg`). +- **Topology (.conf)**: Derived from `tools/topology/topology2/include/components/igo_nr.conf`, it defines the `igo_nr` widget object for topology generation. Included with mixer controls binding get/put operations (`259`) and defaults to UUID `bc:e2:6a:69:77:28:eb:11:ad:c1:02:42:ac:12:00:02` (type `effect`). diff --git a/src/audio/igo_nr/igo_nr.c b/src/audio/igo_nr/igo_nr.c index 78eead2b1e97..f762cf86b49d 100644 --- a/src/audio/igo_nr/igo_nr.c +++ b/src/audio/igo_nr/igo_nr.c @@ -12,7 +12,6 @@ #include <user/trace.h> #include <sof/common.h> #include <rtos/panic.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> #include <sof/list.h> @@ -45,8 +44,6 @@ LOG_MODULE_REGISTER(igo_nr, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(igo_nr); -DECLARE_TR_CTX(igo_nr_tr, SOF_UUID(igo_nr_uuid), LOG_LEVEL_INFO); - static void igo_nr_lib_process(struct comp_data *cd) { /* Pass through the active channel if @@ -72,10 +69,10 @@ static int igo_nr_capture_s16(struct comp_data *cd, struct sof_sink *sink, int32_t frames) { - int16_t *x, *y1, *y2; - int16_t *x_start, *y_start, *x_end, *y_end; + int16_t const *x, *x_start, *x_end; + int16_t *y1, *y2, *y_start, *y_end; int16_t sample; - size_t x_size, y_size; + int x_size, y_size; size_t request_size = frames * source_get_frame_bytes(source); int sink_samples_without_wrap; int samples_without_wrap; @@ -96,12 +93,14 @@ static int igo_nr_capture_s16(struct comp_data *cd, #endif - ret = source_get_data(source, request_size, (void const **)&x, - (void const **)&x_start, &x_size); + /* use the sample-count source/sink accessors so the returned sizes are + * already in samples and need no byte-to-element conversion + */ + ret = source_get_data_s16(source, request_size, &x, &x_start, &x_size); if (ret) return ret; - ret = sink_get_buffer(sink, request_size, (void **)&y1, (void **)&y_start, &y_size); + ret = sink_get_buffer_s16(sink, request_size, &y1, &y_start, &y_size); if (ret) { source_release_data(source, 0); return ret; @@ -133,7 +132,10 @@ static int igo_nr_capture_s16(struct comp_data *cd, i++; } - x = cir_buf_wrap(x, x_start, x_end); + /* x is const (read-only source), so wrap manually instead of + * cir_buf_wrap() which takes a non-const void * + */ + x = (x >= x_end) ? x - x_size : x; y1 = cir_buf_wrap(y1, y_start, y_end); samples_left -= samples_without_wrap; } @@ -175,9 +177,9 @@ static int igo_nr_capture_s24(struct comp_data *cd, struct sof_sink *sink, int32_t frames) { - int32_t *x, *y1, *y2; - int32_t *x_start, *y_start, *x_end, *y_end; - size_t x_size, y_size; + int32_t const *x, *x_start, *x_end; + int32_t *y1, *y2, *y_start, *y_end; + int x_size, y_size; size_t request_size = frames * source_get_frame_bytes(source); int sink_samples_without_wrap; int samples_without_wrap; @@ -198,12 +200,14 @@ static int igo_nr_capture_s24(struct comp_data *cd, #endif - ret = source_get_data(source, request_size, (void const **)&x, - (void const **)&x_start, &x_size); + /* use the sample-count source/sink accessors so the returned sizes are + * already in samples and need no byte-to-element conversion + */ + ret = source_get_data_s32(source, request_size, &x, &x_start, &x_size); if (ret) return ret; - ret = sink_get_buffer(sink, request_size, (void **)&y1, (void **)&y_start, &y_size); + ret = sink_get_buffer_s32(sink, request_size, &y1, &y_start, &y_size); if (ret) { source_release_data(source, 0); return ret; @@ -234,7 +238,10 @@ static int igo_nr_capture_s24(struct comp_data *cd, i++; } - x = cir_buf_wrap(x, x_start, x_end); + /* x is const (read-only source), so wrap manually instead of + * cir_buf_wrap() which takes a non-const void * + */ + x = (x >= x_end) ? x - x_size : x; y1 = cir_buf_wrap(y1, y_start, y_end); samples_left -= samples_without_wrap; } @@ -276,9 +283,9 @@ static int igo_nr_capture_s32(struct comp_data *cd, struct sof_sink *sink, int32_t frames) { - int32_t *x, *y1, *y2; - int32_t *x_start, *y_start, *x_end, *y_end; - size_t x_size, y_size; + int32_t const *x, *x_start, *x_end; + int32_t *y1, *y2, *y_start, *y_end; + int x_size, y_size; size_t request_size = frames * source_get_frame_bytes(source); int sink_samples_without_wrap; int samples_without_wrap; @@ -299,12 +306,14 @@ static int igo_nr_capture_s32(struct comp_data *cd, #endif - ret = source_get_data(source, request_size, (void const **)&x, - (void const **)&x_start, &x_size); + /* use the sample-count source/sink accessors so the returned sizes are + * already in samples and need no byte-to-element conversion + */ + ret = source_get_data_s32(source, request_size, &x, &x_start, &x_size); if (ret) return ret; - ret = sink_get_buffer(sink, request_size, (void **)&y1, (void **)&y_start, &y_size); + ret = sink_get_buffer_s32(sink, request_size, &y1, &y_start, &y_size); if (ret) { source_release_data(source, 0); return ret; @@ -335,7 +344,10 @@ static int igo_nr_capture_s32(struct comp_data *cd, i++; } - x = cir_buf_wrap(x, x_start, x_end); + /* x is const (read-only source), so wrap manually instead of + * cir_buf_wrap() which takes a non-const void * + */ + x = (x >= x_end) ? x - x_size : x; y1 = cir_buf_wrap(y1, y_start, y_end); samples_left -= samples_without_wrap; } @@ -380,24 +392,24 @@ static inline int32_t set_capture_func(struct processing_module *mod, struct sof switch (source_get_frm_fmt(source)) { #if CONFIG_FORMAT_S16LE case SOF_IPC_FRAME_S16_LE: - comp_info(dev, "set_capture_func(), SOF_IPC_FRAME_S16_LE"); + comp_info(dev, "SOF_IPC_FRAME_S16_LE"); cd->igo_nr_func = igo_nr_capture_s16; break; #endif #if CONFIG_FORMAT_S24LE case SOF_IPC_FRAME_S24_4LE: - comp_info(dev, "set_capture_func(), SOF_IPC_FRAME_S24_4LE"); + comp_info(dev, "SOF_IPC_FRAME_S24_4LE"); cd->igo_nr_func = igo_nr_capture_s24; break; #endif #if CONFIG_FORMAT_S32LE case SOF_IPC_FRAME_S32_LE: - comp_info(dev, "set_capture_func(), SOF_IPC_FRAME_S32_LE"); + comp_info(dev, "SOF_IPC_FRAME_S32_LE"); cd->igo_nr_func = igo_nr_capture_s32; break; #endif default: - comp_err(dev, "set_capture_func(), invalid frame_fmt"); + comp_err(dev, "invalid frame_fmt"); return -EINVAL; } return 0; @@ -412,39 +424,39 @@ static int igo_nr_init(struct processing_module *mod) size_t bs = cfg->size; int32_t ret; - comp_info(dev, "igo_nr_init()"); + comp_info(dev, "entry"); /* Check first that configuration blob size is sane */ if (bs > SOF_IGO_NR_MAX_SIZE) { - comp_err(dev, "igo_nr_init() error: configuration blob size = %u > %d", + comp_err(dev, "error: configuration blob size = %u > %d", bs, SOF_IGO_NR_MAX_SIZE); return -EINVAL; } - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; md->private = cd; ret = IgoLibGetInfo(&cd->igo_lib_info); if (ret != IGO_RET_OK) { - comp_err(dev, "igo_nr_init(): IgoLibGetInfo() Failed."); + comp_err(dev, "IgoLibGetInfo() Failed."); ret = -EINVAL; goto cd_fail; } - cd->p_handle = rballoc(0, SOF_MEM_CAPS_RAM, cd->igo_lib_info.handle_size); + cd->p_handle = mod_balloc(mod, cd->igo_lib_info.handle_size); if (!cd->p_handle) { - comp_err(dev, "igo_nr_init(): igo_handle memory rballoc error for size %d", + comp_err(dev, "igo_handle memory mod_balloc error for size %d", cd->igo_lib_info.handle_size); ret = -ENOMEM; goto cd_fail; } /* Handler for configuration data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "igo_nr_init(): comp_data_blob_handler_new() failed."); + comp_err(dev, "mod_data_blob_handler_new() failed."); ret = -ENOMEM; goto cd_fail2; } @@ -452,7 +464,7 @@ static int igo_nr_init(struct processing_module *mod) /* Get configuration data */ ret = comp_init_data_blob(cd->model_handler, bs, cfg->data); if (ret < 0) { - comp_err(dev, "igo_nr_init(): comp_init_data_blob() failed."); + comp_err(dev, "comp_init_data_blob() failed."); ret = -ENOMEM; goto cd_fail3; } @@ -463,13 +475,13 @@ static int igo_nr_init(struct processing_module *mod) return 0; cd_fail3: - comp_data_blob_handler_free(cd->model_handler); + mod_data_blob_handler_free(mod, cd->model_handler); cd_fail2: - rfree(cd->p_handle); + mod_free(mod, cd->p_handle); cd_fail: - rfree(cd); + mod_free(mod, cd); return ret; } @@ -477,12 +489,12 @@ static int igo_nr_free(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "igo_nr_free()"); + comp_info(mod->dev, "entry"); - comp_data_blob_handler_free(cd->model_handler); + mod_data_blob_handler_free(mod, cd->model_handler); - rfree(cd->p_handle); - rfree(cd); + mod_free(mod, cd->p_handle); + mod_free(mod, cd); return 0; } @@ -493,30 +505,30 @@ static int32_t igo_nr_check_params(struct processing_module *mod, struct sof_sou struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - comp_info(dev, "igo_nr_check_params()"); + comp_info(dev, "entry"); /* set source/sink_frames/rate */ cd->source_rate = source_get_rate(source); cd->sink_rate = sink_get_rate(sink); if (source_get_channels(source) != sink_get_channels(sink)) { - comp_err(dev, "igo_nr_check_params(), mismatch source/sink stream channels"); + comp_err(dev, "mismatch source/sink stream channels"); cd->invalid_param = true; } if (!cd->sink_rate) { - comp_err(dev, "igo_nr_check_params(), zero sink rate"); + comp_err(dev, "zero sink rate"); return -EINVAL; } /* The igo_nr supports sample rate 48000 only. */ switch (cd->source_rate) { case 48000: - comp_info(dev, "igo_nr_check_params(), sample rate = 48000"); + comp_info(dev, "sample rate = 48000"); cd->invalid_param = false; break; default: - comp_err(dev, "igo_nr_check_params(), invalid sample rate"); + comp_err(dev, "invalid sample rate"); cd->invalid_param = true; } @@ -529,10 +541,10 @@ static int32_t igo_nr_check_config_validity(struct comp_dev *dev, struct sof_igo_nr_config *p_config = comp_get_data_blob(cd->model_handler, NULL, NULL); if (!p_config) { - comp_err(dev, "igo_nr_check_config_validity() error: invalid cd->model_handler"); + comp_err(dev, "error: invalid cd->model_handler"); return -EINVAL; } else if (p_config->active_channel_idx >= SOF_IPC_MAX_CHANNELS) { - comp_err(dev, "igo_nr_check_config_validity() error: invalid active_channel_idxs"); + comp_err(dev, "error: invalid active_channel_idxs"); return -EINVAL; } else { return 0; @@ -566,13 +578,17 @@ static int igo_nr_get_config(struct processing_module *mod, switch (cdata->cmd) { case SOF_CTRL_CMD_BINARY: - comp_info(dev, "igo_nr_get_config(), SOF_CTRL_CMD_BINARY"); + comp_info(dev, "SOF_CTRL_CMD_BINARY"); return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); case SOF_CTRL_CMD_SWITCH: + if (cdata->num_elems > SOF_IPC_MAX_CHANNELS) { + comp_err(dev, "num_elems %u out of range", cdata->num_elems); + return -EINVAL; + } for (j = 0; j < cdata->num_elems; j++) { cdata->chanv[j].channel = j; cdata->chanv[j].value = cd->process_enable[j]; - comp_info(dev, "igo_nr_get_config(), channel = %u, value = %u", + comp_info(dev, "channel = %u, value = %u", cdata->chanv[j].channel, cdata->chanv[j].value); } @@ -629,7 +645,7 @@ static int igo_nr_set_config(struct processing_module *mod, uint32_t param_id, struct comp_dev *dev = mod->dev; int ret; - comp_info(dev, "igo_nr_set_config()"); + comp_info(dev, "entry"); #if CONFIG_IPC_MAJOR_3 struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; @@ -660,7 +676,7 @@ static int igo_nr_set_config(struct processing_module *mod, uint32_t param_id, comp_info(dev, "igo_nr_cmd_set_config(), SOF_IPC4_SWITCH_CONTROL_PARAM_ID"); return igo_nr_set_chan(mod, ctl); case SOF_IPC4_ENUM_CONTROL_PARAM_ID: - comp_err(dev, "igo_nr_set_config(), illegal control."); + comp_err(dev, "illegal control."); return -EINVAL; } @@ -675,7 +691,7 @@ static int igo_nr_set_config(struct processing_module *mod, uint32_t param_id, static void igo_nr_print_config(struct processing_module *mod) { - struct comp_data *cd = module_get_private_data(mod); + struct comp_data __maybe_unused *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; comp_dbg(dev, " igo_params_ver %d", @@ -718,17 +734,32 @@ static void igo_nr_print_config(struct processing_module *mod) static void igo_nr_set_igo_params(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - struct sof_igo_nr_config *p_config = comp_get_data_blob(cd->model_handler, NULL, NULL); + size_t config_size; + struct sof_igo_nr_config *p_config = comp_get_data_blob(cd->model_handler, + &config_size, NULL); struct comp_dev *dev = mod->dev; - comp_info(dev, "igo_nr_set_igo_params()"); - igo_nr_check_config_validity(dev, cd); + comp_info(dev, "entry"); + + if (!p_config) + return; - if (p_config) { - comp_info(dev, "New config detected."); - cd->config = *p_config; - igo_nr_print_config(mod); + /* the whole config struct is copied below, so the blob must be at + * least that large + */ + if (config_size < sizeof(cd->config)) { + comp_err(dev, "New config too small: %zu < %zu", + config_size, sizeof(cd->config)); + return; } + + /* Adopt the host blob only when the new config is valid */ + if (igo_nr_check_config_validity(dev, cd) != 0) + return; + + comp_info(dev, "New config detected."); + cd->config = *p_config; + igo_nr_print_config(mod); } /* copy and process stream data from source to sink buffers */ @@ -816,7 +847,12 @@ static int32_t igo_nr_prepare(struct processing_module *mod, struct sof_sink *sink = sinks[0]; int ret; - comp_dbg(dev, "igo_nr_prepare()"); + comp_dbg(dev, "entry"); + + if (!source || !sink) { + comp_err(dev, "no source or sink"); + return -ENOTCONN; + } #if CONFIG_IPC_MAJOR_4 ret = igo_nr_ipc4_params(mod, source, sink); @@ -830,8 +866,7 @@ static int32_t igo_nr_prepare(struct processing_module *mod, if (ret) return ret; - source_set_alignment_constants(source, 1, IGO_FRAME_SIZE); - sink_set_alignment_constants(sink, 1, IGO_FRAME_SIZE); + source_set_alignment_constants(source, SOF_FRAME_BYTE_ALIGN, IGO_FRAME_SIZE); igo_nr_set_igo_params(mod); @@ -862,7 +897,7 @@ static int igo_nr_reset(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "igo_nr_reset()"); + comp_info(mod->dev, "entry"); cd->igo_nr_func = NULL; @@ -883,9 +918,6 @@ static const struct module_interface igo_nr_interface = { .free = igo_nr_free }; -DECLARE_MODULE_ADAPTER(igo_nr_interface, igo_nr_uuid, igo_nr_tr); -SOF_MODULE_INIT(igo_nr, sys_comp_module_igo_nr_interface_init); - #if CONFIG_COMP_IGO_NR_MODULE /* modular: llext dynamic link */ @@ -893,14 +925,15 @@ SOF_MODULE_INIT(igo_nr, sys_comp_module_igo_nr_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_IGO_NR 0xBC, 0xE2, 0x6A, 0x69, 0x77, 0x28, 0xEB, 0x11, 0xC1, 0xAD, \ - 0x02, 0x42, 0xAC, 0x12, 0x00, 0x02 - -SOF_LLEXT_MOD_ENTRY(igo_nr, &igo_nr_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("IGO_NR", igo_nr_llext_entry, 1, UUID_IGO_NR, 40); + SOF_LLEXT_MODULE_MANIFEST("IGO_NR", &igo_nr_interface, 1, SOF_REG_UUID(igo_nr), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(igo_nr_tr, SOF_UUID(igo_nr_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(igo_nr_interface, igo_nr_uuid, igo_nr_tr); +SOF_MODULE_INIT(igo_nr, sys_comp_module_igo_nr_interface_init); + #endif diff --git a/src/audio/igo_nr/igo_nr.toml b/src/audio/igo_nr/igo_nr.toml index ad14ad2a7691..723066425f83 100644 --- a/src/audio/igo_nr/igo_nr.toml +++ b/src/audio/igo_nr/igo_nr.toml @@ -5,7 +5,7 @@ REM # IGO_NR module config [[module.entry]] name = "IGO_NR" - uuid = "696AE2BC-2877-11EB-ADC1-0242AC120002" + uuid = UUIDREG_STR_IGO_NR affinity_mask = "0x1" instance_count = "40" domain_types = "0" diff --git a/src/audio/igo_nr/llext/CMakeLists.txt b/src/audio/igo_nr/llext/CMakeLists.txt index 3f336184fb7c..2e974cae7945 100644 --- a/src/audio/igo_nr/llext/CMakeLists.txt +++ b/src/audio/igo_nr/llext/CMakeLists.txt @@ -5,7 +5,6 @@ if(CONFIG_DTS_CODEC_STUB) sof_llext_build("igo_nr" SOURCES ../igo_nr.c ../igo_nr_stub.c - LIB openmodules ) target_include_directories(igo_nr_llext_lib PRIVATE "../../../../third_party/include" diff --git a/src/audio/intel_uaol.c b/src/audio/intel_uaol.c new file mode 100644 index 000000000000..baeb4a217103 --- /dev/null +++ b/src/audio/intel_uaol.c @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 Intel Corporation. All rights reserved. + */ + +#include <zephyr/drivers/uaol.h> +#include <rtos/string.h> +#include <sof/tlv.h> +#include <sof/audio/component_ext.h> +#include <sof/audio/intel_uaol.h> + +LOG_MODULE_REGISTER(uaol, CONFIG_SOF_LOG_LEVEL); + +struct ipc4_uaol_link_capabilities { + uint32_t input_streams_supported : 4; + uint32_t output_streams_supported : 4; + uint32_t bidirectional_streams_supported : 5; + uint32_t rsvd : 19; + uint32_t max_tx_fifo_size; + uint32_t max_rx_fifo_size; +} __packed __aligned(4); + +struct ipc4_uaol_capabilities { + uint32_t link_count; + struct ipc4_uaol_link_capabilities link_caps[]; +} __packed __aligned(4); + +#define DEV_AND_COMMA(node) DEVICE_DT_GET(node), +static const struct device *uaol_devs[] = { + DT_FOREACH_STATUS_OKAY(intel_adsp_uaol, DEV_AND_COMMA) +}; + +#if !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY +__cold void tlv_value_set_uaol_caps(struct sof_tlv *tuple, uint32_t type) +{ + const size_t dev_count = ARRAY_SIZE(uaol_devs); + struct uaol_capabilities dev_cap; + struct ipc4_uaol_capabilities *caps = (struct ipc4_uaol_capabilities *)tuple->value; + size_t caps_size = offsetof(struct ipc4_uaol_capabilities, link_caps[dev_count]); + size_t i; + int ret; + + assert_can_be_cold(); + + memset(caps, 0, caps_size); + + caps->link_count = dev_count; + for (i = 0; i < dev_count; i++) { + ret = uaol_get_capabilities(uaol_devs[i], &dev_cap); + if (ret) + continue; + + caps->link_caps[i].input_streams_supported = dev_cap.input_streams; + caps->link_caps[i].output_streams_supported = dev_cap.output_streams; + caps->link_caps[i].bidirectional_streams_supported = dev_cap.bidirectional_streams; + caps->link_caps[i].max_tx_fifo_size = dev_cap.max_tx_fifo_size; + caps->link_caps[i].max_rx_fifo_size = dev_cap.max_rx_fifo_size; + } + + tlv_value_set(tuple, type, caps_size, caps); +} +#endif /* !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY */ + +__cold int uaol_stream_id_to_hda_link_stream_id(int uaol_stream_id) +{ + size_t dev_count = ARRAY_SIZE(uaol_devs); + size_t i; + + assert_can_be_cold(); + + for (i = 0; i < dev_count; i++) { + int hda_link_stream_id = uaol_get_mapped_hda_link_stream_id(uaol_devs[i], + uaol_stream_id); + if (hda_link_stream_id >= 0) + return hda_link_stream_id; + } + + return -1; +} diff --git a/src/audio/kpb.c b/src/audio/kpb.c index 064b3acddb45..2cec91393517 100644 --- a/src/audio/kpb.c +++ b/src/audio/kpb.c @@ -55,6 +55,10 @@ #include <sof/lib/notifier.h> #endif +#ifdef KPB_HIFI3 +#include <xtensa/tie/xt_hifi3.h> +#endif + static const struct comp_driver comp_kpb; LOG_MODULE_REGISTER(kpb, CONFIG_SOF_LOG_LEVEL); @@ -66,8 +70,6 @@ SOF_DEFINE_REG_UUID(kpb); #define KPB_UUID kpb_uuid #endif -DECLARE_TR_CTX(kpb_tr, SOF_UUID(KPB_UUID), LOG_LEVEL_INFO); - SOF_DEFINE_REG_UUID(kpb_task); /* KPB private data, runtime data */ @@ -160,7 +162,19 @@ static void devicelist_reset(struct device_list *devlist, bool remove_items); static uint64_t kpb_task_deadline(void *data) { +#ifndef __ZEPHYR__ return SOF_TASK_DEADLINE_ALMOST_IDLE; +#else + struct draining_data *dd = (struct draining_data *)data; + uint64_t now; + + if (dd->next_copy_time == 0) + return 0; /* run immediately */ + + now = sof_cycle_get_64(); + return dd->next_copy_time > now ? + k_uptime_ticks() + k_cyc_to_ticks_near64(dd->next_copy_time - now) : 0; +#endif } #if CONFIG_AMS @@ -175,7 +189,7 @@ static void kpb_ams_kpd_notification(const struct ams_message_payload *const ams struct kpb_client *cli_data = (struct kpb_client *)ams_message_payload->message; struct comp_dev *dev = ctx; - comp_dbg(dev, "kpb_ams_kpd_notification()"); + comp_dbg(dev, "entry"); kpb_init_draining(dev, cli_data); } @@ -242,17 +256,17 @@ static int kpb_set_verify_ipc_params(struct comp_dev *dev, kpb->host_sink = NULL; if (!kpb_is_sample_width_supported(kpb->config.sampling_width)) { - comp_err(dev, "kpb_set_verify_ipc_params(): requested sampling width not supported"); + comp_err(dev, "requested sampling width not supported"); return -EINVAL; } if (kpb->config.channels > KPB_MAX_SUPPORTED_CHANNELS) { - comp_err(dev, "kpb_set_verify_ipc_params(): no of channels exceeded the limit"); + comp_err(dev, "no of channels exceeded the limit"); return -EINVAL; } if (kpb->config.sampling_freq != KPB_SAMPLNG_FREQUENCY) { - comp_err(dev, "kpb_set_verify_ipc_params(): requested sampling frequency not supported"); + comp_err(dev, "requested sampling frequency not supported"); return -EINVAL; } @@ -271,7 +285,7 @@ static void kpb_set_params(struct comp_dev *dev, struct comp_data *kpb = comp_get_drvdata(dev); enum sof_ipc_frame frame_fmt, valid_fmt; - comp_dbg(dev, "kpb_set_params()"); + comp_dbg(dev, "entry"); memset_s(params, sizeof(*params), 0, sizeof(*params)); params->channels = kpb->ipc4_cfg.base_cfg.audio_fmt.channels_count; @@ -321,19 +335,19 @@ static int kpb_get_attribute(struct comp_dev *dev, /** * \brief Initialize KPB sinks when binding. * \param[in] dev - component device pointer. - * \param[in] data - ipc4 bind/unbind data. + * \param[in] bind_data - bind/unbind data. * \return: none. */ -static int kpb_bind(struct comp_dev *dev, void *data) +static int kpb_bind(struct comp_dev *dev, struct bind_info *bind_data) { struct comp_data *kpb = comp_get_drvdata(dev); struct ipc4_module_bind_unbind *bu; int buf_id; int ret = 0; - comp_dbg(dev, "kpb_bind()"); + comp_dbg(dev, "entry"); - bu = (struct ipc4_module_bind_unbind *)data; + bu = bind_data->ipc4_data; buf_id = IPC4_COMP_ID(bu->extension.r.src_queue, bu->extension.r.dst_queue); /* We're assuming here that KPB Real Time sink (kpb->sel_sink) is @@ -371,15 +385,15 @@ static int kpb_bind(struct comp_dev *dev, void *data) * \param[in] data - ipc4 bind/unbind data. * \return: none. */ -static int kpb_unbind(struct comp_dev *dev, void *data) +static int kpb_unbind(struct comp_dev *dev, struct bind_info *unbind_data) { struct comp_data *kpb = comp_get_drvdata(dev); struct ipc4_module_bind_unbind *bu; int buf_id; - comp_dbg(dev, "kpb_bind()"); + comp_dbg(dev, "entry"); - bu = (struct ipc4_module_bind_unbind *)data; + bu = unbind_data->ipc4_data; buf_id = IPC4_COMP_ID(bu->extension.r.src_queue, bu->extension.r.dst_queue); /* Reset sinks when unbinding */ @@ -409,7 +423,7 @@ static int kpb_set_verify_ipc_params(struct comp_dev *dev, ipc_config->size); if (ret) { - comp_err(dev, "kpb_new(): cannot memcpy_s %d bytes into sof_kpb_config (%zu)\n", + comp_err(dev, "cannot memcpy_s %d bytes into sof_kpb_config (%zu)\n", ipc_config->size, sizeof(kpb->config)); return -EINVAL; } @@ -419,17 +433,17 @@ static int kpb_set_verify_ipc_params(struct comp_dev *dev, kpb->host_sink = NULL; if (!kpb_is_sample_width_supported(kpb->config.sampling_width)) { - comp_err(dev, "kpb_set_verify_ipc_params(): requested sampling width not supported"); + comp_err(dev, "requested sampling width not supported"); return -EINVAL; } if (kpb->config.channels > KPB_MAX_SUPPORTED_CHANNELS) { - comp_err(dev, "kpb_set_verify_ipc_params(): no of channels exceeded the limit"); + comp_err(dev, "no of channels exceeded the limit"); return -EINVAL; } if (kpb->config.sampling_freq != KPB_SAMPLNG_FREQUENCY) { - comp_err(dev, "kpb_set_verify_ipc_params(): requested sampling frequency not supported"); + comp_err(dev, "requested sampling frequency not supported"); return -EINVAL; } @@ -441,6 +455,8 @@ static void kpb_set_params(struct comp_dev *dev, {} #endif /* CONFIG_IPC_MAJOR_4 */ +static int kpb_params(struct comp_dev *dev, struct sof_ipc_stream_params *params); + /* * \brief Create a key phrase buffer component. * \param[in] config - generic ipc component pointer. @@ -473,7 +489,7 @@ static struct comp_dev *kpb_new(const struct comp_driver *drv, /* make sure data size is not bigger than config space */ if (ipc_config_size > kpb_config_size) { - comp_cl_err(&comp_kpb, "kpb_new(): ipc config size %zu too big", + comp_cl_err(&comp_kpb, "ipc config size %zu too big", ipc_config_size); return NULL; } @@ -483,9 +499,9 @@ static struct comp_dev *kpb_new(const struct comp_driver *drv, return NULL; dev->ipc_config = *config; - kpb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*kpb)); + kpb = rzalloc(SOF_MEM_FLAG_USER, sizeof(*kpb)); if (!kpb) { - rfree(dev); + comp_free_device(dev); return NULL; } @@ -493,7 +509,7 @@ static struct comp_dev *kpb_new(const struct comp_driver *drv, ret = kpb_set_verify_ipc_params(dev, ipc_process); if (ret) { - rfree(dev); + comp_free_device(dev); return NULL; } @@ -522,6 +538,17 @@ static struct comp_dev *kpb_new(const struct comp_driver *drv, dev->state = COMP_STATE_READY; kpb_change_state(kpb, KPB_STATE_CREATED); +#if CONFIG_IPC_MAJOR_4 + struct sof_ipc_stream_params params; + + /* retrieve params from the base config for IPC4 */ + ret = kpb_params(dev, ¶ms); + if (ret < 0) { + comp_free_device(dev); + return NULL; + } +#endif + return dev; } @@ -541,17 +568,16 @@ static size_t kpb_allocate_history_buffer(struct comp_data *kpb, /*! Current allocation size */ size_t ca_size = hb_size; /*! Memory caps priorites for history buffer */ - int hb_mcp[KPB_NO_OF_MEM_POOLS] = {SOF_MEM_CAPS_LP, SOF_MEM_CAPS_HP, - SOF_MEM_CAPS_RAM }; + int hb_mcp[KPB_NO_OF_MEM_POOLS] = {SOF_MEM_FLAG_USER | SOF_MEM_FLAG_LOW_POWER, SOF_MEM_FLAG_USER}; void *new_mem_block = NULL; size_t temp_ca_size; int i = 0; size_t allocated_size = 0; - comp_cl_info(&comp_kpb, "kpb_allocate_history_buffer()"); + comp_cl_info(&comp_kpb, "entry"); /* Initialize history buffer */ - kpb->hd.c_hb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + kpb->hd.c_hb = rzalloc(SOF_MEM_FLAG_USER, sizeof(struct history_buffer)); if (!kpb->hd.c_hb) return 0; @@ -568,7 +594,7 @@ static size_t kpb_allocate_history_buffer(struct comp_data *kpb, /* Try to allocate ca_size (current allocation size). At first * attempt it will be equal to hb_size (history buffer size). */ - new_mem_block = rballoc(0, hb_mcp[i], ca_size); + new_mem_block = rballoc(hb_mcp[i], ca_size); if (new_mem_block) { /* We managed to allocate a block of ca_size. @@ -590,8 +616,7 @@ static size_t kpb_allocate_history_buffer(struct comp_data *kpb, /* Yes, we still need at least one more buffer. * Let's first create new container for it. */ - new_hb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, - SOF_MEM_CAPS_RAM, + new_hb = rzalloc(SOF_MEM_FLAG_USER, sizeof(struct history_buffer)); if (!new_hb) return 0; @@ -623,7 +648,7 @@ static size_t kpb_allocate_history_buffer(struct comp_data *kpb, } } - comp_cl_info(&comp_kpb, "kpb_allocate_history_buffer(): allocated %zu bytes", + comp_cl_info(&comp_kpb, "allocated %zu bytes for history buffer", allocated_size); return allocated_size; @@ -640,7 +665,7 @@ static void kpb_free_history_buffer(struct history_buffer *buff) struct history_buffer *_buff; struct history_buffer *first_buff = buff; - comp_cl_info(&comp_kpb, "kpb_free_history_buffer()"); + comp_cl_info(&comp_kpb, "entry"); if (!buff) return; @@ -667,7 +692,7 @@ static void kpb_free(struct comp_dev *dev) { struct comp_data *kpb = comp_get_drvdata(dev); - comp_info(dev, "kpb_free()"); + comp_info(dev, "entry"); #if CONFIG_AMS /* Unregister KPB as AMS consumer */ @@ -676,7 +701,7 @@ static void kpb_free(struct comp_dev *dev) ret = ams_helper_unregister_consumer(dev, kpb->kpd_uuid_id, kpb_ams_kpd_notification); if (ret) - comp_err(dev, "kpb_free(): AMS unregister error %d", ret); + comp_err(dev, "AMS unregister error %d", ret); #else /* Unregister KPB from notifications */ notifier_unregister(dev, NULL, NOTIFIER_ID_KPB_CLIENT_EVT); @@ -695,7 +720,7 @@ static void kpb_free(struct comp_dev *dev) /* Free KPB */ rfree(kpb); - rfree(dev); + comp_free_device(dev); } /** @@ -706,21 +731,21 @@ static void kpb_free(struct comp_dev *dev) */ static int kpb_trigger(struct comp_dev *dev, int cmd) { - comp_info(dev, "kpb_trigger()"); + comp_info(dev, "entry"); return comp_set_state(dev, cmd); } -static int kbp_verify_params(struct comp_dev *dev, +static int kpb_verify_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) { int ret; - comp_dbg(dev, "kbp_verify_params()"); + comp_dbg(dev, "entry"); ret = comp_verify_params(dev, 0, params); if (ret < 0) { - comp_err(dev, "kpb_verify_params(): comp_verify_params() failed"); + comp_err(dev, "comp_verify_params() failed"); return ret; } @@ -740,15 +765,15 @@ static int kpb_params(struct comp_dev *dev, int err; if (dev->state == COMP_STATE_PREPARE) { - comp_err(dev, "kpb_params(): kpb has been already configured."); + comp_err(dev, "kpb has been already configured."); return PPL_STATUS_PATH_STOP; } kpb_set_params(dev, params); - err = kbp_verify_params(dev, params); + err = kpb_verify_params(dev, params); if (err < 0) { - comp_err(dev, "kpb_params(): pcm params verification failed"); + comp_err(dev, "pcm params verification failed"); return -EINVAL; } @@ -774,15 +799,25 @@ static int kpb_params(struct comp_dev *dev, static int kpb_prepare(struct comp_dev *dev) { struct comp_data *kpb = comp_get_drvdata(dev); + struct sof_ipc_stream_params params; int ret = 0; int i; size_t hb_size_req = KPB_MAX_BUFFER_SIZE(kpb->config.sampling_width, kpb->config.channels); - comp_dbg(dev, "kpb_prepare()"); + comp_dbg(dev, "entry"); + + /* retrieve the params from the base_cfg and update the source/sink buffer params */ + kpb_set_params(dev, ¶ms); + + ret = kpb_verify_params(dev, ¶ms); + if (ret < 0) { + comp_err(dev, "pcm params verification failed"); + return -EINVAL; + } if (kpb->state == KPB_STATE_RESETTING || kpb->state == KPB_STATE_RESET_FINISHING) { - comp_cl_err(&comp_kpb, "kpb_prepare(): can not prepare KPB due to ongoing reset, state log %x", + comp_cl_err(&comp_kpb, "can not prepare KPB due to ongoing reset, state log %x", kpb->state_log); return -EBUSY; } @@ -818,7 +853,7 @@ static int kpb_prepare(struct comp_dev *dev) /* Have we allocated what we requested? */ if (kpb->hd.buffer_size < hb_size_req) { - comp_cl_err(&comp_kpb, "kpb_prepare(): failed to allocate space for KPB buffer"); + comp_cl_err(&comp_kpb, "failed to allocate space for KPB buffer"); kpb_free_history_buffer(kpb->hd.c_hb); kpb->hd.c_hb = NULL; kpb->hd.buffer_size = 0; @@ -902,7 +937,7 @@ static int kpb_prepare(struct comp_dev *dev) #endif /* CONFIG_IPC_MAJOR_4 */ if (!kpb->sel_sink) { - comp_err(dev, "kpb_prepare(): could not find sink: sel_sink %p", + comp_err(dev, "could not find sink: sel_sink %p", kpb->sel_sink); ret = -EIO; } @@ -940,7 +975,7 @@ static int kpb_reset(struct comp_dev *dev) int ret = 0; int i; - comp_cl_info(&comp_kpb, "kpb_reset(): resetting from state %d, state log %x", + comp_cl_info(&comp_kpb, "resetting from state %d, state log %x", kpb->state, kpb->state_log); switch (kpb->state) { @@ -998,18 +1033,19 @@ static void kpb_micselect_copy16(struct comp_buffer *sink, { struct audio_stream *istream = &source->stream; struct audio_stream *ostream = &sink->stream; - uint16_t ch; + uint32_t ch; size_t i; AE_SETCBEGIN0(audio_stream_get_addr(ostream)); AE_SETCEND0(audio_stream_get_end_addr(ostream)); - buffer_stream_invalidate(source, size); + const size_t samples_per_chan = size / (sizeof(ae_int16) * micsel_channels); + + buffer_stream_invalidate(source, samples_per_chan * in_channels * sizeof(ae_int16)); const ae_int16 *in_ptr = audio_stream_get_rptr(istream); ae_int16x4 d16 = AE_ZERO16(); const size_t in_offset = in_channels * sizeof(ae_int16); const size_t out_offset = micsel_channels * sizeof(ae_int16); - const size_t samples_per_chan = size / (sizeof(uint16_t) * micsel_channels); ae_int16 *out_ptr; for (ch = 0; ch < micsel_channels; ch++) { @@ -1031,19 +1067,20 @@ static void kpb_micselect_copy32(struct comp_buffer *sink, { struct audio_stream *istream = &source->stream; struct audio_stream *ostream = &sink->stream; - uint16_t ch; + uint32_t ch; size_t i; AE_SETCBEGIN0(audio_stream_get_addr(ostream)); AE_SETCEND0(audio_stream_get_end_addr(ostream)); - buffer_stream_invalidate(source, size); + const size_t samples_per_chan = size / (sizeof(ae_int32) * micsel_channels); + + buffer_stream_invalidate(source, samples_per_chan * in_channels * sizeof(ae_int32)); const ae_int32 *in_ptr = audio_stream_get_rptr(istream); ae_int32x2 d32 = AE_ZERO32(); const size_t in_offset = in_channels * sizeof(ae_int32); const size_t out_offset = micsel_channels * sizeof(ae_int32); - const size_t samples_per_chan = size / (sizeof(uint32_t) * micsel_channels); ae_int32 *out_ptr; for (ch = 0; ch < micsel_channels; ch++) { @@ -1065,14 +1102,14 @@ static void kpb_micselect_copy16(struct comp_buffer *sink, { struct audio_stream *istream = &source->stream; struct audio_stream *ostream = &sink->stream; - - buffer_stream_invalidate(source, size); size_t out_samples; - uint16_t ch; + uint32_t ch; const int16_t *in_data; int16_t *out_data; - const uint32_t samples_per_chan = size / (sizeof(uint16_t) * micsel_channels); + const size_t samples_per_chan = size / (sizeof(uint16_t) * micsel_channels); + + buffer_stream_invalidate(source, samples_per_chan * in_channels * sizeof(uint16_t)); for (ch = 0; ch < micsel_channels; ch++) { out_samples = 0; @@ -1097,13 +1134,13 @@ static void kpb_micselect_copy32(struct comp_buffer *sink, { struct audio_stream *istream = &source->stream; struct audio_stream *ostream = &sink->stream; - - buffer_stream_invalidate(source, size); size_t out_samples; - uint16_t ch; + uint32_t ch; const int32_t *in_data; int32_t *out_data; - const uint32_t samples_per_chan = size / (sizeof(uint32_t) * micsel_channels); + const size_t samples_per_chan = size / (sizeof(uint32_t) * micsel_channels); + + buffer_stream_invalidate(source, samples_per_chan * in_channels * sizeof(uint32_t)); for (ch = 0; ch < micsel_channels; ch++) { out_samples = 0; @@ -1174,10 +1211,10 @@ static int kpb_copy(struct comp_dev *dev) uint32_t avail_bytes; uint32_t channels = kpb->config.channels; - comp_dbg(dev, "kpb_copy()"); + comp_dbg(dev, "entry"); if (list_is_empty(&dev->bsource_list)) { - comp_err(dev, "kpb_copy(): no source."); + comp_err(dev, "no source."); return -EINVAL; } @@ -1186,7 +1223,7 @@ static int kpb_copy(struct comp_dev *dev) /* Validate source */ if (!audio_stream_get_rptr(&source->stream)) { - comp_err(dev, "kpb_copy(): invalid source pointers."); + comp_err(dev, "invalid source pointers."); ret = -EINVAL; return ret; } @@ -1198,21 +1235,29 @@ static int kpb_copy(struct comp_dev *dev) ret = PPL_STATUS_PATH_STOP; if (!sink) { - comp_err(dev, "kpb_copy(): no sink."); + comp_err(dev, "no sink."); ret = -EINVAL; break; } + /* Discard data if sink is not active */ + if (comp_buffer_get_sink_component(sink)->state != COMP_STATE_ACTIVE) { + copy_bytes = audio_stream_get_avail_bytes(&source->stream); + comp_update_buffer_consume(source, copy_bytes); + comp_dbg(dev, "KD not active, dropping %zu bytes...", copy_bytes); + break; + } + /* Validate sink */ if (!audio_stream_get_wptr(&sink->stream)) { - comp_err(dev, "kpb_copy(): invalid selector sink pointers."); + comp_err(dev, "invalid selector sink pointers."); ret = -EINVAL; break; } 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", + comp_err(dev, "nothing to copy sink->free %u source->avail %u", audio_stream_get_free_bytes(&sink->stream), audio_stream_get_avail_bytes(&source->stream)); ret = PPL_STATUS_PATH_STOP; @@ -1233,7 +1278,7 @@ static int kpb_copy(struct comp_dev *dev) produced_bytes = copy_bytes * kpb->num_of_sel_mic / channels; produced_bytes = ROUND_DOWN(produced_bytes, total_bytes_per_sample); if (!copy_bytes) { - comp_err(dev, "kpb_copy(): nothing to copy sink->free %d source->avail %d", + comp_err(dev, "nothing to copy sink->free %u source->avail %u", free, avail); ret = PPL_STATUS_PATH_STOP; @@ -1248,7 +1293,7 @@ static int kpb_copy(struct comp_dev *dev) ret = kpb_buffer_data(dev, source, copy_bytes); if (ret) { - comp_err(dev, "kpb_copy(): internal buffering failed."); + comp_err(dev, "internal buffering failed."); break; } ret = PPL_STATUS_PATH_STOP; @@ -1260,7 +1305,7 @@ static int kpb_copy(struct comp_dev *dev) kpb->hd.buffered, copy_bytes); } else { - comp_err(dev, "kpb_copy(): too much data to buffer."); + comp_err(dev, "too much data to buffer."); } if (kpb->num_of_sel_mic == 0) @@ -1276,21 +1321,21 @@ static int kpb_copy(struct comp_dev *dev) sink = kpb->host_sink; if (!sink) { - comp_err(dev, "kpb_copy(): no sink."); + comp_err(dev, "no sink."); ret = -EINVAL; break; } /* Validate sink */ if (!audio_stream_get_wptr(&sink->stream)) { - comp_err(dev, "kpb_copy(): invalid host sink pointers."); + comp_err(dev, "invalid host sink pointers."); ret = -EINVAL; break; } 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", + comp_err(dev, "nothing to copy sink->free %u source->avail %u", audio_stream_get_free_bytes(&sink->stream), audio_stream_get_avail_bytes(&source->stream)); /* NOTE! We should stop further pipeline copy due to @@ -1322,20 +1367,20 @@ static int kpb_copy(struct comp_dev *dev) kpb->hd.free -= copy_bytes; if (ret) { - comp_err(dev, "kpb_copy(): internal buffering failed."); + comp_err(dev, "internal buffering failed."); break; } comp_update_buffer_consume(source, copy_bytes); } else { - comp_warn(dev, "kpb_copy(): buffering skipped (no data to copy, avail %d, free %zu", + comp_warn(dev, "buffering skipped (no data to copy, avail %u, free %zu", audio_stream_get_avail_bytes(&source->stream), kpb->hd.free); } break; default: - comp_cl_err(&comp_kpb, "kpb_copy(): wrong state (state %d, state log %x)", + comp_cl_err(&comp_kpb, "wrong state (state %d, state log %x)", kpb->state, kpb->state_log); ret = -EIO; break; @@ -1366,7 +1411,7 @@ static int kpb_buffer_data(struct comp_dev *dev, enum kpb_state state_preserved = kpb->state; size_t sample_width = kpb->config.sampling_width; - comp_dbg(dev, "kpb_buffer_data()"); + comp_dbg(dev, "entry"); /* We are allowed to buffer data in internal history buffer * only in KPB_STATE_RUN, KPB_STATE_DRAINING or KPB_STATE_INIT_DRAINING @@ -1375,7 +1420,7 @@ static int kpb_buffer_data(struct comp_dev *dev, if (kpb->state != KPB_STATE_RUN && kpb->state != KPB_STATE_DRAINING && kpb->state != KPB_STATE_INIT_DRAINING) { - comp_err(dev, "kpb_buffer_data(): wrong state! (current state %d, state log %x)", + comp_err(dev, "wrong state! (current state %d, state log %x)", kpb->state, kpb->state_log); return PPL_STATUS_PATH_STOP; } @@ -1400,12 +1445,12 @@ static int kpb_buffer_data(struct comp_dev *dev, timeout = k_cyc_to_ms_near64(current_time - timeout); if (timeout <= UINT_MAX) comp_err(dev, - "kpb_buffer_data(): timeout of %u [ms] (current state %d, state log %x)", + "timeout of %u [ms] (current state %d, state log %x)", (unsigned int)(timeout), kpb->state, kpb->state_log); else comp_err(dev, - "kpb_buffer_data(): timeout > %u [ms] (current state %d, state log %x)", + "timeout > %u [ms] (current state %d, state log %x)", UINT_MAX, kpb->state, kpb->state_log); return -ETIME; @@ -1485,7 +1530,7 @@ static void kpb_event_handler(void *arg, enum notify_id type, void *event_data) struct kpb_event_data *evd = event_data; struct kpb_client *cli = evd->client_data; - comp_info(dev, "kpb_event_handler(): received event with ID: %d ", + comp_info(dev, "received event with ID: %d ", evd->event_id); switch (evd->event_id) { @@ -1502,7 +1547,7 @@ static void kpb_event_handler(void *arg, enum notify_id type, void *event_data) /*TODO*/ break; default: - comp_err(dev, "kpb_cmd(): unsupported command"); + comp_err(dev, "unsupported command"); break; } } @@ -1521,20 +1566,20 @@ static int kpb_register_client(struct comp_data *kpb, struct kpb_client *cli) { int ret = 0; - comp_cl_info(&comp_kpb, "kpb_register_client()"); + comp_cl_info(&comp_kpb, "entry"); if (!cli) { - comp_cl_err(&comp_kpb, "kpb_register_client(): no client data"); + comp_cl_err(&comp_kpb, "no client data"); return -EINVAL; } /* Do we have a room for a new client? */ if (kpb->kpb_no_of_clients >= KPB_MAX_NO_OF_CLIENTS || cli->id >= KPB_MAX_NO_OF_CLIENTS) { - comp_cl_err(&comp_kpb, "kpb_register_client(): no free room for client = %u ", + comp_cl_err(&comp_kpb, "no free room for client = %u", cli->id); ret = -EINVAL; } else if (kpb->clients[cli->id].state != KPB_CLIENT_UNREGISTERED) { - comp_cl_err(&comp_kpb, "kpb_register_client(): client = %u already registered", + comp_cl_err(&comp_kpb, "client = %u already registered", cli->id); ret = -EINVAL; } else { @@ -1564,7 +1609,7 @@ static void kpb_init_draining(struct comp_dev *dev, struct kpb_client *cli) struct comp_data *kpb = comp_get_drvdata(dev); bool is_sink_ready = (comp_buffer_get_sink_state(kpb->host_sink) == COMP_STATE_ACTIVE); size_t sample_width = kpb->config.sampling_width; - size_t drain_req = cli->drain_req * kpb->config.channels * + size_t drain_req = (size_t)cli->drain_req * kpb->config.channels * (kpb->config.sampling_freq / 1000) * (KPB_SAMPLE_CONTAINER_SIZE(sample_width) / 8); struct history_buffer *buff = kpb->hd.c_hb; @@ -1573,24 +1618,24 @@ static void kpb_init_draining(struct comp_dev *dev, struct kpb_client *cli) size_t local_buffered; size_t drain_interval; size_t host_period_size = kpb->host_period_size; - size_t bytes_per_ms = KPB_SAMPLES_PER_MS * + size_t bytes_per_ms = (size_t)KPB_SAMPLES_PER_MS * (KPB_SAMPLE_CONTAINER_SIZE(sample_width) / 8) * kpb->config.channels; size_t period_bytes_limit; - comp_info(dev, "kpb_init_draining(): requested draining of %d [ms] from history buffer", + comp_info(dev, "requested draining of %d [ms] from history buffer", cli->drain_req); if (kpb->state != KPB_STATE_RUN) { - comp_err(dev, "kpb_init_draining(): wrong KPB state"); + comp_err(dev, "wrong KPB state"); } else if (cli->id > KPB_MAX_NO_OF_CLIENTS) { - comp_err(dev, "kpb_init_draining(): wrong client id"); + comp_err(dev, "wrong client id"); /* TODO: check also if client is registered */ } else if (!is_sink_ready) { - comp_err(dev, "kpb_init_draining(): sink not ready for draining"); + comp_err(dev, "sink not ready for draining"); } else if (kpb->hd.buffered < drain_req || cli->drain_req > KPB_MAX_DRAINING_REQ) { - comp_cl_err(&comp_kpb, "kpb_init_draining(): not enough data in history buffer"); + comp_cl_err(&comp_kpb, "not enough data in history buffer"); } else { /* Draining accepted, find proper buffer to start reading * At this point we are guaranteed that there is enough data @@ -1621,7 +1666,7 @@ static void kpb_init_draining(struct comp_dev *dev, struct kpb_client *cli) (uintptr_t)buff->start_addr; buffered += local_buffered; } else { - comp_err(dev, "kpb_init_draining(): incorrect buffer label"); + comp_err(dev, "incorrect buffer label"); } /* Check if this is already sufficient to start draining * if not, go to previous buffer and continue @@ -1669,26 +1714,33 @@ static void kpb_init_draining(struct comp_dev *dev, struct kpb_client *cli) drain_interval = k_ms_to_cyc_ceil64(host_period_size / bytes_per_ms) / KPB_DRAIN_NUM_OF_PPL_PERIODS_AT_ONCE; period_bytes_limit = host_period_size; - comp_info(dev, "kpb_init_draining(): sync_draining_mode selected with interval %u [uS].", + comp_info(dev, "sync_draining_mode selected with interval %u [uS].", (unsigned int)k_cyc_to_us_near64(drain_interval)); } else { /* Unlimited draining */ drain_interval = 0; period_bytes_limit = 0; - comp_info(dev, "kpb_init_draining: unlimited draining speed selected."); + comp_info(dev, "unlimited draining speed selected."); } - comp_info(dev, "kpb_init_draining(), schedule draining task"); + comp_info(dev, "schedule draining task"); /* Add one-time draining task into the scheduler. */ kpb->draining_task_data.sink = kpb->host_sink; kpb->draining_task_data.hb = buff; kpb->draining_task_data.drain_req = drain_req; + kpb->draining_task_data.drained = 0; kpb->draining_task_data.sample_width = sample_width; kpb->draining_task_data.drain_interval = drain_interval; + kpb->draining_task_data.period_copy_start = 0; kpb->draining_task_data.pb_limit = period_bytes_limit; + kpb->draining_task_data.period_bytes = 0; + kpb->draining_task_data.next_copy_time = 0; kpb->draining_task_data.dev = dev; kpb->draining_task_data.sync_mode_on = kpb->sync_draining_mode; + kpb->draining_task_data.task_iteration = 0; + kpb->draining_task_data.prev_adjustment_time = 0; + kpb->draining_task_data.prev_adjustment_drained = 0; /* save current sink copy type */ comp_get_attribute(comp_buffer_get_sink_component(kpb->host_sink), @@ -1701,11 +1753,67 @@ static void kpb_init_draining(struct comp_dev *dev, struct kpb_client *cli) /* Pause selector copy. */ comp_buffer_get_sink_component(kpb->sel_sink)->state = COMP_STATE_PAUSED; + if (!pm_runtime_is_active(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID)) + pm_runtime_disable(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID); + + comp_info(dev, "Scheduling draining task"); + + /* Change KPB internal state to DRAINING */ + kpb_change_state(kpb, KPB_STATE_DRAINING); + + kpb->draining_task_data.draining_time_start = sof_cycle_get_64(); + /* Schedule draining task */ schedule_task(&kpb->draining_task, 0, 0); } } +static void adjust_drain_interval(struct comp_data *kpb, struct draining_data *dd) +{ + uint64_t now; /* timestamp in wall-clock cycles */ + + /* readjast drain_interval every 32 task iterations */ + if (dd->task_iteration++ % 32) + return; + + now = sof_cycle_get_64(); + + if (dd->prev_adjustment_time) { + size_t drained; + size_t elapsed; + size_t actual_pace, optimal_pace; + size_t pipeline_period; + + drained = dd->drained - dd->prev_adjustment_drained; + elapsed = now - dd->prev_adjustment_time; + assert(elapsed); + /* average drained bytes per second */ + actual_pace = (size_t)k_ms_to_cyc_ceil64(1000) / elapsed * drained; + + pipeline_period = (size_t)KPB_SAMPLES_PER_MS * + (KPB_SAMPLE_CONTAINER_SIZE(dd->sample_width) / 8) * kpb->config.channels; + /* desired draining pace in bytes per second */ + optimal_pace = pipeline_period * KPB_DRAIN_NUM_OF_PPL_PERIODS_AT_ONCE * 1000; + + /* just in case to prevent div by 0 if draining is stuck (e.g. because of host) */ + if (actual_pace) { + if (actual_pace < optimal_pace) { + dd->drain_interval /= optimal_pace / actual_pace; + dd->drain_interval -= dd->drain_interval / 8; + } else if (actual_pace > optimal_pace) { + dd->drain_interval *= actual_pace / optimal_pace; + dd->drain_interval += dd->drain_interval / 8; + } + /* the above algorithm will get stuck if the drain_interval is below 8 */ + if (dd->drain_interval < 8) + dd->drain_interval = 8; + } + } + + dd->prev_adjustment_time = now; + dd->prev_adjustment_drained = dd->drained; +} + /** * \brief Draining task. * @@ -1719,26 +1827,15 @@ static enum task_state kpb_draining_task(void *arg) struct draining_data *draining_data = (struct draining_data *)arg; 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; - size_t size_to_read; + size_t avail; size_t size_to_copy; - bool move_buffer = false; - uint32_t drained = 0; - uint64_t draining_time_start; uint64_t draining_time_end; uint64_t draining_time_ms; - uint64_t drain_interval = draining_data->drain_interval; - uint64_t next_copy_time = 0; - uint64_t current_time; - size_t period_bytes = 0; size_t period_bytes_limit = draining_data->pb_limit; - size_t period_copy_start; - size_t time_taken; size_t *rt_stream_update = &draining_data->buffered_while_draining; struct comp_data *kpb = comp_get_drvdata(draining_data->dev); bool sync_mode_on = draining_data->sync_mode_on; - bool pm_is_active; /* * WORKAROUND: The code below accesses KPB sink buffer and calls comp_copy() on @@ -1751,78 +1848,55 @@ static enum task_state kpb_draining_task(void *arg) k_sched_lock(); #endif - comp_cl_info(&comp_kpb, "kpb_draining_task(), start."); - - pm_is_active = pm_runtime_is_active(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID); - - if (!pm_is_active) - pm_runtime_disable(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID); + comp_cl_dbg(&comp_kpb, "entry"); - /* Change KPB internal state to DRAINING */ - kpb_change_state(kpb, KPB_STATE_DRAINING); - - draining_time_start = sof_cycle_get_64(); - period_copy_start = draining_time_start; + /* Have we received reset request? */ + if (kpb->state == KPB_STATE_RESETTING) { + kpb_change_state(kpb, KPB_STATE_RESET_FINISHING); + kpb_reset(draining_data->dev); + draining_data->drain_req = 0; + goto out; + } - while (drain_req > 0) { - /* - * Draining task usually runs for quite a lot of time (could be few seconds). - * LL should not be blocked for such a long time. - */ -#ifdef __ZEPHYR__ - k_sched_unlock(); - k_yield(); - k_sched_lock(); -#endif + adjust_drain_interval(kpb, draining_data); - /* Have we received reset request? */ - if (kpb->state == KPB_STATE_RESETTING) { - kpb_change_state(kpb, KPB_STATE_RESET_FINISHING); - kpb_reset(draining_data->dev); - goto out; - } + if (draining_data->drain_req > 0) { /* Are we ready to drain further or host still need some time * to read the data already provided? */ - if (sync_mode_on && - next_copy_time > sof_cycle_get_64()) { - period_bytes = 0; - period_copy_start = sof_cycle_get_64(); - continue; - } else if (next_copy_time == 0) { - period_copy_start = sof_cycle_get_64(); + if (sync_mode_on && draining_data->next_copy_time > sof_cycle_get_64()) { + /* Restore original EDF thread priority */ +#ifdef __ZEPHYR__ + k_sched_unlock(); +#endif + return SOF_TASK_STATE_RESCHEDULE; } - size_to_read = (uintptr_t)buff->end_addr - (uintptr_t)buff->r_ptr; - - if (size_to_read > audio_stream_get_free_bytes(&sink->stream)) { - if (audio_stream_get_free_bytes(&sink->stream) >= drain_req) - size_to_copy = drain_req; - else - size_to_copy = audio_stream_get_free_bytes(&sink->stream); - } else { - if (size_to_read > drain_req) { - size_to_copy = drain_req; - } else { - size_to_copy = size_to_read; - move_buffer = true; - } + if (draining_data->period_copy_start == 0) { + /* starting new draining period */ + draining_data->period_copy_start = sof_cycle_get_64(); + draining_data->period_bytes = 0; } + avail = (uintptr_t)buff->end_addr - (uintptr_t)buff->r_ptr; + size_to_copy = MIN(avail, + MIN(draining_data->drain_req, + audio_stream_get_free_bytes(&sink->stream))); + kpb_drain_samples(buff->r_ptr, &sink->stream, size_to_copy, sample_width); buff->r_ptr = (char *)buff->r_ptr + (uint32_t)size_to_copy; - drain_req -= size_to_copy; - drained += size_to_copy; - period_bytes += size_to_copy; + draining_data->drain_req -= size_to_copy; + draining_data->drained += size_to_copy; + draining_data->period_bytes += size_to_copy; kpb->hd.free += MIN(kpb->hd.buffer_size - kpb->hd.free, size_to_copy); - if (move_buffer) { + /* no data left in the current buffer -- switch to the next buffer */ + if (size_to_copy == avail) { buff->r_ptr = buff->start_addr; - buff = buff->next; - move_buffer = false; + draining_data->hb = buff->next; } if (size_to_copy) { @@ -1836,14 +1910,15 @@ static enum task_state kpb_draining_task(void *arg) comp_copy(comp_buffer_get_sink_component(sink)); } - if (sync_mode_on && period_bytes >= period_bytes_limit) { - current_time = sof_cycle_get_64(); - time_taken = current_time - period_copy_start; - next_copy_time = current_time + drain_interval - - time_taken; + if (sync_mode_on && draining_data->period_bytes >= period_bytes_limit) { + draining_data->next_copy_time = draining_data->period_copy_start + + draining_data->drain_interval; + draining_data->period_copy_start = 0; + } else { + draining_data->next_copy_time = 0; } - if (drain_req == 0) { + if (draining_data->drain_req == 0) { /* We have finished draining of requested data however * while we were draining real time stream could provided * new data which needs to be copy to host. @@ -1851,9 +1926,9 @@ static enum task_state kpb_draining_task(void *arg) comp_cl_info(&comp_kpb, "kpb: update drain_req by %zu", *rt_stream_update); kpb_lock(kpb); - drain_req += *rt_stream_update; + draining_data->drain_req += *rt_stream_update; *rt_stream_update = 0; - if (!drain_req && kpb->state == KPB_STATE_DRAINING) { + if (!draining_data->drain_req && kpb->state == KPB_STATE_DRAINING) { /* Draining is done. Now switch KPB to copy real time * stream to client's sink. This state is called * "draining on demand" @@ -1867,19 +1942,37 @@ static enum task_state kpb_draining_task(void *arg) } out: + if (draining_data->drain_req > 0) { + /* Restore original EDF thread priority */ +#ifdef __ZEPHYR__ + k_sched_unlock(); +#endif + + /* continue drainig on next task iteration */ + return SOF_TASK_STATE_RESCHEDULE; + } + + /* finished drainig */ draining_time_end = sof_cycle_get_64(); - /* Reset host-sink copy mode back to its pre-draining value */ - comp_set_attribute(comp_buffer_get_sink_component(kpb->host_sink), COMP_ATTR_COPY_TYPE, - &kpb->draining_task_data.copy_type); + /* Reset host-sink copy mode back to its pre-draining value. + * kpb->host_sink is NULL after a reset or unbind. + */ + if (kpb->host_sink) + comp_set_attribute(comp_buffer_get_sink_component(kpb->host_sink), + COMP_ATTR_COPY_TYPE, + &kpb->draining_task_data.copy_type); + else + comp_cl_err(&comp_kpb, "Failed to restore host copy mode!"); - draining_time_ms = k_cyc_to_ms_near64(draining_time_end - draining_time_start); + draining_time_ms = k_cyc_to_ms_near64(draining_time_end - + draining_data->draining_time_start); if (draining_time_ms <= UINT_MAX) - comp_cl_info(&comp_kpb, "KPB: kpb_draining_task(), done. %u drained in %u ms", - drained, (unsigned int)draining_time_ms); + comp_cl_info(&comp_kpb, "KPB: done. %zu drained in %u ms", + draining_data->drained, (unsigned int)draining_time_ms); else - comp_cl_info(&comp_kpb, "KPB: kpb_draining_task(), done. %u drained in > %u ms", - drained, UINT_MAX); + comp_cl_info(&comp_kpb, "KPB: done. %zu drained in > %u ms", + draining_data->drained, UINT_MAX); /* Restore original EDF thread priority */ #ifdef __ZEPHYR__ @@ -2119,7 +2212,7 @@ static void kpb_clear_history_buffer(struct history_buffer *buff) void *start_addr; size_t size; - comp_cl_info(&comp_kpb, "kpb_clear_history_buffer()"); + comp_cl_info(&comp_kpb, "entry"); do { start_addr = buff->start_addr; @@ -2270,7 +2363,7 @@ static void kpb_reset_history_buffer(struct history_buffer *buff) { struct history_buffer *first_buff = buff; - comp_cl_info(&comp_kpb, "kpb_reset_history_buffer()"); + comp_cl_info(&comp_kpb, "entry"); if (!buff) return; @@ -2303,7 +2396,7 @@ static inline bool validate_host_params(struct comp_dev *dev, */ struct comp_data *kpb = comp_get_drvdata(dev); size_t sample_width = kpb->config.sampling_width; - size_t bytes_per_ms = KPB_SAMPLES_PER_MS * + size_t bytes_per_ms = (size_t)KPB_SAMPLES_PER_MS * (KPB_SAMPLE_CONTAINER_SIZE(sample_width) / 8) * kpb->config.channels; size_t pipeline_period_size = (dev->pipeline->period / 1000) @@ -2355,7 +2448,7 @@ static inline bool validate_host_params(struct comp_dev *dev, static inline void kpb_change_state(struct comp_data *kpb, enum kpb_state state) { - comp_cl_dbg(&comp_kpb, "kpb_change_state(): from %d to %d", + comp_cl_dbg(&comp_kpb, "change state from %d to %d", kpb->state, state); kpb->state = state; kpb->state_log = (kpb->state_log << 4) | state; @@ -2366,12 +2459,27 @@ static int kpb_set_micselect(struct comp_dev *dev, const void *data, { const struct kpb_micselector_config *mic_sel = data; struct comp_data *kpb = comp_get_drvdata(dev); - const size_t mic_cnt = kpb->config.channels - KPB_REFERENCE_SUPPORT_CHANNELS; - const uint8_t valid_mask = KPB_COUNT_TO_BITMASK(mic_cnt); + size_t mic_cnt; + uint8_t valid_mask; size_t i; + if (max_data_size < (int)sizeof(*mic_sel)) { + comp_err(dev, "micselector payload too small: got %d, need %d", + max_data_size, (int)sizeof(*mic_sel)); + return -EINVAL; + } + + if (kpb->config.channels < KPB_REFERENCE_SUPPORT_CHANNELS || + kpb->config.channels > KPB_MAX_SUPPORTED_CHANNELS) { + comp_err(dev, "unsupported channel count %u", kpb->config.channels); + return -EINVAL; + } + + mic_cnt = kpb->config.channels - KPB_REFERENCE_SUPPORT_CHANNELS; + valid_mask = KPB_COUNT_TO_BITMASK(mic_cnt); + if ((valid_mask & mic_sel->mask) == 0) { - comp_err(dev, "error: invalid micselector bit mask"); + comp_err(dev, "invalid micselector bit mask"); return -EINVAL; } /* selected mics counter */ @@ -2379,6 +2487,10 @@ static int kpb_set_micselect(struct comp_dev *dev, const void *data, for (i = 0; i < mic_cnt; i++) { if (KPB_IS_BIT_SET(mic_sel->mask, i)) { + if (num_of_sel_mic >= ARRAY_SIZE(kpb->offsets)) { + comp_err(dev, "too many selected mics"); + return -EINVAL; + } kpb->offsets[num_of_sel_mic] = i; num_of_sel_mic++; } @@ -2449,32 +2561,42 @@ static int prepare_fmt_modules_list(struct comp_dev *kpb_dev, struct kpb_fmt_dev_list *fmt_device_list = &((struct comp_data *)comp_get_drvdata(kpb_dev))->fmt_device_list; + if (outpin_idx >= KPB_MAX_SINK_CNT) + return -EINVAL; + 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; + goto err; 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; + if (!dev) { + ret = -EINVAL; + goto err; + } 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; + goto err; *new_list_item_ptr = dev; ret = devicelist_push(&fmt_device_list->device_list[outpin_idx], new_list_item_ptr); if (ret < 0) - return ret; + goto err; } return 0; + +err: + /* drop any entries pushed so far to avoid leaving a half-configured list */ + clear_fmt_modules_list(fmt_device_list, outpin_idx); + return ret; } static int clear_fmt_modules_list(struct kpb_fmt_dev_list *fmt_device_list, @@ -2562,7 +2684,7 @@ static int kpb_set_large_config(struct comp_dev *dev, uint32_t param_id, /* 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()"); + comp_info(dev, "entry"); extended_param_id.full = param_id; @@ -2576,6 +2698,15 @@ static int kpb_set_large_config(struct comp_dev *dev, uint32_t param_id, const struct kpb_task_params *cfg = (struct kpb_task_params *)data; uint32_t outpin_id = extended_param_id.part.parameter_instance; + /* payload must cover the header and all declared dev_ids[] entries */ + if (!cfg || data_offset < offsetof(struct kpb_task_params, dev_ids)) + return -EINVAL; + + if (cfg->number_of_modules > + (data_offset - offsetof(struct kpb_task_params, dev_ids)) / + sizeof(cfg->dev_ids[0])) + return -EINVAL; + return configure_fast_mode_task(dev, cfg, outpin_id); } #endif @@ -2586,6 +2717,8 @@ static int kpb_set_large_config(struct comp_dev *dev, uint32_t param_id, } } +DECLARE_TR_CTX(kpb_tr, SOF_UUID(KPB_UUID), LOG_LEVEL_INFO); + static const struct comp_driver comp_kpb = { .type = SOF_COMP_KPB, .uid = SOF_RT_UUID(KPB_UUID), @@ -2615,8 +2748,7 @@ static SHARED_DATA struct comp_driver_info comp_kpb_info = { UT_STATIC void sys_comp_kpb_init(void) { - comp_register(platform_shared_get(&comp_kpb_info, - sizeof(comp_kpb_info))); + comp_register(&comp_kpb_info); } DECLARE_MODULE(sys_comp_kpb_init); diff --git a/src/audio/kpb.toml b/src/audio/kpb.toml index 1aa10e007b76..e384632c1be8 100644 --- a/src/audio/kpb.toml +++ b/src/audio/kpb.toml @@ -1,6 +1,6 @@ [[module.entry]] name = "KPB" - uuid = "A8A0CB32-4A77-4DB1-85C7-53D7EE07BCE6" + uuid = UUIDREG_STR_KPB4 affinity_mask = "0x1" instance_count = "1" domain_types = "0" diff --git a/src/audio/level_multiplier/CMakeLists.txt b/src/audio/level_multiplier/CMakeLists.txt new file mode 100644 index 000000000000..1805c56a0bce --- /dev/null +++ b/src/audio/level_multiplier/CMakeLists.txt @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_COMP_LEVEL_MULTIPLIER STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/level_multiplier_llext) + add_dependencies(app level_multiplier) +else() + add_local_sources(sof level_multiplier.c) + add_local_sources(sof level_multiplier-generic.c) + add_local_sources(sof level_multiplier-hifi3.c) + add_local_sources(sof level_multiplier-hifi5.c) + + if(CONFIG_IPC_MAJOR_4) + add_local_sources(sof level_multiplier-ipc4.c) + endif() +endif() diff --git a/src/audio/level_multiplier/Kconfig b/src/audio/level_multiplier/Kconfig new file mode 100644 index 000000000000..cc8a79632cd7 --- /dev/null +++ b/src/audio/level_multiplier/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config COMP_LEVEL_MULTIPLIER + tristate "Level multiplier component" + default y + help + Select for Level multiplier component. This component + applies a fixed gain to audio. The amount of gain + is configured in the bytes control that is typically + set in boot time from topology. It can e.g. increase + capture sensitivity of voice applications by 20 dB + compared to media capture. diff --git a/src/audio/level_multiplier/README.md b/src/audio/level_multiplier/README.md new file mode 100644 index 000000000000..278b895d099c --- /dev/null +++ b/src/audio/level_multiplier/README.md @@ -0,0 +1,14 @@ +# Level Multiplier Architecture + +This directory contains the Level Multiplier component. + +## Overview + +Applies simple digital gain/attenuation (multiplication) to an audio signal stream. + +## Configuration and Scripts + +- **Kconfig**: Enables the Level multiplier component (`COMP_LEVEL_MULTIPLIER`). This applies a configured fixed gain to an audio stream, typically to increase capture sensitivity of voice applications compared to media capture. +- **CMakeLists.txt**: Manages local base sources and optimized implementations (`level_multiplier-generic.c`, `level_multiplier-hifi3.c`, `level_multiplier-hifi5.c`). Includes the IPC version 4 wrapper (`level_multiplier-ipc4.c`) when `CONFIG_IPC_MAJOR_4` is present, and supports `llext`. +- **level_multiplier.toml**: Holds topology module entry parameters including UUIDs, standard pin layouts, and `mod_cfg` limits. +- **Topology (.conf)**: `tools/topology/topology2/include/components/level_multiplier.conf` configures the `level_multiplier` widget object. It specifies `num_input_pins` and `num_output_pins` mapping and defaults to type `effect` with UUID `56:74:39:30:61:46:44:46:97:e5:39:a9:e5:ab:17:78`. diff --git a/src/audio/level_multiplier/level_multiplier-generic.c b/src/audio/level_multiplier/level_multiplier-generic.c new file mode 100644 index 000000000000..554a5f7f49c6 --- /dev/null +++ b/src/audio/level_multiplier/level_multiplier-generic.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/source_api.h> +#include <stdint.h> +#include "level_multiplier.h" + +#define LEVEL_MULTIPLIER_S16_SHIFT Q_SHIFT_BITS_32(15, LEVEL_MULTIPLIER_QXY_Y, 15) +#define LEVEL_MULTIPLIER_S24_SHIFT Q_SHIFT_BITS_64(23, LEVEL_MULTIPLIER_QXY_Y, 23) +#define LEVEL_MULTIPLIER_S32_SHIFT Q_SHIFT_BITS_64(31, LEVEL_MULTIPLIER_QXY_Y, 31) + +#if SOF_USE_HIFI(NONE, VOLUME) + +#if CONFIG_FORMAT_S16LE +/** + * level_multiplier_s16() - Process S16_LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 16-bit signed integer PCM formats. The + * audio samples are copied from source to sink with gain defined in cd->gain. + * + * Return: Value zero for success, otherwise an error code. + */ +static int level_multiplier_s16(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + const int32_t gain = cd->gain; + int16_t const *x, *x_start, *x_end; + int16_t *y, *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int remaining_samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int i; + + ret = source_get_data_s16(source, bytes, &x, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s16(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (remaining_samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - x; + samples_without_wrap = y_end - y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + for (i = 0; i < samples_without_wrap; i++) { + *y = q_multsr_sat_32x32_16(*x, gain, LEVEL_MULTIPLIER_S16_SHIFT); + x++; + y++; + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= x_end) ? x - x_size : x; + y = (y >= y_end) ? y - y_size : y; + + remaining_samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S24LE +/** + * level_multiplier_s24() - Process S24_4LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 24-bit signed integer PCM formats. The + * audio samples are copied from source to sink with gain defined in cd->gain. + * + * Return: Value zero for success, otherwise an error code. + */ +static int level_multiplier_s24(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + const int32_t gain = cd->gain; + int32_t const *x, *x_start, *x_end; + int32_t *y, *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int remaining_samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int i; + + ret = source_get_data_s32(source, bytes, &x, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s32(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (remaining_samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - x; + samples_without_wrap = y_end - y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + for (i = 0; i < samples_without_wrap; i++) { + *y = q_multsr_sat_32x32_24(sign_extend_s24(*x), gain, + LEVEL_MULTIPLIER_S24_SHIFT); + x++; + y++; + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= x_end) ? x - x_size : x; + y = (y >= y_end) ? y - y_size : y; + + remaining_samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S32LE +/** + * level_multiplier_s32() - Process S32_LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 32-bit signed integer PCM formats. The + * audio samples are copied from source to sink with gain defined in cd->gain. + * + * Return: Value zero for success, otherwise an error code. + */ +static int level_multiplier_s32(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + const int32_t gain = cd->gain; + int32_t const *x, *x_start, *x_end; + int32_t *y, *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int remaining_samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int i; + + ret = source_get_data_s32(source, bytes, &x, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s32(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (remaining_samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - x; + samples_without_wrap = y_end - y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + for (i = 0; i < samples_without_wrap; i++) { + *y = q_multsr_sat_32x32(*x, gain, LEVEL_MULTIPLIER_S32_SHIFT); + x++; + y++; + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= x_end) ? x - x_size : x; + y = (y >= y_end) ? y - y_size : y; + + remaining_samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S32LE */ + +/* This struct array defines the used processing functions for + * the PCM formats + */ +const struct level_multiplier_proc_fnmap level_multiplier_proc_fnmap[] = { +#if CONFIG_FORMAT_S16LE + { SOF_IPC_FRAME_S16_LE, level_multiplier_s16 }, +#endif +#if CONFIG_FORMAT_S24LE + { SOF_IPC_FRAME_S24_4LE, level_multiplier_s24 }, +#endif +#if CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S32_LE, level_multiplier_s32 }, +#endif +}; + +/** + * level_multiplier_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +level_multiplier_func level_multiplier_find_proc_func(enum sof_ipc_frame src_fmt) +{ + int i; + + /* Find suitable processing function from map */ + for (i = 0; i < ARRAY_SIZE(level_multiplier_proc_fnmap); i++) + if (src_fmt == level_multiplier_proc_fnmap[i].frame_fmt) + return level_multiplier_proc_fnmap[i].level_multiplier_proc_func; + + return NULL; +} + +#endif /* SOF_USE_HIFI(NONE, VOLUME) */ diff --git a/src/audio/level_multiplier/level_multiplier-hifi3.c b/src/audio/level_multiplier/level_multiplier-hifi3.c new file mode 100644 index 000000000000..077476254c0e --- /dev/null +++ b/src/audio/level_multiplier/level_multiplier-hifi3.c @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/source_api.h> +#include <stdint.h> +#include "level_multiplier.h" + +#define LEVEL_MULTIPLIER_S32_SHIFT 8 /* See explanation from level_multiplier_s32() */ + +#if SOF_USE_HIFI(3, VOLUME) || SOF_USE_HIFI(4, VOLUME) + +#include <xtensa/tie/xt_hifi3.h> + +#if CONFIG_FORMAT_S16LE +/** + * level_multiplier_s16() - Process S16_LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 16-bit signed integer PCM formats. The + * audio samples are copied from source to sink with gain defined in cd->gain. + * + * Return: Value zero for success, otherwise an error code. + */ +static int level_multiplier_s16(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + ae_valign x_align; + ae_valign y_align = AE_ZALIGN64(); + ae_f32x2 samples0; + ae_f32x2 samples1; + const ae_f32x2 gain = cd->gain; + ae_f16x4 samples; + ae_f16x4 const *x; + ae_f16x4 *y; + int16_t const *x_start, *x_end; + int16_t *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int remaining_samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int n, i; + + ret = source_get_data_s16(source, bytes, (const int16_t **)&x, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s16(sink, bytes, (int16_t **)&y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (remaining_samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - (int16_t *)x; + samples_without_wrap = y_end - (int16_t *)y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + x_align = AE_LA64_PP(x); + + /* Process with 64 bit loads and stores */ + n = samples_without_wrap >> 2; + for (i = 0; i < n; i++) { + AE_LA16X4_IP(samples, x_align, x); + + /* Multiply the input sample */ + samples0 = AE_MULFP32X16X2RS_H(gain, samples); + samples1 = AE_MULFP32X16X2RS_L(gain, samples); + + /* Q9.23 to Q1.31 */ + samples0 = AE_SLAI32S(samples0, 8); + samples1 = AE_SLAI32S(samples1, 8); + + /* To Q1.15 */ + samples = AE_ROUND16X4F32SSYM(samples0, samples1); + AE_SA16X4_IP(samples, y_align, y); + } + + AE_SA64POS_FP(y_align, y); + n = samples_without_wrap - (n << 2); + for (i = 0; i < n; i++) { + AE_L16_IP(samples, (ae_f16 *)x, sizeof(ae_f16)); + samples0 = AE_MULFP32X16X2RS_H(gain, samples); + samples0 = AE_SLAI32S(samples0, 8); + samples = AE_ROUND16X4F32SSYM(samples0, samples0); + AE_S16_0_IP(samples, (ae_f16 *)y, sizeof(ae_f16)); + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= (ae_f16x4 *)x_end) ? x - x_size : x; + y = (y >= (ae_f16x4 *)y_end) ? y - y_size : y; + remaining_samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S24LE +/** + * level_multiplier_s24() - Process S24_4LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 24-bit signed integer PCM formats. The + * audio samples are copied from source to sink with gain defined in cd->gain. + * + * Return: Value zero for success, otherwise an error code. + */ +static int level_multiplier_s24(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + ae_valign x_align; + ae_valign y_align = AE_ZALIGN64(); + const ae_f32x2 gain = cd->gain; + ae_f32x2 samples; + ae_f32x2 const *x; + ae_f32x2 *y; + int32_t const *x_start, *x_end; + int32_t *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int remaining_samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int n, i; + + ret = source_get_data_s32(source, bytes, (const int32_t **)&x, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s32(sink, bytes, (int32_t **)&y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (remaining_samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - (int32_t *)x; + samples_without_wrap = y_end - (int32_t *)y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + x_align = AE_LA64_PP(x); + + /* Process with 64 bit loads and stores */ + n = samples_without_wrap >> 1; + for (i = 0; i < n; i++) { + AE_LA32X2_IP(samples, x_align, x); + samples = AE_MULFP32X2RS(gain, AE_SLAI32(samples, 8)); + samples = AE_SLAI32S(samples, 8); + samples = AE_SRAI32(samples, 8); + AE_SA32X2_IP(samples, y_align, y); + } + + AE_SA64POS_FP(y_align, y); + if (samples_without_wrap - (n << 1)) { + AE_L32_IP(samples, (ae_f32 *)x, sizeof(ae_f32)); + samples = AE_MULFP32X2RS(gain, AE_SLAI32(samples, 8)); + samples = AE_SLAI32S(samples, 8); + samples = AE_SRAI32(samples, 8); + AE_S32_L_IP(samples, (ae_f32 *)y, sizeof(ae_f32)); + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= (ae_f32x2 *)x_end) ? x - x_size : x; + y = (y >= (ae_f32x2 *)y_end) ? y - y_size : y; + remaining_samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S32LE +/** + * level_multiplier_s32() - Process S32_LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 32-bit signed integer PCM formats. The + * audio samples are copied from source to sink with gain defined in cd->gain. + * + * Return: Value zero for success, otherwise an error code. + */ +static int level_multiplier_s32(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + ae_valign x_align; + ae_valign y_align = AE_ZALIGN64(); + ae_f64 mult0; + ae_f64 mult1; + const ae_f32x2 gain = cd->gain; + ae_f32x2 samples; + ae_f32x2 const *x; + ae_f32x2 *y; + int32_t const *x_start, *x_end; + int32_t *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int remaining_samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int n, i; + + ret = source_get_data_s32(source, bytes, (const int32_t **)&x, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s32(sink, bytes, (int32_t **)&y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (remaining_samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - (int32_t *)x; + samples_without_wrap = y_end - (int32_t *)y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + x_align = AE_LA64_PP(x); + + /* Process with 64 bit loads and stores */ + n = samples_without_wrap >> 1; + for (i = 0; i < n; i++) { + AE_LA32X2_IP(samples, x_align, x); + /* Q31 gain would give Q47, then Q23 gain gives Q39, need to shift + * the product left by 8 to get Q47 for round instruction. + */ + mult0 = AE_MULF32R_HH(gain, samples); + mult1 = AE_MULF32R_LL(gain, samples); + mult0 = AE_SLAI64(mult0, LEVEL_MULTIPLIER_S32_SHIFT); + mult1 = AE_SLAI64(mult1, LEVEL_MULTIPLIER_S32_SHIFT); + samples = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ + AE_SA32X2_IP(samples, y_align, y); + } + + AE_SA64POS_FP(y_align, y); + if (samples_without_wrap - (n << 1)) { + AE_L32_IP(samples, (ae_f32 *)x, sizeof(ae_f32)); + mult0 = AE_MULF32R_HH(gain, samples); + mult0 = AE_SLAI64(mult0, LEVEL_MULTIPLIER_S32_SHIFT); + samples = AE_ROUND32F48SSYM(mult0); + AE_S32_L_IP(samples, (ae_f32 *)y, sizeof(ae_f32)); + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= (ae_f32x2 *)x_end) ? x - x_size : x; + y = (y >= (ae_f32x2 *)y_end) ? y - y_size : y; + remaining_samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S32LE */ + +/* This struct array defines the used processing functions for + * the PCM formats + */ +const struct level_multiplier_proc_fnmap level_multiplier_proc_fnmap[] = { +#if CONFIG_FORMAT_S16LE + { SOF_IPC_FRAME_S16_LE, level_multiplier_s16 }, +#endif +#if CONFIG_FORMAT_S24LE + { SOF_IPC_FRAME_S24_4LE, level_multiplier_s24 }, +#endif +#if CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S32_LE, level_multiplier_s32 }, +#endif +}; + +/** + * level_multiplier_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +level_multiplier_func level_multiplier_find_proc_func(enum sof_ipc_frame src_fmt) +{ + int i; + + /* Find suitable processing function from map */ + for (i = 0; i < ARRAY_SIZE(level_multiplier_proc_fnmap); i++) + if (src_fmt == level_multiplier_proc_fnmap[i].frame_fmt) + return level_multiplier_proc_fnmap[i].level_multiplier_proc_func; + + return NULL; +} + +#endif /* SOF_USE_HIFI(3, VOLUME) || SOF_USE_HIFI(4, VOLUME) */ diff --git a/src/audio/level_multiplier/level_multiplier-hifi5.c b/src/audio/level_multiplier/level_multiplier-hifi5.c new file mode 100644 index 000000000000..91f52ade4767 --- /dev/null +++ b/src/audio/level_multiplier/level_multiplier-hifi5.c @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/source_api.h> +#include <stdint.h> +#include "level_multiplier.h" + +#define LEVEL_MULTIPLIER_S32_SHIFT 8 /* See explanation from level_multiplier_s32() */ + +#if SOF_USE_MIN_HIFI(5, VOLUME) + +#include <xtensa/tie/xt_hifi3.h> + +#if CONFIG_FORMAT_S16LE +/** + * level_multiplier_s16() - Process S16_LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 16-bit signed integer PCM formats. The + * audio samples are copied from source to sink with gain defined in cd->gain. + * + * Return: Value zero for success, otherwise an error code. + */ +static int level_multiplier_s16(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + ae_valignx2 x_align; + ae_valignx2 y_align = AE_ZALIGN128(); + ae_f32x2 tmp0; + ae_f32x2 tmp1; + const ae_f32x2 gain = cd->gain; + ae_f16x4 samples0; + ae_f16x4 samples1; + ae_int16x8 const *x; + ae_int16x8 *y; + int16_t const *x_start, *x_end; + int16_t *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int remaining_samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int n, i; + + ret = source_get_data_s16(source, bytes, (const int16_t **)&x, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s16(sink, bytes, (int16_t **)&y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (remaining_samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - (int16_t *)x; + samples_without_wrap = y_end - (int16_t *)y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + x_align = AE_LA128_PP(x); + + /* Process with 128 bit loads and stores */ + n = samples_without_wrap >> 3; + for (i = 0; i < n; i++) { + AE_LA16X4X2_IP(samples0, samples1, x_align, x); + + AE_MULF2P32X16X4RS(tmp0, tmp1, gain, gain, samples0); + /* Q9.23 to Q1.31 */ + tmp0 = AE_SLAI32S(tmp0, 8); + tmp1 = AE_SLAI32S(tmp1, 8); + samples0 = AE_ROUND16X4F32SSYM(tmp0, tmp1); + + AE_MULF2P32X16X4RS(tmp0, tmp1, gain, gain, samples1); + /* Q9.23 to Q1.31 */ + tmp0 = AE_SLAI32S(tmp0, 8); + tmp1 = AE_SLAI32S(tmp1, 8); + samples1 = AE_ROUND16X4F32SSYM(tmp0, tmp1); + + AE_SA16X4X2_IP(samples0, samples1, y_align, y); + } + + AE_SA128POS_FP(y_align, y); + n = samples_without_wrap - (n << 3); + for (i = 0; i < n; i++) { + AE_L16_IP(samples0, (ae_f16 *)x, sizeof(ae_f16)); + tmp0 = AE_MULFP32X16X2RS_H(gain, samples0); + tmp0 = AE_SLAI32S(tmp0, 8); + samples0 = AE_ROUND16X4F32SSYM(tmp0, tmp0); + AE_S16_0_IP(samples0, (ae_f16 *)y, sizeof(ae_f16)); + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= (ae_int16x8 *)x_end) ? x - x_size : x; + y = (y >= (ae_int16x8 *)y_end) ? y - y_size : y; + remaining_samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S24LE +/** + * level_multiplier_s24() - Process S24_4LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 24-bit signed integer PCM formats. The + * audio samples are copied from source to sink with gain defined in cd->gain. + * + * Return: Value zero for success, otherwise an error code. + */ +static int level_multiplier_s24(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + ae_valignx2 x_align; + ae_valignx2 y_align = AE_ZALIGN128(); + const ae_f32x2 gain = cd->gain; + ae_f32x2 samples0; + ae_f32x2 samples1; + ae_f32x2 tmp0; + ae_f32x2 tmp1; + ae_int32x4 const *x; + ae_int32x4 *y; + int32_t const *x_start, *x_end; + int32_t *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int remaining_samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int n, i; + + ret = source_get_data_s32(source, bytes, (const int32_t **)&x, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s32(sink, bytes, (int32_t **)&y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (remaining_samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - (int32_t *)x; + samples_without_wrap = y_end - (int32_t *)y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + x_align = AE_LA128_PP(x); + + /* Process with 64 bit loads and stores */ + n = samples_without_wrap >> 2; + for (i = 0; i < n; i++) { + AE_LA32X2X2_IP(samples0, samples1, x_align, x); + AE_MULF2P32X4RS(tmp0, tmp1, gain, gain, + AE_SLAI32(samples0, 8), + AE_SLAI32(samples1, 8)); + samples0 = AE_SRAI32(AE_SLAI32S(tmp0, 8), 8); + samples1 = AE_SRAI32(AE_SLAI32S(tmp1, 8), 8); + AE_SA32X2X2_IP(samples0, samples1, y_align, y); + } + + AE_SA128POS_FP(y_align, y); + n = samples_without_wrap - (n << 2); + for (i = 0; i < n; i++) { + AE_L32_IP(samples0, (ae_f32 *)x, sizeof(ae_f32)); + samples0 = AE_MULFP32X2RS(gain, AE_SLAI32(samples0, 8)); + samples0 = AE_SRAI32(AE_SLAI32S(samples0, 8), 8); + AE_S32_L_IP(samples0, (ae_f32 *)y, sizeof(ae_f32)); + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= (ae_int32x4 *)x_end) ? x - x_size : x; + y = (y >= (ae_int32x4 *)y_end) ? y - y_size : y; + remaining_samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S32LE +/** + * level_multiplier_s32() - Process S32_LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 32-bit signed integer PCM formats. The + * audio samples are copied from source to sink with gain defined in cd->gain. + * + * Return: Value zero for success, otherwise an error code. + */ +static int level_multiplier_s32(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + ae_valignx2 x_align; + ae_valignx2 y_align = AE_ZALIGN128(); + ae_f64 mult0; + ae_f64 mult1; + const ae_f32x2 gain = cd->gain; + ae_f32x2 samples0; + ae_f32x2 samples1; + ae_int32x4 const *x; + ae_int32x4 *y; + int32_t const *x_start, *x_end; + int32_t *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int remaining_samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int n, i; + + ret = source_get_data_s32(source, bytes, (const int32_t **)&x, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s32(sink, bytes, (int32_t **)&y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (remaining_samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - (int32_t *)x; + samples_without_wrap = y_end - (int32_t *)y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + x_align = AE_LA128_PP(x); + + /* Process with 64 bit loads and stores */ + n = samples_without_wrap >> 2; + for (i = 0; i < n; i++) { + AE_LA32X2X2_IP(samples0, samples1, x_align, x); + + AE_MULF32X2R_HH_LL(mult0, mult1, gain, samples0); + mult0 = AE_SLAI64(mult0, LEVEL_MULTIPLIER_S32_SHIFT); + mult1 = AE_SLAI64(mult1, LEVEL_MULTIPLIER_S32_SHIFT); + samples0 = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ + + AE_MULF32X2R_HH_LL(mult0, mult1, gain, samples1); + mult0 = AE_SLAI64(mult0, LEVEL_MULTIPLIER_S32_SHIFT); + mult1 = AE_SLAI64(mult1, LEVEL_MULTIPLIER_S32_SHIFT); + samples1 = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ + + AE_SA32X2X2_IP(samples0, samples1, y_align, y); + } + + AE_SA128POS_FP(y_align, y); + n = samples_without_wrap - (n << 2); + for (i = 0; i < n; i++) { + AE_L32_IP(samples0, (ae_f32 *)x, sizeof(ae_f32)); + mult0 = AE_MULF32R_HH(gain, samples0); + mult0 = AE_SLAI64(mult0, LEVEL_MULTIPLIER_S32_SHIFT); + samples0 = AE_ROUND32F48SSYM(mult0); + AE_S32_L_IP(samples0, (ae_f32 *)y, sizeof(ae_f32)); + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= (ae_int32x4 *)x_end) ? x - x_size : x; + y = (y >= (ae_int32x4 *)y_end) ? y - y_size : y; + remaining_samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S32LE */ + +/* This struct array defines the used processing functions for + * the PCM formats + */ +const struct level_multiplier_proc_fnmap level_multiplier_proc_fnmap[] = { +#if CONFIG_FORMAT_S16LE + { SOF_IPC_FRAME_S16_LE, level_multiplier_s16 }, +#endif +#if CONFIG_FORMAT_S24LE + { SOF_IPC_FRAME_S24_4LE, level_multiplier_s24 }, +#endif +#if CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S32_LE, level_multiplier_s32 }, +#endif +}; + +/** + * level_multiplier_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +level_multiplier_func level_multiplier_find_proc_func(enum sof_ipc_frame src_fmt) +{ + int i; + + /* Find suitable processing function from map */ + for (i = 0; i < ARRAY_SIZE(level_multiplier_proc_fnmap); i++) + if (src_fmt == level_multiplier_proc_fnmap[i].frame_fmt) + return level_multiplier_proc_fnmap[i].level_multiplier_proc_func; + + return NULL; +} + +#endif /* SOF_USE_MIN_HIFI(5, VOLUME) */ diff --git a/src/audio/level_multiplier/level_multiplier-ipc4.c b/src/audio/level_multiplier/level_multiplier-ipc4.c new file mode 100644 index 000000000000..02289d844f63 --- /dev/null +++ b/src/audio/level_multiplier/level_multiplier-ipc4.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include "level_multiplier.h" + +LOG_MODULE_DECLARE(level_multiplier, CONFIG_SOF_LOG_LEVEL); + +/* IPC4 controls handler */ +__cold int level_multiplier_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 level_multiplier_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + + assert_can_be_cold(); + + switch (param_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + comp_err(dev, "Illegal control param_id %d.", param_id); + return -EINVAL; + } + + if (fragment_size != sizeof(int32_t)) { + comp_err(dev, "Illegal fragment size %d.", fragment_size); + return -EINVAL; + } + + memcpy_s(&cd->gain, sizeof(int32_t), fragment, sizeof(int32_t)); + comp_dbg(mod->dev, "Gain set to %d", cd->gain); + return 0; +} diff --git a/src/audio/level_multiplier/level_multiplier.c b/src/audio/level_multiplier/level_multiplier.c new file mode 100644 index 000000000000..4fca482ced72 --- /dev/null +++ b/src/audio/level_multiplier/level_multiplier.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/source_api.h> +#include <rtos/init.h> +#include "level_multiplier.h" + +/* UUID identifies the components. Use e.g. command uuidgen from package + * uuid-runtime, add it to uuid-registry.txt in SOF top level. + */ +SOF_DEFINE_REG_UUID(level_multiplier); + +/* Creates logging data for the component */ +LOG_MODULE_REGISTER(level_multiplier, CONFIG_SOF_LOG_LEVEL); + +/** + * level_multiplier_init() - Initialize the level_multiplier component. + * @mod: Pointer to module data. + * + * This function is called when the instance is created. The + * macro __cold informs that the code that is non-critical + * is loaded to slower but large DRAM. + * + * Return: Zero if success, otherwise error code. + */ +__cold static int level_multiplier_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct comp_dev *dev = mod->dev; + struct level_multiplier_comp_data *cd; + + comp_info(dev, "entry"); + + cd = mod_alloc(mod, sizeof(*cd)); + if (!cd) + return -ENOMEM; + + md->private = cd; + cd->gain = LEVEL_MULTIPLIER_GAIN_ONE; + return 0; +} + +/** + * level_multiplier_process() - The audio data processing function. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * This is the processing function that is called for scheduled + * pipelines. The processing is controlled by the enable switch. + * + * Return: Zero if success, otherwise error code. + */ +static int level_multiplier_process(struct processing_module *mod, + struct sof_source **sources, + int num_of_sources, + struct sof_sink **sinks, + int num_of_sinks) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + struct sof_source *source = sources[0]; /* One input */ + struct sof_sink *sink = sinks[0]; /* One output */ + int frames = source_get_data_frames_available(source); + int sink_frames = sink_get_free_frames(sink); + + comp_dbg(dev, "entry"); + + frames = MIN(frames, sink_frames); + frames = MIN(frames, dev->frames); + if (cd->gain != LEVEL_MULTIPLIER_GAIN_ONE) + /* Process the data with the requested gain. */ + return cd->level_multiplier_func(mod, source, sink, frames); + + /* Just copy from source to sink. */ + source_to_sink_copy(source, sink, true, frames * cd->frame_bytes); + return 0; +} + +/** + * level_multiplier_prepare() - Prepare the component for processing. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * Function prepare is called just before the pipeline is started. In + * this case the audio format parameters are for better code performance + * saved to component data to avoid to find out them in process. The + * processing function pointer is set to process the current audio format. + * + * Return: Value zero if success, otherwise error code. + */ +static int level_multiplier_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + enum sof_ipc_frame source_format; + + comp_dbg(dev, "entry"); + + /* The processing example in this component supports one input and one + * output. Generally there can be more. + */ + if (num_of_sources != 1 || num_of_sinks != 1) + return -EINVAL; + + /* get source data format */ + cd->frame_bytes = source_get_frame_bytes(sources[0]); + cd->channels = source_get_channels(sources[0]); + source_format = source_get_frm_fmt(sources[0]); + + cd->level_multiplier_func = level_multiplier_find_proc_func(source_format); + if (!cd->level_multiplier_func) { + comp_err(dev, "No processing function found for format %d.", + source_format); + return -EINVAL; + } + + return 0; +} + +/** + * level_multiplier_reset() - Reset the component. + * @mod: Pointer to module data. + * + * The component reset is called when pipeline is stopped. The reset + * should return the component to same state as init. + * + * Return: Value zero, always success. + */ +static int level_multiplier_reset(struct processing_module *mod) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + + comp_dbg(mod->dev, "entry"); + + memset(cd, 0, sizeof(*cd)); + cd->gain = LEVEL_MULTIPLIER_GAIN_ONE; + return 0; +} + +/** + * level_multiplier_free() - Free dynamic allocations. + * @mod: Pointer to module data. + * + * Component free is called when the pipelines are deleted. All + * dynamic allocations need to be freed here. The macro __cold + * instructs the build to locate this performance wise non-critical + * function to large and slower DRAM. + * + * Return: Value zero, always success. + */ +__cold static int level_multiplier_free(struct processing_module *mod) +{ + struct level_multiplier_comp_data *cd = module_get_private_data(mod); + + assert_can_be_cold(); + + comp_dbg(mod->dev, "entry"); + mod_free(mod, cd); + return 0; +} + +/* This defines the module operations */ +static const struct module_interface level_multiplier_interface = { + .init = level_multiplier_init, + .prepare = level_multiplier_prepare, + .process = level_multiplier_process, + .set_configuration = level_multiplier_set_config, + .reset = level_multiplier_reset, + .free = level_multiplier_free +}; + +/* This controls build of the module. If COMP_MODULE is selected in kconfig + * this is build as dynamically loadable module. + */ +#if CONFIG_COMP_LEVEL_MULTIPLIER_MODULE + +#include <module/module/api_ver.h> +#include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> + +SOF_LLEXT_MOD_ENTRY(level_multiplier, &level_multiplier_interface); + +static const struct sof_man_module_manifest mod_manifest __section(".module") __used = + SOF_LLEXT_MODULE_MANIFEST("LEVEL_MULTIPLIER", level_multiplier_llext_entry, 1, + SOF_REG_UUID(level_multiplier), 40); + +SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_TR_CTX(level_multiplier_tr, SOF_UUID(level_multiplier_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(level_multiplier_interface, level_multiplier_uuid, level_multiplier_tr); +SOF_MODULE_INIT(level_multiplier, sys_comp_module_level_multiplier_interface_init); + +#endif diff --git a/src/audio/level_multiplier/level_multiplier.h b/src/audio/level_multiplier/level_multiplier.h new file mode 100644 index 000000000000..e6df98c68c61 --- /dev/null +++ b/src/audio/level_multiplier/level_multiplier.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + * + */ +#ifndef __SOF_AUDIO_LEVEL_MULTIPLIER_H__ +#define __SOF_AUDIO_LEVEL_MULTIPLIER_H__ + +#include <sof/audio/module_adapter/module/generic.h> +#include <stdbool.h> +#include <stdint.h> + +/** \brief Level multiplier gain Qx.y integer x number of bits including sign bit. + * With Q8.23 format the gain range is -138.47 to +48.17 dB. + */ +#define LEVEL_MULTIPLIER_QXY_X 9 + +/** \brief Level multiplier gain Qx.y fractional y number of bits. */ +#define LEVEL_MULTIPLIER_QXY_Y 23 + +/** \brief Level multiplier unity gain */ +#define LEVEL_MULTIPLIER_GAIN_ONE (1 << LEVEL_MULTIPLIER_QXY_Y) + +/** + * struct level_multiplier_func - Function call pointer for process function + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + */ +typedef int (*level_multiplier_func)(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames); + +/* Level_Multiplier component private data */ + +/** + * struct level_multiplier_comp_data + * @level_multiplier_func: Pointer to used processing function. + * @gain: Applied gain in linear Q9.23 format + * @source_format: Source samples format. + * @frame_bytes: Number of bytes in an audio frame. + * @channels: Channels count. + * @enable: Control processing on/off, on - reorder channels + */ +struct level_multiplier_comp_data { + level_multiplier_func level_multiplier_func; + int32_t gain; + int source_format; + int frame_bytes; + int channels; +}; + +/** + * struct level_multiplier_proc_fnmap - processing functions for frame formats + * @frame_fmt: Current frame format + * @level_multiplier_proc_func: Function pointer for the suitable processing function + */ +struct level_multiplier_proc_fnmap { + enum sof_ipc_frame frame_fmt; + level_multiplier_func level_multiplier_proc_func; +}; + +/** + * level_multiplier_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +level_multiplier_func level_multiplier_find_proc_func(enum sof_ipc_frame src_fmt); + +/** + * level_multiplier_set_config() - Handle controls set + * @mod: Pointer to module data. + * @param_id: Id to know control type, used to know ALSA control type. + * @pos: Position of the fragment in the large message. + * @data_offset_size: Size of the whole configuration if it is the first or only + * fragment. Otherwise it is offset of the fragment. + * @fragment: Message payload data. + * @fragment_size: Size of this fragment. + * @response_size: Size of response. + * + * This function handles the real-time controls. The ALSA controls have the + * param_id set to indicate the control type. The control ID, from topology, + * is used to separate the controls instances of same type. In control payload + * the num_elems defines to how many channels the control is applied to. + * + * Return: Zero if success, otherwise error code. + */ + +#if CONFIG_IPC_MAJOR_3 +static inline int level_multiplier_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) +{ + /* No controls implementation for IPC3, add level_multiplier-ipc3.c + * handler if need. + */ + return 0; +} +#else +int level_multiplier_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); +#endif + +#endif // __SOF_AUDIO_LEVEL_MULTIPLIER_H__ diff --git a/src/audio/level_multiplier/level_multiplier.toml b/src/audio/level_multiplier/level_multiplier.toml new file mode 100644 index 000000000000..6eafd4efa8d7 --- /dev/null +++ b/src/audio/level_multiplier/level_multiplier.toml @@ -0,0 +1,21 @@ +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + + REM # Level Multiplier module config + [[module.entry]] + name = "LVLMULT" + uuid = UUIDREG_STR_LEVEL_MULTIPLIER + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = LOAD_TYPE + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + REM # 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] + + index = __COUNTER__ diff --git a/src/audio/level_multiplier/llext/CMakeLists.txt b/src/audio/level_multiplier/llext/CMakeLists.txt new file mode 100644 index 000000000000..49d91bc6a7ce --- /dev/null +++ b/src/audio/level_multiplier/llext/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +sof_llext_build("level_multiplier" + SOURCES ../level_multiplier.c + ../level_multiplier-generic.c + ../level_multiplier-hifi3.c + ../level_multiplier-hifi5.c + ../level_multiplier-ipc4.c + LIB openmodules +) diff --git a/src/audio/level_multiplier/llext/llext.toml.h b/src/audio/level_multiplier/llext/llext.toml.h new file mode 100644 index 000000000000..019909d20697 --- /dev/null +++ b/src/audio/level_multiplier/llext/llext.toml.h @@ -0,0 +1,6 @@ +#include <tools/rimage/config/platform.toml> +#define LOAD_TYPE "2" +#include "../level_multiplier.toml" + +[module] +count = __COUNTER__ diff --git a/src/audio/level_multiplier/tune/sof_level_multiplier_blobs.m b/src/audio/level_multiplier/tune/sof_level_multiplier_blobs.m new file mode 100644 index 000000000000..7312bae25444 --- /dev/null +++ b/src/audio/level_multiplier/tune/sof_level_multiplier_blobs.m @@ -0,0 +1,83 @@ +% Export configuration blobs for Level Multiplier +% +% This script creates configuration blobs for the Level Multiplier +% component to apply gains -40, -30, -20, -10, 0, 10, 20, 30, 40 dB. +% Run the script interactively from Octave shell with just command: +% +% sof_level_multiplier_blobs +% +% There are no arguments for the function. Or from SOF level directory +% with command: +% +% cd src/audio/level_multiplier/tune; octave sof_level_multiplier_blobs.m +% + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2025, Intel Corporation. + +function sof_level_multiplier_blobs() + + % Set the parameters here + sof_tools = '../../../../tools'; + sof_tplg = fullfile(sof_tools, 'topology/topology2'); + sof_tplg_level_multiplier = fullfile(sof_tplg, 'include/components/level_multiplier'); + sof_ctl_level_multiplier = fullfile(sof_tools, 'ctl/ipc4/level_multiplier'); + + sof_level_multiplier_paths(true); + + for param = -40:10:40 + gain_value = sof_level_multiplier_db2lin(param); + blob8 = sof_level_multiplier_build_blob(gain_value); + tplg2_fn = sprintf("%s/gain_%d_db.conf", sof_tplg_level_multiplier, param); + sof_tplg2_write(tplg2_fn, blob8, "level_multiplier_config", ... + "Exported with script sof_level_multiplier_blobs.m" , ... + "cd tools/tune/level_multiplier; octave sof_level_multiplier_blobs.m"); + ctl_fn = sprintf("%s/gain_%d_db.txt", sof_ctl_level_multiplier, param); + sof_alsactl_write(ctl_fn, blob8); + end + + sof_level_multiplier_paths(false); +end + +function lin_value = sof_level_multiplier_db2lin(db) + scale = 2^23; + lin_value = int32(10^(db/20) * scale); +end + +function sof_level_multiplier_paths(enable) + + common = '../../../../tools/tune/common'; + if enable + addpath(common); + else + rmpath(common); + end +end + +function blob8 = sof_level_multiplier_build_blob(param_values) + + blob_type = 0; + blob_param_id = 1; + data_length = length(param_values); + data_size = 4 * data_length; + ipc_ver = 4; + [abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver, blob_type, blob_param_id); + blob_size = data_size + abi_size; + blob8 = uint8(zeros(1, blob_size)); + blob8(1:abi_size) = abi_bytes; + j = abi_size + 1; + for i = 1:data_length + blob8(j:j+3) = word2byte(param_values(i)); + j=j+4; + end +end + +function bytes = word2byte(word) + sh = [0 -8 -16 -24]; + bytes = uint8(zeros(1,4)); + bytes(1) = bitand(bitshift(word, sh(1)), 255); + bytes(2) = bitand(bitshift(word, sh(2)), 255); + bytes(3) = bitand(bitshift(word, sh(3)), 255); + bytes(4) = bitand(bitshift(word, sh(4)), 255); +end diff --git a/src/audio/mfcc/CMakeLists.txt b/src/audio/mfcc/CMakeLists.txt index c8ed971f2da6..274c7aa05eb8 100644 --- a/src/audio/mfcc/CMakeLists.txt +++ b/src/audio/mfcc/CMakeLists.txt @@ -1,3 +1,11 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof mfcc.c mfcc_setup.c mfcc_common.c mfcc_generic.c mfcc_hifi4.c mfcc_hifi3.c) +if(CONFIG_COMP_MFCC STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/mfcc_llext) + add_dependencies(app mfcc) +else() + add_local_sources(sof mfcc.c mfcc_setup.c mfcc_common.c mfcc_generic.c mfcc_hifi4.c mfcc_hifi3.c mfcc_vad.c) + if(CONFIG_IPC_MAJOR_4) + add_local_sources(sof mfcc_ipc4.c) + endif() +endif() diff --git a/src/audio/mfcc/Kconfig b/src/audio/mfcc/Kconfig index 36d2af94dabd..f56cadb40de2 100644 --- a/src/audio/mfcc/Kconfig +++ b/src/audio/mfcc/Kconfig @@ -4,7 +4,8 @@ config COMP_MFCC tristate "MFCC component" depends on COMP_MODULE_ADAPTER select CORDIC_FIXED - select MATH_16BIT_MEL_FILTERBANK + select MATH_32BIT_FFT + select MATH_32BIT_MEL_FILTERBANK select MATH_AUDITORY select MATH_DCT select MATH_DECIBELS @@ -14,6 +15,7 @@ config COMP_MFCC select NATURAL_LOGARITHM_FIXED select NUMBERS_NORM select SQRT_FIXED + default m if LIBRARY_DEFAULT_MODULAR default y help This option enables build of a Mel-frequency cepstral coefficients diff --git a/src/audio/mfcc/README.md b/src/audio/mfcc/README.md new file mode 100644 index 000000000000..31f9c331e545 --- /dev/null +++ b/src/audio/mfcc/README.md @@ -0,0 +1,25 @@ +# MFCC Feature Extraction Architecture + +This directory contains the Mel-Frequency Cepstral Coefficients (MFCC) feature extractor. + +## Overview + +MFCC extracts audio features commonly used as inputs for machine learning models, such as wake-word detection or speech recognition. + +## Architecture Diagram + +```mermaid +graph LR + In[Audio Frame] --> Win[Windowing] + Win --> FFT[FFT] + FFT --> Mel[Mel Filterbank] + Mel --> DCT[DCT] + DCT --> Out[MFCC Output Features] +``` + +## Configuration and Scripts + +- **Kconfig**: Enables the MFCC component (`COMP_MFCC`) which selects necessary math libraries (`MATH_FFT`, `MATH_DCT`, `MATH_16BIT_MEL_FILTERBANK`, etc.). Depends on `COMP_MODULE_ADAPTER`. +- **CMakeLists.txt**: Compiles generic, common, and HIFI implementations (`mfcc_hifi3.c`, `mfcc_hifi4.c`). Provides support for Zephyr loadable extensions (`llext`). +- **mfcc.toml**: Specifies the topology configuration for the MFCC module (UUID, affinity, memory parameters, and pin formats). +- **Topology (.conf)**: Derived from `tools/topology/topology2/include/components/mfcc.conf`, configuring a `mfcc` widget object of type `effect` with UUID `73:a7:10:db:a4:1a:ea:4c:a2:1f:2d:57:a5:c9:82:eb`. diff --git a/src/audio/mfcc/mfcc.c b/src/audio/mfcc/mfcc.c index 964b4bae7d38..724d3d7faf06 100644 --- a/src/audio/mfcc/mfcc.c +++ b/src/audio/mfcc/mfcc.c @@ -12,6 +12,8 @@ #include <sof/audio/format.h> #include <sof/audio/pipeline.h> #include <sof/audio/ipc-config.h> +#include <module/audio/source_api.h> +#include <module/audio/sink_api.h> #include <sof/common.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> @@ -36,31 +38,39 @@ LOG_MODULE_REGISTER(mfcc, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(mfcc); -DECLARE_TR_CTX(mfcc_tr, SOF_UUID(mfcc_uuid), LOG_LEVEL_INFO); +/** \brief Source/sink API based source copy function map. */ +struct mfcc_source_func_map { + uint8_t source_fmt; + mfcc_source_func func; +}; -__cold_rodata const struct mfcc_func_map mfcc_fm[] = { +__cold_rodata static const struct mfcc_source_func_map mfcc_sfm[] = { #if CONFIG_FORMAT_S16LE - {SOF_IPC_FRAME_S16_LE, mfcc_s16_default}, -#endif /* CONFIG_FORMAT_S16LE */ + {SOF_IPC_FRAME_S16_LE, mfcc_source_copy_s16}, +#endif #if CONFIG_FORMAT_S24LE - {SOF_IPC_FRAME_S24_4LE, NULL}, -#endif /* CONFIG_FORMAT_S24LE */ + {SOF_IPC_FRAME_S24_4LE, mfcc_source_copy_s24}, +#endif #if CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S32_LE, NULL}, -#endif /* CONFIG_FORMAT_S32LE */ + {SOF_IPC_FRAME_S32_LE, mfcc_source_copy_s32}, +#endif }; -static mfcc_func mfcc_find_func(enum sof_ipc_frame source_format, - enum sof_ipc_frame sink_format, - const struct mfcc_func_map *map, - int n) +/** + * \brief Look up the source copy function for a given input format. + * + * \param[in] source_format SOF IPC frame format of the input stream. + * + * \return Pointer to the matching mfcc_source_func, or NULL if the + * format is not supported in this build. + */ +static mfcc_source_func mfcc_find_source_func(enum sof_ipc_frame source_format) { int i; - /* Find suitable processing function from map. */ - for (i = 0; i < n; i++) { - if (source_format == map[i].source) - return map[i].func; + for (i = 0; i < ARRAY_SIZE(mfcc_sfm); i++) { + if (source_format == mfcc_sfm[i].source_fmt) + return mfcc_sfm[i].func; } return NULL; @@ -70,111 +80,133 @@ static mfcc_func mfcc_find_func(enum sof_ipc_frame source_format, * End of MFCC setup code. Next the standard component methods. */ +/** + * \brief MFCC module init callback. + * + * Allocates the component private data and the configuration blob + * handler used to receive the MFCC configuration from user space. + * + * \param[in,out] mod Processing module being initialized. + * + * \return 0 on success, -ENOMEM on allocation failure. + */ static int mfcc_init(struct processing_module *mod) { struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; - struct module_config *cfg = &md->cfg; struct mfcc_comp_data *cd = NULL; - size_t bs = cfg->size; - int ret; - comp_info(dev, "mfcc_init()"); + comp_info(dev, "entry"); - /* Check first that configuration blob size is sane */ - if (bs > SOF_MFCC_CONFIG_MAX_SIZE) { - comp_err(dev, "mfcc_init() error: configuration blob size %zu exceeds %d", - bs, SOF_MFCC_CONFIG_MAX_SIZE); - return -EINVAL; - } - - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; /* Handler for configuration data */ md->private = cd; - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "mfcc_init(): comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto err; - } - - /* Get configuration data */ - ret = comp_init_data_blob(cd->model_handler, bs, cfg->init_data); - if (ret < 0) { - comp_err(mod->dev, "mfcc_init(): comp_init_data_blob() failed."); - goto err_init; + comp_err(dev, "comp_data_blob_handler_new() failed."); + mod_free(mod, cd); + return -ENOMEM; } return 0; - -err_init: - comp_data_blob_handler_free(cd->model_handler); - -err: - rfree(cd); - return ret; } +/** + * \brief MFCC module free callback. + * + * Releases the IPC notification message, configuration blob handler, + * runtime buffers and the private data structure. + * + * \param[in,out] mod Processing module being freed. + * + * \return 0 on success. + */ static int mfcc_free(struct processing_module *mod) { struct mfcc_comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "mfcc_free()"); - comp_data_blob_handler_free(cd->model_handler); - mfcc_free_buffers(cd); - rfree(cd); + comp_info(mod->dev, "entry"); + ipc_msg_free(cd->msg); + cd->msg = NULL; + mod_data_blob_handler_free(mod, cd->model_handler); + mfcc_free_buffers(mod); + mod_free(mod, cd); return 0; } -static int mfcc_get_config(struct processing_module *mod, - uint32_t config_id, uint32_t *data_offset_size, - uint8_t *fragment, size_t fragment_size) -{ - struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; - struct mfcc_comp_data *cd = module_get_private_data(mod); - - comp_info(mod->dev, "mfcc_get_config()"); - - return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); -} - -static int mfcc_set_config(struct processing_module *mod, uint32_t config_id, - enum module_cfg_fragment_position pos, uint32_t data_offset_size, - const uint8_t *fragment, size_t fragment_size, uint8_t *response, - size_t response_size) -{ - struct mfcc_comp_data *cd = module_get_private_data(mod); - - comp_info(mod->dev, "mfcc_set_config()"); - - return comp_data_blob_set(cd->model_handler, pos, data_offset_size, - fragment, fragment_size); -} - +/** + * \brief Source/sink API based process function for MFCC. + * + * Reads input audio from sof_source, runs the STFT/Mel/DCT stage, and + * delegates output formatting and commit handling to mfcc_common.c. + * + * \param[in,out] mod Processing module. + * \param[in,out] sources Source array; only sources[0] is used. + * \param[in] num_of_sources Number of sources (must be 1). + * \param[in,out] sinks Sink array; only sinks[0] is used. + * \param[in] num_of_sinks Number of sinks (must be 1). + * + * \return 0 on success, or a negative error code from the STFT or output stages. + */ static int mfcc_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 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 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"); - - frames = MIN(frames, cd->max_frames); - cd->mfcc_func(mod, input_buffers, output_buffers, frames); - - /* TODO: use module_update_buffer_position() from #6194 */ - input_buffers->consumed += audio_stream_frame_bytes(source) * frames; - output_buffers->size += audio_stream_frame_bytes(sink) * frames; - comp_dbg(mod->dev, "mfcc_process(), done"); - return 0; + struct comp_dev *dev = mod->dev; + struct mfcc_state *state = &cd->state; + bool pending; + size_t source_avail; + int frames; + int num_ceps; + + comp_dbg(dev, "start"); + + /* In compress mode, retry pending output first and avoid producing + * new frames until previous frame has been committed. In legacy + * mode, pending output is held in a dedicated staging buffer + * (state->out_stage) that STFT does not touch, so input processing + * can continue while the previous period is drained. + */ + pending = state->header_pending || state->out_remain > 0; + if (cd->config->compress_output && pending) + return mfcc_process_output(mod, cd, sources, sinks, 0, 0); + + source_avail = source_get_data_frames_available(sources[0]); + frames = MIN(source_avail, cd->max_frames); + if (!frames) + return 0; + + /* Copy input audio from source to MFCC internal circular buffer */ + cd->source_func(sources[0], &state->buf, &state->emph, frames, state->source_channel); + + /* Run STFT and Mel/DCT processing */ + num_ceps = mfcc_stft_process(mod, cd); + if (num_ceps < 0) + return num_ceps; + + return mfcc_process_output(mod, cd, sources, sinks, num_ceps, frames); } +/** + * \brief MFCC module prepare callback. + * + * Validates the source/sink connection, reads the configuration blob, + * initializes the MFCC processing state via mfcc_setup(), selects the + * input copy function for the source frame format, and prepares the + * VAD switch control notification when enabled. + * + * \param[in,out] mod Processing module being prepared. + * \param[in,out] sources Source array; only sources[0] is used. + * \param[in] num_of_sources Number of sources (must be 1). + * \param[in,out] sinks Sink array; only sinks[0] is used. + * \param[in] num_of_sinks Number of sinks (must be 1). + * + * \return 0 on success or a negative error code. + */ static int mfcc_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) @@ -185,64 +217,95 @@ static int mfcc_prepare(struct processing_module *mod, struct comp_dev *dev = mod->dev; enum sof_ipc_frame source_format; enum sof_ipc_frame sink_format; - uint32_t sink_period_bytes; + size_t data_size; int ret; - comp_info(dev, "mfcc_prepare()"); + comp_info(dev, "entry"); /* MFCC component will only ever have 1 source and 1 sink buffer */ sourceb = comp_dev_get_first_data_producer(dev); sinkb = comp_dev_get_first_data_consumer(dev); + if (!sourceb || !sinkb) { + comp_err(dev, "no source or sink"); + return -ENOTCONN; + } /* get source data format */ source_format = audio_stream_get_frm_fmt(&sourceb->stream); /* get sink data format and period bytes */ 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(&sinkb->stream) < sink_period_bytes) { - comp_err(dev, "mfcc_prepare(): sink buffer size %d is insufficient < %d", - audio_stream_get_size(&sinkb->stream), sink_period_bytes); - ret = -ENOMEM; - goto err; - } + comp_info(dev, "source_format = %d, sink_format = %d", source_format, sink_format); - cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); + cd->config = comp_get_data_blob(cd->model_handler, &data_size, NULL); /* Initialize MFCC, max_frames is set to dev->frames + 4 */ - if (cd->config) { + if (cd->config && data_size > 0) { 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; + comp_err(dev, "setup failed."); + return ret; } + } else { + comp_err(dev, "configuration is missing."); + return -EINVAL; } - cd->mfcc_func = mfcc_find_func(source_format, sink_format, mfcc_fm, ARRAY_SIZE(mfcc_fm)); - if (!cd->mfcc_func) { - comp_err(dev, "mfcc_prepare(), No proc func"); - ret = -EINVAL; - goto err; + cd->source_func = mfcc_find_source_func(source_format); + if (!cd->source_func) { + comp_err(dev, "No source func"); + mfcc_free_buffers(mod); + return -EINVAL; } - return 0; + cd->source_format = source_format; + + if (cd->config->compress_output) + comp_info(dev, "compress PCM output mode enabled"); + + if (cd->config->enable_dtx && !cd->config->compress_output) + comp_warn(dev, "enable_dtx ignored in normal PCM mode, only applies to compress"); + + /* Initialize VAD switch control notification if enabled */ + if (cd->config->enable_vad && cd->config->update_controls) { + if (!cd->msg) { + ret = mfcc_ipc_notification_init(mod); + if (ret < 0) { + mfcc_free_buffers(mod); + return ret; + } + } + } -err: - comp_set_state(dev, COMP_TRIGGER_RESET); - return ret; + cd->vad_prev = false; + return 0; } +/** + * \brief MFCC module reset callback. + * + * Frees runtime buffers (NULLing their pointers) so a subsequent + * mfcc_prepare() can re-allocate cleanly. The configuration blob + * handler and IPC notification message are preserved. + * + * \param[in,out] mod Processing module being reset. + * + * \return 0 on success. + */ static int mfcc_reset(struct processing_module *mod) { struct mfcc_comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "mfcc_reset()"); + comp_info(mod->dev, "entry"); + + /* Free MFCC buffers to prevent leaks on reset->prepare cycles. + * mfcc_free_buffers() NULLs the pointers after free. + */ + mfcc_free_buffers(mod); /* Reset to similar state as init() */ - cd->mfcc_func = NULL; + cd->source_func = NULL; return 0; } @@ -251,14 +314,11 @@ static const struct module_interface mfcc_interface = { .free = mfcc_free, .set_configuration = mfcc_set_config, .get_configuration = mfcc_get_config, - .process_audio_stream = mfcc_process, + .process = mfcc_process, .prepare = mfcc_prepare, .reset = mfcc_reset, }; -DECLARE_MODULE_ADAPTER(mfcc_interface, mfcc_uuid, mfcc_tr); -SOF_MODULE_INIT(mfcc, sys_comp_module_mfcc_interface_init); - #if CONFIG_COMP_MFCC_MODULE /* modular: llext dynamic link */ @@ -266,14 +326,15 @@ SOF_MODULE_INIT(mfcc, sys_comp_module_mfcc_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_MFCC 0x73, 0xA7, 0x10, 0xDB, 0xA4, 0x1A, 0xEA, 0x4C, 0x1F, 0xA2, \ - 0x2D, 0x57, 0xA5, 0xC9, 0x82, 0xEB - -SOF_LLEXT_MOD_ENTRY(mfcc, &mfcc_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("MFCC", mfcc_llext_entry, 1, UUID_MFCC, 40); + SOF_LLEXT_MODULE_MANIFEST("MFCC", &mfcc_interface, 1, SOF_REG_UUID(mfcc), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(mfcc_tr, SOF_UUID(mfcc_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(mfcc_interface, mfcc_uuid, mfcc_tr); +SOF_MODULE_INIT(mfcc, sys_comp_module_mfcc_interface_init); + #endif diff --git a/src/audio/mfcc/mfcc.toml b/src/audio/mfcc/mfcc.toml index 5b07b2377752..9cc6291840de 100644 --- a/src/audio/mfcc/mfcc.toml +++ b/src/audio/mfcc/mfcc.toml @@ -5,7 +5,7 @@ REM # MFCC module config [[module.entry]] name = "MFCC" -uuid = "DB10A773-1AA4-4CEA-A21F-2D57A5C982EB" +uuid = UUIDREG_STR_MFCC affinity_mask = "0x1" instance_count = "40" domain_types = "0" diff --git a/src/audio/mfcc/mfcc_common.c b/src/audio/mfcc/mfcc_common.c index 63ab84943669..3890671165fd 100644 --- a/src/audio/mfcc/mfcc_common.c +++ b/src/audio/mfcc/mfcc_common.c @@ -1,14 +1,17 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2023 Intel Corporation. All rights reserved. +// Copyright(c) 2023-2026 Intel Corporation. // // Author: Andrula Song <andrula.song@intel.com> #include <sof/audio/mfcc/mfcc_comp.h> #include <sof/audio/component.h> -#include <sof/audio/audio_stream.h> +#include <module/audio/sink_api.h> +#include <module/audio/source_api.h> +#include <sof/audio/format.h> #include <sof/math/auditory.h> +#include <sof/math/fft.h> #include <sof/math/matrix.h> #include <sof/math/sqrt.h> #include <sof/math/trig.h> @@ -18,39 +21,284 @@ #include <errno.h> #include <stddef.h> #include <stdint.h> +#include <rtos/string.h> + +#include <sof/audio/mfcc/mfcc_vad.h> LOG_MODULE_REGISTER(mfcc_common, CONFIG_SOF_LOG_LEVEL); -/* MFCC with 16 bit FFT benefits from data normalize, for 32 bits there's no - * significant impact. The amount of left shifts for FFT input is limited to - * 10 that equals about 60 dB boost. The boost is compensated in Mel energy - * calculation. + +/* + * Source/sink API based source copy functions. + * These use sof_source API and are compiled on all platforms (generic, HiFi3, HiFi4). + */ + +#if CONFIG_FORMAT_S16LE +/** + * \brief Copy S16_LE input frames from source to MFCC circular buffer. + * + * Reads \p frames frames from \p source, selects channel \p source_channel, + * optionally applies the pre-emphasis filter \p emph, and writes Q1.15 mono + * samples to the MFCC input circular buffer \p buf. The source read is + * released after the copy completes. On source read failure the function + * returns without modifying \p buf state. + * + * \param[in,out] source Audio source providing interleaved S16_LE frames. + * \param[in,out] buf MFCC input circular buffer (mono Q1.15). + * \param[in,out] emph Pre-emphasis filter state; updated when enabled. + * \param[in] frames Number of input frames to copy. + * \param[in] source_channel Channel index to extract from the source. + */ +void mfcc_source_copy_s16(struct sof_source *source, struct mfcc_buffer *buf, + struct mfcc_pre_emph *emph, int frames, int source_channel) +{ + int16_t const *x; + int16_t const *x_start; + int16_t const *x_end; + int x_size; + int num_channels = source_get_channels(source); + size_t req_bytes = frames * num_channels * sizeof(int16_t); + int16_t *w = buf->w_ptr; + int src_without_wrap; + int dst_without_wrap; + int samples_without_wrap; + int remaining = frames; + int32_t s; + int ret; + int i; + + ret = source_get_data_s16(source, req_bytes, &x, &x_start, &x_size); + if (ret) + return; + + x += source_channel; + x_end = x_start + x_size; + + while (remaining) { + src_without_wrap = (x_end - x) / num_channels; + dst_without_wrap = buf->end_addr - w; + samples_without_wrap = MIN(src_without_wrap, dst_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining); + if (emph->enable) { + for (i = 0; i < samples_without_wrap; i++) { + s = (int32_t)emph->delay * emph->coef + + Q_SHIFT_LEFT(*x, 15, 30); + *w = sat_int16(Q_SHIFT_RND(s, 30, 15)); + emph->delay = *x; + x += num_channels; + w++; + } + } else { + for (i = 0; i < samples_without_wrap; i++) { + *w = *x; + x += num_channels; + w++; + } + } + x = (x >= x_end) ? x - x_size : x; + w = mfcc_buffer_wrap(buf, w); + remaining -= samples_without_wrap; + } + + buf->s_avail += frames; + buf->s_free -= frames; + buf->w_ptr = w; + source_release_data(source, req_bytes); +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S24LE +/** + * \brief Copy S24_4LE input frames from source to MFCC circular buffer. + * + * Same as mfcc_source_copy_s16() but accepts S24_4LE input (24-bit data + * sign-extended in a 32-bit container). Samples are downscaled to Q1.15 + * for the MFCC pipeline. + * + * \param[in,out] source Audio source providing interleaved S24_4LE frames. + * \param[in,out] buf MFCC input circular buffer (mono Q1.15). + * \param[in,out] emph Pre-emphasis filter state; updated when enabled. + * \param[in] frames Number of input frames to copy. + * \param[in] source_channel Channel index to extract from the source. */ -#if MFCC_FFT_BITS == 16 -#define MFCC_NORMALIZE_FFT -#else -#undef MFCC_NORMALIZE_FFT -#endif -#define MFCC_NORMALIZE_MAX_SHIFT 10 +void mfcc_source_copy_s24(struct sof_source *source, struct mfcc_buffer *buf, + struct mfcc_pre_emph *emph, int frames, int source_channel) +{ + int32_t const *x; + int32_t const *x_start; + int32_t const *x_end; + int x_size; + int num_channels = source_get_channels(source); + size_t req_bytes = frames * num_channels * sizeof(int32_t); + int16_t *w = buf->w_ptr; + int src_without_wrap; + int dst_without_wrap; + int samples_without_wrap; + int remaining = frames; + int32_t s, tmp; + int ret; + int i; + + ret = source_get_data_s32(source, req_bytes, &x, &x_start, &x_size); + if (ret) + return; + + x += source_channel; + x_end = x_start + x_size; + + while (remaining) { + src_without_wrap = (x_end - x) / num_channels; + dst_without_wrap = buf->end_addr - w; + samples_without_wrap = MIN(src_without_wrap, dst_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining); + if (emph->enable) { + for (i = 0; i < samples_without_wrap; i++) { + s = (int32_t)((uint32_t)*x << 8); + tmp = (int32_t)emph->delay * emph->coef + + Q_SHIFT(s, 31, 30); + *w = sat_int16(Q_SHIFT_RND(tmp, 30, 15)); + emph->delay = sat_int16(Q_SHIFT_RND(s, 31, 15)); + x += num_channels; + w++; + } + } else { + for (i = 0; i < samples_without_wrap; i++) { + s = (int32_t)((uint32_t)*x << 8); + *w = sat_int16(Q_SHIFT_RND(s, 31, 15)); + x += num_channels; + w++; + } + + } + x = (x >= x_end) ? x - x_size : x; + w = mfcc_buffer_wrap(buf, w); + remaining -= samples_without_wrap; + } + + buf->s_avail += frames; + buf->s_free -= frames; + buf->w_ptr = w; + source_release_data(source, req_bytes); +} +#endif /* CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S32LE +/** + * \brief Copy S32_LE input frames from source to MFCC circular buffer. + * + * Same as mfcc_source_copy_s16() but accepts S32_LE input. Samples are + * downscaled to Q1.15 for the MFCC pipeline. + * + * \param[in,out] source Audio source providing interleaved S32_LE frames. + * \param[in,out] buf MFCC input circular buffer (mono Q1.15). + * \param[in,out] emph Pre-emphasis filter state; updated when enabled. + * \param[in] frames Number of input frames to copy. + * \param[in] source_channel Channel index to extract from the source. + */ +void mfcc_source_copy_s32(struct sof_source *source, struct mfcc_buffer *buf, + struct mfcc_pre_emph *emph, int frames, int source_channel) +{ + int32_t const *x; + int32_t const *x_start; + int32_t const *x_end; + int x_size; + int num_channels = source_get_channels(source); + size_t req_bytes = frames * num_channels * sizeof(int32_t); + int16_t *w = buf->w_ptr; + int src_without_wrap; + int dst_without_wrap; + int samples_without_wrap; + int remaining = frames; + int32_t s; + int ret; + int i; + + ret = source_get_data_s32(source, req_bytes, &x, &x_start, &x_size); + if (ret) + return; + + x += source_channel; + x_end = x_start + x_size; + while (remaining) { + src_without_wrap = (x_end - x) / num_channels; + dst_without_wrap = buf->end_addr - w; + samples_without_wrap = MIN(src_without_wrap, dst_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, remaining); + if (emph->enable) { + for (i = 0; i < samples_without_wrap; i++) { + s = (int32_t)emph->delay * emph->coef + + Q_SHIFT(*x, 31, 30); + *w = sat_int16(Q_SHIFT_RND(s, 30, 15)); + emph->delay = sat_int16(Q_SHIFT_RND(*x, 31, 15)); + x += num_channels; + w++; + } + } else { + for (i = 0; i < samples_without_wrap; i++) { + *w = sat_int16(Q_SHIFT_RND(*x, 31, 15)); + x += num_channels; + w++; + } + } + + x = (x >= x_end) ? x - x_size : x; + w = mfcc_buffer_wrap(buf, w); + remaining -= samples_without_wrap; + } + + buf->s_avail += frames; + buf->s_free -= frames; + buf->w_ptr = w; + source_release_data(source, req_bytes); +} +#endif /* CONFIG_FORMAT_S32LE */ /* * The main processing function for MFCC */ -static int mfcc_stft_process(const struct comp_dev *dev, struct mfcc_state *state) +/** + * \brief Run one STFT hop and Mel/DCT processing. + * + * Waits until the input circular buffer has at least one FFT window of + * samples, then for each available hop: copies the overlap-add window + * into the FFT scratch buffer, applies the analysis window, runs the + * 32-bit FFT, computes Mel log spectra, and either keeps the Mel output + * (when \c state->mel_only is true) or applies DCT and cepstral lifter + * to produce cepstral coefficients. Optionally runs VAD on the Mel + * spectrum and sends an IPC notification on VAD state changes. + * + * \param[in,out] mod Processing module. + * \param[in,out] cd MFCC component data; state and configuration updated + * in-place. Output values land in \c state->mel_log_32 + * (Mel mode) or \c state->cepstral_coef (cepstral mode). + * + * \return Number of int32_t output values produced this call (0 if not + * enough input data was available, or no error condition was + * detected). + */ +int mfcc_stft_process(struct processing_module *mod, struct mfcc_comp_data *cd) { + const struct comp_dev *dev = mod->dev; + struct sof_mfcc_config *config = cd->config; + struct mfcc_state *state = &cd->state; struct mfcc_buffer *buf = &state->buf; struct mfcc_fft *fft = &state->fft; int mel_scale_shift; int input_shift; - int i; + int j; int m; int cc_count = 0; + int64_t s; + int32_t mel_value; + int32_t peak; + int32_t clamp_value; + bool vad_now; /* Phase 1, wait until whole fft_size is filled with valid data. This way * first output cepstral coefficients originate from streamed data and not * from buffers with zero data. */ - comp_dbg(dev, "mfcc_stft_process(), avail = %d", buf->s_avail); + comp_dbg(dev, "avail = %d", buf->s_avail); if (state->waiting_fill) { if (buf->s_avail < fft->fft_size) return 0; @@ -66,9 +314,9 @@ static int mfcc_stft_process(const struct comp_dev *dev, struct mfcc_state *stat state->prev_samples_valid = true; } - /* Check if enough samples in buffer for FFT hop */ + /* Check if enough samples in buffer for one FFT hop */ m = buf->s_avail / fft->fft_hop_size; - for (i = 0; i < m; i++) { + if (m > 0) { /* Clear FFT input buffer because it has been used as scratch */ bzero(fft->fft_buf, fft->fft_buffer_size); @@ -79,12 +327,7 @@ static int mfcc_stft_process(const struct comp_dev *dev, struct mfcc_state *stat /* TODO: use_energy & raw_energy */ -#ifdef MFCC_NORMALIZE_FFT - /* Find block scale left shift for FFT input */ - input_shift = mfcc_normalize_fft_buffer(state); -#else input_shift = 0; -#endif /* Window function */ mfcc_apply_window(state, input_shift); @@ -97,87 +340,468 @@ static int mfcc_stft_process(const struct comp_dev *dev, struct mfcc_state *stat bzero(fft->fft_out, fft->fft_buffer_size); /* Compute FFT */ -#if MFCC_FFT_BITS == 16 - fft_execute_16(fft->fft_plan, false); -#else fft_execute_32(fft->fft_plan, false); -#endif - /* Convert powerspectrum to Mel band logarithmic spectrum */ - mat_init_16b(state->mel_spectra, 1, state->dct.num_in, 7); /* Q8.7 */ + /* Initialize 16-bit Mel log spectrum buffer in Q9.7. The Mel values + * are converted from Q9.23 to Q9.7 for DCT matrix multiplication. + */ + mat_init_16b(state->mel_spectra, 1, state->dct.num_in, 7); /* Q9.7 */ /* Compensate FFT lib scaling to Mel log values, e.g. for 512 long FFT * the fft_plan->len is 9. The scaling is 1/512. Subtract from input_shift it * to add the missing "gain". */ mel_scale_shift = input_shift - fft->fft_plan->len; -#if MFCC_FFT_BITS == 16 - psy_apply_mel_filterbank_16(&state->melfb, fft->fft_out, state->power_spectra, - state->mel_spectra->data, mel_scale_shift); -#else psy_apply_mel_filterbank_32(&state->melfb, fft->fft_out, state->power_spectra, - state->mel_spectra->data, mel_scale_shift); -#endif + state->mel_log_32, mel_scale_shift); + + if (state->mel_only) { + /* In Mel-only mode output Mel log spectra directly */ + cc_count += state->dct.num_in; + + /* Find peak mel value and track state->mmax in Q9.23 */ + if (config->dynamic_mmax) { + peak = state->mel_log_32[0]; + for (j = 1; j < state->dct.num_in; j++) { + if (state->mel_log_32[j] > peak) + peak = state->mel_log_32[j]; + } + + /* Jump to peak immediately if higher, decay otherwise */ + if (peak > state->mmax) { + state->mmax = peak; + } else { + /* Q9.23 * Q1.15, result Q9.23. The coefficient is small + * so no need for saturation. + */ + s = (int64_t)peak - state->mmax; + state->mmax += + Q_MULTSR_32X32(s, config->mmax_coef, 23, 15, 23); + } + } + + /* Clamp Mel values lower than mmax - top_db, add offset, and scale. + * Config top_db and mel_offset are Q9.7, shift to Q9.23. + */ + clamp_value = state->mmax - ((int32_t)config->top_db << 16); + for (j = 0; j < state->dct.num_in; j++) { + mel_value = state->mel_log_32[j]; + if (mel_value < clamp_value) + mel_value = clamp_value; + + /* Q9.23 * Q4.12, result Q9.23 */ + s = (int64_t)mel_value + ((int32_t)config->mel_offset << 16); + state->mel_log_32[j] = + sat_int32(Q_MULTSR_32X32(s, config->mel_scale, 23, 12, 23)); + } + + /* Enable this to check mmax decay */ + comp_dbg(dev, "state->mmax = %d", state->mmax); + } else { + /* Convert Q9.23 to Q9.7 for 16-bit DCT */ + for (j = 0; j < state->dct.num_in; j++) + state->mel_spectra->data[j] = + sat_int16(state->mel_log_32[j] >> 16); + + /* Multiply Mel spectra with DCT matrix to get cepstral coefficients */ + mat_init_16b(state->cepstral_coef, 1, state->dct.num_out, 7); /* Q9.7 */ + mat_multiply(state->mel_spectra, state->dct.matrix, state->cepstral_coef); - /* Multiply Mel spectra with DCT matrix to get cepstral coefficients */ - mat_init_16b(state->cepstral_coef, 1, state->dct.num_out, 7); /* Q8.7 */ - mat_multiply(state->mel_spectra, state->dct.matrix, state->cepstral_coef); + /* Apply cepstral lifter */ + if (state->lifter.cepstral_lifter != 0) { + mat_multiply_elementwise(state->cepstral_coef, state->lifter.matrix, + state->cepstral_coef); + } - /* Apply cepstral lifter */ - if (state->lifter.cepstral_lifter != 0) - mat_multiply_elementwise(state->cepstral_coef, state->lifter.matrix, - state->cepstral_coef); + cc_count += state->dct.num_out; + } - cc_count += state->dct.num_out; + /* Use hop counter for frame numbering (independent of VAD enable) */ + state->header.frame_number = state->hop_count; - /* Output to sink buffer */ + /* Run VAD on the mel log spectrum (available in both modes) */ + if (config->enable_vad) { + mfcc_vad_update(&cd->vad, state->mel_log_32); + + /* Populate data header for this output frame */ + state->header.energy = cd->vad.energy; + state->header.noise_energy = cd->vad.noise_energy; + state->header.vad_flag = cd->vad.is_speech ? 1 : 0; + } + + /* Increment hop counter at end of hop processing */ + state->hop_count++; + + /* Send notification when VAD state changes */ + if (config->enable_vad && config->update_controls) { + vad_now = cd->vad.is_speech; + + if (vad_now != cd->vad_prev) { + mfcc_send_vad_notification(mod, vad_now ? 1 : 0); + cd->vad_prev = vad_now; + } + } } - /* TODO: This version handles only one FFT run per copy(). How to pass multiple - * cepstral coefficients sets return is an open. - */ return cc_count; } -#if CONFIG_FORMAT_S16LE -void mfcc_s16_default(struct processing_module *mod, struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, int frames) +/** + * \brief Write bytes into a possibly wrapped sink buffer. + * + * Caller must ensure max_bytes <= buf_size; otherwise the wrap branch + * would write past the end of the buffer. Returns 0 on bound violation. + */ +static size_t mfcc_sink_write_bytes(uint8_t **dst, uint8_t *buf_start, + size_t buf_size, const uint8_t *src, + size_t max_bytes) { - 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; - uint32_t magic = MFCC_MAGIC; - int16_t *w_ptr = audio_stream_get_wptr(sink); - // int num_magic = sizeof(magic) / sizeof(int16_t); - const int num_magic = 2; - int num_ceps; - int zero_samples; - - /* Get samples from source buffer */ - mfcc_source_copy_s16(bsource, buf, &state->emph, frames, state->source_channel); - - /* Run STFT and processing after FFT: Mel auditory filter and DCT. The sink - * buffer is updated during STDF processing. + uint8_t *buf_end = buf_start + buf_size; + size_t chunk; + + if (max_bytes == 0) + return 0; + + /* Guard: a single write must not exceed total sink buffer size. */ + if (max_bytes > buf_size) + return 0; + + chunk = MIN(max_bytes, (size_t)(buf_end - *dst)); + memcpy(*dst, src, chunk); + if (chunk < max_bytes) { + memcpy(buf_start, src + chunk, max_bytes - chunk); + *dst = buf_start + (max_bytes - chunk); + } else { + *dst += chunk; + if (*dst >= buf_end) + *dst = buf_start; + } + + return max_bytes; +} + +/** + * \brief Prepare the next MFCC output frame after STFT processing. + * + * Copies Mel (int32 Q9.23) or cepstral (int16 Q9.7 widened to int32 Q9.23) + * output into \c state->out_stage, sets up the read pointer for staged output, + * and marks the data header as pending. + * + * \param[in,out] state MFCC state. + * \param[in] num_ceps Number of int32_t values to publish; no-op if <= 0. + */ +static void mfcc_prepare_output(struct mfcc_state *state, int num_ceps) +{ + int k; + + if (num_ceps <= 0) + return; + + /* Copy into out_stage so the next STFT hop may freely reuse + * mel_log_32 / cepstral_coef while this frame is still pending. */ - num_ceps = mfcc_stft_process(mod->dev, state); + if (state->mel_only) { + for (k = 0; k < num_ceps; k++) + state->out_stage[k] = state->mel_log_32[k]; + } else { + /* Widen int16 Q9.7 cepstral coefficients to int32 Q9.23. */ + for (k = 0; k < num_ceps; k++) + state->out_stage[k] = (int32_t)state->cepstral_coef->data[k] << 16; + } + + state->out_data_ptr = state->out_stage; + state->out_remain = num_ceps; + state->header_pending = true; +} + +/** + * \brief Commit MFCC output in compress mode. + * + * Writes the pending data header (if any) followed by the pending + * int32_t Mel/cepstral payload into the sink as a contiguous blob, + * without zero padding. When VAD + DTX are enabled, suppresses silence + * frames after a configurable trailing-silence count and optionally + * sends periodic keep-alive silence updates. + * + * \param[in,out] mod Processing module. + * \param[in,out] cd MFCC component data. + * \param[in,out] sinks Sink array; only sinks[0] is used. + * \param[in] num_ceps Number of int32_t values prepared for this hop. + * + * \return 0 on success, -ENOSPC if the sink cannot accept the frame, + * or a negative error from the sink API. + */ +static int mfcc_output_compress(struct processing_module *mod, struct mfcc_comp_data *cd, + struct sof_sink **sinks, int num_ceps) +{ + struct mfcc_state *state = &cd->state; + size_t out_bytes; + size_t commit_bytes; + void *sink_ptr; + void *sink_start; + size_t sink_buf_size; + uint8_t *dst; + int ret; + bool pending; + bool send_periodic; + + pending = state->header_pending || state->out_remain > 0; + if (!pending) + return 0; + + if (num_ceps > 0 && cd->config->enable_vad && !cd->vad.is_speech) { + state->vad_silence_count++; + /* With DTX enabled, send trailing silence frames + * (configurable count) then suppress. After trailing + * frames, optionally send periodic silence updates + * at the configured interval. This gives the host + * enough silence to detect end-of-speech while + * keeping alive updates during long silence. + * Without DTX, output every frame regardless of VAD. + */ + if (cd->config->enable_dtx && + state->vad_silence_count > state->dtx_trailing_silence) { + send_periodic = false; + + /* Check periodic silence frame send */ + if (state->dtx_silence_interval > 0) { + state->dtx_silence_counter++; + if (state->dtx_silence_counter >= + state->dtx_silence_interval) { + state->dtx_silence_counter = 0; + send_periodic = true; + } + } + + if (!send_periodic) { + /* Suppress this frame */ + state->header_pending = false; + state->out_remain = 0; + return 0; + } + } + } else { + state->vad_silence_count = 0; + state->dtx_silence_counter = 0; + } + + out_bytes = (state->header_pending ? sizeof(state->header) : 0) + + state->out_remain * sizeof(int32_t); + if (out_bytes == 0) + return 0; - /* Done, copy data to sink. This works only if the period has room for magic (2) - * plus num_ceps int16_t samples. TODO: split ceps over multiple periods. + commit_bytes = out_bytes; + if (sink_get_free_size(sinks[0]) < commit_bytes) + return -ENOSPC; + + ret = sink_get_buffer(sinks[0], commit_bytes, &sink_ptr, + &sink_start, &sink_buf_size); + if (ret) + return ret; + + dst = sink_ptr; + if (state->header_pending) { + mfcc_sink_write_bytes(&dst, sink_start, sink_buf_size, + (uint8_t *)&state->header, + sizeof(state->header)); + } + + if (state->out_remain > 0) { + mfcc_sink_write_bytes(&dst, sink_start, sink_buf_size, + (uint8_t *)state->out_data_ptr, + state->out_remain * sizeof(int32_t)); + } + + ret = sink_commit_buffer(sinks[0], commit_bytes); + if (ret) + return ret; + + state->header_pending = false; + state->out_remain = 0; + return 0; +} + +/** + * \brief Commit MFCC output in legacy PCM mode. + * + * Acquires a sink period sized as \p frames audio frames, zero-fills it, + * then writes any pending data header and pending int32_t Mel/cepstral + * payload. Any payload that does not fit in the current period stays in + * \c state->out_data_ptr / \c state->out_remain for the next call. + * + * \param[in,out] mod Processing module. + * \param[in,out] cd MFCC component data. + * \param[in,out] sources Sources array (unused; reserved for symmetry). + * \param[in,out] sinks Sink array; only sinks[0] is used. + * \param[in] frames Number of audio frames the sink expects this period. + * + * \return 0 on success, -ENOSPC if the sink cannot accept the period, + * or a negative error from the sink API. + */ +static int mfcc_output_legacy(struct processing_module *mod, struct mfcc_comp_data *cd, + struct sof_source **sources, struct sof_sink **sinks, + int frames) +{ + struct mfcc_state *state = &cd->state; + size_t commit_bytes; + size_t bytes_to_end; + size_t avail; + size_t hdr_size; + size_t data_bytes; + size_t to_write; + void *sink_ptr; + void *sink_start; + size_t sink_buf_size; + uint8_t *dst; + int n32; + int ret; + + /* The MFCC sink is treated as an opaque byte container: the period + * carries an MFCC blob (header + int32 features), not PCM audio. + * Sizing the commit as sink_frame_bytes * frames keeps the period + * size matched to whatever the sink advertises (S16_LE / S24_4LE / + * S32_LE), so no format-specific conversion is needed. Any payload + * that does not fit in the current period is carried over via + * state->out_remain and drained in the next call(s). The host side + * decodes the bytes as MFCC features regardless of the sink's + * nominal PCM format, so non-S32 sinks (e.g. bench S16 topologies) + * remain supported. */ - zero_samples = frames * audio_stream_get_channels(sink); - if (num_ceps > 0) { - zero_samples -= num_ceps + num_magic; - w_ptr = mfcc_sink_copy_data_s16(sink, w_ptr, num_magic, (int16_t *)&magic); - w_ptr = mfcc_sink_copy_data_s16(sink, w_ptr, num_ceps, state->cepstral_coef->data); + commit_bytes = sink_get_frame_bytes(sinks[0]) * frames; + if (sink_get_free_size(sinks[0]) < commit_bytes) + return -ENOSPC; + + ret = sink_get_buffer(sinks[0], commit_bytes, &sink_ptr, + &sink_start, &sink_buf_size); + if (ret) + return ret; + + /* Zero-fill entire period first */ + bytes_to_end = (size_t)((uint8_t *)sink_start + sink_buf_size - + (uint8_t *)sink_ptr); + + if (bytes_to_end >= commit_bytes) { + memset(sink_ptr, 0, commit_bytes); + } else { + memset(sink_ptr, 0, bytes_to_end); + memset(sink_start, 0, commit_bytes - bytes_to_end); } - w_ptr = mfcc_sink_copy_zero_s16(sink, w_ptr, zero_samples); + dst = sink_ptr; + avail = commit_bytes; + + /* Write pending header */ + if (state->header_pending && avail > 0) { + hdr_size = sizeof(state->header); + + if (avail >= hdr_size) { + mfcc_sink_write_bytes(&dst, sink_start, sink_buf_size, + (uint8_t *)&state->header, hdr_size); + avail -= hdr_size; + state->header_pending = false; + } + } + + /* Write pending feature data (always int32) */ + if (state->out_remain > 0 && avail > 0) { + data_bytes = state->out_remain * sizeof(int32_t); + to_write = MIN(data_bytes, avail) & ~(size_t)3; + if (to_write > 0) { + mfcc_sink_write_bytes(&dst, sink_start, sink_buf_size, + (uint8_t *)state->out_data_ptr, + to_write); + n32 = to_write / sizeof(int32_t); + state->out_data_ptr += n32; + state->out_remain -= n32; + } + } + + return sink_commit_buffer(sinks[0], commit_bytes); } -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S24LE -#endif /* CONFIG_FORMAT_S24LE */ +int mfcc_process_output(struct processing_module *mod, struct mfcc_comp_data *cd, + struct sof_source **sources, struct sof_sink **sinks, + int num_ceps, int frames) +{ + bool pending; -#if CONFIG_FORMAT_S32LE -#endif /* CONFIG_FORMAT_S32LE */ + pending = cd->state.header_pending || cd->state.out_remain > 0; + + if (cd->config->compress_output) { + /* Keep retrying pending frame first; don't overwrite pending state. */ + if (!pending && num_ceps > 0) + mfcc_prepare_output(&cd->state, num_ceps); + else if (pending) + num_ceps = 0; + + return mfcc_output_compress(mod, cd, sinks, num_ceps); + } + + /* Legacy PCM mode: same guard. Overwriting out_data_ptr / out_remain + * while a previous period's data is still pending would drop samples. + */ + if (!pending && num_ceps > 0) + mfcc_prepare_output(&cd->state, num_ceps); + + return mfcc_output_legacy(mod, cd, sources, sinks, frames); +} + +/** + * \brief Refill the FFT input scratch from the input circular buffer. + * + * Copies the saved overlap (\c state->prev_data) into the first samples + * of \c fft->fft_buf, appends one \c fft_hop_size of new data from the + * input circular buffer (consuming it), and finally saves the trailing + * window of the FFT input back to \c state->prev_data for the next hop. + * The caller is expected to have zeroed \c fft->fft_buf so that the + * complex imaginary parts remain 0. + * + * \param[in,out] state MFCC state. Input buffer pointers/counters and + * \c prev_data are updated; \c fft->fft_buf is filled. + */ +void mfcc_fill_fft_buffer(struct mfcc_state *state) +{ + struct mfcc_buffer *buf = &state->buf; + struct mfcc_fft *fft = &state->fft; + int32_t *d = &fft->fft_buf[fft->fft_fill_start_idx].real; + const int fft_elem_inc = sizeof(fft->fft_buf[0]) / sizeof(int32_t); + int16_t *prev = state->prev_data; + int16_t *prev_end = prev + state->prev_data_size; + int16_t *r = buf->r_ptr; + int copied; + int nmax; + int n; + int j; + + /* Copy overlapped samples from state buffer. The fft_buf has been + * cleared by caller so imaginary part remains zero. + */ + while (prev < prev_end) { + *d = *prev++; + d += fft_elem_inc; + } + + /* Copy hop size of new data from circular buffer */ + for (copied = 0; copied < fft->fft_hop_size; copied += n) { + nmax = fft->fft_hop_size - copied; + n = mfcc_buffer_samples_without_wrap(buf, r); + n = MIN(n, nmax); + for (j = 0; j < n; j++) { + *d = *r++; + d += fft_elem_inc; + } + r = mfcc_buffer_wrap(buf, r); + } + + buf->s_avail -= copied; + buf->s_free += copied; + buf->r_ptr = r; + + /* Copy for next time data back to overlap buffer */ + d = (int32_t *)&fft->fft_buf[fft->fft_fill_start_idx + fft->fft_hop_size].real; + prev = state->prev_data; + while (prev < prev_end) { + *prev++ = *d; + d += fft_elem_inc; + } +} diff --git a/src/audio/mfcc/mfcc_generic.c b/src/audio/mfcc/mfcc_generic.c index 9384b16e0cee..65f4760a0ea3 100644 --- a/src/audio/mfcc/mfcc_generic.c +++ b/src/audio/mfcc/mfcc_generic.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2022 Intel Corporation. All rights reserved. +// Copyright(c) 2022-2026 Intel Corporation. // // Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> @@ -8,8 +8,9 @@ #ifdef MFCC_GENERIC #include <sof/audio/component.h> -#include <sof/audio/audio_stream.h> #include <sof/math/auditory.h> +#include <sof/math/icomplex16.h> +#include <sof/math/icomplex32.h> #include <sof/math/matrix.h> #include <sof/math/sqrt.h> #include <sof/math/trig.h> @@ -24,53 +25,17 @@ * MFCC algorithm code */ -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 *source = bsource->data; - int32_t s; - int16_t *x0; - int16_t *x = audio_stream_get_rptr(source); - int16_t *w = buf->w_ptr; - int copied; - int nmax; - int n1; - int n2; - int n; - int i; - int num_channels = audio_stream_get_channels(source); - - /* Copy from source to pre-buffer for FFT. - * The pre-emphasis filter is done in this step. - */ - for (copied = 0; copied < frames; copied += n) { - nmax = frames - copied; - n1 = audio_stream_frames_without_wrap(source, x); - n2 = mfcc_buffer_samples_without_wrap(buf, w); - n = MIN(n1, n2); - n = MIN(n, nmax); - x0 = x + source_channel; - for (i = 0; i < n; i++) { - if (emph->enable) { - /* Q1.15 x Q1.15 -> Q2.30 */ - s = (int32_t)emph->delay * emph->coef + Q_SHIFT_LEFT(*x0, 15, 30); - *w = sat_int16(Q_SHIFT_RND(s, 30, 15)); - emph->delay = *x0; - } else { - *w = *x0; - } - x0 += num_channels; - w++; - } - - x = audio_stream_wrap(source, x + n * audio_stream_get_channels(source)); - w = mfcc_buffer_wrap(buf, w); - } - buf->s_avail += copied; - buf->s_free -= copied; - buf->w_ptr = w; -} - +/** + * \brief Generic-C copy of the overlap window from the input circular buffer. + * + * Copies \p prev_data_length samples from the front of \p buf into + * \p prev_data and advances the read pointer. Used once on first frame + * to seed the overlap region for subsequent STFT hops. + * + * \param[in,out] buf Input circular buffer (Q1.15 mono). + * \param[out] prev_data Destination overlap buffer. + * \param[in] prev_data_length Number of samples to copy. + */ void mfcc_fill_prev_samples(struct mfcc_buffer *buf, int16_t *prev_data, int prev_data_length) { @@ -96,144 +61,28 @@ void mfcc_fill_prev_samples(struct mfcc_buffer *buf, int16_t *prev_data, buf->r_ptr = r; } -void mfcc_fill_fft_buffer(struct mfcc_state *state) -{ - struct mfcc_buffer *buf = &state->buf; - struct mfcc_fft *fft = &state->fft; - int16_t *r = buf->r_ptr; - int copied; - int nmax; - int idx = fft->fft_fill_start_idx; - int j; - int n; - - /* Copy overlapped samples from state buffer. Imaginary part of input - * remains zero. - */ - for (j = 0; j < state->prev_data_size; j++) - fft->fft_buf[idx + j].real = state->prev_data[j]; - - /* Copy hop size of new data from circular buffer */ - idx += state->prev_data_size; - for (copied = 0; copied < fft->fft_hop_size; copied += n) { - nmax = fft->fft_hop_size - copied; - n = mfcc_buffer_samples_without_wrap(buf, r); - n = MIN(n, nmax); - for (j = 0; j < n; j++) { - fft->fft_buf[idx].real = *r; - r++; - idx++; - } - r = mfcc_buffer_wrap(buf, r); - } - - buf->s_avail -= copied; - buf->s_free += copied; - buf->r_ptr = r; - - /* Copy for next time data back to overlap buffer */ - idx = fft->fft_fill_start_idx + fft->fft_hop_size; - for (j = 0; j < state->prev_data_size; j++) - state->prev_data[j] = fft->fft_buf[idx + j].real; -} - -#ifdef MFCC_NORMALIZE_FFT -int mfcc_normalize_fft_buffer(struct mfcc_state *state) -{ - struct mfcc_fft *fft = &state->fft; - int32_t absx; - int32_t smax = 0; - int32_t x; - int shift; - int j; - int i = fft->fft_fill_start_idx; - - for (j = 0; j < fft->fft_size; j++) { - x = fft->fft_buf[i + j].real; - absx = (x < 0) ? -x : x; - if (smax < absx) - smax = absx; - } - - shift = norm_int32(smax << 15) - 1; /* 16 bit data */ - shift = MAX(shift, 0); - shift = MIN(shift, MFCC_NORMALIZE_MAX_SHIFT); - return shift; -} -#endif - +/** + * \brief Generic-C window function application on the FFT input buffer. + * + * Multiplies the real part of \c fft->fft_buf (sized \c fft->fft_size, + * Q1.15 input upcast to int32) by \c state->window (Q1.15) in-place and + * left-shifts by \p input_shift + 1 to produce Q1.31 fixed-point input + * to the FFT. + * + * \param[in,out] state MFCC state; \c state->fft.fft_buf is updated in-place. + * \param[in] input_shift Additional left shift applied to the windowed sample. + */ void mfcc_apply_window(struct mfcc_state *state, int input_shift) { struct mfcc_fft *fft = &state->fft; int j; int i = fft->fft_fill_start_idx; -#if MFCC_FFT_BITS == 16 - /* TODO: Use proper multiply and saturate function to make sure no overflows */ - int32_t x; - int s = 14 - input_shift; /* Q1.15 x Q1.15 -> Q30 -> Q15, shift by 15 - 1 for round */ - - for (j = 0; j < fft->fft_size; j++) { - x = (int32_t)fft->fft_buf[i + j].real * state->window[j]; - fft->fft_buf[i + j].real = ((x >> s) + 1) >> 1; - } -#else /* TODO: Use proper multiply and saturate function to make sure no overflows */ int s = input_shift + 1; /* To convert 16 -> 32 with Q1.15 x Q1.15 -> Q30 -> Q31 */ for (j = 0; j < fft->fft_size; j++) fft->fft_buf[i + j].real = (fft->fft_buf[i + j].real * state->window[j]) << s; -#endif -} - -#if CONFIG_FORMAT_S16LE - -int16_t *mfcc_sink_copy_zero_s16(const struct audio_stream *sink, - int16_t *w_ptr, int samples) -{ - int copied; - int nmax; - int i; - int n; - - for (copied = 0; copied < samples; copied += n) { - nmax = samples - copied; - n = audio_stream_samples_without_wrap_s16(sink, w_ptr); - n = MIN(n, nmax); - for (i = 0; i < n; i++) { - *w_ptr = 0; - w_ptr++; - } - - w_ptr = audio_stream_wrap(sink, w_ptr); - } - - return w_ptr; -} - -int16_t *mfcc_sink_copy_data_s16(const struct audio_stream *sink, int16_t *w_ptr, - int samples, int16_t *r_ptr) -{ - int copied; - int nmax; - int i; - int n; - - for (copied = 0; copied < samples; copied += n) { - nmax = samples - copied; - n = audio_stream_samples_without_wrap_s16(sink, w_ptr); - n = MIN(n, nmax); - for (i = 0; i < n; i++) { - *w_ptr = *r_ptr; - r_ptr++; - w_ptr++; - } - - w_ptr = audio_stream_wrap(sink, w_ptr); - } - - return w_ptr; } -#endif /* CONFIG_FORMAT_S16LE */ -#endif +#endif /* MFCC_GENERIC */ diff --git a/src/audio/mfcc/mfcc_hifi3.c b/src/audio/mfcc/mfcc_hifi3.c index 76f0a79da668..fdf8e47d2deb 100644 --- a/src/audio/mfcc/mfcc_hifi3.c +++ b/src/audio/mfcc/mfcc_hifi3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2023 Intel Corporation. All rights reserved. +// Copyright(c) 2023-2026 Intel Corporation. // // Author: Andrula Song <andrula.song@intel.com> @@ -9,8 +9,9 @@ #ifdef MFCC_HIFI3 #include <sof/audio/component.h> -#include <sof/audio/audio_stream.h> #include <sof/math/auditory.h> +#include <sof/math/icomplex16.h> +#include <sof/math/icomplex32.h> #include <sof/math/matrix.h> #include <sof/math/sqrt.h> #include <sof/math/trig.h> @@ -33,64 +34,16 @@ static inline void set_circular_buf0(const void *start, const void *end) * MFCC algorithm code */ -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 *source = bsource->data; - int copied; - int nmax; - int n; - int i; - int num_channels = audio_stream_get_channels(source); - ae_int16 *in; - ae_int16 *x = (ae_int16 *)audio_stream_get_rptr(source); - ae_int16 *out = (ae_int16 *)buf->w_ptr; - ae_int16x4 sample; - ae_int32x2 temp; - ae_int16x4 coef = emph->coef; - ae_int16x4 delay; - const int in_inc = sizeof(ae_int16) * num_channels; - - /* Copy from source to pre-buffer for FFT. - * The pre-emphasis filter is done in this step. - */ - for (copied = 0; copied < frames; copied += n) { - nmax = frames - copied; - n = audio_stream_frames_without_wrap(source, x); - n = MIN(n, nmax); - nmax = mfcc_buffer_samples_without_wrap(buf, (int16_t *)out); - n = MIN(n, nmax); - in = x + source_channel; - if (emph->enable) { - delay = emph->delay; - for (i = 0; i < n; i++) { - AE_L16_XP(sample, in, in_inc); - /* Q1.15 -> Q1.31 */ - temp = AE_CVT32X2F16_10(sample); - AE_MULAF16SS_00(temp, delay, coef); - delay = sample; - sample = AE_ROUND16X4F32SSYM(temp, temp); - /* 2 = sizeof(ae_int16)*/ - AE_S16_0_IP(sample, out, 2); - } - emph->delay = delay; - - } else { - for (i = 0; i < n; i++) { - AE_L16_XP(sample, in, in_inc); - /* 2 = sizeof(ae_int16)*/ - AE_S16_0_IP(sample, out, 2); - } - } - - x = audio_stream_wrap(source, x + n * num_channels); - out = (ae_int16 *)mfcc_buffer_wrap(buf, (int16_t *)out); - } - buf->s_avail += copied; - buf->s_free -= copied; - buf->w_ptr = (int16_t *)out; -} - +/** + * \brief HiFi3 copy of the overlap window from the input circular buffer. + * + * HiFi3 implementation equivalent to the generic mfcc_fill_prev_samples(); + * uses xtensa circular addressing for the source pointer. + * + * \param[in,out] buf Input circular buffer (Q1.15 mono). + * \param[out] prev_data Destination overlap buffer. + * \param[in] prev_data_length Number of samples to copy. + */ void mfcc_fill_prev_samples(struct mfcc_buffer *buf, int16_t *prev_data, int prev_data_length) { @@ -124,72 +77,16 @@ void mfcc_fill_prev_samples(struct mfcc_buffer *buf, int16_t *prev_data, buf->r_ptr = (void *)in; /* int16_t pointer but direct cast is not possible */ } -void mfcc_fill_fft_buffer(struct mfcc_state *state) -{ - struct mfcc_buffer *buf = &state->buf; - struct mfcc_fft *fft = &state->fft; - int idx = fft->fft_fill_start_idx; - ae_int16 *out = (ae_int16 *)&fft->fft_buf[idx].real; - ae_int16 *in = (ae_int16 *)state->prev_data; - ae_int16x4 sample; - const int buf_inc = sizeof(ae_int16); - const int fft_inc = sizeof(fft->fft_buf[0]); - int j; - - /* Copy overlapped samples from state buffer. Imaginary part of input - * remains zero. - */ - for (j = 0; j < state->prev_data_size; j++) { - AE_L16_XP(sample, in, buf_inc); - AE_S16_0_XP(sample, out, fft_inc); - } - - /* Copy hop size of new data from circular buffer */ - idx += state->prev_data_size; - in = (ae_int16 *)buf->r_ptr; - out = (ae_int16 *)&fft->fft_buf[idx].real; - set_circular_buf0(buf->addr, buf->end_addr); - for (j = 0; j < fft->fft_hop_size; j++) { - AE_L16_XC(sample, in, buf_inc); - AE_S16_0_XP(sample, out, fft_inc); - } - - buf->s_avail -= fft->fft_hop_size; - buf->s_free += fft->fft_hop_size; - 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; - in = (ae_int16 *)&fft->fft_buf[idx].real; - out = (ae_int16 *)state->prev_data; - for (j = 0; j < state->prev_data_size; j++) { - AE_L16_XP(sample, in, fft_inc); - AE_S16_0_XP(sample, out, buf_inc); - } -} - -#ifdef MFCC_NORMALIZE_FFT -int mfcc_normalize_fft_buffer(struct mfcc_state *state) -{ - struct mfcc_fft *fft = &state->fft; - ae_p16s *in = (ae_p16s *)&fft->fft_buf[fft->fft_fill_start_idx].real; - ae_int32x2 sample; - ae_int32x2 max = AE_ZERO32(); - const int fft_inc = sizeof(fft->fft_buf[0]); - int shift; - int j; - - for (j = 0; j < fft->fft_size; j++) { - /* load 16-bit data to middle of 32-bit container*/ - AE_L16M_XU(sample, in, fft_inc); - max = AE_MAXABS32S(max, sample); - } - shift = AE_NSAZ32_L(max) - 8;/* 16 bit data */ - shift = MAX(shift, 0); - shift = MIN(shift, MFCC_NORMALIZE_MAX_SHIFT); - return shift; -} -#endif +/** + * \brief HiFi3 window function application on the FFT input buffer. + * + * HiFi3 implementation equivalent to the generic mfcc_apply_window(); + * uses fractional multiply with saturating shift to produce Q1.31 + * FFT input data. + * + * \param[in,out] state MFCC state; \c state->fft.fft_buf is updated in-place. + * \param[in] input_shift Additional left shift applied to the windowed sample. + */ void mfcc_apply_window(struct mfcc_state *state, int input_shift) { struct mfcc_fft *fft = &state->fft; @@ -200,92 +97,18 @@ void mfcc_apply_window(struct mfcc_state *state, int input_shift) ae_int16x4 win; int j; -#if MFCC_FFT_BITS == 16 - ae_int16 *fft_in = (ae_int16 *)&fft->fft_buf[fft->fft_fill_start_idx].real; - ae_int16x4 sample; - - for (j = 0; j < fft->fft_size; j++) { - AE_L16_IP(sample, fft_in, 0); - AE_L16_XP(win, win_in, win_inc); - temp = AE_MULF16SS_00(sample, win); - temp = AE_SLAA32S(temp, input_shift); - sample = AE_ROUND16X4F32SASYM(temp, temp); - AE_S16_0_XP(sample, fft_in, fft_inc); - } -#else ae_int32 *fft_in = (ae_int32 *)&fft->fft_buf[fft->fft_fill_start_idx].real; ae_int32x2 sample; for (j = 0; j < fft->fft_size; j++) { AE_L32_IP(sample, fft_in, 0); AE_L16_XP(win, win_in, win_inc); - temp = AE_MULFP32X16X2RS_H(sample, win); + /* Data is 16-bit in 32-bit container, shift to Q1.31 for fractional multiply */ + sample = AE_SLAI32S(sample, 16); temp = AE_MULFP32X16X2RS_L(sample, win); temp = AE_SLAA32S(temp, input_shift); AE_S32_L_XP(temp, fft_in, fft_inc); } -#endif -} - -#if CONFIG_FORMAT_S16LE - -int16_t *mfcc_sink_copy_zero_s16(const struct audio_stream *sink, - int16_t *w_ptr, int samples) -{ - int i; - int n = samples >> 2; - int m = samples & 0x03; - ae_int16x4 *out = (ae_int16x4 *)w_ptr; - const int inc = sizeof(ae_int16); - ae_valign outu = AE_ZALIGN64(); - ae_int16x4 zero = AE_ZERO16(); - - set_circular_buf0(sink->addr, sink->end_addr); - - for (i = 0; i < n; i++) - AE_SA16X4_IC(zero, outu, out); - - AE_SA64POS_FP(outu, out); - /* process the left samples that less than 4 - * one by one to avoid memory access overrun - */ - for (i = 0; i < m ; i++) - AE_S16_0_XC(zero, (ae_int16 *)out, inc); - - return (int16_t *)out; -} - -int16_t *mfcc_sink_copy_data_s16(const struct audio_stream *sink, int16_t *w_ptr, - int samples, int16_t *r_ptr) -{ - int i; - int n = samples >> 2; - int m = samples & 0x03; - ae_int16x4 *out = (ae_int16x4 *)w_ptr; - ae_int16x4 *in = (ae_int16x4 *)r_ptr; - ae_valign outu = AE_ZALIGN64(); - ae_valign inu = AE_ZALIGN64(); - const int inc = sizeof(ae_int16); - ae_int16x4 in_sample; - - set_circular_buf0(sink->addr, sink->end_addr); - - inu = AE_LA64_PP(in); - for (i = 0; i < n; i++) { - AE_LA16X4_IP(in_sample, inu, in); - AE_SA16X4_IC(in_sample, outu, out); - } - AE_SA64POS_FP(outu, out); - /* process the left samples that less than 4 - * one by one to avoid memory access overrun - */ - for (i = 0; i < m ; i++) { - AE_L16_XP(in_sample, (ae_int16 *)in, inc); - AE_S16_0_XC(in_sample, (ae_int16 *)out, inc); - } - - return (int16_t *)out; } -#endif /* CONFIG_FORMAT_S16LE */ -#endif +#endif /* MFCC_HIFI3 */ diff --git a/src/audio/mfcc/mfcc_hifi4.c b/src/audio/mfcc/mfcc_hifi4.c index d033dfe36124..e86d066b408b 100644 --- a/src/audio/mfcc/mfcc_hifi4.c +++ b/src/audio/mfcc/mfcc_hifi4.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2023 Intel Corporation. All rights reserved. +// Copyright(c) 2023-2026 Intel Corporation. // // Author: Andrula Song <andrula.song@intel.com> @@ -9,8 +9,9 @@ #ifdef MFCC_HIFI4 #include <sof/audio/component.h> -#include <sof/audio/audio_stream.h> #include <sof/math/auditory.h> +#include <sof/math/icomplex16.h> +#include <sof/math/icomplex32.h> #include <sof/math/matrix.h> #include <sof/math/sqrt.h> #include <sof/math/trig.h> @@ -29,63 +30,21 @@ static inline void set_circular_buf0(const void *start, const void *end) AE_SETCEND0(end); } -/* Setup circular for buffer 1 */ -static inline void set_circular_buf1(const void *start, const void *end) -{ - AE_SETCBEGIN1(start); - AE_SETCEND1(end); -} - /* * MFCC algorithm code */ -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 *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; - ae_int16x4 sample; - ae_int32x2 temp; - ae_int16x4 coef; - ae_int16x4 delay; - const int in_inc = sizeof(ae_int16) * num_channels; - const int out_inc = sizeof(ae_int16); - int i; - - set_circular_buf1(buf->addr, buf->end_addr); - set_circular_buf0(source->addr, source->end_addr); - - /* Copy from source to pre-buffer for FFT. - * The pre-emphasis filter is done in this step. - */ - if (emph->enable) { - delay = emph->delay; - coef = emph->coef; - for (i = 0; i < frames; i++) { - AE_L16_XC(sample, in, in_inc); - - /* Q1.15 -> Q1.31 */ - temp = AE_CVT32X2F16_10(sample); - AE_MULAF16SS_00(temp, delay, coef); - delay = sample; - sample = AE_ROUND16X4F32SSYM(temp, temp); - AE_S16_0_XC1(sample, out, out_inc); - } - emph->delay = delay; - } else { - for (i = 0; i < frames; i++) { - AE_L16_XC(sample, in, in_inc); - AE_S16_0_XC1(sample, out, out_inc); - } - } - - buf->s_avail += frames; - buf->s_free -= frames; - buf->w_ptr = (int16_t *)out; -} +/** + * \brief HiFi4 copy of the overlap window from the input circular buffer. + * + * HiFi4/HiFi5 implementation equivalent to the generic + * mfcc_fill_prev_samples(); uses xtensa circular addressing for the + * source pointer. + * + * \param[in,out] buf Input circular buffer (Q1.15 mono). + * \param[out] prev_data Destination overlap buffer. + * \param[in] prev_data_length Number of samples to copy. + */ void mfcc_fill_prev_samples(struct mfcc_buffer *buf, int16_t *prev_data, int prev_data_length) { @@ -119,73 +78,16 @@ void mfcc_fill_prev_samples(struct mfcc_buffer *buf, int16_t *prev_data, buf->r_ptr = (int16_t *)in; } -void mfcc_fill_fft_buffer(struct mfcc_state *state) -{ - struct mfcc_buffer *buf = &state->buf; - struct mfcc_fft *fft = &state->fft; - int idx = fft->fft_fill_start_idx; - ae_int16 *out = (ae_int16 *)&fft->fft_buf[idx].real; - ae_int16 *in = (ae_int16 *)state->prev_data; - ae_int16x4 sample; - const int buf_inc = sizeof(ae_int16); - const int fft_inc = sizeof(fft->fft_buf[0]); - int j; - - /* Copy overlapped samples from state buffer. Imaginary part of input - * remains zero. - */ - for (j = 0; j < state->prev_data_size; j++) { - AE_L16_XP(sample, in, buf_inc); - AE_S16_0_XP(sample, out, fft_inc); - } - - /* Copy hop size of new data from circular buffer */ - idx += state->prev_data_size; - in = (ae_int16 *)buf->r_ptr; - out = (ae_int16 *)&fft->fft_buf[idx].real; - set_circular_buf0(buf->addr, buf->end_addr); - for (j = 0; j < fft->fft_hop_size; j++) { - AE_L16_XC(sample, in, buf_inc); - AE_S16_0_XP(sample, out, fft_inc); - } - - buf->s_avail -= fft->fft_hop_size; - buf->s_free += fft->fft_hop_size; - 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; - in = (ae_int16 *)&fft->fft_buf[idx].real; - out = (ae_int16 *)state->prev_data; - for (j = 0; j < state->prev_data_size; j++) { - AE_L16_XP(sample, in, fft_inc); - AE_S16_0_XP(sample, out, buf_inc); - } -} - -#ifdef MFCC_NORMALIZE_FFT -int mfcc_normalize_fft_buffer(struct mfcc_state *state) -{ - struct mfcc_fft *fft = &state->fft; - ae_p16s *in = (ae_p16s *)&fft->fft_buf[fft->fft_fill_start_idx].real; - ae_int32x2 sample; - ae_int32x2 max = AE_ZERO32(); - const int fft_inc = sizeof(fft->fft_buf[0]); - int shift; - int j; - - for (j = 0; j < fft->fft_size; j++) { - /* load 16-bit data to middle of 32-bit container*/ - AE_L16M_XU(sample, in, fft_inc); - max = AE_MAXABS32S(max, sample); - } - shift = AE_NSAZ32_L(max) - 8;/* 16 bit data */ - shift = MAX(shift, 0); - shift = MIN(shift, MFCC_NORMALIZE_MAX_SHIFT); - return shift; -} -#endif - +/** + * \brief HiFi4 window function application on the FFT input buffer. + * + * HiFi4/HiFi5 implementation equivalent to the generic + * mfcc_apply_window(); uses fractional multiply with saturating shift to + * produce Q1.31 FFT input data. + * + * \param[in,out] state MFCC state; \c state->fft.fft_buf is updated in-place. + * \param[in] input_shift Additional left shift applied to the windowed sample. + */ void mfcc_apply_window(struct mfcc_state *state, int input_shift) { struct mfcc_fft *fft = &state->fft; @@ -196,92 +98,18 @@ void mfcc_apply_window(struct mfcc_state *state, int input_shift) ae_int16x4 win; int j; -#if MFCC_FFT_BITS == 16 - ae_int16 *fft_in = (ae_int16 *)&fft->fft_buf[fft->fft_fill_start_idx].real; - ae_int16x4 sample; - - for (j = 0; j < fft->fft_size; j++) { - AE_L16_IP(sample, fft_in, 0); - AE_L16_XP(win, win_in, win_inc); - temp = AE_MULF16SS_00(sample, win); - temp = AE_SLAA32S(temp, input_shift); - sample = AE_ROUND16X4F32SASYM(temp, temp); - AE_S16_0_XP(sample, fft_in, fft_inc); - } -#else ae_int32 *fft_in = (ae_int32 *)&fft->fft_buf[fft->fft_fill_start_idx].real; ae_int32x2 sample; for (j = 0; j < fft->fft_size; j++) { AE_L32_IP(sample, fft_in, 0); AE_L16_XP(win, win_in, win_inc); - temp = AE_MULFP32X16X2RS_H(sample, win); + /* Data is 16-bit in 32-bit container, shift to Q1.31 for fractional multiply */ + sample = AE_SLAI32S(sample, 16); temp = AE_MULFP32X16X2RS_L(sample, win); temp = AE_SLAA32S(temp, input_shift); AE_S32_L_XP(temp, fft_in, fft_inc); } -#endif -} - -#if CONFIG_FORMAT_S16LE - -int16_t *mfcc_sink_copy_zero_s16(const struct audio_stream *sink, - int16_t *w_ptr, int samples) -{ - int i; - int n = samples >> 2; - int m = samples & 0x03; - ae_int16x4 *out = (ae_int16x4 *)w_ptr; - const int inc = sizeof(ae_int16); - ae_valign outu = AE_ZALIGN64(); - ae_int16x4 zero = AE_ZERO16(); - - set_circular_buf0(sink->addr, sink->end_addr); - - for (i = 0; i < n; i++) - AE_SA16X4_IC(zero, outu, out); - - AE_SA64POS_FP(outu, out); - /* process the left samples that less than 4 - * one by one to avoid memory access overrun - */ - for (i = 0; i < m ; i++) - AE_S16_0_XC(zero, (ae_int16 *)out, inc); - - return (int16_t *)out; -} - -int16_t *mfcc_sink_copy_data_s16(const struct audio_stream *sink, int16_t *w_ptr, - int samples, int16_t *r_ptr) -{ - int i; - int n = samples >> 2; - int m = samples & 0x03; - ae_int16x4 *out = (ae_int16x4 *)w_ptr; - ae_int16x4 *in = (ae_int16x4 *)r_ptr; - ae_valign outu = AE_ZALIGN64(); - ae_valign inu = AE_ZALIGN64(); - const int inc = sizeof(ae_int16); - ae_int16x4 in_sample; - - set_circular_buf0(sink->addr, sink->end_addr); - - inu = AE_LA64_PP(in); - for (i = 0; i < n; i++) { - AE_LA16X4_IP(in_sample, inu, in); - AE_SA16X4_IC(in_sample, outu, out); - } - AE_SA64POS_FP(outu, out); - /* process the left samples that less than 4 - * one by one to avoid memory access overrun - */ - for (i = 0; i < m ; i++) { - AE_L16_XP(in_sample, (ae_int16 *)in, inc); - AE_S16_0_XC(in_sample, (ae_int16 *)out, inc); - } - - return (int16_t *)out; } -#endif /* CONFIG_FORMAT_S16LE */ -#endif +#endif /* MFCC_HIFI4 */ diff --git a/src/audio/mfcc/mfcc_ipc4.c b/src/audio/mfcc/mfcc_ipc4.c new file mode 100644 index 000000000000..bb20d85e413b --- /dev/null +++ b/src/audio/mfcc/mfcc_ipc4.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +/** + * \file mfcc_ipc4.c + * \brief IPC4-specific functions for MFCC component. + * + * Provides VAD switch control notification to user space via the + * IPC4 module notification mechanism. + */ + +#include <sof/audio/mfcc/mfcc_comp.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include <sof/ipc/msg.h> +#include <sof/trace/trace.h> +#include <ipc4/base-config.h> +#include <ipc4/header.h> +#include <ipc4/module.h> +#include <ipc4/notification.h> +#include <rtos/string.h> +#include <errno.h> +#include <stdint.h> + +LOG_MODULE_DECLARE(mfcc, CONFIG_SOF_LOG_LEVEL); + +/** + * \brief Initialize IPC notification message for VAD switch control. + * + * Allocates and configures the IPC message used to send VAD state + * change notifications to user space via a switch control. + */ +int mfcc_ipc_notification_init(struct processing_module *mod) +{ + struct mfcc_comp_data *cd = module_get_private_data(mod); + 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 sof_ipc4_notify_module_data *msg_module_data; + struct sof_ipc4_control_msg_payload *msg_payload; + + 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; + cd->msg = ipc_msg_w_ext_init(msg_proto.header, msg_proto.extension, + sizeof(struct sof_ipc4_notify_module_data) + + sizeof(struct sof_ipc4_control_msg_payload) + + sizeof(struct sof_ipc4_ctrl_value_chan)); + if (!cd->msg) { + comp_err(dev, "Failed to initialize VAD notification"); + return -ENOMEM; + } + + msg_module_data = (struct sof_ipc4_notify_module_data *)cd->msg->tx_data; + msg_module_data->instance_id = IPC4_INST_ID(ipc_config->id); + msg_module_data->module_id = IPC4_MOD_ID(ipc_config->id); + msg_module_data->event_id = SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL | + SOF_IPC4_SWITCH_CONTROL_PARAM_ID; + msg_module_data->event_data_size = sizeof(struct sof_ipc4_control_msg_payload) + + sizeof(struct sof_ipc4_ctrl_value_chan); + + msg_payload = (struct sof_ipc4_control_msg_payload *)msg_module_data->event_data; + msg_payload->id = MFCC_CTRL_INDEX_VAD; + msg_payload->num_elems = 1; + msg_payload->chanv[0].channel = 0; + + comp_dbg(dev, "VAD notification init: instance_id = 0x%08x, module_id = 0x%08x", + msg_module_data->instance_id, msg_module_data->module_id); + return 0; +} + +/** + * \brief Send VAD switch control notification to user space. + * \param mod Processing module. + * \param val VAD value: 1 = speech, 0 = silence. + */ +void mfcc_send_vad_notification(struct processing_module *mod, uint32_t val) +{ + struct mfcc_comp_data *cd = module_get_private_data(mod); + struct sof_ipc4_notify_module_data *msg_module_data; + struct sof_ipc4_control_msg_payload *msg_payload; + + if (!cd->msg) + return; + + msg_module_data = (struct sof_ipc4_notify_module_data *)cd->msg->tx_data; + msg_payload = (struct sof_ipc4_control_msg_payload *)msg_module_data->event_data; + msg_payload->chanv[0].value = val; + ipc_msg_send(cd->msg, NULL, false); +} + +int mfcc_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) +{ + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + struct mfcc_comp_data *cd = module_get_private_data(mod); + struct sof_ipc4_control_msg_payload *ctl; + + comp_info(mod->dev, "entry"); + + switch (config_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + ctl = (struct sof_ipc4_control_msg_payload *)fragment; + if (ctl->id == MFCC_CTRL_INDEX_VAD && ctl->num_elems == 1) { + ctl->chanv[0].value = cd->vad_prev ? 1 : 0; + *data_offset_size = sizeof(*ctl) + sizeof(ctl->chanv[0]); + return 0; + } + return -EINVAL; + default: + return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); + } +} + +int mfcc_set_config(struct processing_module *mod, uint32_t config_id, + enum module_cfg_fragment_position pos, uint32_t data_offset_size, + const uint8_t *fragment, size_t fragment_size, uint8_t *response, + size_t response_size) +{ + struct mfcc_comp_data *cd = module_get_private_data(mod); + + comp_info(mod->dev, "entry"); + + switch (config_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + /* VAD switch is read-only, ignore set requests */ + return 0; + default: + return comp_data_blob_set(cd->model_handler, pos, data_offset_size, + fragment, fragment_size); + } +} diff --git a/src/audio/mfcc/mfcc_setup.c b/src/audio/mfcc/mfcc_setup.c index 7f88e0b6eb9b..1d062b2a5206 100644 --- a/src/audio/mfcc/mfcc_setup.c +++ b/src/audio/mfcc/mfcc_setup.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2022 Intel Corporation. All rights reserved. +// Copyright(c) 2022-2026 Intel Corporation. // // Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> @@ -8,6 +8,8 @@ #include <sof/audio/component.h> #include <sof/audio/audio_stream.h> #include <sof/math/auditory.h> +#include <sof/math/icomplex16.h> +#include <sof/math/icomplex32.h> #include <sof/math/trig.h> #include <sof/math/window.h> #include <sof/trace/trace.h> @@ -16,6 +18,8 @@ #include <stddef.h> #include <stdint.h> +#include <sof/audio/mfcc/mfcc_vad.h> + /* Definitions for cepstral lifter */ #define PI_Q23 Q_CONVERT_FLOAT(3.1415926536, 23) #define TWO_PI_Q23 Q_CONVERT_FLOAT(6.2831853072, 23) @@ -23,6 +27,13 @@ LOG_MODULE_REGISTER(mfcc_setup, CONFIG_SOF_LOG_LEVEL); +/** + * \brief Initialize an MFCC input circular buffer descriptor. + * + * \param[out] buf Circular buffer descriptor to initialize. + * \param[in] base Backing storage (Q1.15 samples). + * \param[in] size Buffer length in samples. + */ static void mfcc_init_buffer(struct mfcc_buffer *buf, int16_t *base, int size) { buf->addr = base; @@ -34,6 +45,15 @@ static void mfcc_init_buffer(struct mfcc_buffer *buf, int16_t *base, int size) buf->s_length = size; } +/** + * \brief Fill \c state->window with the configured analysis window. + * + * \param[in,out] state MFCC state; \c state->window is written, sized + * \c state->fft.fft_size and in Q1.15. + * \param[in] name Window type identifier from the MFCC configuration. + * + * \return 0 on success, -EINVAL for an unsupported window type. + */ static int mfcc_get_window(struct mfcc_state *state, enum sof_mfcc_fft_window_type name) { struct mfcc_fft *fft = &state->fft; @@ -48,10 +68,12 @@ static int mfcc_get_window(struct mfcc_state *state, enum sof_mfcc_fft_window_ty case MFCC_HAMMING_WINDOW: win_hamming_16b(state->window, fft->fft_size); return 0; + case MFCC_HANN_WINDOW: + win_hann_16b(state->window, fft->fft_size); + return 0; case MFCC_POVEY_WINDOW: win_povey_16b(state->window, fft->fft_size); return 0; - default: return -EINVAL; } @@ -65,7 +87,7 @@ static int mfcc_get_window(struct mfcc_state *state, enum sof_mfcc_fft_window_ty * coef[i] = 1.0 + 0.5 * lifter * sin(pi * i / lifter), i = 0 to num_ceps-1 */ -static int mfcc_get_cepstral_lifter(struct mfcc_cepstral_lifter *cl) +static int mfcc_get_cepstral_lifter(struct processing_module *mod, struct mfcc_cepstral_lifter *cl) { int32_t inv_cepstral_lifter; int32_t val; @@ -75,7 +97,7 @@ static int mfcc_get_cepstral_lifter(struct mfcc_cepstral_lifter *cl) if (cl->num_ceps > DCT_MATRIX_SIZE_MAX) return -EINVAL; - cl->matrix = mat_matrix_alloc_16b(1, cl->num_ceps, 9); /* Use Q7.9 */ + cl->matrix = mod_mat_matrix_alloc_16b(mod, 1, cl->num_ceps, 9); /* Use Q7.9 */ if (!cl->matrix) return -ENOMEM; @@ -97,6 +119,24 @@ static int mfcc_get_cepstral_lifter(struct mfcc_cepstral_lifter *cl) /* TODO mfcc setup needs to use the config blob, not hard coded parameters. * Also this is a too long function. Split to STFT, Mel filter, etc. parts. */ +/** + * \brief Allocate and initialize MFCC runtime state from the config blob. + * + * Validates the supplied configuration, allocates the input circular + * buffer, overlap buffer, window vector, FFT scratch, Mel filterbank, + * DCT/cepstral lifter matrices (when \c num_ceps > 0) and VAD state + * (when enabled). All allocations are freed on any failure path. + * + * \param[in,out] mod Processing module that owns the MFCC instance. + * \param[in] max_frames Maximum input frames the pipeline will deliver + * per call; sizes the input buffer. + * \param[in] sample_rate Input sample rate in Hz; must match + * \c config->sample_frequency. + * \param[in] channels Number of channels in the input stream. + * + * \return 0 on success or a negative error code (\c -EINVAL for bad + * configuration, \c -ENOMEM for an allocation failure). + */ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, int channels) { struct mfcc_comp_data *cd = module_get_private_data(mod); @@ -106,25 +146,66 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i struct mfcc_fft *fft = &state->fft; struct psy_mel_filterbank *fb = &state->melfb; struct dct_plan_16 *dct = &state->dct; + int mel_log_32_space; + int max_out_per_hop; + int out_per_hop; + int sink_per_hop; int ret; - comp_dbg(dev, "mfcc_setup()"); + comp_dbg(dev, "entry"); /* Check size */ if (config->size != sizeof(struct sof_mfcc_config)) { - comp_err(dev, "mfcc_setup(): Illegal configuration size %d.", config->size); + comp_err(dev, "Illegal configuration size %d.", config->size); return -EINVAL; } /* Check currently hard-coded features to match configuration request */ if (!config->round_to_power_of_two || !config->snip_edges || config->subtract_mean || config->use_energy) { - comp_err(dev, "mfcc_setup(): Can't change currently hard-coded features"); + comp_err(dev, "Can't change currently hard-coded features"); + return -EINVAL; + } + + if (sample_rate <= 0 || sample_rate > MFCC_MAX_SAMPLE_RATE) { + comp_err(dev, "Sample rate %d out of range (1..%d Hz)", + sample_rate, MFCC_MAX_SAMPLE_RATE); return -EINVAL; } if (config->sample_frequency != sample_rate) { - comp_err(dev, "mfcc_setup(): Config sample_frequency does not match stream"); + comp_err(dev, "Config sample_frequency does not match stream"); + return -EINVAL; + } + + /* Validate configuration parameters up front so that runtime code + * (executed every hop in the DSP) can skip divide-by-zero / range + * checks. Any later division by these fields is safe after this. + */ + if (config->frame_length <= 0 || config->frame_shift <= 0 || + config->frame_shift > config->frame_length) { + comp_err(dev, "Illegal frame_length %d or frame_shift %d", + config->frame_length, config->frame_shift); + return -EINVAL; + } + + if (config->num_mel_bins <= 0) { + comp_err(dev, "Illegal num_mel_bins %d", config->num_mel_bins); + return -EINVAL; + } + + if (config->num_ceps < 0) { + comp_err(dev, "Illegal num_ceps %d", config->num_ceps); + return -EINVAL; + } + + /* cepstral_lifter is used as a divisor in mfcc_get_cepstral_lifter(). + * Either disabled (== 0) or strictly positive. Negative values are + * rejected to keep runtime math (every hop in DSP) free of guards. + */ + if (config->num_ceps > 0 && config->cepstral_lifter < 0) { + comp_err(dev, "Illegal cepstral_lifter %d (must be >= 0)", + config->cepstral_lifter); return -EINVAL; } @@ -133,14 +214,13 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i state->low_freq = config->low_freq; state->high_freq = (config->high_freq == 0) ? (sample_rate >> 1) : config->high_freq; if (state->low_freq > state->high_freq) { - comp_err(dev, "mfcc_setup(): Config high_freq must be larger than low_freq"); + comp_err(dev, "Config high_freq must be larger than low_freq"); return -EINVAL; } - comp_info(dev, "mfcc_setup(), source_channel = %d, stream_channels = %d", - config->channel, channels); - if (config->channel >= channels) { - comp_err(dev, "mfcc_setup(): Illegal channel"); + if (config->channel >= channels || (config->channel < 0 && channels != 1)) { + comp_err(dev, "Illegal source_channel %d for stream channels %d", config->channel, + channels); return -EINVAL; } @@ -149,6 +229,7 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i else state->source_channel = config->channel; + state->mmax = (int32_t)config->mmax_init << 16; /* Q9.7 -> Q9.23 */ state->emph.enable = config->preemphasis_coefficient > 0; state->emph.coef = -config->preemphasis_coefficient; /* Negate config parameter */ fft->fft_size = config->frame_length; @@ -156,7 +237,7 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i fft->fft_hop_size = config->frame_shift; fft->half_fft_size = (fft->fft_padded_size >> 1) + 1; - comp_info(dev, "mfcc_setup(), emphasis = %d, fft_size = %d, fft_padded_size = %d, fft_hop_size = %d", + comp_info(dev, "emphasis = %d, fft_size = %d, fft_padded_size = %d, fft_hop_size = %d", config->preemphasis_coefficient, fft->fft_size, fft->fft_padded_size, fft->fft_hop_size); @@ -168,13 +249,12 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i state->sample_buffers_size = sizeof(int16_t) * (state->buffer_size + state->prev_data_size + fft->fft_size); - comp_info(dev, "mfcc_setup(), buffer_size = %d, prev_size = %d", + comp_info(dev, "buffer_size = %d, prev_size = %d", state->buffer_size, state->prev_data_size); - state->buffers = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - state->sample_buffers_size); + state->buffers = mod_zalloc(mod, state->sample_buffers_size); if (!state->buffers) { - comp_err(dev, "mfcc_setup(): Failed buffer allocate"); + comp_err(dev, "Failed buffer allocate"); ret = -ENOMEM; goto exit; } @@ -184,21 +264,17 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i state->window = state->prev_data + state->prev_data_size; /* Allocate buffers for FFT input and output data */ -#if MFCC_FFT_BITS == 16 - fft->fft_buffer_size = fft->fft_padded_size * sizeof(struct icomplex16); -#else fft->fft_buffer_size = fft->fft_padded_size * sizeof(struct icomplex32); -#endif - fft->fft_buf = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, fft->fft_buffer_size); + fft->fft_buf = mod_zalloc(mod, fft->fft_buffer_size); if (!fft->fft_buf) { - comp_err(dev, "mfcc_setup(): Failed FFT buffer allocate"); + comp_err(dev, "Failed FFT buffer allocate"); ret = -ENOMEM; goto free_buffers; } - fft->fft_out = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, fft->fft_buffer_size); + fft->fft_out = mod_zalloc(mod, fft->fft_buffer_size); if (!fft->fft_out) { - comp_err(dev, "mfcc_setup(): Failed FFT output allocate"); + comp_err(dev, "Failed FFT output allocate"); ret = -ENOMEM; goto free_fft_buf; } @@ -206,24 +282,24 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i fft->fft_fill_start_idx = 0; /* From config pad_type */ /* Setup FFT */ - fft->fft_plan = fft_plan_new(fft->fft_buf, fft->fft_out, fft->fft_padded_size, - MFCC_FFT_BITS); + fft->fft_plan = mod_fft_plan_new(mod, fft->fft_buf, fft->fft_out, fft->fft_padded_size, + MFCC_FFT_BITS); if (!fft->fft_plan) { - comp_err(dev, "mfcc_setup(): Failed FFT init"); + comp_err(dev, "Failed FFT init"); ret = -EINVAL; goto free_fft_out; } - comp_info(dev, "mfcc_setup(), window = %d, num_mel_bins = %d, num_ceps = %d, norm = %d", + comp_info(dev, "window = %d, num_mel_bins = %d, num_ceps = %d, norm = %d", config->window, config->num_mel_bins, config->num_ceps, config->norm); - comp_info(dev, "mfcc_setup(), low_freq = %d, high_freq = %d", + comp_info(dev, "low_freq = %d, high_freq = %d", state->low_freq, state->high_freq); /* Setup window */ ret = mfcc_get_window(state, config->window); if (ret < 0) { - comp_err(dev, "mfcc_setup(): Failed Window function"); - goto free_fft_out; + comp_err(dev, "Failed Window function"); + goto free_fft_plan; } /* Setup Mel auditory filterbank. FFT input and output buffers are used @@ -242,42 +318,61 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i fb->scratch_data2 = (int16_t *)fft->fft_out; fb->scratch_length1 = fft->fft_buffer_size / sizeof(int16_t); fb->scratch_length2 = fft->fft_buffer_size / sizeof(int16_t); - ret = psy_get_mel_filterbank(fb); - if (ret < 0) { - comp_err(dev, "mfcc_setup(): Failed Mel filterbank"); - goto free_fft_out; - } - - /* Setup DCT */ - dct->num_in = config->num_mel_bins; - dct->num_out = config->num_ceps; - dct->type = (enum dct_type)config->dct; - dct->ortho = true; - ret = dct_initialize_16(dct); + ret = mod_psy_get_mel_filterbank(mod, fb); if (ret < 0) { - comp_err(dev, "mfcc_setup(): Failed DCT init"); - goto free_melfb_data; + comp_err(dev, "Failed Mel filterbank"); + goto free_fft_plan; } - state->lifter.num_ceps = config->num_ceps; - state->lifter.cepstral_lifter = config->cepstral_lifter; /* Q7.9 max 64.0*/ - ret = mfcc_get_cepstral_lifter(&state->lifter); - if (ret < 0) { - comp_err(dev, "mfcc_setup(): Failed cepstral lifter"); - goto free_dct_matrix; + /* Setup DCT and cepstral lifter only when num_ceps > 0. + * When num_ceps is zero, skip DCT/lifter and output Mel + * log spectra directly. + */ + if (config->num_ceps > 0) { + dct->num_in = config->num_mel_bins; + dct->num_out = config->num_ceps; + dct->type = (enum dct_type)config->dct; + dct->ortho = true; + ret = mod_dct_initialize_16(mod, dct); + if (ret < 0) { + comp_err(dev, "Failed DCT init"); + goto free_melfb_data; + } + + state->lifter.num_ceps = config->num_ceps; + state->lifter.cepstral_lifter = config->cepstral_lifter; /* Q7.9 max 64.0*/ + if (state->lifter.cepstral_lifter > 0) { + ret = mfcc_get_cepstral_lifter(mod, &state->lifter); + if (ret < 0) { + comp_err(dev, "Failed cepstral lifter"); + goto free_dct_matrix; + } + } else { + state->lifter.matrix = NULL; + } + + state->mel_only = false; + } else { + comp_info(dev, "num_ceps is 0, Mel log spectra output mode"); + dct->num_in = config->num_mel_bins; + dct->num_out = 0; + dct->matrix = NULL; + state->lifter.matrix = NULL; + state->mel_only = true; } /* Scratch overlay during runtime * - * +--------------------------------------------------------+ - * | 1. fft_buf[], 16 bits,size x 4, e.g. 512 -> 2048 bytes | - * +-------------------------------------+------------------+ - * | 3. power_spectra[], | - * | 32 bits, e.g. x257 -> 1028 bytes | - * +-------------------------------------+ + * +------------------------------------------------------------+ + * | 1. fft_buf[], 32 bits, size x 8, e.g. 512 -> 4096 bytes | + * +-------------------------------------+----------------------+ + * | 3. power_spectra[], | 6. mel_log_32[], | + * | 32 bits, e.g. x257 -> 1028 bytes | 32 bits, e.g. x80 | + * | | 320 bytes | + * +-------------------------------------+----------------------+ * * +---------------------------------------------------------------------------------+ - * | 2. fft_out[], 16 bits,size x 4, e.g. 512 -> 2048 bytes | + * | 2. fft_out[], 32 bits, size x 8, e.g. 512 -> 4096 bytes | * +----------------------------------+----------------------------------+-----------+ * | 4. mel_spectra[], | 5. cepstral_coef[], | * | 16 bits, e.g. x23 -> 46 bytes | 16 bits, e.g. 13x -> 26 bytes | @@ -287,43 +382,152 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i /* Use FFT buffer as scratch for later computed data */ state->power_spectra = (int32_t *)&fft->fft_buf[0]; + state->mel_log_32 = &state->power_spectra[fft->half_fft_size]; + + /* Check that mel_log_32 fits in the remaining fft_buf scratch space */ + mel_log_32_space = (int)(fft->fft_buffer_size / sizeof(int32_t)) - fft->half_fft_size; + + if (config->num_mel_bins > mel_log_32_space) { + comp_err(dev, "num_mel_bins %d exceeds mel_log_32 scratch space %d", + config->num_mel_bins, mel_log_32_space); + ret = -EINVAL; + goto free_lifter; + } + state->mel_spectra = (struct mat_matrix_16b *)&fft->fft_out[0]; - state->cepstral_coef = (struct mat_matrix_16b *) - &state->mel_spectra->data[state->dct.num_in]; + if (!state->mel_only) { + state->cepstral_coef = + (struct mat_matrix_16b *)&state->mel_spectra->data[state->dct.num_in]; + } else { + state->cepstral_coef = NULL; + } + + /* Allocate output buffer for multi-period output. Size allows for + * current output data plus leftover from previous period. + */ + max_out_per_hop = state->mel_only ? dct->num_in : dct->num_out; + + /* Check that output data can be drained within the periods spanned by one + * FFT hop. Each hop consumes fft_hop_size input samples and produces + * max_out_per_hop + header int32_t output values. The sink provides + * at least fft_hop_size * channels int32_t samples per hop (worst case s32). + * If output exceeds this, data accumulates and will eventually overflow. + * This check is not needed in compress output mode where only actual data + * bytes are committed without zero padding. + */ + out_per_hop = max_out_per_hop + sizeof(state->header) / sizeof(int32_t); + sink_per_hop = fft->fft_hop_size * channels; + + if (!config->compress_output && out_per_hop > sink_per_hop) { + comp_err(dev, "Output %d int32 per hop exceeds sink capacity %d (hop %d x ch %d)", + out_per_hop, sink_per_hop, fft->fft_hop_size, channels); + ret = -EINVAL; + goto free_lifter; + } + + /* Staging buffer for pending output. Decouples committed data from + * the FFT scratch (mel_log_32) so the next STFT hop can run while a + * previous frame is still being drained across multiple periods. + */ + state->out_stage_size = max_out_per_hop; + state->out_stage = mod_zalloc(mod, max_out_per_hop * sizeof(int32_t)); + if (!state->out_stage) { + comp_err(dev, "Failed output staging buffer allocate"); + ret = -ENOMEM; + goto free_lifter; + } /* Set initial state for STFT */ state->waiting_fill = true; state->prev_samples_valid = false; + state->header_pending = false; + state->hop_count = 0; + memset(&state->header, 0, sizeof(state->header)); + state->header.magic = MFCC_MAGIC; + state->out_data_ptr = NULL; + state->out_remain = 0; + state->vad_silence_count = 0; + state->dtx_trailing_silence = config->dtx_trailing_silence_hops; + state->dtx_silence_interval = config->dtx_silence_hops_interval; + state->dtx_silence_counter = 0; + + if (config->enable_vad) { + ret = mfcc_vad_init(&cd->vad, config->num_mel_bins, sample_rate, mod); + if (ret < 0) { + comp_err(dev, "Failed VAD init"); + goto free_out_stage; + } + } - comp_dbg(dev, "mfcc_setup(), done"); + comp_dbg(dev, "done"); return 0; +free_out_stage: + mod_free(mod, state->out_stage); + +free_lifter: + mod_free(mod, state->lifter.matrix); + free_dct_matrix: - rfree(state->dct.matrix); + mod_free(mod, state->dct.matrix); free_melfb_data: - rfree(fb->data); + mod_free(mod, fb->data); + +free_fft_plan: + mod_fft_plan_free(mod, fft->fft_plan); free_fft_out: - rfree(fft->fft_out); + mod_free(mod, fft->fft_out); free_fft_buf: - rfree(fft->fft_buf); + mod_free(mod, fft->fft_buf); free_buffers: - rfree(state->buffers); + mod_free(mod, state->buffers); exit: return ret; } -void mfcc_free_buffers(struct mfcc_comp_data *cd) +/** + * \brief Free a single MFCC allocation and clear the caller's pointer. + * + * \param[in,out] mod Processing module owning the allocation. + * \param[in,out] ptr Address of the pointer to free; set to NULL on return. + */ +static void mfcc_free_and_null(struct processing_module *mod, void **ptr) +{ + mod_free(mod, *ptr); + *ptr = NULL; +} + +/* Free MFCC buffers to prevent leaks on reset->prepare cycles. + * mfcc_free_buffers() NULLs the pointers after free. + */ +/** + * \brief Release all MFCC runtime allocations. + * + * Frees FFT plan, scratch buffers, input/overlap buffers, Mel + * filterbank data, DCT matrix, cepstral lifter matrix, and VAD state. + * All freed pointers are set to NULL so the function is safe to call + * across repeated reset/prepare cycles. + * + * \param[in,out] mod Processing module that owns the MFCC instance. + */ +void mfcc_free_buffers(struct processing_module *mod) { - fft_plan_free(cd->state.fft.fft_plan); - rfree(cd->state.fft.fft_buf); - rfree(cd->state.fft.fft_out); - rfree(cd->state.buffers); - rfree(cd->state.melfb.data); - rfree(cd->state.dct.matrix); - rfree(cd->state.lifter.matrix); + struct mfcc_comp_data *cd = module_get_private_data(mod); + + mod_fft_plan_free(mod, cd->state.fft.fft_plan); + cd->state.fft.fft_plan = NULL; + mfcc_free_and_null(mod, (void **)&cd->state.fft.fft_buf); + mfcc_free_and_null(mod, (void **)&cd->state.fft.fft_out); + mfcc_free_and_null(mod, (void **)&cd->state.buffers); + mfcc_free_and_null(mod, (void **)&cd->state.melfb.data); + mfcc_free_and_null(mod, (void **)&cd->state.dct.matrix); + mfcc_free_and_null(mod, (void **)&cd->state.lifter.matrix); + mfcc_free_and_null(mod, (void **)&cd->state.out_stage); + mfcc_free_and_null(mod, (void **)&cd->vad.noise_floor); + mfcc_free_and_null(mod, (void **)&cd->vad.weights); } diff --git a/src/audio/mfcc/mfcc_vad.c b/src/audio/mfcc/mfcc_vad.c new file mode 100644 index 000000000000..f44a89a7dea3 --- /dev/null +++ b/src/audio/mfcc/mfcc_vad.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +/** + * \file mfcc_vad.c + * \brief Voice Activity Detection based on Mel spectrum energy. + * + * Implements a VAD that tracks per-bin noise floor and computes a + * speech-frequency weighted energy above the floor. Speech is declared + * when the weighted delta exceeds a threshold, with hangover to prevent + * rapid toggling. + */ + +#include <sof/audio/mfcc/mfcc_vad.h> + +#include <sof/audio/component.h> +#include <sof/audio/format.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/math/auditory.h> +#include <sof/trace/trace.h> +#include <errno.h> +#include <stddef.h> + +LOG_MODULE_DECLARE(mfcc, CONFIG_SOF_LOG_LEVEL); + +/** + * \brief A-weighting table: 1/3 octave band center frequencies in Hz (Q16.0). + * + * From IEC 61672-1:2013, source: + * https://acousticalengineer.com/a-weighting-table/ + */ +#define A_WEIGHT_TABLE_SIZE 36 + +static const int16_t a_weight_hz[A_WEIGHT_TABLE_SIZE] = { + 6, 8, 10, 13, 16, 20, 25, 32, + 40, 50, 63, 80, 100, 125, 160, 200, + 250, 315, 400, 500, 630, 800, 1000, 1250, + 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000, + 10000, 12500, 16000, 20000, +}; + +/** + * \brief A-weighting linear amplitude, scaled so peak (at 2500 Hz) maps + * to INT16_MAX (32767). Original dB values converted via + * 10^(dB/20) then scaled by 32767 / max. + */ +static const int16_t a_weight_lin[A_WEIGHT_TABLE_SIZE] = { + 2, 4, 9, 19, 43, 85, 162, 299, + 531, 862, 1382, 2140, 3129, 4370, 6172, 8136, + 10362, 13196, 16234, 19518, 22669, 25730, 28212, 30230, + 31655, 32392, 32767, 32392, 31655, 30230, 27889, 24856, + 21156, 17196, 13045, 9670, +}; + +/** + * \brief Compute A-weighted speech-frequency emphasis weights for Mel bins. + * + * Weights are computed by linearly interpolating the A-weighting table + * at each Mel bin center frequency. Output weights are in Q1.15 and + * sum to approximately 2^15. + * + * \param[out] weights Output weight array. + * \param[in] num_mel Number of Mel bins. + * \param[in] sample_rate Sample rate in Hz. + */ +static void mfcc_vad_build_weights(int16_t *weights, int num_mel, int32_t sample_rate) +{ + int32_t scaled, num; + int32_t sum = 0; + int16_t f_hz, f0, f1, w, w0, w1, den; + int16_t mel_end = psy_hz_to_mel((int16_t)(sample_rate / 2)); /* Nyquist (max 32767 Hz) in Mel */ + int16_t mel_step = mel_end / (num_mel + 1); + int i, j; + + if (!num_mel) + return; + + for (i = 0; i < num_mel; i++) { + f_hz = psy_mel_to_hz((int16_t)((i + 1) * mel_step)); + + /* Find the table interval containing f_hz and interpolate */ + if (f_hz <= a_weight_hz[0]) { + w = a_weight_lin[0]; + } else if (f_hz >= a_weight_hz[A_WEIGHT_TABLE_SIZE - 1]) { + w = a_weight_lin[A_WEIGHT_TABLE_SIZE - 1]; + } else { + /* Find j such that a_weight_hz[j] <= f_hz < a_weight_hz[j+1] */ + for (j = 0; j < A_WEIGHT_TABLE_SIZE - 2; j++) { + if (f_hz < a_weight_hz[j + 1]) + break; + } + + /* Linear interpolation: w = w0 + (w1 - w0) * (f - f0) / (f1 - f0) */ + f0 = a_weight_hz[j]; + f1 = a_weight_hz[j + 1]; + w0 = a_weight_lin[j]; + w1 = a_weight_lin[j + 1]; + num = (int32_t)(w1 - w0) * (f_hz - f0); + den = f1 - f0; + w = w0 + (int16_t)(num / den); + } + + weights[i] = w; + sum += w; + } + + /* Normalize weights so they sum to 1.0 */ + for (i = 0; i < num_mel; i++) { + scaled = ((int32_t)weights[i] << 16) / sum; /* Q1.16 */ + weights[i] = (int16_t)Q_SHIFT_RND(scaled, 16, 15); /* Round to Q1.15 */ + } +} + +int mfcc_vad_init(struct mfcc_vad_state *vad, int num_mel_bins, int32_t sample_rate, + struct processing_module *mod) +{ + if (!vad) + return -EINVAL; + + if (num_mel_bins <= 0) + return -EINVAL; + + vad->num_mel_bins = num_mel_bins; + vad->energy_threshold = MFCC_VAD_ENERGY_THRESHOLD; + vad->noise_rise_alpha_slow = MFCC_VAD_NOISE_RISE_ALPHA; + vad->noise_rise_alpha_fast = MFCC_VAD_NOISE_RISE_ALPHA_FAST; + vad->hangover_max = MFCC_VAD_HANGOVER_FRAMES; + vad->hangover_counter = 0; + vad->init_frames = MFCC_VAD_NOISE_INIT_FRAMES; + vad->frame_count = 0; + vad->is_speech = false; + vad->initialized = false; + + /* Allocate per-bin noise floor */ + vad->noise_floor = mod_zalloc(mod, num_mel_bins * sizeof(int32_t)); + if (!vad->noise_floor) + return -ENOMEM; + + /* Allocate and compute per-bin weights */ + vad->weights = mod_zalloc(mod, num_mel_bins * sizeof(int16_t)); + if (!vad->weights) { + mod_free(mod, vad->noise_floor); + vad->noise_floor = NULL; + return -ENOMEM; + } + + mfcc_vad_build_weights(vad->weights, num_mel_bins, sample_rate); + return 0; +} + +int mfcc_vad_update(struct mfcc_vad_state *vad, const int32_t *mel_log) +{ + int64_t signal_energy = 0; + int64_t noise_energy = 0; + int64_t energy_delta = 0; + int32_t delta; + int32_t p; + int16_t alpha; + int i; + + if (!vad || !mel_log) + return 0; + + /* Stop incrementing after init phase to avoid wrap-around restarting fast alpha. + * Select rise alpha based on convergence phase. + */ + if (vad->frame_count < vad->init_frames) { + vad->frame_count++; + alpha = vad->noise_rise_alpha_fast; + } else { + alpha = vad->noise_rise_alpha_slow; + } + + /* Initialize noise floor to first frame */ + if (!vad->initialized) { + for (i = 0; i < vad->num_mel_bins; i++) + vad->noise_floor[i] = mel_log[i]; + + vad->initialized = true; + } + + /* Update noise floor: follow down instantly, rise slowly */ + for (i = 0; i < vad->num_mel_bins; i++) { + if (mel_log[i] < vad->noise_floor[i]) { + /* Instant follow-down */ + vad->noise_floor[i] = mel_log[i]; + } else { + /* Slow rise: floor += alpha * (mel - floor) + * Q9.23 + Q1.15 * Q9.23 => need Q9.23 result + * alpha is Q1.15, delta is Q9.23 + */ + delta = mel_log[i] - vad->noise_floor[i]; + p = (int32_t)Q_MULTSR_32X32((int64_t)alpha, delta, 15, 23, 23); + vad->noise_floor[i] += p; + } + } + + /* Compute weighted signal energy and noise floor energy. + * weights are Q1.15, mel values are Q9.23 + * Products are Q10.38, accumulate in int64_t then shift to Q9.23 + */ + + for (i = 0; i < vad->num_mel_bins; i++) { + signal_energy += (int64_t)vad->weights[i] * mel_log[i]; + noise_energy += (int64_t)vad->weights[i] * vad->noise_floor[i]; + } + + vad->energy = sat_int32(Q_SHIFT_RND(signal_energy, 38, 23)); + vad->noise_energy = sat_int32(Q_SHIFT_RND(noise_energy, 38, 23)); + energy_delta = vad->energy - vad->noise_energy; + + /* Round accumulated energy from Q10.38 to Q9.23, saturate to int32 */ + if (energy_delta > vad->energy_threshold) { + vad->hangover_counter = vad->hangover_max; + vad->is_speech = true; + } else { + if (vad->hangover_counter > 0) { + vad->hangover_counter--; + vad->is_speech = true; + } else { + vad->is_speech = false; + } + } + + return vad->is_speech ? 1 : 0; +} diff --git a/src/audio/mfcc/tune/README.md b/src/audio/mfcc/tune/README.md new file mode 100644 index 000000000000..422f849b56b4 --- /dev/null +++ b/src/audio/mfcc/tune/README.md @@ -0,0 +1,259 @@ +# SOF MFCC Tuning Tools + +This directory contains a tool to create configuration blob for SOF +MFCC component. It's simply run in Matlab or Octave with command +`setup_mfcc`. The MFCC configuration parameters can be edited from the +script. + +## Testbench run + +The configuration can be test run with testbench. First the test topologies +need to be created with `scripts/build-tools.sh -t`. Next the testbench +is built with `scripts/rebuild-testbench.sh`. + +Once the previous steps are done, a sample wav file can be processed +with script `run_mfcc.sh`. The script converts the input to raw 16 kHz +stereo format and runs the testbench for S16, S24, and S32 bit depths, +producing both cepstral coefficient (MFCC) and Mel spectrogram outputs. + +``` +./run_mfcc.sh /usr/share/sounds/alsa/Front_Center.wav +``` + +Output files from host testbench: + +| File | Content | +|------|---------| +| `mfcc_s16.raw`, `mfcc_s24.raw`, `mfcc_s32.raw` | Cepstral coefficients | +| `mel_s16.raw`, `mel_s24.raw`, `mel_s32.raw` | Mel spectrogram | + +If the `XTENSA_PATH` environment variable is set, the script also runs +the Xtensa build of the testbench (via `xt-run`) and produces additional +output files prefixed with `xt_`: + +| File | Content | +|------|---------| +| `xt_mfcc_s16.raw`, `xt_mfcc_s24.raw`, `xt_mfcc_s32.raw` | Cepstral coefficients | +| `xt_mel_s16.raw`, `xt_mel_s24.raw`, `xt_mel_s32.raw` | Mel spectrogram | + +## Decoding and Plotting + +All output files can be decoded and plotted at once in Matlab or Octave +with the `decode_all.m` script: + +```matlab +decode_all +``` + +This calls `decode_ceps` for each MFCC file (13 cepstral coefficients) and +`decode_mel` for each Mel file (80 Mel bins), plotting spectrograms for all +files that exist including the Xtensa variants. + +Individual files can also be decoded manually: + +```matlab +[ceps, t, n] = decode_ceps('mfcc_s16.raw', 13); +``` + +In the above it's known from configuration script that MFCC was set up to +output 13 cepstral coefficients from each FFT → Mel → DCT → Cepstral +coefficients computation run. + +The 80 bands Mel output can be visualized with command: + +```matlab +[mel, t, n] = decode_mel('mel_s16.raw', 80); +``` + +## Live Whisper Transcription with DSP VAD + +The directory contains a Python script `sof_mel_to_text_live_dsp_vad.py`. +It can be used with development topologies +`sof-arl-cs42l43-l0-cs35l56-l23-mfcc-mel-normal.tplg` and +`sof-mtl-rt713-l0-rt1316-l12-mfcc-mel-normal.tplg`. + +It captures from default audio device `hw:0,47` (headset microphone PCM). +The Mel audio features and VAD flags are packed to be compatible with a +normal PCM stream. The captured frames with detected speech are sent to the +Whisper speech recognizer model for conversion to text. + +The more efficient method for audio features capture uses the compress PCM without +continuous redundant data. Such MFCC development topologies are: + +- `sof-mtl-rt713-l0-rt1316-l12-mfcc-mel-compr.tplg` +- `sof-mtl-rt713-l0-rt1316-l12-mfcc-ceps-compr.tplg` +- `sof-arl-cs42l43-l0-cs35l56-l23-mfcc-mel-compr.tplg` +- `sof-arl-cs42l43-l0-cs35l56-l23-mfcc-ceps-compr.tplg` + +E.g. the script `sof_mel_spectrogram_compress.py` uses the mfcc-mel-compr topology version. + +### Prerequisites + +The script needs OpenVINO. Please follow the install procedure from +<https://docs.openvino.ai/2025/get-started/install-openvino.html>. + +The following Python pip installs are needed into the same OpenVINO venv. + +```bash +pip install openvino openvino-tokenizers openvino-genai +pip install optimum[intel] +pip install transformers +pip install huggingface_hub +``` + +The real-time spectrogram viewers in this directory use GTK 4; their setup is described +under [Live Spectrogram Viewers](#live-spectrogram-viewers) below. + +### NPU / GPU Support + +The script by default runs the Whisper encoder model in the NPU. To +use the NPU, install the driver from +<https://github.com/intel/linux-npu-driver/releases>. If the NPU is not +available, change the encoder to CPU with run option `--encoder-device CPU`. +With a GPU both `--encoder-device GPU` and `--decoder-device GPU` can be set. + +### Example run + +Check which capture devices are available. + +```bash +arecord -l +``` + +In this example the devices hw:0,47 and hw:0,48 support the audio +features stream. + +```bash +**** List of CAPTURE Hardware Devices **** +card 0: sofsoundwire [sof-soundwire], device 1: Jack In (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 +card 0: sofsoundwire [sof-soundwire], device 4: Microphone (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 +card 0: sofsoundwire [sof-soundwire], device 47: Jack In Audio Features (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 +card 0: sofsoundwire [sof-soundwire], device 48: Microphone Audio Features (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 +``` + +With Whisper model run the CPU and with internal microphones of laptop +the run command is: + +```bash +python3 sof_mel_to_text_live_dsp_vad.py --encoder-device CPU --device hw:0,48 +``` + +The script run output is shown below + +```bash +=== Live SOF Mel → Whisper Transcription (DSP VAD) === + +Starting capture: arecord -D hw:0,48 -f S32_LE -c 2 -r 16000 -t raw --buffer-size 8192 +VAD source: DSP (embedded in stream) +Silence trigger: 100ms (10 frames) +Whisper model: whisper-medium-int4-ov (encoder: CPU, decoder: CPU) + + [ 0.01s] SILENCE + [ 1.39s] SPEECH + [ 2.57s] SILENCE + [ 2.66s] Transcribing 118 frames (1.2s)... + [Whisper] encoder: 1.30s + [Whisper] decoder: 0.59s (3 tokens) + + >> "Hello computer" +``` +## Live Whisper Transcription with Compress PCM + +The `sof_mel_to_text_live_compress.py` script captures Mel spectrogram +frames from a SOF compress PCM device and performs live Whisper +transcription using OpenVINO. Unlike `sof_mel_to_text_live_dsp_vad.py` +which uses `arecord`, this script reads directly from the compress PCM +device with discontinuous frames handling. + +The same OpenVINO prerequisites and pip packages apply as described above +for `sof_mel_to_text_live_dsp_vad.py`. + +```bash +# Microphone compress audio features +python3 sof_mel_to_text_live_compress.py --card 0 --device 54 --model whisper-medium-int4-ov + +# Jack In compress audio features +python3 sof_mel_to_text_live_compress.py --card 0 --device 53 --model whisper-medium-int4-ov +``` + +### Compress PCM device IDs + +The compress audio-features capture PCMs in the topology2 platform +configs use the following IDs (see +`tools/topology/topology2/platform/intel/sdw-*-audio-feature-compress.conf`): + +| Device | Name | PCM ID | +|--------|-----------------------------------|--------| +| Jack | "Jack In Compress Audio Features" | 53 | +| Mic | "Microphone Compress Audio Features" | 54 | + +The non-compress PCMs (`47` jack, `48` mic, "Audio Features") are PCM +streams intended for `arecord`/`hw:0,N` (used by +`sof_mel_to_text_live_dsp_vad.py` above) and will not work with the +compress scripts below. + +## Live Spectrogram Viewers + +These viewers are helpful for interactively checking VAD operation and +developing improvements, or for educational visualization of Mel and +cepstral-coefficient spectrograms. + +#### Additional dependencies to install + +GTK 4 and the introspection bindings are shipped by the distribution. +On Debian / Ubuntu (24.04 or newer): + +```bash +sudo apt install python3-gi gir1.2-gtk-4.0 python3-numpy +sudo apt install libgirepository-2.0-dev libcairo2-dev pkg-config \ + python3-dev gir1.2-gtk-4.0 build-essential +pip install PyGObject pycairo numpy +``` + +#### Renderer selection + +GSK auto-selects the renderer; to force the GL or Vulkan back-ends +(usually the smoothest): + +```bash +GSK_RENDERER=ngl python3 sof_mel_spectrogram_compress.py ... +GSK_RENDERER=vulkan python3 sof_mel_spectrogram_compress.py ... +``` + +### Mel Spectrogram + +The `sof_mel_spectrogram_compress.py` script captures Mel spectrogram +frames from a SOF compress PCM device and displays them as a live +scrolling spectrogram with VAD status in a GTK 4 window. This is a +lightweight viewer that does not run Whisper inference. + +```bash +# Microphone compress audio features +python3 sof_mel_spectrogram_compress.py --card 0 --device 54 --width 300 + +# Jack In compress audio features +python3 sof_mel_spectrogram_compress.py --card 0 --device 53 --width 300 +``` + +### Cepstral Spectrogram + +The `sof_ceps_spectrogram_compress.py` script is the counterpart +that displays cepstral coefficients (MFCC) instead of Mel bands. It +imports the GPU-accelerated widgets from `sof_mel_spectrogram_compress.py`, +so both files must remain in the same directory. + +```bash +# Microphone compress audio features +python3 sof_ceps_spectrogram_compress.py --card 0 --device 54 --num-ceps 13 --width 300 + +# Jack In compress audio features +python3 sof_ceps_spectrogram_compress.py --card 0 --device 53 --num-ceps 13 --width 300 +``` diff --git a/src/audio/mfcc/tune/decode_all.m b/src/audio/mfcc/tune/decode_all.m new file mode 100644 index 000000000000..4c377bf5029a --- /dev/null +++ b/src/audio/mfcc/tune/decode_all.m @@ -0,0 +1,38 @@ +% decode_all.m - Decode all MFCC and Mel raw output files from run_mfcc.sh +% +% SPDX-License-Identifier: BSD-3-Clause +% Copyright(c) 2026 Intel Corporation. + +num_ceps = 13; +num_mel = 80; + +% MFCC cepstral output files (all int32 output, Q9.23) +ceps_files = {'mfcc_s16.raw', 'mfcc_s24.raw', 'mfcc_s32.raw'}; + +% Mel output files (all int32 output, Q9.23) +mel_files = {'mel_s16.raw', 'mel_s24.raw', 'mel_s32.raw'}; + +% Xtensa prefixed variants +xt_ceps_files = {'xt_mfcc_s16.raw', 'xt_mfcc_s24.raw', 'xt_mfcc_s32.raw'}; +xt_mel_files = {'xt_mel_s16.raw', 'xt_mel_s24.raw', 'xt_mel_s32.raw'}; + +all_ceps_files = [ceps_files, xt_ceps_files]; +all_mel_files = [mel_files, xt_mel_files]; + +for i = 1:length(all_ceps_files) + fn = all_ceps_files{i}; + if exist(fn, 'file') + fprintf('Decoding MFCC ceps: %s\n', fn); + [ceps, t, n, vad, energy, noise_energy, frame_num] = ... + decode_ceps(fn, num_ceps); + end +end + +for i = 1:length(all_mel_files) + fn = all_mel_files{i}; + if exist(fn, 'file') + fprintf('Decoding Mel: %s\n', fn); + [mel, t, n, vad, energy, noise_energy, frame_num] = ... + decode_mel(fn, num_mel); + end +end diff --git a/src/audio/mfcc/tune/decode_ceps.m b/src/audio/mfcc/tune/decode_ceps.m new file mode 100644 index 000000000000..480eadea2945 --- /dev/null +++ b/src/audio/mfcc/tune/decode_ceps.m @@ -0,0 +1,148 @@ +% [ceps, t, n, vad, energy, noise_energy, frame_number] = decode_ceps(fn, num_ceps, hop, num_channels) +% +% Input +% fn - File with MFCC data in .raw or .wav format +% num_ceps - number of cepstral coefficients per frame +% hop - STFT hop in seconds, defaults to 10e-3 for 10 ms +% num_channels - needed for .raw format, omit for .wav, default 1 +% +% Outputs +% ceps - cepstral coefficients +% t - time vector for plotting +% n - ceps 1..num_ceps vector for plotting +% vad - VAD flag per frame from DSP +% energy - weighted signal energy per frame from DSP +% noise_energy - weighted noise floor energy per frame from DSP +% frame_number - frame number from DSP + +% SPDX-License-Identifier: BSD-3-Clause +% Copyright(c) 2022-2026 Intel Corporation. All rights reserved. + +function [ceps, t, n, vad, energy, noise_energy, frame_number] = ... + decode_ceps(fn, num_ceps, hop, num_channels) + +if nargin < 3 + hop = 10e-3; +end +if nargin < 4 + num_channels = 1; +end + +% MFCC stream +qformat = 23; % Q9.23 in int32 +magic = int32(1835426659); % 0x6D666363 as int32 +num_magic = 1; % magic word is 1 x int32 + +% Load output data (always int32) +[data, num_channels] = get_file(fn, num_channels); + +idx = find(data == magic); + +if isempty(idx) + error('No magic value markers found from stream'); +end + +num_frames = length(idx); + +% Header after magic is [frame_number, reserved, energy, noise_energy, vad_flag] +% as int32, followed by num_ceps coefficients (int32). +payload_len = 5 + num_ceps; + +% Last frame can be incomplete due to span over multiple periods +last = idx(end) + num_magic + payload_len - 1; +if (last > length(data)) + num_frames = num_frames - 1; +end + +payload = zeros(payload_len, num_frames); +for i = 1:num_frames + i1 = idx(i) + num_magic; + i2 = i1 + payload_len - 1; + payload(:,i) = double(data(i1:i2)); +end + +frame_number = payload(1, :); +% payload(2,:) is reserved, skip +energy = payload(3, :) / 2^23; +noise_energy = payload(4, :) / 2^23; +vad = payload(5, :); +ceps = payload(6:payload_len, :) / 2^qformat; + +% Fill gaps from DTX-suppressed VAD=0 frames to create continuous timeline. +% Missing frames are filled with the minimum ceps value found in the data. +first_frame = frame_number(1); +last_frame = frame_number(end); +total_frames = last_frame - first_frame + 1; +if total_frames > num_frames + ceps_fill = min(ceps(:)); + ceps_full = ones(num_ceps, total_frames) * ceps_fill; + vad_full = zeros(1, total_frames); + energy_full = zeros(1, total_frames); + noise_energy_full = zeros(1, total_frames); + frame_number_full = first_frame:last_frame; + has_data = false(1, total_frames); + for i = 1:num_frames + fi = frame_number(i) - first_frame + 1; + ceps_full(:, fi) = ceps(:, i); + vad_full(fi) = vad(i); + energy_full(fi) = energy(i); + noise_energy_full(fi) = noise_energy(i); + has_data(fi) = true; + end + % Forward-fill gaps with last received values + for fi = 2:total_frames + if ~has_data(fi) + ceps_full(:, fi) = ceps_full(:, fi - 1); + energy_full(fi) = energy_full(fi - 1); + noise_energy_full(fi) = noise_energy_full(fi - 1); + end + end + ceps = ceps_full; + vad = vad_full; + energy = energy_full; + noise_energy = noise_energy_full; + frame_number = frame_number_full; +end + +t = (frame_number - first_frame) * hop; +n = 1:num_ceps; + +figure; +surf(t, n, ceps, 'EdgeColor', 'none'); +colormap(jet); +view(45, 60) +tstr = sprintf('SOF MFCC cepstral coefficients (%s)', fn); +title(tstr, 'Interpreter', 'None'); +xlabel('Time (s)'); +ylabel('Cepstral coef #'); + +end + +function [data, num_channels] = get_file(fn, num_channels) + +[~, ~, ext] = fileparts(fn); + +switch lower(ext) + case '.raw' + fh = fopen(fn, 'r'); + data = fread(fh, 'int32'); + fclose(fh); + case '.wav' + tmp = audioread(fn, 'native'); + t = whos('tmp'); + if ~strcmp(t.class, 'int32') + error('Expected 32-bit wav for int32 MFCC output format'); + end + s = size(tmp); + num_channels = s(2); + if num_channels > 1 + data = int32(zeros(prod(s), 1)); + for i = 1:num_channels + data(i:num_channels:end) = tmp(:, i); + end + end + otherwise + error('Unknown audio format'); +end + +end diff --git a/src/audio/mfcc/tune/decode_mel.m b/src/audio/mfcc/tune/decode_mel.m new file mode 100644 index 000000000000..0aca1e35ec8d --- /dev/null +++ b/src/audio/mfcc/tune/decode_mel.m @@ -0,0 +1,176 @@ +% [mel, t, n, vad, energy, noise_energy, frame_number] = decode_mel(fn, num_mel, hop, num_channels) +% +% Input +% fn - File with Mel data in .raw or .wav format +% hop - STFT hop in seconds, defaults to 10e-3 for 10 ms +% num_mel - number of Mel coefficients per frame +% num_channels - needed for .raw format, omit for .wav, default 1 +% +% Outputs +% mel - Mel coefficients +% t - time vector for plotting +% n - mel 1..num_mel vector for plotting +% vad - VAD flag per frame from DSP +% energy - weighted signal energy per frame from DSP +% noise_energy - weighted noise floor energy per frame from DSP +% frame_number - frame number from DSP + +% SPDX-License-Identifier: BSD-3-Clause +% Copyright(c) 2026 Intel Corporation. + +function [mel, t, n, vad, energy, noise_energy, frame_number] = ... + decode_mel(fn, num_mel, hop, num_channels) + +if nargin < 3 + hop = 10e-3; +end +if nargin < 4 + num_channels = 1; +end + +% MFCC stream +fs = 16e3; +qformat = 23; % Q9.23 in int32 + +magic = int32(1835426659); % 0x6D666363 as int32 +num_magic = 1; % magic word is 1 x int32 +num_other_header = 5; % frame_number, reserved, energy, noise, vad (all int32) + +% Load output data (always int32) +[data, num_channels] = get_file(fn, num_channels); + +if isempty(data) + error('File %s is empty', fn); +end + +idx = find(data == magic); + +if isempty(idx) + error('No magic value markers found from stream'); +end + +period_mel = idx(2)-idx(1); +num_frames = length(idx); + +% Header after magic is [frame_number, reserved, energy, noise_energy, vad_flag] +% as int32, followed by num_mel coefficients. +% For s16 each int32 occupies 2 int16 slots. +payload_len = num_other_header + num_mel; + +% Last frame can be incomplete due to span over multiple periods +last = idx(end) + num_magic + payload_len - 1; +if (last > length(data)) + num_frames = num_frames - 1; +end + +payload = zeros(payload_len, num_frames); +for i = 1:num_frames + i1 = idx(i) + num_magic; + i2 = i1 + payload_len - 1; + payload(:,i) = double(data(i1:i2)); +end + +frame_number = payload(1, :); +% payload(2,:) is reserved, skip +energy = payload(3, :) / 2^23; +noise_energy = payload(4, :) / 2^23; +vad = payload(5, :); +mel = payload(6:payload_len, :) / 2^qformat; + +% Fill gaps from DTX-suppressed VAD=0 frames to create continuous timeline. +% Missing frames are filled with the minimum Mel value found in the data. +first_frame = frame_number(1); +last_frame = frame_number(end); +total_frames = last_frame - first_frame + 1; +if total_frames > num_frames + mel_fill = min(mel(:)); + mel_full = ones(num_mel, total_frames) * mel_fill; + vad_full = zeros(1, total_frames); + energy_full = zeros(1, total_frames); + noise_energy_full = zeros(1, total_frames); + frame_number_full = first_frame:last_frame; + has_data = false(1, total_frames); + for i = 1:num_frames + fi = frame_number(i) - first_frame + 1; + mel_full(:, fi) = mel(:, i); + vad_full(fi) = vad(i); + energy_full(fi) = energy(i); + noise_energy_full(fi) = noise_energy(i); + has_data(fi) = true; + end + % Forward-fill gaps with last received values + for fi = 2:total_frames + if ~has_data(fi) + mel_full(:, fi) = mel_full(:, fi - 1); + energy_full(fi) = energy_full(fi - 1); + noise_energy_full(fi) = noise_energy_full(fi - 1); + end + end + mel = mel_full; + vad = vad_full; + energy = energy_full; + noise_energy = noise_energy_full; + frame_number = frame_number_full; +end + +t = (frame_number - first_frame) * hop; +n = 1:num_mel; + +figure +imagesc(t, n, mel); +axis xy; +colormap(jet); +colorbar; +tstr = sprintf('SOF MFCC Mel coefficients (%s)', fn); +title(tstr, 'Interpreter', 'None'); +ylabel('Mel coef #'); + +figure +subplot(2,1,1); +plot(t, vad) +ax = axis(); +axis([ax(1:2) -0.1 1.1]); +grid on; +title(tstr, 'Interpreter', 'None'); +xlabel('Time (s)'); +ylabel('VAD flag'); + +subplot(2,1,2); +plot(t, energy, t, noise_energy); +grid on; +legend('Energy', 'Noise Energy'); +xlabel('Time (s)'); +ylabel('Energy'); + +end + +function [data, num_channels] = get_file(fn, num_channels) + +[~, ~, ext] = fileparts(fn); + +switch lower(ext) + case '.raw' + fh = fopen(fn, 'r'); + data = fread(fh, 'int32'); + fclose(fh); + case '.wav' + tmp = audioread(fn, 'native'); + t = whos('tmp'); + if ~strcmp(t.class, 'int32') + error('Expected 32-bit wav for int32 MFCC output format'); + end + s = size(tmp); + num_channels = s(2); + if num_channels > 1 + data = zeros(prod(s), 1, t.class); + for i = 1:num_channels + data(i:num_channels:end) = tmp(:, i); + end + else + data = tmp; + end + otherwise + error('Unknown audio format'); +end + +end diff --git a/src/audio/mfcc/tune/run_mfcc.sh b/src/audio/mfcc/tune/run_mfcc.sh new file mode 100755 index 000000000000..e3c309fbc03e --- /dev/null +++ b/src/audio/mfcc/tune/run_mfcc.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2022-2026 Intel Corporation. All rights reserved. + +set -e + +RAW_INPUT_S16=in_s16.raw +RAW_INPUT_S24=in_s24.raw +RAW_INPUT_S32=in_s32.raw + +VALGRIND="valgrind --leak-check=full" +#VALGRIND="" +TESTBENCH=$SOF_WORKSPACE/sof/tools/testbench/build_testbench/install/bin/sof-testbench4 +TESTBENCH_RUN="$VALGRIND $TESTBENCH" + +convert_input() { + sox -R --encoding signed-integer "$1" -L -r 16000 -c 2 -b 16 "$RAW_INPUT_S16" + sox -R --no-dither --encoding signed-integer -L -r 16000 -c 2 -b 16 \ + "$RAW_INPUT_S16" -b 32 "$RAW_INPUT_S32" + sox -R --no-dither --encoding signed-integer -L -r 16000 -c 2 -b 16 \ + "$RAW_INPUT_S16" -b 32 "$RAW_INPUT_S24" vol 0.003906250000 +} + +run_testbench() { + local tplg_base="$1" + local out_s16="$2" + local out_s24="$3" + local out_s32="$4" + local label="$5" + local tplg_s16="${SOF_WORKSPACE}/sof/tools/build_tools/topology/topology2/development/${tplg_base}16.tplg" + local tplg_s24="${SOF_WORKSPACE}/sof/tools/build_tools/topology/topology2/development/${tplg_base}24.tplg" + local tplg_s32="${SOF_WORKSPACE}/sof/tools/build_tools/topology/topology2/development/${tplg_base}32.tplg" + + $TESTBENCH_RUN -r 16000 -c 2 -b S16_LE -p 3,4 -t "$tplg_s16" -i "$RAW_INPUT_S16" -o "$out_s16" + $TESTBENCH_RUN -r 16000 -c 2 -b S24_LE -p 3,4 -t "$tplg_s24" -i "$RAW_INPUT_S24" -o "$out_s24" + $TESTBENCH_RUN -r 16000 -c 2 -b S32_LE -p 3,4 -t "$tplg_s32" -i "$RAW_INPUT_S32" -o "$out_s32" + + echo ---------------------------------------------------------------------------------- + echo "The ${label} data was output to file ${out_s16}, ${out_s24}, ${out_s32}" + echo ---------------------------------------------------------------------------------- +} + +main() { + convert_input "$1" + run_testbench "sof-hda-benchmark-mfcc" mfcc_s16.raw mfcc_s24.raw mfcc_s32.raw "MFCC" + run_testbench "sof-hda-benchmark-mfccmel" mel_s16.raw mel_s24.raw mel_s32.raw "MFCC Mel" + + if [ -n "$XTENSA_PATH" ]; then + TESTBENCH_RUN="$XTENSA_PATH/xt-run $SOF_WORKSPACE/sof/tools/testbench/build_xt_testbench/sof-testbench4" + run_testbench "sof-hda-benchmark-mfcc" xt_mfcc_s16.raw xt_mfcc_s24.raw xt_mfcc_s32.raw "Xtensa MFCC" + run_testbench "sof-hda-benchmark-mfccmel" xt_mel_s16.raw xt_mel_s24.raw xt_mel_s32.raw "Xtensa MFCC Mel" + fi +} + +main "$@" diff --git a/src/audio/mfcc/tune/setup_mfcc.m b/src/audio/mfcc/tune/setup_mfcc.m new file mode 100644 index 000000000000..dbf69587a74f --- /dev/null +++ b/src/audio/mfcc/tune/setup_mfcc.m @@ -0,0 +1,339 @@ +% setup_mfcc() +% +% Create binary configuration blobs for the MFCC component. +% The hex data is written to files in directory +% tools/topology/topology2/include/components/mfcc. + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2018-2026, Intel Corporation. + +function setup_mfcc() + + gen_cfg.tplg_ver = 2; + gen_cfg.ipc_ver = 4; + gen_cfg.tools_path = '../../../../tools/'; + gen_cfg.mfcc_conf_path = [gen_cfg.tools_path 'topology/topology2/include/components/mfcc/']; + + % Default blob + setup = get_mfcc_default_config(); + setup.tplg_fn = 'default.conf'; + export_mfcc_setup(gen_cfg, setup); + + % Blob for mel spectrogram data + setup = get_mel_spectrogram_config(); + setup.tplg_fn = 'mel80.conf'; + export_mfcc_setup(gen_cfg, setup); + + % Blob for mel spectrogram with compress PCM output + setup = get_mel_spectrogram_config(); + setup.compress_output = true; + setup.tplg_fn = 'mel80_compress.conf'; + export_mfcc_setup(gen_cfg, setup); + + % Blob for mel spectrogram with compress PCM output and DTX + setup = get_mel_spectrogram_config(); + setup.compress_output = true; + setup.enable_dtx = true; + setup.dtx_trailing_silence_hops = 20; + setup.dtx_silence_hops_interval = 500; + setup.tplg_fn = 'mel80_compress_dtx.conf'; + export_mfcc_setup(gen_cfg, setup); + + % Default MFCC (cepstral) with compress PCM output + setup = get_mfcc_default_config(); + setup.compress_output = true; + setup.enable_vad = true; + setup.enable_dtx = true; + setup.dtx_trailing_silence_hops = 20; + setup.dtx_silence_hops_interval = 500; + setup.update_controls = true; + setup.tplg_fn = 'ceps13_compress_dtx.conf'; + export_mfcc_setup(gen_cfg, setup); + +end + +function cfg = get_mfcc_default_config() + cfg.blackman_coef = 0.42; + cfg.cepstral_lifter = 22.0; + cfg.channel = 0; % -1 expect mono, 0 left, 1 right ... + cfg.dither = 0.0; % no support + cfg.energy_floor = 1.0; + cfg.frame_length = 25.0; % ms + cfg.frame_shift = 10.0; % ms + cfg.high_freq = 0.0; % 0 is Nyquist + cfg.htk_compat = false; % no support + cfg.low_freq = 20.0; % Hz + cfg.num_ceps = 13; + cfg.min_duration = 0.0; % no support + cfg.norm = 'none'; % Use none or slaney + cfg.num_mel_bins = 23; + cfg.preemphasis_coefficient = 0; % disable + cfg.raw_energy = true; + cfg.remove_dc_offset = true; + cfg.round_to_power_of_two = true; % must be true + cfg.sample_frequency = 16000; + cfg.snip_edges = true; % must be true + cfg.subtract_mean = false; % must be false + cfg.use_energy = false; + cfg.vtln_high = -500.0; % no support + cfg.vtln_low = 100.0; % no support + cfg.vtln_warp = 1.0; % must be 1.0 (vocal tract length normalization) + cfg.window_type = 'hamming'; + cfg.mel_log = 'log'; % Set to 'db' for librosa, set to 'log10' for matlab + cfg.pmin = 5e-10; % Set to 1e-10 for librosa + cfg.top_db = 200; % Set to 80 for librosa + cfg.mel_offset = 0; % For mel_only mode, no impact with num_ceps > 0 + cfg.mel_scale = 0; % same + cfg.mmax_init = 0; % same + cfg.mmax_coef = 0; % same + cfg.dynamic_mmax = false; % same + cfg.enable_vad = false; + cfg.enable_dtx = false; + cfg.dtx_trailing_silence_hops = 0; + cfg.dtx_silence_hops_interval = 0; + cfg.update_controls = false; + cfg.compress_output = false; +end + +function cfg = get_mel_spectrogram_config() + cfg.blackman_coef = 0; + cfg.cepstral_lifter = 0; + cfg.channel = 0; + cfg.dither = 0; + cfg.energy_floor = 1.0; + cfg.frame_length = 25.0; % 400 samples at 16 kHz + cfg.frame_shift = 10.0; % 160 samples at 16 kHz + cfg.high_freq = 8000; + cfg.htk_compat = false; + cfg.low_freq = 0; + cfg.num_ceps = 0; % Mel-only mode, no DCT + cfg.min_duration = 0; + cfg.norm = 'slaney'; + cfg.num_mel_bins = 80; + cfg.preemphasis_coefficient = 0; + cfg.raw_energy = false; + cfg.remove_dc_offset = false; + cfg.round_to_power_of_two = true; + cfg.sample_frequency = 16000; + cfg.snip_edges = true; + cfg.subtract_mean = false; + cfg.use_energy = false; + cfg.vtln_high = 0; + cfg.vtln_low = 0; + cfg.vtln_warp = 1.0; + cfg.window_type = 'hann'; + cfg.mel_log = 'log10'; + cfg.pmin = 1e-10; + cfg.top_db = 8; % applied for log10, would be 80 dB clamp for decibels as 10*log10() + cfg.mel_offset = 4.0; % For whisper like Mel scale and normalize + cfg.mel_scale = 0.25; % For whisper like Mel scale and normalize + cfg.mmax_init = 0; % Initial value max Mel value, data clamp is mmax - top_db + cfg.mmax_coef = 0; % Dynamic max Mel value decay coefficient (zero lock to found max) + cfg.dynamic_mmax = true; + cfg.enable_vad = true; + cfg.enable_dtx = false; + cfg.dtx_trailing_silence_hops = 0; + cfg.dtx_silence_hops_interval = 0; + cfg.update_controls = true; + cfg.compress_output = false; +end + +function export_mfcc_setup(gen_cfg, cfg) + +%% Use blob tool from EQ +addpath([gen_cfg.tools_path 'tune/common']); + +%% Blob size, size plus reserved(8) + current parameters +nbytes_data = 116; + +%% Little endian +sh32 = [0 -8 -16 -24]; +sh16 = [0 -8]; + +%% Get ABI information +[abi_bytes, nbytes_abi] = sof_get_abi(nbytes_data, gen_cfg.ipc_ver); + +%% Initialize correct size uint8 array +nbytes = nbytes_abi + nbytes_data; +b8 = uint8(zeros(1,nbytes)); + +%% Insert ABI header +fprintf(1, 'MFCC blob size is %d, ABI header is %d, data is %d\n',nbytes, nbytes_abi, nbytes_data); +b8(1:nbytes_abi) = abi_bytes; +j = nbytes_abi + 1; + +%% Apply default MFCC configuration, first struct header and reserved, then data +[b8, j] = add_w32b(nbytes_data, b8, j); + +v = q_convert(cfg.mel_offset, 7); [b8, j] = add_w16b(v, b8, j); +v = q_convert(cfg.mel_scale, 12); [b8, j] = add_w16b(v, b8, j); +v = q_convert(cfg.mmax_init, 7); [b8, j] = add_w16b(v, b8, j); +v = q_convert(cfg.mmax_coef, 15); [b8, j] = add_w16b(v, b8, j); + +v = cfg.dtx_trailing_silence_hops; [b8, j] = add_w16b(v, b8, j); % DTX trailing silence hops +v = cfg.dtx_silence_hops_interval; [b8, j] = add_w16b(v, b8, j); % DTX silence frame interval +% Reserved +for i = 1:5 + [b8, j] = add_w32b(0, b8, j); +end + +v = q_convert(cfg.sample_frequency, 0); [b8, j] = add_w32b(v, b8, j); +v = q_convert(cfg.pmin, 31); [b8, j] = add_w32b(v, b8, j); +v = get_mel_log_value(cfg.mel_log); [b8, j] = add_w32b(v, b8, j); % enum mel_log +v = get_norm_value(cfg.norm); [b8, j] = add_w32b(v, b8, j); % enum norm +v = 0; [b8, j] = add_w32b(v, b8, j); % enum pad +v = get_window(cfg); [b8, j] = add_w32b(v, b8, j); % enum window +v = 1; [b8, j] = add_w32b(v, b8, j); % enum dct type +v = q_convert(cfg.blackman_coef, 15); [b8, j] = add_w16b(v, b8, j); +v = q_convert(cfg.cepstral_lifter, 9); [b8, j] = add_w16b(v, b8, j); +v = cfg.channel; [b8, j] = add_w16b(v, b8, j); +v = cfg.dither; [b8, j] = add_w16b(v, b8, j); +v = round(cfg.frame_length/1000 * cfg.sample_frequency); [b8, j] = add_w16b(v, b8, j); +v = round(cfg.frame_shift/1000 * cfg.sample_frequency); [b8, j] = add_w16b(v, b8, j); +v = q_convert(cfg.high_freq, 0); [b8, j] = add_w16b(v, b8, j); +v = q_convert(cfg.low_freq, 0); [b8, j] = add_w16b(v, b8, j); +v = cfg.num_ceps; [b8, j] = add_w16b(v, b8, j); +v = cfg.num_mel_bins; [b8, j] = add_w16b(v, b8, j); +v = q_convert(cfg.preemphasis_coefficient, 15); [b8, j] = add_w16b(v, b8, j); +v = q_convert(cfg.top_db, 7); [b8, j] = add_w16b(v, b8, j); +v = 0; [b8, j] = add_w16b(v, b8, j); % vtln_high Qx.y TBD +v = 0; [b8, j] = add_w16b(v, b8, j); % vtln_low Qx.y TBD +v = 0; [b8, j] = add_w16b(v, b8, j); % vtln_warp Qx.y TBD +% reserved16[3] +for i = 1:3 + [b8, j] = add_w16b(0, b8, j); +end +v = cfg.htk_compat; [b8, j] = add_w8b(v, b8, j); % bool +v = cfg.raw_energy; [b8, j] = add_w8b(v, b8, j); % bool +v = cfg.remove_dc_offset; [b8, j] = add_w8b(v, b8, j); % bool +v = cfg.round_to_power_of_two; [b8, j] = add_w8b(v, b8, j); % bool +v = cfg.snip_edges; [b8, j] = add_w8b(v, b8, j); % bool +v = cfg.subtract_mean; [b8, j] = add_w8b(v, b8, j); % bool +v = cfg.use_energy; [b8, j] = add_w8b(v, b8, j); % bool +v = cfg.dynamic_mmax; [b8, j] = add_w8b(v, b8, j); % bool +v = cfg.enable_vad; [b8, j] = add_w8b(v, b8, j); % bool +v = cfg.enable_dtx; [b8, j] = add_w8b(v, b8, j); % bool +v = cfg.update_controls; [b8, j] = add_w8b(v, b8, j); % bool +v = cfg.compress_output; [b8, j] = add_w8b(v, b8, j); % bool +% reserved_bool[4] +for i = 1:4 + [b8, j] = add_w8b(0, b8, j); +end + +%% Export +tplg_fn = [gen_cfg.mfcc_conf_path cfg.tplg_fn]; +switch gen_cfg.tplg_ver + case 1 + sof_tplg_write(tplg_fn, b8, "DEF_MFCC_PRIV", ... + "Exported with script setup_mfcc.m", ... + "cd src/audio/mfcc/tune; octave setup_mfcc.m"); + case 2 + sof_tplg2_write(tplg_fn, b8, "mfcc_config", ... + "Exported MFCC configuration", ... + "cd src/audio/mfcc/tune; octave setup_mfcc.m"); + otherwise + error("Illegal tplg_ver, use 1 for topology v1 or 2 topology v2."); +end + +rmpath([gen_cfg.tools_path 'tune/common']); + +end + +%% Helper functions + +function n = get_window(cfg) + switch lower(cfg.window_type) + case 'rectangular' + n = 0; + case 'blackman' + n = 1; + case 'hamming' + n = 2; + case 'hann' + n = 3; + case 'povey' + n = 4; + otherwise + error('Unknown window type'); + end +end + +function n = get_mel_log_value(mel_log) + switch lower(mel_log) + case 'log' + n = 0; + case 'log10' + n = 1; + case 'db' + n = 2; + otherwise + error('Unknown mel_log type'); + end +end + +function n = get_norm_value(norm) + switch lower(norm) + case 'none' + n = 0; + case 'slaney' + n = 1; + otherwise + error('Unknown norm type'); + end +end + +function bytes = w8b(word) +bytes = uint8(zeros(1,1)); +bytes(1) = bitand(word, 255); +end + +function bytes = w16b(word) +sh = [0 -8]; +bytes = uint8(zeros(1,2)); +bytes(1) = bitand(bitshift(word, sh(1)), 255); +bytes(2) = bitand(bitshift(word, sh(2)), 255); +end + +function bytes = w32b(word) +sh = [0 -8 -16 -24]; +bytes = uint8(zeros(1,4)); +bytes(1) = bitand(bitshift(word, sh(1)), 255); +bytes(2) = bitand(bitshift(word, sh(2)), 255); +bytes(3) = bitand(bitshift(word, sh(3)), 255); +bytes(4) = bitand(bitshift(word, sh(4)), 255); +end + +function n = q_convert(val, q) +n = round(val * 2^q); +end + +function [blob8, j] = add_w8b(v, blob8, j) +if j > length(blob8) + error('Blob size is not sufficient'); +end +blob8(j) = w8b(v); +j = j + 1; +end + +function [blob8, j] = add_w16b(v, blob8, j) +if j + 1 > length(blob8) + error('Blob size is not sufficient'); +end +if v < 0 + v = 2^16 + v; +end +blob8(j : j + 1) = w16b(v); +j = j + 2; +end + +function [blob8, j] = add_w32b(v, blob8, j) +if j + 3 > length(blob8) + error('Blob size is not sufficient'); +end +if v < 0 + v = 2^32 + v; +end +blob8(j : j + 3) = w32b(v); +j = j + 4; +end diff --git a/src/audio/mfcc/tune/sof_ceps_spectrogram_compress.py b/src/audio/mfcc/tune/sof_ceps_spectrogram_compress.py new file mode 100755 index 000000000000..8cb8190c56b4 --- /dev/null +++ b/src/audio/mfcc/tune/sof_ceps_spectrogram_compress.py @@ -0,0 +1,374 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) 2026, Intel Corporation. + +"""Live scrolling cepstral coefficient viewer for SOF compress PCM capture. + +GTK 4 application that displays a live scrolling MFCC cepstral +spectrogram with VAD status from a SOF compress audio-features PCM. +Rendering goes through ``Gtk.Snapshot`` with ``Gdk.MemoryTexture`` for +the spectrogram and native GSK render nodes (``Gsk.Path`` strokes, +``append_color``, ``append_layout``) for the strip plots, so the +GL/Vulkan renderer handles compositing on the GPU. Vsync-aligned +redraws (``add_tick_callback``) and sub-pixel scrolling keep the 100 Hz +data stream looking smooth on a 60+ Hz display. + +Dependencies (Debian/Ubuntu): + sudo apt install python3-gi gir1.2-gtk-4.0 + pip install numpy + +Frame format: [magic(int32), frame_number(uint32), reserved(int32), + energy(int32), noise_energy(int32), vad_flag(int32), + ceps[0..N-1](int32)] + +Cepstral coefficients are in Q9.23 fixed-point format. + +Usage: + python sof_ceps_spectrogram_compress.py [--card 0] [--device 54] + python sof_ceps_spectrogram_compress.py --num-ceps 13 --width 300 +""" + +import argparse +import os +import queue +import signal +import struct +import subprocess +import sys +import threading +import time + +import numpy as np + +import gi +gi.require_version('Gtk', '4.0') +gi.require_version('Gdk', '4.0') +gi.require_version('Gsk', '4.0') +gi.require_version('Graphene', '1.0') +gi.require_version('Pango', '1.0') +from gi.repository import GLib, Gtk # noqa: E402 + +# Reuse the GPU-accelerated widgets from the mel viewer. +from sof_mel_spectrogram_compress import ( # noqa: E402 + MelSpectrogramArea as SpectrogramArea, + CurveStripArea, + GUI_REFRESH_MS, +) + +# SOF compress frame format constants (with DSP data header) +SOF_MAGIC_BYTES = struct.pack('<i', 0x6D666363) # ASCII 'mfcc' as int32 +SOF_NUM_HEADER = 6 # magic, frame_number, reserved, energy, noise_energy, vad_flag +SOF_HEADER_BYTES = SOF_NUM_HEADER * 4 # 24 bytes +SOF_HOP_SEC = 0.01 # 10 ms per STFT hop + +SPECTROGRAM_WIDTH = 200 # default number of frames visible +DEFAULT_NUM_CEPS = 13 # default cepstral coefficients +Q_FORMAT = 23 # Q9.23 fixed-point + +# Color range for the image (cepstral coefficients in float) +CEPS_VMIN = -50.0 +CEPS_VMAX = 50.0 + + +def decode_ceps_frame(raw_ints): + """Convert int32 Q9.23 cepstral coefficients to float32.""" + return raw_ints.astype(np.float32) / (2 ** Q_FORMAT) + + +def parse_frame(buf, num_ceps): + """Parse one complete ceps frame from a bytearray buffer. + + Mutates buf in-place (deletes consumed bytes). + Returns: (frame_number, vad_flag, energy, noise, ceps_ints) or + (None, None, None, None, None) when no frame is ready. + """ + frame_bytes = SOF_HEADER_BYTES + num_ceps * 4 + idx = buf.find(SOF_MAGIC_BYTES) + if idx < 0: + if len(buf) > 3: + del buf[:-3] + return None, None, None, None, None + end = idx + frame_bytes + if end > len(buf): + del buf[:idx] + return None, None, None, None, None + + frame_number = struct.unpack_from('<I', buf, idx + 4)[0] + energy_int = struct.unpack_from('<i', buf, idx + 12)[0] + noise_int = struct.unpack_from('<i', buf, idx + 16)[0] + vad_flag = struct.unpack_from('<i', buf, idx + 20)[0] + + ceps_bytes = bytes(buf[idx + SOF_HEADER_BYTES:end]) + ceps_ints = np.frombuffer(ceps_bytes, dtype=np.int32) + del buf[:end] + energy = energy_int / (2 ** Q_FORMAT) + noise = noise_int / (2 ** Q_FORMAT) + return frame_number, vad_flag, energy, noise, ceps_ints + + +def start_crecord(card, device): + """Spawn crecord as subprocess; return Popen.""" + crecord_cmd = [ + 'crecord', '-v', + '-c', str(card), + '-d', str(device), + '-I', 'BESPOKE', + '-R', '16000', + '-C', '2', + '-F', 'S32_LE', + '-b', '6144', + '-f', '3', + ] + cmd = ['stdbuf', '-o0'] + crecord_cmd + print(f"Starting compress capture: {' '.join(crecord_cmd)}") + return subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + bufsize=0) + + +class CepsViewer: + """Top-level controller: capture process + GTK window.""" + + def __init__(self, app, card, device, width, num_ceps): + self.app = app + self.num_ceps = num_ceps + self.width_frames = width + self.frame_bytes = SOF_HEADER_BYTES + num_ceps * 4 + + # Ring buffers stored as (frames, ceps) for cheap shifts along axis 0. + self.ceps_buf = np.zeros((width, num_ceps), dtype=np.float32) + self.vad_buf = np.zeros(width, dtype=np.float32) + self.energy_buf = np.zeros(width, dtype=np.float32) + self.noise_buf = np.zeros(width, dtype=np.float32) + + self.recv_frames = 0 + self.prev_speech = None + self._closing = False + self._last_frame_mono = None + self._frame_period = SOF_HOP_SEC + + self._build_ui() + + # Start capture + self.proc = start_crecord(card, device) + self.frame_q = queue.Queue() + self.reader = threading.Thread(target=self._reader_thread, daemon=True) + self.reader.start() + + # Vsync-aligned redraws via the frame clock; fall back to a periodic + # timer if add_tick_callback is unavailable. + self._tick_id = 0 + self._timer_id = 0 + if hasattr(self.ceps_area, 'add_tick_callback'): + self._tick_id = self.ceps_area.add_tick_callback(self._on_tick_clock) + else: + self._timer_id = GLib.timeout_add(GUI_REFRESH_MS, self._on_timer) + + print(f"Cepstral coefficients: {num_ceps} (frame size: {self.frame_bytes} bytes)") + print(f"Spectrogram width: {width} frames ({width * SOF_HOP_SEC:.1f}s)") + if self._tick_id: + print("GUI refresh: vsync-aligned via frame clock, " + "sub-pixel scroll enabled") + else: + print(f"GUI refresh: fallback timer at {GUI_REFRESH_MS} ms " + f"({1000.0 / GUI_REFRESH_MS:.0f} FPS)") + print() + + def _build_ui(self): + self.window = Gtk.ApplicationWindow(application=self.app) + self.window.set_title( + f"SOF MFCC Cepstral Coefficients ({self.num_ceps} ceps) — DSP VAD" + ) + self.window.set_default_size(1100, 600) + self.window.connect('close-request', self._on_close) + + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2) + box.set_margin_start(4) + box.set_margin_end(4) + box.set_margin_top(4) + box.set_margin_bottom(4) + self.window.set_child(box) + + # Spectrogram-style cepstral image (re-uses the GPU texture widget). + self.ceps_area = SpectrogramArea(self.ceps_buf, CEPS_VMIN, CEPS_VMAX) + self.vad_area = CurveStripArea( + lambda: {'vad': self.vad_buf}, + ymin=-0.1, ymax=1.1, + lines=[('vad', (0.2, 0.9, 0.2, 1.0))], + yticks=[(0, 'Silent'), (1, 'Speech')], + label='VAD', + height_request=70, + ) + self.level_area = CurveStripArea( + lambda: {'energy': self.energy_buf, 'noise': self.noise_buf}, + autoscale=True, + lines=[ + ('energy', (1.0, 0.9, 0.2, 1.0)), + ('noise', (0.2, 0.9, 1.0, 1.0)), + ], + label='Level (Y=speech, C=noise)', + height_request=110, + ) + + self.ceps_area.set_vexpand(True) + box.append(self.ceps_area) + box.append(self.vad_area) + box.append(self.level_area) + + # --- I/O thread --------------------------------------------------- + def _reader_thread(self): + buf = bytearray() + raw_fd = self.proc.stdout.fileno() + try: + while True: + data = os.read(raw_fd, self.frame_bytes * 4) + if not data: + break + buf.extend(data) + while True: + fn, vf, en, no, ci = parse_frame(buf, self.num_ceps) + if ci is None: + break + self.frame_q.put((fn, vf, en, no, ci)) + except OSError: + pass + self.frame_q.put(None) + + # --- GUI tick ----------------------------------------------------- + def _drain_and_redraw(self): + drained = 0 + eof = False + while True: + try: + item = self.frame_q.get_nowait() + except queue.Empty: + break + if item is None: + eof = True + break + fn, vf, en, no, ci = item + self._ingest(fn, vf, en, no, ci) + drained += 1 + if drained >= 64: + break + + if self._last_frame_mono is None: + sub = 0.0 + else: + sub = (time.monotonic() - self._last_frame_mono) / self._frame_period + if sub < 0.0: + sub = 0.0 + elif sub > 1.0: + sub = 1.0 + self.ceps_area.set_sub_offset(sub) + self.vad_area.set_sub_offset(sub) + self.level_area.set_sub_offset(sub) + + if eof: + self._on_eof() + return False + return True + + def _on_tick_clock(self, _widget, _frame_clock): + return True if self._drain_and_redraw() else False + + def _on_timer(self): + return GLib.SOURCE_CONTINUE if self._drain_and_redraw() \ + else GLib.SOURCE_REMOVE + + def _ingest(self, frame_number, vad_flag, energy, noise, ceps_ints): + self.recv_frames += 1 + self._last_frame_mono = time.monotonic() + ceps = decode_ceps_frame(ceps_ints) + speech = vad_flag != 0 + + if speech != self.prev_speech: + t = frame_number * SOF_HOP_SEC + tag = "SPEECH" if speech else "SILENCE" + print(f" [{t:7.2f}s] {tag} (hop {frame_number})", flush=True) + self.prev_speech = speech + + # Scroll left and append new frame on the right. + self.ceps_buf[:-1] = self.ceps_buf[1:] + self.ceps_buf[-1] = ceps + self.vad_buf[:-1] = self.vad_buf[1:] + self.vad_buf[-1] = 1.0 if speech else 0.0 + self.energy_buf[:-1] = self.energy_buf[1:] + self.energy_buf[-1] = energy + self.noise_buf[:-1] = self.noise_buf[1:] + self.noise_buf[-1] = noise + + def _on_eof(self): + if self._closing: + return + if self.proc.poll() is None: + self.proc.terminate() + try: + rc = self.proc.wait(timeout=2) + except subprocess.TimeoutExpired: + self.proc.kill() + rc = self.proc.wait() + try: + stderr_out = self.proc.stderr.read().decode(errors='replace') + except Exception: + stderr_out = '' + print(f"\ncrecord exited with code {rc}") + if stderr_out: + print(f"stderr: {stderr_out}") + self.window.close() + + # --- shutdown ----------------------------------------------------- + def _on_close(self, *_args): + self._closing = True + if self._tick_id: + self.ceps_area.remove_tick_callback(self._tick_id) + self._tick_id = 0 + if self._timer_id: + GLib.source_remove(self._timer_id) + self._timer_id = 0 + if self.proc.poll() is None: + self.proc.terminate() + try: + self.proc.wait(timeout=3) + except subprocess.TimeoutExpired: + self.proc.kill() + self.proc.wait() + print(f"\nCapture stopped. Received {self.recv_frames} frames.") + return False + + +def main(): + parser = argparse.ArgumentParser( + description="Live scrolling MFCC cepstral coefficient viewer " + "from SOF compress PCM capture (GTK 4 / GSK)") + parser.add_argument('--card', '-c', type=int, default=0, + help='ALSA card number (default: 0)') + parser.add_argument('--device', '-d', type=int, default=54, + help='ALSA compress device number (default: 54)') + parser.add_argument('--width', '-w', type=int, default=SPECTROGRAM_WIDTH, + help=f'Spectrogram width in frames (default: {SPECTROGRAM_WIDTH})') + parser.add_argument('--num-ceps', '-n', type=int, default=DEFAULT_NUM_CEPS, + help=f'Number of cepstral coefficients (default: {DEFAULT_NUM_CEPS})') + args = parser.parse_args() + + print("=== SOF MFCC Cepstral Coefficient Viewer (Compress PCM, GTK 4) ===\n") + + signal.signal(signal.SIGINT, signal.SIG_DFL) + + app = Gtk.Application(application_id='org.sof.ceps_spectrogram') + holder = {} + + def on_activate(application): + viewer = CepsViewer(application, args.card, args.device, + args.width, args.num_ceps) + viewer.window.present() + holder['viewer'] = viewer + + app.connect('activate', on_activate) + sys.exit(app.run(None)) + + +if __name__ == '__main__': + main() diff --git a/src/audio/mfcc/tune/sof_mel_spectrogram_compress.py b/src/audio/mfcc/tune/sof_mel_spectrogram_compress.py new file mode 100755 index 000000000000..e85e0494cf22 --- /dev/null +++ b/src/audio/mfcc/tune/sof_mel_spectrogram_compress.py @@ -0,0 +1,625 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) 2026, Intel Corporation. + +"""Live scrolling mel spectrogram viewer for SOF compress PCM capture. + +GTK 4 application that displays a live scrolling mel spectrogram with +VAD status from a SOF compress audio-features PCM. Rendering uses +``Gtk.Snapshot`` with a ``Gdk.MemoryTexture`` for the spectrogram so +that the per-frame upload is handed to the GSK GPU renderer; the small +VAD / level strips use Cairo snapshot nodes. + +Dependencies (Debian/Ubuntu): + sudo apt install python3-gi gir1.2-gtk-4.0 + pip install numpy + +Frame format: [magic(int32), frame_number(uint32), reserved(int32), + energy(int32), noise_energy(int32), vad_flag(int32), + mel[0..79](int32)] + +Usage: + python sof_mel_spectrogram_compress.py [--card 0] [--device 54] + python sof_mel_spectrogram_compress.py --width 400 +""" + +import argparse +import os +import queue +import signal +import struct +import subprocess +import sys +import threading +import time + +import numpy as np + +import gi +gi.require_version('Gtk', '4.0') +gi.require_version('Gdk', '4.0') +gi.require_version('Gsk', '4.0') +gi.require_version('Graphene', '1.0') +gi.require_version('Pango', '1.0') +from gi.repository import Gdk, GLib, Gsk, Gtk, Graphene, Pango # noqa: E402 + +# SOF compress mel frame format constants (with DSP data header) +SOF_MAGIC_BYTES = struct.pack('<i', 0x6D666363) # ASCII 'mfcc' as int32 +SOF_NUM_HEADER = 6 # magic, frame_number, reserved, energy, noise_energy, vad_flag +SOF_Q_FORMAT = 23 # Q9.23 fixed-point +SOF_NUM_MEL = 80 +SOF_FRAME_INTS = SOF_NUM_HEADER + SOF_NUM_MEL # 86 int32 per frame +SOF_FRAME_BYTES = SOF_FRAME_INTS * 4 # 344 bytes per frame +SOF_HOP_SEC = 0.01 # 10 ms per STFT hop + +SPECTROGRAM_WIDTH = 200 # default number of frames visible + +# Color range for the mel image (float coefficients) +MEL_VMIN = -2.0 +MEL_VMAX = 2.0 + +# Fallback redraw period when no frame clock is available (ms). +GUI_REFRESH_MS = 16 + + +def decode_mel_frame(raw_ints): + """Convert 80 int32 Q9.23 values to float32 mel coefficients.""" + return raw_ints.astype(np.float32) / (2 ** SOF_Q_FORMAT) + + +def parse_frame(buf): + """Parse one complete mel frame from a bytearray buffer. + + Mutates buf in-place (deletes consumed bytes). + Returns: (frame_number, vad_flag, energy, noise, mel_ints) or + (None, None, None, None, None) when no frame is ready. + """ + idx = buf.find(SOF_MAGIC_BYTES) + if idx < 0: + if len(buf) > 3: + del buf[:-3] + return None, None, None, None, None + end = idx + SOF_FRAME_BYTES + if end > len(buf): + del buf[:idx] + return None, None, None, None, None + + frame_number = struct.unpack_from('<I', buf, idx + 4)[0] + energy_int = struct.unpack_from('<i', buf, idx + 12)[0] + noise_int = struct.unpack_from('<i', buf, idx + 16)[0] + vad_flag = struct.unpack_from('<i', buf, idx + 20)[0] + + mel_bytes = bytes(buf[idx + SOF_NUM_HEADER * 4:end]) + mel_ints = np.frombuffer(mel_bytes, dtype=np.int32) + del buf[:end] + energy = energy_int / (2 ** SOF_Q_FORMAT) + noise = noise_int / (2 ** SOF_Q_FORMAT) + return frame_number, vad_flag, energy, noise, mel_ints + + +def start_crecord(card, device): + """Spawn crecord as subprocess; return Popen.""" + crecord_cmd = [ + 'crecord', '-v', + '-c', str(card), + '-d', str(device), + '-I', 'BESPOKE', + '-R', '16000', + '-C', '2', + '-F', 'S32_LE', + '-b', '6144', + '-f', '3', + ] + cmd = ['stdbuf', '-o0'] + crecord_cmd + print(f"Starting compress capture: {' '.join(crecord_cmd)}") + return subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + bufsize=0) + + +def _build_turbo_lut(n=256): + """Return an Nx4 uint8 RGBA lookup table for the 'turbo' colormap. + + Polynomial approximation by A. Mikhailov (Google, public-domain + snippet) — fast and dependency-free. + """ + t = np.linspace(0.0, 1.0, n, dtype=np.float32) + r = (0.13572138 + 4.61539260 * t - 42.66032258 * t**2 + + 132.13108234 * t**3 - 152.94239396 * t**4 + + 59.28637943 * t**5) + g = (0.09140261 + 2.19418839 * t + 4.84296658 * t**2 + - 14.18503333 * t**3 + 4.27729857 * t**4 + + 2.82956604 * t**5) + b = (0.10667330 + 12.64194608 * t - 60.58204836 * t**2 + + 110.36276771 * t**3 - 89.90310912 * t**4 + + 27.34824973 * t**5) + rgb = np.clip(np.stack([r, g, b], axis=1), 0.0, 1.0) + rgba = np.concatenate( + [rgb, np.ones((n, 1), dtype=np.float32)], axis=1) + return (rgba * 255.0).astype(np.uint8) + + +TURBO_LUT = _build_turbo_lut(256) + + +class MelSpectrogramArea(Gtk.Widget): + """GTK 4 widget that renders the mel ring buffer as a GPU texture. + + The numpy buffer is colour-mapped to RGBA8 once per redraw, wrapped + in a ``Gdk.MemoryTexture`` and pushed to the snapshot. The GSK + renderer uploads it to the GPU and scales it to the widget size. + + Supports sub-pixel scrolling via :meth:`set_sub_offset`: the texture + is built with one extra column on the right (a hold of the latest + frame) and translated left by ``sub * column_width`` so the newest + column slides smoothly in between data arrivals. + """ + + def __init__(self, mel_buf, vmin, vmax): + super().__init__() + self._mel_buf = mel_buf # shape (frames, bins) + self._vmin = vmin + self._vmax = vmax + self._lut = TURBO_LUT + self._sub = 0.0 + self.set_hexpand(True) + self.set_vexpand(True) + + def set_sub_offset(self, sub): + if sub < 0.0: + sub = 0.0 + elif sub > 1.0: + sub = 1.0 + if sub != self._sub: + self._sub = sub + self.queue_draw() + + def _build_texture(self): + bins = self._mel_buf.shape[1] + frames = self._mel_buf.shape[0] + norm = (self._mel_buf - self._vmin) / (self._vmax - self._vmin) + np.clip(norm, 0.0, 1.0, out=norm) + idx = (norm * 255.0).astype(np.uint8) # (frames, bins) + # Extend on the right by holding the latest column constant so the + # sub-pixel translate has something to reveal at the right edge. + idx_ext = np.empty((frames + 1, bins), dtype=np.uint8) + idx_ext[:frames] = idx + idx_ext[frames] = idx[-1] + idx_img = idx_ext.T[::-1, :] # (bins, frames+1) + rgba = self._lut[idx_img] # (bins, frames+1, 4) + data = rgba.tobytes() + gbytes = GLib.Bytes.new(data) + return Gdk.MemoryTexture.new( + frames + 1, bins, + Gdk.MemoryFormat.R8G8B8A8, + gbytes, + (frames + 1) * 4, + ) + + def do_snapshot(self, snapshot): + w = self.get_width() + h = self.get_height() + if w <= 0 or h <= 0: + return + frames = self._mel_buf.shape[0] + col_w = w / frames + offset_x = -self._sub * col_w + ext_w = w + col_w + clip_rect = Graphene.Rect().init(0.0, 0.0, float(w), float(h)) + draw_rect = Graphene.Rect().init(offset_x, 0.0, float(ext_w), float(h)) + texture = self._build_texture() + snapshot.push_clip(clip_rect) + if hasattr(snapshot, 'append_scaled_texture'): + snapshot.append_scaled_texture( + texture, Gsk.ScalingFilter.LINEAR, draw_rect) + else: + snapshot.append_texture(texture, draw_rect) + snapshot.pop() + + +class CurveStripArea(Gtk.Widget): + """Strip plot rendered with GSK render nodes (GPU path). + + All drawing goes through native ``Gsk`` nodes so the GL/Vulkan + renderer handles compositing on the GPU: + + * background & grid -> ``snapshot.append_color()`` + * curves -> ``snapshot.append_stroke()`` with ``Gsk.Path`` + * tick / title text -> ``snapshot.append_layout()`` + + Requires GTK 4.14+ (for ``Gsk.PathBuilder`` and + ``Gtk.Snapshot.append_stroke``). + """ + + def __init__(self, get_data, *, ymin=None, ymax=None, autoscale=False, + lines=(), background=(0.10, 0.10, 0.12), + yticks=None, label=None, height_request=80): + super().__init__() + self._get_data = get_data + self._ymin = ymin + self._ymax = ymax + self._autoscale = autoscale + self._lines = lines + self._bg = self._mk_rgba((background[0], background[1], background[2], 1.0)) + self._grid_color = self._mk_rgba((0.4, 0.4, 0.45, 0.6)) + self._text_color = self._mk_rgba((0.85, 0.85, 0.85, 0.9)) + self._line_colors = [self._mk_rgba(rgba) for _, rgba in lines] + self._stroke = Gsk.Stroke.new(1.5) + self._stroke.set_line_cap(Gsk.LineCap.ROUND) + self._stroke.set_line_join(Gsk.LineJoin.ROUND) + self._yticks = yticks + self._label = label + self._tick_font = Pango.FontDescription.from_string("sans-serif 9") + self._title_font = Pango.FontDescription.from_string("sans-serif 10") + self._tick_layouts = None # built lazily once we have a Pango context + self._title_layout = None + self._sub = 0.0 + self.set_hexpand(True) + self.set_size_request(-1, height_request) + + def set_sub_offset(self, sub): + if sub < 0.0: + sub = 0.0 + elif sub > 1.0: + sub = 1.0 + if sub != self._sub: + self._sub = sub + self.queue_draw() + + @staticmethod + def _mk_rgba(t): + c = Gdk.RGBA() + c.red, c.green, c.blue, c.alpha = ( + float(t[0]), float(t[1]), float(t[2]), float(t[3])) + return c + + def _ensure_layouts(self): + if self._tick_layouts is not None: + return + pctx = self.get_pango_context() + self._tick_layouts = [] + if self._yticks: + for yv, txt in self._yticks: + layout = Pango.Layout(pctx) + layout.set_font_description(self._tick_font) + layout.set_text(str(txt), -1) + self._tick_layouts.append((yv, layout)) + if self._label: + self._title_layout = Pango.Layout(pctx) + self._title_layout.set_font_description(self._title_font) + self._title_layout.set_text(self._label, -1) + + def _yrange(self, arrays): + if not self._autoscale: + return self._ymin, self._ymax + vmin = min(float(a.min()) for a in arrays if a.size) + vmax = max(float(a.max()) for a in arrays if a.size) + if vmax - vmin < 1e-6: + vmax = vmin + 1.0 + margin = 0.05 * (vmax - vmin) + return vmin - margin, vmax + margin + + @staticmethod + def _build_path(arr, x_scale, h, ymin, yspan): + """Build a stroke path covering [0, n*x_scale] (one extra sample held).""" + builder = Gsk.PathBuilder.new() + n = arr.shape[0] + ys = h - (arr - ymin) / yspan * h + builder.move_to(0.0, float(ys[0])) + for i in range(1, n): + builder.line_to(float(i * x_scale), float(ys[i])) + # Hold last value for one extra column so the slide-in area is filled. + builder.line_to(float(n * x_scale), float(ys[-1])) + return builder.to_path() + + def do_snapshot(self, snapshot): + w = self.get_width() + h = self.get_height() + if w <= 0 or h <= 0: + return + + bg_rect = Graphene.Rect().init(0.0, 0.0, float(w), float(h)) + snapshot.append_color(self._bg, bg_rect) + + data = self._get_data() + arrays = [data[k] for k, _ in self._lines] + if not arrays or arrays[0].size == 0: + return + n = arrays[0].size + ymin, ymax = self._yrange(arrays) + yspan = (ymax - ymin) or 1.0 + x_scale = w / max(n - 1, 1) + offset_x = -self._sub * x_scale + + # Y grid lines as 1px coloured rectangles (GSK color nodes). + if self._yticks: + for yv, _ in self._yticks: + py = h - (yv - ymin) / yspan * h + grid_rect = Graphene.Rect().init(0.0, py - 0.5, float(w), 1.0) + snapshot.append_color(self._grid_color, grid_rect) + + # Curves -> GSK stroke nodes (GPU rasterised), translated for smooth scroll. + clip_rect = Graphene.Rect().init(0.0, 0.0, float(w), float(h)) + snapshot.push_clip(clip_rect) + snapshot.save() + snapshot.translate(Graphene.Point().init(offset_x, 0.0)) + for (key, _), color in zip(self._lines, self._line_colors): + path = self._build_path(data[key], x_scale, h, ymin, yspan) + snapshot.append_stroke(path, self._stroke, color) + snapshot.restore() + snapshot.pop() + + # Text -> Pango layouts via append_layout (no scroll offset). + self._ensure_layouts() + if self._tick_layouts: + for yv, layout in self._tick_layouts: + py = h - (yv - ymin) / yspan * h + _, ext = layout.get_pixel_extents() + ty = max(0.0, min(float(h) - ext.height, py - ext.height - 1.0)) + snapshot.save() + snapshot.translate(Graphene.Point().init(4.0, ty)) + snapshot.append_layout(layout, self._text_color) + snapshot.restore() + + if self._title_layout is not None: + _, ext = self._title_layout.get_pixel_extents() + snapshot.save() + snapshot.translate( + Graphene.Point().init(float(w) - ext.width - 6.0, 2.0)) + snapshot.append_layout(self._title_layout, self._text_color) + snapshot.restore() + + +class MelViewer: + """Top-level controller: capture process + GTK window.""" + + def __init__(self, app, card, device, width): + self.app = app + self.width_frames = width + + # Ring buffer stored as (frames, mel_bins) for cheap shifts along axis 0. + self.mel_buf = np.zeros((width, SOF_NUM_MEL), dtype=np.float32) + self.vad_buf = np.zeros(width, dtype=np.float32) + self.energy_buf = np.zeros(width, dtype=np.float32) + self.noise_buf = np.zeros(width, dtype=np.float32) + + self.recv_frames = 0 + self.prev_speech = None + self._closing = False + self._last_frame_mono = None # timestamp of most recent ingest + self._frame_period = SOF_HOP_SEC # nominal 10 ms per hop + + self._build_ui() + + # Start capture + self.proc = start_crecord(card, device) + self.frame_q = queue.Queue() + self.reader = threading.Thread(target=self._reader_thread, daemon=True) + self.reader.start() + + # Vsync-aligned redraws via the frame clock — fires once per monitor + # refresh while the widget is mapped. Falls back to a periodic timer + # if add_tick_callback isn't available for some reason. + self._tick_id = 0 + self._timer_id = 0 + if hasattr(self.mel_area, 'add_tick_callback'): + self._tick_id = self.mel_area.add_tick_callback(self._on_tick_clock) + else: + self._timer_id = GLib.timeout_add(GUI_REFRESH_MS, self._on_timer) + + print(f"Spectrogram width: {width} frames ({width * SOF_HOP_SEC:.1f}s)") + if self._tick_id: + print("GUI refresh: vsync-aligned via frame clock, " + "sub-pixel scroll enabled") + else: + print(f"GUI refresh: fallback timer at {GUI_REFRESH_MS} ms " + f"({1000.0 / GUI_REFRESH_MS:.0f} FPS)") + print() + + def _build_ui(self): + self.window = Gtk.ApplicationWindow(application=self.app) + self.window.set_title("SOF Mel Spectrogram (compress PCM) — DSP VAD") + self.window.set_default_size(1100, 600) + self.window.connect('close-request', self._on_close) + + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2) + box.set_margin_start(4) + box.set_margin_end(4) + box.set_margin_top(4) + box.set_margin_bottom(4) + self.window.set_child(box) + + self.mel_area = MelSpectrogramArea(self.mel_buf, MEL_VMIN, MEL_VMAX) + self.vad_area = CurveStripArea( + lambda: {'vad': self.vad_buf}, + ymin=-0.1, ymax=1.1, + lines=[('vad', (0.2, 0.9, 0.2, 1.0))], + yticks=[(0, 'Silent'), (1, 'Speech')], + label='VAD', + height_request=70, + ) + self.level_area = CurveStripArea( + lambda: {'energy': self.energy_buf, 'noise': self.noise_buf}, + autoscale=True, + lines=[ + ('energy', (1.0, 0.9, 0.2, 1.0)), + ('noise', (0.2, 0.9, 1.0, 1.0)), + ], + label='Level (Y=speech, C=noise)', + height_request=110, + ) + + # Vertical stretch: spectrogram dominates. + self.mel_area.set_vexpand(True) + box.append(self.mel_area) + box.append(self.vad_area) + box.append(self.level_area) + + # --- I/O thread --------------------------------------------------- + def _reader_thread(self): + buf = bytearray() + raw_fd = self.proc.stdout.fileno() + try: + while True: + data = os.read(raw_fd, SOF_FRAME_BYTES * 4) + if not data: + break + buf.extend(data) + while True: + fn, vf, en, no, mi = parse_frame(buf) + if mi is None: + break + self.frame_q.put((fn, vf, en, no, mi)) + except OSError: + pass + self.frame_q.put(None) + + # --- GUI tick ----------------------------------------------------- + def _drain_and_redraw(self): + """Drain queued frames, update sub-pixel offset, queue redraws. + + Returns True while running, False when EOF. + """ + drained = 0 + eof = False + while True: + try: + item = self.frame_q.get_nowait() + except queue.Empty: + break + if item is None: + eof = True + break + fn, vf, en, no, mi = item + self._ingest(fn, vf, en, no, mi) + drained += 1 + if drained >= 64: + break + + # Sub-pixel scroll position: time since last ingest as a fraction of + # the nominal frame period, clamped to [0, 1] so we never overshoot. + if self._last_frame_mono is None: + sub = 0.0 + else: + sub = (time.monotonic() - self._last_frame_mono) / self._frame_period + if sub < 0.0: + sub = 0.0 + elif sub > 1.0: + sub = 1.0 + self.mel_area.set_sub_offset(sub) + self.vad_area.set_sub_offset(sub) + self.level_area.set_sub_offset(sub) + + # If no new data arrived, still queue a redraw so the sub-pixel + # translate advances each vsync. set_sub_offset only does it on + # a change; force it when sub is at 1.0 (no-op) and frames were 0. + if drained == 0 and sub >= 1.0: + # We've slid the maximum distance; nothing to redraw. + pass + + if eof: + self._on_eof() + return False + return True + + def _on_tick_clock(self, _widget, _frame_clock): + return True if self._drain_and_redraw() else False + + def _on_timer(self): + return GLib.SOURCE_CONTINUE if self._drain_and_redraw() \ + else GLib.SOURCE_REMOVE + + def _ingest(self, frame_number, vad_flag, energy, noise, mel_ints): + self.recv_frames += 1 + self._last_frame_mono = time.monotonic() + mel = decode_mel_frame(mel_ints) + speech = vad_flag != 0 + + if speech != self.prev_speech: + t = frame_number * SOF_HOP_SEC + tag = "SPEECH" if speech else "SILENCE" + print(f" [{t:7.2f}s] {tag} (hop {frame_number})", flush=True) + self.prev_speech = speech + + # Scroll left and append new frame on the right. + self.mel_buf[:-1] = self.mel_buf[1:] + self.mel_buf[-1] = mel + self.vad_buf[:-1] = self.vad_buf[1:] + self.vad_buf[-1] = 1.0 if speech else 0.0 + self.energy_buf[:-1] = self.energy_buf[1:] + self.energy_buf[-1] = energy + self.noise_buf[:-1] = self.noise_buf[1:] + self.noise_buf[-1] = noise + + def _on_eof(self): + if self._closing: + return + if self.proc.poll() is None: + self.proc.terminate() + try: + rc = self.proc.wait(timeout=2) + except subprocess.TimeoutExpired: + self.proc.kill() + rc = self.proc.wait() + try: + stderr_out = self.proc.stderr.read().decode(errors='replace') + except Exception: + stderr_out = '' + print(f"\ncrecord exited with code {rc}") + if stderr_out: + print(f"stderr: {stderr_out}") + self.window.close() + + # --- shutdown ----------------------------------------------------- + def _on_close(self, *_args): + self._closing = True + if self._tick_id: + self.mel_area.remove_tick_callback(self._tick_id) + self._tick_id = 0 + if self._timer_id: + GLib.source_remove(self._timer_id) + self._timer_id = 0 + if self.proc.poll() is None: + self.proc.terminate() + try: + self.proc.wait(timeout=3) + except subprocess.TimeoutExpired: + self.proc.kill() + self.proc.wait() + print(f"\nCapture stopped. Received {self.recv_frames} frames.") + return False # allow the window to close + + +def main(): + parser = argparse.ArgumentParser( + description="Live scrolling mel spectrogram viewer " + "from SOF compress PCM capture (GTK 4 / GSK)") + parser.add_argument('--card', '-c', type=int, default=0, + help='ALSA card number (default: 0)') + parser.add_argument('--device', '-d', type=int, default=54, + help='ALSA compress device number (default: 54)') + parser.add_argument('--width', '-w', type=int, default=SPECTROGRAM_WIDTH, + help=f'Spectrogram width in frames (default: {SPECTROGRAM_WIDTH})') + args = parser.parse_args() + + print("=== SOF Mel Spectrogram Viewer (Compress PCM, GTK 4) ===\n") + + # Let Python receive Ctrl-C while the GLib loop is running. + signal.signal(signal.SIGINT, signal.SIG_DFL) + + app = Gtk.Application(application_id='org.sof.mel_spectrogram') + holder = {} + + def on_activate(application): + viewer = MelViewer(application, args.card, args.device, args.width) + viewer.window.present() + holder['viewer'] = viewer + + app.connect('activate', on_activate) + sys.exit(app.run(None)) + + +if __name__ == '__main__': + main() diff --git a/src/audio/mfcc/tune/sof_mel_to_text_live_compress.py b/src/audio/mfcc/tune/sof_mel_to_text_live_compress.py new file mode 100755 index 000000000000..6f0032d241fa --- /dev/null +++ b/src/audio/mfcc/tune/sof_mel_to_text_live_compress.py @@ -0,0 +1,490 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) 2026, Intel Corporation. + +"""Live SOF mel capture from compress PCM with DTX-aware Whisper transcription. + +Captures mel frames from ALSA compress device (crecord) with embedded VAD flag. +Frame format: [magic(int32), frame_number(uint32), reserved(int32), + energy(int32), noise_energy(int32), vad_flag(int32), + mel[0..79](int32)] + +With DTX enabled, the DSP sends a configurable number of trailing silence +frames (e.g. 20 = 200ms) after each speech-to-silence transition, then +suppresses further silence. This gives the host enough silence to detect +end-of-speech via a wall-clock patience timer. + +Usage: + python sof_mel_to_text_live_compress.py [--card 0] [--device 54] [--model whisper-medium-int4-ov] +""" + +import argparse +import os +import queue +import struct +import subprocess +import threading +import time +import numpy as np +import openvino as ov +import huggingface_hub as hf_hub +from pathlib import Path + +# SOF compress mel frame format constants (with DSP data header) +SOF_MAGIC_BYTES = struct.pack('<i', 0x6D666363) # ASCII 'mfcc' as int32 +SOF_NUM_HEADER = 6 # magic, frame_number, reserved, energy, noise_energy, vad_flag +SOF_Q_FORMAT = 23 # Q9.23 fixed-point +SOF_NUM_MEL = 80 +SOF_FRAME_INTS = SOF_NUM_HEADER + SOF_NUM_MEL # 86 int32 per frame +SOF_FRAME_BYTES = SOF_FRAME_INTS * 4 # 344 bytes per frame +SOF_HOP_SEC = 0.01 # 10 ms per STFT hop + +# Speech buffering +SILENCE_PATIENCE_S = 0.2 # seconds of silence patience before triggering +MIN_SPEECH_MS = 500 # minimum speech duration to send to Whisper +MIN_SPEECH_FRAMES = MIN_SPEECH_MS // 10 # 50 frames at 10ms/frame +MAX_SPEECH_MS = 60000 # max speech buffer before forced transcription +MAX_SPEECH_FRAMES = MAX_SPEECH_MS // 10 # 6000 frames at 10ms/frame + +# Whisper model constants +WHISPER_FEATURE_SIZE = 80 +WHISPER_NB_MAX_FRAMES = 3000 # 30 seconds at 10ms per frame + + +def decode_mel_frame(raw_ints): + """Convert 80 int32 Q9.23 values to float32 mel coefficients.""" + return raw_ints.astype(np.float32) / (2 ** SOF_Q_FORMAT) + + +# ---------- Whisper inference ---------- + +class WhisperTranscriber: + """Whisper encoder+decoder using OpenVINO, runs in a background thread.""" + + def __init__(self, model_path, encoder_device="NPU", decoder_device="CPU"): + self.model_path = model_path + core = ov.Core() + encoder_xml = str(Path(model_path) / "openvino_encoder_model.xml") + decoder_xml = str(Path(model_path) / "openvino_decoder_model.xml") + # NPU requires static shapes — fix [?,?,3000] to [1,80,3000] + encoder_model = core.read_model(encoder_xml) + encoder_model.reshape({0: [1, WHISPER_FEATURE_SIZE, WHISPER_NB_MAX_FRAMES]}) + self.encoder = core.compile_model(encoder_model, encoder_device) + self.decoder = core.compile_model(decoder_xml, decoder_device) + self._load_tokenizer() + self._busy = False + self._lock = threading.Lock() + + def _load_tokenizer(self): + """Load Whisper tokenizer.""" + try: + from transformers import WhisperTokenizer + self.tokenizer = WhisperTokenizer.from_pretrained(self.model_path) + self._tokenizer_type = "hf" + except ImportError: + import openvino_genai as ov_genai + self.tokenizer = ov_genai.Tokenizer(self.model_path) + self._tokenizer_type = "ov" + + def is_busy(self): + with self._lock: + return self._busy + + def transcribe_async(self, mel_frames, callback): + """Run transcription in a background thread. + + Args: + mel_frames: list of np.ndarray [80] mel frames + callback: function(text) called with result + """ + with self._lock: + if self._busy: + return False + self._busy = True + + t = threading.Thread(target=self._run, args=(mel_frames, callback), + daemon=True) + t.start() + return True + + def _run(self, mel_frames, callback): + try: + text = self._transcribe(mel_frames) + callback(text) + except Exception as e: + print(f" [Whisper ERROR] {e}", flush=True) + finally: + with self._lock: + self._busy = False + + def _transcribe(self, mel_frames): + """Encode mel frames and decode to text.""" + n_frames = len(mel_frames) + if n_frames == 0: + return "" + + # Stack frames into [80, n_frames] + features = np.column_stack(mel_frames).astype(np.float32) + + # Pad to 3000 frames + silence_val = features.min() + padded = np.full((WHISPER_FEATURE_SIZE, WHISPER_NB_MAX_FRAMES), + silence_val, dtype=np.float32) + n = min(n_frames, WHISPER_NB_MAX_FRAMES) + padded[:, :n] = features[:, :n] + + # Encoder + t0 = time.time() + encoder_input = padded.reshape(1, WHISPER_FEATURE_SIZE, WHISPER_NB_MAX_FRAMES) + encoder_req = self.encoder.create_infer_request() + encoder_req.set_tensor("input_features", ov.Tensor(encoder_input)) + encoder_req.infer() + hidden_state = encoder_req.get_tensor("last_hidden_state").data.copy() + t1 = time.time() + print(f" [Whisper] encoder: {t1-t0:.2f}s", flush=True) + + # Decoder: greedy decode + token_ids = self._greedy_decode(hidden_state) + t2 = time.time() + print(f" [Whisper] decoder: {t2-t1:.2f}s ({len(token_ids)} tokens)", + flush=True) + + # Convert to text + text_tokens = [t for t in token_ids if t < 50257] + text = self.tokenizer.decode(text_tokens) + + return text.strip() + + def _greedy_decode(self, hidden_state, max_tokens=448): + """Greedy decoding loop.""" + sot_tokens = [50258, 50259, 50359, 50363] + eos_token = 50257 + + decoder_req = self.decoder.create_infer_request() + input_names = [inp.get_any_name() for inp in self.decoder.inputs] + has_cache_position = "cache_position" in input_names + + decoder_req.set_tensor("encoder_hidden_states", ov.Tensor(hidden_state)) + + # Prefill with SOT tokens + input_ids = np.array([sot_tokens], dtype=np.int64) + beam_idx = np.array([0], dtype=np.int32) + + decoder_req.set_tensor("input_ids", ov.Tensor(input_ids)) + if "beam_idx" in input_names: + decoder_req.set_tensor("beam_idx", ov.Tensor(beam_idx)) + if has_cache_position: + cache_pos = np.arange(len(sot_tokens), dtype=np.int64).reshape(1, -1) + decoder_req.set_tensor("cache_position", ov.Tensor(cache_pos)) + + decoder_req.infer() + logits = decoder_req.get_tensor("logits").data + next_token = int(np.argmax(logits[0, -1, :])) + + generated = [next_token] + position = len(sot_tokens) + + for _ in range(max_tokens - 1): + if next_token == eos_token: + break + + decoder_req.set_tensor("input_ids", + ov.Tensor(np.array([[next_token]], dtype=np.int64))) + if "beam_idx" in input_names: + decoder_req.set_tensor("beam_idx", ov.Tensor(beam_idx)) + if has_cache_position: + decoder_req.set_tensor("cache_position", + ov.Tensor(np.array([[position]], dtype=np.int64))) + + decoder_req.infer() + logits = decoder_req.get_tensor("logits").data + next_token = int(np.argmax(logits[0, -1, :])) + generated.append(next_token) + position += 1 + + return generated + + +# ---------- Frame parser ---------- + +def parse_frame(buf): + """Parse one complete mel frame from a bytearray buffer. + + Frame layout: [magic(4B), frame_number(4B), reserved(4B), energy(4B), + noise_energy(4B), vad_flag(4B), mel[0..79](320B)] = 344 bytes + + In compress PCM mode, each read delivers complete frames with no zero + padding, so we search for magic and extract. + + Mutates buf in-place (deletes consumed bytes). + Returns: (frame_number, vad_flag, mel_ints) or (None, None, None) + """ + idx = buf.find(SOF_MAGIC_BYTES) + if idx < 0: + if len(buf) > 3: + del buf[:-3] + return None, None, None + end = idx + SOF_FRAME_BYTES + if end > len(buf): + del buf[:idx] + return None, None, None + + # Parse header fields + frame_number = struct.unpack_from('<I', buf, idx + 4)[0] + vad_flag = struct.unpack_from('<i', buf, idx + 20)[0] + + # Parse 80 mel coefficients (after 24-byte header) + mel_bytes = bytes(buf[idx + SOF_NUM_HEADER * 4:end]) + mel_ints = np.frombuffer(mel_bytes, dtype=np.int32) + del buf[:end] + return frame_number, vad_flag, mel_ints + + +# ---------- Main capture + transcription loop ---------- + +def try_transcribe(transcriber, speech_buffer, t, on_transcription): + """Attempt to send speech buffer to Whisper. Returns True if sent or discarded.""" + n = len(speech_buffer) + duration = n * SOF_HOP_SEC + + if n < MIN_SPEECH_FRAMES: + print(f" [{t:7.2f}s] Too short ({duration:.1f}s), " + f"discarding {n} frames", flush=True) + return True + + if not transcriber.is_busy(): + print(f" [{t:7.2f}s] Transcribing {n} frames " + f"({duration:.1f}s)...", flush=True) + frames_copy = list(speech_buffer) + transcriber.transcribe_async(frames_copy, on_transcription) + return True + + print(f" [{t:7.2f}s] (Whisper busy, queuing {n} frames)", flush=True) + return False + + +def run_capture(card, device, model_path, encoder_device, decoder_device, + patience=SILENCE_PATIENCE_S): + """Main capture loop: crecord compress PCM → DSP VAD → buffer speech → Whisper. + + With DTX, the FW sends: + - All VAD=1 (speech) frames + - Trailing VAD=0 silence frames (e.g. 20 = 200ms) after speech ends + + A wall-clock patience timer triggers transcription after silence. + If speech resumes within the patience window, buffering continues. + """ + + transcriber = WhisperTranscriber(model_path, encoder_device=encoder_device, + decoder_device=decoder_device) + + crecord_cmd = [ + 'crecord', '-v', + '-c', str(card), + '-d', str(device), + '-I', 'BESPOKE', + '-R', '16000', + '-C', '2', + '-F', 'S32_LE', + '-b', '6144', + '-f', '3', + ] + + # Wrap with stdbuf to disable crecord's stdio buffering. When stdout + # is a pipe, C stdio uses full buffering (~4-8KB). A single DTX + # silence frame (344 bytes) would sit in crecord's buffer until enough + # data accumulates, delaying the patience timer by many seconds. + cmd = ['stdbuf', '-o0'] + crecord_cmd + + print(f"Starting compress capture: {' '.join(crecord_cmd)}") + print(f"VAD source: DSP (embedded in stream, DTX mode)") + print(f"Silence patience: {patience}s") + print(f"Whisper model: {model_path} (encoder: {encoder_device}, decoder: {decoder_device})") + print() + + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + bufsize=0) + + # Reader thread feeds parsed frames into a queue to decouple pipe I/O + # from the patience timer in the main thread. + frame_q = queue.Queue() + + def reader_thread(): + buf = bytearray() + raw_fd = proc.stdout.fileno() + try: + while True: + # Use os.read() for unbuffered reads — returns immediately + # when any data is available. Python's read(n) waits for + # exactly n bytes, which delays SILENCE frames until the + # next speech burst fills the buffer. + data = os.read(raw_fd, SOF_FRAME_BYTES * 4) + if not data: + break + buf.extend(data) + while True: + frame_number, vad_flag, frame_ints = parse_frame(buf) + if frame_ints is None: + break + frame_q.put((frame_number, vad_flag, frame_ints)) + except (OSError, ValueError): + pass + frame_q.put(None) # sentinel + + reader = threading.Thread(target=reader_thread, daemon=True) + reader.start() + + recv_frames = 0 + prev_speech = None + last_hop = 0 + + # Speech buffering state + speech_buffer = [] # list of mel frames during speech + silence_time = None # wall-clock time when first VAD=0 arrived + pending_queue = None # queued frames waiting for Whisper to become free + pending_t = 0.0 # timestamp for queued frames + + def on_transcription(text): + if text: + print(f"\n >> \"{text}\"\n", flush=True) + else: + print(" [Whisper] empty result", flush=True) + + def flush_speech(t_now): + """Flush speech buffer to Whisper.""" + nonlocal speech_buffer, silence_time, pending_queue, pending_t + if not speech_buffer: + silence_time = None + return + if not try_transcribe(transcriber, speech_buffer, t_now, + on_transcription): + pending_queue = list(speech_buffer) + pending_t = t_now + speech_buffer.clear() + silence_time = None + + try: + while True: + # Calculate queue timeout based on patience timer + get_timeout = 0.1 # default polling interval + if silence_time is not None: + remaining = patience - (time.monotonic() - silence_time) + get_timeout = max(remaining, 0.01) + + try: + item = frame_q.get(timeout=get_timeout) + except queue.Empty: + # Patience expired — flush speech to Whisper + if silence_time is not None: + elapsed = time.monotonic() - silence_time + if elapsed >= patience: + t = last_hop * SOF_HOP_SEC + flush_speech(t) + + # Drain pending queue when Whisper becomes free + if pending_queue is not None and not transcriber.is_busy(): + print(f" [{pending_t:7.2f}s] Whisper free, sending " + f"{len(pending_queue)} queued frames", flush=True) + transcriber.transcribe_async(pending_queue, on_transcription) + pending_queue = None + continue + + if item is None: + # Reader thread ended (crecord exited) + stderr_out = proc.stderr.read().decode(errors='replace') + rc = proc.wait() + print(f"\ncrecord exited with code {rc}") + if stderr_out: + print(f"stderr: {stderr_out}") + break + + frame_number, vad_flag, frame_ints = item + recv_frames += 1 + last_hop = frame_number + mel = decode_mel_frame(frame_ints) + speech = vad_flag != 0 + t = frame_number * SOF_HOP_SEC + + # Print VAD transitions + if speech != prev_speech: + tag = "SPEECH" if speech else "SILENCE" + print(f" [{t:7.2f}s] {tag} (hop {frame_number}, " + f"received {recv_frames})", flush=True) + prev_speech = speech + + # Drain pending queue when Whisper becomes free + if pending_queue is not None and not transcriber.is_busy(): + print(f" [{pending_t:7.2f}s] Whisper free, sending " + f"{len(pending_queue)} queued frames", flush=True) + transcriber.transcribe_async(pending_queue, on_transcription) + pending_queue = None + + # --- Speech buffering logic --- + if speech: + if len(speech_buffer) >= MAX_SPEECH_FRAMES: + n = len(speech_buffer) + duration = n * SOF_HOP_SEC + print(f" [{t:7.2f}s] Buffer full ({duration:.1f}s), " + f"forcing transcription", flush=True) + flush_speech(t) + + speech_buffer.append(mel.copy()) + silence_time = None # speech resumed, cancel patience timer + + else: + # VAD=0: start patience timer if we have buffered speech. + # Don't refresh if already running so trailing silence + # frames don't extend the wait. + if speech_buffer and silence_time is None: + silence_time = time.monotonic() + + except (KeyboardInterrupt, BrokenPipeError): + pass + finally: + # Flush remaining speech + if speech_buffer: + t = last_hop * SOF_HOP_SEC + flush_speech(t) + if proc.poll() is None: + proc.terminate() + try: + proc.wait(timeout=3) + except subprocess.TimeoutExpired: + proc.kill() + proc.wait() + print(f"\n\nCapture stopped. Received {recv_frames} frames.") + + +def main(): + parser = argparse.ArgumentParser( + description="Live SOF mel capture from compress PCM with DTX-aware " + "Whisper transcription") + parser.add_argument('--card', '-c', type=int, default=0, + help='ALSA card number (default: 0)') + parser.add_argument('--device', '-d', type=int, default=54, + help='ALSA compress device number (default: 54)') + parser.add_argument('--model', '-m', default='whisper-medium-int4-ov', + help='Path to Whisper OpenVINO model directory') + parser.add_argument('--encoder-device', default='NPU', + help='OpenVINO device for encoder (default: NPU)') + parser.add_argument('--decoder-device', default='CPU', + help='OpenVINO device for decoder (default: CPU)') + parser.add_argument('--patience', type=float, default=SILENCE_PATIENCE_S, + help=f'Seconds of silence patience before triggering ' + f'transcription (default: {SILENCE_PATIENCE_S})') + args = parser.parse_args() + + model_id = "OpenVINO/" + os.path.basename(args.model) + if not os.path.isdir(args.model): + print(f"Downloading model {model_id} ...") + hf_hub.snapshot_download(model_id, local_dir=args.model) + + print("=== Live SOF Mel → Whisper Transcription (Compress PCM, DTX) ===\n") + run_capture(args.card, args.device, args.model, args.encoder_device, + args.decoder_device, patience=args.patience) + + +if __name__ == '__main__': + main() diff --git a/src/audio/mfcc/tune/sof_mel_to_text_live_dsp_vad.py b/src/audio/mfcc/tune/sof_mel_to_text_live_dsp_vad.py new file mode 100755 index 000000000000..90941b42822a --- /dev/null +++ b/src/audio/mfcc/tune/sof_mel_to_text_live_dsp_vad.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) 2026, Intel Corporation. + +"""Live SOF mel capture with DSP VAD-triggered Whisper transcription. + +Captures mel frames from ALSA with embedded VAD flag from the DSP. +Frame format: [magic(int32), frame_number(uint32), reserved(int32), energy(int32), noise_energy(int32), vad_flag(int32), mel[0..79](int32)] +When silence of 100ms is detected after speech, sends the buffered mel +features to Whisper (OpenVINO encoder+decoder) for transcription. +Capture continues running during Whisper inference. + +Usage: + python sof_mel_to_text_live_dsp_vad.py [--device hw:0,47] [--model whisper-medium-int4-ov] +""" + +import argparse +import os +import struct +import subprocess +import threading +import time +import numpy as np +import openvino as ov +import huggingface_hub as hf_hub +from pathlib import Path + +# SOF mel_s32.raw format constants (with DSP data header) +SOF_MAGIC_BYTES = struct.pack('<i', 0x6D666363) # ASCII 'mfcc' as int32 +SOF_NUM_HEADER = 6 # magic, frame_number, reserved, energy, noise_energy, vad_flag +SOF_Q_FORMAT = 23 # Q9.23 fixed-point +SOF_NUM_MEL = 80 +SOF_FRAME_INTS = SOF_NUM_HEADER + SOF_NUM_MEL # 86 int32 per frame +SOF_FRAME_BYTES = SOF_FRAME_INTS * 4 # 344 bytes per frame + +# Speech buffering +SILENCE_TRIGGER_MS = 100 # ms of silence after speech to trigger transcription +SILENCE_TRIGGER_FRAMES = SILENCE_TRIGGER_MS // 10 # 10 frames at 10ms/frame +MIN_SPEECH_MS = 500 # minimum speech duration to send to Whisper +MIN_SPEECH_FRAMES = MIN_SPEECH_MS // 10 # 50 frames at 10ms/frame +MAX_SPEECH_MS = 60000 # max speech buffer before forced transcription +MAX_SPEECH_FRAMES = MAX_SPEECH_MS // 10 # 6000 frames at 10ms/frame + +# Whisper model constants +WHISPER_FEATURE_SIZE = 80 +WHISPER_NB_MAX_FRAMES = 3000 # 30 seconds at 10ms per frame + + +def decode_mel_frame(raw_ints): + """Convert 80 int32 Q9.23 values to float32 mel coefficients.""" + return raw_ints.astype(np.float32) / (2 ** SOF_Q_FORMAT) + + +# ---------- Whisper inference ---------- + +class WhisperTranscriber: + """Whisper encoder+decoder using OpenVINO, runs in a background thread.""" + + def __init__(self, model_path, encoder_device="NPU", decoder_device="CPU"): + self.model_path = model_path + core = ov.Core() + encoder_xml = str(Path(model_path) / "openvino_encoder_model.xml") + decoder_xml = str(Path(model_path) / "openvino_decoder_model.xml") + # NPU requires static shapes — fix [?,?,3000] to [1,80,3000] + encoder_model = core.read_model(encoder_xml) + encoder_model.reshape({0: [1, WHISPER_FEATURE_SIZE, WHISPER_NB_MAX_FRAMES]}) + self.encoder = core.compile_model(encoder_model, encoder_device) + self.decoder = core.compile_model(decoder_xml, decoder_device) + self._load_tokenizer() + self._busy = False + self._lock = threading.Lock() + + def _load_tokenizer(self): + """Load Whisper tokenizer.""" + try: + from transformers import WhisperTokenizer + self.tokenizer = WhisperTokenizer.from_pretrained(self.model_path) + self._tokenizer_type = "hf" + except ImportError: + import openvino_genai as ov_genai + self.tokenizer = ov_genai.Tokenizer(self.model_path) + self._tokenizer_type = "ov" + + def is_busy(self): + with self._lock: + return self._busy + + def transcribe_async(self, mel_frames, callback): + """Run transcription in a background thread. + + Args: + mel_frames: list of np.ndarray [80] mel frames + callback: function(text) called with result + """ + with self._lock: + if self._busy: + return False + self._busy = True + + t = threading.Thread(target=self._run, args=(mel_frames, callback), + daemon=True) + t.start() + return True + + def _run(self, mel_frames, callback): + try: + text = self._transcribe(mel_frames) + callback(text) + except Exception as e: + print(f" [Whisper ERROR] {e}", flush=True) + finally: + with self._lock: + self._busy = False + + def _transcribe(self, mel_frames): + """Encode mel frames and decode to text.""" + n_frames = len(mel_frames) + if n_frames == 0: + return "" + + # Stack frames into [80, n_frames] + features = np.column_stack(mel_frames).astype(np.float32) + + # Pad to 3000 frames + silence_val = features.min() + padded = np.full((WHISPER_FEATURE_SIZE, WHISPER_NB_MAX_FRAMES), + silence_val, dtype=np.float32) + n = min(n_frames, WHISPER_NB_MAX_FRAMES) + padded[:, :n] = features[:, :n] + + # Encoder + t0 = time.time() + encoder_input = padded.reshape(1, WHISPER_FEATURE_SIZE, WHISPER_NB_MAX_FRAMES) + encoder_req = self.encoder.create_infer_request() + encoder_req.set_tensor("input_features", ov.Tensor(encoder_input)) + encoder_req.infer() + hidden_state = encoder_req.get_tensor("last_hidden_state").data.copy() + t1 = time.time() + print(f" [Whisper] encoder: {t1-t0:.2f}s", flush=True) + + # Decoder: greedy decode + token_ids = self._greedy_decode(hidden_state) + t2 = time.time() + print(f" [Whisper] decoder: {t2-t1:.2f}s ({len(token_ids)} tokens)", + flush=True) + + # Convert to text + text_tokens = [t for t in token_ids if t < 50257] + text = self.tokenizer.decode(text_tokens) + + return text.strip() + + def _greedy_decode(self, hidden_state, max_tokens=448): + """Greedy decoding loop.""" + sot_tokens = [50258, 50259, 50359, 50363] + eos_token = 50257 + + decoder_req = self.decoder.create_infer_request() + input_names = [inp.get_any_name() for inp in self.decoder.inputs] + has_cache_position = "cache_position" in input_names + + decoder_req.set_tensor("encoder_hidden_states", ov.Tensor(hidden_state)) + + # Prefill with SOT tokens + input_ids = np.array([sot_tokens], dtype=np.int64) + beam_idx = np.array([0], dtype=np.int32) + + decoder_req.set_tensor("input_ids", ov.Tensor(input_ids)) + if "beam_idx" in input_names: + decoder_req.set_tensor("beam_idx", ov.Tensor(beam_idx)) + if has_cache_position: + cache_pos = np.arange(len(sot_tokens), dtype=np.int64).reshape(1, -1) + decoder_req.set_tensor("cache_position", ov.Tensor(cache_pos)) + + decoder_req.infer() + logits = decoder_req.get_tensor("logits").data + next_token = int(np.argmax(logits[0, -1, :])) + + generated = [next_token] + position = len(sot_tokens) + + for _ in range(max_tokens - 1): + if next_token == eos_token: + break + + decoder_req.set_tensor("input_ids", + ov.Tensor(np.array([[next_token]], dtype=np.int64))) + if "beam_idx" in input_names: + decoder_req.set_tensor("beam_idx", ov.Tensor(beam_idx)) + if has_cache_position: + decoder_req.set_tensor("cache_position", + ov.Tensor(np.array([[position]], dtype=np.int64))) + + decoder_req.infer() + logits = decoder_req.get_tensor("logits").data + next_token = int(np.argmax(logits[0, -1, :])) + generated.append(next_token) + position += 1 + + return generated + + +# ---------- Frame parser ---------- + +def find_frame_in_buffer(buf): + """Find the first complete mel frame with data header in a bytearray. + + Frame layout: [magic(4B), frame_number(4B), reserved(4B), energy(4B), + noise_energy(4B), vad_flag(4B), mel[0..79](320B)] = 344 bytes + Mutates buf in-place (deletes consumed bytes). + Returns: (vad_flag, mel_ints) or (None, None) + """ + idx = buf.find(SOF_MAGIC_BYTES) + if idx < 0: + if len(buf) > 3: + del buf[:-3] + return None, None + end = idx + SOF_FRAME_BYTES + if end > len(buf): + del buf[:idx] + return None, None + # Parse vad_flag at offset 20 (after magic + frame_number + reserved + energy + noise_energy) + vad_flag = struct.unpack_from('<i', buf, idx + 20)[0] + # Parse 80 mel coefficients (after 24-byte header) + mel_bytes = bytes(buf[idx + SOF_NUM_HEADER * 4 : end]) + mel_ints = np.frombuffer(mel_bytes, dtype=np.int32) + del buf[:end] + return vad_flag, mel_ints + + +# ---------- Main capture + transcription loop ---------- + +def run_capture(device, rate, model_path, encoder_device, decoder_device): + """Main capture loop: ALSA → DSP VAD → buffer speech → Whisper.""" + + transcriber = WhisperTranscriber(model_path, encoder_device=encoder_device, + decoder_device=decoder_device) + + cmd = [ + 'arecord', '-D', device, '-f', 'S32_LE', '-c', '2', + '-r', str(rate), '-t', 'raw', '--buffer-size', '8192', + ] + + print(f"Starting capture: {' '.join(cmd)}") + print(f"VAD source: DSP (embedded in stream)") + print(f"Silence trigger: {SILENCE_TRIGGER_MS}ms ({SILENCE_TRIGGER_FRAMES} frames)") + print(f"Whisper model: {model_path} (encoder: {encoder_device}, decoder: {decoder_device})") + print() + + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + buf = bytearray() + read_chunk = SOF_FRAME_BYTES * 4 + frame_num = 0 + prev_speech = None + + # Speech buffering state + speech_buffer = [] # list of mel frames during speech + silence_counter = 0 # consecutive silence frames after speech + was_speaking = False # True if we have buffered speech frames + + def on_transcription(text): + if text: + print(f"\n >> \"{text}\"\n", flush=True) + else: + print(" [Whisper] empty result", flush=True) + + try: + while True: + data = proc.stdout.read(read_chunk) + if not data: + rc = proc.poll() + if rc is not None: + stderr_out = proc.stderr.read().decode(errors='replace') + print(f"\narecord exited with code {rc}") + if stderr_out: + print(f"stderr: {stderr_out}") + break + continue + + buf.extend(data) + + while True: + vad_flag, frame_ints = find_frame_in_buffer(buf) + if frame_ints is None: + break + + frame_num += 1 + mel = decode_mel_frame(frame_ints) + speech = vad_flag != 0 + + # Print VAD transitions + if speech != prev_speech: + t = frame_num * 0.01 + tag = "SPEECH" if speech else "SILENCE" + print(f" [{t:7.2f}s] {tag}", flush=True) + prev_speech = speech + + # --- Speech buffering logic --- + if speech: + if len(speech_buffer) >= MAX_SPEECH_FRAMES: + n = len(speech_buffer) + duration = n * 0.01 + t = frame_num * 0.01 + print(f" [{t:7.2f}s] Buffer full ({duration:.1f}s), " + f"forcing transcription of {n} frames", + flush=True) + if not transcriber.is_busy(): + frames_copy = list(speech_buffer) + transcriber.transcribe_async( + frames_copy, on_transcription) + else: + print(f" [{t:7.2f}s] (Whisper busy, " + f"dropping {n} frames)", flush=True) + speech_buffer.clear() + speech_buffer.append(mel.copy()) + silence_counter = 0 + was_speaking = True + else: + if was_speaking: + silence_counter += 1 + if silence_counter >= SILENCE_TRIGGER_FRAMES: + n = len(speech_buffer) + duration = n * 0.01 + t = frame_num * 0.01 + + if n < MIN_SPEECH_FRAMES: + # Too short — discard + speech_buffer.clear() + silence_counter = 0 + was_speaking = False + continue + + # Silence threshold reached — send to Whisper + print(f" [{t:7.2f}s] Transcribing {n} frames " + f"({duration:.1f}s)...", flush=True) + + if not transcriber.is_busy(): + frames_copy = list(speech_buffer) + transcriber.transcribe_async( + frames_copy, on_transcription) + else: + print(f" [{t:7.2f}s] (Whisper busy, " + f"dropping {n} frames)", flush=True) + + speech_buffer.clear() + silence_counter = 0 + was_speaking = False + + except (KeyboardInterrupt, BrokenPipeError): + pass + finally: + if proc.poll() is None: + proc.terminate() + try: + proc.wait(timeout=3) + except subprocess.TimeoutExpired: + proc.kill() + proc.wait() + print("\n\nCapture stopped.") + + +def main(): + parser = argparse.ArgumentParser( + description="Live SOF mel capture with DSP VAD-triggered Whisper transcription") + parser.add_argument('--device', '-D', default='hw:0,47', + help='ALSA capture device (default: hw:0,47)') + parser.add_argument('--rate', '-r', type=int, default=16000, + help='Sample rate for arecord (default: 16000)') + parser.add_argument('--model', '-m', default='whisper-medium-int4-ov', + help='Path to Whisper OpenVINO model directory') + parser.add_argument('--encoder-device', default='NPU', + help='OpenVINO device for encoder (default: NPU)') + parser.add_argument('--decoder-device', default='CPU', + help='OpenVINO device for decoder (default: CPU)') + args = parser.parse_args() + model_id = "OpenVINO/" + os.path.basename(args.model) + if not os.path.isdir(args.model): + print(f"Downloading model {model_id} ...") + hf_hub.snapshot_download(model_id, local_dir=args.model) + + print("=== Live SOF Mel → Whisper Transcription (DSP VAD) ===\n") + run_capture(args.device, args.rate, args.model, args.encoder_device, + args.decoder_device) + + +if __name__ == '__main__': + main() diff --git a/src/audio/mic_privacy_manager/CMakeLists.txt b/src/audio/mic_privacy_manager/CMakeLists.txt new file mode 100644 index 000000000000..b4ae270f7669 --- /dev/null +++ b/src/audio/mic_privacy_manager/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources(sof mic_privacy_manager_intel.c) diff --git a/src/audio/mic_privacy_manager/README.md b/src/audio/mic_privacy_manager/README.md new file mode 100644 index 000000000000..8d85f43e1a2b --- /dev/null +++ b/src/audio/mic_privacy_manager/README.md @@ -0,0 +1,11 @@ +# Microphone Privacy Manager Architecture + +This directory contains the Mic Privacy Manager. + +## Overview + +Provides a secure mechanism to optionally mute the microphone paths deeply inside the DSP, ensuring user privacy regardless of host OS behavior. + +## Configuration and Scripts + +- **CMakeLists.txt**: Simply builds the Intel-specific privacy implementation (`mic_privacy_manager_intel.c`). Currently, there is no generic or separate module wrapper defined within the scope of this directory. diff --git a/src/audio/mic_privacy_manager/mic_privacy_manager_intel.c b/src/audio/mic_privacy_manager/mic_privacy_manager_intel.c new file mode 100644 index 000000000000..a5ff86a04fd1 --- /dev/null +++ b/src/audio/mic_privacy_manager/mic_privacy_manager_intel.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. + +#include "sof/audio/mic_privacy_manager.h" + +#include <zephyr/device.h> +#include <zephyr/drivers/mic_privacy/intel/mic_privacy.h> +#include <zephyr/logging/log.h> +#include <sof/audio/audio_stream.h> +#include <sof/audio/buffer.h> +#include <sof/audio/mic_privacy_manager.h> +#include <sof/lib/memory.h> + +const struct device *mic_priv_dev; + +static struct mic_privacy_api_funcs *mic_privacy_api; +static enum mic_privacy_policy mic_privacy_policy; + +#define LOG_DOMAIN mic_priv + +LOG_MODULE_REGISTER(LOG_DOMAIN); + +void handle_dmic_irq(void const *self, int a, int b) +{ + LOG_DBG("mic_privacy DMIC IRQ"); + + if (mic_privacy_api->get_dmic_irq_status()) { + uint32_t mic_disable_status = mic_privacy_api->get_dmic_mic_disable_status(); + struct mic_privacy_settings settings; + + mic_privacy_fill_settings(&settings, mic_disable_status); + mic_privacy_propagate_settings(&settings); + mic_privacy_api->clear_dmic_irq_status(); + } +} + +void handle_fw_managed_irq(void const *dev) +{ + LOG_DBG("mic_privacy FW Managed IRQ"); + + uint32_t mic_disable_status = mic_privacy_api->get_fw_managed_mic_disable_status(); + struct mic_privacy_settings settings; + + mic_privacy_fill_settings(&settings, mic_disable_status); + mic_privacy_propagate_settings(&settings); + + if (mic_disable_status) + mic_privacy_api->set_fw_mic_disable_status(true); + else + mic_privacy_api->set_fw_mic_disable_status(false); + + mic_privacy_api->clear_fw_managed_irq(); +} + +static void enable_fw_managed_irq(bool enable_irq) +{ + if (enable_irq) + mic_privacy_api->enable_fw_managed_irq(true, handle_fw_managed_irq); + else + mic_privacy_api->enable_fw_managed_irq(false, NULL); +} + +void mic_privacy_enable_dmic_irq(bool enable_irq) +{ + /* Only proceed if we have a valid device and API */ + if (!mic_priv_dev || !mic_privacy_api) { + LOG_ERR("mic_privacy device or API not initialized"); + return; + } + + if (mic_privacy_api->get_policy() == MIC_PRIVACY_HW_MANAGED) { + if (enable_irq) { + mic_privacy_api->enable_dmic_irq(true, handle_dmic_irq); + + /* Check current status immediately to handle any transitions during D3 */ + if (mic_privacy_api->get_dmic_irq_status()) { + struct mic_privacy_settings settings; + uint32_t mic_disable_status = + mic_privacy_api->get_dmic_mic_disable_status(); + + mic_privacy_fill_settings(&settings, mic_disable_status); + mic_privacy_propagate_settings(&settings); + mic_privacy_api->clear_dmic_irq_status(); + } + } else { + mic_privacy_api->enable_dmic_irq(false, NULL); + } + } +} + +__cold int mic_privacy_manager_init(void) +{ + mic_priv_dev = DEVICE_DT_GET(DT_NODELABEL(mic_privacy)); + + assert_can_be_cold(); + + if (!mic_priv_dev) + return -EINVAL; + + mic_privacy_api = (struct mic_privacy_api_funcs *)mic_priv_dev->api; + mic_privacy_policy = mic_privacy_api->get_policy(); + + if (mic_privacy_policy == MIC_PRIVACY_FW_MANAGED) { + LOG_INF("mic_privacy init FW_MANAGED mode"); + mic_privacy_api->set_fw_managed_mode(true); + enable_fw_managed_irq(true); + } + + return 0; +} + +int mic_privacy_manager_get_policy(void) +{ + mic_privacy_api = (struct mic_privacy_api_funcs *)mic_priv_dev->api; + + return mic_privacy_api->get_policy(); +} + +uint32_t mic_privacy_get_policy_register(void) +{ + if (!mic_priv_dev) + return 0; + mic_privacy_api = (struct mic_privacy_api_funcs *)mic_priv_dev->api; + + return mic_privacy_api->get_privacy_policy_register_raw_value(); +} + +void mic_privacy_propagate_settings(struct mic_privacy_settings *settings) +{ + notifier_event(mic_priv_dev, NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE, + NOTIFIER_TARGET_CORE_ALL_MASK, settings, + sizeof(struct mic_privacy_settings)); +} + +uint32_t mic_privacy_get_dma_zeroing_wait_time(void) +{ + return (uint32_t)mic_privacy_api->get_dma_data_zeroing_wait_time(); +} + +uint32_t mic_privacy_get_privacy_mask(void) +{ + if (mic_privacy_policy == MIC_PRIVACY_HW_MANAGED) + return mic_privacy_api->get_dma_data_zeroing_link_select(); + + /* hardcoded for FW_MANAGED */ + return 0xFFFFFFFF; +} + +void mic_privacy_fill_settings(struct mic_privacy_settings *settings, uint32_t mic_disable_status) +{ + if (!settings) { + LOG_ERR("Invalid mic_privacy_settings pointer"); + return; + } + + settings->mic_privacy_mode = mic_privacy_policy; + settings->mic_privacy_state = mic_disable_status; + settings->privacy_mask_bits.value = mic_privacy_get_privacy_mask(); + settings->max_ramp_time = mic_privacy_get_dma_zeroing_wait_time(); + + LOG_DBG("mic_privacy_mode = %d, mic_disable_status = %d, \ + privacy_mask = %x, max_ramp_time_in_ms = %d", + settings->mic_privacy_mode, + settings->mic_privacy_state, + settings->privacy_mask_bits.value, + settings->max_ramp_time); +} + +void mic_privacy_set_gtw_mic_state(struct mic_privacy_data *mic_priv_data, + uint32_t mic_disable_status) +{ + if (mic_privacy_policy == MIC_PRIVACY_HW_MANAGED) { + if (mic_disable_status != 0) + mic_priv_data->mic_privacy_state = MIC_PRIV_MUTED; + else + mic_priv_data->mic_privacy_state = MIC_PRIV_UNMUTED; + } else if (mic_privacy_policy == MIC_PRIVACY_FW_MANAGED) { + if (mic_disable_status != 0) { + LOG_DBG("MUTED"); + mic_priv_data->mic_privacy_state = MIC_PRIV_MUTED; + mic_priv_data->dma_data_zeroing = true; + mic_privacy_api->set_fw_mic_disable_status(true); + } else { + LOG_DBG("UNMUTED"); + mic_priv_data->mic_privacy_state = MIC_PRIV_UNMUTED; + mic_priv_data->dma_data_zeroing = false; + mic_privacy_api->set_fw_mic_disable_status(false); + } + } +} + +void mic_privacy_update_gtw_mic_state(struct mic_privacy_data *mic_priv_data, + uint32_t hw_mic_disable_status) +{ + switch (mic_privacy_policy) { + case MIC_PRIVACY_HW_MANAGED: + mic_privacy_set_gtw_mic_state(mic_priv_data, hw_mic_disable_status); + break; + case MIC_PRIVACY_FW_MANAGED: + mic_privacy_set_gtw_mic_state(mic_priv_data, + mic_privacy_api->get_fw_managed_mic_disable_status()); + break; + default: + break; + } +} + +void mic_privacy_process(struct comp_dev *dev, struct mic_privacy_data *mic_priv, + struct comp_buffer *buffer, uint32_t copy_samples) +{ + uint32_t sg_size_in_bytes; + + sg_size_in_bytes = audio_stream_frame_bytes(&buffer->stream); + uint32_t one_ms_in_bytes = sg_size_in_bytes * (buffer->stream.runtime_stream_params.rate / 1000); + uint32_t copy_bytes = copy_samples * audio_stream_sample_bytes(&buffer->stream); + + switch (mic_priv->mic_privacy_state) { + case MIC_PRIV_UNMUTED: + break; + case MIC_PRIV_MUTED: + buffer_zero(buffer); + break; + case MIC_PRIV_FADE_IN: + if (mic_priv->fade_in_out_bytes == 0) { + /* start addition */ + mic_priv->mic_priv_gain_params.fade_in_sg_count = 0; + mic_priv->mic_priv_gain_params.gain_env = 0; + } + mic_priv->fade_in_out_bytes += copy_bytes; + if (mic_priv->fade_in_out_bytes > one_ms_in_bytes * mic_priv->max_ramp_time_in_ms) { + mic_priv->mic_privacy_state = MIC_PRIV_UNMUTED; + mic_priv->fade_in_out_bytes = 0; + } + + if (mic_priv->max_ramp_time_in_ms > 0) + copier_gain_input(dev, buffer, &mic_priv->mic_priv_gain_params, GAIN_ADD, copy_bytes); + break; + case MIC_PRIV_FADE_OUT: + if (mic_priv->fade_in_out_bytes == 0) { + /* start subtraction */ + mic_priv->mic_priv_gain_params.fade_in_sg_count = 0; + mic_priv->mic_priv_gain_params.gain_env = INT64_MAX; + } + mic_priv->fade_in_out_bytes += copy_bytes; + if (mic_priv->fade_in_out_bytes > one_ms_in_bytes * mic_priv->max_ramp_time_in_ms) { + mic_priv->mic_privacy_state = MIC_PRIV_MUTED; + mic_priv->fade_in_out_bytes = 0; + buffer_zero(buffer); + } + if (mic_priv->max_ramp_time_in_ms > 0) + copier_gain_input(dev, buffer, &mic_priv->mic_priv_gain_params, GAIN_SUBTRACT, copy_bytes); + break; + default: + LOG_ERR("invalid state %x", mic_priv->mic_privacy_state); + break; + } +} + +uint32_t mic_privacy_get_mic_disable_status(void) +{ + if (!mic_priv_dev) { + LOG_ERR("mic_privacy device not initialized"); + return 0; + } + + mic_privacy_api = (struct mic_privacy_api_funcs *)mic_priv_dev->api; + if (mic_privacy_api->get_policy() == MIC_PRIVACY_FW_MANAGED) + return mic_privacy_api->get_fw_managed_mic_disable_status(); + + return mic_privacy_api->get_dmic_mic_disable_status(); +} diff --git a/src/audio/mixer/README.md b/src/audio/mixer/README.md new file mode 100644 index 000000000000..eef844d0313c --- /dev/null +++ b/src/audio/mixer/README.md @@ -0,0 +1,22 @@ +# Mixer Architecture + +This directory contains the Mixer component. + +## Overview + +The Mixer adds together multiple input audio streams into a single output stream, applying required scaling or saturation logic. + +## Architecture Diagram + +```mermaid +graph TD + In1[Source 1] --> Mix[Mixer Core] + In2[Source 2] --> Mix + InN[Source N] --> Mix + Mix --> Out[Mixed Output] +``` + +## Configuration and Scripts + +- **Kconfig**: Enables the Mixer component (`COMP_MIXER`), which inherently depends on the older IPC framework `IPC_MAJOR_3`. +- **CMakeLists.txt**: Manages local base sources and optimized implementations (`mixer_generic.c`, `mixer_hifi3.c`) alongside the core `mixer.c`. diff --git a/src/audio/mixer/mixer.c b/src/audio/mixer/mixer.c index f7583c8b4d1b..26023bb6a570 100644 --- a/src/audio/mixer/mixer.c +++ b/src/audio/mixer/mixer.c @@ -14,7 +14,6 @@ #include <sof/common.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> #include <sof/list.h> @@ -36,18 +35,15 @@ LOG_MODULE_REGISTER(mixer, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(mixer); -DECLARE_TR_CTX(mixer_tr, SOF_UUID(mixer_uuid), LOG_LEVEL_INFO); - - static int mixer_init(struct processing_module *mod) { struct module_data *mod_data = &mod->priv; struct comp_dev *dev = mod->dev; struct mixer_data *md; - comp_dbg(dev, "mixer_init()"); + comp_dbg(dev, "entry"); - md = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*md)); + md = mod_zalloc(mod, sizeof(*md)); if (!md) return -ENOMEM; @@ -64,9 +60,9 @@ static int mixer_free(struct processing_module *mod) struct mixer_data *md = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - comp_dbg(dev, "mixer_free()"); + comp_dbg(dev, "entry"); - rfree(md); + mod_free(mod, md); return 0; } @@ -89,7 +85,7 @@ static int mixer_process(struct processing_module *mod, uint32_t sink_bytes; int active_input_buffers = 0; - comp_dbg(dev, "mixer_process() %d", num_input_buffers); + comp_dbg(dev, "%d", num_input_buffers); /* too many sources ? */ if (num_input_buffers >= PLATFORM_MAX_STREAMS) @@ -129,7 +125,7 @@ static int mixer_process(struct processing_module *mod, sink_bytes = frames * audio_stream_frame_bytes(mod->output_buffers[0].data); - comp_dbg(dev, "mixer_process(), source_bytes = 0x%x, sink_bytes = 0x%x", + comp_dbg(dev, "source_bytes = 0x%x, sink_bytes = 0x%x", source_bytes, sink_bytes); /* mix streams */ @@ -164,7 +160,7 @@ static int mixer_reset(struct processing_module *mod) struct comp_dev *dev = mod->dev; int dir = dev->pipeline->source_comp->direction; - comp_dbg(dev, "mixer_reset()"); + comp_dbg(dev, "entry"); if (dir == SOF_IPC_STREAM_PLAYBACK) { struct comp_buffer *source; @@ -191,18 +187,18 @@ 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 *source) { -#if XCHAL_HAVE_HIFI3 || XCHAL_HAVE_HIFI4 /* Xtensa intrinsics ask for 8-byte aligned. 5.1 format SSE audio - * requires 16-byte aligned. + * requires 16-byte aligned. Note: The SOF_FRAME_BYTE_ALIGN is the + * same value 16 with HiFi5. */ - const uint32_t byte_align = audio_stream_get_channels(source) == 6 ? 16 : 8; + const uint32_t byte_align = audio_stream_get_channels(source) == 6 ? + MIXER_HIFI_FRAME_BYTE_ALIGN_6CH : SOF_FRAME_BYTE_ALIGN; - /*There is no limit for frame number, so set it as 1*/ - const uint32_t frame_align_req = 1; + /* There is no limit for frame number, so set it as default (1). */ + const uint32_t frame_align_req = SOF_FRAME_COUNT_ALIGN; audio_stream_set_align(byte_align, frame_align_req, source); -#endif } static int mixer_prepare(struct processing_module *mod, @@ -214,8 +210,16 @@ static int mixer_prepare(struct processing_module *mod, struct comp_buffer *sink; sink = comp_dev_get_first_data_consumer(dev); + if (!sink) { + comp_err(dev, "no sink"); + return -ENOTCONN; + } + md->mix_func = mixer_get_processing_function(dev, sink); - mixer_set_frame_alignment(&sink->stream); + + /* No need to set sink align constraints, set constraints for each + * source next. The sink align will follow to common source alignment. + */ /* check each mixer source state */ struct comp_buffer *source; @@ -252,5 +256,6 @@ static const struct module_interface mixer_interface = { .free = mixer_free, }; +DECLARE_TR_CTX(mixer_tr, SOF_UUID(mixer_uuid), LOG_LEVEL_INFO); DECLARE_MODULE_ADAPTER(mixer_interface, mixer_uuid, mixer_tr); SOF_MODULE_INIT(mixer, sys_comp_module_mixer_interface_init); diff --git a/src/audio/mixer/mixer.h b/src/audio/mixer/mixer.h index 118aaf1c914f..875ddcbb26fe 100644 --- a/src/audio/mixer/mixer.h +++ b/src/audio/mixer/mixer.h @@ -32,6 +32,9 @@ void sys_comp_module_mixer_interface_init(void); #define MIXER_MAX_SOURCES 2 +/* Xtensa HiFi optimized version needs this for 5.1ch */ +#define MIXER_HIFI_FRAME_BYTE_ALIGN_6CH 16 + /* mixer component private data */ struct mixer_data { void (*mix_func)(struct comp_dev *dev, struct audio_stream *sink, diff --git a/src/audio/mixin_mixout/CMakeLists.txt b/src/audio/mixin_mixout/CMakeLists.txt index 2e6dc7456ae5..11eccf85f499 100644 --- a/src/audio/mixin_mixout/CMakeLists.txt +++ b/src/audio/mixin_mixout/CMakeLists.txt @@ -1 +1,12 @@ -add_local_sources(sof mixin_mixout.c mixin_mixout_generic.c mixin_mixout_hifi3.c mixin_mixout_hifi5.c) +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_COMP_MIXIN_MIXOUT STREQUAL "m" AND DEFINED CONFIG_LLEXT) + + add_subdirectory(llext ${PROJECT_BINARY_DIR}/mixin_mixout_llext) + add_dependencies(app mixin_mixout) + +else() + + add_local_sources(sof mixin_mixout.c mixin_mixout_generic.c mixin_mixout_hifi3.c mixin_mixout_hifi5.c) + +endif() diff --git a/src/audio/mixin_mixout/README.md b/src/audio/mixin_mixout/README.md new file mode 100644 index 000000000000..a73b39e7655b --- /dev/null +++ b/src/audio/mixin_mixout/README.md @@ -0,0 +1,14 @@ +# Mix-In / Mix-Out Architecture + +This directory provides specialized Mix-in and Mix-out instances. + +## Overview + +These components typically act as routing endpoints to inject or extract specific streams in/out of an ongoing audio mix. + +## Configuration and Scripts + +- **Kconfig**: Compiles the Mixin_mixout component (`COMP_MIXIN_MIXOUT`), which depends on the modern `IPC_MAJOR_4`. Allows choosing SIMD optimization logic explicitly. +- **CMakeLists.txt**: Integrates generic, HIFI3, and HIFI5 specialized processing source files. Fully supports modular execution via `llext`. +- **mixin_mixout.toml**: Extensive configuration separating `MIXIN` and `MIXOUT` instances. Configures UUIDs, domain types, and highly localized `mod_cfg` arrays adapted for `CONFIG_METEORLAKE`, `CONFIG_LUNARLAKE`, and ACE SOCs. +- **Topology (.conf)**: Uses `tools/topology/topology2/include/components/mixin.conf` (type `mixer` with `mix_type` `"mix_in"`, defaulting to UUID `b2:6e:65:39:71:3b:49:40:8d:3f:f9:2c:d5:c4:3c:09`, supporting 3 output pins) and `mixout.conf` (type `mixer` with `mix_type` `"mix_out"`, defaulting to UUID `5a:50:56:3c:d7:24:8f:41:bd:dc:c1:f5:a3:ac:2a:e0`, mapping to 8 input pins). Both force a 32-bit depth processing format. diff --git a/src/audio/mixin_mixout/mixin_mixout.c b/src/audio/mixin_mixout/mixin_mixout.c index 94a61c89d097..6e30eaee72d3 100644 --- a/src/audio/mixin_mixout/mixin_mixout.c +++ b/src/audio/mixin_mixout/mixin_mixout.c @@ -12,7 +12,6 @@ #include <sof/compiler_attributes.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> #include <sof/list.h> @@ -24,6 +23,7 @@ #include <ipc/stream.h> #include <ipc/topology.h> #include <ipc4/base-config.h> +#include <ipc4/notification.h> #include <user/trace.h> #include <stddef.h> #include <stdint.h> @@ -34,11 +34,9 @@ LOG_MODULE_REGISTER(mixin_mixout, CONFIG_SOF_LOG_LEVEL); /* mixin 39656eb2-3b71-4049-8d3f-f92cd5c43c09 */ SOF_DEFINE_REG_UUID(mixin); -DECLARE_TR_CTX(mixin_tr, SOF_UUID(mixin_uuid), LOG_LEVEL_INFO); /* mixout 3c56505a-24d7-418f-bddc-c1f5a3ac2ae0 */ SOF_DEFINE_REG_UUID(mixout); -DECLARE_TR_CTX(mixout_tr, SOF_UUID(mixout_uuid), LOG_LEVEL_INFO); #define MIXIN_MAX_SINKS IPC4_MIXIN_MODULE_MAX_OUTPUT_QUEUES #define MIXOUT_MAX_SOURCES IPC4_MIXOUT_MODULE_MAX_INPUT_QUEUES @@ -74,6 +72,12 @@ struct mixin_data { mix_func mix; mix_func gain_mix; struct mixin_sink_config sink_config[MIXIN_MAX_SINKS]; +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE + uint32_t last_reported_underrun; + uint32_t underrun_notification_period; + uint32_t eos_delay_periods; + bool eos_delay_configured; +#endif }; /* @@ -131,13 +135,16 @@ static int mixin_init(struct processing_module *mod) struct mixin_data *md; int i; - comp_dbg(dev, "mixin_init()"); + comp_dbg(dev, "entry"); - md = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*md)); + md = mod_zalloc(mod, sizeof(*md)); if (!md) return -ENOMEM; mod_data->private = md; +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE + md->underrun_notification_period = MIXIN_MODULE_DEFAULT_UNDERRUN_NOTIFICATION_PERIOD; +#endif for (i = 0; i < MIXIN_MAX_SINKS; i++) { md->sink_config[i].mixer_mode = IPC4_MIXER_NORMAL_MODE; @@ -155,9 +162,9 @@ static int mixout_init(struct processing_module *mod) struct comp_dev *dev = mod->dev; struct mixout_data *mo_data; - comp_dbg(dev, "mixout_new()"); + comp_dbg(dev, "entry"); - mo_data = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*mo_data)); + mo_data = mod_zalloc(mod, sizeof(*mo_data)); if (!mo_data) return -ENOMEM; @@ -173,14 +180,14 @@ static int mixin_free(struct processing_module *mod) { struct mixin_data *md = module_get_private_data(mod); - rfree(md); + mod_free(mod, md); return 0; } static int mixout_free(struct processing_module *mod) { - rfree(module_get_private_data(mod)); + mod_free(mod, module_get_private_data(mod)); return 0; } @@ -237,6 +244,39 @@ static void silence(struct cir_buf_ptr *stream, uint32_t start_offset, } } +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE +static void mixin_check_notify_underrun(struct comp_dev *dev, struct mixin_data *mixin_data, + enum sof_audio_buffer_state state, + size_t source_avail, size_t sinks_free) +{ + const bool eos_detected = state == AUDIOBUF_STATE_END_OF_STREAM_FLUSH || + state == AUDIOBUF_STATE_END_OF_STREAM; + + mixin_data->last_reported_underrun++; + + if (!source_avail || eos_detected) { + if (eos_detected) { + if (mixin_data->eos_delay_configured) { + mixin_data->eos_delay_periods--; + } else { + pipeline_get_dai_comp_latency(dev->pipeline->pipeline_id, + &mixin_data->eos_delay_periods); + mixin_data->eos_delay_configured = true; + } + } + + if ((!eos_detected && mixin_data->last_reported_underrun >= + mixin_data->underrun_notification_period) || + (eos_detected && mixin_data->eos_delay_periods == 0)) { + mixin_data->last_reported_underrun = 0; + + send_mixer_underrun_notif_msg(dev->ipc_config.id, eos_detected, + source_avail, sinks_free); + } + } +} +#endif + /* Most of the mixing is done here on mixin side. mixin mixes its source data * into each connected mixout sink buffer. Basically, if mixout sink buffer has * no data, mixin copies its source data into mixout sink buffer. If mixout sink @@ -262,19 +302,20 @@ static int mixin_process(struct processing_module *mod, uint32_t source_avail_frames, sinks_free_frames; struct processing_module *active_mixouts[MIXIN_MAX_SINKS]; uint16_t sinks_ids[MIXIN_MAX_SINKS]; + struct pending_frames *pending_frames; uint32_t bytes_to_consume = 0; uint32_t frames_to_copy; - struct pending_frames *pending_frames; + size_t frame_bytes; int i, ret; struct cir_buf_ptr source_ptr; - comp_dbg(dev, "mixin_process()"); + comp_dbg(dev, "entry"); source_avail_frames = source_get_data_frames_available(sources[0]); sinks_free_frames = INT32_MAX; if (num_of_sinks > MIXIN_MAX_SINKS) { - comp_err(dev, "mixin_process(): Invalid output sink count %d", + comp_err(dev, "Invalid output sink count %d", num_of_sinks); return -EINVAL; } @@ -356,14 +397,25 @@ static int mixin_process(struct processing_module *mod, if (sinks_free_frames == 0 || sinks_free_frames == INT32_MAX) return 0; +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE + frame_bytes = source_get_frame_bytes(sources[0]); + const size_t min_frames = MIN(dev->frames, sinks_free_frames); + + mixin_check_notify_underrun(dev, mixin_data, source_get_state(sources[0]), + source_avail_frames * frame_bytes, + min_frames * frame_bytes); +#endif + if (source_avail_frames > 0) { size_t buf_size; frames_to_copy = MIN(source_avail_frames, sinks_free_frames); bytes_to_consume = frames_to_copy * source_get_frame_bytes(sources[0]); - source_get_data(sources[0], bytes_to_consume, (const void **)&source_ptr.ptr, - (const void **)&source_ptr.buf_start, &buf_size); + ret = source_get_data(sources[0], bytes_to_consume, (const void **)&source_ptr.ptr, + (const void **)&source_ptr.buf_start, &buf_size); + if (ret < 0) + return ret; source_ptr.buf_end = (uint8_t *)source_ptr.buf_start + buf_size; } else { /* if source does not produce any data -- do NOT block mixing but generate @@ -408,8 +460,13 @@ static int mixin_process(struct processing_module *mod, size_t free_bytes = sink_get_free_size(sink); size_t buf_size; - sink_get_buffer(sink, free_bytes, &mixout_data->acquired_buf.ptr, - &mixout_data->acquired_buf.buf_start, &buf_size); + ret = sink_get_buffer(sink, free_bytes, &mixout_data->acquired_buf.ptr, + &mixout_data->acquired_buf.buf_start, &buf_size); + /* on failed acquire, skip this mixout and keep mixing the rest; + * source is consumed once after the loop so it is not reprocessed + */ + if (ret < 0) + continue; mixout_data->acquired_buf.buf_end = (uint8_t *)mixout_data->acquired_buf.buf_start + buf_size; mixout_data->acquired_buf_free_frames = @@ -420,7 +477,7 @@ static int mixin_process(struct processing_module *mod, * silence instead of that source data */ if (source_avail_frames == 0) { - uint32_t frame_bytes = sink_get_frame_bytes(mixout_mod->sinks[0]); + frame_bytes = sink_get_frame_bytes(mixout_mod->sinks[0]); /* generate silence */ silence(&mixout_data->acquired_buf, start_frame * frame_bytes, @@ -463,9 +520,9 @@ static int mixout_process(struct processing_module *mod, uint32_t frames_to_produce = INT32_MAX; uint32_t bytes_to_produce; struct pending_frames *pending_frames; - int i; + int i, ret; - comp_dbg(dev, "mixout_process()"); + comp_dbg(dev, "entry"); md = module_get_private_data(mod); @@ -524,8 +581,11 @@ static int mixout_process(struct processing_module *mod, if (!md->acquired_buf.ptr) { size_t buf_size; - sink_get_buffer(sinks[0], bytes_to_produce, &md->acquired_buf.ptr, - &md->acquired_buf.buf_start, &buf_size); + ret = sink_get_buffer(sinks[0], bytes_to_produce, &md->acquired_buf.ptr, + &md->acquired_buf.buf_start, &buf_size); + if (ret < 0) + return ret; + md->acquired_buf.buf_end = (uint8_t *)md->acquired_buf.buf_start + buf_size; } @@ -589,7 +649,7 @@ static int mixin_params(struct processing_module *mod) int i; int ret; - comp_dbg(dev, "mixin_params()"); + comp_dbg(dev, "entry"); ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); @@ -632,7 +692,7 @@ static int mixin_params(struct processing_module *mod) ret = comp_verify_params(dev, 0, params); if (ret < 0) { - comp_err(dev, "mixin_params(): comp_verify_params() failed!"); + comp_err(dev, "comp_verify_params() failed!"); return -EINVAL; } @@ -656,7 +716,10 @@ static int mixin_prepare(struct processing_module *mod, enum sof_ipc_frame fmt; int ret; - comp_info(dev, "mixin_prepare()"); + comp_info(dev, "entry"); +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE + md->eos_delay_configured = false; +#endif ret = mixin_params(mod); if (ret < 0) @@ -691,13 +754,13 @@ static int mixout_params(struct processing_module *mod) enum sof_ipc_frame frame_fmt, valid_fmt; int ret; - comp_dbg(dev, "mixout_params()"); + comp_dbg(dev, "entry"); ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); ret = comp_verify_params(dev, 0, params); if (ret < 0) { - comp_err(dev, "mixout_params(): comp_verify_params() failed!"); + comp_err(dev, "comp_verify_params() failed!"); return -EINVAL; } @@ -728,7 +791,7 @@ static int mixout_prepare(struct processing_module *mod, if (ret < 0) return ret; - comp_dbg(dev, "mixout_prepare()"); + comp_dbg(dev, "entry"); /* * Since mixout sink buffer stream is reset on .prepare(), let's @@ -743,7 +806,7 @@ static int mixout_prepare(struct processing_module *mod, return 0; } -static int mixout_bind(struct processing_module *mod, void *data) +static int mixout_bind(struct processing_module *mod, struct bind_info *bind_data) { struct ipc4_module_bind_unbind *bu; struct comp_dev *mixin; @@ -751,9 +814,7 @@ static int mixout_bind(struct processing_module *mod, void *data) int src_id; struct mixout_data *mixout_data; - comp_dbg(mod->dev, "mixout_bind() %p", data); - - bu = (struct ipc4_module_bind_unbind *)data; + bu = bind_data->ipc4_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 */ @@ -762,7 +823,7 @@ static int mixout_bind(struct processing_module *mod, void *data) mixin = ipc4_get_comp_dev(src_id); if (!mixin) { - comp_err(mod->dev, "mixout_bind: no mixin with ID %d found", src_id); + comp_err(mod->dev, "no mixin with ID %d found", src_id); return -EINVAL; } @@ -792,7 +853,7 @@ static int mixout_bind(struct processing_module *mod, void *data) return 0; } -static int mixout_unbind(struct processing_module *mod, void *data) +static int mixout_unbind(struct processing_module *mod, struct bind_info *unbind_data) { struct ipc4_module_bind_unbind *bu; struct comp_dev *mixin; @@ -800,9 +861,9 @@ static int mixout_unbind(struct processing_module *mod, void *data) int src_id; struct mixout_data *mixout_data; - comp_dbg(mod->dev, "mixout_unbind()"); + comp_dbg(mod->dev, "entry"); - bu = (struct ipc4_module_bind_unbind *)data; + bu = unbind_data->ipc4_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 */ @@ -811,7 +872,7 @@ static int mixout_unbind(struct processing_module *mod, void *data) mixin = ipc4_get_comp_dev(src_id); if (!mixin) { - comp_err(mod->dev, "mixout_bind: no mixin with ID %d found", src_id); + comp_err(mod->dev, "no mixin with ID %d found", src_id); return -EINVAL; } @@ -840,30 +901,30 @@ static int mixin_set_config(struct processing_module *mod, uint32_t config_id, uint16_t gain; if (config_id != IPC4_MIXER_MODE) { - comp_err(dev, "mixin_set_config() unsupported param ID: %u", config_id); + comp_err(dev, "unsupported param ID: %u", config_id); return -EINVAL; } if (!(pos & MODULE_CFG_FRAGMENT_SINGLE)) { - comp_err(dev, "mixin_set_config() data is expected to be sent as one chunk"); + comp_err(dev, "data is expected to be sent as one chunk"); return -EINVAL; } /* for a single chunk data, data_offset_size is size */ if (data_offset_size < sizeof(struct ipc4_mixer_mode_config)) { - comp_err(dev, "mixin_set_config() too small data size: %u", data_offset_size); + comp_err(dev, "too small data size: %u", data_offset_size); return -EINVAL; } if (data_offset_size > SOF_IPC_MSG_MAX_SIZE) { - comp_err(dev, "mixin_set_config() too large data size: %u", data_offset_size); + comp_err(dev, "too large data size: %u", data_offset_size); return -EINVAL; } cfg = (const struct ipc4_mixer_mode_config *)fragment; if (cfg->mixer_mode_config_count < 1 || cfg->mixer_mode_config_count > MIXIN_MAX_SINKS) { - comp_err(dev, "mixin_set_config() invalid mixer_mode_config_count: %u", + comp_err(dev, "invalid mixer_mode_config_count: %u", cfg->mixer_mode_config_count); return -EINVAL; } @@ -871,14 +932,14 @@ static int mixin_set_config(struct processing_module *mod, uint32_t config_id, if (sizeof(struct ipc4_mixer_mode_config) + (cfg->mixer_mode_config_count - 1) * sizeof(struct ipc4_mixer_mode_sink_config) > data_offset_size) { - comp_err(dev, "mixin_set_config(): unexpected data size: %u", data_offset_size); + comp_err(dev, "unexpected data size: %u", data_offset_size); return -EINVAL; } for (i = 0; i < cfg->mixer_mode_config_count; i++) { sink_index = cfg->mixer_mode_sink_configs[i].output_queue_id; if (sink_index >= MIXIN_MAX_SINKS) { - comp_err(dev, "mixin_set_config(): invalid sink index: %u", sink_index); + comp_err(dev, "invalid sink index: %u", sink_index); return -EINVAL; } @@ -887,7 +948,7 @@ static int mixin_set_config(struct processing_module *mod, uint32_t config_id, gain = IPC4_MIXIN_UNITY_GAIN; mixin_data->sink_config[sink_index].gain = gain; - comp_dbg(dev, "mixin_set_config(): gain 0x%x will be applied for sink %u", + comp_dbg(dev, "gain 0x%x will be applied for sink %u", gain, sink_index); if (cfg->mixer_mode_sink_configs[i].mixer_mode == @@ -895,7 +956,7 @@ static int mixin_set_config(struct processing_module *mod, uint32_t config_id, uint32_t channel_count = cfg->mixer_mode_sink_configs[i].output_channel_count; if (channel_count < 1 || channel_count > 8) { - comp_err(dev, "mixin_set_config(): Invalid output_channel_count %u for sink %u", + comp_err(dev, "Invalid output_channel_count %u for sink %u", channel_count, sink_index); return -EINVAL; } @@ -904,7 +965,7 @@ static int mixin_set_config(struct processing_module *mod, uint32_t config_id, mixin_data->sink_config[sink_index].output_channel_map = cfg->mixer_mode_sink_configs[i].output_channel_map; - comp_dbg(dev, "mixin_set_config(): output_channel_count: %u, chmap: 0x%x for sink: %u", + comp_dbg(dev, "output_channel_count: %u, chmap: 0x%x for sink: %u", channel_count, mixin_data->sink_config[sink_index].output_channel_map, sink_index); @@ -917,18 +978,53 @@ static int mixin_set_config(struct processing_module *mod, uint32_t config_id, return 0; } +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE +static int mixin_set_config_param(struct processing_module *mod, uint32_t param_id_data) +{ + struct mixin_data *mixin_data = module_get_private_data(mod); + union config_param_id_data cfg; + + cfg.dw = param_id_data; + + if (cfg.f.id == IPC4_MIXER_UNDERRUN_NOTIF_PERIOD) { + if (cfg.f.data16 < MIXIN_MODULE_MIN_UNDERRUN_NOTIFICATION_PERIOD) + return -EINVAL; + + mixin_data->underrun_notification_period = cfg.f.data16; + return 0; + } + return -EINVAL; +} + +static int mixin_get_config_param(struct processing_module *mod, uint32_t *param_id_data) +{ + struct mixin_data *mixin_data = module_get_private_data(mod); + union config_param_id_data cfg; + + cfg.dw = *param_id_data; + + if (cfg.f.id == IPC4_MIXER_UNDERRUN_NOTIF_PERIOD) { + cfg.f.data16 = mixin_data->underrun_notification_period; + *param_id_data = cfg.dw; + return 0; + } + return -EINVAL; +} +#endif + static const struct module_interface mixin_interface = { .init = mixin_init, .prepare = mixin_prepare, .process = mixin_process, .set_configuration = mixin_set_config, +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE + .set_config_param = mixin_set_config_param, + .get_config_param = mixin_get_config_param, +#endif .reset = mixin_reset, .free = mixin_free }; -DECLARE_MODULE_ADAPTER(mixin_interface, mixin_uuid, mixin_tr); -SOF_MODULE_INIT(mixin, sys_comp_module_mixin_interface_init); - static const struct module_interface mixout_interface = { .init = mixout_init, .prepare = mixout_prepare, @@ -939,9 +1035,6 @@ static const struct module_interface mixout_interface = { .unbind = mixout_unbind }; -DECLARE_MODULE_ADAPTER(mixout_interface, mixout_uuid, mixout_tr); -SOF_MODULE_INIT(mixout, sys_comp_module_mixout_interface_init); - #if CONFIG_COMP_MIXIN_MIXOUT_MODULE /* modular: llext dynamic link */ @@ -949,20 +1042,22 @@ SOF_MODULE_INIT(mixout, sys_comp_module_mixout_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_MIXIN 0xB2, 0x6E, 0x65, 0x39, 0x71, 0x3B, 0x49, 0x40, \ - 0x8D, 0x3F, 0xF9, 0x2C, 0xD5, 0xC4, 0x3C, 0x09 -#define UUID_MIXOUT 0x5A, 0x50, 0x56, 0x3C, 0xD7, 0x24, 0x8F, 0x41, \ - 0xBD, 0xDC, 0xC1, 0xF5, 0xA3, 0xAC, 0x2A, 0xE0 - -SOF_LLEXT_MOD_ENTRY(mixin, &mixin_interface); -SOF_LLEXT_MOD_ENTRY(mixout, &mixout_interface); - static const struct sof_man_module_manifest mod_manifest[] __section(".module") __used = { - SOF_LLEXT_MODULE_MANIFEST("MIXIN", mixin_llext_entry, 1, UUID_MIXIN, 30), - SOF_LLEXT_MODULE_MANIFEST("MIXOUT", mixout_llext_entry, 1, UUID_MIXOUT, 30), + SOF_LLEXT_MODULE_MANIFEST("MIXIN", &mixin_interface, 1, SOF_REG_UUID(mixin), 30), + SOF_LLEXT_MODULE_MANIFEST("MIXOUT", &mixout_interface, 1, SOF_REG_UUID(mixout), 30), }; SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(mixin_tr, SOF_UUID(mixin_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(mixin_interface, mixin_uuid, mixin_tr); +SOF_MODULE_INIT(mixin, sys_comp_module_mixin_interface_init); + +DECLARE_TR_CTX(mixout_tr, SOF_UUID(mixout_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(mixout_interface, mixout_uuid, mixout_tr); +SOF_MODULE_INIT(mixout, sys_comp_module_mixout_interface_init); + #endif diff --git a/src/audio/mixin_mixout/mixin_mixout.h b/src/audio/mixin_mixout/mixin_mixout.h index d7519ca80fd8..5cfb30f26c43 100644 --- a/src/audio/mixin_mixout/mixin_mixout.h +++ b/src/audio/mixin_mixout/mixin_mixout.h @@ -32,6 +32,8 @@ #include <stddef.h> enum ipc4_mixin_config_param { + /* config_param param id to set/get underrun notification period. */ + IPC4_MIXER_UNDERRUN_NOTIF_PERIOD = 0, /* large_config_set param id for ipc4_mixer_mode_config */ IPC4_MIXER_MODE = 1 }; @@ -42,6 +44,13 @@ enum ipc4_mixin_config_param { /* Number of supported input pins that are mixed together */ #define IPC4_MIXOUT_MODULE_MAX_INPUT_QUEUES 8 +/* Each mixin instance by default has set default notification + * period to avoid notification flooding. + */ +#define MIXIN_MODULE_DEFAULT_UNDERRUN_NOTIFICATION_PERIOD 10 +#define MIXIN_MODULE_MIN_UNDERRUN_NOTIFICATION_PERIOD 1 +#define MIXIN_MODULE_MAX_UNDERRUN_NOTIFICATION_PERIOD 65535 + enum ipc4_mixer_mode { /* Normal mode, just mixing */ IPC4_MIXER_NORMAL_MODE = 0, @@ -90,13 +99,6 @@ struct ipc4_mixer_mode_config { struct ipc4_mixer_mode_sink_config mixer_mode_sink_configs[1]; } __packed __aligned(4); -/* Pointer to data in circular buffer together with buffer boundaries */ -struct cir_buf_ptr { - void *buf_start; - void *buf_end; - void *ptr; -}; - /** * \brief mixin processing function interface */ diff --git a/src/audio/mixin_mixout/mixin_mixout.toml b/src/audio/mixin_mixout/mixin_mixout.toml index 22a6d3e471e6..16edc0567aa3 100644 --- a/src/audio/mixin_mixout/mixin_mixout.toml +++ b/src/audio/mixin_mixout/mixin_mixout.toml @@ -4,7 +4,7 @@ [[module.entry]] name = "MIXIN" - uuid = "39656EB2-3B71-4049-8D3F-F92CD5C43C09" + uuid = UUIDREG_STR_MIXIN affinity_mask = "0x1" instance_count = "30" domain_types = "0" @@ -21,29 +21,30 @@ REM # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] #if CONFIG_METEORLAKE - 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] -#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_PANTHERLAKE) - 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] + mod_cfg = [0, 0, 0, 0, 296, 4996000, 384, 384, 0, 4996, 0, + 1, 0, 0, 0, 296, 2652000, 384, 384, 0, 2652, 0, + 2, 0, 0, 0, 296, 2928000, 512, 512, 0, 2928, 0, + 3, 0, 0, 0, 296, 2572000, 128, 128, 0, 2572, 0, + 4, 0, 0, 0, 296, 3760000, 1536, 1536, 0, 3760, 0] +#elif CONFIG_LUNARLAKE + mod_cfg = [0, 0, 0, 0, 296, 2336000, 384, 384, 0, 2336, 0, + 1, 0, 0, 0, 296, 2344000, 384, 384, 0, 2344, 0, + 2, 0, 0, 0, 296, 2448000, 512, 512, 0, 2448, 0, + 3, 0, 0, 0, 296, 2160000, 128, 128, 0, 2160, 0, + 4, 0, 0, 0, 296, 3268000, 1536, 1536, 0, 3268, 0] +#elif CONFIG_SOC_ACE30 || CONFIG_SOC_ACE40 + mod_cfg = [0, 0, 0, 0, 296, 5091000, 384, 384, 0, 5091, 0, + 1, 0, 0, 0, 296, 5111000, 384, 384, 0, 5111, 0, + 2, 0, 0, 0, 296, 5195000, 512, 512, 0, 5195, 0, + 3, 0, 0, 0, 296, 5219000, 128, 128, 0, 5219, 0, + 4, 0, 0, 0, 296, 5631000, 1536, 1536, 0, 5631, 0] #endif index = __COUNTER__ [[module.entry]] name = "MIXOUT" - uuid = "3C56505A-24D7-418F-BDDC-C1F5A3AC2AE0" + uuid = UUIDREG_STR_MIXOUT affinity_mask = "0x1" instance_count = "30" domain_types = "0" @@ -65,20 +66,23 @@ REM # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] #if CONFIG_METEORLAKE - 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] -#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_PANTHERLAKE) - 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] + mod_cfg = [0, 0, 0, 0, 520, 2280000, 384, 384, 0, 2280, 0, + 1, 0, 0, 0, 520, 1988000, 384, 384, 0, 1988, 0, + 2, 0, 0, 0, 520, 7631000, 512, 512, 0, 7631, 0, + 3, 0, 0, 0, 520, 1953000, 128, 128, 0, 1953, 0, + 4, 0, 0, 0, 520, 2301000, 1536, 1536, 0, 2301, 0] +#elif CONFIG_LUNARLAKE + mod_cfg = [0, 0, 0, 0, 520, 2280000, 384, 384, 0, 0, 0, + 1, 0, 0, 0, 520, 1988000, 384, 384, 0, 0, 0, + 2, 0, 0, 0, 520, 7631000, 512, 512, 0, 0, 0, + 3, 0, 0, 0, 520, 1953000, 128, 128, 0, 0, 0, + 4, 0, 0, 0, 520, 2301000, 1536, 1536, 0, 0, 0] +#elif CONFIG_SOC_ACE30 || CONFIG_SOC_ACE40 + mod_cfg = [0, 0, 0, 0, 520, 3999000, 384, 384, 0, 3999, 0, + 1, 0, 0, 0, 520, 3999000, 384, 384, 0, 3999, 0, + 2, 0, 0, 0, 520, 4055000, 512, 512, 0, 4055, 0, + 3, 0, 0, 0, 520, 3987000, 128, 128, 0, 3987, 0, + 4, 0, 0, 0, 520, 2273000, 1536, 1536, 0, 2273, 0] #endif index = __COUNTER__ diff --git a/src/audio/mixin_mixout/mixin_mixout_hifi3.c b/src/audio/mixin_mixout/mixin_mixout_hifi3.c index da22be3634c5..40962339dbce 100644 --- a/src/audio/mixin_mixout/mixin_mixout_hifi3.c +++ b/src/audio/mixin_mixout/mixin_mixout_hifi3.c @@ -10,6 +10,8 @@ #if SOF_USE_HIFI(3, MIXIN_MIXOUT) || SOF_USE_HIFI(4, MIXIN_MIXOUT) +#include <xtensa/tie/xt_hifi3.h> + #if CONFIG_FORMAT_S16LE static void mix_s16(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples, const struct cir_buf_ptr *source, @@ -21,8 +23,8 @@ static void mix_s16(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe ae_int16x4 out_sample; ae_int16x4 *in; ae_int16x4 *out; - ae_valign inu = AE_ZALIGN64(); - ae_valign outu1 = AE_ZALIGN64(); + ae_valign inu; + ae_valign outu1; ae_valign outu2 = AE_ZALIGN64(); /* cir_buf_wrap() is required and is done below in a loop */ ae_int16 *dst = (ae_int16 *)sink->ptr + start_sample; @@ -47,7 +49,7 @@ static void mix_s16(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe outu1 = AE_LA64_PP(out); m = n >> 2; left = n & 0x03; - /* process 4 frames per loop */ + /* process 4 samples per loop */ for (i = 0; i < m; i++) { AE_LA16X4_IP(in_sample, inu, in); AE_LA16X4_IP(out_sample, outu1, out); @@ -81,7 +83,7 @@ static void mix_s16(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe inu = AE_LA64_PP(in); m = n >> 2; left = n & 0x03; - /* process 4 frames per loop */ + /* process 4 samples per loop */ for (i = 0; i < m; i++) { AE_LA16X4_IP(in_sample, inu, in); AE_SA16X4_IP(in_sample, outu2, out); @@ -108,16 +110,19 @@ static void mix_s16_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t ae_int16x4 out_sample; ae_int16x4 *in; ae_int16x4 *out; - ae_valign inu = AE_ZALIGN64(); - ae_valign outu1 = AE_ZALIGN64(); + ae_valign inu; + ae_valign outu1; ae_valign outu2 = AE_ZALIGN64(); /* cir_buf_wrap() is required and is done below in a loop */ ae_int16 *dst = (ae_int16 *)sink->ptr + start_sample; ae_int16 *src = source->ptr; - ae_int16x4 gain_vec; - ae_int32x2 tmpl, tmph; + ae_f16x4 gain_vec; + + /* this func does not support unity gain as 1 cannot be represented as Q1.15 value */ + assert(gain < IPC4_MIXIN_UNITY_GAIN); gain_vec = AE_L16_I((ae_int16 *)&gain, 0); + gain_vec = AE_SLAI16S(gain_vec, 5); /* convert to Q1.15 */ assert(mixed_samples >= start_sample); samples_to_mix = AE_MIN_32_signed(mixed_samples - start_sample, sample_count); @@ -138,16 +143,11 @@ static void mix_s16_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t outu1 = AE_LA64_PP(out); m = n >> 2; left = n & 0x03; - /* process 4 frames per loop */ + /* process 4 samples per loop */ for (i = 0; i < m; i++) { AE_LA16X4_IP(in_sample, inu, in); - /* apply gain to in_sample */ - AE_MUL16X4(tmph, tmpl, in_sample, gain_vec); - tmpl = AE_SRAI32(tmpl, IPC4_MIXIN_GAIN_SHIFT); - tmph = AE_SRAI32(tmph, IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_CVT16X4(tmph, tmpl); - + in_sample = AE_MULFP16X4S(in_sample, gain_vec); AE_LA16X4_IP(out_sample, outu1, out); out--; out_sample = AE_ADD16S(in_sample, out_sample); @@ -160,11 +160,7 @@ static void mix_s16_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t */ for (i = 0; i < left ; i++) { AE_L16_IP(in_sample, (ae_int16 *)in, sizeof(ae_int16)); - - AE_MUL16X4(tmph, tmpl, in_sample, gain_vec); - tmpl = AE_SRAI32(tmpl, IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_CVT16X4(tmpl, tmpl); - + in_sample = AE_MULFP16X4S(in_sample, gain_vec); AE_L16_IP(out_sample, (ae_int16 *)out, 0); out_sample = AE_ADD16S(in_sample, out_sample); AE_S16_0_IP(out_sample, (ae_int16 *)out, sizeof(ae_int16)); @@ -184,15 +180,10 @@ static void mix_s16_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t inu = AE_LA64_PP(in); m = n >> 2; left = n & 0x03; - /* process 4 frames per loop */ + /* process 4 samples per loop */ for (i = 0; i < m; i++) { AE_LA16X4_IP(in_sample, inu, in); - - AE_MUL16X4(tmph, tmpl, in_sample, gain_vec); - tmpl = AE_SRAI32(tmpl, IPC4_MIXIN_GAIN_SHIFT); - tmph = AE_SRAI32(tmph, IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_CVT16X4(tmph, tmpl); - + in_sample = AE_MULFP16X4S(in_sample, gain_vec); AE_SA16X4_IP(in_sample, outu2, out); } AE_SA64POS_FP(outu2, out); @@ -202,11 +193,7 @@ static void mix_s16_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t */ for (i = 0; i < left ; i++) { AE_L16_IP(in_sample, (ae_int16 *)in, sizeof(ae_int16)); - - AE_MUL16X4(tmph, tmpl, in_sample, gain_vec); - tmpl = AE_SRAI32(tmpl, IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_CVT16X4(tmpl, tmpl); - + in_sample = AE_MULFP16X4S(in_sample, gain_vec); AE_S16_0_IP(in_sample, (ae_int16 *)out, sizeof(ae_int16)); } } @@ -224,8 +211,8 @@ static void mix_s24(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe ae_int32x2 out_sample; ae_int32x2 *in; ae_int32x2 *out; - ae_valign inu = AE_ZALIGN64(); - ae_valign outu1 = AE_ZALIGN64(); + ae_valign inu; + ae_valign outu1; ae_valign outu2 = AE_ZALIGN64(); /* cir_buf_wrap() is required and is done below in a loop */ int32_t *dst = (int32_t *)sink->ptr + start_sample; @@ -255,6 +242,9 @@ static void mix_s24(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe AE_LA32X2_IP(in_sample, inu, in); AE_LA32X2_IP(out_sample, outu1, out); out--; + /* sign extent in_sample as AE_ADD24S expects Q9.23 arguments */ + in_sample = AE_SLAI24S(AE_MOVF24X2_FROMINT32X2(in_sample), 0); + /* out_sample is already sign extended by other mixin in a loop below */ out_sample = AE_ADD24S(in_sample, out_sample); AE_SA32X2_IP(out_sample, outu2, out); } @@ -264,6 +254,8 @@ static void mix_s24(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe if (left) { AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); AE_L32_IP(out_sample, (ae_int32 *)out, 0); + /* sign extension */ + in_sample = AE_SLAI24S(AE_MOVF24X2_FROMINT32X2(in_sample), 0); out_sample = AE_ADD24S(in_sample, out_sample); AE_S32_L_IP(out_sample, (ae_int32 *)out, sizeof(ae_int32)); } @@ -283,12 +275,16 @@ static void mix_s24(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe left = n & 1; for (i = 0; i < m; i++) { AE_LA32X2_IP(in_sample, inu, in); + /* sign extension */ + in_sample = AE_SLAI24S(AE_MOVF24X2_FROMINT32X2(in_sample), 0); AE_SA32X2_IP(in_sample, outu2, out); } AE_SA64POS_FP(outu2, out); /* process the left sample to avoid memory access overrun */ if (left) { AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); + /* sign extension */ + in_sample = AE_SLAI24S(AE_MOVF24X2_FROMINT32X2(in_sample), 0); AE_S32_L_IP(in_sample, (ae_int32 *)out, sizeof(ae_int32)); } } @@ -300,20 +296,24 @@ static void mix_s24_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t { int samples_to_mix, samples_to_copy, left_samples; int n, nmax, i, m, left; - ae_int32x2 in_sample, in_sample32; + ae_int32x2 in_sample; ae_int32x2 out_sample; ae_int32x2 *in; ae_int32x2 *out; - ae_valign inu = AE_ZALIGN64(); - ae_valign outu1 = AE_ZALIGN64(); + ae_valign inu; + ae_valign outu1; ae_valign outu2 = AE_ZALIGN64(); /* cir_buf_wrap() is required and is done below in a loop */ int32_t *dst = (int32_t *)sink->ptr + start_sample; int32_t *src = source->ptr; - ae_int16x4 gain_vec; - ae_int64 tmph, tmpl; + ae_f24x2 gain_vec; + ae_int32 gain32 = (ae_int32)gain; - gain_vec = AE_L16_I((ae_int16 *)&gain, 0); + /* this func does not support unity gain as 1 cannot be represented as Q1.23 value */ + assert(gain < IPC4_MIXIN_UNITY_GAIN); + + gain_vec = AE_MOVF24X2_FROMINT32X2(AE_L32_I(&gain32, 0)); + gain_vec = AE_SLAI24S(gain_vec, 13); /* convert to Q1.23 */ assert(mixed_samples >= start_sample); samples_to_mix = AE_MIN_32_signed(mixed_samples - start_sample, sample_count); @@ -337,18 +337,10 @@ static void mix_s24_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t /* process 2 samples per time */ for (i = 0; i < m; i++) { AE_LA32X2_IP(in_sample, inu, in); - - /* apply gain to in_sample */ - in_sample32 = AE_SLAI32(in_sample, 8); /* sign extension */ - tmpl = AE_MUL32X16_L0(in_sample32, gain_vec); - tmph = AE_MUL32X16_H0(in_sample32, gain_vec); - tmpl = AE_SRAI64(tmpl, 8 + IPC4_MIXIN_GAIN_SHIFT); - tmph = AE_SRAI64(tmph, 8 + IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_SEL32_LL(AE_MOVINT32X2_FROMINT64(tmph), - AE_MOVINT32X2_FROMINT64(tmpl)); - + in_sample = AE_MULFP24X2R(AE_MOVF24X2_FROMINT32X2(in_sample), gain_vec); AE_LA32X2_IP(out_sample, outu1, out); out--; + /* out samples are already sign extended by other mixin in a loop below */ out_sample = AE_ADD24S(in_sample, out_sample); AE_SA32X2_IP(out_sample, outu2, out); } @@ -357,13 +349,9 @@ static void mix_s24_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t /* process the left sample to avoid memory access overrun */ if (left) { AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); - - in_sample32 = AE_SLAI32(in_sample, 8); /* sign extension */ - tmpl = AE_MUL32X16_L0(in_sample32, gain_vec); - tmpl = AE_SRAI64(tmpl, 8 + IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_MOVINT32X2_FROMINT64(tmpl); - + in_sample = AE_MULFP24X2R(AE_MOVF24X2_FROMINT32X2(in_sample), gain_vec); AE_L32_IP(out_sample, (ae_int32 *)out, 0); + /* out samples are already sign extended by other mixin in a loop below */ out_sample = AE_ADD24S(in_sample, out_sample); AE_S32_L_IP(out_sample, (ae_int32 *)out, sizeof(ae_int32)); } @@ -383,27 +371,14 @@ static void mix_s24_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t left = n & 1; for (i = 0; i < m; i++) { AE_LA32X2_IP(in_sample, inu, in); - - in_sample32 = AE_SLAI32(in_sample, 8); /* sign extension */ - tmpl = AE_MUL32X16_L0(in_sample32, gain_vec); - tmph = AE_MUL32X16_H0(in_sample32, gain_vec); - tmpl = AE_SRAI64(tmpl, 8 + IPC4_MIXIN_GAIN_SHIFT); - tmph = AE_SRAI64(tmph, 8 + IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_SEL32_LL(AE_MOVINT32X2_FROMINT64(tmph), - AE_MOVINT32X2_FROMINT64(tmpl)); - + in_sample = AE_MULFP24X2R(AE_MOVF24X2_FROMINT32X2(in_sample), gain_vec); AE_SA32X2_IP(in_sample, outu2, out); } AE_SA64POS_FP(outu2, out); /* process the left sample to avoid memory access overrun */ if (left) { AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); - - in_sample32 = AE_SLAI32(in_sample, 8); /* sign extension */ - tmpl = AE_MUL32X16_L0(in_sample32, gain_vec); - tmpl = AE_SRAI64(tmpl, 8 + IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_MOVINT32X2_FROMINT64(tmpl); - + in_sample = AE_MULFP24X2R(AE_MOVF24X2_FROMINT32X2(in_sample), gain_vec); AE_S32_L_IP(in_sample, (ae_int32 *)out, sizeof(ae_int32)); } } @@ -422,8 +397,8 @@ static void mix_s32(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe ae_int32x2 out_sample; ae_int32x2 *in; ae_int32x2 *out; - ae_valign inu = AE_ZALIGN64(); - ae_valign outu1 = AE_ZALIGN64(); + ae_valign inu; + ae_valign outu1; ae_valign outu2 = AE_ZALIGN64(); /* cir_buf_wrap() is required and is done below in a loop */ int32_t *dst = (int32_t *)sink->ptr + start_sample; @@ -503,16 +478,19 @@ static void mix_s32_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t ae_int32x2 out_sample; ae_int32x2 *in; ae_int32x2 *out; - ae_valign inu = AE_ZALIGN64(); - ae_valign outu1 = AE_ZALIGN64(); + ae_valign inu; + ae_valign outu1; ae_valign outu2 = AE_ZALIGN64(); /* cir_buf_wrap() is required and is done below in a loop */ int32_t *dst = (int32_t *)sink->ptr + start_sample; int32_t *src = source->ptr; - ae_int16x4 gain_vec; - ae_int64 tmpl, tmph; + ae_f16x4 gain_vec; + + /* this func does not support unity gain as 1 cannot be represented as Q1.15 value */ + assert(gain < IPC4_MIXIN_UNITY_GAIN); gain_vec = AE_L16_I((ae_int16 *)&gain, 0); + gain_vec = AE_SLAI16S(gain_vec, 5); /* convert to Q1.15 */ assert(mixed_samples >= start_sample); samples_to_mix = AE_MIN_32_signed(mixed_samples - start_sample, sample_count); @@ -535,18 +513,9 @@ static void mix_s32_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t left = n & 1; for (i = 0; i < m; i++) { AE_LA32X2_IP(in_sample, inu, in); - - /* apply gain to in_sample */ - tmpl = AE_MUL32X16_L0(in_sample, gain_vec); - tmph = AE_MUL32X16_H0(in_sample, gain_vec); - tmpl = AE_SRAI64(tmpl, IPC4_MIXIN_GAIN_SHIFT); - tmph = AE_SRAI64(tmph, IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_SEL32_LL(AE_MOVINT32X2_FROMINT64(tmph), - AE_MOVINT32X2_FROMINT64(tmpl)); - AE_LA32X2_IP(out_sample, outu1, out); out--; - out_sample = AE_ADD32S(in_sample, out_sample); + AE_MULAFP32X16X2RS_L(out_sample, in_sample, gain_vec); AE_SA32X2_IP(out_sample, outu2, out); } AE_SA64POS_FP(outu2, out); @@ -554,13 +523,8 @@ static void mix_s32_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t /* process the left sample to avoid memory access overrun */ if (left) { AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); - - tmpl = AE_MUL32X16_L0(in_sample, gain_vec); - tmpl = AE_SRAI64(tmpl, IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_MOVINT32X2_FROMINT64(tmpl); - AE_L32_IP(out_sample, (ae_int32 *)out, 0); - out_sample = AE_ADD32S(in_sample, out_sample); + AE_MULAFP32X16X2RS_L(out_sample, in_sample, gain_vec); AE_S32_L_IP(out_sample, (ae_int32 *)out, sizeof(ae_int32)); } } @@ -580,14 +544,7 @@ static void mix_s32_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t left = n & 1; for (i = 0; i < m; i++) { AE_LA32X2_IP(in_sample, inu, in); - - tmpl = AE_MUL32X16_L0(in_sample, gain_vec); - tmph = AE_MUL32X16_H0(in_sample, gain_vec); - tmpl = AE_SRAI64(tmpl, IPC4_MIXIN_GAIN_SHIFT); - tmph = AE_SRAI64(tmph, IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_SEL32_LL(AE_MOVINT32X2_FROMINT64(tmph), - AE_MOVINT32X2_FROMINT64(tmpl)); - + in_sample = AE_MULFP32X16X2RS_L(in_sample, gain_vec); AE_SA32X2_IP(in_sample, outu2, out); } AE_SA64POS_FP(outu2, out); @@ -595,11 +552,7 @@ static void mix_s32_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t /* process the left sample to avoid memory access overrun */ if (left) { AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); - - tmpl = AE_MUL32X16_L0(in_sample, gain_vec); - tmpl = AE_SRAI64(tmpl, IPC4_MIXIN_GAIN_SHIFT); - in_sample = AE_MOVINT32X2_FROMINT64(tmpl); - + in_sample = AE_MULFP32X16X2RS_L(in_sample, gain_vec); AE_S32_L_IP(in_sample, (ae_int32 *)out, sizeof(ae_int32)); } } diff --git a/src/audio/mixin_mixout/mixin_mixout_hifi5.c b/src/audio/mixin_mixout/mixin_mixout_hifi5.c index 14bea3d98773..7e42e0f8d376 100644 --- a/src/audio/mixin_mixout/mixin_mixout_hifi5.c +++ b/src/audio/mixin_mixout/mixin_mixout_hifi5.c @@ -21,8 +21,8 @@ static void mix_s16(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe ae_int16x4 out_sample, out_sample1; ae_int16x8 *in; ae_int16x8 *out; - ae_valignx2 inu = AE_ZALIGN128(); - ae_valignx2 outu1 = AE_ZALIGN128(); + ae_valignx2 inu; + ae_valignx2 outu1; ae_valignx2 outu2 = AE_ZALIGN128(); /* cir_buf_wrap() is required and is done below in a loop */ ae_int16 *dst = (ae_int16 *)sink->ptr + start_sample; @@ -82,9 +82,109 @@ static void mix_s16(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe inu = AE_LA128_PP(in); m = n >> 3; left = n & 0x07; - /* process 8 frames per loop */ + /* process 8 samples per loop */ + for (i = 0; i < m; i++) { + AE_LA16X4X2_IP(in_sample, in_sample1, inu, in); + AE_SA16X4X2_IP(in_sample, in_sample1, outu2, out); + } + AE_SA128POS_FP(outu2, out); + + /* process the left samples that less than 8 + * one by one to avoid memory access overrun + */ + for (i = 0; i < left ; i++) { + AE_L16_IP(in_sample, (ae_int16 *)in, sizeof(ae_int16)); + AE_S16_0_IP(in_sample, (ae_int16 *)out, sizeof(ae_int16)); + } + } +} + +static void mix_s16_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples, + const struct cir_buf_ptr *source, + int32_t sample_count, uint16_t gain) +{ + int samples_to_mix, samples_to_copy, left_samples; + int n, nmax, i, m, left; + ae_int16x4 in_sample, in_sample1; + ae_int16x4 out_sample, out_sample1; + ae_int16x8 *in; + ae_int16x8 *out; + ae_valignx2 inu; + ae_valignx2 outu1; + ae_valignx2 outu2 = AE_ZALIGN128(); + /* cir_buf_wrap() is required and is done below in a loop */ + ae_int16 *dst = (ae_int16 *)sink->ptr + start_sample; + ae_int16 *src = source->ptr; + ae_f16x4 gain_vec; + + /* this func does not support unity gain as 1 cannot be represented as Q1.15 value */ + assert(gain < IPC4_MIXIN_UNITY_GAIN); + + gain_vec = AE_L16_I((ae_int16 *)&gain, 0); + gain_vec = AE_SLAI16S(gain_vec, 5); /* convert to Q1.15 */ + + assert(mixed_samples >= start_sample); + samples_to_mix = AE_MIN32(mixed_samples - start_sample, sample_count); + samples_to_copy = sample_count - samples_to_mix; + n = 0; + + for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); + /* calculate the remaining samples*/ + nmax = (ae_int16 *)source->buf_end - src; + n = AE_MIN32(left_samples, nmax); + nmax = (ae_int16 *)sink->buf_end - dst; + n = AE_MIN32(n, nmax); + in = (ae_int16x8 *)src; + out = (ae_int16x8 *)dst; + inu = AE_LA128_PP(in); + outu1 = AE_LA128_PP(out); + m = n >> 3; + left = n & 0x07; + /* process 8 samples per loop */ + for (i = 0; i < m; i++) { + AE_LA16X4X2_IP(in_sample, in_sample1, inu, in); + AE_LA16X4X2_IP(out_sample, out_sample1, outu1, out); + out--; + in_sample = AE_MULFP16X4RS(in_sample, gain_vec); + in_sample1 = AE_MULFP16X4RS(in_sample1, gain_vec); + out_sample = AE_ADD16S(in_sample, out_sample); + out_sample1 = AE_ADD16S(in_sample1, out_sample1); + AE_SA16X4X2_IP(out_sample, out_sample1, outu2, out); + } + AE_SA128POS_FP(outu2, out); + + /* process the left samples that less than 8 + * one by one to avoid memory access overrun + */ + for (i = 0; i < left ; i++) { + AE_L16_IP(in_sample, (ae_int16 *)in, sizeof(ae_int16)); + AE_L16_IP(out_sample, (ae_int16 *)out, 0); + in_sample = AE_MULFP16X4RS(in_sample, gain_vec); + out_sample = AE_ADD16S(in_sample, out_sample); + AE_S16_0_IP(out_sample, (ae_int16 *)out, sizeof(ae_int16)); + } + } + + for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); + /* calculate the remaining samples*/ + nmax = (ae_int16 *)source->buf_end - src; + n = AE_MIN32(left_samples, nmax); + nmax = (ae_int16 *)sink->buf_end - dst; + n = AE_MIN32(n, nmax); + in = (ae_int16x8 *)src; + out = (ae_int16x8 *)dst; + inu = AE_LA128_PP(in); + m = n >> 3; + left = n & 0x07; + /* process 8 samples per loop */ for (i = 0; i < m; i++) { AE_LA16X4X2_IP(in_sample, in_sample1, inu, in); + in_sample = AE_MULFP16X4RS(in_sample, gain_vec); + in_sample1 = AE_MULFP16X4RS(in_sample1, gain_vec); AE_SA16X4X2_IP(in_sample, in_sample1, outu2, out); } AE_SA128POS_FP(outu2, out); @@ -94,6 +194,7 @@ static void mix_s16(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe */ for (i = 0; i < left ; i++) { AE_L16_IP(in_sample, (ae_int16 *)in, sizeof(ae_int16)); + in_sample = AE_MULFP16X4RS(in_sample, gain_vec); AE_S16_0_IP(in_sample, (ae_int16 *)out, sizeof(ae_int16)); } } @@ -111,8 +212,8 @@ static void mix_s24(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe ae_int32x2 out_sample, out_sample1; ae_int32x4 *in; ae_int32x4 *out; - ae_valignx2 inu = AE_ZALIGN128(); - ae_valignx2 outu1 = AE_ZALIGN128(); + ae_valignx2 inu; + ae_valignx2 outu1; ae_valignx2 outu2 = AE_ZALIGN128(); /* cir_buf_wrap() is required and is done below in a loop */ int32_t *dst = (int32_t *)sink->ptr + start_sample; @@ -137,21 +238,27 @@ static void mix_s24(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe outu1 = AE_LA128_PP(out); m = n >> 2; left = n & 3; - /* process 2 samples per time */ + /* process 4 samples per time */ for (i = 0; i < m; i++) { AE_LA32X2X2_IP(in_sample, in_sample1, inu, in); AE_LA32X2X2_IP(out_sample, out_sample1, outu1, out); out--; - out_sample = AE_ADD24S(in_sample, out_sample); + /* sign extent in samples as AE_ADD24S expects Q9.23 arguments */ + in_sample = AE_SLAI24S(AE_MOVF24X2_FROMINT32X2(in_sample), 0); + in_sample1 = AE_SLAI24S(AE_MOVF24X2_FROMINT32X2(in_sample1), 0); + /* out samples are already sign extended by other mixin in a loop below */ + out_sample = AE_ADD24S(in_sample, out_sample); out_sample1 = AE_ADD24S(in_sample1, out_sample1); AE_SA32X2X2_IP(out_sample, out_sample1, outu2, out); } AE_SA128POS_FP(outu2, out); - /* process the left sample to avoid memory access overrun */ - if (left) { + /* process the left samples to avoid memory access overrun */ + for (i = 0; i < left; i++) { AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); AE_L32_IP(out_sample, (ae_int32 *)out, 0); + /* sign extension */ + in_sample = AE_SLAI24S(AE_MOVF24X2_FROMINT32X2(in_sample), 0); out_sample = AE_ADD24S(in_sample, out_sample); AE_S32_L_IP(out_sample, (ae_int32 *)out, sizeof(ae_int32)); } @@ -171,17 +278,118 @@ static void mix_s24(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe left = n & 3; for (i = 0; i < m; i++) { AE_LA32X2X2_IP(in_sample, in_sample1, inu, in); + /* sign extension */ + in_sample = AE_SLAI24S(AE_MOVF24X2_FROMINT32X2(in_sample), 0); + in_sample1 = AE_SLAI24S(AE_MOVF24X2_FROMINT32X2(in_sample1), 0); AE_SA32X2X2_IP(in_sample, in_sample1, outu2, out); } AE_SA128POS_FP(outu2, out); - /* process the left sample to avoid memory access overrun */ - if (left) { + /* process the left samples to avoid memory access overrun */ + for (i = 0; i < left; i++) { AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); + /* sign extension */ + in_sample = AE_SLAI24S(AE_MOVF24X2_FROMINT32X2(in_sample), 0); AE_S32_L_IP(in_sample, (ae_int32 *)out, sizeof(ae_int32)); } } } +static void mix_s24_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples, + const struct cir_buf_ptr *source, + int32_t sample_count, uint16_t gain) +{ + int samples_to_mix, samples_to_copy, left_samples; + int n, nmax, i, m, left; + ae_int32x2 in_sample, in_sample1; + ae_int32x2 out_sample, out_sample1; + ae_int32x4 *in; + ae_int32x4 *out; + ae_valignx2 inu; + ae_valignx2 outu1; + ae_valignx2 outu2 = AE_ZALIGN128(); + /* cir_buf_wrap() is required and is done below in a loop */ + int32_t *dst = (int32_t *)sink->ptr + start_sample; + int32_t *src = source->ptr; + ae_f24x2 gain_vec; + ae_int32 gain32 = (ae_int32)gain; + + /* this func does not support unity gain as 1 cannot be represented as Q1.23 value */ + assert(gain < IPC4_MIXIN_UNITY_GAIN); + + gain_vec = AE_MOVF24X2_FROMINT32X2(AE_L32_I(&gain32, 0)); + gain_vec = AE_SLAI24S(gain_vec, 13); /* convert to Q1.23 */ + + assert(mixed_samples >= start_sample); + samples_to_mix = AE_MIN32(mixed_samples - start_sample, sample_count); + samples_to_copy = sample_count - samples_to_mix; + n = 0; + + for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); + /* calculate the remaining samples*/ + nmax = (int32_t *)source->buf_end - src; + n = AE_MIN32(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; + n = AE_MIN32(n, nmax); + in = (ae_int32x4 *)src; + out = (ae_int32x4 *)dst; + inu = AE_LA128_PP(in); + outu1 = AE_LA128_PP(out); + m = n >> 2; + left = n & 3; + /* process 4 samples per time */ + for (i = 0; i < m; i++) { + AE_LA32X2X2_IP(in_sample, in_sample1, inu, in); + AE_LA32X2X2_IP(out_sample, out_sample1, outu1, out); + out--; + in_sample = AE_MULFP24X2R(AE_MOVF24X2_FROMINT32X2(in_sample), gain_vec); + in_sample1 = AE_MULFP24X2R(AE_MOVF24X2_FROMINT32X2(in_sample1), gain_vec); + /* out samples are already sign extended by other mixin in a loop below */ + out_sample = AE_ADD24S(in_sample, out_sample); + out_sample1 = AE_ADD24S(in_sample1, out_sample1); + AE_SA32X2X2_IP(out_sample, out_sample1, outu2, out); + } + AE_SA128POS_FP(outu2, out); + + /* process the left samples to avoid memory access overrun */ + for (i = 0; i < left; i++) { + AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(out_sample, (ae_int32 *)out, 0); + in_sample = AE_MULFP24X2R(AE_MOVF24X2_FROMINT32X2(in_sample), gain_vec); + /* out samples are already sign extended by other mixin in a loop below */ + out_sample = AE_ADD24S(in_sample, out_sample); + AE_S32_L_IP(out_sample, (ae_int32 *)out, sizeof(ae_int32)); + } + } + + for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); + nmax = (int32_t *)source->buf_end - src; + n = AE_MIN32(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; + n = AE_MIN32(n, nmax); + in = (ae_int32x4 *)src; + out = (ae_int32x4 *)dst; + inu = AE_LA128_PP(in); + m = n >> 2; + left = n & 3; + for (i = 0; i < m; i++) { + AE_LA32X2X2_IP(in_sample, in_sample1, inu, in); + in_sample = AE_MULFP24X2R(AE_MOVF24X2_FROMINT32X2(in_sample), gain_vec); + in_sample1 = AE_MULFP24X2R(AE_MOVF24X2_FROMINT32X2(in_sample1), gain_vec); + AE_SA32X2X2_IP(in_sample, in_sample1, outu2, out); + } + AE_SA128POS_FP(outu2, out); + /* process the left samples to avoid memory access overrun */ + for (i = 0; i < left; i++) { + AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); + in_sample = AE_MULFP24X2R(AE_MOVF24X2_FROMINT32X2(in_sample), gain_vec); + AE_S32_L_IP(in_sample, (ae_int32 *)out, sizeof(ae_int32)); + } + } +} #endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE @@ -195,8 +403,8 @@ static void mix_s32(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe ae_int32x2 out_sample, out_sample1; ae_int32x4 *in; ae_int32x4 *out; - ae_valignx2 inu = AE_ZALIGN128(); - ae_valignx2 outu1 = AE_ZALIGN128(); + ae_valignx2 inu; + ae_valignx2 outu1; ae_valignx2 outu2 = AE_ZALIGN128(); /* cir_buf_wrap() is required and is done below in a loop */ int32_t *dst = (int32_t *)sink->ptr + start_sample; @@ -231,8 +439,8 @@ static void mix_s32(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe } AE_SA128POS_FP(outu2, out); - /* process the left sample to avoid memory access overrun */ - if (left) { + /* process the left samples to avoid memory access overrun */ + for (i = 0; i < left; i++) { AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); AE_L32_IP(out_sample, (ae_int32 *)out, 0); out_sample = AE_ADD32S(in_sample, out_sample); @@ -258,26 +466,116 @@ static void mix_s32(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe AE_SA32X2X2_IP(in_sample, in_sample1, outu2, out); } AE_SA128POS_FP(outu2, out); - /* process the left sample to avoid memory access overrun */ - if (left) { + /* process the left samples to avoid memory access overrun */ + for (i = 0; i < left; i++) { AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); AE_S32_L_IP(in_sample, (ae_int32 *)out, sizeof(ae_int32)); } } } +static void mix_s32_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples, + const struct cir_buf_ptr *source, + int32_t sample_count, uint16_t gain) +{ + int samples_to_mix, samples_to_copy, left_samples; + int n, nmax, i, m, left; + ae_int32x2 in_sample, in_sample1; + ae_int32x2 out_sample, out_sample1; + ae_int32x4 *in; + ae_int32x4 *out; + ae_valignx2 inu; + ae_valignx2 outu1; + ae_valignx2 outu2 = AE_ZALIGN128(); + /* cir_buf_wrap() is required and is done below in a loop */ + int32_t *dst = (int32_t *)sink->ptr + start_sample; + int32_t *src = source->ptr; + ae_f16x4 gain_vec; + + /* this func does not support unity gain as 1 cannot be represented as Q1.15 value */ + assert(gain < IPC4_MIXIN_UNITY_GAIN); + + gain_vec = AE_L16_I((ae_int16 *)&gain, 0); + gain_vec = AE_SLAI16S(gain_vec, 5); /* convert to Q1.15 */ + + assert(mixed_samples >= start_sample); + samples_to_mix = AE_MIN32(mixed_samples - start_sample, sample_count); + samples_to_copy = sample_count - samples_to_mix; + n = 0; + + for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); + /* calculate the remaining samples*/ + nmax = (int32_t *)source->buf_end - src; + n = AE_MIN32(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; + n = AE_MIN32(n, nmax); + in = (ae_int32x4 *)src; + out = (ae_int32x4 *)dst; + inu = AE_LA128_PP(in); + outu1 = AE_LA128_PP(out); + m = n >> 2; + left = n & 3; + for (i = 0; i < m; i++) { + AE_LA32X2X2_IP(in_sample, in_sample1, inu, in); + AE_LA32X2X2_IP(out_sample, out_sample1, outu1, out); + out--; + AE_MULAFP32X16X2RS_L(out_sample, in_sample, gain_vec); + AE_MULAFP32X16X2RS_L(out_sample1, in_sample1, gain_vec); + AE_SA32X2X2_IP(out_sample, out_sample1, outu2, out); + } + AE_SA128POS_FP(outu2, out); + + /* process the left samples to avoid memory access overrun */ + for (i = 0; i < left; i++) { + AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(out_sample, (ae_int32 *)out, 0); + AE_MULAFP32X16X2RS_L(out_sample, in_sample, gain_vec); + AE_S32_L_IP(out_sample, (ae_int32 *)out, sizeof(ae_int32)); + } + } + + for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); + /* calculate the remaining samples*/ + nmax = (int32_t *)source->buf_end - src; + n = AE_MIN32(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; + n = AE_MIN32(n, nmax); + in = (ae_int32x4 *)src; + out = (ae_int32x4 *)dst; + inu = AE_LA128_PP(in); + m = n >> 2; + left = n & 3; + for (i = 0; i < m; i++) { + AE_LA32X2X2_IP(in_sample, in_sample1, inu, in); + in_sample = AE_MULFP32X16X2RS_L(in_sample, gain_vec); + in_sample1 = AE_MULFP32X16X2RS_L(in_sample1, gain_vec); + AE_SA32X2X2_IP(in_sample, in_sample1, outu2, out); + } + AE_SA128POS_FP(outu2, out); + /* process the left samples to avoid memory access overrun */ + for (i = 0; i < left; i++) { + AE_L32_IP(in_sample, (ae_int32 *)in, sizeof(ae_int32)); + in_sample = AE_MULFP32X16X2RS_L(in_sample, gain_vec); + AE_S32_L_IP(in_sample, (ae_int32 *)out, sizeof(ae_int32)); + } + } +} #endif /* CONFIG_FORMAT_S32LE */ /* TODO: implement mixing functions with gain support!*/ __cold_rodata const struct mix_func_map mix_func_map[] = { #if CONFIG_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, mix_s16, mix_s16 }, + { SOF_IPC_FRAME_S16_LE, mix_s16, mix_s16_gain }, #endif #if CONFIG_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, mix_s24, mix_s24 }, + { SOF_IPC_FRAME_S24_4LE, mix_s24, mix_s24_gain }, #endif #if CONFIG_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, mix_s32, mix_s32 } + { SOF_IPC_FRAME_S32_LE, mix_s32, mix_s32_gain } #endif }; diff --git a/src/audio/module_adapter/CMakeLists.txt b/src/audio/module_adapter/CMakeLists.txt index 300296dc6205..c4b4a43e99e5 100644 --- a/src/audio/module_adapter/CMakeLists.txt +++ b/src/audio/module_adapter/CMakeLists.txt @@ -1,12 +1,107 @@ # SPDX-License-Identifier: BSD-3-Clause - 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() +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + # modules and codecs in alphabetical order +if (CONFIG_IPC_MAJOR_3) + zephyr_library_sources_ifdef(CONFIG_CADENCE_CODEC module/cadence.c module/cadence_ipc3.c) +elseif (CONFIG_IPC_MAJOR_4) + zephyr_include_directories(${sof_top_dir}/src/include/sof/audio/cadence) + zephyr_library_sources_ifdef(CONFIG_CADENCE_CODEC module/cadence.c module/cadence_ipc4.c) +endif() + + if (CONFIG_CADENCE_CODEC_AAC_DEC) + zephyr_library_import(xa_aac_dec ${CONFIG_CADENCE_CODEC_AAC_DEC_LIB}) + endif() + + if (CONFIG_CADENCE_CODEC_VORBIS_DEC) + zephyr_library_import(xa_vorbis_dec ${CONFIG_CADENCE_CODEC_VORBIS_DEC_LIB}) + endif() + + if (CONFIG_CADENCE_CODEC_MP3_DEC) + zephyr_library_import(xa_mp3_dec ${CONFIG_CADENCE_CODEC_MP3_DEC_LIB}) + endif() + + if (CONFIG_CADENCE_CODEC_MP3_ENC) + zephyr_library_import(xa_mp3_enc ${CONFIG_CADENCE_CODEC_MP3_ENC_LIB}) + endif() + + if (CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING) + if(CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(module/dolby/llext + ${PROJECT_BINARY_DIR}/dolby_dax_audio_processing_llext) + add_dependencies(app dolby_dax_audio_processing) + else() + zephyr_library_sources( + module/dolby/dax.c + module/dolby/dax_instance_manager.c + ) + if (CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING_MOCK) + zephyr_library_sources( + module/dolby/dax_mock.c + ) + else() + target_link_libraries(SOF INTERFACE m) + target_link_libraries(SOF INTERFACE c) + zephyr_library_import(dax_effect + ${sof_top_dir}/third_party/lib/libdax.a) + endif() + endif() + endif() + + zephyr_include_directories_ifdef(CONFIG_LIBRARY_MANAGER + ${SOF_SRC_PATH}/include/sof/audio/module_adapter/iadk/ + ${SOF_SRC_PATH}/include/sof/audio/module_adapter/library/ + ) + + zephyr_library_sources_ifdef(CONFIG_LIBRARY_MANAGER + library/native_system_agent.c + ) + + zephyr_library_sources_ifdef(CONFIG_INTEL_MODULES + module/modules.c + iadk/module_initial_settings_concrete.cpp + iadk/iadk_module_adapter.cpp + iadk/system_agent.cpp + library/native_system_service.c + ) + + zephyr_library_sources_ifdef(CONFIG_SOF_USERSPACE_PROXY + library/userspace_proxy.c + library/userspace_proxy_user.c + ) + + zephyr_library_sources_ifdef(CONFIG_PASSTHROUGH_CODEC + module/passthrough.c + ) + + if(CONFIG_WAVES_CODEC) + set(WAVES_DIR module/waves) + if(CONFIG_WAVES_CODEC STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(${WAVES_DIR}/llext ${PROJECT_BINARY_DIR}/waves_llext) + add_dependencies(app waves) + else() + zephyr_library_sources(${WAVES_DIR}/waves.c) + if(CONFIG_WAVES_CODEC_STUB) + zephyr_library_sources_ifdef(CONFIG_WAVES_CODEC_STUB + ${WAVES_DIR}/maxx_stub.c) + else() + zephyr_library_import(waves_codec + ${sof_top_dir}/third_party/lib/libMaxxChrome.a) + endif() + endif() + endif() + + return() +endif() + if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) if(CONFIG_CADENCE_CODEC) add_local_sources(sof module/cadence.c) @@ -53,6 +148,20 @@ if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) endif() + if(CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING) + target_include_directories(sof PRIVATE ${PROJECT_SOURCE_DIR}/third_party/include) + add_local_sources(sof module/dolby/dax.c) + add_local_sources(sof module/dolby/dax_instance_manager.c) + if (CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING_MOCK) + add_local_sources(sof module/dolby/dax_mock.c) + else() + target_link_libraries(sof PRIVATE m) + target_link_libraries(sof PRIVATE c) + sof_add_static_library(dax_effect + ${PROJECT_SOURCE_DIR}/third_party/lib/libdax.a) + endif() + endif() + if(CONFIG_PASSTHROUGH_CODEC) add_local_sources(sof module/passthrough.c) endif() diff --git a/src/audio/module_adapter/Kconfig b/src/audio/module_adapter/Kconfig index fb646a7f47e6..9bea2a5dd175 100644 --- a/src/audio/module_adapter/Kconfig +++ b/src/audio/module_adapter/Kconfig @@ -3,9 +3,18 @@ menu "Processing modules" visible if COMP_MODULE_ADAPTER + config MODULE_MEMORY_API_CONTAINER_CHUNK_SIZE + int "Number of memory containers to allocate at once" + default 16 + help + The per module resource containers are allocated in + chunks. The unused containers are kept in free + list. When the free list is empty the amount of + containers to allocate at once is selected by this + config option. + config CADENCE_CODEC bool "Cadence codec" - default n help Select for codecs which conforms to the Cadence API. This will cause codec adapter component to include header @@ -14,7 +23,6 @@ menu "Processing modules" if CADENCE_CODEC config CADENCE_CODEC_WRAPPER bool 'Cadence codec wrapper' - default n help Select for cadence_codec_api wrapper function that will allow users to call into codecs which conforms to the Cadence API without @@ -29,7 +37,6 @@ if CADENCE_CODEC config CADENCE_CODEC_AAC_DEC bool "Cadence AAC decoder" - default n help Select for Cadence AAC decoder support. This will cause Cadence codec to include Cadence AAC library @@ -44,7 +51,6 @@ if CADENCE_CODEC config CADENCE_CODEC_BSAC_DEC bool "Cadence BSAC decoder" - default n help Select for Cadence BSAC decoder support. This will cause Cadence codec to include Cadence BSAC library @@ -59,7 +65,6 @@ if CADENCE_CODEC config CADENCE_CODEC_DAB_DEC bool "Cadence DAB decoder" - default n help Select for Cadence DAB decoder support. This will cause Cadence codec to include Cadence DAB library @@ -74,7 +79,6 @@ if CADENCE_CODEC config CADENCE_CODEC_DRM_DEC bool "Cadence DRM decoder" - default n help Select for Cadence DRM decoder support. This will cause Cadence codec to include Cadence DRM library @@ -89,7 +93,6 @@ if CADENCE_CODEC config CADENCE_CODEC_MP3_DEC bool "Cadence MP3 decoder" - default n help Select for Cadence MP3 decoder support. This will cause Cadence codec to include Cadence MP3 library @@ -104,7 +107,6 @@ if CADENCE_CODEC config CADENCE_CODEC_MP3_ENC bool "Cadence MP3 encoder" - default n help Select for Cadence MP3 encoder support. This will cause Cadence codec to include Cadence MP3 library @@ -119,7 +121,6 @@ if CADENCE_CODEC config CADENCE_CODEC_SBC_DEC bool "Cadence SBC decoder" - default n help Select for Cadence SBC decoder support. This will cause Cadence codec to include Cadence SBC library @@ -135,7 +136,6 @@ if CADENCE_CODEC config CADENCE_CODEC_VORBIS_DEC bool "Cadence VORBIS decoder" - default n help Select for Cadence VORBIS decoder support. This will cause Cadence codec to include Cadence VORBIS library @@ -150,7 +150,6 @@ if CADENCE_CODEC config CADENCE_CODEC_SRC_PP bool "Cadence SRC polyphase" - default n help Select for Cadence SRC polyphase support. This will cause Cadence codec to include Cadence SRC library @@ -165,18 +164,31 @@ if CADENCE_CODEC endif # Cadence + config COMP_DOLBY_DAX_AUDIO_PROCESSING + tristate "Dolby DAX audio processing component" + help + Select to include Dolby DAX component. Dolby DAX component implements DAX API. + API definition together with pre-compiled library is shared by Dolby. + If library is not provided, COMP_DOLBY_DAX_AUDIO_PROCESSING_MOCK must be true, + then the input will be copied to the output. + + config COMP_DOLBY_DAX_AUDIO_PROCESSING_MOCK + bool "Dolby DAX audio processing component mock" + default y if COMP_STUBS + depends on COMP_DOLBY_DAX_AUDIO_PROCESSING + help + Mock DAX audio processing. It allows for compilation check and basic audio + flow checking. + config PASSTHROUGH_CODEC bool "Passthrough codec" - default n help Select for a passthrough API codec implementation. This will cause codec adapter component to include header files specific to PASSTHROUGH base codecs. config WAVES_CODEC - bool "Waves codec" - select WAVES_CODEC_STUB if COMP_STUBS - default n + tristate "Waves codec" help Select to include Waves codec. Waves codec implements MaxxEffect API. API definition together with pre-compiled library is shared by Waves Audio Ltd. @@ -185,15 +197,14 @@ endif # Cadence config WAVES_CODEC_STUB bool "Waves codec stub" - depends on WAVES_CODEC - default n + depends on WAVES_CODEC != "n" + default y if COMP_STUBS help Select to build the waves codec with a stub file. This should only be used for testing or CI. config INTEL_MODULES bool "Intel modules" - default n depends on LIBRARY_MANAGER help Select for a Intel modules API implementation. diff --git a/src/audio/module_adapter/README.md b/src/audio/module_adapter/README.md new file mode 100644 index 000000000000..c642c46096bd --- /dev/null +++ b/src/audio/module_adapter/README.md @@ -0,0 +1,115 @@ +# Module Adapter Architecture + +This directory contains the Module Adapter. + +## Overview + +The Module Adapter is a crucial piece of the IPC4 pipeline, allowing the core SOF graph mechanism to interact with 3rd party processing modules (like Windows APOs or customized vendor DSP engines) through a generic wrapper format. + +## Creation and Teardown Flow + +The Module Adapter wraps an external DSP processing component and translates standard SOF pipeline calls (like `comp_new`, `comp_free`, `comp_trigger`) into an interface the external module natively understands (`ops->init`, `ops->free`, `ops->reset`, etc.). + +```mermaid +sequenceDiagram + participant Pipe as Pipeline + participant ModAd as Module Adapter (module_adapter_new) + participant Mod as Processing Module + participant Ext as External DSP Module (e.g., Windows APO) + + Pipe->>ModAd: comp_new() + activate ModAd + ModAd->>ModAd: Allocates comp_dev & struct processing_module + ModAd->>ModAd: module_adapter_dp_heap_new() (If DP domain) + ModAd->>ModAd: pipeline_comp_dp_task_init() (Spins up Zephyr thread if DP) + ModAd->>Mod: module_init() + Mod->>Ext: ops->init(mod) + Ext-->>ModAd: Init OK + ModAd-->>Pipe: Component READY + deactivate ModAd + + Note over Pipe,Ext: ... Audio Streaming ... + + Pipe->>ModAd: comp_free() + activate ModAd + ModAd->>Mod: module_free() + Mod->>Ext: ops->free(mod) + ModAd->>ModAd: schedule_task_free() (terminates thread) + ModAd->>ModAd: mod_free_all() (cleans up objpool and heap) + ModAd-->>Pipe: Component Destroyed + deactivate ModAd +``` + +## Configuration and Binding Flow + +Connection establishes buffer relationships (`comp_buffer`) connecting the component sources and sinks to the rest of the generic pipeline graph. + +```mermaid +sequenceDiagram + participant Pipe as Pipeline + participant ModAd as Module Adapter + participant Mod as Processing Module + + Pipe->>ModAd: comp_bind() / comp_unbind() + activate ModAd + ModAd->>Mod: module_bind() / module_unbind() + ModAd->>ModAd: module_update_source_buffer_params() + ModAd-->>Pipe: Bind successfully mapped + deactivate ModAd + + Pipe->>ModAd: comp_prepare() + activate ModAd + ModAd->>ModAd: Calculate chunks (period bytes, deep_buff_bytes) + ModAd->>Mod: module_prepare() + Mod-->>ModAd: External DSP prepared internal states + ModAd-->>Pipe: Prepared (Buffer formats synced) + deactivate ModAd +``` + +## Processing Flow (DP and LL Execution) + +To unify components operating directly in interrupt boundaries (DMA Low Latency (LL)) with heavy computational blocks executing asynchronously in Zephyr RTOS threads (Data Processing (DP)), the wrapper intercepts `comp_copy()`. + +### Low Latency (LL) Execution + +For LL modules, processing is fully synchronous within the pipeline tick: + +1. `comp_copy()` invokes `module_adapter_copy()`. +2. Data is fetched directly into `module_process_legacy()` or `module_process_sink_src()`. +3. `ops->process()` consumes upstream arrays and produces downstream arrays. + +### Data Processing (DP) Execution + +For DP modules, a discrete Zephyr thread manages execution asynchronously: + +```mermaid +sequenceDiagram + participant Sched as LL Scheduler + participant ModAd as Module Adapter (comp_copy) + participant DP as DP Thread (dp_task_run) + participant Mod as Processing Module (Ops) + + Sched->>ModAd: comp_copy() + activate ModAd + ModAd->>ModAd: Checks source data & sink free space + ModAd->>DP: Wakeup background thread (module_adapter_process_dp) + ModAd-->>Sched: Returns (No computation done yet) + deactivate ModAd + + activate DP + DP->>Mod: module_process_sink_src() + Mod->>Mod: ops->process(sources, sinks) + Mod-->>DP: Computation Complete + DP->>Sched: Signals data is ready + deactivate DP +``` + +## Error Handling and Memory Sandboxing + +* **Sandboxing (`mod_balloc_align`, `z_impl_mod_fast_get`, `z_impl_mod_free`)**: Since third-party DSP code is treated as semi-untrusted in memory lifetimes, module allocations grab slices from a dedicated component `dp_heap_user` heap instead of the global system heap (`mod_heap_info`). The wrapper automatically prunes leaked objects (`mod_free_all(mod)`) during teardown by keeping an `objpool` of all resource containers. +* **Reset Propagation**: Re-initializations via `COMP_TRIGGER_STOP` map down to `module_reset()` clearing the runtime state of the nested DSP module back to `MODULE_INITIALIZED`. + +## Configuration and Scripts + +* **Kconfig**: Highly customizable environment for "Processing modules" (`COMP_MODULE_ADAPTER`). Provides options for memory allocations, CADENCE codecs (AAC, BSAC, DAB, DRM, MP3, SBC, VORBIS, and their associated libraries), Dolby DAX Audio processing hooks (with stub support), Waves MaxxEffect codec support, and Intel module loaders. +* **CMakeLists.txt**: Handles the sprawling linkage process for the enabled processing modules. Links the core IPC abstraction layers (`module_adapter_ipc3.c` vs `module_adapter_ipc4.c`), external static libraries directly (e.g., `libdax.a`, `libMaxxChrome.a`, arbitrary CADENCE libraries), and includes custom Zephyr build options for `IADK` and `LIBRARY_MANAGER` systems. diff --git a/src/audio/module_adapter/iadk/README.md b/src/audio/module_adapter/iadk/README.md new file mode 100644 index 000000000000..d04ea1924bd8 --- /dev/null +++ b/src/audio/module_adapter/iadk/README.md @@ -0,0 +1,85 @@ +# Intel Audio Development Kit (`module_adapter/iadk`) + +The `iadk` directory provides the Module Adapter implementation for external 3rd-party audio algorithms developed using the **Intel Audio Development Kit (IADK)**. + +Unlike the native SOF `module_interface` API (written primarily in C), the IADK modules are object-oriented C++ classes that derive from `intel_adsp::ProcessingModuleInterface`. The SOF `IadkModuleAdapter` acts as a C++ to C "glue layer" that wraps these IADK methods so they can be natively plugged into the SOF `module_adapter` pipeline without modification to the module's pre-compiled binary. + +## Architecture and Class Hierarchy + +The system defines an `IadkModuleAdapter` class which internally holds an instance of the 3rd-party `ProcessingModuleInterface`. + +```mermaid +classDiagram + class SOF_ModuleAdapter { + +init + +process + +bind + } + + class iadk_wrapper { + iadk_wrapper_process + iadk_wrapper_init + } + + class IadkModuleAdapter { + -processing_module_ + +IadkModuleAdapter_Init + +IadkModuleAdapter_Process + +IadkModuleAdapter_SetConfiguration + } + + class ProcessingModuleInterface { + +Init + +Process + +SetConfiguration + +Reset + } + + class IADK_3rdParty_Algorithm { + +Init + +Process + } + + SOF_ModuleAdapter --> iadk_wrapper : C Function Pointers + iadk_wrapper --> IadkModuleAdapter : Instantiates and Wraps + IadkModuleAdapter --> ProcessingModuleInterface : Polymorphic Interface + ProcessingModuleInterface <|-- IADK_3rdParty_Algorithm : Inherits +``` + +## System Agent and Instantiation Flow + +Because the actual module resides in an external binary, it requires a "System Agent" to correctly instantiate the C++ objects during the component's `init` phase. + +1. The OS host driver sends an IPC `INIT_INSTANCE` command for the module. +2. The `system_agent_start()` function intercepts this, invokes the dynamic module's `create_instance` entry point (which invokes a `ModuleFactory`). +3. The `SystemAgent` deduces the pin count (interfaces) and initial pipeline configurations using `ModuleInitialSettingsConcrete`. +4. The factory allocates the concrete algorithm and checks it back into SOF through `SystemAgent::CheckIn`. + +```mermaid +sequenceDiagram + participant IPC + participant SA + participant Fac + participant Mod + + IPC->>SA: Trigger Mod Creation + SA->>Fac: CI invokes create_instance + Fac->>Fac: Deduce BaseModuleCfgExt + Fac->>Mod: operator new instantiate + + Fac->>SA: SystemAgent CheckIn Module + SA->>Adp: Create new IadkModuleAdapter Module + + SA-->>IPC: Return CPP adapter to C Pipeline +``` + +## Data Buffer Translation + +A significant task of `IadkModuleAdapter_Process` is converting SOF's underlying buffer formats to IADK's `InputStreamBuffer` and `OutputStreamBuffer` structures. + +Instead of letting the module directly touch the SOF `comp_buffer` (which could change with SOF version updates), the adapter uses the abstraction APIs (`source_get_data` / `sink_get_buffer`) and wraps them: + +1. Request raw continuous memory pointers from `source_get_data()`. +2. Construct an `intel_adsp::InputStreamBuffer` pointing to that continuous memory chunk. +3. Call the IADK `processing_module_.Process()`. +4. Release precisely the amount of consumed data using `source_release_data()`. diff --git a/src/audio/module_adapter/iadk/iadk_module_adapter.cpp b/src/audio/module_adapter/iadk/iadk_module_adapter.cpp index c680622963ea..f940f08fad4b 100644 --- a/src/audio/module_adapter/iadk/iadk_module_adapter.cpp +++ b/src/audio/module_adapter/iadk/iadk_module_adapter.cpp @@ -121,9 +121,9 @@ IadkModuleAdapter::IadkModuleAdapter_SetConfiguration(uint32_t config_id, AdspErrorCode IadkModuleAdapter::IadkModuleAdapter_GetConfiguration(uint32_t config_id, enum module_cfg_fragment_position pos, - uint32_t data_offset_size, + uint32_t &data_offset_size, uint8_t *fragment_buffer, - size_t fragment_size) + size_t &fragment_size) { intel_adsp::ConfigurationFragmentPosition fragment_position = (intel_adsp::ConfigurationFragmentPosition::Enum) pos; @@ -219,14 +219,14 @@ int iadk_wrapper_set_configuration(void *md, uint32_t config_id, int iadk_wrapper_get_configuration(void *md, uint32_t config_id, enum module_cfg_fragment_position pos, - uint32_t data_offset_size, - uint8_t *fragment, size_t fragment_size) + uint32_t *data_offset_size, + uint8_t *fragment, size_t *fragment_size) { struct IadkModuleAdapter *mod_adp = (struct IadkModuleAdapter *) md; return mod_adp->IadkModuleAdapter_GetConfiguration(config_id, pos, - data_offset_size, + *data_offset_size, fragment, - fragment_size); + *fragment_size); } int iadk_wrapper_process(void *md, diff --git a/src/audio/module_adapter/iadk/system_agent.cpp b/src/audio/module_adapter/iadk/system_agent.cpp index 18f20311e147..caed8cf65860 100644 --- a/src/audio/module_adapter/iadk/system_agent.cpp +++ b/src/audio/module_adapter/iadk/system_agent.cpp @@ -13,6 +13,7 @@ #include <stddef.h> #include <stdint.h> #include <rtos/string.h> +#include <rtos/userspace_helper.h> #include <utilities/array.h> #include <module/iadk/adsp_error_code.h> #include <system_service.h> @@ -21,6 +22,7 @@ #include <iadk_module_adapter.h> #include <system_agent.h> #include <sof/audio/module_adapter/library/native_system_service.h> +#include <sof/audio/module_adapter/library/native_system_agent.h> using namespace intel_adsp; using namespace intel_adsp::system; @@ -37,7 +39,7 @@ namespace system { /* Structure storing handles to system service operations */ -const AdspSystemService SystemAgent::system_service_ = { +const APP_TASK_DATA AdspSystemService SystemAgent::system_service_ = { native_system_service_log_message, native_system_service_safe_memcpy, native_system_service_safe_memmove, @@ -124,16 +126,17 @@ int SystemAgent::CheckIn(ProcessingModuleFactoryInterface& module_factory, typedef int (*create_instance_f)(uint32_t module_id, uint32_t instance_id, uint32_t core_id, void *mod_cfg, void *parent_ppl, void **mod_ptr); -int system_agent_start(uint32_t entry_point, uint32_t module_id, uint32_t instance_id, - uint32_t core_id, uint32_t log_handle, void* mod_cfg, - void **adapter) +int system_agent_start(const struct system_agent_params *params, + const void **adapter) { uint32_t ret; - SystemAgent system_agent(module_id, instance_id, core_id, log_handle); + SystemAgent system_agent(params->module_id, params->instance_id, params->core_id, + params->log_handle); void* system_agent_p = reinterpret_cast<void*>(&system_agent); - create_instance_f ci = (create_instance_f)(entry_point); - ret = ci(module_id, instance_id, core_id, mod_cfg, NULL, &system_agent_p); + create_instance_f ci = (create_instance_f)(params->entry_point); + ret = ci(params->module_id, params->instance_id, params->core_id, params->mod_cfg, NULL, + &system_agent_p); IadkModuleAdapter* module_adapter = reinterpret_cast<IadkModuleAdapter*>(system_agent_p); *adapter = module_adapter; diff --git a/src/audio/module_adapter/library/README.md b/src/audio/module_adapter/library/README.md new file mode 100644 index 000000000000..3dd9aee14f7c --- /dev/null +++ b/src/audio/module_adapter/library/README.md @@ -0,0 +1,80 @@ +# Loadable Library & Userspace Proxy (`module_adapter/library`) + +The `library` directory within the module adapter manages the lifecycle and execution isolation for dynamically loaded algorithms, often referred to as "LLEXT modules" or "Userspace Modules". + +It acts as a secure intermediary layer between the native SOF/Zephyr kernel execution mode (supervisor mode) and the 3rd-party module running in an isolated user-mode context. By relying on Zephyr's Userspace mechanisms (`k_mem_domain`, `K_USER` threads), a faulting or misbehaving loadable extension cannot crash the entire firmware. + +## Architecture & Userspace Sandbox + +The Userspace Proxy architecture involves: + +- **`struct userspace_context`**: This encapsulates the memory domain (`k_mem_domain`) mapped exclusively for this module (code, rodata, BSS, and private heap memory). +- **`user_work_item`**: A Zephyr `k_work_user` mechanism. IPC configuration commands and data processing calls are packaged into a work item and executed safely inside the memory boundaries via `userspace_proxy_worker_handler`. + +```mermaid +graph TD + subgraph SOF Supervisor Domain + P["Pipeline DP Scheduler"] + MADP["Module Adapter Context"] + PROXY["Userspace Proxy (userspace_proxy_invoke)"] + end + + subgraph Zephyr Userspace Domain + SYSAGENT["LLEXT System Agent"] + HANDLER["Worker Handler (userspace_proxy_handle_request)"] + MOD["External Loadable Module (struct module_interface)"] + end + + P -->|Triggers process| MADP + MADP -->|Invokes Proxy| PROXY + + PROXY -->|Packages params & k_work| HANDLER + + HANDLER -->|Safe Call Context| MOD + SYSAGENT -.->|Bootstraps| MOD + + style SOF Supervisor Domain fill:#1d2951,stroke:#333 + style Zephyr Userspace Domain fill:#2e0b1a,stroke:#333 +``` + +## State Transitions & IPC Handling + +IPC messages arriving from the host (e.g. `SET_CONF`, `GET_CONF`, `MODULE_INIT`, `MODULE_BIND`) first hit the Module Adapter running in Supervisor Mode. The adapter checks its configuration and invokes the Userspace Proxy. The proxy performs the following context switch: + +```mermaid +sequenceDiagram + participant IPC as SOF IPC Task + participant MA as Module Adapter + participant Proxy as Userspace Proxy + participant Worker as Zephyr k_work_user Thread + participant UserMod as LLEXT Module + + IPC->>MA: IPC SET_CONF config_id + MA->>Proxy: userspace_proxy_set_configuration + + note over Proxy: 1. Package proxy params + note over Proxy: 2. Add Mailbox memory to `k_mem_domain` + note over Proxy: 3. Post `k_work_user` / event + + Proxy->>Worker: Context Switch -> User Mode + + Worker->>UserMod: module_interface set_configuration + + note over UserMod: Parse config payload safely + + UserMod-->>Worker: Return status + Worker-->>Proxy: Signal Task Done + + note over Proxy: Remove Mailbox memory from domain + + Proxy-->>MA: Return execution + MA-->>IPC: Send Reply/Status to Host +``` + +### Memory Domain Adjustments + +A crucial aspect of the userspace proxy is dynamic memory permission elevation: + +- Normally, the userspace module can only access its own `heap`, `data`, and `bss` partitions. +- When an IPC like `GET_CONF` requests large IPC buffers, the proxy temporarily adds the hardware `MAILBOX_HOSTBOX` into the module's `k_mem_domain` using `k_mem_domain_add_partition()`. +- Once the userspace thread returns, that hardware window is immediately removed from the memory domain to minimize the vulnerability window. diff --git a/src/audio/module_adapter/library/native_system_agent.c b/src/audio/module_adapter/library/native_system_agent.c index 9704da50739e..b93405b8bd27 100644 --- a/src/audio/module_adapter/library/native_system_agent.c +++ b/src/audio/module_adapter/library/native_system_agent.c @@ -19,17 +19,23 @@ typedef void* (*native_create_instance_f)(void *mod_cfg, void *parent_ppl, struct native_system_agent native_sys_agent; -void *native_system_agent_start(uint32_t entry_point, uint32_t module_id, uint32_t instance_id, - uint32_t core_id, uint32_t log_handle, void *mod_cfg) +int native_system_agent_start(const struct system_agent_params *params, + const void **iface) { - native_sys_agent.module_id = module_id; - native_sys_agent.instance_id = instance_id; - native_sys_agent.core_id = core_id; - native_sys_agent.log_handle = log_handle; + native_sys_agent.module_id = params->module_id; + native_sys_agent.instance_id = params->instance_id; + native_sys_agent.core_id = params->core_id; + native_sys_agent.log_handle = params->log_handle; + const void *ret; void *system_agent_p = &native_sys_agent; - native_create_instance_f ci = (native_create_instance_f)entry_point; + native_create_instance_f ci = (native_create_instance_f)params->entry_point; - return ci(mod_cfg, NULL, &system_agent_p); + ret = ci(params->mod_cfg, NULL, &system_agent_p); + if (!ret) + return -EINVAL; + + *iface = ret; + return 0; } diff --git a/src/audio/module_adapter/library/native_system_service.c b/src/audio/module_adapter/library/native_system_service.c index 5126fa5ff12b..1c4688e885d0 100644 --- a/src/audio/module_adapter/library/native_system_service.c +++ b/src/audio/module_adapter/library/native_system_service.c @@ -19,6 +19,7 @@ #include <native_system_service.h> #include <sof/lib_manager.h> #include <module/module/logger.h> +#include <rtos/userspace_helper.h> #define RSIZE_MAX 0x7FFFFFFF @@ -162,7 +163,7 @@ AdspErrorCode native_system_service_get_interface(enum interface_id id, return ADSP_NO_ERROR; } -const struct native_system_service native_system_service = { +const APP_TASK_DATA struct native_system_service native_system_service = { .basic = { .log_message = native_system_service_log_message, .safe_memcpy = native_system_service_safe_memcpy, diff --git a/src/audio/module_adapter/library/userspace_proxy.c b/src/audio/module_adapter/library/userspace_proxy.c new file mode 100644 index 000000000000..79e55bd4124e --- /dev/null +++ b/src/audio/module_adapter/library/userspace_proxy.c @@ -0,0 +1,932 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. +// +// Author: Jaroslaw Stelter <jaroslaw.stelter@intel.com> +// Author: Adrian Warecki <adrian.warecki@intel.com> + +/** + * \file audio/module_adapter/library/userspace_proxy.c + * \brief Userspace proxy. Acts as an intermediary between SOF and a userspace module. + * \brief Responsible for preparing the memory domain required for userspace execution + * \brief and forwarding API calls. The proxy invokes corresponding module methods + * \brief in userspace context. Enables execution of any module implementing module_interface + * \brief as a userspace module. + * \authors Adrian Warecki + */ + +#include <sof/common.h> +#include <rtos/alloc.h> +#include <rtos/cache.h> +#include <sof/lib/memory.h> +#include <rtos/string.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include <sof/lib_manager.h> +#include <sof/llext_manager.h> +#include <sof/audio/component.h> +#include <sof/schedule/dp_schedule.h> +#include <rtos/userspace_helper.h> +#include <utilities/array.h> +#include <zephyr/sys/sem.h> +#include <sof/audio/module_adapter/module/generic.h> + +#include <sof/audio/module_adapter/library/userspace_proxy.h> +#include <sof/audio/module_adapter/library/userspace_proxy_user.h> +#include <rimage/sof/user/manifest.h> + + /* Assume that all the code runs in supervisor mode and don't make system calls. */ +#define __ZEPHYR_SUPERVISOR__ + +LOG_MODULE_REGISTER(userspace_proxy, CONFIG_SOF_LOG_LEVEL); + +/* 6f6b6f4b-6f73-7466-20e1e62b9779f003 */ +SOF_DEFINE_REG_UUID(userspace_proxy); + +DECLARE_TR_CTX(userspace_proxy_tr, SOF_UUID(userspace_proxy_uuid), LOG_LEVEL_INFO); + +static const struct module_interface userspace_proxy_interface; + +#if IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) +#include <sof/audio/module_adapter/iadk/system_agent.h> +#include <sof/schedule/dp_schedule.h> + +static inline int user_worker_get(void) +{ + return 0; +} + +static inline void user_worker_put(void) { } + +struct k_work_user *userspace_proxy_register_ipc_handler(struct processing_module *mod, + struct k_event *event) +{ + struct userspace_context * const user_ctx = mod->user_ctx; + + if (user_ctx) { + tr_dbg(&userspace_proxy_tr, "Set DP event %p for module %p", + (void *)event, (void *)mod); + assert(user_ctx->work_item); + + user_ctx->dp_event = event; + user_ctx->work_item->event = event; + + return &user_ctx->work_item->work_item; + } + + return NULL; +} +#else +/* IPC requests targeting userspace modules are handled through a user work queue. + * Each userspace module provides its own work item that carries the IPC request parameters. + * The worker thread is switched into the module's memory domain and receives the work item. + * It invokes the appropriate module function in userspace context and writes the operation + * result back into the work item. + * + * There is only a single work queue, which is shared by all userspace modules. It is created + * dynamically when needed. Because SOF uses a single dedicated thread for handling IPC, there + * is no need to perform any additional serialization when accessing the worker. + */ +struct user_worker { + k_tid_t thread_id; /* ipc worker thread ID */ + uint32_t reference_count; /* module reference count */ + void *stack_ptr; /* pointer to worker stack */ + struct k_work_user_q work_queue; + struct k_event event; +}; + +static struct user_worker worker; + +static int user_worker_get(void) +{ + if (worker.reference_count) { + worker.reference_count++; + return 0; + } + + worker.stack_ptr = user_stack_allocate(CONFIG_SOF_USERSPACE_PROXY_WORKER_STACK_SIZE, + K_USER); + if (!worker.stack_ptr) { + tr_err(&userspace_proxy_tr, "Userspace worker stack allocation failed."); + return -ENOMEM; + } + + k_event_init(&worker.event); + k_work_user_queue_start(&worker.work_queue, worker.stack_ptr, + CONFIG_SOF_USERSPACE_PROXY_WORKER_STACK_SIZE, 0, NULL); + + worker.thread_id = k_work_user_queue_thread_get(&worker.work_queue); + + k_thread_access_grant(worker.thread_id, &worker.event); + + worker.reference_count++; + return 0; +} + +static void user_worker_put(void) +{ + /* Module removed so decrement counter */ + worker.reference_count--; + + /* Free worker resources if no more active user space modules */ + if (worker.reference_count == 0) { + k_thread_abort(worker.thread_id); + user_stack_free(worker.stack_ptr); + } +} +#endif + +static int user_work_item_init(struct userspace_context *user_ctx, struct k_heap *user_heap) +{ + struct user_work_item *work_item = NULL; + int ret; + + ret = user_worker_get(); + if (ret) + return ret; + + /* We have only a single userspace IPC worker. It handles requests for all userspace + * modules, which may run on different cores. Because the worker processes work items + * coming from any core, the work item must be allocated in coherent memory. + */ + work_item = sof_heap_alloc(user_heap, SOF_MEM_FLAG_COHERENT, sizeof(*work_item), 0); + if (!work_item) { + user_worker_put(); + return -ENOMEM; + } + + k_work_user_init(&work_item->work_item, userspace_proxy_worker_handler); + +#if !IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) + work_item->event = &worker.event; +#endif + work_item->params.context = user_ctx; + work_item->params.mod = NULL; + user_ctx->work_item = work_item; + + return 0; +} + +static void user_work_item_free(struct userspace_context *user_ctx, struct k_heap *user_heap) +{ + sof_heap_free(user_heap, user_ctx->work_item); + user_worker_put(); +} + +static inline struct module_params *user_work_get_params(struct userspace_context *user_ctx) +{ + return &user_ctx->work_item->params; +} + +BUILD_ASSERT(IS_ALIGNED(MAILBOX_HOSTBOX_BASE, CONFIG_MMU_PAGE_SIZE), + "MAILBOX_HOSTBOX_BASE is not page aligned"); + +BUILD_ASSERT(IS_ALIGNED(MAILBOX_HOSTBOX_SIZE, CONFIG_MMU_PAGE_SIZE), + "MAILBOX_HOSTBOX_SIZE is not page aligned"); + +static int userspace_proxy_invoke(struct userspace_context *user_ctx, uint32_t cmd, + bool ipc_payload_access) +{ +#if IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) + struct k_event * const event = user_ctx->dp_event; +#else + struct k_event * const event = &worker.event; +#endif + struct module_params *params = user_work_get_params(user_ctx); + const uintptr_t ipc_req_buf = (uintptr_t)MAILBOX_HOSTBOX_BASE; + struct k_mem_partition ipc_part = { + .start = ipc_req_buf, + .size = MAILBOX_HOSTBOX_SIZE, + .attr = user_get_partition_cache_attr(ipc_req_buf) | K_MEM_PARTITION_P_RO_U_RO, + }; + int ret = 0, ret2; + + params->cmd = cmd; + + if (ipc_payload_access) { + ret = k_mem_domain_add_partition(user_ctx->comp_dom, &ipc_part); + if (ret < 0) { + tr_err(&userspace_proxy_tr, "Add mailbox to domain error: %d", ret); + return ret; + } + } + +#if !IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) + /* Switch worker thread to module memory domain */ + ret = k_mem_domain_add_thread(user_ctx->comp_dom, worker.thread_id); + if (ret < 0) { + tr_err(&userspace_proxy_tr, "Failed to switch memory domain, error: %d", ret); + goto done; + } + +#ifdef CONFIG_SCHED_CPU_MASK + /* Pin worker thread to the same core as the module */ + ret = k_thread_cpu_pin(worker.thread_id, cpu_get_id()); + if (ret < 0) { + tr_err(&userspace_proxy_tr, "Failed to pin cpu, error: %d", ret); + goto done; + } +#endif + + ret = k_work_user_submit_to_queue(&worker.work_queue, &user_ctx->work_item->work_item); + if (ret < 0) { + tr_err(&userspace_proxy_tr, "Submit to queue error: %d", ret); + goto done; + } +#else + assert(event); + k_event_post(event, DP_TASK_EVENT_IPC); +#endif + + /* Timeout value is aligned with the ipc_wait_for_compound_msg function */ + if (!k_event_wait_safe(event, DP_TASK_EVENT_IPC_DONE, false, + Z_TIMEOUT_US(250 * 20))) { + tr_err(&userspace_proxy_tr, "IPC processing timedout."); + ret = -ETIMEDOUT; + } + +done: + if (ipc_payload_access) { + ret2 = k_mem_domain_remove_partition(user_ctx->comp_dom, &ipc_part); + if (ret2 < 0) { + tr_err(&userspace_proxy_tr, "Mailbox remove from domain error: %d", ret); + + if (!ret) + ret = ret2; + } + } + + return ret; +} + +extern struct k_mem_partition common_partition; + +static int userspace_proxy_memory_init(struct userspace_context *user_ctx, + const struct comp_driver *drv) +{ + /* Add module private heap to memory partitions */ + struct k_mem_partition heap_part = { .attr = K_MEM_PARTITION_P_RW_U_RW }; + struct sys_heap *heap = &drv->user_heap->heap; + + k_mem_region_align(&heap_part.start, &heap_part.size, + POINTER_TO_UINT(heap->init_mem), + heap->init_bytes, CONFIG_MM_DRV_PAGE_SIZE); + + tr_dbg(&userspace_proxy_tr, "Heap partition %#lx + %zx, attr = %u", + heap_part.start, heap_part.size, heap_part.attr); + + /* When a new memory domain is created, only the "factory" entries from the L2 page + * tables are copied. Memory that was dynamically mapped during firmware execution + * will not be accessible from the new domain. The k_heap structure (drv->user_heap) + * resides in such dynamically mapped memory, so we must explicitly add a partition + * for it to ensure that syscalls can access this structure from the userspace domain. + */ + struct k_mem_partition heap_struct_part = { + .attr = K_MEM_PARTITION_P_RW_U_NA | + user_get_partition_cache_attr(POINTER_TO_UINT(drv->user_heap)) + }; + + k_mem_region_align(&heap_struct_part.start, &heap_struct_part.size, + POINTER_TO_UINT(drv->user_heap), + sizeof(*drv->user_heap), CONFIG_MM_DRV_PAGE_SIZE); + + tr_dbg(&userspace_proxy_tr, "Heap struct partition %#lx + %zx, attr = %u", + heap_struct_part.start, heap_struct_part.size, heap_struct_part.attr); + +#if defined(CONFIG_SOF_ZEPHYR_HEAP_CACHED) + /* Add cached module private heap to memory partitions */ + struct k_mem_partition heap_cached_part = { + .attr = K_MEM_PARTITION_P_RW_U_RW | XTENSA_MMU_CACHED_WB + }; + + k_mem_region_align(&heap_cached_part.start, &heap_cached_part.size, + POINTER_TO_UINT(sys_cache_cached_ptr_get(heap->init_mem)), + heap->init_bytes, CONFIG_MM_DRV_PAGE_SIZE); + + tr_dbg(&userspace_proxy_tr, "Cached heap partition %#lx + %zx, attr = %u", + heap_cached_part.start, heap_cached_part.size, heap_cached_part.attr); +#endif + + struct k_mem_partition *parts_ptr[] = { + /* The common partition contains sof components accessible to the userspace module. + * These include ops structures marked with APP_TASK_DATA. + */ + &common_partition, +#ifdef CONFIG_SOF_ZEPHYR_HEAP_CACHED + &heap_cached_part, +#endif + &heap_part, + &heap_struct_part + }; + + tr_dbg(&userspace_proxy_tr, "Common partition %#lx + %zx, attr = %u", + common_partition.start, common_partition.size, common_partition.attr); + + return k_mem_domain_init(user_ctx->comp_dom, ARRAY_SIZE(parts_ptr), parts_ptr); +} + +static int userspace_proxy_add_sections(struct userspace_context *user_ctx, uint32_t instance_id, + const struct sof_man_module *const mod) +{ + struct k_mem_partition mem_partition; + void *va_base; + int idx, ret; + + for (idx = 0; idx < ARRAY_SIZE(mod->segment); ++idx) { + if (!mod->segment[idx].flags.r.load) + continue; + + if (mod->segment[idx].flags.r.code) + mem_partition.attr = K_MEM_PARTITION_P_RX_U_RX; + else if (!mod->segment[idx].flags.r.readonly) + mem_partition.attr = K_MEM_PARTITION_P_RW_U_RW; + else + mem_partition.attr = K_MEM_PARTITION_P_RO_U_RO; + + mem_partition.start = mod->segment[idx].v_base_addr; + mem_partition.size = mod->segment[idx].flags.r.length * CONFIG_MM_DRV_PAGE_SIZE; + mem_partition.attr |= user_get_partition_cache_attr(mem_partition.start); + + ret = k_mem_domain_add_partition(user_ctx->comp_dom, &mem_partition); + + tr_dbg(&userspace_proxy_tr, "Add mod partition %#lx + %zx, attr = %u, ret = %d", + mem_partition.start, mem_partition.size, mem_partition.attr, ret); + + if (ret < 0) + return ret; + } + + lib_manager_get_instance_bss_address(instance_id, mod, &va_base, &mem_partition.size); + mem_partition.start = POINTER_TO_UINT(va_base); + mem_partition.attr = user_get_partition_cache_attr(mem_partition.start) | + K_MEM_PARTITION_P_RW_U_RW; + ret = k_mem_domain_add_partition(user_ctx->comp_dom, &mem_partition); + + tr_dbg(&userspace_proxy_tr, "Add bss partition %#lx + %zx, attr = %u, ret = %d", + mem_partition.start, mem_partition.size, mem_partition.attr, ret); + + return ret; +} + +static int userspace_proxy_start_agent(struct userspace_context *user_ctx, + system_agent_start_fn start_fn, + const struct system_agent_params *agent_params, + const void **agent_interface) +{ + const byte_array_t * const mod_cfg = (byte_array_t *)agent_params->mod_cfg; + struct module_params *params = user_work_get_params(user_ctx); + + params->ext.agent.start_fn = start_fn; + + /* Start the system agent, if provided. */ + if (start_fn) { + params->ext.agent.params = *agent_params; + params->ext.agent.params.mod_cfg = ¶ms->ext.agent.mod_cfg; + params->ext.agent.mod_cfg = *mod_cfg; + + /* In case of processing modules ipc in the DP thread, the agent will be started in + * the init function. At this point the DP thread does not exist yet. + */ +#if !IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) + int ret = userspace_proxy_invoke(user_ctx, USER_PROXY_MOD_CMD_AGENT_START, true); + + if (ret) + return ret; + + *agent_interface = params->ext.agent.out_interface; + return params->status; +#endif + } + return 0; +} + +int userspace_proxy_create(struct userspace_context **user_ctx, const struct comp_driver *drv, + const struct sof_man_module *manifest, system_agent_start_fn agent_fn, + const struct system_agent_params *agent_params, + const void **agent_interface, const struct module_interface **ops) +{ + struct userspace_context *context; + struct k_mem_domain *domain; + int ret; + + tr_dbg(&userspace_proxy_tr, "userspace create"); + + context = k_heap_alloc(drv->user_heap, sizeof(struct userspace_context), K_FOREVER); + if (!context) + return -ENOMEM; + + context->dp_event = NULL; + + /* Allocate memory domain struct */ + domain = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(*domain)); + if (!domain) { + ret = -ENOMEM; + goto error; + } + context->comp_dom = domain; + + ret = userspace_proxy_memory_init(context, drv); + if (ret) + goto error_dom; + + if (agent_fn) + ret = userspace_proxy_add_sections(context, agent_params->instance_id, manifest); + else + /* llext modules do not use the system agent. */ + ret = llext_manager_add_domain(agent_params->module_id, domain); + + if (ret) + goto error_dom; + + ret = user_work_item_init(context, drv->user_heap); + if (ret) + goto error_dom; + + ret = userspace_proxy_start_agent(context, agent_fn, agent_params, agent_interface); + if (ret) { + tr_err(&userspace_proxy_tr, "System agent failed with error %d.", ret); + goto error_work_item; + } + + *user_ctx = context; + + /* Store a pointer to the module's interface. For the LMDK modules, the agent places a + * pointer to the module interface at the address specified by agent_interface. Since this + * points to ops, the assignment of the module interface used by this proxy must occur + * after the agent has been started. For other module types, the ops parameter points to a + * valid module interface. + */ + context->interface = *ops; + + /* All calls to the module interface must pass through the proxy. Set up our own interface. + */ + *ops = &userspace_proxy_interface; + + return 0; + +error_work_item: + user_work_item_free(context, drv->user_heap); +error_dom: + rfree(domain); +error: + k_heap_free(drv->user_heap, context); + return ret; +} + +void userspace_proxy_destroy(const struct comp_driver *drv, struct userspace_context *user_ctx) +{ + tr_dbg(&userspace_proxy_tr, "userspace proxy destroy"); + user_work_item_free(user_ctx, drv->user_heap); + rfree(user_ctx->comp_dom); + k_heap_free(drv->user_heap, user_ctx); +} + +/** + * Copy parameters to user worker accessible space. + * Queue module init() operation and return its result. + * Module init() code is performed in user workqueue. + * + * @param mod - pointer to processing module structure. + * @return 0 for success, error otherwise. + */ +static int userspace_proxy_init(struct processing_module *mod) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + + comp_dbg(mod->dev, "start"); + +#if IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) + /* Start the system agent, if provided. Params is already filled by + * the userspace_proxy_start_agent function. + */ + if (params->ext.agent.start_fn) { + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_AGENT_START, true); + if (ret) + return ret; + + if (params->ext.agent.start_fn == system_agent_start) + module_set_private_data(mod, (void *)params->ext.agent.out_interface); + else + mod->user_ctx->interface = params->ext.agent.out_interface; + } +#endif + + params->mod = mod; + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_INIT, true); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; +} + +/** + * Copy parameters to user worker accessible space. + * Queue module prepare() operation and return its result. + * Module prepare() code is performed in user workqueue. + * + * @return 0 for success, error otherwise. + */ +static int userspace_proxy_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + + comp_dbg(mod->dev, "start"); + + if (!mod->user_ctx->interface->prepare) + return 0; + + params->ext.proc.sources = sources; + params->ext.proc.num_of_sources = num_of_sources; + params->ext.proc.sinks = sinks; + params->ext.proc.num_of_sinks = num_of_sinks; + + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_PREPARE, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; +} + +/** + * Forward processing request to the module's process() implementation. + * + * It is invoked by the DP thread running in userspace, so no + * additional queuing or context switching is performed here. + * + * @param mod Pointer to the processing module instance. + * @param sources Array of input sources for the module. + * @param num_of_sources Number of input sources. + * @param sinks Array of output sinks for the module. + * @param num_of_sinks Number of output sinks. + * + * @return 0 on success, negative error code on failure. + */ +static int userspace_proxy_process(struct processing_module *mod, struct sof_source **sources, + int num_of_sources, struct sof_sink **sinks, int num_of_sinks) +{ + return mod->user_ctx->interface->process(mod, sources, num_of_sources, sinks, num_of_sinks); +} + +/** + * Copy parameters to user worker accessible space. + * Queue module reset() operation and return its result. + * Module reset() code is performed in user workqueue. + * + * @param mod - pointer to processing module structure. + * @return 0 for success, error otherwise. + */ +static int userspace_proxy_reset(struct processing_module *mod) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + + if (!mod->user_ctx->interface->reset) + return 0; + + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_RESET, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; +} + +/** + * Copy parameters to user worker accessible space. + * Queue module free() operation and return its result. + * Module free() code is performed in user workqueue. + * + * @param mod - pointer to processing module structure. + * @return 0 for success, error otherwise. + */ +static int userspace_proxy_free(struct processing_module *mod) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret = 0; + + comp_dbg(mod->dev, "start"); + + if (mod->user_ctx->interface->free) { + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_FREE, false); + if (ret) + return ret; + ret = params->status; + } + + /* Destroy workqueue if this was last active userspace module */ + userspace_proxy_destroy(mod->dev->drv, mod->user_ctx); + mod->user_ctx = NULL; + + /* Return status from module code operation. */ + return ret; +} + +/** + * Copy parameters to user worker accessible space. + * Queue module set_configuration() operation and return its result. + * Module set_configuration() code is performed in user workqueue. + * + * @param[in] mod - struct processing_module pointer + * @param[in] config_id - Configuration ID + * @param[in] pos - position of the fragment in the large message + * @param[in] data_offset_size: size of the whole configuration if it is the first fragment or the + * only fragment. Otherwise, it is the offset of the fragment in the whole + * configuration. + * @param[in] fragment: configuration fragment buffer + * @param[in] fragment_size: size of @fragment + * @params[in] response: optional response buffer to fill + * @params[in] response_size: size of @response + * + * @return 0 for success, error otherwise. + */ +static int userspace_proxy_set_configuration(struct processing_module *mod, uint32_t config_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, const uint8_t *fragment, + size_t fragment_size, uint8_t *response, + size_t response_size) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + + comp_dbg(mod->dev, "start"); + + if (!mod->user_ctx->interface->set_configuration) + return 0; + + params->ext.set_conf.config_id = config_id; + params->ext.set_conf.pos = pos; + params->ext.set_conf.data_off_size = data_offset_size; + params->ext.set_conf.fragment = fragment; + params->ext.set_conf.fragment_size = fragment_size; + params->ext.set_conf.response = response; + params->ext.set_conf.response_size = response_size; + + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_SET_CONF, true); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; +} + +/** + * Copy parameters to user worker accessible space. + * Queue module get_configuration() operation and return its result. + * Module get_configuration() code is performed in user workqueue. + * + * @param[in] mod - struct processing_module pointer + * @param[in] config_id - Configuration ID + * @param[in] data_offset_size: size of the whole configuration if it is the first fragment or the + * only fragment. Otherwise, it is the offset of the fragment in the whole + * configuration. + * @param[in] fragment: configuration fragment buffer + * @param[in] fragment_size: size of @fragment + * + * @return 0 for success, error otherwise. + */ +static int userspace_proxy_get_configuration(struct processing_module *mod, uint32_t config_id, + uint32_t *data_offset_size, uint8_t *fragment, + size_t fragment_size) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + struct k_mem_domain *domain = mod->user_ctx->comp_dom; + const uintptr_t ipc_resp_buf = POINTER_TO_UINT(ipc_get()->comp_data); + + /* Memory partition exposing the IPC response buffer. This buffer is allocated + * by the IPC driver and contains the payload of IPC replies sent to the host. + */ + struct k_mem_partition ipc_resp_part = { + .start = ipc_resp_buf, + .size = SOF_IPC_MSG_MAX_SIZE, + .attr = user_get_partition_cache_attr(ipc_resp_buf) | K_MEM_PARTITION_P_RW_U_RW, + }; + int ret; + + comp_dbg(mod->dev, "start"); + + if (!mod->user_ctx->interface->get_configuration) + return -EIO; + + params->ext.get_conf.config_id = config_id; + params->ext.get_conf.data_off_size = data_offset_size; + params->ext.get_conf.fragment = fragment; + params->ext.get_conf.fragment_size = fragment_size; + + ret = k_mem_domain_add_partition(domain, &ipc_resp_part); + if (ret < 0) { + comp_err(mod->dev, "add response buffer to domain error: %d", ret); + return ret; + } + + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_GET_CONF, true); + + k_mem_domain_remove_partition(domain, &ipc_resp_part); + + /* Return status from module code operation. */ + return ret ? ret : params->status; +} + +/** + * Copy parameters to user worker accessible space. + * Queue module set_processing_mode() operation and return its result. + * Module set_processing_mode() code is performed in user workqueue. + * + * @param mod - pointer to processing module structure. + * @param mode - processing mode to be set. + * @return 0 for success, error otherwise. + */ +static int userspace_proxy_set_processing_mode(struct processing_module *mod, + enum module_processing_mode mode) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + + comp_dbg(mod->dev, "start"); + + if (!mod->user_ctx->interface->set_processing_mode) + return 0; + + params->ext.proc_mode.mode = mode; + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_SET_PROCMOD, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; +} + +/** + * Copy parameters to user worker accessible space. + * Queue module get_processing_mode() operation and return its result. + * Module get_processing_mode() code is performed in user workqueue. + * + * @param mod - pointer to processing module structure. + * @return processing mode. + */ +static +enum module_processing_mode userspace_proxy_get_processing_mode(struct processing_module *mod) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + + comp_dbg(mod->dev, "start"); + + if (!mod->user_ctx->interface->get_processing_mode) + return -EIO; + + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_GET_PROCMOD, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->ext.proc_mode.mode; +} + +/** + * Copy parameters to user worker accessible space. + * Queue module is_ready_to_process() operation and return its result. + * Module is_ready_to_process() code is performed in user workqueue. + * + * @param mod - pointer to processing module structure. + * @return true if the module is ready to process + */ +static bool userspace_proxy_is_ready_to_process(struct processing_module *mod, + struct sof_source **sources, + int num_of_sources, + struct sof_sink **sinks, + int num_of_sinks) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + + comp_dbg(mod->dev, "start"); + + if (!mod->user_ctx->interface->is_ready_to_process) + return generic_module_is_ready_to_process(mod, sources, num_of_sources, sinks, + num_of_sinks); + + params->ext.proc.sources = sources; + params->ext.proc.num_of_sources = num_of_sources; + params->ext.proc.sinks = sinks; + params->ext.proc.num_of_sinks = num_of_sinks; + + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_PROC_READY, false); + if (ret) + return generic_module_is_ready_to_process(mod, sources, num_of_sources, sinks, + num_of_sinks); + + /* Return status from module code operation. */ + return params->status; +} + +/** + * Copy parameters to user worker accessible space. + * Queue module bind() operation and return its result. + * Module bind() code is performed in user workqueue. + * + * @param mod - pointer to processing module structure. + * @param bind_data - pointer to bind_info structure. + * @return 0 for success, error otherwise. + */ +static int userspace_proxy_bind(struct processing_module *mod, struct bind_info *bind_data) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + + comp_dbg(mod->dev, "start"); + + if (!mod->user_ctx->interface->bind) + return 0; + + params->ext.bind_data = bind_data; + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_BIND, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; +} + +/** + * Copy parameters to user worker accessible space. + * Queue module unbind() operation and return its result. + * Module unbind() code is performed in user workqueue. + * + * @param mod - pointer to processing module structure. + * @param unbind_data - pointer to bind_info structure. + * @return 0 for success, error otherwise. + */ +static int userspace_proxy_unbind(struct processing_module *mod, struct bind_info *unbind_data) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + + comp_dbg(mod->dev, "start"); + + if (!mod->user_ctx->interface->unbind) + return 0; + + params->ext.bind_data = unbind_data; + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_UNBIND, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; +} + +/** + * Copy parameters to user worker accessible space. + * Queue module trigger() operation and return its result. + * Module trigger() code is performed in user workqueue. + * + * @param mod - pointer to processing module structure. + * @return 0 for success, error otherwise. + */ +static int userspace_proxy_trigger(struct processing_module *mod, int cmd) +{ + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret = 0; + + comp_dbg(mod->dev, "start"); + + if (mod->user_ctx->interface->trigger) { + params->ext.trigger_data = cmd; + ret = userspace_proxy_invoke(mod->user_ctx, USER_PROXY_MOD_CMD_TRIGGER, false); + if (ret) + return ret; + ret = params->status; + } + + if (!ret) + ret = module_adapter_set_state(mod, mod->dev, cmd); + + /* Return status from module code operation. */ + return ret; +} + +/* Userspace Proxy Module API */ +APP_TASK_DATA static const struct module_interface userspace_proxy_interface = { + .init = userspace_proxy_init, + .is_ready_to_process = userspace_proxy_is_ready_to_process, + .prepare = userspace_proxy_prepare, + .process = userspace_proxy_process, + .set_configuration = userspace_proxy_set_configuration, + .get_configuration = userspace_proxy_get_configuration, + .set_processing_mode = userspace_proxy_set_processing_mode, + .get_processing_mode = userspace_proxy_get_processing_mode, + .reset = userspace_proxy_reset, + .free = userspace_proxy_free, + .bind = userspace_proxy_bind, + .unbind = userspace_proxy_unbind, + .trigger = userspace_proxy_trigger, +}; diff --git a/src/audio/module_adapter/library/userspace_proxy_user.c b/src/audio/module_adapter/library/userspace_proxy_user.c new file mode 100644 index 000000000000..105c9841318f --- /dev/null +++ b/src/audio/module_adapter/library/userspace_proxy_user.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// Author: Adrian Warecki <adrian.warecki@intel.com> + +/** + * \file audio/module_adapter/library/userspace_proxy_user.c + * \brief Userspace proxy functions executed only in userspace context. + * \authors Adrian Warecki + */ + +/* Assume that all the code runs in user mode and unconditionally makes system calls. */ +#define __ZEPHYR_USER__ + +#include <sof/common.h> +#include <errno.h> +#include <stddef.h> +#include <stdint.h> + +#include <sof/audio/component.h> +#include <sof/schedule/dp_schedule.h> +#include <sof/audio/module_adapter/module/generic.h> + +#include <sof/audio/module_adapter/library/userspace_proxy.h> +#include <sof/audio/module_adapter/library/userspace_proxy_user.h> + +void userspace_proxy_handle_request(struct processing_module *mod, struct module_params *params) +{ + const struct module_interface *ops = params->context->interface; + + switch (params->cmd) { + case USER_PROXY_MOD_CMD_AGENT_START: + params->status = params->ext.agent.start_fn(¶ms->ext.agent.params, + ¶ms->ext.agent.out_interface); + break; + + case USER_PROXY_MOD_CMD_INIT: + params->status = ops->init(params->mod); + break; + + case USER_PROXY_MOD_CMD_PREPARE: + params->status = ops->prepare(params->mod, params->ext.proc.sources, + params->ext.proc.num_of_sources, + params->ext.proc.sinks, + params->ext.proc.num_of_sinks); + break; + + case USER_PROXY_MOD_CMD_PROC_READY: + params->status = ops->is_ready_to_process(params->mod, + params->ext.proc.sources, + params->ext.proc.num_of_sources, + params->ext.proc.sinks, + params->ext.proc.num_of_sinks); + break; + + case USER_PROXY_MOD_CMD_BIND: + params->status = ops->bind(params->mod, params->ext.bind_data); + break; + + case USER_PROXY_MOD_CMD_UNBIND: + params->status = ops->unbind(params->mod, params->ext.bind_data); + break; + + case USER_PROXY_MOD_CMD_RESET: + params->status = ops->reset(params->mod); + break; + + case USER_PROXY_MOD_CMD_FREE: + params->status = ops->free(params->mod); + break; + + case USER_PROXY_MOD_CMD_SET_CONF: + params->status = ops->set_configuration(params->mod, + params->ext.set_conf.config_id, + params->ext.set_conf.pos, + params->ext.set_conf.data_off_size, + params->ext.set_conf.fragment, + params->ext.set_conf.fragment_size, + params->ext.set_conf.response, + params->ext.set_conf.response_size); + break; + + case USER_PROXY_MOD_CMD_GET_CONF: + params->status = ops->get_configuration(params->mod, + params->ext.get_conf.config_id, + params->ext.get_conf.data_off_size, + params->ext.get_conf.fragment, + params->ext.get_conf.fragment_size); + break; + + case USER_PROXY_MOD_CMD_SET_PROCMOD: + params->status = ops->set_processing_mode(params->mod, + params->ext.proc_mode.mode); + break; + + case USER_PROXY_MOD_CMD_GET_PROCMOD: + params->ext.proc_mode.mode = ops->get_processing_mode(params->mod); + break; + + case USER_PROXY_MOD_CMD_TRIGGER: + params->status = ops->trigger(params->mod, params->ext.trigger_data); + break; + + default: + params->status = -EINVAL; + break; + } +} + +void userspace_proxy_worker_handler(struct k_work_user *work_item) +{ + struct user_work_item *user_work_item = CONTAINER_OF(work_item, struct user_work_item, + work_item); + struct module_params *params = &user_work_item->params; + + userspace_proxy_handle_request(params->mod, params); + k_event_post(user_work_item->event, DP_TASK_EVENT_IPC_DONE); +} diff --git a/src/audio/module_adapter/module/README.md b/src/audio/module_adapter/module/README.md new file mode 100644 index 000000000000..4586f060f37d --- /dev/null +++ b/src/audio/module_adapter/module/README.md @@ -0,0 +1,88 @@ +# Module Implementing Interfaces (`module_adapter/module`) + +The `module` directory contains the concrete `module_interface` implementations that bridge the core SOF Component API with various audio processing algorithms. These adapters translate the generic initialization, parameter configuration, and process loop calls into the specific operational sequences required by different module frameworks. + +The directory primarily houses three distinct module adapters: + +1. **Generic Core Adapter (`generic.c`)** +2. **Modules (IADK/Shim) Adapter (`modules.c`)** +3. **Cadence DSP Codec Adapter (`cadence.c`, `cadence_ipc4.c`)** + +## 1. Generic Core Adapter (`generic.c`) + +The Generic adapter provides the default runtime container for typical native SOF processing modules (e.g., volume, eq, src). + +It implements the full `struct module_interface` contract: + +* **Memory Management**: It intercepts memory allocation mappings using `mod_balloc_align` and tracks memory requests in a module-specific resource pool (`module_resource`). When the module goes out of scope, the framework garbage-collects any leaked allocations automatically via `mod_free_all()`. +* **Configuration Handling**: Manages large blob configuration messages across multiple IPC fragments (`module_set_configuration`). It allocates memory for `runtime_params` until the blob is fully assembled, then triggers the underlying algorithm with the completed struct. +* **State Machine Enforcement**: It wraps `process_audio_stream` and `process_raw_data` calls to verify the module is in either `MODULE_IDLE` or `MODULE_PROCESSING` states before execution. + +## 2. Modules (IADK Shim) Adapter (`modules.c`) + +The `modules.c` base is an extension adapter designed specifically to run Intel Audio Development Kit (IADK) 3rd party algorithms. + +Unlike the generic modules, the IADK modules are object-oriented C++ architectures linked into a separate library (`module_adapter/iadk`). This file acts as the primary C entry point wrapper. + +* It utilizes the `iadk_wrapper_*` C-bridge functions to invoke methods on the C++ `intel_adsp::ProcessingModuleInterface` classes. +* It exposes the standard `DECLARE_MODULE_ADAPTER(processing_module_adapter_interface)` that is bound to the SOF pipeline. + +## 3. Cadence Codec Adapter (`cadence.c`) + +This is a highly specialized adapter used for integrating Xtensa Audio (XA) codecs from Cadence (e.g., MP3, AAC, Vorbis, SBC, DAB). + +The `cadence.c` implementation maps the standard SOF pipeline controls into the Cadence memory buffer management and synchronous execution models. + +```mermaid +graph TD + subgraph SOF Initialization + INIT["cadence_codec_init"] + CONFIG["cadence_configure_codec_params"] + RESOLVE["cadence_codec_resolve_api"] + end + + subgraph Cadence Library Init XA API + MEMTABS["cadence_codec_init_memory_tables"] + GETSIZE["XA_API_CMD_GET_MEM_INFO_SIZE"] + SETPTR["XA_API_CMD_SET_MEM_PTR"] + end + + subgraph Data Processing Loop + PROC["cadence_codec_process_data"] + FILL["XA_API_CMD_SET_INPUT_BYTES"] + EXEC["XA_API_CMD_EXECUTE"] + GETOUT["XA_API_CMD_GET_OUTPUT_BYTES"] + end + + INIT --> RESOLVE + RESOLVE --> CONFIG + CONFIG --> MEMTABS + + MEMTABS -. Iterates Memory Types .-> GETSIZE + GETSIZE -. Assigns Buffers .-> SETPTR + + SETPTR ==>|Pipeline Trigger| PROC + + PROC --> FILL + FILL --> EXEC + EXEC --> GETOUT +``` + +### Cadence Memory Tables + +Unlike standard modules that directly read from a `sof_source` API, Cadence codecs require their memory isolated exclusively into exact predefined chunks categorized by "type". `cadence_codec_init_memory_tables` iterates through the codec's hardware definition to construct these memory areas: + +* `XA_MEMTYPE_INPUT` +* `XA_MEMTYPE_OUTPUT` +* `XA_MEMTYPE_SCRATCH` +* `XA_MEMTYPE_PERSIST` + +The SOF adapter allocates tracking structures via `mod_alloc_align` for each of these mandatory regions prior to audio playback. + +### Execution Wrapper + +During `cadence_codec_process()`, the adapter: + +1. Performs `source_get_data` and mechanically copies audio bytes into the isolated `XA_MEMTYPE_INPUT` buffer. +2. Invokes the Xtensa Audio codec API (`XA_API_CMD_EXECUTE`). +3. Reads the produced byte count and copies them back out from `XA_MEMTYPE_OUTPUT` into the `sof_sink`. diff --git a/src/audio/module_adapter/module/cadence.c b/src/audio/module_adapter/module/cadence.c index 02e95d429bfa..1da75081e2f8 100644 --- a/src/audio/module_adapter/module/cadence.c +++ b/src/audio/module_adapter/module/cadence.c @@ -1,15 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 - 2026 Intel Corporation. All rights reserved. // -// Author: Marcin Rajwa <marcin.rajwa@linux.intel.com> - -/* - * \file cadence.c - * \brief Cadence Codec API - * \author Marcin Rajwa <marcin.rajwa@linux.intel.com> - * - */ #include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/module_adapter/module/cadence.h> @@ -18,29 +10,10 @@ LOG_MODULE_REGISTER(cadence_codec, CONFIG_SOF_LOG_LEVEL); -SOF_DEFINE_REG_UUID(cadence_codec); - -DECLARE_TR_CTX(cadence_codec_tr, SOF_UUID(cadence_codec_uuid), LOG_LEVEL_INFO); - -enum cadence_api_id { - CADENCE_CODEC_WRAPPER_ID = 0x01, - CADENCE_CODEC_AAC_DEC_ID = 0x02, - CADENCE_CODEC_BSAC_DEC_ID = 0x03, - CADENCE_CODEC_DAB_DEC_ID = 0x04, - CADENCE_CODEC_DRM_DEC_ID = 0x05, - CADENCE_CODEC_MP3_DEC_ID = 0x06, - CADENCE_CODEC_SBC_DEC_ID = 0x07, - CADENCE_CODEC_VORBIS_DEC_ID = 0x08, - CADENCE_CODEC_SRC_PP_ID = 0x09, - CADENCE_CODEC_MP3_ENC_ID = 0x0A, -}; - -#define DEFAULT_CODEC_ID CADENCE_CODEC_WRAPPER_ID - /*****************************************************************************/ /* Cadence API functions array */ /*****************************************************************************/ -static struct cadence_api cadence_api_table[] = { +struct cadence_api cadence_api_table[] = { #ifdef CONFIG_CADENCE_CODEC_WRAPPER { .id = CADENCE_CODEC_WRAPPER_ID, @@ -103,12 +76,15 @@ static struct cadence_api cadence_api_table[] = { #endif }; -static int cadence_code_get_api_id(uint32_t compress_id) +static int cadence_codec_get_api_id(uint32_t compress_id, uint32_t direction) { /* convert compress id to SOF cadence SOF id */ switch (compress_id) { case SND_AUDIOCODEC_MP3: - return CADENCE_CODEC_MP3_DEC_ID; + if (direction == SOF_IPC_STREAM_PLAYBACK) + return CADENCE_CODEC_MP3_DEC_ID; + + return CADENCE_CODEC_MP3_ENC_ID; case SND_AUDIOCODEC_AAC: return CADENCE_CODEC_AAC_DEC_ID; case SND_AUDIOCODEC_VORBIS: @@ -118,357 +94,21 @@ static int cadence_code_get_api_id(uint32_t compress_id) } } -#if CONFIG_IPC_MAJOR_4 -static int cadence_codec_resolve_api(struct processing_module *mod) +void cadence_codec_free_memory_tables(struct processing_module *mod) { - int ret; - struct snd_codec codec_params; - struct comp_dev *dev = mod->dev; struct cadence_codec_data *cd = module_get_private_data(mod); - uint32_t api_id = CODEC_GET_API_ID(DEFAULT_CODEC_ID); - uint32_t n_apis = ARRAY_SIZE(cadence_api_table); - struct module_data *codec = &mod->priv; - struct module_param *param; int i; - xa_codec_func_t *api = NULL; - - /* For ipc4 protocol codec parameters has to be retrieved from configuration */ - if (!codec->cfg.data) { - comp_err(dev, "cadence_codec_resolve_api(): could not find cadence config"); - return -EINVAL; - } - param = codec->cfg.data; - api_id = param->id >> 16; - - /* Find and assign API function */ - for (i = 0; i < n_apis; i++) { - if (cadence_api_table[i].id == api_id) { - api = cadence_api_table[i].api; - break; - } - } - - /* Verify API assignment */ - if (!api) { - comp_err(dev, "cadence_codec_resolve_api(): could not find API function for id %x", - api_id); - return -EINVAL; - } - cd->api = api; - cd->api_id = api_id; - - return 0; -} - -#elif CONFIG_IPC_MAJOR_3 -static int cadence_codec_resolve_api(struct processing_module *mod) -{ - int ret; - struct snd_codec codec_params; - struct comp_dev *dev = mod->dev; - struct cadence_codec_data *cd = module_get_private_data(mod); - uint32_t api_id = CODEC_GET_API_ID(DEFAULT_CODEC_ID); - uint32_t n_apis = ARRAY_SIZE(cadence_api_table); - int i; - xa_codec_func_t *api = NULL; - - if (mod->stream_params->ext_data_length) { - ret = memcpy_s(&codec_params, mod->stream_params->ext_data_length, - (uint8_t *)mod->stream_params + sizeof(*mod->stream_params), - mod->stream_params->ext_data_length); - if (ret < 0) - return ret; - - ret = cadence_code_get_api_id(codec_params.id); - if (ret < 0) - return ret; - - api_id = ret; - } - - /* Find and assign API function */ - for (i = 0; i < n_apis; i++) { - if (cadence_api_table[i].id == api_id) { - api = cadence_api_table[i].api; - break; - } - } - - /* Verify API assignment */ - if (!api) { - comp_err(dev, "cadence_codec_resolve_api(): could not find API function for id %x", - api_id); - return -EINVAL; - } - cd->api = api; - cd->api_id = api_id; - - return 0; -} -#else -#error Unknown IPC major version -#endif - -static int cadence_codec_post_init(struct processing_module *mod) -{ - int ret; - struct comp_dev *dev = mod->dev; - struct cadence_codec_data *cd = module_get_private_data(mod); - uint32_t obj_size; - - comp_dbg(dev, "cadence_codec_post_init() start"); - - ret = cadence_codec_resolve_api(mod); - if (ret < 0) - return ret; - - /* Obtain codec name */ - API_CALL(cd, XA_API_CMD_GET_LIB_ID_STRINGS, - XA_CMD_TYPE_LIB_NAME, cd->name, ret); - if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_init() error %x: failed to get lib name", - ret); - return ret; - } - /* Get codec object size */ - API_CALL(cd, XA_API_CMD_GET_API_SIZE, 0, &obj_size, ret); - if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_init() error %x: failed to get lib object size", - ret); - return ret; - } - /* Allocate space for codec object */ - cd->self = rballoc(0, SOF_MEM_CAPS_RAM, obj_size); - if (!cd->self) { - comp_err(dev, "cadence_codec_init(): failed to allocate space for lib object"); - return -ENOMEM; - } - - comp_dbg(dev, "cadence_codec_post_init(): allocated %d bytes for lib object", obj_size); - - /* Set all params to their default values */ - API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, - NULL, ret); - if (ret != LIB_NO_ERROR) { - rfree(cd->self); - return ret; - } - - comp_dbg(dev, "cadence_codec_post_init() done"); - - return 0; -} - -#if CONFIG_IPC_MAJOR_4 -static int cadence_codec_init(struct processing_module *mod) -{ - const struct ipc4_cadence_module_cfg *cfg; - struct module_data *codec = &mod->priv; - struct cadence_codec_data *cd; - struct module_config *setup_cfg; - struct comp_dev *dev = mod->dev; - int ret; - - comp_dbg(dev, "cadence_codec_init() start"); - - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(struct cadence_codec_data)); - if (!cd) { - comp_err(dev, "cadence_codec_init(): failed to allocate memory for cadence codec data"); - return -ENOMEM; - } - - codec->private = cd; - codec->mpd.init_done = 0; - - /* copy the setup config only for the first init */ - if (codec->state == MODULE_DISABLED && codec->cfg.avail) { - setup_cfg = &cd->setup_cfg; - - cfg = (const struct ipc4_cadence_module_cfg *)codec->cfg.init_data; - - /* allocate memory for set up config */ - setup_cfg->data = rmalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - cfg->param_size); - if (!setup_cfg->data) { - comp_err(dev, "cadence_codec_init(): failed to alloc setup config"); - ret = -ENOMEM; - goto free; - } - - /* allocate memory for runtime set up config */ - codec->cfg.data = rmalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - cfg->param_size); - if (!codec->cfg.data) { - comp_err(dev, "cadence_codec_init(): failed to alloc runtime setup config"); - ret = -ENOMEM; - goto free_cfg; - } - - codec->cfg.size = cfg->param_size; - ret = memcpy_s(codec->cfg.data, codec->cfg.size, - cfg->param, cfg->param_size); - if (ret) { - comp_err(dev, "cadence_codec_init(): failed to init runtime config %d", - ret); - goto free_cfg2; - } - codec->cfg.avail = true; - - setup_cfg->size = cfg->param_size; - ret = memcpy_s(setup_cfg->data, setup_cfg->size, - cfg->param, cfg->param_size); - if (ret) { - comp_err(dev, "cadence_codec_init(): failed to copy setup config %d", ret); - goto free_cfg2; - } - setup_cfg->avail = true; - } - comp_dbg(dev, "cadence_codec_init() done"); + if (cd->mem_to_be_freed) + for (i = 0; i < cd->mem_to_be_freed_len; i++) + mod_free(mod, cd->mem_to_be_freed[i]); - return 0; - -free_cfg2: - rfree(codec->cfg.data); -free_cfg: - rfree(setup_cfg->data); -free: - rfree(cd); - return ret; + mod_free(mod, cd->mem_to_be_freed); + cd->mem_to_be_freed = NULL; + cd->mem_to_be_freed_len = 0; } -#elif CONFIG_IPC_MAJOR_3 -static int cadence_codec_init(struct processing_module *mod) -{ - struct module_data *codec = &mod->priv; - struct cadence_codec_data *cd; - struct comp_dev *dev = mod->dev; - struct module_config *setup_cfg; - int ret; - - comp_dbg(dev, "cadence_codec_init() start"); - - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(struct cadence_codec_data)); - if (!cd) { - comp_err(dev, "cadence_codec_init(): failed to allocate memory for cadence codec data"); - return -ENOMEM; - } - - codec->private = cd; - codec->mpd.init_done = 0; - - /* copy the setup config only for the first init */ - if (codec->state == MODULE_DISABLED && codec->cfg.avail) { - setup_cfg = &cd->setup_cfg; - - /* allocate memory for set up config */ - setup_cfg->data = rmalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - codec->cfg.size); - if (!setup_cfg->data) { - comp_err(dev, "cadence_codec_init(): failed to alloc setup config"); - ret = -ENOMEM; - goto free; - } - - /* copy the setup config */ - setup_cfg->size = codec->cfg.size; - ret = memcpy_s(setup_cfg->data, setup_cfg->size, - codec->cfg.init_data, setup_cfg->size); - if (ret) { - comp_err(dev, "cadence_codec_init(): failed to copy setup config %d", ret); - goto free_cfg; - } - setup_cfg->avail = true; - } - - comp_dbg(dev, "cadence_codec_init() done"); - - return 0; - -free_cfg: - rfree(setup_cfg->data); -free: - rfree(cd); - return ret; -} - -#else -#error Unknown IPC major version -#endif - -static int cadence_codec_apply_config(struct processing_module *mod) -{ - int ret = 0; - int size; - uint16_t param_id; - uint16_t codec_id; - struct module_config *cfg; - void *data; - struct module_param *param; - struct comp_dev *dev = mod->dev; - struct module_data *codec = &mod->priv; - struct cadence_codec_data *cd = codec->private; - - comp_dbg(dev, "cadence_codec_apply_config() start"); - - cfg = &codec->cfg; - - /* use setup config if no runtime config available. This will be true during reset */ - if (!cfg->avail) - cfg = &cd->setup_cfg; - - data = cfg->data; - size = cfg->size; - - if (!cfg->avail || !size) { - comp_err(dev, "cadence_codec_apply_config() error: no config available"); - return -EIO; - } - - /* Read parameters stored in `data` - it may keep plenty of - * parameters. The `size` variable is equal to param->size * count, - * where count is number of parameters stored in `data`. - */ - while (size > 0) { - param = data; - comp_dbg(dev, "cadence_codec_apply_config() applying param %d value %d", - param->id, param->data[0]); - - param_id = param->id & 0xFF; - codec_id = param->id >> 16; - - /* if the parameter is not for current codec skip it! */ - if (codec_id && codec_id != cd->api_id) { - /* Obtain next parameter */ - data = (char *)data + param->size; - size -= param->size; - continue; - } - - /* Set read parameter */ - API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, param_id, - param->data, ret); - if (ret != LIB_NO_ERROR) { - if (LIB_IS_FATAL_ERROR(ret)) { - comp_err(dev, "cadence_codec_apply_config(): failed to apply parameter: %d value: %d error: %#x", - param->id, *(int32_t *)param->data, ret); - - return ret; - } - comp_warn(dev, "cadence_codec_apply_config(): applied parameter %d value %d with return code: %#x", - param->id, *(int32_t *)param->data, ret); - } - /* Obtain next parameter, it starts right after the preceding one */ - data = (char *)data + param->size; - size -= param->size; - } - - comp_dbg(dev, "cadence_codec_apply_config() done"); - - return 0; -} - -static int init_memory_tables(struct processing_module *mod) +int cadence_codec_init_memory_tables(struct processing_module *mod) { int ret, no_mem_tables, i, mem_type, mem_size, mem_alignment; void *ptr, *scratch, *persistent; @@ -483,7 +123,7 @@ static int init_memory_tables(struct processing_module *mod) API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, NULL, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "init_memory_tables() error %x: failed to calculate memory blocks size", + comp_err(dev, "error %x: failed to calculate memory blocks size", ret); return ret; } @@ -491,17 +131,22 @@ static int init_memory_tables(struct processing_module *mod) /* Get number of memory tables */ API_CALL(cd, XA_API_CMD_GET_N_MEMTABS, 0, &no_mem_tables, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "init_memory_tables() error %x: failed to get number of memory tables", + comp_err(dev, "error %x: failed to get number of memory tables", ret); return ret; } + cd->mem_to_be_freed = mod_zalloc(mod, no_mem_tables * sizeof(*cd->mem_to_be_freed)); + if (!cd->mem_to_be_freed) + return -ENOMEM; + cd->mem_to_be_freed_len = no_mem_tables; + /* Initialize each memory table */ for (i = 0; i < no_mem_tables; i++) { /* Get type of memory - it specifies how the memory will be used */ API_CALL(cd, XA_API_CMD_GET_MEM_INFO_TYPE, i, &mem_type, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "init_memory_tables() error %x: failed to get mem. type info of id %d out of %d", + comp_err(dev, "error %x: failed to get mem. type info of id %d out of %d", ret, i, no_mem_tables); goto err; } @@ -510,29 +155,30 @@ static int init_memory_tables(struct processing_module *mod) */ API_CALL(cd, XA_API_CMD_GET_MEM_INFO_SIZE, i, &mem_size, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "init_memory_tables() error %x: failed to get mem. size for mem. type %d", + comp_err(dev, "error %x: failed to get mem. size for mem. type %d", ret, mem_type); goto err; } /* Get alignment constrains */ API_CALL(cd, XA_API_CMD_GET_MEM_INFO_ALIGNMENT, i, &mem_alignment, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "init_memory_tables() error %x: failed to get mem. alignment of mem. type %d", + comp_err(dev, "error %x: failed to get mem. alignment of mem. type %d", ret, mem_type); goto err; } /* Allocate memory for this type, taking alignment into account */ - ptr = module_allocate_memory(mod, mem_size, mem_alignment); + ptr = mod_alloc_align(mod, mem_size, mem_alignment); if (!ptr) { - comp_err(dev, "init_memory_tables() error %x: failed to allocate memory for %d", + comp_err(dev, "error %x: failed to allocate memory for %d", ret, mem_type); ret = -EINVAL; goto err; } + cd->mem_to_be_freed[i] = ptr; /* Finally, provide this memory for codec */ API_CALL(cd, XA_API_CMD_SET_MEM_PTR, i, ptr, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "init_memory_tables() error %x: failed to set memory pointer for %d", + comp_err(dev, "error %x: failed to set memory pointer for %d", ret, mem_type); goto err; } @@ -553,35 +199,34 @@ static int init_memory_tables(struct processing_module *mod) codec->mpd.out_buff_size = mem_size; break; default: - comp_err(dev, "init_memory_tables() error %x: unrecognized memory type!", + comp_err(dev, "error %x: unrecognized memory type!", mem_type); ret = -EINVAL; goto err; } - comp_dbg(dev, "init_memory_tables: allocated memory of %d bytes and alignment %d for mem. type %d", + comp_dbg(dev, "allocated memory of %d bytes and alignment %d for mem. type %d", mem_size, mem_alignment, mem_type); } return 0; err: - if (scratch) - module_free_memory(mod, scratch); - if (persistent) - module_free_memory(mod, persistent); - if (codec->mpd.in_buff) - module_free_memory(mod, codec->mpd.in_buff); - if (codec->mpd.out_buff) - module_free_memory(mod, codec->mpd.out_buff); + cadence_codec_free_memory_tables(mod); + return ret; } -static int cadence_codec_get_samples(struct processing_module *mod) +size_t cadence_api_table_size(void) +{ + return ARRAY_SIZE(cadence_api_table); +} + +unsigned int cadence_codec_get_samples(struct processing_module *mod) { struct cadence_codec_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - comp_dbg(dev, "cadence_codec_get_samples() start"); + comp_dbg(dev, "start"); switch (cd->api_id) { case CADENCE_CODEC_WRAPPER_ID: @@ -598,35 +243,26 @@ static int cadence_codec_get_samples(struct processing_module *mod) return 0; } -static int cadence_codec_deep_buff_allowed(struct processing_module *mod) -{ - struct cadence_codec_data *cd = module_get_private_data(mod); - - switch (cd->api_id) { - case CADENCE_CODEC_MP3_ENC_ID: - return 0; - default: - return 1; - } -} - -static int cadence_codec_init_process(struct processing_module *mod) +int cadence_codec_init_process(struct processing_module *mod) { int ret; struct module_data *codec = &mod->priv; struct cadence_codec_data *cd = codec->private; struct comp_dev *dev = mod->dev; + codec->mpd.eos_reached = false; + codec->mpd.eos_notification_sent = false; + API_CALL(cd, XA_API_CMD_SET_INPUT_BYTES, 0, &codec->mpd.avail, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_init_process() error %x: failed to set size of input data", + comp_err(dev, "error %x: failed to set size of input data", ret); return ret; } API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_PROCESS, NULL, ret); if (LIB_IS_FATAL_ERROR(ret)) { - comp_err(dev, "cadence_codec_init_process() error %x: failed to initialize codec", + comp_err(dev, "error %x: failed to initialize codec", ret); return ret; } else if (ret != LIB_NO_ERROR) { @@ -639,21 +275,21 @@ static int cadence_codec_init_process(struct processing_module *mod) * a non-fatal error and let the init process continue. Next * chunk will contain the useful data. */ - comp_warn(dev, "cadence_codec_init_process() returned non-fatal error: 0x%x", + comp_warn(dev, "returned non-fatal error: 0x%x", ret); } API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_DONE_QUERY, &codec->mpd.init_done, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_init_process() error %x: failed to get lib init status", + comp_err(dev, "error %x: failed to get lib init status", ret); return ret; } API_CALL(cd, XA_API_CMD_GET_CURIDX_INPUT_BUF, 0, &codec->mpd.consumed, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_init_process() error %x: could not get consumed bytes", + comp_err(dev, "error %x: could not get consumed bytes", ret); return ret; } @@ -661,262 +297,329 @@ static int cadence_codec_init_process(struct processing_module *mod) return 0; } -static int cadence_codec_prepare(struct processing_module *mod, - struct sof_source **sources, int num_of_sources, - struct sof_sink **sinks, int num_of_sinks) +int cadence_codec_free(struct processing_module *mod) { - int ret = 0, mem_tabs_size; - struct comp_dev *dev = mod->dev; - struct module_data *codec = &mod->priv; - struct cadence_codec_data *cd = codec->private; + struct cadence_codec_data *cd = module_get_private_data(mod); + + mod_free(mod, cd->setup_cfg.data); + + cadence_codec_free_memory_tables(mod); + mod_free(mod, cd->mem_tabs); + + mod_free(mod, cd->self); + mod_free(mod, cd); + return 0; +} - comp_dbg(dev, "cadence_codec_prepare() start"); +int cadence_codec_set_configuration(struct processing_module *mod, uint32_t config_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, const uint8_t *fragment, + size_t fragment_size, uint8_t *response, size_t response_size) +{ + struct module_data *md = &mod->priv; + struct comp_dev *dev = mod->dev; + int ret; - ret = cadence_codec_post_init(mod); - if (ret) + ret = module_set_configuration(mod, config_id, pos, data_offset_size, fragment, + fragment_size, response, response_size); + if (ret < 0) return ret; + /* return if more fragments are expected or if the module is not prepared */ + if ((pos != MODULE_CFG_FRAGMENT_LAST && pos != MODULE_CFG_FRAGMENT_SINGLE) || + md->state < MODULE_IDLE) + return 0; + + /* whole configuration received, apply it now */ ret = cadence_codec_apply_config(mod); if (ret) { - comp_err(dev, "cadence_codec_prepare() error %x: failed to apply config", - ret); + comp_err(dev, "runtime config apply failed with error %x: ", ret); return ret; } - /* Allocate memory for the codec */ - API_CALL(cd, XA_API_CMD_GET_MEMTABS_SIZE, 0, &mem_tabs_size, ret); - if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_prepare() error %x: failed to get memtabs size", - ret); - return ret; - } + comp_dbg(dev, "config applied"); - cd->mem_tabs = module_allocate_memory(mod, mem_tabs_size, 4); - if (!cd->mem_tabs) { - comp_err(dev, "cadence_codec_prepare() error: failed to allocate space for memtabs"); - return -ENOMEM; + return 0; +} + +int cadence_codec_apply_params(struct processing_module *mod, int size, void *data) +{ + struct module_data *codec = &mod->priv; + struct comp_dev *dev = mod->dev; + struct cadence_codec_data *cd = codec->private; + struct module_param *param; + uint16_t param_id; + uint16_t codec_id; + int ret; + + /* Read parameters stored in `data` - it may keep plenty of + * parameters. The `size` variable is equal to param->size * count, + * where count is number of parameters stored in `data`. + */ + while (size > 0) { + param = data; + + if (size < (int)sizeof(*param)) { + comp_err(dev, "param header truncated, %d bytes left", size); + return -EINVAL; + } + + /* param->size covers the whole record and must fit */ + if (param->size <= sizeof(*param) || param->size > (uint32_t)size) { + comp_err(dev, "invalid param size %u, %d bytes left", + param->size, size); + return -EINVAL; + } + + comp_dbg(dev, "cadence_codec_apply_config() applying param %d value %d", + param->id, param->data[0]); + + param_id = param->id & 0xFF; + codec_id = param->id >> 16; + + /* if the parameter is not for current codec skip it! */ + if (codec_id && codec_id != cd->api_id) { + /* Obtain next parameter */ + data = (char *)data + param->size; + size -= param->size; + continue; + } + + /* Set read parameter */ + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, param_id, + param->data, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply parameter: %d value: %d error: %#x", + param->id, *(int32_t *)param->data, ret); + + return ret; + } + comp_warn(dev, "applied parameter %d value %d with return code: %#x", + param->id, *(int32_t *)param->data, ret); + } + /* Obtain next parameter, it starts right after the preceding one */ + data = (char *)data + param->size; + size -= param->size; } - comp_dbg(dev, "cadence_codec_prepare(): allocated %d bytes for memtabs", mem_tabs_size); + return 0; +} + +int cadence_init_codec_object(struct processing_module *mod) +{ + int ret; + struct comp_dev *dev = mod->dev; + struct cadence_codec_data *cd = module_get_private_data(mod); + uint32_t obj_size; + + ret = cadence_codec_resolve_api(mod); + if (ret < 0) + return ret; - API_CALL(cd, XA_API_CMD_SET_MEMTABS_PTR, 0, cd->mem_tabs, ret); + /* Obtain codec name */ + API_CALL(cd, XA_API_CMD_GET_LIB_ID_STRINGS, + XA_CMD_TYPE_LIB_NAME, cd->name, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_prepare() error %x: failed to set memtabs", - ret); - goto free; + comp_err(dev, "failed to get lib name error: %x: ", ret); + return ret; } - - ret = init_memory_tables(mod); + /* Get codec object size */ + API_CALL(cd, XA_API_CMD_GET_API_SIZE, 0, &obj_size, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_prepare() error %x: failed to init memory tables", - ret); - goto free; + comp_err(dev, "failed to get lib object size error %x:", ret); + return ret; } - /* Check init done status. Note, it may happen that init_done flag will return - * false value, this is normal since some codec variants needs input in order to - * fully finish initialization. That's why at codec_adapter_copy() we call - * codec_init_process() base on result obtained below. - */ -#ifdef CONFIG_CADENCE_CODEC_WRAPPER - /* TODO: remove the "#ifdef CONFIG_CADENCE_CODEC_WRAPPER" once cadence fixes the bug - * in the init/prepare sequence. Basically below API_CALL shall return 1 for - * PCM streams and 0 for compress ones. As it turns out currently it returns 1 - * in both cases so in turn compress stream won't finish its prepare during first copy - * in codec_adapter_copy(). - */ - API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_DONE_QUERY, - &codec->mpd.init_done, ret); + /* Allocate space for codec object */ + cd->self = mod_balloc(mod, obj_size); + if (!cd->self) { + comp_err(dev, "failed to allocate space for lib object"); + return -ENOMEM; + } + + comp_dbg(dev, "allocated %d bytes for lib object", obj_size); + + /* Set all params to their default values */ + API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, + NULL, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_init_process() error %x: failed to get lib init status", - ret); + mod_free(mod, cd->self); return ret; } -#endif - comp_dbg(dev, "cadence_codec_prepare() done"); + return 0; -free: - module_free_memory(mod, cd->mem_tabs); - return ret; } -static int -cadence_codec_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) +int cadence_codec_resolve_api_with_id(struct processing_module *mod, uint32_t codec_id, + uint32_t direction) { - struct comp_buffer *local_buff; + struct cadence_codec_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct module_data *codec = &mod->priv; - struct cadence_codec_data *cd = codec->private; - int free_bytes, output_bytes = cadence_codec_get_samples(mod) * - mod->stream_params->sample_container_bytes * - mod->stream_params->channels; - uint32_t remaining = input_buffers[0].size; - int ret; + uint32_t api_id; + uint32_t n_apis = cadence_api_table_size(); + xa_codec_func_t *api = NULL; + int i; - if (!cadence_codec_deep_buff_allowed(mod)) { - mod->deep_buff_bytes = 0; + api_id = cadence_codec_get_api_id(codec_id, direction); + if (api_id < 0) + return api_id; + + /* Find and assign API function */ + for (i = 0; i < n_apis; i++) { + if (cadence_api_table[i].id == api_id) { + api = cadence_api_table[i].api; + break; + } } - /* Proceed only if we have enough data to fill the module buffer completely */ - if (input_buffers[0].size < codec->mpd.in_buff_size) { - comp_dbg(dev, "cadence_codec_process(): not enough data to process"); - return -ENODATA; + /* Verify API assignment */ + if (!api) { + comp_err(dev, "could not find API function for id %x", + api_id); + return -EINVAL; } + cd->api = api; + cd->api_id = api_id; - if (!codec->mpd.init_done) { - memcpy_s(codec->mpd.in_buff, codec->mpd.in_buff_size, input_buffers[0].data, - codec->mpd.in_buff_size); - codec->mpd.avail = codec->mpd.in_buff_size; + return 0; +} - ret = cadence_codec_init_process(mod); - if (ret) - return ret; +static void cadence_store_api_error_code(struct comp_dev *dev, + XA_ERRORCODE *api_error_code, + int ret, const char *cmd_name) +{ + if (!api_error_code) + return; - remaining -= codec->mpd.consumed; - input_buffers[0].consumed = codec->mpd.consumed; - } + if (*api_error_code && *api_error_code != ret) + comp_dbg(dev, "overwriting api error code at %s: old %#x new %#x", + cmd_name, *api_error_code, ret); - /* 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); - free_bytes = audio_stream_get_free(&local_buff->stream); - if (free_bytes < output_bytes) - return -ENOSPC; + *api_error_code = ret; +} - /* Proceed only if we have enough data to fill the module buffer completely */ - if (remaining < codec->mpd.in_buff_size) - return -ENODATA; +int cadence_codec_process_data(struct processing_module *mod, + XA_ERRORCODE *api_error_code) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + struct module_data *codec = &mod->priv; + struct comp_dev *dev = mod->dev; + uint32_t done = 0; + int ret; - memcpy_s(codec->mpd.in_buff, codec->mpd.in_buff_size, - (uint8_t *)input_buffers[0].data + input_buffers[0].consumed, - codec->mpd.in_buff_size); - codec->mpd.avail = codec->mpd.in_buff_size; + if (api_error_code) + *api_error_code = 0; - comp_dbg(dev, "cadence_codec_process() start"); + if (codec->mpd.eos_reached) { + codec->mpd.produced = 0; + codec->mpd.consumed = 0; + + return 0; + } + + if (dev->pipeline->expect_eos) { + /* Signal that the stream is expected to end anytime soon */ + API_CALL(cd, XA_API_CMD_INPUT_OVER, 0, NULL, ret); + if (ret != LIB_NO_ERROR) { + if (api_error_code) + *api_error_code = ret; + + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "input_over failed with error: %x", ret); + return ret; + } + } + } API_CALL(cd, XA_API_CMD_SET_INPUT_BYTES, 0, &codec->mpd.avail, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_process() error %x: failed to set size of input data", - ret); + comp_err(dev, "failed to set size of input data with error: %x:", ret); return ret; } API_CALL(cd, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DO_EXECUTE, NULL, ret); if (ret != LIB_NO_ERROR) { + cadence_store_api_error_code(dev, api_error_code, ret, + "XA_API_CMD_EXECUTE_DO_EXECUTE"); + + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "processing failed with error: %x", ret); + return ret; + } + } + + API_CALL(cd, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DONE_QUERY, &done, ret); + if (ret != LIB_NO_ERROR) { + cadence_store_api_error_code(dev, api_error_code, ret, + "XA_API_CMD_EXECUTE_DONE_QUERY"); + if (LIB_IS_FATAL_ERROR(ret)) { - comp_err(dev, "cadence_codec_process() error %x: processing failed", - ret); + comp_err(dev, "done query failed with error: %x", ret); return ret; } - comp_warn(dev, "cadence_codec_process() nonfatal error %x", ret); } API_CALL(cd, XA_API_CMD_GET_OUTPUT_BYTES, 0, &codec->mpd.produced, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_process() error %x: could not get produced bytes", + comp_err(dev, "could not get produced bytes, error %x:", ret); return ret; } API_CALL(cd, XA_API_CMD_GET_CURIDX_INPUT_BUF, 0, &codec->mpd.consumed, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_process() error %x: could not get consumed bytes", - ret); + comp_err(dev, "could not get consumed bytes, error: %x", ret); return ret; } - /* update consumed with the number of samples consumed during init */ - input_buffers[0].consumed += codec->mpd.consumed; - codec->mpd.consumed = input_buffers[0].consumed; - - /* copy the produced samples into the output buffer */ - memcpy_s(output_buffers[0].data, codec->mpd.produced, codec->mpd.out_buff, - codec->mpd.produced); - output_buffers[0].size = codec->mpd.produced; + if (dev->pipeline->expect_eos) { + /* + * AAC decoder cannot signal DONE, check if it stopped + * producing data when EOS is expected + */ + if (cd->api_id == CADENCE_CODEC_AAC_DEC_ID && !codec->mpd.produced) + done = true; - comp_dbg(dev, "cadence_codec_process() done"); + if (done) + codec->mpd.eos_reached = true; + } return 0; } -static int cadence_codec_reset(struct processing_module *mod) +void cadence_copy_data_from_buffer(void *dest, const void *buffer_ptr, size_t bytes_to_copy, + size_t buffer_size, void const *buffer_start) { - struct module_data *codec = &mod->priv; - struct cadence_codec_data *cd = codec->private; - int ret; - - /* - * Current CADENCE API doesn't support reset of codec's runtime parameters. - * So, free all memory associated with runtime params. These will be reallocated during - * prepare. - */ - module_free_all_memory(mod); - - /* reset to default params */ - API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL, ret); - if (ret != LIB_NO_ERROR) - return ret; - - codec->mpd.init_done = 0; - - rfree(cd->self); - cd->self = NULL; - - return ret; -} + size_t bytes_to_end = (size_t)((const uint8_t *)buffer_start + + buffer_size - (const uint8_t *)buffer_ptr); -static int cadence_codec_free(struct processing_module *mod) -{ - struct cadence_codec_data *cd = module_get_private_data(mod); + if (bytes_to_end >= bytes_to_copy) { + /* No wrap, copy directly */ + memcpy_s(dest, bytes_to_copy, buffer_ptr, bytes_to_copy); + return; + } - rfree(cd->setup_cfg.data); - module_free_all_memory(mod); - rfree(cd->self); - rfree(cd); - return 0; + /* Wrap occurs, copy in two parts */ + memcpy_s(dest, bytes_to_end, buffer_ptr, bytes_to_end); + memcpy_s((uint8_t *)dest + bytes_to_end, bytes_to_copy - bytes_to_end, + buffer_start, bytes_to_copy - bytes_to_end); } -static int -cadence_codec_set_configuration(struct processing_module *mod, uint32_t config_id, - enum module_cfg_fragment_position pos, uint32_t data_offset_size, - const uint8_t *fragment, size_t fragment_size, uint8_t *response, - size_t response_size) +void cadence_copy_data_to_buffer(void *buffer_ptr, size_t bytes_to_copy, + size_t buffer_size, void *buffer_start, + const void *src) { - struct module_data *md = &mod->priv; - struct comp_dev *dev = mod->dev; - int ret; + size_t bytes_to_end = (size_t)((uint8_t *)buffer_start + + buffer_size - (uint8_t *)buffer_ptr); - ret = module_set_configuration(mod, config_id, pos, data_offset_size, fragment, - fragment_size, response, response_size); - if (ret < 0) - return ret; - - /* return if more fragments are expected or if the module is not prepared */ - if ((pos != MODULE_CFG_FRAGMENT_LAST && pos != MODULE_CFG_FRAGMENT_SINGLE) || - md->state < MODULE_IDLE) - return 0; - - /* whole configuration received, apply it now */ - ret = cadence_codec_apply_config(mod); - if (ret) { - comp_err(dev, "cadence_codec_set_configuration(): error %x: runtime config apply failed", - ret); - return ret; + if (bytes_to_end >= bytes_to_copy) { + /* No wrap, copy directly */ + memcpy_s(buffer_ptr, bytes_to_copy, src, bytes_to_copy); + return; } - comp_dbg(dev, "cadence_codec_set_configuration(): config applied"); - - return 0; + /* Wrap occurs, copy in two parts */ + memcpy_s(buffer_ptr, bytes_to_end, src, bytes_to_end); + memcpy_s(buffer_start, bytes_to_copy - bytes_to_end, + (const uint8_t *)src + bytes_to_end, bytes_to_copy - bytes_to_end); } - -static const struct module_interface cadence_codec_interface = { - .init = cadence_codec_init, - .prepare = cadence_codec_prepare, - .process_raw_data = cadence_codec_process, - .set_configuration = cadence_codec_set_configuration, - .reset = cadence_codec_reset, - .free = cadence_codec_free -}; - -DECLARE_MODULE_ADAPTER(cadence_codec_interface, cadence_codec_uuid, cadence_codec_tr); -SOF_MODULE_INIT(cadence_codec, sys_comp_module_cadence_codec_interface_init); diff --git a/src/audio/module_adapter/module/cadence.toml b/src/audio/module_adapter/module/cadence.toml index 078e8ec6bba8..4c0466196577 100644 --- a/src/audio/module_adapter/module/cadence.toml +++ b/src/audio/module_adapter/module/cadence.toml @@ -1,7 +1,7 @@ REM # Cadence module config [[module.entry]] name = "CADENCE" - uuid = "D8218443-5FF3-4A4C-B388-6CFE07B956AA" + uuid = UUIDREG_STR_CADENCE_CODEC affinity_mask = "0x3" instance_count = "1" domain_types = "0" diff --git a/src/audio/module_adapter/module/cadence_ipc3.c b/src/audio/module_adapter/module/cadence_ipc3.c new file mode 100644 index 000000000000..c9a6f7705062 --- /dev/null +++ b/src/audio/module_adapter/module/cadence_ipc3.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. +// +// Author: Marcin Rajwa <marcin.rajwa@linux.intel.com> + +/* + * \file cadence.c + * \brief Cadence Codec API + * \author Marcin Rajwa <marcin.rajwa@linux.intel.com> + * + */ + +#include <ipc/compress_params.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/module_adapter/module/cadence.h> +#include <rtos/init.h> + +SOF_DEFINE_REG_UUID(cadence_codec); +LOG_MODULE_DECLARE(cadence_codec, CONFIG_SOF_LOG_LEVEL); +DECLARE_TR_CTX(cadence_codec_tr, SOF_UUID(cadence_codec_uuid), LOG_LEVEL_INFO); + +int cadence_codec_resolve_api(struct processing_module *mod) +{ + int ret; + struct snd_codec codec_params; + uint32_t codec_id = DEFAULT_CODEC_ID; + + if (mod->stream_params->ext_data_length) { + ret = memcpy_s(&codec_params, mod->stream_params->ext_data_length, + (uint8_t *)mod->stream_params + sizeof(*mod->stream_params), + mod->stream_params->ext_data_length); + if (ret < 0) + return ret; + + codec_id = codec_params.id; + } + + /* IPC3 only supports playback */ + return cadence_codec_resolve_api_with_id(mod, codec_id, mod->stream_params->direction); +} + +static int cadence_codec_init(struct processing_module *mod) +{ + struct module_data *codec = &mod->priv; + struct cadence_codec_data *cd; + struct comp_dev *dev = mod->dev; + struct module_config *setup_cfg; + int ret; + + comp_dbg(dev, "cadence_codec_init() start"); + + cd = mod_zalloc(mod, sizeof(struct cadence_codec_data)); + if (!cd) { + comp_err(dev, "failed to allocate memory for cadence codec data"); + return -ENOMEM; + } + + codec->private = cd; + codec->mpd.init_done = 0; + + /* copy the setup config only for the first init */ + if (codec->state == MODULE_DISABLED && codec->cfg.avail) { + setup_cfg = &cd->setup_cfg; + + /* allocate memory for set up config */ + setup_cfg->data = mod_alloc(mod, codec->cfg.size); + if (!setup_cfg->data) { + comp_err(dev, "failed to alloc setup config"); + ret = -ENOMEM; + goto free; + } + + /* copy the setup config */ + setup_cfg->size = codec->cfg.size; + ret = memcpy_s(setup_cfg->data, setup_cfg->size, + codec->cfg.init_data, setup_cfg->size); + if (ret) { + comp_err(dev, "failed to copy setup config %d", ret); + goto free_cfg; + } + setup_cfg->avail = true; + } + + comp_dbg(dev, "cadence_codec_init() done"); + + return 0; + +free_cfg: + mod_free(mod, setup_cfg->data); +free: + mod_free(mod, cd); + return ret; +} + +int cadence_codec_apply_config(struct processing_module *mod) +{ + int size; + struct module_config *cfg; + void *data; + struct comp_dev *dev = mod->dev; + struct module_data *codec = &mod->priv; + struct cadence_codec_data *cd = codec->private; + + comp_dbg(dev, "cadence_codec_apply_config() start"); + + cfg = &codec->cfg; + + /* use setup config if no runtime config available. This will be true during reset */ + if (!cfg->avail) + cfg = &cd->setup_cfg; + + data = cfg->data; + size = cfg->size; + + if (!cfg->avail || !size) { + comp_err(dev, "cadence_codec_apply_config() error: no config available"); + return -EIO; + } + + return cadence_codec_apply_params(mod, size, data); +} + +static int cadence_codec_deep_buff_allowed(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + + switch (cd->api_id) { + case CADENCE_CODEC_MP3_ENC_ID: + return 0; + default: + return 1; + } +} + +static int cadence_codec_prepare(struct processing_module *mod, + 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; + struct module_data *codec = &mod->priv; + struct cadence_codec_data *cd = codec->private; + + comp_dbg(dev, "cadence_codec_prepare() start"); + + ret = cadence_init_codec_object(mod); + if (ret) + return ret; + + ret = cadence_codec_apply_config(mod); + if (ret) { + comp_err(dev, "cadence_codec_prepare() error %x: failed to apply config", + ret); + return ret; + } + + /* Allocate memory for the codec */ + API_CALL(cd, XA_API_CMD_GET_MEMTABS_SIZE, 0, &mem_tabs_size, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "cadence_codec_prepare() error %x: failed to get memtabs size", + ret); + return ret; + } + + cd->mem_tabs = mod_alloc(mod, mem_tabs_size); + if (!cd->mem_tabs) { + comp_err(dev, "cadence_codec_prepare() error: failed to allocate space for memtabs"); + return -ENOMEM; + } + + comp_dbg(dev, "allocated %d bytes for memtabs", mem_tabs_size); + + API_CALL(cd, XA_API_CMD_SET_MEMTABS_PTR, 0, cd->mem_tabs, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "cadence_codec_prepare() error %x: failed to set memtabs", + ret); + goto free; + } + + ret = cadence_codec_init_memory_tables(mod); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "cadence_codec_prepare() error %x: failed to init memory tables", + ret); + goto free; + } + /* Check init done status. Note, it may happen that init_done flag will return + * false value, this is normal since some codec variants needs input in order to + * fully finish initialization. That's why at codec_adapter_copy() we call + * codec_init_process() base on result obtained below. + */ +#ifdef CONFIG_CADENCE_CODEC_WRAPPER + /* TODO: remove the "#ifdef CONFIG_CADENCE_CODEC_WRAPPER" once cadence fixes the bug + * in the init/prepare sequence. Basically below API_CALL shall return 1 for + * PCM streams and 0 for compress ones. As it turns out currently it returns 1 + * in both cases so in turn compress stream won't finish its prepare during first copy + * in codec_adapter_copy(). + */ + API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_DONE_QUERY, + &codec->mpd.init_done, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "cadence_codec_init_process() error %x: failed to get lib init status", + ret); + return ret; + } +#endif + comp_dbg(dev, "cadence_codec_prepare() done"); + return 0; +free: + mod_free(mod, cd->mem_tabs); + return ret; +} + +static int cadence_codec_process(struct processing_module *mod, + 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; + size_t output_bytes = cadence_codec_get_samples(mod) * + mod->stream_params->sample_container_bytes * + mod->stream_params->channels; + size_t remaining = source_get_data_available(sources[0]); + const void *source_buffer_start, *src_ptr; + void *sink_ptr, *sink_buffer_start; + size_t src_bytes, sink_bytes; + int ret; + + if (!cadence_codec_deep_buff_allowed(mod)) + mod->deep_buff_bytes = 0; + + /* Proceed only if we have enough data to fill the module buffer completely */ + if (remaining < codec->mpd.in_buff_size) { + comp_dbg(dev, "not enough data to process"); + return -ENODATA; + } + + if (!codec->mpd.init_done) { + ret = source_get_data(sources[0], codec->mpd.in_buff_size, &src_ptr, + &source_buffer_start, &src_bytes); + if (ret) { + comp_err(dev, "cannot get data from source buffer"); + return ret; + } + + cadence_copy_data_from_buffer(codec->mpd.in_buff, src_ptr, + codec->mpd.in_buff_size, src_bytes, + source_buffer_start); + codec->mpd.avail = codec->mpd.in_buff_size; + + ret = cadence_codec_init_process(mod); + if (ret) { + source_release_data(sources[0], 0); + return ret; + } + + remaining -= codec->mpd.consumed; + source_release_data(sources[0], codec->mpd.consumed); + } + + /* do not proceed with processing if not enough free space left in the sink buffer */ + if (sink_get_free_size(sinks[0]) < output_bytes) + return -ENOSPC; + + /* Proceed only if we have enough data to fill the module buffer completely */ + if (remaining < codec->mpd.in_buff_size) + return -ENODATA; + + ret = source_get_data(sources[0], codec->mpd.in_buff_size, &src_ptr, &source_buffer_start, + &src_bytes); + if (ret) + return ret; + + cadence_copy_data_from_buffer(codec->mpd.in_buff, src_ptr, + codec->mpd.in_buff_size, src_bytes, + source_buffer_start); + codec->mpd.avail = codec->mpd.in_buff_size; + + comp_dbg(dev, "cadence_codec_process() start"); + + ret = cadence_codec_process_data(mod, NULL); + if (ret) { + source_release_data(sources[0], 0); + return ret; + } + + source_release_data(sources[0], codec->mpd.consumed); + + ret = sink_get_buffer(sinks[0], codec->mpd.produced, &sink_ptr, &sink_buffer_start, + &sink_bytes); + if (ret) { + comp_err(dev, "cannot get sink buffer"); + return ret; + } + + /* Copy the produced samples into the output buffer */ + cadence_copy_data_to_buffer(sink_ptr, codec->mpd.produced, sink_bytes, + sink_buffer_start, codec->mpd.out_buff); + + sink_commit_buffer(sinks[0], codec->mpd.produced); + + comp_dbg(dev, "cadence_codec_process() done"); + + return 0; +} + +static int cadence_codec_reset(struct processing_module *mod) +{ + struct module_data *codec = &mod->priv; + struct cadence_codec_data *cd = codec->private; + int ret; + + cadence_codec_free_memory_tables(mod); + mod_free(mod, cd->mem_tabs); + + /* reset to default params */ + API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL, ret); + if (ret != LIB_NO_ERROR) + return ret; + + codec->mpd.init_done = 0; + + mod_free(mod, cd->self); + cd->self = NULL; + + return ret; +} + +static const struct module_interface cadence_codec_interface = { + .init = cadence_codec_init, + .prepare = cadence_codec_prepare, + .process = cadence_codec_process, + .set_configuration = cadence_codec_set_configuration, + .reset = cadence_codec_reset, + .free = cadence_codec_free +}; + +DECLARE_MODULE_ADAPTER(cadence_codec_interface, cadence_codec_uuid, cadence_codec_tr); +SOF_MODULE_INIT(cadence_codec, sys_comp_module_cadence_codec_interface_init); diff --git a/src/audio/module_adapter/module/cadence_ipc4.c b/src/audio/module_adapter/module/cadence_ipc4.c new file mode 100644 index 000000000000..00cb20405f92 --- /dev/null +++ b/src/audio/module_adapter/module/cadence_ipc4.c @@ -0,0 +1,584 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025-2026 Intel Corporation. All rights reserved. +// + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/module_adapter/module/cadence.h> +#include <sof/audio/cadence/mp3_dec/xa_mp3_dec_api.h> +#include <sof/audio/cadence/mp3_enc/xa_mp3_enc_api.h> +#include <sof/audio/cadence/aac_dec/xa_aac_dec_api.h> +#include <sof/ipc/msg.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <ipc/compress_params.h> +#include <ipc4/notification.h> +#include <rtos/init.h> + +SOF_DEFINE_REG_UUID(cadence_codec); +LOG_MODULE_DECLARE(cadence_codec, CONFIG_SOF_LOG_LEVEL); +DECLARE_TR_CTX(cadence_codec_tr, SOF_UUID(cadence_codec_uuid), LOG_LEVEL_INFO); + +int cadence_codec_resolve_api(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + struct module_config *setup_cfg = &cd->setup_cfg; + struct snd_codec *codec_params; + uint32_t codec_id = DEFAULT_CODEC_ID; + + /* update codec_id if setup_cfg is available */ + if (setup_cfg->avail) { + codec_params = (struct snd_codec *)cd->setup_cfg.data; + codec_id = codec_params->id; + } + + return cadence_codec_resolve_api_with_id(mod, codec_id, cd->direction); +} + +static int cadence_configure_mp3_dec_params(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + int word_size; + int ret; + + /* Cadence module only supports 16bit or 24 bits for word size */ + switch (cd->base_cfg.audio_fmt.depth) { + case IPC4_DEPTH_16BIT: + word_size = 16; + break; + case IPC4_DEPTH_24BIT: + case IPC4_DEPTH_32BIT: + word_size = 24; + break; + default: + comp_err(dev, "Unsupported bit depth: %d", cd->base_cfg.audio_fmt.depth); + return -EINVAL; + } + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_MP3DEC_CONFIG_PARAM_PCM_WDSZ, + (void *)&word_size, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config param word size: error: %#x", ret); + return ret; + } + comp_warn(dev, "applied param word size return code: %#x", ret); + } + + return 0; +} + +static int cadence_configure_mp3_enc_params(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + int word_size = 16; + int ret; + + /* + * Cadence encoder only supports 16-bit word size. Make sure the topology is set up + * correctly + */ + switch (cd->base_cfg.audio_fmt.depth) { + case IPC4_DEPTH_24BIT: + case IPC4_DEPTH_32BIT: + comp_err(dev, "Unsupported bit depth: %d for MP3 encoder", + cd->base_cfg.audio_fmt.depth); + return -EINVAL; + default: + break; + } + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_MP3ENC_CONFIG_PARAM_PCM_WDSZ, + (void *)&word_size, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config param word size: error: %#x", ret); + return ret; + } + comp_warn(dev, "applied param word size return code: %#x", ret); + } + + int num_channels = cd->base_cfg.audio_fmt.channels_count; + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_MP3ENC_CONFIG_PARAM_NUM_CHANNELS, + (void *)&num_channels, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config num_channels: error: %#x", ret); + return ret; + } + } + + int sampling_freq = cd->base_cfg.audio_fmt.sampling_frequency; + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_MP3ENC_CONFIG_PARAM_SAMP_FREQ, + (void *)&sampling_freq, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config sampling_frequency: error: %#x", ret); + return ret; + } + } + + int bitrate = CADENCE_MP3_ENCODER_DEFAULT_BITRATE; + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_MP3ENC_CONFIG_PARAM_BITRATE, + (void *)&bitrate, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config bitrate: error: %#x", ret); + return ret; + } + } + + return 0; +} + +static int cadence_configure_aac_dec_params(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + struct module_config *setup_cfg = &cd->setup_cfg; + struct comp_dev *dev = mod->dev; + struct snd_codec *codec_params; + int bitstream_format = XA_AACDEC_EBITSTREAM_TYPE_AAC_ADTS; + int word_size; + int ret; + + /* check bitstream format. Only MPEG-4 ADTS supported for now */ + if (setup_cfg->avail) { + codec_params = (struct snd_codec *)cd->setup_cfg.data; + if (codec_params->format != SND_AUDIOSTREAMFORMAT_MP4ADTS) { + comp_err(dev, "Unsupported AAC format: %d", codec_params->format); + return -EINVAL; + } + } else { + comp_err(dev, "No setup config available for AAC decoder"); + return -EINVAL; + } + + /* AAC decoder module only supports 16bit or 24 bits for word size */ + switch (cd->base_cfg.audio_fmt.depth) { + case IPC4_DEPTH_16BIT: + word_size = 16; + break; + case IPC4_DEPTH_24BIT: + case IPC4_DEPTH_32BIT: + word_size = 24; + break; + default: + comp_err(dev, "Unsupported bit depth: %d", cd->base_cfg.audio_fmt.depth); + return -EINVAL; + } + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_AACDEC_CONFIG_PARAM_PCM_WDSZ, + (void *)&word_size, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config param word size: error: %#x", ret); + return ret; + } + comp_warn(dev, "applied param word size return code: %#x", ret); + } + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_AACDEC_CONFIG_PARAM_EXTERNALBSFORMAT, + (void *)&bitstream_format, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config param bitstream format: error: %#x", + ret); + return ret; + } + comp_warn(dev, "applied param bitstream format return code: %#x", ret); + } + + return 0; +} + +static int cadence_configure_codec_params(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + + switch (cd->api_id) { + case CADENCE_CODEC_MP3_DEC_ID: + return cadence_configure_mp3_dec_params(mod); + case CADENCE_CODEC_MP3_ENC_ID: + return cadence_configure_mp3_enc_params(mod); + case CADENCE_CODEC_AAC_DEC_ID: + return cadence_configure_aac_dec_params(mod); + case CADENCE_CODEC_VORBIS_DEC_ID: + /* No configuration needed for Vorbis */ + return 0; + default: + break; + } + + comp_err(mod->dev, "Unsupported codec API ID: %u", cd->api_id); + return -EINVAL; +} + +static struct ipc_msg *cadence_codec_notification_init(struct processing_module *mod) +{ + struct comp_dev *dev = mod->dev; + struct comp_ipc_config *ipc_config = &dev->ipc_config; + struct sof_ipc4_notify_module_data *msg_module_data; + union ipc4_notification_header primary; + struct ipc_msg *msg; + + primary.dat = 0; + 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(primary.dat, 0, sizeof(*msg_module_data)); + if (!msg) + return NULL; + + msg_module_data = (struct sof_ipc4_notify_module_data *)msg->tx_data; + msg_module_data->instance_id = IPC4_INST_ID(ipc_config->id); + msg_module_data->module_id = IPC4_MOD_ID(ipc_config->id); + msg_module_data->event_id = SOF_IPC4_NOTIFY_MODULE_EVENTID_COMPR_MAGIC_VAL; + msg_module_data->event_data_size = 0; + + return msg; +} + +static int cadence_codec_init(struct processing_module *mod) +{ + struct module_data *codec = &mod->priv; + struct module_config *cfg = &codec->cfg; + struct module_ext_init_data *ext_data = cfg->ext_data; + struct module_config *setup_cfg = NULL; + struct cadence_codec_data *cd; + struct comp_dev *dev = mod->dev; + int mem_tabs_size; + int ret; + + comp_dbg(dev, "cadence_codec_init() start"); + + cd = mod_zalloc(mod, sizeof(struct cadence_codec_data)); + if (!cd) { + comp_err(dev, "failed to allocate memory for cadence codec data"); + return -ENOMEM; + } + + codec->private = cd; + cd->msg = cadence_codec_notification_init(mod); + if (!cd->msg) { + comp_err(dev, "failed to allocate IPC notification template"); + ret = -ENOMEM; + goto free_cd; + } + + memcpy_s(&cd->base_cfg, sizeof(cd->base_cfg), &cfg->base_cfg, sizeof(cd->base_cfg)); + + codec->mpd.init_done = 0; + + /* copy the setup config only for the first init */ + if (codec->state == MODULE_DISABLED && ext_data->module_data_size > 0) { + int size = ext_data->module_data_size; + uint8_t *init_bytes; + uint32_t direction; + + /* the init payload holds the codec params followed by the + * direction word; validate the size up front before using it + */ + if (size < (int)(sizeof(struct snd_codec) + sizeof(uint32_t))) { + comp_err(dev, "setup config too small: %d", size); + ret = -EINVAL; + goto free_cd; + } + + setup_cfg = &cd->setup_cfg; + + /* allocate memory for set up config (codec params) */ + setup_cfg->data = mod_alloc(mod, size); + if (!setup_cfg->data) { + comp_err(dev, "failed to alloc setup config"); + ret = -ENOMEM; + goto free_notification; + } + + setup_cfg->size = size; + ret = memcpy_s(setup_cfg->data, size, ext_data->module_data, size); + if (ret) { + comp_err(dev, "failed to copy setup config %d", ret); + goto free_cfg; + } + setup_cfg->avail = true; + codec->cfg.avail = false; + + /* direction follows the codec params; copy it out rather than + * dereferencing a possibly unaligned uint32_t pointer + */ + init_bytes = (uint8_t *)ext_data->module_data; + memcpy(&direction, init_bytes + sizeof(struct snd_codec), + sizeof(direction)); + cd->direction = direction; + + comp_info(dev, "codec direction set to %u", cd->direction); + } + + ret = cadence_init_codec_object(mod); + if (ret) + goto free_cfg; + + ret = cadence_configure_codec_params(mod); + if (ret) + goto free_cfg; + + /* Allocate memory for the codec */ + API_CALL(cd, XA_API_CMD_GET_MEMTABS_SIZE, 0, &mem_tabs_size, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "error %x: failed to get memtabs size", ret); + goto free_cfg; + } + + cd->mem_tabs = mod_alloc(mod, mem_tabs_size); + if (!cd->mem_tabs) { + comp_err(dev, "failed to allocate space for memtabs"); + goto free_cfg; + } + + comp_dbg(dev, "allocated %d bytes for memtabs", mem_tabs_size); + + API_CALL(cd, XA_API_CMD_SET_MEMTABS_PTR, 0, cd->mem_tabs, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "error %x: failed to set memtabs", ret); + goto free; + } + + ret = cadence_codec_init_memory_tables(mod); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "error %x: failed to init memory tables", ret); + goto free; + } + + comp_dbg(dev, "cadence_codec_init() done"); + + return 0; +free: + mod_free(mod, cd->mem_tabs); +free_cfg: + if (setup_cfg) + mod_free(mod, setup_cfg->data); +free_notification: + ipc_msg_free(cd->msg); +free_cd: + mod_free(mod, cd); + + return ret; +} + +int cadence_codec_apply_config(struct processing_module *mod) +{ + int size; + struct module_config *cfg; + void *data; + struct comp_dev *dev = mod->dev; + struct module_data *codec = &mod->priv; + + cfg = &codec->cfg; + + /* this will be true during prepare if there's no config available after init */ + if (!cfg->avail) + return 0; + + data = cfg->data; + size = cfg->size; + + if (!size) { + comp_err(dev, "error: no data available in config to apply"); + return -EIO; + } + + return cadence_codec_apply_params(mod, size, data); +} + +static int cadence_codec_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + int ret = 0; + struct comp_dev *dev = mod->dev; + struct module_data *codec = &mod->priv; + + comp_dbg(dev, "cadence_codec_prepare() start"); + + ret = cadence_codec_apply_config(mod); + if (ret) { + comp_err(dev, "failed to apply config error %x:", ret); + return ret; + } + + /* Check init done status. Note, it may happen that init_done flag will return + * false value, this is normal since some codec variants needs input in order to + * fully finish initialization. That's why at codec_adapter_copy() we call + * codec_init_process() base on result obtained below. + */ +#ifdef CONFIG_CADENCE_CODEC_WRAPPER + /* TODO: remove the "#ifdef CONFIG_CADENCE_CODEC_WRAPPER" once cadence fixes the bug + * in the init/prepare sequence. Basically below API_CALL shall return 1 for + * PCM streams and 0 for compress ones. As it turns out currently it returns 1 + * in both cases so in turn compress stream won't finish its prepare during first copy + * in codec_adapter_copy(). + */ + API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_DONE_QUERY, + &codec->mpd.init_done, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "failed to get lib init status error %x:", ret); + return ret; + } +#endif + + /* set the period based on the minimum required input data size */ + dev->period = 1000000ULL * codec->mpd.in_buff_size / + (source_get_frame_bytes(sources[0]) * source_get_rate(sources[0])); + comp_dbg(dev, "period set to %u usec", dev->period); + + /* align down period to LL cycle time */ + dev->period /= LL_TIMER_PERIOD_US; + dev->period *= LL_TIMER_PERIOD_US; + + comp_dbg(dev, "cadence_codec_prepare() done"); + return 0; +} + +static int cadence_codec_process(struct processing_module *mod, 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; + size_t in_size = source_get_data_available(sources[0]); + size_t out_space = sink_get_free_size(sinks[0]); + const void *source_buffer_start, *src_ptr; + void *sink_buffer_start, *sink_ptr; + size_t src_bytes, sink_bytes; + uint32_t remaining = in_size; + int ret; + + if (!codec->mpd.init_done) { + /* Acquire data from the source buffer */ + ret = source_get_data(sources[0], codec->mpd.in_buff_size, &src_ptr, + (const void **)&source_buffer_start, &src_bytes); + if (ret) { + comp_err(dev, "cannot get data from source buffer"); + return ret; + } + + cadence_copy_data_from_buffer(codec->mpd.in_buff, src_ptr, codec->mpd.in_buff_size, + src_bytes, source_buffer_start); + + codec->mpd.avail = codec->mpd.in_buff_size; + ret = cadence_codec_init_process(mod); + if (ret) + return ret; + + remaining -= codec->mpd.consumed; + source_release_data(sources[0], codec->mpd.consumed); + } + + codec->mpd.consumed = 0; + + /* Proceed only if we have enough data to fill the module buffer completely */ + if (remaining < codec->mpd.in_buff_size) + return -ENODATA; + + /* Acquire data from the source buffer */ + ret = source_get_data(sources[0], codec->mpd.in_buff_size, &src_ptr, &source_buffer_start, + &src_bytes); + + cadence_copy_data_from_buffer(codec->mpd.in_buff, src_ptr, codec->mpd.in_buff_size, + src_bytes, source_buffer_start); + codec->mpd.avail = codec->mpd.in_buff_size; + + comp_dbg(dev, "cadence_codec_process() start"); + + ret = cadence_codec_process_data(mod, NULL); + if (ret) { + source_release_data(sources[0], 0); + return ret; + } + + if (codec->mpd.eos_reached && !codec->mpd.eos_notification_sent) { + struct cadence_codec_data *cd = module_get_private_data(mod); + + ipc_msg_send(cd->msg, NULL, false); + codec->mpd.eos_notification_sent = true; + + /* Set EOS for the sink as we are not going to produce more data */ + audio_buffer_set_eos(sof_audio_buffer_from_sink(sinks[0])); + } + + /* do not proceed if not enough free space left */ + if (out_space < codec->mpd.produced) { + source_release_data(sources[0], 0); + return -ENOSPC; + } + + ret = sink_get_buffer(sinks[0], codec->mpd.produced, &sink_ptr, &sink_buffer_start, + &sink_bytes); + if (ret) { + comp_err(dev, "cannot get sink buffer"); + return ret; + } + + /* Copy the produced samples into the output buffer */ + cadence_copy_data_to_buffer(sink_ptr, codec->mpd.produced, sink_bytes, + sink_buffer_start, codec->mpd.out_buff); + + source_release_data(sources[0], codec->mpd.consumed); + sink_commit_buffer(sinks[0], codec->mpd.produced); + + /* reset produced and consumed */ + codec->mpd.consumed = 0; + codec->mpd.produced = 0; + + comp_dbg(dev, "cadence_codec_process() done"); + + return 0; +} + +static int cadence_codec_reset(struct processing_module *mod) +{ + struct module_data *codec = &mod->priv; + + codec->mpd.init_done = 0; + + return 0; +} + +static bool cadence_is_ready_to_process(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct module_data *codec = &mod->priv; + + if (source_get_data_available(sources[0]) < codec->mpd.in_buff_size || + sink_get_free_size(sinks[0]) < codec->mpd.out_buff_size) + return false; + + return true; +} + +static int ipc4_cadence_codec_free(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + + ipc_msg_free(cd->msg); + + return cadence_codec_free(mod); +} + +static const struct module_interface cadence_codec_interface = { + .init = cadence_codec_init, + .prepare = cadence_codec_prepare, + .process = cadence_codec_process, + .set_configuration = cadence_codec_set_configuration, + .reset = cadence_codec_reset, + .free = ipc4_cadence_codec_free, + .is_ready_to_process = cadence_is_ready_to_process, +}; + +DECLARE_MODULE_ADAPTER(cadence_codec_interface, cadence_codec_uuid, cadence_codec_tr); +SOF_MODULE_INIT(cadence_codec, sys_comp_module_cadence_codec_interface_init); diff --git a/src/audio/module_adapter/module/dolby/dax.c b/src/audio/module_adapter/module/dolby/dax.c new file mode 100644 index 000000000000..984bd2c11680 --- /dev/null +++ b/src/audio/module_adapter/module/dolby/dax.c @@ -0,0 +1,976 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE +// +// Copyright(c) 2025 Dolby Laboratories. All rights reserved. +// +// Author: Jun Lai <jun.lai@dolby.com> +// + +#include <rtos/atomic.h> +#include <rtos/init.h> +#include <sof/audio/data_blob.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/compiler_attributes.h> + +#include "dax.h" + +LOG_MODULE_REGISTER(dolby_dax_audio_processing, CONFIG_SOF_LOG_LEVEL); +SOF_DEFINE_REG_UUID(dolby_dax_audio_processing); + +#define MAX_PARAMS_STR_BUFFER_SIZE 1536 +#define DAX_ENABLE_MASK 0x1 +#define DAX_PROFILE_MASK 0x2 +#define DAX_DEVICE_MASK 0x4 +#define DAX_CP_MASK 0x8 +#define DAX_VOLUME_MASK 0x10 +#define DAX_CTC_MASK 0x20 +#define DAX_PROCESSING_MASK 0x10000 +#define DAX_RESET_MASK 0x20000 +#define DAX_FREE_MASK 0x40000 + +#define DAX_SWITCH_ENABLE_CONTROL_ID 0 +#define DAX_SWITCH_CP_CONTROL_ID 1 +#define DAX_SWITCH_CTC_CONTROL_ID 2 +#define DAX_ENUM_PROFILE_CONTROL_ID 0 +#define DAX_ENUM_DEVICE_CONTROL_ID 1 + +enum dax_flag_opt_mode { + DAX_FLAG_READ = 0, + DAX_FLAG_SET, + DAX_FLAG_CLEAR, + DAX_FLAG_READ_AND_CLEAR, +}; + +static int32_t flag_process(struct dax_adapter_data *adapter_data, + uint32_t flag, + enum dax_flag_opt_mode opt_mode) +{ +#ifdef __ZEPHYR__ + int32_t bit = ffs(flag) - 1; + + switch (opt_mode) { + case DAX_FLAG_READ: + return atomic_test_bit(&adapter_data->proc_flags, bit); + case DAX_FLAG_SET: + atomic_set_bit(&adapter_data->proc_flags, bit); + break; + case DAX_FLAG_CLEAR: + atomic_clear_bit(&adapter_data->proc_flags, bit); + break; + case DAX_FLAG_READ_AND_CLEAR: + return atomic_test_and_clear_bit(&adapter_data->proc_flags, bit); + default: + break; + } +#else + /* Non-Zephyr builds run single-threaded (no DP mode), there is no synchronous problem */ + int32_t old_flags = atomic_read(&adapter_data->proc_flags); + + switch (opt_mode) { + case DAX_FLAG_READ: + return (old_flags & flag) != 0; + case DAX_FLAG_SET: + atomic_set(&adapter_data->proc_flags, old_flags | flag); + break; + case DAX_FLAG_CLEAR: + atomic_set(&adapter_data->proc_flags, old_flags & ~flag); + break; + case DAX_FLAG_READ_AND_CLEAR: + atomic_set(&adapter_data->proc_flags, old_flags & ~flag); + return (old_flags & flag) != 0; + default: + break; + } +#endif + return 0; +} + +static int itostr(int num, char *str) +{ + int index = 0, digit_count = 0; + int temp; + + if (num < 0) { + str[0] = '-'; + index = 1; + num = -num; + } + + if (num == 0) { + str[index] = '0'; + str[index + 1] = '\0'; + return index + 1; + } + + temp = num; + while (temp > 0) { + temp /= 10; + digit_count++; + } + + temp = index + digit_count - 1; + while (num > 0) { + str[temp] = (num % 10) + '0'; + num /= 10; + temp--; + } + + str[index + digit_count] = '\0'; + return index + digit_count; +} + +static const char *get_params_str(const void *val, uint32_t val_sz) +{ + static char params_str[MAX_PARAMS_STR_BUFFER_SIZE + 16]; + const int32_t *param_val = (const int32_t *)val; + const uint32_t param_sz = val_sz >> 2; + uint32_t offset = 0; + + for (uint32_t i = 0; i < param_sz && offset < MAX_PARAMS_STR_BUFFER_SIZE; i++) { + offset += itostr(param_val[i], params_str + offset); + params_str[offset] = ','; + offset++; + params_str[offset] = '\0'; + } + return ¶ms_str[0]; +} + +static int sof_to_dax_frame_fmt(enum sof_ipc_frame sof_frame_fmt) +{ + switch (sof_frame_fmt) { + case SOF_IPC_FRAME_S16_LE: + return DAX_FMT_SHORT_16; + case SOF_IPC_FRAME_S32_LE: + return DAX_FMT_INT; + case SOF_IPC_FRAME_FLOAT: + return DAX_FMT_FLOAT; + default: + return DAX_FMT_UNSUPPORTED; + } +} + +static int sof_to_dax_sample_rate(uint32_t rate) +{ + switch (rate) { + case 48000: + return rate; + default: + return DAX_RATE_UNSUPPORTED; + } +} + +static int sof_to_dax_channels(uint32_t channels) +{ + switch (channels) { + case 2: + case 6 /* 5.1 */: + case 8 /* 7.1 */: + return channels; + default: + return DAX_CHANNLES_UNSUPPORTED; + } +} + +static int sof_to_dax_buffer_layout(enum sof_ipc_buffer_format sof_buf_fmt) +{ + switch (sof_buf_fmt) { + case SOF_IPC_BUFFER_INTERLEAVED: + return DAX_BUFFER_LAYOUT_INTERLEAVED; + case SOF_IPC_BUFFER_NONINTERLEAVED: + return DAX_BUFFER_LAYOUT_NONINTERLEAVED; + default: + return DAX_BUFFER_LAYOUT_UNSUPPORTED; + } +} + +void dax_buffer_release(struct processing_module *mod, struct dax_buffer *dax_buff) +{ + if (dax_buff->addr) { + mod_free(mod, dax_buff->addr); + dax_buff->addr = NULL; + } + dax_buff->size = 0; + dax_buff->avail = 0; + dax_buff->free = 0; +} + +int dax_buffer_alloc(struct processing_module *mod, + struct dax_buffer *dax_buff, uint32_t bytes) +{ + dax_buffer_release(mod, dax_buff); + dax_buff->addr = mod_balloc(mod, bytes); + if (!dax_buff->addr) + dax_buff->addr = mod_zalloc(mod, bytes); + if (!dax_buff->addr) + return -ENOMEM; + + dax_buff->size = bytes; + dax_buff->avail = 0; + dax_buff->free = bytes; + return 0; +} + +/* After reading from buffer */ +static void dax_buffer_consume(struct dax_buffer *dax_buff, uint32_t bytes) +{ + uint8_t *buf = (uint8_t *)dax_buff->addr; + uint32_t copy_bytes; + + bytes = MIN(bytes, dax_buff->avail); + copy_bytes = dax_buff->avail - bytes; + for (int i = 0; i < copy_bytes; i++) + buf[i] = buf[bytes + i]; + dax_buff->avail = copy_bytes; + dax_buff->free = dax_buff->size - dax_buff->avail; +} + +/* After writing to buffer */ +static void dax_buffer_produce(struct dax_buffer *dax_buff, uint32_t bytes) +{ + dax_buff->avail += bytes; + dax_buff->avail = MIN(dax_buff->avail, dax_buff->size); + dax_buff->free = dax_buff->size - dax_buff->avail; +} + +static bool is_enabled(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + + return dax_ctx->enable && dax_ctx->p_dax; +} + +static int set_tuning_file(struct processing_module *mod, void *value, uint32_t size) +{ + int ret = 0; + struct comp_dev *dev = mod->dev; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + + if (dax_buffer_alloc(mod, &dax_ctx->tuning_file_buffer, size) != 0) { + comp_err(dev, "allocate %u bytes failed for tuning file", size); + ret = -ENOMEM; + } else { + memcpy_s(dax_ctx->tuning_file_buffer.addr, + dax_ctx->tuning_file_buffer.free, + value, + size); + } + + comp_info(dev, "allocated: tuning %u, ret %d", dax_ctx->tuning_file_buffer.size, ret); + return ret; +} + +static int set_enable(struct processing_module *mod, int32_t enable) +{ + int ret; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + + ret = dax_set_enable(enable, dax_ctx); + comp_info(mod->dev, "set dax enable %d, ret %d", enable, ret); + return ret; +} + +static int set_volume(struct processing_module *mod, int32_t abs_volume) +{ + int ret; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + + ret = dax_set_volume(abs_volume, dax_ctx); + comp_info(mod->dev, "set volume %d, ret %d", abs_volume, ret); + return ret; +} + +static int set_device(struct processing_module *mod, int32_t out_device) +{ + int ret; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + + ret = dax_set_device(out_device, dax_ctx); + comp_info(mod->dev, "set device %d, ret %d", out_device, ret); + return ret; +} + +static int set_crosstalk_cancellation_enable(struct processing_module *mod, int32_t enable) +{ + int ret; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + + ret = dax_set_ctc_enable(enable, dax_ctx); + comp_info(mod->dev, "set ctc enable %d, ret %d", enable, ret); + return ret; +} + +static int update_params_from_buffer(struct processing_module *mod, void *params, uint32_t size); + +static int set_profile(struct processing_module *mod, int32_t profile_id) +{ + int ret = -EINVAL; + struct comp_dev *dev = mod->dev; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + uint32_t params_sz = 0; + void *params; + + params = dax_find_params(DAX_PARAM_ID_PROFILE, profile_id, ¶ms_sz, dax_ctx); + if (params) + ret = update_params_from_buffer(mod, params, params_sz); + comp_info(dev, "switched to profile %d, ret %d", profile_id, ret); + return ret; +} + +static int set_tuning_device(struct processing_module *mod, int32_t tuning_device) +{ + int ret = -EINVAL; + struct comp_dev *dev = mod->dev; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + uint32_t params_sz = 0; + void *params; + + params = dax_find_params(DAX_PARAM_ID_TUNING_DEVICE, tuning_device, ¶ms_sz, dax_ctx); + if (params) + ret = update_params_from_buffer(mod, params, params_sz); + comp_info(dev, "switched to tuning device %d, ret %d", tuning_device, ret); + return ret; +} + +static int set_content_processing_enable(struct processing_module *mod, int32_t enable) +{ + int ret = -EINVAL; + struct comp_dev *dev = mod->dev; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + uint32_t params_sz = 0; + void *params; + + params = dax_find_params(DAX_PARAM_ID_CP_ENABLE, enable, ¶ms_sz, dax_ctx); + if (params) + ret = update_params_from_buffer(mod, params, params_sz); + comp_info(dev, "set content processing enable %d, ret %d", enable, ret); + return ret; +} + +static int dax_set_param_wrapper(struct processing_module *mod, + uint32_t id, void *value, uint32_t size) +{ + int ret = 0; + struct comp_dev *dev = mod->dev; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + int32_t tmp_val; + + switch (id) { + case DAX_PARAM_ID_TUNING_FILE: + set_tuning_file(mod, value, size); + break; + case DAX_PARAM_ID_ENABLE: + tmp_val = *((int32_t *)value); + tmp_val = !!tmp_val; + if (dax_ctx->enable != tmp_val) { + dax_ctx->enable = tmp_val; + flag_process(adapter_data, DAX_ENABLE_MASK, DAX_FLAG_SET); + } + break; + case DAX_PARAM_ID_ABSOLUTE_VOLUME: + dax_ctx->volume = *((int32_t *)value); + flag_process(adapter_data, DAX_VOLUME_MASK, DAX_FLAG_SET); + break; + case DAX_PARAM_ID_OUT_DEVICE: + tmp_val = *((int32_t *)value); + if (dax_ctx->out_device != tmp_val) { + dax_ctx->out_device = tmp_val; + flag_process(adapter_data, DAX_DEVICE_MASK, DAX_FLAG_SET); + } + break; + case DAX_PARAM_ID_PROFILE: + tmp_val = *((int32_t *)value); + if (dax_ctx->profile != tmp_val) { + dax_ctx->profile = tmp_val; + flag_process(adapter_data, DAX_PROFILE_MASK, DAX_FLAG_SET); + } + break; + case DAX_PARAM_ID_CP_ENABLE: + tmp_val = *((int32_t *)value); + tmp_val = !!tmp_val; + if (dax_ctx->content_processing_enable != tmp_val) { + dax_ctx->content_processing_enable = tmp_val; + flag_process(adapter_data, DAX_CP_MASK, DAX_FLAG_SET); + } + break; + case DAX_PARAM_ID_CTC_ENABLE: + tmp_val = *((int32_t *)value); + tmp_val = !!tmp_val; + if (dax_ctx->ctc_enable != tmp_val) { + dax_ctx->ctc_enable = tmp_val; + flag_process(adapter_data, DAX_CTC_MASK, DAX_FLAG_SET); + } + break; + case DAX_PARAM_ID_ENDPOINT: + if (dax_ctx->endpoint == *((int32_t *)value)) { + ret = update_params_from_buffer(mod, (uint8_t *)value + 4, size - 4); + comp_info(dev, "switched to endpoint %d, ret %d", dax_ctx->endpoint, ret); + } + break; + default: + ret = dax_set_param(id, (void *)(value), size, dax_ctx); + comp_info(dev, "dax_set_param: ret %d, id %#x, size %u, value %s", + ret, id, size >> 2, get_params_str(value, size)); + break; + } + + return ret; +} + +static int update_params_from_buffer(struct processing_module *mod, void *data, uint32_t data_size) +{ + struct comp_dev *dev = mod->dev; + struct module_param *param; + void *pos = data; + const uint32_t param_header_size = 8; + uint32_t param_data_size; + + for (uint32_t i = 0; i < data_size;) { + param = (struct module_param *)(pos); + if (param->size < param_header_size || + param->size > data_size - i || + (param->size & 0x03) != 0) { + comp_err(dev, "invalid param %#x, param size %u, pos %u", + param->id, param->size, i); + return -EINVAL; + } + + if (param->size > param_header_size) { + param_data_size = param->size - param_header_size; + dax_set_param_wrapper(mod, param->id, (void *)(param->data), + param_data_size); + } + + pos = (void *)((uint8_t *)(pos) + param->size); + i += param->size; + } + + return 0; +} + +static void check_and_update_settings(struct processing_module *mod) +{ + int ret; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + + /* ret equals to 0 mean a new creation or destruction of dax instance */ + ret = dax_check_and_update_instance(mod); + if (ret == 0) { + if (is_enabled(mod) /* A new creation */) { + /* set DAX_ENABLE_MASK bit to trigger the fully update of kcontrol values */ + flag_process(adapter_data, DAX_ENABLE_MASK, DAX_FLAG_SET); + } else if (!dax_ctx->p_dax /* A new destruction */) { + set_enable(mod, 0); + comp_info(mod->dev, "falling back to pass-through mode."); + } + } + + if (flag_process(adapter_data, DAX_ENABLE_MASK, DAX_FLAG_READ_AND_CLEAR)) { + set_enable(mod, dax_ctx->enable); + if (is_enabled(mod)) { + flag_process(adapter_data, DAX_DEVICE_MASK, DAX_FLAG_SET); + flag_process(adapter_data, DAX_VOLUME_MASK, DAX_FLAG_SET); + } + return; + } + + if (!is_enabled(mod)) + return; + + if (flag_process(adapter_data, DAX_DEVICE_MASK, DAX_FLAG_READ_AND_CLEAR)) { + set_device(mod, dax_ctx->out_device); + set_tuning_device(mod, dax_ctx->tuning_device); + flag_process(adapter_data, DAX_PROFILE_MASK, DAX_FLAG_SET); + return; + } + if (flag_process(adapter_data, DAX_CTC_MASK, DAX_FLAG_READ_AND_CLEAR)) { + set_crosstalk_cancellation_enable(mod, dax_ctx->ctc_enable); + flag_process(adapter_data, DAX_PROFILE_MASK, DAX_FLAG_SET); + return; + } + if (flag_process(adapter_data, DAX_PROFILE_MASK, DAX_FLAG_READ_AND_CLEAR)) { + set_profile(mod, dax_ctx->profile); + if (!dax_ctx->content_processing_enable) + flag_process(adapter_data, DAX_CP_MASK, DAX_FLAG_SET); + return; + } + if (flag_process(adapter_data, DAX_CP_MASK, DAX_FLAG_READ_AND_CLEAR)) { + set_content_processing_enable(mod, dax_ctx->content_processing_enable); + return; + } + if (flag_process(adapter_data, DAX_VOLUME_MASK, DAX_FLAG_READ_AND_CLEAR)) + set_volume(mod, dax_ctx->volume); +} + +static int sof_dax_reset(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx; + + /* dax instance will be established on prepare(), and destroyed on reset() */ + if (adapter_data) { + dax_ctx = &adapter_data->dax_ctx; + if (flag_process(adapter_data, DAX_PROCESSING_MASK, DAX_FLAG_READ)) { + flag_process(adapter_data, DAX_RESET_MASK, DAX_FLAG_SET); + } else { + dax_unregister_user(mod); + dax_buffer_release(mod, &dax_ctx->input_buffer); + dax_buffer_release(mod, &dax_ctx->output_buffer); + } + } + + return 0; +} + +static int sof_dax_free(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx; + + if (adapter_data) { + dax_ctx = &adapter_data->dax_ctx; + if (flag_process(adapter_data, DAX_PROCESSING_MASK, DAX_FLAG_READ)) { + flag_process(adapter_data, DAX_FREE_MASK, DAX_FLAG_SET); + } else { + sof_dax_reset(mod); + dax_buffer_release(mod, &dax_ctx->tuning_file_buffer); + mod_data_blob_handler_free(mod, dax_ctx->blob_handler); + dax_ctx->blob_handler = NULL; + mod_free(mod, adapter_data); + module_set_private_data(mod, NULL); + } + } + return 0; +} + +static void check_and_update_state(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + + if (!adapter_data) + return; + + if (flag_process(adapter_data, DAX_FREE_MASK, DAX_FLAG_READ_AND_CLEAR)) + sof_dax_free(mod); + else if (flag_process(adapter_data, DAX_RESET_MASK, DAX_FLAG_READ_AND_CLEAR)) + sof_dax_reset(mod); +} + +static int sof_dax_init(struct processing_module *mod) +{ + struct comp_dev *dev = mod->dev; + struct module_data *md = &mod->priv; + struct dax_adapter_data *adapter_data; + struct sof_dax *dax_ctx; + + md->private = mod_zalloc(mod, sizeof(struct dax_adapter_data)); + if (!md->private) { + comp_err(dev, "failed to allocate %u bytes for initialization", + sizeof(struct sof_dax)); + return -ENOMEM; + } + + adapter_data = module_get_private_data(mod); + adapter_data->comp_id = dev->ipc_config.id; + adapter_data->priority = DAX_USER_PRIORITY_DEFAULT; + dax_ctx = &adapter_data->dax_ctx; + dax_ctx->enable = 0; + dax_ctx->profile = 0; + dax_ctx->out_device = 0; + dax_ctx->ctc_enable = 1; + dax_ctx->content_processing_enable = 1; + dax_ctx->volume = 1 << 23; + dax_ctx->update_flags = 0; + + dax_ctx->blob_handler = mod_data_blob_handler_new(mod); + if (!dax_ctx->blob_handler) { + comp_err(dev, "create blob handler failed"); + mod_free(mod, adapter_data); + module_set_private_data(mod, NULL); + return -ENOMEM; + } + + dax_instance_manager_init(); + + return 0; +} + +static int check_media_format(struct processing_module *mod) +{ + int ret = 0; + struct comp_dev *dev = mod->dev; + struct comp_buffer *source = comp_dev_get_first_data_producer(dev); + struct comp_buffer *sink = comp_dev_get_first_data_consumer(dev); + const struct audio_stream *src_stream = &source->stream; + const struct audio_stream *sink_stream = &sink->stream; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + + if (audio_stream_get_frm_fmt(src_stream) != audio_stream_get_frm_fmt(sink_stream) || + sof_to_dax_frame_fmt(audio_stream_get_frm_fmt(src_stream)) == DAX_FMT_UNSUPPORTED) { + comp_err(dev, "unsupported format, source %d, sink %d", + audio_stream_get_frm_fmt(src_stream), + audio_stream_get_frm_fmt(sink_stream)); + ret = -EINVAL; + } + + if (audio_stream_get_rate(src_stream) != audio_stream_get_rate(sink_stream) || + sof_to_dax_sample_rate(audio_stream_get_rate(src_stream)) == DAX_RATE_UNSUPPORTED) { + comp_err(dev, "unsupported sample rate, source %d, sink %d", + audio_stream_get_rate(src_stream), audio_stream_get_rate(sink_stream)); + ret = -EINVAL; + } + + if (audio_stream_get_channels(sink_stream) != 2 || + sof_to_dax_channels(audio_stream_get_channels(src_stream)) == + DAX_CHANNLES_UNSUPPORTED) { + comp_err(dev, "unsupported number of channels, source %d, sink %d", + audio_stream_get_channels(src_stream), + audio_stream_get_channels(sink_stream)); + ret = -EINVAL; + } + + if (audio_stream_get_buffer_fmt(src_stream) != audio_stream_get_buffer_fmt(sink_stream) || + sof_to_dax_buffer_layout(audio_stream_get_buffer_fmt(src_stream)) == + DAX_BUFFER_LAYOUT_UNSUPPORTED) { + comp_err(dev, "unsupported buffer layout %d", + audio_stream_get_buffer_fmt(src_stream)); + ret = -EINVAL; + } + + if (ret != 0) + return ret; + + dax_ctx->input_media_format.data_format = + sof_to_dax_frame_fmt(audio_stream_get_frm_fmt(src_stream)); + dax_ctx->input_media_format.sampling_rate = + sof_to_dax_sample_rate(audio_stream_get_rate(src_stream)); + dax_ctx->input_media_format.num_channels = + sof_to_dax_channels(audio_stream_get_channels(src_stream)); + dax_ctx->input_media_format.layout = + sof_to_dax_buffer_layout(audio_stream_get_buffer_fmt(src_stream)); + dax_ctx->input_media_format.bytes_per_sample = audio_stream_sample_bytes(src_stream); + + dax_ctx->output_media_format.data_format = + sof_to_dax_frame_fmt(audio_stream_get_frm_fmt(sink_stream)); + dax_ctx->output_media_format.sampling_rate = + sof_to_dax_sample_rate(audio_stream_get_rate(sink_stream)); + dax_ctx->output_media_format.num_channels = + sof_to_dax_channels(audio_stream_get_channels(sink_stream)); + dax_ctx->output_media_format.layout = + sof_to_dax_buffer_layout(audio_stream_get_buffer_fmt(sink_stream)); + dax_ctx->output_media_format.bytes_per_sample = audio_stream_sample_bytes(sink_stream); + + comp_info(dev, "format %d, sample rate %d, channels %d, data format %d", + dax_ctx->input_media_format.data_format, + dax_ctx->input_media_format.sampling_rate, + dax_ctx->input_media_format.num_channels, + dax_ctx->input_media_format.data_format); + return 0; +} + +static int sof_dax_prepare(struct processing_module *mod, struct sof_source **sources, + int num_of_sources, struct sof_sink **sinks, int num_of_sinks) +{ + int ret; + struct comp_dev *dev = mod->dev; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + uint32_t ibs, obs; + + if (num_of_sources != 1 || num_of_sinks != 1) { + comp_err(dev, "unsupported number of buffers, in %d, out %d", + num_of_sources, num_of_sinks); + return -EINVAL; + } + + ret = check_media_format(mod); + if (ret != 0) + return ret; + + dax_ctx->sof_period_bytes = dev->frames * + dax_ctx->output_media_format.num_channels * + dax_ctx->output_media_format.bytes_per_sample; + dax_ctx->period_bytes = dax_query_period_frames(dax_ctx) * + dax_ctx->output_media_format.num_channels * + dax_ctx->output_media_format.bytes_per_sample; + dax_ctx->period_us = 1000000 * dax_ctx->period_bytes / + (dax_ctx->output_media_format.bytes_per_sample * + dax_ctx->output_media_format.num_channels * + dax_ctx->output_media_format.sampling_rate); + + ibs = (dax_query_period_frames(dax_ctx) + dev->frames) * + dax_ctx->input_media_format.num_channels * + dax_ctx->input_media_format.bytes_per_sample; + obs = dax_ctx->period_bytes + dax_ctx->sof_period_bytes; + if (dax_buffer_alloc(mod, &dax_ctx->input_buffer, ibs) != 0) { + comp_err(dev, "allocate %u bytes failed for input", ibs); + ret = -ENOMEM; + goto err; + } + if (dax_buffer_alloc(mod, &dax_ctx->output_buffer, obs) != 0) { + comp_err(dev, "allocate %u bytes failed for output", obs); + ret = -ENOMEM; + goto err; + } + memset(dax_ctx->output_buffer.addr, 0, dax_ctx->output_buffer.size); + dax_buffer_produce(&dax_ctx->output_buffer, dax_ctx->output_buffer.size); + comp_info(dev, "allocated: ibs %u, obs %u", ibs, obs); + + dax_register_user(mod); + dax_check_and_update_instance(mod); + + return 0; + +err: + dax_buffer_release(mod, &dax_ctx->input_buffer); + dax_buffer_release(mod, &dax_ctx->output_buffer); + return ret; +} + +static int sof_dax_process(struct processing_module *mod, struct sof_source **sources, + int num_of_sources, struct sof_sink **sinks, int num_of_sinks) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + struct sof_source *source = sources[0]; + struct sof_sink *sink = sinks[0]; + uint8_t *buf, *bufstart, *bufend, *dax_buf; + size_t bufsz; + struct dax_buffer *dax_input_buffer = &dax_ctx->input_buffer; + struct dax_buffer *dax_output_buffer = &dax_ctx->output_buffer; + uint32_t consumed_bytes, processed_bytes, produced_bytes; + + flag_process(adapter_data, DAX_PROCESSING_MASK, DAX_FLAG_SET); + + if (!adapter_data) { + comp_err(mod->dev, "invalid adapter data"); + return -EINVAL; + } + + /* source stream -> internal input buffer */ + consumed_bytes = MIN(source_get_data_available(source), dax_input_buffer->free); + source_get_data(source, consumed_bytes, (void *)&buf, (void *)&bufstart, &bufsz); + bufend = &bufstart[bufsz]; + dax_buf = (uint8_t *)(dax_input_buffer->addr); + cir_buf_copy(buf, bufstart, bufend, + dax_buf + dax_input_buffer->avail, + dax_buf, + dax_buf + dax_input_buffer->size, + consumed_bytes); + dax_buffer_produce(dax_input_buffer, consumed_bytes); + source_release_data(source, consumed_bytes); + + check_and_update_settings(mod); + + /* internal input buffer -> internal output buffer */ + processed_bytes = dax_process(dax_ctx); + dax_buffer_consume(dax_input_buffer, processed_bytes); + dax_buffer_produce(dax_output_buffer, processed_bytes); + + /* internal output buffer -> sink stream */ + produced_bytes = MIN(dax_output_buffer->avail, sink_get_free_size(sink)); + if (produced_bytes > 0) { + sink_get_buffer(sink, produced_bytes, (void *)&buf, (void *)&bufstart, &bufsz); + bufend = &bufstart[bufsz]; + dax_buf = (uint8_t *)(dax_output_buffer->addr); + cir_buf_copy(dax_buf, dax_buf, dax_buf + dax_output_buffer->size, + buf, bufstart, bufend, produced_bytes); + dax_buffer_consume(dax_output_buffer, produced_bytes); + sink_commit_buffer(sink, produced_bytes); + } + flag_process(adapter_data, DAX_PROCESSING_MASK, DAX_FLAG_CLEAR); + check_and_update_state(mod); + + return 0; +} + +static int sof_dax_set_configuration(struct processing_module *mod, uint32_t config_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, const uint8_t *fragment, + size_t fragment_size, + uint8_t *response, size_t response_size) +{ + int ret; + struct comp_dev *dev = mod->dev; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + int32_t dax_param_id = 0; + int32_t val; + + if (fragment_size == 0) + return 0; + +#if CONFIG_IPC_MAJOR_4 + const struct sof_ipc4_control_msg_payload *ctl = NULL; + + switch (config_id) { + case 0: /* IPC4_VOLUME */ + /* ipc4_peak_volume_config::target_volume */ + val = ((const int32_t *)fragment)[1]; + val = sat_int32(Q_SHIFT_RND((int64_t)val, 31, 23)); + dax_param_id = DAX_PARAM_ID_ABSOLUTE_VOLUME; + break; + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + ctl = (const struct sof_ipc4_control_msg_payload *)fragment; + if (ctl->num_elems != 1) + return -EINVAL; + + val = ctl->chanv[0].value; + switch (ctl->id) { + case DAX_SWITCH_ENABLE_CONTROL_ID: + dax_param_id = DAX_PARAM_ID_ENABLE; + break; + case DAX_SWITCH_CP_CONTROL_ID: + dax_param_id = DAX_PARAM_ID_CP_ENABLE; + break; + case DAX_SWITCH_CTC_CONTROL_ID: + dax_param_id = DAX_PARAM_ID_CTC_ENABLE; + break; + default: + comp_err(dev, "unknown switch control %d", ctl->id); + return -EINVAL; + } + break; + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + ctl = (const struct sof_ipc4_control_msg_payload *)fragment; + if (ctl->num_elems != 1) + return -EINVAL; + + val = ctl->chanv[0].value; + switch (ctl->id) { + case DAX_ENUM_PROFILE_CONTROL_ID: + dax_param_id = DAX_PARAM_ID_PROFILE; + break; + case DAX_ENUM_DEVICE_CONTROL_ID: + dax_param_id = DAX_PARAM_ID_OUT_DEVICE; + break; + default: + comp_err(dev, "unknown enum control %d", ctl->id); + return -EINVAL; + } + break; + default: + break; + } +#else + struct sof_ipc_ctrl_data *ctl = (struct sof_ipc_ctrl_data *)fragment; + + switch (ctl->cmd) { + case SOF_CTRL_CMD_VOLUME: + val = ctl->chanv[0].value; + dax_param_id = DAX_PARAM_ID_ABSOLUTE_VOLUME; + break; + case SOF_CTRL_CMD_SWITCH: + if (ctl->num_elems != 1) + return -EINVAL; + + val = ctl->chanv[0].value; + switch (ctl->index) { + case DAX_SWITCH_ENABLE_CONTROL_ID: + dax_param_id = DAX_PARAM_ID_ENABLE; + break; + case DAX_SWITCH_CP_CONTROL_ID: + dax_param_id = DAX_PARAM_ID_CP_ENABLE; + break; + case DAX_SWITCH_CTC_CONTROL_ID: + dax_param_id = DAX_PARAM_ID_CTC_ENABLE; + break; + default: + comp_err(dev, "unknown switch control %d", ctl->index); + return -EINVAL; + } + break; + case SOF_CTRL_CMD_ENUM: + if (ctl->num_elems != 1) + return -EINVAL; + + val = ctl->chanv[0].value; + switch (ctl->index) { + case DAX_ENUM_PROFILE_CONTROL_ID: + dax_param_id = DAX_PARAM_ID_PROFILE; + break; + case DAX_ENUM_DEVICE_CONTROL_ID: + dax_param_id = DAX_PARAM_ID_OUT_DEVICE; + break; + default: + comp_err(dev, "unknown enum control %d", ctl->index); + return -EINVAL; + } + break; + default: + break; + } +#endif + + if (dax_param_id == 0) { + ret = comp_data_blob_set(dax_ctx->blob_handler, pos, + data_offset_size, fragment, fragment_size); + if (ret == 0 && (pos == MODULE_CFG_FRAGMENT_LAST || + pos == MODULE_CFG_FRAGMENT_SINGLE)) { + void *data = NULL; + size_t data_size = 0; + + data = comp_get_data_blob(dax_ctx->blob_handler, &data_size, NULL); + if (data && data_size > 0) + update_params_from_buffer(mod, data, data_size); + } + } else { + ret = dax_set_param_wrapper(mod, dax_param_id, &val, sizeof(val)); + } + return ret; +} + +static const struct module_interface dolby_dax_audio_processing_interface = { + .init = sof_dax_init, + .prepare = sof_dax_prepare, + .process = sof_dax_process, + .set_configuration = sof_dax_set_configuration, + .reset = sof_dax_reset, + .free = sof_dax_free, +}; + +#if CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING_MODULE +/* modular: llext dynamic link */ + +#include <module/module/api_ver.h> +#include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> + +static const struct sof_man_module_manifest main_manifest __section(".module") __used = { + .module = { + .name = "DAX", + .uuid = SOF_REG_UUID(dolby_dax_audio_processing), + .entry_point = (uint32_t)(&dolby_dax_audio_processing_interface), + .instance_max_count = DAX_MAX_INSTANCE, + .type = { + .load_type = SOF_MAN_MOD_TYPE_LLEXT, + .domain_dp = 1, + }, + .affinity_mask = 7, + } +}; + +SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_TR_CTX(dolby_dax_audio_processing_tr, SOF_UUID(dolby_dax_audio_processing_uuid), + LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(dolby_dax_audio_processing_interface, dolby_dax_audio_processing_uuid, + dolby_dax_audio_processing_tr); +SOF_MODULE_INIT(dolby_dax_audio_processing, + sys_comp_module_dolby_dax_audio_processing_interface_init); + +#endif diff --git a/src/audio/module_adapter/module/dolby/dax.h b/src/audio/module_adapter/module/dolby/dax.h new file mode 100644 index 000000000000..da0419fa3766 --- /dev/null +++ b/src/audio/module_adapter/module/dolby/dax.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE + * + * Copyright(c) 2025 Dolby Laboratories. All rights reserved. + * + * Author: Jun Lai <jun.lai@dolby.com> + */ + +#include <sof/audio/module_adapter/module/generic.h> +#include <dax_inf.h> + +#define DAX_USER_ID_INVALID 0 +#define DAX_MAX_INSTANCE 2 + +enum dax_user_priority { + DAX_USER_PRIORITY_DEFAULT = 0, + DAX_USER_PRIORITY_P0 = 0, + DAX_USER_PRIORITY_P1 = 1, /* Highest priority */ +}; + +struct dax_adapter_data { + struct sof_dax dax_ctx; + atomic_t proc_flags; + uint32_t comp_id; + int32_t priority; +}; + +/** + * @brief Release memory used by a DAX buffer. + * + * @param[in] mod Pointer to the processing module. + * @param[in,out] dax_buff Pointer to the DAX buffer to release. + */ +void dax_buffer_release(struct processing_module *mod, struct dax_buffer *dax_buff); + +/** + * @brief Allocate memory for a DAX buffer. + * + * @param[in] mod Pointer to the processing module. + * @param[in,out] dax_buff Pointer to the DAX buffer to allocate. + * @param[in] bytes Number of bytes to allocate. + * + * @return 0 on success, negative error code on failure. + */ +int dax_buffer_alloc(struct processing_module *mod, struct dax_buffer *dax_buff, uint32_t bytes); + +/** + * @brief Initialize global DAX instance manager state. + */ +void dax_instance_manager_init(void); + +/** + * @brief Register the current module as a DAX instance user. + * + * @param[in] mod Pointer to the processing module. + * + * @return 0 on success, negative error code on failure. + */ +int dax_register_user(struct processing_module *mod); + +/** + * @brief Unregister the current module from DAX instance user management. + * + * @param[in] mod Pointer to the processing module. + * + * @return 0 on success, negative error code on failure. + */ +int dax_unregister_user(struct processing_module *mod); + +/** + * @brief Reconcile DAX instance allocation based on user priority. + * + * @param[in] mod Pointer to the processing module. + * + * @return 0 on success, negative error code on failure. + */ +int dax_check_and_update_instance(struct processing_module *mod); diff --git a/src/audio/module_adapter/module/dolby/dax.toml b/src/audio/module_adapter/module/dolby/dax.toml new file mode 100644 index 000000000000..e57f29c8c792 --- /dev/null +++ b/src/audio/module_adapter/module/dolby/dax.toml @@ -0,0 +1,25 @@ +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + + REM # DAX module config + [[module.entry]] + name = "DAX" + uuid = "40F66C8B-5AA5-4345-8919-53EC431AAA98" + affinity_mask = "0x7" + instance_count = "2" + domain_types = "1" + load_type = LOAD_TYPE + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + REM # see struct fw_pin_description + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0x400, 0x8, 0x8, 0x4404] + + REM # see struct sof_man_mod_config + REM # 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, 135000000, 1024, 1024, 0, 675000, 0] + + index = __COUNTER__ diff --git a/src/audio/module_adapter/module/dolby/dax_instance_manager.c b/src/audio/module_adapter/module/dolby/dax_instance_manager.c new file mode 100644 index 000000000000..36ef4f052757 --- /dev/null +++ b/src/audio/module_adapter/module/dolby/dax_instance_manager.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE +// +// Copyright(c) 2026 Dolby Laboratories. All rights reserved. +// +// Author: Jun Lai <jun.lai@dolby.com> +// + +#include <stdbool.h> + +#include <rtos/spinlock.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/compiler_attributes.h> + +#include "dax.h" + +LOG_MODULE_DECLARE(dolby_dax_audio_processing, CONFIG_SOF_LOG_LEVEL); + +/* A DAX user refers to a DAX component, i.e., the processing_module + * object. When a DAX user intends to process audio data, it first needs + * to create a DAX instance. However, when multiple DAX users coexist + * in the system simultaneously, each DAX user will request its own DAX instance. + * Under limited memory resources, users that make later requests may fail to + * allocate the required memory. To address this, each DAX user is assigned a + * priority level, ensuring that higher-priority users are always granted + * instance resources first, regardless of the order in which the requests + * were made. + * + * The specific priority value will be automatically assigned in the dax_register_user + * function based on the configuration of the DAX component. + */ +struct dax_user { + uint32_t id; /* Component ID */ + enum dax_user_priority priority; + bool allocated; /* Whether the instance memory has been allocated */ +}; + +struct dax_instance_manager { + struct dax_user users[DAX_MAX_INSTANCE]; + + /* The maximum count of DAX instances that can be allocated simultaneously, + * determined by the system memory resource + */ + int32_t available_inst_cnt; + + struct k_spinlock lock; + bool initialized; +}; + +static struct dax_instance_manager inst_mgr; + +static void update_alloc_state_l(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + struct dax_user *user = NULL; + + for (int i = 0; i < DAX_MAX_INSTANCE; i++) { + if (inst_mgr.users[i].id == adapter_data->comp_id) { + user = &inst_mgr.users[i]; + break; + } + } + + if (!user) + return; + + if (dax_ctx->p_dax && dax_ctx->persist_buffer.addr && dax_ctx->scratch_buffer.addr) + user->allocated = true; + else + user->allocated = false; +} + +static int destroy_instance(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + + if (!dax_ctx->p_dax) + return -EFAULT; + + /* free internal dax instance data and set dax_ctx->p_dax to NULL */ + dax_free(dax_ctx); + dax_buffer_release(mod, &dax_ctx->persist_buffer); + dax_buffer_release(mod, &dax_ctx->scratch_buffer); + comp_info(mod->dev, "freed instance"); + + return 0; +} + +static int establish_instance(struct processing_module *mod) +{ + int ret; + struct comp_dev *dev = mod->dev; + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + uint32_t persist_sz; + uint32_t scratch_sz; + + if (dax_ctx->p_dax && dax_ctx->persist_buffer.addr && dax_ctx->scratch_buffer.addr) + return -EEXIST; + + if (dax_ctx->persist_buffer.addr || dax_ctx->scratch_buffer.addr) + destroy_instance(mod); + + persist_sz = dax_query_persist_memory(dax_ctx); + if (dax_buffer_alloc(mod, &dax_ctx->persist_buffer, persist_sz) != 0) { + comp_err(dev, "allocate %u bytes failed for persist", persist_sz); + ret = -ENOMEM; + goto err; + } + scratch_sz = dax_query_scratch_memory(dax_ctx); + if (dax_buffer_alloc(mod, &dax_ctx->scratch_buffer, scratch_sz) != 0) { + comp_err(dev, "allocate %u bytes failed for scratch", scratch_sz); + ret = -ENOMEM; + goto err; + } + ret = dax_init(dax_ctx); + if (ret != 0) { + comp_err(dev, "dax instance initialization failed, ret %d", ret); + goto err; + } + + comp_info(dev, "allocated: persist %u, scratch %u. version: %s", + persist_sz, scratch_sz, dax_get_version()); + return 0; + +err: + destroy_instance(mod); + return ret; +} + +static bool check_priority_l(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct dax_user *user = NULL; + int32_t allocated_cnt = 0; + + for (int i = 0; i < DAX_MAX_INSTANCE; i++) { + if (inst_mgr.users[i].id == adapter_data->comp_id) { + user = &inst_mgr.users[i]; + break; + } + } + + /* If the current module (user) is not existing in user manager, + * instance memory allocation is not allowed. + */ + if (!user) + return false; + + for (int i = 0; i < DAX_MAX_INSTANCE; i++) { + if (inst_mgr.users[i].priority > user->priority && !inst_mgr.users[i].allocated) + return false; + if (inst_mgr.users[i].allocated) + allocated_cnt++; + } + + /* Resource is exhausted */ + if (!user->allocated && allocated_cnt >= inst_mgr.available_inst_cnt) + return false; + + return true; +} + +void dax_instance_manager_init(void) +{ + if (!inst_mgr.initialized) { + k_spinlock_init(&inst_mgr.lock); + /* Assume memory source is sufficient for maximum instances at the beginning */ + inst_mgr.available_inst_cnt = DAX_MAX_INSTANCE; + inst_mgr.initialized = true; + } +} + +int dax_register_user(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + struct dax_user *user = NULL; + k_spinlock_key_t key; + + key = k_spin_lock(&inst_mgr.lock); + for (int i = 0; i < DAX_MAX_INSTANCE; i++) { + if (!user && inst_mgr.users[i].id == DAX_USER_ID_INVALID) + user = &inst_mgr.users[i]; + + if (inst_mgr.users[i].id == adapter_data->comp_id) { + k_spin_unlock(&inst_mgr.lock, key); + return -EEXIST; + } + } + + if (!user) { + k_spin_unlock(&inst_mgr.lock, key); + return -ENOSPC; + } + + user->id = adapter_data->comp_id; + if (dax_ctx->out_device == DAX_DEVICE_SPEAKER) { + /* If the current component's output device is a speaker, it is assigned + * the highest priority. + */ + user->priority = DAX_USER_PRIORITY_P1; + } else if (dax_ctx->out_device == DAX_DEVICE_HEADPHONE) { + user->priority = DAX_USER_PRIORITY_P0; + } else { + user->priority = DAX_USER_PRIORITY_DEFAULT; + } + adapter_data->priority = user->priority; + + if (dax_ctx->p_dax && dax_ctx->persist_buffer.addr && dax_ctx->scratch_buffer.addr) + user->allocated = true; + else + user->allocated = false; + + k_spin_unlock(&inst_mgr.lock, key); + + comp_info(mod->dev, "added user %#x, priority %d", + adapter_data->comp_id, adapter_data->priority); + return 0; +} + +int dax_unregister_user(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct dax_user *user = NULL; + k_spinlock_key_t key; + + key = k_spin_lock(&inst_mgr.lock); + for (int i = 0; i < DAX_MAX_INSTANCE; i++) { + if (inst_mgr.users[i].id == adapter_data->comp_id) { + user = &inst_mgr.users[i]; + break; + } + } + + if (!user) { + k_spin_unlock(&inst_mgr.lock, key); + return -EINVAL; + } + k_spin_unlock(&inst_mgr.lock, key); + + destroy_instance(mod); + adapter_data->priority = DAX_USER_PRIORITY_DEFAULT; + + key = k_spin_lock(&inst_mgr.lock); + user->id = DAX_USER_ID_INVALID; + user->priority = DAX_USER_PRIORITY_DEFAULT; + user->allocated = false; + k_spin_unlock(&inst_mgr.lock, key); + + comp_info(mod->dev, "removed user %#x", adapter_data->comp_id); + return 0; +} + +int dax_check_and_update_instance(struct processing_module *mod) +{ + k_spinlock_key_t key; + bool has_priority; + int ret = 0; + + key = k_spin_lock(&inst_mgr.lock); + /* Check whether any user that has higher priority is waiting for allocating instance + * memory (allocated == false), if is, current user should release its instance memory + * to make sure the higher priority user can allocate memory successfully. + */ + has_priority = check_priority_l(mod); + k_spin_unlock(&inst_mgr.lock, key); + + /* This section of logic do not need lock protection because + * it does not involve access to any shared resources. `has_priority` + * may be stale when using in if condition but it is OK, `update_alloc_state_l` + * will synchronize instance state which will be used in the next check phase. + */ + if (has_priority) + ret = establish_instance(mod); + else + ret = destroy_instance(mod); + + key = k_spin_lock(&inst_mgr.lock); + update_alloc_state_l(mod); + + /* Auto detect and update the available memory count */ + if (ret == -ENOMEM) { + inst_mgr.available_inst_cnt = 0; + for (int i = 0; i < DAX_MAX_INSTANCE; i++) { + if (inst_mgr.users[i].id != DAX_USER_ID_INVALID && + inst_mgr.users[i].allocated) { + inst_mgr.available_inst_cnt++; + } + } + } + k_spin_unlock(&inst_mgr.lock, key); + return ret; +} diff --git a/src/audio/module_adapter/module/dolby/dax_mock.c b/src/audio/module_adapter/module/dolby/dax_mock.c new file mode 100644 index 000000000000..c8889699a7e8 --- /dev/null +++ b/src/audio/module_adapter/module/dolby/dax_mock.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE +// +// Copyright(c) 2025 Dolby Laboratories. All rights reserved. +// +// Author: Jun Lai <jun.lai@dolby.com> +// + +#include <dax_inf.h> +#include <rtos/string.h> + +#define PLACEHOLDER_BUF_SZ 8 + +uint32_t dax_query_persist_memory(struct sof_dax *dax_ctx) +{ + return PLACEHOLDER_BUF_SZ; +} + +uint32_t dax_query_scratch_memory(struct sof_dax *dax_ctx) +{ + return PLACEHOLDER_BUF_SZ; +} + +uint32_t dax_query_period_frames(struct sof_dax *dax_ctx) +{ + return 256; +} + +int dax_free(struct sof_dax *dax_ctx) +{ + return 0; +} + +int dax_init(struct sof_dax *dax_ctx) +{ + return 0; +} + +int dax_process(struct sof_dax *dax_ctx) +{ + uint32_t peroid_bytes = dax_query_period_frames(dax_ctx) * + dax_ctx->input_media_format.num_channels * + dax_ctx->input_media_format.bytes_per_sample; + + if (dax_ctx->input_buffer.avail < peroid_bytes || + dax_ctx->output_buffer.free < peroid_bytes) { + return 0; + } + memcpy_s((uint8_t *)dax_ctx->output_buffer.addr + dax_ctx->output_buffer.avail, + dax_ctx->output_buffer.free, + dax_ctx->input_buffer.addr, + peroid_bytes); + return peroid_bytes; +} + +int dax_set_param(uint32_t id, const void *val, uint32_t val_sz, struct sof_dax *dax_ctx) +{ + return 0; +} + +int dax_set_enable(int32_t enable, struct sof_dax *dax_ctx) +{ + return 0; +} + +int dax_set_volume(int32_t pregain, struct sof_dax *dax_ctx) +{ + return 0; +} + +int dax_set_device(int32_t out_device, struct sof_dax *dax_ctx) +{ + return 0; +} + +int dax_set_ctc_enable(int32_t enable, struct sof_dax *dax_ctx) +{ + return 0; +} + +const char *dax_get_version(void) +{ + return ""; +} + +void *dax_find_params(uint32_t query_id, + int32_t query_val, + uint32_t *query_sz, + struct sof_dax *dax_ctx) +{ + return NULL; +} diff --git a/src/audio/module_adapter/module/dolby/llext-wrap.c b/src/audio/module_adapter/module/dolby/llext-wrap.c new file mode 100644 index 000000000000..30c7be24e22b --- /dev/null +++ b/src/audio/module_adapter/module/dolby/llext-wrap.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. + +#include <stdint.h> +#include <errno.h> +#include <assert.h> +#include <rtos/symbol.h> + +/* + * Stubs that are needed for linkage of some applications or libraries + * that come from porting userspace code. Anyone porting should + * make sure that any code does not depend on working copies of these + * reentrant functions. We will fail for any caller. + */ + +struct stat; +struct _reent; + +size_t _read_r(struct _reent *ptr, int fd, char *buf, size_t cnt) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +size_t _write_r(struct _reent *ptr, int fd, char *buf, size_t cnt) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +void *_sbrk_r(struct _reent *ptr, ptrdiff_t incr) +{ + errno = -ENOTSUP; + return NULL; +} + +int _lseek_r(struct _reent *ptr, int fd, int pos, int whence) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +int _kill_r(struct _reent *ptr, int pid, int sig) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +int _getpid_r(struct _reent *ptr) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +int _fstat_r(struct _reent *ptr, int fd, struct stat *pstat) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +int _close_r(struct _reent *ptr, int fd) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +void _exit(int status) +{ + assert(0); + while (1) { + /* spin forever */ + } + /* NOTREACHED */ +} diff --git a/src/audio/module_adapter/module/dolby/llext/CMakeLists.txt b/src/audio/module_adapter/module/dolby/llext/CMakeLists.txt new file mode 100644 index 000000000000..377373ddc5b5 --- /dev/null +++ b/src/audio/module_adapter/module/dolby/llext/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright(c) 2025 Dolby Laboratories. +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING_MOCK) + sof_llext_build("dolby_dax_audio_processing" + SOURCES ../dax.c + ../dax_instance_manager.c + ../dax_mock.c + INCLUDES ${sof_top_dir}/third_party/include + ) +else() + sof_llext_build("dolby_dax_audio_processing" + SOURCES ../dax.c ../dax_instance_manager.c ../llext-wrap.c + INCLUDES ${sof_top_dir}/third_party/include + LIBS_PATH ${sof_top_dir}/third_party/lib/ + LIBS dax m c gcc + ) +endif() diff --git a/src/audio/module_adapter/module/dolby/llext/llext.toml.h b/src/audio/module_adapter/module/dolby/llext/llext.toml.h new file mode 100644 index 000000000000..74f92b85fb81 --- /dev/null +++ b/src/audio/module_adapter/module/dolby/llext/llext.toml.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Dolby Laboratories. All rights reserved. + */ +#include <tools/rimage/config/platform.toml> +#define LOAD_TYPE "2" +#include "../dax.toml" + +[module] +count = __COUNTER__ diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 5f6dc96fe236..ee1b2df92829 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -12,8 +12,19 @@ */ #include <rtos/symbol.h> - +#include <rtos/mutex.h> +#include <sof/compiler_attributes.h> +#include <sof/objpool.h> #include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/data_blob.h> +#include <sof/lib/fast-get.h> +#include <sof/lib/vregion.h> +#include <sof/schedule/dp_schedule.h> +#if CONFIG_IPC_MAJOR_4 +#include <ipc4/header.h> +#include <ipc4/module.h> +#include <ipc4/pipeline.h> +#endif LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL); @@ -25,10 +36,10 @@ int module_load_config(struct comp_dev *dev, const void *cfg, size_t size) struct processing_module *mod = comp_mod(dev); struct module_data *md = &mod->priv; - comp_dbg(dev, "module_load_config() start"); + comp_dbg(dev, "entry"); if (!cfg || !size) { - comp_err(dev, "module_load_config(): wrong input params! dev %zx, cfg %zx size %zu", + comp_err(dev, "wrong input params! dev %zx, cfg %zx size %zu", (size_t)dev, (size_t)cfg, size); return -EINVAL; } @@ -37,16 +48,18 @@ int module_load_config(struct comp_dev *dev, const void *cfg, size_t size) if (!dst->data) { /* No space for config available yet, allocate now */ - dst->data = rballoc(0, SOF_MEM_CAPS_RAM, size); + dst->data = sof_heap_alloc(sof_sys_user_heap_get(), + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_LARGE_BUFFER, size, 0); } else if (dst->size != size) { /* The size allocated for previous config doesn't match the new one. * Free old container and allocate new one. */ - rfree(dst->data); - dst->data = rballoc(0, SOF_MEM_CAPS_RAM, size); + sof_heap_free(sof_sys_user_heap_get(), dst->data); + dst->data = sof_heap_alloc(sof_sys_user_heap_get(), + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_LARGE_BUFFER, size, 0); } if (!dst->data) { - comp_err(dev, "module_load_config(): failed to allocate space for setup config."); + comp_err(dev, "failed to allocate space for setup config."); return -ENOMEM; } @@ -57,18 +70,30 @@ int module_load_config(struct comp_dev *dev, const void *cfg, size_t size) dst->size = size; dst->avail = true; - comp_dbg(dev, "module_load_config() done"); + comp_dbg(dev, "done"); return ret; } +void mod_resource_init(struct processing_module *mod) +{ + struct module_resources *res = &mod->priv.resources; + + /* Init memory list */ + k_mutex_init(&res->lock); + list_init(&res->objpool.list); + res->objpool.heap = res->alloc->heap; + res->objpool.vreg = res->alloc->vreg; + res->heap_usage = 0; + res->heap_high_water_mark = 0; +} + int module_init(struct processing_module *mod) { int ret; - struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; const struct module_interface *const interface = dev->drv->adapter_ops; - comp_dbg(dev, "module_init() start"); + comp_dbg(dev, "entry"); #if CONFIG_IPC_MAJOR_3 if (mod->priv.state == MODULE_INITIALIZED) @@ -77,8 +102,7 @@ int module_init(struct processing_module *mod) return -EPERM; #endif if (!interface) { - comp_err(dev, "module_init(): module interface not defined for comp id %d", - dev_comp_id(dev)); + comp_err(dev, "module interface not defined"); return -EIO; } @@ -86,103 +110,439 @@ int module_init(struct processing_module *mod) if (!interface->init || (!!interface->process + !!interface->process_audio_stream + !!interface->process_raw_data < 1)) { - comp_err(dev, "module_init(): comp %d is missing mandatory interfaces", - dev_comp_id(dev)); + comp_err(dev, "comp is missing mandatory interfaces"); return -EIO; } - /* Init memory list */ - list_init(&md->memory.mem_list); - /* Now we can proceed with module specific initialization */ - ret = interface->init(mod); +#if CONFIG_SOF_USERSPACE_APPLICATION + if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) + ret = scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_INIT_INSTANCE, NULL); + else +#endif + ret = interface->init(mod); + if (ret) { - comp_err(dev, "module_init() error %d: module specific init failed, comp id %d", - ret, dev_comp_id(dev)); + comp_err(dev, "error %d: module specific init failed", ret); + mod_free_all(mod); return ret; } - comp_dbg(dev, "module_init() done"); + comp_dbg(dev, "done"); #if CONFIG_IPC_MAJOR_3 - md->state = MODULE_INITIALIZED; + mod->priv.state = MODULE_INITIALIZED; #endif return 0; } -void *module_allocate_memory(struct processing_module *mod, uint32_t size, uint32_t alignment) +static struct module_resource *container_get(struct processing_module *mod) { - struct comp_dev *dev = mod->dev; - struct module_memory *container; - void *ptr; + return objpool_alloc(&mod->priv.resources.objpool, sizeof(struct module_resource), 0); +} + +static void container_put(struct processing_module *mod, struct module_resource *container) +{ + objpool_free(&mod->priv.resources.objpool, container); +} + +#if CONFIG_USERSPACE +void mod_heap_info(struct processing_module *mod, size_t *size, uintptr_t *start) +{ + struct module_resources *res = &mod->priv.resources; + + if (res->alloc->vreg) { + vregion_mem_info(res->alloc->vreg, size, start); + } else if (res->alloc->heap) { + if (size) + *size = res->alloc->heap->heap.init_bytes; + + if (start) + *start = (uintptr_t)res->alloc->heap->heap.init_mem; + } +} +#endif + +/** + * Allocates aligned buffer memory block for module. + * @param mod Pointer to the module this memory block is allocated for. + * @param bytes Size in bytes. + * @param alignment Alignment in bytes. + * @return Pointer to the allocated memory or NULL if failed. + * + * The allocated memory is automatically freed when the module is + * unloaded. The back-end, rballoc(), always aligns the memory to + * PLATFORM_DCACHE_ALIGN at the minimum. + */ +void *z_impl_mod_balloc_align(struct processing_module *mod, size_t size, size_t alignment) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container; + + k_mutex_lock(&res->lock, K_FOREVER); + + container = container_get(mod); + if (!container) { + k_mutex_unlock(&res->lock); + return NULL; + } if (!size) { - comp_err(dev, "module_allocate_memory: requested allocation of 0 bytes."); + comp_err(mod->dev, "requested allocation of 0 bytes."); + container_put(mod, container); + k_mutex_unlock(&res->lock); + return NULL; + } + + /* Allocate buffer memory for module */ + void *ptr = sof_heap_alloc(res->alloc->heap, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_LARGE_BUFFER, + size, alignment); + + if (!ptr) { + comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.", + size, alignment, dev_comp_id(mod->dev)); + container_put(mod, container); + k_mutex_unlock(&res->lock); return NULL; } + /* Store reference to allocated memory */ + container->ptr = ptr; + container->size = size; + container->type = MOD_RES_HEAP; - /* Allocate memory container */ - container = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(struct module_memory)); + res->heap_usage += size; + if (res->heap_usage > res->heap_high_water_mark) + res->heap_high_water_mark = res->heap_usage; + + k_mutex_unlock(&res->lock); + return ptr; +} +EXPORT_SYMBOL(z_impl_mod_balloc_align); + +/** + * Allocates aligned memory block with flags for module. + * @param mod Pointer to the module this memory block is allocated for. + * @param flags Allocator flags. + * @param bytes Size in bytes. + * @param alignment Alignment in bytes. + * @return Pointer to the allocated memory or NULL if failed. + * + * The allocated memory is automatically freed when the module is unloaded. + */ +void *z_impl_mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size, + size_t alignment) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container; + + k_mutex_lock(&res->lock, K_FOREVER); + + container = container_get(mod); if (!container) { - comp_err(dev, "module_allocate_memory: failed to allocate memory container."); + k_mutex_unlock(&res->lock); + return NULL; + } + + if (!size) { + comp_err(mod->dev, "requested allocation of 0 bytes."); + container_put(mod, container); + k_mutex_unlock(&res->lock); return NULL; } /* Allocate memory for module */ - if (alignment) - ptr = rballoc_align(0, SOF_MEM_CAPS_RAM, size, alignment); - else - ptr = rballoc(0, SOF_MEM_CAPS_RAM, size); + void *ptr = sof_ctx_alloc(res->alloc, flags, size, alignment); if (!ptr) { - comp_err(dev, "module_allocate_memory: failed to allocate memory for comp %x.", - dev_comp_id(dev)); + comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.", + size, alignment, dev_comp_id(mod->dev)); + container_put(mod, container); + k_mutex_unlock(&res->lock); return NULL; } /* Store reference to allocated memory */ container->ptr = ptr; - list_item_prepend(&container->mem_list, &mod->priv.memory.mem_list); + container->size = size; + container->type = MOD_RES_HEAP; + res->heap_usage += size; + if (res->heap_usage > res->heap_high_water_mark) + res->heap_high_water_mark = res->heap_usage; + + k_mutex_unlock(&res->lock); return ptr; } +EXPORT_SYMBOL(z_impl_mod_alloc_ext); -int module_free_memory(struct processing_module *mod, void *ptr) +/** + * Creates a blob handler and releases it when the module is unloaded + * @param mod Pointer to module this memory block is allocated for. + * @return Pointer to the created data blob handler + * + * Like comp_data_blob_handler_new() but the handler is automatically freed. + */ +#if CONFIG_COMP_BLOB +struct comp_data_blob_handler *z_impl_mod_data_blob_handler_new(struct processing_module *mod) { - struct module_memory *mem; - struct list_item *mem_list; - struct list_item *_mem_list; + struct module_resources *res = &mod->priv.resources; + struct comp_data_blob_handler *bhp; + struct module_resource *container; - if (!ptr) - return 0; + k_mutex_lock(&res->lock, K_FOREVER); - /* Find which container keeps this memory */ - list_for_item_safe(mem_list, _mem_list, &mod->priv.memory.mem_list) { - mem = container_of(mem_list, struct module_memory, mem_list); - if (mem->ptr == ptr) { - rfree(mem->ptr); - list_item_del(&mem->mem_list); - rfree(mem); - return 0; - } + container = container_get(mod); + if (!container) { + k_mutex_unlock(&res->lock); + return NULL; + } + + bhp = comp_data_blob_handler_new_ext(mod->dev, false, NULL, NULL); + if (!bhp) { + container_put(mod, container); + k_mutex_unlock(&res->lock); + return NULL; + } + + container->bhp = bhp; + container->size = 0; + container->type = MOD_RES_BLOB_HANDLER; + + k_mutex_unlock(&res->lock); + return bhp; +} +EXPORT_SYMBOL(z_impl_mod_data_blob_handler_new); +#endif + +/** + * Make a module associated shared SRAM copy of DRAM read-only data. + * @param mod Pointer to module this copy is allocated for. + * @return Pointer to the SRAM copy. + * + * Like fast_get() but the handler is automatically freed. + */ +#if CONFIG_FAST_GET +const void *z_impl_mod_fast_get(struct processing_module *mod, const void * const dram_ptr, + size_t size) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container; + const void *ptr; + + k_mutex_lock(&res->lock, K_FOREVER); + + container = container_get(mod); + if (!container) { + k_mutex_unlock(&res->lock); + return NULL; } - comp_err(mod->dev, "module_free_memory: error: could not find memory pointed by %p", - ptr); + ptr = fast_get(res->alloc, dram_ptr, size); + if (!ptr) { + container_put(mod, container); + k_mutex_unlock(&res->lock); + return NULL; + } + container->sram_ptr = ptr; + container->size = 0; + container->type = MOD_RES_FAST_GET; + + k_mutex_unlock(&res->lock); + return ptr; +} +EXPORT_SYMBOL(z_impl_mod_fast_get); +#endif + +static int free_contents(struct processing_module *mod, struct module_resource *container) +{ + struct module_resources *res = &mod->priv.resources; +#if CONFIG_FAST_GET + struct k_mem_domain *mdom; +#endif + + switch (container->type) { + case MOD_RES_HEAP: + sof_ctx_free(res->alloc, container->ptr); + res->heap_usage -= container->size; + return 0; +#if CONFIG_COMP_BLOB + case MOD_RES_BLOB_HANDLER: + comp_data_blob_handler_free(container->bhp); + return 0; +#endif +#if CONFIG_FAST_GET + case MOD_RES_FAST_GET: +#if CONFIG_USERSPACE + mdom = mod->mdom; +#else + mdom = NULL; +#endif + fast_put(res->alloc, mdom, container->sram_ptr); + return 0; +#endif + default: + comp_err(mod->dev, "Unknown resource type: %d", container->type); + } return -EINVAL; } +struct mod_res_cb_arg { + struct processing_module *mod; + const void *ptr; +}; + +static bool mod_res_free(void *data, void *arg) +{ + struct mod_res_cb_arg *cb_arg = arg; + struct module_resource *container = data; + + if (cb_arg->ptr && container->ptr != cb_arg->ptr) + return false; + + int ret = free_contents(cb_arg->mod, container); + + if (ret < 0) + comp_err(cb_arg->mod->dev, "Cannot free allocation %p", cb_arg->ptr); + + container_put(cb_arg->mod, container); + + /* cb_arg->ptr == NULL means, that we're freeing all. Continue iterating */ + return !!cb_arg->ptr; +} + +/** + * Frees the memory block removes it from module's book keeping. + * @param mod Pointer to module this memory block was allocated for. + * @param ptr Pointer to the memory block. + */ +int z_impl_mod_free(struct processing_module *mod, const void *ptr) +{ + struct module_resources *res = &mod->priv.resources; + + if (!ptr) + return 0; + + /* Find which container holds this memory */ + struct mod_res_cb_arg cb_arg = {mod, ptr}; + + k_mutex_lock(&res->lock, K_FOREVER); + int ret = objpool_iterate(&res->objpool, mod_res_free, &cb_arg); + + k_mutex_unlock(&res->lock); + + if (ret < 0) + comp_err(mod->dev, "error: could not find memory pointed by %p", ptr); + + return ret; +} +EXPORT_SYMBOL(z_impl_mod_free); + +#ifdef CONFIG_USERSPACE +#include <zephyr/internal/syscall_handler.h> + +#if CONFIG_FAST_GET +const void *z_vrfy_mod_fast_get(struct processing_module *mod, const void * const dram_ptr, + size_t size) +{ + size_t h_size = 0; + uintptr_t h_start; + + K_OOPS(K_SYSCALL_MEMORY_WRITE(mod, sizeof(*mod))); + mod_heap_info(mod, &h_size, &h_start); + if (h_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE(h_start, h_size)); + K_OOPS(K_SYSCALL_MEMORY_READ(dram_ptr, size)); + + return z_impl_mod_fast_get(mod, dram_ptr, size); +} +#include <zephyr/syscalls/mod_fast_get_mrsh.c> +#endif + +void *z_vrfy_mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size, + size_t alignment) +{ + size_t h_size = 0; + uintptr_t h_start; + + K_OOPS(K_SYSCALL_MEMORY_WRITE(mod, sizeof(*mod))); + mod_heap_info(mod, &h_size, &h_start); + if (h_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE(h_start, h_size)); + + return z_impl_mod_alloc_ext(mod, flags, size, alignment); +} +#include <zephyr/syscalls/mod_alloc_ext_mrsh.c> + +void *z_vrfy_mod_balloc_align(struct processing_module *mod, size_t size, size_t alignment) +{ + size_t h_size = 0; + uintptr_t h_start; + + K_OOPS(K_SYSCALL_MEMORY_WRITE(mod, sizeof(*mod))); + mod_heap_info(mod, &h_size, &h_start); + if (h_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE(h_start, h_size)); + + return z_impl_mod_balloc_align(mod, size, alignment); +} +#include <zephyr/syscalls/mod_balloc_align_mrsh.c> + +int z_vrfy_mod_free(struct processing_module *mod, const void *ptr) +{ + size_t h_size = 0; + uintptr_t h_start; + + K_OOPS(K_SYSCALL_MEMORY_WRITE(mod, sizeof(*mod))); + mod_heap_info(mod, &h_size, &h_start); + if (h_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE(h_start, h_size)); + + return z_impl_mod_free(mod, ptr); +} +#include <zephyr/syscalls/mod_free_mrsh.c> + +#if CONFIG_COMP_BLOB +struct comp_data_blob_handler *z_vrfy_mod_data_blob_handler_new(struct processing_module *mod) +{ + size_t h_size = 0; + uintptr_t h_start; + + K_OOPS(K_SYSCALL_MEMORY_WRITE(mod, sizeof(*mod))); + mod_heap_info(mod, &h_size, &h_start); + if (h_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE(h_start, h_size)); + + return z_impl_mod_data_blob_handler_new(mod); +} +#include <zephyr/syscalls/mod_data_blob_handler_new_mrsh.c> +#endif +#endif + +#if CONFIG_COMP_BLOB +void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_blob_handler *dbh) +{ + mod_free(mod, (void *)dbh); +} +EXPORT_SYMBOL(mod_data_blob_handler_free); +#endif + +#if CONFIG_FAST_GET +void mod_fast_put(struct processing_module *mod, const void *sram_ptr) +{ + mod_free(mod, sram_ptr); +} +EXPORT_SYMBOL(mod_fast_put); +#endif + int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) { - int ret = 0; struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; const struct module_interface *const ops = dev->drv->adapter_ops; - comp_dbg(dev, "module_prepare() start"); + comp_dbg(dev, "entry"); #if CONFIG_IPC_MAJOR_3 if (mod->priv.state == MODULE_IDLE) @@ -191,10 +551,27 @@ int module_prepare(struct processing_module *mod, return -EPERM; #endif if (ops->prepare) { - ret = ops->prepare(mod, sources, num_of_sources, sinks, num_of_sinks); + int ret; + +#if CONFIG_SOF_USERSPACE_APPLICATION + if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { + const union scheduler_dp_thread_ipc_param param = { + .pipeline_state = { + .trigger_cmd = COMP_TRIGGER_PREPARE, + .state = SOF_IPC4_PIPELINE_STATE_RUNNING, + .n_sources = num_of_sources, + .sources = sources, + .n_sinks = num_of_sinks, + .sinks = sinks, + }, + }; + ret = scheduler_dp_thread_ipc(mod, SOF_IPC4_GLB_SET_PIPELINE_STATE, ¶m); + } else +#endif + ret = ops->prepare(mod, sources, num_of_sources, sinks, num_of_sinks); + if (ret) { - comp_err(dev, "module_prepare() error %d: module specific prepare failed, comp_id %d", - ret, dev_comp_id(dev)); + comp_err(dev, "error %d: module specific prepare failed", ret); return ret; } } @@ -203,7 +580,7 @@ int module_prepare(struct processing_module *mod, * as it has been applied during the procedure - it is safe to * free it. */ - rfree(md->cfg.data); + sof_heap_free(sof_sys_user_heap_get(), md->cfg.data); md->cfg.avail = false; md->cfg.data = NULL; @@ -211,9 +588,9 @@ int module_prepare(struct processing_module *mod, #if CONFIG_IPC_MAJOR_3 md->state = MODULE_IDLE; #endif - comp_dbg(dev, "module_prepare() done"); + comp_dbg(dev, "done"); - return ret; + return 0; } int module_process_legacy(struct processing_module *mod, @@ -225,14 +602,13 @@ int module_process_legacy(struct processing_module *mod, const struct module_interface *const ops = dev->drv->adapter_ops; int ret; - comp_dbg(dev, "module_process_legacy() start"); + comp_dbg(dev, "entry"); #if CONFIG_IPC_MAJOR_3 struct module_data *md = &mod->priv; if (md->state != MODULE_IDLE) { - comp_err(dev, "module_process(): wrong state of comp_id %x, state %d", - dev_comp_id(dev), md->state); + comp_err(dev, "wrong state %d", md->state); return -EPERM; } @@ -249,12 +625,11 @@ int module_process_legacy(struct processing_module *mod, ret = -EOPNOTSUPP; if (ret && ret != -ENOSPC && ret != -ENODATA) { - comp_err(dev, "module_process() error %d: for comp %d", - ret, dev_comp_id(dev)); + comp_err(dev, "error %d", ret); return ret; } - comp_dbg(dev, "module_process_legacy() done"); + comp_dbg(dev, "done"); #if CONFIG_IPC_MAJOR_3 /* reset state to idle */ @@ -272,13 +647,12 @@ int module_process_sink_src(struct processing_module *mod, const struct module_interface *const ops = dev->drv->adapter_ops; int ret; - comp_dbg(dev, "module_process sink src() start"); + comp_dbg(dev, "entry"); #if CONFIG_IPC_MAJOR_3 struct module_data *md = &mod->priv; if (md->state != MODULE_IDLE) { - comp_err(dev, "module_process(): wrong state of comp_id %x, state %d", - dev_comp_id(dev), md->state); + comp_err(dev, "wrong state %d", md->state); return -EPERM; } @@ -289,18 +663,17 @@ int module_process_sink_src(struct processing_module *mod, ret = ops->process(mod, sources, num_of_sources, sinks, num_of_sinks); if (ret && ret != -ENOSPC && ret != -ENODATA) { - comp_err(dev, "module_process() error %d: for comp %d", - ret, dev_comp_id(dev)); + comp_err(dev, "error %d", ret); return ret; } - comp_dbg(dev, "module_process sink src() done"); + comp_dbg(dev, "done"); #if CONFIG_IPC_MAJOR_3 /* reset state to idle */ md->state = MODULE_IDLE; #endif - return ret; + return 0; } int module_reset(struct processing_module *mod) @@ -314,23 +687,35 @@ int module_reset(struct processing_module *mod) if (md->state < MODULE_IDLE) return 0; #endif + /* cancel task if DP task*/ - if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP && mod->dev->task) + if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP && mod->dev->task && + !IS_ENABLED(CONFIG_SOF_USERSPACE_APPLICATION) && + !IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD)) schedule_task_cancel(mod->dev->task); + if (ops->reset) { - ret = ops->reset(mod); +#if CONFIG_SOF_USERSPACE_APPLICATION + if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { + const union scheduler_dp_thread_ipc_param param = { + .pipeline_state.trigger_cmd = COMP_TRIGGER_STOP, + }; + ret = scheduler_dp_thread_ipc(mod, SOF_IPC4_GLB_SET_PIPELINE_STATE, ¶m); + } else +#endif + ret = ops->reset(mod); + if (ret) { if (ret != PPL_STATUS_PATH_STOP) comp_err(mod->dev, - "module_reset() error %d: module specific reset() failed for comp %d", - ret, dev_comp_id(mod->dev)); + "error %d: module specific reset() failed", ret); return ret; } } md->cfg.avail = false; md->cfg.size = 0; - rfree(md->cfg.data); + sof_heap_free(sof_sys_user_heap_get(), md->cfg.data); md->cfg.data = NULL; #if CONFIG_IPC_MAJOR_3 @@ -343,19 +728,26 @@ int module_reset(struct processing_module *mod) return 0; } -void module_free_all_memory(struct processing_module *mod) +/** + * Frees all the resources registered for this module + * @param mod Pointer to module that should have its resource freed. + * + * This function is called automatically when the module is unloaded. + */ +void mod_free_all(struct processing_module *mod) { - struct module_memory *mem; - struct list_item *mem_list; - struct list_item *_mem_list; + struct module_resources *res = &mod->priv.resources; - /* Find which container keeps this memory */ - list_for_item_safe(mem_list, _mem_list, &mod->priv.memory.mem_list) { - mem = container_of(mem_list, struct module_memory, mem_list); - rfree(mem->ptr); - list_item_del(&mem->mem_list); - rfree(mem); - } + /* Free all contents found in used containers */ + struct mod_res_cb_arg cb_arg = {mod, NULL}; + + k_mutex_lock(&res->lock, K_FOREVER); + objpool_iterate(&res->objpool, mod_res_free, &cb_arg); + objpool_prune(&res->objpool); + k_mutex_unlock(&res->lock); + + /* Make sure resource lists and accounting are reset */ + mod_resource_init(mod); } int module_free(struct processing_module *mod) @@ -364,20 +756,20 @@ int module_free(struct processing_module *mod) struct module_data *md = &mod->priv; int ret = 0; - if (ops->free) { + if (ops->free && (mod->dev->ipc_config.proc_domain != COMP_PROCESSING_DOMAIN_DP || + !IS_ENABLED(CONFIG_SOF_USERSPACE_APPLICATION))) { ret = ops->free(mod); if (ret) - comp_warn(mod->dev, "module_free(): error: %d for %d", - ret, dev_comp_id(mod->dev)); + comp_warn(mod->dev, "error: %d", ret); } /* Free all memory shared by module_adapter & module */ md->cfg.avail = false; md->cfg.size = 0; - rfree(md->cfg.data); + sof_heap_free(sof_sys_user_heap_get(), md->cfg.data); md->cfg.data = NULL; if (md->runtime_params) { - rfree(md->runtime_params); + sof_heap_free(sof_sys_user_heap_get(), md->runtime_params); md->runtime_params = NULL; } #if CONFIG_IPC_MAJOR_3 @@ -430,23 +822,25 @@ int module_set_configuration(struct processing_module *mod, /* Check that there is no previous request in progress */ if (md->runtime_params) { - comp_err(dev, "module_set_configuration(): error: busy with previous request"); + comp_err(dev, "error: busy with previous request"); return -EBUSY; } if (!md->new_cfg_size) return 0; - if (md->new_cfg_size > MAX_BLOB_SIZE) { - comp_err(dev, "module_set_configuration(): error: blob size is too big cfg size %zu, allowed %d", - md->new_cfg_size, MAX_BLOB_SIZE); + if (md->new_cfg_size > CONFIG_MODULE_MAX_BLOB_SIZE) { + comp_err(dev, "error: blob size is too big cfg size %zu, allowed %d", + md->new_cfg_size, CONFIG_MODULE_MAX_BLOB_SIZE); return -EINVAL; } /* Allocate buffer for new params */ - md->runtime_params = rballoc(0, SOF_MEM_CAPS_RAM, md->new_cfg_size); + md->runtime_params = sof_heap_alloc(sof_sys_user_heap_get(), + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_LARGE_BUFFER, + md->new_cfg_size, 0); if (!md->runtime_params) { - comp_err(dev, "module_set_configuration(): space allocation for new params failed"); + comp_err(dev, "space allocation for new params failed"); return -ENOMEM; } @@ -454,7 +848,7 @@ int module_set_configuration(struct processing_module *mod, break; default: if (!md->runtime_params) { - comp_err(dev, "module_set_configuration(): error: no memory available for runtime params in consecutive load"); + comp_err(dev, "error: no memory available for runtime params in consecutive load"); return -EIO; } @@ -467,8 +861,7 @@ int module_set_configuration(struct processing_module *mod, ret = memcpy_s(dst, md->new_cfg_size - offset, fragment, fragment_size); if (ret < 0) { - comp_err(dev, "module_set_configuration(): error: %d failed to copy fragment", - ret); + comp_err(dev, "error: %d failed to copy fragment", ret); return ret; } @@ -479,36 +872,84 @@ int module_set_configuration(struct processing_module *mod, /* config fully copied, now load it */ ret = module_load_config(dev, md->runtime_params, md->new_cfg_size); if (ret) - comp_err(dev, "module_set_configuration(): error %d: config failed", ret); + comp_err(dev, "error %d: config failed", ret); else - comp_dbg(dev, "module_set_configuration(): config load successful"); + comp_dbg(dev, "config load successful"); md->new_cfg_size = 0; if (md->runtime_params) - rfree(md->runtime_params); + sof_heap_free(sof_sys_user_heap_get(), md->runtime_params); md->runtime_params = NULL; return ret; } EXPORT_SYMBOL(module_set_configuration); -int module_bind(struct processing_module *mod, void *data) +int module_bind(struct processing_module *mod, struct bind_info *bind_data) { + int ret; const struct module_interface *const ops = mod->dev->drv->adapter_ops; - if (ops->bind) - return ops->bind(mod, data); - return 0; + switch (bind_data->bind_type) { + case COMP_BIND_TYPE_SINK: + ret = sink_bind(bind_data->sink, mod); + break; + case COMP_BIND_TYPE_SOURCE: + ret = source_bind(bind_data->source, mod); + break; + default: + ret = -EINVAL; + } + if (ret) + return ret; + + if (ops->bind) { +#if CONFIG_SOF_USERSPACE_APPLICATION + if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { + const union scheduler_dp_thread_ipc_param param = { + .bind_data = bind_data, + }; + ret = scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_BIND, ¶m); + } else +#endif + ret = ops->bind(mod, bind_data); + } + + return ret; } -int module_unbind(struct processing_module *mod, void *data) +int module_unbind(struct processing_module *mod, struct bind_info *unbind_data) { + int ret; const struct module_interface *const ops = mod->dev->drv->adapter_ops; - if (ops->unbind) - return ops->unbind(mod, data); - return 0; + switch (unbind_data->bind_type) { + case COMP_BIND_TYPE_SINK: + ret = sink_unbind(unbind_data->sink); + break; + case COMP_BIND_TYPE_SOURCE: + ret = source_unbind(unbind_data->source); + break; + default: + ret = -EINVAL; + } + if (ret) + return ret; + + if (ops->unbind) { +#if CONFIG_SOF_USERSPACE_APPLICATION + if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { + const union scheduler_dp_thread_ipc_param param = { + .bind_data = unbind_data, + }; + ret = scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_UNBIND, ¶m); + } else +#endif + ret = ops->unbind(mod, unbind_data); + } + + return ret; } void module_update_buffer_position(struct input_stream_buffer *input_buffers, @@ -522,3 +963,26 @@ void module_update_buffer_position(struct input_stream_buffer *input_buffers, output_buffers->size += audio_stream_frame_bytes(sink) * frames; } EXPORT_SYMBOL(module_update_buffer_position); + +uint32_t module_get_deadline(struct processing_module *mod) +{ + uint32_t deadline; + + /* LL modules have no deadline - it is always "now" */ + if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) + return 0; + + /* startup condition - set deadline to "unknown" */ + if (mod->dp_startup_delay) + return UINT32_MAX / 2; + + deadline = UINT32_MAX; + /* calculate the shortest LFT for all sinks */ + for (size_t i = 0; i < mod->num_of_sinks; i++) { + uint32_t sink_lft = sink_get_last_feeding_time(mod->sinks[i]); + + deadline = MIN(deadline, sink_lft); + } + + return deadline; +} diff --git a/src/audio/module_adapter/module/modules.c b/src/audio/module_adapter/module/modules.c index 690f111fb0bc..589a25e33887 100644 --- a/src/audio/module_adapter/module/modules.c +++ b/src/audio/module_adapter/module/modules.c @@ -7,9 +7,9 @@ #include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/module_adapter/module/modules.h> +#include <rtos/userspace_helper.h> #include <utilities/array.h> #include <iadk_module_adapter.h> -#include <system_agent.h> #include <sof/lib_manager.h> #include <sof/audio/module_adapter/module/module_interface.h> @@ -43,7 +43,6 @@ LOG_MODULE_REGISTER(sof_modules, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(modules); -DECLARE_TR_CTX(intel_codec_tr, SOF_UUID(modules_uuid), LOG_LEVEL_INFO); /** * \brief modules_init. @@ -56,46 +55,16 @@ static int modules_init(struct processing_module *mod) { struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; - const struct comp_driver *const drv = dev->drv; const struct ipc4_base_module_cfg *src_cfg = &md->cfg.base_cfg; - const struct comp_ipc_config *config = &dev->ipc_config; - void *adapter; - int ret; - - uintptr_t module_entry_point = lib_manager_allocate_module(mod, config, src_cfg); - - if (module_entry_point == 0) { - comp_err(dev, "modules_init(), lib_manager_allocate_module() failed!"); - return -EINVAL; - } /* At this point module resources are allocated and it is moved to L2 memory. */ - comp_info(dev, "modules_init() start"); - - const uint32_t module_id = IPC4_MOD_ID(config->id); - const uint32_t instance_id = IPC4_INST_ID(config->id); - const uint32_t log_handle = (uint32_t)drv->tctx; - - byte_array_t mod_cfg = { - .data = (uint8_t *)md->cfg.init_data, - /* Intel modules expects DW size here */ - .size = md->cfg.size >> 2, - }; - - ret = system_agent_start(module_entry_point, module_id, instance_id, 0, log_handle, - &mod_cfg, &adapter); - if (ret) { - comp_info(dev, "System agent failed"); - return ret; - } - - module_set_private_data(mod, adapter); + comp_info(dev, "entry"); md->mpd.in_buff_size = src_cfg->ibs; md->mpd.out_buff_size = src_cfg->obs; mod->proc_type = MODULE_PROCESS_TYPE_SOURCE_SINK; - return iadk_wrapper_init(adapter); + return iadk_wrapper_init(module_get_private_data(mod)); } /** @@ -115,7 +84,7 @@ static int modules_prepare(struct processing_module *mod, { struct comp_dev *dev = mod->dev; - comp_info(dev, "modules_prepare()"); + comp_info(dev, "entry"); return iadk_wrapper_prepare(module_get_private_data(mod)); } @@ -140,15 +109,10 @@ static int modules_free(struct processing_module *mod) struct comp_dev *dev = mod->dev; int ret; - comp_info(dev, "modules_free()"); + comp_info(dev, "entry"); ret = iadk_wrapper_free(module_get_private_data(mod)); if (ret) - comp_err(dev, "modules_free(): iadk_wrapper_free failed with error: %d", ret); - - /* Free module resources allocated in L2 memory. */ - ret = lib_manager_free_module(dev->ipc_config.id); - if (ret < 0) - comp_err(dev, "modules_free(), lib_manager_free_module() failed!"); + comp_err(dev, "iadk_wrapper_free failed with error: %d", ret); return ret; } @@ -196,8 +160,8 @@ static int modules_get_configuration(struct processing_module *mod, uint32_t con size_t fragment_size) { return iadk_wrapper_get_configuration(module_get_private_data(mod), config_id, - MODULE_CFG_FRAGMENT_SINGLE, *data_offset_size, - fragment, fragment_size); + MODULE_CFG_FRAGMENT_SINGLE, data_offset_size, + fragment, &fragment_size); } /** @@ -237,7 +201,7 @@ static int modules_reset(struct processing_module *mod) } /* Processing Module Adapter API*/ -const struct module_interface processing_module_adapter_interface = { +APP_TASK_DATA const struct module_interface processing_module_adapter_interface = { .init = modules_init, .prepare = modules_prepare, .process = modules_process, diff --git a/src/audio/module_adapter/module/passthrough.c b/src/audio/module_adapter/module/passthrough.c index 1955e3bc487a..4a0a8eb2a655 100644 --- a/src/audio/module_adapter/module/passthrough.c +++ b/src/audio/module_adapter/module/passthrough.c @@ -12,11 +12,10 @@ LOG_MODULE_REGISTER(passthrough, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(passthrough); -DECLARE_TR_CTX(passthrough_tr, SOF_UUID(passthrough_uuid), LOG_LEVEL_INFO); static int passthrough_codec_init(struct processing_module *mod) { - comp_info(mod->dev, "passthrough_codec_init() start"); + comp_info(mod->dev, "entry"); return 0; } @@ -28,20 +27,20 @@ static int passthrough_codec_prepare(struct processing_module *mod, struct module_data *codec = &mod->priv; struct comp_buffer *source = comp_dev_get_first_data_producer(dev); - comp_info(dev, "passthrough_codec_prepare()"); + comp_info(dev, "entry"); mod->period_bytes = audio_stream_period_bytes(&source->stream, dev->frames); - codec->mpd.in_buff = rballoc(0, SOF_MEM_CAPS_RAM, mod->period_bytes); + codec->mpd.in_buff = rballoc(SOF_MEM_FLAG_USER, mod->period_bytes); if (!codec->mpd.in_buff) { - comp_err(dev, "passthrough_codec_prepare(): Failed to alloc in_buff"); + comp_err(dev, "Failed to alloc in_buff"); return -ENOMEM; } codec->mpd.in_buff_size = mod->period_bytes; - codec->mpd.out_buff = rballoc(0, SOF_MEM_CAPS_RAM, mod->period_bytes); + codec->mpd.out_buff = rballoc(SOF_MEM_FLAG_USER, mod->period_bytes); if (!codec->mpd.out_buff) { - comp_err(dev, "passthrough_codec_prepare(): Failed to alloc out_buff"); + comp_err(dev, "Failed to alloc out_buff"); rfree(codec->mpd.in_buff); return -ENOMEM; } @@ -55,7 +54,7 @@ static int passthrough_codec_init_process(struct processing_module *mod) struct module_data *codec = &mod->priv; struct comp_dev *dev = mod->dev; - comp_dbg(dev, "passthrough_codec_init_process()"); + comp_dbg(dev, "entry"); codec->mpd.produced = 0; codec->mpd.consumed = 0; @@ -64,38 +63,62 @@ static int passthrough_codec_init_process(struct processing_module *mod) return 0; } -static int -passthrough_codec_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) +static int passthrough_codec_process(struct processing_module *mod, + 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; + const void *src_ptr, *src_buf_start; + void *snk_ptr, *snk_buf_start; + size_t src_buf_size, snk_buf_size; + size_t n_bytes = codec->mpd.in_buff_size; + size_t size_to_wrap; + int err; + + comp_dbg(dev, "entry"); /* Proceed only if we have enough data to fill the module buffer completely */ - if (input_buffers[0].size < codec->mpd.in_buff_size) { - comp_dbg(dev, "passthrough_codec_process(): not enough data to process"); + if (source_get_data_available(sources[0]) < n_bytes) { + comp_dbg(dev, "not enough data to process"); return -ENODATA; } if (!codec->mpd.init_done) passthrough_codec_init_process(mod); - memcpy_s(codec->mpd.in_buff, codec->mpd.in_buff_size, - input_buffers[0].data, codec->mpd.in_buff_size); - - comp_dbg(dev, "passthrough_codec_process()"); - - memcpy_s(codec->mpd.out_buff, codec->mpd.out_buff_size, - codec->mpd.in_buff, codec->mpd.in_buff_size); - codec->mpd.produced = mod->period_bytes; - codec->mpd.consumed = mod->period_bytes; - input_buffers[0].consumed = codec->mpd.consumed; - - /* copy the produced samples into the output buffer */ - memcpy_s(output_buffers[0].data, codec->mpd.produced, codec->mpd.out_buff, - codec->mpd.produced); - output_buffers[0].size = codec->mpd.produced; + err = source_get_data(sources[0], n_bytes, &src_ptr, &src_buf_start, &src_buf_size); + if (err) + return err; + + /* src_buf_size is the total ring buffer size; handle wrap when copying to in_buff */ + size_to_wrap = (const uint8_t *)src_buf_start + src_buf_size - (const uint8_t *)src_ptr; + if (n_bytes <= size_to_wrap) { + memcpy_s(codec->mpd.in_buff, n_bytes, src_ptr, n_bytes); + } else { + memcpy_s(codec->mpd.in_buff, n_bytes, src_ptr, size_to_wrap); + memcpy_s((uint8_t *)codec->mpd.in_buff + size_to_wrap, n_bytes - size_to_wrap, + src_buf_start, n_bytes - size_to_wrap); + } + source_release_data(sources[0], n_bytes); + + memcpy_s(codec->mpd.out_buff, codec->mpd.out_buff_size, codec->mpd.in_buff, n_bytes); + + err = sink_get_buffer(sinks[0], n_bytes, &snk_ptr, &snk_buf_start, &snk_buf_size); + if (err) + return err; + + /* snk_buf_size is the total ring buffer size; handle wrap when copying from out_buff */ + size_to_wrap = (uint8_t *)snk_buf_start + snk_buf_size - (uint8_t *)snk_ptr; + if (n_bytes <= size_to_wrap) { + memcpy_s(snk_ptr, n_bytes, codec->mpd.out_buff, n_bytes); + } else { + memcpy_s(snk_ptr, n_bytes, codec->mpd.out_buff, size_to_wrap); + memcpy_s(snk_buf_start, n_bytes - size_to_wrap, + (const uint8_t *)codec->mpd.out_buff + size_to_wrap, + n_bytes - size_to_wrap); + } + sink_commit_buffer(sinks[0], n_bytes); return 0; } @@ -104,7 +127,7 @@ static int passthrough_codec_reset(struct processing_module *mod) { struct module_data *codec = &mod->priv; - comp_info(mod->dev, "passthrough_codec_reset()"); + comp_info(mod->dev, "entry"); rfree(codec->mpd.in_buff); rfree(codec->mpd.out_buff); @@ -113,7 +136,7 @@ static int passthrough_codec_reset(struct processing_module *mod) static int passthrough_codec_free(struct processing_module *mod) { - comp_info(mod->dev, "passthrough_codec_free()"); + comp_info(mod->dev, "entry"); /* Nothing to do */ return 0; @@ -122,10 +145,11 @@ static int passthrough_codec_free(struct processing_module *mod) static const struct module_interface passthrough_interface = { .init = passthrough_codec_init, .prepare = passthrough_codec_prepare, - .process_raw_data = passthrough_codec_process, + .process = passthrough_codec_process, .reset = passthrough_codec_reset, .free = passthrough_codec_free }; +DECLARE_TR_CTX(passthrough_tr, SOF_UUID(passthrough_uuid), LOG_LEVEL_INFO); DECLARE_MODULE_ADAPTER(passthrough_interface, passthrough_uuid, passthrough_tr); SOF_MODULE_INIT(passthrough, sys_comp_module_passthrough_interface_init); diff --git a/src/audio/module_adapter/module/waves/llext/CMakeLists.txt b/src/audio/module_adapter/module/waves/llext/CMakeLists.txt new file mode 100644 index 000000000000..63104b8d71a0 --- /dev/null +++ b/src/audio/module_adapter/module/waves/llext/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_WAVES_CODEC_STUB) +sof_llext_build("waves" + SOURCES ../waves.c + ../maxx_stub.c +) +else() +message(FATAL_ERROR "Add library linking support in src/audio/module_adapter/module/waves/llext/CMakeLists.txt") +endif() diff --git a/src/audio/module_adapter/module/waves/llext/llext.toml.h b/src/audio/module_adapter/module/waves/llext/llext.toml.h new file mode 100644 index 000000000000..af98b94af57d --- /dev/null +++ b/src/audio/module_adapter/module/waves/llext/llext.toml.h @@ -0,0 +1,6 @@ +#include <tools/rimage/config/platform.toml> +#define LOAD_TYPE "2" +#include "../waves.toml" + +[module] +count = __COUNTER__ diff --git a/src/audio/module_adapter/module/waves/waves.c b/src/audio/module_adapter/module/waves/waves.c index 8ea54c8e21ed..aa800b32f992 100644 --- a/src/audio/module_adapter/module/waves/waves.c +++ b/src/audio/module_adapter/module/waves/waves.c @@ -19,7 +19,8 @@ #define NUM_IO_STREAMS (1) SOF_DEFINE_REG_UUID(waves); -DECLARE_TR_CTX(waves_tr, SOF_UUID(waves_uuid), LOG_LEVEL_INFO); + +LOG_MODULE_REGISTER(waves, CONFIG_SOF_LOG_LEVEL); struct waves_codec_data { uint32_t sample_rate; @@ -41,6 +42,7 @@ struct waves_codec_data { void *response; uint32_t config_blob_size; void *config_blob; + bool initialized; }; enum waves_codec_params { @@ -188,25 +190,25 @@ static int waves_effect_allocate(struct processing_module *mod) struct waves_codec_data *waves_codec = codec->private; MaxxStatus_t status; - comp_dbg(dev, "waves_effect_allocate() start"); + comp_dbg(dev, "start"); status = MaxxEffect_GetEffectSize(&waves_codec->effect_size); if (status) { - comp_err(dev, "waves_effect_allocate() MaxxEffect_GetEffectSize returned %d", + comp_err(dev, "MaxxEffect_GetEffectSize returned %d", status); return -EINVAL; } - waves_codec->effect = (MaxxEffect_t *)module_allocate_memory(mod, + waves_codec->effect = (MaxxEffect_t *)mod_alloc_align(mod, waves_codec->effect_size, 16); if (!waves_codec->effect) { - comp_err(dev, "waves_effect_allocate() failed to allocate %d bytes for effect", + comp_err(dev, "failed to allocate %d bytes for effect", waves_codec->effect_size); return -ENOMEM; } - comp_dbg(dev, "waves_effect_allocate() allocated %d bytes for effect", + comp_dbg(dev, "allocated %d bytes for effect", waves_codec->effect_size); return 0; @@ -221,60 +223,66 @@ static int waves_effect_check(struct comp_dev *dev) const struct audio_stream *snk_fmt = &sink->stream; /* Init sink & source buffers */ - comp_dbg(dev, "waves_effect_check() start"); + comp_dbg(dev, "start"); + + if (!source || !sink) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } /* todo use fallback to comp_verify_params when ready */ /* resampling not supported */ 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", + comp_err(dev, "source %d sink %d rate mismatch", audio_stream_get_rate(src_fmt), audio_stream_get_rate(snk_fmt)); 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", + comp_err(dev, "source %d sink %d channels mismatch", audio_stream_get_channels(src_fmt), audio_stream_get_channels(snk_fmt)); 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", + comp_err(dev, "source %d sink %d sample format mismatch", audio_stream_get_frm_fmt(src_fmt), audio_stream_get_frm_fmt(snk_fmt)); 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"); + comp_err(dev, "source %d sink %d buffer format mismatch", + audio_stream_get_buffer_fmt(src_fmt), audio_stream_get_buffer_fmt(snk_fmt)); return -EINVAL; } if (!format_is_supported(audio_stream_get_frm_fmt(src_fmt))) { - comp_err(dev, "waves_effect_check() float samples not supported"); + comp_err(dev, "float samples not supported"); return -EINVAL; } if (!layout_is_supported(audio_stream_get_buffer_fmt(src_fmt))) { - comp_err(dev, "waves_effect_check() non interleaved format not supported"); + comp_err(dev, "non interleaved format not supported"); return -EINVAL; } if (!rate_is_supported(audio_stream_get_rate(src_fmt))) { - comp_err(dev, "waves_effect_check() rate %d not supported", + comp_err(dev, "rate %d not supported", audio_stream_get_rate(src_fmt)); return -EINVAL; } if (audio_stream_get_channels(src_fmt) != 2) { - comp_err(dev, "waves_effect_check() channels %d not supported", + comp_err(dev, "channels %d not supported", audio_stream_get_channels(src_fmt)); return -EINVAL; } - comp_dbg(dev, "waves_effect_check() done"); + comp_dbg(dev, "done"); return 0; } @@ -293,25 +301,25 @@ static int waves_effect_init(struct processing_module *mod) MaxxStreamFormat_t *i_formats[NUM_IO_STREAMS] = { &waves_codec->i_format }; MaxxStreamFormat_t *o_formats[NUM_IO_STREAMS] = { &waves_codec->o_format }; - comp_dbg(dev, "waves_effect_init() start"); + comp_dbg(dev, "start"); sample_format = format_convert_sof_to_me(audio_stream_get_frm_fmt(src_fmt)); if (sample_format < 0) { - comp_err(dev, "waves_effect_init() sof sample format %d not supported", + comp_err(dev, "sof sample format %d not supported", audio_stream_get_frm_fmt(src_fmt)); 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", + comp_err(dev, "sof buffer format %d not supported", audio_stream_get_buffer_fmt(src_fmt)); 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", + comp_err(dev, "sample_format %d not supported", sample_format); return -EINVAL; } @@ -337,21 +345,22 @@ static int waves_effect_init(struct processing_module *mod) // trace allows printing only up-to 4 words at a time // logging all the information in two calls - comp_info(dev, "waves_effect_init() rate %d, channels %d", waves_codec->i_format.sampleRate, + comp_info(dev, "rate %d, channels %d", waves_codec->i_format.sampleRate, waves_codec->i_format.numChannels); - comp_info(dev, "waves_effect_init() format %d, layout %d, frame %d", + comp_info(dev, "format %d, layout %d, frame %d", waves_codec->i_format.samplesFormat, waves_codec->i_format.samplesLayout, waves_codec->buffer_samples); status = MaxxEffect_Initialize(waves_codec->effect, i_formats, 1, o_formats, 1); if (status) { - comp_err(dev, "waves_effect_init() MaxxEffect_Initialize returned %d", status); + comp_err(dev, "MaxxEffect_Initialize returned %d", status); return -EINVAL; } + waves_codec->initialized = true; - comp_dbg(dev, "waves_effect_init() done"); + comp_dbg(dev, "done"); return 0; } @@ -364,19 +373,19 @@ static int waves_effect_buffers(struct processing_module *mod) int ret; void *i_buffer = NULL, *o_buffer = NULL; - comp_dbg(dev, "waves_effect_buffers() start"); + comp_dbg(dev, "start"); - i_buffer = module_allocate_memory(mod, waves_codec->buffer_bytes, 16); + i_buffer = mod_alloc_align(mod, waves_codec->buffer_bytes, 16); if (!i_buffer) { - comp_err(dev, "waves_effect_buffers() failed to allocate %d bytes for i_buffer", + comp_err(dev, "failed to allocate %d bytes for i_buffer", waves_codec->buffer_bytes); ret = -ENOMEM; goto err; } - o_buffer = module_allocate_memory(mod, waves_codec->buffer_bytes, 16); + o_buffer = mod_alloc_align(mod, waves_codec->buffer_bytes, 16); if (!o_buffer) { - comp_err(dev, "waves_effect_buffers() failed to allocate %d bytes for o_buffer", + comp_err(dev, "failed to allocate %d bytes for o_buffer", waves_codec->buffer_bytes); ret = -ENOMEM; goto err; @@ -389,17 +398,17 @@ static int waves_effect_buffers(struct processing_module *mod) codec->mpd.out_buff = waves_codec->o_buffer; codec->mpd.out_buff_size = waves_codec->buffer_bytes; - comp_dbg(dev, "waves_effect_buffers() in_buff_size %d, out_buff_size %d", + comp_dbg(dev, "in_buff_size %d, out_buff_size %d", codec->mpd.in_buff_size, codec->mpd.out_buff_size); - comp_dbg(dev, "waves_effect_buffers() done"); + comp_dbg(dev, "done"); return 0; err: if (i_buffer) - module_free_memory(mod, i_buffer); + mod_free(mod, i_buffer); if (o_buffer) - module_free_memory(mod, o_buffer); + mod_free(mod, o_buffer); return ret; } @@ -413,12 +422,12 @@ static int waves_effect_revision(struct processing_module *mod) uint32_t revision_len; MaxxStatus_t status; - comp_info(dev, "waves_effect_revision() start"); + comp_info(dev, "start"); status = MaxxEffect_Revision_Get(waves_codec->effect, &revision, &revision_len); if (status) { - comp_err(dev, "waves_effect_revision() MaxxEffect_Revision_Get returned %d", + comp_err(dev, "MaxxEffect_Revision_Get returned %d", status); return -EINVAL; } @@ -448,7 +457,7 @@ static int waves_effect_revision(struct processing_module *mod) } #endif - comp_info(dev, "waves_effect_revision() done"); + comp_info(dev, "done"); return 0; } @@ -460,21 +469,21 @@ static int waves_effect_save_config_blob_to_cache(struct processing_module *mod, struct module_data *codec = &mod->priv; struct waves_codec_data *waves_codec = codec->private; - comp_info(dev, "waves_effect_save_config_blob_to_cache() start"); + comp_info(dev, "start"); /* release old cached config blob*/ if (waves_codec->config_blob && size != waves_codec->config_blob_size) { - comp_info(dev, "waves_effect_save_config_blob_to_cache() release blob"); - module_free_memory(mod, waves_codec->config_blob); + comp_info(dev, "release blob"); + mod_free(mod, waves_codec->config_blob); waves_codec->config_blob = NULL; waves_codec->config_blob_size = 0; } if (!waves_codec->config_blob) { - waves_codec->config_blob = module_allocate_memory(mod, size, 16); + waves_codec->config_blob = mod_alloc_align(mod, size, 16); if (!waves_codec->config_blob) { comp_err(dev, - "waves_effect_save_config_blob_to_cache() failed to allocate %d bytes for config blob", + "failed to allocate %d bytes for config blob", size); return -ENOMEM; } @@ -485,15 +494,15 @@ static int waves_effect_save_config_blob_to_cache(struct processing_module *mod, data, size); if (ret) { comp_err(dev, - "waves_effect_save_config_blob_to_cache(): failed to copy config blob %d", + "failed to copy config blob %d", ret); - module_free_memory(mod, waves_codec->config_blob); + mod_free(mod, waves_codec->config_blob); waves_codec->config_blob = NULL; waves_codec->config_blob_size = 0; return ret; } - comp_dbg(dev, "waves_effect_save_config_blob_to_cache() done"); + comp_dbg(dev, "done"); return 0; } @@ -506,14 +515,17 @@ static int waves_effect_message(struct processing_module *mod, void *data, uint3 MaxxStatus_t status; uint32_t response_size = 0; - comp_info(dev, "waves_effect_message() start data %p size %d", data, size); + if (waves_codec->initialized) { + comp_info(dev, "start data %p size %d", data, size); - status = MaxxEffect_Message(waves_codec->effect, data, size, - waves_codec->response, &response_size); + status = MaxxEffect_Message(waves_codec->effect, data, size, + waves_codec->response, &response_size); - if (status) { - comp_err(dev, "waves_effect_message() MaxxEffect_Message returned %d", status); - return -EINVAL; + if (status) { + comp_err(dev, "MaxxEffect_Message returned %d", + status); + return -EINVAL; + } } #if CONFIG_TRACEV @@ -540,7 +552,7 @@ static int waves_effect_apply_config_blob_from_cache(struct processing_module *m struct module_data *codec = &mod->priv; struct waves_codec_data *waves_codec = codec->private; - comp_info(dev, "waves_effect_apply_config_blob_from_cache()"); + comp_info(dev, "entry"); if (waves_codec->config_blob) { return waves_effect_message(mod, waves_codec->config_blob, @@ -571,24 +583,24 @@ static int waves_effect_apply_config(struct processing_module *mod) uint32_t param_number = 0; int ret = 0; - comp_info(dev, "waves_effect_apply_config() start"); + comp_info(dev, "start"); cfg = &codec->cfg; - comp_info(dev, "waves_effect_apply_config() config %p, size %d, avail %d", + comp_info(dev, "config %p, size %d, avail %d", cfg->data, cfg->size, cfg->avail); if (!cfg->data) { ret = waves_effect_apply_config_blob_from_cache(mod); if (ret) { - comp_err(dev, "waves_effect_apply_config() error %x: apply cache fail", + comp_err(dev, "error %x: apply cache fail", ret); return ret; } } if (cfg->size > MAX_CONFIG_SIZE_BYTES) { - comp_err(dev, "waves_effect_apply_config() provided config is too big, size %d", + comp_err(dev, "provided config is too big, size %d", cfg->size); return -EINVAL; } @@ -600,27 +612,36 @@ static int waves_effect_apply_config(struct processing_module *mod) for (index = 0; index < cfg->size && (!ret); param_number++) { uint32_t param_data_size; + /* make sure a whole param header remains before reading + * param->size / param->id below + */ + if (index + header_size > cfg->size) { + comp_err(dev, "module_param header at index %u (header %u) exceeds cfg size %zu", + index, header_size, cfg->size); + return -EINVAL; + } + param = (struct module_param *)((char *)cfg->data + index); param_data_size = param->size - sizeof(param->size) - sizeof(param->id); - comp_info(dev, "waves_effect_apply_config() param num %d id %d size %d", + comp_info(dev, "param num %d id %d size %d", param_number, param->id, param->size); if ((param->size <= header_size) || (param->size > MAX_CONFIG_SIZE_BYTES)) { - comp_err(dev, "waves_effect_apply_config() invalid module_param size: %d", + comp_err(dev, "invalid module_param size: %d", param->size); return -EINVAL; } if ((index + param->size) > cfg->size) { - comp_err(dev, "waves_effect_apply_config() module_param size: %d exceeds cfg buffer size: %d", + comp_err(dev, "module_param size: %d exceeds cfg buffer size: %d", param->size, cfg->size); return -EINVAL; } switch (param->id) { case PARAM_NOP: - comp_info(dev, "waves_effect_apply_config() NOP"); + comp_info(dev, "NOP"); break; case PARAM_MESSAGE: ret = waves_effect_handle_param_message(mod, param->data, param_data_size); @@ -637,11 +658,11 @@ static int waves_effect_apply_config(struct processing_module *mod) } if (ret) { - comp_err(dev, "waves_effect_apply_config() failed %d", ret); + comp_err(dev, "failed %d", ret); return ret; } - comp_dbg(dev, "waves_effect_apply_config() done"); + comp_dbg(dev, "done"); return 0; } @@ -653,25 +674,23 @@ static int waves_codec_init(struct processing_module *mod) int ret = 0; void *response = NULL; - comp_dbg(dev, "waves_codec_init() start"); + comp_dbg(dev, "start"); - waves_codec = module_allocate_memory(mod, sizeof(struct waves_codec_data), 16); + waves_codec = mod_alloc_align(mod, sizeof(struct waves_codec_data), 16); if (!waves_codec) { - comp_err(dev, "waves_codec_init() failed to allocate %d bytes for waves_codec_data", + comp_err(dev, "failed to allocate %d bytes for waves_codec_data", sizeof(struct waves_codec_data)); ret = -ENOMEM; } else { memset(waves_codec, 0, sizeof(struct waves_codec_data)); codec->private = waves_codec; ret = waves_effect_allocate(mod); - if (ret) { - module_free_memory(mod, waves_codec); + if (ret) codec->private = NULL; - } } if (ret) { - comp_err(dev, "waves_codec_init() failed %d", ret); + comp_err(dev, "failed %d", ret); return ret; } @@ -679,19 +698,20 @@ static int waves_codec_init(struct processing_module *mod) &waves_codec->response_max_bytes); if (ret) { - comp_err(dev, "waves_codec_init() MaxxEffect_GetMessageMaxSize returned %d", ret); + comp_err(dev, "MaxxEffect_GetMessageMaxSize returned %d", ret); return -EINVAL; } - response = module_allocate_memory(mod, waves_codec->response_max_bytes, 16); + response = mod_alloc_align(mod, waves_codec->response_max_bytes, 16); if (!response) { - comp_err(dev, "waves_codec_init() failed to allocate %d bytes for response", + comp_err(dev, "failed to allocate %d bytes for response", waves_codec->response_max_bytes); return -ENOMEM; } waves_codec->response = response; + waves_codec->initialized = false; - comp_dbg(dev, "waves_codec_init() done"); + comp_dbg(dev, "done"); return ret; } @@ -702,7 +722,7 @@ static int waves_codec_prepare(struct processing_module *mod, struct comp_dev *dev = mod->dev; int ret; - comp_dbg(dev, "waves_codec_prepare() start"); + comp_dbg(dev, "start"); ret = waves_effect_check(dev); if (ret) @@ -720,11 +740,11 @@ static int waves_codec_prepare(struct processing_module *mod, if (ret) goto error; - comp_dbg(dev, "waves_codec_prepare() done"); + comp_dbg(dev, "done"); return 0; error: - comp_err(dev, "waves_codec_prepare() failed %d", ret); + comp_err(dev, "failed %d", ret); return ret; } @@ -733,7 +753,7 @@ static int waves_codec_init_process(struct processing_module *mod) struct module_data *codec = &mod->priv; struct comp_dev *dev = mod->dev; - comp_dbg(dev, "waves_codec_init_process()"); + comp_dbg(dev, "entry"); codec->mpd.produced = 0; codec->mpd.consumed = 0; @@ -742,30 +762,48 @@ static int waves_codec_init_process(struct processing_module *mod) return 0; } -static int -waves_codec_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) +static int waves_codec_process(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { int ret; struct comp_dev *dev = mod->dev; struct module_data *codec = &mod->priv; struct waves_codec_data *waves_codec = codec->private; + const void *src_ptr; + const void *src_buf_start; + size_t src_buf_size; + void *snk_ptr; + void *snk_buf_start; + size_t snk_buf_size; + size_t n_bytes = codec->mpd.in_buff_size; + size_t size_to_wrap; /* Proceed only if we have enough data to fill the module buffer completely */ - if (input_buffers[0].size < codec->mpd.in_buff_size) { - comp_dbg(dev, "waves_codec_process(): not enough data to process"); + if (source_get_data_available(sources[0]) < n_bytes) { + comp_dbg(dev, "not enough data to process"); return -ENODATA; } if (!codec->mpd.init_done) waves_codec_init_process(mod); - memcpy_s(codec->mpd.in_buff, codec->mpd.in_buff_size, - input_buffers[0].data, codec->mpd.in_buff_size); - codec->mpd.avail = codec->mpd.in_buff_size; + ret = source_get_data(sources[0], n_bytes, &src_ptr, &src_buf_start, &src_buf_size); + if (ret) + return ret; + + /* src_buf_size is the total ring buffer size; handle wrap when copying to in_buff */ + size_to_wrap = (const uint8_t *)src_buf_start + src_buf_size - (const uint8_t *)src_ptr; + if (n_bytes <= size_to_wrap) { + memcpy_s(codec->mpd.in_buff, n_bytes, src_ptr, n_bytes); + } else { + memcpy_s(codec->mpd.in_buff, n_bytes, src_ptr, size_to_wrap); + memcpy_s((uint8_t *)codec->mpd.in_buff + size_to_wrap, n_bytes - size_to_wrap, + src_buf_start, n_bytes - size_to_wrap); + } + codec->mpd.avail = n_bytes; - comp_dbg(dev, "waves_codec_process() start"); + comp_dbg(dev, "start"); MaxxStream_t *i_streams[NUM_IO_STREAMS] = { &waves_codec->i_stream }; MaxxStream_t *o_streams[NUM_IO_STREAMS] = { &waves_codec->o_stream }; @@ -777,7 +815,7 @@ waves_codec_process(struct processing_module *mod, * on the other hand there is available/produced counters in mpd, check them anyways */ if (codec->mpd.avail != waves_codec->buffer_bytes) { - comp_warn(dev, "waves_codec_process() input buffer %d is not full %d", + comp_warn(dev, "input buffer %d is not full %d", codec->mpd.avail, waves_codec->buffer_bytes); num_input_samples = codec->mpd.avail / (waves_codec->sample_size_in_bytes * waves_codec->i_format.numChannels); @@ -795,24 +833,40 @@ waves_codec_process(struct processing_module *mod, status = MaxxEffect_Process(waves_codec->effect, i_streams, o_streams); if (status) { - comp_err(dev, "waves_codec_process() MaxxEffect_Process returned %d", status); + source_release_data(sources[0], 0); + comp_err(dev, "MaxxEffect_Process returned %d", status); ret = -EINVAL; } else { codec->mpd.produced = waves_codec->o_stream.numAvailableSamples * waves_codec->o_format.numChannels * waves_codec->sample_size_in_bytes; codec->mpd.consumed = codec->mpd.produced; - input_buffers[0].consumed = codec->mpd.consumed; - ret = 0; - /* copy the produced samples into the output buffer */ - memcpy_s(output_buffers[0].data, codec->mpd.produced, codec->mpd.out_buff, - codec->mpd.produced); - output_buffers[0].size = codec->mpd.produced; + + source_release_data(sources[0], codec->mpd.consumed); + + ret = sink_get_buffer(sinks[0], codec->mpd.produced, + &snk_ptr, &snk_buf_start, &snk_buf_size); + if (!ret) { + /* snk_buf_size is the total ring buffer size; handle wrap */ + size_to_wrap = (uint8_t *)snk_buf_start + snk_buf_size - + (uint8_t *)snk_ptr; + if (codec->mpd.produced <= size_to_wrap) { + memcpy_s(snk_ptr, codec->mpd.produced, + codec->mpd.out_buff, codec->mpd.produced); + } else { + memcpy_s(snk_ptr, codec->mpd.produced, + codec->mpd.out_buff, size_to_wrap); + memcpy_s(snk_buf_start, codec->mpd.produced - size_to_wrap, + (const uint8_t *)codec->mpd.out_buff + size_to_wrap, + codec->mpd.produced - size_to_wrap); + } + sink_commit_buffer(sinks[0], codec->mpd.produced); + } } if (ret) - comp_err(dev, "waves_codec_process() failed %d", ret); + comp_err(dev, "failed %d", ret); - comp_dbg(dev, "waves_codec_process() done"); + comp_dbg(dev, "done"); return ret; } @@ -824,31 +878,31 @@ static int waves_codec_reset(struct processing_module *mod) struct module_data *codec = &mod->priv; struct waves_codec_data *waves_codec = codec->private; - comp_info(dev, "waves_codec_reset() start"); + comp_info(dev, "start"); status = MaxxEffect_Reset(waves_codec->effect); if (status) { - comp_err(dev, "waves_codec_reset() MaxxEffect_Reset returned %d", status); + comp_err(dev, "MaxxEffect_Reset returned %d", status); ret = -EINVAL; } if (ret) - comp_err(dev, "waves_codec_reset() failed %d", ret); + comp_err(dev, "failed %d", ret); if (codec->mpd.in_buff) - module_free_memory(mod, codec->mpd.in_buff); + mod_free(mod, codec->mpd.in_buff); if (codec->mpd.out_buff) - module_free_memory(mod, codec->mpd.out_buff); + mod_free(mod, codec->mpd.out_buff); - comp_dbg(dev, "waves_codec_reset() done"); + waves_codec->initialized = false; + comp_dbg(dev, "done"); return ret; } static int waves_codec_free(struct processing_module *mod) { - module_free_all_memory(mod); - comp_dbg(mod->dev, "waves_codec_free()"); + comp_dbg(mod->dev, "entry"); return 0; } @@ -875,12 +929,12 @@ waves_codec_set_configuration(struct processing_module *mod, uint32_t config_id, /* whole configuration received, apply it now */ ret = waves_effect_apply_config(mod); if (ret) { - comp_err(dev, "waves_codec_set_configuration(): error %x: runtime config apply failed", + comp_err(dev, "error %x: runtime config apply failed", ret); return ret; } - comp_dbg(dev, "waves_codec_set_configuration(): config applied"); + comp_dbg(dev, "config applied"); return 0; } @@ -888,11 +942,28 @@ waves_codec_set_configuration(struct processing_module *mod, uint32_t config_id, static const struct module_interface waves_interface = { .init = waves_codec_init, .prepare = waves_codec_prepare, - .process_raw_data = waves_codec_process, + .process = waves_codec_process, .set_configuration = waves_codec_set_configuration, .reset = waves_codec_reset, .free = waves_codec_free }; +#if CONFIG_WAVES_CODEC_MODULE && CONFIG_WAVES_CODEC_STUB +/* modular: llext dynamic link */ + +#include <module/module/api_ver.h> +#include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> + +static const struct sof_man_module_manifest mod_manifest __section(".module") __used = + SOF_LLEXT_MODULE_MANIFEST("WAVES", &waves_interface, 7, SOF_REG_UUID(waves), 8); + +SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_TR_CTX(waves_tr, SOF_UUID(waves_uuid), LOG_LEVEL_INFO); DECLARE_MODULE_ADAPTER(waves_interface, waves_uuid, waves_tr); SOF_MODULE_INIT(waves, sys_comp_module_waves_interface_init); + +#endif diff --git a/src/audio/module_adapter/module/waves/waves.toml b/src/audio/module_adapter/module/waves/waves.toml new file mode 100644 index 000000000000..3d13fe01994b --- /dev/null +++ b/src/audio/module_adapter/module/waves/waves.toml @@ -0,0 +1,24 @@ +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + + REM # waves module config + [[module.entry]] + name = "WAVES" + uuid = UUIDREG_STR_WAVES + affinity_mask = "0x1" + instance_count = "4" + domain_types = "0" + load_type = LOAD_TYPE + module_type = "13" + auto_start = "0" + sched_caps = [1, 0x00008000] + + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + REM # 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] + + index = __COUNTER__ diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 116a744c4113..3da4079d757e 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -18,11 +18,19 @@ #include <sof/audio/source_api.h> #include <sof/audio/audio_buffer.h> #include <sof/audio/pipeline.h> +#include <sof/lib/vregion.h> +#include <sof/schedule/dp_schedule.h> +#include <sof/schedule/ll_schedule_domain.h> #include <sof/common.h> #include <sof/platform.h> #include <sof/ut.h> +#if CONFIG_IPC_MAJOR_4 +#include <ipc4/base_fw.h> +#include <ipc4/header.h> +#include <ipc4/module.h> +#endif #include <rtos/interrupt.h> -#include <rtos/symbol.h> +#include <rtos/kernel.h> #include <limits.h> #include <stdint.h> @@ -33,59 +41,234 @@ LOG_MODULE_REGISTER(module_adapter, CONFIG_SOF_LOG_LEVEL); * \param[in] drv - component driver pointer. * \param[in] config - component ipc descriptor pointer. * \param[in] spec - passdowned data from driver. + * \param[in] mod_priv - Pointer to private data for processing module. * * \return: a pointer to newly created module adapter component on success. NULL on error. */ struct comp_dev *module_adapter_new(const struct comp_driver *drv, - const struct comp_ipc_config *config, - const void *spec) + const struct comp_ipc_config *config, const void *spec) { - int ret; - struct comp_dev *dev; + return module_adapter_new_ext(drv, config, spec, NULL, NULL, NULL); +} + +#if CONFIG_MM_DRV +#define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE +#else +#include <sof/platform.h> +#define PAGE_SZ HOST_PAGE_SIZE +#endif + +static struct vregion *module_adapter_dp_heap_new(const struct comp_ipc_config *config, + size_t *heap_size) +{ + /* src-lite with 8 channels has been seen allocating 14k in one go */ + /* FIXME: the size will be derived from configuration */ + const size_t buf_size = 28 * 1024; + + return vregion_create(buf_size); +} + +static struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv, + const struct comp_ipc_config *config) +{ + struct k_heap *mod_heap; + struct vregion *mod_vreg; struct processing_module *mod; - struct module_config *dst; - const struct module_interface *const interface = drv->adapter_ops; + struct comp_dev *dev; + /* + * For DP shared modules the struct processing_module object 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. + */ + uint32_t flags = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ? + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT : SOF_MEM_FLAG_USER; + size_t heap_size; + + if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP && IS_ENABLED(CONFIG_SOF_VREGIONS) && + IS_ENABLED(CONFIG_USERSPACE) && !IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP)) { + mod_vreg = module_adapter_dp_heap_new(config, &heap_size); + if (!mod_vreg) { + comp_cl_err(drv, "Failed to allocate DP module heap / vregion"); + return NULL; + } + mod_heap = NULL; + } else { +#ifdef CONFIG_SOF_USERSPACE_LL + mod_heap = sof_sys_user_heap_get(); + comp_cl_dbg(drv, "using ll user heap for module"); +#else + mod_heap = drv->user_heap; +#endif + heap_size = 0; + mod_vreg = NULL; + } - comp_cl_dbg(drv, "module_adapter_new() start"); + if (!mod_vreg) + mod = sof_heap_alloc(mod_heap, flags, sizeof(*mod), 0); + else if (flags & SOF_MEM_FLAG_COHERENT) + mod = vregion_alloc_coherent(mod_vreg, sizeof(*mod)); + else + mod = vregion_alloc(mod_vreg, sizeof(*mod)); - if (!config) { - comp_cl_err(drv, "module_adapter_new(), wrong input params! drv = %zx config = %zx", - (size_t)drv, (size_t)config); - return NULL; + if (!mod) { + comp_cl_err(drv, "failed to allocate memory for module"); + goto emod; } - dev = comp_alloc(drv, sizeof(*dev)); + struct mod_alloc_ctx *alloc = sof_heap_alloc(mod_heap, flags, sizeof(*alloc), 0); + + if (!alloc) + goto ealloc; + + memset(mod, 0, sizeof(*mod)); + alloc->heap = mod_heap; + alloc->vreg = mod_vreg; + mod->priv.resources.alloc = alloc; + mod_resource_init(mod); + + /* + * Would be difficult to optimize the allocation to use cache. Only if + * the whole currently active topology is running on the primary core, + * then it can be cached. Effectively it can be only cached in + * single-core configurations. + */ + if (mod_vreg) + dev = vregion_alloc_coherent(mod_vreg, sizeof(*dev)); + else + dev = sof_heap_alloc(mod_heap, SOF_MEM_FLAG_COHERENT, sizeof(*dev), 0); + if (!dev) { - comp_cl_err(drv, "module_adapter_new(), failed to allocate memory for comp_dev"); - return NULL; + comp_cl_err(drv, "failed to allocate memory for comp_dev"); + goto edev; } + + memset(dev, 0, sizeof(*dev)); + comp_init(drv, dev, sizeof(*dev)); dev->ipc_config = *config; + mod->dev = dev; + dev->mod = 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 + return mod; + +edev: + sof_heap_free(mod_heap, alloc); +ealloc: + if (mod_vreg) + vregion_free(mod_vreg, mod); + else + sof_heap_free(mod_heap, mod); +emod: + vregion_put(mod_vreg); + + return NULL; +} + +static void module_adapter_mem_free(struct processing_module *mod) +{ + struct mod_alloc_ctx *alloc = mod->priv.resources.alloc; + struct k_heap *mod_heap = alloc->heap; + + /* + * In principle it shouldn't even be needed to free individual objects + * on the module heap since we're freeing the heap itself too */ - enum mem_zone zone = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ? - SOF_MEM_ZONE_RUNTIME_SHARED : SOF_MEM_ZONE_RUNTIME; +#if CONFIG_IPC_MAJOR_4 + sof_heap_free(mod_heap, mod->priv.cfg.input_pins); +#endif + if (alloc->vreg) { + struct vregion *mod_vreg = alloc->vreg; - mod = rzalloc(zone, 0, SOF_MEM_CAPS_RAM, sizeof(*mod)); - if (!mod) { - comp_err(dev, "module_adapter_new(), failed to allocate memory for module"); - goto err; + vregion_free(mod_vreg, mod->dev); + vregion_free(mod_vreg, mod); + if (!vregion_put(mod_vreg)) + sof_heap_free(alloc->heap, alloc); + } else { + sof_heap_free(mod_heap, mod->dev); + sof_heap_free(mod_heap, mod); + sof_heap_free(mod_heap, alloc); } +} - dst = &mod->priv.cfg; +/* + * \brief Create a module adapter component. + * \param[in] drv - component driver pointer. + * \param[in] config - component ipc descriptor pointer. + * \param[in] const_spec - passdowned data from driver. + * \param[in] mod_priv - Pointer to private data for processing module. + * + * \return: a pointer to newly created module adapter component on success. NULL on error. + * + * Note: Use the ext version if you need to set the module's private data before calling + * the create method. + */ +struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *const_spec, void *mod_priv, + struct userspace_context *user_ctx, + const struct module_interface *ops) +{ + int ret; + struct module_config *dst; + const struct module_interface *const interface = ops ? : drv->adapter_ops; + struct ipc_config_process spec = + *((const struct ipc_config_process *) const_spec); +#if CONFIG_IPC_MAJOR_4 + struct module_ext_init_data ext_data = { 0 }; +#endif + comp_cl_dbg(drv, "start"); - mod->dev = dev; - dev->mod = mod; + if (!config) { + comp_cl_err(drv, "NULL config! drv = %p", drv); + return NULL; + } +#if CONFIG_IPC_MAJOR_4 + if (config->ipc_extended_init) { + ret = module_ext_init_decode(drv, &ext_data, &spec); + if (ret != 0) + return NULL; + } +#endif - list_init(&mod->sink_buffer_list); + struct processing_module *mod = module_adapter_mem_alloc(drv, config); - ret = module_adapter_init_data(dev, dst, config, spec); + if (!mod) + return NULL; + + module_set_private_data(mod, mod_priv); + list_init(&mod->raw_data_buffers_list); +#if CONFIG_USERSPACE + mod->user_ctx = user_ctx; +#endif /* CONFIG_USERSPACE */ + + struct comp_dev *dev = mod->dev; + +#if CONFIG_ZEPHYR_DP_SCHEDULER + /* create a task for DP processing */ + if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP) { + /* All data allocated, create a thread */ + ret = pipeline_comp_dp_task_init(dev); + if (ret) { + comp_cl_err(drv, "DP task creation failed with error %d.", ret); + goto err; + } + } +#endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ + + dst = &mod->priv.cfg; + /* + * NOTE: dst->ext_data points to stack variable and contains + * pointers to IPC payload mailbox, so its only valid in + * functions that called from this function. This why + * the pointer is set NULL before this function exits. + */ +#if CONFIG_IPC_MAJOR_4 + dst->ext_data = &ext_data; +#endif + ret = module_adapter_init_data(dev, dst, config, &spec); if (ret) { - comp_err(dev, "module_adapter_new() %d: module init data failed", + comp_err(dev, "%d: module init data failed", ret); goto err; } @@ -104,32 +287,65 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv, else goto err; +#if CONFIG_IPC_MAJOR_4 + struct ipc_comp_dev *ipc_pipe; + struct ipc *ipc = ipc_get(); + + /* set the pipeline pointer if ipc_pipe is valid */ + ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, config->pipeline_id, + IPC_COMP_IGNORE_REMOTE); + if (ipc_pipe) { + dev->pipeline = ipc_pipe->pipeline; + + /* LL modules have the same period as the pipeline */ + if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) + dev->period = ipc_pipe->pipeline->period; + } +#endif + /* Init processing module */ ret = module_init(mod); if (ret) { - comp_err(dev, "module_adapter_new() %d: module initialization failed", + comp_err(dev, "%d: module initialization failed", ret); goto err; } -#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"); +#if CONFIG_IPC_MAJOR_4 + struct sof_ipc_stream_params params; + + /* + * retrieve the stream params based on the module base cfg. There's no need to initialize + * params here because it will be filled in based on the module base_cfg. + */ + ret = module_adapter_params(dev, ¶ms); + if (ret) { + comp_err(dev, "%d: module params failed", ret); + goto err; + } + + /* set component period frames */ + component_set_nearest_period_frames(dev, params.rate); +#endif + +#if CONFIG_IPC_MAJOR_4 + dst->ext_data = NULL; +#endif + comp_dbg(dev, "done"); return dev; + err: - rfree(mod); - rfree(dev); +#if CONFIG_ZEPHYR_DP_SCHEDULER + if (dev->task) + schedule_task_free(dev->task); +#endif + module_adapter_mem_free(mod); return NULL; } -EXPORT_SYMBOL(module_adapter_new); #if CONFIG_ZEPHYR_DP_SCHEDULER static void module_adapter_calculate_dp_period(struct comp_dev *dev) @@ -138,8 +354,10 @@ static void module_adapter_calculate_dp_period(struct comp_dev *dev) unsigned int period = UINT32_MAX; for (int i = 0; i < mod->num_of_sinks; i++) { - /* 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]) / + /* calculate time required the module to provide OBS data portion - a period + * use 64bit integers to avoid overflows + */ + unsigned int sink_period = 1000000ULL * 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 */ @@ -169,10 +387,22 @@ int module_adapter_prepare(struct comp_dev *dev) struct list_item *blist, *_blist; uint32_t buff_periods; uint32_t buff_size; /* size of local buffer */ + int memory_flags; int i = 0; - comp_dbg(dev, "module_adapter_prepare() start"); + comp_dbg(dev, "start"); +#if CONFIG_IPC_MAJOR_4 + /* allocate stream_params and retrieve the params from the basecfg if needed */ + if (!mod->stream_params) { + struct sof_ipc_stream_params params; + ret = module_adapter_params(dev, ¶ms); + if (ret) { + comp_err(dev, "module params failed: %d", ret); + return ret; + } + } +#endif /* Prepare module */ if (IS_PROCESSING_MODE_SINK_SOURCE(mod)) ret = module_adapter_sink_src_prepare(dev); @@ -186,8 +416,7 @@ int module_adapter_prepare(struct comp_dev *dev) if (ret) { if (ret != PPL_STATUS_PATH_STOP) - comp_err(dev, "module_adapter_prepare() error %x: module prepare failed", - ret); + comp_err(dev, "error %d: module prepare failed", ret); return ret; } @@ -198,9 +427,21 @@ int module_adapter_prepare(struct comp_dev *dev) * 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 (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP && !dev->period) { - module_adapter_calculate_dp_period(dev); - comp_info(dev, "DP Module period set to %u", dev->period); + if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { + /* calculate DP period if a module didn't */ + if (!dev->period) + module_adapter_calculate_dp_period(dev); + + if (dev->period < LL_TIMER_PERIOD_US) { + comp_err(dev, "DP Module period too short (%u us), must be at least 1LL cycle (%llu us)", + dev->period, LL_TIMER_PERIOD_US); + return -EINVAL; + } + + /* align down period to LL cycle time */ + dev->period /= LL_TIMER_PERIOD_US; + dev->period *= LL_TIMER_PERIOD_US; + comp_info(dev, "DP Module period set to %u us", dev->period); } #endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ @@ -217,7 +458,7 @@ int module_adapter_prepare(struct comp_dev *dev) return ret; if (ret == COMP_STATUS_STATE_ALREADY_SET) { - comp_warn(dev, "module_adapter_prepare(): module has already been prepared"); + comp_warn(dev, "module has already been prepared"); return PPL_STATUS_PATH_STOP; } @@ -227,13 +468,18 @@ int module_adapter_prepare(struct comp_dev *dev) mod->deep_buff_bytes = 0; - /* Get period_bytes first on prepare(). At this point it is guaranteed that the stream - * parameter from sink buffer is settled, and still prior to all references to period_bytes. + /* Get period_bytes first on prepare(). At this point the stream parameter from sink buffer + * shall be settled, provided that the pipeline is built correctly (bind IPC received). + * Hence check for NULL. */ - sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); + sink = comp_dev_get_first_data_consumer(dev); + if (!sink) { + comp_err(dev, "no sink present on period size calculation"); + return -EINVAL; + } mod->period_bytes = audio_stream_period_bytes(&sink->stream, dev->frames); - comp_dbg(dev, "module_adapter_prepare(): got period_bytes = %u", mod->period_bytes); + comp_dbg(dev, "got period_bytes = %u", mod->period_bytes); /* no more to do for sink/source mode */ if (IS_PROCESSING_MODE_SINK_SOURCE(mod)) @@ -250,27 +496,43 @@ int module_adapter_prepare(struct comp_dev *dev) mod->num_of_sinks++; if (!mod->num_of_sources && !mod->num_of_sinks) { - comp_err(dev, "module_adapter_prepare(): no source and sink buffers connected!"); + comp_err(dev, "no source and sink buffers connected!"); + return -EINVAL; + } + if (mod->num_of_sources > CONFIG_MODULE_MAX_CONNECTIONS || + mod->num_of_sinks > CONFIG_MODULE_MAX_CONNECTIONS) { + comp_err(dev, "too many connected sinks %d or sources %d!", + mod->num_of_sinks, mod->num_of_sources); + return -EINVAL; + } + + if (mod->num_of_sources > mod->max_sources || + mod->num_of_sinks > mod->max_sinks) { + comp_err(dev, "connected sources %d (max %d) or sinks %d (max %d) exceed module capacity", + mod->num_of_sources, mod->max_sources, + mod->num_of_sinks, mod->max_sinks); return -EINVAL; } /* check processing mode */ if (IS_PROCESSING_MODE_AUDIO_STREAM(mod) && mod->max_sources > 1 && mod->max_sinks > 1) { - comp_err(dev, "module_adapter_prepare(): Invalid use of simple_copy"); + comp_err(dev, "Invalid use of simple_copy"); return -EINVAL; } module_adapter_check_data(mod, dev, sink); + memory_flags = user_get_buffer_memory_region(dev->drv); /* allocate memory for input buffers */ if (mod->max_sources) { mod->input_buffers = - rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(*mod->input_buffers) * mod->max_sources); + sof_heap_alloc(sof_sys_user_heap_get(), memory_flags, + sizeof(*mod->input_buffers) * mod->max_sources, 0); if (!mod->input_buffers) { - comp_err(dev, "module_adapter_prepare(): failed to allocate input buffers"); + comp_err(dev, "failed to allocate input buffers"); return -ENOMEM; } + memset(mod->input_buffers, 0, sizeof(*mod->input_buffers) * mod->max_sources); } else { mod->input_buffers = NULL; } @@ -278,13 +540,14 @@ int module_adapter_prepare(struct comp_dev *dev) /* allocate memory for output buffers */ if (mod->max_sinks) { mod->output_buffers = - rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(*mod->output_buffers) * mod->max_sinks); + sof_heap_alloc(sof_sys_user_heap_get(), memory_flags, + sizeof(*mod->output_buffers) * mod->max_sinks, 0); if (!mod->output_buffers) { - comp_err(dev, "module_adapter_prepare(): failed to allocate output buffers"); + comp_err(dev, "failed to allocate output buffers"); ret = -ENOMEM; goto in_out_free; } + memset(mod->output_buffers, 0, sizeof(*mod->output_buffers) * mod->max_sinks); } else { mod->output_buffers = NULL; } @@ -342,12 +605,13 @@ int module_adapter_prepare(struct comp_dev *dev) mod->output_buffer_size = buff_size; /* allocate memory for input buffer data */ - list_for_item(blist, &dev->bsource_list) { - size_t size = MAX(mod->deep_buff_bytes, mod->period_bytes); + size_t size = MAX(mod->deep_buff_bytes, mod->period_bytes); - mod->input_buffers[i].data = rballoc(0, SOF_MEM_CAPS_RAM, size); + list_for_item(blist, &dev->bsource_list) { + mod->input_buffers[i].data = sof_heap_alloc(sof_sys_user_heap_get(), + memory_flags, size, 0); if (!mod->input_buffers[i].data) { - comp_err(mod->dev, "module_adapter_prepare(): Failed to alloc input buffer data"); + comp_err(mod->dev, "Failed to alloc input buffer data"); ret = -ENOMEM; goto in_data_free; } @@ -357,9 +621,11 @@ 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 = rballoc(0, SOF_MEM_CAPS_RAM, md->mpd.out_buff_size); + mod->output_buffers[i].data = sof_heap_alloc(sof_sys_user_heap_get(), + memory_flags, + md->mpd.out_buff_size, 0); if (!mod->output_buffers[i].data) { - comp_err(mod->dev, "module_adapter_prepare(): Failed to alloc output buffer data"); + comp_err(mod->dev, "Failed to alloc output buffer data"); ret = -ENOMEM; goto out_data_free; } @@ -367,34 +633,38 @@ int module_adapter_prepare(struct comp_dev *dev) } /* allocate buffer for all sinks */ - if (list_is_empty(&mod->sink_buffer_list)) { + if (list_is_empty(&mod->raw_data_buffers_list)) { 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, false); + struct comp_buffer *buffer = buffer_alloc(md->resources.alloc, + buff_size, memory_flags, + PLATFORM_DCACHE_ALIGN, + BUFFER_USAGE_NOT_SHARED); uint32_t flags; if (!buffer) { - comp_err(dev, "module_adapter_prepare(): failed to allocate local buffer"); + comp_err(dev, "failed to allocate local buffer"); ret = -ENOMEM; goto free; } + vregion_get(md->resources.alloc->vreg); + irq_local_disable(flags); - buffer_attach(buffer, &mod->sink_buffer_list, PPL_DIR_UPSTREAM); + list_item_prepend(&buffer->buffers_list, &mod->raw_data_buffers_list); irq_local_enable(flags); buffer_set_params(buffer, mod->stream_params, BUFFER_UPDATE_FORCE); audio_buffer_reset(&buffer->audio_buffer); } } else { - list_for_item(blist, &mod->sink_buffer_list) { + list_for_item(blist, &mod->raw_data_buffers_list) { struct comp_buffer *buffer = container_of(blist, struct comp_buffer, - sink_list); + buffers_list); ret = buffer_set_size(buffer, buff_size, 0); if (ret < 0) { - comp_err(dev, "module_adapter_prepare(): buffer_set_size() failed, buff_size = %u", + comp_err(dev, "buffer_set_size() failed, buff_size = %u", buff_size); goto free; } @@ -404,38 +674,37 @@ int module_adapter_prepare(struct comp_dev *dev) } } - comp_dbg(dev, "module_adapter_prepare() done"); + comp_dbg(dev, "done"); return 0; free: - list_for_item_safe(blist, _blist, &mod->sink_buffer_list) { + list_for_item_safe(blist, _blist, &mod->raw_data_buffers_list) { struct comp_buffer *buffer = container_of(blist, struct comp_buffer, - sink_list); + buffers_list); uint32_t flags; irq_local_disable(flags); - buffer_detach(buffer, &mod->sink_buffer_list, PPL_DIR_UPSTREAM); + list_item_del(&buffer->buffers_list); irq_local_enable(flags); buffer_free(buffer); } out_data_free: for (i = 0; i < mod->num_of_sinks; i++) - rfree(mod->output_buffers[i].data); + sof_heap_free(sof_sys_user_heap_get(), mod->output_buffers[i].data); in_data_free: for (i = 0; i < mod->num_of_sources; i++) - rfree(mod->input_buffers[i].data); + sof_heap_free(sof_sys_user_heap_get(), mod->input_buffers[i].data); in_out_free: - rfree(mod->output_buffers); + sof_heap_free(sof_sys_user_heap_get(), mod->output_buffers); mod->output_buffers = NULL; - rfree(mod->input_buffers); + sof_heap_free(sof_sys_user_heap_get(), mod->input_buffers); mod->input_buffers = NULL; return ret; } -EXPORT_SYMBOL(module_adapter_prepare); int module_adapter_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) { @@ -444,18 +713,18 @@ int module_adapter_params(struct comp_dev *dev, struct sof_ipc_stream_params *pa module_adapter_set_params(mod, params); +#if CONFIG_IPC_MAJOR_3 ret = comp_verify_params(dev, mod->verify_params_flags, params); if (ret < 0) { - comp_err(dev, "module_adapter_params(): comp_verify_params() failed."); + comp_err(dev, "comp_verify_params() failed."); return ret; } +#endif /* allocate stream_params each time */ - if (mod->stream_params) - rfree(mod->stream_params); + mod_free(mod, mod->stream_params); - mod->stream_params = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(*mod->stream_params) + params->ext_data_length); + mod->stream_params = mod_alloc(mod, sizeof(*mod->stream_params) + params->ext_data_length); if (!mod->stream_params) return -ENOMEM; @@ -475,7 +744,6 @@ int module_adapter_params(struct comp_dev *dev, struct sof_ipc_stream_params *pa return 0; } -EXPORT_SYMBOL(module_adapter_params); /* * Function to copy from source buffer to the module buffer @@ -484,9 +752,8 @@ EXPORT_SYMBOL(module_adapter_params); * @buff_size: size of the module input buffer * @bytes: number of bytes available in the source buffer */ -static void -ca_copy_from_source_to_module(const struct audio_stream *source, - void *buff, uint32_t buff_size, size_t bytes) +static void 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, @@ -512,9 +779,8 @@ ca_copy_from_source_to_module(const struct audio_stream *source, * @buff: pointer to the module output buffer * @bytes: number of bytes available in the module output buffer */ -static void -ca_copy_from_module_to_sink(const struct audio_stream *sink, - void *buff, size_t bytes) +static void 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)); @@ -570,11 +836,11 @@ static void module_copy_samples(struct comp_dev *dev, struct comp_buffer *src_bu return; } - comp_dbg(dev, "module_copy_samples(): deep buffering has ended after gathering %d bytes of processed data", + comp_dbg(dev, "deep buffering has ended after gathering %d bytes of processed data", audio_stream_get_avail_bytes(&src_buffer->stream)); mod->deep_buff_bytes = 0; } else if (!produced) { - comp_dbg(dev, "module_copy_samples(): nothing processed in this call"); + comp_dbg(dev, "nothing processed in this call"); /* * No data produced anything in this period but there still be data in the buffer * to copy to sink @@ -606,11 +872,11 @@ static void module_adapter_process_output(struct comp_dev *dev) * copy all produced output samples to output buffers. This loop will do nothing when * there are no samples produced. */ - list_for_item(blist, &mod->sink_buffer_list) { + list_for_item(blist, &mod->raw_data_buffers_list) { if (mod->output_buffers[i].size > 0) { struct comp_buffer *buffer; - buffer = container_of(blist, struct comp_buffer, sink_list); + buffer = container_of(blist, struct comp_buffer, buffers_list); ca_copy_from_module_to_sink(&buffer->stream, mod->output_buffers[i].data, mod->output_buffers[i].size); @@ -621,17 +887,14 @@ static void module_adapter_process_output(struct comp_dev *dev) /* copy from all output local buffers to sink buffers */ i = 0; - list_for_item(blist, &dev->bsink_list) { - struct list_item *_blist; + comp_dev_for_each_consumer(dev, sink) { int j = 0; - list_for_item(_blist, &mod->sink_buffer_list) { + list_for_item(blist, &mod->raw_data_buffers_list) { if (i == j) { struct comp_buffer *source; - sink = container_of(blist, struct comp_buffer, source_list); - source = container_of(_blist, struct comp_buffer, sink_list); - + source = container_of(blist, struct comp_buffer, buffers_list); module_copy_samples(dev, source, sink, mod->output_buffers[i].size); @@ -646,10 +909,9 @@ static void module_adapter_process_output(struct comp_dev *dev) mod->total_data_produced += mod->output_buffers[0].size; } -static uint32_t -module_single_sink_setup(struct comp_dev *dev, - struct comp_buffer **source, - struct comp_buffer **sinks) +static uint32_t module_single_sink_setup(struct comp_dev *dev, + struct comp_buffer **source, + struct comp_buffer **sinks) { struct processing_module *mod = comp_mod(dev); struct list_item *blist; @@ -687,10 +949,9 @@ module_single_sink_setup(struct comp_dev *dev, return num_input_buffers; } -static uint32_t -module_single_source_setup(struct comp_dev *dev, - struct comp_buffer **source, - struct comp_buffer **sinks) +static uint32_t module_single_source_setup(struct comp_dev *dev, + struct comp_buffer **source, + struct comp_buffer **sinks) { struct processing_module *mod = comp_mod(dev); struct list_item *blist; @@ -756,7 +1017,7 @@ static int module_adapter_audio_stream_copy_1to1(struct comp_dev *dev) /* Note: Source buffer state is not checked to enable mixout to generate zero * PCM codes when source is not active. */ - if (mod->sink_comp_buffer->sink->state == dev->state) + if (comp_buffer_get_sink_state(mod->sink_comp_buffer) == dev->state) num_output_buffers = 1; ret = module_process_legacy(mod, mod->input_buffers, 1, @@ -783,10 +1044,11 @@ static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) { struct comp_buffer *sources[PLATFORM_MAX_STREAMS]; struct comp_buffer *sinks[PLATFORM_MAX_STREAMS]; + struct comp_buffer *sink; + struct comp_buffer *source; struct processing_module *mod = comp_mod(dev); - struct list_item *blist; uint32_t num_input_buffers, num_output_buffers; - int ret, i = 0; + int ret, i; /* handle special case of HOST/DAI type components */ if (dev->ipc_config.type == SOF_COMP_HOST || dev->ipc_config.type == SOF_COMP_DAI) @@ -796,12 +1058,9 @@ static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) return module_adapter_audio_stream_copy_1to1(dev); /* acquire all sink and source buffers */ - list_for_item(blist, &dev->bsink_list) { - struct comp_buffer *sink; - - sink = container_of(blist, struct comp_buffer, source_list); + i = 0; + comp_dev_for_each_consumer(dev, sink) sinks[i++] = sink; - } num_output_buffers = i; if (num_output_buffers > mod->max_sinks) { comp_err(dev, "Invalid number of sinks %d\n", num_output_buffers); @@ -809,12 +1068,8 @@ static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) } i = 0; - list_for_item(blist, &dev->bsource_list) { - struct comp_buffer *source; - - source = container_of(blist, struct comp_buffer, sink_list); + comp_dev_for_each_producer(dev, source) sources[i++] = source; - } num_input_buffers = i; if (num_input_buffers > mod->max_sources) { comp_err(dev, "Invalid number of sources %d\n", num_input_buffers); @@ -824,11 +1079,11 @@ static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) /* setup active input/output buffers for processing */ if (num_output_buffers == 1) { module_single_sink_setup(dev, sources, sinks); - if (sinks[0]->sink->state != dev->state) + if (comp_buffer_get_sink_state(sinks[0]) != dev->state) num_output_buffers = 0; } else if (num_input_buffers == 1) { module_single_source_setup(dev, sources, sinks); - if (sources[0]->source->state != dev->state) { + if (comp_buffer_get_source_state(sources[0]) != dev->state) { num_input_buffers = 0; } } else { @@ -840,9 +1095,7 @@ static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) mod->output_buffers, num_output_buffers); if (ret) { if (ret != -ENOSPC && ret != -ENODATA) { - comp_err(dev, - "module_adapter_audio_stream_type_copy() failed with error: %x", - ret); + comp_err(dev, "failed with error: %d", ret); goto out; } @@ -910,15 +1163,13 @@ static int module_adapter_copy_ring_buffers(struct comp_dev *dev) * This is an adapter, to be removed when pipeline2.0 is ready */ struct processing_module *mod = comp_mod(dev); - struct list_item *blist; + struct comp_buffer *buffer; int err; - list_for_item(blist, &dev->bsource_list) { + comp_dev_for_each_producer(dev, buffer) { /* input - we need to copy data from audio_stream (as source) * to ring_buffer (as sink) */ - struct comp_buffer *buffer = - container_of(blist, struct comp_buffer, sink_list); err = audio_buffer_sync_secondary_buffer(&buffer->audio_buffer, UINT_MAX); if (err) { @@ -930,7 +1181,7 @@ static int module_adapter_copy_ring_buffers(struct comp_dev *dev) if (mod->dp_startup_delay) return 0; - list_for_item(blist, &dev->bsink_list) { + comp_dev_for_each_consumer(dev, buffer) { /* output - we need to copy data from ring_buffer (as source) * to audio_stream (as sink) * @@ -943,8 +1194,6 @@ static int module_adapter_copy_ring_buffers(struct comp_dev *dev) * * FIX: copy only the following module's IBS in each LL cycle */ - struct comp_buffer *buffer = - container_of(blist, struct comp_buffer, source_list); struct sof_source *following_mod_data_source = audio_buffer_get_source(&buffer->audio_buffer); @@ -972,7 +1221,7 @@ static int module_adapter_sink_source_copy(struct comp_dev *dev) int ret; int i = 0; - comp_dbg(dev, "module_adapter_sink_source_copy(): start"); + comp_dbg(dev, "start"); /* reset number of processed bytes */ for (i = 0; i < mod->num_of_sources; i++) @@ -984,10 +1233,8 @@ static int module_adapter_sink_source_copy(struct comp_dev *dev) 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); - } + if (ret) + comp_err(dev, "process failed with error: %d", ret); /* count number of processed data. To be removed in pipeline 2.0 */ for (i = 0; i < mod->num_of_sources; i++) @@ -996,7 +1243,7 @@ static int module_adapter_sink_source_copy(struct comp_dev *dev) 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"); + comp_dbg(dev, "done"); return ret; } @@ -1011,24 +1258,22 @@ static int module_adapter_raw_data_type_copy(struct comp_dev *dev) uint32_t min_free_frames = UINT_MAX; int ret, i = 0; - comp_dbg(dev, "module_adapter_raw_data_type_copy(): start"); + comp_dbg(dev, "start"); - list_for_item(blist, &mod->sink_buffer_list) { - sink = container_of(blist, struct comp_buffer, sink_list); + list_for_item(blist, &mod->raw_data_buffers_list) { + sink = container_of(blist, struct comp_buffer, buffers_list); min_free_frames = MIN(min_free_frames, audio_stream_get_free_frames(&sink->stream)); } /* copy source samples into input buffer */ - list_for_item(blist, &dev->bsource_list) { + comp_dev_for_each_producer(dev, source) { uint32_t bytes_to_process; int frames, source_frame_bytes; - source = container_of(blist, struct comp_buffer, sink_list); - /* check if the source dev is in the same state as the dev */ - if (!source->source || source->source->state != dev->state) + if (comp_buffer_get_source_state(source) != dev->state) continue; frames = MIN(min_free_frames, @@ -1050,9 +1295,7 @@ static int module_adapter_raw_data_type_copy(struct comp_dev *dev) mod->output_buffers, mod->num_of_sinks); if (ret) { if (ret != -ENOSPC && ret != -ENODATA) { - comp_err(dev, - "module_adapter_raw_data_type_copy() %x: module processing failed", - ret); + comp_err(dev, "%d: module processing failed", ret); goto out; } @@ -1061,10 +1304,7 @@ 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) { - - source = container_of(blist, struct comp_buffer, sink_list); - + comp_dev_for_each_producer(dev, source) { comp_update_buffer_consume(source, mod->input_buffers[i].consumed); bzero((__sparse_force void *)mod->input_buffers[i].data, size); @@ -1078,7 +1318,7 @@ static int module_adapter_raw_data_type_copy(struct comp_dev *dev) module_adapter_process_output(dev); - comp_dbg(dev, "module_adapter_raw_data_type_copy(): done"); + comp_dbg(dev, "done"); return 0; @@ -1091,13 +1331,13 @@ static int module_adapter_raw_data_type_copy(struct comp_dev *dev) mod->input_buffers[i].size = 0; mod->input_buffers[i].consumed = 0; } - comp_dbg(dev, "module_adapter_raw_data_type_copy(): error %x", ret); + comp_dbg(dev, "error %x", ret); return ret; } int module_adapter_copy(struct comp_dev *dev) { - comp_dbg(dev, "module_adapter_copy(): start"); + comp_dbg(dev, "start"); struct processing_module *mod = comp_mod(dev); @@ -1115,17 +1355,16 @@ int module_adapter_copy(struct comp_dev *dev) } - comp_err(dev, "module_adapter_copy(): unknown processing_data_type"); + comp_err(dev, "unknown processing_data_type"); return -EINVAL; } -EXPORT_SYMBOL(module_adapter_copy); int module_adapter_trigger(struct comp_dev *dev, int cmd) { struct processing_module *mod = comp_mod(dev); const struct module_interface *const interface = mod->dev->drv->adapter_ops; - comp_dbg(dev, "module_adapter_trigger(): cmd %d", cmd); + comp_dbg(dev, "cmd %d", cmd); /* handle host/DAI gateway modules separately */ if (dev->ipc_config.type == SOF_COMP_HOST || dev->ipc_config.type == SOF_COMP_DAI) @@ -1139,12 +1378,23 @@ int module_adapter_trigger(struct comp_dev *dev, int cmd) dev->state = COMP_STATE_ACTIVE; return PPL_STATUS_PATH_STOP; } - if (interface->trigger) + + if (interface->trigger) { +#if CONFIG_SOF_USERSPACE_APPLICATION + if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { + /* Process DP module's trigger */ + const union scheduler_dp_thread_ipc_param param = { + .pipeline_state.trigger_cmd = cmd, + }; + return scheduler_dp_thread_ipc(mod, SOF_IPC4_GLB_SET_PIPELINE_STATE, + ¶m); + } +#endif return interface->trigger(mod, cmd); + } return module_adapter_set_state(mod, dev, cmd); } -EXPORT_SYMBOL(module_adapter_trigger); int module_adapter_reset(struct comp_dev *dev) { @@ -1152,25 +1402,27 @@ int module_adapter_reset(struct comp_dev *dev) struct processing_module *mod = comp_mod(dev); struct list_item *blist; - comp_dbg(dev, "module_adapter_reset(): resetting"); + comp_dbg(dev, "resetting"); ret = module_reset(mod); if (ret) { if (ret != PPL_STATUS_PATH_STOP) - comp_err(dev, "module_adapter_reset(): failed with error: %d", ret); + comp_err(dev, "failed with error: %d", ret); return ret; } if (IS_PROCESSING_MODE_RAW_DATA(mod)) { for (i = 0; i < mod->num_of_sinks; i++) - rfree((__sparse_force void *)mod->output_buffers[i].data); + sof_heap_free(sof_sys_user_heap_get(), + (__sparse_force void *)mod->output_buffers[i].data); for (i = 0; i < mod->num_of_sources; i++) - rfree((__sparse_force void *)mod->input_buffers[i].data); + sof_heap_free(sof_sys_user_heap_get(), + (__sparse_force void *)mod->input_buffers[i].data); } if (IS_PROCESSING_MODE_RAW_DATA(mod) || IS_PROCESSING_MODE_AUDIO_STREAM(mod)) { - rfree(mod->output_buffers); - rfree(mod->input_buffers); + sof_heap_free(sof_sys_user_heap_get(), mod->output_buffers); + sof_heap_free(sof_sys_user_heap_get(), mod->input_buffers); mod->num_of_sources = 0; mod->num_of_sinks = 0; @@ -1179,20 +1431,19 @@ int module_adapter_reset(struct comp_dev *dev) mod->total_data_consumed = 0; mod->total_data_produced = 0; - list_for_item(blist, &mod->sink_buffer_list) { + list_for_item(blist, &mod->raw_data_buffers_list) { struct comp_buffer *buffer = container_of(blist, struct comp_buffer, - sink_list); + buffers_list); buffer_zero(buffer); } - rfree(mod->stream_params); + mod_free(mod, mod->stream_params); mod->stream_params = NULL; - comp_dbg(dev, "module_adapter_reset(): done"); + comp_dbg(dev, "done"); return comp_set_state(dev, COMP_TRIGGER_RESET); } -EXPORT_SYMBOL(module_adapter_reset); void module_adapter_free(struct comp_dev *dev) { @@ -1200,31 +1451,52 @@ void module_adapter_free(struct comp_dev *dev) struct processing_module *mod = comp_mod(dev); struct list_item *blist, *_blist; - comp_dbg(dev, "module_adapter_free(): start"); + comp_dbg(dev, "start"); + +#if CONFIG_SOF_USERSPACE_APPLICATION + if (dev->task) + /* + * Run DP module's .free() method in its thread context. + * Unlike with other IPCs we first run module's .free() in + * thread context, then cancel the thread, and then execute + * final clean up + */ + scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_DELETE_INSTANCE, NULL); +#endif ret = module_free(mod); if (ret) - comp_err(dev, "module_adapter_free(): failed with error: %d", ret); + comp_err(dev, "failed with error: %d", ret); + + if (dev->task) + schedule_task_free(dev->task); - list_for_item_safe(blist, _blist, &mod->sink_buffer_list) { + list_for_item_safe(blist, _blist, &mod->raw_data_buffers_list) { struct comp_buffer *buffer = container_of(blist, struct comp_buffer, - sink_list); + buffers_list); uint32_t flags; irq_local_disable(flags); - buffer_detach(buffer, &mod->sink_buffer_list, PPL_DIR_UPSTREAM); + list_item_del(&buffer->buffers_list); irq_local_enable(flags); buffer_free(buffer); } -#if CONFIG_IPC_MAJOR_4 - rfree(mod->priv.cfg.input_pins); -#endif + mod_free(mod, mod->stream_params); + mod_free_all(mod); + + module_adapter_mem_free(mod); +} + +size_t module_adapter_heap_usage(struct processing_module *mod, size_t *hwm) +{ + struct module_resources *res = &mod->priv.resources; + + if (hwm) + *hwm = res->heap_high_water_mark; - rfree(mod); - rfree(dev); + return res->heap_usage; } -EXPORT_SYMBOL(module_adapter_free); /* * \brief Get DAI hw params @@ -1247,7 +1519,6 @@ int module_adapter_get_hw_params(struct comp_dev *dev, struct sof_ipc_stream_par return -EOPNOTSUPP; } -EXPORT_SYMBOL(module_adapter_get_hw_params); /* * \brief Get stream position @@ -1268,7 +1539,6 @@ int module_adapter_position(struct comp_dev *dev, struct sof_ipc_stream_posn *po return -EOPNOTSUPP; } -EXPORT_SYMBOL(module_adapter_position); /* * \brief DAI timestamp configure @@ -1288,7 +1558,6 @@ int module_adapter_ts_config_op(struct comp_dev *dev) return -EOPNOTSUPP; } -EXPORT_SYMBOL(module_adapter_ts_config_op); /* * \brief DAI timestamp start @@ -1308,7 +1577,6 @@ int module_adapter_ts_start_op(struct comp_dev *dev) return -EOPNOTSUPP; } -EXPORT_SYMBOL(module_adapter_ts_start_op); /* * \brief DAI timestamp stop @@ -1328,7 +1596,6 @@ int module_adapter_ts_stop_op(struct comp_dev *dev) return -EOPNOTSUPP; } -EXPORT_SYMBOL(module_adapter_ts_stop_op); /* * \brief Get DAI timestamp @@ -1353,4 +1620,3 @@ int module_adapter_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd) return -EOPNOTSUPP; } -EXPORT_SYMBOL(module_adapter_ts_get_op); diff --git a/src/audio/module_adapter/module_adapter_ipc3.c b/src/audio/module_adapter/module_adapter_ipc3.c index 5adc3079708c..e6098dec0799 100644 --- a/src/audio/module_adapter/module_adapter_ipc3.c +++ b/src/audio/module_adapter/module_adapter_ipc3.c @@ -91,7 +91,7 @@ int module_adapter_init_data(struct comp_dev *dev, break; } default: - comp_err(dev, "module_adapter_init_data() unsupported comp type %d", config->type); + comp_err(dev, "unsupported comp type %d", config->type); return -EINVAL; } @@ -99,7 +99,7 @@ int module_adapter_init_data(struct comp_dev *dev, if (size) { ret = module_load_config(dev, data, size); if (ret < 0) { - comp_err(dev, "module_adapter_init_data() error %d: config loading has failed.", + comp_err(dev, "error %d: config loading has failed.", ret); return ret; } @@ -121,8 +121,7 @@ void module_adapter_check_data(struct processing_module *mod, struct comp_dev *d */ 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->source_comp_buffer = comp_dev_get_first_data_producer(dev); mod->sink_comp_buffer = sink; mod->stream_copy_single_to_single = true; } @@ -132,13 +131,13 @@ void module_adapter_set_params(struct processing_module *mod, struct sof_ipc_str { } -static int module_source_status_count(struct comp_dev *dev, uint32_t status) +static int module_source_state_count(struct comp_dev *dev, uint32_t state) { - struct list_item *blist; int count = 0; + struct comp_buffer *source; /* count source with state == status */ - list_for_item(blist, &dev->bsource_list) { + comp_dev_for_each_producer(dev, source) /* * FIXME: this is racy, state can be changed by another core. * This is implicitly protected by serialised IPCs. Even when @@ -146,12 +145,8 @@ static int module_source_status_count(struct comp_dev *dev, uint32_t status) * 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) + if (comp_buffer_get_source_state(source) == state) count++; - } return count; } @@ -163,8 +158,8 @@ int module_adapter_set_state(struct processing_module *mod, struct comp_dev *dev bool sources_active; int ret; - sources_active = module_source_status_count(dev, COMP_STATE_ACTIVE) || - module_source_status_count(dev, COMP_STATE_PAUSED); + sources_active = module_source_state_count(dev, COMP_STATE_ACTIVE) || + module_source_state_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) { @@ -189,21 +184,25 @@ static int module_adapter_get_set_params(struct comp_dev *dev, struct sof_ipc_ct const struct module_interface *const interface = mod->dev->drv->adapter_ops; enum module_cfg_fragment_position pos; uint32_t data_offset_size; - static uint32_t size; - comp_dbg(dev, "module_adapter_set_params(): num_of_elem %d, elem remain %d msg_index %u", + comp_dbg(dev, "num_of_elem %d, elem remain %d msg_index %u", cdata->num_elems, cdata->elems_remaining, cdata->msg_index); - /* set the fragment position, data offset and config data size */ + /* + * The total fragmented-transfer size is kept per instance in + * mod->runtime_params_size; a file-scope static would be shared across + * all module_adapter components and corrupted by interleaved transfers. + */ if (!cdata->msg_index) { - size = cdata->num_elems + cdata->elems_remaining; - data_offset_size = size; + mod->runtime_params_size = cdata->num_elems + cdata->elems_remaining; + data_offset_size = mod->runtime_params_size; if (cdata->elems_remaining) pos = MODULE_CFG_FRAGMENT_FIRST; else pos = MODULE_CFG_FRAGMENT_SINGLE; } else { - data_offset_size = size - (cdata->num_elems + cdata->elems_remaining); + data_offset_size = mod->runtime_params_size - + (cdata->num_elems + cdata->elems_remaining); if (cdata->elems_remaining) pos = MODULE_CFG_FRAGMENT_MIDDLE; else @@ -221,7 +220,7 @@ static int module_adapter_get_set_params(struct comp_dev *dev, struct sof_ipc_ct (const uint8_t *)cdata, cdata->num_elems, NULL, 0); - comp_warn(dev, "module_adapter_get_set_params(): no configuration op set for %d", + comp_warn(dev, "no configuration op set for %d", dev_comp_id(dev)); return 0; } @@ -230,7 +229,7 @@ static int module_adapter_get_set_params(struct comp_dev *dev, struct sof_ipc_ct return interface->get_configuration(mod, pos, &data_offset_size, (uint8_t *)cdata, cdata->num_elems); - comp_err(dev, "module_adapter_get_set_params(): no configuration op get for %d", + comp_err(dev, "no configuration op get for %d", dev_comp_id(dev)); return -EIO; /* non-implemented error */ } @@ -246,13 +245,13 @@ static int module_adapter_ctrl_get_set_data(struct comp_dev *dev, struct sof_ipc /* Check version from ABI header */ if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { - comp_err(dev, "module_adapter_ctrl_set_data(): ABI mismatch!"); + comp_err(dev, "ABI mismatch!"); return -EINVAL; } switch (cdata->cmd) { case SOF_CTRL_CMD_ENUM: - comp_err(dev, "module_adapter_ctrl_set_data(): set enum is not implemented"); + comp_err(dev, "set enum is not implemented"); ret = -EIO; break; case SOF_CTRL_CMD_BINARY: @@ -275,7 +274,7 @@ int module_adapter_cmd(struct comp_dev *dev, int cmd, void *data, int max_data_s const struct module_interface *const interface = mod->dev->drv->adapter_ops; int ret = 0; - comp_dbg(dev, "module_adapter_cmd() %d start", cmd); + comp_dbg(dev, "%d start", cmd); switch (cmd) { case COMP_CMD_SET_DATA: @@ -312,44 +311,38 @@ int module_adapter_cmd(struct comp_dev *dev, int cmd, void *data, int max_data_s ret = interface->get_configuration(mod, 0, 0, (uint8_t *)cdata, 0); break; default: - comp_err(dev, "module_adapter_cmd() error: unknown command"); + comp_err(dev, "error: unknown command"); ret = -EINVAL; break; } - comp_dbg(dev, "module_adapter_cmd() done"); + comp_dbg(dev, "done"); return ret; } int module_adapter_sink_src_prepare(struct comp_dev *dev) { struct processing_module *mod = comp_mod(dev); - struct list_item *blist; - int ret; + struct comp_buffer *sink_buffer; + struct comp_buffer *source_buffer; 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 = - container_of(blist, struct comp_buffer, source_list); + comp_dev_for_each_consumer(dev, sink_buffer) { mod->sinks[i] = audio_buffer_get_sink(&sink_buffer->audio_buffer); i++; } mod->num_of_sinks = i; i = 0; - list_for_item(blist, &dev->bsource_list) { - struct comp_buffer *source_buffer = - container_of(blist, struct comp_buffer, sink_list); - + comp_dev_for_each_producer(dev, source_buffer) { mod->sources[i] = audio_buffer_get_source(&source_buffer->audio_buffer); i++; } mod->num_of_sources = i; /* Prepare module */ - ret = module_prepare(mod, mod->sources, mod->num_of_sources, mod->sinks, mod->num_of_sinks); - - return ret; + return module_prepare(mod, mod->sources, mod->num_of_sources, mod->sinks, + mod->num_of_sinks); } diff --git a/src/audio/module_adapter/module_adapter_ipc4.c b/src/audio/module_adapter/module_adapter_ipc4.c index 060cef446f73..57b918b20f86 100644 --- a/src/audio/module_adapter/module_adapter_ipc4.c +++ b/src/audio/module_adapter/module_adapter_ipc4.c @@ -16,15 +16,114 @@ #include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/pipeline.h> #include <sof/common.h> +#include <sof/lib/mailbox.h> #include <sof/platform.h> #include <sof/ut.h> #include <rtos/interrupt.h> #include <rtos/symbol.h> +#include <ipc4/base_fw.h> #include <limits.h> #include <stdint.h> LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL); +int module_ext_init_decode(const struct comp_driver *drv, struct module_ext_init_data *ext_data, + struct ipc_config_process *spec) +{ + const struct ipc4_module_init_ext_init *ext_init; + const struct ipc4_module_init_ext_object *obj; + bool last_object; + size_t consumed; + + assert(drv->type == SOF_COMP_MODULE_ADAPTER); + + /* Validate size before dereferencing ext_init pointer */ + if (spec->size < sizeof(*ext_init)) { + comp_cl_err(drv, "Size too small for ext init %u < %zu", + spec->size, sizeof(*ext_init)); + return -EINVAL; + } + + ext_init = (const struct ipc4_module_init_ext_init *)spec->data; + last_object = !ext_init->data_obj_array; + /* TODO: Handle ext_init->gna_used and ext_init->rtos_domain here */ + /* Get the first obj struct right after ext_init struct */ + obj = (const struct ipc4_module_init_ext_object *)(ext_init + 1); + while (!last_object) { + const struct ipc4_module_init_ext_object *next_obj; + + /* Check if there is space for the object header */ + if ((unsigned char *)(obj + 1) - spec->data > spec->size) { + comp_cl_err(drv, "ext init obj overflow, %u > %u", + (unsigned char *)(obj + 1) - spec->data, spec->size); + return -EINVAL; + } + /* Calculate would be next object position and check if current object fits */ + next_obj = (const struct ipc4_module_init_ext_object *) + (((uint32_t *) (obj + 1)) + obj->object_words); + if ((unsigned char *)next_obj - spec->data > spec->size) { + comp_cl_err(drv, "ext init object array overflow, %u > %u", + (unsigned char *)obj - spec->data, spec->size); + return -EINVAL; + } + switch (obj->object_id) { + case IPC4_MOD_INIT_DATA_ID_DP_DATA: + { + /* Get dp_data struct that follows the obj struct */ + const struct ipc4_module_init_ext_obj_dp_data *dp_data = + (const struct ipc4_module_init_ext_obj_dp_data *)(obj + 1); + + if (obj->object_words * sizeof(uint32_t) < sizeof(*dp_data)) { + comp_cl_warn(drv, "dp_data object too small %zu < %zu", + obj->object_words * sizeof(uint32_t), + sizeof(*dp_data)); + break; + } + ext_data->dp_data = dp_data; + comp_cl_info(drv, + "init_ext_obj_dp_data domain %u stack %u heap %u", + dp_data->domain_id, dp_data->stack_bytes, + dp_data->heap_bytes); + break; + } + case IPC4_MOD_INIT_DATA_ID_MODULE_DATA: + { + /* + * set the module init_data. Modules must copy/save this in their init + * callbacks if they need this to be persistent + */ + ext_data->module_data = (const void *)(obj + 1); + ext_data->module_data_size = obj->object_words * sizeof(uint32_t); + comp_cl_info(drv, "module init data size %u bytes", + ext_data->module_data_size); + break; + } + default: + comp_cl_info(drv, "Unknown ext init object id %u of %u words", + obj->object_id, obj->object_words); + } + /* Read the last object flag from obj header */ + last_object = obj->last_object; + /* Move to next object */ + obj = next_obj; + } + + /* + * Remove decoded ext_init payload from spec. + * consumed <= spec->size is guaranteed here: + * - no-loop path: consumed == sizeof(*ext_init) <= spec->size (validated above) + * - loop path: in-loop bounds checks (obj/next_obj vs spec->size) ensure + * obj never advances past spec->data + spec->size + */ + consumed = (unsigned char *)obj - spec->data; + assert(consumed <= spec->size); + + spec->size -= consumed; + spec->data = (const unsigned char *)obj; + + return 0; +} + /* * \module adapter data initialize. * \param[in] dev - device. @@ -39,17 +138,31 @@ int module_adapter_init_data(struct comp_dev *dev, const struct comp_ipc_config *config, const void *spec) { + const struct ipc4_base_module_extended_cfg *cfg; const struct ipc_config_process *args = spec; - const struct ipc4_base_module_extended_cfg *cfg = (void *)args->data; size_t cfgsz = args->size; assert(dev->drv->type == SOF_COMP_MODULE_ADAPTER); - if (cfgsz < sizeof(cfg->base_cfg)) + cfg = (const struct ipc4_base_module_extended_cfg *)args->data; + + if (cfg == NULL) return -EINVAL; + if (cfgsz > MAILBOX_HOSTBOX_SIZE || cfgsz < sizeof(cfg->base_cfg)) { + comp_err(dev, "invalid config size %zu", cfgsz); + return -EINVAL; + } dst->base_cfg = cfg->base_cfg; dst->size = cfgsz; + /* Host-supplied channel count indexes PLATFORM_MAX_CHANNELS arrays. */ + if (dst->base_cfg.audio_fmt.channels_count == 0 || + dst->base_cfg.audio_fmt.channels_count > PLATFORM_MAX_CHANNELS) { + comp_err(dev, "invalid channels count %u", + dst->base_cfg.audio_fmt.channels_count); + return -EINVAL; + } + if (cfgsz >= sizeof(*cfg)) { int n_in = cfg->base_cfg_ext.nb_input_pins; int n_out = cfg->base_cfg_ext.nb_output_pins; @@ -57,10 +170,14 @@ int module_adapter_init_data(struct comp_dev *dev, + (n_out * sizeof(*dst->output_pins)); if (cfgsz == (sizeof(*cfg) + pinsz)) { + if (n_in > IPC4_MAX_SRC_QUEUE || n_out > IPC4_MAX_DST_QUEUE) + return -EINVAL; + dst->nb_input_pins = n_in; dst->nb_output_pins = n_out; - dst->input_pins = rmalloc(SOF_MEM_ZONE_RUNTIME_SHARED, - 0, SOF_MEM_CAPS_RAM, pinsz); + dst->input_pins = sof_heap_alloc(dev->mod->priv.resources.alloc->heap, + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + pinsz, 0); if (!dst->input_pins) return -ENOMEM; @@ -70,8 +187,12 @@ int module_adapter_init_data(struct comp_dev *dev, } } - dst->init_data = cfg; /* legacy API */ - dst->avail = true; + /* Assume legacy API if module data was not found in ext_init payload */ + if (!config->ipc_extended_init || !dst->ext_data->module_data) { + dst->init_data = cfg; /* legacy API */ + dst->avail = true; + } + return 0; } @@ -95,6 +216,7 @@ int module_adapter_set_state(struct processing_module *mod, struct comp_dev *dev { return comp_set_state(dev, cmd); } +EXPORT_SYMBOL(module_adapter_set_state); 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) @@ -123,7 +245,7 @@ int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ fragment_size = md->new_cfg_size - data_offset_size; break; default: - comp_err(dev, "module_set_large_config(): invalid fragment position"); + comp_err(dev, "invalid fragment position"); return -EINVAL; } @@ -133,7 +255,6 @@ int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ NULL, 0); return 0; } -EXPORT_SYMBOL(module_set_large_config); 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) @@ -150,10 +271,16 @@ int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ else fragment_size = SOF_IPC_MSG_MAX_SIZE; } else { - if (!last_block) + if (!last_block) { fragment_size = SOF_IPC_MSG_MAX_SIZE; - else + } else { + if (*data_offset_size > md->cfg.size) { + comp_err(dev, "invalid data_offset_size %u > cfg size %zu", + *data_offset_size, md->cfg.size); + return -EINVAL; + } fragment_size = md->cfg.size - *data_offset_size; + } } if (interface->get_configuration) @@ -165,46 +292,62 @@ int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ */ return -EIO; } -EXPORT_SYMBOL(module_get_large_config); int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value) { struct processing_module *mod = comp_mod(dev); + const struct module_interface *const interface = mod->dev->drv->adapter_ops; 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; + case COMP_ATTR_IPC4_CONFIG: + if (interface->get_config_param) + return interface->get_config_param(mod, (uint32_t *)value); + return -ENOEXEC; + default: + return -EINVAL; + } + + return 0; +} + +int module_adapter_set_attribute(struct comp_dev *dev, uint32_t type, void *value) +{ + struct processing_module *mod = comp_mod(dev); + const struct module_interface *const interface = mod->dev->drv->adapter_ops; + + switch (type) { + case COMP_ATTR_IPC4_CONFIG: + if (interface->set_config_param) + return interface->set_config_param(mod, *(uint32_t *)value); + return -ENOEXEC; default: return -EINVAL; } return 0; } -EXPORT_SYMBOL(module_adapter_get_attribute); static bool module_adapter_multi_sink_source_prepare(struct comp_dev *dev) { struct processing_module *mod = comp_mod(dev); - struct list_item *blist; + struct comp_buffer *sink_buffer; + struct comp_buffer *source_buffer; 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 = - container_of(blist, struct comp_buffer, source_list); + comp_dev_for_each_consumer(dev, sink_buffer) { mod->sinks[i] = audio_buffer_get_sink(&sink_buffer->audio_buffer); i++; } mod->num_of_sinks = i; i = 0; - list_for_item(blist, &dev->bsource_list) { - struct comp_buffer *source_buffer = - container_of(blist, struct comp_buffer, sink_list); - + comp_dev_for_each_producer(dev, source_buffer) { mod->sources[i] = audio_buffer_get_source(&source_buffer->audio_buffer); i++; } @@ -216,19 +359,54 @@ static bool module_adapter_multi_sink_source_prepare(struct comp_dev *dev) 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); + mod->sink_comp_buffer = comp_dev_get_first_data_consumer(dev); + mod->source_comp_buffer = comp_dev_get_first_data_producer(dev); return false; } -int module_adapter_bind(struct comp_dev *dev, void *data) +static int module_update_source_buffer_params(struct processing_module *mod, + struct bind_info *bind_data) +{ + struct module_config *dst = &mod->priv.cfg; + struct sof_ipc_stream_params params; + struct comp_buffer *buffer; + int dst_queue_id = bind_data->ipc4_data->extension.r.dst_queue; + + /* only update buffer params for sink components */ + if (bind_data->bind_type != COMP_BIND_TYPE_SOURCE) + return 0; + + comp_dev_for_each_producer(mod->dev, buffer) { + if (IPC4_SINK_QUEUE_ID(buffer->stream.runtime_stream_params.id) != dst_queue_id) + continue; + + /* use base_cfg params for pin 0 or if base config extn is missing */ + if (!dst_queue_id || dst_queue_id >= dst->nb_input_pins) { + buffer_set_params(buffer, mod->stream_params, BUFFER_UPDATE_FORCE); + return 0; + } + + /* otherwise use the respective input pin audio format */ + ipc4_audio_format_to_stream_params(&dst->input_pins[dst_queue_id].audio_fmt, + ¶ms); + buffer_set_params(buffer, ¶ms, BUFFER_UPDATE_FORCE); + return 0; + } + + return 0; +} + +int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data) { struct processing_module *mod = comp_mod(dev); int ret; - ret = module_bind(mod, data); + ret = module_update_source_buffer_params(mod, bind_data); + if (ret < 0) + return ret; + + ret = module_bind(mod, bind_data); if (ret < 0) return ret; @@ -236,14 +414,13 @@ int module_adapter_bind(struct comp_dev *dev, void *data) return 0; } -EXPORT_SYMBOL(module_adapter_bind); -int module_adapter_unbind(struct comp_dev *dev, void *data) +int module_adapter_unbind(struct comp_dev *dev, struct bind_info *unbind_data) { struct processing_module *mod = comp_mod(dev); int ret; - ret = module_unbind(mod, data); + ret = module_unbind(mod, unbind_data); if (ret < 0) return ret; @@ -251,7 +428,6 @@ int module_adapter_unbind(struct comp_dev *dev, void *data) return 0; } -EXPORT_SYMBOL(module_adapter_unbind); uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, uint32_t stream_no, bool input) @@ -267,7 +443,6 @@ uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, else return mod->total_data_consumed; } -EXPORT_SYMBOL(module_adapter_get_total_data_processed); int module_adapter_sink_src_prepare(struct comp_dev *dev) { diff --git a/src/audio/multiband_drc/CMakeLists.txt b/src/audio/multiband_drc/CMakeLists.txt index 3579af97f97b..0651cb9884e6 100644 --- a/src/audio/multiband_drc/CMakeLists.txt +++ b/src/audio/multiband_drc/CMakeLists.txt @@ -1,8 +1,15 @@ -add_local_sources(sof multiband_drc.c) -add_local_sources(sof multiband_drc_generic.c) +# SPDX-License-Identifier: BSD-3-Clause -if(CONFIG_IPC_MAJOR_3) - add_local_sources(sof multiband_drc_ipc3.c) -elseif(CONFIG_IPC_MAJOR_4) - add_local_sources(sof multiband_drc_ipc4.c) +if(CONFIG_COMP_MULTIBAND_DRC STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/multiband_drc_llext) + add_dependencies(app multiband_drc) +else() + add_local_sources(sof multiband_drc.c) + add_local_sources(sof multiband_drc_generic.c) + + if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof multiband_drc_ipc3.c) + elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof multiband_drc_ipc4.c) + endif() endif() diff --git a/src/audio/multiband_drc/Kconfig b/src/audio/multiband_drc/Kconfig index 5adb668497a4..07a67573cf24 100644 --- a/src/audio/multiband_drc/Kconfig +++ b/src/audio/multiband_drc/Kconfig @@ -5,7 +5,7 @@ config COMP_MULTIBAND_DRC tristate "Multiband Dynamic Range Compressor component" select CORDIC_FIXED select COMP_BLOB - default n + default m if LIBRARY_DEFAULT_MODULAR help Select for Multiband Dynamic Range Compressor (DRC) component. It consists of Emphasis Equalizer, n-way Crossover Filter, per-band DRC, diff --git a/src/audio/multiband_drc/README.md b/src/audio/multiband_drc/README.md new file mode 100644 index 000000000000..2a86e93ddbb6 --- /dev/null +++ b/src/audio/multiband_drc/README.md @@ -0,0 +1,27 @@ +# Multi-Band DRC Architecture + +This directory contains the Multi-Band Dynamic Range Compressor. + +## Overview + +Splits the audio into several discrete frequency bands (e.g., bass, mids, treble) and applies a separate instance of DRC to each band before remixing them. + +## Architecture Diagram + +```mermaid +graph LR + In[Audio Input] --> Splitter[Band Splitter] + Splitter --> DRC1[DRC Band 1] + Splitter --> DRC2[DRC Band 2] + DRC1 --> Sum[Mixer] + DRC2 --> Sum + Sum --> Out[Audio Output] +``` + +## Configuration and Scripts + +- **Kconfig**: Enables the Multiband Dynamic Range Compressor component (`COMP_MULTIBAND_DRC`). Has explicit dependencies on standard equalizers and filters: `COMP_IIR && COMP_CROSSOVER && COMP_DRC`. +- **CMakeLists.txt**: Compiles `multiband_drc.c` and generic versions, wrapping with IPC specifics (`multiband_drc_ipc3.c` or `multiband_drc_ipc4.c`). Supports Zephyr loadable extensions (`llext`). +- **multiband_drc.toml**: Defines module topology constraints and mapping (UUID `UUIDREG_STR_MULTIBAND_DRC`, module type 9). +- **Topology (.conf)**: Derived from `tools/topology/topology2/include/components/multiband_drc.conf`, configuring the `multiband_drc` widget object of type `effect` (UUID `56:22:9f:0d:4f:8e:b3:47:84:48:23:9a:33:4f:11:91`). Utilizes an internal switch control for `fc`. +- **MATLAB Tuning (`tune/`)**: Features `sof_example_multiband_drc.m` to generate the complex configuration structures necessary to bind multiple EQs, crossovers, and compressors together. The scripts output the aggregated `.m4`, binary `.bin`, and ALSA `.txt` blobs which define parameter blocks for each individual sub-system active within the multiband processor. diff --git a/src/audio/multiband_drc/multiband_drc.c b/src/audio/multiband_drc/multiband_drc.c index 3ffe8e0f511e..1c36c4e5c184 100644 --- a/src/audio/multiband_drc/multiband_drc.c +++ b/src/audio/multiband_drc/multiband_drc.c @@ -10,6 +10,7 @@ #include <sof/audio/ipc-config.h> #include <sof/audio/pipeline.h> #include <sof/ipc/msg.h> +#include <sof/lib/memory.h> #include <sof/lib/uuid.h> #include <sof/math/numbers.h> #include <module/crossover/crossover_common.h> @@ -38,36 +39,40 @@ LOG_MODULE_REGISTER(multiband_drc, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(multiband_drc); -DECLARE_TR_CTX(multiband_drc_tr, SOF_UUID(multiband_drc_uuid), LOG_LEVEL_INFO); - -static void multiband_drc_reset_state(struct multiband_drc_state *state) +/* Called from multiband_drc_setup() from multiband_drc_process(), so cannot be __cold */ +static void multiband_drc_reset_state(struct processing_module *mod, + struct multiband_drc_state *state) { int i; /* Reset emphasis eq-iir state */ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) - multiband_drc_iir_reset_state_ch(&state->emphasis[i]); + multiband_drc_iir_reset_state_ch(mod, &state->emphasis[i]); /* Reset crossover state */ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) - crossover_reset_state_ch(&state->crossover[i]); + crossover_reset_state_ch(mod, &state->crossover[i]); /* Reset drc kernel state */ for (i = 0; i < SOF_MULTIBAND_DRC_MAX_BANDS; i++) - drc_reset_state(&state->drc[i]); + drc_reset_state(mod, &state->drc[i]); /* Reset deemphasis eq-iir state */ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) - multiband_drc_iir_reset_state_ch(&state->deemphasis[i]); + multiband_drc_iir_reset_state_ch(mod, &state->deemphasis[i]); } -static int multiband_drc_eq_init_coef_ch(struct sof_eq_iir_biquad *coef, - struct iir_state_df2t *eq) +static int multiband_drc_eq_init_coef_ch(struct processing_module *mod, + struct sof_eq_iir_biquad *coef, + struct iir_state_df1 *eq) { int ret; - eq->coef = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(struct sof_eq_iir_biquad) * SOF_EMP_DEEMP_BIQUADS); + /* Ensure the LR4 can be processed with the simplified 4th order IIR */ + if (SOF_EMP_DEEMP_BIQUADS != SOF_IIR_DF1_4TH_NUM_BIQUADS) + return -EINVAL; + + eq->coef = mod_zalloc(mod, sizeof(struct sof_eq_iir_biquad) * SOF_EMP_DEEMP_BIQUADS); if (!eq->coef) return -ENOMEM; @@ -80,8 +85,7 @@ static int multiband_drc_eq_init_coef_ch(struct sof_eq_iir_biquad *coef, * delay[0..1] -> state for first biquad * delay[2..3] -> state for second biquad */ - eq->delay = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(uint64_t) * CROSSOVER_NUM_DELAYS_LR4); + eq->delay = mod_zalloc(mod, sizeof(uint64_t) * CROSSOVER_NUM_DELAYS_LR4); if (!eq->delay) return -ENOMEM; @@ -104,7 +108,7 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u int i, ch, ret, num_bands; if (!config) { - comp_err(dev, "multiband_drc_init_coef(), no config is set"); + comp_err(dev, "no config is set"); return -EINVAL; } @@ -113,22 +117,22 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u /* Sanity checks */ if (nch > PLATFORM_MAX_CHANNELS) { comp_err(dev, - "multiband_drc_init_coef(), invalid channels count(%i)", nch); + "invalid channels count(%i)", nch); return -EINVAL; } if (config->num_bands > SOF_MULTIBAND_DRC_MAX_BANDS) { - comp_err(dev, "multiband_drc_init_coef(), invalid bands count(%i)", + comp_err(dev, "invalid bands count(%i)", config->num_bands); return -EINVAL; } - comp_info(dev, "multiband_drc_init_coef(), initializing %i-way crossover", + comp_info(dev, "initializing %i-way crossover", config->num_bands); /* Crossover: determine the split function */ cd->crossover_split = crossover_find_split_func(config->num_bands); if (!cd->crossover_split) { - comp_err(dev, "multiband_drc_init_coef(), No crossover_split for band count(%i)", + comp_err(dev, "No crossover_split for band count(%i)", config->num_bands); return -EINVAL; } @@ -136,39 +140,39 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u /* Crossover: collect the coef array and assign it to every channel */ crossover = config->crossover_coef; for (ch = 0; ch < nch; ch++) { - ret = crossover_init_coef_ch(crossover, &state->crossover[ch], + ret = crossover_init_coef_ch(mod, crossover, &state->crossover[ch], config->num_bands); /* Free all previously allocated blocks in case of an error */ if (ret < 0) { comp_err(dev, - "multiband_drc_init_coef(), could not assign coeffs to ch %d", ch); + "could not assign coeffs to ch %d", ch); goto err; } } - comp_info(dev, "multiband_drc_init_coef(), initializing emphasis_eq"); + comp_info(dev, "initializing emphasis_eq"); /* Emphasis: collect the coef array and assign it to every channel */ emphasis = config->emp_coef; for (ch = 0; ch < nch; ch++) { - ret = multiband_drc_eq_init_coef_ch(emphasis, &state->emphasis[ch]); + ret = multiband_drc_eq_init_coef_ch(mod, emphasis, &state->emphasis[ch]); /* Free all previously allocated blocks in case of an error */ if (ret < 0) { - comp_err(dev, "multiband_drc_init_coef(), could not assign coeffs to ch %d", + comp_err(dev, "could not assign coeffs to ch %d", ch); goto err; } } - comp_info(dev, "multiband_drc_init_coef(), initializing deemphasis_eq"); + comp_info(dev, "initializing deemphasis_eq"); /* Deemphasis: collect the coef array and assign it to every channel */ deemphasis = config->deemp_coef; for (ch = 0; ch < nch; ch++) { - ret = multiband_drc_eq_init_coef_ch(deemphasis, &state->deemphasis[ch]); + ret = multiband_drc_eq_init_coef_ch(mod, deemphasis, &state->deemphasis[ch]); /* Free all previously allocated blocks in case of an error */ if (ret < 0) { - comp_err(dev, "multiband_drc_init_coef(), could not assign coeffs to ch %d", + comp_err(dev, "could not assign coeffs to ch %d", ch); goto err; } @@ -176,19 +180,20 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u /* Allocate all DRC pre-delay buffers and set delay time with band number */ for (i = 0; i < num_bands; i++) { - comp_info(dev, "multiband_drc_init_coef(), initializing drc band %d", i); + comp_info(dev, "initializing drc band %d", i); - ret = drc_init_pre_delay_buffers(&state->drc[i], (size_t)sample_bytes, (int)nch); + ret = drc_init_pre_delay_buffers(mod, &state->drc[i], + (size_t)sample_bytes, (int)nch); if (ret < 0) { comp_err(dev, - "multiband_drc_init_coef(), could not init pre delay buffers"); + "could not init pre delay buffers"); goto err; } ret = drc_set_pre_delay_time(&state->drc[i], cd->config->drc_coef[i].pre_delay_time, rate); if (ret < 0) { - comp_err(dev, "multiband_drc_init_coef(), could not set pre delay time"); + comp_err(dev, "could not set pre delay time"); goto err; } } @@ -196,16 +201,18 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u return 0; err: - multiband_drc_reset_state(state); + multiband_drc_reset_state(mod, state); return ret; } -static int multiband_drc_setup(struct processing_module *mod, int16_t channels, uint32_t rate) +/* Called from multiband_drc_process(), so cannot be __cold */ +static int multiband_drc_setup(struct processing_module *mod, int16_t channels, + uint32_t rate) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); /* Reset any previous state */ - multiband_drc_reset_state(&cd->state); + multiband_drc_reset_state(mod, &cd->state); /* Setup Crossover, Emphasis EQ, Deemphasis EQ, and DRC */ return multiband_drc_init_coef(mod, channels, rate); @@ -219,23 +226,11 @@ static int multiband_drc_init(struct processing_module *mod) { struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; - struct module_config *cfg = &md->cfg; struct multiband_drc_comp_data *cd; - size_t bs = cfg->size; - int ret; - - comp_info(dev, "multiband_drc_init()"); - /* Check first before proceeding with dev and cd that coefficients - * blob size is sane. - */ - if (bs > SOF_MULTIBAND_DRC_MAX_BLOB_SIZE) { - comp_err(dev, "multiband_drc_init(), error: configuration blob size = %u > %d", - bs, SOF_MULTIBAND_DRC_MAX_BLOB_SIZE); - return -EINVAL; - } + comp_info(dev, "entry"); - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -250,62 +245,57 @@ static int multiband_drc_init(struct processing_module *mod) multiband_drc_process_enable(&cd->process_enabled); /* Handler for configuration data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "multiband_drc_init(): comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto cd_fail; + comp_err(dev, "comp_data_blob_handler_new() failed."); + mod_free(mod, cd); + return -ENOMEM; } - /* Get configuration data and reset DRC state */ - ret = comp_init_data_blob(cd->model_handler, bs, cfg->data); - if (ret < 0) { - comp_err(dev, "multiband_drc_init(): comp_init_data_blob() failed."); - goto cd_fail; - } - multiband_drc_reset_state(&cd->state); + multiband_drc_reset_state(mod, &cd->state); return 0; - -cd_fail: - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); - return ret; } -static int multiband_drc_free(struct processing_module *mod) +__cold static int multiband_drc_free(struct processing_module *mod) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "multiband_drc_free()"); + assert_can_be_cold(); + + comp_info(mod->dev, "entry"); - comp_data_blob_handler_free(cd->model_handler); + mod_data_blob_handler_free(mod, cd->model_handler); - rfree(cd); + mod_free(mod, cd); return 0; } -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) +__cold 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 comp_dev *dev = mod->dev; - comp_dbg(dev, "multiband_drc_set_config()"); + assert_can_be_cold(); + + comp_dbg(dev, "entry"); return multiband_drc_set_ipc_config(mod, param_id, fragment, pos, data_offset_size, fragment_size); } -static int multiband_drc_get_config(struct processing_module *mod, - uint32_t config_id, uint32_t *data_offset_size, - uint8_t *fragment, size_t fragment_size) +__cold static int multiband_drc_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) { struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; - comp_dbg(mod->dev, "multiband_drc_get_config()"); + assert_can_be_cold(); + + comp_dbg(mod->dev, "entry"); return multiband_drc_get_ipc_config(mod, cdata, fragment_size); } @@ -322,7 +312,7 @@ static int multiband_drc_process(struct processing_module *mod, int frames = input_buffers[0].size; int ret; - comp_dbg(dev, "multiband_drc_process()"); + comp_dbg(dev, "entry"); /* Check for changed configuration */ if (comp_is_new_data_blob_available(cd->model_handler)) { @@ -330,7 +320,7 @@ static int multiband_drc_process(struct processing_module *mod, ret = multiband_drc_setup(mod, (int16_t)audio_stream_get_channels(sink), audio_stream_get_rate(sink)); if (ret < 0) { - comp_err(dev, "multiband_drc_process(), failed DRC setup"); + comp_err(dev, "failed DRC setup"); return ret; } } @@ -352,11 +342,12 @@ static int multiband_drc_prepare(struct processing_module *mod, struct multiband_drc_comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; struct comp_buffer *sourceb; + size_t data_size; int channels; int rate; int ret = 0; - comp_info(dev, "multiband_drc_prepare()"); + comp_info(dev, "entry"); ret = multiband_drc_params(mod); if (ret < 0) @@ -364,6 +355,10 @@ static int multiband_drc_prepare(struct processing_module *mod, /* DRC component will only ever have 1 source and 1 sink buffer */ sourceb = comp_dev_get_first_data_producer(dev); + if (!sourceb) { + comp_err(dev, "no source buffer"); + return -ENOTCONN; + } /* get source data format */ cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); @@ -371,20 +366,27 @@ static int multiband_drc_prepare(struct processing_module *mod, rate = audio_stream_get_rate(&sourceb->stream); /* Initialize DRC */ - comp_dbg(dev, "multiband_drc_prepare(), source_format=%d, sink_format=%d", + comp_dbg(dev, "source_format=%d, sink_format=%d", cd->source_format, cd->source_format); - cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - if (cd->config) { + cd->config = comp_get_data_blob(cd->model_handler, &data_size, NULL); + /* the blob holds a base struct followed by num_bands variable-length + * band coefficients; require the base struct first, then the full + * per-band payload, so setup cannot read past the blob + */ + if (cd->config && data_size >= sizeof(struct sof_multiband_drc_config) && + cd->config->num_bands <= SOF_MULTIBAND_DRC_MAX_BANDS && + data_size >= sizeof(struct sof_multiband_drc_config) + + (size_t)cd->config->num_bands * sizeof(struct sof_drc_params)) { ret = multiband_drc_setup(mod, channels, rate); if (ret < 0) { - comp_err(dev, "multiband_drc_prepare() error: multiband_drc_setup failed."); + comp_err(dev, "error: multiband_drc_setup failed."); return ret; } } cd->multiband_drc_func = multiband_drc_find_proc_func(cd->source_format); if (!cd->multiband_drc_func) { - comp_err(dev, "multiband_drc_prepare(), No proc func"); + comp_err(dev, "No proc func"); return -EINVAL; } @@ -395,9 +397,9 @@ static int multiband_drc_reset(struct processing_module *mod) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "multiband_drc_reset()"); + comp_info(mod->dev, "entry"); - multiband_drc_reset_state(&cd->state); + multiband_drc_reset_state(mod, &cd->state); cd->source_format = 0; cd->multiband_drc_func = NULL; @@ -416,9 +418,6 @@ static const struct module_interface multiband_drc_interface = { .free = multiband_drc_free }; -DECLARE_MODULE_ADAPTER(multiband_drc_interface, multiband_drc_uuid, multiband_drc_tr); -SOF_MODULE_INIT(multiband_drc, sys_comp_module_multiband_drc_interface_init); - #if CONFIG_COMP_MULTIBAND_DRC_MODULE /* modular: llext dynamic link */ @@ -426,14 +425,16 @@ SOF_MODULE_INIT(multiband_drc, sys_comp_module_multiband_drc_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_MULTIBAND_DRC 0x56, 0x22, 0x9F, 0x0D, 0x4F, 0x8E, 0xB3, 0x47, 0x48, 0x84, \ - 0x23, 0x9A, 0x33, 0x4F, 0x11, 0x91 - -SOF_LLEXT_MOD_ENTRY(multiband_drc, &multiband_drc_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("MB_DRC", multiband_drc_llext_entry, 1, UUID_MULTIBAND_DRC, 40); + SOF_LLEXT_MODULE_MANIFEST("MB_DRC", &multiband_drc_interface, 1, + SOF_REG_UUID(multiband_drc), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(multiband_drc_tr, SOF_UUID(multiband_drc_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(multiband_drc_interface, multiband_drc_uuid, multiband_drc_tr); +SOF_MODULE_INIT(multiband_drc, sys_comp_module_multiband_drc_interface_init); + #endif diff --git a/src/audio/multiband_drc/multiband_drc.h b/src/audio/multiband_drc/multiband_drc.h index 26ba6dcf33ae..6a99fda55cef 100644 --- a/src/audio/multiband_drc/multiband_drc.h +++ b/src/audio/multiband_drc/multiband_drc.h @@ -9,7 +9,7 @@ #include <sof/audio/module_adapter/module/generic.h> #include <module/crossover/crossover_common.h> -#include <sof/math/iir_df2t.h> +#include <sof/math/iir_df1.h> #include <sof/audio/component.h> #include <sof/audio/data_blob.h> #include <sof/platform.h> @@ -22,10 +22,10 @@ * Stores the state of the sub-components in Multiband DRC */ struct multiband_drc_state { - struct iir_state_df2t emphasis[PLATFORM_MAX_CHANNELS]; + struct iir_state_df1 emphasis[PLATFORM_MAX_CHANNELS]; struct crossover_state crossover[PLATFORM_MAX_CHANNELS]; struct drc_state drc[SOF_MULTIBAND_DRC_MAX_BANDS]; - struct iir_state_df2t deemphasis[PLATFORM_MAX_CHANNELS]; + struct iir_state_df1 deemphasis[PLATFORM_MAX_CHANNELS]; }; typedef void (*multiband_drc_func)(const struct processing_module *mod, @@ -89,10 +89,11 @@ static inline multiband_drc_func multiband_drc_find_proc_func_pass(enum sof_ipc_ return NULL; } -static inline void multiband_drc_iir_reset_state_ch(struct iir_state_df2t *iir) +static inline void multiband_drc_iir_reset_state_ch(struct processing_module *mod, + struct iir_state_df1 *iir) { - rfree(iir->coef); - rfree(iir->delay); + mod_free(mod, iir->coef); + mod_free(mod, iir->delay); iir->coef = NULL; iir->delay = NULL; diff --git a/src/audio/multiband_drc/multiband_drc.toml b/src/audio/multiband_drc/multiband_drc.toml index 008da93dcef0..5ac07295d4a1 100644 --- a/src/audio/multiband_drc/multiband_drc.toml +++ b/src/audio/multiband_drc/multiband_drc.toml @@ -5,7 +5,7 @@ REM # Multiband-DRC module config [[module.entry]] name = "MB_DRC" - uuid = "0D9F2256-8E4F-47B3-8448-239A334F1191" + uuid = UUIDREG_STR_MULTIBAND_DRC affinity_mask = "0x1" instance_count = "40" domain_types = "0" diff --git a/src/audio/multiband_drc/multiband_drc_generic.c b/src/audio/multiband_drc/multiband_drc_generic.c index 2a26f12f03eb..bd64f5012fc8 100644 --- a/src/audio/multiband_drc/multiband_drc_generic.c +++ b/src/audio/multiband_drc/multiband_drc_generic.c @@ -6,7 +6,7 @@ #include <stdint.h> #include <sof/audio/format.h> -#include <sof/math/iir_df2t.h> +#include <sof/math/iir_df1.h> #include "multiband_drc.h" #include "../drc/drc_algorithm.h" @@ -27,7 +27,7 @@ static void multiband_drc_process_emp_crossover(struct multiband_drc_state *stat int nch, int nband) { - struct iir_state_df2t *emp_s; + struct iir_state_df1 *emp_s; struct crossover_state *crossover_s; int32_t *buf_sink_band; int ch, band; @@ -39,7 +39,7 @@ static void multiband_drc_process_emp_crossover(struct multiband_drc_state *stat crossover_s = &state->crossover[ch]; if (enable_emp) - emp_out = iir_df2t(emp_s, *buf_src); + emp_out = iir_df1_4th(emp_s, *buf_src); else emp_out = *buf_src; @@ -162,7 +162,7 @@ static void multiband_drc_process_deemp(struct multiband_drc_state *state, int nch, int nband) { - struct iir_state_df2t *deemp_s; + struct iir_state_df1 *deemp_s; int32_t *buf_src_band; int ch, band; int32_t mix_out; @@ -178,7 +178,7 @@ static void multiband_drc_process_deemp(struct multiband_drc_state *state, } if (enable_deemp) - *buf_sink = iir_df2t(deemp_s, mix_out); + *buf_sink = iir_df1_4th(deemp_s, mix_out); else *buf_sink = mix_out; diff --git a/src/audio/multiband_drc/multiband_drc_ipc3.c b/src/audio/multiband_drc/multiband_drc_ipc3.c index fdc9de9e5ba9..04aa4fc33e40 100644 --- a/src/audio/multiband_drc/multiband_drc_ipc3.c +++ b/src/audio/multiband_drc/multiband_drc_ipc3.c @@ -30,10 +30,10 @@ static int multiband_drc_cmd_set_value(struct processing_module *mod, switch (cdata->cmd) { case SOF_CTRL_CMD_SWITCH: - comp_dbg(dev, "multiband_drc_multiband_drc_cmd_set_value(), SOF_CTRL_CMD_SWITCH"); + comp_dbg(dev, "multiband_drc_SOF_CTRL_CMD_SWITCH"); if (cdata->num_elems == 1) { cd->process_enabled = cdata->chanv[0].value; - comp_info(dev, "multiband_drc_cmd_set_value(), process_enabled = %d", + comp_info(dev, "process_enabled = %d", cd->process_enabled); return 0; } @@ -68,13 +68,13 @@ static int multiband_drc_cmd_get_value(struct processing_module *mod, switch (cdata->cmd) { case SOF_CTRL_CMD_SWITCH: - comp_dbg(dev, "multiband_drc_cmd_get_value(), SOF_CTRL_CMD_SWITCH"); + comp_dbg(dev, "SOF_CTRL_CMD_SWITCH"); for (j = 0; j < cdata->num_elems; j++) cdata->chanv[j].value = cd->process_enabled; if (cdata->num_elems == 1) return 0; - comp_warn(dev, "multiband_drc_cmd_get_value() warn: num_elems should be 1, got %d", + comp_warn(dev, "warn: num_elems should be 1, got %d", cdata->num_elems); return 0; } @@ -91,7 +91,7 @@ int multiband_drc_get_ipc_config(struct processing_module *mod, struct sof_ipc_c if (cdata->cmd != SOF_CTRL_CMD_BINARY) return multiband_drc_cmd_get_value(mod, cdata); - comp_dbg(mod->dev, "multiband_drc_get_ipc_config(), SOF_CTRL_CMD_BINARY"); + comp_dbg(mod->dev, "SOF_CTRL_CMD_BINARY"); return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); } diff --git a/src/audio/multiband_drc/multiband_drc_ipc4.c b/src/audio/multiband_drc/multiband_drc_ipc4.c index a573d1101c5b..ac2a7a7426aa 100644 --- a/src/audio/multiband_drc/multiband_drc_ipc4.c +++ b/src/audio/multiband_drc/multiband_drc_ipc4.c @@ -16,6 +16,7 @@ #include <ipc/stream.h> #include <sof/audio/buffer.h> #include <sof/audio/audio_stream.h> +#include <sof/lib/memory.h> #include <sof/list.h> #include "multiband_drc.h" @@ -27,9 +28,10 @@ void multiband_drc_process_enable(bool *process_enabled) *process_enabled = true; } -int multiband_drc_set_ipc_config(struct processing_module *mod, uint32_t param_id, - const uint8_t *fragment, enum module_cfg_fragment_position pos, - uint32_t data_offset_size, size_t fragment_size) +__cold int multiband_drc_set_ipc_config(struct processing_module *mod, uint32_t param_id, + const uint8_t *fragment, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, size_t fragment_size) { struct sof_ipc4_control_msg_payload *ctl = (struct sof_ipc4_control_msg_payload *)fragment; struct multiband_drc_comp_data *cd = module_get_private_data(mod); @@ -52,21 +54,21 @@ int multiband_drc_set_ipc_config(struct processing_module *mod, uint32_t param_i return 0; case SOF_IPC4_ENUM_CONTROL_PARAM_ID: - comp_err(dev, "multiband_drc_set_ipc_config(), illegal control."); + comp_err(dev, "illegal control."); return -EINVAL; } - comp_dbg(mod->dev, "multiband_drc_set_ipc_config(), SOF_CTRL_CMD_BINARY"); + comp_dbg(mod->dev, "SOF_CTRL_CMD_BINARY"); return comp_data_blob_set(cd->model_handler, pos, data_offset_size, fragment, fragment_size); } -int multiband_drc_get_ipc_config(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata, - size_t fragment_size) +__cold int multiband_drc_get_ipc_config(struct processing_module *mod, + struct sof_ipc_ctrl_data *cdata, size_t fragment_size) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "multiband_drc_get_ipc_config(), SOF_CTRL_CMD_BINARY"); + comp_dbg(mod->dev, "SOF_CTRL_CMD_BINARY"); return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); } @@ -78,9 +80,9 @@ int multiband_drc_params(struct processing_module *mod) struct comp_dev *dev = mod->dev; struct comp_buffer *sinkb; enum sof_ipc_frame valid_fmt, frame_fmt; - int i, ret; + int i; - comp_dbg(dev, "multiband_drc_params()"); + comp_dbg(dev, "entry"); comp_params = *params; comp_params.channels = mod->priv.cfg.base_cfg.audio_fmt.channels_count; @@ -99,8 +101,11 @@ int multiband_drc_params(struct processing_module *mod) component_set_nearest_period_frames(dev, comp_params.rate); sinkb = comp_dev_get_first_data_consumer(dev); - ret = buffer_set_params(sinkb, &comp_params, true); + if (!sinkb) { + comp_err(dev, "no sink buffer"); + return -ENOTCONN; + } - return ret; + return buffer_set_params(sinkb, &comp_params, true); } diff --git a/src/audio/multiband_drc/tune/sof_example_multiband_drc.m b/src/audio/multiband_drc/tune/sof_example_multiband_drc.m index 2626c1600310..9ebd3ef56b97 100644 --- a/src/audio/multiband_drc/tune/sof_example_multiband_drc.m +++ b/src/audio/multiband_drc/tune/sof_example_multiband_drc.m @@ -39,9 +39,9 @@ function export_multiband_drc(prm) tplg1_fn = sprintf("%s/topology/topology1/m4/multiband_drc_coef_%s.m4", sof_tools, prm.name); % Control Bytes File tplg2_fn = sprintf("%s/topology/topology2/include/components/multiband_drc/%s.conf", sof_tools, prm.name); % Control Bytes File % Use those files with sof-ctl to update the component's configuration -blob3_fn = sprintf("%s/ctl/ipc3/multiband_drc/%s.blob", sof_tools, prm.name); % Blob binary file +blob3_fn = sprintf("%s/ctl/ipc3/multiband_drc/%s.bin", sof_tools, prm.name); % Blob binary file alsa3_fn = sprintf("%s/ctl/ipc3/multiband_drc/%s.txt", sof_tools, prm.name); % ALSA CSV format file -blob4_fn = sprintf("%s/ctl/ipc4/multiband_drc/%s.blob", sof_tools, prm.name); % Blob binary file +blob4_fn = sprintf("%s/ctl/ipc4/multiband_drc/%s.bin", sof_tools, prm.name); % Blob binary file alsa4_fn = sprintf("%s/ctl/ipc4/multiband_drc/%s.txt", sof_tools, prm.name); % ALSA CSV format file endian = "little"; @@ -117,12 +117,12 @@ function export_multiband_drc(prm) deemp_coefs, crossover_coefs, drc_coefs, ... endian, 4); -tplg_write(tplg1_fn, blob8, "MULTIBAND_DRC"); -tplg2_write(tplg2_fn, blob8_ipc4, "multiband_drc_config", "Exported with script sof_example_multiband_drc.m"); +sof_tplg_write(tplg1_fn, blob8, "MULTIBAND_DRC"); +sof_tplg2_write(tplg2_fn, blob8_ipc4, "multiband_drc_config", "Exported with script sof_example_multiband_drc.m"); sof_ucm_blob_write(blob3_fn, blob8); -alsactl_write(alsa3_fn, blob8); +sof_alsactl_write(alsa3_fn, blob8); sof_ucm_blob_write(blob4_fn, blob8_ipc4); -alsactl_write(alsa4_fn, blob8_ipc4); +sof_alsactl_write(alsa4_fn, blob8_ipc4); sof_multiband_drc_paths(false); diff --git a/src/audio/multiband_drc/tune/sof_multiband_drc_build_blob.m b/src/audio/multiband_drc/tune/sof_multiband_drc_build_blob.m index ab3fc063a8ec..520c38e9a2e4 100644 --- a/src/audio/multiband_drc/tune/sof_multiband_drc_build_blob.m +++ b/src/audio/multiband_drc/tune/sof_multiband_drc_build_blob.m @@ -28,7 +28,7 @@ crossover_data_num = numel(crossover_coefs); drc_data_num = numel(fieldnames(drc_coefs(1))) * length(drc_coefs); data_size = 4 * (1 + 1 + 1 + 8 + emp_data_num + deemp_data_num + crossover_data_num + drc_data_num); -[abi_bytes, abi_size] = get_abi(data_size, ipc_ver); +[abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver); blob_size = data_size + abi_size; blob8 = uint8(zeros(1, blob_size)); diff --git a/src/audio/mux/CMakeLists.txt b/src/audio/mux/CMakeLists.txt index a7b890cb3512..e8872dfd41d4 100644 --- a/src/audio/mux/CMakeLists.txt +++ b/src/audio/mux/CMakeLists.txt @@ -1,10 +1,14 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof mux.c mux_generic.c) +if(CONFIG_COMP_MUX STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/mux_llext) + add_dependencies(app mux) +else() + add_local_sources(sof mux.c mux_generic.c) -if(CONFIG_IPC_MAJOR_3) - add_local_sources(sof mux_ipc3.c) -elseif(CONFIG_IPC_MAJOR_4) - add_local_sources(sof mux_ipc4.c) + if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof mux_ipc3.c) + elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof mux_ipc4.c) + endif() endif() - diff --git a/src/audio/mux/README.md b/src/audio/mux/README.md new file mode 100644 index 000000000000..97a5a3905b5e --- /dev/null +++ b/src/audio/mux/README.md @@ -0,0 +1,23 @@ +# Multiplexer/Demultiplexer Architecture + +This directory contains the Mux/Demux component. + +## Overview + +Selects between multiple audio paths, routing N inputs to 1 output, or 1 input to N outputs. + +## Architecture Diagram + +```mermaid +graph LR + In1[Path A] --> Mux[Path Selector] + In2[Path B] --> Mux + Mux --> Out[Selected Path] +``` + +## Configuration and Scripts + +- **Kconfig**: Enables the MUX component (`COMP_MUX`), relying on the standard `COMP_MODULE_ADAPTER`. +- **CMakeLists.txt**: Manages `mux.c` and generic code paths alongside IPC abstraction interfaces (`mux_ipc3.c`, `mux_ipc4.c`). Supports `llext` modular integration. +- **mux.toml**: Topology settings defining UUID `UUIDREG_STR_MUX4` and accommodating up to 15 concurrent instances with multiple 10-channel I/O pins. +- **Topology (.conf)**: Found at `tools/topology/topology2/include/components/muxdemux.conf`, which declares a `muxdemux` widget object. Provides flexible process typing such as `DEMUX` with type `effect` (UUID `68:68:b2:c4:30:14:0e:47:a0:89:15:d1:c7:7f:85:1a`). diff --git a/src/audio/mux/mux.c b/src/audio/mux/mux.c index 8d65b2b2698d..1476779e7324 100644 --- a/src/audio/mux/mux.c +++ b/src/audio/mux/mux.c @@ -11,7 +11,6 @@ #include <sof/audio/ipc-config.h> #include <sof/common.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/uuid.h> #include <sof/list.h> @@ -89,19 +88,18 @@ static int mux_demux_common_init(struct processing_module *mod, enum sof_comp_ty comp_dbg(dev, "mux_init()"); if (cfg->size > MUX_BLOB_MAX_SIZE) { - comp_err(dev, "mux_init(): blob size %zu exceeds %zu", + comp_err(dev, "blob size %zu exceeds %zu", cfg->size, MUX_BLOB_MAX_SIZE); return -EINVAL; } - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(*cd) + MUX_BLOB_STREAMS_SIZE); + cd = mod_zalloc(mod, sizeof(*cd) + MUX_BLOB_STREAMS_SIZE); if (!cd) return -ENOMEM; - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "mux_init(): comp_data_blob_handler_new() failed."); + comp_err(dev, "mod_data_blob_handler_new() failed."); ret = -ENOMEM; goto err; } @@ -109,7 +107,7 @@ static int mux_demux_common_init(struct processing_module *mod, enum sof_comp_ty module_data->private = cd; ret = comp_init_data_blob(cd->model_handler, cfg->size, cfg->init_data); if (ret < 0) { - comp_err(dev, "mux_init(): comp_init_data_blob() failed."); + comp_err(dev, "module data blob initialization failed."); goto err_init; } @@ -119,10 +117,10 @@ static int mux_demux_common_init(struct processing_module *mod, enum sof_comp_ty return 0; err_init: - comp_data_blob_handler_free(cd->model_handler); + mod_data_blob_handler_free(mod, cd->model_handler); err: - rfree(cd); + mod_free(mod, cd); return ret; } @@ -133,21 +131,14 @@ static int mux_init(struct processing_module *mod) return mux_demux_common_init(mod, SOF_COMP_MUX); } -static int demux_init(struct processing_module *mod) -{ - mod->max_sinks = MUX_MAX_STREAMS; - - return mux_demux_common_init(mod, SOF_COMP_DEMUX); -} - static int mux_free(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "mux_free()"); + comp_dbg(mod->dev, "entry"); - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); + mod_data_blob_handler_free(mod, cd->model_handler); + mod_free(mod, cd); return 0; } @@ -159,25 +150,11 @@ static int get_stream_index(struct comp_dev *dev, struct comp_data *cd, uint32_t if (cd->config.streams[idx].pipeline_id == pipe_id) return idx; - comp_err(dev, "get_stream_index(): couldn't find configuration for connected pipeline %u", + comp_err(dev, "couldn't find configuration for connected pipeline %u", pipe_id); return -EINVAL; } -static struct mux_look_up *get_lookup_table(struct comp_dev *dev, struct comp_data *cd, - uint32_t pipe_id) -{ - int i; - - for (i = 0; i < MUX_MAX_STREAMS; i++) - if (cd->config.streams[i].pipeline_id == pipe_id) - return &cd->lookup[i]; - - comp_err(dev, "get_lookup_table(): couldn't find configuration for connected pipeline %u", - pipe_id); - return 0; -} - static void mux_prepare_active_look_up(struct comp_data *cd, struct audio_stream *sink, const struct audio_stream **sources) @@ -203,6 +180,28 @@ static void mux_prepare_active_look_up(struct comp_data *cd, cd->active_lookup.num_elems = active_elem; } +#if !CONFIG_COMP_MUX_MODULE +static int demux_init(struct processing_module *mod) +{ + mod->max_sinks = MUX_MAX_STREAMS; + + return mux_demux_common_init(mod, SOF_COMP_DEMUX); +} + +static struct mux_look_up *get_lookup_table(struct comp_dev *dev, struct comp_data *cd, + uint32_t pipe_id) +{ + int i; + + for (i = 0; i < MUX_MAX_STREAMS; i++) + if (cd->config.streams[i].pipeline_id == pipe_id) + return &cd->lookup[i]; + + comp_err(dev, "couldn't find configuration for connected pipeline %u", + pipe_id); + return 0; +} + static void demux_prepare_active_look_up(struct comp_data *cd, struct audio_stream *sink, const struct audio_stream *source, @@ -239,7 +238,7 @@ static int demux_process(struct processing_module *mod, int source_bytes; int i; - comp_dbg(dev, "demux_process()"); + comp_dbg(dev, "entry"); /* align sink streams with their respective configurations */ comp_dev_for_each_consumer(dev, sink) { @@ -279,6 +278,31 @@ static int demux_process(struct processing_module *mod, return 0; } +static int demux_trigger(struct processing_module *mod, int cmd) +{ + /* Check for cross-pipeline sinks: in general foreign + * pipelines won't be started synchronously with ours (it's + * under control of host software), so output can't be + * guaranteed not to overflow. Always set the + * overrun_permitted flag. These sink components are assumed + * responsible for flushing/synchronizing the stream + * themselves. + */ + if (cmd == COMP_TRIGGER_PRE_START) { + struct comp_buffer *b; + struct comp_dev *sink_comp; + + comp_dev_for_each_consumer(mod->dev, b) { + sink_comp = comp_buffer_get_sink_component(b); + if (sink_comp && sink_comp->pipeline != mod->dev->pipeline) + audio_stream_set_overrun(&b->stream, true); + } + } + + return module_adapter_set_state(mod, mod->dev, cmd); +} +#endif + /* process and copy stream data from source to sink buffers */ static int mux_process(struct processing_module *mod, struct input_stream_buffer *input_buffers, int num_input_buffers, @@ -290,10 +314,9 @@ static int mux_process(struct processing_module *mod, const struct audio_stream *sources_stream[MUX_MAX_STREAMS] = { NULL }; int frames = 0; int sink_bytes; - int source_bytes; int i, j; - comp_dbg(dev, "mux_process()"); + comp_dbg(dev, "entry"); /* align source streams with their respective configurations */ j = 0; @@ -319,18 +342,18 @@ static int mux_process(struct processing_module *mod, if (num_input_buffers == 0) return 0; - source_bytes = frames * audio_stream_frame_bytes(mod->input_buffers[0].data); sink_bytes = frames * audio_stream_frame_bytes(mod->output_buffers[0].data); mux_prepare_active_look_up(cd, output_buffers[0].data, &sources_stream[0]); /* produce output */ cd->mux(dev, output_buffers[0].data, &sources_stream[0], frames, &cd->active_lookup); - /* Update consumed and produced */ + /* Update consumed per source using each source's own frame size */ j = 0; comp_dev_for_each_producer(dev, source) { if (comp_buffer_get_source_state(source) == dev->state) - mod->input_buffers[j].consumed = source_bytes; + mod->input_buffers[j].consumed = + frames * audio_stream_frame_bytes(mod->input_buffers[j].data); j++; } mod->output_buffers[0].size = sink_bytes; @@ -344,7 +367,7 @@ static int mux_reset(struct processing_module *mod) struct comp_dev *dev = mod->dev; int dir = dev->pipeline->source_comp->direction; - comp_dbg(dev, "mux_reset()"); + comp_dbg(dev, "entry"); if (dir == SOF_IPC_STREAM_PLAYBACK) { comp_dev_for_each_producer(dev, source) { @@ -368,19 +391,9 @@ static int mux_prepare(struct processing_module *mod, { struct comp_dev *dev = mod->dev; struct comp_data *cd = module_get_private_data(mod); - struct sof_mux_config *config; - size_t blob_size; int ret; - comp_dbg(dev, "mux_prepare()"); - - config = comp_get_data_blob(cd->model_handler, &blob_size, NULL); - if (blob_size > MUX_BLOB_MAX_SIZE) { - comp_err(dev, "mux_prepare(): illegal blob size %zu", blob_size); - return -EINVAL; - } - - memcpy_s(&cd->config, MUX_BLOB_MAX_SIZE, config, blob_size); + comp_dbg(dev, "entry"); ret = mux_params(mod); if (ret < 0) @@ -392,7 +405,7 @@ static int mux_prepare(struct processing_module *mod, cd->demux = demux_get_processing_function(mod); if (!cd->mux && !cd->demux) { - comp_err(dev, "mux_prepare(): Invalid configuration, couldn't find suitable processing function."); + comp_err(dev, "Invalid configuration, couldn't find suitable processing function."); return -EINVAL; } @@ -407,7 +420,7 @@ static int mux_get_config(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "mux_get_config()"); + comp_dbg(mod->dev, "entry"); return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); } @@ -419,35 +432,12 @@ static int mux_set_config(struct processing_module *mod, uint32_t config_id, { struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "mux_set_config()"); + comp_dbg(mod->dev, "entry"); return comp_data_blob_set(cd->model_handler, pos, data_offset_size, fragment, fragment_size); } -static int demux_trigger(struct processing_module *mod, int cmd) -{ - /* Check for cross-pipeline sinks: in general foreign - * pipelines won't be started synchronously with ours (it's - * under control of host software), so output can't be - * guaranteed not to overflow. Always set the - * overrun_permitted flag. These sink components are assumed - * responsible for flushing/synchronizing the stream - * themselves. - */ - if (cmd == COMP_TRIGGER_PRE_START) { - struct comp_buffer *b; - - comp_dev_for_each_producer(mod->dev, b) { - if (comp_buffer_get_sink_component(b)->pipeline != mod->dev->pipeline) - audio_stream_set_overrun(&b->stream, true); - } - - } - - return module_adapter_set_state(mod, mod->dev, cmd); -} - static const struct module_interface mux_interface = { .init = mux_init, .set_configuration = mux_set_config, @@ -458,9 +448,7 @@ static const struct module_interface mux_interface = { .free = mux_free, }; -DECLARE_MODULE_ADAPTER(mux_interface, MUX_UUID, mux_tr); -SOF_MODULE_INIT(mux, sys_comp_module_mux_interface_init); - +#if !CONFIG_COMP_MUX_MODULE static const struct module_interface demux_interface = { .init = demux_init, .set_configuration = mux_set_config, @@ -471,9 +459,7 @@ static const struct module_interface demux_interface = { .reset = mux_reset, .free = mux_free, }; - -DECLARE_MODULE_ADAPTER(demux_interface, demux_uuid, demux_tr); -SOF_MODULE_INIT(demux, sys_comp_module_demux_interface_init); +#endif #if CONFIG_COMP_MUX_MODULE /* modular: llext dynamic link */ @@ -482,26 +468,24 @@ SOF_MODULE_INIT(demux, sys_comp_module_demux_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_MUX 0x35, 0x6E, 0xCE, 0x64, 0x7A, 0x85, 0x78, 0x48, 0xE8, 0xAC, \ - 0xE2, 0xA2, 0xF4, 0x2E, 0x30, 0x69 -SOF_LLEXT_MOD_ENTRY(mux, &mux_interface); - -/* - * The demux entry is removed because mtl.toml doesn't have an entry - * for it. Once that is fixed, the manifest line below can be - * re-activated: - * #define UUID_DEMUX 0x68, 0x68, 0xB2, 0xC4, 0x30, 0x14, 0x0E, 0x47, 0x89, 0xA0, \ - * 0x15, 0xD1, 0xC7, 0x7F, 0x85, 0x1A - * SOF_LLEXT_MOD_ENTRY(demux, &demux_interface); - */ - static const struct sof_man_module_manifest mod_manifest[] __section(".module") __used = { - SOF_LLEXT_MODULE_MANIFEST("MUX", mux_llext_entry, 1, UUID_MUX, 15), + SOF_LLEXT_MODULE_MANIFEST("MUX", &mux_interface, 1, SOF_REG_UUID(mux4), 15), /* - * See comment above for a demux deactivation reason - * SOF_LLEXT_MODULE_MANIFEST("DEMUX", demux_llext_entry, 1, UUID_DEMUX, 15), + * The demux entry is removed because mtl.toml doesn't have an entry + * for it. Once that is fixed, the manifest line below can be + * re-activated: + * SOF_LLEXT_MODULE_MANIFEST("DEMUX", demux_llext_entry, 1, SOF_REG_UUID(demux), 15), */ }; SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_MODULE_ADAPTER(mux_interface, MUX_UUID, mux_tr); +SOF_MODULE_INIT(mux, sys_comp_module_mux_interface_init); + +DECLARE_MODULE_ADAPTER(demux_interface, demux_uuid, demux_tr); +SOF_MODULE_INIT(demux, sys_comp_module_demux_interface_init); + #endif diff --git a/src/audio/mux/mux.h b/src/audio/mux/mux.h index 526d70ecb870..0fb11d8300b5 100644 --- a/src/audio/mux/mux.h +++ b/src/audio/mux/mux.h @@ -213,7 +213,11 @@ void sys_comp_module_demux_interface_init(void); #endif /* UNIT_TEST */ #define MUX_BLOB_STREAMS_SIZE (MUX_MAX_STREAMS * sizeof(struct mux_stream_data)) +#ifdef CONFIG_IPC_MAJOR_4 +#define MUX_BLOB_MAX_SIZE (sizeof(struct mux_data)) +#else #define MUX_BLOB_MAX_SIZE (sizeof(struct sof_mux_config) + MUX_BLOB_STREAMS_SIZE) +#endif extern const struct sof_uuid demux_uuid; extern struct tr_ctx mux_tr; diff --git a/src/audio/mux/mux.toml b/src/audio/mux/mux.toml index 76a50383d0bc..f42b294850df 100644 --- a/src/audio/mux/mux.toml +++ b/src/audio/mux/mux.toml @@ -4,7 +4,7 @@ [[module.entry]] name = "MUX" - uuid = "64CE6E35-857A-4878-ACE8-E2A2F42E3069" + uuid = UUIDREG_STR_MUX4 affinity_mask = "0x1" instance_count = "15" domain_types = "0" diff --git a/src/audio/mux/mux_generic.c b/src/audio/mux/mux_generic.c index 991b79097fec..20d21afdffb1 100644 --- a/src/audio/mux/mux_generic.c +++ b/src/audio/mux/mux_generic.c @@ -171,7 +171,7 @@ static void demux_s16le(struct comp_dev *dev, struct audio_stream *sink, uint32_t elem; uint32_t frames_without_wrap; - comp_dbg(dev, "demux_s16le()"); + comp_dbg(dev, "entry"); if (!lookup || !lookup->num_elems) return; @@ -224,7 +224,7 @@ static void mux_s16le(struct comp_dev *dev, struct audio_stream *sink, uint32_t elem; uint32_t frames_without_wrap; - comp_dbg(dev, "mux_s16le()"); + comp_dbg(dev, "entry"); if (!lookup || !lookup->num_elems) return; @@ -371,7 +371,7 @@ static void demux_s32le(struct comp_dev *dev, struct audio_stream *sink, uint32_t elem; uint32_t frames_without_wrap; - comp_dbg(dev, "demux_s32le"); + comp_dbg(dev, "entry"); if (!lookup || !lookup->num_elems) return; @@ -424,7 +424,7 @@ static void mux_s32le(struct comp_dev *dev, struct audio_stream *sink, uint32_t elem; uint32_t frames_without_wrap; - comp_dbg(dev, "mux_s32le()"); + comp_dbg(dev, "entry"); if (!lookup || !lookup->num_elems) return; diff --git a/src/audio/mux/mux_ipc3.c b/src/audio/mux/mux_ipc3.c index 4c658d8e588d..b8454043e0fd 100644 --- a/src/audio/mux/mux_ipc3.c +++ b/src/audio/mux/mux_ipc3.c @@ -9,6 +9,7 @@ #include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/component.h> +#include <sof/audio/data_blob.h> #include <module/module/base.h> #include <sof/trace/trace.h> #include <rtos/string_macro.h> @@ -38,11 +39,11 @@ static int mux_set_values(struct processing_module *mod) unsigned int i; unsigned int j; - comp_dbg(dev, "mux_set_values()"); + comp_dbg(dev, "entry"); /* check if number of streams configured doesn't exceed maximum */ if (cfg->num_streams > MUX_MAX_STREAMS) { - comp_err(dev, "mux_set_values(): configured number of streams (%u) exceeds maximum = " + comp_err(dev, "configured number of streams (%u) exceeds maximum = " STRINGIFY(MUX_MAX_STREAMS), cfg->num_streams); return -EINVAL; } @@ -52,7 +53,7 @@ static int mux_set_values(struct processing_module *mod) for (j = i + 1; j < cfg->num_streams; j++) { if (cfg->streams[i].pipeline_id == cfg->streams[j].pipeline_id) { - comp_err(dev, "mux_set_values(): multiple configured streams have same pipeline ID = %u", + comp_err(dev, "multiple configured streams have same pipeline ID = %u", cfg->streams[i].pipeline_id); return -EINVAL; } @@ -62,15 +63,17 @@ static int mux_set_values(struct processing_module *mod) for (i = 0; i < cfg->num_streams; i++) { for (j = 0 ; j < PLATFORM_MAX_CHANNELS; j++) { if (popcount(cfg->streams[i].mask[j]) > 1) { - comp_err(dev, "mux_set_values(): mux component is not able to mix channels"); + comp_err(dev, "mux component is not able to mix channels"); return -EINVAL; } } } if (cd->comp_type == SOF_COMP_MUX) { - if (mux_mix_check(cfg)) - comp_err(dev, "mux_set_values(): mux component is not able to mix channels"); + if (mux_mix_check(cfg)) { + comp_err(dev, "mux component is not able to mix channels"); + return -EINVAL; + } } for (i = 0; i < cfg->num_streams; i++) { @@ -98,6 +101,18 @@ static int mux_set_values(struct processing_module *mod) int mux_params(struct processing_module *mod) { + struct comp_data *cd = module_get_private_data(mod); + struct sof_mux_config *config; + size_t blob_size; + + config = comp_get_data_blob(cd->model_handler, &blob_size, NULL); + if (blob_size > MUX_BLOB_MAX_SIZE) { + comp_err(mod->dev, "illegal blob size %zu", blob_size); + return -EINVAL; + } + + memcpy_s(&cd->config, MUX_BLOB_MAX_SIZE, config, blob_size); + return mux_set_values(mod); } #endif /* CONFIG_COMP_MUX */ diff --git a/src/audio/mux/mux_ipc4.c b/src/audio/mux/mux_ipc4.c index 446ad2f566ae..f5ead3a93368 100644 --- a/src/audio/mux/mux_ipc4.c +++ b/src/audio/mux/mux_ipc4.c @@ -11,6 +11,7 @@ #include <sof/audio/audio_stream.h> #include <sof/audio/component.h> #include <sof/audio/buffer.h> +#include <sof/audio/data_blob.h> #include <sof/trace/trace.h> #include <sof/lib/uuid.h> #include <sof/list.h> @@ -31,13 +32,25 @@ SOF_DEFINE_REG_UUID(demux); DECLARE_TR_CTX(demux_tr, SOF_UUID(demux_uuid), LOG_LEVEL_INFO); -static int build_config(struct processing_module *mod) +static int build_config(struct processing_module *mod, struct mux_data *cfg) { struct comp_dev *dev = mod->dev; struct comp_data *cd = module_get_private_data(mod); + uint32_t base_ch = cfg->base_cfg.audio_fmt.channels_count; + uint32_t ref_ch = cfg->reference_format.channels_count; + uint32_t out_ch = cfg->output_format.channels_count; int mask = 1; int i; + /* base+reference map 1:1 to contiguous output channels: sink width + * must equal their sum and fit the 8-bit output mask + */ + if (base_ch + ref_ch > PLATFORM_MAX_CHANNELS || out_ch != base_ch + ref_ch) { + comp_err(dev, "invalid channel count: base %u + reference %u -> output %u (max %d)", + base_ch, ref_ch, out_ch, PLATFORM_MAX_CHANNELS); + return -EINVAL; + } + cd->config.num_streams = MUX_MAX_STREAMS; /* clear masks */ @@ -45,19 +58,19 @@ static int build_config(struct processing_module *mod) memset(cd->config.streams[i].mask, 0, sizeof(cd->config.streams[i].mask)); /* Setting masks for streams */ - for (i = 0; i < cd->md.base_cfg.audio_fmt.channels_count; i++) { + for (i = 0; i < base_ch; i++) { cd->config.streams[0].mask[i] = mask; mask <<= 1; } - for (i = 0; i < cd->md.reference_format.channels_count; i++) { + for (i = 0; i < ref_ch; i++) { cd->config.streams[1].mask[i] = mask; mask <<= 1; } /* validation of matrix mixing */ if (mux_mix_check(&cd->config)) { - comp_err(dev, "build_config(): mux component is not able to mix channels"); + comp_err(dev, "mux component is not able to mix channels"); return -EINVAL; } return 0; @@ -67,7 +80,7 @@ static int build_config(struct processing_module *mod) * set up param then verify param. BTW for IPC3 path, the param is sent by * host driver. */ -static void set_mux_params(struct processing_module *mod) +static int set_mux_params(struct processing_module *mod, struct mux_data *cfg) { struct sof_ipc_stream_params *params = mod->stream_params; struct comp_data *cd = module_get_private_data(mod); @@ -76,12 +89,12 @@ static void set_mux_params(struct processing_module *mod) int j; params->direction = dev->direction; - params->channels = cd->md.base_cfg.audio_fmt.channels_count; - params->rate = cd->md.base_cfg.audio_fmt.sampling_frequency; - params->sample_container_bytes = cd->md.base_cfg.audio_fmt.depth / 8; - params->sample_valid_bytes = cd->md.base_cfg.audio_fmt.valid_bit_depth / 8; - params->buffer_fmt = cd->md.base_cfg.audio_fmt.interleaving_style; - params->buffer.size = cd->md.base_cfg.ibs; + params->channels = cfg->base_cfg.audio_fmt.channels_count; + params->rate = cfg->base_cfg.audio_fmt.sampling_frequency; + params->sample_container_bytes = cfg->base_cfg.audio_fmt.depth / 8; + params->sample_valid_bytes = cfg->base_cfg.audio_fmt.valid_bit_depth / 8; + params->buffer_fmt = cfg->base_cfg.audio_fmt.interleaving_style; + params->buffer.size = cfg->base_cfg.ibs; params->no_stream_position = 1; /* There are two input pins and one output pin in the mux. @@ -95,7 +108,7 @@ static void set_mux_params(struct processing_module *mod) sink = comp_dev_get_first_data_consumer(dev); if (!audio_buffer_hw_params_configured(&sink->audio_buffer)) { - ipc4_update_buffer_format(sink, &cd->md.output_format); + ipc4_update_buffer_format(sink, &cfg->output_format); params->frame_fmt = audio_stream_get_frm_fmt(&sink->stream); } } @@ -105,30 +118,45 @@ static void set_mux_params(struct processing_module *mod) struct ipc4_audio_format *audio_fmt; comp_dev_for_each_producer(dev, source) { - j = buf_get_id(source); + j = IPC4_SINK_QUEUE_ID(buf_get_id(source)); + /* host-supplied queue ID indexes streams[] */ + if (j >= MUX_MAX_STREAMS) { + comp_err(dev, "invalid source queue ID %d (valid range 0..%d)", + j, MUX_MAX_STREAMS - 1); + return -EINVAL; + } cd->config.streams[j].pipeline_id = buffer_pipeline_id(source); if (j == BASE_CFG_QUEUED_ID) - audio_fmt = &cd->md.base_cfg.audio_fmt; + audio_fmt = &cfg->base_cfg.audio_fmt; else - audio_fmt = &cd->md.reference_format; + audio_fmt = &cfg->reference_format; ipc4_update_buffer_format(source, audio_fmt); } } mux_prepare_look_up_table(mod); + + return 0; } int mux_params(struct processing_module *mod) { + struct comp_data *cd = module_get_private_data(mod); + struct mux_data *cfg; + size_t blob_size; int ret; - ret = build_config(mod); + cfg = comp_get_data_blob(cd->model_handler, &blob_size, NULL); + if (!cfg || blob_size > MUX_BLOB_MAX_SIZE) { + comp_err(mod->dev, "illegal blob size %zu", blob_size); + return -EINVAL; + } + + ret = build_config(mod, cfg); if (ret < 0) return ret; - set_mux_params(mod); - - return ret; + return set_mux_params(mod, cfg); } #endif /* CONFIG_COMP_MUX */ diff --git a/src/audio/nxp/CMakeLists.txt b/src/audio/nxp/CMakeLists.txt new file mode 100644 index 000000000000..967f2f019164 --- /dev/null +++ b/src/audio/nxp/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_COMP_NXP_EAP) + + zephyr_include_directories(${sof_top_dir}/eap_sdk) + zephyr_include_directories(${sof_top_dir}/third_party) + + zephyr_library_sources(eap.c) + + if(CONFIG_COMP_NXP_EAP_STUB) + zephyr_library_sources(eap_stub.c) + else() + zephyr_library_import(EAPLibrary + ${sof_top_dir}/eap_sdk/EAP_Library/libEAP16_3_0_13_FP1_RT600.a) + endif() + +endif() diff --git a/src/audio/nxp/Kconfig b/src/audio/nxp/Kconfig new file mode 100644 index 000000000000..45a9a15f80ef --- /dev/null +++ b/src/audio/nxp/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config COMP_NXP_EAP + tristate "NXP EAP Component" + help + Select for NXP Essential Audio Processing Component. + The EAP is a bundle of audio processing blocks for enhancing the tonal + and spatial perception of sound in audio applications. + +config COMP_NXP_EAP_STUB + tristate "NXP EAP Component stub" + depends on COMP_NXP_EAP + help + Select for NXP EAP stub support. diff --git a/src/audio/nxp/README.md b/src/audio/nxp/README.md new file mode 100644 index 000000000000..b8a59e0256aa --- /dev/null +++ b/src/audio/nxp/README.md @@ -0,0 +1,10 @@ +# NXP Specific Components Architecture + +## Overview + +This directory contains DSP components tailored for NXP hardware acceleration or special features. + +## Configuration and Scripts + +- **Kconfig**: Manages the proprietary NXP Essential Audio Processing blocks (`COMP_NXP_EAP`), aiming to enhance tonal and spatial audio perception. Also supports testing through a stub mechanism (`COMP_NXP_EAP_STUB`). +- **CMakeLists.txt**: Configures external NXP SDK directories and intelligently links the `eap.c` wrapper either against the stub logic or the authentic `libEAP16_3_0_13_FP1_RT600.a` static library blob. diff --git a/src/audio/nxp/eap.c b/src/audio/nxp/eap.c new file mode 100644 index 000000000000..3e596a5cf85d --- /dev/null +++ b/src/audio/nxp/eap.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright 2025 NXP +// +// Author: Daniel Baluta <daniel.baluta@nxp.com> + +#include <rtos/panic.h> +#include <rtos/cache.h> +#include <rtos/init.h> +#include <rtos/string.h> +#include <sof/audio/buffer.h> +#include <sof/audio/format.h> +#include <sof/audio/pipeline.h> +#include <sof/ipc/msg.h> +#include <sof/lib/uuid.h> +#include <sof/list.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/ut.h> +#include <sof/trace/trace.h> +#include <ipc/dai.h> +#include <user/trace.h> +#include <errno.h> +#include <stddef.h> +#include <stdint.h> +#include <module/module/interface.h> +#include <zephyr/logging/log.h> + +#include <sof/audio/nxp/eap/eap_lib_defines.h> +#include <nxp/eap/EAP_Includes/EAP16.h> +#include <sof/audio/nxp/eap/EAP_Parameter_presets.h> + +LOG_MODULE_REGISTER(nxp_eap, CONFIG_SOF_LOG_LEVEL); +SOF_DEFINE_REG_UUID(nxp_eap); +DECLARE_TR_CTX(nxp_eap_tr, SOF_UUID(nxp_eap_uuid), LOG_LEVEL_INFO); + +#define NXP_EAP_DEFAULT_MAX_BLOCK_SIZE 480 + +struct nxp_eap_data { + LVM_Handle_t instance; + LVM_MemTab_t mem_tab; + LVM_InstParams_t inst_params; + LVM_ControlParams_t ctrl_params; + int sample_rate; + int channels; + int frame_bytes; + int audio_time_ms; + uint32_t buffer_bytes; +}; + +struct nxp_eap_preset_params { + char *name; + LVM_ControlParams_t *params; +}; + +struct nxp_eap_preset_params nxp_eap_effect_presets[] = { + { + .name = "AllEffectsOff", + .params = (LVM_ControlParams_t *)&ControlParamSet_allEffectOff, + }, + { + .name = "AutoVolumeLeveler", + .params = (LVM_ControlParams_t *)&ControlParamSet_autoVolumeLeveler, + }, + { + .name = "ConcertSound", + .params = (LVM_ControlParams_t *)&ControlParamSet_concertSound, + }, + { + .name = "LoudnessMaximiser", + .params = (LVM_ControlParams_t *)&ControlParamSet_loudnessMaximiser, + }, + { + .name = "MusicEnhancer", + .params = (LVM_ControlParams_t *)&ControlParamSet_musicEnhancerRmsLimiter, + }, + { + .name = "VoiceEnhancer", + .params = (LVM_ControlParams_t *)&ControlParamSet_voiceEnhancer, + } +}; + +static int nxp_eap_init(struct processing_module *mod) +{ + struct comp_dev *dev = mod->dev; + struct nxp_eap_data *eap; + LVM_VersionInfo_st info; + LVM_ReturnStatus_en lvm_ret; + int ret = 0; + + LVM_GetVersionInfo(&info); + + tr_info(mod->dev, "NXP EAP library, platform: %s version:%s", + info.pPlatform, info.pVersionNumber); + + eap = mod_alloc(mod, sizeof(*eap)); + if (!eap) { + comp_err(dev, "failed to allocate module private data"); + return -ENOMEM; + } + + module_set_private_data(mod, eap); + + memcpy(&eap->inst_params, &InstParams_allEffectOff, sizeof(eap->inst_params)); + + lvm_ret = LVM_GetMemoryTable(LVM_NULL, &eap->mem_tab, &eap->inst_params); + if (lvm_ret != LVM_SUCCESS) { + comp_err(dev, "failed to get memory table %d", lvm_ret); + mod_free(mod, eap); + return -EINVAL; + } + + /* mark all pBaseAddress with NULL so that would be easier to implement cleanup */ + for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) + eap->mem_tab.Region[i].pBaseAddress = NULL; + + for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) { + eap->mem_tab.Region[i].pBaseAddress = mod_balloc(mod, eap->mem_tab.Region[i].Size); + if (!eap->mem_tab.Region[i].pBaseAddress) { + comp_err(dev, "failed to allocate memory for region %d", i); + ret = -ENOMEM; + goto free_mem; + } + } + + lvm_ret = LVM_GetInstanceHandle(&eap->instance, &eap->mem_tab, &eap->inst_params); + if (lvm_ret != LVM_SUCCESS) { + comp_err(dev, "failed to get instance handle err: %d", lvm_ret); + ret = -EINVAL; + goto free_mem; + } + + /* default parameters, no effects */ + memcpy(&eap->ctrl_params, &ControlParamSet_allEffectOff, sizeof(eap->ctrl_params)); + + return 0; + +free_mem: + for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) { + if (eap->mem_tab.Region[i].pBaseAddress) { + mod_free(mod, eap->mem_tab.Region[i].pBaseAddress); + eap->mem_tab.Region[i].pBaseAddress = NULL; + } + } + mod_free(mod, eap); + return ret; +} + +static int nxp_eap_free(struct processing_module *mod) +{ + struct comp_dev *dev = mod->dev; + struct nxp_eap_data *eap = module_get_private_data(mod); + + comp_dbg(dev, "entry"); + + for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) { + if (eap->mem_tab.Region[i].pBaseAddress) { + mod_free(mod, eap->mem_tab.Region[i].pBaseAddress); + eap->mem_tab.Region[i].pBaseAddress = NULL; + } + } + mod_free(mod, eap); + + return 0; +} + +static int nxp_eap_prepare(struct processing_module *mod, + 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 *md = &mod->priv; + struct nxp_eap_data *eap = module_get_private_data(mod); + struct comp_buffer *source = comp_dev_get_first_data_producer(dev); + const struct audio_stream *stream; + + comp_dbg(dev, "entry"); + + stream = &source->stream; + eap->sample_rate = audio_stream_get_rate(stream); + eap->channels = audio_stream_get_channels(stream); + eap->frame_bytes = audio_stream_frame_bytes(stream); + eap->audio_time_ms = 0; + + /* total bytes needed to be in the input buffer to be processed + * by the EAP library + */ + eap->buffer_bytes = NXP_EAP_DEFAULT_MAX_BLOCK_SIZE; + + md->mpd.in_buff = mod_balloc_align(mod, eap->buffer_bytes, 32); + if (!md->mpd.in_buff) + return -ENOMEM; + + md->mpd.out_buff = mod_balloc_align(mod, eap->buffer_bytes, 32); + if (!md->mpd.out_buff) { + mod_free(mod, md->mpd.in_buff); + return -ENOMEM; + } + + md->mpd.in_buff_size = eap->buffer_bytes; + md->mpd.out_buff_size = eap->buffer_bytes; + + return 0; +} + +static int nxp_eap_reset(struct processing_module *mod) +{ + struct comp_dev *dev = mod->dev; + struct module_data *md = &mod->priv; + + comp_dbg(dev, "entry"); + + if (md->mpd.in_buff) { + mod_free(mod, md->mpd.in_buff); + md->mpd.in_buff = NULL; + md->mpd.in_buff_size = 0; + } + + if (md->mpd.out_buff) { + mod_free(mod, md->mpd.out_buff); + md->mpd.out_buff = NULL; + md->mpd.out_buff_size = 0; + } + + return 0; +} + +static int nxp_eap_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 comp_dev *dev = mod->dev; + struct module_data *eap = &mod->priv; + struct nxp_eap_data *eap_data = module_get_private_data(mod); + LVM_INT16 *buffer_table[2]; + LVM_ReturnStatus_en ret; + + comp_dbg(dev, "entry"); + + /* we need to input buffer to be completely full to be able to process it */ + if (input_buffers[0].size < eap->mpd.in_buff_size) + return -ENODATA; + + memcpy_s(eap->mpd.in_buff, eap->mpd.in_buff_size, + (uint8_t *)input_buffers[0].data + input_buffers[0].consumed, + eap->mpd.in_buff_size); + eap->mpd.avail = eap->mpd.in_buff_size; + + buffer_table[0] = eap->mpd.out_buff; + buffer_table[1] = LVM_NULL; + + eap_data->audio_time_ms += eap->mpd.avail / (eap_data->sample_rate / 1000); + + ret = LVM_Process(eap_data->instance, (LVM_INT16 *)eap->mpd.in_buff, + (LVM_INT16 **)buffer_table, eap->mpd.avail / eap_data->frame_bytes, + eap_data->audio_time_ms); + if (ret != LVM_SUCCESS) { + comp_err(dev, "failed with error %d", ret); + return -EIO; + } + + eap->mpd.produced = eap->mpd.in_buff_size; + eap->mpd.consumed = eap->mpd.in_buff_size; + + input_buffers[0].consumed = eap->mpd.consumed; + + /* copy produced samples to output buffer */ + memcpy_s(output_buffers[0].data, eap->mpd.produced, eap->mpd.out_buff, eap->mpd.produced); + output_buffers[0].size = eap->mpd.produced; + + return 0; +} + +static int nxp_eap_cmd_set_value(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata) +{ + int index; + LVM_ReturnStatus_en ret; + struct comp_dev *dev = mod->dev; + struct nxp_eap_data *eap = module_get_private_data(mod); + + index = cdata->chanv[0].value; + + if (index >= ARRAY_SIZE(nxp_eap_effect_presets)) { + comp_info(dev, "invalid index (%d), config not changed", + index); + } else { + memcpy(&eap->ctrl_params, nxp_eap_effect_presets[index].params, + sizeof(eap->ctrl_params)); + comp_info(dev, "New config set to %s", nxp_eap_effect_presets[index].name); + } + + ret = LVM_SetControlParameters(eap->instance, &eap->ctrl_params); + if (ret != LVM_SUCCESS) { + comp_err(dev, "LVM_SetControlParameters failed with error %d", ret); + return -EIO; + } + return 0; +} + +static int nxp_eap_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 comp_dev *dev = mod->dev; + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + + comp_dbg(dev, "entry"); + + if (cdata->cmd != SOF_CTRL_CMD_BINARY) + return nxp_eap_cmd_set_value(mod, cdata); + + comp_err(dev, "nxp_set_config() binary config not supported"); + return -EINVAL; +} + +static int nxp_eap_get_config(struct processing_module *mod, + uint32_t param_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) +{ + struct comp_dev *dev = mod->dev; + + comp_dbg(dev, "entry"); + + return 0; +} + +static const struct module_interface nxp_eap_interface = { + .init = nxp_eap_init, + .prepare = nxp_eap_prepare, + .process_raw_data = nxp_eap_process, + .set_configuration = nxp_eap_set_config, + .get_configuration = nxp_eap_get_config, + .reset = nxp_eap_reset, + .free = nxp_eap_free, +}; + +DECLARE_MODULE_ADAPTER(nxp_eap_interface, nxp_eap_uuid, nxp_eap_tr); +SOF_MODULE_INIT(nxp_eap, sys_comp_module_nxp_eap_interface_init); diff --git a/src/audio/nxp/eap_stub.c b/src/audio/nxp/eap_stub.c new file mode 100644 index 000000000000..568bb9745b17 --- /dev/null +++ b/src/audio/nxp/eap_stub.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright 2025 NXP + + +#include <sof/audio/nxp/eap/eap_lib_defines.h> +#include <nxp/eap/EAP_Includes/EAP16.h> + +LVM_ReturnStatus_en LVM_GetVersionInfo(LVM_VersionInfo_st *pVersion) +{ + return LVM_SUCCESS; +} + +LVM_ReturnStatus_en LVM_GetInstanceHandle(LVM_Handle_t *phInstance, + LVM_MemTab_t *pMemoryTable, + LVM_InstParams_t *pInstParams) +{ + return LVM_SUCCESS; +}; + +LVM_ReturnStatus_en LVM_GetMemoryTable(LVM_Handle_t hInstance, LVM_MemTab_t *pMemoryTable, + LVM_InstParams_t *pInstParams) +{ + return LVM_SUCCESS; +} + +LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance, const LVM_INT16 *pInData, + LVM_INT16 **pOutData, LVM_UINT16 NumSamples, + LVM_UINT32 AudioTime) +{ + return LVM_SUCCESS; +} + +LVM_ReturnStatus_en LVM_SetControlParameters(LVM_Handle_t hInstance, LVM_ControlParams_t *pParams) +{ + return LVM_SUCCESS; +} diff --git a/src/audio/pcm_converter/README.md b/src/audio/pcm_converter/README.md new file mode 100644 index 000000000000..d9fd8152383a --- /dev/null +++ b/src/audio/pcm_converter/README.md @@ -0,0 +1,11 @@ +# PCM Format Converter Architecture + +This directory provides PCM format conversion. + +## Overview + +Handles conversions like 16-bit to 24-bit, interleaved to non-interleaved, and other basic PCM layout translations. + +## Configuration and Scripts + +- **CMakeLists.txt**: Organizes standard and highly performant HIFI implementations (`pcm_converter.c`, `pcm_converter_generic.c`, `pcm_converter_hifi3.c`). Includes optional support for `pcm_remap.c` dependent on the `CONFIG_PCM_REMAPPING_CONVERTERS` flag. diff --git a/src/audio/pcm_converter/pcm_converter_generic.c b/src/audio/pcm_converter/pcm_converter_generic.c index 3d4110c57165..56d2cf599288 100644 --- a/src/audio/pcm_converter/pcm_converter_generic.c +++ b/src/audio/pcm_converter/pcm_converter_generic.c @@ -21,6 +21,8 @@ #include <sof/audio/buffer.h> #include <sof/audio/format.h> +#include <sof/math/a_law.h> +#include <sof/math/mu_law.h> #include <rtos/bit.h> #include <sof/common.h> #include <sof/compiler_attributes.h> @@ -93,6 +95,126 @@ static int pcm_convert_s32_to_u8(const struct audio_stream *source, } #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ +#if CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE +static int pcm_convert_alaw_to_s32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, + uint32_t ooffset, uint32_t samples, uint32_t chmap) +{ + const uint8_t *src = audio_stream_get_rptr(source); + int32_t *dst = audio_stream_get_wptr(sink); + uint32_t processed; + uint32_t nmax, i, n; + + src += ioffset; + dst += ooffset; + for (processed = 0; processed < samples; processed += n) { + src = audio_stream_wrap(source, (void *)src); + dst = audio_stream_wrap(sink, dst); + n = samples - processed; + nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_U8_SAMPLES; + n = MIN(n, nmax); + nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + n = MIN(n, nmax); + for (i = 0; i < n; i++) { + *dst = sofm_a_law_decode(*src) << 16; + src++; + dst++; + } + } + + return samples; +} + +static int pcm_convert_s32_to_alaw(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, + uint32_t ooffset, uint32_t samples, uint32_t chmap) +{ + const int32_t *src = audio_stream_get_rptr(source); + uint8_t *dst = audio_stream_get_wptr(sink); + uint32_t processed; + uint32_t nmax, i, n; + + src += ioffset; + dst += ooffset; + for (processed = 0; processed < samples; processed += n) { + src = audio_stream_wrap(source, (void *)src); + dst = audio_stream_wrap(sink, dst); + n = samples - processed; + nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + n = MIN(n, nmax); + nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_U8_SAMPLES; + n = MIN(n, nmax); + for (i = 0; i < n; i++) { + *dst = sofm_a_law_encode(*src >> 16); + src++; + dst++; + } + } + + return samples; +} +#endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ + +#if CONFIG_PCM_CONVERTER_FORMAT_MU_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE +static int pcm_convert_mulaw_to_s32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, + uint32_t ooffset, uint32_t samples, uint32_t chmap) +{ + const uint8_t *src = audio_stream_get_rptr(source); + int32_t *dst = audio_stream_get_wptr(sink); + uint32_t processed; + uint32_t nmax, i, n; + + src += ioffset; + dst += ooffset; + for (processed = 0; processed < samples; processed += n) { + src = audio_stream_wrap(source, (void *)src); + dst = audio_stream_wrap(sink, dst); + n = samples - processed; + nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_U8_SAMPLES; + n = MIN(n, nmax); + nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + n = MIN(n, nmax); + for (i = 0; i < n; i++) { + *dst = sofm_mu_law_decode(*src) << 16; + src++; + dst++; + } + } + + return samples; +} + +static int pcm_convert_s32_to_mulaw(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, + uint32_t ooffset, uint32_t samples, uint32_t chmap) +{ + const int32_t *src = audio_stream_get_rptr(source); + uint8_t *dst = audio_stream_get_wptr(sink); + uint32_t processed; + uint32_t nmax, i, n; + + src += ioffset; + dst += ooffset; + for (processed = 0; processed < samples; processed += n) { + src = audio_stream_wrap(source, (void *)src); + dst = audio_stream_wrap(sink, dst); + n = samples - processed; + nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + n = MIN(n, nmax); + nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_U8_SAMPLES; + n = MIN(n, nmax); + for (i = 0; i < n; i++) { + *dst = sofm_mu_law_encode(*src >> 16); + src++; + dst++; + } + } + + return samples; +} +#endif /* CONFIG_PCM_CONVERTER_FORMAT_MU_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ + #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE static int pcm_convert_s16_to_s24(const struct audio_stream *source, @@ -555,6 +677,20 @@ const struct pcm_func_map pcm_func_map[] = { { SOF_IPC_FRAME_U8, SOF_IPC_FRAME_S32_LE, pcm_convert_u8_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_U8, pcm_convert_s32_to_u8 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ +#if CONFIG_PCM_CONVERTER_FORMAT_A_LAW + { SOF_IPC_FRAME_A_LAW, SOF_IPC_FRAME_A_LAW, just_copy }, +#endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW */ +#if CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE + { SOF_IPC_FRAME_A_LAW, SOF_IPC_FRAME_S32_LE, pcm_convert_alaw_to_s32 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_A_LAW, pcm_convert_s32_to_alaw }, +#endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ +#if CONFIG_PCM_CONVERTER_FORMAT_MU_LAW + { SOF_IPC_FRAME_MU_LAW, SOF_IPC_FRAME_MU_LAW, just_copy }, +#endif /* CONFIG_PCM_CONVERTER_FORMAT_MU_LAW */ +#if CONFIG_PCM_CONVERTER_FORMAT_MU_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE + { SOF_IPC_FRAME_MU_LAW, SOF_IPC_FRAME_S32_LE, pcm_convert_mulaw_to_s32 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_MU_LAW, pcm_convert_s32_to_mulaw }, +#endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S16LE */ @@ -579,6 +715,10 @@ const struct pcm_func_map pcm_func_map[] = { { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s24_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE */ +#if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, pcm_convert_s32_to_s24_be }, + { SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, just_copy }, +#endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT */ @@ -956,6 +1096,13 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s32_to_s16 }, #endif + +#if CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S24LE + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_FLOAT, + SOF_IPC_FRAME_FLOAT, pcm_convert_s24_to_f }, + { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_S32_LE, + SOF_IPC_FRAME_S24_4LE, pcm_convert_f_to_s24 }, +#endif }; const size_t pcm_func_vc_count = ARRAY_SIZE(pcm_func_vc_map); diff --git a/src/audio/pcm_converter/pcm_converter_hifi3.c b/src/audio/pcm_converter/pcm_converter_hifi3.c index 1759e66ce149..2b6ca607415d 100644 --- a/src/audio/pcm_converter/pcm_converter_hifi3.c +++ b/src/audio/pcm_converter/pcm_converter_hifi3.c @@ -1274,6 +1274,13 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s32_to_s16 }, #endif + +#if CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S24LE + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_FLOAT, + SOF_IPC_FRAME_FLOAT, pcm_convert_s24_to_f }, + { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_S32_LE, + SOF_IPC_FRAME_S24_4LE, pcm_convert_f_to_s24 }, +#endif }; const size_t pcm_func_vc_count = ARRAY_SIZE(pcm_func_vc_map); diff --git a/src/audio/pcm_converter/pcm_remap.c b/src/audio/pcm_converter/pcm_remap.c index 9204b21ee8ab..f0ad6912a5f8 100644 --- a/src/audio/pcm_converter/pcm_remap.c +++ b/src/audio/pcm_converter/pcm_remap.c @@ -68,13 +68,14 @@ static int remap_c16(const struct audio_stream *source, uint32_t dummy1, src_channel = chmap & 0xf; chmap >>= 4; - if (src_channel == 0xf) { + /* 0xf means "mute"; also mute any out-of-range source channel so + * a crafted chmap nibble cannot index past the source frame. + */ + if (src_channel == 0xf || src_channel >= num_src_channels) { mute_channel_c16(sink, sink_channel, frames); continue; } - assert(src_channel < num_src_channels); - src = (int16_t *)audio_stream_get_rptr(source) + src_channel; dst = (int16_t *)audio_stream_get_wptr(sink) + sink_channel; @@ -126,13 +127,14 @@ static inline int remap_c32_left_shift(const struct audio_stream *source, src_channel = chmap & 0xf; chmap >>= 4; - if (src_channel == 0xf) { + /* 0xf means "mute"; also mute any out-of-range source channel so + * a crafted chmap nibble cannot index past the source frame. + */ + if (src_channel == 0xf || src_channel >= num_src_channels) { mute_channel_c32(sink, sink_channel, frames); continue; } - assert(src_channel < num_src_channels); - src = (int32_t *)audio_stream_get_rptr(source) + src_channel; dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; @@ -184,13 +186,14 @@ static inline int remap_c32_right_shift(const struct audio_stream *source, src_channel = chmap & 0xf; chmap >>= 4; - if (src_channel == 0xf) { + /* 0xf means "mute"; also mute any out-of-range source channel so + * a crafted chmap nibble cannot index past the source frame. + */ + if (src_channel == 0xf || src_channel >= num_src_channels) { mute_channel_c32(sink, sink_channel, frames); continue; } - assert(src_channel < num_src_channels); - src = (int32_t *)audio_stream_get_rptr(source) + src_channel; dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; @@ -243,13 +246,14 @@ static inline int remap_c16_to_c32(const struct audio_stream *source, src_channel = chmap & 0xf; chmap >>= 4; - if (src_channel == 0xf) { + /* 0xf means "mute"; also mute any out-of-range source channel so + * a crafted chmap nibble cannot index past the source frame. + */ + if (src_channel == 0xf || src_channel >= num_src_channels) { mute_channel_c32(sink, sink_channel, frames); continue; } - assert(src_channel < num_src_channels); - src = (int16_t *)audio_stream_get_rptr(source) + src_channel; dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; @@ -302,13 +306,14 @@ static inline int remap_c32_to_c16(const struct audio_stream *source, src_channel = chmap & 0xf; chmap >>= 4; - if (src_channel == 0xf) { + /* 0xf means "mute"; also mute any out-of-range source channel so + * a crafted chmap nibble cannot index past the source frame. + */ + if (src_channel == 0xf || src_channel >= num_src_channels) { mute_channel_c16(sink, sink_channel, frames); continue; } - assert(src_channel < num_src_channels); - src = (int32_t *)audio_stream_get_rptr(source) + src_channel; dst = (int16_t *)audio_stream_get_wptr(sink) + sink_channel; diff --git a/src/audio/phase_vocoder/CMakeLists.txt b/src/audio/phase_vocoder/CMakeLists.txt new file mode 100644 index 000000000000..b632c50af6cb --- /dev/null +++ b/src/audio/phase_vocoder/CMakeLists.txt @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_COMP_PHASE_VOCODER STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/phase_vocoder_llext) + add_dependencies(app phase_vocoder) +else() + add_local_sources(sof phase_vocoder.c) + add_local_sources(sof phase_vocoder_setup.c) + add_local_sources(sof phase_vocoder_common.c) + add_local_sources(sof phase_vocoder-generic.c) + + if(CONFIG_IPC_MAJOR_4) + add_local_sources(sof phase_vocoder-ipc4.c) + endif() +endif() diff --git a/src/audio/phase_vocoder/Kconfig b/src/audio/phase_vocoder/Kconfig new file mode 100644 index 000000000000..a3eecfc8023f --- /dev/null +++ b/src/audio/phase_vocoder/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config COMP_PHASE_VOCODER + tristate "Phase Vocoder component" + default m if LIBRARY_DEFAULT_MODULAR + select MATH_FFT + select MATH_32BIT_FFT + help + Select for phase_vocoder component. The component provides + render speed control in range 0.5-2.0x. The pitch is + preserved in audio waveform stretch or shorten. The module + is using a frequency domain algorithm in STFT domain to + interpolate magnitude and phase of output IFFT frames from + input FFT frames. diff --git a/src/audio/phase_vocoder/llext/CMakeLists.txt b/src/audio/phase_vocoder/llext/CMakeLists.txt new file mode 100644 index 000000000000..ffefa29c7080 --- /dev/null +++ b/src/audio/phase_vocoder/llext/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2026 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +sof_llext_build("phase_vocoder" + SOURCES ../phase_vocoder.c + ../phase_vocoder_setup.c + ../phase_vocoder_common.c + ../phase_vocoder-generic.c + ../phase_vocoder-ipc4.c + LIB openmodules +) diff --git a/src/audio/phase_vocoder/llext/llext.toml.h b/src/audio/phase_vocoder/llext/llext.toml.h new file mode 100644 index 000000000000..94cfd0d67d50 --- /dev/null +++ b/src/audio/phase_vocoder/llext/llext.toml.h @@ -0,0 +1,6 @@ +#include <tools/rimage/config/platform.toml> +#define LOAD_TYPE "2" +#include "../phase_vocoder.toml" + +[module] +count = __COUNTER__ diff --git a/src/audio/phase_vocoder/phase_vocoder-generic.c b/src/audio/phase_vocoder/phase_vocoder-generic.c new file mode 100644 index 000000000000..5cc382cb5b8b --- /dev/null +++ b/src/audio/phase_vocoder/phase_vocoder-generic.c @@ -0,0 +1,694 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include <sof/audio/format.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/source_api.h> +#include <stdint.h> +#include "phase_vocoder.h" + +#if CONFIG_FORMAT_S32LE +/** + * phase_vocoder_source_s32() - Read S32_LE samples into the input ring buffer. + * @cd: Pointer to component private data. + * @source: Source for PCM samples data. + * @frames: Number of audio data frames to consume. + * + * Copies up to @frames frames of S32_LE PCM from @source into the per-channel + * input ring buffers. In mono-mix mode the channels are pre-summed using + * @cd->mono_mix_coef so that downstream STFT processing runs on a single + * channel. + * + * Return: Value zero for success, otherwise an error code. + */ +int phase_vocoder_source_s32(struct phase_vocoder_comp_data *cd, struct sof_source *source, + int frames) +{ + struct phase_vocoder_state *state = &cd->state; + struct phase_vocoder_buffer *ibuf; + int32_t const *x, *x_start, *x_end; + const int32_t mix_gain = cd->mono_mix_coef; + int64_t mix; + int frames_left; + int x_size; + int bytes; + int ret; + int n1; + int n2; + int n; + int i; + int j; + int stream_channels = cd->stream_channels; + int process_channels = cd->process_channels; + bool process_mono = cd->config->mono; + + ibuf = &state->ibuf[0]; + frames = MIN(frames, ibuf->s_free); + bytes = frames * cd->frame_bytes; + + /* Get pointer to source data in circular buffer */ + ret = source_get_data_s32(source, bytes, &x, &x_start, &x_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + + frames_left = frames; + while (frames_left) { + /* Find out samples to process before first wrap or end of data. */ + ibuf = &state->ibuf[0]; + n1 = (x_end - x) / stream_channels; + n2 = phase_vocoder_buffer_samples_without_wrap(ibuf, ibuf->w_ptr); + n = MIN(n1, n2); + n = MIN(n, frames_left); + if (process_mono) { + for (i = 0; i < n; i++) { + mix = 0; + for (j = 0; j < stream_channels; j++) + mix += Q_MULTSR_32X32((int64_t)mix_gain, *x++, 31, 31, 31); + + *ibuf->w_ptr++ = sat_int32(mix); + } + } else { + for (i = 0; i < n; i++) { + for (j = 0; j < stream_channels; j++) { + ibuf = &state->ibuf[j]; + *ibuf->w_ptr++ = *x++; + } + } + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + for (j = 0; j < process_channels; j++) { + ibuf = &state->ibuf[j]; + ibuf->w_ptr = phase_vocoder_buffer_wrap(ibuf, ibuf->w_ptr); + } + + if (x >= x_end) + x -= x_size; + + /* Update processed samples count for next loop iteration. */ + frames_left -= n; + } + + /* Update the source for bytes consumed. Return success. */ + source_release_data(source, bytes); + for (j = 0; j < process_channels; j++) { + ibuf = &state->ibuf[j]; + ibuf->s_avail += frames; + ibuf->s_free -= frames; + } + + return 0; +} + +/** + * phase_vocoder_sink_s32() - Write processed samples out as S32_LE. + * @cd: Pointer to component private data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to produce. + * + * Copies up to @frames frames from the per-channel output ring buffer to + * @sink in S32_LE format. In mono-mix mode the single processed channel is + * replicated to all output channels. The output ring buffer slots are + * cleared after read so the next overlap-add pass starts from zero. + * + * Return: Value zero for success, otherwise an error code. + */ +int phase_vocoder_sink_s32(struct phase_vocoder_comp_data *cd, struct sof_sink *sink, int frames) +{ + struct phase_vocoder_state *state = &cd->state; + struct phase_vocoder_buffer *obuf; + int32_t *y, *y_start, *y_end; + int frames_remain; + int bytes; + int y_size; + int ret; + int ch, n1, n, i; + int stream_channels = cd->stream_channels; + int process_channels = cd->process_channels; + bool process_mono = cd->config->mono; + + obuf = &state->obuf[0]; + frames = MIN(frames, obuf->s_avail); + if (!frames) + return 0; + + /* Get pointer to sink data in circular buffer */ + bytes = frames * cd->frame_bytes; + ret = sink_get_buffer_s32(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + y_end = y_start + y_size; + + frames_remain = frames; + while (frames_remain) { + /* Find out samples to process before first wrap or end of data. */ + obuf = &state->obuf[0]; + n1 = (y_end - y) / stream_channels; + n = phase_vocoder_buffer_samples_without_wrap(obuf, obuf->r_ptr); + n = MIN(n1, n); + n = MIN(n, frames_remain); + + if (process_mono) { + for (i = 0; i < n; i++) { + for (ch = 0; ch < stream_channels; ch++) + *y++ = *obuf->r_ptr; + + *obuf->r_ptr++ = 0; /* clear overlap add mix */ + } + } else { + for (i = 0; i < n; i++) { + for (ch = 0; ch < stream_channels; ch++) { + obuf = &state->obuf[ch]; + *y++ = *obuf->r_ptr; + *obuf->r_ptr++ = 0; /* clear overlap add mix */ + } + } + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + for (ch = 0; ch < process_channels; ch++) { + obuf = &state->obuf[ch]; + obuf->r_ptr = phase_vocoder_buffer_wrap(obuf, obuf->r_ptr); + } + + if (y >= y_end) + y -= y_size; + + /* Update processed samples count for next loop iteration. */ + frames_remain -= n; + } + + /* Update the sink for bytes produced. Return success. */ + sink_commit_buffer(sink, bytes); + for (ch = 0; ch < process_channels; ch++) { + obuf = &state->obuf[ch]; + obuf->s_avail -= frames; + obuf->s_free += frames; + } + + return 0; +} +#endif /* CONFIG_FORMAT_S32LE */ + +#if CONFIG_FORMAT_S24LE +/** + * phase_vocoder_source_s24() - Read S24_4LE samples into the input ring buffer. + * @cd: Pointer to component private data. + * @source: Source for PCM samples data. + * @frames: Number of audio data frames to consume. + * + * Copies up to @frames frames of S24_4LE PCM from @source into the per-channel + * input ring buffers, left-shifting each 24-bit sample by 8 to align to Q1.31 + * for STFT processing. In mono-mix mode the channels are pre-summed using + * @cd->mono_mix_coef so that downstream STFT processing runs on a single + * channel. + * + * Return: Value zero for success, otherwise an error code. + */ +int phase_vocoder_source_s24(struct phase_vocoder_comp_data *cd, struct sof_source *source, + int frames) +{ + struct phase_vocoder_state *state = &cd->state; + struct phase_vocoder_buffer *ibuf; + int32_t const *x, *x_start, *x_end; + const int32_t mix_gain = cd->mono_mix_coef; + int64_t mix; + int32_t tmp; + int frames_left; + int x_size; + int bytes; + int ret; + int n1; + int n2; + int n; + int i; + int j; + int stream_channels = cd->stream_channels; + int process_channels = cd->process_channels; + bool process_mono = cd->config->mono; + + ibuf = &state->ibuf[0]; + frames = MIN(frames, ibuf->s_free); + bytes = frames * cd->frame_bytes; + + /* Get pointer to source data in circular buffer */ + ret = source_get_data_s32(source, bytes, &x, &x_start, &x_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + + frames_left = frames; + while (frames_left) { + /* Find out samples to process before first wrap or end of data. */ + ibuf = &state->ibuf[0]; + n1 = (x_end - x) / stream_channels; + n2 = phase_vocoder_buffer_samples_without_wrap(ibuf, ibuf->w_ptr); + n = MIN(n1, n2); + n = MIN(n, frames_left); + if (process_mono) { + for (i = 0; i < n; i++) { + mix = 0; + for (j = 0; j < stream_channels; j++) { + tmp = (int32_t)(((uint32_t)*x++) << 8); + mix += Q_MULTSR_32X32((int64_t)mix_gain, tmp, 31, 31, 31); + } + + *ibuf->w_ptr++ = sat_int32(mix); + } + } else { + for (i = 0; i < n; i++) { + for (j = 0; j < stream_channels; j++) { + ibuf = &state->ibuf[j]; + tmp = (int32_t)(((uint32_t)*x++) << 8); + *ibuf->w_ptr++ = tmp; + } + } + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + for (j = 0; j < process_channels; j++) { + ibuf = &state->ibuf[j]; + ibuf->w_ptr = phase_vocoder_buffer_wrap(ibuf, ibuf->w_ptr); + } + + if (x >= x_end) + x -= x_size; + + /* Update processed samples count for next loop iteration. */ + frames_left -= n; + } + + /* Update the source for bytes consumed. Return success. */ + source_release_data(source, bytes); + for (j = 0; j < process_channels; j++) { + ibuf = &state->ibuf[j]; + ibuf->s_avail += frames; + ibuf->s_free -= frames; + } + + return 0; +} + +/** + * phase_vocoder_sink_s24() - Write processed samples out as S24_4LE. + * @cd: Pointer to component private data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to produce. + * + * Copies up to @frames frames from the per-channel output ring buffer to + * @sink in S24_4LE format, right-shifting each Q1.31 sample by 8 to produce + * the 24-bit output. In mono-mix mode the single processed channel is + * replicated to all output channels. The output ring buffer slots are + * cleared after read so the next overlap-add pass starts from zero. + * + * Return: Value zero for success, otherwise an error code. + */ +int phase_vocoder_sink_s24(struct phase_vocoder_comp_data *cd, struct sof_sink *sink, int frames) +{ + struct phase_vocoder_state *state = &cd->state; + struct phase_vocoder_buffer *obuf; + int32_t *y, *y_start, *y_end; + int frames_remain; + int bytes; + int y_size; + int ret; + int ch, n1, n, i; + int stream_channels = cd->stream_channels; + int process_channels = cd->process_channels; + bool process_mono = cd->config->mono; + + obuf = &state->obuf[0]; + frames = MIN(frames, obuf->s_avail); + if (!frames) + return 0; + + /* Get pointer to sink data in circular buffer */ + bytes = frames * cd->frame_bytes; + ret = sink_get_buffer_s32(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + y_end = y_start + y_size; + + frames_remain = frames; + while (frames_remain) { + /* Find out samples to process before first wrap or end of data. */ + obuf = &state->obuf[0]; + n1 = (y_end - y) / stream_channels; + n = phase_vocoder_buffer_samples_without_wrap(obuf, obuf->r_ptr); + n = MIN(n1, n); + n = MIN(n, frames_remain); + + if (process_mono) { + for (i = 0; i < n; i++) { + for (ch = 0; ch < stream_channels; ch++) + *y++ = *obuf->r_ptr >> 8; + + *obuf->r_ptr++ = 0; /* clear overlap add mix */ + } + } else { + for (i = 0; i < n; i++) { + for (ch = 0; ch < stream_channels; ch++) { + obuf = &state->obuf[ch]; + *y++ = *obuf->r_ptr >> 8; + *obuf->r_ptr++ = 0; /* clear overlap add mix */ + } + } + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + for (ch = 0; ch < process_channels; ch++) { + obuf = &state->obuf[ch]; + obuf->r_ptr = phase_vocoder_buffer_wrap(obuf, obuf->r_ptr); + } + + if (y >= y_end) + y -= y_size; + + /* Update processed samples count for next loop iteration. */ + frames_remain -= n; + } + + /* Update the sink for bytes produced. Return success. */ + sink_commit_buffer(sink, bytes); + for (ch = 0; ch < process_channels; ch++) { + obuf = &state->obuf[ch]; + obuf->s_avail -= frames; + obuf->s_free += frames; + } + + return 0; +} +#endif /* CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S16LE +/** + * phase_vocoder_source_s16() - Read S16_LE samples into the input ring buffer. + * @cd: Pointer to component private data. + * @source: Source for PCM samples data. + * @frames: Number of audio data frames to consume. + * + * Copies up to @frames frames of S16_LE PCM from @source into the per-channel + * input ring buffers, sign-extending each sample to S32 left-aligned. In + * mono-mix mode the channels are pre-summed using @cd->mono_mix_coef. + * + * Return: Value zero for success, otherwise an error code. + */ +int phase_vocoder_source_s16(struct phase_vocoder_comp_data *cd, struct sof_source *source, + int frames) +{ + struct phase_vocoder_state *state = &cd->state; + struct phase_vocoder_buffer *ibuf; + const int32_t mix_gain = cd->mono_mix_coef; + int64_t mix; + int16_t const *x, *x_start, *x_end; + int16_t in; + int frames_left; + int x_size; + int bytes; + int ret; + int n1; + int n2; + int n; + int i; + int j; + int stream_channels = cd->stream_channels; + int process_channels = cd->process_channels; + bool process_mono = cd->config->mono; + + ibuf = &state->ibuf[0]; + frames = MIN(frames, ibuf->s_free); + bytes = frames * cd->frame_bytes; + frames_left = frames; + + /* Get pointer to source data in circular buffer, get buffer start and size to + * check for wrap. The size in bytes is converted to number of s16 samples to + * control the samples process loop. If the number of bytes requested is not + * possible, an error is returned. + */ + ret = source_get_data_s16(source, bytes, &x, &x_start, &x_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + + while (frames_left) { + /* Find out samples to process before first wrap or end of data. */ + ibuf = &state->ibuf[0]; + n1 = (x_end - x) / stream_channels; + n2 = phase_vocoder_buffer_samples_without_wrap(ibuf, ibuf->w_ptr); + n = MIN(n1, n2); + n = MIN(n, frames_left); + if (process_mono) { + for (i = 0; i < n; i++) { + mix = 0; + for (j = 0; j < stream_channels; j++) + mix += Q_MULTSR_32X32((int64_t)mix_gain, *x++, 31, 15, 31); + + *ibuf->w_ptr++ = sat_int32(mix); + } + } else { + for (i = 0; i < n; i++) { + for (j = 0; j < stream_channels; j++) { + ibuf = &state->ibuf[j]; + in = *x++; + *ibuf->w_ptr++ = (int32_t)in << 16; + } + } + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + for (j = 0; j < process_channels; j++) { + ibuf = &state->ibuf[j]; + ibuf->w_ptr = phase_vocoder_buffer_wrap(ibuf, ibuf->w_ptr); + } + + if (x >= x_end) + x -= x_size; + + /* Update processed samples count for next loop iteration. */ + frames_left -= n; + } + + /* Update the source for bytes consumed. Return success. */ + source_release_data(source, bytes); + for (j = 0; j < process_channels; j++) { + ibuf = &state->ibuf[j]; + ibuf->s_avail += frames; + ibuf->s_free -= frames; + } + return 0; +} + +/** + * phase_vocoder_sink_s16() - Write processed samples out as S16_LE. + * @cd: Pointer to component private data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to produce. + * + * Copies up to @frames frames from the per-channel output ring buffer to + * @sink in S16_LE format with rounding shift from Q1.31 down to Q1.15. In + * mono-mix mode the single processed channel is replicated to all output + * channels. The output ring buffer slots are cleared after read. + * + * Return: Value zero for success, otherwise an error code. + */ +int phase_vocoder_sink_s16(struct phase_vocoder_comp_data *cd, struct sof_sink *sink, int frames) +{ + struct phase_vocoder_state *state = &cd->state; + struct phase_vocoder_buffer *obuf; + int16_t sample; + int16_t *y, *y_start, *y_end; + int frames_remain; + int y_size; + int bytes; + int ret; + int ch, n1, n, i; + int stream_channels = cd->stream_channels; + int process_channels = cd->process_channels; + bool process_mono = cd->config->mono; + + obuf = &state->obuf[0]; + frames = MIN(frames, obuf->s_avail); + if (!frames) + return 0; + + /* Get pointer to sink data in circular buffer */ + bytes = frames * cd->frame_bytes; + frames_remain = frames; + ret = sink_get_buffer_s16(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + y_end = y_start + y_size; + while (frames_remain) { + /* Find out samples to process before first wrap or end of data. */ + obuf = &state->obuf[0]; + n1 = (y_end - y) / stream_channels; + n = phase_vocoder_buffer_samples_without_wrap(obuf, obuf->r_ptr); + n = MIN(n1, n); + n = MIN(n, frames_remain); + + if (process_mono) { + for (i = 0; i < n; i++) { + sample = sat_int16(Q_SHIFT_RND(*obuf->r_ptr, 31, 15)); + for (ch = 0; ch < stream_channels; ch++) + *y++ = sample; + + *obuf->r_ptr++ = 0; /* clear overlap add mix */ + } + } else { + for (i = 0; i < n; i++) { + for (ch = 0; ch < stream_channels; ch++) { + obuf = &state->obuf[ch]; + *y++ = sat_int16(Q_SHIFT_RND(*obuf->r_ptr, 31, 15)); + *obuf->r_ptr++ = 0; /* clear overlap add mix */ + } + } + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + for (ch = 0; ch < process_channels; ch++) { + obuf = &state->obuf[ch]; + obuf->r_ptr = phase_vocoder_buffer_wrap(obuf, obuf->r_ptr); + } + + if (y >= y_end) + y -= y_size; + + /* Update processed samples count for next loop iteration. */ + frames_remain -= n; + } + + /* Update the sink for bytes produced. Return success. */ + sink_commit_buffer(sink, bytes); + for (ch = 0; ch < process_channels; ch++) { + obuf = &state->obuf[ch]; + obuf->s_avail -= frames; + obuf->s_free += frames; + } + + return 0; +} +#endif /* CONFIG_FORMAT_S16LE */ + +void phase_vocoder_fill_fft_buffer(struct phase_vocoder_state *state, int ch) +{ + struct phase_vocoder_buffer *ibuf = &state->ibuf[ch]; + struct phase_vocoder_fft *fft = &state->fft; + struct icomplex32 *fft_buf_ptr; + int32_t *prev_data = state->prev_data[ch]; + int32_t *r = ibuf->r_ptr; + const int prev_data_size = state->prev_data_size; + const int fft_hop_size = fft->fft_hop_size; + int samples_remain = fft_hop_size; + int j; + int n; + + /* Copy overlapped samples from state buffer. Imaginary part of input + * remains zero. + */ + fft_buf_ptr = fft->fft_buf; + for (j = 0; j < prev_data_size; j++) { + *fft_buf_ptr = (struct icomplex32){.real = prev_data[j], .imag = 0}; + fft_buf_ptr++; + } + + /* Copy hop size of new data from circular buffer */ + fft_buf_ptr = &fft->fft_buf[prev_data_size]; + while (samples_remain) { + n = phase_vocoder_buffer_samples_without_wrap(ibuf, r); + n = MIN(n, samples_remain); + for (j = 0; j < n; j++) { + *fft_buf_ptr = (struct icomplex32){.real = *r++, .imag = 0}; + fft_buf_ptr++; + } + r = phase_vocoder_buffer_wrap(ibuf, r); + samples_remain -= n; + } + + ibuf->r_ptr = r; + ibuf->s_avail -= fft_hop_size; + ibuf->s_free += fft_hop_size; + + /* Copy for next time data back to input data overlap buffer */ + fft_buf_ptr = &fft->fft_buf[fft_hop_size]; + for (j = 0; j < prev_data_size; j++) + *prev_data++ = fft_buf_ptr++->real; +} + +int phase_vocoder_overlap_add_ifft_buffer(struct phase_vocoder_state *state, int ch) +{ + struct phase_vocoder_buffer *obuf = &state->obuf[ch]; + struct phase_vocoder_fft *fft = &state->fft; + int32_t *w = obuf->w_ptr; + int32_t sample; + int i; + int n; + int samples_remain = fft->fft_size; + int idx = 0; + + if (obuf->s_free < samples_remain) + return -EINVAL; + + while (samples_remain) { + n = phase_vocoder_buffer_samples_without_wrap(obuf, w); + n = MIN(samples_remain, n); + for (i = 0; i < n; i++) { + sample = Q_MULTSR_32X32((int64_t)state->gain_comp, fft->fft_buf[idx].real, + 31, 31, 31); + *w = sat_int32((int64_t)*w + sample); + w++; + idx++; + } + w = phase_vocoder_buffer_wrap(obuf, w); + samples_remain -= n; + } + + w = obuf->w_ptr + fft->fft_hop_size; + obuf->w_ptr = phase_vocoder_buffer_wrap(obuf, w); + obuf->s_avail += fft->fft_hop_size; + obuf->s_free -= fft->fft_hop_size; + return 0; +} + +void phase_vocoder_apply_window(struct phase_vocoder_state *state) +{ + struct phase_vocoder_fft *fft = &state->fft; + struct icomplex32 *fft_buf_ptr = fft->fft_buf; + const int32_t *window = state->window; + const int fft_size = fft->fft_size; + int i; + + for (i = 0; i < fft_size; i++) { + fft_buf_ptr->real = sat_int32(Q_MULTSR_32X32((int64_t)fft_buf_ptr->real, + window[i], 31, 31, 31)); + fft_buf_ptr++; + } +} diff --git a/src/audio/phase_vocoder/phase_vocoder-ipc4.c b/src/audio/phase_vocoder/phase_vocoder-ipc4.c new file mode 100644 index 000000000000..f28e7d5db833 --- /dev/null +++ b/src/audio/phase_vocoder/phase_vocoder-ipc4.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include "phase_vocoder.h" + +LOG_MODULE_DECLARE(phase_vocoder, CONFIG_SOF_LOG_LEVEL); + +/* IPC4 controls handler */ +__cold int phase_vocoder_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 sof_ipc4_control_msg_payload *ctl = (struct sof_ipc4_control_msg_payload *)fragment; + struct phase_vocoder_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + + assert_can_be_cold(); + + switch (param_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + if (ctl->id != 0) { + comp_err(dev, "Illegal switch control id = %d.", ctl->id); + return -EINVAL; + } + + if (ctl->num_elems != 1) { + comp_err(dev, "Illegal switch control num_elems = %d.", ctl->num_elems); + return -EINVAL; + } + + cd->enable = ctl->chanv[0].value; + comp_info(dev, "enable = %d", cd->enable); + return 0; + + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + if (ctl->id != 0) { + comp_err(dev, "Illegal enum control id = %d.", ctl->id); + return -EINVAL; + } + + if (ctl->num_elems != 1) { + comp_err(dev, "Illegal enum control num_elems = %d.", ctl->num_elems); + return -EINVAL; + } + + if (ctl->chanv[0].value > 15) { + comp_err(dev, "Illegal enum control value = %d.", ctl->chanv[0].value); + return -EINVAL; + } + + cd->speed_enum = ctl->chanv[0].value; + cd->speed_ctrl = PHASE_VOCODER_MIN_SPEED_Q29 + + Q_MULTSR_32X32((int64_t)cd->speed_enum, PHASE_VOCODER_SPEED_STEP_Q31, + 0, 31, 29); + + comp_info(dev, "speed_enum = %d, speed = %d", cd->speed_enum, cd->speed_ctrl); + return 0; + } + + if (fragment_size != sizeof(struct sof_phase_vocoder_config)) { + comp_err(dev, "Illegal fragment size %d, expect %d.", fragment_size, + sizeof(struct sof_phase_vocoder_config)); + return -EINVAL; + } + + if (!cd->config) { + cd->config = mod_alloc(mod, sizeof(struct sof_phase_vocoder_config)); + if (!cd->config) { + comp_err(dev, "Failed to allocate configuration."); + return -ENOMEM; + } + } + + memcpy_s(cd->config, sizeof(struct sof_phase_vocoder_config), fragment, fragment_size); + return 0; +} + +/* Not used in IPC4 systems, if IPC4 only component, omit .get_configuration set */ +__cold int phase_vocoder_get_config(struct processing_module *mod, uint32_t config_id, + uint32_t *data_offset_size, uint8_t *fragment, + size_t fragment_size) +{ + assert_can_be_cold(); + return 0; +} diff --git a/src/audio/phase_vocoder/phase_vocoder.c b/src/audio/phase_vocoder/phase_vocoder.c new file mode 100644 index 000000000000..b82bf700eb9e --- /dev/null +++ b/src/audio/phase_vocoder/phase_vocoder.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/source_api.h> +#include <rtos/init.h> +#include "phase_vocoder.h" + +/* UUID identifies the components. Use e.g. command uuidgen from package + * uuid-runtime, add it to uuid-registry.txt in SOF top level. + */ +SOF_DEFINE_REG_UUID(phase_vocoder); + +/* Creates logging data for the component */ +LOG_MODULE_REGISTER(phase_vocoder, CONFIG_SOF_LOG_LEVEL); + +/* Creates the component trace. Traces show in trace console the component + * info, warning, and error messages. + */ +DECLARE_TR_CTX(phase_vocoder_tr, SOF_UUID(phase_vocoder_uuid), LOG_LEVEL_INFO); + +#if STFT_DEBUG +FILE *stft_debug_fft_in_fh; +FILE *stft_debug_fft_out_fh; +FILE *stft_debug_ifft_out_fh; +#endif + +static void phase_vocoder_reset_parameters(struct processing_module *mod) +{ + struct phase_vocoder_comp_data *cd = module_get_private_data(mod); + struct sof_phase_vocoder_config *config = cd->config; + + memset(cd, 0, sizeof(*cd)); + cd->config = config; + cd->enable = false; + cd->speed_ctrl = PHASE_VOCODER_SPEED_NORMAL; + + /* Sync state.speed */ + phase_vocoder_reset_for_new_speed(cd); +} + +/** + * phase_vocoder_init() - Initialize the phase_vocoder component. + * @mod: Pointer to module data. + * + * This function is called when the instance is created. The + * macro __cold informs that the code that is non-critical + * is loaded to slower but large DRAM. + * + * Return: Zero if success, otherwise error code. + */ +__cold static int phase_vocoder_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct comp_dev *dev = mod->dev; + struct phase_vocoder_comp_data *cd; + + assert_can_be_cold(); + + comp_info(dev, "phase_vocoder_init()"); + + cd = mod_zalloc(mod, sizeof(*cd)); + if (!cd) + return -ENOMEM; + + md->private = cd; + phase_vocoder_reset_parameters(mod); + +#if STFT_DEBUG + stft_debug_fft_in_fh = fopen("stft_debug_fft_in.txt", "w"); + if (!stft_debug_fft_in_fh) { + fprintf(stderr, "Debug file open failed.\n"); + return -EINVAL; + } + + stft_debug_fft_out_fh = fopen("stft_debug_fft_out.txt", "w"); + if (!stft_debug_fft_out_fh) { + fclose(stft_debug_fft_in_fh); + fprintf(stderr, "Debug file open failed.\n"); + return -EINVAL; + } + + stft_debug_ifft_out_fh = fopen("stft_debug_ifft_out.txt", "w"); + if (!stft_debug_ifft_out_fh) { + fprintf(stderr, "Debug file open failed.\n"); + fclose(stft_debug_fft_in_fh); + fclose(stft_debug_fft_out_fh); + return -EINVAL; + } +#endif + + return 0; +} + +/** + * phase_vocoder_process() - The audio data processing function. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * This is the processing function that is called for scheduled + * pipelines. The processing is controlled by the enable switch. + * + * Return: Zero if success, otherwise error code. + */ +static int phase_vocoder_process(struct processing_module *mod, struct sof_source **sources, + int num_of_sources, struct sof_sink **sinks, int num_of_sinks) +{ + struct phase_vocoder_comp_data *cd = module_get_private_data(mod); + struct sof_source *source = sources[0]; /* One input */ + struct sof_sink *sink = sinks[0]; /* One output */ + int source_frames = source_get_data_frames_available(source); + int sink_frames = sink_get_free_frames(sink); + int frames; + int ret; + + if (cd->speed_ctrl != cd->state.speed) + phase_vocoder_reset_for_new_speed(cd); + + if (cd->enable) { + ret = cd->phase_vocoder_func(mod, source, sink, source_frames, sink_frames); + if (ret) + comp_err(mod->dev, "Failure, check the setup parameters."); + + return ret; + } + + /* Just copy from source to sink. */ + frames = MIN(source_frames, sink_frames); + source_to_sink_copy(source, sink, true, frames * cd->frame_bytes); + return 0; +} + +/** + * phase_vocoder_prepare() - Prepare the component for processing. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * Function prepare is called just before the pipeline is started. In + * this case the audio format parameters are for better code performance + * saved to component data to avoid to find out them in process. The + * processing function pointer is set to process the current audio format. + * + * Return: Value zero if success, otherwise error code. + */ +static int phase_vocoder_prepare(struct processing_module *mod, struct sof_source **sources, + int num_of_sources, struct sof_sink **sinks, int num_of_sinks) +{ + struct module_data *mod_priv = &mod->priv; + struct ipc4_base_module_cfg *base_cfg = &mod_priv->cfg.base_cfg; + struct phase_vocoder_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + enum sof_ipc_frame source_format; + int ret; + + comp_dbg(dev, "prepare"); + + /* The processing example in this component supports one input and one + * output. Generally there can be more. + */ + if (num_of_sources != 1 || num_of_sinks != 1) { + comp_err(dev, "Only one source and one sink is supported."); + return -EINVAL; + } + + /* Initialize STFT, max_frames is set to dev->frames + 4 */ + if (!cd->config) { + comp_err(dev, "Can't prepare without bytes control configuration."); + return -EINVAL; + } + + /* get source data format */ + cd->frame_bytes = source_get_frame_bytes(sources[0]); + cd->stream_channels = source_get_channels(sources[0]); + cd->sample_rate = source_get_rate(sources[0]); + + /* Note: dev->frames is zero, use ibs */ + cd->max_input_frames = base_cfg->ibs / cd->frame_bytes + PHASE_VOCODER_MAX_FRAMES_MARGIN; + cd->max_output_frames = base_cfg->obs / cd->frame_bytes + PHASE_VOCODER_MAX_FRAMES_MARGIN; + source_format = source_get_valid_fmt(sources[0]); + comp_info(dev, "source_format %d channels %d max_input_frames %d max_output_frames %d", + source_format, cd->stream_channels, cd->max_input_frames, cd->max_output_frames); + + ret = phase_vocoder_setup(mod); + if (ret < 0) { + comp_err(dev, "setup failed."); + return ret; + } + + cd->phase_vocoder_func = phase_vocoder_find_proc_func(source_format); + if (!cd->phase_vocoder_func) { + comp_err(dev, "No processing function found for format %d.", source_format); + return -EINVAL; + } + + return 0; +} + +/** + * phase_vocoder_reset() - Reset the component. + * @mod: Pointer to module data. + * + * The component reset is called when pipeline is stopped. The reset + * should return the component to same state as init. + * + * Return: Value zero, always success. + */ +static int phase_vocoder_reset(struct processing_module *mod) +{ + comp_dbg(mod->dev, "reset"); + + phase_vocoder_free_buffers(mod); + phase_vocoder_reset_parameters(mod); + return 0; +} + +/** + * phase_vocoder_free() - Free dynamic allocations. + * @mod: Pointer to module data. + * + * Component free is called when the pipelines are deleted. All + * dynamic allocations need to be freed here. The macro __cold + * instructs the build to locate this performance wise non-critical + * function to large and slower DRAM. + * + * Return: Value zero, always success. + */ +__cold static int phase_vocoder_free(struct processing_module *mod) +{ + struct phase_vocoder_comp_data *cd = module_get_private_data(mod); + + assert_can_be_cold(); + + comp_dbg(mod->dev, "free"); + mod_free(mod, cd->config); + mod_free(mod, cd); + +#if STFT_DEBUG + fclose(stft_debug_fft_in_fh); + fclose(stft_debug_fft_out_fh); + fclose(stft_debug_ifft_out_fh); +#endif + return 0; +} + +/* This defines the module operations */ +static const struct module_interface phase_vocoder_interface = { + .init = phase_vocoder_init, + .prepare = phase_vocoder_prepare, + .process = phase_vocoder_process, + .set_configuration = phase_vocoder_set_config, + .get_configuration = phase_vocoder_get_config, + .reset = phase_vocoder_reset, + .free = phase_vocoder_free}; + +/* This controls build of the module. If COMP_MODULE is selected in kconfig + * this is build as dynamically loadable module. + */ +#if CONFIG_COMP_PHASE_VOCODER_MODULE + +#include <module/module/api_ver.h> +#include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> + +static const struct sof_man_module_manifest mod_manifest __section(".module") __used = + SOF_LLEXT_MODULE_MANIFEST("PHASEVOC", &phase_vocoder_interface, 1, + SOF_REG_UUID(phase_vocoder), 40); + +SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_MODULE_ADAPTER(phase_vocoder_interface, phase_vocoder_uuid, phase_vocoder_tr); +SOF_MODULE_INIT(phase_vocoder, sys_comp_module_phase_vocoder_interface_init); + +#endif diff --git a/src/audio/phase_vocoder/phase_vocoder.h b/src/audio/phase_vocoder/phase_vocoder.h new file mode 100644 index 000000000000..fbf95fdeeeec --- /dev/null +++ b/src/audio/phase_vocoder/phase_vocoder.h @@ -0,0 +1,334 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + * + */ +#ifndef __SOF_AUDIO_PHASE_VOCODER_H__ +#define __SOF_AUDIO_PHASE_VOCODER_H__ + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/math/auditory.h> +#include <sof/math/dct.h> +#include <sof/math/fft.h> + +#include <stdbool.h> +#include <stdint.h> + +#if CONFIG_LIBRARY +#define STFT_DEBUG 0 /* Keep zero, produces large files with fprintf() */ +#else +#define STFT_DEBUG 0 +#endif + +#define PHASE_VOCODER_MAX_FRAMES_MARGIN 0 /* Adds to buffer size */ +#define PHASE_VOCODER_MIN_SPEED_Q29 Q_CONVERT_FLOAT(0.5, 29) /* Min. speed is 0.5 */ +#define PHASE_VOCODER_MAX_SPEED_Q29 Q_CONVERT_FLOAT(2.0, 29) /* Max. speed is 2.0 */ +#define PHASE_VOCODER_SPEED_STEP_Q31 Q_CONVERT_FLOAT((2 - 0.5) / 15, 31) /* Steps for enum ctrl */ +#define PHASE_VOCODER_SPEED_NORMAL Q_CONVERT_FLOAT(1.0, 29) /* Default to speed 1 */ +#define PHASE_VOCODER_ONE_Q29 Q_CONVERT_FLOAT(1.0, 29) /* One as Q29 */ +#define PHASE_VOCODER_HALF_Q29 Q_CONVERT_FLOAT(0.5, 29) /* 0.5 as Q29 */ + +#define PHASE_VOCODER_PI_Q28 843314857 /* int32(pi * 2^28), Q28 */ +#define PHASE_VOCODER_TWO_PI_Q28 1686629713 /* int32(2 * pi * 2^28), Q28 */ + +#define PHASE_VOCODER_PI_Q27 421657428 /* int32(pi * 2^27) */ +#define PHASE_VOCODER_TWO_PI_Q27 843314857 /* int32(2 * pi * 2^27) */ + +enum sof_phase_vocoder_fft_window_type { + STFT_RECTANGULAR_WINDOW = 0, + STFT_BLACKMAN_WINDOW = 1, + STFT_HAMMING_WINDOW = 2, + STFT_HANN_WINDOW = 3, +}; + +/** + * struct sof_phase_vocoder_config - IPC configuration blob for phase vocoder + * @size: Size of this struct in bytes + * @reserved: Reserved for future use + * @sample_frequency: Sample rate in Hz, e.g. 16000 + * @window_gain_comp: Q1.31 gain for IFFT + * @reserved_32: Reserved for future use + * @mono: Set to 1 for mono, zero for all channels + * @frame_length: Frame length in samples, e.g. 400 for 25 ms @ 16 kHz + * @frame_shift: Frame shift in samples, e.g. 160 for 10 ms @ 16 kHz + * @reserved_16: Reserved for future use + * @reserved_pad: Reserved for future use, kept for ABI compatibility + * @window: Window type, use RECTANGULAR_WINDOW, etc. + */ +struct sof_phase_vocoder_config { + uint32_t size; + uint32_t reserved[8]; + int32_t sample_frequency; + int32_t window_gain_comp; + int32_t reserved_32; + int16_t mono; + int16_t frame_length; + int16_t frame_shift; + int16_t reserved_16; + int32_t reserved_pad; + enum sof_phase_vocoder_fft_window_type window; +} __attribute__((packed)); + +/** + * struct phase_vocoder_buffer - Circular buffer for phase vocoder audio data + * @addr: Start address of the buffer + * @end_addr: End address of the buffer + * @r_ptr: Read pointer + * @w_ptr: Write pointer + * @s_avail: Available samples count + * @s_free: Free samples count + * @s_length: Buffer length in samples for wrap + */ +struct phase_vocoder_buffer { + int32_t *addr; + int32_t *end_addr; + int32_t *r_ptr; + int32_t *w_ptr; + int s_avail; + int s_free; + int s_length; +}; + +/** + * struct phase_vocoder_fft - FFT processing state + * @fft_buf: FFT input buffer, size is fft_size + * @fft_out: FFT output buffer, size is fft_size + * @fft_plan: FFT plan instance + * @ifft_plan: Inverse FFT plan instance + * @fft_size: FFT length in samples + * @fft_hop_size: FFT hop size in samples + * @half_fft_size: Half of the FFT size + * @fft_buffer_size: FFT buffer size in bytes + */ +struct phase_vocoder_fft { + struct icomplex32 *fft_buf; + struct icomplex32 *fft_out; + struct fft_plan *fft_plan; + struct fft_plan *ifft_plan; + int fft_size; + int fft_hop_size; + int half_fft_size; + size_t fft_buffer_size; +}; + +/** + * struct phase_vocoder_polar - Polar domain processing data + * @polar: Current polar representation per channel + * @polar_prev: Previous polar representation per channel + * @polar_tmp: Temporary polar buffer + * @polar_buffer: Base address of the joint polar/angle/output-phase allocation + * @angle_delta_prev: Previous angle delta per channel + * @angle_delta: Current angle delta per channel + * @output_phase: Output phase per channel + */ +struct phase_vocoder_polar { + struct ipolar32 *polar[PLATFORM_MAX_CHANNELS]; + struct ipolar32 *polar_prev[PLATFORM_MAX_CHANNELS]; + struct ipolar32 *polar_tmp; + int32_t *polar_buffer; + int32_t *angle_delta_prev[PLATFORM_MAX_CHANNELS]; + int32_t *angle_delta[PLATFORM_MAX_CHANNELS]; + int32_t *output_phase[PLATFORM_MAX_CHANNELS]; +}; + +/** + * struct phase_vocoder_state - Phase vocoder algorithm state + * @ibuf: Circular buffers for input data, per channel + * @obuf: Circular buffers for output data, per channel + * @fft: FFT instance, common for all channels + * @polar: Processing state in polar domain + * @phase_vocoder_polar_bytes: Size in bytes of the joint polar allocation + * @prev_data: Previous frame data per channel, size is prev_data_size + * @buffers: Pointer to allocated memory for all buffers + * @window: Window function coefficients, size is fft_size + * @num_input_fft_to_use: Number of input FFTs to use for processing + * @num_input_fft: Total input FFTs count + * @num_output_ifft: Total output IFFTs count + * @gain_comp: Gain to compensate window gain + * @interpolate_fraction: Q3.29 interpolation coefficient + * @speed: Q3.29 actual render speed + * @prev_data_size: Size of previous data buffer + * @first_output_ifft_done: True after first output IFFT is completed + */ +struct phase_vocoder_state { + struct phase_vocoder_buffer ibuf[PLATFORM_MAX_CHANNELS]; + struct phase_vocoder_buffer obuf[PLATFORM_MAX_CHANNELS]; + struct phase_vocoder_fft fft; + struct phase_vocoder_polar polar; + size_t phase_vocoder_polar_bytes; + int32_t *prev_data[PLATFORM_MAX_CHANNELS]; + int32_t *buffers; + int32_t *window; + int32_t num_input_fft_to_use; + int32_t num_input_fft; + int32_t num_output_ifft; + int32_t gain_comp; + int32_t interpolate_fraction; + int32_t speed; + int prev_data_size; + bool first_output_ifft_done; +}; + +/** + * typedef phase_vocoder_func - Function pointer for process function + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @source_frames: Number of source audio data frames to process. + * @sink_frames: Number of sink audio data frames to produce. + */ +typedef int (*phase_vocoder_func)(const struct processing_module *mod, struct sof_source *source, + struct sof_sink *sink, uint32_t source_frames, + uint32_t sink_frames); + +/** + * struct phase_vocoder_comp_data - Phase vocoder component data + * @phase_vocoder_func: Pointer to used processing function. + * @state: Phase vocoder algorithm state. + * @config: Configuration blob for the module. + * @mono_mix_coef: Gain for channel for mixing, Q1.15 + * @sample_rate: Audio sample rate in Hz + * @speed_ctrl: Speed Q3.29, allowed range 0.5 to 2.0 + * @speed_enum: Speed control value as enum 0-15 + * @frame_bytes: Number of bytes in an audio frame. + * @max_input_frames: Maximum number of input frames per processing call + * @max_output_frames: Maximum number of output frames per processing call + * @stream_channels: Channels count to consume/produce + * @process_channels: Channels count to process. + * @enable: Control processing on/off, off is pass-through + */ +struct phase_vocoder_comp_data { + phase_vocoder_func phase_vocoder_func; + struct phase_vocoder_state state; + struct sof_phase_vocoder_config *config; + int32_t mono_mix_coef; + int32_t sample_rate; + int32_t speed_ctrl; + int32_t speed_enum; + size_t frame_bytes; + int max_input_frames; + int max_output_frames; + int stream_channels; + int process_channels; + bool enable; +}; + +static inline int phase_vocoder_buffer_samples_without_wrap(struct phase_vocoder_buffer *buffer, + int32_t *ptr) +{ + return buffer->end_addr - ptr; +} + +static inline int32_t *phase_vocoder_buffer_wrap(struct phase_vocoder_buffer *buffer, int32_t *ptr) +{ + if (ptr >= buffer->end_addr) + ptr -= buffer->s_length; + + return ptr; +} + +/** + * struct phase_vocoder_proc_fnmap - processing functions for frame formats + * @frame_fmt: Current frame format + * @phase_vocoder_proc_func: Function pointer for the suitable processing function + */ +struct phase_vocoder_proc_fnmap { + enum sof_ipc_frame frame_fmt; + phase_vocoder_func phase_vocoder_function; +}; + +/** + * phase_vocoder_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +phase_vocoder_func phase_vocoder_find_proc_func(enum sof_ipc_frame src_fmt); + +#if CONFIG_IPC_MAJOR_4 +/** + * phase_vocoder_set_config() - Handle controls set + * @mod: Pointer to module data. + * @param_id: Id to know control type, used to know ALSA control type. + * @pos: Position of the fragment in the large message. + * @data_offset_size: Size of the whole configuration if it is the first or only + * fragment. Otherwise it is offset of the fragment. + * @fragment: Message payload data. + * @fragment_size: Size of this fragment. + * @response_size: Size of response. + * + * This function handles the real-time controls. The ALSA controls have the + * param_id set to indicate the control type. The control ID, from topology, + * is used to separate the controls instances of same type. In control payload + * the num_elems defines to how many channels the control is applied to. + * + * Return: Zero if success, otherwise error code. + */ +int phase_vocoder_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); +/** + * phase_vocoder_get_config() - Handle controls get + * @mod: Pointer to module data. + * @config_id: Configuration ID. + * @data_offset_size: Size of the whole configuration if it is the first or only + * fragment. Otherwise it is offset of the fragment. + * @fragment: Message payload data. + * @fragment_size: Size of this fragment. + * + * This function is used for controls get. + * + * Return: Zero if success, otherwise error code. + */ +int phase_vocoder_get_config(struct processing_module *mod, uint32_t config_id, + uint32_t *data_offset_size, uint8_t *fragment, size_t fragment_size); +#else +static inline int phase_vocoder_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) +{ + return 0; +} + +static inline int phase_vocoder_get_config(struct processing_module *mod, uint32_t config_id, + uint32_t *data_offset_size, uint8_t *fragment, + size_t fragment_size) +{ + return 0; +} +#endif + +void phase_vocoder_apply_window(struct phase_vocoder_state *state); + +void phase_vocoder_fill_fft_buffer(struct phase_vocoder_state *state, int ch); + +void phase_vocoder_free_buffers(struct processing_module *mod); + +int phase_vocoder_overlap_add_ifft_buffer(struct phase_vocoder_state *state, int ch); + +void phase_vocoder_reset_for_new_speed(struct phase_vocoder_comp_data *cd); + +int phase_vocoder_setup(struct processing_module *mod); + +int phase_vocoder_sink_s16(struct phase_vocoder_comp_data *cd, struct sof_sink *sink, int frames); + +int phase_vocoder_sink_s24(struct phase_vocoder_comp_data *cd, struct sof_sink *sink, int frames); + +int phase_vocoder_sink_s32(struct phase_vocoder_comp_data *cd, struct sof_sink *sink, int frames); + +int phase_vocoder_source_s16(struct phase_vocoder_comp_data *cd, struct sof_source *source, + int frames); + +int phase_vocoder_source_s24(struct phase_vocoder_comp_data *cd, struct sof_source *source, + int frames); + +int phase_vocoder_source_s32(struct phase_vocoder_comp_data *cd, struct sof_source *source, + int frames); + +#endif // __SOF_AUDIO_PHASE_VOCODER_H__ diff --git a/src/audio/phase_vocoder/phase_vocoder.toml b/src/audio/phase_vocoder/phase_vocoder.toml new file mode 100644 index 000000000000..9ec249fe01a5 --- /dev/null +++ b/src/audio/phase_vocoder/phase_vocoder.toml @@ -0,0 +1,21 @@ +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + + REM # Template component module config + [[module.entry]] + name = "PHASEVOC" + uuid = UUIDREG_STR_PHASE_VOCODER + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = LOAD_TYPE + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + REM # 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] + + index = __COUNTER__ diff --git a/src/audio/phase_vocoder/phase_vocoder_common.c b/src/audio/phase_vocoder/phase_vocoder_common.c new file mode 100644 index 000000000000..d21f4e9e90e5 --- /dev/null +++ b/src/audio/phase_vocoder/phase_vocoder_common.c @@ -0,0 +1,588 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include <sof/audio/component.h> +#include <sof/audio/audio_stream.h> +#include <sof/math/auditory.h> +#include <sof/math/icomplex32.h> +#include <sof/math/matrix.h> +#include <sof/math/numbers.h> +#include <sof/math/sqrt.h> +#include <sof/math/trig.h> +#include <sof/math/window.h> +#include <sof/trace/trace.h> + +#include "phase_vocoder.h" + +#include <errno.h> +#include <stddef.h> +#include <stdint.h> + +#if STFT_DEBUG +extern FILE *stft_debug_fft_in_fh; +extern FILE *stft_debug_fft_out_fh; +extern FILE *stft_debug_ifft_out_fh; + +static void debug_print_to_file_real(FILE *fh, struct icomplex32 *c, int n) +{ + for (int i = 0; i < n; i++) + fprintf(fh, "%d\n", c[i].real); +} + +static void debug_print_to_file_complex(FILE *fh, struct icomplex32 *c, int n) +{ + for (int i = 0; i < n; i++) + fprintf(fh, "%d %d\n", c[i].real, c[i].imag); +} +#endif + +LOG_MODULE_REGISTER(phase_vocoder_common, CONFIG_SOF_LOG_LEVEL); + +static int stft_get_num_ffts_avail(struct phase_vocoder_state *state, int channel) +{ + struct phase_vocoder_buffer *ibuf = &state->ibuf[channel]; + struct phase_vocoder_fft *fft = &state->fft; + + /* Wait for FFT hop size of new data */ + return ibuf->s_avail / fft->fft_hop_size; +} + +static void stft_do_fft(struct phase_vocoder_state *state, int ch) +{ + struct phase_vocoder_fft *fft = &state->fft; + + /* Copy data to FFT input buffer from overlap buffer and from new samples buffer */ + phase_vocoder_fill_fft_buffer(state, ch); + + /* Window function */ + phase_vocoder_apply_window(state); + +#if STFT_DEBUG + debug_print_to_file_real(stft_debug_fft_in_fh, fft->fft_buf, fft->fft_size); +#endif + + /* Compute FFT. A full scale s16 sine input with 2^N samples period in low + * part of s32 real part and zero imaginary part gives to output about 0.5 + * full scale 32 bit output to real and imaginary. The scaling is same for + * all FFT sizes. + */ + fft_execute_32(fft->fft_plan, false); + +#if STFT_DEBUG + debug_print_to_file_complex(stft_debug_fft_out_fh, fft->fft_out, fft->fft_size); +#endif +} + +static int stft_do_ifft(struct phase_vocoder_state *state, int ch) +{ + struct phase_vocoder_fft *fft = &state->fft; + + /* Compute IFFT */ + fft_execute_32(fft->ifft_plan, true); + +#if STFT_DEBUG + debug_print_to_file_complex(stft_debug_ifft_out_fh, fft->fft_buf, fft->fft_size); +#endif + + /* Window function */ + phase_vocoder_apply_window(state); + + /* Copy to output buffer */ + return phase_vocoder_overlap_add_ifft_buffer(state, ch); +} + +/** + * stft_convert_to_polar() - Convert FFT output to polar format + * @fft: FFT state containing the FFT output buffer and parameters as Q1.31. + * @polar_data: Output buffer for polar data, size is half of FFT size. + * Magnitude is Q2.30 and phase is Q5.27. + */ +static void stft_convert_to_polar(struct phase_vocoder_fft *fft, struct ipolar32 *polar_data) +{ + int i; + + /* Get magnitude and phase, convert phase from Q3.29 to Q5.27. */ + for (i = 0; i < fft->half_fft_size; i++) { + sofm_icomplex32_to_polar(&fft->fft_out[i], &polar_data[i]); + polar_data[i].angle = Q_SHIFT_RND(polar_data[i].angle, 29, 27); + } +} + +/** + * stft_convert_to_complex() - Convert polar data back to complex format for IFFT + * @polar_data: Input polar data, size is half of FFT size. + * Magnitude is Q2.30 and phase is Q5.27. + * @fft: FFT state containing the output buffer where complex data will + * be stored and parameters as Q1.31. + */ +static void stft_convert_to_complex(struct ipolar32 *polar_data, struct phase_vocoder_fft *fft) +{ + int i; + + /* Convert phase from Q5.27 to Q3.29, and then to (re, im) complex format as Q1.31*/ + for (i = 0; i < fft->half_fft_size; i++) { + polar_data[i].angle = Q_SHIFT_LEFT(polar_data[i].angle, 27, 29); + sofm_ipolar32_to_complex(&polar_data[i], &fft->fft_out[i]); + } +} + +static void stft_apply_fft_symmetry(struct phase_vocoder_fft *fft) +{ + int i, j, k; + + j = 2 * fft->half_fft_size - 2; + for (i = fft->half_fft_size; i < fft->fft_size; i++) { + k = j - i; + fft->fft_out[i].real = fft->fft_out[k].real; + fft->fft_out[i].imag = -fft->fft_out[k].imag; + } +} + +/** + * phase_vocoder_normalize_counters - Prevent int32 overflow in frame counters + * + * The interpolation fraction depends on (num_output_ifft * speed) mod 2^29. + * By subtracting a multiple of the fraction cycle period from num_output_ifft + * (and the corresponding integer amount from num_input_fft), the fraction is + * preserved exactly while keeping both counters small. + */ +static void phase_vocoder_normalize_counters(struct phase_vocoder_state *state, int32_t speed) +{ + int32_t g; + int32_t output_period; + int32_t delta_output; + int64_t delta_input_scaled; + + if (state->num_output_ifft < (1 << 28)) + return; + + /* The fraction cycle repeats every (2^29 / gcd(speed, 2^29)) output IFFTs */ + g = gcd(speed, 1 << 29); + output_period = (1 << 29) / g; + + /* Subtract the largest multiple of output_period that fits */ + delta_output = (state->num_output_ifft / output_period) * output_period; + if (!delta_output) + return; + + /* delta_output * speed is a multiple of 2^29 by construction, + * so the interpolation fraction is exactly preserved. + */ + delta_input_scaled = (int64_t)delta_output * speed; + + state->num_output_ifft -= delta_output; + state->num_input_fft -= (int32_t)(delta_input_scaled >> 29); +} + +static void phase_vocoder_interpolation_parameters(struct phase_vocoder_comp_data *cd) +{ + struct phase_vocoder_state *state = &cd->state; + int64_t input_frame_num_frac; + int32_t input_frame_num_floor; + + phase_vocoder_normalize_counters(state, cd->state.speed); + + input_frame_num_frac = (int64_t)state->num_output_ifft * cd->state.speed; /* Q31.29 */ + input_frame_num_floor = (int32_t)(input_frame_num_frac >> 29); /* Use floor, not round */ + state->num_input_fft_to_use = input_frame_num_floor + 1; + state->interpolate_fraction = input_frame_num_frac - ((int64_t)input_frame_num_floor << 29); +} + +#if 0 +static int32_t unwrap_angle(int32_t angle) +{ + if (angle > PHASE_VOCODER_PI_Q28) + return angle - PHASE_VOCODER_TWO_PI_Q28; + else if (angle < -PHASE_VOCODER_PI_Q28) + return angle + PHASE_VOCODER_TWO_PI_Q28; + else + return angle; +} +#endif + +static int32_t unwrap_angle_q27(int32_t angle) +{ + while (angle > PHASE_VOCODER_PI_Q27) + angle -= PHASE_VOCODER_TWO_PI_Q27; + + while (angle < -PHASE_VOCODER_PI_Q27) + angle += PHASE_VOCODER_TWO_PI_Q27; + + return angle; +} + +void phase_vocoder_reset_for_new_speed(struct phase_vocoder_comp_data *cd) +{ + struct phase_vocoder_state *state = &cd->state; + + state->speed = cd->speed_ctrl; + + /* Keep num_input_fft at 1, not 0, to avoid re-entering the first + * analysis FFT cold-start path. That path sets angle_delta to the + * absolute phase angle (not a delta between frames). For non-unity + * speeds, multiple IFFTs are produced per input FFT, and the + * absolute angle gets repeatedly accumulated into output_phase + * causing random inter-bin phase incoherence and gain variation. + * + * By setting num_input_fft = 1 the existing polar, angle_delta, + * and output_phase state from the last processing step is preserved. + * These contain proper phase deltas, so interpolation continues + * correctly at the new speed. + */ + state->num_input_fft = 1; + state->num_output_ifft = 0; +} + +static void copy_polar_angles(int32_t *angle_delta_ch, struct ipolar32 *polar_data_ch, + int num_angles) +{ + int i; + + for (i = 0; i < num_angles; i++) + angle_delta_ch[i] = polar_data_ch[i].angle; +} + +// TODO: Civilized input and output counters reset to prevent int32_t wrap +static int stft_do_fft_ifft(const struct processing_module *mod) +{ + struct phase_vocoder_comp_data *cd = module_get_private_data(mod); + struct phase_vocoder_state *state = &cd->state; + struct phase_vocoder_polar *polar = &state->polar; + struct phase_vocoder_fft *fft = &state->fft; + struct ipolar32 *polar_data_prev_ch; + struct ipolar32 *polar_data_ch; + int32_t *angle_delta_prev_ch; + int32_t *angle_delta_ch; + int32_t *output_phase_ch; + int32_t one_minus_frac; + int32_t frac; + int32_t p1, p2; + int32_t a; + const size_t polar_fft_half_bytes = sizeof(struct ipolar32) * fft->half_fft_size; + const size_t int32_fft_half_bytes = sizeof(int32_t) * fft->half_fft_size; + int num_fft; + int ret = 0; + int ch; + int i; + + num_fft = stft_get_num_ffts_avail(state, 0); + if (!num_fft) + return 0; + + /* First analysis FFT */ + if (!state->num_input_fft) { + for (ch = 0; ch < cd->process_channels; ch++) { + stft_do_fft(state, ch); + + /* Convert half-FFT to polar. Magnitude is Q2.30 and phase + * angle is Q5.27. + */ + polar_data_ch = polar->polar[ch]; /* struct ipolar32 */ + stft_convert_to_polar(&state->fft, polar_data_ch); + + /* Initialize output phase directly to the absolute phase + * of the first frame. This avoids the accumulation path + * which would double-count the initial phase when it + * later moves from angle_delta to angle_delta_prev. + */ + output_phase_ch = polar->output_phase[ch]; + copy_polar_angles(output_phase_ch, polar_data_ch, fft->half_fft_size); + + /* Initialize prev polar to same data so magnitude + * interpolation works before second FFT is consumed. + * Leave angle_delta and angle_delta_prev at zero so the + * phase does not advance until real deltas are computed. + */ + memcpy(polar->polar_prev[ch], polar_data_ch, polar_fft_half_bytes); + } + state->num_input_fft++; + num_fft--; + } + + phase_vocoder_interpolation_parameters(cd); + while (state->num_input_fft < state->num_input_fft_to_use && num_fft > 0) { + for (ch = 0; ch < cd->process_channels; ch++) { + stft_do_fft(state, ch); + + /* Update previous polar data. + * Note: Not using memcpy_s() since this is hot algorithm code. + */ + polar_data_prev_ch = polar->polar_prev[ch]; + polar_data_ch = polar->polar[ch]; + memcpy(polar_data_prev_ch, polar_data_ch, polar_fft_half_bytes); + + /* Convert half-FFT to polar. Magnitude is Q2.30 and phase + * angle is Q5.27. + */ + stft_convert_to_polar(&state->fft, polar_data_ch); + + /* Update previous delta phase data */ + angle_delta_ch = polar->angle_delta[ch]; + angle_delta_prev_ch = polar->angle_delta_prev[ch]; + memcpy(angle_delta_prev_ch, angle_delta_ch, int32_fft_half_bytes); + + /* Calculate new delta phase */ + for (i = 0; i < fft->half_fft_size; i++) { + a = polar_data_ch[i].angle - polar_data_prev_ch[i].angle; + angle_delta_ch[i] = unwrap_angle_q27(a); + } + } + state->num_input_fft++; + num_fft--; + } + + if (state->num_input_fft < state->num_input_fft_to_use) + return 0; + + /* Interpolate IFFT frame */ + frac = state->interpolate_fraction; + one_minus_frac = PHASE_VOCODER_ONE_Q29 - frac; + + for (ch = 0; ch < cd->process_channels; ch++) { + polar_data_prev_ch = polar->polar_prev[ch]; + polar_data_ch = polar->polar[ch]; + angle_delta_ch = polar->angle_delta[ch]; + angle_delta_prev_ch = polar->angle_delta_prev[ch]; + output_phase_ch = polar->output_phase[ch]; + + for (i = 0; i < fft->half_fft_size; i++) { + p1 = Q_MULTSR_32X32((int64_t)one_minus_frac, + polar_data_prev_ch[i].magnitude, 29, 30, 30); + p2 = Q_MULTSR_32X32((int64_t)frac, polar_data_ch[i].magnitude, 29, 30, 30); + polar->polar_tmp[i].magnitude = p1 + p2; + + a = output_phase_ch[i]; + p1 = Q_MULTSR_32X32((int64_t)one_minus_frac, angle_delta_prev_ch[i], 29, 27, + 27); + p2 = Q_MULTSR_32X32((int64_t)frac, angle_delta_ch[i], 29, 27, 27); + a = output_phase_ch[i] + p1 + p2; + output_phase_ch[i] = unwrap_angle_q27(a); + polar->polar_tmp[i].angle = output_phase_ch[i]; + } + + /* Convert back to (re, im) complex, and fix upper part */ + stft_convert_to_complex(polar->polar_tmp, &state->fft); + stft_apply_fft_symmetry(&state->fft); + ret = stft_do_ifft(state, ch); + if (ret) { + comp_err(mod->dev, "IFFT failure, check output overlap-add buffer size"); + return ret; + } + } + + comp_dbg(mod->dev, "no = %d, ni = %d, frac = %d", state->num_output_ifft, + state->num_input_fft, frac); + state->num_output_ifft++; + state->first_output_ifft_done = true; + return 0; +} + +static int phase_vocoder_check_fft_run_need(struct phase_vocoder_comp_data *cd) +{ + return cd->state.obuf[0].s_avail < cd->state.fft.fft_hop_size; +} + +#if CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S24LE +static int phase_vocoder_output_zeros_s32(struct phase_vocoder_comp_data *cd, struct sof_sink *sink, + int frames) +{ + int32_t *y, *y_start, *y_end; + int samples = frames * cd->stream_channels; + size_t bytes = samples * sizeof(int32_t); + int samples_without_wrap; + int y_size; + int ret; + + /* Get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s32(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + y_end = y_start + y_size; + while (samples) { + /* Find out samples to process before first wrap or end of data. */ + samples_without_wrap = y_end - y; + samples_without_wrap = MIN(samples_without_wrap, samples); + memset(y, 0, samples_without_wrap * sizeof(int32_t)); + y += samples_without_wrap; + + /* Check for wrap */ + if (y >= y_end) + y -= y_size; + + /* Update processed samples count for next loop iteration. */ + samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + sink_commit_buffer(sink, bytes); + return 0; +} +#endif + +#if CONFIG_FORMAT_S32LE +static int phase_vocoder_s32(const struct processing_module *mod, struct sof_source *source, + struct sof_sink *sink, uint32_t source_frames, uint32_t sink_frames) +{ + struct phase_vocoder_comp_data *cd = module_get_private_data(mod); + int ret; + + if (phase_vocoder_check_fft_run_need(cd)) { + /* Get samples from source buffer */ + ret = phase_vocoder_source_s32(cd, source, source_frames); + if (ret) + return ret; + + /* Do STFT, processing and inverse STFT */ + ret = stft_do_fft_ifft(mod); + if (ret) + return ret; + } + + /* Get samples from source buffer */ + if (cd->state.first_output_ifft_done) + ret = phase_vocoder_sink_s32(cd, sink, sink_frames); + else + ret = phase_vocoder_output_zeros_s32(cd, sink, sink_frames); + + return ret; +} +#endif /* CONFIG_FORMAT_S32LE */ + +#if CONFIG_FORMAT_S24LE +static int phase_vocoder_s24(const struct processing_module *mod, struct sof_source *source, + struct sof_sink *sink, uint32_t source_frames, uint32_t sink_frames) +{ + struct phase_vocoder_comp_data *cd = module_get_private_data(mod); + int ret; + + if (phase_vocoder_check_fft_run_need(cd)) { + /* Get samples from source buffer */ + ret = phase_vocoder_source_s24(cd, source, source_frames); + if (ret) + return ret; + + /* Do STFT, processing and inverse STFT */ + ret = stft_do_fft_ifft(mod); + if (ret) + return ret; + } + + /* Get samples from source buffer */ + if (cd->state.first_output_ifft_done) + ret = phase_vocoder_sink_s24(cd, sink, sink_frames); + else + /* Use the s32 function */ + ret = phase_vocoder_output_zeros_s32(cd, sink, sink_frames); + + return ret; +} +#endif /* CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S16LE +static int phase_vocoder_output_zeros_s16(struct phase_vocoder_comp_data *cd, struct sof_sink *sink, + int frames) +{ + int16_t *y, *y_start, *y_end; + int samples = frames * cd->stream_channels; + size_t bytes = samples * sizeof(int16_t); + int samples_without_wrap; + int y_size; + int ret; + + /* Get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s16(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + y_end = y_start + y_size; + while (samples) { + /* Find out samples to process before first wrap or end of data. */ + samples_without_wrap = y_end - y; + samples_without_wrap = MIN(samples_without_wrap, samples); + memset(y, 0, samples_without_wrap * sizeof(int16_t)); + y += samples_without_wrap; + + /* Check for wrap */ + if (y >= y_end) + y -= y_size; + + /* Update processed samples count for next loop iteration. */ + samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + sink_commit_buffer(sink, bytes); + return 0; +} + +static int phase_vocoder_s16(const struct processing_module *mod, struct sof_source *source, + struct sof_sink *sink, uint32_t source_frames, uint32_t sink_frames) +{ + struct phase_vocoder_comp_data *cd = module_get_private_data(mod); + int ret; + + if (phase_vocoder_check_fft_run_need(cd)) { + /* Get samples from source buffer */ + ret = phase_vocoder_source_s16(cd, source, source_frames); + if (ret) + return ret; + + /* Do STFT, processing and inverse STFT */ + ret = stft_do_fft_ifft(mod); + if (ret) + return ret; + } + + /* Get samples from source buffer */ + if (cd->state.first_output_ifft_done) + ret = phase_vocoder_sink_s16(cd, sink, sink_frames); + else + ret = phase_vocoder_output_zeros_s16(cd, sink, sink_frames); + + return ret; +} +#endif /* CONFIG_FORMAT_S16LE */ + +/* This struct array defines the used processing functions for + * the PCM formats. + */ +const struct phase_vocoder_proc_fnmap phase_vocoder_functions[] = { +#if CONFIG_FORMAT_S16LE + {SOF_IPC_FRAME_S16_LE, phase_vocoder_s16}, +#endif +#if CONFIG_FORMAT_S24LE + {SOF_IPC_FRAME_S24_4LE, phase_vocoder_s24}, +#endif +#if CONFIG_FORMAT_S32LE + {SOF_IPC_FRAME_S32_LE, phase_vocoder_s32}, +#endif +}; + +/** + * phase_vocoder_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +phase_vocoder_func phase_vocoder_find_proc_func(enum sof_ipc_frame src_fmt) +{ + int i; + + /* Find suitable processing function from map */ + for (i = 0; i < ARRAY_SIZE(phase_vocoder_functions); i++) + if (src_fmt == phase_vocoder_functions[i].frame_fmt) + return phase_vocoder_functions[i].phase_vocoder_function; + + return NULL; +} diff --git a/src/audio/phase_vocoder/phase_vocoder_setup.c b/src/audio/phase_vocoder/phase_vocoder_setup.c new file mode 100644 index 000000000000..c6baf5b8908a --- /dev/null +++ b/src/audio/phase_vocoder/phase_vocoder_setup.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include <sof/audio/component.h> +#include <sof/audio/audio_stream.h> +#include <sof/math/auditory.h> +#include <sof/math/icomplex32.h> +#include <sof/math/trig.h> +#include <sof/math/window.h> +#include <sof/trace/trace.h> +#include "phase_vocoder.h" + +#include <errno.h> +#include <stddef.h> +#include <stdint.h> + +#define STFT_MAX_ALLOC_SIZE 65536 + +LOG_MODULE_REGISTER(phase_vocoder_setup, CONFIG_SOF_LOG_LEVEL); + +static void phase_vocoder_init_buffer(struct phase_vocoder_buffer *buf, int32_t *base, int size) +{ + buf->addr = base; + buf->end_addr = base + size; + buf->r_ptr = base; + buf->w_ptr = base; + buf->s_free = size; + buf->s_avail = 0; + buf->s_length = size; +} + +static int phase_vocoder_get_window(struct phase_vocoder_state *state, + enum sof_phase_vocoder_fft_window_type name) +{ + struct phase_vocoder_fft *fft = &state->fft; + + switch (name) { + case STFT_RECTANGULAR_WINDOW: + win_rectangular_32b(state->window, fft->fft_size); + return 0; + case STFT_BLACKMAN_WINDOW: + win_blackman_32b(state->window, fft->fft_size, WIN_BLACKMAN_A0_Q31); + return 0; + case STFT_HAMMING_WINDOW: + win_hamming_32b(state->window, fft->fft_size); + return 0; + case STFT_HANN_WINDOW: + win_hann_32b(state->window, fft->fft_size); + return 0; + + default: + return -EINVAL; + } +} + +int phase_vocoder_setup(struct processing_module *mod) +{ + struct phase_vocoder_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + struct sof_phase_vocoder_config *config = cd->config; + struct phase_vocoder_state *state = &cd->state; + struct phase_vocoder_fft *fft = &state->fft; + struct phase_vocoder_polar *polar = &state->polar; + size_t sample_buffers_size; + size_t ibuf_size; + size_t obuf_size; + size_t prev_size; + int32_t *addr; + int channels; + int ret; + int i; + + comp_dbg(dev, "phase_vocoder_setup()"); + + /* Check size */ + if (config->size != sizeof(struct sof_phase_vocoder_config)) { + comp_err(dev, "Illegal configuration size %d.", config->size); + return -EINVAL; + } + + if (config->sample_frequency != cd->sample_rate) + comp_warn(dev, "Config sample_frequency does not match stream"); + + if (config->mono) { + cd->process_channels = 1; + if (cd->stream_channels > 1) + cd->mono_mix_coef = (int32_t)((1LL << 31) / cd->stream_channels); + else + cd->mono_mix_coef = INT32_MAX; /* Q1.31 1.0 */ + + comp_info(dev, "mono_mix_coef %d", cd->mono_mix_coef); + } else { + cd->process_channels = cd->stream_channels; + cd->mono_mix_coef = 0; + } + + fft->fft_size = config->frame_length; + fft->fft_hop_size = config->frame_shift; + fft->half_fft_size = (fft->fft_size >> 1) + 1; + + /* FFT size needs to be a multiple of 4 for Xtensa HiFi SIMD, + * and FFT hop size needs to be a multiple of 2. Check also + * for otherwise sane values. + */ + if (fft->fft_size <= 0 || fft->fft_hop_size <= 0 || + fft->fft_hop_size > fft->fft_size || + (fft->fft_size & 3) || (fft->fft_hop_size & 1)) { + comp_err(dev, "FFT size %d or hop size %d are invalid.", + fft->fft_size, fft->fft_hop_size); + return -EINVAL; + } + + comp_info(dev, "fft_size = %d, fft_hop_size = %d, window = %d", fft->fft_size, + fft->fft_hop_size, config->window); + + /* Calculated parameters */ + prev_size = fft->fft_size - fft->fft_hop_size; + ibuf_size = fft->fft_hop_size + cd->max_input_frames; + obuf_size = fft->fft_size + fft->fft_hop_size; + state->prev_data_size = prev_size; + + /* Allocate buffer for input samples, overlap buffer, window */ + channels = cd->process_channels; + sample_buffers_size = + sizeof(int32_t) * (channels * (ibuf_size + obuf_size + prev_size) + fft->fft_size); + + if (sample_buffers_size > STFT_MAX_ALLOC_SIZE) { + comp_err(dev, "Illegal allocation size"); + return -EINVAL; + } + + addr = mod_balloc(mod, sample_buffers_size); + if (!addr) { + comp_err(dev, "Failed buffer allocate"); + ret = -ENOMEM; + goto exit; + } + + memset(addr, 0, sample_buffers_size); + state->buffers = addr; + for (i = 0; i < channels; i++) { + phase_vocoder_init_buffer(&state->ibuf[i], addr, ibuf_size); + addr += ibuf_size; + phase_vocoder_init_buffer(&state->obuf[i], addr, obuf_size); + addr += obuf_size; + state->prev_data[i] = addr; + addr += prev_size; + } + state->window = addr; + + /* Allocate buffers for FFT input and output data */ + fft->fft_buffer_size = fft->fft_size * sizeof(struct icomplex32); + fft->fft_buf = mod_balloc(mod, fft->fft_buffer_size); + if (!fft->fft_buf) { + comp_err(dev, "Failed FFT buffer allocate"); + ret = -ENOMEM; + goto cleanup; + } + + fft->fft_out = mod_balloc(mod, fft->fft_buffer_size); + if (!fft->fft_out) { + comp_err(dev, "Failed FFT output allocate"); + ret = -ENOMEM; + goto cleanup; + } + + /* Setup FFT */ + fft->fft_plan = mod_fft_plan_new(mod, fft->fft_buf, fft->fft_out, fft->fft_size, 32); + if (!fft->fft_plan) { + comp_err(dev, "Failed FFT init"); + ret = -EINVAL; + goto cleanup; + } + + fft->ifft_plan = mod_fft_plan_new(mod, fft->fft_out, fft->fft_buf, fft->fft_size, 32); + if (!fft->ifft_plan) { + comp_err(dev, "Failed IFFT init"); + ret = -EINVAL; + goto cleanup; + } + + /* Setup window */ + ret = phase_vocoder_get_window(state, config->window); + if (ret < 0) { + comp_err(dev, "Failed Window function"); + goto cleanup; + } + + /* Need to compensate the window function gain */ + state->gain_comp = config->window_gain_comp; + + /* Allocate buffers for polar format data for magnitude and phase interpolation */ + state->phase_vocoder_polar_bytes = + channels * fft->half_fft_size * (2 * sizeof(struct ipolar32) + 3 * sizeof(int32_t)); + comp_info(dev, "polar buffers size %zu", state->phase_vocoder_polar_bytes); + addr = mod_balloc(mod, state->phase_vocoder_polar_bytes); + if (!addr) { + comp_err(dev, "Failed polar data buffer allocate"); + ret = -ENOMEM; + goto cleanup; + } + + memset(addr, 0, state->phase_vocoder_polar_bytes); + polar->polar_buffer = addr; + for (i = 0; i < channels; i++) { + polar->polar[i] = (struct ipolar32 *)addr; + addr = (int32_t *)((struct ipolar32 *)addr + fft->half_fft_size); + } + + for (i = 0; i < channels; i++) { + polar->polar_prev[i] = (struct ipolar32 *)addr; + addr = (int32_t *)((struct ipolar32 *)addr + fft->half_fft_size); + } + + for (i = 0; i < channels; i++) { + polar->angle_delta[i] = addr; + addr += fft->half_fft_size; + } + + for (i = 0; i < channels; i++) { + polar->angle_delta_prev[i] = addr; + addr += fft->half_fft_size; + } + + for (i = 0; i < channels; i++) { + polar->output_phase[i] = addr; + addr += fft->half_fft_size; + } + + /* Use FFT buffer as scratch */ + polar->polar_tmp = (struct ipolar32 *)fft->fft_out; + comp_dbg(dev, "phase_vocoder_setup(), done"); + return 0; + +cleanup: + phase_vocoder_free_buffers(mod); +exit: + return ret; +} + +void phase_vocoder_free_buffers(struct processing_module *mod) +{ + struct phase_vocoder_comp_data *cd = module_get_private_data(mod); + struct phase_vocoder_state *state = &cd->state; + struct phase_vocoder_fft *fft = &state->fft; + struct phase_vocoder_polar *polar = &state->polar; + + /* All free helpers tolerate NULL; clear pointers so a subsequent reset + * does not double-free if setup() failed mid-way. + */ + mod_fft_plan_free(mod, fft->ifft_plan); + fft->ifft_plan = NULL; + mod_fft_plan_free(mod, fft->fft_plan); + fft->fft_plan = NULL; + mod_free(mod, fft->fft_buf); + fft->fft_buf = NULL; + mod_free(mod, fft->fft_out); + fft->fft_out = NULL; + mod_free(mod, state->buffers); + state->buffers = NULL; + mod_free(mod, polar->polar_buffer); + polar->polar_buffer = NULL; +} diff --git a/src/audio/phase_vocoder/tune/phase_vocoder_s16.sh b/src/audio/phase_vocoder/tune/phase_vocoder_s16.sh new file mode 100755 index 000000000000..5cfa0ee441a5 --- /dev/null +++ b/src/audio/phase_vocoder/tune/phase_vocoder_s16.sh @@ -0,0 +1,48 @@ +#!/bin/bash +set -euo pipefail + +if [ $# -lt 2 ]; then + echo "Usage: $0 <input_file.wav/flac/etc.> <output_file.wav>" >&2 + exit 1 +fi + +: "${SOF_WORKSPACE:?SOF_WORKSPACE must be set}" + +CLIP_IN=$1 +WAV_OUT=$2 +TESTBENCH=$SOF_WORKSPACE/sof/tools/testbench/build_testbench/install/bin/sof-testbench4 +TPLG_DIR=$SOF_WORKSPACE/sof/tools/build_tools/topology/topology2/development +TPLG=sof-hda-benchmark-phase_vocoder16.tplg + +RAW_IN=$(mktemp --suffix=_in.raw) +RAW_OUT=$(mktemp --suffix=_out.raw) +CONTROL_SCRIPT_LONG=$(mktemp --suffix=_controls.sh) +trap 'rm -f "$RAW_IN" "$RAW_OUT" "$CONTROL_SCRIPT_LONG"' EXIT + +# Uncomment to run under valgrind: +# VALGRIND=(valgrind --leak-check=full --track-origins=yes) +VALGRIND=() +CONTROL_SCRIPT=(-s "$CONTROL_SCRIPT_LONG") + +# Generated script is consumed by the testbench's -s option, not executed +# directly by a shell. +{ + echo "#!/bin/sh" + echo "amixer -c0 cset name='Analog Playback Phase Vocoder speed' 0.5" + echo "amixer -c0 cset name='Analog Playback Phase Vocoder enable' on" + for s in 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 \ + 2.0 1.9 1.8 1.7 1.6 1.5 1.4 1.3 1.2 1.1 1.0; do + echo "sleep 1" + echo "amixer -c0 cset name='Analog Playback Phase Vocoder speed' $s" + done + echo "amixer -c0 cset name='Analog Playback Phase Vocoder enable' off" +} > "$CONTROL_SCRIPT_LONG" + +sox "$CLIP_IN" --encoding signed-integer -L -r 48000 -c 2 -b 16 "$RAW_IN" +"${VALGRIND[@]}" "$TESTBENCH" "${CONTROL_SCRIPT[@]}" \ + -r 48000 -c 2 -b S16_LE -p 1,2 \ + -t "$TPLG_DIR/$TPLG" -i "$RAW_IN" -o "$RAW_OUT" +sox --encoding signed-integer -L -r 48000 -c 2 -b 16 "$RAW_OUT" "$WAV_OUT" + +printf '\n' +file "$WAV_OUT" diff --git a/src/audio/phase_vocoder/tune/phase_vocoder_s32.sh b/src/audio/phase_vocoder/tune/phase_vocoder_s32.sh new file mode 100755 index 000000000000..26dbe89b3e1a --- /dev/null +++ b/src/audio/phase_vocoder/tune/phase_vocoder_s32.sh @@ -0,0 +1,48 @@ +#!/bin/bash +set -euo pipefail + +if [ $# -lt 2 ]; then + echo "Usage: $0 <input_file.wav/flac/etc.> <output_file.wav>" >&2 + exit 1 +fi + +: "${SOF_WORKSPACE:?SOF_WORKSPACE must be set}" + +CLIP_IN=$1 +WAV_OUT=$2 +TESTBENCH=$SOF_WORKSPACE/sof/tools/testbench/build_testbench/install/bin/sof-testbench4 +TPLG_DIR=$SOF_WORKSPACE/sof/tools/build_tools/topology/topology2/development +TPLG=sof-hda-benchmark-phase_vocoder32.tplg + +RAW_IN=$(mktemp --suffix=_in.raw) +RAW_OUT=$(mktemp --suffix=_out.raw) +CONTROL_SCRIPT_LONG=$(mktemp --suffix=_controls.sh) +trap 'rm -f "$RAW_IN" "$RAW_OUT" "$CONTROL_SCRIPT_LONG"' EXIT + +# Uncomment to run under valgrind: +# VALGRIND=(valgrind --leak-check=full --track-origins=yes) +VALGRIND=() +CONTROL_SCRIPT=(-s "$CONTROL_SCRIPT_LONG") + +# Generated script is consumed by the testbench's -s option, not executed +# directly by a shell. +{ + echo "#!/bin/sh" + echo "amixer -c0 cset name='Analog Playback Phase Vocoder speed' 0.5" + echo "amixer -c0 cset name='Analog Playback Phase Vocoder enable' on" + for s in 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 \ + 2.0 1.9 1.8 1.7 1.6 1.5 1.4 1.3 1.2 1.1 1.0; do + echo "sleep 1" + echo "amixer -c0 cset name='Analog Playback Phase Vocoder speed' $s" + done + echo "amixer -c0 cset name='Analog Playback Phase Vocoder enable' off" +} > "$CONTROL_SCRIPT_LONG" + +sox "$CLIP_IN" --encoding signed-integer -L -r 48000 -c 2 -b 32 "$RAW_IN" +"${VALGRIND[@]}" "$TESTBENCH" "${CONTROL_SCRIPT[@]}" \ + -r 48000 -c 2 -b S32_LE -p 1,2 \ + -t "$TPLG_DIR/$TPLG" -i "$RAW_IN" -o "$RAW_OUT" +sox --encoding signed-integer -L -r 48000 -c 2 -b 32 "$RAW_OUT" "$WAV_OUT" + +printf '\n' +file "$WAV_OUT" diff --git a/src/audio/phase_vocoder/tune/setup_phase_vocoder.m b/src/audio/phase_vocoder/tune/setup_phase_vocoder.m new file mode 100644 index 000000000000..0bc2ab4061d8 --- /dev/null +++ b/src/audio/phase_vocoder/tune/setup_phase_vocoder.m @@ -0,0 +1,180 @@ +% setup_phase_vocoder() +% +% Create binary configuration blob for Phase Vocoder component. + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2026, Intel Corporation. + +function setup_phase_vocoder(cfg) + + cfg.tools_path = '../../../../tools/'; + cfg.tplg_path = [cfg.tools_path 'topology/topology2/include/components/phase_vocoder/']; + cfg.common_path = [cfg.tools_path 'tune/common']; + cfg.tplg_ver = 2; + cfg.ipc_ver = 4; + cfg.mono = 0; + cfg.sample_frequency = 48000; + + cfg.frame_length = 256; % 5.3 ms + cfg.frame_shift = 128; % 2.7 ms + cfg.window_type = 'hann'; + cfg.tplg_fn = 'hann_256_128.conf'; + export_phase_vocoder_setup(cfg); + + cfg.frame_length = 512; % 10.7 ms + cfg.frame_shift = 128; % 2.7 ms + cfg.window_type = 'hann'; + cfg.tplg_fn = 'hann_512_128.conf'; + export_phase_vocoder_setup(cfg); + + cfg.frame_length = 512; % 10.7 ms + cfg.frame_shift = 256; % 5.3 ms + cfg.window_type = 'hann'; + cfg.tplg_fn = 'hann_512_256.conf'; + export_phase_vocoder_setup(cfg); + + % Default configuration, stereo + cfg.frame_length = 1024; % 21.3 ms + cfg.frame_shift = 256; % 5.3 ms + cfg.window_type = 'hann'; + cfg.tplg_fn = 'hann_1024_256.conf'; + export_phase_vocoder_setup(cfg); + + % Default configuration, force mono processing + cfg.mono = 1; + cfg.tplg_fn = 'hann_1024_256_mono.conf'; + export_phase_vocoder_setup(cfg); + +end + +function export_phase_vocoder_setup(cfg) + + % Use blob tool from EQ + addpath(cfg.common_path); + + % Blob size, size plus reserved(8) + current parameters + nbytes_data = 64; + + % Get ABI information + [abi_bytes, nbytes_abi] = sof_get_abi(nbytes_data, cfg.ipc_ver); + + % Initialize correct size uint8 array + nbytes = nbytes_abi + nbytes_data; + b8 = uint8(zeros(1,nbytes)); + + % Insert ABI header + fprintf(1, 'PHASE_VOCODER blob size is %d, ABI header is %d, data is %d\n',nbytes, nbytes_abi, nbytes_data); + b8(1:nbytes_abi) = abi_bytes; + j = nbytes_abi + 1; + + % Apply default PHASE_VOCODER configuration, first struct header and reserved, then data + [b8, j] = add_w32b(nbytes_data, b8, j); + for i = 1:8 + [b8, j] = add_w32b(0, b8, j); + end + + fft_length = cfg.frame_length; + fft_hop = cfg.frame_shift; + [window_idx, window_gain_comp] = get_window(cfg, fft_length, fft_hop); + + v = q_convert(cfg.sample_frequency, 0); [b8, j] = add_w32b(v, b8, j); + v = q_convert(window_gain_comp, 31); [b8, j] = add_w32b(v, b8, j); + v = 0; [b8, j] = add_w32b(v, b8, j); % reserved + v = cfg.mono; [b8, j] = add_w16b(v, b8, j); + v = fft_length; [b8, j] = add_w16b(v, b8, j); + v = fft_hop; [b8, j] = add_w16b(v, b8, j); + v = 0; [b8, j] = add_w16b(v, b8, j); % reserved + v = 0; [b8, j] = add_w32b(v, b8, j); % reserved_pad + v = window_idx; [b8, j] = add_w32b(v, b8, j); % enum window + + % Export + switch cfg.tplg_ver + case 2 + sof_tplg2_write([cfg.tplg_path cfg.tplg_fn], b8, "phase_vocoder_config", ... + "Exported PHASE_VOCODER configuration", ... + "cd src/audio/phase_vocoder/tune; octave setup_phase_vocoder.m"); + otherwise + error("Illegal cfg.tplg_ver, use 2 topology v2."); + end + + rmpath(cfg.common_path); + +end + +%% Helper functions + +function [idx, iwg] = get_window(cfg, len, hop) + switch lower(cfg.window_type) + case 'rectangular' + win = boxcar(len); + idx = 0; + case 'blackman' + win = blackman(len); + idx = 1; + case 'hamming' + win = hamming(len); + idx = 2; + case 'hann' + win = hann(len); + idx = 3; + otherwise + error('Unknown window type'); + end + iwg = hop / sum(win.^2); +end + +function bytes = w8b(word) + bytes = uint8(zeros(1,1)); + bytes(1) = bitand(word, 255); +end + +function bytes = w16b(word) + sh = [0 -8]; + bytes = uint8(zeros(1,2)); + bytes(1) = bitand(bitshift(word, sh(1)), 255); + bytes(2) = bitand(bitshift(word, sh(2)), 255); +end + +function bytes = w32b(word) + sh = [0 -8 -16 -24]; + bytes = uint8(zeros(1,4)); + bytes(1) = bitand(bitshift(word, sh(1)), 255); + bytes(2) = bitand(bitshift(word, sh(2)), 255); + bytes(3) = bitand(bitshift(word, sh(3)), 255); + bytes(4) = bitand(bitshift(word, sh(4)), 255); +end + +function n = q_convert(val, q) + n = round(val * 2^q); +end + +function [blob8, j] = add_w8b(v, blob8, j) + if j > length(blob8) + error('Blob size is not sufficient'); + end + blob8(j) = w8b(v); + j = j + 1; +end + +function [blob8, j] = add_w16b(v, blob8, j) + if j + 1 > length(blob8) + error('Blob size is not sufficient'); + end + if v < 0 + v = 2^16 + v; + end + blob8(j : j + 1) = w16b(v); + j = j + 2; +end + +function [blob8, j] = add_w32b(v, blob8, j) + if j + 3 > length(blob8) + error('Blob size is not sufficient'); + end + if v < 0 + v = 2^32 + v; + end + blob8(j : j + 3) = w32b(v); + j = j + 4; +end diff --git a/src/audio/pipeline/CMakeLists.txt b/src/audio/pipeline/CMakeLists.txt index 242ace4b2a69..cb26dc3214bd 100644 --- a/src/audio/pipeline/CMakeLists.txt +++ b/src/audio/pipeline/CMakeLists.txt @@ -1,9 +1,9 @@ # SPDX-License-Identifier: BSD-3-Clause add_local_sources(sof - pipeline-graph.c - pipeline-stream.c - pipeline-params.c - pipeline-xrun.c - pipeline-schedule.c + pipeline-graph.c + pipeline-stream.c + pipeline-params.c + pipeline-xrun.c + pipeline-schedule.c ) diff --git a/src/audio/pipeline/README.md b/src/audio/pipeline/README.md new file mode 100644 index 000000000000..4e530bdc1463 --- /dev/null +++ b/src/audio/pipeline/README.md @@ -0,0 +1,245 @@ +# Pipeline Engine Architecture + +This directory contains the core graph/pipeline logic. + +## Overview + +The Pipeline engine is the heart of the SOF processing architecture. It links `components` together using `buffers`, and provides scheduling execution entities (tasks) to repeatedly trigger these component graphs. + +## Architecture Diagram + +```mermaid +graph TD + Host[Host Topology] -.-> Manager[Pipeline Manager] + Manager --> Buf1[Buffer] + Manager --> CompA[Component] + Manager --> Sched[Task Scheduler] + Sched --> CompA +``` + +## State Machine + +The pipeline progresses through various states (`COMP_STATE_INIT`, `COMP_STATE_READY`, `COMP_STATE_ACTIVE`, etc.) largely directed by `comp_trigger()` commands cascaded down the graph. + +```mermaid +stateDiagram-v2 + [*] --> INIT : pipeline_new() + INIT --> READY : pipeline_complete() + READY --> PRE_ACTIVE : COMP_TRIGGER_PRE_START + PRE_ACTIVE --> ACTIVE : COMP_TRIGGER_START + ACTIVE --> PAUSED : COMP_TRIGGER_PAUSE + PAUSED --> ACTIVE : COMP_TRIGGER_RELEASE / START + ACTIVE --> SUSPEND : COMP_TRIGGER_SUSPEND + SUSPEND --> ACTIVE : COMP_TRIGGER_RESUME + ACTIVE --> PRE_ACTIVE : COMP_TRIGGER_PRE_RELEASE + ACTIVE --> READY : COMP_TRIGGER_STOP + ACTIVE --> XRUN_PAUSED : COMP_TRIGGER_XRUN + XRUN_PAUSED --> READY : pipeline_xrun_recover() +``` + +## Processing Flow (LL and DP Modes) + +Execution within the SOF pipeline is divided between two primary timing domains depending on the component's `proc_domain` property. + +1. **Low Latency (LL) Domain:** + * **Driven By:** DMA interrupts or precise timers. + * **Execution:** A single cooperative scheduler task (`pipeline_task`) iterates over the entire connected graph. + * **Process:** The pipeline scheduler invokes `pipeline_copy()` which calls `comp_copy()` on the source or sink, and then recursively relies on `pipeline_for_each_comp` to pull or push data through the graph synchronously within that single timeslice. + +2. **Data Processing (DP) Domain:** + * **Driven By:** A Zephyr-based discrete RTOS thread (`CONFIG_ZEPHYR_DP_SCHEDULER`). + * **Execution:** Modules that require extensive computation (especially those leveraging the `module_adapter`) are spun off into their own isolated threads using `pipeline_comp_dp_task_init()`. + * **Process:** Instead of synchronous execution alongside the DMA, they consume and produce data (`module_process_sink_src`) with their own stack (`TASK_DP_STACK_SIZE`), relying on inter-component buffers and thread synchronization to pass chunks back to the LL domain when ready. + +```mermaid +sequenceDiagram + participant DMA + participant Sched as LL Scheduler (pipeline_task) + participant Source as Source Component (e.g., Host Interface) + participant Buffer as Internal Buffer + participant Filter as Filter Component (e.g., EQ) + participant Sink as Sink Component (e.g., DAI) + + DMA->>Sched: Interrupt / Timer Tick + activate Sched + Sched->>Source: pipeline_copy() -> comp_copy() + Source-->>Buffer: Copies PCM Data to Buffer + Sched->>Filter: pipeline_for_each_comp() -> comp_copy() + Filter->>Buffer: Reads PCM Data + Filter-->>Buffer: Writes Processed Data + Sched->>Sink: pipeline_for_each_comp() -> comp_copy() + Sink->>Buffer: Reads Processed Data + Sink-->>Sink: Transmits to Audio Hardware + deactivate Sched +``` + +### Mixed LL and DP Execution + +```mermaid +sequenceDiagram + participant DMA + participant Sched as LL Scheduler (pipeline_task) + participant DPThread as DP Thread (dp_task_run) + participant CompLL as LL Component + participant CompDP as DP Component + + DMA->>Sched: Interrupt / Timer Tick + activate Sched + Sched->>CompLL: pipeline_copy() -> comp_copy() + CompLL-->>Sched: Data Produced into Buffer + Sched->>DPThread: Wakeup (Buffer Data Available) + deactivate Sched + + activate DPThread + DPThread->>CompDP: module_process_sink_src() + CompDP-->>DPThread: Computations finished + DPThread->>Sched: Notification (Data Ready) + deactivate DPThread +``` + +## Control and Configuration Flows + +The lifecycle of a pipeline graph involves several discrete initialization and connection steps orchestrated by IPC topology commands before streaming begins. + +1. **Creation (`pipeline_new`)**: Instantiates the `struct pipeline` object, associates the memory heap, and grabs a mailbox offset for IPC position tracking. +2. **Connection (`pipeline_connect` / `pipeline_disconnect`)**: Establishes the directional edges of the graph by attaching a `comp_buffer` between a source and sink `comp_dev`. It updates the component's internal buffer lists. +3. **Completion (`pipeline_complete`)**: Validates the graph structure. It recursively walks the entire chain from source to sink (`pipeline_for_each_comp`), verifying consistency (e.g., ensuring components aren't part of mismatched pipelines unless properly handled), and transitions the pipeline state to `COMP_STATE_READY`. +4. **Parameter Propagation (`pipeline_params`, `pipeline_prepare`)**: Triggered prior to streaming, `pipeline_prepare()` walks the graph to finalize PCM formats, period sizes, and hardware configurations (like iterating over the audio buffers to `audio_buffer_reset_params`). +5. **Teardown (`pipeline_free`)**: When a stream is closed, after all `comp_dev` objects internal to the pipeline are halted and detached, `pipeline_free` cleans up the `pipe_task` scheduler footprint, IPC messages, and unlinks memory allocations freeing the `struct pipeline` entirely. + +### Creation and Teardown Flow + +```mermaid +sequenceDiagram + participant Host + participant Sched as LL Scheduler + participant Pipe as Pipeline + participant Source as Source Component + + Host->>Pipe: pipeline_new() + activate Pipe + Pipe-->>Pipe: Allocates struct pipeline & gets Mailbox Offset + + Host->>Source: comp_new() (Creates Components) + + Host->>Pipe: pipeline_connect() + Pipe-->>Pipe: Links comp_buffers internally + + Host->>Pipe: pipeline_complete() + Pipe->>Source: pipeline_for_each_comp() + Source-->>Pipe: Graph validates + Pipe-->>Host: Status: COMP_STATE_READY + + Note over Host,Pipe: ... Active Audio Streaming ... + + Host->>Pipe: pipeline_free() + Pipe->>Sched: schedule_task_free(pipe_task) + Pipe-->>Pipe: sof_heap_free() (Frees tracking structs) + Pipe-->>Host: Pipeline Extinguished + deactivate Pipe +``` + +### Triggering Flow + +Triggering is fundamentally responsible for transitioning graph states (`COMP_STATE_ACTIVE`, `COMP_STATE_PAUSED`, etc). A trigger (like `COMP_TRIGGER_START` or `COMP_TRIGGER_STOP`) commands an underlying state change and pushes the `pipeline_task` into the `schedule_task` queue. + +```mermaid +sequenceDiagram + participant Host + participant PPL as Pipeline (pipeline_trigger) + participant Sched as LL Scheduler (pipeline_task) + participant Source as Source Component + participant Sink as Sink Component + + Host->>PPL: pipeline_trigger(COMP_TRIGGER_START) + activate PPL + PPL->>Source: pipeline_for_each_comp(COMP_TRIGGER_START) + Source->>Sink: comp_trigger(COMP_TRIGGER_START) + Sink-->>PPL: State -> COMP_STATE_ACTIVE + + PPL->>Sched: pipeline_schedule_copy() + Sched-->>Sched: Adds `pipe_task` to active scheduler + PPL-->>Host: Trigger successful + deactivate PPL + + Note over PPL,Sched: Pipeline repeatedly scheduled via DMA or Timers + + Host->>PPL: pipeline_trigger(COMP_TRIGGER_STOP) + activate PPL + PPL->>Sched: pipeline_schedule_cancel() + Sched-->>Sched: Removes `pipe_task` from active scheduler + PPL->>Source: pipeline_for_each_comp(COMP_TRIGGER_STOP) + Source->>Sink: comp_trigger(COMP_TRIGGER_STOP) + Sink-->>PPL: State -> COMP_STATE_PAUSED / READY + PPL-->>Host: Trigger successful + deactivate PPL +``` + +```mermaid +sequenceDiagram + participant Host + participant Pipe as Pipeline (pipeline_complete) + participant Source as Source Component + participant Sink as Sink Component + participant Buf as Buffer + + Host->>Pipe: ipc_pipeline_complete() + activate Pipe + Pipe->>Source: pipeline_for_each_comp(PPL_DIR_DOWNSTREAM) + Source->>Buf: buffer_set_comp() + Buf->>Sink: comp_is_single_pipeline() + Sink-->>Pipe: Pipeline graph linked + Pipe-->>Host: Status: COMP_STATE_READY + deactivate Pipe + + Host->>Pipe: ipc_comp_prepare() + activate Pipe + Pipe->>Source: pipeline_prepare() + Source->>Buf: audio_buffer_reset_params() + Buf->>Sink: comp_prepare() + Sink-->>Pipe: Prepared formats + Pipe-->>Host: Prepared + deactivate Pipe +``` + +## Error Handling (XRUNs) + +Overruns (host writes too fast/firmware reads too slow) and underruns (host reads too fast/firmware writes too slow) are tracked continuously. + +1. **Detection**: Components directly hooked to interfaces (like a host IPC component or a hardware DAI) monitor their `comp_copy` status. If they detect starvation or overflow, they trigger an XRUN event. +2. **Propagation (`pipeline_xrun`)**: The pipeline immediately invokes a broadcast `pipeline_trigger(..., COMP_TRIGGER_XRUN)` forcing all internal components to drop to a halted `XRUN_PAUSED` state. In older IPC3 topologies, it additionally signals the host via mailbox offsets (`ipc_build_stream_posn`). +3. **Recovery (`pipeline_xrun_handle_trigger` / `pipeline_xrun_recover`)**: By default, the `pipeline_task` scheduler will intercept the `xrun_bytes` flag. Unless `NO_XRUN_RECOVERY` is defined, the firmware attempts self-healing: + * It resets the pipeline downstream of the source (`pipeline_reset`). + * It prepares it again (`pipeline_prepare`). + * It issues an internal `COMP_TRIGGER_START` to restart data flow automatically without host intervention. + +```mermaid +sequenceDiagram + participant DAI as Hardware Interface + participant Comp as Connected Component + participant PPL as Pipeline (pipeline_xrun) + participant Sched as LL Scheduler (pipeline_task) + participant Host as Host Interface + + DAI-->>Comp: Overflow/Underrun Detected + activate Comp + Comp->>PPL: pipeline_xrun() + PPL->>Comp: pipeline_trigger(COMP_TRIGGER_XRUN) + PPL-->>Host: Mailbox XRUN position (IPC3) + deactivate Comp + + Note over PPL,Sched: Pipeline halts (XRUN_PAUSED) + + Sched->>PPL: intercepts xrun_bytes > 0 + activate Sched + Sched->>PPL: pipeline_xrun_recover() + PPL->>Comp: pipeline_reset() + PPL->>Comp: pipeline_prepare() + PPL->>Comp: pipeline_trigger(COMP_TRIGGER_START) + PPL-->>Sched: Recovered (xrun_bytes = 0) + deactivate Sched +``` + +## Configuration and Scripts + +* **CMakeLists.txt**: Straightforward build configuration integrating the fundamental internal execution blocks of the SOF graph: `pipeline-graph.c`, `pipeline-stream.c`, `pipeline-params.c`, `pipeline-xrun.c`, and `pipeline-schedule.c`. diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index f30731fa4874..adcb00a80719 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -7,9 +7,14 @@ #include <sof/audio/buffer.h> #include <sof/audio/component_ext.h> +#include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/pipeline.h> #include <sof/ipc/msg.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <sof/lib/vregion.h> #include <rtos/interrupt.h> +#include <rtos/symbol.h> +#include <rtos/alloc.h> #include <sof/lib/mm_heap.h> #include <sof/lib/uuid.h> #include <sof/compiler_attributes.h> @@ -101,13 +106,13 @@ static inline void pipeline_posn_offset_put(uint32_t posn_offset) void pipeline_posn_init(struct sof *sof) { - sof->pipeline_posn = platform_shared_get(&pipeline_posn_shared, - sizeof(pipeline_posn_shared)); + sof->pipeline_posn = &pipeline_posn_shared; k_spinlock_init(&sof->pipeline_posn->lock); } /* create new pipeline - returns pipeline id or negative error */ -struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t comp_id) +struct pipeline *pipeline_new(struct k_heap *heap, uint32_t pipeline_id, uint32_t priority, + uint32_t comp_id, struct create_pipeline_params *pparams) { struct sof_ipc_stream_posn posn; struct pipeline *p; @@ -120,13 +125,16 @@ struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t heap_trace_all(0); /* allocate new pipeline */ - p = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*p)); + p = sof_heap_alloc(heap, SOF_MEM_FLAG_USER, sizeof(*p), 0); if (!p) { - pipe_cl_err("pipeline_new(): Out of Memory"); + pipe_cl_err("Out of Memory"); return NULL; } + memset(p, 0, sizeof(*p)); + /* init pipeline */ + p->heap = heap; p->comp_id = comp_id; p->priority = priority; p->pipeline_id = pipeline_id; @@ -135,13 +143,13 @@ struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t ret = memcpy_s(&p->tctx, sizeof(struct tr_ctx), &pipe_tr, sizeof(struct tr_ctx)); if (ret < 0) { - pipe_err(p, "pipeline_new(): failed to copy trace settings"); + pipe_err(p, "failed to copy trace settings"); goto free; } ret = pipeline_posn_offset_get(&p->posn_offset); if (ret < 0) { - pipe_err(p, "pipeline_new(): pipeline_posn_offset_get failed %d", + pipe_err(p, "pipeline_posn_offset_get failed %d", ret); goto free; } @@ -152,14 +160,14 @@ struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t if (posn.rhdr.hdr.size) { p->msg = ipc_msg_init(posn.rhdr.hdr.cmd, posn.rhdr.hdr.size); if (!p->msg) { - pipe_err(p, "pipeline_new(): ipc_msg_init failed"); + pipe_err(p, "ipc_msg_init failed"); goto free; } } return p; free: - rfree(p); + sof_heap_free(heap, p); return NULL; } @@ -167,29 +175,57 @@ static void buffer_set_comp(struct comp_buffer *buffer, struct comp_dev *comp, int dir) { if (dir == PPL_CONN_DIR_COMP_TO_BUFFER) - buffer->source = comp; + comp_buffer_set_source_component(buffer, comp); else - buffer->sink = comp; + comp_buffer_set_sink_component(buffer, comp); } +#ifdef CONFIG_SOF_USERSPACE_LL +/* + * User-space LL: callers (IPC handlers) already hold the per-core LL + * lock via user_ll_lock_sched()/ll_block() while modifying pipeline + * connections, which provides mutual exclusion with the LL thread. No + * additional lock is taken here; instead assert that the lock is held. + */ +#define PPL_LOCK_DECLARE +#define PPL_LOCK(x) user_ll_assert_locked(x) +#define PPL_UNLOCK() +#else +/* + * Kernel-space LL. When modifying pipeline connections, block IRQs + * and prevent LL from running. No locking needed when iterating + * the pipeline in the LL thread. + */ +#define PPL_LOCK_DECLARE uint32_t flags +#define PPL_LOCK(x) irq_local_disable(flags) +#define PPL_UNLOCK() irq_local_enable(flags) +#endif + int pipeline_connect(struct comp_dev *comp, struct comp_buffer *buffer, int dir) { struct list_item *comp_list; - uint32_t flags; + int ret; + PPL_LOCK_DECLARE; if (dir == PPL_CONN_DIR_COMP_TO_BUFFER) comp_info(comp, "connect buffer %d as sink", buf_get_id(buffer)); else comp_info(comp, "connect buffer %d as source", buf_get_id(buffer)); - irq_local_disable(flags); + PPL_LOCK(buffer->core); comp_list = comp_buffer_list(comp, dir); - buffer_attach(buffer, comp_list, dir); + ret = buffer_attach(buffer, comp_list, dir); + if (ret < 0) { + comp_err(comp, "buffer %d already connected dir %d", + buf_get_id(buffer), dir); + PPL_UNLOCK(); + return ret; + } buffer_set_comp(buffer, comp, dir); - irq_local_enable(flags); + PPL_UNLOCK(); return 0; } @@ -197,26 +233,26 @@ int pipeline_connect(struct comp_dev *comp, struct comp_buffer *buffer, void pipeline_disconnect(struct comp_dev *comp, struct comp_buffer *buffer, int dir) { struct list_item *comp_list; - uint32_t flags; + PPL_LOCK_DECLARE; if (dir == PPL_CONN_DIR_COMP_TO_BUFFER) comp_dbg(comp, "disconnect buffer %d as sink", buf_get_id(buffer)); else comp_dbg(comp, "disconnect buffer %d as source", buf_get_id(buffer)); - irq_local_disable(flags); + PPL_LOCK(buffer->core); comp_list = comp_buffer_list(comp, dir); buffer_detach(buffer, comp_list, dir); buffer_set_comp(buffer, NULL, dir); - irq_local_enable(flags); + PPL_UNLOCK(); } /* pipelines must be inactive */ int pipeline_free(struct pipeline *p) { - pipe_dbg(p, "pipeline_free()"); + pipe_dbg(p, "entry"); /* * pipeline_free should always be called only after all the widgets in the pipeline have @@ -228,7 +264,7 @@ int pipeline_free(struct pipeline *p) #if !CONFIG_LIBRARY || UNIT_TEST schedule_task_free(p->pipe_task); #endif - rfree(p->pipe_task); + sof_heap_free(p->heap, p->pipe_task); } ipc_msg_free(p->msg); @@ -236,7 +272,7 @@ int pipeline_free(struct pipeline *p) pipeline_posn_offset_put(p->posn_offset); /* now free the pipeline */ - rfree(p); + sof_heap_free(p->heap, p); /* show heap status */ heap_trace_all(0); @@ -250,11 +286,11 @@ static int pipeline_comp_complete(struct comp_dev *current, { struct pipeline_data *ppl_data = ctx->comp_data; - pipe_dbg(ppl_data->p, "pipeline_comp_complete(), current->comp.id = 0x%x, dir = %u", + pipe_dbg(ppl_data->p, "current->comp.id = 0x%x, dir = %u", dev_comp_id(current), dir); if (!comp_is_single_pipeline(current, ppl_data->start)) { - pipe_dbg(ppl_data->p, "pipeline_comp_complete(), current is from another pipeline"); + pipe_dbg(ppl_data->p, "current is from another pipeline"); return 0; } @@ -265,8 +301,14 @@ static int pipeline_comp_complete(struct comp_dev *current, * 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) + if (current->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) { current->period = ppl_data->p->period; + } else { + struct processing_module *mod = comp_mod(current); + + if (mod && mod->priv.resources.alloc) + vregion_set_interim(mod->priv.resources.alloc->vreg); + } current->priority = ppl_data->p->priority; @@ -293,7 +335,7 @@ int pipeline_complete(struct pipeline *p, struct comp_dev *source, /* check whether pipeline is already completed */ if (p->status != COMP_STATE_INIT) { - pipe_err(p, "pipeline_complete(): Pipeline already completed"); + pipe_err(p, "Pipeline already completed"); return -EINVAL; } @@ -325,11 +367,11 @@ static int pipeline_comp_reset(struct comp_dev *current, int is_single_ppl; int err; - pipe_dbg(p_current, "pipeline_comp_reset(), current->comp.id = 0x%x, dir = %u", + pipe_dbg(p_current, "current->comp.id = 0x%x, dir = %u", dev_comp_id(current), dir); if (!p->source_comp) { - pipe_err(p, "pipeline_comp_reset(): source_comp is NULL"); + pipe_err(p, "source_comp is NULL"); return -EINVAL; } @@ -340,7 +382,7 @@ static int pipeline_comp_reset(struct comp_dev *current, * scheduled together, except for IPC4, where each pipeline receives * commands from the host separately */ - if (!is_single_ppl && IPC4_MOD_ID(current->ipc_config.id)) + if (!is_single_ppl && IS_ENABLED(CONFIG_IPC_MAJOR_4)) return 0; /* Propagate reset across pipelines only in the same direction @@ -354,10 +396,10 @@ static int pipeline_comp_reset(struct comp_dev *current, * 2. trigger functon skipped due to error of other component's trigger function */ if (current->state == COMP_STATE_ACTIVE) { - pipe_warn(current->pipeline, "pipeline_comp_reset(): component is in active state, try to stop it"); + pipe_warn(current->pipeline, "component is in active state, try to stop it"); err = comp_trigger(current, COMP_TRIGGER_STOP); if (err) - pipe_err(current->pipeline, "pipeline_comp_reset(): failed to recover"); + pipe_err(current->pipeline, "failed to recover"); } err = comp_reset(current); @@ -387,7 +429,7 @@ int pipeline_reset(struct pipeline *p, struct comp_dev *host) ret = walk_ctx.comp_func(host, NULL, &walk_ctx, host->direction); if (ret < 0) { - pipe_err(p, "pipeline_reset(): ret = %d, host->comp.id = 0x%x", + pipe_err(p, "ret = %d, host->comp.id = 0x%x", ret, dev_comp_id(host)); } else { /* pipeline is reset to default state */ @@ -551,4 +593,6 @@ struct comp_dev *pipeline_get_dai_comp_latency(uint32_t pipeline_id, uint32_t *l return NULL; } +EXPORT_SYMBOL(pipeline_get_dai_comp_latency); + #endif diff --git a/src/audio/pipeline/pipeline-params.c b/src/audio/pipeline/pipeline-params.c index 2fa3d19e62bc..ed32fc9e3b02 100644 --- a/src/audio/pipeline/pipeline-params.c +++ b/src/audio/pipeline/pipeline-params.c @@ -31,7 +31,7 @@ static int pipeline_comp_params_neg(struct comp_dev *current, struct pipeline_data *ppl_data = ctx->comp_data; int err = 0; - pipe_dbg(current->pipeline, "pipeline_comp_params_neg(), current->comp.id = 0x%x, dir = %u", + pipe_dbg(current->pipeline, "current->comp.id = 0x%x, dir = %u", dev_comp_id(current), dir); /* check if 'current' is already configured */ @@ -60,7 +60,7 @@ static int pipeline_comp_params_neg(struct comp_dev *current, * drop an error and reject the .params() command. */ pipe_err(current->pipeline, - "pipeline_comp_params_neg(): params conflict with existing active pipeline!"); + "params conflict with existing active pipeline!"); err = -EINVAL; } } @@ -81,7 +81,7 @@ static int pipeline_comp_params(struct comp_dev *current, int stream_direction = ppl_data->params->params.direction; int err; - pipe_dbg(current->pipeline, "pipeline_comp_params(), current->comp.id = 0x%x, dir = %u", + pipe_dbg(current->pipeline, "current->comp.id = 0x%x, dir = %u", dev_comp_id(current), dir); /* Don't propagate to pipelines in the opposite direction */ @@ -131,7 +131,7 @@ static int pipeline_comp_hw_params(struct comp_dev *current, struct pipeline_data *ppl_data = ctx->comp_data; int ret; - pipe_dbg(current->pipeline, "pipeline_comp_hw_params(), current->comp.id = 0x%x, dir = %u", + pipe_dbg(current->pipeline, "current->comp.id = 0x%x, dir = %u", dev_comp_id(current), dir); ret = pipeline_for_each_comp(current, ctx, dir); @@ -144,7 +144,7 @@ static int pipeline_comp_hw_params(struct comp_dev *current, &ppl_data->params->params, dir); if (ret < 0) { pipe_err(current->pipeline, - "pipeline_comp_hw_params(): failed getting DAI parameters: %d", + "failed getting DAI parameters: %d", ret); return ret; } @@ -170,7 +170,7 @@ static int pipeline_comp_hw_params_buf(struct comp_dev *current, BUFFER_UPDATE_IF_UNSET); if (ret < 0) pipe_err(current->pipeline, - "pipeline_comp_hw_params(): buffer_set_params(): %d", ret); + "buffer_set_params(): %d", ret); } return ret; @@ -226,14 +226,14 @@ int pipeline_params(struct pipeline *p, struct comp_dev *host, ret = hw_param_ctx.comp_func(host, NULL, &hw_param_ctx, dir); if (ret < 0) { - pipe_err(p, "pipeline_params(): ret = %d, dev->comp.id = 0x%x", + pipe_err(p, "ret = %d, dev->comp.id = 0x%x", ret, dev_comp_id(host)); return ret; } ret = buf_param_ctx.comp_func(host, NULL, &buf_param_ctx, dir); if (ret < 0) { - pipe_err(p, "pipeline_params(): ret = %d, dev->comp.id = 0x%x", + pipe_err(p, "ret = %d, dev->comp.id = 0x%x", ret, dev_comp_id(host)); return ret; } @@ -244,7 +244,7 @@ int pipeline_params(struct pipeline *p, struct comp_dev *host, ret = param_ctx.comp_func(host, NULL, ¶m_ctx, dir); if (ret < 0) { - pipe_err(p, "pipeline_params(): ret = %d, host->comp.id = 0x%x", + pipe_err(p, "ret = %d, host->comp.id = 0x%x", ret, dev_comp_id(host)); } @@ -262,12 +262,12 @@ static int pipeline_comp_prepare(struct comp_dev *current, struct pipeline_data *ppl_data = ctx->comp_data; int err; - pipe_dbg(current->pipeline, "pipeline_comp_prepare(), current->comp.id = 0x%x, dir = %u", + pipe_dbg(current->pipeline, "current->comp.id = 0x%x, dir = %u", dev_comp_id(current), dir); if (!comp_is_single_pipeline(current, ppl_data->start)) { /* ipc4 module is only prepared in its parent pipeline */ - if (IPC4_MOD_ID(current->ipc_config.id)) + if (IS_ENABLED(CONFIG_IPC_MAJOR_4)) return 0; /* Propagate prepare only to pipelines in the same direction */ @@ -312,7 +312,7 @@ int pipeline_prepare(struct pipeline *p, struct comp_dev *dev) ret = walk_ctx.comp_func(dev, NULL, &walk_ctx, dev->direction); if (ret < 0) { - pipe_err(p, "pipeline_prepare(): ret = %d, dev->comp.id = 0x%x", + pipe_err(p, "ret = %d, dev->comp.id = 0x%x", ret, dev_comp_id(dev)); return ret; } diff --git a/src/audio/pipeline/pipeline-schedule.c b/src/audio/pipeline/pipeline-schedule.c index b9f23e0d467a..cb4ec8fd3c62 100644 --- a/src/audio/pipeline/pipeline-schedule.c +++ b/src/audio/pipeline/pipeline-schedule.c @@ -8,6 +8,7 @@ #include <sof/audio/buffer.h> #include <sof/audio/component_ext.h> #include <sof/audio/pipeline.h> +#include <rtos/alloc.h> #include <rtos/interrupt.h> #include <sof/lib/agent.h> #include <sof/list.h> @@ -26,6 +27,7 @@ #include <stdbool.h> #include <stddef.h> #include <stdint.h> +#include <sof/audio/module_adapter/module/generic.h> LOG_MODULE_DECLARE(pipe, CONFIG_SOF_LOG_LEVEL); @@ -39,7 +41,7 @@ SOF_DEFINE_REG_UUID(dp_task); * current static stack size for each DP component * TODO: to be taken from module manifest */ -#define TASK_DP_STACK_SIZE 8192 +#define TASK_DP_STACK_SIZE CONFIG_SOF_STACK_SIZE #endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ @@ -100,7 +102,7 @@ static enum task_state pipeline_task_cmd(struct pipeline *p, err = pipeline_trigger_run(p, host, cmd); if (err < 0) { - pipe_err(p, "pipeline_task_cmd(): failed to trigger components: %d", err); + pipe_err(p, "failed to trigger components: %d", err); reply->error = err; err = SOF_TASK_STATE_COMPLETED; } else { @@ -138,7 +140,7 @@ static enum task_state pipeline_task_cmd(struct pipeline *p, err = SOF_TASK_STATE_RESCHEDULE; } else if (p->status == COMP_STATE_PAUSED) { /* reset the pipeline components for IPC4 after the STOP trigger */ - if (cmd == COMP_TRIGGER_STOP && IPC4_MOD_ID(host->ipc_config.id)) { + if (cmd == COMP_TRIGGER_STOP && IS_ENABLED(CONFIG_IPC_MAJOR_4)) { err = pipeline_reset(host->pipeline, host); if (err < 0) reply->error = err; @@ -166,7 +168,7 @@ static enum task_state pipeline_task(void *arg) struct pipeline *p = arg; int err; - pipe_dbg(p, "pipeline_task()"); + pipe_dbg(p, "entry"); /* are we in xrun ? */ if (p->xrun_bytes) { @@ -225,13 +227,13 @@ static enum task_state pipeline_task(void *arg) /* try to recover */ err = pipeline_xrun_recover(p); if (err < 0) { - pipe_err(p, "pipeline_task(): xrun recovery failed! pipeline is stopped."); + pipe_err(p, "xrun recovery failed! pipeline is stopped."); /* failed - host will stop this pipeline */ return SOF_TASK_STATE_COMPLETED; } } - pipe_dbg(p, "pipeline_task() sched"); + pipe_dbg(p, "sched"); return SOF_TASK_STATE_RESCHEDULE; } @@ -240,15 +242,17 @@ static struct task *pipeline_task_init(struct pipeline *p, uint32_t type) { struct pipeline_task *task = NULL; - task = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(*task)); + task = sof_heap_alloc(p->heap, SOF_MEM_FLAG_USER, + sizeof(*task), 0); if (!task) return NULL; + memset(task, 0, sizeof(*task)); + if (schedule_task_init_ll(&task->task, SOF_UUID(pipe_task_uuid), type, p->priority, pipeline_task, p, p->core, 0) < 0) { - rfree(task); + sof_heap_free(p->heap, task); return NULL; } @@ -280,6 +284,16 @@ void pipeline_schedule_triggered(struct pipeline_walk_context *ctx, struct pipeline *p; uint32_t flags; +#ifdef CONFIG_IPC_MAJOR_4 + /* + * With IPC4, each pipeline is triggered separately. Exactly 1 pipeline + * is expected in the pipelines list (it's unclear whether an empty list + * should be tolerated). + */ + assert(list_is_empty(&ctx->pipelines) || + list_item_is_last(ctx->pipelines.next, &ctx->pipelines)); +#endif + /* * Interrupts have to be disabled while adding tasks to or removing them * from the scheduler list. Without that scheduling can begin @@ -359,7 +373,7 @@ int pipeline_comp_ll_task_init(struct pipeline *p) p->pipe_task = pipeline_task_init(p, type); if (!p->pipe_task) { - pipe_err(p, "pipeline_comp_task_init(): task init failed"); + pipe_err(p, "task init failed"); return -ENOMEM; } } @@ -372,15 +386,16 @@ static enum task_state dp_task_run(void *data) { struct processing_module *mod = data; - module_process_sink_src(mod, mod->sources, mod->num_of_sources, - mod->sinks, mod->num_of_sinks); + int ret = module_process_sink_src(mod, mod->sources, mod->num_of_sources, + mod->sinks, mod->num_of_sinks); + if (ret) + pipeline_comp_copy_error_notify(mod->dev, ret); return SOF_TASK_STATE_RESCHEDULE; } int pipeline_comp_dp_task_init(struct comp_dev *comp) { - int ret; /* DP tasks are guaranteed to have a module_adapter */ struct processing_module *mod = comp_mod(comp); struct task_ops ops = { @@ -389,18 +404,17 @@ int pipeline_comp_dp_task_init(struct comp_dev *comp) .complete = NULL }; - if (!comp->task) { - ret = scheduler_dp_task_init(&comp->task, - SOF_UUID(dp_task_uuid), - &ops, - mod, - comp->ipc_config.core, - TASK_DP_STACK_SIZE); - if (ret < 0) - return ret; - } + if (comp->task) + return 0; - return 0; +#if CONFIG_SOF_USERSPACE_PROXY + unsigned int flags = mod->user_ctx ? K_USER : 0; +#else + unsigned int flags = IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0; +#endif + + return scheduler_dp_task_init(&comp->task, SOF_UUID(dp_task_uuid), &ops, mod, + comp->ipc_config.core, TASK_DP_STACK_SIZE, flags); } #endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index 8f0d70e90b66..5fd795e818db 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -21,6 +21,11 @@ #include <rtos/kernel.h> #include <sof/audio/module_adapter/module/generic.h> #include <sof/lib/cpu-clk-manager.h> +#include <sof/schedule/ll_schedule_domain.h> + +#ifdef CONFIG_IPC_MAJOR_4 +#include <ipc4/notification.h> +#endif #include <errno.h> #include <stdbool.h> @@ -88,6 +93,13 @@ pipeline_should_report_enodata_on_trigger(struct comp_dev *rsrc, return false; } +void pipeline_comp_copy_error_notify(const struct comp_dev *component, int err) +{ +#ifdef CONFIG_IPC_MAJOR_4 + send_process_data_error_notif_msg(component->ipc_config.id, err); +#endif +} + static int pipeline_comp_copy(struct comp_dev *current, struct comp_buffer *calling_buf, struct pipeline_walk_context *ctx, int dir) @@ -96,24 +108,28 @@ static int pipeline_comp_copy(struct comp_dev *current, bool is_single_ppl = comp_is_single_pipeline(current, ppl_data->start); int err; - pipe_dbg(current->pipeline, "pipeline_comp_copy(), current->comp.id = %u, dir = %u", + pipe_dbg(current->pipeline, "current->comp.id = %u, dir = %u", dev_comp_id(current), dir); if (!is_single_ppl) { pipe_dbg(current->pipeline, - "pipeline_comp_copy(), current is from another pipeline and can't be scheduled together"); + "current is from another pipeline and can't be scheduled together"); return 0; } if (!comp_is_active(current)) { - pipe_dbg(current->pipeline, "pipeline_comp_copy(), current is not active"); + pipe_dbg(current->pipeline, "current is not active"); return 0; } /* copy to downstream immediately */ if (dir == PPL_DIR_DOWNSTREAM) { err = comp_copy(current); - if (err < 0 || err == PPL_STATUS_PATH_STOP) + if (err < 0) { + pipeline_comp_copy_error_notify(current, err); + return err; + } + if (err == PPL_STATUS_PATH_STOP) return err; } @@ -121,12 +137,29 @@ static int pipeline_comp_copy(struct comp_dev *current, if (err < 0 || err == PPL_STATUS_PATH_STOP) return err; - if (dir == PPL_DIR_UPSTREAM) + if (dir == PPL_DIR_UPSTREAM) { err = comp_copy(current); + if (err < 0) + pipeline_comp_copy_error_notify(current, err); + } return err; } +#ifdef CONFIG_SOF_USERSPACE_LL +/* + * User-space LL: pipeline_copy() runs as an LL task, with the per-core + * LL lock already held by the LL thread for the whole tick. Taking the + * lock again here would only add syscall overhead on this hot path, so + * we just assert that the lock is in fact held. + */ +#define PPL_LOCK(x) user_ll_assert_locked(x) +#define PPL_UNLOCK() +#else +#define PPL_LOCK(x) +#define PPL_UNLOCK() +#endif + /* Copy data across all pipeline components. * For capture pipelines it always starts from source component * and continues downstream and for playback pipelines it first @@ -144,6 +177,8 @@ int pipeline_copy(struct pipeline *p) uint32_t dir; int ret; + PPL_LOCK(p->core); + if (p->source_comp->direction == SOF_IPC_STREAM_PLAYBACK) { dir = PPL_DIR_UPSTREAM; start = p->sink_comp; @@ -157,9 +192,11 @@ int pipeline_copy(struct pipeline *p) ret = walk_ctx.comp_func(start, NULL, &walk_ctx, dir); if (ret < 0) - pipe_err(p, "pipeline_copy(): ret = %d, start->comp.id = %u, dir = %u", + pipe_err(p, "ret = %d, start->comp.id = %u, dir = %u", ret, dev_comp_id(start), dir); + PPL_UNLOCK(); + return ret; } @@ -211,9 +248,9 @@ static int pipeline_comp_list(struct comp_dev *current, * component and we aren't using IPC4. With IPC4 each pipeline receives * commands separately so we don't need to trigger them together */ - if (!is_single_ppl && (!is_same_sched || IPC4_MOD_ID(current->ipc_config.id))) { + if (!is_single_ppl && (!is_same_sched || IS_ENABLED(CONFIG_IPC_MAJOR_4))) { pipe_dbg(current->pipeline, - "pipeline_comp_list(), current is from another pipeline"); + "current is from another pipeline"); return 0; } @@ -241,7 +278,7 @@ static int pipeline_trigger_list(struct pipeline *p, struct comp_dev *host, int ret = walk_ctx.comp_func(host, NULL, &walk_ctx, host->direction); if (ret < 0) { - pipe_err(p, "pipeline_trigger_list(): ret = %d, host->comp.id = %u, cmd = %d", + pipe_err(p, "ret = %d, host->comp.id = %u, cmd = %d", ret, dev_comp_id(host), cmd); } else { if (cmd == COMP_TRIGGER_PRE_START) { @@ -447,7 +484,7 @@ static int pipeline_comp_trigger(struct comp_dev *current, int err; pipe_dbg(current->pipeline, - "pipeline_comp_trigger(), current->comp.id = %u, dir = %u", + "current->comp.id = %u, dir = %u", dev_comp_id(current), dir); switch (ppl_data->cmd) { @@ -494,7 +531,7 @@ static int pipeline_comp_trigger(struct comp_dev *current, */ if (!is_single_ppl && (!is_same_sched || IS_ENABLED(CONFIG_IPC_MAJOR_4))) { pipe_dbg(current->pipeline, - "pipeline_comp_trigger(), current is from another pipeline"); + "current is from another pipeline"); if (pipeline_should_report_enodata_on_trigger(current, ctx, dir)) return -ENODATA; @@ -569,7 +606,7 @@ int pipeline_trigger_run(struct pipeline *p, struct comp_dev *host, int cmd) ret = walk_ctx.comp_func(host, NULL, &walk_ctx, host->direction); if (ret < 0) { - pipe_err(p, "pipeline_trigger_run(): ret = %d, host->comp.id = %u, cmd = %d", + pipe_err(p, "ret = %d, host->comp.id = %u, cmd = %d", ret, dev_comp_id(host), cmd); goto out; } @@ -598,7 +635,7 @@ int pipeline_trigger_run(struct pipeline *p, struct comp_dev *host, int cmd) ret = walk_ctx.comp_func(host, NULL, &walk_ctx, host->direction); if (ret < 0) - pipe_err(p, "pipeline_trigger_run(): ret = %d, host->comp.id = %u, cmd = %d", + pipe_err(p, "ret = %d, host->comp.id = %u, cmd = %d", ret, dev_comp_id(host), cmd); else if (ret == PPL_STATUS_PATH_STOP) ret = 0; @@ -632,7 +669,7 @@ void pipeline_get_timestamp(struct pipeline *p, struct comp_dev *host, dai = pipeline_get_dai_comp(host->pipeline->pipeline_id, PPL_DIR_UPSTREAM); if (!dai) { - pipe_dbg(p, "pipeline_get_timestamp(): DAI position update failed"); + pipe_dbg(p, "DAI position update failed"); return; } diff --git a/src/audio/pipeline/pipeline-xrun.c b/src/audio/pipeline/pipeline-xrun.c index 480a428d6f67..c535ddbb84a1 100644 --- a/src/audio/pipeline/pipeline-xrun.c +++ b/src/audio/pipeline/pipeline-xrun.c @@ -29,6 +29,8 @@ LOG_MODULE_DECLARE(pipe, CONFIG_SOF_LOG_LEVEL); */ #define NO_XRUN_RECOVERY 1 +#if CONFIG_IPC_MAJOR_3 + /* This function always returns success */ static int pipeline_comp_xrun(struct comp_dev *current, struct comp_buffer *calling_buf, @@ -49,6 +51,8 @@ static int pipeline_comp_xrun(struct comp_dev *current, return pipeline_for_each_comp(current, ctx, dir); } +#endif /* CONFIG_IPC_MAJOR_3 */ + #if NO_XRUN_RECOVERY /* recover the pipeline from a XRUN condition */ int pipeline_xrun_recover(struct pipeline *p) @@ -63,12 +67,12 @@ int pipeline_xrun_recover(struct pipeline *p) { int ret; - pipe_err(p, "pipeline_xrun_recover()"); + pipe_err(p, "entry"); /* prepare the pipeline */ ret = pipeline_prepare(p, p->source_comp); if (ret < 0) { - pipe_err(p, "pipeline_xrun_recover(): pipeline_prepare() failed, ret = %d", + pipe_err(p, "pipeline_prepare() failed, ret = %d", ret); return ret; } @@ -79,7 +83,7 @@ int pipeline_xrun_recover(struct pipeline *p) /* restart pipeline comps */ ret = pipeline_trigger(p, p->source_comp, COMP_TRIGGER_START); if (ret < 0) { - pipe_err(p, "pipeline_xrun_recover(): pipeline_trigger() failed, ret = %d", + pipe_err(p, "pipeline_trigger() failed, ret = %d", ret); return ret; } @@ -139,6 +143,7 @@ int pipeline_xrun_handle_trigger(struct pipeline *p, int cmd) void pipeline_xrun(struct pipeline *p, struct comp_dev *dev, int32_t bytes) { +#if CONFIG_IPC_MAJOR_3 struct pipeline_data data; struct pipeline_walk_context walk_ctx = { .comp_func = pipeline_comp_xrun, @@ -146,6 +151,7 @@ void pipeline_xrun(struct pipeline *p, struct comp_dev *dev, .skip_incomplete = true, }; struct sof_ipc_stream_posn posn; +#endif int ret; /* don't flood host */ @@ -159,9 +165,15 @@ void pipeline_xrun(struct pipeline *p, struct comp_dev *dev, /* notify all pipeline comps we are in XRUN, and stop copying */ ret = pipeline_trigger(p, p->source_comp, COMP_TRIGGER_XRUN); if (ret < 0) - pipe_err(p, "pipeline_xrun(): Pipelines notification about XRUN failed, ret = %d", + pipe_err(p, "Pipelines notification about XRUN failed, ret = %d", ret); + /* + * The IPC position info reporting via window2 is only + * used for IPC3 and e.g. in IPC4 this is conflicting + * with the debug window usages (logging, debug, ..) + */ +#if CONFIG_IPC_MAJOR_3 memset(&posn, 0, sizeof(posn)); ipc_build_stream_posn(&posn, SOF_IPC_STREAM_TRIG_XRUN, dev_comp_id(dev)); @@ -172,4 +184,5 @@ void pipeline_xrun(struct pipeline *p, struct comp_dev *dev, data.p = p; walk_ctx.comp_func(dev, NULL, &walk_ctx, dev->direction); +#endif } diff --git a/src/audio/rtnr/CMakeLists.txt b/src/audio/rtnr/CMakeLists.txt index dc396d5d9035..e3bc38d1f51c 100644 --- a/src/audio/rtnr/CMakeLists.txt +++ b/src/audio/rtnr/CMakeLists.txt @@ -1,11 +1,22 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof rtnr.c) - -if (CONFIG_COMP_RTNR_STUB) - add_local_sources(sof rtnr_stub.c) -elseif(CONFIG_TIGERLAKE) - add_subdirectory(rtklib/tgl) -elseif(CONFIG_MT8195) - add_subdirectory(rtklib/mt8195) +if(CONFIG_COMP_RTNR STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/rtnr_llext) + add_dependencies(app rtnr) + return() +endif() + +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + zephyr_library_sources(rtnr.c) + zephyr_library_sources_ifdef(CONFIG_COMP_RTNR_STUB rtnr_stub.c) + +else() ### library, e.g. testbench or plugin ### + + add_local_sources(sof rtnr.c) + if (CONFIG_COMP_RTNR_STUB) + add_local_sources(sof rtnr_stub.c) + endif() + endif() diff --git a/src/audio/rtnr/Kconfig b/src/audio/rtnr/Kconfig index 24345461d2bc..0b872ffb44e8 100644 --- a/src/audio/rtnr/Kconfig +++ b/src/audio/rtnr/Kconfig @@ -4,7 +4,6 @@ config COMP_RTNR tristate "RTNR component" select COMP_BLOB select COMP_RTNR_STUB if COMP_STUBS - default n help Select for Realtek noise reduction/suppression(NR/NS) component. Noise Suppression technology reduces stationary and transient noises in @@ -19,6 +18,5 @@ config COMP_RTNR_STUB bool "RTNR component stub" select COMP_BLOB depends on COMP_RTNR - default n help Stub out the RTNR library for testing and CI purposes. diff --git a/src/audio/rtnr/README.md b/src/audio/rtnr/README.md new file mode 100644 index 000000000000..2dd6d718f15f --- /dev/null +++ b/src/audio/rtnr/README.md @@ -0,0 +1,13 @@ +# Real-Time Noise Reduction (RTNR) Architecture + +This directory houses the RTNR component. + +## Overview + +Reduces steady-state or transient background noise from an input signal path in real time. + +## Configuration and Scripts + +- **Kconfig**: Dictates the build behavior for the Realtek noise reduction and suppression components (`COMP_RTNR`). The feature depends heavily on specific, proprietary Realtek libraries (`libSOF_RTK_MA_API.a`, etc.). Configures stubs (`COMP_RTNR_STUB`) to circumvent library unavailability during testing and CI logic runs. +- **CMakeLists.txt**: Injects `rtnr.c` directly into Zephyr builds and gracefully falls back to Zephyr external libraries handling. Offers thorough `llext` generation and cleanly wraps stub testing modules `rtnr_stub.c`. +- **rtnr.toml**: Defines topology properties for the loadable RTNR logic (UUID binding, generic pinning setups). diff --git a/src/audio/rtnr/llext/CMakeLists.txt b/src/audio/rtnr/llext/CMakeLists.txt index 1abba6c3befc..3d028ace0adf 100644 --- a/src/audio/rtnr/llext/CMakeLists.txt +++ b/src/audio/rtnr/llext/CMakeLists.txt @@ -5,7 +5,6 @@ if(CONFIG_COMP_RTNR_STUB) sof_llext_build("rtnr" SOURCES ../rtnr.c ../rtnr_stub.c - LIB openmodules ) else() message(FATAL_ERROR "Add library linking support in src/audio/rtnr/llext/CMakeFiles.txt") diff --git a/src/audio/rtnr/rtnr.c b/src/audio/rtnr/rtnr.c index 830bbde413e7..13c4f8d12b4d 100644 --- a/src/audio/rtnr/rtnr.c +++ b/src/audio/rtnr/rtnr.c @@ -74,27 +74,27 @@ void rtnr_printf(int a, int b, int c, int d, int e) { switch (a) { case 0xa: - tr_info(&rtnr_tr, "rtnr_printf 1st=%08x, 2nd=%08x, 3rd=%08x, 4st=%08x", + tr_info(&rtnr_tr, "1st=%08x, 2nd=%08x, 3rd=%08x, 4st=%08x", b, c, d, e); break; case 0xb: - tr_info(&rtnr_tr, "rtnr_printf 1st=%08x, 2nd=%08x, 3rd=%08x, 4st=%08x", + tr_info(&rtnr_tr, "1st=%08x, 2nd=%08x, 3rd=%08x, 4st=%08x", b, c, d, e); break; case 0xc: - tr_warn(&rtnr_tr, "rtnr_printf 1st=%08x, 2nd=%08x, 3rd=%08x, 4st=%08x", + tr_warn(&rtnr_tr, "1st=%08x, 2nd=%08x, 3rd=%08x, 4st=%08x", b, c, d, e); break; case 0xd: - tr_dbg(&rtnr_tr, "rtnr_printf 1st=%08x, 2nd=%08x, 3rd=%08x, 4st=%08x", + tr_dbg(&rtnr_tr, "1st=%08x, 2nd=%08x, 3rd=%08x, 4st=%08x", b, c, d, e); break; case 0xe: - tr_err(&rtnr_tr, "rtnr_printf 1st=%08x, 2nd=%08x, 3rd=%08x, 4st=%08x", + tr_err(&rtnr_tr, "1st=%08x, 2nd=%08x, 3rd=%08x, 4st=%08x", b, c, d, e); break; @@ -105,7 +105,7 @@ void rtnr_printf(int a, int b, int c, int d, int e) void *rtk_rballoc(unsigned int flags, unsigned int caps, unsigned int bytes) { - return rballoc(flags, caps, bytes); + return rballoc(flags, bytes); } void rtk_rfree(void *ptr) @@ -197,7 +197,7 @@ static inline void rtnr_set_process_sample_rate(struct processing_module *mod, u { struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "rtnr_set_process_sample_rate()"); + comp_dbg(mod->dev, "entry"); cd->process_sample_rate = sample_rate; } @@ -206,12 +206,12 @@ static int32_t rtnr_check_config_validity(struct processing_module *mod) struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - comp_dbg(dev, "rtnr_check_config_validity() sample_rate:%d enabled: %d", + comp_dbg(dev, "sample_rate:%d enabled: %d", cd->config.params.sample_rate, cd->config.params.enabled); if ((cd->config.params.sample_rate != 48000) && (cd->config.params.sample_rate != 16000)) { - comp_err(dev, "rtnr_check_config_validity() invalid sample_rate:%d", + comp_err(dev, "invalid sample_rate:%d", cd->config.params.sample_rate); return -EINVAL; } @@ -241,7 +241,7 @@ static int rtnr_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -250,16 +250,16 @@ static int rtnr_init(struct processing_module *mod) cd->process_enable = true; /* Handler for component data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "rtnr_new(): comp_data_blob_handler_new() failed."); + comp_err(dev, "mod_data_blob_handler_new() failed."); ret = -ENOMEM; goto cd_fail; } ret = comp_init_data_blob(cd->model_handler, bs, ipc_rtnr->data); if (ret < 0) { - comp_err(dev, "rtnr_init(): comp_init_data_blob() failed with error: %d", ret); + comp_err(dev, "comp_init_data_blob() failed with error: %d", ret); goto cd_fail; } @@ -268,11 +268,11 @@ static int rtnr_init(struct processing_module *mod) cd->rtk_agl = RTKMA_API_Context_Create(cd->process_sample_rate); if (cd->rtk_agl == 0) { - comp_err(dev, "rtnr_new(): RTKMA_API_Context_Create failed."); + comp_err(dev, "RTKMA_API_Context_Create failed."); ret = -EINVAL; goto cd_fail; } - comp_info(dev, "rtnr_new(): RTKMA_API_Context_Create succeeded."); + comp_info(dev, "RTKMA_API_Context_Create succeeded."); /* comp_is_new_data_blob_available always returns false for the first * control write with non-empty config. The first non-empty write may @@ -285,8 +285,8 @@ static int rtnr_init(struct processing_module *mod) return 0; cd_fail: - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); + mod_data_blob_handler_free(mod, cd->model_handler); + mod_free(mod, cd); return ret; } @@ -294,13 +294,13 @@ static int rtnr_free(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "rtnr_free()"); + comp_info(mod->dev, "entry"); - comp_data_blob_handler_free(cd->model_handler); + mod_data_blob_handler_free(mod, cd->model_handler); RTKMA_API_Context_Free(cd->rtk_agl); - rfree(cd); + mod_free(mod, cd); return 0; } @@ -312,7 +312,7 @@ static int rtnr_check_params(struct processing_module *mod, struct audio_stream struct comp_data *cd = module_get_private_data(mod); bool channels_valid; - comp_info(dev, "rtnr_check_params()"); + comp_info(dev, "entry"); /* set source/sink_frames/rate */ cd->source_rate = audio_stream_get_rate(source); @@ -395,7 +395,7 @@ static int rtnr_get_comp_data(struct processing_module *mod, struct sof_ipc_ctrl max_data_size, config, size); - comp_info(mod->dev, "rtnr_get_comp_data(): size= %d, ret = %d", + comp_info(mod->dev, "size= %d, ret = %d", size, ret); if (ret) return ret; @@ -415,18 +415,18 @@ static int rtnr_get_bin_data(struct processing_module *mod, struct sof_ipc_ctrl_ if (!dev) return -ENODEV; - comp_err(dev, "rtnr_get_bin_data(): type = %u, index = %u, size = %d", + comp_err(dev, "type = %u, index = %u, size = %d", cdata->data->type, cdata->msg_index, cdata->num_elems); switch (cdata->data->type) { case SOF_RTNR_CONFIG: - comp_err(dev, "rtnr_get_bin_data(): SOF_RTNR_CONFIG"); + comp_err(dev, "SOF_RTNR_CONFIG"); return rtnr_get_comp_config(mod, cdata, max_data_size); case SOF_RTNR_DATA: - comp_err(dev, "rtnr_get_bin_data(): SOF_RTNR_DATA"); + comp_err(dev, "SOF_RTNR_DATA"); return rtnr_get_comp_data(mod, cdata, max_data_size); default: - comp_err(dev, "rtnr_get_bin_data(): unknown binary data type"); + comp_err(dev, "unknown binary data type"); return -EINVAL; } } @@ -439,7 +439,7 @@ static int rtnr_get_config(struct processing_module *mod, struct comp_dev *dev = mod->dev; #if CONFIG_IPC_MAJOR_4 - comp_err(dev, "rtnr_get_config(), Not supported, should not happen"); + comp_err(dev, "Not supported, should not happen"); return -EINVAL; #elif CONFIG_IPC_MAJOR_3 @@ -447,13 +447,18 @@ static int rtnr_get_config(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; int j; - comp_dbg(dev, "rtnr_get_config()"); + comp_dbg(dev, "entry"); switch (cdata->cmd) { case SOF_CTRL_CMD_BINARY: return rtnr_get_bin_data(mod, cdata, fragment_size); case SOF_CTRL_CMD_SWITCH: + if (cdata->num_elems > SOF_IPC_MAX_CHANNELS) { + comp_err(dev, "num_elems %u > max %u", + cdata->num_elems, SOF_IPC_MAX_CHANNELS); + return -EINVAL; + } for (j = 0; j < cdata->num_elems; j++) { cdata->chanv[j].channel = j; cdata->chanv[j].value = cd->process_enable; @@ -478,7 +483,7 @@ static int rtnr_reconfigure(struct processing_module *mod) uint8_t *config; size_t size; - comp_dbg(dev, "rtnr_reconfigure()"); + comp_dbg(dev, "entry"); if (!comp_is_current_data_blob_valid(cd->model_handler) && !comp_is_new_data_blob_available(cd->model_handler)) { @@ -494,7 +499,7 @@ static int rtnr_reconfigure(struct processing_module *mod) } config = comp_get_data_blob(cd->model_handler, &size, NULL); - comp_dbg(dev, "rtnr_reconfigure() size: %d", size); + comp_dbg(dev, "size: %d", size); if (size == 0) { /* No data to be handled */ @@ -502,11 +507,11 @@ static int rtnr_reconfigure(struct processing_module *mod) } if (!config) { - comp_err(dev, "rtnr_reconfigure(): Config not set"); + comp_err(dev, "Config not set"); return -EINVAL; } - comp_info(dev, "rtnr_reconfigure(): New data applied %p (%zu bytes)", + comp_info(dev, "New data applied %p (%zu bytes)", config, size); cd->reconfigure = false; @@ -530,7 +535,7 @@ static int rtnr_set_config_bytes(struct processing_module *mod, * the whole config data is received. */ if (size < sizeof(cd->config)) { - comp_err(dev, "rtnr_set_config_data(): invalid size %u", + comp_err(dev, "invalid size %u", size); return -EINVAL; } @@ -541,7 +546,7 @@ static int rtnr_set_config_bytes(struct processing_module *mod, sizeof(cd->config)); comp_info(dev, - "rtnr_set_config_data(): sample_rate = %u, enabled=%d", + "sample_rate = %u, enabled=%d", cd->config.params.sample_rate, cd->config.params.enabled); @@ -560,16 +565,22 @@ static int32_t rtnr_set_value(struct processing_module *mod, void *ctl_data) uint32_t val = 0; int32_t j; + if (cdata->num_elems > SOF_IPC_MAX_CHANNELS) { + comp_err(dev, "num_elems %u > max %u", + cdata->num_elems, SOF_IPC_MAX_CHANNELS); + return -EINVAL; + } + for (j = 0; j < cdata->num_elems; j++) { val |= cdata->chanv[j].value; - comp_dbg(dev, "rtnr_set_value(), value = %u", val); + comp_dbg(dev, "value = %u", val); } if (val) { - comp_info(dev, "rtnr_set_value(): enabled"); + comp_info(dev, "enabled"); cd->process_enable = true; } else { - comp_info(dev, "rtnr_set_value(): passthrough"); + comp_info(dev, "passthrough"); cd->process_enable = false; } @@ -591,7 +602,7 @@ static int rtnr_set_config(struct processing_module *mod, uint32_t param_id, switch (cdata->cmd) { case SOF_CTRL_CMD_BINARY: if (dev->state < COMP_STATE_READY) { - comp_err(dev, "rtnr_set_config(): driver in init!"); + comp_err(dev, "driver in init!"); return -EBUSY; } @@ -614,14 +625,14 @@ static int rtnr_set_config(struct processing_module *mod, uint32_t param_id, * concurrently which is the case when there is no preemption. */ if (comp_is_new_data_blob_available(cd->model_handler)) { - comp_dbg(dev, "rtnr_set_config(), new data blob available"); + comp_dbg(dev, "new data blob available"); comp_get_data_blob(cd->model_handler, NULL, NULL); cd->reconfigure = true; } return 0; } - comp_err(dev, "rtnr_set_config(): unknown binary data type"); + comp_err(dev, "unknown binary data type"); return -EINVAL; case SOF_CTRL_CMD_SWITCH: @@ -629,7 +640,7 @@ static int rtnr_set_config(struct processing_module *mod, uint32_t param_id, return rtnr_set_value(mod, cdata); } - comp_err(dev, "rtnr_set_config() error: invalid command %d", cdata->cmd); + comp_err(dev, "error: invalid command %d", cdata->cmd); return -EINVAL; #elif CONFIG_IPC_MAJOR_4 @@ -637,20 +648,20 @@ static int rtnr_set_config(struct processing_module *mod, uint32_t param_id, switch (param_id) { case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: - comp_dbg(dev, "rtnr_set_config(), SOF_IPC4_SWITCH_CONTROL_PARAM_ID"); + comp_dbg(dev, "SOF_IPC4_SWITCH_CONTROL_PARAM_ID"); return rtnr_set_value(mod, ctl); case SOF_RTNR_CONFIG: - comp_dbg(dev, "rtnr_set_config(), SOF_RTNR_CONFIG"); + comp_dbg(dev, "SOF_RTNR_CONFIG"); if (dev->state < COMP_STATE_READY) { - comp_err(dev, "rtnr_set_config(): driver in init!"); + comp_err(dev, "driver in init!"); return -EBUSY; } return rtnr_set_config_bytes(mod, fragment, fragment_size); case SOF_RTNR_DATA: - comp_dbg(dev, "rtnr_set_config(), SOF_RTNR_DATA"); + comp_dbg(dev, "SOF_RTNR_DATA"); if (dev->state < COMP_STATE_READY) { - comp_err(dev, "rtnr_set_config(): driver in init!"); + comp_err(dev, "driver in init!"); return -EBUSY; } @@ -675,7 +686,7 @@ static int rtnr_set_config(struct processing_module *mod, uint32_t param_id, return 0; } - comp_err(dev, "rtnr_set_config(), error: invalid param_id = %d", param_id); + comp_err(dev, "error: invalid param_id = %d", param_id); return -EINVAL; #endif } @@ -780,6 +791,8 @@ static void rtnr_params(struct processing_module *mod) ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); component_set_nearest_period_frames(dev, params->rate); + /* The caller has checked validity of source and sink buffers */ + sourceb = comp_dev_get_first_data_producer(dev); ipc4_update_buffer_format(sourceb, &mod->priv.cfg.base_cfg.audio_fmt); @@ -797,7 +810,14 @@ static int rtnr_prepare(struct processing_module *mod, struct comp_buffer *sourceb, *sinkb; int ret; - comp_dbg(dev, "rtnr_prepare()"); + comp_dbg(dev, "entry"); + + sinkb = comp_dev_get_first_data_consumer(dev); + sourceb = comp_dev_get_first_data_producer(dev); + if (!sourceb || !sinkb) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } #if CONFIG_IPC_MAJOR_4 rtnr_params(mod); @@ -806,26 +826,24 @@ static int rtnr_prepare(struct processing_module *mod, /* Check config */ ret = rtnr_check_config_validity(mod); if (ret < 0) { - comp_err(dev, "rtnr_prepare(): rtnr_check_config_validity() failed."); + comp_err(dev, "rtnr_check_config_validity() failed."); goto err; } /* Initialize RTNR */ /* Get sink data format */ - sinkb = comp_dev_get_first_data_consumer(dev); cd->sink_format = audio_stream_get_frm_fmt(&sinkb->stream); cd->sink_stream.frame_fmt = audio_stream_get_frm_fmt(&sinkb->stream); - sourceb = comp_dev_get_first_data_producer(dev); ret = rtnr_check_params(mod, &sourceb->stream, &sinkb->stream); if (ret) goto err; /* Check source and sink PCM format and get processing function */ - comp_info(dev, "rtnr_prepare(), sink_format=%d", cd->sink_format); + comp_info(dev, "sink_format=%d", cd->sink_format); cd->rtnr_func = rtnr_find_func(cd->sink_format); if (!cd->rtnr_func) { - comp_err(dev, "rtnr_prepare(): No suitable processing function found."); + comp_err(dev, "No suitable processing function found."); ret = -EINVAL; goto err; } @@ -846,7 +864,7 @@ static int rtnr_reset(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "rtnr_reset()"); + comp_info(mod->dev, "entry"); cd->sink_format = 0; cd->rtnr_func = NULL; @@ -866,9 +884,6 @@ static const struct module_interface rtnr_interface = { .free = rtnr_free }; -DECLARE_MODULE_ADAPTER(rtnr_interface, rtnr_uuid, rtnr_tr); -SOF_MODULE_INIT(rtnr, sys_comp_module_rtnr_interface_init); - #if CONFIG_COMP_RTNR_MODULE /* modular: llext dynamic link */ @@ -876,15 +891,14 @@ SOF_MODULE_INIT(rtnr, sys_comp_module_rtnr_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -/* 5c7ca334-e15d-11eb-ba800242ac130004 */ -#define UUID_RTNR 0x34, 0xA3, 0x7C, 0x5C, 0x5D, 0xE1, 0xEB, 0x11, \ - 0xBA, 0x80, 0x02, 0x42, 0xAC, 0x13, 0x00, 0x04 - -SOF_LLEXT_MOD_ENTRY(rtnr, &rtnr_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("RTNR", rtnr_llext_entry, 1, UUID_RTNR, 40); + SOF_LLEXT_MODULE_MANIFEST("RTNR", &rtnr_interface, 1, SOF_REG_UUID(rtnr), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_MODULE_ADAPTER(rtnr_interface, rtnr_uuid, rtnr_tr); +SOF_MODULE_INIT(rtnr, sys_comp_module_rtnr_interface_init); + #endif diff --git a/src/audio/rtnr/rtnr.toml b/src/audio/rtnr/rtnr.toml index 3acd2510e1ae..7281f2b72ee0 100644 --- a/src/audio/rtnr/rtnr.toml +++ b/src/audio/rtnr/rtnr.toml @@ -5,7 +5,7 @@ REM # RTNR module config [[module.entry]] name = "RTNR" - uuid = "5C7CA334-E15D-11EB-BA80-0242AC130004" + uuid = UUIDREG_STR_RTNR affinity_mask = "0x1" instance_count = "40" domain_types = "0" diff --git a/src/audio/rtnr/rtnr_stub.c b/src/audio/rtnr/rtnr_stub.c index 1ce74a31b96d..a825396ece3f 100644 --- a/src/audio/rtnr/rtnr_stub.c +++ b/src/audio/rtnr/rtnr_stub.c @@ -73,7 +73,7 @@ void *RTKMA_API_Context_Create(int sample_rate) /* Allocate something, to avoid return NULL and cause error * in check of success of this. */ - return rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, RTNR_STUB_CONTEXT_SIZE); + return rzalloc(SOF_MEM_FLAG_USER, RTNR_STUB_CONTEXT_SIZE); } void RTKMA_API_Context_Free(void *Context) diff --git a/src/audio/selector/CMakeLists.txt b/src/audio/selector/CMakeLists.txt index 1c7e9a43ad44..d3d96e00b829 100644 --- a/src/audio/selector/CMakeLists.txt +++ b/src/audio/selector/CMakeLists.txt @@ -1,3 +1,9 @@ # SPDX-License-Identifier: BSD-3-Clause +if(CONFIG_COMP_SEL STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/selector_llext) + add_dependencies(app selector) + return() +endif() + add_local_sources(sof selector_generic.c selector.c) diff --git a/src/audio/selector/Kconfig b/src/audio/selector/Kconfig index 6dd8c8b02507..636330dabe1f 100644 --- a/src/audio/selector/Kconfig +++ b/src/audio/selector/Kconfig @@ -2,6 +2,7 @@ config COMP_SEL tristate "Channel selector component" + default m if LIBRARY_DEFAULT_MODULAR default y help Select for SEL component diff --git a/src/audio/selector/README.md b/src/audio/selector/README.md new file mode 100644 index 000000000000..54f09e2ba876 --- /dev/null +++ b/src/audio/selector/README.md @@ -0,0 +1,14 @@ +# Channel Selector Architecture + +This directory contains the Channel Selector component. + +## Overview + +Given a multi-channel stream (e.g., 8-channel microphone array), the channel selector component isolates specific channels (e.g., channels 1 and 2) to pass forward while dropping the rest. + +## Configuration and Scripts + +- **Kconfig**: Enables the selector component (`COMP_SEL`). +- **CMakeLists.txt**: Compiles `selector.c` and `selector_generic.c`, and natively supports Zephyr environment modules (`llext`). +- **selector.toml**: Includes topology parameters under `MICSEL`, using UUID `UUIDREG_STR_SELECTOR4` and limits up to 8 instances, with distinct `mod_cfg` limits depending on chipset architectures (Meteor Lake, Lunar Lake, ACE). +- **Topology (.conf)**: Derived from `tools/topology/topology2/include/components/micsel.conf`, which defines a `micsel` widget of type `effect` (UUID `c1:92:fe:32:17:1e:c2:4f:97:58:c7:f3:54:2e:98:0a`). diff --git a/src/audio/selector/selector.c b/src/audio/selector/selector.c index 8032a3d7dea9..faf21da0e228 100644 --- a/src/audio/selector/selector.c +++ b/src/audio/selector/selector.c @@ -37,13 +37,16 @@ #include <stddef.h> #include <stdint.h> +#if CONFIG_IPC_MAJOR_4 +#define SEL_MAX_CONFIG_BLOB_SIZE (SEL_MAX_NUM_CONFIGS * sizeof(struct ipc4_selector_coeffs_config)) +#endif + LOG_MODULE_REGISTER(selector, CONFIG_SOF_LOG_LEVEL); #if CONFIG_IPC_MAJOR_3 static const struct comp_driver comp_selector; SOF_DEFINE_REG_UUID(selector); -DECLARE_TR_CTX(selector_tr, SOF_UUID(selector_uuid), LOG_LEVEL_INFO); static int selector_verify_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) @@ -53,7 +56,7 @@ static int selector_verify_params(struct comp_dev *dev, uint32_t in_channels; uint32_t out_channels; - comp_dbg(dev, "selector_verify_params()"); + comp_dbg(dev, "entry"); sinkb = comp_dev_get_first_data_consumer(dev); @@ -68,7 +71,7 @@ static int selector_verify_params(struct comp_dev *dev, buffer = comp_dev_get_first_data_consumer(dev); if (cd->config.in_channels_count && cd->config.in_channels_count != params->channels) { - comp_err(dev, "selector_verify_params(): src in_channels_count does not match pcm channels"); + comp_err(dev, "src in_channels_count does not match pcm channels"); return -EINVAL; } in_channels = cd->config.in_channels_count; @@ -86,7 +89,7 @@ static int selector_verify_params(struct comp_dev *dev, buffer = comp_dev_get_first_data_producer(dev); if (cd->config.out_channels_count && cd->config.out_channels_count != params->channels) { - comp_err(dev, "selector_verify_params(): src in_channels_count does not match pcm channels"); + comp_err(dev, "src in_channels_count does not match pcm channels"); return -EINVAL; } out_channels = cd->config.out_channels_count; @@ -113,7 +116,7 @@ static int selector_verify_params(struct comp_dev *dev, case SEL_SOURCE_4CH: break; default: - comp_err(dev, "selector_verify_params(): in_channels = %u", in_channels); + comp_err(dev, "in_channels = %u", in_channels); return -EINVAL; } @@ -125,19 +128,19 @@ static int selector_verify_params(struct comp_dev *dev, case SEL_SINK_4CH: /* verify proper channels for passthrough mode */ if (in_channels != out_channels) { - comp_err(dev, "selector_verify_params(): in_channels = %u, out_channels = %u" + comp_err(dev, "in_channels = %u, out_channels = %u" , in_channels, out_channels); return -EINVAL; } break; default: - comp_err(dev, "selector_verify_params(): out_channels = %u" + comp_err(dev, "out_channels = %u" , out_channels); return -EINVAL; } if (cd->config.sel_channel > (params->channels - 1)) { - comp_err(dev, "selector_verify_params(): ch_idx = %u" + comp_err(dev, "ch_idx = %u" , cd->config.sel_channel); return -EINVAL; } @@ -162,9 +165,9 @@ static struct comp_dev *selector_new(const struct comp_driver *drv, return NULL; dev->ipc_config = *config; - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); if (!cd) { - rfree(dev); + comp_free_device(dev); return NULL; } @@ -173,7 +176,7 @@ static struct comp_dev *selector_new(const struct comp_driver *drv, ret = memcpy_s(&cd->config, sizeof(cd->config), ipc_process->data, bs); if (ret) { rfree(cd); - rfree(dev); + comp_free_device(dev); return NULL; } @@ -189,10 +192,10 @@ static void selector_free(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); - comp_dbg(dev, "selector_free()"); + comp_dbg(dev, "entry"); rfree(cd); - rfree(dev); + comp_free_device(dev); } /** @@ -207,11 +210,11 @@ static int selector_params(struct comp_dev *dev, { int err; - comp_dbg(dev, "selector_params()"); + comp_dbg(dev, "entry"); err = selector_verify_params(dev, params); if (err < 0) { - comp_err(dev, "selector_params(): pcm params verification failed."); + comp_err(dev, "pcm params verification failed."); return -EINVAL; } @@ -228,23 +231,93 @@ static int selector_ctrl_set_data(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata) { struct comp_data *cd = comp_get_drvdata(dev); + struct comp_buffer *src; struct sof_sel_config *cfg; + uint32_t src_channels; int ret = 0; switch (cdata->cmd) { case SOF_CTRL_CMD_BINARY: - comp_dbg(dev, "selector_ctrl_set_data(), SOF_CTRL_CMD_BINARY"); + comp_dbg(dev, "SOF_CTRL_CMD_BINARY"); + + if (cdata->data->size < sizeof(struct sof_sel_config)) { + comp_err(dev, "invalid config blob size %u", cdata->data->size); + return -EINVAL; + } cfg = (struct sof_sel_config *) ASSUME_ALIGNED(&cdata->data->data, 4); + /* + * The config validated at .params() time can be replaced here at + * runtime, so re-validate the new channel counts and selected + * channel before accepting them; otherwise an out-of-range value + * later indexes past the source channels in the copy routine. + */ + switch (cfg->in_channels_count) { + case 0: + case SEL_SOURCE_1CH: + case SEL_SOURCE_2CH: + case SEL_SOURCE_4CH: + break; + default: + comp_err(dev, "invalid in_channels_count %u", + cfg->in_channels_count); + return -EINVAL; + } + + switch (cfg->out_channels_count) { + case 0: + case SEL_SINK_1CH: + case SEL_SINK_2CH: + case SEL_SINK_4CH: + break; + default: + comp_err(dev, "invalid out_channels_count %u", + cfg->out_channels_count); + return -EINVAL; + } + + /* sel_channel indexes the source channels, so it must be below + * the source channel count, otherwise the copy routine reads + * past the end of each source frame. The copy routine strides by + * the live producer stream channel count, so when the source is + * already connected that live count is the authority for both the + * selected channel and any fixed input count; before connection + * fall back to the configured input count. Always cap by the + * maximum supported source width. + */ + src = comp_dev_get_first_data_producer(dev); + if (src) + src_channels = audio_stream_get_channels(&src->stream); + else + src_channels = cfg->in_channels_count; + + /* A fixed (non-zero) input count must not exceed the live source + * width, otherwise sel_channel could be accepted below the + * requested count yet still index past the actual stream. + */ + if (src && cfg->in_channels_count && + cfg->in_channels_count > src_channels) { + comp_err(dev, "in_channels_count %u exceeds source channels %u", + cfg->in_channels_count, src_channels); + return -EINVAL; + } + + if (cfg->sel_channel >= SEL_SOURCE_4CH || + (src_channels && cfg->sel_channel >= src_channels)) { + comp_err(dev, "invalid sel_channel %u (source channels %u)", + cfg->sel_channel, src_channels); + return -EINVAL; + } + /* Just set the configuration */ cd->config.in_channels_count = cfg->in_channels_count; cd->config.out_channels_count = cfg->out_channels_count; cd->config.sel_channel = cfg->sel_channel; break; default: - comp_err(dev, "selector_ctrl_set_cmd(): invalid cdata->cmd = %u", + comp_err(dev, "invalid cdata->cmd = %u", cdata->cmd); ret = -EINVAL; break; @@ -269,7 +342,7 @@ static int selector_ctrl_get_data(struct comp_dev *dev, switch (cdata->cmd) { case SOF_CTRL_CMD_BINARY: - comp_dbg(dev, "selector_ctrl_get_data(), SOF_CTRL_CMD_BINARY"); + comp_dbg(dev, "SOF_CTRL_CMD_BINARY"); if (size < sizeof(cd->config)) return -EINVAL; @@ -284,7 +357,7 @@ static int selector_ctrl_get_data(struct comp_dev *dev, break; default: - comp_err(dev, "selector_ctrl_get_data(): invalid cdata->cmd"); + comp_err(dev, "invalid cdata->cmd"); ret = -EINVAL; break; } @@ -306,7 +379,7 @@ static int selector_cmd(struct comp_dev *dev, int cmd, void *data, struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4); int ret = 0; - comp_dbg(dev, "selector_cmd()"); + comp_dbg(dev, "entry"); switch (cmd) { case COMP_CMD_SET_DATA: @@ -316,13 +389,13 @@ static int selector_cmd(struct comp_dev *dev, int cmd, void *data, ret = selector_ctrl_get_data(dev, cdata, max_data_size); break; case COMP_CMD_SET_VALUE: - comp_dbg(dev, "selector_cmd(), COMP_CMD_SET_VALUE"); + comp_dbg(dev, "COMP_CMD_SET_VALUE"); break; case COMP_CMD_GET_VALUE: - comp_dbg(dev, "selector_cmd(), COMP_CMD_GET_VALUE"); + comp_dbg(dev, "COMP_CMD_GET_VALUE"); break; default: - comp_err(dev, "selector_cmd(): invalid command"); + comp_err(dev, "invalid command"); ret = -EINVAL; } @@ -341,11 +414,17 @@ static int selector_trigger(struct comp_dev *dev, int cmd) enum sof_comp_type type; int ret; - comp_dbg(dev, "selector_trigger()"); + comp_dbg(dev, "entry"); sourceb = comp_dev_get_first_data_producer(dev); + if (!sourceb) { + comp_err(dev, "source disconnected"); + return -ENODEV; + } ret = comp_set_state(dev, cmd); + if (ret == COMP_STATUS_STATE_ALREADY_SET) + ret = 0; /* TODO: remove in the future after adding support for case when * kpb_init_draining() and kpb_draining_task() are interrupted by @@ -369,7 +448,7 @@ static int selector_copy(struct comp_dev *dev) uint32_t source_bytes; uint32_t sink_bytes; - comp_dbg(dev, "selector_copy()"); + comp_dbg(dev, "entry"); /* selector component will have 1 source and 1 sink buffer */ source = comp_dev_get_first_data_producer(dev); @@ -382,7 +461,7 @@ static int selector_copy(struct comp_dev *dev) 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", + comp_dbg(dev, "source_bytes = 0x%x, sink_bytes = 0x%x", source_bytes, sink_bytes); /* copy selected channels from in to out */ @@ -409,7 +488,7 @@ static int selector_prepare(struct comp_dev *dev) size_t sink_size; int ret; - comp_dbg(dev, "selector_prepare()"); + comp_dbg(dev, "entry"); ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); if (ret < 0) @@ -421,6 +500,10 @@ static int selector_prepare(struct comp_dev *dev) /* selector component will have 1 source and 1 sink buffer */ sourceb = comp_dev_get_first_data_producer(dev); sinkb = comp_dev_get_first_data_consumer(dev); + if (!sourceb || !sinkb) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } /* get source data format and period bytes */ cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); @@ -434,15 +517,15 @@ static int selector_prepare(struct comp_dev *dev) * proper number of channels [1] for selector to actually * reduce channel count between source and sink */ - comp_dbg(dev, "selector_prepare(): sourceb->schannels = %u", + comp_dbg(dev, "sourceb->schannels = %u", audio_stream_get_channels(&sourceb->stream)); - comp_dbg(dev, "selector_prepare(): sinkb->channels = %u", + comp_dbg(dev, "sinkb->channels = %u", audio_stream_get_channels(&sinkb->stream)); sink_size = audio_stream_get_size(&sinkb->stream); if (sink_size < cd->sink_period_bytes) { - comp_err(dev, "selector_prepare(): sink buffer size %zu is insufficient < %d", + comp_err(dev, "sink buffer size %zu is insufficient < %d", sink_size, cd->sink_period_bytes); ret = -ENOMEM; goto err; @@ -450,14 +533,14 @@ static int selector_prepare(struct comp_dev *dev) /* validate */ if (cd->sink_period_bytes == 0) { - comp_err(dev, "selector_prepare(): cd->sink_period_bytes = 0, dev->frames = %u", + comp_err(dev, "cd->sink_period_bytes = 0, dev->frames = %u", dev->frames); ret = -EINVAL; goto err; } if (cd->source_period_bytes == 0) { - comp_err(dev, "selector_prepare(): cd->source_period_bytes = 0, dev->frames = %u", + comp_err(dev, "cd->source_period_bytes = 0, dev->frames = %u", dev->frames); ret = -EINVAL; goto err; @@ -465,7 +548,7 @@ static int selector_prepare(struct comp_dev *dev) cd->sel_func = sel_get_processing_function(dev); if (!cd->sel_func) { - comp_err(dev, "selector_prepare(): invalid cd->sel_func, cd->source_format = %u, cd->sink_format = %u, cd->out_channels_count = %u", + comp_err(dev, "invalid cd->sel_func, cd->source_format = %u, cd->sink_format = %u, cd->out_channels_count = %u", cd->source_format, cd->sink_format, cd->config.out_channels_count); ret = -EINVAL; @@ -489,7 +572,7 @@ static int selector_reset(struct comp_dev *dev) int ret; struct comp_data *cd = comp_get_drvdata(dev); - comp_dbg(dev, "selector_reset()"); + comp_dbg(dev, "entry"); cd->source_period_bytes = 0; cd->sink_period_bytes = 0; @@ -500,6 +583,8 @@ static int selector_reset(struct comp_dev *dev) return ret; } +DECLARE_TR_CTX(selector_tr, SOF_UUID(selector_uuid), LOG_LEVEL_INFO); + /** \brief Selector component definition. */ static const struct comp_driver comp_selector = { .type = SOF_COMP_SELECTOR, @@ -524,8 +609,7 @@ static SHARED_DATA struct comp_driver_info comp_selector_info = { /** \brief Initializes selector component. */ UT_STATIC void sys_comp_selector_init(void) { - comp_register(platform_shared_get(&comp_selector_info, - sizeof(comp_selector_info))); + comp_register(&comp_selector_info); } DECLARE_MODULE(sys_comp_selector_init); @@ -534,7 +618,6 @@ SOF_MODULE_INIT(selector, sys_comp_selector_init); #else SOF_DEFINE_REG_UUID(selector4); -DECLARE_TR_CTX(selector_tr, SOF_UUID(selector4_uuid), LOG_LEVEL_INFO); static void build_config(struct comp_data *cd, struct module_config *cfg) { @@ -564,7 +647,7 @@ static void build_config(struct comp_data *cd, struct module_config *cfg) /* Build default coefficient array (unity Q10 on diagonal, i.e. pass-through mode) */ memset(&cd->coeffs_config, 0, sizeof(cd->coeffs_config)); for (i = 0; i < MIN(SEL_SOURCE_CHANNELS_MAX, SEL_SINK_CHANNELS_MAX); i++) - cd->coeffs_config.coeffs[i][i] = 1 << 10; + cd->coeffs_config.coeffs[i][i] = SEL_COEF_ONE_Q10; } static int selector_init(struct processing_module *mod) @@ -579,7 +662,7 @@ static int selector_init(struct processing_module *mod) size_t bs[2]; int ret; - comp_dbg(mod->dev, "selector_init()"); + comp_dbg(mod->dev, "entry"); init_cfg_ext = cfg->init_data; init_cfg_out_fmt = cfg->init_data; @@ -593,17 +676,17 @@ static int selector_init(struct processing_module *mod) if (init_cfg_ext->base_cfg_ext.nb_input_pins != SEL_NUM_IN_PIN_FMTS || init_cfg_ext->base_cfg_ext.nb_output_pins != SEL_NUM_OUT_PIN_FMTS) { - comp_err(mod->dev, "selector_init(): Invalid pin configuration"); + comp_err(mod->dev, "Invalid pin configuration"); return -EINVAL; } } else if (cfg->size == base_cfg_size + bs[1]) { payload_fmt = IPC4_SEL_INIT_PAYLOAD_BASE_WITH_OUT_FMT; } else { - comp_err(mod->dev, "selector_init(): Invalid configuration size"); + comp_err(mod->dev, "Invalid configuration size"); return -EINVAL; } - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -682,17 +765,17 @@ static int selector_verify_params(struct processing_module *mod, uint32_t in_channels = cd->config.in_channels_count; uint32_t out_channels = cd->config.out_channels_count; - comp_dbg(dev, "selector_verify_params()"); + comp_dbg(dev, "entry"); /* verify input channels */ if (in_channels == 0 || in_channels > SEL_SOURCE_CHANNELS_MAX) { - comp_err(dev, "selector_verify_params(): in_channels = %u", in_channels); + comp_err(dev, "in_channels = %u", in_channels); return -EINVAL; } /* verify output channels */ if (out_channels == 0 || out_channels > SEL_SINK_CHANNELS_MAX) { - comp_err(dev, "selector_verify_params(): out_channels = %u", out_channels); + comp_err(dev, "out_channels = %u", out_channels); return -EINVAL; } @@ -721,9 +804,10 @@ static int selector_free(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "selector_free()"); + comp_dbg(mod->dev, "entry"); - rfree(cd); + mod_free(mod, cd->multi_coeffs_config); + mod_free(mod, cd); return 0; } @@ -740,13 +824,13 @@ static int selector_params(struct processing_module *mod) struct sof_ipc_stream_params *params = mod->stream_params; int err; - comp_dbg(mod->dev, "selector_params()"); + comp_dbg(mod->dev, "entry"); set_selector_params(mod, params); err = selector_verify_params(mod, params); if (err < 0) { - comp_err(mod->dev, "selector_params(): pcm params verification failed."); + comp_err(mod->dev, "pcm params verification failed."); return -EINVAL; } @@ -759,13 +843,51 @@ static int selector_set_config(struct processing_module *mod, uint32_t config_id size_t response_size) { struct comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + int n; if (config_id == IPC4_SELECTOR_COEFFS_CONFIG_ID) { - if (data_offset_size != sizeof(cd->coeffs_config)) + if (data_offset_size > SEL_MAX_CONFIG_BLOB_SIZE || + fragment_size < data_offset_size || + pos != MODULE_CFG_FRAGMENT_SINGLE) { + comp_err(dev, "Failure with data_offset_size %u fragment_size %u pos %u", + data_offset_size, (uint32_t)fragment_size, (uint32_t)pos); return -EINVAL; + } - memcpy_s(&cd->coeffs_config, sizeof(cd->coeffs_config), fragment, data_offset_size); - return 0; + /* The size must be N times the coefficient vectors size of one channels + * up/down mix profile. + */ + n = data_offset_size / sizeof(struct ipc4_selector_coeffs_config); + if (n < 1 || data_offset_size != n * sizeof(struct ipc4_selector_coeffs_config)) { + comp_err(dev, "Invalid configuration size."); + return -EINVAL; + } + + cd->num_configs = n; + if (cd->multi_coeffs_config && cd->multi_coeffs_config_size < data_offset_size) { + /* Configuration exist but the allocation is too small to write over. */ + mod_free(mod, cd->multi_coeffs_config); + cd->multi_coeffs_config = NULL; + } + + if (!cd->multi_coeffs_config) { + cd->multi_coeffs_config_size = data_offset_size; + cd->multi_coeffs_config = mod_alloc(mod, cd->multi_coeffs_config_size); + if (!cd->multi_coeffs_config) { + comp_err(dev, "Failed to allocate configuration blob."); + return -ENOMEM; + } + } + + /* Copy the configuration and notify for need to re-configure. If for + * some reason the memcpy_s() would return an error (it can't because + * of the previous checks), the partial or incorrect blob would remain + * allocated but be freed later in module error handling and ending. + */ + cd->new_config = true; + return memcpy_s(cd->multi_coeffs_config, cd->multi_coeffs_config_size, + fragment, data_offset_size); } return -EINVAL; @@ -778,6 +900,112 @@ static int selector_get_config(struct processing_module *mod, uint32_t config_id return 0; } +/** + * \brief Loop the array of mix coefficients sets and find a set with matching channels + * in and out count. + * \param[in] cd Selector component data. + * \param[in] source_channels Number of channels in source. + * \param[in] sink_channels Number of channels in sink. + * + * \return Pointer to the matching ipc4_selector_coeffs_config if found, or NULL if + * no matching configuration exists. + */ +static struct ipc4_selector_coeffs_config *selector_config_array_search(struct comp_data *cd, + int source_channels, + int sink_channels) +{ + struct ipc4_selector_coeffs_config *found = NULL; + int i; + + for (i = 0; i < cd->num_configs; i++) { + if (cd->multi_coeffs_config[i].source_channels_count == source_channels && + cd->multi_coeffs_config[i].sink_channels_count == sink_channels) { + found = &cd->multi_coeffs_config[i]; + break; + } + } + + return found; +} + +/** + * \brief Get mix coefficients set from configuration blob with multiple coefficients sets. + * Also activate more efficient pass-through copy mode if the coefficients indicate 1:1 + * copy from source to sink. + * \param[in,out] mod Selector base module device. + * \param[in] source_channels Number of channels in source. + * \param[in] sink_channels Number of channels in sink. + * + * \return Error code. + */ +static int selector_find_coefficients(struct processing_module *mod) +{ + struct comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + struct ipc4_selector_coeffs_config *config; + uint32_t source_channels = cd->config.in_channels_count; + uint32_t sink_channels = cd->config.out_channels_count; + int16_t coef; + int ret, i, j; + + /* In set_config() the blob is copied to cd->multi_coeffs_config. A legacy blob contains a + * single set of mix coefficients without channels information. A new blob with multiple + * configurations has the source and sink channels count information. If there has been no + * set_config(), then the cd->coeffs_config has been initialized in set_selector_params() + * to mix with coefficients SEL_COEF_ONE_Q10 for matching input and output channels. + */ + if (cd->multi_coeffs_config) { + if (cd->num_configs > 1) { + config = selector_config_array_search(cd, source_channels, sink_channels); + /* If not found, check if pass-through mix is defined for the max + * channels count (8). + */ + if (!config && source_channels == sink_channels) + config = selector_config_array_search(cd, SEL_SOURCE_CHANNELS_MAX, + SEL_SINK_CHANNELS_MAX); + + if (!config) { + comp_err(dev, "No mix coefficients found for %u to %u channels.", + source_channels, sink_channels); + return -EINVAL; + } + } else { + config = cd->multi_coeffs_config; + } + + ret = memcpy_s(&cd->coeffs_config, sizeof(struct ipc4_selector_coeffs_config), + config, sizeof(*config)); + if (ret) + return ret; + } + + /* The pass-through copy function can be used if coefficients are a unit matrix for + * 1:1 stream copy. + */ + if (source_channels == sink_channels) { + cd->passthrough = true; + for (i = 0; i < sink_channels; i++) { + for (j = 0; j < source_channels; j++) { + coef = cd->coeffs_config.coeffs[i][j]; + if ((i == j && coef != SEL_COEF_ONE_Q10) || (i != j && coef != 0)) { + cd->passthrough = false; + break; + } + } + } + } else { + cd->passthrough = false; + } + + if (cd->passthrough) + comp_info(dev, "Passthrough mode."); + else + comp_info(dev, "Using coefficients for %u to %u channels.", + source_channels, sink_channels); + + return 0; +} + /** * \brief Copies and processes stream data. * \param[in,out] mod Selector base module device. @@ -789,10 +1017,28 @@ static int selector_process(struct processing_module *mod, struct output_stream_buffer *output_buffers, int num_output_buffers) { + struct audio_stream *source; + struct audio_stream *sink; struct comp_data *cd = module_get_private_data(mod); uint32_t avail_frames = input_buffers[0].size; + int ret; + + comp_dbg(mod->dev, "entry"); - comp_dbg(mod->dev, "selector_process()"); + if (cd->new_config) { + cd->new_config = false; + ret = selector_find_coefficients(mod); + if (ret) + return ret; + } + + if (cd->passthrough) { + source = input_buffers->data; + sink = output_buffers->data; + audio_stream_copy(source, 0, sink, 0, avail_frames * cd->config.in_channels_count); + module_update_buffer_position(input_buffers, output_buffers, avail_frames); + return 0; + } if (avail_frames) /* copy selected channels from in to out */ @@ -817,7 +1063,7 @@ static int selector_prepare(struct processing_module *mod, size_t sink_size; int ret; - comp_dbg(dev, "selector_prepare()"); + comp_dbg(dev, "entry"); ret = selector_params(mod); if (ret < 0) @@ -830,8 +1076,7 @@ static int selector_prepare(struct processing_module *mod, sourceb = comp_dev_get_first_data_producer(dev); sinkb = comp_dev_get_first_data_consumer(dev); - audio_stream_set_align(4, 1, &sourceb->stream); - audio_stream_set_align(4, 1, &sinkb->stream); + audio_stream_set_align(SOF_FRAME_BYTE_ALIGN, SOF_FRAME_COUNT_ALIGN, &sourceb->stream); /* get source data format and period bytes */ cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); @@ -840,47 +1085,42 @@ static int selector_prepare(struct processing_module *mod, /* get sink data format and period bytes */ 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(&sourceb->stream), - audio_stream_get_channels(&sinkb->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; if (sink_size < cd->sink_period_bytes) { - comp_err(dev, "selector_prepare(): sink buffer size %d is insufficient < %d", + comp_err(dev, "sink buffer size %d is insufficient < %d", sink_size, cd->sink_period_bytes); return -ENOMEM; } /* validate */ if (cd->sink_period_bytes == 0) { - comp_err(dev, "selector_prepare(): cd->sink_period_bytes = 0, dev->frames = %u", + comp_err(dev, "cd->sink_period_bytes = 0, dev->frames = %u", dev->frames); return -EINVAL; } if (cd->source_period_bytes == 0) { - comp_err(dev, "selector_prepare(): cd->source_period_bytes = 0, dev->frames = %u", + comp_err(dev, "cd->source_period_bytes = 0, dev->frames = %u", dev->frames); return -EINVAL; } cd->sel_func = sel_get_processing_function(mod); if (!cd->sel_func) { - comp_err(dev, "selector_prepare(): invalid cd->sel_func, cd->source_format = %u, cd->sink_format = %u, cd->out_channels_count = %u", + comp_err(dev, "invalid cd->sel_func, cd->source_format = %u, cd->sink_format = %u, cd->out_channels_count = %u", cd->source_format, cd->sink_format, cd->config.out_channels_count); return -EINVAL; } + if (cd->new_config) { + cd->new_config = false; + return selector_find_coefficients(mod); + } + return 0; } @@ -893,12 +1133,14 @@ static int selector_reset(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "selector_reset()"); + comp_dbg(mod->dev, "entry"); cd->source_period_bytes = 0; cd->sink_period_bytes = 0; cd->sel_func = NULL; - + cd->num_configs = 0; + cd->passthrough = false; + cd->new_config = false; return 0; } @@ -913,9 +1155,6 @@ static const struct module_interface selector_interface = { .free = selector_free }; -DECLARE_MODULE_ADAPTER(selector_interface, selector4_uuid, selector_tr); -SOF_MODULE_INIT(selector, sys_comp_module_selector_interface_init); - #if CONFIG_COMP_SEL_MODULE /* modular: llext dynamic link */ @@ -923,16 +1162,17 @@ SOF_MODULE_INIT(selector, sys_comp_module_selector_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_SELECTOR 0x32, 0xFE, 0x92, 0xC1, 0x17, 0x1E, 0xC2, 0x4F, 0x58, 0x97, \ - 0xC7, 0xF3, 0x54, 0x2E, 0x98, 0x0A - -SOF_LLEXT_MOD_ENTRY(selector, &selector_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("MICSEL", selector_llext_entry, 1, UUID_SELECTOR, 8); + SOF_LLEXT_MODULE_MANIFEST("MICSEL", &selector_interface, 1, SOF_REG_UUID(selector4), 8); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(selector_tr, SOF_UUID(selector4_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(selector_interface, selector4_uuid, selector_tr); +SOF_MODULE_INIT(selector, sys_comp_module_selector_interface_init); + #endif #endif diff --git a/src/audio/selector/selector.toml b/src/audio/selector/selector.toml index d3fc2784a674..3c984a00fd45 100644 --- a/src/audio/selector/selector.toml +++ b/src/audio/selector/selector.toml @@ -4,7 +4,7 @@ [[module.entry]] name = "MICSEL" - uuid = "32FE92C1-1E17-4FC2-9758-C7F3542E980A" + uuid = UUIDREG_STR_SELECTOR4 affinity_mask = "0x1" instance_count = "8" domain_types = "0" @@ -22,15 +22,40 @@ 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] -#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_PANTHERLAKE) - 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] +#elif CONFIG_LUNARLAKE + mod_cfg = [0, 0, 0, 0, 216, 2338000, 384, 192, 0, 2338, 0, + 1, 0, 0, 0, 216, 3634000, 384, 384, 0, 3634, 0, + 2, 0, 0, 0, 216, 4524000, 576, 384, 0, 4524, 0, + 3, 0, 0, 0, 216, 4786000, 768, 384, 0, 4786, 0, + 4, 0, 0, 0, 216, 2914000, 768, 192, 0, 2914, 0, + 5, 0, 0, 0, 216, 3372000, 960, 192, 0, 3372, 0, + 6, 0, 0, 0, 216, 3516000, 1152, 192, 0, 3516, 0, + 7, 0, 0, 0, 216, 4066000, 1536, 192, 0, 4066, 0, + 8, 0, 0, 0, 216, 3058000, 192, 384, 0, 3058, 0, + 9, 0, 0, 0, 216, 5676000, 960, 384, 0, 5676, 0, + 10, 0, 0, 0, 216, 5964000, 1152, 384, 0, 5964, 0, + 11, 0, 0, 0, 216, 7090000, 1536, 384, 0, 7090, 0, + 12, 0, 0, 0, 216, 7090000, 192, 1152, 0, 7090, 0, + 13, 0, 0, 0, 216, 8818000, 384, 1152, 0, 8818, 0, + 14, 0, 0, 0, 216, 12274000, 768, 1152, 0, 12274, 0, + 15, 0, 0, 0, 216, 19186000, 1536, 1152, 0, 19186, 0] +#elif CONFIG_SOC_ACE30 || CONFIG_SOC_ACE40 + mod_cfg = [0, 0, 0, 0, 216, 2952000, 384, 192, 0, 2952, 0, + 1, 0, 0, 0, 216, 4720000, 384, 384, 0, 4720, 0, + 2, 0, 0, 0, 216, 5705000, 576, 384, 0, 5705, 0, + 3, 0, 0, 0, 216, 6640000, 768, 384, 0, 6640, 0, + 4, 0, 0, 0, 216, 3910000, 768, 192, 0, 3910, 0, + 5, 0, 0, 0, 216, 4421000, 960, 192, 0, 4421, 0, + 6, 0, 0, 0, 216, 4899000, 1152, 192, 0, 4899, 0, + 7, 0, 0, 0, 216, 5832000, 1536, 192, 0, 5832, 0, + 8, 0, 0, 0, 216, 3768000, 192, 384, 0, 3768, 0, + 9, 0, 0, 0, 216, 7625000, 960, 384, 0, 7625, 0, + 10, 0, 0, 0, 216, 8595000, 1152, 384, 0, 8595, 0, + 11, 0, 0, 0, 216, 10488000, 1536, 384, 0, 10488, 0, + 12, 0, 0, 0, 216, 8952000, 192, 1152, 0, 8952, 0, + 13, 0, 0, 0, 216, 11832000, 384, 1152, 0, 11832, 0, + 14, 0, 0, 0, 216, 17592000, 768, 1152, 0, 17592, 0, + 15, 0, 0, 0, 216, 30172000, 1536, 1152, 0, 30172, 0] #endif index = __COUNTER__ diff --git a/src/audio/selector/selector_generic.c b/src/audio/selector/selector_generic.c index 923277ec3f46..5b4d8d8f5edd 100644 --- a/src/audio/selector/selector_generic.c +++ b/src/audio/selector/selector_generic.c @@ -12,6 +12,7 @@ #include <sof/audio/buffer.h> #include <sof/audio/component.h> +#include <sof/audio/format.h> #include <sof/audio/selector.h> #include <sof/common.h> #include <ipc/stream.h> @@ -191,7 +192,7 @@ static void process_frame_s16le(int16_t dst[], int dst_channels, accum += (int32_t)src[j] * (int32_t)coeffs_config->coeffs[i][j]; /* shift out 10 LSbits with rounding to get 16-bit result */ - dst[i] = (int16_t)((accum + (1 << 9)) >> 10); + dst[i] = sat_int16((accum + (1 << 9)) >> 10); } } @@ -240,7 +241,80 @@ static void sel_s16le(struct processing_module *mod, struct input_stream_buffer } #endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE +#if CONFIG_FORMAT_S24LE +/** + * \brief Mixing routine for 24-bit, m channel input x n channel output single frame. + * \param[out] dst Sink buffer. + * \param[in] dst_channels Number of sink channels. + * \param[in] src Source data. + * \param[in] src_channels Number of source channels. + * \param[in] coeffs_config IPC4 micsel config with Q10 coefficients. + */ +static void process_frame_s24le(int32_t dst[], int dst_channels, + int32_t src[], int src_channels, + struct ipc4_selector_coeffs_config *coeffs_config) +{ + int64_t accum; + int i, j; + + for (i = 0; i < dst_channels; i++) { + accum = 0; + for (j = 0; j < src_channels; j++) + accum += (int64_t)src[j] * (int64_t)coeffs_config->coeffs[i][j]; + + /* accum is Q1.23 * Q6.10 --> Q7.33, shift right by 10 and + * saturate to get Q1.23. + */ + dst[i] = sat_int24((accum + (1 << 9)) >> 10); + } +} + +/** + * \brief Channel selection for 24-bit, m channel input x n channel output data format. + * \param[in] mod Selector base module device. + * \param[in,out] bsource Source buffer. + * \param[in,out] bsink Sink buffer. + * \param[in] frames Number of frames to process. + */ +static void sel_s24le(struct processing_module *mod, struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames) +{ + struct comp_data *cd = module_get_private_data(mod); + 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; + int i; + int n; + int processed = 0; + int source_frame_bytes = audio_stream_frame_bytes(source); + int sink_frame_bytes = audio_stream_frame_bytes(sink); + int n_chan_source = MIN(SEL_SOURCE_CHANNELS_MAX, audio_stream_get_channels(source)); + int n_chan_sink = MIN(SEL_SINK_CHANNELS_MAX, audio_stream_get_channels(sink)); + + while (processed < frames) { + n = frames - processed; + nmax = audio_stream_bytes_without_wrap(source, src) / source_frame_bytes; + n = MIN(n, nmax); + nmax = audio_stream_bytes_without_wrap(sink, dest) / sink_frame_bytes; + n = MIN(n, nmax); + for (i = 0; i < n; i++) { + process_frame_s24le(dest, n_chan_sink, src, n_chan_source, + &cd->coeffs_config); + src += audio_stream_get_channels(source); + dest += audio_stream_get_channels(sink); + } + src = audio_stream_wrap(source, src); + dest = audio_stream_wrap(sink, dest); + processed += n; + } + + module_update_buffer_position(bsource, bsink, frames); +} +#endif /* CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S32LE /** * \brief Mixing routine for 32-bit, m channel input x n channel output single frame. * \param[out] dst Sink buffer. @@ -262,7 +336,7 @@ static void process_frame_s32le(int32_t dst[], int dst_channels, accum += (int64_t)src[j] * (int64_t)coeffs_config->coeffs[i][j]; /* shift out 10 LSbits with rounding to get 32-bit result */ - dst[i] = (int32_t)((accum + (1 << 9)) >> 10); + dst[i] = sat_int32((accum + (1 << 9)) >> 10); } } @@ -309,7 +383,7 @@ static void sel_s32le(struct processing_module *mod, struct input_stream_buffer module_update_buffer_position(bsource, bsink, frames); } -#endif /* CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE */ +#endif /* CONFIG_FORMAT_S32LE */ #endif const struct comp_func_map func_table[] = { @@ -334,7 +408,7 @@ const struct comp_func_map func_table[] = { {SOF_IPC_FRAME_S16_LE, 0, sel_s16le}, #endif #if CONFIG_FORMAT_S24LE - {SOF_IPC_FRAME_S24_4LE, 0, sel_s32le}, + {SOF_IPC_FRAME_S24_4LE, 0, sel_s24le}, #endif #if CONFIG_FORMAT_S32LE {SOF_IPC_FRAME_S32_LE, 0, sel_s32le}, diff --git a/src/audio/selector/tune/sof_selector_blobs.m b/src/audio/selector/tune/sof_selector_blobs.m new file mode 100644 index 000000000000..1b370d4030de --- /dev/null +++ b/src/audio/selector/tune/sof_selector_blobs.m @@ -0,0 +1,261 @@ +% sof_selector_blobs - export configuration blobs for Selector +% +% This script is run without arguments. It exports a number of +% configuration blobs for selector/micsel component. The first +% category of blobs are for upmix and downmix between mono to +% 7.1 channel audio formats. +% +% The second category is for duplicating stereo to four channels +% for 2-way speaker crossover filter. +% + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2025-2026, Intel Corporation. + +function sof_selector_blobs() + + % See ITU-R BS.775-4 for mix coefficient values + sof_selector_paths(true); + + % Values of enum ipc4_channel_config + IPC4_CHANNEL_CONFIG_MONO = 0; + IPC4_CHANNEL_CONFIG_STEREO = 1; + IPC4_CHANNEL_CONFIG_QUATRO = 5; + IPC4_CHANNEL_CONFIG_5_POINT_1 = 8; + IPC4_CHANNEL_CONFIG_7_POINT_1 = 12; + + % Matrix for 1:1 pass-through + sel.ch_count = [8 8]; % Number of channels + sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_7_POINT_1]; + sel.coeffs = diag(ones(8, 1)); + passthrough_pack8 = write_blob(sel, "passthrough"); + + % Stereo to mono downmix + sel.ch_count = [2 1]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_MONO]; + sel.coeffs = zeros(8,8); + sel.coeffs(1, 1) = 0.7071; + sel.coeffs(1, 2) = 0.7071; + stereo_to_mono_pack8 = write_blob(sel, "downmix_stereo_to_mono"); + + % 5.1 to stereo downmix + sel.ch_count = [6 2]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_5_POINT_1 IPC4_CHANNEL_CONFIG_STEREO]; + fl = 1; fr = 2; fc = 3; lfe = 4; sl = 5; sr = 6; + m = zeros(8,8); + m(1, fl) = 1.0000; m(1, fr) = 0.0000; m(1, fc) = 0.7071; m(1, sl) = 0.7071; m(1, sr) = 0.0000; + m(2, fl) = 0.0000; m(2, fr) = 1.0000; m(2, fc) = 0.7071; m(2, sl) = 0.0000; m(2, sr) = 0.7071; + sel.coeffs = m; + sel.coeffs(1, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to left + sel.coeffs(2, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to right + sixch_to_stereo_pack8 = write_blob(sel, "downmix_51_to_stereo_with_lfe"); + + % 5.1 to mono downmix + sel.ch_count = [6 1]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_5_POINT_1 IPC4_CHANNEL_CONFIG_MONO]; + fl = 1; fr = 2; fc = 3; lfe = 4; sl = 5; sr = 6; + m = zeros(8,8); + m(1, fl) = 0.7071; m(1, fr) = 0.7071; m(1, fc) = 1.0000; m(1, sl) = 0.5000; m(1, sr) = 0.5000; + sel.coeffs = m; + sel.coeffs(1, lfe) = 10^(+10/20); + sixch_to_mono_pack8 = write_blob(sel, "downmix_51_to_mono_with_lfe"); + + % 7.1 to 5.1 downmix + sel.ch_count = [8 6]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_5_POINT_1]; + fl8 = 1; fr8 = 2; fc8 = 3; lfe8 = 4; bl8 = 5; br8 = 6; sl8 = 7; sr8 = 8; + fl6 = 1; fr6 = 2; fc6 = 3; lfe6 = 4; sl6 = 5; sr6 = 6; + m = zeros(8,8); + m(fl6, fl8) = 1; + m(fr6, fr8) = 1; + m(fc6, fc8) = 1; + m(sl6, sl8) = 1; + m(sr6, sr8) = 1; + m(sl6, bl8) = 1; + m(sr6, br8) = 1; + m(lfe6, lfe8) = 1; + sel.coeffs = m; + eightch_to_sixch_pack8 = write_blob(sel, "downmix_71_to_51"); + + % 7.1 to stereo downmix + sel.ch_count = [8 2]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_STEREO]; + fl = 1; fr = 2; fc = 3; lfe = 4; bl = 5; br = 6; sl = 7; sr = 8; + m = zeros(8,8); + m(1, fl) = 1.0000; m(1, fr) = 0.0000; m(1, fc) = 0.7071; m(1, sl) = 0.7071; m(1, sr) = 0.0000; m(1, bl) = 0.7071; m(1, br) = 0.0000; + m(2, fl) = 0.0000; m(2, fr) = 1.0000; m(2, fc) = 0.7071; m(2, sl) = 0.0000; m(2, sr) = 0.7071; m(2, bl) = 0.0000; m(2, br) = 0.7071; + sel.coeffs = m; + sel.coeffs(1, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to left + sel.coeffs(2, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to right + eightch_to_stereo_pack8 = write_blob(sel, "downmix_71_to_stereo_with_lfe"); + + % 7.1 to mono downmix + sel.ch_count = [8 1]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_MONO]; + fl = 1; fc = 3; fr = 2; sr = 8; br = 6; bl = 5; sl = 7; lfe = 4; + m = zeros(8,8); + m(1, fl) = 0.7071; m(1, fr) = 0.7071; m(1, fc) = 1.0000; m(1, sl) = 0.5000; m(1, sr) = 0.5000; m(1, bl) = 0.5000; m(1, br) = 0.5000; + sel.coeffs = m; + m(1, lfe) = 10^(+19/20); % +10 dB + eightch_to_mono_pack8 = write_blob(sel, "downmix_71_to_mono_with_lfe"); + + % mono to stereo upmix + sel.ch_count = [1 2]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_STEREO]; + sel.coeffs = zeros(8,8); + sel.coeffs(1, 1) = 10^(-3/20); + sel.coeffs(2, 1) = 10^(-3/20); + mono_to_stereo_pack8 = write_blob(sel, "upmix_mono_to_stereo"); + + % mono to 5.1 / 7.1 upmix + sel.ch_count = [1 6]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_5_POINT_1]; + fc = 3; + sel.coeffs = zeros(8,8); + sel.coeffs(fc, 1) = 1; + mono_to_sixch_pack8 = write_blob(sel, "upmix_mono_to_51"); + sel.ch_count = [1 8]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_7_POINT_1]; + mono_to_eightch_pack8 = write_blob(sel, "upmix_mono_to_71"); + + % stereo to 5.1 / 7.1 upmix + sel.ch_count = [2 6]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_5_POINT_1]; + fl = 1; fr = 2; + sel.coeffs = zeros(8,8); + sel.coeffs(fl, 1) = 1; + sel.coeffs(fr, 2) = 1; + stereo_to_sixch_pack8 = write_blob(sel, "upmix_stereo_to_51"); + sel.ch_count = [2 8]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_7_POINT_1]; + stereo_to_eightch_pack8 = write_blob(sel, "upmix_stereo_to_71"); + + % For blob format with multiple up/down-mix profiles, intended + % for playback decoder offload conversions. + multi_pack8 = [passthrough_pack8 mono_to_stereo_pack8 sixch_to_stereo_pack8 eightch_to_stereo_pack8]; + write_8bit_packed(multi_pack8, 'stereo_endpoint_playback_updownmix'); + + % Stereo to L,L,R,R + sel.ch_count = [2 4]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO]; + sel.coeffs = [ 1 0 0 0 0 0 0 0 ; ... + 1 0 0 0 0 0 0 0 ; ... + 0 1 0 0 0 0 0 0 ; ... + 0 1 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ]; + write_blob(sel, "xover_selector_lr_to_llrr"); + + % Stereo to R,R,L,L + sel.ch_count = [2 4]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO]; + sel.coeffs = [ 0 1 0 0 0 0 0 0 ; ... + 0 1 0 0 0 0 0 0 ; ... + 1 0 0 0 0 0 0 0 ; ... + 1 0 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ]; + write_blob(sel, "xover_selector_lr_to_rrll"); + + % Stereo to L,R,L,R + sel.ch_count = [2 4]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO]; + sel.coeffs = [ 1 0 0 0 0 0 0 0 ; ... + 0 1 0 0 0 0 0 0 ; ... + 1 0 0 0 0 0 0 0 ; ... + 0 1 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ; ... + 0 0 0 0 0 0 0 0 ]; + write_blob(sel, "xover_selector_lr_to_lrlr"); + + sof_selector_paths(false); +end + +function pack8 = write_blob(sel, blobname) + pack8 = pack_selector_config(sel); + pack8_copy = pack8; + pack8_copy(1:4) = uint8([0 0 0 0]); + write_8bit_packed(pack8_copy, blobname); +end + +function write_8bit_packed(pack8, blobname) + blob8 = sof_selector_build_blob(pack8); + str_config = "selector_config"; + str_exported = "Exported with script sof_selector_blobs.m"; + str_howto = "cd tools/tune/selector; octave sof_selector_blobs.m"; + sof_tools = '../../../../tools'; + sof_tplg = fullfile(sof_tools, 'topology'); + sof_tplg_selector = fullfile(sof_tplg, 'topology2/include/components/micsel'); + tplg2_fn = sprintf("%s/%s.conf", sof_tplg_selector, blobname); + sof_check_create_dir(tplg2_fn); + sof_tplg2_write(tplg2_fn, blob8, str_config, str_exported, str_howto); +end + +function pack8 = pack_selector_config(sel) + + sum_coefs = sum(sel.coeffs, 2)'; + max_sum_coef = max(sum_coefs); + if max_sum_coef > 1 + scale = 1 / max_sum_coef; + else + scale = 1; + end + + sel.coeffs = scale .* sel.coeffs'; + coeffs_vec = reshape(sel.coeffs, 1, []); % convert to row vector + coeffs_q10 = int16(round(coeffs_vec .* 1024)); % Q6.10 + pack8 = uint8(zeros(1, 2 * length(coeffs_q10) + 4)); + + % header + j = 1; + pack8(j:j + 1) = uint8(sel.ch_count); + j = j + 2; + pack8(j:j + 1) = uint8(sel.ch_config); + j = j + 2; + + % coeffs matrix + for i = 1:length(coeffs_q10) + pack8(j:j+1) = int16_to_byte(coeffs_q10(i)); + j = j + 2; + end + + end + +function sof_selector_paths(enable) + + common = '../../../../tools/tune/common'; + if enable + addpath(common); + else + rmpath(common); + end +end + +function blob8 = sof_selector_build_blob(pack8) + + blob_type = 0; + blob_param_id = 0; % IPC4_SELECTOR_COEFFS_CONFIG_ID + data_size = length(pack8); + ipc_ver = 4; + [abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver, blob_type, blob_param_id); + blob_size = data_size + abi_size; + blob8 = uint8(zeros(1, blob_size)); + blob8(1:abi_size) = abi_bytes; + j = abi_size + 1; + + blob8(j:j+data_size-1) = pack8; +end + +function bytes = int16_to_byte(word) + sh = [0 -8]; + bytes = uint8(zeros(1,2)); + bytes(1) = bitand(bitshift(word, sh(1)), 255); + bytes(2) = bitand(bitshift(word, sh(2)), 255); +end diff --git a/src/audio/sink_source_utils.c b/src/audio/sink_source_utils.c index cc75c3b848d3..1fb86df386c2 100644 --- a/src/audio/sink_source_utils.c +++ b/src/audio/sink_source_utils.c @@ -73,3 +73,63 @@ int source_to_sink_copy(struct sof_source *source, return 0; } EXPORT_SYMBOL(source_to_sink_copy); + +int sink_fill_with_silence(struct sof_sink *sink, size_t size) +{ + uint8_t *dst_ptr; + uint8_t *dst_begin; + uint8_t *dst_end; + size_t dst_size; + int ret; + + if (!size) + return 0; + if (size > sink_get_free_size(sink)) + return -ENOSPC; + + ret = sink_get_buffer(sink, size, (void **)&dst_ptr, (void **)&dst_begin, &dst_size); + if (ret) + return ret; + + dst_end = dst_begin + dst_size; + while (size) { + uint32_t dst_to_buf_overlap = (uintptr_t)dst_end - (uintptr_t)dst_ptr; + uint32_t to_fill = MIN(dst_to_buf_overlap, size); + + ret = memset_s(dst_ptr, dst_to_buf_overlap, 0, to_fill); + assert(!ret); + + size -= to_fill; + dst_ptr += to_fill; + if (to_fill == dst_to_buf_overlap) + dst_ptr = dst_begin; + } + + sink_commit_buffer(sink, INT_MAX); + return 0; +} +EXPORT_SYMBOL(sink_fill_with_silence); + +int source_drop_data(struct sof_source *source, size_t size) +{ + uint8_t const *src_ptr; + uint8_t const *src_begin; + size_t src_size; + int ret; + + if (!size) + return 0; + if (size > source_get_data_available(source)) + return -EFBIG; + + ret = source_get_data(source, size, + (void const **)&src_ptr, + (void const **)&src_begin, + &src_size); + if (ret) + return ret; + + source_release_data(source, INT_MAX); + return 0; +} +EXPORT_SYMBOL(source_drop_data); diff --git a/src/audio/smart_amp/CMakeLists.txt b/src/audio/smart_amp/CMakeLists.txt index 387381057804..cb4eac564634 100644 --- a/src/audio/smart_amp/CMakeLists.txt +++ b/src/audio/smart_amp/CMakeLists.txt @@ -3,13 +3,23 @@ add_local_sources(sof smart_amp.c smart_amp_generic.c) if(CONFIG_MAXIM_DSM) -add_local_sources(sof smart_amp_maxim_dsm.c) -if(CONFIG_MAXIM_DSM_STUB) -add_local_sources(sof maxim_dsm_stub.c) + add_local_sources(sof smart_amp_maxim_dsm.c) + if(CONFIG_MAXIM_DSM_STUB) + add_local_sources(sof maxim_dsm_stub.c) + endif() else() -sof_add_static_library(dsm ${CMAKE_CURRENT_LIST_DIR}/lib/release/dsm_lib/libdsm.a) + add_local_sources(sof smart_amp_passthru.c) endif() -target_include_directories(sof PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/dsm_api/inc) -else() -add_local_sources(sof smart_amp_passthru.c) + +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + if(CONFIG_MAXIM_DSM) + if(NOT CONFIG_MAXIM_DSM_STUB) + zephyr_library_import(dsm ${CMAKE_CURRENT_LIST_DIR}/lib/release/dsm_lib/libdsm.a) + endif() + + zephyr_include_directories(CONFIG_MAXIM_DSM ${CMAKE_CURRENT_LIST_DIR}/include/dsm_api/inc/) + endif() + endif() diff --git a/src/audio/smart_amp/Kconfig b/src/audio/smart_amp/Kconfig index 6f947650d48d..51564f99eebc 100644 --- a/src/audio/smart_amp/Kconfig +++ b/src/audio/smart_amp/Kconfig @@ -2,8 +2,6 @@ config COMP_SMART_AMP bool "Smart Amplifier component" - select COMP_BLOB - default n help Select for Smart Amp component. This component protect the speaker from overheating and excursion violation. This consists of two parts @@ -50,7 +48,6 @@ endchoice config MAXIM_DSM_STUB bool "Maxim DSM solution" depends on MAXIM_DSM - default n help Select to build the Maxim DSM adapter with a stub library. This should only be used for CI and testing. diff --git a/src/audio/smart_amp/README.md b/src/audio/smart_amp/README.md new file mode 100644 index 000000000000..848d7abd7b15 --- /dev/null +++ b/src/audio/smart_amp/README.md @@ -0,0 +1,23 @@ +# Smart Amplifier Architecture + +This directory contains the Smart Amp Component. + +## Overview + +Uses predictive speaker models and real-time Current/Voltage (I/V) feedback to push speakers louder without causing thermal damage or physical over-excursion. + +## Architecture Diagram + +```mermaid +graph LR + In[Audio Input] --> Proc[Protection Algorithm] + FB[I/V Sense Input] --> Proc + Model[(Speaker Parameters)] --> Proc + Proc --> Out[Safe Audio Output] +``` + +## Configuration and Scripts + +- **Kconfig**: Enables the Smart Amplifier component (`COMP_SMART_AMP`). Features selectable architectures depending on third-party supply (defaults to `PASSTHRU_AMP`, or optionally `MAXIM_DSM` utilizing `libdsm.a`). Includes stubs for CI (`MAXIM_DSM_STUB`). +- **CMakeLists.txt**: Manages standard smart amp implementations (`smart_amp.c`, `smart_amp_generic.c`) and vendor-specific paths (`smart_amp_maxim_dsm.c`, `smart_amp_passthru.c`). Uses `zephyr_library_import` to link the Maxim SDK libraries. +- **Topology (.conf)**: Configured in `tools/topology/topology2/include/components/smart_amp.conf`, declaring a `smart_amp` effect component with UUID `1e:96:7a:16:e4:8a:ea:11:89:f1:00:0c:29:ce:16:35` (matching the test module) and hardcoding default configuration payloads into ALSA controls (`tlv_read`/`extctl`). diff --git a/src/audio/smart_amp/smart_amp.c b/src/audio/smart_amp/smart_amp.c index 1b72ef4a65f8..f82e3d2f7360 100644 --- a/src/audio/smart_amp/smart_amp.c +++ b/src/audio/smart_amp/smart_amp.c @@ -11,6 +11,7 @@ #include <sys/types.h> #include <rtos/init.h> +#include <sof/audio/module_adapter/module/generic.h> #include <sof/trace/trace.h> #include <sof/ipc/msg.h> #include <sof/ut.h> @@ -18,8 +19,6 @@ #include <sof/audio/ipc-config.h> #include <sof/audio/smart_amp/smart_amp.h> -static const struct comp_driver comp_smart_amp; - /* NOTE: this code builds itself with one of two distinct UUIDs * depending on configuration! */ @@ -29,25 +28,23 @@ SOF_DEFINE_REG_UUID(maxim_dsm); #else /* Passthrough */ SOF_DEFINE_REG_UUID(passthru_smart_amp); -#define UUID_SYM passthru_smart_amp +#define UUID_SYM passthru_smart_amp_uuid #endif -DECLARE_TR_CTX(smart_amp_comp_tr, SOF_UUID(UUID_SYM), - LOG_LEVEL_INFO); + +LOG_MODULE_REGISTER(smart_amp, CONFIG_SOF_LOG_LEVEL); /* Amp configuration & model calibration data for tuning/debug */ #define SOF_SMART_AMP_CONFIG 0 #define SOF_SMART_AMP_MODEL 1 struct smart_amp_data { + struct processing_module *mod; 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 */ - 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 */ @@ -69,33 +66,34 @@ struct smart_amp_data { static inline void smart_amp_free_mod_memories(struct smart_amp_data *sad) { /* sof -> mod feed-forward data re-mapping and format conversion */ - rfree(sad->ff_mod.buf.data); + mod_free(sad->mod, 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); + mod_free(sad->mod, sad->fb_mod.buf.data); sad->fb_mod.buf.data = NULL; /* mod -> sof processed data format conversion */ - rfree(sad->out_mod.buf.data); + mod_free(sad->mod, 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); + mod_free(sad->mod, 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); + mod_free(sad->mod, 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); + mod_free(sad->mod, sad->mod_mems[MOD_MEMBLK_PARAM].data); sad->mod_mems[MOD_MEMBLK_PARAM].data = NULL; /* inner model data struct */ - rfree(sad->mod_data); + mod_free(sad->mod, sad->mod_data); sad->mod_data = NULL; } -static inline int smart_amp_buf_alloc(struct smart_amp_buf *buf, size_t size) +static inline int smart_amp_buf_alloc(struct processing_module *mod, + struct smart_amp_buf *buf, size_t size) { - buf->data = rballoc(0, SOF_MEM_CAPS_RAM, size); + buf->data = mod_alloc(mod, size); if (!buf->data) return -ENOMEM; buf->size = size; @@ -105,12 +103,12 @@ static inline int smart_amp_buf_alloc(struct smart_amp_buf *buf, size_t 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; + struct smart_amp_mod_data_base *smod = sad->mod_data; int ret; size_t size; /* query the required size from inner model. */ - ret = mod->mod_ops->query_memblk_size(mod, blk); + ret = smod->mod_ops->query_memblk_size(smod, blk); if (ret < 0) goto error; @@ -120,12 +118,12 @@ static ssize_t smart_amp_alloc_mod_memblk(struct smart_amp_data *sad, /* allocate the memory block when returned size > 0. */ size = ret; - ret = smart_amp_buf_alloc(&sad->mod_mems[blk], size); + ret = smart_amp_buf_alloc(sad->mod, &sad->mod_mems[blk], size); if (ret < 0) goto error; /* provide the memory block information to inner model. */ - ret = mod->mod_ops->set_memblk(mod, blk, &sad->mod_mems[blk]); + ret = smod->mod_ops->set_memblk(smod, blk, &sad->mod_mems[blk]); if (ret < 0) goto error; @@ -145,26 +143,26 @@ static int smart_amp_alloc_data_buffers(struct comp_dev *dev, /* 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); + ret = smart_amp_buf_alloc(sad->mod, &sad->ff_mod.buf, size); if (ret < 0) goto error; total_size = size; /* 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); + ret = smart_amp_buf_alloc(sad->mod, &sad->fb_mod.buf, size); if (ret < 0) goto error; total_size += size; /* 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); + ret = smart_amp_buf_alloc(sad->mod, &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); + comp_dbg(dev, "used data buffer %zu bytes", total_size); return 0; error: @@ -172,103 +170,89 @@ static int smart_amp_alloc_data_buffers(struct comp_dev *dev, return ret; } -static struct comp_dev *smart_amp_new(const struct comp_driver *drv, - const struct comp_ipc_config *config, - const void *spec) +static int smart_amp_init(struct processing_module *mod) { - struct comp_dev *dev; - const struct ipc_config_process *ipc_sa = spec; + struct comp_dev *dev = mod->dev; + struct module_config *mcfg = &mod->priv.cfg; struct smart_amp_data *sad; struct sof_smart_amp_config *cfg; size_t bs; int ret; - dev = comp_alloc(drv, sizeof(*dev)); - if (!dev) - return NULL; - - dev->ipc_config = *config; - - sad = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*sad)); - if (!sad) { - rfree(dev); - return NULL; - } - - comp_set_drvdata(dev, sad); - sad->ipc_config = *ipc_sa; + /* Allocate smart_amp_data using module API */ + sad = mod_zalloc(mod, sizeof(*sad)); + if (!sad) + return -ENOMEM; - cfg = (struct sof_smart_amp_config *)ipc_sa->data; - bs = ipc_sa->size; + mod->priv.private = sad; + sad->mod = mod; - if (bs > 0 && bs < sizeof(struct sof_smart_amp_config)) { - comp_err(dev, "smart_amp_new(): failed to apply config"); - goto error; + /* Copy config blob if present */ + if (mcfg->avail && mcfg->init_data && mcfg->size >= sizeof(struct sof_smart_amp_config)) { + cfg = (struct sof_smart_amp_config *)mcfg->init_data; + bs = mcfg->size; + memcpy_s(&sad->config, sizeof(struct sof_smart_amp_config), cfg, bs); } - memcpy_s(&sad->config, sizeof(struct sof_smart_amp_config), cfg, bs); - /* 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"); + comp_err(dev, "failed to allocate inner model data"); + ret = -ENOMEM; goto error; } /* 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); + comp_err(dev, "failed to allocate data buffers, ret:%d", ret); goto error; } /* (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); + comp_err(dev, "failed to allocate mod private, ret:%d", ret); goto error; } - comp_dbg(dev, "smart_amp_new(): used mod private buffer %d bytes", ret); + comp_dbg(dev, "used mod private buffer %d bytes", ret); /* 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); + comp_err(dev, "failed to init inner model, ret:%d", ret); goto error; } /* (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); + comp_err(dev, "failed to allocate mod buffer, ret:%d", ret); goto error; } - comp_dbg(dev, "smart_amp_new(): used mod data buffer %d bytes", ret); + comp_dbg(dev, "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); + comp_err(dev, "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; + comp_dbg(dev, "used mod config buffer %d bytes", ret); + return 0; error: smart_amp_free_mod_memories(sad); - rfree(sad); - rfree(dev); - return NULL; + mod_free(mod, sad); + return ret; } -static int smart_amp_set_config(struct comp_dev *dev, +static int smart_amp_set_config(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata) { - struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_data *sad = module_get_private_data(mod); struct sof_smart_amp_config *cfg; + struct comp_dev *dev = mod->dev; size_t bs; /* Copy new config, find size from header */ @@ -276,11 +260,11 @@ static int smart_amp_set_config(struct comp_dev *dev, ASSUME_ALIGNED(&cdata->data->data, sizeof(uint32_t)); bs = cfg->size; - comp_dbg(dev, "smart_amp_set_config(), actual blob size = %zu, expected blob size = %zu", + comp_dbg(dev, "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 = %zu, expected blob size = %zu", + comp_err(dev, "invalid blob size, actual blob size = %zu, expected blob size = %zu", bs, sizeof(struct sof_smart_amp_config)); return -EINVAL; } @@ -291,17 +275,18 @@ static int smart_amp_set_config(struct comp_dev *dev, return 0; } -static int smart_amp_get_config(struct comp_dev *dev, +static int smart_amp_get_config(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata, int size) { - struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_data *sad = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; size_t bs; int ret = 0; /* Copy back to user space */ bs = sad->config.size; - comp_dbg(dev, "smart_amp_get_config(), actual blob size = %zu, expected blob size = %zu", + comp_dbg(dev, "actual blob size = %zu, expected blob size = %zu", bs, sizeof(struct sof_smart_amp_config)); if (bs == 0 || bs > size) @@ -316,108 +301,113 @@ static int smart_amp_get_config(struct comp_dev *dev, return ret; } -#if CONFIG_IPC_MAJOR_3 -static int smart_amp_ctrl_get_bin_data(struct comp_dev *dev, +static int smart_amp_ctrl_get_bin_data(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata, int size) { - struct smart_amp_data *sad = comp_get_drvdata(dev); - struct smart_amp_mod_data_base *mod; + struct smart_amp_data *sad = module_get_private_data(mod); + struct smart_amp_mod_data_base *smod; + struct comp_dev *dev = mod->dev; int ret = 0; assert(sad); - mod = sad->mod_data; + smod = sad->mod_data; switch (cdata->data->type) { case SOF_SMART_AMP_CONFIG: - ret = smart_amp_get_config(dev, cdata, size); + ret = smart_amp_get_config(mod, cdata, size); break; case SOF_SMART_AMP_MODEL: - ret = mod->mod_ops->get_config(mod, cdata, size); + ret = smod->mod_ops->get_config(smod, cdata, size); if (ret < 0) { - comp_err(dev, "smart_amp_ctrl_get_bin_data(): failed to read inner model!"); + comp_err(dev, "failed to read inner model!"); return ret; } break; default: - comp_err(dev, "smart_amp_ctrl_get_bin_data(): unknown binary data type"); + comp_err(dev, "unknown binary data type"); break; } return ret; } -static int smart_amp_ctrl_get_data(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata, int size) +static int smart_amp_get_configuration(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) { - int ret = 0; + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + struct comp_dev *dev = mod->dev; - comp_dbg(dev, "smart_amp_ctrl_get_data() size: %d", size); + comp_dbg(dev, "config_id %u size: %zu", config_id, fragment_size); +#if CONFIG_IPC_MAJOR_3 switch (cdata->cmd) { case SOF_CTRL_CMD_BINARY: - ret = smart_amp_ctrl_get_bin_data(dev, cdata, size); - break; + return smart_amp_ctrl_get_bin_data(mod, cdata, fragment_size); default: - comp_err(dev, "smart_amp_ctrl_get_data(): invalid cdata->cmd"); - return -EINVAL; + comp_err(dev, "invalid cdata->cmd"); } - - return ret; +#elif CONFIG_IPC_MAJOR_4 + return smart_amp_ctrl_get_bin_data(mod, cdata, fragment_size); +#endif + return -EINVAL; } -static int smart_amp_ctrl_set_bin_data(struct comp_dev *dev, +static int smart_amp_ctrl_set_bin_data(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata) { - struct smart_amp_data *sad = comp_get_drvdata(dev); - struct smart_amp_mod_data_base *mod; + struct smart_amp_data *sad = module_get_private_data(mod); + struct smart_amp_mod_data_base *smod; + struct comp_dev *dev = mod->dev; int ret = 0; assert(sad); - mod = sad->mod_data; + smod = sad->mod_data; if (dev->state < COMP_STATE_READY) { - comp_err(dev, "smart_amp_ctrl_set_bin_data(): driver in init!"); + comp_err(dev, "driver in init!"); return -EBUSY; } switch (cdata->data->type) { case SOF_SMART_AMP_CONFIG: - ret = smart_amp_set_config(dev, cdata); + ret = smart_amp_set_config(mod, cdata); break; case SOF_SMART_AMP_MODEL: - ret = mod->mod_ops->set_config(mod, cdata); + ret = smod->mod_ops->set_config(smod, cdata); if (ret < 0) { - comp_err(dev, "smart_amp_ctrl_set_bin_data(): failed to write inner model!"); + comp_err(dev, "failed to write inner model!"); return ret; } break; default: - comp_err(dev, "smart_amp_ctrl_set_bin_data(): unknown binary data type"); + comp_err(dev, "unknown binary data type"); break; } return ret; } -static int smart_amp_ctrl_set_data(struct comp_dev *dev, +static int smart_amp_ctrl_set_data(struct processing_module *mod, struct sof_ipc_ctrl_data *cdata) { + struct comp_dev *dev = mod->dev; int ret = 0; /* Check version from ABI header */ if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { - comp_err(dev, "smart_amp_ctrl_set_data(): invalid version"); + comp_err(dev, "invalid version"); return -EINVAL; } switch (cdata->cmd) { case SOF_CTRL_CMD_BINARY: - comp_dbg(dev, "smart_amp_ctrl_set_data(), SOF_CTRL_CMD_BINARY"); - ret = smart_amp_ctrl_set_bin_data(dev, cdata); + comp_dbg(dev, "SOF_CTRL_CMD_BINARY"); + ret = smart_amp_ctrl_set_bin_data(mod, cdata); break; default: - comp_err(dev, "smart_amp_ctrl_set_data(): invalid cdata->cmd"); + comp_err(dev, "invalid cdata->cmd"); ret = -EINVAL; break; } @@ -425,77 +415,74 @@ static int smart_amp_ctrl_set_data(struct comp_dev *dev, return ret; } -/* used to pass standard and bespoke commands (with data) to component */ -static int smart_amp_cmd(struct comp_dev *dev, int cmd, void *data, - int max_data_size) +static int smart_amp_set_configuration(struct processing_module *mod, + uint32_t config_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, + const uint8_t *fragment, size_t fragment_size, + uint8_t *response, size_t response_size) { - struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4); + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + struct comp_dev *dev = mod->dev; - comp_dbg(dev, "smart_amp_cmd(): cmd: %d", cmd); + comp_info(dev, "config_id %u size %zu", config_id, response_size); - switch (cmd) { - case COMP_CMD_SET_DATA: - return smart_amp_ctrl_set_data(dev, cdata); - case COMP_CMD_GET_DATA: - return smart_amp_ctrl_get_data(dev, cdata, max_data_size); +#if CONFIG_IPC_MAJOR_3 + switch (cdata->cmd) { + case SOF_CTRL_CMD_BINARY: + comp_info(dev, "SOF_CTRL_CMD_BINARY"); + return smart_amp_ctrl_set_data(mod, cdata); default: - return -EINVAL; + comp_err(dev, "unknown cmd %d", cdata->cmd); } -} +#elif CONFIG_IPC_MAJOR_4 + return smart_amp_ctrl_set_data(mod, cdata); #endif + return -EINVAL; +} -static void smart_amp_free(struct comp_dev *dev) +static int smart_amp_free(struct processing_module *mod) { - struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_data *sad = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; - comp_dbg(dev, "smart_amp_free()"); + comp_dbg(dev, "entry"); + if (!sad) + return 0; smart_amp_free_mod_memories(sad); - rfree(sad); - sad = NULL; - rfree(dev); - dev = NULL; -} - -static int smart_amp_verify_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) -{ - int ret; - - comp_dbg(dev, "smart_amp_verify_params()"); - - ret = comp_verify_params(dev, BUFF_PARAMS_CHANNELS, params); - if (ret < 0) { - comp_err(dev, "volume_verify_params() error: comp_verify_params() failed."); - return ret; - } + mod_free(mod, sad); + mod->priv.private = NULL; return 0; } -static int smart_amp_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) +#if CONFIG_IPC_MAJOR_4 +static void smart_amp_ipc4_params(struct processing_module *mod) { - int err; + struct sof_ipc_stream_params *params = mod->stream_params; + struct comp_buffer *sinkb, *sourceb; + struct comp_dev *dev = mod->dev; - comp_dbg(dev, "smart_amp_params()"); + ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); + component_set_nearest_period_frames(dev, params->rate); - err = smart_amp_verify_params(dev, params); - if (err < 0) { - comp_err(dev, "smart_amp_params(): pcm params verification failed."); - return -EINVAL; - } + sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); + ipc4_update_buffer_format(sourceb, &mod->priv.cfg.base_cfg.audio_fmt); - return 0; + 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 /* CONFIG_IPC_MAJOR_4 */ -static int smart_amp_trigger(struct comp_dev *dev, int cmd) +static int smart_amp_trigger(struct processing_module *mod, int cmd) { - struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_data *sad = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; int ret = 0; - comp_dbg(dev, "smart_amp_trigger(), command = %u", cmd); + comp_dbg(dev, "command = %u", cmd); ret = comp_set_state(dev, cmd); @@ -516,34 +503,35 @@ static int smart_amp_trigger(struct comp_dev *dev, int cmd) return ret; } -static int smart_amp_ff_process(struct comp_dev *dev, +static int smart_amp_ff_process(struct processing_module *mod, 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; + struct smart_amp_data *sad = module_get_private_data(mod); + struct smart_amp_mod_data_base *smod = sad->mod_data; + struct comp_dev *dev = mod->dev; int 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."); + comp_warn(dev, "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); + comp_err(dev, "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); + ret = smod->mod_ops->ff_proc(smod, frames, &sad->ff_mod, &sad->out_mod); if (ret) { - comp_err(dev, "smart_amp_copy(): feed forward inner model process error"); + comp_err(dev, "feed forward inner model process error"); return ret; } @@ -552,43 +540,47 @@ static int smart_amp_ff_process(struct comp_dev *dev, return 0; } -static int smart_amp_fb_process(struct comp_dev *dev, +static int smart_amp_fb_process(struct processing_module *mod, const struct audio_stream *source, 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; + struct smart_amp_data *sad = module_get_private_data(mod); + struct smart_amp_mod_data_base *smod = sad->mod_data; + struct comp_dev *dev = mod->dev; int ret; sad->fb_mod.consumed = 0; if (frames == 0) { - comp_warn(dev, "smart_amp_copy(): feedback frame size zero warning."); + comp_warn(dev, "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); + comp_err(dev, "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); + ret = smod->mod_ops->fb_proc(smod, frames, &sad->fb_mod); if (ret) { - comp_err(dev, "smart_amp_copy(): feedback inner model process error"); + comp_err(dev, "feedback inner model process error"); return ret; } return 0; } -static int smart_amp_copy(struct comp_dev *dev) +static int smart_amp_process(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { - struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_data *sad = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; struct comp_buffer *source_buf = sad->source_buf; - struct comp_buffer *sink_buf = sad->sink_buf; + struct comp_buffer *sink_buf = comp_buffer_get_from_sink(sinks[0]); uint32_t avail_passthrough_frames; uint32_t avail_feedback_frames; uint32_t avail_frames; @@ -596,7 +588,7 @@ static int smart_amp_copy(struct comp_dev *dev) uint32_t sink_bytes; uint32_t feedback_bytes; - comp_dbg(dev, "smart_amp_copy()"); + comp_dbg(dev, "%d sources %d sinks", num_of_sources, num_of_sinks); /* available bytes and samples calculation */ avail_passthrough_frames = audio_stream_avail_frames(&source_buf->stream, @@ -618,16 +610,16 @@ 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 %u feedback frames (avail_passthrough_frames: %u)", + comp_dbg(dev, "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); - smart_amp_fb_process(dev, &feedback_buf->stream, + smart_amp_fb_process(mod, &feedback_buf->stream, avail_feedback_frames, sad->config.feedback_ch_map); - comp_dbg(dev, "smart_amp_copy(): consumed %u feedback frames", + comp_dbg(dev, "consumed %u feedback frames", sad->fb_mod.consumed); if (sad->fb_mod.consumed < avail_feedback_frames) { feedback_bytes = sad->fb_mod.consumed * @@ -642,10 +634,10 @@ static int smart_amp_copy(struct comp_dev *dev) source_bytes = avail_frames * audio_stream_frame_bytes(&source_buf->stream); buffer_stream_invalidate(source_buf, source_bytes); - smart_amp_ff_process(dev, &source_buf->stream, &sink_buf->stream, + smart_amp_ff_process(mod, &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)", + comp_dbg(dev, "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); @@ -660,26 +652,20 @@ static int smart_amp_copy(struct comp_dev *dev) return 0; } -static int smart_amp_reset(struct comp_dev *dev) +static int smart_amp_reset(struct processing_module *mod) { - struct smart_amp_data *sad = comp_get_drvdata(dev); - struct smart_amp_mod_data_base *mod = sad->mod_data; - int ret; + struct smart_amp_data *sad = module_get_private_data(mod); + struct smart_amp_mod_data_base *smod = sad->mod_data; + struct comp_dev *dev = mod->dev; - comp_dbg(dev, "smart_amp_reset()"); + comp_dbg(dev, "entry"); 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; + return smod->mod_ops->reset(smod); } /* supported formats: {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE} @@ -690,19 +676,20 @@ 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) +static int smart_amp_resolve_mod_fmt(struct processing_module *mod, uint32_t least_req_depth) { - struct smart_amp_data *sad = comp_get_drvdata(dev); - struct smart_amp_mod_data_base *mod = sad->mod_data; + struct smart_amp_data *sad = module_get_private_data(mod); + struct smart_amp_mod_data_base *smod = sad->mod_data; + struct comp_dev *dev = mod->dev; 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); + ret = smod->mod_ops->get_supported_fmts(smod, &mod_fmts, &num_mod_fmts); if (ret) { - comp_err(dev, "smart_amp_resolve_mod_fmt(): failed to get supported formats"); + comp_err(dev, "failed to get supported formats"); return ret; } @@ -710,12 +697,12 @@ static int smart_amp_resolve_mod_fmt(struct comp_dev *dev, uint32_t least_req_de 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", + comp_dbg(dev, "set mod format to %u", mod_fmts[i]); - ret = mod->mod_ops->set_fmt(mod, mod_fmts[i]); + ret = smod->mod_ops->set_fmt(smod, mod_fmts[i]); if (ret) { comp_err(dev, - "smart_amp_resolve_mod_fmt(): failed setting format %u", + "failed setting format %u", mod_fmts[i]); return ret; } @@ -724,36 +711,44 @@ static int smart_amp_resolve_mod_fmt(struct comp_dev *dev, uint32_t least_req_de } } - comp_err(dev, "smart_amp_resolve_mod_fmt(): failed to resolve the frame format for mod"); + comp_err(dev, "failed to resolve the frame format for mod"); return -EINVAL; } -static int smart_amp_prepare(struct comp_dev *dev) +static int smart_amp_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { - struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_data *sad = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; uint16_t ff_src_fmt, fb_src_fmt, resolved_mod_fmt; uint32_t least_req_depth; - uint32_t rate; - int ret; - - comp_dbg(dev, "smart_amp_prepare()"); - - ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); - if (ret < 0) - return ret; + int ret, i; - /* searching for stream and feedback source buffers */ - struct comp_buffer *source_buffer; + comp_dbg(dev, "%d sources %d sinks", num_of_sources, num_of_sinks); +#if CONFIG_IPC_MAJOR_4 + smart_amp_ipc4_params(mod); +#endif - comp_dev_for_each_producer(dev, source_buffer) { - if (source_buffer->source->ipc_config.type == SOF_COMP_DEMUX) - sad->feedback_buf = source_buffer; + /* In module API, state is managed by the framework, so no comp_set_state needed */ + for (i = 0; i < num_of_sources; i++) { + /* NOTE: This should not work in module based environment: + * sources[i]->bound_module->dev->ipc_config.type == SOF_COMP_DEMUX + * So let's check which one of the sources is from a capture stream. + * The code is not tested and may not work. + */ + if (sources[i]->bound_module->dev->direction == SOF_IPC_STREAM_CAPTURE) + sad->feedback_buf = comp_buffer_get_from_source(sources[i]); else - sad->source_buf = source_buffer; + sad->source_buf = comp_buffer_get_from_source(sources[i]); } /* sink buffer */ - sad->sink_buf = comp_dev_get_first_data_consumer(dev); + sad->sink_buf = comp_buffer_get_from_sink(sinks[0]); + if (!sad->sink_buf) { + comp_err(dev, "no sink buffer"); + return -ENOTCONN; + } /* get frame format and channels param of stream and feedback source */ ff_src_fmt = audio_stream_get_frm_fmt(&sad->source_buf->stream); @@ -774,14 +769,13 @@ static int smart_amp_prepare(struct comp_dev *dev) 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)); } /* 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); + ret = smart_amp_resolve_mod_fmt(mod, least_req_depth); if (ret < 0) return ret; @@ -794,47 +788,32 @@ static int smart_amp_prepare(struct comp_dev *dev) 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", + comp_dbg(dev, "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", + comp_dbg(dev, "output mod buffer channels:%u fmt_conv:%u -> %u", sad->out_mod.channels, sad->out_mod.frame_fmt, ff_src_fmt); 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", + comp_dbg(dev, "fb mod buffer channels:%u fmt_conv:%u -> %u", sad->fb_mod.channels, fb_src_fmt, sad->fb_mod.frame_fmt); } + return 0; } -static const struct comp_driver comp_smart_amp = { - .type = SOF_COMP_SMART_AMP, - .uid = SOF_RT_UUID(UUID_SYM), - .tctx = &smart_amp_comp_tr, - .ops = { - .create = smart_amp_new, - .free = smart_amp_free, - .params = smart_amp_params, - .prepare = smart_amp_prepare, -#if CONFIG_IPC_MAJOR_3 - .cmd = smart_amp_cmd, -#endif - .trigger = smart_amp_trigger, - .copy = smart_amp_copy, - .reset = smart_amp_reset, - }, -}; - -static SHARED_DATA struct comp_driver_info comp_smart_amp_info = { - .drv = &comp_smart_amp, +static struct module_interface smart_amp_interface = { + .init = smart_amp_init, + .prepare = smart_amp_prepare, + .process = smart_amp_process, + .set_configuration = smart_amp_set_configuration, + .get_configuration = smart_amp_get_configuration, + .reset = smart_amp_reset, + .free = smart_amp_free, + .trigger = smart_amp_trigger, }; -UT_STATIC void sys_comp_smart_amp_init(void) -{ - comp_register(platform_shared_get(&comp_smart_amp_info, - sizeof(comp_smart_amp_info))); -} - -DECLARE_MODULE(sys_comp_smart_amp_init); -SOF_MODULE_INIT(smart_amp, sys_comp_smart_amp_init); +DECLARE_TR_CTX(smart_amp_comp_tr, SOF_UUID(UUID_SYM), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(smart_amp_interface, UUID_SYM, smart_amp_comp_tr); +SOF_MODULE_INIT(smart_amp, sys_comp_module_smart_amp_interface_init); diff --git a/src/audio/smart_amp/smart_amp_generic.c b/src/audio/smart_amp/smart_amp_generic.c index 5f6a1698d16b..91223eb398bd 100644 --- a/src/audio/smart_amp/smart_amp_generic.c +++ b/src/audio/smart_amp/smart_amp_generic.c @@ -221,7 +221,6 @@ static void feed_s32_to_s24(const struct smart_amp_mod_stream *sink_mod, uint32_ const struct audio_stream __sparse_cache *sink) { int i; - 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; diff --git a/src/audio/smart_amp/smart_amp_maxim_dsm.c b/src/audio/smart_amp/smart_amp_maxim_dsm.c index e45620248dd4..c83a971d8175 100644 --- a/src/audio/smart_amp/smart_amp_maxim_dsm.c +++ b/src/audio/smart_amp/smart_amp_maxim_dsm.c @@ -20,6 +20,8 @@ #include <sof/audio/smart_amp/smart_amp.h> #include "dsm_api_public.h" +LOG_MODULE_DECLARE(smart_amp, CONFIG_SOF_LOG_LEVEL); + /* 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) @@ -319,7 +321,7 @@ static int maxim_dsm_get_param(struct smart_amp_mod_struct_t *hspk, * required size */ if (bs > size) { - comp_err(dev, "[DSM] maxim_dsm_get_param(): invalid size %d", bs); + comp_err(dev, "[DSM] invalid size %d", bs); return -EINVAL; } @@ -383,6 +385,13 @@ static int maxim_dsm_set_param(struct smart_amp_mod_struct_t *hspk, id = DSM_CH_MASK(param->param.id); ch = (param->param.id & DSM_CH1_BITMASK) ? 0 : 1; + /* id indexes the model database; reject values past its size */ + if (id >= hspk->param.max_param) { + comp_err(dev, "[DSM] invalid param id:%x max:%d", + id, hspk->param.max_param); + return -EINVAL; + } + /* 2nd channel has (hspk->param.max_param * DSM_PARAM_MAX) sized offset */ db[(id + ch * hspk->param.max_param) * DSM_PARAM_MAX + DSM_PARAM_VALUE] = param->param.value; @@ -392,7 +401,7 @@ static int maxim_dsm_set_param(struct smart_amp_mod_struct_t *hspk, */ retcode = dsm_api_set_params(hspk->dsmhandle, 1, value); if (retcode != DSM_API_OK) { - comp_err(dev, "[DSM] maxim_dsm_set_param() write failure. (id:%x, ret:%x)", + comp_err(dev, "[DSM] write failure. (id:%x, ret:%x)", id, retcode); return -EINVAL; } @@ -420,7 +429,7 @@ static int maxim_dsm_restore_param(struct smart_amp_mod_struct_t *hspk) retcode = dsm_api_set_params(hspk->dsmhandle, 1, value); if (retcode != DSM_API_OK) { - comp_err(dev, "[DSM] maxim_dsm_restore_param() write failure. (id:%x, ret:%x)", + comp_err(dev, "[DSM] write failure. (id:%x, ret:%x)", value[DSM_SET_ID_IDX], retcode); return -EINVAL; } @@ -838,7 +847,7 @@ struct smart_amp_mod_data_base *mod_data_create(const struct comp_dev *dev) { struct smart_amp_mod_struct_t *hspk; - hspk = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*hspk)); + hspk = rzalloc(SOF_MEM_FLAG_USER, sizeof(*hspk)); if (!hspk) return NULL; diff --git a/src/audio/smart_amp/smart_amp_passthru.c b/src/audio/smart_amp/smart_amp_passthru.c index dd5c2fe3d789..53084345d6d1 100644 --- a/src/audio/smart_amp/smart_amp_passthru.c +++ b/src/audio/smart_amp/smart_amp_passthru.c @@ -10,12 +10,13 @@ #include <sof/trace/trace.h> #include <user/trace.h> -#include <sof/bit.h> #include <sof/common.h> #include <stdint.h> #include <stdlib.h> #include <sof/audio/smart_amp/smart_amp.h> +LOG_MODULE_DECLARE(smart_amp, CONFIG_SOF_LOG_LEVEL); + /* self-declared inner model data struct */ struct passthru_mod_data { struct smart_amp_mod_data_base base; @@ -137,7 +138,7 @@ 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)); + mod = rzalloc(SOF_MEM_FLAG_USER, sizeof(*mod)); if (!mod) return NULL; diff --git a/src/audio/sound_dose/CMakeLists.txt b/src/audio/sound_dose/CMakeLists.txt new file mode 100644 index 000000000000..d6cd9c10b798 --- /dev/null +++ b/src/audio/sound_dose/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_COMP_SOUND_DOSE STREQUAL "m") + add_subdirectory(llext ${PROJECT_BINARY_DIR}/sound_dose_llext) + add_dependencies(app sound_dose) +else() + add_local_sources(sof sound_dose.c) + add_local_sources(sof sound_dose-generic.c) + add_local_sources(sof sound_dose-ipc4.c) +endif() diff --git a/src/audio/sound_dose/Kconfig b/src/audio/sound_dose/Kconfig new file mode 100644 index 000000000000..a15e9a2b724a --- /dev/null +++ b/src/audio/sound_dose/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config COMP_SOUND_DOSE + tristate "Sound Dose module" + default m if LIBRARY_DEFAULT_MODULAR + depends on COMP_MODULE_ADAPTER + depends on IPC_MAJOR_4 + select MATH_IIR + select MATH_IIR_DF1 + select MATH_EXP + help + Select this for Sound Dose SOF module. The purpose is + to calculate for audio playback MEL values (momentary + sound exposure level) to provide to user space the data + to compute the sound dose CSD as defined in EN 50332-3. diff --git a/src/audio/sound_dose/README.md b/src/audio/sound_dose/README.md new file mode 100644 index 000000000000..0436da7b886d --- /dev/null +++ b/src/audio/sound_dose/README.md @@ -0,0 +1,14 @@ +# Sound Dose Architecture + +This directory contains the Sound Dose component. + +## Overview + +Monitors the acoustic energy output to headphones over time, ensuring it complies with regulations governing maximum cumulative sound exposure (to protect user hearing). + +## Configuration and Scripts + +- **Kconfig**: Dictates the Sound Dose component (`COMP_SOUND_DOSE`) with prerequisites on `IPC_MAJOR_4` and `COMP_MODULE_ADAPTER`, plus mathematical modules (`MATH_EXP`, `MATH_IIR`). +- **CMakeLists.txt**: Compiles generic operations (`sound_dose-generic.c`, `sound_dose.c`) alongside their IPC wrappers (`sound_dose-ipc4.c`), offering full `llext` enablement. +- **sound_dose.toml**: Contains topology descriptors, declaring UUID `UUIDREG_STR_SOUND_DOSE` and standard memory allocation bounds. +- **Topology (.conf)**: Extracted from `tools/topology/topology2/include/components/sound_dose.conf`, configuring a `sound_dose` widget of type `effect` (UUID `7c:9d:3f:a4:75:ea:d5:44:94:2d:96:79:91:a3:38:09`). diff --git a/src/audio/sound_dose/llext/CMakeLists.txt b/src/audio/sound_dose/llext/CMakeLists.txt new file mode 100644 index 000000000000..705280b08648 --- /dev/null +++ b/src/audio/sound_dose/llext/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +sof_llext_build("sound_dose" + SOURCES ../sound_dose.c + ../sound_dose-generic.c + ../sound_dose-ipc4.c + LIB openmodules +) diff --git a/src/audio/sound_dose/llext/llext.toml.h b/src/audio/sound_dose/llext/llext.toml.h new file mode 100644 index 000000000000..b5bc25562bd2 --- /dev/null +++ b/src/audio/sound_dose/llext/llext.toml.h @@ -0,0 +1,6 @@ +#include <tools/rimage/config/platform.toml> +#define LOAD_TYPE "2" +#include "../sound_dose.toml" + +[module] +count = __COUNTER__ diff --git a/src/audio/sound_dose/sound_dose-generic.c b/src/audio/sound_dose/sound_dose-generic.c new file mode 100644 index 000000000000..fb5f63fc844a --- /dev/null +++ b/src/audio/sound_dose/sound_dose-generic.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/source_api.h> +#include <sof/math/log.h> +#include <sof/math/iir_df1.h> +#include <user/eq.h> +#include <stdbool.h> +#include <stdint.h> + +#include "sound_dose.h" + +LOG_MODULE_DECLARE(sound_dose, CONFIG_SOF_LOG_LEVEL); + +static void sound_dose_calculate_mel(const struct processing_module *mod, int frames) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + uint64_t energy_sum; + uint32_t log_arg; + int32_t tmp; + int ch; + + cd->frames_count += frames; + if (cd->frames_count < cd->report_count) + return; + + cd->frames_count = 0; + energy_sum = 0; + for (ch = 0; ch < cd->channels; ch++) { + energy_sum += cd->energy[ch]; + cd->energy[ch] = 0; + } + + /* Log2 argument is Q32.0 unsigned, log2 returns Q16.16 signed. + * Energy is Qx.30, so the argument 2^30 times scaled. Also to keep + * argument within uint32_t range, need to scale it down by 19. + * To compensate these, need to add 19 (Q16.16) and subtract 30 (Q16.16) + * from logarithm value. + */ + log_arg = (uint32_t)(energy_sum >> SOUND_DOSE_ENERGY_SHIFT); + log_arg = MAX(log_arg, 1); + tmp = base2_logarithm(log_arg); + tmp += SOUND_DOSE_LOG_FIXED_OFFSET; /* Compensate Q2.30 and energy shift */ + tmp += cd->log_offset_for_mean; /* logarithm subtract for mean */ + tmp = Q_MULTSR_32X32((int64_t)tmp, SOUND_DOSE_TEN_OVER_LOG2_10_Q29, + SOUND_DOSE_LOGOFFS_Q, SOUND_DOSE_LOGMULT_Q, SOUND_DOSE_LOGOFFS_Q); + cd->level_dbfs = tmp + SOUND_DOSE_WEIGHT_FILTERS_OFFS_Q16 + SOUND_DOSE_DFBS_OFFS_Q16; + + /* If stereo sum channel level values and subtract 3 dB, to generalize + * For stereo or more subtract -1.5 dB per channel. + */ + if (cd->channels > 1) + cd->level_dbfs += cd->channels * SOUND_DOSE_MEL_CHANNELS_SUM_FIX; + + sound_dose_report_mel(mod); +} + +#if CONFIG_FORMAT_S16LE + +/** + * sound_dose_s16() - Process S16_LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 16-bit signed integer PCM formats. The + * audio samples in every frame are re-order to channels order defined in + * component data channel_map[]. + * + * Return: Value zero for success, otherwise an error code. + */ +static int sound_dose_s16(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + struct iir_state_df1 *iir; + int32_t weighted; + int16_t sample; + int16_t const *x0, *x, *x_start, *x_end; + int16_t *y0, *y, *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int ch; + int i; + const int channels = cd->channels; + + /* Get pointer to source data in circular buffer, get buffer start and size to + * check for wrap. The size in bytes is converted to number of s16 samples to + * control the samples process loop. If the number of bytes requested is not + * possible, an error is returned. + */ + ret = source_get_data_s16(source, bytes, &x0, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s16(sink, bytes, &y0, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - x0; + samples_without_wrap = y_end - y0; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, samples); + for (ch = 0; ch < cd->channels; ch++) { + iir = &cd->iir[ch]; + x = x0++; + y = y0++; + for (i = 0; i < samples_without_wrap; i += channels) { + sample = sat_int16(Q_MULTSR_32X32((int64_t)cd->gain, *x, + SOUND_DOSE_GAIN_Q, + SOUND_DOSE_S16_Q, + SOUND_DOSE_S16_Q)); + *y = sample; + x += channels; + y += channels; + weighted = iir_df1(iir, ((int32_t)sample) << 16) >> 16; + + /* Update sound dose, energy is Q1.15 * Q1.15 --> Q2.30 */ + cd->energy[ch] += weighted * weighted; + } + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x0 += samples_without_wrap; + y0 += samples_without_wrap; + x0 = (x0 >= x_end) ? x0 - x_size : x0; + y0 = (y0 >= y_end) ? y0 - y_size : y0; + + /* Update processed samples count for next loop iteration. */ + samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + + sound_dose_calculate_mel(mod, frames); + return 0; +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S24LE + +/** + * sound_dose_s32() - Process S32_LE or S24_4LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * Processing function for signed integer 32-bit PCM formats. The same + * function works for s24 and s32 formats since the samples values are + * not modified in computation. The audio samples in every frame are + * re-order to channels order defined in component data channel_map[]. + * + * Return: Value zero for success, otherwise an error code. + */ +static int sound_dose_s32(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + struct iir_state_df1 *iir; + int32_t sample; + int32_t const *x0, *x, *x_start, *x_end; + int32_t *y0, *y, *y_start, *y_end; + int32_t weighted; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int ch; + int i; + const int channels = cd->channels; + + /* Get pointer to source data in circular buffer, get buffer start and size to + * check for wrap. The size in bytes is converted to number of s32 samples to + * control the samples process loop. If the number of bytes requested is not + * possible, an error is returned. + */ + ret = source_get_data_s32(source, bytes, &x0, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s32(sink, bytes, &y0, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - x0; + samples_without_wrap = y_end - y0; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, samples); + for (ch = 0; ch < cd->channels; ch++) { + iir = &cd->iir[ch]; + x = x0++; + y = y0++; + for (i = 0; i < samples_without_wrap; i += channels) { + sample = sat_int32(Q_MULTSR_32X32((int64_t)cd->gain, *x, + SOUND_DOSE_GAIN_Q, + SOUND_DOSE_S32_Q, + SOUND_DOSE_S32_Q)); + *y = sample; + x += channels; + y += channels; + weighted = iir_df1(iir, sample) >> 16; + + /* Update sound dose, energy is Q1.15 * Q1.15 --> Q2.30 */ + cd->energy[ch] += weighted * weighted; + } + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x0 += samples_without_wrap; + y0 += samples_without_wrap; + x0 = (x0 >= x_end) ? x0 - x_size : x0; + y0 = (y0 >= y_end) ? y0 - y_size : y0; + + /* Update processed samples count for next loop iteration. */ + samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + + sound_dose_calculate_mel(mod, frames); + return 0; +} +#endif /* CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S24LE */ + +/* This struct array defines the used processing functions for + * the PCM formats + */ +const struct sound_dose_proc_fnmap sound_dose_proc_fnmap[] = { +#if CONFIG_FORMAT_S16LE + { SOF_IPC_FRAME_S16_LE, sound_dose_s16}, +#endif +#if CONFIG_FORMAT_S24LE + { SOF_IPC_FRAME_S24_4LE, sound_dose_s32}, +#endif +#if CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S32_LE, sound_dose_s32}, +#endif +}; + +/** + * sound_dose_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +sound_dose_func sound_dose_find_proc_func(enum sof_ipc_frame src_fmt) +{ + int i; + + /* Find suitable processing function from map */ + for (i = 0; i < ARRAY_SIZE(sound_dose_proc_fnmap); i++) + if (src_fmt == sound_dose_proc_fnmap[i].frame_fmt) + return sound_dose_proc_fnmap[i].sound_dose_proc_func; + + return NULL; +} diff --git a/src/audio/sound_dose/sound_dose-ipc4.c b/src/audio/sound_dose/sound_dose-ipc4.c new file mode 100644 index 000000000000..fd3a8151e984 --- /dev/null +++ b/src/audio/sound_dose/sound_dose-ipc4.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/component.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <ipc4/base-config.h> +#include <ipc4/header.h> +#include <ipc4/module.h> +#include <ipc4/notification.h> + +#include "sound_dose.h" + +LOG_MODULE_DECLARE(sound_dose, CONFIG_SOF_LOG_LEVEL); + +static struct ipc_msg *sound_dose_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 sof_ipc4_notify_module_data *msg_module_data; + struct sof_ipc4_control_msg_payload *msg_payload; + struct ipc_msg *msg; + + /* 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 sof_ipc4_notify_module_data) + + sizeof(struct sof_ipc4_control_msg_payload)); + if (!msg) + return NULL; + + msg_module_data = (struct sof_ipc4_notify_module_data *)msg->tx_data; + msg_module_data->instance_id = IPC4_INST_ID(ipc_config->id); + msg_module_data->module_id = IPC4_MOD_ID(ipc_config->id); + msg_module_data->event_id = SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL | + control_type_param_id; + msg_module_data->event_data_size = sizeof(struct sof_ipc4_control_msg_payload); + msg_payload = (struct sof_ipc4_control_msg_payload *)msg_module_data->event_data; + msg_payload->id = control_id; + msg_payload->num_elems = 0; + comp_dbg(dev, "instance_id = 0x%08x, module_id = 0x%08x", + msg_module_data->instance_id, msg_module_data->module_id); + return msg; +} + +int sound_dose_ipc_notification_init(struct processing_module *mod) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + + cd->msg = sound_dose_notification_init(mod, SOF_IPC4_BYTES_CONTROL_PARAM_ID, + SOF_SOUND_DOSE_PAYLOAD_PARAM_ID); + if (!cd->msg) { + comp_err(mod->dev, "Failed to initialize control notification."); + return -ENOMEM; + } + + return 0; +} + +void sound_dose_send_ipc_notification(const struct processing_module *mod) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + + ipc_msg_send(cd->msg, cd->msg->tx_data, false); +} + +/* This function handles the set_config() commands. The controls have the next purpose: + * - SOF_SOUND_DOSE_SETUP_PARAM_ID sets the acoustical sensitivity of the DAC, headphone + * amplifier and assumed worst-case loud headphones. E.g. 0 dBFS equals 100 dBSPL. The + * sensitivity is for max user volume. + * -SOF_SOUND_DOSE_VOLUME_PARAM_ID is set to new decibels value if volume is adjusted + * down from user maximum. + * - SOF_SOUND_DOSE_GAIN_PARAM_ID is normally set to 0 decibels value. If the user's + * listening is exceeding the safe MSD threshold the user's volume can be forced down + * with this gain. The bytes control is not visible in the mixer, so there is no simple + * way for user to force volume up with alsamixer or amixer utililities. The gain + * should be restored to 0 dB after the MSD value looks again safe. + * E.g. setting -10 dB value lowers user's listening volume with -10 dB and also lower + * the reported MEL values by -10 dB. + * + * These controls can be used as preferred by the MEL->MSD algorithm in user space. The + * controls offset the reported MEL values. The same offset can be also done in user + * space. And could use codec volume instead of SOF_SOUND_DOSE_GAIN_PARAM_ID if preferred. + */ +__cold static int +_sound_dose_set_config(struct processing_module *mod, uint32_t param_id, + uint32_t control_id, const void *data, uint32_t data_size) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + struct sound_dose_setup_config *new_setup; + struct sound_dose_volume_config *new_volume; + struct sound_dose_gain_config *new_gain; + struct comp_dev *dev = mod->dev; + uint8_t *dest; + size_t dest_size; + + assert_can_be_cold(); + + if (param_id != SOF_IPC4_BYTES_CONTROL_PARAM_ID) { + comp_warn(dev, "Not supported control type: %u", param_id); + return 0; + } + + comp_dbg(dev, "param_id = %u, control_id: %u", param_id, control_id); + + switch (control_id) { + case SOF_SOUND_DOSE_SETUP_PARAM_ID: + dest_size = sizeof(struct sound_dose_setup_config); + dest = (uint8_t *)&cd->setup; + break; + case SOF_SOUND_DOSE_VOLUME_PARAM_ID: + dest_size = sizeof(struct sound_dose_volume_config); + dest = (uint8_t *)&cd->vol; + break; + case SOF_SOUND_DOSE_GAIN_PARAM_ID: + dest_size = sizeof(struct sound_dose_gain_config); + dest = (uint8_t *)&cd->att; + break; + case SOF_SOUND_DOSE_PAYLOAD_PARAM_ID: + return 0; /* Just return, no need to set the audio feature data */ + default: + comp_warn(dev, "Ignored illegal control_id: %u", control_id); + return 0; + } + + if (data_size != dest_size) { + comp_err(dev, "Illegal fragment_size %u for %u:%u", + data_size, param_id, control_id); + return -EINVAL; + } + + switch (control_id) { + case SOF_SOUND_DOSE_SETUP_PARAM_ID: + new_setup = (struct sound_dose_setup_config *)data; + if (new_setup->sens_dbfs_dbspl < SOF_SOUND_DOSE_SENS_MIN_DB || + new_setup->sens_dbfs_dbspl > SOF_SOUND_DOSE_SENS_MAX_DB) { + comp_err(dev, "Illegal sensitivity = %d", new_setup->sens_dbfs_dbspl); + return -EINVAL; + } + break; + case SOF_SOUND_DOSE_VOLUME_PARAM_ID: + new_volume = (struct sound_dose_volume_config *)data; + if (new_volume->volume_offset < SOF_SOUND_DOSE_VOLUME_MIN_DB || + new_volume->volume_offset > SOF_SOUND_DOSE_VOLUME_MAX_DB) { + comp_err(dev, "Illegal volume = %d", new_volume->volume_offset); + return -EINVAL; + } + break; + case SOF_SOUND_DOSE_GAIN_PARAM_ID: + new_gain = (struct sound_dose_gain_config *)data; + if (new_gain->gain < SOF_SOUND_DOSE_GAIN_MIN_DB || + new_gain->gain > SOF_SOUND_DOSE_GAIN_MAX_DB) { + comp_err(dev, "Illegal gain = %d", new_gain->gain); + return -EINVAL; + } + cd->gain_update = true; + break; + } + + memcpy_s(dest, dest_size, data, data_size); + return 0; +} + +/* This function is the main set_config() handler. The two variants of bytes control + * are handled. The case where param_id is set to SOF_IPC4_BYTES_CONTROL_PARAM_ID + * with header sof_ipc4_control_msg_payload has the benefit of being able to pass + * the id of the control. It is useful when there are multiple instances of + * bytes control. The legacy case is where control instances are identified with + * param_id value. The first format with header must be used when a control supports + * a notification to user space. The legacy works only for simple set control usage. + */ +__cold int sound_dose_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) +{ + int ret; + + assert_can_be_cold(); + + if (!fragment_size) { + comp_warn(mod->dev, "Zero fragment size for param_id %d", param_id); + return 0; + } + + if (param_id == SOF_IPC4_BYTES_CONTROL_PARAM_ID) { + struct sof_ipc4_control_msg_payload *msg_payload; + + msg_payload = (struct sof_ipc4_control_msg_payload *)fragment; + + ret = _sound_dose_set_config(mod, param_id, msg_payload->id, + msg_payload->data, msg_payload->num_elems); + } else { + ret = _sound_dose_set_config(mod, SOF_IPC4_BYTES_CONTROL_PARAM_ID, + param_id, fragment, fragment_size); + } + + return ret; +} + +/* This function copies the data for get_config() request by the driver. Only + * the SOF_SOUND_DOSE_PAYLOAD_PARAM_ID as control_id is supported. The audio + * feature payload for sound_dose is copied to the recipient. + */ +__cold static int +_sound_dose_get_config(struct processing_module *mod, uint32_t param_id, + uint32_t control_id, uint32_t *size_out, + uint8_t *data, size_t data_size) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + size_t payload_size; + + assert_can_be_cold(); + + if (param_id != SOF_IPC4_BYTES_CONTROL_PARAM_ID) { + comp_warn(dev, "Not supported control type: %u", param_id); + return 0; + } + + comp_dbg(dev, "param_id = %u, control_id: %u", param_id, control_id); + + if (control_id != SOF_SOUND_DOSE_PAYLOAD_PARAM_ID) { + comp_warn(dev, "Ignored get config control_id: %u", control_id); + memset(data, 0, data_size); + *size_out = 0; + return 0; + } + + payload_size = cd->abi->size; + memcpy_s(data, data_size, cd->abi->data, payload_size); + *size_out = payload_size; + + return 0; +} + +/* This is the main get_config() handler. As in set_config() case, the no-header + * way is legacy. The response get_config() after notify must use the + * sof_ipc4_control_msg_payload header. + */ +__cold int sound_dose_get_config(struct processing_module *mod, + uint32_t param_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) +{ + int ret; + + assert_can_be_cold(); + + if (!fragment_size) { + comp_warn(mod->dev, "Zero fragment size for param_id %d", param_id); + return 0; + } + + if (param_id == SOF_IPC4_BYTES_CONTROL_PARAM_ID) { + struct sof_ipc4_control_msg_payload *msg_payload; + + /* Note: msg_payload will get overwrite as fragment. */ + msg_payload = (struct sof_ipc4_control_msg_payload *)fragment; + ret = _sound_dose_get_config(mod, param_id, msg_payload->id, + data_offset_size, fragment, + fragment_size); + } else { + ret = _sound_dose_get_config(mod, SOF_IPC4_BYTES_CONTROL_PARAM_ID, + param_id, data_offset_size, + fragment, fragment_size); + } + + return ret; +} diff --git a/src/audio/sound_dose/sound_dose.c b/src/audio/sound_dose/sound_dose.c new file mode 100644 index 000000000000..c28b55baee4d --- /dev/null +++ b/src/audio/sound_dose/sound_dose.c @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/format.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/source_api.h> +#include <sof/ipc/msg.h> +#include <sof/math/exp_fcn.h> +#include <sof/math/iir_df1.h> +#include <kernel/abi.h> +#include <kernel/header.h> +#include <rtos/init.h> +#include <user/eq.h> +#include <user/sound_dose.h> +#include "sound_dose.h" +#include "sound_dose_iir_44k.h" +#include "sound_dose_iir_48k.h" + +/* UUID identifies the components. Use e.g. command uuidgen from package + * uuid-runtime, add it to uuid-registry.txt in SOF top level. + */ +SOF_DEFINE_REG_UUID(sound_dose); + +/* Creates logging data for the component */ +LOG_MODULE_REGISTER(sound_dose, CONFIG_SOF_LOG_LEVEL); + +void sound_dose_report_mel(const struct processing_module *mod) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + uint64_t tmp_h, tmp_l; + + cd->dose->current_sens_dbfs_dbspl = cd->setup.sens_dbfs_dbspl; + cd->dose->current_volume_offset = cd->vol.volume_offset; + cd->dose->current_gain = cd->att.gain; + cd->dose->dbfs_value = (int32_t)(((int64_t)cd->level_dbfs * 100) >> 16); + cd->dose->mel_value = cd->dose->dbfs_value + + cd->setup.sens_dbfs_dbspl + + cd->vol.volume_offset; + /* Multiply in two 32x32 -> 64 bits parts and do sum of the parts + * including the shift from Q26 to Q0. The simplified 96 bits + * equation would be time = ((tmp_h << 32) + tmp_l) >> 26. + */ + tmp_l = (cd->total_frames_count & 0xffffffff) * cd->rate_to_us_coef; + tmp_h = (cd->total_frames_count >> 32) * cd->rate_to_us_coef; + cd->feature->stream_time_us = (tmp_l >> 26) + ((tmp_h & ((1LL << 32) - 1)) << 6); +#if SOUND_DOSE_DEBUG + comp_info(mod->dev, "Time %d dBFS %d MEL %d", + (int32_t)(cd->feature->stream_time_us / 1000000), + cd->dose->dbfs_value, cd->dose->mel_value); +#endif + + sound_dose_send_ipc_notification(mod); +} + +int sound_dose_filters_init(struct processing_module *mod) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + struct sof_eq_iir_config *iir_config; + struct sof_eq_iir_header *iir_coef; + struct comp_dev *dev = mod->dev; + struct sof_abi_hdr *blob; + size_t iir_size, alloc_size; + int32_t *data; + int i; + + /* Initialize FIR */ + switch (cd->rate) { + case 48000: + blob = (struct sof_abi_hdr *)sound_dose_iir_48k; + iir_config = (struct sof_eq_iir_config *)blob->data; + cd->log_offset_for_mean = SOUND_DOSE_LOG2_INV_48K_Q16; + cd->rate_to_us_coef = SOUND_DOSE_1M_OVER_48K_Q26; + break; + case 44100: + blob = (struct sof_abi_hdr *)sound_dose_iir_44k; + iir_config = (struct sof_eq_iir_config *)blob->data; + cd->log_offset_for_mean = SOUND_DOSE_LOG2_INV_44K_Q16; + cd->rate_to_us_coef = SOUND_DOSE_1M_OVER_44K_Q26; + break; + default: + /* TODO: 96 kHz and 192 kHz with integer decimation factor. The A-weight is not + * defined above 20 kHz, so high frequency energy is not needed. Also it will + * help keep the module load reasonable. + */ + comp_err(dev, "error: unsupported sample rate %d", cd->rate); + return -EINVAL; + } + + /* Apply the first responses in the blobs */ + iir_coef = (struct sof_eq_iir_header *)&iir_config->data[iir_config->channels_in_config]; + iir_size = iir_delay_size_df1(iir_coef); + alloc_size = cd->channels * iir_size; + cd->delay_lines = rzalloc(SOF_MEM_FLAG_USER, alloc_size); + if (!cd->delay_lines) { + comp_err(dev, "Failed to allocate memory for weighting filters."); + return -ENOMEM; + } + + data = cd->delay_lines; + for (i = 0; i < cd->channels; i++) { + iir_init_coef_df1(&cd->iir[i], iir_coef); + iir_init_delay_df1(&cd->iir[i], &data); + cd->energy[i] = 0; + } + + cd->report_count = cd->rate; /* report every 1s, for 48k frames */ + return 0; +} + +void sound_dose_filters_free(struct sound_dose_comp_data *cd) +{ + rfree(cd->delay_lines); +} + +__cold static void sound_dose_setup_init(struct sound_dose_comp_data *cd) +{ + cd->setup.sens_dbfs_dbspl = 0; /* 0 dbFS is 100 dB */ + cd->vol.volume_offset = 0; /* Assume max vol */ + cd->att.gain = 0; /* No attenuation, 0 dB */ + cd->gain = SOUND_DOSE_GAIN_ONE_Q30; + cd->new_gain = SOUND_DOSE_GAIN_ONE_Q30; +} + +static int sound_dose_audio_feature_init(struct processing_module *mod) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + size_t alloc_size = sizeof(struct sof_abi_hdr) + + sizeof(struct sof_audio_feature) + + sizeof(struct sof_sound_dose); + + cd->abi = rzalloc(SOF_MEM_FLAG_USER, alloc_size); + if (!cd->abi) { + comp_err(mod->dev, "Failed to allocate audio feature data."); + return -ENOMEM; + } + + cd->abi->magic = SOF_IPC4_ABI_MAGIC; + cd->abi->abi = SOF_ABI_VERSION; + cd->abi->size = sizeof(struct sof_audio_feature) + sizeof(struct sof_sound_dose); + cd->feature = (struct sof_audio_feature *)cd->abi->data; + cd->feature->data_size = sizeof(struct sof_sound_dose); + cd->feature->type = SOF_AUDIO_FEATURE_SOUND_DOSE_MEL; + cd->feature->num_audio_features = 1; /* Single MEL value in audio feature data */ + cd->dose = (struct sof_sound_dose *)cd->feature->data; + return 0; +} + +/** + * sound_dose_init() - Initialize the component. + * @mod: Pointer to module data. + * + * This function is called when the instance is created. The + * macro __cold informs that the code that is non-critical + * is loaded to slower but large DRAM. + * + * Return: Zero if success, otherwise error code. + */ +__cold static int sound_dose_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct comp_dev *dev = mod->dev; + struct sound_dose_comp_data *cd; + int ret; + + comp_info(dev, "Initialize"); + + cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + if (!cd) { + comp_err(dev, "Failed to allocate component data."); + return -ENOMEM; + } + + md->private = cd; + + sound_dose_setup_init(cd); + ret = sound_dose_audio_feature_init(mod); + if (ret) { + rfree(cd); + return ret; + } + + ret = sound_dose_ipc_notification_init(mod); + if (ret) { + rfree(cd->abi); + rfree(cd); + } + + return ret; +} + +/** + * sound_dose_process() - The audio data processing function. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * This is the processing function that is called for scheduled + * pipelines. The processing is controlled by the enable switch. + * + * Return: Zero if success, otherwise error code. + */ +static int sound_dose_process(struct processing_module *mod, + struct sof_source **sources, + int num_of_sources, + struct sof_sink **sinks, + int num_of_sinks) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + struct sof_source *source = sources[0]; /* One input in this example */ + struct sof_sink *sink = sinks[0]; /* One output in this example */ + struct comp_dev *dev = mod->dev; + int32_t arg; + int frames = source_get_data_frames_available(source); + int sink_frames = sink_get_free_frames(sink); + + comp_dbg(dev, "entry"); + + if (cd->gain_update) { + /* Convert dB * 100 to Q8.24 */ + arg = (int32_t)cd->att.gain * SOUND_DOSE_ONE_OVER_100_Q24; + + /* Calculate linear value as Q12.20 and convert to Q2.30 */ + cd->new_gain = Q_SHIFT_LEFT(sofm_db2lin_fixed(arg), 20, 30); + cd->gain_update = false; + } + + if (cd->new_gain < cd->gain) { + cd->gain = Q_MULTSR_32X32((int64_t)cd->gain, SOUND_DOSE_GAIN_DOWN_Q30, 30, 30, 30); + cd->gain = MAX(cd->gain, cd->new_gain); + } else if (cd->new_gain > cd->gain) { + cd->gain = Q_MULTSR_32X32((int64_t)cd->gain, SOUND_DOSE_GAIN_UP_Q30, 30, 30, 30); + cd->gain = MIN(cd->gain, SOUND_DOSE_GAIN_ONE_Q30); + } + + frames = MIN(frames, sink_frames); + cd->total_frames_count += frames; + return cd->sound_dose_func(mod, source, sink, frames); +} + +/** + * sound_dose_prepare() - Prepare the component for processing. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * Function prepare is called just before the pipeline is started. In + * this case the audio format parameters are for better code performance + * saved to component data to avoid to find out them in process. The + * processing function pointer is set to process the current audio format. + * + * Return: Value zero if success, otherwise error code. + */ +static int sound_dose_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + enum sof_ipc_frame source_format; + + comp_dbg(dev, "entry"); + + /* The processing example in this component supports one input and one + * output. Generally there can be more. + */ + if (num_of_sources != 1 || num_of_sinks != 1) + return -EINVAL; + + /* get source data format */ + cd->frame_bytes = source_get_frame_bytes(sources[0]); + cd->channels = source_get_channels(sources[0]); + source_format = source_get_frm_fmt(sources[0]); + cd->rate = source_get_rate(sources[0]); + + cd->sound_dose_func = sound_dose_find_proc_func(source_format); + if (!cd->sound_dose_func) { + comp_err(dev, "No processing function found for format %d.", + source_format); + return -EINVAL; + } + + return sound_dose_filters_init(mod); +} + +/** + * sound_dose_reset() - Reset the component. + * @mod: Pointer to module data. + * + * The component reset is called when pipeline is stopped. The reset + * should return the component to same state as init. + * + * Return: Value zero, always success. + */ +static int sound_dose_reset(struct processing_module *mod) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + + comp_dbg(mod->dev, "entry"); + + sound_dose_setup_init(cd); + return 0; +} + +/** + * sound_dose_free() - Free dynamic allocations. + * @mod: Pointer to module data. + * + * Component free is called when the pipelines are deleted. All + * dynamic allocations need to be freed here. The macro __cold + * instructs the build to locate this performance wise non-critical + * function to large and slower DRAM. + * + * Return: Value zero, always success. + */ +__cold static int sound_dose_free(struct processing_module *mod) +{ + struct sound_dose_comp_data *cd = module_get_private_data(mod); + + assert_can_be_cold(); + comp_dbg(mod->dev, "entry"); + + sound_dose_filters_free(cd); + ipc_msg_free(cd->msg); + rfree(cd->abi); + rfree(cd); + return 0; +} + +/* This defines the module operations */ +static const struct module_interface sound_dose_interface = { + .init = sound_dose_init, + .prepare = sound_dose_prepare, + .process = sound_dose_process, + .set_configuration = sound_dose_set_config, + .get_configuration = sound_dose_get_config, + .reset = sound_dose_reset, + .free = sound_dose_free +}; + +/* This controls build of the module. If COMP_MODULE is selected in kconfig + * this is build as dynamically loadable module. + */ +#if CONFIG_COMP_SOUND_DOSE_MODULE + +#include <module/module/api_ver.h> +#include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> + +static const struct sof_man_module_manifest mod_manifest __section(".module") __used = + SOF_LLEXT_MODULE_MANIFEST("SNDDOSE", &sound_dose_interface, 1, + SOF_REG_UUID(sound_dose), 4); + +SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_TR_CTX(sound_dose_tr, SOF_UUID(sound_dose_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(sound_dose_interface, sound_dose_uuid, sound_dose_tr); +SOF_MODULE_INIT(sound_dose, sys_comp_module_sound_dose_interface_init); + +#endif diff --git a/src/audio/sound_dose/sound_dose.h b/src/audio/sound_dose/sound_dose.h new file mode 100644 index 000000000000..0366d1dc9b35 --- /dev/null +++ b/src/audio/sound_dose/sound_dose.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + * + */ +#ifndef __SOF_AUDIO_SOUND_DOSE_H__ +#define __SOF_AUDIO_SOUND_DOSE_H__ + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/math/iir_df1.h> +#include <user/sound_dose.h> +#include <stdbool.h> +#include <stdint.h> + +#define SOUND_DOSE_DEBUG 0 + +#define SOUND_DOSE_1M_OVER_44K_Q26 1521742948 /* int32(1000/44.1 * 2^26) */ +#define SOUND_DOSE_1M_OVER_48K_Q26 1398101333 /* int32(1000/48 * 2^26) */ +#define SOUND_DOSE_ONE_OVER_100_Q24 167772 /* int32(0.01*2^24) */ +#define SOUND_DOSE_GAIN_ONE_Q30 1073741824 /* int32(2^30) */ +#define SOUND_DOSE_GAIN_UP_Q30 1079940603 /* int32(10^(+0.05/20)*2^30) */ +#define SOUND_DOSE_GAIN_DOWN_Q30 1067578625 /* int32(10^(-0.05/20)*2^30) */ +#define SOUND_DOSE_LOG2_INV_44K_Q16 -1011122 /* int32(log2(1/44.1e3) * 2^16) */ +#define SOUND_DOSE_LOG2_INV_48K_Q16 -1019134 /* int32(log2(1/48e3) * 2^16) */ +#define SOUND_DOSE_TEN_OVER_LOG2_10_Q29 1616142483 /* int32(10 / log2(10) * 2^29) */ +#define SOUND_DOSE_WEIGHT_FILTERS_OFFS_Q16 196608 /* int32(3 * 2^16) */ +#define SOUND_DOSE_DFBS_OFFS_Q16 197263 /* int32(3.01 * 2^16) */ +#define SOUND_DOSE_MEL_CHANNELS_SUM_FIX -98304 /* int32(-1.5 * 2^16) */ +#define SOUND_DOSE_ENERGY_SHIFT 19 /* Scale shift for 1s energy */ +#define SOUND_DOSE_LOG_FIXED_OFFSET (65536 * (SOUND_DOSE_ENERGY_SHIFT - 30)) + +#define SOUND_DOSE_S16_Q 15 /* Q1.15 samples */ +#define SOUND_DOSE_S32_Q 31 /* Q1.31 samples */ +#define SOUND_DOSE_GAIN_Q 30 /* Q2.30 gain */ +#define SOUND_DOSE_LOGOFFS_Q 16 /* see SOUND_DOSE_LOG2_INV_48K_Q16 */ +#define SOUND_DOSE_LOGMULT_Q 29 /* see SOUND_DOSE_TEN_OVER_LOG2_10_Q29 */ + +/** + * struct sound_dose_func - Function call pointer for process function + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + */ +typedef int (*sound_dose_func)(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames); + +/* Sound Dose component private data */ + +/** + * struct sound_dose_comp_data + * @sound_dose_func: Pointer to used processing function. + * @channels_order[]: Vector with desired sink channels order. + * @source_format: Source samples format. + * @frame_bytes: Number of bytes in an audio frame. + * @channels: Channels count. + * @enable: Control processing on/off, on - reorder channels + */ +struct sound_dose_comp_data { + struct iir_state_df1 iir[PLATFORM_MAX_CHANNELS]; + struct sound_dose_setup_config setup; + struct sound_dose_volume_config vol; + struct sound_dose_gain_config att; + struct sof_abi_hdr *abi; + struct sof_audio_feature *feature; + struct sof_sound_dose *dose; + struct ipc_msg *msg; + sound_dose_func sound_dose_func; + int64_t energy[PLATFORM_MAX_CHANNELS]; + int64_t total_frames_count; + int32_t log_offset_for_mean; + int32_t rate_to_us_coef; + int32_t *delay_lines; + int32_t level_dbfs; + int32_t new_gain; + int32_t gain; + bool gain_update; + int report_count; + int frames_count; + int frame_bytes; + int channels; + int rate; +}; + +/** + * struct sound_dose_proc_fnmap - processing functions for frame formats + * @frame_fmt: Current frame format + * @sound_dose_proc_func: Function pointer for the suitable processing function + */ +struct sound_dose_proc_fnmap { + enum sof_ipc_frame frame_fmt; + sound_dose_func sound_dose_proc_func; +}; + +/** + * sound_dose_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +sound_dose_func sound_dose_find_proc_func(enum sof_ipc_frame src_fmt); + +/** + * sound_dose_set_config() - Handle controls set request + * @mod: Pointer to module data. + * @param_id: Id to know control type, used to know ALSA control type. + * @pos: Position of the fragment in the large message. + * @data_offset_size: Size of the whole configuration if it is the first or only + * fragment. Otherwise it is offset of the fragment. + * @fragment: Message payload data. + * @fragment_size: Size of this fragment. + * @response_size: Size of response. + * + * This function handles the real-time controls. The ALSA controls have the + * param_id set to indicate the control type. The control ID, from topology, + * is used to separate the controls instances of same type. In control payload + * the num_elems defines to how many channels the control is applied to. + * + * Return: Zero if success, otherwise error code. + */ +int sound_dose_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); + +/** + * sound_dose_get_config() - Handle controls get request + * @mod: Pointer to module data. + * @config_id: Configuration ID. + * @data_offset_size: Size of the whole configuration if it is the first or only + * fragment. Otherwise it is offset of the fragment. + * @fragment: Message payload data. + * @fragment_size: Size of this fragment. + * + * This function is used for controls get. + * + * Return: Zero if success, otherwise error code. + */ +int sound_dose_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size); + +void sound_dose_filters_free(struct sound_dose_comp_data *cd); +int sound_dose_filters_init(struct processing_module *mod); +void sound_dose_report_mel(const struct processing_module *mod); +int sound_dose_ipc_notification_init(struct processing_module *mod); +void sound_dose_send_ipc_notification(const struct processing_module *mod); + +#endif /* __SOF_AUDIO_SOUND_DOSE_H__ */ diff --git a/src/audio/sound_dose/sound_dose.toml b/src/audio/sound_dose/sound_dose.toml new file mode 100644 index 000000000000..95f58ae27e05 --- /dev/null +++ b/src/audio/sound_dose/sound_dose.toml @@ -0,0 +1,21 @@ +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + + REM # Sound Dose component module config + [[module.entry]] + name = "SNDDOSE" + uuid = UUIDREG_STR_SOUND_DOSE + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = LOAD_TYPE + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + REM # 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] + + index = __COUNTER__ diff --git a/src/audio/sound_dose/sound_dose_iir_44k.h b/src/audio/sound_dose/sound_dose_iir_44k.h new file mode 100644 index 000000000000..d6fbf665f4eb --- /dev/null +++ b/src/audio/sound_dose/sound_dose_iir_44k.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 2025-08-15 with command: + * cd src/audio/sound_dose/tune + * octave --quiet --no-window-system sof_sound_dose_time_domain_filters.m + */ + +#include <stdint.h> + +static const uint32_t sound_dose_iir_44k[51] = { + 0x34464f53, 0x00000000, 0x000000ac, 0x0301d001, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x000000ac, 0x00000002, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000004, 0x00000004, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xc04a8747, + 0x7fb56455, 0x2000c3eb, 0xbffe782a, 0x2000c3eb, + 0x00000000, 0x00004000, 0xc5d5ada3, 0x7a174530, + 0x1e9ac221, 0xc2ca7bbd, 0x1e9ac221, 0x00000000, + 0x00004000, 0xc382c10f, 0x7c63e3c7, 0x1e4cf2c0, + 0xc1d9d144, 0x1fe2eeaa, 0x00000000, 0x00004000, + 0xfe0cb792, 0xe92a46fc, 0x02d2f1b4, 0x10d57d25, + 0x18d70df1, 0xfffffffd, 0x000067d8 +}; diff --git a/src/audio/sound_dose/sound_dose_iir_48k.h b/src/audio/sound_dose/sound_dose_iir_48k.h new file mode 100644 index 000000000000..6dca9af5e4b8 --- /dev/null +++ b/src/audio/sound_dose/sound_dose_iir_48k.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 2025-08-15 with command: + * cd src/audio/sound_dose/tune + * octave --quiet --no-window-system sof_sound_dose_time_domain_filters.m + */ + +#include <stdint.h> + +static const uint32_t sound_dose_iir_48k[51] = { + 0x34464f53, 0x00000000, 0x000000ac, 0x0301d001, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x000000ac, 0x00000002, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000004, 0x00000004, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xc0447c54, + 0x7fbb7275, 0x200247f9, 0xbffb700e, 0x200247f9, + 0x00000000, 0x00004000, 0xc56175ce, 0x7a8e6600, + 0x1eb83f18, 0xc28f81d0, 0x1eb83f18, 0x00000000, + 0x00004000, 0xc33b9ba4, 0x7caef0cf, 0x1e6ee6bd, + 0xc1b48ddf, 0x1fe4bfc4, 0x00000000, 0x00004000, + 0xff729f84, 0xf3612432, 0x01acb380, 0x0cd1120d, + 0x182fcd24, 0xfffffffd, 0x000067e0 +}; diff --git a/src/audio/sound_dose/tune/sof_sound_dose_blobs.m b/src/audio/sound_dose/tune/sof_sound_dose_blobs.m new file mode 100644 index 000000000000..7670303c2770 --- /dev/null +++ b/src/audio/sound_dose/tune/sof_sound_dose_blobs.m @@ -0,0 +1,95 @@ +% Export configuration blobs for Sound Dose + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2025, Intel Corporation. + +function sof_sound_dose_blobs() + + % Common definitions + sof_tools = '../../../../tools'; + sof_tplg = fullfile(sof_tools, 'topology'); + fn.tpath = fullfile(sof_tplg, 'topology2/include/components/sound_dose'); + str_comp = "sound_dose_config"; + str_comment = "Exported with script sof_sound_dose_blobs.m"; + str_howto = "cd src/audio/sound_dose/tune; octave sof_sound_dose_blobs.m"; + bytes_control_param_id = 202; + + % Set the parameters here + sof_tools = '../../../../tools'; + sof_tplg = fullfile(sof_tools, 'topology'); + sof_tplg_sound_dose = fullfile(sof_tplg, 'topology2/include/components/sound_dose'); + sof_ctl_sound_dose = fullfile(sof_tools, 'ctl/ipc4/sound_dose'); + + sof_sound_dose_paths(true); + + blob8 = sof_sound_dose_build_blob([10000 0], 0); + tplg2_fn = sprintf("%s/setup_sens_100db.conf", sof_tplg_sound_dose); + sof_tplg2_write(tplg2_fn, blob8, str_comp, str_comment, str_howto); + sof_alsactl_write([sof_ctl_sound_dose "/setup_sens_100db.txt"], blob8); + + blob8 = sof_sound_dose_build_blob([0 0], 0); + tplg2_fn = sprintf("%s/setup_sens_0db.conf", sof_tplg_sound_dose); + sof_tplg2_write(tplg2_fn, blob8, str_comp, str_comment, str_howto); + sof_alsactl_write([sof_ctl_sound_dose "/setup_sens_0db.txt"], blob8); + + blob8 = sof_sound_dose_build_blob([0 0], 1); + tplg2_fn = sprintf("%s/setup_vol_0db.conf", sof_tplg_sound_dose); + sof_tplg2_write(tplg2_fn, blob8, str_comp, str_comment, str_howto); + sof_alsactl_write([sof_ctl_sound_dose "/setup_vol_0db.txt"], blob8); + + blob8 = sof_sound_dose_build_blob([-1000 0], 1); + tplg2_fn = sprintf("%s/setup_vol_-10db.conf", sof_tplg_sound_dose); + sof_tplg2_write(tplg2_fn, blob8, str_comp, str_comment, str_howto); + sof_alsactl_write([sof_ctl_sound_dose "/setup_vol_-10db.txt"], blob8); + + blob8 = sof_sound_dose_build_blob([-1000 0], 2); + tplg2_fn = sprintf("%s/setup_gain_-10db.conf", sof_tplg_sound_dose); + sof_tplg2_write(tplg2_fn, blob8, str_comp, str_comment, str_howto); + sof_alsactl_write([sof_ctl_sound_dose "/setup_gain_-10db.txt"], blob8); + + blob8 = sof_sound_dose_build_blob([0 0], 2); + tplg2_fn = sprintf("%s/setup_gain_0db.conf", sof_tplg_sound_dose); + sof_tplg2_write(tplg2_fn, blob8, str_comp, str_comment, str_howto); + sof_alsactl_write([sof_ctl_sound_dose "/setup_gain_0db.txt"], blob8); + + blob8 = sof_sound_dose_build_blob([], bytes_control_param_id); + tplg2_fn = sprintf("%s/setup_data_init.conf", sof_tplg_sound_dose); + sof_tplg2_write(tplg2_fn, blob8, str_comp, str_comment, str_howto); + + sof_sound_dose_paths(false); +end + +function sof_sound_dose_paths(enable) + + common = '../../../../tools/tune/common'; + if enable + addpath(common); + else + rmpath(common); + end +end + +function blob8 = sof_sound_dose_build_blob(param_values, blob_param_id) + + blob_type = 0; + data_length = length(param_values); + data_size = 2 * data_length; + ipc_ver = 4; + [abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver, blob_type, blob_param_id); + blob_size = data_size + abi_size; + blob8 = uint8(zeros(1, blob_size)); + blob8(1:abi_size) = abi_bytes; + j = abi_size + 1; + for i = 1:data_length + blob8(j:j+1) = short2byte(int16(param_values(i))); + j=j+2; + end +end + +function bytes = short2byte(word) + sh = [0 -8]; + bytes = uint8(zeros(1,2)); + bytes(1) = bitand(bitshift(word, sh(1)), 255); + bytes(2) = bitand(bitshift(word, sh(2)), 255); +end diff --git a/src/audio/sound_dose/tune/sof_sound_dose_ref.m b/src/audio/sound_dose/tune/sof_sound_dose_ref.m new file mode 100644 index 000000000000..dc15ab9f3567 --- /dev/null +++ b/src/audio/sound_dose/tune/sof_sound_dose_ref.m @@ -0,0 +1,69 @@ +% Compute MEL every 1s +tc = 1.0; + +% Load sound clip +sound_clip = "/usr/share/sounds/alsa/Front_Right.wav"; +[x1, fs] = audioread(sound_clip); +if size(x1, 2) == 1 + x1 = repmat(x1, 1, 2); +end +sx = size(x1); +num_frames = sx(1); +num_channels = sx(2); + +% load A-weight filters +load sof_sound_dose_time_domain_filters.mat + +% Filter with IIR, FIR +x2 = filter(b_iir, a_iir, x1); +x3 = filter(b_fir, 1, x2); + +%figure +%plot(x1) + +%figure +%plot(x3) + +% compute RMS level in 1s chunks +np = 1; +nc = tc * fs; +num_chunks = floor(num_frames/nc); +l_dbfs_all = zeros(num_chunks, num_channels); +mel_all = zeros(num_chunks, 1); + +dbfs_offs = 3.01; +dbfs_offs_weight_filters = 3; +i1 = 1; +for n = 1:num_chunks + sum = 0; + i2 = i1 + nc - 1; + for ch = 1:num_channels + y = x3(i1:i2, ch); + sum = sum + mean(y.^2); + l_dbfs = 20*log10(sqrt(mean(y.^2))) + dbfs_offs + dbfs_offs_weight_filters; + l_dbfs_all(np, ch) = l_dbfs; + end + mel = 10*log10(sum) + dbfs_offs_weight_filters; + if num_channels > 1 + mel = mel - 1.5 * num_channels; + end + mel_all(np) = mel; + i1 = i1 + nc; + np = np + 1; +end + +figure(1) +plot(l_dbfs_all) +grid on +xlabel('Time (s)'); +ylabel('Level (dBSFS)'); + +figure(2) +plot(mel_all) +grid on +xlabel('Time (s)'); +ylabel('MEL (dB)'); + +mel_all + +mel_all_rnd = round(mel_all) diff --git a/src/audio/sound_dose/tune/sof_sound_dose_time_domain_filters.m b/src/audio/sound_dose/tune/sof_sound_dose_time_domain_filters.m new file mode 100644 index 000000000000..26e2b2e00fa5 --- /dev/null +++ b/src/audio/sound_dose/tune/sof_sound_dose_time_domain_filters.m @@ -0,0 +1,163 @@ +% Export time domain IIR and FIR filter to apply A-weight for sound dose. +% +% Usage: +% sof_sound_dose_time_domain_filters() + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2025, Intel Corporation. + +function sof_sound_dose_time_domain_filters(fs) + + if exist('OCTAVE_VERSION', 'builtin') + pkg load signal; + end + + sof_sound_dose_time_domain_filters_for_rate(48e3); + sof_sound_dose_time_domain_filters_for_rate(44.1e3); + +end + +function sof_sound_dose_time_domain_filters_for_rate(fs) + + sof_sound_dose = '../../sound_dose'; + sof_ctl = '../../../../tools/ctl'; + sound_dose_paths(true); + + + fs_str = sprintf('%dk', round(fs/1000)); + fir_str = sprintf('sound_dose_fir_%s', fs_str); + iir_str = sprintf('sound_dose_iir_%s', fs_str); + prm.fir_coef_fn = fullfile(sof_sound_dose, [fir_str '.h']); + prm.iir_coef_fn = fullfile(sof_sound_dose, [iir_str '.h']); + prm.fir_blob_fn = fullfile(sof_ctl, ['ipc4/eq_fir/' fir_str '.txt']); + prm.iir_blob_fn = fullfile(sof_ctl, ['ipc4/eq_iir/' iir_str '.txt']); + prm.fir_blob_vn = fir_str; + prm.iir_blob_vn = iir_str; + prm.ipc_ver = 4; + eq = sound_dose_filters(fs); + export_filters(eq, prm); + + sound_dose_paths(false); +end + +function export_filters(eq, prm) + + b_fir = 1; + b_iir = 1; + a_iir = 1; + howto = 'cd src/audio/sound_dose/tune; octave --quiet --no-window-system sof_sound_dose_time_domain_filters.m'; + + % Export FIR + if eq.enable_fir + bq = sof_eq_fir_blob_quant(eq.b_fir); + channels_in_config = 2; % Setup max 2 channels EQ + assign_response = [0 0]; % Same response for L and R + num_responses = 1; % One response + bm = sof_eq_fir_blob_merge(channels_in_config, ... + num_responses, ... + assign_response, ... + bq); + bp = sof_eq_fir_blob_pack(bm, prm.ipc_ver); + sof_export_c_eq_uint32t(prm.fir_coef_fn, bp, prm.fir_blob_vn, 0, howto); + sof_alsactl_write(prm.fir_blob_fn, bp); + b_fir = eq.b_fir; + end + + % Export IIR + if eq.enable_iir + coefq = sof_eq_iir_blob_quant(eq.p_z, eq.p_p, eq.p_k); + channels_in_config = 2; % Setup max 2 channels EQ + assign_response = [0 0]; % Same response for L and R + num_responses = 1; % One response + coefm = sof_eq_iir_blob_merge(channels_in_config, ... + num_responses, ... + assign_response, ... + coefq); + coefp = sof_eq_iir_blob_pack(coefm, prm.ipc_ver); + sof_export_c_eq_uint32t(prm.iir_coef_fn, coefp, prm.iir_blob_vn, 0, howto); + sof_alsactl_write(prm.iir_blob_fn, coefp); + [b_iir, a_iir] = zp2tf( eq.p_z, eq.p_p, eq.p_k); + end + + % Export mat file + save sof_sound_dose_time_domain_filters.mat b_fir b_iir a_iir; + +end + +function eq = sound_dose_filters(fs) + + np = 200; + f_hi = 0.95 * fs/2; + fv = logspace(log10(10), log10(f_hi), np); + ref_a_weight = func_a_weight_db(fv); + + eq = sof_eq_defaults(); + eq.fs = fs; + eq.enable_fir = 0; + eq.enable_iir = 1; + eq.iir_norm_type = '1k'; % At 1 kHz -3 dB + eq.iir_norm_offs_db = -3; + eq.fir_norm_type = '1k'; % At 1 kHz 0 dB, total -3 dB gain to avoid clip + eq.fir_norm_offs_db = 0; + eq.p_fmin = 10; + eq.p_fmax = 30e3; + + eq.fir_minph = 1; + eq.fir_beta = 4; + eq.fir_length = 31; + eq.fir_autoband = 0; + eq.fmin_fir = 300; + eq.fmax_fir = f_hi; + + eq.raw_f = fv; + eq.raw_m_db = zeros(1, length(fv)); + eq.target_f = fv; + eq.target_m_db = ref_a_weight; + + eq.peq = [ ... + eq.PEQ_HP1 12 0 0; ... + eq.PEQ_HP1 20 0 0; ... + eq.PEQ_HP2 280 0 0; ... + eq.PEQ_PN2 245 -5.45 0.5; ... + eq.PEQ_HS1 13000 -3 0; ... + eq.PEQ_HS1 14000 -3 0; ... + ]; + + eq = sof_eq_compute(eq); + sof_eq_plot(eq, 1); + figure(3); + axis([10 20e3 -60 10]); + + +end + +% See https://en.wikipedia.org/wiki/A-weighting +% IEC 61672-1:2013 Electroacoustics - Sound level meters, +% Part 1: Specifications. IEC. 2013. + +function a_weight = func_a_weight_db(fv) + a_weight = 20*log10(func_ra(fv)) - 20*log10(func_ra(1000)); +end + +function y = func_ra(f) + f2 = f.^2; + f4 = f.^4; + c1 = 12194^2; + c2 = 20.6^2; + c3 = 107.7^2; + c4 = 737.9^2; + c5 = 12194^2; + y = c1 * f4 ./ ((f2 + c2).*sqrt((f2 + c3).*(f2 + c4).*(f2 + c5))); +end + +function sound_dose_paths(enable) + switch enable + case true + addpath('../../eq_iir/tune'); + addpath('../../../../tools/tune/common'); + case false + rmpath('../../eq_iir/tune'); + rmpath('../../../../tools/tune/common'); + end +end diff --git a/src/audio/src/CMakeLists.txt b/src/audio/src/CMakeLists.txt index bfc6361afedb..6def00db23ac 100644 --- a/src/audio/src/CMakeLists.txt +++ b/src/audio/src/CMakeLists.txt @@ -1,9 +1,31 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof src_generic.c src_hifi2ep.c src_hifi3.c src_hifi4.c src_common.c src.c) +set(base_files src_generic.c src_hifi2ep.c src_hifi3.c src_hifi4.c src_hifi5.c src_common.c src.c) if(CONFIG_IPC_MAJOR_3) - add_local_sources(sof src_ipc3.c) + list(APPEND base_files src_ipc3.c) elseif(CONFIG_IPC_MAJOR_4) - add_local_sources(sof src_ipc4.c) + list(APPEND base_files src_ipc4.c) +endif() + +sof_list_append_ifdef(CONFIG_COMP_SRC_LITE base_files src_lite.c) + +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + if(CONFIG_COMP_SRC STREQUAL "m" AND DEFINED CONFIG_LLEXT) + + add_subdirectory(llext ${PROJECT_BINARY_DIR}/src_llext) + add_dependencies(app src) + + else() + + zephyr_library_sources(${base_files}) + + endif() + +else() ### library, e.g. testbench or plugin ### + + add_local_sources(sof ${base_files}) + endif() diff --git a/src/audio/src/README.md b/src/audio/src/README.md new file mode 100644 index 000000000000..0cb434a67b81 --- /dev/null +++ b/src/audio/src/README.md @@ -0,0 +1,23 @@ +# Synchronous Sample Rate Converter (SRC) Architecture + +This directory contains the Synchronous SRC implementation. + +## Overview + +Converts sample rates by an exact, locked integer or fractional ratio (e.g., 48 kHz to 44.1 kHz) using a polyphase filter bank. + +## Architecture Diagram + +```mermaid +graph LR + In[48kHz Stream] --> SRC[Polyphase FIR Interpolator] + SRC --> Out[44.1kHz Stream] +``` + +## Configuration and Scripts + +- **Kconfig**: Extensive options for `COMP_SRC`, determining conversion quality targets and memory consumption limitations: standard (`COMP_SRC_STD`), small (`COMP_SRC_SMALL`), and tiny (`COMP_SRC_TINY`) filter sets. Alternatively targets IPC4 full conversions (`COMP_SRC_IPC4_FULL_MATRIX`), and supports lite conversions (`COMP_SRC_LITE`). +- **CMakeLists.txt**: Wraps numerous internal source implementations spanning multiple SIMD platforms (`src_hifi2ep.c`, `src_hifi3.c`, `src_hifi4.c`, `src_hifi5.c`) and connects the required IPC APIs. Allows Zephyr out-of-tree loader configurations (`llext`). +- **src.toml**: Declares massive topology limits under `mod_cfg` per chipset to enforce correct processing behavior of varied rate conversions internally, specifying `UUIDREG_STR_SRC4` and `UUIDREG_STR_SRC_LITE`. +- **Topology (.conf)**: Instantiated via `tools/topology/topology2/include/components/src.conf`, utilizing `rate_in` and `rate_out` attributes to specify integer transformations. Associates as a `src` widget type with UUID `8d:b2:1b:e6:9a:14:1f:4c:b7:09:46:82:3e:f5:f5:ae`. +- **MATLAB Tuning (`tune/`)**: Houses heavily comprehensive scripts like `sof_src_generate.m` which compute optimal polyphase filter bank coefficients for a massive grid of supported input-to-output fractional sample rate conversions. The scripts export these fixed-point (or float) arrays as C header data structs (`.h` code outputs) allowing the DSP to pull static transition parameters depending on memory (`std`, `small`, `tiny`, `lite`) profiles. diff --git a/src/audio/src/coef/src_ipc4_int32_10_21_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_10_21_2500_5000.h index ce545706e446..074af07daf32 100644 --- a/src/audio/src/coef/src_ipc4_int32_10_21_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_10_21_2500_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_10_21_2500_5000_fir[480] = { +__cold_rodata static const int32_t src_int32_10_21_2500_5000_fir[480] = { 176197, 283398, -489527, diff --git a/src/audio/src/coef/src_ipc4_int32_10_21_3455_5000.h b/src/audio/src/coef/src_ipc4_int32_10_21_3455_5000.h index 97d276a98791..38678a2a6353 100644 --- a/src/audio/src/coef/src_ipc4_int32_10_21_3455_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_10_21_3455_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_10_21_3455_5000_fir[640] = { +__cold_rodata static const int32_t src_int32_10_21_3455_5000_fir[640] = { 110400, 517669, 162088, diff --git a/src/audio/src/coef/src_ipc4_int32_10_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_10_21_4535_5000.h index 4380004274a1..96a242482b97 100644 --- a/src/audio/src/coef/src_ipc4_int32_10_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_10_21_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_10_21_4535_5000_fir[2320] = { +__cold_rodata static const int32_t src_int32_10_21_4535_5000_fir[2320] = { 26554, 22041, -35569, diff --git a/src/audio/src/coef/src_ipc4_int32_10_9_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_10_9_4535_5000.h index 944eb78028a2..83ca193c21a0 100644 --- a/src/audio/src/coef/src_ipc4_int32_10_9_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_10_9_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_10_9_4535_5000_fir[1080] = { +__cold_rodata static const int32_t src_int32_10_9_4535_5000_fir[1080] = { -35695, 60551, -91611, diff --git a/src/audio/src/coef/src_ipc4_int32_16_21_4319_5000.h b/src/audio/src/coef/src_ipc4_int32_16_21_4319_5000.h index 6c277f298c79..3fec8272839d 100644 --- a/src/audio/src/coef/src_ipc4_int32_16_21_4319_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_16_21_4319_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_16_21_4319_5000_fir[1472] = { +__cold_rodata static const int32_t src_int32_16_21_4319_5000_fir[1472] = { 69743, -28255, -123867, diff --git a/src/audio/src/coef/src_ipc4_int32_16_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_16_21_4535_5000.h index 6c9764cbadf3..816a41276149 100644 --- a/src/audio/src/coef/src_ipc4_int32_16_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_16_21_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_16_21_4535_5000_fir[2048] = { +__cold_rodata static const int32_t src_int32_16_21_4535_5000_fir[2048] = { 66387, -68365, -7975, diff --git a/src/audio/src/coef/src_ipc4_int32_16_7_4082_5000.h b/src/audio/src/coef/src_ipc4_int32_16_7_4082_5000.h index d3c468bc50f1..b4b00eb4d21e 100644 --- a/src/audio/src/coef/src_ipc4_int32_16_7_4082_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_16_7_4082_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_16_7_4082_5000_fir[896] = { +__cold_rodata static const int32_t src_int32_16_7_4082_5000_fir[896] = { -71000, 181977, -339747, diff --git a/src/audio/src/coef/src_ipc4_int32_1_2_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_2268_5000.h index ff326eeda32f..8ac49de99916 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_2_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_2268_5000.h @@ -7,7 +7,7 @@ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ #include <stdint.h> -static const int32_t src_int32_1_2_2268_5000_fir[36] = { +__cold_rodata static const int32_t src_int32_1_2_2268_5000_fir[36] = { 1065827, -37924, -4976218, diff --git a/src/audio/src/coef/src_ipc4_int32_1_2_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_2500_5000.h index 4c7a24273cd7..99ac5b22e7f4 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_2_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_2500_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_1_2_2500_5000_fir[40] = { +__cold_rodata static const int32_t src_int32_1_2_2500_5000_fir[40] = { -879692, 460291, 4237437, diff --git a/src/audio/src/coef/src_ipc4_int32_1_2_2721_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_2721_5000.h index 0ee1fe85270d..cbaa50a52342 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_2_2721_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_2721_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_1_2_2721_5000_fir[44] = { +__cold_rodata static const int32_t src_int32_1_2_2721_5000_fir[44] = { 776925, -535235, -3522824, diff --git a/src/audio/src/coef/src_ipc4_int32_1_2_3401_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_3401_5000.h index ba97ad2fb9f7..147fdc0258b8 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_2_3401_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_3401_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_1_2_3401_5000_fir[60] = { +__cold_rodata static const int32_t src_int32_1_2_3401_5000_fir[60] = { 483288, -83413, -1522435, diff --git a/src/audio/src/coef/src_ipc4_int32_1_2_3887_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_3887_5000.h index b1ca37835159..5e3fb20738a0 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_2_3887_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_3887_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_1_2_3887_5000_fir[84] = { +__cold_rodata static const int32_t src_int32_1_2_3887_5000_fir[84] = { 488732, -7737, -1049640, diff --git a/src/audio/src/coef/src_ipc4_int32_1_2_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_4535_5000.h index 5d2f5750ef3a..f9a2d9e1ed55 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_2_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_1_2_4535_5000_fir[192] = { +__cold_rodata static const int32_t src_int32_1_2_4535_5000_fir[192] = { -215107, -43725, 301513, diff --git a/src/audio/src/coef/src_ipc4_int32_1_3_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_1_3_2268_5000.h index 400311d50d4f..8c088177f4f0 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_3_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_3_2268_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_1_3_2268_5000_fir[52] = { +__cold_rodata static const int32_t src_int32_1_3_2268_5000_fir[52] = { 856478, -618891, -4156030, diff --git a/src/audio/src/coef/src_ipc4_int32_1_3_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_1_3_4535_5000.h index b668f710a423..d13e60802e5a 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_3_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_3_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_1_3_4535_5000_fir[260] = { +__cold_rodata static const int32_t src_int32_1_3_4535_5000_fir[260] = { -76785, 87265, 208768, diff --git a/src/audio/src/coef/src_ipc4_int32_1_4_1512_5000.h b/src/audio/src/coef/src_ipc4_int32_1_4_1512_5000.h index f39d4d866277..fa07fd026a7d 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_4_1512_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_4_1512_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_1_4_1512_5000_fir[52] = { +__cold_rodata static const int32_t src_int32_1_4_1512_5000_fir[52] = { 740488, -111252, -2633435, diff --git a/src/audio/src/coef/src_ipc4_int32_1_4_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_1_4_2268_5000.h index 7de054371d04..b65fec0b639b 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_4_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_4_2268_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_1_4_2268_5000_fir[60] = { +__cold_rodata static const int32_t src_int32_1_4_2268_5000_fir[60] = { -1265010, -1300023, 42822, diff --git a/src/audio/src/coef/src_ipc4_int32_1_4_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_1_4_4535_5000.h index 59f3c464e2e3..07aae148bd91 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_4_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_4_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_1_4_4535_5000_fir[332] = { +__cold_rodata static const int32_t src_int32_1_4_4535_5000_fir[332] = { -246503, -173077, 24381, diff --git a/src/audio/src/coef/src_ipc4_int32_1_6_1134_5000.h b/src/audio/src/coef/src_ipc4_int32_1_6_1134_5000.h index 77293237d64a..9e20a2f4ffed 100644 --- a/src/audio/src/coef/src_ipc4_int32_1_6_1134_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_6_1134_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_1_6_1134_5000_fir[68] = { +__cold_rodata static const int32_t src_int32_1_6_1134_5000_fir[68] = { -2393808, -3445469, -3907601, diff --git a/src/audio/src/coef/src_ipc4_int32_20_21_1250_5000.h b/src/audio/src/coef/src_ipc4_int32_20_21_1250_5000.h index cb9898d01873..83409ba4cda2 100644 --- a/src/audio/src/coef/src_ipc4_int32_20_21_1250_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_21_1250_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_20_21_1250_5000_fir[320] = { +__cold_rodata static const int32_t src_int32_20_21_1250_5000_fir[320] = { 134710, 1035873, -9174506, diff --git a/src/audio/src/coef/src_ipc4_int32_20_21_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_20_21_2500_5000.h index bbecd688b192..d2f606331586 100644 --- a/src/audio/src/coef/src_ipc4_int32_20_21_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_21_2500_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_20_21_2500_5000_fir[560] = { +__cold_rodata static const int32_t src_int32_20_21_2500_5000_fir[560] = { -5217, -381011, 1487277, diff --git a/src/audio/src/coef/src_ipc4_int32_20_21_3125_5000.h b/src/audio/src/coef/src_ipc4_int32_20_21_3125_5000.h index 8727d574fd7c..8465b979b4ce 100644 --- a/src/audio/src/coef/src_ipc4_int32_20_21_3125_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_21_3125_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_20_21_3125_5000_fir[640] = { +__cold_rodata static const int32_t src_int32_20_21_3125_5000_fir[640] = { 81905, -392860, 605436, diff --git a/src/audio/src/coef/src_ipc4_int32_20_21_4167_5000.h b/src/audio/src/coef/src_ipc4_int32_20_21_4167_5000.h index c1cb209a0235..efd2acc0b5d3 100644 --- a/src/audio/src/coef/src_ipc4_int32_20_21_4167_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_21_4167_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_20_21_4167_5000_fir[1200] = { +__cold_rodata static const int32_t src_int32_20_21_4167_5000_fir[1200] = { 54594, -184742, 399571, diff --git a/src/audio/src/coef/src_ipc4_int32_20_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_20_21_4535_5000.h index 4ed3c222a10d..243140a639c8 100644 --- a/src/audio/src/coef/src_ipc4_int32_20_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_21_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_20_21_4535_5000_fir[2080] = { +__cold_rodata static const int32_t src_int32_20_21_4535_5000_fir[2080] = { -39854, 85177, -146854, diff --git a/src/audio/src/coef/src_ipc4_int32_20_7_2976_5000.h b/src/audio/src/coef/src_ipc4_int32_20_7_2976_5000.h index 4e543c4fdca4..86c446340c58 100644 --- a/src/audio/src/coef/src_ipc4_int32_20_7_2976_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_7_2976_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_20_7_2976_5000_fir[560] = { +__cold_rodata static const int32_t src_int32_20_7_2976_5000_fir[560] = { -33375, 393038, -1331352, diff --git a/src/audio/src/coef/src_ipc4_int32_21_10_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_21_10_2500_5000.h index 624fca1bf2ad..43a6b47e3354 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_10_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_10_2500_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_10_2500_5000_fir[504] = { +__cold_rodata static const int32_t src_int32_21_10_2500_5000_fir[504] = { 7704, 568453, -2657822, diff --git a/src/audio/src/coef/src_ipc4_int32_21_10_3455_5000.h b/src/audio/src/coef/src_ipc4_int32_21_10_3455_5000.h index eb39b94a3648..d0188db84fca 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_10_3455_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_10_3455_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_10_3455_5000_fir[756] = { +__cold_rodata static const int32_t src_int32_21_10_3455_5000_fir[756] = { -37222, 240677, -698458, diff --git a/src/audio/src/coef/src_ipc4_int32_21_10_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_10_4535_5000.h index 7766a5163142..ae0134902654 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_10_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_10_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_10_4535_5000_fir[2520] = { +__cold_rodata static const int32_t src_int32_21_10_4535_5000_fir[2520] = { -9118, 18975, -33943, diff --git a/src/audio/src/coef/src_ipc4_int32_21_16_4319_5000.h b/src/audio/src/coef/src_ipc4_int32_21_16_4319_5000.h index bb7c44e00392..fd8d48b9b1ef 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_16_4319_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_16_4319_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_16_4319_5000_fir[1596] = { +__cold_rodata static const int32_t src_int32_21_16_4319_5000_fir[1596] = { -50136, 105527, -181643, diff --git a/src/audio/src/coef/src_ipc4_int32_21_16_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_16_4535_5000.h index 0c2def816397..7308ab4368ae 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_16_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_16_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_16_4535_5000_fir[2436] = { +__cold_rodata static const int32_t src_int32_21_16_4535_5000_fir[2436] = { -15208, 29050, -48628, diff --git a/src/audio/src/coef/src_ipc4_int32_21_20_1250_5000.h b/src/audio/src/coef/src_ipc4_int32_21_20_1250_5000.h index db43622d1c84..4ce048243ecc 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_20_1250_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_20_1250_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_20_1250_5000_fir[420] = { +__cold_rodata static const int32_t src_int32_21_20_1250_5000_fir[420] = { 94664, -1133291, 202774, diff --git a/src/audio/src/coef/src_ipc4_int32_21_20_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_21_20_2500_5000.h index ce4da411ce8f..acdf97328a05 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_20_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_20_2500_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_20_2500_5000_fir[504] = { +__cold_rodata static const int32_t src_int32_21_20_2500_5000_fir[504] = { 8116, 587965, -2725209, diff --git a/src/audio/src/coef/src_ipc4_int32_21_20_3125_5000.h b/src/audio/src/coef/src_ipc4_int32_21_20_3125_5000.h index 66edd652830e..c37db1770a28 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_20_3125_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_20_3125_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_20_3125_5000_fir[672] = { +__cold_rodata static const int32_t src_int32_21_20_3125_5000_fir[672] = { 4928, 190845, -929522, diff --git a/src/audio/src/coef/src_ipc4_int32_21_20_4167_5000.h b/src/audio/src/coef/src_ipc4_int32_21_20_4167_5000.h index 737cf8968eb0..31c0a15809d3 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_20_4167_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_20_4167_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_20_4167_5000_fir[1260] = { +__cold_rodata static const int32_t src_int32_21_20_4167_5000_fir[1260] = { -79259, 176349, -298364, diff --git a/src/audio/src/coef/src_ipc4_int32_21_20_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_20_4535_5000.h index f49e48439c7d..c6a76782842e 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_20_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_20_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_20_4535_5000_fir[2268] = { +__cold_rodata static const int32_t src_int32_21_20_4535_5000_fir[2268] = { -37260, 62223, -92794, diff --git a/src/audio/src/coef/src_ipc4_int32_21_2_3239_5000.h b/src/audio/src/coef/src_ipc4_int32_21_2_3239_5000.h index 111cf33bdf6c..3798885c991c 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_2_3239_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_2_3239_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_2_3239_5000_fir[672] = { +__cold_rodata static const int32_t src_int32_21_2_3239_5000_fir[672] = { -35882, 307961, -974587, diff --git a/src/audio/src/coef/src_ipc4_int32_21_32_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_32_4535_5000.h index 0d7cf6c46d53..4b2c8db312d0 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_32_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_32_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_32_4535_5000_fir[3612] = { +__cold_rodata static const int32_t src_int32_21_32_4535_5000_fir[3612] = { -8897, -11309, 29648, diff --git a/src/audio/src/coef/src_ipc4_int32_21_40_2381_5000.h b/src/audio/src/coef/src_ipc4_int32_21_40_2381_5000.h index 3c9e9af6c834..c465a9ce6b14 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_40_2381_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_40_2381_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_40_2381_5000_fir[924] = { +__cold_rodata static const int32_t src_int32_21_40_2381_5000_fir[924] = { 139084, 174433, -727541, diff --git a/src/audio/src/coef/src_ipc4_int32_21_40_3968_5000.h b/src/audio/src/coef/src_ipc4_int32_21_40_3968_5000.h index c5e7d514e40b..1eca6eab5318 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_40_3968_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_40_3968_5000.h @@ -1,1694 +1,1693 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2022 Intel Corporation. All rights reserved. + * Copyright(c) 2025 Intel Corporation. All rights reserved. * */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ - #include <stdint.h> -static const int32_t src_int32_21_40_3968_5000_fir[1680] = { - 150373, - 421455, - -262792, - -985265, - 269861, - 1875135, +__cold_rodata static const int32_t src_int32_21_40_3968_5000_fir[1680] = { + 150367, + 421440, + -262784, + -985237, + 269854, + 1875091, -22201, - -3129391, - -684671, - 4728437, - 2102440, - -6567585, - -4512257, - 8432040, - 8197609, - -9977208, - -13409901, - 10716388, - 20330450, - -10015623, - -29033872, - 7091565, - 39458553, - -1001588, - -51389962, - -9396746, - 64462109, - 25565498, - -78182089, - -49598462, - 91984362, - 85028813, - -105331978, - -139114863, - 117932138, - 230724389, - -130422250, - -430062814, - 148819018, - 1386618319, - 2021685202, - 1330470362, - 98857077, - -431550259, - -107131055, - 236402487, - 104162468, - -145450386, - -96677417, - 91129950, - 86565139, - -55111115, - -74954592, - 30331112, - 62746086, - -13360365, - -50698982, - 2172403, - 39429663, - 4648441, - -29394721, - -8214204, - 20881323, - 9450845, - -14011450, - -9136879, - 8760444, - 7911043, - -4986978, - -6271869, - 2469883, - 4580122, - -946664, - -3068510, - 148902, - 1859173, - 169186, - -987038, - -211313, - 425991, - 171535, - 414292, - -314741, - -978120, - 372046, - 1881670, - -197388, - -3175447, - -413545, - 4855453, - 1717224, - -6835125, - -4006339, - 8918784, - 7584225, - -10779812, - -12731604, - 11945809, - 19669273, - -11790762, - -28521901, - 9530377, - 39289138, - -4210069, - -51830991, - -5337219, - 65875244, - 20612387, - -81057436, - -43765527, - 97014010, - 78414720, - -113587103, - -131976165, - 131360328, - 223763329, - -153654181, - -426345130, - 200525502, - 1441278573, - 2018325678, - 1272995597, - 50746076, - -430872949, - -83890644, - 240797033, - 90124014, - -150964753, - -87671716, - 96695227, - 80788198, - -60280322, - -71395293, - 34887901, - 60739362, - -17209548, - -49764528, - 5296530, - 39205082, - 2213243, - -29604604, - -6395851, - 21320641, - 8156023, - -14534351, - -8263609, - 9270690, - 7358972, - -5428636, - -5949973, - 2818022, - 4411680, - -1198374, - -2993447, - 315133, - 1834110, - 70510, - -983597, - -160571, - 427981, - 192807, - 404438, - -366878, - -965474, - 475230, - 1878496, - -375831, - -3206104, - -134504, - 4960086, - 1315887, - -7072607, - -3471282, - 9368222, - 6922626, - -11540030, - -11978882, - 13132354, - 18899622, - -13530282, - -27859415, - 11952509, - 38919774, - -7437303, - -52016772, - -1201021, - 66974672, - 15494312, - -83561796, - -37637370, - 101623741, - 71313432, - -121395745, - -124056476, - 144374684, - 215525925, - -176714395, - -420338540, - 253862892, - 1494293678, - 2011616748, - 1214357798, - 4584865, - -428102842, - -60808263, - 243913355, - 75889473, - -155644208, - -78364169, - 101704667, - 74686731, - -65084899, - -67525922, - 39215828, - 58455422, - -20926560, - -48594211, - 8355856, - 38788367, - -201990, - -29664429, - -4569872, - 21647729, - 6838813, - -14977124, - -7362275, - 9726604, - 6779111, - -5835563, - -5603989, - 3145451, - 4224365, - -1438732, - -2904900, - 475748, - 1800309, - -25700, - -975120, - -110822, - 427516, - 214053, - 391840, - -418912, - -947221, - 578880, - 1865377, - -556665, - -3220852, - 151162, - 5041346, - 900198, - -7278267, - -2909331, - 9777442, - 6215426, - -12253345, - -11154471, - 14269391, - 18023904, - -15224902, - -27047795, - 14345515, - 38349806, - -10667262, - -51943227, - 2991989, - 67751021, - 10234907, - -85677948, - -31240843, - 105784895, - 63753480, - -128712349, - -115382139, - 156903537, - 206024904, - -199488456, - -411991515, - 308710631, - 1545510183, - 2001578612, - 1154723052, - -39535524, - -423318009, - -37987969, - 245762565, - 61531206, - -159479215, - -68804818, - 106141279, - 68295090, - -69505728, - -63369475, - 43296232, - 55908959, - -24494534, - -47196722, - 11335951, - 38183992, - -2585467, - -29575844, - -2745490, - 21862485, - 5506125, - -15338717, - -6437824, - 10126745, - 6174832, - -6206299, - -5236095, - 3450898, - 4019502, - -1666745, - -2803627, - 630051, - 1758172, - -119006, - -961813, - -62308, - 424699, - 235134, - 376461, - -470543, - -923288, - 682450, - 1842125, - -738991, - -3219259, - 442105, - 5098349, - 472032, - -7450477, - -2322908, - 10143692, - 5465516, - -12915413, - -10261510, - 15350449, - 17045096, - -16865443, - -26089194, - 16696942, - 37579584, - -13883708, - -51607535, - 7221428, - 68196421, - 4858808, - -87390395, - -24604478, - 109470657, - 55766057, - -135493101, - -105983599, - 168876251, - 195279161, - -221860366, - -401259958, - 364941607, - 1594779183, - 1988241480, - 1094259174, - -81532107, - -416602245, - -15530266, - 246361409, - 47120910, - -162464447, - -59044202, - 109991099, - 61648604, - -73525820, - -58950082, - 47111907, - 53115794, - -27897550, - -45581779, - 14222955, - 37397310, - -4925707, - -29341220, - -931799, - 21965372, - 4164848, - -15618499, - -5495243, - 10469975, - 5549577, - -6539588, - -4848544, - 3733226, - 3798481, - -1881508, - -2690431, - 777396, - 1708137, - -208996, - -943897, + -3129329, + -684659, + 4728358, + 2102408, + -6567493, + -4512199, + 8431940, + 8197520, + -9977109, + -13409780, + 10716300, + 20330299, + -10015556, + -29033697, + 7091526, + 39458363, + -1001584, + -51389769, + -9396715, + 64461926, + 25565435, + -78181927, + -49598376, + 91984231, + 85028715, + -105331883, + -139114767, + 117932078, + 230724308, + -130422221, + -430062761, + 148819010, + 1386618304, + 2021685208, + 1330470346, + 98857072, + -431550204, + -107131031, + 236402403, + 104162415, + -145450284, + -96677329, + 91129844, + 86565015, + -55111019, + -74954436, + 30331038, + 62745906, + -13360321, + -50698790, + 2172394, + 39429472, + 4648416, + -29394543, + -8214148, + 20881167, + 9450768, + -14011323, + -9136788, + 8760348, + 7910949, + -4986913, + -6271781, + 2469845, + 4580045, + -946646, + -3068450, + 148898, + 1859130, + 169182, + -987010, + -211306, + 425976, + 171528, + 414278, + -314731, + -978093, + 372037, + 1881626, + -197384, + -3175385, + -413537, + 4855373, + 1717198, + -6835030, + -4006287, + 8918679, + 7584144, + -10779706, + -12731490, + 11945711, + 19669128, + -11790683, + -28521729, + 9530326, + 39288950, + -4210051, + -51830798, + -5337201, + 65875058, + 20612337, + -81057270, + -43765452, + 97013873, + 78414631, + -113587002, + -131976075, + 131360263, + 223763252, + -153654148, + -426345080, + 200525492, + 1441278560, + 2018325683, + 1272995580, + 50746073, + -430872893, + -83890624, + 240796946, + 90123967, + -150964646, + -87671635, + 96695113, + 80788080, + -60280215, + -71395142, + 34887814, + 60739187, + -17209491, + -49764339, + 5296507, + 39204891, + 2213230, + -29604423, + -6395808, + 21320481, + 8155955, + -14534218, + -8263527, + 9270589, + 7358884, + -5428565, + -5949889, + 2817978, + 4411606, + -1198352, + -2993387, + 315126, + 1834066, + 70509, + -983569, + -160565, + 427966, + 192799, + 404424, + -366867, + -965447, + 475218, + 1878452, + -375823, + -3206041, + -134502, + 4960004, + 1315867, + -7072508, + -3471237, + 9368112, + 6922551, + -11539916, + -11978775, + 13132247, + 18899483, + -13530192, + -27859249, + 11952445, + 38919589, + -7437271, + -52016579, + -1201017, + 66974485, + 15494275, + -83561626, + -37637306, + 101623599, + 71313352, + -121395638, + -124056393, + 144374613, + 215525853, + -176714358, + -420338492, + 253862880, + 1494293665, + 2011616752, + 1214357780, + 4584864, + -428102784, + -60808248, + 243913265, + 75889433, + -155644096, + -78364095, + 101704546, + 74686621, + -65084783, + -67525778, + 39215730, + 58455252, + -20926490, + -48594025, + 8355819, + 38788177, + -201989, + -29664247, + -4569841, + 21647565, + 6838756, + -14976987, + -7362201, + 9726497, + 6779029, + -5835487, + -5603909, + 3145402, + 4224294, + -1438705, + -2904843, + 475738, + 1800266, + -25699, + -975093, + -110818, + 427500, + 214045, + 391826, + -418899, + -947195, + 578866, + 1865334, + -556654, + -3220789, + 151159, + 5041263, + 900184, + -7278166, + -2909294, + 9777328, + 6215359, + -12253225, + -11154371, + 14269276, + 18023772, + -15224801, + -27047635, + 14345439, + 38349624, + -10667218, + -51943035, + 2991980, + 67750832, + 10234883, + -85677775, + -31240790, + 105784748, + 63753409, + -128712237, + -115382063, + 156903461, + 206024836, + -199488415, + -411991470, + 308710617, + 1545510172, + 2001578616, + 1154723033, + -39535521, + -423317950, + -37987959, + 245762473, + 61531173, + -159479099, + -68804752, + 106141151, + 68294989, + -69505604, + -63369339, + 43296123, + 55908795, + -24494452, + -47196540, + 11335901, + 38183804, + -2585453, + -29575662, + -2745472, + 21862319, + 5506079, + -15338576, + -6437759, + 10126633, + 6174758, + -6206217, + -5236020, + 3450844, + 4019434, + -1666714, + -2803571, + 630038, + 1758130, + -119003, + -961785, + -62306, + 424684, + 235124, + 376448, + -470529, + -923262, + 682432, + 1842083, + -738976, + -3219196, + 442097, + 5098265, + 472025, + -7450374, + -2322879, + 10143573, + 5465458, + -12915287, + -10261419, + 15350326, + 17044972, + -16865332, + -26089040, + 16696853, + 37579406, + -13883650, + -51607346, + 7221405, + 68196233, + 4858796, + -87390220, + -24604437, + 109470507, + 55765995, + -135492984, + -105983530, + 168876171, + 195279098, + -221860321, + -401259915, + 364941592, + 1594779173, + 1988241483, + 1094259154, + -81532102, + -416602185, + -15530263, + 246361315, + 47120885, + -162464327, + -59044145, + 109990966, + 61648512, + -73525687, + -58949955, + 47111788, + 53115638, + -27897455, + -45581602, + 14222893, + 37397125, + -4925680, + -29341039, + -931792, + 21965205, + 4164813, + -15618355, + -5495187, + 10469859, + 5549510, + -6539502, + -4848474, + 3733167, + 3798417, + -1881473, + -2690377, + 777379, + 1708096, + -208990, + -943870, -15255, - 419644, - 255902, - 358281, - -521462, - -893629, - 785374, - 1808602, - -921882, - -3200967, - 736921, - 5130317, + 419629, + 255892, + 358269, + -521446, + -893604, + 785355, + 1808560, + -921862, + -3200905, + 736907, + 5130233, 33364, - -7587754, - -1714602, - 10464394, - 4676053, - -13522088, - -9303538, - 16369249, - 15966744, - -18442879, - -24986537, - 18994384, - 36610474, - -17070268, - -51008161, - 11466478, - 68304570, - -608463, - -88685464, - -17758373, - 112656216, - 47384910, - -141696158, - -95895319, - 180223571, - 183313793, - -243713015, - -388107473, - 422422539, - 1641956834, - 1971645460, - 1033135130, - -121330165, - -408044674, - 6468238, - 245732088, - 32729297, - -164598739, - -49133110, - 113243221, - 54783394, - -77130372, - -54292874, - 50647163, - 50092781, - -31120698, - -43760063, - 17003645, - 36434518, - -7211590, - -28963627, - 862285, - 21957408, - 2821819, - -15816262, - -4539538, - 10755463, - 4906837, - -6834390, - -4443647, - 3991438, - 3562749, - -2082201, - -2566162, - 917185, - 1650670, - -295287, - -921615, - 30126, - 412474, - 276207, - 337295, - -571356, - -858229, - 887079, - 1764721, - -1104384, - -3165699, - 1034153, - 5136590, - -413737, - -7688768, - -1087158, - 10737166, - 3850443, - -14069443, - -8284475, - 17319740, - 14792945, - -19948386, - -23743518, - 21225554, - 35444865, - -20210518, - -50144879, - 15705989, - 68070780, - -6140610, - -89551394, - -10734057, - 115318912, - 38646205, - -147281886, - -85155679, - 190877968, - 170160104, - -264928631, - -372505612, - 481014382, - 1686904873, - 1951840419, - 971520455, - -158863411, - -397739328, - 27915162, - 243902060, - 18425782, - -165885041, - -39122330, - 115889804, - 47736183, - -80306817, - -49423851, - 53887892, - 46857709, - -34150142, - -41743155, - 19665486, - 35302615, - -9432409, - -28446809, - 2628058, - 21840154, - 1483787, - -15932213, - -3575704, - 10982682, - 4250135, - -7089875, - -4023763, - 4224679, - 3313797, - -2268096, - -2431707, - 1048879, - 1586266, - -377528, - -895227, - 73642, - 403319, - 295897, - 313515, - -619904, - -817108, - 986980, - 1710451, - -1285525, - -3113264, - 1332306, - 5116629, - -867124, - -7752354, - -443468, - 10959831, - 2992333, - -14553796, - -7208611, - 18196135, - 13528340, - -21373384, - -22364590, - 23378342, - 34086167, - -23288067, - -49018787, - 19918580, - 67492022, - -11710690, - -89978422, - -3564353, - 117438376, - 29588384, - -152213083, - -73806857, - 200773985, - 155855585, - -285389240, - -354434084, - 540572768, - 1729491104, - 1928885795, - 909584664, - -194074134, - -385784715, - 48722651, - 240903821, - 4278182, - -166330332, - -29062407, - 117926072, - 40544116, - -83044852, - -44369735, - 56821613, - 43429207, - -36973178, - -39543466, - 22196693, - 34009357, - -11577918, - -27795161, - 4357077, - 21615697, - 157379, - -15966969, - -2608704, - 11151409, - 3583008, - -7305428, - -3591286, - 4432237, - 3053158, - -2438555, - -2287989, - 1171990, - 1515443, - -455399, - -865006, - 115117, - 392318, - 314814, - 286971, - -666787, - -770315, - 1084487, - 1645816, - -1464315, - -3043555, - 1629846, - 5070021, - -1324574, - -7777520, - 213445, - 11130436, - 2105591, - -14971733, - -6080586, - 18992944, - 12178093, - -22709591, - -20854953, - 25440881, - 32538809, - -26286634, - -47632323, - 24082746, - 66566959, - -17291235, - -89958853, - 3716767, - 118996661, - 20252009, - -156455193, - -61894685, - 209848575, - 140443868, - -304977135, - -333880946, - 600948462, - 1769589870, + -7587650, + -1714580, + 10464273, + 4676003, + -13521957, + -9303456, + 16369117, + 15966628, + -18442759, + -24986390, + 18994284, + 36610302, + -17070197, + -51007975, + 11466442, + 68304383, + -608461, + -88685288, + -17758344, + 112656063, + 47384858, + -141696037, + -95895257, + 180223488, + 183313736, + -243712967, + -388107433, + 422422522, + 1641956825, + 1971645464, + 1033135110, + -121330157, + -408044613, + 6468236, + 245731993, + 32729279, + -164598616, + -49133062, + 113243082, + 54783311, + -77130232, + -54292756, + 50647034, + 50092632, + -31120591, + -43759892, + 17003569, + 36434337, + -7211550, + -28963446, + 862279, + 21957240, + 2821795, + -15816115, + -4539492, + 10755344, + 4906777, + -6834300, + -4443583, + 3991375, + 3562688, + -2082163, + -2566110, + 917165, + 1650630, + -295279, + -921588, + 30125, + 412459, + 276196, + 337284, + -571338, + -858206, + 887057, + 1764681, + -1104361, + -3165638, + 1034135, + 5136506, + -413731, + -7688663, + -1087145, + 10737042, + 3850403, + -14069307, + -8284403, + 17319601, + 14792838, + -19948256, + -23743379, + 21225443, + 35444700, + -20210435, + -50144697, + 15705939, + 68070595, + -6140596, + -89551218, + -10734039, + 115318757, + 38646163, + -147281763, + -85155625, + 190877881, + 170160052, + -264928581, + -372505574, + 481014364, + 1686904866, + 1951840421, + 971520434, + -158863400, + -397739267, + 27915154, + 243901963, + 18425772, + -165884915, + -39122292, + 115889661, + 47736111, + -80306669, + -49423742, + 53887753, + 46857569, + -34150025, + -41742991, + 19665398, + 35302438, + -9432356, + -28446631, + 2628040, + 21839986, + 1483774, + -15932065, + -3575668, + 10982560, + 4250083, + -7089781, + -4023705, + 4224612, + 3313741, + -2268054, + -2431658, + 1048856, + 1586227, + -377518, + -895201, + 73640, + 403304, + 295885, + 313504, + -619886, + -817086, + 986956, + 1710412, + -1285498, + -3113204, + 1332283, + 5116546, + -867111, + -7752248, + -443463, + 10959705, + 2992301, + -14553656, + -7208548, + 18195991, + 13528243, + -21373246, + -22364460, + 23378221, + 34086009, + -23287972, + -49018611, + 19918518, + 67491839, + -11710663, + -89978246, + -3564347, + 117438220, + 29588353, + -152212957, + -73806811, + 200773895, + 155855538, + -285389187, + -354434050, + 540572749, + 1729491098, + 1928885796, + 909584643, + -194074119, + -385784655, + 48722638, + 240903723, + 4278179, + -166330204, + -29062378, + 117925924, + 40544053, + -83044697, + -44369637, + 56821465, + 43429076, + -36973050, + -39543310, + 22196593, + 34009186, + -11577853, + -27794987, + 4357047, + 21615530, + 157378, + -15966820, + -2608677, + 11151283, + 3582964, + -7305331, + -3591234, + 4432167, + 3053105, + -2438510, + -2287942, + 1171964, + 1515406, + -455387, + -864980, + 115114, + 392303, + 314802, + 286962, + -666767, + -770294, + 1084460, + 1645778, + -1464285, + -3043497, + 1629818, + 5069939, + -1324554, + -7777414, + 213442, + 11130309, + 2105569, + -14971590, + -6080533, + 18992794, + 12178006, + -22709444, + -20854832, + 25440750, + 32538659, + -26286527, + -47632153, + 24082671, + 66566780, + -17291196, + -89958679, + 3716761, + 118996505, + 20251988, + -156455065, + -61894647, + 209848483, + 140443826, + -304977080, + -333880915, + 600948442, + 1769589865, 1902850390, - 847496679, - -226913303, - -372283380, - 68807659, - 236774674, - -9647574, - -165945535, - -19003403, - 119350297, - 33244565, - -85336463, - -39157837, - 59437518, - 39826637, - -39578279, - -37174170, - 24586275, - 32563209, - -13638378, - -27013696, - 6041195, - 21286636, - -1150926, - -15921547, - -1643439, - 11261717, - 2908988, - -7480648, - -3148631, - 4613546, - 2782392, - -2593034, - -2135956, - 1286090, - 1438742, - -528612, - -831239, - 154393, - 379615, - 332802, - 257712, - -711682, - -717934, - 1179007, - 1570895, - -1639758, - -2956557, - 1925212, - 4996486, - -1783804, - -7763456, - 880437, - 11247265, - 1194295, - -15320128, - -4905375, - 19705005, - 10747874, - -23949064, - -19220536, - 27401610, - 30808227, - -29190139, - -45989263, - 28176961, - 65295977, - -22854386, - -89487127, - 11074335, - 119978364, - 10679592, - -159976512, - -49468489, - 218041439, - 123974649, - -323575351, - -310842754, - 661987843, - 1807082499, + 847496658, + -226913285, + -372283320, + 68807641, + 236774576, + -9647568, + -165945406, + -19003383, + 119350146, + 33244513, + -85336304, + -39157750, + 59437363, + 39826516, + -39578141, + -37174022, + 24586164, + 32563044, + -13638301, + -27013525, + 6041152, + 21286471, + -1150916, + -15921397, + -1643422, + 11261590, + 2908952, + -7480548, + -3148585, + 4613473, + 2782344, + -2592985, + -2135912, + 1286061, + 1438707, + -528598, + -831214, + 154388, + 379601, + 332789, + 257703, + -711660, + -717915, + 1178978, + 1570859, + -1639724, + -2956500, + 1925179, + 4996405, + -1783777, + -7763350, + 880426, + 11247137, + 1194283, + -15319982, + -4905333, + 19704850, + 10747797, + -23948910, + -19220425, + 27401469, + 30808086, + -29190021, + -45989099, + 28176874, + 65295803, + -22854334, + -89486955, + 11074317, + 119978208, + 10679581, + -159976383, + -49468459, + 218041344, + 123974614, + -323575294, + -310842726, + 661987823, + 1807082496, 1873812119, - 785424253, - -257340647, - -357341442, - 88092202, - 231556471, - -23287719, - -164745402, - -8994662, - 120163765, - 25874950, - -87175940, - -33815915, - 61726505, - 36069992, - -41955141, - -34649120, - 26824083, - 30973292, - -15604598, - -26108009, - 7672597, - 20856057, - -2434835, - -15797351, - -684730, - 11313978, - 2231583, - -7615346, - -2698222, - 4768185, - 2503082, - -2731081, - -1976579, - 1390807, - 1356720, - -596914, - -794223, - 191329, - 365359, - 349702, - 225803, - -754267, - -660083, - 1269948, - 1485826, - -1810847, - -2852343, - 2216822, - 4895876, - -2242478, - -7709540, - 1554263, - 11308848, - 262709, - -15596164, - -3688266, - 20327514, - 9243838, - -25084246, - -17467977, - 29249335, - 28900851, - -31982780, - -44094721, - 32179789, - 63681201, - -28372025, - -88559869, - 18472552, - 120370732, - 915415, - -162748389, - -36580913, - 225295349, - 106503594, - -341068138, - -285324689, - 723533401, - 1841857732, - 1841857732, - 723533401, - -285324689, - -341068138, - 106503594, - 225295349, - -36580913, - -162748389, - 915415, - 120370732, - 18472552, - -88559869, - -28372025, - 63681201, - 32179789, - -44094721, - -31982780, - 28900851, - 29249335, - -17467977, - -25084246, - 9243838, - 20327514, - -3688266, - -15596164, - 262709, - 11308848, - 1554263, - -7709540, - -2242478, - 4895876, - 2216822, - -2852343, - -1810847, - 1485826, - 1269948, - -660083, - -754267, - 225803, - 349702, - 365359, - 191329, - -794223, - -596914, - 1356720, - 1390807, - -1976579, - -2731081, - 2503082, - 4768185, - -2698222, - -7615346, - 2231583, - 11313978, - -684730, - -15797351, - -2434835, - 20856057, - 7672597, - -26108009, - -15604598, - 30973292, - 26824083, - -34649120, - -41955141, - 36069992, - 61726505, - -33815915, - -87175940, - 25874950, - 120163765, - -8994662, - -164745402, - -23287719, - 231556471, - 88092202, - -357341442, - -257340647, - 785424253, + 785424232, + -257340626, + -357341382, + 88092178, + 231556374, + -23287705, + -164745272, + -8994653, + 120163611, + 25874909, + -87175776, + -33815839, + 61726343, + 36069882, + -41954994, + -34648981, + 26823962, + 30973135, + -15604509, + -26107843, + 7672543, + 20855894, + -2434814, + -15797202, + -684723, + 11313850, + 2231556, + -7615243, + -2698182, + 4768109, + 2503038, + -2731030, + -1976539, + 1390775, + 1356687, + -596898, + -794200, + 191322, + 365345, + 349689, + 225795, + -754244, + -660065, + 1269916, + 1485793, + -1810810, + -2852289, + 2216784, + 4895798, + -2242445, + -7709436, + 1554243, + 11308720, + 262707, + -15596016, + -3688234, + 20327355, + 9243772, + -25084085, + -17467877, + 29249185, + 28900719, + -31982651, + -44094565, + 32179691, + 63681032, + -28371961, + -88559701, + 18472523, + 120370577, + 915414, + -162748259, + -36580891, + 225295253, + 106503564, + -341068080, + -285324664, + 723533380, + 1841857730, + 1841857730, + 723533380, + -285324664, + -341068080, + 106503564, + 225295253, + -36580891, + -162748259, + 915414, + 120370577, + 18472523, + -88559701, + -28371961, + 63681032, + 32179691, + -44094565, + -31982651, + 28900719, + 29249185, + -17467877, + -25084085, + 9243772, + 20327355, + -3688234, + -15596016, + 262707, + 11308720, + 1554243, + -7709436, + -2242445, + 4895798, + 2216784, + -2852289, + -1810810, + 1485793, + 1269916, + -660065, + -754244, + 225795, + 349689, + 365345, + 191322, + -794200, + -596898, + 1356687, + 1390775, + -1976539, + -2731030, + 2503038, + 4768109, + -2698182, + -7615243, + 2231556, + 11313850, + -684723, + -15797202, + -2434814, + 20855894, + 7672543, + -26107843, + -15604509, + 30973135, + 26823962, + -34648981, + -41954994, + 36069882, + 61726343, + -33815839, + -87175776, + 25874909, + 120163611, + -8994653, + -164745272, + -23287705, + 231556374, + 88092178, + -357341382, + -257340626, + 785424232, 1873812119, - 1807082499, - 661987843, - -310842754, - -323575351, - 123974649, - 218041439, - -49468489, - -159976512, - 10679592, - 119978364, - 11074335, - -89487127, - -22854386, - 65295977, - 28176961, - -45989263, - -29190139, - 30808227, - 27401610, - -19220536, - -23949064, - 10747874, - 19705005, - -4905375, - -15320128, - 1194295, - 11247265, - 880437, - -7763456, - -1783804, - 4996486, - 1925212, - -2956557, - -1639758, - 1570895, - 1179007, - -717934, - -711682, - 257712, - 332802, - 379615, - 154393, - -831239, - -528612, - 1438742, - 1286090, - -2135956, - -2593034, - 2782392, - 4613546, - -3148631, - -7480648, - 2908988, - 11261717, - -1643439, - -15921547, - -1150926, - 21286636, - 6041195, - -27013696, - -13638378, - 32563209, - 24586275, - -37174170, - -39578279, - 39826637, - 59437518, - -39157837, - -85336463, - 33244565, - 119350297, - -19003403, - -165945535, - -9647574, - 236774674, - 68807659, - -372283380, - -226913303, - 847496679, + 1807082496, + 661987823, + -310842726, + -323575294, + 123974614, + 218041344, + -49468459, + -159976383, + 10679581, + 119978208, + 11074317, + -89486955, + -22854334, + 65295803, + 28176874, + -45989099, + -29190021, + 30808086, + 27401469, + -19220425, + -23948910, + 10747797, + 19704850, + -4905333, + -15319982, + 1194283, + 11247137, + 880426, + -7763350, + -1783777, + 4996405, + 1925179, + -2956500, + -1639724, + 1570859, + 1178978, + -717915, + -711660, + 257703, + 332789, + 379601, + 154388, + -831214, + -528598, + 1438707, + 1286061, + -2135912, + -2592985, + 2782344, + 4613473, + -3148585, + -7480548, + 2908952, + 11261590, + -1643422, + -15921397, + -1150916, + 21286471, + 6041152, + -27013525, + -13638301, + 32563044, + 24586164, + -37174022, + -39578141, + 39826516, + 59437363, + -39157750, + -85336304, + 33244513, + 119350146, + -19003383, + -165945406, + -9647568, + 236774576, + 68807641, + -372283320, + -226913285, + 847496658, 1902850390, - 1769589870, - 600948462, - -333880946, - -304977135, - 140443868, - 209848575, - -61894685, - -156455193, - 20252009, - 118996661, - 3716767, - -89958853, - -17291235, - 66566959, - 24082746, - -47632323, - -26286634, - 32538809, - 25440881, - -20854953, - -22709591, - 12178093, - 18992944, - -6080586, - -14971733, - 2105591, - 11130436, - 213445, - -7777520, - -1324574, - 5070021, - 1629846, - -3043555, - -1464315, - 1645816, - 1084487, - -770315, - -666787, - 286971, - 314814, - 392318, - 115117, - -865006, - -455399, - 1515443, - 1171990, - -2287989, - -2438555, - 3053158, - 4432237, - -3591286, - -7305428, - 3583008, - 11151409, - -2608704, - -15966969, - 157379, - 21615697, - 4357077, - -27795161, - -11577918, - 34009357, - 22196693, - -39543466, - -36973178, - 43429207, - 56821613, - -44369735, - -83044852, - 40544116, - 117926072, - -29062407, - -166330332, - 4278182, - 240903821, - 48722651, - -385784715, - -194074134, - 909584664, - 1928885795, - 1729491104, - 540572768, - -354434084, - -285389240, - 155855585, - 200773985, - -73806857, - -152213083, - 29588384, - 117438376, - -3564353, - -89978422, - -11710690, - 67492022, - 19918580, - -49018787, - -23288067, - 34086167, - 23378342, - -22364590, - -21373384, - 13528340, - 18196135, - -7208611, - -14553796, - 2992333, - 10959831, - -443468, - -7752354, - -867124, - 5116629, - 1332306, - -3113264, - -1285525, - 1710451, - 986980, - -817108, - -619904, - 313515, - 295897, - 403319, - 73642, - -895227, - -377528, - 1586266, - 1048879, - -2431707, - -2268096, - 3313797, - 4224679, - -4023763, - -7089875, - 4250135, - 10982682, - -3575704, - -15932213, - 1483787, - 21840154, - 2628058, - -28446809, - -9432409, - 35302615, - 19665486, - -41743155, - -34150142, - 46857709, - 53887892, - -49423851, - -80306817, - 47736183, - 115889804, - -39122330, - -165885041, - 18425782, - 243902060, - 27915162, - -397739328, - -158863411, - 971520455, - 1951840419, - 1686904873, - 481014382, - -372505612, - -264928631, - 170160104, - 190877968, - -85155679, - -147281886, - 38646205, - 115318912, - -10734057, - -89551394, - -6140610, - 68070780, - 15705989, - -50144879, - -20210518, - 35444865, - 21225554, - -23743518, - -19948386, - 14792945, - 17319740, - -8284475, - -14069443, - 3850443, - 10737166, - -1087158, - -7688768, - -413737, - 5136590, - 1034153, - -3165699, - -1104384, - 1764721, - 887079, - -858229, - -571356, - 337295, - 276207, - 412474, - 30126, - -921615, - -295287, - 1650670, - 917185, - -2566162, - -2082201, - 3562749, - 3991438, - -4443647, - -6834390, - 4906837, - 10755463, - -4539538, - -15816262, - 2821819, - 21957408, - 862285, - -28963627, - -7211590, - 36434518, - 17003645, - -43760063, - -31120698, - 50092781, - 50647163, - -54292874, - -77130372, - 54783394, - 113243221, - -49133110, - -164598739, - 32729297, - 245732088, - 6468238, - -408044674, - -121330165, - 1033135130, - 1971645460, - 1641956834, - 422422539, - -388107473, - -243713015, - 183313793, - 180223571, - -95895319, - -141696158, - 47384910, - 112656216, - -17758373, - -88685464, - -608463, - 68304570, - 11466478, - -51008161, - -17070268, - 36610474, - 18994384, - -24986537, - -18442879, - 15966744, - 16369249, - -9303538, - -13522088, - 4676053, - 10464394, - -1714602, - -7587754, + 1769589865, + 600948442, + -333880915, + -304977080, + 140443826, + 209848483, + -61894647, + -156455065, + 20251988, + 118996505, + 3716761, + -89958679, + -17291196, + 66566780, + 24082671, + -47632153, + -26286527, + 32538659, + 25440750, + -20854832, + -22709444, + 12178006, + 18992794, + -6080533, + -14971590, + 2105569, + 11130309, + 213442, + -7777414, + -1324554, + 5069939, + 1629818, + -3043497, + -1464285, + 1645778, + 1084460, + -770294, + -666767, + 286962, + 314802, + 392303, + 115114, + -864980, + -455387, + 1515406, + 1171964, + -2287942, + -2438510, + 3053105, + 4432167, + -3591234, + -7305331, + 3582964, + 11151283, + -2608677, + -15966820, + 157378, + 21615530, + 4357047, + -27794987, + -11577853, + 34009186, + 22196593, + -39543310, + -36973050, + 43429076, + 56821465, + -44369637, + -83044697, + 40544053, + 117925924, + -29062378, + -166330204, + 4278179, + 240903723, + 48722638, + -385784655, + -194074119, + 909584643, + 1928885796, + 1729491098, + 540572749, + -354434050, + -285389187, + 155855538, + 200773895, + -73806811, + -152212957, + 29588353, + 117438220, + -3564347, + -89978246, + -11710663, + 67491839, + 19918518, + -49018611, + -23287972, + 34086009, + 23378221, + -22364460, + -21373246, + 13528243, + 18195991, + -7208548, + -14553656, + 2992301, + 10959705, + -443463, + -7752248, + -867111, + 5116546, + 1332283, + -3113204, + -1285498, + 1710412, + 986956, + -817086, + -619886, + 313504, + 295885, + 403304, + 73640, + -895201, + -377518, + 1586227, + 1048856, + -2431658, + -2268054, + 3313741, + 4224612, + -4023705, + -7089781, + 4250083, + 10982560, + -3575668, + -15932065, + 1483774, + 21839986, + 2628040, + -28446631, + -9432356, + 35302438, + 19665398, + -41742991, + -34150025, + 46857569, + 53887753, + -49423742, + -80306669, + 47736111, + 115889661, + -39122292, + -165884915, + 18425772, + 243901963, + 27915154, + -397739267, + -158863400, + 971520434, + 1951840421, + 1686904866, + 481014364, + -372505574, + -264928581, + 170160052, + 190877881, + -85155625, + -147281763, + 38646163, + 115318757, + -10734039, + -89551218, + -6140596, + 68070595, + 15705939, + -50144697, + -20210435, + 35444700, + 21225443, + -23743379, + -19948256, + 14792838, + 17319601, + -8284403, + -14069307, + 3850403, + 10737042, + -1087145, + -7688663, + -413731, + 5136506, + 1034135, + -3165638, + -1104361, + 1764681, + 887057, + -858206, + -571338, + 337284, + 276196, + 412459, + 30125, + -921588, + -295279, + 1650630, + 917165, + -2566110, + -2082163, + 3562688, + 3991375, + -4443583, + -6834300, + 4906777, + 10755344, + -4539492, + -15816115, + 2821795, + 21957240, + 862279, + -28963446, + -7211550, + 36434337, + 17003569, + -43759892, + -31120591, + 50092632, + 50647034, + -54292756, + -77130232, + 54783311, + 113243082, + -49133062, + -164598616, + 32729279, + 245731993, + 6468236, + -408044613, + -121330157, + 1033135110, + 1971645464, + 1641956825, + 422422522, + -388107433, + -243712967, + 183313736, + 180223488, + -95895257, + -141696037, + 47384858, + 112656063, + -17758344, + -88685288, + -608461, + 68304383, + 11466442, + -51007975, + -17070197, + 36610302, + 18994284, + -24986390, + -18442759, + 15966628, + 16369117, + -9303456, + -13521957, + 4676003, + 10464273, + -1714580, + -7587650, 33364, - 5130317, - 736921, - -3200967, - -921882, - 1808602, - 785374, - -893629, - -521462, - 358281, - 255902, - 419644, + 5130233, + 736907, + -3200905, + -921862, + 1808560, + 785355, + -893604, + -521446, + 358269, + 255892, + 419629, -15255, - -943897, - -208996, - 1708137, - 777396, - -2690431, - -1881508, - 3798481, - 3733226, - -4848544, - -6539588, - 5549577, - 10469975, - -5495243, - -15618499, - 4164848, - 21965372, - -931799, - -29341220, - -4925707, - 37397310, - 14222955, - -45581779, - -27897550, - 53115794, - 47111907, - -58950082, - -73525820, - 61648604, - 109991099, - -59044202, - -162464447, - 47120910, - 246361409, - -15530266, - -416602245, - -81532107, - 1094259174, - 1988241480, - 1594779183, - 364941607, - -401259958, - -221860366, - 195279161, - 168876251, - -105983599, - -135493101, - 55766057, - 109470657, - -24604478, - -87390395, - 4858808, - 68196421, - 7221428, - -51607535, - -13883708, - 37579584, - 16696942, - -26089194, - -16865443, - 17045096, - 15350449, - -10261510, - -12915413, - 5465516, - 10143692, - -2322908, - -7450477, - 472032, - 5098349, - 442105, - -3219259, - -738991, - 1842125, - 682450, - -923288, - -470543, - 376461, - 235134, - 424699, - -62308, - -961813, - -119006, - 1758172, - 630051, - -2803627, - -1666745, - 4019502, - 3450898, - -5236095, - -6206299, - 6174832, - 10126745, - -6437824, - -15338717, - 5506125, - 21862485, - -2745490, - -29575844, - -2585467, - 38183992, - 11335951, - -47196722, - -24494534, - 55908959, - 43296232, - -63369475, - -69505728, - 68295090, - 106141279, - -68804818, - -159479215, - 61531206, - 245762565, - -37987969, - -423318009, - -39535524, - 1154723052, - 2001578612, - 1545510183, - 308710631, - -411991515, - -199488456, - 206024904, - 156903537, - -115382139, - -128712349, - 63753480, - 105784895, - -31240843, - -85677948, - 10234907, - 67751021, - 2991989, - -51943227, - -10667262, - 38349806, - 14345515, - -27047795, - -15224902, - 18023904, - 14269391, - -11154471, - -12253345, - 6215426, - 9777442, - -2909331, - -7278267, - 900198, - 5041346, - 151162, - -3220852, - -556665, - 1865377, - 578880, - -947221, - -418912, - 391840, - 214053, - 427516, - -110822, - -975120, - -25700, - 1800309, - 475748, - -2904900, - -1438732, - 4224365, - 3145451, - -5603989, - -5835563, - 6779111, - 9726604, - -7362275, - -14977124, - 6838813, - 21647729, - -4569872, - -29664429, - -201990, - 38788367, - 8355856, - -48594211, - -20926560, - 58455422, - 39215828, - -67525922, - -65084899, - 74686731, - 101704667, - -78364169, - -155644208, - 75889473, - 243913355, - -60808263, - -428102842, - 4584865, - 1214357798, - 2011616748, - 1494293678, - 253862892, - -420338540, - -176714395, - 215525925, - 144374684, - -124056476, - -121395745, - 71313432, - 101623741, - -37637370, - -83561796, - 15494312, - 66974672, - -1201021, - -52016772, - -7437303, - 38919774, - 11952509, - -27859415, - -13530282, - 18899622, - 13132354, - -11978882, - -11540030, - 6922626, - 9368222, - -3471282, - -7072607, - 1315887, - 4960086, - -134504, - -3206104, - -375831, - 1878496, - 475230, - -965474, - -366878, - 404438, - 192807, - 427981, - -160571, - -983597, - 70510, - 1834110, - 315133, - -2993447, - -1198374, - 4411680, - 2818022, - -5949973, - -5428636, - 7358972, - 9270690, - -8263609, - -14534351, - 8156023, - 21320641, - -6395851, - -29604604, - 2213243, - 39205082, - 5296530, - -49764528, - -17209548, - 60739362, - 34887901, - -71395293, - -60280322, - 80788198, - 96695227, - -87671716, - -150964753, - 90124014, - 240797033, - -83890644, - -430872949, - 50746076, - 1272995597, - 2018325678, - 1441278573, - 200525502, - -426345130, - -153654181, - 223763329, - 131360328, - -131976165, - -113587103, - 78414720, - 97014010, - -43765527, - -81057436, - 20612387, - 65875244, - -5337219, - -51830991, - -4210069, - 39289138, - 9530377, - -28521901, - -11790762, - 19669273, - 11945809, - -12731604, - -10779812, - 7584225, - 8918784, - -4006339, - -6835125, - 1717224, - 4855453, - -413545, - -3175447, - -197388, - 1881670, - 372046, - -978120, - -314741, - 414292, - 171535, - 425991, - -211313, - -987038, - 169186, - 1859173, - 148902, - -3068510, - -946664, - 4580122, - 2469883, - -6271869, - -4986978, - 7911043, - 8760444, - -9136879, - -14011450, - 9450845, - 20881323, - -8214204, - -29394721, - 4648441, - 39429663, - 2172403, - -50698982, - -13360365, - 62746086, - 30331112, - -74954592, - -55111115, - 86565139, - 91129950, - -96677417, - -145450386, - 104162468, - 236402487, - -107131055, - -431550259, - 98857077, - 1330470362, - 2021685202, - 1386618319, - 148819018, - -430062814, - -130422250, - 230724389, - 117932138, - -139114863, - -105331978, - 85028813, - 91984362, - -49598462, - -78182089, - 25565498, - 64462109, - -9396746, - -51389962, - -1001588, - 39458553, - 7091565, - -29033872, - -10015623, - 20330450, - 10716388, - -13409901, - -9977208, - 8197609, - 8432040, - -4512257, - -6567585, - 2102440, - 4728437, - -684671, - -3129391, + -943870, + -208990, + 1708096, + 777379, + -2690377, + -1881473, + 3798417, + 3733167, + -4848474, + -6539502, + 5549510, + 10469859, + -5495187, + -15618355, + 4164813, + 21965205, + -931792, + -29341039, + -4925680, + 37397125, + 14222893, + -45581602, + -27897455, + 53115638, + 47111788, + -58949955, + -73525687, + 61648512, + 109990966, + -59044145, + -162464327, + 47120885, + 246361315, + -15530263, + -416602185, + -81532102, + 1094259154, + 1988241483, + 1594779173, + 364941592, + -401259915, + -221860321, + 195279098, + 168876171, + -105983530, + -135492984, + 55765995, + 109470507, + -24604437, + -87390220, + 4858796, + 68196233, + 7221405, + -51607346, + -13883650, + 37579406, + 16696853, + -26089040, + -16865332, + 17044972, + 15350326, + -10261419, + -12915287, + 5465458, + 10143573, + -2322879, + -7450374, + 472025, + 5098265, + 442097, + -3219196, + -738976, + 1842083, + 682432, + -923262, + -470529, + 376448, + 235124, + 424684, + -62306, + -961785, + -119003, + 1758130, + 630038, + -2803571, + -1666714, + 4019434, + 3450844, + -5236020, + -6206217, + 6174758, + 10126633, + -6437759, + -15338576, + 5506079, + 21862319, + -2745472, + -29575662, + -2585453, + 38183804, + 11335901, + -47196540, + -24494452, + 55908795, + 43296123, + -63369339, + -69505604, + 68294989, + 106141151, + -68804752, + -159479099, + 61531173, + 245762473, + -37987959, + -423317950, + -39535521, + 1154723033, + 2001578616, + 1545510172, + 308710617, + -411991470, + -199488415, + 206024836, + 156903461, + -115382063, + -128712237, + 63753409, + 105784748, + -31240790, + -85677775, + 10234883, + 67750832, + 2991980, + -51943035, + -10667218, + 38349624, + 14345439, + -27047635, + -15224801, + 18023772, + 14269276, + -11154371, + -12253225, + 6215359, + 9777328, + -2909294, + -7278166, + 900184, + 5041263, + 151159, + -3220789, + -556654, + 1865334, + 578866, + -947195, + -418899, + 391826, + 214045, + 427500, + -110818, + -975093, + -25699, + 1800266, + 475738, + -2904843, + -1438705, + 4224294, + 3145402, + -5603909, + -5835487, + 6779029, + 9726497, + -7362201, + -14976987, + 6838756, + 21647565, + -4569841, + -29664247, + -201989, + 38788177, + 8355819, + -48594025, + -20926490, + 58455252, + 39215730, + -67525778, + -65084783, + 74686621, + 101704546, + -78364095, + -155644096, + 75889433, + 243913265, + -60808248, + -428102784, + 4584864, + 1214357780, + 2011616752, + 1494293665, + 253862880, + -420338492, + -176714358, + 215525853, + 144374613, + -124056393, + -121395638, + 71313352, + 101623599, + -37637306, + -83561626, + 15494275, + 66974485, + -1201017, + -52016579, + -7437271, + 38919589, + 11952445, + -27859249, + -13530192, + 18899483, + 13132247, + -11978775, + -11539916, + 6922551, + 9368112, + -3471237, + -7072508, + 1315867, + 4960004, + -134502, + -3206041, + -375823, + 1878452, + 475218, + -965447, + -366867, + 404424, + 192799, + 427966, + -160565, + -983569, + 70509, + 1834066, + 315126, + -2993387, + -1198352, + 4411606, + 2817978, + -5949889, + -5428565, + 7358884, + 9270589, + -8263527, + -14534218, + 8155955, + 21320481, + -6395808, + -29604423, + 2213230, + 39204891, + 5296507, + -49764339, + -17209491, + 60739187, + 34887814, + -71395142, + -60280215, + 80788080, + 96695113, + -87671635, + -150964646, + 90123967, + 240796946, + -83890624, + -430872893, + 50746073, + 1272995580, + 2018325683, + 1441278560, + 200525492, + -426345080, + -153654148, + 223763252, + 131360263, + -131976075, + -113587002, + 78414631, + 97013873, + -43765452, + -81057270, + 20612337, + 65875058, + -5337201, + -51830798, + -4210051, + 39288950, + 9530326, + -28521729, + -11790683, + 19669128, + 11945711, + -12731490, + -10779706, + 7584144, + 8918679, + -4006287, + -6835030, + 1717198, + 4855373, + -413537, + -3175385, + -197384, + 1881626, + 372037, + -978093, + -314731, + 414278, + 171528, + 425976, + -211306, + -987010, + 169182, + 1859130, + 148898, + -3068450, + -946646, + 4580045, + 2469845, + -6271781, + -4986913, + 7910949, + 8760348, + -9136788, + -14011323, + 9450768, + 20881167, + -8214148, + -29394543, + 4648416, + 39429472, + 2172394, + -50698790, + -13360321, + 62745906, + 30331038, + -74954436, + -55111019, + 86565015, + 91129844, + -96677329, + -145450284, + 104162415, + 236402403, + -107131031, + -431550204, + 98857072, + 1330470346, + 2021685208, + 1386618304, + 148819010, + -430062761, + -130422221, + 230724308, + 117932078, + -139114767, + -105331883, + 85028715, + 91984231, + -49598376, + -78181927, + 25565435, + 64461926, + -9396715, + -51389769, + -1001584, + 39458363, + 7091526, + -29033697, + -10015556, + 20330299, + 10716300, + -13409780, + -9977109, + 8197520, + 8431940, + -4512199, + -6567493, + 2102408, + 4728358, + -684659, + -3129329, -22201, - 1875135, - 269861, - -985265, - -262792, - 421455, - 150373 + 1875091, + 269854, + -985237, + -262784, + 421440, + 150367 }; diff --git a/src/audio/src/coef/src_ipc4_int32_21_4_1080_5000.h b/src/audio/src/coef/src_ipc4_int32_21_4_1080_5000.h index a4011678f867..e3c84132ecb0 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_4_1080_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_4_1080_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_4_1080_5000_fir[336] = { +__cold_rodata static const int32_t src_int32_21_4_1080_5000_fir[336] = { 139978, 2034094, -10158575, diff --git a/src/audio/src/coef/src_ipc4_int32_21_4_3239_5000.h b/src/audio/src/coef/src_ipc4_int32_21_4_3239_5000.h index d73ebbd2afed..c950787ac76e 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_4_3239_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_4_3239_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_4_3239_5000_fir[672] = { +__cold_rodata static const int32_t src_int32_21_4_3239_5000_fir[672] = { -35812, 307539, -973534, diff --git a/src/audio/src/coef/src_ipc4_int32_21_5_1728_5000.h b/src/audio/src/coef/src_ipc4_int32_21_5_1728_5000.h index 4a7e1c132eee..2afa32a460e6 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_5_1728_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_5_1728_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_5_1728_5000_fir[420] = { +__cold_rodata static const int32_t src_int32_21_5_1728_5000_fir[420] = { 99153, 137369, -3779111, diff --git a/src/audio/src/coef/src_ipc4_int32_21_5_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_5_4535_5000.h index 84d603013e34..16d3af828ad9 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_5_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_5_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_5_4535_5000_fir[2184] = { +__cold_rodata static const int32_t src_int32_21_5_4535_5000_fir[2184] = { -46288, 73523, -104226, diff --git a/src/audio/src/coef/src_ipc4_int32_21_80_3968_5000.h b/src/audio/src/coef/src_ipc4_int32_21_80_3968_5000.h index b98729cef63c..66ae1019b3f5 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_80_3968_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_80_3968_5000.h @@ -1,3374 +1,3373 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2022 Intel Corporation. All rights reserved. + * Copyright(c) 2025 Intel Corporation. All rights reserved. * */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ - #include <stdint.h> -static const int32_t src_int32_21_80_3968_5000_fir[3360] = { - 146819, - 357423, - 426811, - 219294, - -251856, - -770176, - -993037, - -648976, - 246030, - 1299535, - 1882279, - 1470602, - 21093, - -1861523, - -3129465, - -2835643, - -754121, - 2297815, - 4710653, - 4883653, - 2203423, - -2364359, - -6516164, - -7712320, - -4646907, - 1728002, - 8326058, - 11343000, - 8362508, - 27219, - -9791094, - -15685038, - -13593540, - -3384245, - 10421153, - 20502343, - 20510613, - 8870214, - -9580841, - -25384728, - -29175061, - -17032538, - 6488017, - 29723933, - 39509406, - 28424015, - -204430, - -32688951, - -51280307, - -43614233, - -10404437, - 33184686, - 64098663, - 63258609, - 26788801, - -29754802, - -77440429, - -88291119, - -51025741, - 20330768, - 90691381, - 120407205, - 86623547, - -1550575, - -103223048, - -163347747, - -140794695, - -33297440, - 114530716, - 226975349, - 232280856, - 101992233, - -124606291, - -345267058, - -430652075, - -278563886, - 136162146, - 738984246, - 1372717392, - 1850114519, - 2021998805, - 1833424472, - 1344641025, - 708112428, - 111179278, - -291941169, - -431394970, - -336816574, - -112958510, - 110968459, - 235120279, - 223592403, - 107644124, - -39847938, - -143963326, - -162153646, - -98894321, - 3372665, - 89675307, - 120360334, - 87980605, - 16626571, - -53783496, - -88869288, - -75825808, - -27010990, - 29173196, - 64151963, - 63240089, - 31208599, - -12387911, - -44624159, - -50934572, - -31321961, - 1384216, - 29421689, - 39495019, - 28829324, - 5264902, - -17938259, - -29355809, - -24843818, - -8678748, - 9640746, - 20786581, - 20213858, - 9787219, - -4003470, - -13894982, - -15565383, - -9370013, - 498371, - 8644656, - 11326258, - 8064891, - 1389057, - -4884991, - -7749481, - -6367864, - -2134847, - 2387805, - 4940973, - 4636241, - 2152682, - -885675, - -2892297, - -3098911, - -1776863, - 107080, - 1515896, - 1874275, - 1254823, - 195379, - -679454, - -993948, - -749381, - -225914, - 236048, - 429117, - 349205, - 157462, - 365315, - 423847, - 201900, - -277933, - -790288, - -990782, - -617172, - 297090, - 1343161, - 1887932, - 1422823, - -65970, - -1944773, - -3156334, - -2774723, - -620202, - 2441503, - 4779790, - 4819543, - 2014485, - -2592983, - -6657517, - -7665039, - -4400880, - 2067608, - 8578832, - 11345524, - 8067558, - -447619, - -10203014, - -15785794, - -13272741, - -2756284, - 11046462, - 20767030, - 20206928, - 8083287, - -10476934, - -25897307, - -28956467, - -16099560, - 7710817, - 30586898, - 39474293, - 27384446, - -1802675, - -34023377, - -51563863, - -42543443, - -8395792, - 35131268, - 64882177, - 62280516, - 24356135, - -32478390, - -78968185, - -87598721, - -48186372, - 24033706, - 93306662, - 120303644, - 83441981, - -6507383, - -107454861, - -164346588, - -137423961, - -26649095, - 121336454, - 230106790, - 229120403, - 92784901, - -136246221, - -353405569, - -429355439, - -264571182, - 161588079, - 769932249, - 1400431758, - 1866093079, - 2021158536, - 1816035369, - 1316222776, - 677337096, - 86652778, - -304700747, - -431592314, - -328068253, - -101316638, - 119705530, - 237638600, - 219964459, - 100685769, - -46293428, - -146927604, - -160767253, - -94474723, - 8256511, - 92594397, - 120164104, - 85178318, - 12925710, - -56456740, - -89333230, - -74126867, - -24250490, - 31506652, - 64959983, - 62307980, - 29205647, - -14343893, - -45572330, - -50527469, - -29924311, - 2961339, - 30376479, - 39431459, - 27904391, - 4043005, - -18815763, - -29498730, - -24275440, - -7771825, - 10394026, - 21034673, - 19902100, - 9145515, - -4613243, - -14176830, - -15427120, - -8940372, - 965272, - 8913746, - 11295434, - 7795729, - 1051196, - -5114899, - -7776561, - -6212867, - -1904748, - 2567439, - 4991494, - 4556701, - 2006303, - -1014720, - -2944658, - -3064752, - -1690919, - 191894, - 1558675, - 1863962, - 1209098, - 145200, - -708584, - -993536, - -727943, - -200139, - 252151, - 430776, - 340682, - 168156, - 372863, - 420216, - 183879, - -304109, - -809678, - -987166, - -584064, - 348497, - 1385628, - 1891195, - 1372590, - -154006, - -2026487, - -3179441, - -2709570, - -484066, - 2583545, - 4843510, - 4748659, - 1821190, - -2820417, - -6791681, - -7607610, - -4147157, - 2407448, - 8822821, - 11333714, - 7760079, - -925568, - -10605183, - -15867383, - -12932851, - -2120320, - 11662293, - 21007416, - 19875719, - 7280845, - -11365856, - -26380722, - -28700054, - -15140322, - 8931761, - 31416935, - 39389414, - 26304026, - -3408570, - -35323362, - -51784505, - -41412758, - -6364340, - 37045725, - 65589190, - 61218390, - 21877945, - -35178226, - -80406623, - -86792235, - -45268409, - 27730760, - 95822557, - 120048754, - 80133655, - -11491852, - -111583795, - -165147414, - -133853634, - -19910239, - 128052261, - 232980456, - 225639370, - 83354863, - -147864382, - -361218117, - -427497295, - -249965892, - 187443315, - 800935966, - 1427764213, +__cold_rodata static const int32_t src_int32_21_80_3968_5000_fir[3360] = { + 146838, + 357465, + 426859, + 219317, + -251881, + -770248, + -993125, + -649031, + 246050, + 1299636, + 1882418, + 1470706, + 21094, + -1861644, + -3129659, + -2835812, + -754164, + 2297941, + 4710900, + 4883899, + 2203530, + -2364469, + -6516452, + -7712648, + -4647096, + 1728069, + 8326368, + 11343404, + 8362794, + 27220, + -9791399, + -15685505, + -13593926, + -3384336, + 10421422, + 20502848, + 20511093, + 8870412, + -9581044, + -25385237, + -29175616, + -17032845, + 6488128, + 29724411, + 39510006, + 28424422, + -204433, + -32689364, + -51280914, + -43614716, + -10404545, + 33185006, + 64099238, + 63259135, + 26789007, + -29755013, + -77440934, + -88291646, + -51026020, + 20330869, + 90691788, + 120407692, + 86623861, + -1550580, + -103223342, + -163348156, + -140795002, + -33297503, + 114530898, + 226975652, + 232281111, + 101992324, + -124606378, + -345267242, + -430652242, + -278563960, + 136162169, + 738984313, + 1372717440, + 1850114523, + 2021998788, + 1833424479, + 1344641075, + 708112494, + 111179297, + -291941249, + -431395141, + -336816756, + -112958590, + 110968558, + 235120540, + 223592705, + 107644297, + -39848013, + -143963642, + -162154054, + -98894605, + 3372676, + 89675634, + 120360823, + 87981002, + 16626654, + -53783791, + -88869821, + -75826305, + -27011183, + 29173421, + 64152498, + 63240658, + 31208901, + -12388039, + -44624655, + -50935177, + -31322357, + 1384234, + 29422111, + 39495620, + 28829789, + 5264992, + -17938582, + -29356369, + -24844318, + -8678932, + 9640961, + 20787068, + 20214356, + 9787472, + -4003579, + -13895378, + -15565847, + -9370306, + 498388, + 8644952, + 11326663, + 8065192, + 1389111, + -4885190, + -7749810, + -6368146, + -2134946, + 2387921, + 4941222, + 4636485, + 2152800, + -885726, + -2892469, + -3099104, + -1776979, + 107087, + 1516003, + 1874414, + 1254920, + 195395, + -679512, + -994037, + -749451, + -225936, + 236073, + 429165, + 349247, + 157482, + 365359, + 423894, + 201921, + -277961, + -790362, + -990870, + -617224, + 297114, + 1343265, + 1888071, + 1422923, + -65974, + -1944898, + -3156530, + -2774888, + -620237, + 2441637, + 4780040, + 4819785, + 2014582, + -2593103, + -6657812, + -7665364, + -4401059, + 2067689, + 8579151, + 11345928, + 8067833, + -447634, + -10203332, + -15786263, + -13273118, + -2756359, + 11046746, + 20767539, + 20207400, + 8083466, + -10477155, + -25897826, + -28957016, + -16099849, + 7710948, + 30587389, + 39474890, + 27384836, + -1802699, + -34023805, + -51564472, + -42543913, + -8395879, + 35131605, + 64882756, + 62281032, + 24356322, + -32478620, + -78968698, + -87599242, + -48186634, + 24033824, + 93307080, + 120304128, + 83442282, + -6507404, + -107455166, + -164346997, + -137424258, + -26649145, + 121336645, + 230107095, + 229120653, + 92784982, + -136246316, + -353405755, + -429355604, + -264571251, + 161588105, + 769932316, + 1400431804, + 1866093081, + 2021158519, + 1816035377, + 1316222828, + 677337162, + 86652793, + -304700832, + -431592487, + -328068432, + -101316711, + 119705639, + 237638866, + 219964758, + 100685932, + -46293516, + -146927929, + -160767661, + -94474995, + 8256538, + 92594737, + 120164595, + 85178705, + 12925775, + -56457051, + -89333768, + -74127355, + -24250663, + 31506896, + 64960527, + 62308543, + 29205930, + -14344043, + -45572838, + -50528071, + -29924691, + 2961379, + 30376916, + 39432061, + 27904842, + 4043074, + -18816103, + -29499294, + -24275930, + -7771990, + 10394258, + 21035168, + 19902592, + 9145753, + -4613369, + -14177235, + -15427581, + -8940652, + 965304, + 8914051, + 11295839, + 7796021, + 1051237, + -5115107, + -7776893, + -6213144, + -1904836, + 2567563, + 4991746, + 4556941, + 2006413, + -1014778, + -2944834, + -3064943, + -1691029, + 191907, + 1558785, + 1864100, + 1209192, + 145212, + -708645, + -993625, + -728012, + -200159, + 252177, + 430824, + 340724, + 168178, + 372908, + 420263, + 183899, + -304139, + -809753, + -987254, + -584114, + 348525, + 1385735, + 1891334, + 1372687, + -154017, + -2026617, + -3179638, + -2709731, + -484093, + 2583686, + 4843763, + 4748897, + 1821278, + -2820547, + -6791981, + -7607932, + -4147325, + 2407541, + 8823149, + 11334116, + 7760343, + -925598, + -10605513, + -15867854, + -12933217, + -2120377, + 11662592, + 21007931, + 19876182, + 7281007, + -11366095, + -26381249, + -28700597, + -15140593, + 8931913, + 31417438, + 39390008, + 26304400, + -3408616, + -35323806, + -51785114, + -41413214, + -6364406, + 37046080, + 65589773, + 61218895, + 21878112, + -35178474, + -80407143, + -86792749, + -45268654, + 27730896, + 95822983, + 120049235, + 80133942, + -11491889, + -111584109, + -165147822, + -133853922, + -19910275, + 128052462, + 232980762, + 225639614, + 83354936, + -147864483, + -361218304, + -427497456, + -249965956, + 187443345, + 800936034, + 1427764257, 1881348240, - 2019478630, - 1797960144, - 1287482951, - 646678369, - 62595481, - -316840882, - -431252706, - -319036355, - -89694269, - 128195756, - 239836116, - 216098249, - 93664748, - -52626938, - -149685546, - -159191748, - -89970358, - 13095225, - 95378134, - 119819768, - 82288594, - 9232748, - -59042696, - -89683087, - -72346240, - -21476833, - 33786580, - 65682185, - 61303943, - 27178487, - -16270115, - -46457941, - -50059881, - -28497935, - 4525040, - 31287460, - 39319113, - 26950480, - 2823845, - -19664133, - -29603889, - -23680487, - -6861240, - 11129226, - 21254770, - 19567623, - 8496904, - -5212866, - -14438872, - -15270560, - -8502776, - 1427365, - 9169539, - 11250679, - 7518978, - 714838, - -5336407, - -7793616, - -6051431, - -1674358, - 2742139, - 5035218, - 4472185, - 1858880, - -1141116, - -2992704, - -3027072, - -1603816, - 275436, - 1598915, - 1851381, - 1162435, - 95553, - -736347, - -991822, - -705903, - -174566, - 267591, - 431797, - 331874, - 178885, - 380048, - 415910, - 165246, - -330350, - -828307, - -982173, - -549679, - 400187, - 1426863, - 1892034, - 1319939, - -242912, - -2106540, - -3198715, - -2640223, - -345866, - 2723740, - 4901677, - 4671028, - 1623747, - -3046359, - -6918419, - -7540017, - -3885995, - 2747089, - 9057644, - 11307469, - 7440364, - -1406046, - -10997016, - -15929560, - -12574161, - -1477099, - 12267799, - 21223030, - 19517214, - 6463799, - -12246437, - -26834171, - -28405899, - -14155864, - 10149301, - 32212791, - 39254563, - 25183858, - -5020146, - -36587063, - -51941568, - -40223232, - -4312488, - 38925463, - 66218349, - 60073043, - 19357049, - -37850785, - -81753387, - -85871945, - -42274984, - 31417284, - 98235268, - 119641820, - 76701791, - -16497998, - -115603964, - -165747693, - -130086491, - -13088379, - 134669090, - 235590323, - 221838583, - 73710868, - -159446712, - -368690869, - -425070306, - -234751400, - 213713645, - 831974773, - 1454695068, - 1895868617, - 2016960352, - 1779212227, - 1258442029, - 616156159, - 39019747, - -328360384, - -430385145, - -309735257, - -78104812, - 136431810, - 241713496, - 212000723, - 86590153, - -58841684, - -152235429, - -157430516, - -85387394, - 17883169, - 98024018, - 119328748, - 79315582, - 5552206, - -61538716, - -89919141, - -70486646, - -18693548, - 36010472, - 66318193, - 60229665, - 25129792, - -18164356, - -47280267, - -49532760, - -27044787, - 6073452, - 32153764, - 39158426, - 25968966, - 1608930, - -20482495, - -29671401, - -23059879, - -5948160, - 11845546, - 21446787, - 19211004, - 7842248, - -5801658, - -14680921, - -15096036, - -8057837, - 1884105, - 9411818, - 11192159, - 7235049, - 380396, - -5549308, - -7800709, - -5883817, - -1443973, - 2911730, - 5072154, - 4382850, - 1710611, - -1264729, - -3036421, - -2985959, - -1515681, - 357615, - 1636595, - 1836579, - 1114907, - 46496, - -762726, - -988828, - -683299, - -149226, - 282359, - 432193, - 322801, - 189633, - 386849, - 410921, - 146016, - -356618, - -846136, - -975788, - -514044, - 452093, - 1466794, - 1890416, - 1264910, - -332581, - -2184808, - -3214086, - -2566725, - -205762, - 2861889, - 4954160, - 4586684, - 1422369, - -3270506, - -7037503, - -7462258, - -3617666, - 3086098, - 9282926, - 11266708, - 7108724, - -1888461, - -11377938, - -15972100, - -12196987, - -827385, - 12862143, - 21413426, - 19131680, - 5633079, - -13117512, - -27256884, - -28074127, - -13147263, - 11361881, - 32973248, - 39069596, - 24025103, - -6635413, - -37812670, - -52034466, - -38975995, - -2242684, - 40767914, - 66768391, - 58845399, - 16796337, - -40492559, - -83006219, - -84838279, - -39209348, - 35088614, - 100541104, - 119082310, - 73149785, - -21519765, - -119509575, - -166145115, - -126125565, - -6191189, - 141177928, - 237930621, - 217719249, - 63862005, - -170979018, - -375810166, - -422067577, - -218931642, - 240384423, - 863027912, - 1481204879, - 1909643363, - 2013605600, - 1759805529, - 1229120642, - 585790160, - 15937452, - -339258605, - -428999017, - -300179433, - -66561486, - 144406731, - 243271770, - 207679038, - 79471061, - -64931084, - -154575798, - -155487140, - -80732047, - 22614803, - 100529736, - 118692641, - 76263512, - 1888563, - -63942277, - -90041816, - -68550885, - -15904152, - 38175906, - 66867740, - 59086909, - 23062244, - -20024451, - -48038669, - -48947125, - -25566845, - 7604733, - 32974587, - 38949900, - 24961252, - 399753, - -21270018, - -29701426, - -22414562, - -5033746, - 12542215, - 21610675, - 18832844, - 7182413, - -6378956, - -14902819, - -14903901, - -7606170, - 2334957, - 9640382, - 11120060, - 6944359, - 48277, - -5753405, - -7797920, - -5710294, - -1213887, - 3076044, - 5102320, - 4288858, - 1561696, - -1385428, - -3075799, - -2941505, - -1426641, - 438340, - 1671698, - 1819605, - 1066589, + 2019478613, + 1797960154, + 1287483005, + 646678433, + 62595492, + -316840972, + -431252882, + -319036532, + -89694334, + 128195874, + 239836388, + 216098545, + 93664901, + -52627039, + -149685878, + -159192155, + -89970620, + 13095268, + 95378485, + 119820260, + 82288969, + 9232794, + -59043023, + -89683630, + -72346718, + -21476987, + 33786842, + 65682737, + 61304499, + 27178752, + -16270285, + -46458460, + -50060480, + -28498298, + 4525102, + 31287911, + 39319715, + 26950917, + 2823893, + -19664490, + -29604456, + -23680966, + -6861386, + 11129476, + 21255272, + 19568108, + 8497125, + -5213009, + -14439285, + -15271018, + -8503043, + 1427412, + 9169854, + 11251083, + 7519260, + 714866, + -5336626, + -7793948, + -6051701, + -1674435, + 2742272, + 5035473, + 4472421, + 1858982, + -1141182, + -2992883, + -3027261, + -1603921, + 275455, + 1599028, + 1851519, + 1162525, + 95561, + -736410, + -991911, + -705969, + -174583, + 267619, + 431846, + 331915, + 178908, + 380093, + 415956, + 165264, + -330382, + -828384, + -982260, + -549725, + 400219, + 1426972, + 1892173, + 1320032, + -242928, + -2106675, + -3198912, + -2640379, + -345886, + 2723888, + 4901932, + 4671262, + 1623825, + -3046499, + -6918724, + -7540335, + -3886153, + 2747196, + 9057980, + 11307870, + 7440616, + -1406092, + -10997357, + -15930031, + -12574516, + -1477139, + 12268114, + 21223548, + 19517668, + 6463941, + -12246694, + -26834705, + -28406435, + -14156117, + 10149472, + 32213305, + 39255154, + 25184215, + -5020213, + -36587521, + -51942177, + -40223673, + -4312532, + 38925834, + 66218936, + 60073537, + 19357196, + -37851051, + -81753914, + -85872452, + -42275212, + 31417437, + 98235703, + 119642297, + 76702064, + -16498050, + -115604288, + -165748100, + -130086768, + -13088403, + 134669299, + 235590630, + 221838820, + 73710932, + -159446820, + -368691058, + -425070464, + -234751459, + 213713679, + 831974841, + 1454695110, + 1895868616, + 2016960336, + 1779212239, + 1258442085, + 616156222, + 39019755, + -328360478, + -430385323, + -309735431, + -78104870, + 136431936, + 241713773, + 212001016, + 86590296, + -58841798, + -152235770, + -157430920, + -85387644, + 17883228, + 98024381, + 119329241, + 79315946, + 5552234, + -61539058, + -89919688, + -70487114, + -18693683, + 36010753, + 66318752, + 60230212, + 25130038, + -18164547, + -47280798, + -49533354, + -27045133, + 6073534, + 32154229, + 39159027, + 25969389, + 1608958, + -20482868, + -29671971, + -23060347, + -5948287, + 11845812, + 21447294, + 19211481, + 7842453, + -5801817, + -14681342, + -15096490, + -8058090, + 1884167, + 9412142, + 11192562, + 7235321, + 380411, + -5549536, + -7801043, + -5884080, + -1444041, + 2911872, + 5072411, + 4383081, + 1710706, + -1264801, + -3036603, + -2986146, + -1515780, + 357640, + 1636712, + 1836716, + 1114994, + 46499, + -762791, + -988916, + -683364, + -149241, + 282389, + 432242, + 322840, + 189657, + 386894, + 410967, + 146031, + -356653, + -846214, + -975874, + -514087, + 452129, + 1466906, + 1890555, + 1264999, + -332603, + -2184949, + -3214284, + -2566877, + -205773, + 2862044, + 4954418, + 4586913, + 1422437, + -3270656, + -7037812, + -7462572, + -3617812, + 3086217, + 9283269, + 11267107, + 7108964, + -1888522, + -11378290, + -15972572, + -12197331, + -827407, + 12862473, + 21413948, + 19132124, + 5633203, + -13117786, + -27257425, + -28074655, + -13147498, + 11362072, + 32973773, + 39070182, + 24025442, + -6635502, + -37813141, + -52035075, + -38976421, + -2242707, + 40768302, + 66768981, + 58845881, + 16796464, + -40492842, + -83006752, + -84838777, + -39209559, + 35088785, + 100541547, + 119082782, + 73150044, + -21519833, + -119509908, + -166145521, + -126125832, + -6191200, + 141178145, + 237930927, + 217719480, + 63862060, + -170979132, + -375810355, + -422067731, + -218931696, + 240384460, + 863027979, + 1481204920, + 1909643360, + 2013605585, + 1759805544, + 1229120698, + 585790223, + 15937455, + -339258704, + -428999197, + -300179605, + -66561535, + 144406866, + 243272051, + 207679327, + 79471192, + -64931210, + -154576147, + -155487542, + -80732284, + 22614878, + 100530111, + 118693134, + 76263863, + 1888573, + -63942633, + -90042366, + -68551341, + -15904267, + 38176205, + 66868307, + 59087448, + 23062470, + -20024661, + -48039210, + -48947714, + -25567173, + 7604837, + 32975066, + 38950500, + 24961659, + 399760, + -21270406, + -29701998, + -22415018, + -5033853, + 12542498, + 21611187, + 18833313, + 7182600, + -6379131, + -14903247, + -14904350, + -7606410, + 2335035, + 9640715, + 11120461, + 6944621, + 48279, + -5753642, + -7798254, + -5710550, + -1213944, + 3076193, + 5102579, + 4289085, + 1561782, + -1385508, + -3075983, + -2941690, + -1426734, + 438370, + 1671817, + 1819741, + 1066672, -1915, - -787706, - -984578, - -660174, - -124151, - 296447, - 431976, - 313482, - 200381, - 393247, - 405244, - 126206, - -382878, - -863127, - -967997, - -477190, - 504149, - 1505350, - 1886312, - 1207545, - -422904, - -2261169, - -3225491, - -2489129, - -63913, - 2997790, - 5000837, - 4495671, - 1217279, - -3492552, - -7148711, - -7374343, - -3342450, - 3424035, - 9498302, - 11211366, - 6765486, - -2372216, - -11747382, - -15994805, - -11801674, - -171952, - 13444494, - 21578188, - 18719418, - 4789642, - -13977917, - -27648126, - -27704910, - -12115634, - 12567944, - 33697127, - 38834431, - 22828976, - -8252366, - -38998408, - -52062690, - -37672259, - -157412, - 42570543, - 67238142, - 57536488, - 14198767, - -43100052, - -84162965, - -83691806, - -36074860, - 38740075, - 102736479, - 118369876, - 69481207, - -26551038, - -123294929, - -166337603, - -121974151, - 773506, - 147569812, - 239995842, - 213282961, - 53817697, - -182446990, - -382562533, - -418482664, - -202511103, - 267440575, - 894074507, - 1507274459, - 1922662179, - 2009416899, - 1739754433, - 1199539555, - 555599834, - -6640022, - -349535439, - -427104085, - -290383442, - -55077301, - 152113931, - 244512328, - 203140549, - 72316520, - -70888757, - -156705461, - -153365397, - -76010574, - 27284696, - 102893164, - 117913209, - 73136679, - -1753751, - -66250986, - -90051669, - -66541832, - -13112149, - 40280547, - 67330671, - 57877515, - 20978531, - -21848287, - -48732590, - -48304066, - -24066107, - 9117078, - 33749186, - 38694096, - 23928760, - -802209, - -22025915, - -29694169, - -21745507, - -4119151, - 13218493, - 21746421, - 18433769, - 6518263, - -6944116, - -15104434, - -14694528, - -7148395, - 2779399, - 9855051, - 11034581, - 6647332, - -281118, - -5948515, - -7785338, - -5531134, - -984390, - 3234920, - 5125743, - 4190375, - 1412331, - -1503090, - -3110834, - -2893805, - -1336820, - 517522, - 1704209, - 1800508, - 1017556, - -49623, - -811274, - -979098, - -636567, - -99370, - 309847, - 431158, - 303937, - 211114, - 399225, - 398872, - 105832, - -409093, - -879243, - -958790, - -439147, - 556287, - 1542462, - 1879694, - 1147892, - -513770, - -2335500, - -3232872, - -2407491, - 79514, - 3131247, - 5041588, - 4398043, - 1008705, - -3712195, - -7251830, - -7276297, - -3060640, - 3760462, - 9703417, - 11141397, - 6410996, - -2856706, - -12104794, - -15997498, - -11388588, - 488410, - 14014030, - 21716929, - 18280765, - 3934467, - -14826496, - -28007195, - -27298470, - -11062126, - 13765932, - 34383284, - 38549050, - 21596749, - -9868984, - -40142545, - -52025806, - -36313315, - 1940808, - 44330847, - 67626523, - 56147451, - 11567360, - -45669793, - -85221578, - -82433242, - -32874985, - 42366986, - 104817921, - 117504358, - 65699793, - -31585646, - -126954434, - -166323310, - -117635803, - 7797730, - 153835838, - 241780752, - 208531693, - 43587697, - -193836214, - -388934702, - -414309582, - -185494819, - 294866612, - 925093583, - 1532884896, - 1934915322, - 2004397402, - 1719073776, - 1169719655, - 525604387, - -28701794, - -359191318, - -424710475, - -280361909, - -43665055, - 159547194, - 245436916, - 198392797, - 65135544, - -76708536, - -158623489, - -151069254, - -71229272, - 31887531, - 105112365, - 116992378, - 69939445, - -5370362, - -68462584, - -89949397, - -64462438, - -10321024, - 42322151, - 67706935, - 56603392, - 18881349, - -23633814, - -49361556, - -47604734, - -22544584, - 10608715, - 34476880, - 38391628, - 22872940, - -1995500, - -22749442, - -29649883, - -21053709, - -3205525, - 13873668, - 21854048, - 18014424, - 5850664, - -7496516, - -15285660, - -14468307, - -6685135, - 3216918, - 10055663, - 10935937, - 6344394, - -607394, - -6134466, - -7763064, - -5346617, - -755768, - 3388208, - 5142458, - 4087572, - 1262713, - -1617595, - -3141528, - -2842956, - -1246344, - 595078, - 1734119, - 1779341, - 967883, - -96575, - -833419, - -972415, - -612519, - -74915, - 322554, - 429754, - 294187, - 221812, - 404764, - 391800, - 84915, - -435223, - -894447, - -948157, - -399951, - 608438, - 1578060, - 1870540, - 1086001, - -605067, - -2407681, - -3236174, - -2321873, - 224350, - 3262062, - 5076305, - 4293861, - 796884, - -3929130, - -7346657, - -7168157, - -2772541, - 4094937, - 9897925, - 11056773, - 6045616, - -3341322, - -12449629, - -15980028, - -10958124, - 1152902, - 14569941, - 21829294, - 17816096, - 3068554, - -15662100, - -28333429, - -26855078, - -9987927, - 14954283, - 35030619, - 38213497, - 20329745, - -11483233, - -41243389, - -51923463, - -34900528, - 4049424, - 46046363, - 67932550, - 54679532, - 8905198, - -48198335, - -86180118, - -81063446, - -29613294, - 45964667, - 106782077, - 116485782, - 61809445, - -36617366, - -130482609, - -166100630, - -113114327, - 14873368, - 159967173, - 243280398, - 203467808, - 33182074, - -205132184, - -394913619, - -409542818, - -167888372, - 322646639, - 956064082, - 1558017570, - 1946393616, - 1998550886, - 1697778842, - 1139681924, - 495822763, - -50237486, - -368227206, - -421828668, - -270129514, - -32337313, - 166700686, - 246047628, - 193443500, - 57937099, - -82384465, - -160329215, - -148602856, - -66394460, - 36418108, - 107185592, - 115932236, - 66676230, - -8956957, - -70574946, - -89735829, - -62315722, - -7534242, - 44298563, - 67996593, - 55266520, - 16773390, - -25379037, - -49925179, - -46850345, - -21004302, - 12077910, - 35157051, - 38043167, - 21795258, - -3178682, - -23439902, - -29568863, - -20340183, - -2294006, - 14507062, - 21933613, - 17575477, - 5180479, - -8035553, - -15446419, - -14225649, - -6217015, - 3647018, - 10242076, - 10824359, - 6035977, - -930166, - -6311102, - -7731211, - -5157023, - -528303, - 3535764, - 5152509, - 3980624, - 1113036, - -1728830, - -3167889, - -2789060, - -1155339, - 670926, - 1761422, - 1756159, - 917643, - -142719, - -854134, - -964557, - -588071, - -50812, - 334562, - 427777, - 284250, - 232458, - 409844, - 384026, - 63474, - -461231, - -908703, - -936091, - -359637, - 660532, - 1612077, - 1858828, - 1021925, - -696679, - -2477592, - -3235346, - -2232343, - 370422, - 3390038, - 5104881, - 4183196, - 582056, - -4143054, - -7432997, - -7049973, - -2478466, - 4427016, - 10081494, - 10957486, - 5669726, - -3825450, - -12781355, - -15942268, - -10510701, - 1820711, - 15111428, - 21914957, - 17325818, - 2192923, - -16483588, - -28626199, - -26375050, - -8894256, - 16131442, - 35638072, - 37827879, - 19029340, - -13093073, - -42299290, - -51755388, - -33435341, - 6165858, - 47714669, - 68155336, - 53134086, - 6215421, - -50682261, - -87036760, - -79583420, - -26293456, - 49528442, - 108625715, - 115314366, - 57814228, - -41639938, - -133874094, - -165668196, - -108413783, - 21992177, - 165955062, - 244490113, - 198094056, - 22611215, - -216320319, - -400486459, - -404177333, - -149697893, - 350764371, - 986964882, - 1582654172, - 1957088457, - 1991881749, - 1675885341, - 1109447427, - 466273620, - -71237238, - -376644599, - -418469482, - -259700977, - -21106407, - 173568950, - 246346903, - 188300544, - 50730097, - -87910815, - -161822234, - -145970526, - -61512480, - 40871356, - 109111289, - 114735028, - 63351504, - -12509284, - -72586082, - -89411928, - -60104768, - -4755237, - 46207725, - 68199812, - 53868946, - 14657346, - -27082027, - -50423153, - -46042177, - -19447300, - 13522966, - 35789144, - 37649435, - 20697200, - -4350339, - -24096645, - -29451452, - -19605967, - -1385722, - 15118027, - 21985209, - 17117616, - 4508567, - -8560644, - -15586657, - -13966982, - -5744661, - 4069212, - 10414164, - 10700090, - 5722517, - -1249053, - -6478278, - -7689904, - -4962640, - -302275, - 3677455, - 5155946, - 3869707, - 963492, - -1836685, - -3189930, - -2732220, - -1063928, - 744987, - 1786113, - 1731019, - 866911, - -188005, - -873412, - -955553, - -563262, - -27091, - 345867, - 425242, - 274147, - 243033, - 414450, - 375547, - 41530, - -487079, - -921976, - -922586, - -318245, - 712499, - 1644446, - 1844542, - 955723, - -788490, - -2545116, - -3230345, - -2138977, - 517553, - 3514981, - 5127219, - 4066129, - 364469, - -4353667, - -7510663, - -6921809, - -2178740, - 4756257, - 10253799, - 10843543, - 5283721, - -4308471, - -13099452, - -15884115, - -10046763, - 2491016, - 15637704, - 21973625, - 16810376, - 1308614, - -17289831, - -28884916, - -25858754, - -7782363, - 17295855, - 36204627, - 37392368, - 17696961, - -14696454, - -43308647, - -51521388, - -31919272, - 8287503, - 49333384, - 68294092, - 51512569, - 3501223, - -53118189, - -87789793, - -77994311, - -22919236, - 53053647, - 110345731, - 113990515, - 53718362, - -46647067, - -137123655, - -165024887, - -103538482, - 29145787, - 171790845, - 245405530, - 192413574, - 11885809, - -227385975, - -405640647, - -398208576, - -130930055, - 379203142, - 1017774816, - 1606776715, - 1966991825, - 1984395007, - 1653409402, - 1079037291, - 436975322, - -91691708, - -384445514, - -414644060, - -249091041, - -9984415, - 180146913, - 246337519, - 182971969, - 43523381, - -93282078, - -163102402, - -143176754, - -56589684, - 45242330, - 110888091, - 113403152, - 59969787, - -16023164, - -74494140, - -88978786, - -57832718, - -1987418, - 48047674, - 68316865, - 52412776, - 12535902, - -28740918, - -50855258, - -45181566, - -17875623, - 14942228, - 36372669, - 37211209, - 19580268, - -5509078, - -24719065, - -29298032, - -18852118, - -481790, - 15705950, - 22008962, - 16641548, - 3835787, - -9071231, - -15706348, - -13692750, - -5268701, - 4483029, - 10571826, - 10563390, - 5404449, - -1563684, - -6635865, - -7639278, - -4763757, - -77958, - 3813156, - 5152831, - 3755005, - 814272, - -1941059, - -3207669, - -2672542, - -972235, - 817188, - 1808193, - 1703980, - 815760, - -232385, - -891247, - -945434, - -538134, - -3776, - 356468, - 422165, - 263897, - 253519, - 418563, - 366361, - 19105, - -512726, - -934231, - -907639, - -275813, - 764265, - 1675101, - 1827667, - 887456, - -880382, - -2610137, - -3221131, - -2041853, - 665564, - 3636700, - 5143230, - 3942750, - 144378, - -4560667, - -7579479, - -6783743, - -1873698, - 5082215, - 10414531, - 10714974, - 4888013, - -4789763, - -13403414, - -15805492, - -9566775, - 3162988, - 16147996, - 22005036, - 16270249, - 416685, - -18079709, - -29109030, - -25306605, - -6653533, - 18445977, - 36729314, - 36907198, - 16334083, - -16291323, - -44269906, - -51221354, - -30353910, - 10411734, - 50900180, - 68348131, - 49816544, - 765847, - -55502774, - -88437626, - -76297407, - -19494491, - 56535636, - 111939155, - 112514827, - 49526221, - -51632429, - -140226195, - -164169829, - -98492980, - 36325717, - 177465963, - 246022583, - 186429888, - 1016841, - -238314458, - -410363862, - -391632489, - -111592076, - 407945921, - 1048472688, - 1630367554, - 1976096287, - 1976096287, - 1630367554, - 1048472688, - 407945921, - -111592076, - -391632489, - -410363862, - -238314458, - 1016841, - 186429888, - 246022583, - 177465963, - 36325717, - -98492980, - -164169829, - -140226195, - -51632429, - 49526221, - 112514827, - 111939155, - 56535636, - -19494491, - -76297407, - -88437626, - -55502774, - 765847, - 49816544, - 68348131, - 50900180, - 10411734, - -30353910, - -51221354, - -44269906, - -16291323, - 16334083, - 36907198, - 36729314, - 18445977, - -6653533, - -25306605, - -29109030, - -18079709, - 416685, - 16270249, - 22005036, - 16147996, - 3162988, - -9566775, - -15805492, - -13403414, - -4789763, - 4888013, - 10714974, - 10414531, - 5082215, - -1873698, - -6783743, - -7579479, - -4560667, - 144378, - 3942750, - 5143230, - 3636700, - 665564, - -2041853, - -3221131, - -2610137, - -880382, - 887456, - 1827667, - 1675101, - 764265, - -275813, - -907639, - -934231, - -512726, - 19105, - 366361, - 418563, - 253519, - 263897, - 422165, - 356468, - -3776, - -538134, - -945434, - -891247, - -232385, - 815760, - 1703980, - 1808193, - 817188, - -972235, - -2672542, - -3207669, - -1941059, - 814272, - 3755005, - 5152831, - 3813156, - -77958, - -4763757, - -7639278, - -6635865, - -1563684, - 5404449, - 10563390, - 10571826, - 4483029, - -5268701, - -13692750, - -15706348, - -9071231, - 3835787, - 16641548, - 22008962, - 15705950, - -481790, - -18852118, - -29298032, - -24719065, - -5509078, - 19580268, - 37211209, - 36372669, - 14942228, - -17875623, - -45181566, - -50855258, - -28740918, - 12535902, - 52412776, - 68316865, - 48047674, - -1987418, - -57832718, - -88978786, - -74494140, - -16023164, - 59969787, - 113403152, - 110888091, - 45242330, - -56589684, - -143176754, - -163102402, - -93282078, - 43523381, - 182971969, - 246337519, - 180146913, - -9984415, - -249091041, - -414644060, - -384445514, - -91691708, - 436975322, - 1079037291, - 1653409402, - 1984395007, - 1966991825, - 1606776715, - 1017774816, - 379203142, - -130930055, - -398208576, - -405640647, - -227385975, - 11885809, - 192413574, - 245405530, - 171790845, - 29145787, - -103538482, - -165024887, - -137123655, - -46647067, - 53718362, - 113990515, - 110345731, - 53053647, - -22919236, - -77994311, - -87789793, - -53118189, - 3501223, - 51512569, - 68294092, - 49333384, - 8287503, - -31919272, - -51521388, - -43308647, - -14696454, - 17696961, - 37392368, - 36204627, - 17295855, - -7782363, - -25858754, - -28884916, - -17289831, - 1308614, - 16810376, - 21973625, - 15637704, - 2491016, - -10046763, - -15884115, - -13099452, - -4308471, - 5283721, - 10843543, - 10253799, - 4756257, - -2178740, - -6921809, - -7510663, - -4353667, - 364469, - 4066129, - 5127219, - 3514981, - 517553, - -2138977, - -3230345, - -2545116, - -788490, - 955723, - 1844542, - 1644446, - 712499, - -318245, - -922586, - -921976, - -487079, - 41530, - 375547, - 414450, - 243033, - 274147, - 425242, - 345867, - -27091, - -563262, - -955553, - -873412, - -188005, - 866911, - 1731019, - 1786113, - 744987, - -1063928, - -2732220, - -3189930, - -1836685, - 963492, - 3869707, - 5155946, - 3677455, - -302275, - -4962640, - -7689904, - -6478278, - -1249053, - 5722517, - 10700090, - 10414164, - 4069212, - -5744661, - -13966982, - -15586657, - -8560644, - 4508567, - 17117616, - 21985209, - 15118027, - -1385722, - -19605967, - -29451452, - -24096645, - -4350339, - 20697200, - 37649435, - 35789144, - 13522966, - -19447300, - -46042177, - -50423153, - -27082027, - 14657346, - 53868946, - 68199812, - 46207725, - -4755237, - -60104768, - -89411928, - -72586082, - -12509284, - 63351504, - 114735028, - 109111289, - 40871356, - -61512480, - -145970526, - -161822234, - -87910815, - 50730097, - 188300544, - 246346903, - 173568950, - -21106407, - -259700977, - -418469482, - -376644599, - -71237238, - 466273620, - 1109447427, - 1675885341, - 1991881749, - 1957088457, - 1582654172, - 986964882, - 350764371, - -149697893, - -404177333, - -400486459, - -216320319, - 22611215, - 198094056, - 244490113, - 165955062, - 21992177, - -108413783, - -165668196, - -133874094, - -41639938, - 57814228, - 115314366, - 108625715, - 49528442, - -26293456, - -79583420, - -87036760, - -50682261, - 6215421, - 53134086, - 68155336, - 47714669, - 6165858, - -33435341, - -51755388, - -42299290, - -13093073, - 19029340, - 37827879, - 35638072, - 16131442, - -8894256, - -26375050, - -28626199, - -16483588, - 2192923, - 17325818, - 21914957, - 15111428, - 1820711, - -10510701, - -15942268, - -12781355, - -3825450, - 5669726, - 10957486, - 10081494, - 4427016, - -2478466, - -7049973, - -7432997, - -4143054, - 582056, - 4183196, - 5104881, - 3390038, - 370422, - -2232343, - -3235346, - -2477592, - -696679, - 1021925, - 1858828, - 1612077, - 660532, - -359637, - -936091, - -908703, - -461231, - 63474, - 384026, - 409844, - 232458, - 284250, - 427777, - 334562, - -50812, - -588071, - -964557, - -854134, - -142719, - 917643, - 1756159, - 1761422, - 670926, - -1155339, - -2789060, - -3167889, - -1728830, - 1113036, - 3980624, - 5152509, - 3535764, - -528303, - -5157023, - -7731211, - -6311102, - -930166, - 6035977, - 10824359, - 10242076, - 3647018, - -6217015, - -14225649, - -15446419, - -8035553, - 5180479, - 17575477, - 21933613, - 14507062, - -2294006, - -20340183, - -29568863, - -23439902, - -3178682, - 21795258, - 38043167, - 35157051, - 12077910, - -21004302, - -46850345, - -49925179, - -25379037, - 16773390, - 55266520, - 67996593, - 44298563, - -7534242, - -62315722, - -89735829, - -70574946, - -8956957, - 66676230, - 115932236, - 107185592, - 36418108, - -66394460, - -148602856, - -160329215, - -82384465, - 57937099, - 193443500, - 246047628, - 166700686, - -32337313, - -270129514, - -421828668, - -368227206, - -50237486, - 495822763, - 1139681924, - 1697778842, - 1998550886, - 1946393616, - 1558017570, - 956064082, - 322646639, - -167888372, - -409542818, - -394913619, - -205132184, - 33182074, - 203467808, - 243280398, - 159967173, - 14873368, - -113114327, - -166100630, - -130482609, - -36617366, - 61809445, - 116485782, - 106782077, - 45964667, - -29613294, - -81063446, - -86180118, - -48198335, - 8905198, - 54679532, - 67932550, - 46046363, - 4049424, - -34900528, - -51923463, - -41243389, - -11483233, - 20329745, - 38213497, - 35030619, - 14954283, - -9987927, - -26855078, - -28333429, - -15662100, - 3068554, - 17816096, - 21829294, - 14569941, - 1152902, - -10958124, - -15980028, - -12449629, - -3341322, - 6045616, - 11056773, - 9897925, - 4094937, - -2772541, - -7168157, - -7346657, - -3929130, - 796884, - 4293861, - 5076305, - 3262062, - 224350, - -2321873, - -3236174, - -2407681, - -605067, - 1086001, - 1870540, - 1578060, - 608438, - -399951, - -948157, - -894447, - -435223, - 84915, - 391800, - 404764, - 221812, - 294187, - 429754, - 322554, - -74915, - -612519, - -972415, - -833419, - -96575, - 967883, - 1779341, - 1734119, - 595078, - -1246344, - -2842956, - -3141528, - -1617595, - 1262713, - 4087572, - 5142458, - 3388208, - -755768, - -5346617, - -7763064, - -6134466, - -607394, - 6344394, - 10935937, - 10055663, - 3216918, - -6685135, - -14468307, - -15285660, - -7496516, - 5850664, - 18014424, - 21854048, - 13873668, - -3205525, - -21053709, - -29649883, - -22749442, - -1995500, - 22872940, - 38391628, - 34476880, - 10608715, - -22544584, - -47604734, - -49361556, - -23633814, - 18881349, - 56603392, - 67706935, - 42322151, - -10321024, - -64462438, - -89949397, - -68462584, - -5370362, - 69939445, - 116992378, - 105112365, - 31887531, - -71229272, - -151069254, - -158623489, - -76708536, - 65135544, - 198392797, - 245436916, - 159547194, - -43665055, - -280361909, - -424710475, - -359191318, - -28701794, - 525604387, - 1169719655, - 1719073776, - 2004397402, - 1934915322, - 1532884896, - 925093583, - 294866612, - -185494819, - -414309582, - -388934702, - -193836214, - 43587697, - 208531693, - 241780752, - 153835838, - 7797730, - -117635803, - -166323310, - -126954434, - -31585646, - 65699793, - 117504358, - 104817921, - 42366986, - -32874985, - -82433242, - -85221578, - -45669793, - 11567360, - 56147451, - 67626523, - 44330847, - 1940808, - -36313315, - -52025806, - -40142545, - -9868984, - 21596749, - 38549050, - 34383284, - 13765932, - -11062126, - -27298470, - -28007195, - -14826496, - 3934467, - 18280765, - 21716929, - 14014030, - 488410, - -11388588, - -15997498, - -12104794, - -2856706, - 6410996, - 11141397, - 9703417, - 3760462, - -3060640, - -7276297, - -7251830, - -3712195, - 1008705, - 4398043, - 5041588, - 3131247, - 79514, - -2407491, - -3232872, - -2335500, - -513770, - 1147892, - 1879694, - 1542462, - 556287, - -439147, - -958790, - -879243, - -409093, - 105832, - 398872, - 399225, - 211114, - 303937, - 431158, - 309847, - -99370, - -636567, - -979098, - -811274, - -49623, - 1017556, - 1800508, - 1704209, - 517522, - -1336820, - -2893805, - -3110834, - -1503090, - 1412331, - 4190375, - 5125743, - 3234920, - -984390, - -5531134, - -7785338, - -5948515, - -281118, - 6647332, - 11034581, - 9855051, - 2779399, - -7148395, - -14694528, - -15104434, - -6944116, - 6518263, - 18433769, - 21746421, - 13218493, - -4119151, - -21745507, - -29694169, - -22025915, - -802209, - 23928760, - 38694096, - 33749186, - 9117078, - -24066107, - -48304066, - -48732590, - -21848287, - 20978531, - 57877515, - 67330671, - 40280547, - -13112149, - -66541832, - -90051669, - -66250986, - -1753751, - 73136679, - 117913209, - 102893164, - 27284696, - -76010574, - -153365397, - -156705461, - -70888757, - 72316520, - 203140549, - 244512328, - 152113931, - -55077301, - -290383442, - -427104085, - -349535439, - -6640022, - 555599834, - 1199539555, - 1739754433, - 2009416899, - 1922662179, - 1507274459, - 894074507, - 267440575, - -202511103, - -418482664, - -382562533, - -182446990, - 53817697, - 213282961, - 239995842, - 147569812, - 773506, - -121974151, - -166337603, - -123294929, - -26551038, - 69481207, - 118369876, - 102736479, - 38740075, - -36074860, - -83691806, - -84162965, - -43100052, - 14198767, - 57536488, - 67238142, - 42570543, - -157412, - -37672259, - -52062690, - -38998408, - -8252366, - 22828976, - 38834431, - 33697127, - 12567944, - -12115634, - -27704910, - -27648126, - -13977917, - 4789642, - 18719418, - 21578188, - 13444494, - -171952, - -11801674, - -15994805, - -11747382, - -2372216, - 6765486, - 11211366, - 9498302, - 3424035, - -3342450, - -7374343, - -7148711, - -3492552, - 1217279, - 4495671, - 5000837, - 2997790, - -63913, - -2489129, - -3225491, - -2261169, - -422904, - 1207545, - 1886312, - 1505350, - 504149, - -477190, - -967997, - -863127, - -382878, - 126206, - 405244, - 393247, - 200381, - 313482, - 431976, - 296447, - -124151, - -660174, - -984578, - -787706, + -787773, + -984667, + -660237, + -124163, + 296478, + 432025, + 313520, + 200407, + 393294, + 405288, + 126219, + -382916, + -863207, + -968082, + -477230, + 504189, + 1505465, + 1886450, + 1207630, + -422932, + -2261314, + -3225689, + -2489276, + -63916, + 2997953, + 5001096, + 4495895, + 1217337, + -3492712, + -7149024, + -7374653, + -3342585, + 3424167, + 9498652, + 11211762, + 6765714, + -2372292, + -11747744, + -15995276, + -11802005, + -171957, + 13444838, + 21578712, + 18719851, + 4789747, + -13978209, + -27648673, + -27705430, + -12115849, + 12568156, + 33697661, + 38835013, + 22829298, + -8252475, + -38998893, + -52063297, + -37672670, + -157414, + 42570946, + 67238734, + 57536958, + 14198874, + -43100352, + -84163503, + -83692296, + -36075053, + 38740263, + 102736929, + 118370343, + 69481452, + -26551122, + -123295270, + -166338006, + -121974408, + 773507, + 147570038, + 239996148, + 213283184, + 53817743, + -182447110, + -382562723, + -418482814, + -202511152, + 267440615, + 894074574, + 1507274497, + 1922662174, + 2009416884, + 1739754449, + 1199539614, + 555599895, + -6640024, + -349535543, + -427104267, + -290383610, + -55077343, + 152114075, + 244512613, + 203140834, + 72316640, + -70888896, + -156705817, + -153365796, + -76010799, + 27284787, + 102893549, + 117913701, + 73137017, + -1753760, + -66251357, + -90052221, + -66542277, + -13112244, + 40280864, + 67331243, + 57878045, + 20978738, + -21848518, + -48733140, + -48304649, + -24066416, + 9117203, + 33749677, + 38694693, + 23929152, + -802223, + -22026318, + -29694742, + -21745950, + -4119240, + 13218791, + 21746938, + 18434229, + 6518434, + -6944307, + -15104869, + -14694971, + -7148621, + 2779491, + 9855392, + 11034980, + 6647583, + -281129, + -5948760, + -7785672, + -5531383, + -984436, + 3235078, + 5126004, + 4190597, + 1412409, + -1503177, + -3111021, + -2893987, + -1336907, + 517558, + 1704331, + 1800642, + 1017636, + -49627, + -811344, + -979187, + -636628, + -99380, + 309880, + 431207, + 303975, + 211141, + 399272, + 398915, + 105843, + -409132, + -879324, + -958874, + -439184, + 556332, + 1542580, + 1879831, + 1147972, + -513804, + -2335649, + -3233070, + -2407632, + 79519, + 3131416, + 5041850, + 4398261, + 1008754, + -3712364, + -7252148, + -7276602, + -3060763, + 3760607, + 9703774, + 11141790, + 6411212, + -2856798, + -12105166, + -15997968, + -11388907, + 488423, + 14014387, + 21717456, + 18281187, + 3934553, + -14826805, + -28007749, + -27298982, + -11062323, + 13766162, + 34383828, + 38549626, + 21597053, + -9869114, + -40143043, + -52026411, + -36313709, + 1940827, + 44331266, + 67627117, + 56147907, + 11567447, + -45670110, + -85222120, + -82433723, + -32875160, + 42367191, + 104818379, + 117504819, + 65700023, + -31585744, + -126954783, + -166323711, + -117636049, + 7797744, + 153836072, + 241781058, + 208531909, + 43587733, + -193836340, + -388934893, + -414309728, + -185494863, + 294866654, + 925093649, + 1532884932, + 1934915316, + 2004397387, + 1719073795, + 1169719715, + 525604447, + -28701799, + -359191427, + -424710660, + -280362073, + -43665088, + 159547347, + 245437205, + 198393078, + 65135653, + -76708687, + -158623851, + -151069649, + -71229483, + 31887638, + 105112761, + 116992869, + 69939770, + -5370390, + -68462970, + -89949951, + -64462871, + -10321099, + 42322485, + 67707513, + 56603912, + 18881535, + -23634064, + -49362115, + -47605310, + -22544874, + 10608861, + 34477383, + 38392222, + 22873315, + -1995535, + -22749859, + -29650457, + -21054139, + -3205594, + 13873982, + 21854568, + 18014875, + 5850817, + -7496723, + -15286101, + -14468745, + -6685346, + 3217025, + 10056012, + 10936333, + 6344634, + -607418, + -6134719, + -7763398, + -5346857, + -755803, + 3388373, + 5142720, + 4087789, + 1262783, + -1617689, + -3141717, + -2843135, + -1246426, + 595119, + 1734244, + 1779474, + 967959, + -96582, + -833491, + -972504, + -612578, + -74922, + 322588, + 429803, + 294223, + 221840, + 404811, + 391843, + 84924, + -435265, + -894530, + -948240, + -399984, + 608487, + 1578180, + 1870676, + 1086076, + -605107, + -2407834, + -3236372, + -2322009, + 224363, + 3262238, + 5076567, + 4294074, + 796922, + -3929309, + -7346978, + -7168457, + -2772652, + 4095094, + 9898289, + 11057162, + 6045819, + -3341429, + -12450011, + -15980497, + -10958431, + 1152932, + 14570312, + 21829822, + 17816506, + 3068621, + -15662425, + -28333987, + -26855579, + -9988104, + 14954533, + 35031171, + 38214066, + 20330030, + -11483385, + -41243899, + -51924065, + -34900906, + 4049465, + 46046797, + 67933144, + 54679976, + 8905265, + -48198668, + -86180664, + -81063916, + -29613451, + 45964888, + 106782541, + 116486237, + 61809661, + -36617480, + -130482966, + -166101027, + -113114561, + 14873395, + 159967413, + 243280703, + 203468017, + 33182101, + -205132316, + -394913809, + -409542959, + -167888411, + 322646683, + 956064148, + 1558017604, + 1946393609, + 1998550872, + 1697778862, + 1139681985, + 495822821, + -50237497, + -368227321, + -421828854, + -270129675, + -32337338, + 166700847, + 246047920, + 193443777, + 57937198, + -82384629, + -160329584, + -148603248, + -66394659, + 36418231, + 107185997, + 115932725, + 66676541, + -8957003, + -70575345, + -89736384, + -62316142, + -7534297, + 44298914, + 67997175, + 55267030, + 16773556, + -25379307, + -49925746, + -46850914, + -21004574, + 12078076, + 35157565, + 38043757, + 21795617, + -3178737, + -23440333, + -29569437, + -20340599, + -2294056, + 14507391, + 21934136, + 17575918, + 5180615, + -8035775, + -15446866, + -14226080, + -6217212, + 3647139, + 10242431, + 10824751, + 6036206, + -930202, + -6311363, + -7731545, + -5157255, + -528328, + 3535937, + 5152772, + 3980836, + 1113098, + -1728930, + -3168080, + -2789235, + -1155415, + 670972, + 1761548, + 1756291, + 917715, + -142730, + -854208, + -964645, + -588127, + -50818, + 334598, + 427826, + 284285, + 232487, + 409892, + 384068, + 63480, + -461276, + -908787, + -936173, + -359667, + 660585, + 1612199, + 1858963, + 1021996, + -696725, + -2477750, + -3235544, + -2232474, + 370443, + 3390220, + 5105144, + 4183403, + 582083, + -4143243, + -7433321, + -7050267, + -2478565, + 4427186, + 10081864, + 10957870, + 5669916, + -3825572, + -12781746, + -15942734, + -10510995, + 1820759, + 15111811, + 21915486, + 17326216, + 2192971, + -16483930, + -28626762, + -26375542, + -8894412, + 16131711, + 35638632, + 37828440, + 19029606, + -13093245, + -42299811, + -51755986, + -33435702, + 6165920, + 47715116, + 68155930, + 53134515, + 6215468, + -50682609, + -87037309, + -79583880, + -26293595, + 49528679, + 108626184, + 115314813, + 57814429, + -41640067, + -133874458, + -165668590, + -108414006, + 21992216, + 165955310, + 244490417, + 198094257, + 22611234, + -216320456, + -400486650, + -404177470, + -149697927, + 350764418, + 986964948, + 1582654203, + 1957088449, + 1991881736, + 1675885364, + 1109447489, + 466273676, + -71237253, + -376644718, + -418469669, + -259701133, + -21106423, + 173569119, + 246347199, + 188300816, + 50730184, + -87910991, + -161822609, + -145970913, + -61512665, + 40871495, + 109111704, + 114735514, + 63351801, + -12509349, + -72586494, + -89412483, + -60105174, + -4755272, + 46208093, + 68200398, + 53869444, + 14657492, + -27082316, + -50423728, + -46042738, + -19447552, + 13523153, + 35789669, + 37650021, + 20697541, + -4350415, + -24097089, + -29452025, + -19606370, + -1385752, + 15118371, + 21985734, + 17118046, + 4508686, + -8560881, + -15587109, + -13967406, + -5744844, + 4069347, + 10414527, + 10700479, + 5722734, + -1249102, + -6478547, + -7690237, + -4962864, + -302289, + 3677636, + 5156210, + 3869914, + 963546, + -1836792, + -3190123, + -2732392, + -1063998, + 745039, + 1786241, + 1731150, + 866979, + -188020, + -873487, + -955640, + -563316, + -27094, + 345905, + 425291, + 274181, + 243064, + 414498, + 375588, + 41534, + -487126, + -922060, + -922667, + -318271, + 712555, + 1644570, + 1844676, + 955789, + -788543, + -2545278, + -3230542, + -2139102, + 517582, + 3515170, + 5127483, + 4066330, + 364487, + -4353865, + -7510990, + -6922098, + -2178827, + 4756438, + 10254175, + 10843923, + 5283898, + -4308608, + -13099852, + -15884578, + -10047042, + 2491082, + 15638099, + 21974154, + 16810761, + 1308643, + -17290188, + -28885482, + -25859235, + -7782500, + 17296143, + 36205195, + 37392921, + 17697208, + -14696647, + -43309179, + -51521981, + -31919615, + 8287587, + 49333846, + 68294685, + 51512984, + 3501249, + -53118552, + -87790345, + -77994760, + -22919356, + 53053899, + 110346206, + 113990955, + 53718547, + -46647210, + -137124026, + -165025276, + -103538693, + 29145838, + 171791099, + 245405832, + 192413767, + 11885818, + -227386117, + -405640837, + -398208709, + -130930084, + 379203192, + 1017774881, + 1606776744, + 1966991816, + 1984394995, + 1653409427, + 1079037354, + 436975377, + -91691727, + -384445637, + -414644248, + -249091193, + -9984423, + 180147091, + 246337817, + 182972236, + 43523456, + -93282266, + -163102781, + -143177136, + -56589856, + 45242484, + 110888515, + 113403634, + 59970069, + -16023247, + -74494565, + -88979341, + -57833111, + -1987432, + 48048058, + 68317454, + 52413262, + 12536028, + -28741226, + -50855839, + -45182118, + -17875856, + 14942435, + 36373204, + 37211789, + 19580591, + -5509175, + -24719522, + -29298603, + -18852506, + -481801, + 15706308, + 22009490, + 16641967, + 3835888, + -9071483, + -15706804, + -13693166, + -5268869, + 4483179, + 10572194, + 10563775, + 5404655, + -1563746, + -6636140, + -7639609, + -4763972, + -77962, + 3813344, + 5153095, + 3755206, + 814318, + -1941172, + -3207864, + -2672712, + -972299, + 817244, + 1808324, + 1704108, + 815825, + -232404, + -891325, + -945520, + -538186, + -3777, + 356506, + 422214, + 263930, + 253551, + 418611, + 366401, + 19107, + -512776, + -934316, + -907718, + -275836, + 764326, + 1675228, + 1827799, + 887517, + -880441, + -2610303, + -3221327, + -2041972, + 665601, + 3636895, + 5143495, + 3942944, + 144385, + -4560874, + -7579808, + -6784025, + -1873772, + 5082409, + 10414911, + 10715348, + 4888176, + -4789915, + -13403823, + -15805952, + -9567041, + 3163072, + 16148404, + 22005565, + 16270621, + 416694, + -18080082, + -29109599, + -25307074, + -6653650, + 18446282, + 36729889, + 36907742, + 16334309, + -16291535, + -44270448, + -51221942, + -30354236, + 10411838, + 50900654, + 68348722, + 49816943, + 765852, + -55503153, + -88438179, + -76297844, + -19494592, + 56535904, + 111939634, + 112515259, + 49526391, + -51632586, + -140226571, + -164170214, + -98493180, + 36325780, + 177466223, + 246022883, + 186430074, + 1016842, + -238314605, + -410364051, + -391632617, + -111592100, + 407945973, + 1048472752, + 1630367581, + 1976096277, + 1976096277, + 1630367581, + 1048472752, + 407945973, + -111592100, + -391632617, + -410364051, + -238314605, + 1016842, + 186430074, + 246022883, + 177466223, + 36325780, + -98493180, + -164170214, + -140226571, + -51632586, + 49526391, + 112515259, + 111939634, + 56535904, + -19494592, + -76297844, + -88438179, + -55503153, + 765852, + 49816943, + 68348722, + 50900654, + 10411838, + -30354236, + -51221942, + -44270448, + -16291535, + 16334309, + 36907742, + 36729889, + 18446282, + -6653650, + -25307074, + -29109599, + -18080082, + 416694, + 16270621, + 22005565, + 16148404, + 3163072, + -9567041, + -15805952, + -13403823, + -4789915, + 4888176, + 10715348, + 10414911, + 5082409, + -1873772, + -6784025, + -7579808, + -4560874, + 144385, + 3942944, + 5143495, + 3636895, + 665601, + -2041972, + -3221327, + -2610303, + -880441, + 887517, + 1827799, + 1675228, + 764326, + -275836, + -907718, + -934316, + -512776, + 19107, + 366401, + 418611, + 253551, + 263930, + 422214, + 356506, + -3777, + -538186, + -945520, + -891325, + -232404, + 815825, + 1704108, + 1808324, + 817244, + -972299, + -2672712, + -3207864, + -1941172, + 814318, + 3755206, + 5153095, + 3813344, + -77962, + -4763972, + -7639609, + -6636140, + -1563746, + 5404655, + 10563775, + 10572194, + 4483179, + -5268869, + -13693166, + -15706804, + -9071483, + 3835888, + 16641967, + 22009490, + 15706308, + -481801, + -18852506, + -29298603, + -24719522, + -5509175, + 19580591, + 37211789, + 36373204, + 14942435, + -17875856, + -45182118, + -50855839, + -28741226, + 12536028, + 52413262, + 68317454, + 48048058, + -1987432, + -57833111, + -88979341, + -74494565, + -16023247, + 59970069, + 113403634, + 110888515, + 45242484, + -56589856, + -143177136, + -163102781, + -93282266, + 43523456, + 182972236, + 246337817, + 180147091, + -9984423, + -249091193, + -414644248, + -384445637, + -91691727, + 436975377, + 1079037354, + 1653409427, + 1984394995, + 1966991816, + 1606776744, + 1017774881, + 379203192, + -130930084, + -398208709, + -405640837, + -227386117, + 11885818, + 192413767, + 245405832, + 171791099, + 29145838, + -103538693, + -165025276, + -137124026, + -46647210, + 53718547, + 113990955, + 110346206, + 53053899, + -22919356, + -77994760, + -87790345, + -53118552, + 3501249, + 51512984, + 68294685, + 49333846, + 8287587, + -31919615, + -51521981, + -43309179, + -14696647, + 17697208, + 37392921, + 36205195, + 17296143, + -7782500, + -25859235, + -28885482, + -17290188, + 1308643, + 16810761, + 21974154, + 15638099, + 2491082, + -10047042, + -15884578, + -13099852, + -4308608, + 5283898, + 10843923, + 10254175, + 4756438, + -2178827, + -6922098, + -7510990, + -4353865, + 364487, + 4066330, + 5127483, + 3515170, + 517582, + -2139102, + -3230542, + -2545278, + -788543, + 955789, + 1844676, + 1644570, + 712555, + -318271, + -922667, + -922060, + -487126, + 41534, + 375588, + 414498, + 243064, + 274181, + 425291, + 345905, + -27094, + -563316, + -955640, + -873487, + -188020, + 866979, + 1731150, + 1786241, + 745039, + -1063998, + -2732392, + -3190123, + -1836792, + 963546, + 3869914, + 5156210, + 3677636, + -302289, + -4962864, + -7690237, + -6478547, + -1249102, + 5722734, + 10700479, + 10414527, + 4069347, + -5744844, + -13967406, + -15587109, + -8560881, + 4508686, + 17118046, + 21985734, + 15118371, + -1385752, + -19606370, + -29452025, + -24097089, + -4350415, + 20697541, + 37650021, + 35789669, + 13523153, + -19447552, + -46042738, + -50423728, + -27082316, + 14657492, + 53869444, + 68200398, + 46208093, + -4755272, + -60105174, + -89412483, + -72586494, + -12509349, + 63351801, + 114735514, + 109111704, + 40871495, + -61512665, + -145970913, + -161822609, + -87910991, + 50730184, + 188300816, + 246347199, + 173569119, + -21106423, + -259701133, + -418469669, + -376644718, + -71237253, + 466273676, + 1109447489, + 1675885364, + 1991881736, + 1957088449, + 1582654203, + 986964948, + 350764418, + -149697927, + -404177470, + -400486650, + -216320456, + 22611234, + 198094257, + 244490417, + 165955310, + 21992216, + -108414006, + -165668590, + -133874458, + -41640067, + 57814429, + 115314813, + 108626184, + 49528679, + -26293595, + -79583880, + -87037309, + -50682609, + 6215468, + 53134515, + 68155930, + 47715116, + 6165920, + -33435702, + -51755986, + -42299811, + -13093245, + 19029606, + 37828440, + 35638632, + 16131711, + -8894412, + -26375542, + -28626762, + -16483930, + 2192971, + 17326216, + 21915486, + 15111811, + 1820759, + -10510995, + -15942734, + -12781746, + -3825572, + 5669916, + 10957870, + 10081864, + 4427186, + -2478565, + -7050267, + -7433321, + -4143243, + 582083, + 4183403, + 5105144, + 3390220, + 370443, + -2232474, + -3235544, + -2477750, + -696725, + 1021996, + 1858963, + 1612199, + 660585, + -359667, + -936173, + -908787, + -461276, + 63480, + 384068, + 409892, + 232487, + 284285, + 427826, + 334598, + -50818, + -588127, + -964645, + -854208, + -142730, + 917715, + 1756291, + 1761548, + 670972, + -1155415, + -2789235, + -3168080, + -1728930, + 1113098, + 3980836, + 5152772, + 3535937, + -528328, + -5157255, + -7731545, + -6311363, + -930202, + 6036206, + 10824751, + 10242431, + 3647139, + -6217212, + -14226080, + -15446866, + -8035775, + 5180615, + 17575918, + 21934136, + 14507391, + -2294056, + -20340599, + -29569437, + -23440333, + -3178737, + 21795617, + 38043757, + 35157565, + 12078076, + -21004574, + -46850914, + -49925746, + -25379307, + 16773556, + 55267030, + 67997175, + 44298914, + -7534297, + -62316142, + -89736384, + -70575345, + -8957003, + 66676541, + 115932725, + 107185997, + 36418231, + -66394659, + -148603248, + -160329584, + -82384629, + 57937198, + 193443777, + 246047920, + 166700847, + -32337338, + -270129675, + -421828854, + -368227321, + -50237497, + 495822821, + 1139681985, + 1697778862, + 1998550872, + 1946393609, + 1558017604, + 956064148, + 322646683, + -167888411, + -409542959, + -394913809, + -205132316, + 33182101, + 203468017, + 243280703, + 159967413, + 14873395, + -113114561, + -166101027, + -130482966, + -36617480, + 61809661, + 116486237, + 106782541, + 45964888, + -29613451, + -81063916, + -86180664, + -48198668, + 8905265, + 54679976, + 67933144, + 46046797, + 4049465, + -34900906, + -51924065, + -41243899, + -11483385, + 20330030, + 38214066, + 35031171, + 14954533, + -9988104, + -26855579, + -28333987, + -15662425, + 3068621, + 17816506, + 21829822, + 14570312, + 1152932, + -10958431, + -15980497, + -12450011, + -3341429, + 6045819, + 11057162, + 9898289, + 4095094, + -2772652, + -7168457, + -7346978, + -3929309, + 796922, + 4294074, + 5076567, + 3262238, + 224363, + -2322009, + -3236372, + -2407834, + -605107, + 1086076, + 1870676, + 1578180, + 608487, + -399984, + -948240, + -894530, + -435265, + 84924, + 391843, + 404811, + 221840, + 294223, + 429803, + 322588, + -74922, + -612578, + -972504, + -833491, + -96582, + 967959, + 1779474, + 1734244, + 595119, + -1246426, + -2843135, + -3141717, + -1617689, + 1262783, + 4087789, + 5142720, + 3388373, + -755803, + -5346857, + -7763398, + -6134719, + -607418, + 6344634, + 10936333, + 10056012, + 3217025, + -6685346, + -14468745, + -15286101, + -7496723, + 5850817, + 18014875, + 21854568, + 13873982, + -3205594, + -21054139, + -29650457, + -22749859, + -1995535, + 22873315, + 38392222, + 34477383, + 10608861, + -22544874, + -47605310, + -49362115, + -23634064, + 18881535, + 56603912, + 67707513, + 42322485, + -10321099, + -64462871, + -89949951, + -68462970, + -5370390, + 69939770, + 116992869, + 105112761, + 31887638, + -71229483, + -151069649, + -158623851, + -76708687, + 65135653, + 198393078, + 245437205, + 159547347, + -43665088, + -280362073, + -424710660, + -359191427, + -28701799, + 525604447, + 1169719715, + 1719073795, + 2004397387, + 1934915316, + 1532884932, + 925093649, + 294866654, + -185494863, + -414309728, + -388934893, + -193836340, + 43587733, + 208531909, + 241781058, + 153836072, + 7797744, + -117636049, + -166323711, + -126954783, + -31585744, + 65700023, + 117504819, + 104818379, + 42367191, + -32875160, + -82433723, + -85222120, + -45670110, + 11567447, + 56147907, + 67627117, + 44331266, + 1940827, + -36313709, + -52026411, + -40143043, + -9869114, + 21597053, + 38549626, + 34383828, + 13766162, + -11062323, + -27298982, + -28007749, + -14826805, + 3934553, + 18281187, + 21717456, + 14014387, + 488423, + -11388907, + -15997968, + -12105166, + -2856798, + 6411212, + 11141790, + 9703774, + 3760607, + -3060763, + -7276602, + -7252148, + -3712364, + 1008754, + 4398261, + 5041850, + 3131416, + 79519, + -2407632, + -3233070, + -2335649, + -513804, + 1147972, + 1879831, + 1542580, + 556332, + -439184, + -958874, + -879324, + -409132, + 105843, + 398915, + 399272, + 211141, + 303975, + 431207, + 309880, + -99380, + -636628, + -979187, + -811344, + -49627, + 1017636, + 1800642, + 1704331, + 517558, + -1336907, + -2893987, + -3111021, + -1503177, + 1412409, + 4190597, + 5126004, + 3235078, + -984436, + -5531383, + -7785672, + -5948760, + -281129, + 6647583, + 11034980, + 9855392, + 2779491, + -7148621, + -14694971, + -15104869, + -6944307, + 6518434, + 18434229, + 21746938, + 13218791, + -4119240, + -21745950, + -29694742, + -22026318, + -802223, + 23929152, + 38694693, + 33749677, + 9117203, + -24066416, + -48304649, + -48733140, + -21848518, + 20978738, + 57878045, + 67331243, + 40280864, + -13112244, + -66542277, + -90052221, + -66251357, + -1753760, + 73137017, + 117913701, + 102893549, + 27284787, + -76010799, + -153365796, + -156705817, + -70888896, + 72316640, + 203140834, + 244512613, + 152114075, + -55077343, + -290383610, + -427104267, + -349535543, + -6640024, + 555599895, + 1199539614, + 1739754449, + 2009416884, + 1922662174, + 1507274497, + 894074574, + 267440615, + -202511152, + -418482814, + -382562723, + -182447110, + 53817743, + 213283184, + 239996148, + 147570038, + 773507, + -121974408, + -166338006, + -123295270, + -26551122, + 69481452, + 118370343, + 102736929, + 38740263, + -36075053, + -83692296, + -84163503, + -43100352, + 14198874, + 57536958, + 67238734, + 42570946, + -157414, + -37672670, + -52063297, + -38998893, + -8252475, + 22829298, + 38835013, + 33697661, + 12568156, + -12115849, + -27705430, + -27648673, + -13978209, + 4789747, + 18719851, + 21578712, + 13444838, + -171957, + -11802005, + -15995276, + -11747744, + -2372292, + 6765714, + 11211762, + 9498652, + 3424167, + -3342585, + -7374653, + -7149024, + -3492712, + 1217337, + 4495895, + 5001096, + 2997953, + -63916, + -2489276, + -3225689, + -2261314, + -422932, + 1207630, + 1886450, + 1505465, + 504189, + -477230, + -968082, + -863207, + -382916, + 126219, + 405288, + 393294, + 200407, + 313520, + 432025, + 296478, + -124163, + -660237, + -984667, + -787773, -1915, - 1066589, - 1819605, - 1671698, - 438340, - -1426641, - -2941505, - -3075799, - -1385428, - 1561696, - 4288858, - 5102320, - 3076044, - -1213887, - -5710294, - -7797920, - -5753405, - 48277, - 6944359, - 11120060, - 9640382, - 2334957, - -7606170, - -14903901, - -14902819, - -6378956, - 7182413, - 18832844, - 21610675, - 12542215, - -5033746, - -22414562, - -29701426, - -21270018, - 399753, - 24961252, - 38949900, - 32974587, - 7604733, - -25566845, - -48947125, - -48038669, - -20024451, - 23062244, - 59086909, - 66867740, - 38175906, - -15904152, - -68550885, - -90041816, - -63942277, - 1888563, - 76263512, - 118692641, - 100529736, - 22614803, - -80732047, - -155487140, - -154575798, - -64931084, - 79471061, - 207679038, - 243271770, - 144406731, - -66561486, - -300179433, - -428999017, - -339258605, - 15937452, - 585790160, - 1229120642, - 1759805529, - 2013605600, - 1909643363, - 1481204879, - 863027912, - 240384423, - -218931642, - -422067577, - -375810166, - -170979018, - 63862005, - 217719249, - 237930621, - 141177928, - -6191189, - -126125565, - -166145115, - -119509575, - -21519765, - 73149785, - 119082310, - 100541104, - 35088614, - -39209348, - -84838279, - -83006219, - -40492559, - 16796337, - 58845399, - 66768391, - 40767914, - -2242684, - -38975995, - -52034466, - -37812670, - -6635413, - 24025103, - 39069596, - 32973248, - 11361881, - -13147263, - -28074127, - -27256884, - -13117512, - 5633079, - 19131680, - 21413426, - 12862143, - -827385, - -12196987, - -15972100, - -11377938, - -1888461, - 7108724, - 11266708, - 9282926, - 3086098, - -3617666, - -7462258, - -7037503, - -3270506, - 1422369, - 4586684, - 4954160, - 2861889, - -205762, - -2566725, - -3214086, - -2184808, - -332581, - 1264910, - 1890416, - 1466794, - 452093, - -514044, - -975788, - -846136, - -356618, - 146016, - 410921, - 386849, - 189633, - 322801, - 432193, - 282359, - -149226, - -683299, - -988828, - -762726, - 46496, - 1114907, - 1836579, - 1636595, - 357615, - -1515681, - -2985959, - -3036421, - -1264729, - 1710611, - 4382850, - 5072154, - 2911730, - -1443973, - -5883817, - -7800709, - -5549308, - 380396, - 7235049, - 11192159, - 9411818, - 1884105, - -8057837, - -15096036, - -14680921, - -5801658, - 7842248, - 19211004, - 21446787, - 11845546, - -5948160, - -23059879, - -29671401, - -20482495, - 1608930, - 25968966, - 39158426, - 32153764, - 6073452, - -27044787, - -49532760, - -47280267, - -18164356, - 25129792, - 60229665, - 66318193, - 36010472, - -18693548, - -70486646, - -89919141, - -61538716, - 5552206, - 79315582, - 119328748, - 98024018, - 17883169, - -85387394, - -157430516, - -152235429, - -58841684, - 86590153, - 212000723, - 241713496, - 136431810, - -78104812, - -309735257, - -430385145, - -328360384, - 39019747, - 616156159, - 1258442029, - 1779212227, - 2016960352, - 1895868617, - 1454695068, - 831974773, - 213713645, - -234751400, - -425070306, - -368690869, - -159446712, - 73710868, - 221838583, - 235590323, - 134669090, - -13088379, - -130086491, - -165747693, - -115603964, - -16497998, - 76701791, - 119641820, - 98235268, - 31417284, - -42274984, - -85871945, - -81753387, - -37850785, - 19357049, - 60073043, - 66218349, - 38925463, - -4312488, - -40223232, - -51941568, - -36587063, - -5020146, - 25183858, - 39254563, - 32212791, - 10149301, - -14155864, - -28405899, - -26834171, - -12246437, - 6463799, - 19517214, - 21223030, - 12267799, - -1477099, - -12574161, - -15929560, - -10997016, - -1406046, - 7440364, - 11307469, - 9057644, - 2747089, - -3885995, - -7540017, - -6918419, - -3046359, - 1623747, - 4671028, - 4901677, - 2723740, - -345866, - -2640223, - -3198715, - -2106540, - -242912, - 1319939, - 1892034, - 1426863, - 400187, - -549679, - -982173, - -828307, - -330350, - 165246, - 415910, - 380048, - 178885, - 331874, - 431797, - 267591, - -174566, - -705903, - -991822, - -736347, - 95553, - 1162435, - 1851381, - 1598915, - 275436, - -1603816, - -3027072, - -2992704, - -1141116, - 1858880, - 4472185, - 5035218, - 2742139, - -1674358, - -6051431, - -7793616, - -5336407, - 714838, - 7518978, - 11250679, - 9169539, - 1427365, - -8502776, - -15270560, - -14438872, - -5212866, - 8496904, - 19567623, - 21254770, - 11129226, - -6861240, - -23680487, - -29603889, - -19664133, - 2823845, - 26950480, - 39319113, - 31287460, - 4525040, - -28497935, - -50059881, - -46457941, - -16270115, - 27178487, - 61303943, - 65682185, - 33786580, - -21476833, - -72346240, - -89683087, - -59042696, - 9232748, - 82288594, - 119819768, - 95378134, - 13095225, - -89970358, - -159191748, - -149685546, - -52626938, - 93664748, - 216098249, - 239836116, - 128195756, - -89694269, - -319036355, - -431252706, - -316840882, - 62595481, - 646678369, - 1287482951, - 1797960144, - 2019478630, + 1066672, + 1819741, + 1671817, + 438370, + -1426734, + -2941690, + -3075983, + -1385508, + 1561782, + 4289085, + 5102579, + 3076193, + -1213944, + -5710550, + -7798254, + -5753642, + 48279, + 6944621, + 11120461, + 9640715, + 2335035, + -7606410, + -14904350, + -14903247, + -6379131, + 7182600, + 18833313, + 21611187, + 12542498, + -5033853, + -22415018, + -29701998, + -21270406, + 399760, + 24961659, + 38950500, + 32975066, + 7604837, + -25567173, + -48947714, + -48039210, + -20024661, + 23062470, + 59087448, + 66868307, + 38176205, + -15904267, + -68551341, + -90042366, + -63942633, + 1888573, + 76263863, + 118693134, + 100530111, + 22614878, + -80732284, + -155487542, + -154576147, + -64931210, + 79471192, + 207679327, + 243272051, + 144406866, + -66561535, + -300179605, + -428999197, + -339258704, + 15937455, + 585790223, + 1229120698, + 1759805544, + 2013605585, + 1909643360, + 1481204920, + 863027979, + 240384460, + -218931696, + -422067731, + -375810355, + -170979132, + 63862060, + 217719480, + 237930927, + 141178145, + -6191200, + -126125832, + -166145521, + -119509908, + -21519833, + 73150044, + 119082782, + 100541547, + 35088785, + -39209559, + -84838777, + -83006752, + -40492842, + 16796464, + 58845881, + 66768981, + 40768302, + -2242707, + -38976421, + -52035075, + -37813141, + -6635502, + 24025442, + 39070182, + 32973773, + 11362072, + -13147498, + -28074655, + -27257425, + -13117786, + 5633203, + 19132124, + 21413948, + 12862473, + -827407, + -12197331, + -15972572, + -11378290, + -1888522, + 7108964, + 11267107, + 9283269, + 3086217, + -3617812, + -7462572, + -7037812, + -3270656, + 1422437, + 4586913, + 4954418, + 2862044, + -205773, + -2566877, + -3214284, + -2184949, + -332603, + 1264999, + 1890555, + 1466906, + 452129, + -514087, + -975874, + -846214, + -356653, + 146031, + 410967, + 386894, + 189657, + 322840, + 432242, + 282389, + -149241, + -683364, + -988916, + -762791, + 46499, + 1114994, + 1836716, + 1636712, + 357640, + -1515780, + -2986146, + -3036603, + -1264801, + 1710706, + 4383081, + 5072411, + 2911872, + -1444041, + -5884080, + -7801043, + -5549536, + 380411, + 7235321, + 11192562, + 9412142, + 1884167, + -8058090, + -15096490, + -14681342, + -5801817, + 7842453, + 19211481, + 21447294, + 11845812, + -5948287, + -23060347, + -29671971, + -20482868, + 1608958, + 25969389, + 39159027, + 32154229, + 6073534, + -27045133, + -49533354, + -47280798, + -18164547, + 25130038, + 60230212, + 66318752, + 36010753, + -18693683, + -70487114, + -89919688, + -61539058, + 5552234, + 79315946, + 119329241, + 98024381, + 17883228, + -85387644, + -157430920, + -152235770, + -58841798, + 86590296, + 212001016, + 241713773, + 136431936, + -78104870, + -309735431, + -430385323, + -328360478, + 39019755, + 616156222, + 1258442085, + 1779212239, + 2016960336, + 1895868616, + 1454695110, + 831974841, + 213713679, + -234751459, + -425070464, + -368691058, + -159446820, + 73710932, + 221838820, + 235590630, + 134669299, + -13088403, + -130086768, + -165748100, + -115604288, + -16498050, + 76702064, + 119642297, + 98235703, + 31417437, + -42275212, + -85872452, + -81753914, + -37851051, + 19357196, + 60073537, + 66218936, + 38925834, + -4312532, + -40223673, + -51942177, + -36587521, + -5020213, + 25184215, + 39255154, + 32213305, + 10149472, + -14156117, + -28406435, + -26834705, + -12246694, + 6463941, + 19517668, + 21223548, + 12268114, + -1477139, + -12574516, + -15930031, + -10997357, + -1406092, + 7440616, + 11307870, + 9057980, + 2747196, + -3886153, + -7540335, + -6918724, + -3046499, + 1623825, + 4671262, + 4901932, + 2723888, + -345886, + -2640379, + -3198912, + -2106675, + -242928, + 1320032, + 1892173, + 1426972, + 400219, + -549725, + -982260, + -828384, + -330382, + 165264, + 415956, + 380093, + 178908, + 331915, + 431846, + 267619, + -174583, + -705969, + -991911, + -736410, + 95561, + 1162525, + 1851519, + 1599028, + 275455, + -1603921, + -3027261, + -2992883, + -1141182, + 1858982, + 4472421, + 5035473, + 2742272, + -1674435, + -6051701, + -7793948, + -5336626, + 714866, + 7519260, + 11251083, + 9169854, + 1427412, + -8503043, + -15271018, + -14439285, + -5213009, + 8497125, + 19568108, + 21255272, + 11129476, + -6861386, + -23680966, + -29604456, + -19664490, + 2823893, + 26950917, + 39319715, + 31287911, + 4525102, + -28498298, + -50060480, + -46458460, + -16270285, + 27178752, + 61304499, + 65682737, + 33786842, + -21476987, + -72346718, + -89683630, + -59043023, + 9232794, + 82288969, + 119820260, + 95378485, + 13095268, + -89970620, + -159192155, + -149685878, + -52627039, + 93664901, + 216098545, + 239836388, + 128195874, + -89694334, + -319036532, + -431252882, + -316840972, + 62595492, + 646678433, + 1287483005, + 1797960154, + 2019478613, 1881348240, - 1427764213, - 800935966, - 187443315, - -249965892, - -427497295, - -361218117, - -147864382, - 83354863, - 225639370, - 232980456, - 128052261, - -19910239, - -133853634, - -165147414, - -111583795, - -11491852, - 80133655, - 120048754, - 95822557, - 27730760, - -45268409, - -86792235, - -80406623, - -35178226, - 21877945, - 61218390, - 65589190, - 37045725, - -6364340, - -41412758, - -51784505, - -35323362, - -3408570, - 26304026, - 39389414, - 31416935, - 8931761, - -15140322, - -28700054, - -26380722, - -11365856, - 7280845, - 19875719, - 21007416, - 11662293, - -2120320, - -12932851, - -15867383, - -10605183, - -925568, - 7760079, - 11333714, - 8822821, - 2407448, - -4147157, - -7607610, - -6791681, - -2820417, - 1821190, - 4748659, - 4843510, - 2583545, - -484066, - -2709570, - -3179441, - -2026487, - -154006, - 1372590, - 1891195, - 1385628, - 348497, - -584064, - -987166, - -809678, - -304109, - 183879, - 420216, - 372863, - 168156, - 340682, - 430776, - 252151, - -200139, - -727943, - -993536, - -708584, - 145200, - 1209098, - 1863962, - 1558675, - 191894, - -1690919, - -3064752, - -2944658, - -1014720, - 2006303, - 4556701, - 4991494, - 2567439, - -1904748, - -6212867, - -7776561, - -5114899, - 1051196, - 7795729, - 11295434, - 8913746, - 965272, - -8940372, - -15427120, - -14176830, - -4613243, - 9145515, - 19902100, - 21034673, - 10394026, - -7771825, - -24275440, - -29498730, - -18815763, - 4043005, - 27904391, - 39431459, - 30376479, - 2961339, - -29924311, - -50527469, - -45572330, - -14343893, - 29205647, - 62307980, - 64959983, - 31506652, - -24250490, - -74126867, - -89333230, - -56456740, - 12925710, - 85178318, - 120164104, - 92594397, - 8256511, - -94474723, - -160767253, - -146927604, - -46293428, - 100685769, - 219964459, - 237638600, - 119705530, - -101316638, - -328068253, - -431592314, - -304700747, - 86652778, - 677337096, - 1316222776, - 1816035369, - 2021158536, - 1866093079, - 1400431758, - 769932249, - 161588079, - -264571182, - -429355439, - -353405569, - -136246221, - 92784901, - 229120403, - 230106790, - 121336454, - -26649095, - -137423961, - -164346588, - -107454861, - -6507383, - 83441981, - 120303644, - 93306662, - 24033706, - -48186372, - -87598721, - -78968185, - -32478390, - 24356135, - 62280516, - 64882177, - 35131268, - -8395792, - -42543443, - -51563863, - -34023377, - -1802675, - 27384446, - 39474293, - 30586898, - 7710817, - -16099560, - -28956467, - -25897307, - -10476934, - 8083287, - 20206928, - 20767030, - 11046462, - -2756284, - -13272741, - -15785794, - -10203014, - -447619, - 8067558, - 11345524, - 8578832, - 2067608, - -4400880, - -7665039, - -6657517, - -2592983, - 2014485, - 4819543, - 4779790, - 2441503, - -620202, - -2774723, - -3156334, - -1944773, - -65970, - 1422823, - 1887932, - 1343161, - 297090, - -617172, - -990782, - -790288, - -277933, - 201900, - 423847, - 365315, - 157462, - 349205, - 429117, - 236048, - -225914, - -749381, - -993948, - -679454, - 195379, - 1254823, - 1874275, - 1515896, - 107080, - -1776863, - -3098911, - -2892297, - -885675, - 2152682, - 4636241, - 4940973, - 2387805, - -2134847, - -6367864, - -7749481, - -4884991, - 1389057, - 8064891, - 11326258, - 8644656, - 498371, - -9370013, - -15565383, - -13894982, - -4003470, - 9787219, - 20213858, - 20786581, - 9640746, - -8678748, - -24843818, - -29355809, - -17938259, - 5264902, - 28829324, - 39495019, - 29421689, - 1384216, - -31321961, - -50934572, - -44624159, - -12387911, - 31208599, - 63240089, - 64151963, - 29173196, - -27010990, - -75825808, - -88869288, - -53783496, - 16626571, - 87980605, - 120360334, - 89675307, - 3372665, - -98894321, - -162153646, - -143963326, - -39847938, - 107644124, - 223592403, - 235120279, - 110968459, - -112958510, - -336816574, - -431394970, - -291941169, - 111179278, - 708112428, - 1344641025, - 1833424472, - 2021998805, - 1850114519, - 1372717392, - 738984246, - 136162146, - -278563886, - -430652075, - -345267058, - -124606291, - 101992233, - 232280856, - 226975349, - 114530716, - -33297440, - -140794695, - -163347747, - -103223048, - -1550575, - 86623547, - 120407205, - 90691381, - 20330768, - -51025741, - -88291119, - -77440429, - -29754802, - 26788801, - 63258609, - 64098663, - 33184686, - -10404437, - -43614233, - -51280307, - -32688951, - -204430, - 28424015, - 39509406, - 29723933, - 6488017, - -17032538, - -29175061, - -25384728, - -9580841, - 8870214, - 20510613, - 20502343, - 10421153, - -3384245, - -13593540, - -15685038, - -9791094, - 27219, - 8362508, - 11343000, - 8326058, - 1728002, - -4646907, - -7712320, - -6516164, - -2364359, - 2203423, - 4883653, - 4710653, - 2297815, - -754121, - -2835643, - -3129465, - -1861523, - 21093, - 1470602, - 1882279, - 1299535, - 246030, - -648976, - -993037, - -770176, - -251856, - 219294, - 426811, - 357423, - 146819 + 1427764257, + 800936034, + 187443345, + -249965956, + -427497456, + -361218304, + -147864483, + 83354936, + 225639614, + 232980762, + 128052462, + -19910275, + -133853922, + -165147822, + -111584109, + -11491889, + 80133942, + 120049235, + 95822983, + 27730896, + -45268654, + -86792749, + -80407143, + -35178474, + 21878112, + 61218895, + 65589773, + 37046080, + -6364406, + -41413214, + -51785114, + -35323806, + -3408616, + 26304400, + 39390008, + 31417438, + 8931913, + -15140593, + -28700597, + -26381249, + -11366095, + 7281007, + 19876182, + 21007931, + 11662592, + -2120377, + -12933217, + -15867854, + -10605513, + -925598, + 7760343, + 11334116, + 8823149, + 2407541, + -4147325, + -7607932, + -6791981, + -2820547, + 1821278, + 4748897, + 4843763, + 2583686, + -484093, + -2709731, + -3179638, + -2026617, + -154017, + 1372687, + 1891334, + 1385735, + 348525, + -584114, + -987254, + -809753, + -304139, + 183899, + 420263, + 372908, + 168178, + 340724, + 430824, + 252177, + -200159, + -728012, + -993625, + -708645, + 145212, + 1209192, + 1864100, + 1558785, + 191907, + -1691029, + -3064943, + -2944834, + -1014778, + 2006413, + 4556941, + 4991746, + 2567563, + -1904836, + -6213144, + -7776893, + -5115107, + 1051237, + 7796021, + 11295839, + 8914051, + 965304, + -8940652, + -15427581, + -14177235, + -4613369, + 9145753, + 19902592, + 21035168, + 10394258, + -7771990, + -24275930, + -29499294, + -18816103, + 4043074, + 27904842, + 39432061, + 30376916, + 2961379, + -29924691, + -50528071, + -45572838, + -14344043, + 29205930, + 62308543, + 64960527, + 31506896, + -24250663, + -74127355, + -89333768, + -56457051, + 12925775, + 85178705, + 120164595, + 92594737, + 8256538, + -94474995, + -160767661, + -146927929, + -46293516, + 100685932, + 219964758, + 237638866, + 119705639, + -101316711, + -328068432, + -431592487, + -304700832, + 86652793, + 677337162, + 1316222828, + 1816035377, + 2021158519, + 1866093081, + 1400431804, + 769932316, + 161588105, + -264571251, + -429355604, + -353405755, + -136246316, + 92784982, + 229120653, + 230107095, + 121336645, + -26649145, + -137424258, + -164346997, + -107455166, + -6507404, + 83442282, + 120304128, + 93307080, + 24033824, + -48186634, + -87599242, + -78968698, + -32478620, + 24356322, + 62281032, + 64882756, + 35131605, + -8395879, + -42543913, + -51564472, + -34023805, + -1802699, + 27384836, + 39474890, + 30587389, + 7710948, + -16099849, + -28957016, + -25897826, + -10477155, + 8083466, + 20207400, + 20767539, + 11046746, + -2756359, + -13273118, + -15786263, + -10203332, + -447634, + 8067833, + 11345928, + 8579151, + 2067689, + -4401059, + -7665364, + -6657812, + -2593103, + 2014582, + 4819785, + 4780040, + 2441637, + -620237, + -2774888, + -3156530, + -1944898, + -65974, + 1422923, + 1888071, + 1343265, + 297114, + -617224, + -990870, + -790362, + -277961, + 201921, + 423894, + 365359, + 157482, + 349247, + 429165, + 236073, + -225936, + -749451, + -994037, + -679512, + 195395, + 1254920, + 1874414, + 1516003, + 107087, + -1776979, + -3099104, + -2892469, + -885726, + 2152800, + 4636485, + 4941222, + 2387921, + -2134946, + -6368146, + -7749810, + -4885190, + 1389111, + 8065192, + 11326663, + 8644952, + 498388, + -9370306, + -15565847, + -13895378, + -4003579, + 9787472, + 20214356, + 20787068, + 9640961, + -8678932, + -24844318, + -29356369, + -17938582, + 5264992, + 28829789, + 39495620, + 29422111, + 1384234, + -31322357, + -50935177, + -44624655, + -12388039, + 31208901, + 63240658, + 64152498, + 29173421, + -27011183, + -75826305, + -88869821, + -53783791, + 16626654, + 87981002, + 120360823, + 89675634, + 3372676, + -98894605, + -162154054, + -143963642, + -39848013, + 107644297, + 223592705, + 235120540, + 110968558, + -112958590, + -336816756, + -431395141, + -291941249, + 111179297, + 708112494, + 1344641075, + 1833424479, + 2021998788, + 1850114523, + 1372717440, + 738984313, + 136162169, + -278563960, + -430652242, + -345267242, + -124606378, + 101992324, + 232281111, + 226975652, + 114530898, + -33297503, + -140795002, + -163348156, + -103223342, + -1550580, + 86623861, + 120407692, + 90691788, + 20330869, + -51026020, + -88291646, + -77440934, + -29755013, + 26789007, + 63259135, + 64099238, + 33185006, + -10404545, + -43614716, + -51280914, + -32689364, + -204433, + 28424422, + 39510006, + 29724411, + 6488128, + -17032845, + -29175616, + -25385237, + -9581044, + 8870412, + 20511093, + 20502848, + 10421422, + -3384336, + -13593926, + -15685505, + -9791399, + 27220, + 8362794, + 11343404, + 8326368, + 1728069, + -4647096, + -7712648, + -6516452, + -2364469, + 2203530, + 4883899, + 4710900, + 2297941, + -754164, + -2835812, + -3129659, + -1861644, + 21094, + 1470706, + 1882418, + 1299636, + 246050, + -649031, + -993125, + -770248, + -251881, + 219317, + 426859, + 357465, + 146838 }; diff --git a/src/audio/src/coef/src_ipc4_int32_21_8_2160_5000.h b/src/audio/src/coef/src_ipc4_int32_21_8_2160_5000.h index 214eefcfe2d8..4ef8945f6c8c 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_8_2160_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_8_2160_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_8_2160_5000_fir[420] = { +__cold_rodata static const int32_t src_int32_21_8_2160_5000_fir[420] = { -42589, 944576, -2937872, diff --git a/src/audio/src/coef/src_ipc4_int32_21_8_3239_5000.h b/src/audio/src/coef/src_ipc4_int32_21_8_3239_5000.h index 95f58c308284..789b2b69d84c 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_8_3239_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_8_3239_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_8_3239_5000_fir[672] = { +__cold_rodata static const int32_t src_int32_21_8_3239_5000_fir[672] = { -35144, 303498, -963439, diff --git a/src/audio/src/coef/src_ipc4_int32_21_8_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_8_4535_5000.h index d699e2e11073..5855a0713328 100644 --- a/src/audio/src/coef/src_ipc4_int32_21_8_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_8_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_21_8_4535_5000_fir[2436] = { +__cold_rodata static const int32_t src_int32_21_8_4535_5000_fir[2436] = { -16754, 31637, -52542, diff --git a/src/audio/src/coef/src_ipc4_int32_2_1_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_2_1_2268_5000.h index 51e672306fb2..9353a547baee 100644 --- a/src/audio/src/coef/src_ipc4_int32_2_1_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_1_2268_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_2_1_2268_5000_fir[48] = { +__cold_rodata static const int32_t src_int32_2_1_2268_5000_fir[48] = { 179901, -585106, -849108, diff --git a/src/audio/src/coef/src_ipc4_int32_2_1_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_2_1_2500_5000.h index cbdac272866a..22fa881e337b 100644 --- a/src/audio/src/coef/src_ipc4_int32_2_1_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_1_2500_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_2_1_2500_5000_fir[40] = { +__cold_rodata static const int32_t src_int32_2_1_2500_5000_fir[40] = { -879692, 4237437, -6093558, diff --git a/src/audio/src/coef/src_ipc4_int32_2_1_2721_5000.h b/src/audio/src/coef/src_ipc4_int32_2_1_2721_5000.h index 43bf0c26a0e6..1eae05ae0bad 100644 --- a/src/audio/src/coef/src_ipc4_int32_2_1_2721_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_1_2721_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_2_1_2721_5000_fir[48] = { +__cold_rodata static const int32_t src_int32_2_1_2721_5000_fir[48] = { -197638, 2396223, -6798383, diff --git a/src/audio/src/coef/src_ipc4_int32_2_1_3401_5000.h b/src/audio/src/coef/src_ipc4_int32_2_1_3401_5000.h index a992e4c2ec1d..503925d74262 100644 --- a/src/audio/src/coef/src_ipc4_int32_2_1_3401_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_1_3401_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_2_1_3401_5000_fir[72] = { +__cold_rodata static const int32_t src_int32_2_1_3401_5000_fir[72] = { 32352, 96988, -688904, diff --git a/src/audio/src/coef/src_ipc4_int32_2_1_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_2_1_4535_5000.h index 73d53d77fd9f..418db95d9c0d 100644 --- a/src/audio/src/coef/src_ipc4_int32_2_1_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_1_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_2_1_4535_5000_fir[240] = { +__cold_rodata static const int32_t src_int32_2_1_4535_5000_fir[240] = { 2667, 2962, -15029, diff --git a/src/audio/src/coef/src_ipc4_int32_2_3_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_2_3_4535_5000.h index 6110ceffd8e6..b4bcc5e5da9b 100644 --- a/src/audio/src/coef/src_ipc4_int32_2_3_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_3_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_2_3_4535_5000_fir[264] = { +__cold_rodata static const int32_t src_int32_2_3_4535_5000_fir[264] = { -93938, -98991, 260253, diff --git a/src/audio/src/coef/src_ipc4_int32_32_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_32_21_4535_5000.h index 33c00bc23a5c..6e20c5d23123 100644 --- a/src/audio/src/coef/src_ipc4_int32_32_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_32_21_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_32_21_4535_5000_fir[3840] = { +__cold_rodata static const int32_t src_int32_32_21_4535_5000_fir[3840] = { -9755, 20037, -35510, diff --git a/src/audio/src/coef/src_ipc4_int32_3_1_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_3_1_2268_5000.h index 87ba29c6518a..734e68049ada 100644 --- a/src/audio/src/coef/src_ipc4_int32_3_1_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_3_1_2268_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_3_1_2268_5000_fir[72] = { +__cold_rodata static const int32_t src_int32_3_1_2268_5000_fir[72] = { 148487, -366788, -1294441, diff --git a/src/audio/src/coef/src_ipc4_int32_3_1_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_3_1_4535_5000.h index 4074dfcfe90d..fa1e6bb57859 100644 --- a/src/audio/src/coef/src_ipc4_int32_3_1_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_3_1_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_3_1_4535_5000_fir[336] = { +__cold_rodata static const int32_t src_int32_3_1_4535_5000_fir[336] = { -19074, 36914, -62611, diff --git a/src/audio/src/coef/src_ipc4_int32_3_2_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_3_2_4535_5000.h index 3338fc161956..e7b06f3442ac 100644 --- a/src/audio/src/coef/src_ipc4_int32_3_2_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_3_2_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_3_2_4535_5000_fir[324] = { +__cold_rodata static const int32_t src_int32_3_2_4535_5000_fir[324] = { -40556, 70616, -110283, diff --git a/src/audio/src/coef/src_ipc4_int32_3_4_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_3_4_4535_5000.h index 31f656c1f7a8..9bcef1518a93 100644 --- a/src/audio/src/coef/src_ipc4_int32_3_4_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_3_4_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_3_4_4535_5000_fir[360] = { +__cold_rodata static const int32_t src_int32_3_4_4535_5000_fir[360] = { 77760, 40171, -209346, diff --git a/src/audio/src/coef/src_ipc4_int32_40_21_2381_5000.h b/src/audio/src/coef/src_ipc4_int32_40_21_2381_5000.h index a864814eff3d..b207869f84f8 100644 --- a/src/audio/src/coef/src_ipc4_int32_40_21_2381_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_40_21_2381_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_40_21_2381_5000_fir[960] = { +__cold_rodata static const int32_t src_int32_40_21_2381_5000_fir[960] = { 50137, 248031, -2186295, diff --git a/src/audio/src/coef/src_ipc4_int32_40_21_2976_5000.h b/src/audio/src/coef/src_ipc4_int32_40_21_2976_5000.h index 97bf13152ebc..514a6e4988fa 100644 --- a/src/audio/src/coef/src_ipc4_int32_40_21_2976_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_40_21_2976_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_40_21_2976_5000_fir[1120] = { +__cold_rodata static const int32_t src_int32_40_21_2976_5000_fir[1120] = { -34235, 389198, -1297100, diff --git a/src/audio/src/coef/src_ipc4_int32_40_21_3968_5000.h b/src/audio/src/coef/src_ipc4_int32_40_21_3968_5000.h index 1b184cd4c2ca..a37477890e24 100644 --- a/src/audio/src/coef/src_ipc4_int32_40_21_3968_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_40_21_3968_5000.h @@ -7,7 +7,7 @@ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ #include <stdint.h> -static const int32_t src_int32_40_21_3968_5000_fir[2080] = { +__cold_rodata static const int32_t src_int32_40_21_3968_5000_fir[2080] = { -48704, 156750, -338114, diff --git a/src/audio/src/coef/src_ipc4_int32_40_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_40_21_4535_5000.h new file mode 100644 index 000000000000..e472f82c024f --- /dev/null +++ b/src/audio/src/coef/src_ipc4_int32_40_21_4535_5000.h @@ -0,0 +1,4657 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + */ + +/** \cond GENERATED_BY_TOOLS_TUNE_SRC */ +#include <stdint.h> + +__cold_rodata static const int32_t src_int32_40_21_4535_5000_fir[4640] = { + -17358, + 32502, + -53608, + 81190, + -115290, + 155305, + -199820, + 246453, + -291729, + 331005, + -358441, + 367056, + -348863, + 295100, + -196566, + 44045, + 171156, + -456599, + 818033, + -1258669, + 1778436, + -2373265, + 3034421, + -3747934, + 4494169, + -5247567, + 5976600, + -6643964, + 7207030, + -7618573, + 7827765, + -7781443, + 7425599, + -6707081, + 5575444, + -3984893, + 1896243, + 721161, + -3887666, + 7611738, + -11888686, + 16699742, + -22011583, + 27776325, + -33932065, + 40403994, + -47106124, + 53943683, + -60816270, + 67621984, + -74262948, + 80653302, + -86732158, + 92488315, + -98017220, + 103685994, + -110787761, + 126156109, + 2047168391, + 73083649, + -85158443, + 87583119, + -86939464, + 84610238, + -81115659, + 76737477, + -71673616, + 66087803, + -60127521, + 53930417, + -47625970, + 41335105, + -35168940, + 29227284, + -23597195, + 18351795, + -13549446, + 9233348, + -5431572, + 2157523, + 589192, + -2821553, + 4563613, + -5848770, + 6717888, + -7217343, + 7397079, + -7308730, + 7003869, + -6532455, + 5941485, + -5273911, + 4567820, + -3855877, + 3165039, + -2516507, + 1925896, + -1403593, + 955257, + -582435, + 283244, + -53081, + -114664, + 227929, + -295366, + 325795, + -327754, + 309142, + -276967, + 237177, + -194589, + 152883, + -114666, + 81577, + -54429, + 33366, + -16561, + 31427, + -52459, + 80328, + -115263, + 156875, + -203982, + 254441, + -305005, + 351228, + -387414, + 406644, + -400888, + 361207, + -278064, + 141729, + 57204, + -327214, + 675170, + -1105598, + 1619915, + -2215670, + 2885837, + -3618177, + 4394735, + -5191499, + 5978258, + -6718700, + 7370758, + -7887239, + 8216727, + -8304755, + 8095232, + -7532085, + 6561066, + -5131682, + 3199163, + -726396, + -2314246, + 5939287, + -10152811, + 14945502, + -20294146, + 26161671, + -32497818, + 39240553, + -46318336, + 53653486, + -61167019, + 68785693, + -76452815, + 84146145, + -91910882, + 99928711, + -108686429, + 119479583, + -136446551, + 181265755, + 2043340170, + 22174678, + -59692024, + 71263583, + -75519343, + 76342681, + -75096509, + 72423815, + -68702107, + 64194150, + -59106696, + 53615528, + -47876457, + 42029923, + -36202553, + 30507266, + -25042771, + 19892920, + -15126166, + 10795289, + -6937466, + 3574703, + -714650, + -1648261, + 3531373, + -4962133, + 5976262, + -6615829, + 6927306, + -6959673, + 6762636, + -6385010, + 5873306, + -5270564, + 4615435, + -3941539, + 3277077, + -2644690, + 2061546, + -1539616, + 1086113, + -704045, + 392856, + -149109, + -32821, + 160080, + -240713, + 283111, + -295544, + 285782, + -260819, + 226683, + -188332, + 149635, + -113405, + 81497, + -54925, + 34018, + -15641, + 30141, + -50983, + 78988, + -114575, + 157571, + -207037, + 261080, + -316703, + 369680, + -414491, + 444319, + -451133, + 425866, + -358694, + 239422, + -57981, + -194984, + 527433, + -945187, + 1451150, + -2044515, + 2720008, + -3467197, + 4269918, + -5105842, + 5946252, + -6756030, + 7493908, + -8112988, + 8561545, + -8784113, + 8722819, + -8318967, + 7514797, + -6255384, + 4490599, + -2177059, + -720019, + 4225152, + -8351212, + 13098429, + -18453877, + 24391562, + -30873229, + 37850068, + -45265533, + 53059682, + -61175703, + 69569938, + -78228039, + 87193026, + -96618829, + 106885142, + -118882301, + 134871369, + -161998008, + 238276923, + 2035696625, + -26454257, + -34518018, + 54819639, + -63824057, + 67735480, + -68711741, + 67739468, + -65367712, + 61953950, + -57761531, + 53002526, + -47857679, + 42485831, + -37028184, + 31609982, + -26340927, + 21315045, + -16610435, + 12289112, + -8397104, + 4964862, + -2007999, + -471637, + 2484607, + -4052279, + 5205053, + -5980471, + 6421289, + -6573573, + 6484895, + -6202661, + 5772641, + -5237722, + 4636908, + -4004582, + 3370027, + -2757196, + 2184706, + -1666040, + 1209916, + -820778, + 499395, + -243510, + 48504, + 91941, + -185221, + 239257, + -262007, + 261071, + -243392, + 215043, + -181098, + 145590, + -111524, + 80956, + -55098, + 34459, + -14599, + 28649, + -49182, + 77171, + -113219, + 157377, + -208952, + 266316, + -326736, + 386235, + -439498, + 479848, + -499297, + 488697, + -437991, + 336572, + -173757, + -60636, + 375620, + -778289, + 1273023, + -1860672, + 2537754, + -3295711, + 4120263, + -4990901, + 5880562, + -6755527, + 7575555, + -8294308, + 8860040, + -9216583, + 9304604, + -9063099, + 8431107, + -7349558, + 5763227, + -3622681, + 886150, + 2478769, + -6493698, + 11168450, + -16500506, + 22475153, + -29066432, + 36239129, + -43952149, + 52163826, + -60840152, + 69967790, + -79575654, + 89773270, + -100825318, + 113313516, + -128541802, + 149769424, + -187302521, + 297045034, + 2024263503, + -72696724, + -9761504, + 38342697, + -51921452, + 58839818, + -62000080, + 62713428, + -61691600, + 59381975, + -56101526, + 52096565, + -47571237, + 42701558, + -37642296, + 32530166, + -27485136, + 22610802, + -17994403, + 13706790, + -9802543, + 6320348, + -3283664, + 701713, + 1429252, + -3124425, + 4408735, + -5315007, + 5882058, + -6152800, + 6172410, + -5986632, + 5640246, + -5175749, + 4632281, + -4044797, + 3443495, + -2853501, + 2294772, + -1782225, + 1326022, + -932016, + 602289, + -335766, + 128858, + 23896, + -129210, + 194491, + -227345, + 235163, + -224799, + 202337, + -172941, + 140782, + -109043, + 79967, + -54955, + 34692, + -13437, + 26953, + -47060, + 74878, + -111194, + 156282, + -209702, + 270101, + -335030, + 400780, + -462273, + 513009, + -545087, + 549328, + -515495, + 432625, + -289476, + 75088, + 220559, + -605799, + 1086475, + -1665095, + 2339998, + -3104555, + 3946461, + -4847145, + 5781360, + -6716974, + 7615007, + -8429934, + 9110277, + -9599481, + 9837071, + -9760072, + 9304645, + -8407896, + 7009792, + -5055102, + 2495283, + 709804, + -4590440, + 9166003, + -14444445, + 20422470, + -27086631, + 34415602, + -42384104, + 50969180, + -60160112, + 69974441, + -80484992, + 91868645, + -104502185, + 119172198, + -137604018, + 164082901, + -212218256, + 357417072, + 2009079295, + -116456715, + 14457362, + 21922865, + -39879650, + 49707935, + -55001714, + 57376355, + -57696691, + 56494747, + -54137877, + 50904404, + -47020213, + 42677182, + -38042555, + 33263600, + -28469769, + 23773565, + -19270816, + 15040760, + -11146182, + 7633745, + -4534591, + 1865235, + 371263, + -2183860, + 3591900, + -4623325, + 5312816, + -5699900, + 5827127, + -5738328, + 5477049, + -5085168, + 4601742, + -4062103, + 3497196, + -2933173, + 2391220, + -1887592, + 1433839, + -1037179, + 700989, + -425379, + 207799, + -43673, + -72998, + 149073, + -191765, + 208217, + -205158, + 188651, + -163918, + 135250, + -105986, + 78543, + -54502, + 34721, + -12160, + 25059, + -44623, + 72114, + -108500, + 154279, + -209267, + 272397, + -341516, + 413209, + -482663, + 543590, + -588221, + 607396, + -590752, + 527028, + -404482, + 211432, + 63101, + -428652, + 892500, + -1458807, + 2127752, + -2894682, + 3749341, + -4675211, + 5649007, + -6640370, + 7611800, + -8518847, + 9310586, + -9930385, + 10316965, + -10405719, + 10130279, + -9424262, + 8223147, + -6466197, + 4098341, + -1071905, + -2651916, + 7101991, + -12296738, + 18244355, + -24944046, + 32388587, + -40568784, + 49480700, + -59137260, + 69587242, + -80947762, + 93463482, + -107623957, + 124422261, + -146010513, + 177722526, + -236601758, + 419232110, + 1990195080, + -157648913, + 38023811, + 5648505, + -27766679, + 40392828, + -47758056, + 51760396, + -53407512, + 53310436, + -51883404, + 49434360, + -46209154, + 42414124, + -38227835, + 33807132, + -29290117, + 24797487, + -20433061, + 16283969, + -12420802, + 8897907, + -5753899, + 3012463, + -683424, + -1235917, + 2759229, + -3909439, + 4716911, + -5217590, + 5451164, + -5459325, + 5284147, + -4966659, + 4545624, + -4056551, + 3530958, + -2995880, + 2473603, + -1981628, + 1532822, + -1135722, + 794976, + -511866, + 284897, + -110392, + -16904, + 103265, + -155477, + 180396, + -184592, + 174073, + -154092, + 129036, + -102378, + 76699, + -53748, + 34549, + -10773, + 22974, + -41880, + 68887, + -105143, + 151366, + -207634, + 273172, + -346138, + 423429, + -500527, + 571392, + -628430, + 662549, + -663317, + 619233, + -518119, + 347629, + -95882, + -247813, + 692140, + -1242901, + 1902120, + -2667155, + 3529870, + -4475897, + 5484052, + -6525926, + 7565714, + -8560290, + 9459567, + -10207156, + 10741307, + -10996139, + 10903115, + -10392723, + 9396299, + -7847921, + 5686275, + -2856397, + -688855, + 4987714, + -10069001, + 15952411, + -22649868, + 30168378, + -38515002, + 47705023, + -57775206, + 68805736, + -80958111, + 94544779, + -110168020, + 129027735, + -153705677, + 190601085, + -260308573, + 482321861, + 1967674322, + -196198909, + 60828888, + -10394203, + -15650111, + 30947962, + -40311514, + 45898991, + -48850054, + 49848748, + -49352471, + 47696252, + -45144031, + 41915128, + -38198215, + 34158686, + -29942411, + 25677527, + -21475196, + 17429902, + -13619608, + 10105999, + -6934917, + 4137054, + -1728917, + -285943, + 1915469, + -3177465, + 4097829, + -4708732, + 5046803, + -5151364, + 5062796, + -4821056, + 4464398, + -4028316, + 3544724, + -3041383, + 2541556, + -2063888, + 1622483, + -1227145, + 883758, + -594769, + 359733, + -175892, + 38758, + 57329, + -118691, + 151865, + -163226, + 158696, + -143530, + 122184, + -98249, + 74453, + -52704, + 34182, + -9280, + 20706, + -38841, + 65208, + -101131, + 147547, + -204796, + 272403, + -348846, + 431358, + -515739, + 596231, + -665458, + 714448, + -732755, + 708701, + -629733, + 482909, + -255503, + -64279, + 486484, + -1018530, + 1664286, + -2423146, + 3289146, + -4250161, + 5287232, + -6374069, + 7476766, + -8553765, + 9556104, + -10427946, + 11107417, + -11527724, + 11618536, + -11307588, + 10522446, + -9192352, + 7250078, + -4633647, + 1287823, + 2834811, + -7773356, + 13558939, + -20216199, + 27766410, + -36232960, + 45650434, + -56079484, + 67631668, + -80512677, + 95102298, + -112114768, + 132955829, + -160637058, + 202633912, + -283193876, + 546511275, + 1941592615, + -232043374, + 82769853, + -26121668, + -3596706, + 21426965, + -32705242, + 39826682, + -44051618, + 46130804, + -46560893, + 45701338, + -43832202, + 41184244, + -37954978, + 34317273, + -30423845, + 26409473, + -22391980, + 18472624, + -14736261, + 11251535, + -8071224, + 5232825, + -2759409, + 660731, + 1065406, + -2431600, + 3459161, + -4176326, + 4616467, + -4816338, + 4814405, + -4649339, + 4358678, + -3977702, + 3538547, + -3069544, + 2594800, + -2133995, + 1702388, + -1310988, + 966880, + -673652, + 431908, + -239818, + 93681, + 11523, + -81621, + 122794, + -141192, + 142617, + -132301, + 114742, + -93631, + 71825, + -51380, + 33628, + -7688, + 18264, + -35517, + 61091, + -96478, + 142832, + -200755, + 270075, + -349605, + 436926, + -528184, + 617937, + -699067, + 762770, + -798646, + 794902, + -738678, + 616501, + -414865, + 120934, + 276654, + -786902, + 1415512, + -2163926, + 3028396, + -3999116, + 5059470, + -6185439, + 7345214, + -8499045, + 9599368, + -10591215, + 11412930, + -11997177, + 12272221, + -12163438, + 11595015, + -10491742, + 8780831, + -6393623, + 3267067, + 655198, + -5422371, + 11076877, + -17655988, + 25195199, + -33734200, + 43326832, + -54057534, + 66068996, + -79610621, + 95128646, + -113447741, + 136177148, + -166755690, + 213739369, + -305113114, + 611619158, + 1912037381, + -265130181, + 103750544, + -41453291, + 8327940, + 11883343, + -24982901, + 33578915, + -39040650, + 42179015, + -43525847, + 43462245, + -42282361, + 40226796, + -37500592, + 34282986, + -30732580, + 26989962, + -23178899, + 19406805, + -15764915, + 12328410, + -9156679, + 6293785, + -3769204, + 1598819, + 213832, + -1676097, + 2804592, + -3623483, + 4162717, + -4456280, + 4540525, + -4452629, + 4229207, + -3905136, + 3512594, + -3080323, + 2633139, + -2191643, + 1772161, + -1386840, + 1043920, + -748105, + 501039, + -301824, + 147561, + -33896, + -44476, + 93352, + -118620, + 125936, + -120476, + 106762, + -88558, + 68837, + -49791, + 32894, + -6004, + 15660, + -31923, + 56552, + -91201, + 137235, + -195518, + 266183, + -348387, + 440076, + -537763, + 636355, + -729033, + 807210, + -860589, + 877324, + -844317, + 747635, + -573065, + 306792, + 63808, + -549277, + 1157130, + -1890859, + 2748965, + -3724024, + 4801866, + -5960887, + 7171560, + -8396172, + 9588828, + -10695737, + 11655808, + -12401536, + 12860177, + -12955159, + 12607703, + -11738556, + 10269760, + -8126337, + 5237757, + -1539000, + -3028985, + 8519724, + -14982961, + 22468281, + -31031544, + 40745686, + -51718672, + 64123884, + -78253655, + 94619332, + -114153742, + 138665890, + -172016403, + 223839320, + -325922652, + 677458829, + 1879107517, + -295418482, + 123681704, + -56311834, + 20059730, + 2370183, + -17188414, + 27191831, + -33846579, + 38016952, + -40265760, + 40992891, + -40504484, + 39049344, + -36838696, + 34056997, + -30867753, + 27416498, + -23832188, + 20227751, + -16700244, + 13330935, + -10185457, + 7314167, + -4752753, + 2523112, + -634475, + -915237, + 2137875, + -3053414, + 3688225, + -4073352, + 4242843, + -4232179, + 4076859, + -3811165, + 3467139, + -3073777, + 2656461, + -2236600, + 1831486, + -1454338, + 1114495, + -817748, + 566765, + -361579, + 200107, + -78677, + -7468, + 63709, + -95644, + 108754, + -108131, + 98295, + -83065, + 65512, + -47951, + 31989, + -4235, + 12904, + -28074, + 51610, + -85320, + 130775, + -189098, + 260730, + -345177, + 440763, + -544392, + 651350, + -755153, + 847482, + -918197, + 955467, + -946025, + 875552, + -729202, + 492250, + -150876, + -306955, + 890535, + -1605399, + 2452313, + -3426291, + 4515696, + -5701471, + 6956545, + -8245460, + 9524250, + -10740610, + 11834355, + -12738189, + 13378759, + -13677972, + 13554513, + -12925517, + 11708279, + -9821908, + 7188765, + -3735515, + -606443, + 5901472, + -12211552, + 19600139, + -28139032, + 37919976, + -49074050, + 61804677, + -76446048, + 93572822, + -114222943, + 140400028, + -176378110, + 232859592, + -345480429, + 743838800, + 1842913003, + -322878734, + 142481275, + -70623774, + 31536394, + -7060127, + -9365719, + 20702070, + -28499647, + 33669202, + -36800203, + 38308397, + -38509767, + 37659644, + -35974065, + 33641545, + -30829477, + 27687455, + -24348850, + 20931421, + -17537472, + 14253865, + -11152081, + 8288461, + -5704682, + 3428505, + -1474779, + -153312, + 1462811, + -2469409, + 3195767, + -3669832, + 3923166, + -3989369, + 3902630, + -3696452, + 3402565, + -3050060, + 2664741, + -2268703, + 1880109, + -1513166, + 1178260, + -882229, + 628746, + -418769, + 251035, + -122574, + 29198, + 34033, + -72399, + 91174, + -95343, + 89396, + -77191, + 61875, + -45875, + 30922, + -2391, + 10009, + -23988, + 46287, + -78861, + 123478, + -181517, + 253728, + -339970, + 438958, + -548005, + 662802, + -777243, + 883320, + -971108, + 1028854, + -1043196, + 999506, + -882378, + 676258, + -366198, + -61272, + 617177, + -1309076, + 2140007, + -3107458, + 4202405, + -5408453, + 6701148, + -8047492, + 9405707, + -10725265, + 11947230, + -13004891, + 13824697, + -14327462, + 14429788, + -14045649, + 13088048, + -11470615, + 9109021, + -5922006, + 1831778, + 3236529, + -9356825, + 16606129, + -25071849, + 34864132, + -46136605, + 59121873, + -74194623, + 91990571, + -113648968, + 141361465, + -179804090, + 240730427, + -363646608, + 810563475, + 1803574462, + -347492677, + 160074653, + -84319631, + 42697802, + -16356183, + -1558532, + 14146556, + -23030734, + 29161227, + -33149772, + 35424999, + -36310552, + 36066596, + -34912588, + 33039916, + -30618833, + 27802089, + -24726667, + 21514455, + -18272395, + 15092426, + -12051448, + 9211444, + -6619820, + 4310024, + -2302418, + 605406, + 783227, + -1874815, + 2688205, + -3248101, + 3583417, + -3725695, + 3707634, + -3561774, + 3319362, + -3009421, + 2658038, + -2287866, + 1917837, + -1563063, + 1234913, + -941230, + 686666, + -473094, + 300076, + -165350, + 65319, + 4491, + -49017, + 73300, + -82189, + 80124, + -70974, + 57953, + -43581, + 29703, + -481, + 6991, + -19684, + 40608, + -71850, + 115374, + -172805, + 245198, + -332773, + 434644, + -548549, + 670613, + -795140, + 914482, + -1018982, + 1097033, + -1135246, + 1118764, + -1031705, + 857766, + -580946, + 186409, + 338555, + -1003492, + 1813709, + -2769196, + 3863599, + -5083290, + 6406579, + -7803125, + 9233574, + -10649469, + 11993454, + -13199780, + 14195110, + -14899605, + 15228245, + -15092319, + 14401012, + -13062950, + 10987570, + -8086124, + 4272048, + 539639, + -6434389, + 13502396, + -21846247, + 31593960, + -42920994, + 56088077, + -71508734, + 89877033, + -112428961, + 141536184, + -182262236, + 247386910, + -380284228, + 877433881, + 1761222675, + -369253269, + 176394903, + -97334274, + 53486260, + -25467828, + 6189895, + 7562298, + -17471183, + 24519219, + -29335974, + 32359949, + -33920259, + 34280190, + -33661219, + 32256420, + -30237862, + 27760532, + -24964206, + 21974182, + -18901403, + 15842341, + -12878858, + 10078204, + -7493230, + 5162856, + -3112820, + 1356682, + 102954, + -1273023, + 2168467, + -2810627, + 3225619, + -3442762, + 3493092, + -3408013, + 3218117, + -2952203, + 2636494, + -2294076, + 1944540, + -1603816, + 1284192, + -994465, + 740236, + -524277, + 346970, + -206774, + 100697, + -24750, + -25634, + 55236, + -68749, + 70534, + -64457, + 53773, + -41086, + 28343, + 1487, + 3863, + -15184, + 34598, + -64321, + 106497, + -162995, + 235171, + -323605, + 427818, + -545991, + 674703, + -808705, + 940749, + -1061506, + 1159573, + -1221613, + 1232617, + -1176313, + 1035732, + -793904, + 434703, + 56205, + -690313, + 1475175, + -2413294, + 3501037, + -4727629, + 6074278, + -7513479, + 9008531, + -10513327, + 11972419, + -13321389, + 14487529, + -15390792, + 15945007, + -16059273, + 15639456, + -14589677, + 12813640, + -10215588, + 6700653, + -2174199, + -3460316, + 10305790, + -18479459, + 28126564, + -39443530, + 52717949, + -68400236, + 87239667, + -110563635, + 140914364, + -183725293, + 252769392, + -395259851, + 944248409, + 1715998067, + -388164569, + 191382939, + -109607195, + 63846797, + -34346421, + 13837008, + 986177, + -11852624, + 19769948, + -25381094, + 29131416, + -31353298, + 32311442, + -32227943, + 31296363, + -29689549, + 27563791, + -25060831, + 22308635, + -19421496, + 16499849, + -13630036, + 10884173, + -8320233, + 5982371, + -3901538, + 2096348, + -574194, + -667444, + 1639535, + -2359951, + 2851882, + -3142272, + 3260329, + -3236153, + 3099518, + -2878839, + 2600333, + -2287390, + 1960149, + -1635269, + 1325879, + -1041684, + 789192, + -572058, + 391476, + -246628, + 135141, + -53530, + -2379, + 37088, + -55102, + 60687, + -57679, + 49363, + -38408, + 26854, + 3500, + 643, + -10509, + 28288, + -56309, + 96889, + -152129, + 223685, + -312495, + 418492, + -540312, + 675013, + -817819, + 961930, + -1098392, + 1216076, + -1301765, + 1340380, + -1315349, + 1209125, + -1003859, + 682212, + -228303, + -371256, + 1126236, + -2041652, + 3116623, + -4343300, + 5705906, + -7179935, + 8731559, + -10317285, + 11883891, + -13368658, + 14699911, + -15797850, + 16575634, + -16940674, + 16796041, + -16041884, + 14576697, + -12298248, + 9103877, + -4889813, + -451056, + 7033775, + -14989605, + 24480254, + -35722094, + 49028127, + -64883437, + 84088920, + -108057299, + 139490479, + -184171069, + 256823880, + -408444203, + 1010803571, + 1668050139, + -404241579, + 204987659, + -121082758, + 73727425, + -42945082, + 21341174, + -5545247, + -6206794, + 14940609, + -21308069, + 25758375, + -28624990, + 30172330, + -30621716, + 30166013, + -28977798, + 27213735, + -25016695, + 22516558, + -19830299, + 17061728, + -14301156, + 11625142, + -9096433, + 6764154, + -4664268, + 2820324, + -1244439, + -61491, + 1104423, + -1898676, + 2464397, + -2826017, + 3010763, + -3047273, + 2964343, + -2789851, + 2549862, + -2267940, + 1964661, + -1657316, + 1359803, + -1082670, + 833300, + -616199, + 433365, + -284703, + 168467, + -81693, + 20616, + 18957, + -41329, + 50642, + -50685, + 44754, + -35568, + 25247, + 5549, + -2653, + -5685, + 21709, + -47853, + 86593, + -140257, + 210790, + -299485, + 406693, + -531514, + 671503, + -822391, + 977859, + -1129385, + 1266171, + -1375198, + 1441399, + -1447988, + 1376934, + -1209603, + 927537, + -513379, + -48083, + 768797, + -1656271, + 2712395, + -3932303, + 5303334, + -6804131, + 8403937, + -10062130, + 11728016, + -13340936, + 14830655, + -16118067, + 17116148, + -17731140, + 17863858, + -17411032, + 16266514, + -14322155, + 11468077, + -7591943, + 2576661, + 3704331, + -11395604, + 20674454, + -31776050, + 45037156, + -60975032, + 80438187, + -104917870, + 137263378, + -183582620, + 259502414, + -419712799, + 1076894774, + 1617536882, + -417510035, + 217166049, + -131710424, + 83079384, + -51218935, + 28661909, + -11995944, + -565363, + 10058668, + -17140359, + 22260501, + -25751471, + 27875719, + -28852417, + 28872556, + -28107408, + 26713083, + -24832738, + 22597411, + -20126073, + 17525305, + -14888860, + 12297290, + -9817745, + 7504019, + -5396875, + 3524638, + -1904066, + 541438, + 566165, + -1429447, + 2065416, + -2495863, + 2745898, + -2842542, + 2813461, + -2685843, + 2485463, + -2235927, + 1958133, + -1669908, + 1385835, + -1117248, + 872354, + -656486, + 472427, + -320802, + 200499, + -109086, + 43226, + 948, + -27508, + 40458, + -43518, + 39973, + -32583, + 23536, + 7621, + -6007, + -736, + 14894, + -38994, + 75660, + -127433, + 196540, + -284627, + 392460, + -519615, + 664158, + -822352, + 988400, + -1154258, + 1309524, + -1441445, + 1535051, + -1573431, + 1538172, + -1409947, + 1169276, + -797419, + 277409, + 404819, + -1259240, + 2290515, + -3496801, + 4868638, + -6387950, + 8027238, + -9748984, + 11505321, + -13237994, + 14878610, + -16349203, + 17563057, + -18425771, + 18836460, + -18689010, + 17873220, + -16275633, + 13779760, + -10265325, + 5605910, + 335861, + -7717063, + 16729599, + -27626142, + 40765394, + -56694035, + 76303770, + -101156863, + 134236341, + -181948415, + 260763418, + -428946559, + 1142317093, + 1564624147, + -428006161, + 227883239, + -141444941, + 91857370, + -59125330, + 35760088, + -18330605, + 5040240, + 5151709, + -12901810, + 18658053, + -22749601, + 25435286, + -26930784, + 27424055, + -27084043, + 26065382, + -24510678, + 22551364, + -20307718, + 17888471, + -15390274, + 12897199, + -10480406, + 8198041, + -6095412, + 4205450, + -2549436, + 1137983, + 27794, + -954941, + 1657242, + -2153747, + 2467313, + -2623208, + 2647819, + -2567502, + 2407594, + -2191622, + 1940685, + -1673046, + 1403893, + -1145275, + 906179, + -692726, + 508469, + -354744, + 231071, + -135563, + 65328, + -16842, + -13720, + 30196, + -36220, + 35054, + -29476, + 21732, + 9704, + -9400, + 4312, + 7880, + -29778, + 64143, + -113718, + 181001, + -267984, + 375850, + -504651, + 652982, + -817659, + 993446, + -1172820, + 1345834, + -1500074, + 1620750, + -1690919, + 1691880, + -1603723, + 1406042, + -1078812, + 603399, + 36316, + -852727, + 1853256, + -3039108, + 4404088, + -5933517, + 7603318, + -9379303, + 11216711, + -13060024, + 14843085, + -16489509, + 17913380, + -19020184, + 19707903, + -19868176, + 19387367, + -18147343, + 16025661, + -12894779, + 8619667, + -3052913, + -3974175, + 12667024, + -23294389, + 36234910, + -52061681, + 71704802, + -96789360, + 130417102, + -179262467, + 260572020, + -436032406, + 1206866062, + 1509484989, + -435776380, + 237112528, + -150246505, + 100019741, + -66624056, + 42598148, + -24514829, + 10579007, + 247281, + -8616519, + 14971758, + -19636862, + 22865441, + -24868355, + 25829400, + -25914193, + 25274984, + -24053000, + 22379302, + -20374780, + 18149690, + -15803020, + 13421875, + -11081007, + 8842569, + -6756147, + 4859071, + -3177013, + 1724837, + -507673, + -477845, + 1242218, + -1801658, + 2176657, + -2390596, + 2468446, + -2435587, + 2316788, + -2135362, + 1912496, + -1666786, + 1413939, + -1166650, + 934630, + -724755, + 541318, + -386357, + 260025, + -160986, + 86803, + -34313, + -40, + 19914, + -28836, + 30024, + -26266, + 19849, + 11787, + -12814, + 9430, + 703, + -20252, + 52101, + -99179, + 164247, + -249633, + 356931, + -486676, + 638000, + -808298, + 992918, + -1184911, + 1374837, + -1550695, + 1697952, + -1799728, + 1837138, + -1789790, + 1636466, + -1355955, + 928052, + -334663, + -438967, + 1402994, + -2561676, + 3912132, + -5443178, + 7134309, + -8954870, + 10863466, + -12807643, + 14723856, + -16537739, + 18164664, + -19510538, + 20472785, + -20941409, + 20799978, + -19926348, + 18192815, + -15465294, + 11600909, + -6443054, + -187612, + 8508855, + -18803969, + 31469372, + -47101334, + 66663171, + -91833959, + 125817867, + -175524446, + 258900348, + -440863845, + 1270338454, + 1452298982, + -440876977, + 244835359, + -158080894, + 107528693, + -73677538, + 49140283, + -30515313, + 16020510, + -4627259, + -4308703, + 11222694, + -16431263, + 20181240, + -22677390, + 24098252, + -24605137, + 24347021, + -23462932, + 22082806, + -20327449, + 18308006, + -16125231, + 13868759, + -11616500, + 9434250, + -7375578, + 5481987, + -3783377, + 2298767, + -1037252, + -849, + 822711, + -1441631, + 1875633, + -2146094, + 2276436, + -2290930, + 2213645, + -2067549, + 1873805, + -1651237, + 1415981, + -1181308, + 957595, + -752428, + 570818, + -415487, + 287217, + -185224, + 107538, + -51371, + 13454, + 9672, + -21410, + 24917, + -22974, + 17900, + 13855, + -16227, + 14589, + -6598, + -10466, + 39594, + -83889, + 146358, + -229657, + 335786, + -465762, + 619262, + -794276, + 986772, + -1190407, + 1396311, + -1592957, + 1766156, + -1899182, + 1973066, + -1967047, + 1859204, + -1627257, + 1249527, + -706043, + -20249, + 942188, + -2067080, + 3395388, + -4919500, + 6622610, + -8477783, + 10447239, + -12481889, + 14521169, + -16493159, + 18315001, + -19893557, + 21126277, + -21902147, + 22102602, + -21602180, + 20268637, + -17962111, + 14532701, + -9815511, + 3621595, + 4277883, + -14179096, + 26493928, + -41838363, + 61203418, + -86312709, + 120455288, + -170739752, + 255727800, + -443341516, + 1332533071, + 1393251518, + -443373732, + 251041272, + -164919572, + 114350428, + -80251016, + 55352625, + -36300023, + 21335072, + -9444895, + -2555, + 7432167, + -13151232, + 17398298, + -20370809, + 22240988, + -23164895, + 23287367, + -22744429, + 21664149, + -20166555, + 18363041, + -16355554, + 14235741, + -12084218, + 9970044, + -7950452, + 6070872, + -4365248, + 2856630, + -1558011, + 473376, + 401097, + -1075730, + 1565993, + -1891149, + 2072950, + -2134431, + 2098829, + -1988648, + 1824908, + -1626557, + 1410073, + -1189223, + 974992, + -775632, + 596838, + -441997, + 312511, + -208152, + 127423, + -67926, + 26689, + -474, + -13983, + 19762, + -19621, + 15897, + 15897, + -19621, + 19762, + -13983, + -474, + 26689, + -67926, + 127423, + -208152, + 312511, + -441997, + 596838, + -775632, + 974992, + -1189223, + 1410073, + -1626557, + 1824908, + -1988648, + 2098829, + -2134431, + 2072950, + -1891149, + 1565993, + -1075730, + 401097, + 473376, + -1558011, + 2856630, + -4365248, + 6070872, + -7950452, + 9970044, + -12084218, + 14235741, + -16355554, + 18363041, + -20166555, + 21664149, + -22744429, + 23287367, + -23164895, + 22240988, + -20370809, + 17398298, + -13151232, + 7432167, + -2555, + -9444895, + 21335072, + -36300023, + 55352625, + -80251016, + 114350428, + -164919572, + 251041272, + -443373732, + 1393251518, + 1332533071, + -443341516, + 255727800, + -170739752, + 120455288, + -86312709, + 61203418, + -41838363, + 26493928, + -14179096, + 4277883, + 3621595, + -9815511, + 14532701, + -17962111, + 20268637, + -21602180, + 22102602, + -21902147, + 21126277, + -19893557, + 18315001, + -16493159, + 14521169, + -12481889, + 10447239, + -8477783, + 6622610, + -4919500, + 3395388, + -2067080, + 942188, + -20249, + -706043, + 1249527, + -1627257, + 1859204, + -1967047, + 1973066, + -1899182, + 1766156, + -1592957, + 1396311, + -1190407, + 986772, + -794276, + 619262, + -465762, + 335786, + -229657, + 146358, + -83889, + 39594, + -10466, + -6598, + 14589, + -16227, + 13855, + 17900, + -22974, + 24917, + -21410, + 9672, + 13454, + -51371, + 107538, + -185224, + 287217, + -415487, + 570818, + -752428, + 957595, + -1181308, + 1415981, + -1651237, + 1873805, + -2067549, + 2213645, + -2290930, + 2276436, + -2146094, + 1875633, + -1441631, + 822711, + -849, + -1037252, + 2298767, + -3783377, + 5481987, + -7375578, + 9434250, + -11616500, + 13868759, + -16125231, + 18308006, + -20327449, + 22082806, + -23462932, + 24347021, + -24605137, + 24098252, + -22677390, + 20181240, + -16431263, + 11222694, + -4308703, + -4627259, + 16020510, + -30515313, + 49140283, + -73677538, + 107528693, + -158080894, + 244835359, + -440876977, + 1452298982, + 1270338454, + -440863845, + 258900348, + -175524446, + 125817867, + -91833959, + 66663171, + -47101334, + 31469372, + -18803969, + 8508855, + -187612, + -6443054, + 11600909, + -15465294, + 18192815, + -19926348, + 20799978, + -20941409, + 20472785, + -19510538, + 18164664, + -16537739, + 14723856, + -12807643, + 10863466, + -8954870, + 7134309, + -5443178, + 3912132, + -2561676, + 1402994, + -438967, + -334663, + 928052, + -1355955, + 1636466, + -1789790, + 1837138, + -1799728, + 1697952, + -1550695, + 1374837, + -1184911, + 992918, + -808298, + 638000, + -486676, + 356931, + -249633, + 164247, + -99179, + 52101, + -20252, + 703, + 9430, + -12814, + 11787, + 19849, + -26266, + 30024, + -28836, + 19914, + -40, + -34313, + 86803, + -160986, + 260025, + -386357, + 541318, + -724755, + 934630, + -1166650, + 1413939, + -1666786, + 1912496, + -2135362, + 2316788, + -2435587, + 2468446, + -2390596, + 2176657, + -1801658, + 1242218, + -477845, + -507673, + 1724837, + -3177013, + 4859071, + -6756147, + 8842569, + -11081007, + 13421875, + -15803020, + 18149690, + -20374780, + 22379302, + -24053000, + 25274984, + -25914193, + 25829400, + -24868355, + 22865441, + -19636862, + 14971758, + -8616519, + 247281, + 10579007, + -24514829, + 42598148, + -66624056, + 100019741, + -150246505, + 237112528, + -435776380, + 1509484989, + 1206866062, + -436032406, + 260572020, + -179262467, + 130417102, + -96789360, + 71704802, + -52061681, + 36234910, + -23294389, + 12667024, + -3974175, + -3052913, + 8619667, + -12894779, + 16025661, + -18147343, + 19387367, + -19868176, + 19707903, + -19020184, + 17913380, + -16489509, + 14843085, + -13060024, + 11216711, + -9379303, + 7603318, + -5933517, + 4404088, + -3039108, + 1853256, + -852727, + 36316, + 603399, + -1078812, + 1406042, + -1603723, + 1691880, + -1690919, + 1620750, + -1500074, + 1345834, + -1172820, + 993446, + -817659, + 652982, + -504651, + 375850, + -267984, + 181001, + -113718, + 64143, + -29778, + 7880, + 4312, + -9400, + 9704, + 21732, + -29476, + 35054, + -36220, + 30196, + -13720, + -16842, + 65328, + -135563, + 231071, + -354744, + 508469, + -692726, + 906179, + -1145275, + 1403893, + -1673046, + 1940685, + -2191622, + 2407594, + -2567502, + 2647819, + -2623208, + 2467313, + -2153747, + 1657242, + -954941, + 27794, + 1137983, + -2549436, + 4205450, + -6095412, + 8198041, + -10480406, + 12897199, + -15390274, + 17888471, + -20307718, + 22551364, + -24510678, + 26065382, + -27084043, + 27424055, + -26930784, + 25435286, + -22749601, + 18658053, + -12901810, + 5151709, + 5040240, + -18330605, + 35760088, + -59125330, + 91857370, + -141444941, + 227883239, + -428006161, + 1564624147, + 1142317093, + -428946559, + 260763418, + -181948415, + 134236341, + -101156863, + 76303770, + -56694035, + 40765394, + -27626142, + 16729599, + -7717063, + 335861, + 5605910, + -10265325, + 13779760, + -16275633, + 17873220, + -18689010, + 18836460, + -18425771, + 17563057, + -16349203, + 14878610, + -13237994, + 11505321, + -9748984, + 8027238, + -6387950, + 4868638, + -3496801, + 2290515, + -1259240, + 404819, + 277409, + -797419, + 1169276, + -1409947, + 1538172, + -1573431, + 1535051, + -1441445, + 1309524, + -1154258, + 988400, + -822352, + 664158, + -519615, + 392460, + -284627, + 196540, + -127433, + 75660, + -38994, + 14894, + -736, + -6007, + 7621, + 23536, + -32583, + 39973, + -43518, + 40458, + -27508, + 948, + 43226, + -109086, + 200499, + -320802, + 472427, + -656486, + 872354, + -1117248, + 1385835, + -1669908, + 1958133, + -2235927, + 2485463, + -2685843, + 2813461, + -2842542, + 2745898, + -2495863, + 2065416, + -1429447, + 566165, + 541438, + -1904066, + 3524638, + -5396875, + 7504019, + -9817745, + 12297290, + -14888860, + 17525305, + -20126073, + 22597411, + -24832738, + 26713083, + -28107408, + 28872556, + -28852417, + 27875719, + -25751471, + 22260501, + -17140359, + 10058668, + -565363, + -11995944, + 28661909, + -51218935, + 83079384, + -131710424, + 217166049, + -417510035, + 1617536882, + 1076894774, + -419712799, + 259502414, + -183582620, + 137263378, + -104917870, + 80438187, + -60975032, + 45037156, + -31776050, + 20674454, + -11395604, + 3704331, + 2576661, + -7591943, + 11468077, + -14322155, + 16266514, + -17411032, + 17863858, + -17731140, + 17116148, + -16118067, + 14830655, + -13340936, + 11728016, + -10062130, + 8403937, + -6804131, + 5303334, + -3932303, + 2712395, + -1656271, + 768797, + -48083, + -513379, + 927537, + -1209603, + 1376934, + -1447988, + 1441399, + -1375198, + 1266171, + -1129385, + 977859, + -822391, + 671503, + -531514, + 406693, + -299485, + 210790, + -140257, + 86593, + -47853, + 21709, + -5685, + -2653, + 5549, + 25247, + -35568, + 44754, + -50685, + 50642, + -41329, + 18957, + 20616, + -81693, + 168467, + -284703, + 433365, + -616199, + 833300, + -1082670, + 1359803, + -1657316, + 1964661, + -2267940, + 2549862, + -2789851, + 2964343, + -3047273, + 3010763, + -2826017, + 2464397, + -1898676, + 1104423, + -61491, + -1244439, + 2820324, + -4664268, + 6764154, + -9096433, + 11625142, + -14301156, + 17061728, + -19830299, + 22516558, + -25016695, + 27213735, + -28977798, + 30166013, + -30621716, + 30172330, + -28624990, + 25758375, + -21308069, + 14940609, + -6206794, + -5545247, + 21341174, + -42945082, + 73727425, + -121082758, + 204987659, + -404241579, + 1668050139, + 1010803571, + -408444203, + 256823880, + -184171069, + 139490479, + -108057299, + 84088920, + -64883437, + 49028127, + -35722094, + 24480254, + -14989605, + 7033775, + -451056, + -4889813, + 9103877, + -12298248, + 14576697, + -16041884, + 16796041, + -16940674, + 16575634, + -15797850, + 14699911, + -13368658, + 11883891, + -10317285, + 8731559, + -7179935, + 5705906, + -4343300, + 3116623, + -2041652, + 1126236, + -371256, + -228303, + 682212, + -1003859, + 1209125, + -1315349, + 1340380, + -1301765, + 1216076, + -1098392, + 961930, + -817819, + 675013, + -540312, + 418492, + -312495, + 223685, + -152129, + 96889, + -56309, + 28288, + -10509, + 643, + 3500, + 26854, + -38408, + 49363, + -57679, + 60687, + -55102, + 37088, + -2379, + -53530, + 135141, + -246628, + 391476, + -572058, + 789192, + -1041684, + 1325879, + -1635269, + 1960149, + -2287390, + 2600333, + -2878839, + 3099518, + -3236153, + 3260329, + -3142272, + 2851882, + -2359951, + 1639535, + -667444, + -574194, + 2096348, + -3901538, + 5982371, + -8320233, + 10884173, + -13630036, + 16499849, + -19421496, + 22308635, + -25060831, + 27563791, + -29689549, + 31296363, + -32227943, + 32311442, + -31353298, + 29131416, + -25381094, + 19769948, + -11852624, + 986177, + 13837008, + -34346421, + 63846797, + -109607195, + 191382939, + -388164569, + 1715998067, + 944248409, + -395259851, + 252769392, + -183725293, + 140914364, + -110563635, + 87239667, + -68400236, + 52717949, + -39443530, + 28126564, + -18479459, + 10305790, + -3460316, + -2174199, + 6700653, + -10215588, + 12813640, + -14589677, + 15639456, + -16059273, + 15945007, + -15390792, + 14487529, + -13321389, + 11972419, + -10513327, + 9008531, + -7513479, + 6074278, + -4727629, + 3501037, + -2413294, + 1475175, + -690313, + 56205, + 434703, + -793904, + 1035732, + -1176313, + 1232617, + -1221613, + 1159573, + -1061506, + 940749, + -808705, + 674703, + -545991, + 427818, + -323605, + 235171, + -162995, + 106497, + -64321, + 34598, + -15184, + 3863, + 1487, + 28343, + -41086, + 53773, + -64457, + 70534, + -68749, + 55236, + -25634, + -24750, + 100697, + -206774, + 346970, + -524277, + 740236, + -994465, + 1284192, + -1603816, + 1944540, + -2294076, + 2636494, + -2952203, + 3218117, + -3408013, + 3493092, + -3442762, + 3225619, + -2810627, + 2168467, + -1273023, + 102954, + 1356682, + -3112820, + 5162856, + -7493230, + 10078204, + -12878858, + 15842341, + -18901403, + 21974182, + -24964206, + 27760532, + -30237862, + 32256420, + -33661219, + 34280190, + -33920259, + 32359949, + -29335974, + 24519219, + -17471183, + 7562298, + 6189895, + -25467828, + 53486260, + -97334274, + 176394903, + -369253269, + 1761222675, + 877433881, + -380284228, + 247386910, + -182262236, + 141536184, + -112428961, + 89877033, + -71508734, + 56088077, + -42920994, + 31593960, + -21846247, + 13502396, + -6434389, + 539639, + 4272048, + -8086124, + 10987570, + -13062950, + 14401012, + -15092319, + 15228245, + -14899605, + 14195110, + -13199780, + 11993454, + -10649469, + 9233574, + -7803125, + 6406579, + -5083290, + 3863599, + -2769196, + 1813709, + -1003492, + 338555, + 186409, + -580946, + 857766, + -1031705, + 1118764, + -1135246, + 1097033, + -1018982, + 914482, + -795140, + 670613, + -548549, + 434644, + -332773, + 245198, + -172805, + 115374, + -71850, + 40608, + -19684, + 6991, + -481, + 29703, + -43581, + 57953, + -70974, + 80124, + -82189, + 73300, + -49017, + 4491, + 65319, + -165350, + 300076, + -473094, + 686666, + -941230, + 1234913, + -1563063, + 1917837, + -2287866, + 2658038, + -3009421, + 3319362, + -3561774, + 3707634, + -3725695, + 3583417, + -3248101, + 2688205, + -1874815, + 783227, + 605406, + -2302418, + 4310024, + -6619820, + 9211444, + -12051448, + 15092426, + -18272395, + 21514455, + -24726667, + 27802089, + -30618833, + 33039916, + -34912588, + 36066596, + -36310552, + 35424999, + -33149772, + 29161227, + -23030734, + 14146556, + -1558532, + -16356183, + 42697802, + -84319631, + 160074653, + -347492677, + 1803574462, + 810563475, + -363646608, + 240730427, + -179804090, + 141361465, + -113648968, + 91990571, + -74194623, + 59121873, + -46136605, + 34864132, + -25071849, + 16606129, + -9356825, + 3236529, + 1831778, + -5922006, + 9109021, + -11470615, + 13088048, + -14045649, + 14429788, + -14327462, + 13824697, + -13004891, + 11947230, + -10725265, + 9405707, + -8047492, + 6701148, + -5408453, + 4202405, + -3107458, + 2140007, + -1309076, + 617177, + -61272, + -366198, + 676258, + -882378, + 999506, + -1043196, + 1028854, + -971108, + 883320, + -777243, + 662802, + -548005, + 438958, + -339970, + 253728, + -181517, + 123478, + -78861, + 46287, + -23988, + 10009, + -2391, + 30922, + -45875, + 61875, + -77191, + 89396, + -95343, + 91174, + -72399, + 34033, + 29198, + -122574, + 251035, + -418769, + 628746, + -882229, + 1178260, + -1513166, + 1880109, + -2268703, + 2664741, + -3050060, + 3402565, + -3696452, + 3902630, + -3989369, + 3923166, + -3669832, + 3195767, + -2469409, + 1462811, + -153312, + -1474779, + 3428505, + -5704682, + 8288461, + -11152081, + 14253865, + -17537472, + 20931421, + -24348850, + 27687455, + -30829477, + 33641545, + -35974065, + 37659644, + -38509767, + 38308397, + -36800203, + 33669202, + -28499647, + 20702070, + -9365719, + -7060127, + 31536394, + -70623774, + 142481275, + -322878734, + 1842913003, + 743838800, + -345480429, + 232859592, + -176378110, + 140400028, + -114222943, + 93572822, + -76446048, + 61804677, + -49074050, + 37919976, + -28139032, + 19600139, + -12211552, + 5901472, + -606443, + -3735515, + 7188765, + -9821908, + 11708279, + -12925517, + 13554513, + -13677972, + 13378759, + -12738189, + 11834355, + -10740610, + 9524250, + -8245460, + 6956545, + -5701471, + 4515696, + -3426291, + 2452313, + -1605399, + 890535, + -306955, + -150876, + 492250, + -729202, + 875552, + -946025, + 955467, + -918197, + 847482, + -755153, + 651350, + -544392, + 440763, + -345177, + 260730, + -189098, + 130775, + -85320, + 51610, + -28074, + 12904, + -4235, + 31989, + -47951, + 65512, + -83065, + 98295, + -108131, + 108754, + -95644, + 63709, + -7468, + -78677, + 200107, + -361579, + 566765, + -817748, + 1114495, + -1454338, + 1831486, + -2236600, + 2656461, + -3073777, + 3467139, + -3811165, + 4076859, + -4232179, + 4242843, + -4073352, + 3688225, + -3053414, + 2137875, + -915237, + -634475, + 2523112, + -4752753, + 7314167, + -10185457, + 13330935, + -16700244, + 20227751, + -23832188, + 27416498, + -30867753, + 34056997, + -36838696, + 39049344, + -40504484, + 40992891, + -40265760, + 38016952, + -33846579, + 27191831, + -17188414, + 2370183, + 20059730, + -56311834, + 123681704, + -295418482, + 1879107517, + 677458829, + -325922652, + 223839320, + -172016403, + 138665890, + -114153742, + 94619332, + -78253655, + 64123884, + -51718672, + 40745686, + -31031544, + 22468281, + -14982961, + 8519724, + -3028985, + -1539000, + 5237757, + -8126337, + 10269760, + -11738556, + 12607703, + -12955159, + 12860177, + -12401536, + 11655808, + -10695737, + 9588828, + -8396172, + 7171560, + -5960887, + 4801866, + -3724024, + 2748965, + -1890859, + 1157130, + -549277, + 63808, + 306792, + -573065, + 747635, + -844317, + 877324, + -860589, + 807210, + -729033, + 636355, + -537763, + 440076, + -348387, + 266183, + -195518, + 137235, + -91201, + 56552, + -31923, + 15660, + -6004, + 32894, + -49791, + 68837, + -88558, + 106762, + -120476, + 125936, + -118620, + 93352, + -44476, + -33896, + 147561, + -301824, + 501039, + -748105, + 1043920, + -1386840, + 1772161, + -2191643, + 2633139, + -3080323, + 3512594, + -3905136, + 4229207, + -4452629, + 4540525, + -4456280, + 4162717, + -3623483, + 2804592, + -1676097, + 213832, + 1598819, + -3769204, + 6293785, + -9156679, + 12328410, + -15764915, + 19406805, + -23178899, + 26989962, + -30732580, + 34282986, + -37500592, + 40226796, + -42282361, + 43462245, + -43525847, + 42179015, + -39040650, + 33578915, + -24982901, + 11883343, + 8327940, + -41453291, + 103750544, + -265130181, + 1912037381, + 611619158, + -305113114, + 213739369, + -166755690, + 136177148, + -113447741, + 95128646, + -79610621, + 66068996, + -54057534, + 43326832, + -33734200, + 25195199, + -17655988, + 11076877, + -5422371, + 655198, + 3267067, + -6393623, + 8780831, + -10491742, + 11595015, + -12163438, + 12272221, + -11997177, + 11412930, + -10591215, + 9599368, + -8499045, + 7345214, + -6185439, + 5059470, + -3999116, + 3028396, + -2163926, + 1415512, + -786902, + 276654, + 120934, + -414865, + 616501, + -738678, + 794902, + -798646, + 762770, + -699067, + 617937, + -528184, + 436926, + -349605, + 270075, + -200755, + 142832, + -96478, + 61091, + -35517, + 18264, + -7688, + 33628, + -51380, + 71825, + -93631, + 114742, + -132301, + 142617, + -141192, + 122794, + -81621, + 11523, + 93681, + -239818, + 431908, + -673652, + 966880, + -1310988, + 1702388, + -2133995, + 2594800, + -3069544, + 3538547, + -3977702, + 4358678, + -4649339, + 4814405, + -4816338, + 4616467, + -4176326, + 3459161, + -2431600, + 1065406, + 660731, + -2759409, + 5232825, + -8071224, + 11251535, + -14736261, + 18472624, + -22391980, + 26409473, + -30423845, + 34317273, + -37954978, + 41184244, + -43832202, + 45701338, + -46560893, + 46130804, + -44051618, + 39826682, + -32705242, + 21426965, + -3596706, + -26121668, + 82769853, + -232043374, + 1941592615, + 546511275, + -283193876, + 202633912, + -160637058, + 132955829, + -112114768, + 95102298, + -80512677, + 67631668, + -56079484, + 45650434, + -36232960, + 27766410, + -20216199, + 13558939, + -7773356, + 2834811, + 1287823, + -4633647, + 7250078, + -9192352, + 10522446, + -11307588, + 11618536, + -11527724, + 11107417, + -10427946, + 9556104, + -8553765, + 7476766, + -6374069, + 5287232, + -4250161, + 3289146, + -2423146, + 1664286, + -1018530, + 486484, + -64279, + -255503, + 482909, + -629733, + 708701, + -732755, + 714448, + -665458, + 596231, + -515739, + 431358, + -348846, + 272403, + -204796, + 147547, + -101131, + 65208, + -38841, + 20706, + -9280, + 34182, + -52704, + 74453, + -98249, + 122184, + -143530, + 158696, + -163226, + 151865, + -118691, + 57329, + 38758, + -175892, + 359733, + -594769, + 883758, + -1227145, + 1622483, + -2063888, + 2541556, + -3041383, + 3544724, + -4028316, + 4464398, + -4821056, + 5062796, + -5151364, + 5046803, + -4708732, + 4097829, + -3177465, + 1915469, + -285943, + -1728917, + 4137054, + -6934917, + 10105999, + -13619608, + 17429902, + -21475196, + 25677527, + -29942411, + 34158686, + -38198215, + 41915128, + -45144031, + 47696252, + -49352471, + 49848748, + -48850054, + 45898991, + -40311514, + 30947962, + -15650111, + -10394203, + 60828888, + -196198909, + 1967674322, + 482321861, + -260308573, + 190601085, + -153705677, + 129027735, + -110168020, + 94544779, + -80958111, + 68805736, + -57775206, + 47705023, + -38515002, + 30168378, + -22649868, + 15952411, + -10069001, + 4987714, + -688855, + -2856397, + 5686275, + -7847921, + 9396299, + -10392723, + 10903115, + -10996139, + 10741307, + -10207156, + 9459567, + -8560290, + 7565714, + -6525926, + 5484052, + -4475897, + 3529870, + -2667155, + 1902120, + -1242901, + 692140, + -247813, + -95882, + 347629, + -518119, + 619233, + -663317, + 662549, + -628430, + 571392, + -500527, + 423429, + -346138, + 273172, + -207634, + 151366, + -105143, + 68887, + -41880, + 22974, + -10773, + 34549, + -53748, + 76699, + -102378, + 129036, + -154092, + 174073, + -184592, + 180396, + -155477, + 103265, + -16904, + -110392, + 284897, + -511866, + 794976, + -1135722, + 1532822, + -1981628, + 2473603, + -2995880, + 3530958, + -4056551, + 4545624, + -4966659, + 5284147, + -5459325, + 5451164, + -5217590, + 4716911, + -3909439, + 2759229, + -1235917, + -683424, + 3012463, + -5753899, + 8897907, + -12420802, + 16283969, + -20433061, + 24797487, + -29290117, + 33807132, + -38227835, + 42414124, + -46209154, + 49434360, + -51883404, + 53310436, + -53407512, + 51760396, + -47758056, + 40392828, + -27766679, + 5648505, + 38023811, + -157648913, + 1990195080, + 419232110, + -236601758, + 177722526, + -146010513, + 124422261, + -107623957, + 93463482, + -80947762, + 69587242, + -59137260, + 49480700, + -40568784, + 32388587, + -24944046, + 18244355, + -12296738, + 7101991, + -2651916, + -1071905, + 4098341, + -6466197, + 8223147, + -9424262, + 10130279, + -10405719, + 10316965, + -9930385, + 9310586, + -8518847, + 7611800, + -6640370, + 5649007, + -4675211, + 3749341, + -2894682, + 2127752, + -1458807, + 892500, + -428652, + 63101, + 211432, + -404482, + 527028, + -590752, + 607396, + -588221, + 543590, + -482663, + 413209, + -341516, + 272397, + -209267, + 154279, + -108500, + 72114, + -44623, + 25059, + -12160, + 34721, + -54502, + 78543, + -105986, + 135250, + -163918, + 188651, + -205158, + 208217, + -191765, + 149073, + -72998, + -43673, + 207799, + -425379, + 700989, + -1037179, + 1433839, + -1887592, + 2391220, + -2933173, + 3497196, + -4062103, + 4601742, + -5085168, + 5477049, + -5738328, + 5827127, + -5699900, + 5312816, + -4623325, + 3591900, + -2183860, + 371263, + 1865235, + -4534591, + 7633745, + -11146182, + 15040760, + -19270816, + 23773565, + -28469769, + 33263600, + -38042555, + 42677182, + -47020213, + 50904404, + -54137877, + 56494747, + -57696691, + 57376355, + -55001714, + 49707935, + -39879650, + 21922865, + 14457362, + -116456715, + 2009079295, + 357417072, + -212218256, + 164082901, + -137604018, + 119172198, + -104502185, + 91868645, + -80484992, + 69974441, + -60160112, + 50969180, + -42384104, + 34415602, + -27086631, + 20422470, + -14444445, + 9166003, + -4590440, + 709804, + 2495283, + -5055102, + 7009792, + -8407896, + 9304645, + -9760072, + 9837071, + -9599481, + 9110277, + -8429934, + 7615007, + -6716974, + 5781360, + -4847145, + 3946461, + -3104555, + 2339998, + -1665095, + 1086475, + -605799, + 220559, + 75088, + -289476, + 432625, + -515495, + 549328, + -545087, + 513009, + -462273, + 400780, + -335030, + 270101, + -209702, + 156282, + -111194, + 74878, + -47060, + 26953, + -13437, + 34692, + -54955, + 79967, + -109043, + 140782, + -172941, + 202337, + -224799, + 235163, + -227345, + 194491, + -129210, + 23896, + 128858, + -335766, + 602289, + -932016, + 1326022, + -1782225, + 2294772, + -2853501, + 3443495, + -4044797, + 4632281, + -5175749, + 5640246, + -5986632, + 6172410, + -6152800, + 5882058, + -5315007, + 4408735, + -3124425, + 1429252, + 701713, + -3283664, + 6320348, + -9802543, + 13706790, + -17994403, + 22610802, + -27485136, + 32530166, + -37642296, + 42701558, + -47571237, + 52096565, + -56101526, + 59381975, + -61691600, + 62713428, + -62000080, + 58839818, + -51921452, + 38342697, + -9761504, + -72696724, + 2024263503, + 297045034, + -187302521, + 149769424, + -128541802, + 113313516, + -100825318, + 89773270, + -79575654, + 69967790, + -60840152, + 52163826, + -43952149, + 36239129, + -29066432, + 22475153, + -16500506, + 11168450, + -6493698, + 2478769, + 886150, + -3622681, + 5763227, + -7349558, + 8431107, + -9063099, + 9304604, + -9216583, + 8860040, + -8294308, + 7575555, + -6755527, + 5880562, + -4990901, + 4120263, + -3295711, + 2537754, + -1860672, + 1273023, + -778289, + 375620, + -60636, + -173757, + 336572, + -437991, + 488697, + -499297, + 479848, + -439498, + 386235, + -326736, + 266316, + -208952, + 157377, + -113219, + 77171, + -49182, + 28649, + -14599, + 34459, + -55098, + 80956, + -111524, + 145590, + -181098, + 215043, + -243392, + 261071, + -262007, + 239257, + -185221, + 91941, + 48504, + -243510, + 499395, + -820778, + 1209916, + -1666040, + 2184706, + -2757196, + 3370027, + -4004582, + 4636908, + -5237722, + 5772641, + -6202661, + 6484895, + -6573573, + 6421289, + -5980471, + 5205053, + -4052279, + 2484607, + -471637, + -2007999, + 4964862, + -8397104, + 12289112, + -16610435, + 21315045, + -26340927, + 31609982, + -37028184, + 42485831, + -47857679, + 53002526, + -57761531, + 61953950, + -65367712, + 67739468, + -68711741, + 67735480, + -63824057, + 54819639, + -34518018, + -26454257, + 2035696625, + 238276923, + -161998008, + 134871369, + -118882301, + 106885142, + -96618829, + 87193026, + -78228039, + 69569938, + -61175703, + 53059682, + -45265533, + 37850068, + -30873229, + 24391562, + -18453877, + 13098429, + -8351212, + 4225152, + -720019, + -2177059, + 4490599, + -6255384, + 7514797, + -8318967, + 8722819, + -8784113, + 8561545, + -8112988, + 7493908, + -6756030, + 5946252, + -5105842, + 4269918, + -3467197, + 2720008, + -2044515, + 1451150, + -945187, + 527433, + -194984, + -57981, + 239422, + -358694, + 425866, + -451133, + 444319, + -414491, + 369680, + -316703, + 261080, + -207037, + 157571, + -114575, + 78988, + -50983, + 30141, + -15641, + 34018, + -54925, + 81497, + -113405, + 149635, + -188332, + 226683, + -260819, + 285782, + -295544, + 283111, + -240713, + 160080, + -32821, + -149109, + 392856, + -704045, + 1086113, + -1539616, + 2061546, + -2644690, + 3277077, + -3941539, + 4615435, + -5270564, + 5873306, + -6385010, + 6762636, + -6959673, + 6927306, + -6615829, + 5976262, + -4962133, + 3531373, + -1648261, + -714650, + 3574703, + -6937466, + 10795289, + -15126166, + 19892920, + -25042771, + 30507266, + -36202553, + 42029923, + -47876457, + 53615528, + -59106696, + 64194150, + -68702107, + 72423815, + -75096509, + 76342681, + -75519343, + 71263583, + -59692024, + 22174678, + 2043340170, + 181265755, + -136446551, + 119479583, + -108686429, + 99928711, + -91910882, + 84146145, + -76452815, + 68785693, + -61167019, + 53653486, + -46318336, + 39240553, + -32497818, + 26161671, + -20294146, + 14945502, + -10152811, + 5939287, + -2314246, + -726396, + 3199163, + -5131682, + 6561066, + -7532085, + 8095232, + -8304755, + 8216727, + -7887239, + 7370758, + -6718700, + 5978258, + -5191499, + 4394735, + -3618177, + 2885837, + -2215670, + 1619915, + -1105598, + 675170, + -327214, + 57204, + 141729, + -278064, + 361207, + -400888, + 406644, + -387414, + 351228, + -305005, + 254441, + -203982, + 156875, + -115263, + 80328, + -52459, + 31427, + -16561, + 33366, + -54429, + 81577, + -114666, + 152883, + -194589, + 237177, + -276967, + 309142, + -327754, + 325795, + -295366, + 227929, + -114664, + -53081, + 283244, + -582435, + 955257, + -1403593, + 1925896, + -2516507, + 3165039, + -3855877, + 4567820, + -5273911, + 5941485, + -6532455, + 7003869, + -7308730, + 7397079, + -7217343, + 6717888, + -5848770, + 4563613, + -2821553, + 589192, + 2157523, + -5431572, + 9233348, + -13549446, + 18351795, + -23597195, + 29227284, + -35168940, + 41335105, + -47625970, + 53930417, + -60127521, + 66087803, + -71673616, + 76737477, + -81115659, + 84610238, + -86939464, + 87583119, + -85158443, + 73083649, + 2047168391, + 126156109, + -110787761, + 103685994, + -98017220, + 92488315, + -86732158, + 80653302, + -74262948, + 67621984, + -60816270, + 53943683, + -47106124, + 40403994, + -33932065, + 27776325, + -22011583, + 16699742, + -11888686, + 7611738, + -3887666, + 721161, + 1896243, + -3984893, + 5575444, + -6707081, + 7425599, + -7781443, + 7827765, + -7618573, + 7207030, + -6643964, + 5976600, + -5247567, + 4494169, + -3747934, + 3034421, + -2373265, + 1778436, + -1258669, + 818033, + -456599, + 171156, + 44045, + -196566, + 295100, + -348863, + 367056, + -358441, + 331005, + -291729, + 246453, + -199820, + 155305, + -115290, + 81190, + -53608, + 32502, + -17358 + +}; + +static const struct src_stage src_int32_40_21_4535_5000 = { + 11, 21, 40, 116, 4640, 21, 40, 0, 0, + src_int32_40_21_4535_5000_fir}; +/** \endcond */ diff --git a/src/audio/src/coef/src_ipc4_int32_40_7_2976_5000.h b/src/audio/src/coef/src_ipc4_int32_40_7_2976_5000.h index 3fb772e824d2..1a103403383a 100644 --- a/src/audio/src/coef/src_ipc4_int32_40_7_2976_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_40_7_2976_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_40_7_2976_5000_fir[1120] = { +__cold_rodata static const int32_t src_int32_40_7_2976_5000_fir[1120] = { -39160, 426217, -1390884, diff --git a/src/audio/src/coef/src_ipc4_int32_4_1_1134_5000.h b/src/audio/src/coef/src_ipc4_int32_4_1_1134_5000.h index 56e0b902bff8..417b633382a2 100644 --- a/src/audio/src/coef/src_ipc4_int32_4_1_1134_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_1_1134_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_4_1_1134_5000_fir[64] = { +__cold_rodata static const int32_t src_int32_4_1_1134_5000_fir[64] = { 165628, 1977250, -11171259, diff --git a/src/audio/src/coef/src_ipc4_int32_4_1_1512_5000.h b/src/audio/src/coef/src_ipc4_int32_4_1_1512_5000.h index 62a7e9b84f60..081ecf7c2738 100644 --- a/src/audio/src/coef/src_ipc4_int32_4_1_1512_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_1_1512_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_4_1_1512_5000_fir[64] = { +__cold_rodata static const int32_t src_int32_4_1_1512_5000_fir[64] = { -77852, 2381370, -5140518, diff --git a/src/audio/src/coef/src_ipc4_int32_4_1_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_4_1_2268_5000.h index 395b0ca93b9d..36e75377cceb 100644 --- a/src/audio/src/coef/src_ipc4_int32_4_1_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_1_2268_5000.h @@ -1,94 +1,93 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2022 Intel Corporation. All rights reserved. + * Copyright(c) 2025 Intel Corporation. All rights reserved. * */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ - #include <stdint.h> -static const int32_t src_int32_4_1_2268_5000_fir[80] = { - -87628, - 1342863, - -3662077, - 138802, - 20444714, - -52853595, - 53061773, - 47755525, - -289188253, - 690517563, - 1538634380, - 313821176, - -267551160, - 112290716, - 561212, - -34612344, - 22445265, - -5315496, - -1068077, - 835507, - 5227, - 1450670, - -6165446, - 8446930, - 8882839, - -56464266, - 102351002, - -56938534, - -204613045, - 1066329050, - 1369463421, - 1029209, - -175392877, - 128003777, - -38744220, - -11189463, - 17145545, - -7185972, - 722734, - 319852, - 319852, - 722734, - -7185972, - 17145545, - -11189463, - -38744220, - 128003777, - -175392877, - 1029209, - 1369463421, - 1066329050, - -204613045, - -56938534, - 102351002, - -56464266, - 8882839, - 8446930, - -6165446, - 1450670, - 5227, - 835507, - -1068077, - -5315496, - 22445265, - -34612344, - 561212, - 112290716, - -267551160, - 313821176, - 1538634380, - 690517563, - -289188253, - 47755525, - 53061773, - -52853595, - 20444714, - 138802, - -3662077, - 1342863, - -87628 +__cold_rodata static const int32_t src_int32_4_1_2268_5000_fir[80] = { + -79074, + 1261923, + -3505225, + 134551, + 20007489, + -52100361, + 52595384, + 47528502, + -288611016, + 690221989, + 1538628396, + 313597850, + -266863194, + 111657573, + 555592, + -34063205, + 21918363, + -5138234, + -1018364, + 780184, + 4793, + 1370660, + -5922392, + 8209720, + 8710279, + -55744859, + 101567607, + -56713690, + -204307161, + 1066098953, + 1369361423, + 1028111, + -174827784, + 127158385, + -38305258, + -10992658, + 16704845, + -6925322, + 686148, + 296371, + 296371, + 686148, + -6925322, + 16704845, + -10992658, + -38305258, + 127158385, + -174827784, + 1028111, + 1369361423, + 1066098953, + -204307161, + -56713690, + 101567607, + -55744859, + 8710279, + 8209720, + -5922392, + 1370660, + 4793, + 780184, + -1018364, + -5138234, + 21918363, + -34063205, + 555592, + 111657573, + -266863194, + 313597850, + 1538628396, + 690221989, + -288611016, + 47528502, + 52595384, + -52100361, + 20007489, + 134551, + -3505225, + 1261923, + -79074 }; diff --git a/src/audio/src/coef/src_ipc4_int32_4_1_3401_5000.h b/src/audio/src/coef/src_ipc4_int32_4_1_3401_5000.h new file mode 100644 index 000000000000..850a923205be --- /dev/null +++ b/src/audio/src/coef/src_ipc4_int32_4_1_3401_5000.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + */ + +/** \cond GENERATED_BY_TOOLS_TUNE_SRC */ +#include <stdint.h> + +__cold_rodata static const int32_t src_int32_4_1_3401_5000_fir[144] = { + -6865, + 234410, + -916679, + 2089314, + -3289124, + 3374037, + -714769, + -6096148, + 17124328, + -29974467, + 39274091, + -37278552, + 15707980, + 31703226, + -107136821, + 209107855, + -340768703, + 572688133, + 1771256666, + 102715267, + -191004549, + 181011265, + -135967381, + 81093928, + -32110808, + -2348043, + 20148385, + -24086906, + 19483102, + -11768526, + 4834208, + -461556, + -1321405, + 1416940, + -855545, + 320335, + 104772, + -57833, + -491588, + 1910568, + -4204104, + 6582624, + -7246427, + 3699398, + 6252553, + -22987157, + 43559310, + -60904805, + 64275218, + -40793732, + -23167772, + 144955605, + -372356238, + 1085537075, + 1521266396, + -228016089, + -3969993, + 88070338, + -107184976, + 91418514, + -60448310, + 28458177, + -4049351, + -9660080, + 13809725, + -11817164, + 7407345, + -3283250, + 675936, + 387949, + -485772, + 243808, + 243808, + -485772, + 387949, + 675936, + -3283250, + 7407345, + -11817164, + 13809725, + -9660080, + -4049351, + 28458177, + -60448310, + 91418514, + -107184976, + 88070338, + -3969993, + -228016089, + 1521266396, + 1085537075, + -372356238, + 144955605, + -23167772, + -40793732, + 64275218, + -60904805, + 43559310, + -22987157, + 6252553, + 3699398, + -7246427, + 6582624, + -4204104, + 1910568, + -491588, + -57833, + 104772, + 320335, + -855545, + 1416940, + -1321405, + -461556, + 4834208, + -11768526, + 19483102, + -24086906, + 20148385, + -2348043, + -32110808, + 81093928, + -135967381, + 181011265, + -191004549, + 102715267, + 1771256666, + 572688133, + -340768703, + 209107855, + -107136821, + 31703226, + 15707980, + -37278552, + 39274091, + -29974467, + 17124328, + -6096148, + -714769, + 3374037, + -3289124, + 2089314, + -916679, + 234410, + -6865 + +}; + +static const struct src_stage src_int32_4_1_3401_5000 = { + 0, 1, 4, 36, 144, 1, 4, 0, 0, + src_int32_4_1_3401_5000_fir}; +/** \endcond */ diff --git a/src/audio/src/coef/src_ipc4_int32_4_1_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_4_1_4535_5000.h index 3d53542f1d4b..b422972b5d13 100644 --- a/src/audio/src/coef/src_ipc4_int32_4_1_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_1_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_4_1_4535_5000_fir[416] = { +__cold_rodata static const int32_t src_int32_4_1_4535_5000_fir[416] = { -49159, 81297, -120482, diff --git a/src/audio/src/coef/src_ipc4_int32_4_21_1080_5000.h b/src/audio/src/coef/src_ipc4_int32_4_21_1080_5000.h index 91eb1bdd173e..b175e8efba70 100644 --- a/src/audio/src/coef/src_ipc4_int32_4_21_1080_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_21_1080_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_4_21_1080_5000_fir[224] = { +__cold_rodata static const int32_t src_int32_4_21_1080_5000_fir[224] = { -1944411, -1843091, 94714, diff --git a/src/audio/src/coef/src_ipc4_int32_4_21_3239_5000.h b/src/audio/src/coef/src_ipc4_int32_4_21_3239_5000.h index c97905046e66..3085264b8bc6 100644 --- a/src/audio/src/coef/src_ipc4_int32_4_21_3239_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_21_3239_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_4_21_3239_5000_fir[512] = { +__cold_rodata static const int32_t src_int32_4_21_3239_5000_fir[512] = { 27727, -202088, -526392, diff --git a/src/audio/src/coef/src_ipc4_int32_4_3_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_4_3_4535_5000.h index cffc6982be38..752e2a801180 100644 --- a/src/audio/src/coef/src_ipc4_int32_4_3_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_3_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_4_3_4535_5000_fir[432] = { +__cold_rodata static const int32_t src_int32_4_3_4535_5000_fir[432] = { -38206, 66050, -102182, diff --git a/src/audio/src/coef/src_ipc4_int32_5_21_1728_5000.h b/src/audio/src/coef/src_ipc4_int32_5_21_1728_5000.h index c0ec2a704e62..ad1d42e2dec3 100644 --- a/src/audio/src/coef/src_ipc4_int32_5_21_1728_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_5_21_1728_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_5_21_1728_5000_fir[320] = { +__cold_rodata static const int32_t src_int32_5_21_1728_5000_fir[320] = { -201787, 180377, 1173676, diff --git a/src/audio/src/coef/src_ipc4_int32_5_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_5_21_4535_5000.h index dd4c46f9643f..b81b50a4dbf2 100644 --- a/src/audio/src/coef/src_ipc4_int32_5_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_5_21_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_5_21_4535_5000_fir[1740] = { +__cold_rodata static const int32_t src_int32_5_21_4535_5000_fir[1740] = { -236856, -188323, -23805, diff --git a/src/audio/src/coef/src_ipc4_int32_5_7_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_5_7_4535_5000.h index 9fe2321b17c8..59869dfb8c70 100644 --- a/src/audio/src/coef/src_ipc4_int32_5_7_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_5_7_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_5_7_4535_5000_fir[680] = { +__cold_rodata static const int32_t src_int32_5_7_4535_5000_fir[680] = { 42053, -83399, 41109, diff --git a/src/audio/src/coef/src_ipc4_int32_64_21_2381_5000.h b/src/audio/src/coef/src_ipc4_int32_64_21_2381_5000.h new file mode 100644 index 000000000000..4680121475ea --- /dev/null +++ b/src/audio/src/coef/src_ipc4_int32_64_21_2381_5000.h @@ -0,0 +1,1553 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + */ + +/** \cond GENERATED_BY_TOOLS_TUNE_SRC */ +#include <stdint.h> + +__cold_rodata static const int32_t src_int32_64_21_2381_5000_fir[1536] = { + 47591, + 250302, + -2161881, + 5260958, + -3813413, + -11226687, + 39578873, + -56907168, + 18408470, + 109021034, + -306866913, + 500016339, + 1584969758, + 475586321, + -304787599, + 113202848, + 14350486, + -55091896, + 39575290, + -11842807, + -3354035, + 5104429, + -2158300, + 268573, + 53332, + 230720, + -2162004, + 5413465, + -4277163, + -10582872, + 39526837, + -58671546, + 22502033, + 104623873, + -308566270, + 524582475, + 1584255515, + 451309412, + -302338068, + 117167099, + 10333066, + -53229009, + 39517003, + -12430851, + -2899618, + 4944220, + -2151369, + 285546, + 59370, + 209814, + -2158564, + 5561609, + -4744677, + -9911789, + 39418330, + -60381773, + 26626068, + 100013897, + -309876190, + 549267497, + 1582827630, + 427202349, + -299528311, + 120911886, + 6361065, + -51321804, + 39404992, + -12990487, + -2450730, + 4780668, + -2141201, + 301239, + 65701, + 187575, + -2151458, + 5705047, + -5215329, + -9213914, + 39252572, + -62034622, + 30775355, + 95193951, + -310787472, + 574053947, + 1580687306, + 403281600, + -296368555, + 124435620, + 2439212, + -49373589, + 39240295, + -13521430, + -2007922, + 4614110, + -2127910, + 315669, + 72323, + 163996, + -2140588, + 5843434, + -5688476, + -8489773, + 39028849, + -63626894, + 34944559, + 90167203, + -311291202, + 598924161, + 1577836345, + 379563347, + -292869249, + 127737020, + -1427904, + -47387680, + 39024011, + -14023444, + -1571721, + 4444878, + -2111610, + 328856, + 79230, + 139071, + -2125858, + 5976426, + -6163457, + -7739939, + 38746522, + -65155429, + 39128242, + 84937134, + -311378767, + 623860284, + 1574277145, + 356063471, + -289041053, + 130815114, + -5235833, + -45367398, + 38757294, + -14496338, + -1142637, + 4273302, + -2092421, + 340823, + 86416, + 112799, + -2107178, + 6103681, + -6639595, + -6965034, + 38405025, + -66617111, + 43320867, + 79507546, + -311041866, + 648844282, + 1570012701, + 332797542, + -284894819, + 133669233, + -8980270, + -43316059, + 38441352, + -14939966, + -721156, + 4099706, + -2070463, + 351595, + 93874, + 85181, + -2084461, + 6224857, + -7116197, + -6165729, + 38003869, + -68008869, + 47516803, + 73882558, + -310272527, + 673857966, + 1565046601, + 309780804, + -280441585, + 136299008, + -12657056, + -41236974, + 38077443, + -15354231, + -307744, + 3924412, + -2045856, + 361195, + 101595, + 56219, + -2057625, + 6339613, + -7592556, + -5342741, + 37542643, + -69327684, + 51710332, + 68066606, + -309063113, + 698883004, + 1559383019, + 287028158, + -275692553, + 138704368, + -16262187, + -39133445, + 37666873, + -15739077, + 97156, + 3747733, + -2018723, + 369652, + 109571, + 25919, + -2026595, + 6447612, + -8067950, + -4496839, + 37021016, + -70570598, + 55895658, + 62064442, + -307406335, + 723900940, + 1553026714, + 264554155, + -270659081, + 140885533, + -19791811, + -37008756, + 37210994, + -16094496, + 493123, + 3569982, + -1989187, + 376993, + 117790, + -5708, + -1991298, + 6548518, + -8541645, + -3628836, + 36438739, + -71734710, + 60066909, + 55881132, + -305295265, + 748893211, + 1545983024, + 242372982, + -265352664, + 142843015, + -23242237, + -34866172, + 36711199, + -16420520, + 879757, + 3391462, + -1957373, + 383249, + 126243, + -38651, + -1951668, + 6642000, + -9012894, + -2739595, + 35795647, + -72817191, + 64218147, + 49522057, + -302723348, + 773841164, + 1538257861, + 220498447, + -259784925, + 144577605, + -26609932, + -32708934, + 36168925, + -16717225, + 1256681, + 3212471, + -1923404, + 388451, + 134915, + -72894, + -1907645, + 6727731, + -9480939, + -1830023, + 35091658, + -73815282, + 68343375, + 42992903, + -299684407, + 798726077, + 1529857705, + 198943971, + -253967598, + 146090378, + -29891528, + -30540255, + 35585643, + -16984730, + 1623543, + 3033303, + -1887406, + 392630, + 143793, + -108420, + -1859174, + 6805390, + -9945011, + -901076, + 34326779, + -74726302, + 72436545, + 36299668, + -296172659, + 823529173, + 1520789595, + 177722577, + -247912514, + 147382679, + -33083823, + -28363315, + 34962858, + -17223194, + 1980009, + 2854242, + -1849504, + 395819, + 152863, + -145206, + -1806209, + 6874659, + -10404332, + 46246, + 33501104, + -75547652, + 76491561, + 29448654, + -292182721, + 848231640, + 1511061124, + 156846878, + -241631586, + 148456123, + -36183781, + -26181258, + 34302111, + -17432814, + 2325772, + 2675566, + -1809820, + 398053, + 162109, + -183228, + -1748705, + 6935229, + -10858116, + 1010897, + 32614816, + -76276820, + 80502294, + 22446461, + -287709624, + 872814648, + 1500680432, + 136329070, + -235136798, + 149312587, + -39188538, + -23997189, + 33604968, + -17613828, + 2660545, + 2497546, + -1768480, + 399367, + 171512, + -222458, + -1686631, + 6986795, + -11305571, + 1991787, + 31668187, + -76911387, + 84462583, + 15299987, + -282748817, + 897259370, + 1489656194, + 116180917, + -228440188, + 149954205, + -42095400, + -21814165, + 32873024, + -17766511, + 2984066, + 2320445, + -1725607, + 399795, + 181055, + -262864, + -1619956, + 7029060, + -11745895, + 2987784, + 30661582, + -77449029, + 88366247, + 8016425, + -277296177, + 921546997, + 1477997615, + 96413749, + -221553837, + 150383359, + -44901844, + -19635200, + 32107896, + -17891176, + 3296095, + 2144519, + -1681323, + 399374, + 190719, + -304410, + -1548661, + 7061738, + -12178284, + 3997712, + 29595458, + -77887525, + 92207089, + 603252, + -271348022, + 945658759, + 1465714418, + 77038449, + -214489852, + 150602678, + -47605522, + -17463254, + 31311224, + -17988170, + 3596414, + 1970014, + -1635749, + 398140, + 200482, + -347060, + -1472732, + 7084549, + -12601931, + 5020356, + 28470363, + -78224758, + 95978910, + -6931771, + -264901112, + 969575939, + 1452816836, + 58065446, + -207260354, + 150615024, + -50204260, + -15301232, + 30484663, + -18057874, + 3884827, + 1797170, + -1589006, + 396131, + 210324, + -390770, + -1392164, + 7097223, + -13016023, + 6054457, + 27286941, + -78458723, + 99675513, + -14580604, + -257952661, + 993279899, + 1439315596, + 39504709, + -199877464, + 150423493, + -52696059, + -13151983, + 29629886, + -18100704, + 4161162, + 1626216, + -1541212, + 393384, + 220221, + -435497, + -1306960, + 7099499, + -13419748, + 7098722, + 26045928, + -78587528, + 103290711, + -22334939, + -250500343, + 1016752091, + 1425221918, + 21365739, + -192353290, + 150031400, + -55079093, + -11018293, + 28748580, + -18117108, + 4425269, + 1457374, + -1492483, + 389935, + 230149, + -481189, + -1217128, + 7091130, + -13812293, + 8151816, + 24748156, + -78609404, + 106818339, + -30186202, + -242542297, + 1039974078, + 1410547493, + 3657563, + -184699913, + 149442278, + -57351714, + -8902884, + 27842438, + -18107563, + 4677018, + 1290855, + -1442935, + 385823, + 240083, + -527797, + -1122689, + 7071876, + -14192847, + 9212370, + 23394550, + -78522700, + 110252260, + -38125560, + -234077135, + 1062927555, + 1395304478, + -13611270, + -176929375, + 148659867, + -59512446, + -6808413, + 26913165, + -18072577, + 4916304, + 1126865, + -1392682, + 381086, + 249998, + -575263, + -1023669, + 7041513, + -14560598, + 10278979, + 21986132, + -78325896, + 113586372, + -46143931, + -225103949, + 1085594362, + 1379505480, + -30432697, + -169053663, + 147688106, + -61559988, + -4737464, + 25962468, + -18012685, + 5143040, + 965595, + -1341834, + 375761, + 259866, + -623528, + -920104, + 6999826, + -14914743, + 11350206, + 20524016, + -78017603, + 116814621, + -54231989, + -215622310, + 1107956506, + 1363163543, + -46799146, + -161084700, + 146531127, + -63493215, + -2692551, + 24992058, + -17928451, + 5357163, + 807233, + -1290499, + 369886, + 269658, + -672530, + -812038, + 6946617, + -15254478, + 12424581, + 19009414, + -77596567, + 119931007, + -62380170, + -205632280, + 1129996177, + 1346292139, + -62703534, + -153034329, + 145193248, + -65311171, + -676112, + 24003644, + -17820462, + 5558630, + 651952, + -1238785, + 363498, + 279347, + -722203, + -699524, + 6881698, + -15579010, + 13500604, + 17443629, + -77061672, + 122929593, + -70578687, + -195134412, + 1151695767, + 1328905149, + -78139279, + -144914305, + 143678960, + -67013076, + 1309492, + 22998935, + -17689331, + 5747416, + 499920, + -1186795, + 356634, + 288902, + -772475, + -582625, + 6804898, + -15887551, + 14576747, + 15828060, + -76411947, + 125804513, + -78817531, + -184129754, + 1173037887, + 1311016849, + -93100296, + -136736276, + 141992924, + -68598316, + 3261979, + 21979632, + -17535693, + 5923519, + 351293, + -1134630, + 349331, + 298292, + -823275, + -461412, + 6716061, + -16179323, + 15651455, + 14164199, + -75646563, + 128549986, + -87086484, + -172619852, + 1194005384, + 1292641902, + -107581003, + -128511779, + 140139960, + -70066449, + 5179151, + 20947431, + -17360205, + 6086957, + 206217, + -1082389, + 341625, + 307484, + -874526, + -335965, + 6615046, + -16453558, + 16723148, + 12453630, + -74764843, + 131160315, + -95375128, + -160606755, + 1214581359, + 1273795333, + -121576323, + -120252220, + 138125038, + -71417198, + 7058889, + 19904017, + -17163543, + 6237765, + 64830, + -1030166, + 333553, + 316448, + -926147, + -206375, + 6501727, + -16709499, + 17790225, + 10698030, + -73766263, + 133629906, + -103672854, + -148093013, + 1234749186, + 1254492522, + -135081682, + -111968872, + 135953271, + -72650452, + 8899164, + 18851062, + -16946404, + 6375997, + -72740, + -978056, + 325149, + 325149, + -978056, + -72740, + 6375997, + -16946404, + 18851062, + 8899164, + -72650452, + 135953271, + -111968872, + -135081682, + 1254492522, + 1234749186, + -148093013, + -103672854, + 133629906, + -73766263, + 10698030, + 17790225, + -16709499, + 6501727, + -206375, + -926147, + 316448, + 333553, + -1030166, + 64830, + 6237765, + -17163543, + 19904017, + 7058889, + -71417198, + 138125038, + -120252220, + -121576323, + 1273795333, + 1214581359, + -160606755, + -95375128, + 131160315, + -74764843, + 12453630, + 16723148, + -16453558, + 6615046, + -335965, + -874526, + 307484, + 341625, + -1082389, + 206217, + 6086957, + -17360205, + 20947431, + 5179151, + -70066449, + 140139960, + -128511779, + -107581003, + 1292641902, + 1194005384, + -172619852, + -87086484, + 128549986, + -75646563, + 14164199, + 15651455, + -16179323, + 6716061, + -461412, + -823275, + 298292, + 349331, + -1134630, + 351293, + 5923519, + -17535693, + 21979632, + 3261979, + -68598316, + 141992924, + -136736276, + -93100296, + 1311016849, + 1173037887, + -184129754, + -78817531, + 125804513, + -76411947, + 15828060, + 14576747, + -15887551, + 6804898, + -582625, + -772475, + 288902, + 356634, + -1186795, + 499920, + 5747416, + -17689331, + 22998935, + 1309492, + -67013076, + 143678960, + -144914305, + -78139279, + 1328905149, + 1151695767, + -195134412, + -70578687, + 122929593, + -77061672, + 17443629, + 13500604, + -15579010, + 6881698, + -699524, + -722203, + 279347, + 363498, + -1238785, + 651952, + 5558630, + -17820462, + 24003644, + -676112, + -65311171, + 145193248, + -153034329, + -62703534, + 1346292139, + 1129996177, + -205632280, + -62380170, + 119931007, + -77596567, + 19009414, + 12424581, + -15254478, + 6946617, + -812038, + -672530, + 269658, + 369886, + -1290499, + 807233, + 5357163, + -17928451, + 24992058, + -2692551, + -63493215, + 146531127, + -161084700, + -46799146, + 1363163543, + 1107956506, + -215622310, + -54231989, + 116814621, + -78017603, + 20524016, + 11350206, + -14914743, + 6999826, + -920104, + -623528, + 259866, + 375761, + -1341834, + 965595, + 5143040, + -18012685, + 25962468, + -4737464, + -61559988, + 147688106, + -169053663, + -30432697, + 1379505480, + 1085594362, + -225103949, + -46143931, + 113586372, + -78325896, + 21986132, + 10278979, + -14560598, + 7041513, + -1023669, + -575263, + 249998, + 381086, + -1392682, + 1126865, + 4916304, + -18072577, + 26913165, + -6808413, + -59512446, + 148659867, + -176929375, + -13611270, + 1395304478, + 1062927555, + -234077135, + -38125560, + 110252260, + -78522700, + 23394550, + 9212370, + -14192847, + 7071876, + -1122689, + -527797, + 240083, + 385823, + -1442935, + 1290855, + 4677018, + -18107563, + 27842438, + -8902884, + -57351714, + 149442278, + -184699913, + 3657563, + 1410547493, + 1039974078, + -242542297, + -30186202, + 106818339, + -78609404, + 24748156, + 8151816, + -13812293, + 7091130, + -1217128, + -481189, + 230149, + 389935, + -1492483, + 1457374, + 4425269, + -18117108, + 28748580, + -11018293, + -55079093, + 150031400, + -192353290, + 21365739, + 1425221918, + 1016752091, + -250500343, + -22334939, + 103290711, + -78587528, + 26045928, + 7098722, + -13419748, + 7099499, + -1306960, + -435497, + 220221, + 393384, + -1541212, + 1626216, + 4161162, + -18100704, + 29629886, + -13151983, + -52696059, + 150423493, + -199877464, + 39504709, + 1439315596, + 993279899, + -257952661, + -14580604, + 99675513, + -78458723, + 27286941, + 6054457, + -13016023, + 7097223, + -1392164, + -390770, + 210324, + 396131, + -1589006, + 1797170, + 3884827, + -18057874, + 30484663, + -15301232, + -50204260, + 150615024, + -207260354, + 58065446, + 1452816836, + 969575939, + -264901112, + -6931771, + 95978910, + -78224758, + 28470363, + 5020356, + -12601931, + 7084549, + -1472732, + -347060, + 200482, + 398140, + -1635749, + 1970014, + 3596414, + -17988170, + 31311224, + -17463254, + -47605522, + 150602678, + -214489852, + 77038449, + 1465714418, + 945658759, + -271348022, + 603252, + 92207089, + -77887525, + 29595458, + 3997712, + -12178284, + 7061738, + -1548661, + -304410, + 190719, + 399374, + -1681323, + 2144519, + 3296095, + -17891176, + 32107896, + -19635200, + -44901844, + 150383359, + -221553837, + 96413749, + 1477997615, + 921546997, + -277296177, + 8016425, + 88366247, + -77449029, + 30661582, + 2987784, + -11745895, + 7029060, + -1619956, + -262864, + 181055, + 399795, + -1725607, + 2320445, + 2984066, + -17766511, + 32873024, + -21814165, + -42095400, + 149954205, + -228440188, + 116180917, + 1489656194, + 897259370, + -282748817, + 15299987, + 84462583, + -76911387, + 31668187, + 1991787, + -11305571, + 6986795, + -1686631, + -222458, + 171512, + 399367, + -1768480, + 2497546, + 2660545, + -17613828, + 33604968, + -23997189, + -39188538, + 149312587, + -235136798, + 136329070, + 1500680432, + 872814648, + -287709624, + 22446461, + 80502294, + -76276820, + 32614816, + 1010897, + -10858116, + 6935229, + -1748705, + -183228, + 162109, + 398053, + -1809820, + 2675566, + 2325772, + -17432814, + 34302111, + -26181258, + -36183781, + 148456123, + -241631586, + 156846878, + 1511061124, + 848231640, + -292182721, + 29448654, + 76491561, + -75547652, + 33501104, + 46246, + -10404332, + 6874659, + -1806209, + -145206, + 152863, + 395819, + -1849504, + 2854242, + 1980009, + -17223194, + 34962858, + -28363315, + -33083823, + 147382679, + -247912514, + 177722577, + 1520789595, + 823529173, + -296172659, + 36299668, + 72436545, + -74726302, + 34326779, + -901076, + -9945011, + 6805390, + -1859174, + -108420, + 143793, + 392630, + -1887406, + 3033303, + 1623543, + -16984730, + 35585643, + -30540255, + -29891528, + 146090378, + -253967598, + 198943971, + 1529857705, + 798726077, + -299684407, + 42992903, + 68343375, + -73815282, + 35091658, + -1830023, + -9480939, + 6727731, + -1907645, + -72894, + 134915, + 388451, + -1923404, + 3212471, + 1256681, + -16717225, + 36168925, + -32708934, + -26609932, + 144577605, + -259784925, + 220498447, + 1538257861, + 773841164, + -302723348, + 49522057, + 64218147, + -72817191, + 35795647, + -2739595, + -9012894, + 6642000, + -1951668, + -38651, + 126243, + 383249, + -1957373, + 3391462, + 879757, + -16420520, + 36711199, + -34866172, + -23242237, + 142843015, + -265352664, + 242372982, + 1545983024, + 748893211, + -305295265, + 55881132, + 60066909, + -71734710, + 36438739, + -3628836, + -8541645, + 6548518, + -1991298, + -5708, + 117790, + 376993, + -1989187, + 3569982, + 493123, + -16094496, + 37210994, + -37008756, + -19791811, + 140885533, + -270659081, + 264554155, + 1553026714, + 723900940, + -307406335, + 62064442, + 55895658, + -70570598, + 37021016, + -4496839, + -8067950, + 6447612, + -2026595, + 25919, + 109571, + 369652, + -2018723, + 3747733, + 97156, + -15739077, + 37666873, + -39133445, + -16262187, + 138704368, + -275692553, + 287028158, + 1559383019, + 698883004, + -309063113, + 68066606, + 51710332, + -69327684, + 37542643, + -5342741, + -7592556, + 6339613, + -2057625, + 56219, + 101595, + 361195, + -2045856, + 3924412, + -307744, + -15354231, + 38077443, + -41236974, + -12657056, + 136299008, + -280441585, + 309780804, + 1565046601, + 673857966, + -310272527, + 73882558, + 47516803, + -68008869, + 38003869, + -6165729, + -7116197, + 6224857, + -2084461, + 85181, + 93874, + 351595, + -2070463, + 4099706, + -721156, + -14939966, + 38441352, + -43316059, + -8980270, + 133669233, + -284894819, + 332797542, + 1570012701, + 648844282, + -311041866, + 79507546, + 43320867, + -66617111, + 38405025, + -6965034, + -6639595, + 6103681, + -2107178, + 112799, + 86416, + 340823, + -2092421, + 4273302, + -1142637, + -14496338, + 38757294, + -45367398, + -5235833, + 130815114, + -289041053, + 356063471, + 1574277145, + 623860284, + -311378767, + 84937134, + 39128242, + -65155429, + 38746522, + -7739939, + -6163457, + 5976426, + -2125858, + 139071, + 79230, + 328856, + -2111610, + 4444878, + -1571721, + -14023444, + 39024011, + -47387680, + -1427904, + 127737020, + -292869249, + 379563347, + 1577836345, + 598924161, + -311291202, + 90167203, + 34944559, + -63626894, + 39028849, + -8489773, + -5688476, + 5843434, + -2140588, + 163996, + 72323, + 315669, + -2127910, + 4614110, + -2007922, + -13521430, + 39240295, + -49373589, + 2439212, + 124435620, + -296368555, + 403281600, + 1580687306, + 574053947, + -310787472, + 95193951, + 30775355, + -62034622, + 39252572, + -9213914, + -5215329, + 5705047, + -2151458, + 187575, + 65701, + 301239, + -2141201, + 4780668, + -2450730, + -12990487, + 39404992, + -51321804, + 6361065, + 120911886, + -299528311, + 427202349, + 1582827630, + 549267497, + -309876190, + 100013897, + 26626068, + -60381773, + 39418330, + -9911789, + -4744677, + 5561609, + -2158564, + 209814, + 59370, + 285546, + -2151369, + 4944220, + -2899618, + -12430851, + 39517003, + -53229009, + 10333066, + 117167099, + -302338068, + 451309412, + 1584255515, + 524582475, + -308566270, + 104623873, + 22502033, + -58671546, + 39526837, + -10582872, + -4277163, + 5413465, + -2162004, + 230720, + 53332, + 268573, + -2158300, + 5104429, + -3354035, + -11842807, + 39575290, + -55091896, + 14350486, + 113202848, + -304787599, + 475586321, + 1584969758, + 500016339, + -306866913, + 109021034, + 18408470, + -56907168, + 39578873, + -11226687, + -3813413, + 5260958, + -2161881, + 250302, + 47591 + +}; + +static const struct src_stage src_int32_64_21_2381_5000 = { + 20, 61, 64, 24, 1536, 21, 64, 0, 0, + src_int32_64_21_2381_5000_fir}; +/** \endcond */ diff --git a/src/audio/src/coef/src_ipc4_int32_6_1_1134_5000.h b/src/audio/src/coef/src_ipc4_int32_6_1_1134_5000.h index ea5f80c10b6d..24afbc0c515b 100644 --- a/src/audio/src/coef/src_ipc4_int32_6_1_1134_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_6_1_1134_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_6_1_1134_5000_fir[96] = { +__cold_rodata static const int32_t src_int32_6_1_1134_5000_fir[96] = { 141841, 2137064, -10649573, diff --git a/src/audio/src/coef/src_ipc4_int32_7_3_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_7_3_4535_5000.h index ec23514f712f..90b79d1c5e5f 100644 --- a/src/audio/src/coef/src_ipc4_int32_7_3_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_3_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_7_3_4535_5000_fir[728] = { +__cold_rodata static const int32_t src_int32_7_3_4535_5000_fir[728] = { -46837, 76113, -110550, diff --git a/src/audio/src/coef/src_ipc4_int32_7_40_2976_5000.h b/src/audio/src/coef/src_ipc4_int32_7_40_2976_5000.h new file mode 100644 index 000000000000..d88f607edb96 --- /dev/null +++ b/src/audio/src/coef/src_ipc4_int32_7_40_2976_5000.h @@ -0,0 +1,801 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + */ + +/** \cond GENERATED_BY_TOOLS_TUNE_SRC */ +#include <stdint.h> + +__cold_rodata static const int32_t src_int32_7_40_2976_5000_fir[784] = { + -421117, + -873443, + -1322755, + -1593517, + -1494133, + -875322, + 305977, + 1935378, + 3721720, + 5224342, + 5931818, + 5383518, + 3311135, + -233691, + -4803751, + -9565560, + -13411383, + -15168908, + -13877127, + -9073390, + -1022383, + 9181848, + 19692130, + 28180417, + 32279941, + 30125596, + 20884518, + 5151728, + -14905050, + -35729583, + -52906902, + -61980038, + -59421519, + -43572146, + -15337429, + 21547643, + 60810851, + 94518072, + 114439887, + 113704027, + 88442916, + 39109504, + -28839808, + -105108031, + -175639859, + -224529950, + -236499541, + -199554513, + -107371492, + 39028183, + 230661341, + 451202931, + 678817148, + 888962385, + 1057754877, + 1165365556, + 1198903822, + 1154316530, + 1036988523, + 860945132, + 646788849, + 418710646, + 201063855, + 15049839, + -123969705, + -208140633, + -237556125, + -219473106, + -166512376, + -94205483, + -18335557, + 47479356, + 93588752, + 115262298, + 112723681, + 90361539, + 55346507, + 15963162, + -20017836, + -46646307, + -60587377, + -61329947, + -50850645, + -32870225, + -11897359, + 7731235, + 22633035, + 30861893, + 32042571, + 27184128, + 18257378, + 7655385, + -2338819, + -9973487, + -14272925, + -15086232, + -12963411, + -8913684, + -4115983, + 350358, + 3702636, + 5551849, + 5898310, + 5046349, + 3472379, + 1684346, + 105201, + -998677, + -1537513, + -1573189, + -1264997, + -805485, + -480627, + -941437, + -1376902, + -1606222, + -1439974, + -740218, + 516204, + 2189873, + 3965399, + 5386028, + 5939375, + 5183538, + 2888905, + -839329, + -5495912, + -10198866, + -13816387, + -15188511, + -13408417, + -8105599, + 339295, + 10715397, + 21085704, + 29086301, + 32387931, + 29242236, + 19000822, + 2481584, + -17929907, + -38514615, + -54796213, + -62389583, + -57980048, + -40240382, + -10476124, + 27183538, + 66162367, + 98391009, + 115729428, + 111637899, + 82797280, + 30351463, + -39520282, + -115896722, + -184324672, + -228827782, + -234435092, + -189828611, + -89653272, + 63942166, + 260858197, + 483844190, + 710487849, + 916128833, + 1077260839, + 1174887882, + 1197293382, + 1141768318, + 1015012729, + 832143987, + 614476184, + 386436641, + 172121897, + -7956647, + -139435040, + -215597131, + -237634268, + -213699577, + -156989711, + -83233969, + -8043315, + 55438648, + 98227457, + 116319371, + 110598215, + 85944939, + 49793943, + 10451268, + -24502884, + -49456713, + -61479641, + -60447884, + -48639991, + -29950124, + -8918761, + 10211804, + 24242679, + 31451990, + 31680326, + 26104111, + 16788647, + 6142252, + -3605762, + -10804105, + -14596383, + -14942859, + -12475837, + -8246726, + -3435494, + 910992, + 4062796, + 5688996, + 5840056, + 4853574, + 3218822, + 1437851, + -85571, + -1110241, + -1570460, + -1545789, + -1204193, + -738003, + -542379, + -1009006, + -1426859, + -1610769, + -1374731, + -593475, + 735249, + 2446694, + 4201937, + 5529901, + 5919856, + 4951583, + 2436732, + -1464566, + -6189458, + -10810082, + -14175146, + -15142874, + -12866532, + -7072260, + 1741640, + 12249576, + 22430879, + 29895316, + 32362476, + 28211562, + 16986320, + -270294, + -20959622, + -41211706, + -56506417, + -62550798, + -56262045, + -36658385, + -5449480, + 32848951, + 71376299, + 101957388, + 116576173, + 109059101, + 76661321, + 21229682, + -50339571, + -126525855, + -192519577, + -232325660, + -231335763, + -178955902, + -70831317, + 89752427, + 291595903, + 516563953, + 741727992, + 942379288, + 1095458419, + 1182859767, + 1194076531, + 1127752120, + 991881250, + 802627390, + 581952447, + 354448865, + 143889120, + -29958271, + -153758024, + -221937219, + -236765674, + -207252917, + -147119438, + -72237431, + 2002847, + 62967125, + 102353821, + 116883679, + 108082072, + 81292260, + 44177534, + 5032335, + -28779243, + -51998427, + -62101395, + -59343168, + -46287819, + -26982781, + -5980765, + 12585758, + 25710433, + 31897343, + 31198118, + 24947218, + 15293081, + 4648458, + -4819303, + -11563814, + -14848374, + -14741361, + -11952094, + -7568127, + -2765041, + 1446556, + 4391168, + 5795550, + 5758333, + 4647554, + 2962455, + 1196894, + -265863, + -1210038, + -1593362, + -1511884, + -1140901, + -671407, + -606081, + -1075663, + -1472047, + -1606645, + -1298153, + -435273, + 962407, + 2704641, + 4429830, + 5654483, + 5872226, + 4687471, + 1955572, + -2107242, + -6881269, + -11395670, + -14484487, + -15030059, + -12251533, + -5975874, + 3179760, + 13777741, + 23720441, + 30601236, + 32199980, + 27033954, + 14846058, + -3094422, + -23981557, + -43807274, + -58025802, + -62456748, + -54267717, + -32834740, + -274115, + 38521327, + 76427847, + 105194915, + 116965359, + 105964724, + 70046670, + 11770650, + -61258741, + -136949060, + -200177744, + -234984190, + -227177079, + -166932560, + -50925298, + 116416543, + 322813723, + 549290776, + 772465100, + 967650481, + 1112302727, + 1189261314, + 1189261314, + 1112302727, + 967650481, + 772465100, + 549290776, + 322813723, + 116416543, + -50925298, + -166932560, + -227177079, + -234984190, + -200177744, + -136949060, + -61258741, + 11770650, + 70046670, + 105964724, + 116965359, + 105194915, + 76427847, + 38521327, + -274115, + -32834740, + -54267717, + -62456748, + -58025802, + -43807274, + -23981557, + -3094422, + 14846058, + 27033954, + 32199980, + 30601236, + 23720441, + 13777741, + 3179760, + -5975874, + -12251533, + -15030059, + -14484487, + -11395670, + -6881269, + -2107242, + 1955572, + 4687471, + 5872226, + 5654483, + 4429830, + 2704641, + 962407, + -435273, + -1298153, + -1606645, + -1472047, + -1075663, + -606081, + -671407, + -1140901, + -1511884, + -1593362, + -1210038, + -265863, + 1196894, + 2962455, + 4647554, + 5758333, + 5795550, + 4391168, + 1446556, + -2765041, + -7568127, + -11952094, + -14741361, + -14848374, + -11563814, + -4819303, + 4648458, + 15293081, + 24947218, + 31198118, + 31897343, + 25710433, + 12585758, + -5980765, + -26982781, + -46287819, + -59343168, + -62101395, + -51998427, + -28779243, + 5032335, + 44177534, + 81292260, + 108082072, + 116883679, + 102353821, + 62967125, + 2002847, + -72237431, + -147119438, + -207252917, + -236765674, + -221937219, + -153758024, + -29958271, + 143889120, + 354448865, + 581952447, + 802627390, + 991881250, + 1127752120, + 1194076531, + 1182859767, + 1095458419, + 942379288, + 741727992, + 516563953, + 291595903, + 89752427, + -70831317, + -178955902, + -231335763, + -232325660, + -192519577, + -126525855, + -50339571, + 21229682, + 76661321, + 109059101, + 116576173, + 101957388, + 71376299, + 32848951, + -5449480, + -36658385, + -56262045, + -62550798, + -56506417, + -41211706, + -20959622, + -270294, + 16986320, + 28211562, + 32362476, + 29895316, + 22430879, + 12249576, + 1741640, + -7072260, + -12866532, + -15142874, + -14175146, + -10810082, + -6189458, + -1464566, + 2436732, + 4951583, + 5919856, + 5529901, + 4201937, + 2446694, + 735249, + -593475, + -1374731, + -1610769, + -1426859, + -1009006, + -542379, + -738003, + -1204193, + -1545789, + -1570460, + -1110241, + -85571, + 1437851, + 3218822, + 4853574, + 5840056, + 5688996, + 4062796, + 910992, + -3435494, + -8246726, + -12475837, + -14942859, + -14596383, + -10804105, + -3605762, + 6142252, + 16788647, + 26104111, + 31680326, + 31451990, + 24242679, + 10211804, + -8918761, + -29950124, + -48639991, + -60447884, + -61479641, + -49456713, + -24502884, + 10451268, + 49793943, + 85944939, + 110598215, + 116319371, + 98227457, + 55438648, + -8043315, + -83233969, + -156989711, + -213699577, + -237634268, + -215597131, + -139435040, + -7956647, + 172121897, + 386436641, + 614476184, + 832143987, + 1015012729, + 1141768318, + 1197293382, + 1174887882, + 1077260839, + 916128833, + 710487849, + 483844190, + 260858197, + 63942166, + -89653272, + -189828611, + -234435092, + -228827782, + -184324672, + -115896722, + -39520282, + 30351463, + 82797280, + 111637899, + 115729428, + 98391009, + 66162367, + 27183538, + -10476124, + -40240382, + -57980048, + -62389583, + -54796213, + -38514615, + -17929907, + 2481584, + 19000822, + 29242236, + 32387931, + 29086301, + 21085704, + 10715397, + 339295, + -8105599, + -13408417, + -15188511, + -13816387, + -10198866, + -5495912, + -839329, + 2888905, + 5183538, + 5939375, + 5386028, + 3965399, + 2189873, + 516204, + -740218, + -1439974, + -1606222, + -1376902, + -941437, + -480627, + -805485, + -1264997, + -1573189, + -1537513, + -998677, + 105201, + 1684346, + 3472379, + 5046349, + 5898310, + 5551849, + 3702636, + 350358, + -4115983, + -8913684, + -12963411, + -15086232, + -14272925, + -9973487, + -2338819, + 7655385, + 18257378, + 27184128, + 32042571, + 30861893, + 22633035, + 7731235, + -11897359, + -32870225, + -50850645, + -61329947, + -60587377, + -46646307, + -20017836, + 15963162, + 55346507, + 90361539, + 112723681, + 115262298, + 93588752, + 47479356, + -18335557, + -94205483, + -166512376, + -219473106, + -237556125, + -208140633, + -123969705, + 15049839, + 201063855, + 418710646, + 646788849, + 860945132, + 1036988523, + 1154316530, + 1198903822, + 1165365556, + 1057754877, + 888962385, + 678817148, + 451202931, + 230661341, + 39028183, + -107371492, + -199554513, + -236499541, + -224529950, + -175639859, + -105108031, + -28839808, + 39109504, + 88442916, + 113704027, + 114439887, + 94518072, + 60810851, + 21547643, + -15337429, + -43572146, + -59421519, + -61980038, + -52906902, + -35729583, + -14905050, + 5151728, + 20884518, + 30125596, + 32279941, + 28180417, + 19692130, + 9181848, + -1022383, + -9073390, + -13877127, + -15168908, + -13411383, + -9565560, + -4803751, + -233691, + 3311135, + 5383518, + 5931818, + 5224342, + 3721720, + 1935378, + 305977, + -875322, + -1494133, + -1593517, + -1322755, + -873443, + -421117 + +}; + +static const struct src_stage src_int32_7_40_2976_5000 = { + 17, 3, 7, 112, 784, 40, 7, 0, 2, + src_int32_7_40_2976_5000_fir}; +/** \endcond */ diff --git a/src/audio/src/coef/src_ipc4_int32_7_5_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_7_5_4535_5000.h index b7a428c009e0..b4a29de3be84 100644 --- a/src/audio/src/coef/src_ipc4_int32_7_5_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_5_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_7_5_4535_5000_fir[812] = { +__cold_rodata static const int32_t src_int32_7_5_4535_5000_fir[812] = { -13317, 26352, -45392, diff --git a/src/audio/src/coef/src_ipc4_int32_7_8_1361_5000.h b/src/audio/src/coef/src_ipc4_int32_7_8_1361_5000.h index abf0b81aee66..69fb97e904be 100644 --- a/src/audio/src/coef/src_ipc4_int32_7_8_1361_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_8_1361_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_7_8_1361_5000_fir[140] = { +__cold_rodata static const int32_t src_int32_7_8_1361_5000_fir[140] = { -165190, 129875, 4540182, diff --git a/src/audio/src/coef/src_ipc4_int32_7_8_2468_5000.h b/src/audio/src/coef/src_ipc4_int32_7_8_2468_5000.h index 481a61c818ff..3ddeeb8c5fd7 100644 --- a/src/audio/src/coef/src_ipc4_int32_7_8_2468_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_8_2468_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_7_8_2468_5000_fir[196] = { +__cold_rodata static const int32_t src_int32_7_8_2468_5000_fir[196] = { -49360, 723320, -1199972, diff --git a/src/audio/src/coef/src_ipc4_int32_7_8_2721_5000.h b/src/audio/src/coef/src_ipc4_int32_7_8_2721_5000.h index 38608a77d797..4fbb3bb9491a 100644 --- a/src/audio/src/coef/src_ipc4_int32_7_8_2721_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_8_2721_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_7_8_2721_5000_fir[224] = { +__cold_rodata static const int32_t src_int32_7_8_2721_5000_fir[224] = { 65478, 113869, -1097521, diff --git a/src/audio/src/coef/src_ipc4_int32_7_8_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_7_8_4535_5000.h index a5c3fa7a75de..0f0724ddba80 100644 --- a/src/audio/src/coef/src_ipc4_int32_7_8_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_8_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_7_8_4535_5000_fir[840] = { +__cold_rodata static const int32_t src_int32_7_8_4535_5000_fir[840] = { -9, -30815, 77572, diff --git a/src/audio/src/coef/src_ipc4_int32_8_21_2160_5000.h b/src/audio/src/coef/src_ipc4_int32_8_21_2160_5000.h index 15c2e7623a99..c82054dd4455 100644 --- a/src/audio/src/coef/src_ipc4_int32_8_21_2160_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_21_2160_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_8_21_2160_5000_fir[384] = { +__cold_rodata static const int32_t src_int32_8_21_2160_5000_fir[384] = { 401690, 667023, -90063, diff --git a/src/audio/src/coef/src_ipc4_int32_8_21_3239_5000.h b/src/audio/src/coef/src_ipc4_int32_8_21_3239_5000.h index 6eefe17a67f1..c58c41ad824e 100644 --- a/src/audio/src/coef/src_ipc4_int32_8_21_3239_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_21_3239_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_8_21_3239_5000_fir[544] = { +__cold_rodata static const int32_t src_int32_8_21_3239_5000_fir[544] = { 214310, 401153, 58758, diff --git a/src/audio/src/coef/src_ipc4_int32_8_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_8_21_4535_5000.h index 478d4f6ef50c..2090c8a2e429 100644 --- a/src/audio/src/coef/src_ipc4_int32_8_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_21_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_8_21_4535_5000_fir[1984] = { +__cold_rodata static const int32_t src_int32_8_21_4535_5000_fir[1984] = { -4705, 81658, 87540, diff --git a/src/audio/src/coef/src_ipc4_int32_8_7_1361_5000.h b/src/audio/src/coef/src_ipc4_int32_8_7_1361_5000.h index a1bb0e857e1a..01c66f61480a 100644 --- a/src/audio/src/coef/src_ipc4_int32_8_7_1361_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_7_1361_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_8_7_1361_5000_fir[160] = { +__cold_rodata static const int32_t src_int32_8_7_1361_5000_fir[160] = { 128091, -1061856, -689775, diff --git a/src/audio/src/coef/src_ipc4_int32_8_7_2468_5000.h b/src/audio/src/coef/src_ipc4_int32_8_7_2468_5000.h index 4ca99d9d85f8..63bb75d74877 100644 --- a/src/audio/src/coef/src_ipc4_int32_8_7_2468_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_7_2468_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_8_7_2468_5000_fir[192] = { +__cold_rodata static const int32_t src_int32_8_7_2468_5000_fir[192] = { 38025, 446289, -2663076, diff --git a/src/audio/src/coef/src_ipc4_int32_8_7_2721_5000.h b/src/audio/src/coef/src_ipc4_int32_8_7_2721_5000.h index e064904224ee..9529c59e8c45 100644 --- a/src/audio/src/coef/src_ipc4_int32_8_7_2721_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_7_2721_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_8_7_2721_5000_fir[192] = { +__cold_rodata static const int32_t src_int32_8_7_2721_5000_fir[192] = { -68651, 727228, -2055563, diff --git a/src/audio/src/coef/src_ipc4_int32_8_7_4082_5000.h b/src/audio/src/coef/src_ipc4_int32_8_7_4082_5000.h index 2092a7395e88..e4ad44917004 100644 --- a/src/audio/src/coef/src_ipc4_int32_8_7_4082_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_7_4082_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_8_7_4082_5000_fir[480] = { +__cold_rodata static const int32_t src_int32_8_7_4082_5000_fir[480] = { -48290, 148731, -325260, diff --git a/src/audio/src/coef/src_ipc4_int32_8_7_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_8_7_4535_5000.h index 855dacb2ad9c..020e1a0df119 100644 --- a/src/audio/src/coef/src_ipc4_int32_8_7_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_7_4535_5000.h @@ -8,7 +8,7 @@ #include <stdint.h> -static const int32_t src_int32_8_7_4535_5000_fir[896] = { +__cold_rodata static const int32_t src_int32_8_7_4535_5000_fir[896] = { -24053, 43532, -69787, diff --git a/src/audio/src/coef/src_ipc4_int32_define.h b/src/audio/src/coef/src_ipc4_int32_define.h index fede8c51f75f..8eb7de206a8b 100644 --- a/src/audio/src/coef/src_ipc4_int32_define.h +++ b/src/audio/src/coef/src_ipc4_int32_define.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2022 Intel Corporation. All rights reserved. + * Copyright(c) 2025 Intel Corporation. All rights reserved. * */ @@ -8,15 +8,15 @@ #define __SOF_AUDIO_COEFFICIENTS_SRC_SRC_IPC4_INT32_DEFINE_H__ /* SRC constants */ -#define MAX_FIR_DELAY_SIZE 730 -#define MAX_OUT_DELAY_SIZE 900 +#define MAX_FIR_DELAY_SIZE 1305 +#define MAX_OUT_DELAY_SIZE 3844 #define MAX_BLK_IN 80 -#define MAX_BLK_OUT 40 +#define MAX_BLK_OUT 64 #define NUM_IN_FS 16 -#define NUM_OUT_FS 10 +#define NUM_OUT_FS 13 #define STAGE1_TIMES_MAX 32 -#define STAGE2_TIMES_MAX 32 -#define STAGE_BUF_SIZE 672 -#define NUM_ALL_COEFFICIENTS 69224 +#define STAGE2_TIMES_MAX 40 +#define STAGE_BUF_SIZE 840 +#define NUM_ALL_COEFFICIENTS 76328 #endif /* __SOF_AUDIO_COEFFICIENTS_SRC_SRC_IPC4_INT32_DEFINE_H__ */ diff --git a/src/audio/src/coef/src_ipc4_int32_table.h b/src/audio/src/coef/src_ipc4_int32_table.h index 55bf350bead1..96bfe2383016 100644 --- a/src/audio/src/coef/src_ipc4_int32_table.h +++ b/src/audio/src/coef/src_ipc4_int32_table.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2022 Intel Corporation. All rights reserved. + * Copyright(c) 2025 Intel Corporation. All rights reserved. * */ @@ -35,6 +35,7 @@ #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_3401_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" @@ -49,6 +50,7 @@ #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_7_40_2976_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" @@ -97,6 +99,8 @@ #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_ipc4_int32_40_21_4535_5000.h" +#include "src_ipc4_int32_64_21_2381_5000.h" #include <stdint.h> /* SRC table */ @@ -106,9 +110,9 @@ static const struct src_stage src_int32_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, static const int src_in_fs[16] = { 8000, 11025, 12000, 16000, 18900, 22050, 24000, 32000, 37800, 44100, 48000, 64000, 88200, 96000, 176400, 192000 }; -static const int src_out_fs[10] = { 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, - 176400, 192000}; -static const struct src_stage * const src_table1[10][16] = { +static const int src_out_fs[13] = { 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, + 64000, 88200, 96000, 176400, 192000}; +static const struct src_stage * const src_table1[13][16] = { { &src_int32_1_1_0_0, &src_int32_16_21_4319_5000, &src_int32_2_3_4535_5000, &src_int32_1_2_4535_5000, &src_int32_0_0_0_0, &src_int32_10_21_3455_5000, @@ -118,6 +122,15 @@ static const struct src_stage * const src_table1[10][16] = { &src_int32_5_21_1728_5000, &src_int32_1_4_1512_5000, &src_int32_4_21_1080_5000, &src_int32_1_6_1134_5000 }, + { &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_21_80_3968_5000, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_7_40_2976_5000, + &src_int32_0_0_0_0, &src_int32_0_0_0_0 + }, { &src_int32_2_1_4535_5000, &src_int32_32_21_4535_5000, &src_int32_4_3_4535_5000, &src_int32_1_1_0_0, &src_int32_0_0_0_0, &src_int32_16_21_4319_5000, @@ -127,6 +140,15 @@ static const struct src_stage * const src_table1[10][16] = { &src_int32_8_21_2160_5000, &src_int32_1_3_2268_5000, &src_int32_5_21_1728_5000, &src_int32_1_4_1512_5000 }, + { &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_21_40_3968_5000, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_21_80_3968_5000, + &src_int32_0_0_0_0, &src_int32_0_0_0_0 + }, { &src_int32_3_1_4535_5000, &src_int32_8_7_4535_5000, &src_int32_2_1_4535_5000, &src_int32_3_2_4535_5000, &src_int32_10_9_4535_5000, &src_int32_8_7_4535_5000, @@ -163,6 +185,15 @@ static const struct src_stage * const src_table1[10][16] = { &src_int32_8_7_2468_5000, &src_int32_1_2_4535_5000, &src_int32_8_21_3239_5000, &src_int32_1_2_2268_5000 }, + { &src_int32_2_1_4535_5000, &src_int32_40_21_4535_5000, + &src_int32_4_3_4535_5000, &src_int32_2_1_4535_5000, + &src_int32_0_0_0_0, &src_int32_32_21_4535_5000, + &src_int32_4_3_4535_5000, &src_int32_2_1_4535_5000, + &src_int32_0_0_0_0, &src_int32_32_21_4535_5000, + &src_int32_4_3_4535_5000, &src_int32_1_1_0_0, + &src_int32_16_21_4319_5000, &src_int32_2_3_4535_5000, + &src_int32_10_21_3455_5000, &src_int32_1_3_4535_5000 + }, { &src_int32_21_8_4535_5000, &src_int32_2_1_4535_5000, &src_int32_7_5_4535_5000, &src_int32_21_10_4535_5000, &src_int32_0_0_0_0, &src_int32_2_1_4535_5000, @@ -201,7 +232,7 @@ static const struct src_stage * const src_table1[10][16] = { } }; -static const struct src_stage * const src_table2[10][16] = { +static const struct src_stage * const src_table2[13][16] = { { &src_int32_1_1_0_0, &src_int32_20_21_4535_5000, &src_int32_1_1_0_0, &src_int32_1_1_0_0, &src_int32_0_0_0_0, &src_int32_16_21_4535_5000, @@ -211,6 +242,15 @@ static const struct src_stage * const src_table2[10][16] = { &src_int32_8_21_4535_5000, &src_int32_1_3_4535_5000, &src_int32_5_21_4535_5000, &src_int32_1_4_4535_5000 }, + { &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_7_8_4535_5000, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_21_32_4535_5000, + &src_int32_0_0_0_0, &src_int32_0_0_0_0 + }, { &src_int32_1_1_0_0, &src_int32_20_21_3125_5000, &src_int32_1_1_0_0, &src_int32_1_1_0_0, &src_int32_0_0_0_0, &src_int32_20_21_4535_5000, @@ -220,6 +260,15 @@ static const struct src_stage * const src_table2[10][16] = { &src_int32_10_21_4535_5000, &src_int32_1_2_4535_5000, &src_int32_8_21_4535_5000, &src_int32_1_3_4535_5000 }, + { &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_0_0_0_0, + &src_int32_7_8_4535_5000, &src_int32_0_0_0_0, + &src_int32_0_0_0_0, &src_int32_7_8_4535_5000, + &src_int32_0_0_0_0, &src_int32_0_0_0_0 + }, { &src_int32_1_1_0_0, &src_int32_40_21_3968_5000, &src_int32_1_1_0_0, &src_int32_1_1_0_0, &src_int32_8_7_4082_5000, &src_int32_20_21_4167_5000, @@ -256,6 +305,15 @@ static const struct src_stage * const src_table2[10][16] = { &src_int32_10_21_4535_5000, &src_int32_1_1_0_0, &src_int32_5_7_4535_5000, &src_int32_1_2_4535_5000 }, + { &src_int32_4_1_2268_5000, &src_int32_64_21_2381_5000, + &src_int32_4_1_3401_5000, &src_int32_2_1_2268_5000, + &src_int32_0_0_0_0, &src_int32_40_21_2976_5000, + &src_int32_2_1_3401_5000, &src_int32_1_1_0_0, + &src_int32_0_0_0_0, &src_int32_20_21_3125_5000, + &src_int32_1_1_0_0, &src_int32_1_1_0_0, + &src_int32_20_21_4535_5000, &src_int32_1_1_0_0, + &src_int32_16_21_4535_5000, &src_int32_1_1_0_0 + }, { &src_int32_21_5_1728_5000, &src_int32_4_1_2268_5000, &src_int32_21_4_3239_5000, &src_int32_21_8_2160_5000, &src_int32_0_0_0_0, &src_int32_2_1_2268_5000, diff --git a/src/audio/src/coef/src_lite_int32_10_21_3455_5000.h b/src/audio/src/coef/src_lite_int32_10_21_3455_5000.h index fbbd636a9cf7..10572f91d375 100755 --- a/src/audio/src/coef/src_lite_int32_10_21_3455_5000.h +++ b/src/audio/src/coef/src_lite_int32_10_21_3455_5000.h @@ -7,7 +7,7 @@ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ #include <stdint.h> -const int32_t src_int32_10_21_3455_5000_fir[560] = { +__cold_rodata static const int32_t src_int32_10_21_3455_5000_fir[560] = { -656, 634708, 716335, diff --git a/src/audio/src/coef/src_lite_int32_16_21_4535_5000.h b/src/audio/src/coef/src_lite_int32_16_21_4535_5000.h index cfac60bf4581..501428a0123c 100755 --- a/src/audio/src/coef/src_lite_int32_16_21_4535_5000.h +++ b/src/audio/src/coef/src_lite_int32_16_21_4535_5000.h @@ -7,7 +7,7 @@ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ #include <stdint.h> -const int32_t src_int32_16_21_4535_5000_fir[1728] = { +__cold_rodata static const int32_t src_int32_16_21_4535_5000_fir[1728] = { 799, 132548, -237458, diff --git a/src/audio/src/coef/src_lite_int32_1_2_4535_5000.h b/src/audio/src/coef/src_lite_int32_1_2_4535_5000.h index ca1de1ca9818..6665e93d8581 100755 --- a/src/audio/src/coef/src_lite_int32_1_2_4535_5000.h +++ b/src/audio/src/coef/src_lite_int32_1_2_4535_5000.h @@ -7,7 +7,7 @@ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ #include <stdint.h> -const int32_t src_int32_1_2_4535_5000_fir[184] = { +__cold_rodata static const int32_t src_int32_1_2_4535_5000_fir[184] = { -224121, -49304, 317798, diff --git a/src/audio/src/coef/src_lite_int32_1_3_4535_5000.h b/src/audio/src/coef/src_lite_int32_1_3_4535_5000.h index 52e0af45edbd..7fa0f336b35b 100755 --- a/src/audio/src/coef/src_lite_int32_1_3_4535_5000.h +++ b/src/audio/src/coef/src_lite_int32_1_3_4535_5000.h @@ -7,7 +7,7 @@ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ #include <stdint.h> -const int32_t src_int32_1_3_4535_5000_fir[236] = { +__cold_rodata static const int32_t src_int32_1_3_4535_5000_fir[236] = { -114015, 51823, 219093, diff --git a/src/audio/src/coef/src_lite_int32_20_21_4167_5000.h b/src/audio/src/coef/src_lite_int32_20_21_4167_5000.h index 2622d4bd4275..7e93144ee13e 100755 --- a/src/audio/src/coef/src_lite_int32_20_21_4167_5000.h +++ b/src/audio/src/coef/src_lite_int32_20_21_4167_5000.h @@ -7,7 +7,7 @@ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ #include <stdint.h> -const int32_t src_int32_20_21_4167_5000_fir[1200] = { +__cold_rodata static const int32_t src_int32_20_21_4167_5000_fir[1200] = { 5356, -86589, 268036, diff --git a/src/audio/src/coef/src_lite_int32_3_2_4535_5000.h b/src/audio/src/coef/src_lite_int32_3_2_4535_5000.h index 2431175f626d..3f64214097ac 100755 --- a/src/audio/src/coef/src_lite_int32_3_2_4535_5000.h +++ b/src/audio/src/coef/src_lite_int32_3_2_4535_5000.h @@ -7,7 +7,7 @@ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ #include <stdint.h> -const int32_t src_int32_3_2_4535_5000_fir[276] = { +__cold_rodata static const int32_t src_int32_3_2_4535_5000_fir[276] = { -98079, 150065, -205969, diff --git a/src/audio/src/coef/src_lite_int32_8_7_4535_5000.h b/src/audio/src/coef/src_lite_int32_8_7_4535_5000.h index f6596591bea9..ec4acffbd34d 100755 --- a/src/audio/src/coef/src_lite_int32_8_7_4535_5000.h +++ b/src/audio/src/coef/src_lite_int32_8_7_4535_5000.h @@ -7,7 +7,7 @@ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ #include <stdint.h> -const int32_t src_int32_8_7_4535_5000_fir[768] = { +__cold_rodata static const int32_t src_int32_8_7_4535_5000_fir[768] = { -58861, 107730, -172832, diff --git a/src/audio/src/coef/src_small_int32_1_2_2268_5000.h b/src/audio/src/coef/src_small_int32_1_2_2268_5000.h index cb4096c449b1..c76d8df21cac 100644 --- a/src/audio/src/coef/src_small_int32_1_2_2268_5000.h +++ b/src/audio/src/coef/src_small_int32_1_2_2268_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_1_2_2268_5000_fir[40] = { +__cold_rodata static const int32_t src_int32_1_2_2268_5000_fir[40] = { -102613, 1042618, 2316615, diff --git a/src/audio/src/coef/src_small_int32_1_2_4535_5000.h b/src/audio/src/coef/src_small_int32_1_2_4535_5000.h index c6f089dc2788..73627721fb9d 100644 --- a/src/audio/src/coef/src_small_int32_1_2_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_1_2_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_1_2_4535_5000_fir[200] = { +__cold_rodata static const int32_t src_int32_1_2_4535_5000_fir[200] = { -79638, 47425, 131437, diff --git a/src/audio/src/coef/src_small_int32_1_3_2268_5000.h b/src/audio/src/coef/src_small_int32_1_3_2268_5000.h index 8e877cdefb91..8896da331987 100644 --- a/src/audio/src/coef/src_small_int32_1_3_2268_5000.h +++ b/src/audio/src/coef/src_small_int32_1_3_2268_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_1_3_2268_5000_fir[56] = { +__cold_rodata static const int32_t src_int32_1_3_2268_5000_fir[56] = { 636662, 1367445, 1168433, diff --git a/src/audio/src/coef/src_small_int32_1_3_4535_5000.h b/src/audio/src/coef/src_small_int32_1_3_4535_5000.h index 7f4d3d1cec38..35e64f1e36a0 100644 --- a/src/audio/src/coef/src_small_int32_1_3_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_1_3_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_1_3_4535_5000_fir[268] = { +__cold_rodata static const int32_t src_int32_1_3_4535_5000_fir[268] = { 53316, -3193, -78263, diff --git a/src/audio/src/coef/src_small_int32_20_21_4167_5000.h b/src/audio/src/coef/src_small_int32_20_21_4167_5000.h index 6dd79a502a30..9459d265b612 100644 --- a/src/audio/src/coef/src_small_int32_20_21_4167_5000.h +++ b/src/audio/src/coef/src_small_int32_20_21_4167_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_20_21_4167_5000_fir[1120] = { +__cold_rodata static const int32_t src_int32_20_21_4167_5000_fir[1120] = { 125886, -321269, 574508, diff --git a/src/audio/src/coef/src_small_int32_21_20_4167_5000.h b/src/audio/src/coef/src_small_int32_21_20_4167_5000.h index 5258d2df097e..0d9fd93b03c4 100644 --- a/src/audio/src/coef/src_small_int32_21_20_4167_5000.h +++ b/src/audio/src/coef/src_small_int32_21_20_4167_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_21_20_4167_5000_fir[1092] = { +__cold_rodata static const int32_t src_int32_21_20_4167_5000_fir[1092] = { -148365, 253251, -300044, diff --git a/src/audio/src/coef/src_small_int32_2_1_2268_5000.h b/src/audio/src/coef/src_small_int32_2_1_2268_5000.h index 3be189ef34f1..fd6ac5d56a52 100644 --- a/src/audio/src/coef/src_small_int32_2_1_2268_5000.h +++ b/src/audio/src/coef/src_small_int32_2_1_2268_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_2_1_2268_5000_fir[40] = { +__cold_rodata static const int32_t src_int32_2_1_2268_5000_fir[40] = { -96873, 2187025, -6715592, diff --git a/src/audio/src/coef/src_small_int32_2_1_4535_5000.h b/src/audio/src/coef/src_small_int32_2_1_4535_5000.h index cda9b6305c50..f5864de8e02c 100644 --- a/src/audio/src/coef/src_small_int32_2_1_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_2_1_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_2_1_4535_5000_fir[200] = { +__cold_rodata static const int32_t src_int32_2_1_4535_5000_fir[200] = { -79638, 131437, -197166, diff --git a/src/audio/src/coef/src_small_int32_2_3_4535_5000.h b/src/audio/src/coef/src_small_int32_2_3_4535_5000.h index 5047c6230b35..3775e45474e1 100644 --- a/src/audio/src/coef/src_small_int32_2_3_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_2_3_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_2_3_4535_5000_fir[272] = { +__cold_rodata static const int32_t src_int32_2_3_4535_5000_fir[272] = { 12509, 72682, -101869, diff --git a/src/audio/src/coef/src_small_int32_3_1_2268_5000.h b/src/audio/src/coef/src_small_int32_3_1_2268_5000.h index c570c7347d77..8bc858ad0e2a 100644 --- a/src/audio/src/coef/src_small_int32_3_1_2268_5000.h +++ b/src/audio/src/coef/src_small_int32_3_1_2268_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_3_1_2268_5000_fir[60] = { +__cold_rodata static const int32_t src_int32_3_1_2268_5000_fir[60] = { -166536, 2306339, -6050784, diff --git a/src/audio/src/coef/src_small_int32_3_1_4535_5000.h b/src/audio/src/coef/src_small_int32_3_1_4535_5000.h index 40849153f431..66f81808a02c 100644 --- a/src/audio/src/coef/src_small_int32_3_1_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_3_1_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_3_1_4535_5000_fir[276] = { +__cold_rodata static const int32_t src_int32_3_1_4535_5000_fir[276] = { -92545, 140559, -191923, diff --git a/src/audio/src/coef/src_small_int32_3_2_4535_5000.h b/src/audio/src/coef/src_small_int32_3_2_4535_5000.h index 0c593352a8dc..9e4f9e0915d5 100644 --- a/src/audio/src/coef/src_small_int32_3_2_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_3_2_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_3_2_4535_5000_fir[276] = { +__cold_rodata static const int32_t src_int32_3_2_4535_5000_fir[276] = { -92545, 140559, -191923, diff --git a/src/audio/src/coef/src_small_int32_3_4_4535_5000.h b/src/audio/src/coef/src_small_int32_3_4_4535_5000.h index 43ca5ba54e7d..6ea52fbabd3a 100644 --- a/src/audio/src/coef/src_small_int32_3_4_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_3_4_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_3_4_4535_5000_fir[348] = { +__cold_rodata static const int32_t src_int32_3_4_4535_5000_fir[348] = { -44332, 116220, -109098, diff --git a/src/audio/src/coef/src_small_int32_4_3_4535_5000.h b/src/audio/src/coef/src_small_int32_4_3_4535_5000.h index ebd010e2b8f4..dd81b252e4b4 100644 --- a/src/audio/src/coef/src_small_int32_4_3_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_4_3_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_4_3_4535_5000_fir[352] = { +__cold_rodata static const int32_t src_int32_4_3_4535_5000_fir[352] = { -92406, 134596, -172955, diff --git a/src/audio/src/coef/src_small_int32_4_5_4535_5000.h b/src/audio/src/coef/src_small_int32_4_5_4535_5000.h index cc2457a81bec..aa7e35768a9f 100644 --- a/src/audio/src/coef/src_small_int32_4_5_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_4_5_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_4_5_4535_5000_fir[448] = { +__cold_rodata static const int32_t src_int32_4_5_4535_5000_fir[448] = { 71197, -96779, 49471, diff --git a/src/audio/src/coef/src_small_int32_5_4_4535_5000.h b/src/audio/src/coef/src_small_int32_5_4_4535_5000.h index 74987ab7c557..afbbec4122be 100644 --- a/src/audio/src/coef/src_small_int32_5_4_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_5_4_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_5_4_4535_5000_fir[440] = { +__cold_rodata static const int32_t src_int32_5_4_4535_5000_fir[440] = { -83573, 123255, -160503, diff --git a/src/audio/src/coef/src_small_int32_5_6_4354_5000.h b/src/audio/src/coef/src_small_int32_5_6_4354_5000.h index 4a712463e601..414fddc38515 100644 --- a/src/audio/src/coef/src_small_int32_5_6_4354_5000.h +++ b/src/audio/src/coef/src_small_int32_5_6_4354_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_5_6_4354_5000_fir[380] = { +__cold_rodata static const int32_t src_int32_5_6_4354_5000_fir[380] = { -110765, 202615, -181213, diff --git a/src/audio/src/coef/src_small_int32_6_5_4354_5000.h b/src/audio/src/coef/src_small_int32_6_5_4354_5000.h index 8a2f6054f76c..6738c05b884e 100644 --- a/src/audio/src/coef/src_small_int32_6_5_4354_5000.h +++ b/src/audio/src/coef/src_small_int32_6_5_4354_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_6_5_4354_5000_fir[384] = { +__cold_rodata static const int32_t src_int32_6_5_4354_5000_fir[384] = { -122729, 196634, -249782, diff --git a/src/audio/src/coef/src_small_int32_7_8_4535_5000.h b/src/audio/src/coef/src_small_int32_7_8_4535_5000.h index 58a71bc48718..528da1cbe98b 100644 --- a/src/audio/src/coef/src_small_int32_7_8_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_7_8_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_7_8_4535_5000_fir[644] = { +__cold_rodata static const int32_t src_int32_7_8_4535_5000_fir[644] = { -1007, -96094, 242640, diff --git a/src/audio/src/coef/src_small_int32_8_7_4535_5000.h b/src/audio/src/coef/src_small_int32_8_7_4535_5000.h index 4d33f547c081..e20488b0aa6e 100644 --- a/src/audio/src/coef/src_small_int32_8_7_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_8_7_4535_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int32_t src_int32_8_7_4535_5000_fir[640] = { +__cold_rodata static const int32_t src_int32_8_7_4535_5000_fir[640] = { -93442, 125750, -138530, diff --git a/src/audio/src/coef/src_std_int32_10_21_4535_5000.h b/src/audio/src/coef/src_std_int32_10_21_4535_5000.h index 44a207ef5ecd..1fe75ffcfc60 100644 --- a/src/audio/src/coef/src_std_int32_10_21_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_10_21_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_10_21_4535_5000_fir[1720] = { +__cold_rodata static const int32_t src_int32_10_21_4535_5000_fir[1720] = { 64820, 140936, -51986, diff --git a/src/audio/src/coef/src_std_int32_1_2_2268_5000.h b/src/audio/src/coef/src_std_int32_1_2_2268_5000.h index c27402466cff..6da68b7325d3 100644 --- a/src/audio/src/coef/src_std_int32_1_2_2268_5000.h +++ b/src/audio/src/coef/src_std_int32_1_2_2268_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_1_2_2268_5000_fir[40] = { +__cold_rodata static const int32_t src_int32_1_2_2268_5000_fir[40] = { -102613, 1042618, 2316615, diff --git a/src/audio/src/coef/src_std_int32_1_2_4535_5000.h b/src/audio/src/coef/src_std_int32_1_2_4535_5000.h index 64d3f1641c7e..83fcad96732e 100644 --- a/src/audio/src/coef/src_std_int32_1_2_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_1_2_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_1_2_4535_5000_fir[200] = { +__cold_rodata static const int32_t src_int32_1_2_4535_5000_fir[200] = { -84357, 50235, 139225, diff --git a/src/audio/src/coef/src_std_int32_1_3_2268_5000.h b/src/audio/src/coef/src_std_int32_1_3_2268_5000.h index 41f416116967..0119326d60d4 100644 --- a/src/audio/src/coef/src_std_int32_1_3_2268_5000.h +++ b/src/audio/src/coef/src_std_int32_1_3_2268_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_1_3_2268_5000_fir[56] = { +__cold_rodata static const int32_t src_int32_1_3_2268_5000_fir[56] = { 636662, 1367445, 1168433, diff --git a/src/audio/src/coef/src_std_int32_1_3_4535_5000.h b/src/audio/src/coef/src_std_int32_1_3_4535_5000.h index 580ddebacddd..4f432a4c48a6 100644 --- a/src/audio/src/coef/src_std_int32_1_3_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_1_3_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_1_3_4535_5000_fir[268] = { +__cold_rodata static const int32_t src_int32_1_3_4535_5000_fir[268] = { 53316, -3193, -78263, diff --git a/src/audio/src/coef/src_std_int32_20_21_4167_5000.h b/src/audio/src/coef/src_std_int32_20_21_4167_5000.h index a26101ddd7bc..a0dae03d0d09 100644 --- a/src/audio/src/coef/src_std_int32_20_21_4167_5000.h +++ b/src/audio/src/coef/src_std_int32_20_21_4167_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_20_21_4167_5000_fir[1120] = { +__cold_rodata static const int32_t src_int32_20_21_4167_5000_fir[1120] = { 125886, -321269, 574508, diff --git a/src/audio/src/coef/src_std_int32_20_7_2976_5000.h b/src/audio/src/coef/src_std_int32_20_7_2976_5000.h index 9bb8d4879e69..85b8be57e692 100644 --- a/src/audio/src/coef/src_std_int32_20_7_2976_5000.h +++ b/src/audio/src/coef/src_std_int32_20_7_2976_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_20_7_2976_5000_fir[480] = { +__cold_rodata static const int32_t src_int32_20_7_2976_5000_fir[480] = { -256723, 1344746, -2486660, diff --git a/src/audio/src/coef/src_std_int32_21_20_4167_5000.h b/src/audio/src/coef/src_std_int32_21_20_4167_5000.h index 18aca9ba361d..4f72a75d68a2 100644 --- a/src/audio/src/coef/src_std_int32_21_20_4167_5000.h +++ b/src/audio/src/coef/src_std_int32_21_20_4167_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_21_20_4167_5000_fir[1092] = { +__cold_rodata static const int32_t src_int32_21_20_4167_5000_fir[1092] = { -148365, 253251, -300044, diff --git a/src/audio/src/coef/src_std_int32_21_40_3968_5000.h b/src/audio/src/coef/src_std_int32_21_40_3968_5000.h index 388d4216ce90..ac453af42104 100644 --- a/src/audio/src/coef/src_std_int32_21_40_3968_5000.h +++ b/src/audio/src/coef/src_std_int32_21_40_3968_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_21_40_3968_5000_fir[1596] = { +__cold_rodata static const int32_t src_int32_21_40_3968_5000_fir[1596] = { -210430, -287852, 472564, diff --git a/src/audio/src/coef/src_std_int32_21_80_3968_5000.h b/src/audio/src/coef/src_std_int32_21_80_3968_5000.h index fea250e377c6..d42d08134595 100644 --- a/src/audio/src/coef/src_std_int32_21_80_3968_5000.h +++ b/src/audio/src/coef/src_std_int32_21_80_3968_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_21_80_3968_5000_fir[3108] = { +__cold_rodata static const int32_t src_int32_21_80_3968_5000_fir[3108] = { -174020, 2072, 309190, diff --git a/src/audio/src/coef/src_std_int32_2_1_2268_5000.h b/src/audio/src/coef/src_std_int32_2_1_2268_5000.h index 953e65c155ae..f2fda6e7a712 100644 --- a/src/audio/src/coef/src_std_int32_2_1_2268_5000.h +++ b/src/audio/src/coef/src_std_int32_2_1_2268_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_2_1_2268_5000_fir[40] = { +__cold_rodata static const int32_t src_int32_2_1_2268_5000_fir[40] = { -96873, 2187025, -6715592, diff --git a/src/audio/src/coef/src_std_int32_2_1_4535_5000.h b/src/audio/src/coef/src_std_int32_2_1_4535_5000.h index 333d603e97bb..5ba7f5d860dd 100644 --- a/src/audio/src/coef/src_std_int32_2_1_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_2_1_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_2_1_4535_5000_fir[200] = { +__cold_rodata static const int32_t src_int32_2_1_4535_5000_fir[200] = { -79638, 131437, -197166, diff --git a/src/audio/src/coef/src_std_int32_2_3_4535_5000.h b/src/audio/src/coef/src_std_int32_2_3_4535_5000.h index 7863ebe826cf..1a5af78d38fe 100644 --- a/src/audio/src/coef/src_std_int32_2_3_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_2_3_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_2_3_4535_5000_fir[272] = { +__cold_rodata static const int32_t src_int32_2_3_4535_5000_fir[272] = { 12509, 72682, -101869, diff --git a/src/audio/src/coef/src_std_int32_32_21_4535_5000.h b/src/audio/src/coef/src_std_int32_32_21_4535_5000.h index b20976b16dea..8bd7522a8320 100644 --- a/src/audio/src/coef/src_std_int32_32_21_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_32_21_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_32_21_4535_5000_fir[2816] = { +__cold_rodata static const int32_t src_int32_32_21_4535_5000_fir[2816] = { -70924, 93303, -103450, diff --git a/src/audio/src/coef/src_std_int32_3_1_2268_5000.h b/src/audio/src/coef/src_std_int32_3_1_2268_5000.h index bb4ef7d82f07..34e0e2bd2253 100644 --- a/src/audio/src/coef/src_std_int32_3_1_2268_5000.h +++ b/src/audio/src/coef/src_std_int32_3_1_2268_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_3_1_2268_5000_fir[60] = { +__cold_rodata static const int32_t src_int32_3_1_2268_5000_fir[60] = { -166536, 2306339, -6050784, diff --git a/src/audio/src/coef/src_std_int32_3_1_4535_5000.h b/src/audio/src/coef/src_std_int32_3_1_4535_5000.h index db312c9c80ae..e212da23624b 100644 --- a/src/audio/src/coef/src_std_int32_3_1_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_3_1_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_3_1_4535_5000_fir[276] = { +__cold_rodata static const int32_t src_int32_3_1_4535_5000_fir[276] = { -92545, 140559, -191923, diff --git a/src/audio/src/coef/src_std_int32_3_2_4535_5000.h b/src/audio/src/coef/src_std_int32_3_2_4535_5000.h index 8d30cb8efb77..69e7978b6af0 100644 --- a/src/audio/src/coef/src_std_int32_3_2_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_3_2_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_3_2_4535_5000_fir[276] = { +__cold_rodata static const int32_t src_int32_3_2_4535_5000_fir[276] = { -92545, 140559, -191923, diff --git a/src/audio/src/coef/src_std_int32_3_4_4535_5000.h b/src/audio/src/coef/src_std_int32_3_4_4535_5000.h index c679a1f2fe5b..685fdfd7c706 100644 --- a/src/audio/src/coef/src_std_int32_3_4_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_3_4_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_3_4_4535_5000_fir[348] = { +__cold_rodata static const int32_t src_int32_3_4_4535_5000_fir[348] = { -44332, 116220, -109098, diff --git a/src/audio/src/coef/src_std_int32_40_21_3968_5000.h b/src/audio/src/coef/src_std_int32_40_21_3968_5000.h index 6a2da0181623..46a7dbb012a1 100644 --- a/src/audio/src/coef/src_std_int32_40_21_3968_5000.h +++ b/src/audio/src/coef/src_std_int32_40_21_3968_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_40_21_3968_5000_fir[1600] = { +__cold_rodata static const int32_t src_int32_40_21_3968_5000_fir[1600] = { -168855, 272170, -146895, diff --git a/src/audio/src/coef/src_std_int32_4_3_4535_5000.h b/src/audio/src/coef/src_std_int32_4_3_4535_5000.h index ccef7fc03ad8..8476fccf5982 100644 --- a/src/audio/src/coef/src_std_int32_4_3_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_4_3_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_4_3_4535_5000_fir[352] = { +__cold_rodata static const int32_t src_int32_4_3_4535_5000_fir[352] = { -92406, 134596, -172955, diff --git a/src/audio/src/coef/src_std_int32_4_5_4535_5000.h b/src/audio/src/coef/src_std_int32_4_5_4535_5000.h index 4bafe75c987f..148660ded07b 100644 --- a/src/audio/src/coef/src_std_int32_4_5_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_4_5_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_4_5_4535_5000_fir[448] = { +__cold_rodata static const int32_t src_int32_4_5_4535_5000_fir[448] = { 71197, -96779, 49471, diff --git a/src/audio/src/coef/src_std_int32_5_4_4535_5000.h b/src/audio/src/coef/src_std_int32_5_4_4535_5000.h index 4e381a8d69c9..b3416487732b 100644 --- a/src/audio/src/coef/src_std_int32_5_4_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_5_4_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_5_4_4535_5000_fir[440] = { +__cold_rodata static const int32_t src_int32_5_4_4535_5000_fir[440] = { -83573, 123255, -160503, diff --git a/src/audio/src/coef/src_std_int32_5_6_4354_5000.h b/src/audio/src/coef/src_std_int32_5_6_4354_5000.h index 2b103cae3e0c..b861063c4671 100644 --- a/src/audio/src/coef/src_std_int32_5_6_4354_5000.h +++ b/src/audio/src/coef/src_std_int32_5_6_4354_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_5_6_4354_5000_fir[380] = { +__cold_rodata static const int32_t src_int32_5_6_4354_5000_fir[380] = { -110765, 202615, -181213, diff --git a/src/audio/src/coef/src_std_int32_5_7_4535_5000.h b/src/audio/src/coef/src_std_int32_5_7_4535_5000.h index 23c470dc595f..44cfdaf8cf42 100644 --- a/src/audio/src/coef/src_std_int32_5_7_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_5_7_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_5_7_4535_5000_fir[580] = { +__cold_rodata static const int32_t src_int32_5_7_4535_5000_fir[580] = { -38462, 102037, -72148, diff --git a/src/audio/src/coef/src_std_int32_6_5_4354_5000.h b/src/audio/src/coef/src_std_int32_6_5_4354_5000.h index 6ebcb24f63fa..4d61ac9e77c1 100644 --- a/src/audio/src/coef/src_std_int32_6_5_4354_5000.h +++ b/src/audio/src/coef/src_std_int32_6_5_4354_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_6_5_4354_5000_fir[384] = { +__cold_rodata static const int32_t src_int32_6_5_4354_5000_fir[384] = { -122729, 196634, -249782, diff --git a/src/audio/src/coef/src_std_int32_7_8_4535_5000.h b/src/audio/src/coef/src_std_int32_7_8_4535_5000.h index 174e6125864e..01f3b2b2325e 100644 --- a/src/audio/src/coef/src_std_int32_7_8_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_7_8_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_7_8_4535_5000_fir[644] = { +__cold_rodata static const int32_t src_int32_7_8_4535_5000_fir[644] = { -1007, -96094, 242640, diff --git a/src/audio/src/coef/src_std_int32_8_21_3239_5000.h b/src/audio/src/coef/src_std_int32_8_21_3239_5000.h index aaa085d2ae54..4441d148cc71 100644 --- a/src/audio/src/coef/src_std_int32_8_21_3239_5000.h +++ b/src/audio/src/coef/src_std_int32_8_21_3239_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_8_21_3239_5000_fir[480] = { +__cold_rodata static const int32_t src_int32_8_21_3239_5000_fir[480] = { -149226, 295321, 1071448, diff --git a/src/audio/src/coef/src_std_int32_8_7_2468_5000.h b/src/audio/src/coef/src_std_int32_8_7_2468_5000.h index f8d5dc57c3eb..e4dcf0f08514 100644 --- a/src/audio/src/coef/src_std_int32_8_7_2468_5000.h +++ b/src/audio/src/coef/src_std_int32_8_7_2468_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_8_7_2468_5000_fir[160] = { +__cold_rodata static const int32_t src_int32_8_7_2468_5000_fir[160] = { -422312, 2368615, -2932237, diff --git a/src/audio/src/coef/src_std_int32_8_7_4535_5000.h b/src/audio/src/coef/src_std_int32_8_7_4535_5000.h index 8bb33c1bccd8..f6ddb96c7a0a 100644 --- a/src/audio/src/coef/src_std_int32_8_7_4535_5000.h +++ b/src/audio/src/coef/src_std_int32_8_7_4535_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int32_t src_int32_8_7_4535_5000_fir[640] = { +__cold_rodata static const int32_t src_int32_8_7_4535_5000_fir[640] = { -93442, 125750, -138530, diff --git a/src/audio/src/coef/src_tiny_int16_1_2_1814_5000.h b/src/audio/src/coef/src_tiny_int16_1_2_1814_5000.h index b9b2402ab243..a8fde1f7561a 100644 --- a/src/audio/src/coef/src_tiny_int16_1_2_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_1_2_1814_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int16_t src_int16_1_2_1814_5000_fir[32] = { +__cold_rodata static const int16_t src_int16_1_2_1814_5000_fir[32] = { -7, 7, 63, diff --git a/src/audio/src/coef/src_tiny_int16_1_3_1814_5000.h b/src/audio/src/coef/src_tiny_int16_1_3_1814_5000.h index 76634b12c1d6..ef70aaa690d5 100644 --- a/src/audio/src/coef/src_tiny_int16_1_3_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_1_3_1814_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_1_3_1814_5000_fir[48] = { +__cold_rodata static const int16_t src_int16_1_3_1814_5000_fir[48] = { -9, -7, 22, diff --git a/src/audio/src/coef/src_tiny_int16_1_6_1814_5000.h b/src/audio/src/coef/src_tiny_int16_1_6_1814_5000.h index 96dbf415df45..672c44a75c27 100644 --- a/src/audio/src/coef/src_tiny_int16_1_6_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_1_6_1814_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_1_6_1814_5000_fir[92] = { +__cold_rodata static const int16_t src_int16_1_6_1814_5000_fir[92] = { -4, 0, 10, diff --git a/src/audio/src/coef/src_tiny_int16_20_21_1667_5000.h b/src/audio/src/coef/src_tiny_int16_20_21_1667_5000.h index 473fd0736638..923612f9d120 100644 --- a/src/audio/src/coef/src_tiny_int16_20_21_1667_5000.h +++ b/src/audio/src/coef/src_tiny_int16_20_21_1667_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_20_21_1667_5000_fir[320] = { +__cold_rodata static const int16_t src_int16_20_21_1667_5000_fir[320] = { 3, 49, -174, diff --git a/src/audio/src/coef/src_tiny_int16_21_20_1667_5000.h b/src/audio/src/coef/src_tiny_int16_21_20_1667_5000.h index dc0a32fc4388..21a83348dddc 100644 --- a/src/audio/src/coef/src_tiny_int16_21_20_1667_5000.h +++ b/src/audio/src/coef/src_tiny_int16_21_20_1667_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_21_20_1667_5000_fir[336] = { +__cold_rodata static const int16_t src_int16_21_20_1667_5000_fir[336] = { -4, 61, -87, diff --git a/src/audio/src/coef/src_tiny_int16_24_25_1814_5000.h b/src/audio/src/coef/src_tiny_int16_24_25_1814_5000.h index ec618ce32b0d..e68f37e9376c 100644 --- a/src/audio/src/coef/src_tiny_int16_24_25_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_24_25_1814_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_24_25_1814_5000_fir[480] = { +__cold_rodata static const int16_t src_int16_24_25_1814_5000_fir[480] = { 5, -32, -12, diff --git a/src/audio/src/coef/src_tiny_int16_25_24_1814_5000.h b/src/audio/src/coef/src_tiny_int16_25_24_1814_5000.h index 3d2774f423f7..fab00bf21661 100644 --- a/src/audio/src/coef/src_tiny_int16_25_24_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_25_24_1814_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_25_24_1814_5000_fir[400] = { +__cold_rodata static const int16_t src_int16_25_24_1814_5000_fir[400] = { -6, 60, -44, diff --git a/src/audio/src/coef/src_tiny_int16_2_1_1814_5000.h b/src/audio/src/coef/src_tiny_int16_2_1_1814_5000.h index 73aca616e212..79838f8bd89d 100644 --- a/src/audio/src/coef/src_tiny_int16_2_1_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_2_1_1814_5000.h @@ -6,7 +6,7 @@ #include <stdint.h> -static const int16_t src_int16_2_1_1814_5000_fir[32] = { +__cold_rodata static const int16_t src_int16_2_1_1814_5000_fir[32] = { -7, 63, -62, diff --git a/src/audio/src/coef/src_tiny_int16_2_3_1814_5000.h b/src/audio/src/coef/src_tiny_int16_2_3_1814_5000.h index eaf5c779b880..c38daaf5f46b 100644 --- a/src/audio/src/coef/src_tiny_int16_2_3_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_2_3_1814_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_2_3_1814_5000_fir[48] = { +__cold_rodata static const int16_t src_int16_2_3_1814_5000_fir[48] = { -9, 21, 126, diff --git a/src/audio/src/coef/src_tiny_int16_3_1_1814_5000.h b/src/audio/src/coef/src_tiny_int16_3_1_1814_5000.h index 2dac6f53cff0..abf1a6cd7126 100644 --- a/src/audio/src/coef/src_tiny_int16_3_1_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_3_1_1814_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_3_1_1814_5000_fir[48] = { +__cold_rodata static const int16_t src_int16_3_1_1814_5000_fir[48] = { -7, 58, -28, diff --git a/src/audio/src/coef/src_tiny_int16_3_2_1814_5000.h b/src/audio/src/coef/src_tiny_int16_3_2_1814_5000.h index e46edb8d7f31..41bc4fd41cf7 100644 --- a/src/audio/src/coef/src_tiny_int16_3_2_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_3_2_1814_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_3_2_1814_5000_fir[48] = { +__cold_rodata static const int16_t src_int16_3_2_1814_5000_fir[48] = { -6, 58, -28, diff --git a/src/audio/src/coef/src_tiny_int16_6_1_1814_5000.h b/src/audio/src/coef/src_tiny_int16_6_1_1814_5000.h index b19982f98dca..204c4b05c338 100644 --- a/src/audio/src/coef/src_tiny_int16_6_1_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_6_1_1814_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_6_1_1814_5000_fir[96] = { +__cold_rodata static const int16_t src_int16_6_1_1814_5000_fir[96] = { -7, 53, -2, diff --git a/src/audio/src/coef/src_tiny_int16_7_8_1814_5000.h b/src/audio/src/coef/src_tiny_int16_7_8_1814_5000.h index b1ed9c100f9b..9193c1005088 100644 --- a/src/audio/src/coef/src_tiny_int16_7_8_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_7_8_1814_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_7_8_1814_5000_fir[140] = { +__cold_rodata static const int16_t src_int16_7_8_1814_5000_fir[140] = { -3, -28, 94, diff --git a/src/audio/src/coef/src_tiny_int16_8_7_1814_5000.h b/src/audio/src/coef/src_tiny_int16_8_7_1814_5000.h index 4c6dba28deda..c7d2c94d67dd 100644 --- a/src/audio/src/coef/src_tiny_int16_8_7_1814_5000.h +++ b/src/audio/src/coef/src_tiny_int16_8_7_1814_5000.h @@ -7,7 +7,7 @@ #include <stdint.h> -static const int16_t src_int16_8_7_1814_5000_fir[128] = { +__cold_rodata static const int16_t src_int16_8_7_1814_5000_fir[128] = { -7, 55, -1, diff --git a/src/audio/src/llext/CMakeLists.txt b/src/audio/src/llext/CMakeLists.txt index dfb9782ee941..7cd52be725c7 100644 --- a/src/audio/src/llext/CMakeLists.txt +++ b/src/audio/src/llext/CMakeLists.txt @@ -7,6 +7,7 @@ sof_llext_build("src" ../src_generic.c ../src_hifi3.c ../src_hifi4.c + ../src_hifi5.c ../src.c ../src_common.c ../src_ipc4.c @@ -19,6 +20,7 @@ sof_llext_build("src" ../src_generic.c ../src_hifi3.c ../src_hifi4.c + ../src_hifi5.c ../src.c ../src_common.c ../src_ipc4.c diff --git a/src/audio/src/src.c b/src/audio/src/src.c index d75b1eb53822..9870ad911ca8 100644 --- a/src/audio/src/src.c +++ b/src/audio/src/src.c @@ -10,6 +10,8 @@ */ #include <rtos/init.h> +#include <sof/lib/memory.h> +#include <module/module/llext.h> #include "src_common.h" #include "src_config.h" @@ -40,7 +42,7 @@ static int src_prepare(struct processing_module *mod, struct src_param *a = &cd->param; int ret; - comp_info(mod->dev, "src_prepare()"); + comp_info(mod->dev, "entry"); if (num_of_sources != 1 || num_of_sinks != 1) return -EINVAL; @@ -58,8 +60,11 @@ static int src_prepare(struct processing_module *mod, if (ret < 0) return ret; - a->stage1 = src_table1[a->idx_out][a->idx_in]; - a->stage2 = src_table2[a->idx_out][a->idx_in]; + ret = src_allocate_copy_stages(mod, a, + src_table1[a->idx_out][a->idx_in], + src_table2[a->idx_out][a->idx_in]); + if (ret < 0) + return ret; ret = src_params_general(mod, sources[0], sinks[0]); if (ret < 0) @@ -73,15 +78,10 @@ static const struct module_interface src_interface = { .prepare = src_prepare, .process = src_process, .is_ready_to_process = src_is_ready_to_process, - .set_configuration = src_set_config, - .get_configuration = src_get_config, .reset = src_reset, .free = src_free, }; -DECLARE_MODULE_ADAPTER(src_interface, SRC_UUID, src_tr); -SOF_MODULE_INIT(src, sys_comp_module_src_interface_init); - #if CONFIG_COMP_SRC_MODULE /* modular: llext dynamic link */ @@ -89,23 +89,22 @@ SOF_MODULE_INIT(src, sys_comp_module_src_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_SRC 0x8D, 0xB2, 0x1B, 0xE6, 0x9A, 0x14, 0x1F, 0x4C, \ - 0xB7, 0x09, 0x46, 0x82, 0x3E, 0xF5, 0xF5, 0xAE -SOF_LLEXT_MOD_ENTRY(src, &src_interface); - #if CONFIG_COMP_SRC_LITE -#define UUID_SRC_LITE 0x51, 0x10, 0x44, 0x33, 0xCD, 0x44, 0x6A, 0x46, \ - 0x83, 0xA3, 0x17, 0x84, 0x78, 0x70, 0x8A, 0xEA extern const struct module_interface src_lite_interface; -SOF_LLEXT_MOD_ENTRY(src_lite, &src_lite_interface); #endif static const struct sof_man_module_manifest mod_manifest[] __section(".module") __used = { - SOF_LLEXT_MODULE_MANIFEST("SRC", src_llext_entry, 1, UUID_SRC, 1), + SOF_LLEXT_MODULE_MANIFEST("SRC", &src_interface, 1, SOF_REG_UUID(src4), 1), #if CONFIG_COMP_SRC_LITE - SOF_LLEXT_MODULE_MANIFEST("SRC_LITE", src_lite_llext_entry, 1, UUID_SRC_LITE, 1), + SOF_LLEXT_MODULE_MANIFEST("SRC_LITE", &src_lite_interface, 1, SOF_REG_UUID(src_lite), 1), #endif }; SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_MODULE_ADAPTER(src_interface, SRC_UUID, src_tr); +SOF_MODULE_INIT(src, sys_comp_module_src_interface_init); + #endif diff --git a/src/audio/src/src.toml b/src/audio/src/src.toml index 448739cf2f19..ab496c5b8a80 100644 --- a/src/audio/src/src.toml +++ b/src/audio/src/src.toml @@ -4,7 +4,7 @@ [[module.entry]] name = "SRC" - uuid = "E61BB28D-149A-4C1F-B709-46823EF5F5AE" + uuid = UUIDREG_STR_SRC4 affinity_mask = "0x1" REM #instance_count = "10" domain_types = "0" @@ -19,56 +19,86 @@ REM # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] #if CONFIG_METEORLAKE - 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] -#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_PANTHERLAKE) - 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] + mod_cfg = [0, 0, 0, 0, 12832, 15976000, 128, 512, 0, 15976, 0, + 1, 0, 0, 0, 12832, 15340000, 64, 256, 0, 15340, 0, + 2, 0, 0, 0, 12832, 21880000, 96, 512, 0, 21880, 0, + 3, 0, 0, 0, 12832, 19968000, 48, 256, 0, 19968, 0, + 4, 0, 0, 0, 12832, 18236000, 64, 256, 0, 18236, 0, + 5, 0, 0, 0, 12832, 15244000, 32, 256, 0, 15244, 0, + 6, 0, 0, 0, 12832, 56028000, 1536, 512, 0, 56028, 0, + 7, 0, 0, 0, 12832, 46740000, 768, 256, 0, 46740, 0, + 8, 0, 0, 0, 12832, 24656000, 768, 512, 0, 24656, 0, + 9, 0, 0, 0, 12832, 23516000, 384, 256, 0, 23516, 0, + 10, 0, 0, 0, 12832, 29368000, 384, 488, 0, 29368, 0, + 11, 0, 0, 0, 12832, 27164000, 192, 244, 0, 27164, 0, + 12, 0, 0, 0, 12832, 15892000, 384, 384, 0, 15892, 0, + 13, 0, 0, 0, 12832, 19916000, 192, 512, 0, 19916, 0, + 14, 0, 0, 0, 12832, 19176000, 96, 256, 0, 19176, 0, + 15, 0, 0, 0, 12832, 12676000, 192, 192, 0, 12676, 0, + 16, 0, 0, 0, 12832, 16280000, 384, 320, 0, 16280, 0, + 17, 0, 0, 0, 12832, 13076000, 192, 160, 0, 13076, 0, + 18, 0, 0, 0, 12832, 11440000, 384, 256, 0, 11440, 0, + 19, 0, 0, 0, 12832, 10996000, 192, 128, 0, 10996, 0, + 20, 0, 0, 0, 12832, 11428000, 384, 192, 0, 11428, 0, + 21, 0, 0, 0, 12832, 10740000, 192, 96, 0, 10740, 0, + 22, 0, 0, 0, 12832, 29936000, 360, 512, 0, 29936, 0, + 23, 0, 0, 0, 12832, 27696000, 180, 256, 0, 27696, 0, + 24, 0, 0, 0, 12832, 18368000, 256, 512, 0, 18368, 0, + 25, 0, 0, 0, 12832, 15204000, 128, 256, 0, 15204, 0] +#elif CONFIG_LUNARLAKE + mod_cfg = [0, 0, 0, 0, 12832, 14748000, 128, 512, 0, 14748, 0, + 1, 0, 0, 0, 12832, 14152000, 64, 256, 0, 14152, 0, + 2, 0, 0, 0, 12832, 16988000, 96, 512, 0, 16988, 0, + 3, 0, 0, 0, 12832, 15972000, 48, 256, 0, 15972, 0, + 4, 0, 0, 0, 12832, 13272000, 64, 256, 0, 13272, 0, + 5, 0, 0, 0, 12832, 12872000, 32, 256, 0, 12872, 0, + 6, 0, 0, 0, 12832, 45419000, 1536, 512, 0, 45419, 0, + 7, 0, 0, 0, 12832, 43279000, 768, 256, 0, 43279, 0, + 8, 0, 0, 0, 12832, 25796000, 768, 512, 0, 25796, 0, + 9, 0, 0, 0, 12832, 25131000, 384, 256, 0, 25131, 0, + 10, 0, 0, 0, 12832, 27360000, 384, 488, 0, 27360, 0, + 11, 0, 0, 0, 12832, 23032000, 192, 244, 0, 23032, 0, + 12, 0, 0, 0, 12832, 12432000, 384, 384, 0, 12432, 0, + 13, 0, 0, 0, 12832, 15584000, 192, 512, 0, 15584, 0, + 14, 0, 0, 0, 12832, 15360000, 96, 256, 0, 15360, 0, + 15, 0, 0, 0, 12832, 12104000, 192, 192, 0, 12104, 0, + 16, 0, 0, 0, 12832, 13064000, 384, 320, 0, 13064, 0, + 17, 0, 0, 0, 12832, 12768000, 192, 160, 0, 12768, 0, + 18, 0, 0, 0, 12832, 11636000, 384, 256, 0, 11636, 0, + 19, 0, 0, 0, 12832, 11244000, 192, 128, 0, 11244, 0, + 20, 0, 0, 0, 12832, 11224000, 384, 192, 0, 11224, 0, + 21, 0, 0, 0, 12832, 10360000, 192, 96, 0, 10360, 0, + 22, 0, 0, 0, 12832, 27616000, 360, 512, 0, 27616, 0, + 23, 0, 0, 0, 12832, 21852000, 180, 256, 0, 21852, 0, + 24, 0, 0, 0, 12832, 12629000, 256, 512, 0, 12629, 0, + 25, 0, 0, 0, 12832, 13996000, 128, 256, 0, 13996, 0] +#elif CONFIG_SOC_ACE30 || CONFIG_SOC_ACE40 + mod_cfg = [0, 0, 0, 0, 12832, 30633000, 128, 512, 0, 30633, 0, + 1, 0, 0, 0, 12832, 28143000, 64, 256, 0, 28143, 0, + 2, 0, 0, 0, 12832, 33513000, 96, 512, 0, 33513, 0, + 3, 0, 0, 0, 12832, 0, 48, 256, 0, 0, 0, + 4, 0, 0, 0, 12832, 22867000, 64, 256, 0, 22867, 0, + 5, 0, 0, 0, 12832, 19779000, 32, 256, 0, 19779, 0, + 6, 0, 0, 0, 12832, 80857000, 1536, 512, 0, 80857, 0, + 7, 0, 0, 0, 12832, 62393000, 768, 256, 0, 62393, 0, + 8, 0, 0, 0, 12832, 46159000, 768, 512, 0, 46159, 0, + 9, 0, 0, 0, 12832, 36607000, 384, 256, 0, 36607, 0, + 10, 0, 0, 0, 12832, 49951000, 384, 488, 0, 49951, 0, + 11, 0, 0, 0, 12832, 44031000, 192, 244, 0, 44031, 0, + 12, 0, 0, 0, 12832, 28973000, 384, 384, 0, 28973, 0, + 13, 0, 0, 0, 12832, 35669000, 192, 512, 0, 35669, 0, + 14, 0, 0, 0, 12832, 25931000, 96, 256, 0, 25931, 0, + 15, 0, 0, 0, 12832, 19423000, 192, 192, 0, 19423, 0, + 16, 0, 0, 0, 12832, 25667000, 384, 320, 0, 25667, 0, + 17, 0, 0, 0, 12832, 20623000, 192, 160, 0, 20623, 0, + 18, 0, 0, 0, 12832, 23383000, 384, 256, 0, 23383, 0, + 19, 0, 0, 0, 12832, 18269000, 192, 128, 0, 18269, 0, + 20, 0, 0, 0, 12832, 18181000, 384, 192, 0, 18181, 0, + 21, 0, 0, 0, 12832, 15345000, 192, 96, 0, 15345, 0, + 22, 0, 0, 0, 12832, 49977000, 360, 512, 0, 49977, 0, + 23, 0, 0, 0, 12832, 40403000, 180, 256, 0, 40403, 0, + 24, 0, 0, 0, 12832, 28085000, 256, 512, 0, 28085, 0, + 25, 0, 0, 0, 12832, 22923000, 128, 256, 0, 22923, 0] #endif index = __COUNTER__ @@ -77,7 +107,7 @@ REM # SRC lite module config [[module.entry]] name = "SRC_LITE" - uuid = "33441051-44CD-466A-83A3-178478708AEA" + uuid = UUIDREG_STR_SRC_LITE affinity_mask = "0x1" REM #instance_count = "10" domain_types = "0" diff --git a/src/audio/src/src_common.c b/src/audio/src/src_common.c index 3a8fa8541bfa..3a9c7dac280f 100644 --- a/src/audio/src/src_common.c +++ b/src/audio/src/src_common.c @@ -16,6 +16,8 @@ #include <sof/audio/sink_api.h> #include <sof/audio/source_api.h> #include <sof/audio/sink_source_utils.h> +#include <sof/lib/fast-get.h> +#include <sof/lib/memory.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> #include <rtos/alloc.h> @@ -59,7 +61,7 @@ static int src_buffer_lengths(struct comp_dev *dev, struct comp_data *cd, int nc if (nch > PLATFORM_MAX_CHANNELS) { /* TODO: should be device, not class */ - comp_err(dev, "src_buffer_lengths(): nch = %u > PLATFORM_MAX_CHANNELS", + comp_err(dev, "nch = %u > PLATFORM_MAX_CHANNELS", nch); return -EINVAL; } @@ -71,7 +73,7 @@ static int src_buffer_lengths(struct comp_dev *dev, struct comp_data *cd, int nc /* Check from stage1 parameter for a deleted in/out rate combination.*/ if (stage1->filter_length < 1) { - comp_err(dev, "src_buffer_lengths(): Non-supported combination sfs_in = %d, fs_out = %d", + comp_err(dev, "Non-supported combination sfs_in = %d, fs_out = %d", fs_in, fs_out); return -EINVAL; } @@ -382,13 +384,12 @@ int src_copy_sxx(struct comp_data *cd, struct sof_source *source, return -ENOTSUP; } -void src_set_alignment(struct sof_source *source, struct sof_sink *sink) +void src_set_alignment(struct sof_source *source) { - const uint32_t byte_align = 1; - const uint32_t frame_align_req = 1; + const uint32_t byte_align = SOF_FRAME_BYTE_ALIGN; + const uint32_t frame_align_req = SOF_FRAME_COUNT_ALIGN; source_set_alignment_constants(source, byte_align, frame_align_req); - sink_set_alignment_constants(sink, byte_align, frame_align_req); } static int src_verify_params(struct processing_module *mod) @@ -398,7 +399,7 @@ static int src_verify_params(struct processing_module *mod) struct comp_dev *dev = mod->dev; int ret; - comp_dbg(dev, "src_verify_params()"); + comp_dbg(dev, "entry"); /* check whether params->rate (received from driver) are equal * to src->source_rate (PLAYBACK) or src->sink_rate (CAPTURE) set during @@ -408,13 +409,13 @@ static int src_verify_params(struct processing_module *mod) if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { ret = src_stream_pcm_sink_rate_check(cd->ipc_config, params); if (ret < 0) { - comp_err(dev, "src_verify_params(): sink stream rate does not match rate fetched from ipc."); + comp_err(dev, "sink stream rate does not match rate fetched from ipc."); return ret; } } else { ret = src_stream_pcm_source_rate_check(cd->ipc_config, params); if (ret < 0) { - comp_err(dev, "src_verify_params(): source stream rate does not match rate fetched from ipc."); + comp_err(dev, "source stream rate does not match rate fetched from ipc."); return ret; } } @@ -423,7 +424,7 @@ static int src_verify_params(struct processing_module *mod) */ ret = comp_verify_params(dev, BUFF_PARAMS_RATE, params); if (ret < 0) - comp_err(dev, "src_verify_params(): comp_verify_params() failed."); + comp_err(dev, "comp_verify_params() failed."); return ret; } @@ -483,26 +484,26 @@ int src_params_general(struct processing_module *mod, int n; int err; - comp_info(dev, "src_params()"); + comp_info(dev, "entry"); err = src_set_params(mod, sink); if (err < 0) { - comp_err(dev, "src_params(): set params failed."); + comp_err(dev, "set params failed."); return err; } err = src_verify_params(mod); if (err < 0) { - comp_err(dev, "src_params(): pcm params verification failed."); + comp_err(dev, "pcm params verification failed."); return err; } - comp_info(dev, "src_params(), source_rate = %u, sink_rate = %u", + comp_info(dev, "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", + comp_dbg(dev, "sample_container_bytes = %d, channels = %u, dev->frames = %u", cd->sample_container_bytes, cd->channels_count, dev->frames); if (!cd->sink_rate) { - comp_err(dev, "src_params(), zero sink rate"); + comp_err(dev, "zero sink rate"); return -EINVAL; } @@ -512,7 +513,7 @@ int src_params_general(struct processing_module *mod, /* Allocate needed memory for delay lines */ err = src_buffer_lengths(dev, cd, cd->channels_count); if (err < 0) { - comp_err(dev, "src_params(): src_buffer_lengths() failed"); + comp_err(dev, "src_buffer_lengths() failed"); return err; } @@ -523,19 +524,19 @@ int src_params_general(struct processing_module *mod, */ delay_lines_size = ALIGN_UP(sizeof(int32_t) * cd->param.total, 8); if (delay_lines_size == 0) { - comp_err(dev, "src_params(): delay_lines_size = 0"); + comp_err(dev, "delay_lines_size = 0"); return -EINVAL; } /* free any existing delay lines. TODO reuse if same size */ - rfree(cd->delay_lines); + mod_free(mod, cd->delay_lines); - cd->delay_lines = rballoc(0, SOF_MEM_CAPS_RAM, delay_lines_size); + cd->delay_lines = mod_alloc(mod, delay_lines_size); if (!cd->delay_lines) { - comp_err(dev, "src_params(): failed to alloc cd->delay_lines, delay_lines_size = %zu", + comp_err(dev, "failed to alloc cd->delay_lines, delay_lines_size = %zu", delay_lines_size); - return -EINVAL; + return -ENOMEM; } /* Clear all delay lines here */ @@ -565,7 +566,7 @@ int src_params_general(struct processing_module *mod, /* This is possibly due to missing coefficients for * requested rates combination. */ - comp_info(dev, "src_params(), missing coefficients for requested rates combination"); + comp_info(dev, "missing coefficients for requested rates combination"); cd->src_func = src_fallback; return -EINVAL; } @@ -584,7 +585,7 @@ int src_param_set(struct comp_dev *dev, struct comp_data *cd) /* Check that both in and out rates are supported */ if (a->idx_in < 0 || a->idx_out < 0) { - comp_err(dev, "src_buffer_lengths(): rates not supported, fs_in: %u, fs_out: %u", + comp_err(dev, "rates not supported, fs_in: %u, fs_out: %u", fs_in, fs_out); return -EINVAL; } @@ -592,13 +593,62 @@ int src_param_set(struct comp_dev *dev, struct comp_data *cd) return 0; } +int src_allocate_copy_stages(struct processing_module *mod, struct src_param *prm, + const struct src_stage *stage_src1, + const struct src_stage *stage_src2) +{ +#if CONFIG_FAST_GET + struct src_stage *stage_dst; + size_t coef_size[2]; +#if SRC_SHORT + size_t tap_size = sizeof(int16_t); +#else + size_t tap_size = sizeof(int32_t); +#endif + + stage_dst = mod_alloc(mod, 2 * sizeof(*stage_dst)); + if (!stage_dst) { + comp_err(mod->dev, "failed to allocate stages"); + return -ENOMEM; + } + + /* Make local copies of the src_stages */ + stage_dst[0] = *stage_src1; + stage_dst[1] = *stage_src2; + + coef_size[0] = tap_size * stage_src1->filter_length; + coef_size[1] = tap_size * stage_src2->filter_length; + + if (coef_size[0] == 0 || coef_size[1] == 0) { + comp_err(mod->dev, + "illegal zero coefficient vector size for unsupported conversion request %d to %d", + prm->in_fs[prm->idx_in], prm->out_fs[prm->idx_out]); + return -EINVAL; + } + + stage_dst[0].coefs = mod_fast_get(mod, stage_src1->coefs, coef_size[0]); + stage_dst[1].coefs = mod_fast_get(mod, stage_src2->coefs, coef_size[1]); + + if (!stage_dst[0].coefs || !stage_dst[1].coefs) { + comp_err(mod->dev, "failed to allocate coefficients"); + return -ENOMEM; + } + + prm->stage1 = stage_dst; + prm->stage2 = stage_dst + 1; +#else + prm->stage1 = stage_src1; + prm->stage2 = stage_src2; +#endif + + return 0; +} + bool src_is_ready_to_process(struct processing_module *mod, 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); - - return src_get_copy_limits(cd, sources[0], sinks[0]); + return sink_get_free_frames(sinks[0]) || source_get_data_frames_available(sources[0]); } int src_process(struct processing_module *mod, @@ -607,7 +657,7 @@ int src_process(struct processing_module *mod, { struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "src_process()"); + comp_dbg(mod->dev, "entry"); /* src component needs 1 source and 1 sink */ if (!src_get_copy_limits(cd, sources[0], sinks[0])) { @@ -618,25 +668,11 @@ int src_process(struct processing_module *mod, return cd->src_func(cd, sources[0], sinks[0]); } -int src_set_config(struct processing_module *mod, uint32_t config_id, - enum module_cfg_fragment_position pos, uint32_t data_offset_size, - const uint8_t *fragment, size_t fragment_size, uint8_t *response, - size_t response_size) -{ - return -EINVAL; -} - -int src_get_config(struct processing_module *mod, uint32_t config_id, - uint32_t *data_offset_size, uint8_t *fragment, size_t fragment_size) -{ - return -EINVAL; -} - int src_reset(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "src_reset()"); + comp_info(mod->dev, "entry"); cd->src_func = src_fallback; src_polyphase_reset(&cd->src); @@ -644,15 +680,25 @@ int src_reset(struct processing_module *mod) return 0; } -int src_free(struct processing_module *mod) +__cold int src_free(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "src_free()"); + assert_can_be_cold(); + + comp_info(mod->dev, "entry"); + +#if CONFIG_FAST_GET + struct src_param *a = &cd->param; + + if (a->stage1) + mod_fast_put(mod, a->stage1->coefs); + if (a->stage2) + mod_fast_put(mod, a->stage2->coefs); +#endif - /* Free dynamically reserved buffers for SRC algorithm */ - rfree(cd->delay_lines); + mod_free(mod, cd->delay_lines); + mod_free(mod, cd); - rfree(cd); return 0; } diff --git a/src/audio/src/src_common.h b/src/audio/src/src_common.h index d3ed218016db..98f29a263131 100644 --- a/src/audio/src/src_common.h +++ b/src/audio/src/src_common.h @@ -18,15 +18,15 @@ #include "src_ipc.h" struct src_stage { - const int idm; - const int odm; - const int num_of_subfilters; - const int subfilter_length; - const int filter_length; - const int blk_in; - const int blk_out; - const int halfband; - const int shift; + int idm; + int odm; + int num_of_subfilters; + int subfilter_length; + int filter_length; + int blk_in; + int blk_out; + int halfband; + int shift; const void *coefs; /* Can be int16_t or int32_t depending on config */ }; @@ -143,7 +143,7 @@ int32_t src_input_rates(void); int32_t src_output_rates(void); -void src_set_alignment(struct sof_source *source, struct sof_sink *sink); +void src_set_alignment(struct sof_source *source); struct comp_data { #if CONFIG_IPC_MAJOR_4 @@ -215,6 +215,9 @@ static inline int src_fallback(struct comp_data *cd, return 0; } +int src_allocate_copy_stages(struct processing_module *mod, struct src_param *prm, + const struct src_stage *stage_src1, + const struct src_stage *stage_src2); int src_rate_check(const void *spec); int src_set_params(struct processing_module *mod, struct sof_sink *sink); @@ -239,12 +242,6 @@ int src_process(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks); -int src_set_config(struct processing_module *mod, uint32_t config_id, - enum module_cfg_fragment_position pos, uint32_t data_offset_size, - const uint8_t *fragment, size_t fragment_size, uint8_t *response, - size_t response_size); -int src_get_config(struct processing_module *mod, uint32_t config_id, - uint32_t *data_offset_size, uint8_t *fragment, size_t fragment_size); int src_free(struct processing_module *mod); int src_reset(struct processing_module *mod); extern struct tr_ctx src_tr; diff --git a/src/audio/src/src_config.h b/src/audio/src/src_config.h index 01a60230093c..9e53704b123f 100644 --- a/src/audio/src/src_config.h +++ b/src/audio/src/src_config.h @@ -8,55 +8,24 @@ #ifndef __SOF_AUDIO_SRC_SRC_CONFIG_H__ #define __SOF_AUDIO_SRC_SRC_CONFIG_H__ - - -/* If next define is set to 1 the SRC is configured automatically. Setting - * to zero temporarily is useful is for testing needs. - */ -#define SRC_AUTOARCH 1 - -/* Force manually some code variant when SRC_AUTODSP is set to zero. These - * are useful in code debugging. - */ -#if SRC_AUTOARCH == 0 -#define SRC_GENERIC 1 -#define SRC_HIFIEP 0 -#define SRC_HIFI3 0 -#endif - -/* Select optimized code variant when xt-xcc compiler is used */ -#if SRC_AUTOARCH == 1 -#if defined __XCC__ -#include <xtensa/config/core-isa.h> -#define SRC_GENERIC 0 -#if XCHAL_HAVE_HIFI4 == 1 -#define SRC_HIFI4 1 -#define SRC_HIFI3 0 -#define SRC_HIFIEP 0 +#include <sof/common.h> + +/* Follow kconfig for FILTER in SRC component */ +#if SOF_USE_MIN_HIFI(5, FILTER) +#define SRC_HIFI5 1 +#elif SOF_USE_MIN_HIFI(4, FILTER) +#define SRC_HIFI4 1 +#elif SOF_USE_MIN_HIFI(3, FILTER) +#define SRC_HIFI3 1 +#elif SOF_USE_HIFI(2, FILTER) +#define SRC_HIFIEP 1 #else -#define SRC_HIFI4 0 -#if XCHAL_HAVE_HIFI2EP == 1 -#define SRC_HIFIEP 1 -#define SRC_HIFI3 0 -#endif -#if XCHAL_HAVE_HIFI3 == 1 -#define SRC_HIFI3 1 -#define SRC_HIFIEP 0 -#endif -#endif -#else -/* GCC */ -#define SRC_GENERIC 1 -#define SRC_HIFIEP 0 -#define SRC_HIFI3 0 -#if CONFIG_LIBRARY -#else -#define SRC_SHORT 1 /* Need to use for generic code version speed */ -#endif -#endif +#define SRC_GENERIC 1 #endif -/* Kconfig option tiny needs 16 bits coefficients, other options use 32 bits */ +/* Kconfig option tiny needs 16 bits coefficients, other options use 32 bits, + * also gcc builds for all platforms and testbench (library) + */ #if !defined(SRC_SHORT) #if CONFIG_COMP_SRC_TINY #define SRC_SHORT 1 /* 16 bit coefficients filter core */ diff --git a/src/audio/src/src_hifi4.c b/src/audio/src/src_hifi4.c index 1106968f4085..ad3b8583113f 100644 --- a/src/audio/src/src_hifi4.c +++ b/src/audio/src/src_hifi4.c @@ -1,10 +1,11 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2022 Intel Corporation. All rights reserved. +// Copyright(c) 2022-2025 Intel Corporation. // // Author: Krzysztof Frydryk <krzysztofx.frydryk@intel.com> +// Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> -/* HiFi4 optimized code parts for SRC */ +/* HiFi5 optimized code parts for SRC */ #include "src_config.h" @@ -23,20 +24,21 @@ #include <zephyr/sys/util.h> #endif /* __ZEPHYR__ */ -/* HiFi4 has - * 16x 64 bit registers in register file AE_DR - */ +#if SRC_SHORT +#define SRC_COEF_SIZE sizeof(int16_t) +#else +#define SRC_COEF_SIZE sizeof(int32_t) +#endif #if SRC_SHORT /* 16 bit coefficients version */ -static inline void fir_filter(ae_f32 *rp, const void *cp, ae_f32 *wp0, - const int taps_div_4, const int shift, - const int nch) +static inline void fir_filter_2ch(ae_f32 *rp, const void *cp, ae_f32 *wp0, + const int taps_div_4, const int shift) { /* This function uses - * 6x 64 bit registers - * 3x integers - * 5x address pointers, + * 7x 64 bit registers + * 2x integers + * 3x address pointers, */ ae_f64 a0; ae_f64 a1; @@ -47,73 +49,89 @@ static inline void fir_filter(ae_f32 *rp, const void *cp, ae_f32 *wp0, ae_f32x2 data2; ae_f16x4 *coefp; ae_f32x2 *dp; - ae_f32 *dp0; - ae_f32 *dp1; int i; - int j; ae_f32 *wp = wp0; - const int inc = nch * sizeof(int32_t); + const int inc = 2 * sizeof(int32_t); - if (nch == 2) { - /* Move data pointer back by one sample to start from right - * channel sample. Discard read value p0. + /* Move data pointer back by one sample to start from right + * channel sample. Discard read value p0. + */ + dp = (ae_f32x2 *)rp; + AE_L32_XC(d0, (ae_f32 *)dp, -sizeof(ae_f32)); + + /* Reset coefficient pointer and clear accumulator */ + coefp = (ae_f16x4 *)cp; + a0 = AE_ZERO64(); + a1 = AE_ZERO64(); + u = AE_LA64_PP(coefp); + + /* Compute FIR filter for current channel with four + * taps per every loop iteration. Four coefficients + * are loaded simultaneously. Data is read + * from interleaved buffer with stride of channels + * count. + */ + for (i = 0; i < taps_div_4; i++) { + /* Load four coefficients */ + AE_LA16X4_IP(coef4, u, coefp); + + /* Load two data samples from two channels */ + AE_L32X2_XC(d0, dp, inc); /* r0, l0 */ + AE_L32X2_XC(d1, dp, inc); /* r1, l1 */ + + /* Select to data2 sequential samples from a channel + * and then accumulate to a0 and a1 + * data2_h * coef4_3 + data2_l * coef4_2. + * The data is 32 bits Q1.31 and coefficient 16 bits + * Q1.15. The accumulators are Q17.47. */ - dp = (ae_f32x2 *)rp; - AE_L32_XC(d0, (ae_f32 *)dp, -sizeof(ae_f32)); + data2 = AE_SEL32_LL(d0, d1); /* l0, l1 */ + AE_MULAAFD32X16_H3_L2(a0, data2, coef4); + data2 = AE_SEL32_HH(d0, d1); /* r0, r1 */ + AE_MULAAFD32X16_H3_L2(a1, data2, coef4); - /* Reset coefficient pointer and clear accumulator */ - coefp = (ae_f16x4 *)cp; - a0 = AE_ZERO64(); - a1 = AE_ZERO64(); + /* Load two data samples from two channels */ + AE_L32X2_XC(d0, dp, inc); /* r2, l2 */ + AE_L32X2_XC(d1, dp, inc); /* r3, l3 */ - /* Compute FIR filter for current channel with four - * taps per every loop iteration. Four coefficients - * are loaded simultaneously. Data is read - * from interleaved buffer with stride of channels - * count. + /* Accumulate + * data2_h * coef4_1 + data2_l * coef4_0. */ - for (i = 0; i < taps_div_4; i++) { - /* Load four coefficients */ - AE_LA16X4_IP(coef4, u, coefp); - - /* Load two data samples from two channels */ - AE_L64_XC(d0, dp, inc); /* r0, l0 */ - AE_L64_XC(d1, dp, inc); /* r1, l1 */ - - /* Select to data2 sequential samples from a channel - * and then accumulate to a0 and a1 - * data2_h * coef4_3 + data2_l * coef4_2. - * The data is 32 bits Q1.31 and coefficient 16 bits - * Q1.15. The accumulators are Q17.47. - */ - data2 = AE_SEL32_LL(d0, d1); /* l0, l1 */ - AE_MULAAFD32X16_H3_L2(a0, data2, coef4); - data2 = AE_SEL32_HH(d0, d1); /* r0, r1 */ - AE_MULAAFD32X16_H3_L2(a1, data2, coef4); - - /* Load two data samples from two channels */ - AE_L64_XC(d0, dp, inc); /* r2, l2 */ - AE_L64_XC(d1, dp, inc); /* r3, l3 */ - - /* Accumulate - * data2_h * coef4_1 + data2_l * coef4_0. - */ - data2 = AE_SEL32_LL(d0, d1); /* l2, l3 */ - AE_MULAAFD32X16_H1_L0(a0, data2, coef4); - data2 = AE_SEL32_HH(d0, d1); /* r2, r3 */ - AE_MULAAFD32X16_H1_L0(a1, data2, coef4); - } + data2 = AE_SEL32_LL(d0, d1); /* l2, l3 */ + AE_MULAAFD32X16_H1_L0(a0, data2, coef4); + data2 = AE_SEL32_HH(d0, d1); /* r2, r3 */ + AE_MULAAFD32X16_H1_L0(a1, data2, coef4); + } - /* Scale FIR output with right shifts, round/saturate - * to Q1.31, and store 32 bit output. - */ - AE_S32_L_XP(AE_ROUND32F48SSYM(AE_SRAA64(a0, shift)), wp, - sizeof(int32_t)); - AE_S32_L_XP(AE_ROUND32F48SSYM(AE_SRAA64(a1, shift)), wp, - sizeof(int32_t)); + /* Scale FIR output with right shifts, round/saturate + * to Q1.31, and store 32 bit output. + */ + AE_S32_L_XP(AE_ROUND32F48SSYM(AE_SRAA64(a0, shift)), wp, sizeof(int32_t)); + AE_S32_L_XP(AE_ROUND32F48SSYM(AE_SRAA64(a1, shift)), wp, sizeof(int32_t)); +} - return; - } +static inline void fir_filter(ae_f32 *rp, const void *cp, ae_f32 *wp0, + const int taps_div_4, const int shift, + const int nch) +{ + /* This function uses + * 6x 64 bit registers + * 3x integers + * 3x address pointers, + */ + ae_f64 a0; + ae_valign u; + ae_f16x4 coef4; + ae_f32x2 d0; + ae_f32x2 d1; + ae_f32x2 data2; + ae_f16x4 *coefp; + ae_f32 *dp0; + ae_f32 *dp1; + int i; + int j; + ae_f32 *wp = wp0; + const int inc = nch * sizeof(int32_t); dp1 = (ae_f32 *)rp; for (j = 0; j < nch; j++) { @@ -124,6 +142,7 @@ static inline void fir_filter(ae_f32 *rp, const void *cp, ae_f32 *wp0, /* Reset coefficient pointer and clear accumulator */ coefp = (ae_f16x4 *)cp; a0 = AE_ZERO64(); + u = AE_LA64_PP(coefp); /* Compute FIR filter for current channel with four * taps per every loop iteration. Data is read from @@ -169,139 +188,144 @@ static inline void fir_filter(ae_f32 *rp, const void *cp, ae_f32 *wp0, #else /* 32bit coefficients version */ -static inline void fir_filter(ae_f32 *rp, const void *cp, ae_f32 *wp0, - const int taps_div_4, const int shift, - const int nch) +static inline void fir_filter_2ch(ae_f32 *rp, const void *cp, ae_f32 *wp0, + const int taps_div_4, const int shift) { - /* This function uses - * 6x 64 bit registers - * 3x integers - * 5x address pointers, - */ - ae_f64 a0; - ae_f64 a1; - ae_f24x2 data2 = AE_ZERO24(); - ae_f24x2 coef2 = AE_ZERO24(); - ae_f24x2 d0 = AE_ZERO24(); - ae_f24x2 d1 = AE_ZERO24(); - ae_f24x2 *coefp; - ae_f24x2 *dp; - ae_f24 *dp1; - ae_f24 *dp0; - int i; - int j; + ae_f64 a0 = AE_ZERO64(); + ae_f64 a1 = AE_ZERO64(); + ae_valign coef_align; + ae_f32x2 coef32; + ae_f32x2 coef10; + ae_f32x2 sample10; + ae_f32x2 f0; + ae_f32x2 f1; + ae_int32x2 *coefp; + ae_f32x2 *dp; ae_f32 *wp = wp0; - const int inc = nch * sizeof(int32_t); + const int inc = 2 * sizeof(int32_t); + int i; - if (nch == 2) { - /* Move data pointer back by one sample to start from right - * channel sample. Discard read value p0. + /* Move data pointer back by one sample to start from right + * channel sample. Discard read value p0. + */ + dp = (ae_f32x2 *)rp; + AE_L32_XC(f0, (ae_f32 *)dp, -sizeof(ae_f32)); + + /* Reset coefficient pointer and clear accumulator */ + coefp = (ae_int32x2 *)cp; + coef_align = AE_LA64_PP(coefp); + + /* Compute FIR filter for current channel with four + * taps per every loop iteration. Two coefficients + * are loaded simultaneously. Data is read + * from interleaved buffer with stride of channels + * count. + */ + for (i = 0; i < taps_div_4; i++) { + /* Load four coefficients */ + AE_LA32X2_IP(coef10, coef_align, coefp); + AE_LA32X2_IP(coef32, coef_align, coefp); + + /* Load two data samples from two channels. Note: Due to + * polyphase array data start shift for sub-filters can't + * use 128 bits load due to align requirement. */ - dp = (ae_f24x2 *)rp; - AE_L32F24_XC(d0, (ae_f24 *)dp, -sizeof(ae_f24)); + AE_L32X2_XC(f0, dp, inc); /* f0.h is left0, f0.l is right0 */ + AE_L32X2_XC(f1, dp, inc); /* f1.h is left1, f1.l is right1 */ - /* Reset coefficient pointer and clear accumulator */ - coefp = (ae_f24x2 *)cp; - a0 = AE_ZERO64(); - a1 = AE_ZERO64(); - - /* Compute FIR filter for current channel with four - * taps per every loop iteration. Two coefficients - * are loaded simultaneously. Data is read - * from interleaved buffer with stride of channels - * count. + /* a0 (left) += left10.h (left1) * coef10.h (coef2) + * += left10.l (left0) * coef10.l (coef1) + * a1 (right) += right10.h (right1) * coef10.h (coef2) + * += right10.l (right0) * coef10.l (coef1) */ - for (i = 0; i < taps_div_4; i++) { - /* Load two coefficients. Coef2_h contains tap *coefp - * and coef2_l contains the next tap. - */ - /* TODO: Ensure coefficients are 64 bits aligned */ - AE_L32X2F24_IP(coef2, coefp, sizeof(ae_f24x2)); - - /* Load two data samples from two channels */ - AE_L32X2F24_XC(d0, dp, inc); /* r0, l0 */ - AE_L32X2F24_XC(d1, dp, inc); /* r1, l1 */ - - /* Select to data2 two successive left channel samples - * from d0 and d1, multiply-add and accumulate to a0. - * Select to data2 two successive right channel samples - * from d0 and d1, multiply-add and accumulate to a1. - * data2_h * coef2_h + data2_l * coef2_l. The Q1.31 - * data and Q1.15 coefficients are used as 24 bits as - * Q1.23 values. - */ - data2 = AE_SELP24_LL(d0, d1); - AE_MULAAFP24S_HH_LL(a0, data2, coef2); - data2 = AE_SELP24_HH(d0, d1); - AE_MULAAFP24S_HH_LL(a1, data2, coef2); - - /* Repeat for next two taps */ - AE_L32X2F24_IP(coef2, coefp, sizeof(ae_f24x2)); - AE_L32X2F24_XC(d0, dp, inc); /* r2, l2 */ - AE_L32X2F24_XC(d1, dp, inc); /* r3, l3 */ - data2 = AE_SELP24_LL(d0, d1); - AE_MULAAFP24S_HH_LL(a0, data2, coef2); - data2 = AE_SELP24_HH(d0, d1); - AE_MULAAFP24S_HH_LL(a1, data2, coef2); - } + sample10 = AE_SEL32_HH(f0, f1); + AE_MULAAFD32RA_HH_LL(a0, sample10, coef10); + sample10 = AE_SEL32_LL(f0, f1); + AE_MULAAFD32RA_HH_LL(a1, sample10, coef10); + + /* Repeat for next two taps */ + AE_L32X2_XC(f0, dp, inc); /* f0.h is left2, f0.l is right2 */ + AE_L32X2_XC(f1, dp, inc); /* f1.h is left3, f1.l is right3 */ + sample10 = AE_SEL32_HH(f0, f1); + AE_MULAAFD32RA_HH_LL(a0, sample10, coef32); + sample10 = AE_SEL32_LL(f0, f1); + AE_MULAAFD32RA_HH_LL(a1, sample10, coef32); + } - /* Scale FIR output with right shifts, round/saturate - * to Q1.31, and store 32 bit output. - */ - AE_S32_L_XP(AE_ROUND32F48SSYM(AE_SRAA64(a0, shift)), wp, - sizeof(int32_t)); - AE_S32_L_XP(AE_ROUND32F48SSYM(AE_SRAA64(a1, shift)), wp, - sizeof(int32_t)); + /* Scale FIR output with right shifts, round/saturate + * to Q1.31, and store 32 bit output. + */ + f0 = AE_ROUND32X2F48SASYM(AE_SRAA64(a1, shift), AE_SRAA64(a0, shift)); + AE_S32X2_I(f0, (ae_int32x2 *)wp, 0); +} - return; - } +static inline void fir_filter(ae_f32 *rp, const void *cp, ae_f32 *wp0, + const int taps_div_4, const int shift, + const int nch) +{ + ae_f64 a0 = AE_ZERO64(); + ae_valign coef_align; + ae_f32x2 coef32; + ae_f32x2 coef10; + ae_f32x2 sample10; + ae_f32x2 f0; + ae_f32x2 f1; + ae_int32x2 *coefp; + ae_f32 *dp; + ae_f32 *dp1 = rp; + ae_f32 *wp = wp0; + const int inc = nch * sizeof(int32_t); + int i; + int j; - dp1 = (ae_f24 *)rp; for (j = 0; j < nch; j++) { /* Copy pointer and advance to next ch with dummy load */ - dp0 = dp1; - AE_L32F24_XC(data2, dp1, -sizeof(ae_f24)); + dp = dp1; + AE_L32_XC(f0, dp1, -sizeof(ae_f32)); /* Reset coefficient pointer and clear accumulator */ - coefp = (ae_f24x2 *)cp; + coefp = (ae_int32x2 *)cp; a0 = AE_ZERO64(); + coef_align = AE_LA64_PP(coefp); /* Compute FIR filter for current channel with four * taps per every loop iteration. Data is read from * interleaved buffer with stride of channels count. */ for (i = 0; i < taps_div_4; i++) { - /* Load two coefficients */ - coef2 = *coefp++; + /* Load four coefficients + * TODO: Ensure coefficients are 128 bits aligned + */ + AE_LA32X2_IP(coef10, coef_align, coefp); + AE_LA32X2_IP(coef32, coef_align, coefp); /* Load two data samples, place to high and * low of data2. */ - AE_L32F24_XC(d0, dp0, inc); - AE_L32F24_XC(d1, dp0, inc); - data2 = AE_SELP24_LL(d0, d1); + AE_L32_XC(f0, dp, inc); + AE_L32_XC(f1, dp, inc); + sample10 = AE_SEL32_LL(f0, f1); /* Accumulate to data2_h * coef2_h + * data2_l*coef2_l. The Q1.31 bit data is used * as Q1.23 from MSB side bits of the 32 bit * word. The accumulator m is Q17.47. */ - AE_MULAAFD24_HH_LL(a0, data2, coef2); + AE_MULAAFD32RA_HH_LL(a0, sample10, coef10); /* Repeat the same for next two filter taps */ - coef2 = *coefp++; - AE_L32F24_XC(d0, dp0, inc); - AE_L32F24_XC(d1, dp0, inc); - data2 = AE_SELP24_LL(d0, d1); - AE_MULAAFD24_HH_LL(a0, data2, coef2); + AE_L32_XC(f0, dp, inc); + AE_L32_XC(f1, dp, inc); + sample10 = AE_SEL32_LL(f0, f1); + AE_MULAAFD32RA_HH_LL(a0, sample10, coef32); } /* Scale FIR output with right shifts, round/saturate Q17.47 * to Q1.31, and store 32 bit output. Advance write * pointer to next sample. */ - AE_S32_L_XP(AE_ROUND32F48SSYM(AE_SRAA64(a0, shift)), wp, - sizeof(int32_t)); + f0 = AE_ROUND32F48SASYM(AE_SRAA64(a0, shift)); + AE_S32_L_XP(f0, wp, sizeof(int32_t)); } } @@ -315,7 +339,7 @@ void src_polyphase_stage_cir(struct src_stage_prm *s) * 16x integers * 11x address pointers, */ - ae_int32x2 q = AE_ZERO32(); + ae_int32x2 q; ae_f32 *rp; ae_f32 *wp; int i; @@ -342,12 +366,7 @@ void src_polyphase_stage_cir(struct src_stage_prm *s) int32_t *y_wptr = (int32_t *)s->y_wptr; int32_t *x_end_addr = (int32_t *)s->x_end_addr; int32_t *y_end_addr = (int32_t *)s->y_end_addr; - -#if SRC_SHORT - const size_t subfilter_size = cfg->subfilter_length * sizeof(int16_t); -#else - const size_t subfilter_size = cfg->subfilter_length * sizeof(int32_t); -#endif + const size_t subfilter_size = cfg->subfilter_length * SRC_COEF_SIZE; for (n = 0; n < s->times; n++) { /* Input data to filter */ @@ -388,17 +407,25 @@ void src_polyphase_stage_cir(struct src_stage_prm *s) * sub-filters. */ wp = (ae_f32 *)fir->out_rp; - for (i = 0; i < cfg->num_of_subfilters; i++) { - fir_filter(rp, cp, wp, taps_div_4, cfg->shift, nch); - wp += nch_x_odm; - cp = (uint8_t *)cp + subfilter_size; - src_inc_wrap((int32_t **)&wp, out_delay_end, out_size); - - /* Circular advance pointer rp by number of - * channels x input delay multiplier. Loaded value q - * is discarded. - */ - AE_L32_XC(q, rp, nch_x_idm_sz); + if (nch == 2) { + for (i = 0; i < cfg->num_of_subfilters; i++) { + fir_filter_2ch(rp, cp, wp, taps_div_4, cfg->shift); + wp += nch_x_odm; + cp = (uint8_t *)cp + subfilter_size; + src_inc_wrap((int32_t **)&wp, out_delay_end, out_size); + /* Circular advance pointer rp by number of channels x input + * delay multiplier. Loaded value q is discarded. + */ + AE_L32_XC(q, rp, nch_x_idm_sz); + } + } else { + for (i = 0; i < cfg->num_of_subfilters; i++) { + fir_filter(rp, cp, wp, taps_div_4, cfg->shift, nch); + wp += nch_x_odm; + cp = (uint8_t *)cp + subfilter_size; + src_inc_wrap((int32_t **)&wp, out_delay_end, out_size); + AE_L32_XC(q, rp, nch_x_idm_sz); + } } /* Output */ @@ -464,12 +491,7 @@ void src_polyphase_stage_cir_s16(struct src_stage_prm *s) int16_t *y_wptr = (int16_t *)s->y_wptr; int16_t *x_end_addr = (int16_t *)s->x_end_addr; int16_t *y_end_addr = (int16_t *)s->y_end_addr; - -#if SRC_SHORT - const size_t subfilter_size = cfg->subfilter_length * sizeof(int16_t); -#else - const size_t subfilter_size = cfg->subfilter_length * sizeof(int32_t); -#endif + const size_t subfilter_size = cfg->subfilter_length * SRC_COEF_SIZE; for (n = 0; n < s->times; n++) { /* Input data */ @@ -509,17 +531,25 @@ void src_polyphase_stage_cir_s16(struct src_stage_prm *s) * sub-filters. */ wp = (ae_f32 *)fir->out_rp; - for (i = 0; i < cfg->num_of_subfilters; i++) { - fir_filter(rp, cp, wp, taps_div_4, cfg->shift, nch); - wp += nch_x_odm; - cp = (uint8_t *)cp + subfilter_size; - src_inc_wrap((int32_t **)&wp, out_delay_end, out_size); - - /* Circular advance pointer rp by number of - * channels x input delay multiplier. Loaded value q - * is discarded. - */ - AE_L32_XC(q, rp, nch_x_idm_sz); + if (nch == 2) { + for (i = 0; i < cfg->num_of_subfilters; i++) { + fir_filter_2ch(rp, cp, wp, taps_div_4, cfg->shift); + wp += nch_x_odm; + cp = (uint8_t *)cp + subfilter_size; + src_inc_wrap((int32_t **)&wp, out_delay_end, out_size); + /* Circular advance pointer rp by number of channels x input delay + * multiplier. Loaded value q is discarded. + */ + AE_L32_XC(q, rp, nch_x_idm_sz); + } + } else { + for (i = 0; i < cfg->num_of_subfilters; i++) { + fir_filter(rp, cp, wp, taps_div_4, cfg->shift, nch); + wp += nch_x_odm; + cp = (uint8_t *)cp + subfilter_size; + src_inc_wrap((int32_t **)&wp, out_delay_end, out_size); + AE_L32_XC(q, rp, nch_x_idm_sz); + } } /* Output */ diff --git a/src/audio/src/src_hifi5.c b/src/audio/src/src_hifi5.c new file mode 100644 index 000000000000..0adfc4796d25 --- /dev/null +++ b/src/audio/src/src_hifi5.c @@ -0,0 +1,583 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022-2025 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> +// Krzysztof Frydryk <krzysztofx.frydryk@intel.com> + +/* HiFi5 optimized code parts for SRC */ + +#include "src_config.h" + +#if SRC_HIFI5 + +#include "src_common.h" + +#include <sof/math/numbers.h> +#include <xtensa/config/defs.h> +#include <xtensa/tie/xt_hifi5.h> +#include <stddef.h> +#include <stdint.h> + +/* sof/math/numbers.h doesn't define MIN when used with zephyr */ +#ifdef __ZEPHYR__ +#include <zephyr/sys/util.h> +#endif /* __ZEPHYR__ */ + +#if SRC_SHORT +#define SRC_COEF_SIZE sizeof(int16_t) +#else +#define SRC_COEF_SIZE sizeof(int32_t) +#endif + +#if SRC_SHORT /* 16 bit coefficients version */ + +static inline void fir_filter_2ch(ae_f32 *rp, const void *cp, ae_f32 *wp0, + const int taps_div_4, const int shift) +{ + /* This function uses + * 7x 64 bit registers + * 2x integers + * 3x address pointers, + */ + ae_f64 a0; + ae_f64 a1; + ae_valign u; + ae_f16x4 coef4; + ae_f32x2 d0; + ae_f32x2 d1; + ae_f32x2 data2; + ae_f16x4 *coefp; + ae_f32x2 *dp; + int i; + ae_f32 *wp = wp0; + const int inc = 2 * sizeof(int32_t); + + /* Move data pointer back by one sample to start from right + * channel sample. Discard read value p0. + */ + dp = (ae_f32x2 *)rp; + AE_L32_XC(d0, (ae_f32 *)dp, -sizeof(ae_f32)); + + /* Reset coefficient pointer and clear accumulator */ + coefp = (ae_f16x4 *)cp; + a0 = AE_ZERO64(); + a1 = AE_ZERO64(); + u = AE_LA64_PP(coefp); + + /* Compute FIR filter for current channel with four + * taps per every loop iteration. Four coefficients + * are loaded simultaneously. Data is read + * from interleaved buffer with stride of channels + * count. + */ + for (i = 0; i < taps_div_4; i++) { + /* Load four coefficients */ + AE_LA16X4_IP(coef4, u, coefp); + + /* Load two data samples from two channels */ + AE_L32X2_XC(d0, dp, inc); /* r0, l0 */ + AE_L32X2_XC(d1, dp, inc); /* r1, l1 */ + + /* Select to data2 sequential samples from a channel + * and then accumulate to a0 and a1 + * data2_h * coef4_3 + data2_l * coef4_2. + * The data is 32 bits Q1.31 and coefficient 16 bits + * Q1.15. The accumulators are Q17.47. + */ + data2 = AE_SEL32_LL(d0, d1); /* l0, l1 */ + AE_MULAAFD32X16_H3_L2(a0, data2, coef4); + data2 = AE_SEL32_HH(d0, d1); /* r0, r1 */ + AE_MULAAFD32X16_H3_L2(a1, data2, coef4); + + /* Load two data samples from two channels */ + AE_L32X2_XC(d0, dp, inc); /* r2, l2 */ + AE_L32X2_XC(d1, dp, inc); /* r3, l3 */ + + /* Accumulate + * data2_h * coef4_1 + data2_l * coef4_0. + */ + data2 = AE_SEL32_LL(d0, d1); /* l2, l3 */ + AE_MULAAFD32X16_H1_L0(a0, data2, coef4); + data2 = AE_SEL32_HH(d0, d1); /* r2, r3 */ + AE_MULAAFD32X16_H1_L0(a1, data2, coef4); + } + + /* Scale FIR output with right shifts, round/saturate + * to Q1.31, and store 32 bit output. + */ + AE_S32_L_XP(AE_ROUND32F48SSYM(AE_SRAA64(a0, shift)), wp, sizeof(int32_t)); + AE_S32_L_XP(AE_ROUND32F48SSYM(AE_SRAA64(a1, shift)), wp, sizeof(int32_t)); +} + +static inline void fir_filter(ae_f32 *rp, const void *cp, ae_f32 *wp0, + const int taps_div_4, const int shift, + const int nch) +{ + /* This function uses + * 6x 64 bit registers + * 3x integers + * 3x address pointers, + */ + ae_f64 a0; + ae_valign u; + ae_f16x4 coef4; + ae_f32x2 d0; + ae_f32x2 d1; + ae_f32x2 data2; + ae_f16x4 *coefp; + ae_f32 *dp0; + ae_f32 *dp1; + int i; + int j; + ae_f32 *wp = wp0; + const int inc = nch * sizeof(int32_t); + + dp1 = (ae_f32 *)rp; + for (j = 0; j < nch; j++) { + /* Copy pointer and advance to next ch with dummy load */ + dp0 = dp1; + AE_L32_XC(d0, dp1, -sizeof(ae_f32)); + + /* Reset coefficient pointer and clear accumulator */ + coefp = (ae_f16x4 *)cp; + a0 = AE_ZERO64(); + u = AE_LA64_PP(coefp); + + /* Compute FIR filter for current channel with four + * taps per every loop iteration. Data is read from + * interleaved buffer with stride of channels count. + */ + for (i = 0; i < taps_div_4; i++) { + /* Load four coefficients */ + AE_LA16X4_IP(coef4, u, coefp); + + /* Load two data samples, place to high and + * low of data2. + */ + AE_L32_XC(d0, dp0, inc); + AE_L32_XC(d1, dp0, inc); + data2 = AE_SEL32_LL(d0, d1); + + /* Accumulate + * data2_h * coef4_3 + data2_l* coef4_2. + * The data is 32 bits Q1.31 and coefficient 16 bits + * Q1.15. The accumulator is Q17.47. + */ + AE_MULAAFD32X16_H3_L2(a0, data2, coef4); + + /* Repeat with next two samples */ + AE_L32_XC(d0, dp0, inc); + AE_L32_XC(d1, dp0, inc); + data2 = AE_SEL32_LL(d0, d1); + + /* Accumulate + * data2_h * coef4_1 + data2_l * coef4_0. + */ + AE_MULAAFD32X16_H1_L0(a0, data2, coef4); + } + + /* Scale FIR output with right shifts, round/saturate Q17.47 + * to Q1.31, and store 32 bit output. Advance write + * pointer to next sample. + */ + AE_S32_L_XP(AE_ROUND32F48SSYM(AE_SRAA64(a0, shift)), wp, + sizeof(int32_t)); + } +} + +#else /* 32bit coefficients version */ + +static inline void fir_filter_2ch(ae_f32 *rp, const void *cp, ae_f32 *wp0, + const int taps_div_4, const int shift) +{ + ae_valignx2 coef_align; + ae_f64 a0 = AE_ZERO64(); + ae_f64 a1 = AE_ZERO64(); + ae_f32x2 coef32; + ae_f32x2 coef10; + ae_f32x2 left10; + ae_f32x2 right10; + ae_f32x2 f0; + ae_f32x2 f1; + ae_int32x4 *coefp; + ae_f32x2 *dp; + ae_f32 *wp = wp0; + const int inc = 2 * sizeof(int32_t); + int i; + + /* Move data pointer back by one sample to start from right + * channel sample. Discard read value p0. + */ + dp = (ae_f32x2 *)rp; + AE_L32_XC(f0, (ae_f32 *)dp, -sizeof(ae_f32)); + + /* Reset coefficient pointer and clear accumulator */ + coefp = (ae_int32x4 *)cp; + coef_align = AE_LA128_PP(coefp); + + /* Compute FIR filter for current channel with four + * taps per every loop iteration. Two coefficients + * are loaded simultaneously. Data is read + * from interleaved buffer with stride of channels + * count. + */ + for (i = 0; i < taps_div_4; i++) { + /* Load four coefficients */ + AE_LA32X2X2_IP(coef10, coef32, coef_align, coefp); + + /* Load two data samples from two channels. Note: Due to + * polyphase array data start shift for sub-filters can't + * use 128 bits load due to align requirement. + */ + AE_L32X2_XC(f0, dp, inc); /* f0.h is left0, f0.l is right0 */ + AE_L32X2_XC(f1, dp, inc); /* f1.h is left1, f1.l is right1 */ + + /* a0 (left) += left10.h (left1) * coef10.h (coef2) + * += left10.l (left0) * coef10.l (coef1) + * a1 (right) += right10.h (right1) * coef10.h (coef2) + * += right10.l (right0) * coef10.l (coef1) + */ + left10 = AE_SEL32_HH(f0, f1); + right10 = AE_SEL32_LL(f0, f1); + AE_MULAAF2D32RA_HH_LL(a0, a1, left10, right10, coef10, coef10); + + /* Repeat for next two taps */ + AE_L32X2_XC(f0, dp, inc); /* f0.h is left2, f0.l is right2 */ + AE_L32X2_XC(f1, dp, inc); /* f1.h is left3, f1.l is right3 */ + left10 = AE_SEL32_HH(f0, f1); + right10 = AE_SEL32_LL(f0, f1); + AE_MULAAF2D32RA_HH_LL(a0, a1, left10, right10, coef32, coef32); + } + + /* Scale FIR output with right shifts, round/saturate + * to Q1.31, and store 32 bit output. + */ + f0 = AE_ROUND32X2F48SASYM(AE_SRAA64(a1, shift), AE_SRAA64(a0, shift)); + AE_S32X2_I(f0, (ae_int32x2 *)wp, 0); +} + +static inline void fir_filter(ae_f32 *rp, const void *cp, ae_f32 *wp0, + const int taps_div_4, const int shift, + const int nch) +{ + ae_valignx2 coef_align; + ae_f64 a0 = AE_ZERO64(); + ae_f32x2 coef32; + ae_f32x2 coef10; + ae_f32x2 sample10; + ae_f32x2 f0; + ae_f32x2 f1; + ae_int32x4 *coefp; + ae_f32 *dp; + ae_f32 *dp1 = rp; + ae_f32 *wp = wp0; + const int inc = nch * sizeof(int32_t); + int i; + int j; + + for (j = 0; j < nch; j++) { + /* Copy pointer and advance to next ch with dummy load */ + dp = dp1; + AE_L32_XC(f0, dp1, -sizeof(ae_f32)); + + /* Reset coefficient pointer and clear accumulator */ + coefp = (ae_int32x4 *)cp; + a0 = AE_ZERO64(); + coef_align = AE_LA128_PP(coefp); + + /* Compute FIR filter for current channel with four + * taps per every loop iteration. Data is read from + * interleaved buffer with stride of channels count. + */ + for (i = 0; i < taps_div_4; i++) { + /* Load four coefficients + * TODO: Ensure coefficients are 128 bits aligned + */ + AE_LA32X2X2_IP(coef10, coef32, coef_align, coefp); + + /* Load two data samples, place to high and + * low of data2. + */ + AE_L32_XC(f0, dp, inc); + AE_L32_XC(f1, dp, inc); + sample10 = AE_SEL32_LL(f0, f1); + + /* Accumulate to data2_h * coef2_h + + * data2_l*coef2_l. The Q1.31 bit data is used + * as Q1.23 from MSB side bits of the 32 bit + * word. The accumulator m is Q17.47. + */ + AE_MULAAFD32RA_HH_LL(a0, sample10, coef10); + + /* Repeat the same for next two filter taps */ + AE_L32_XC(f0, dp, inc); + AE_L32_XC(f1, dp, inc); + sample10 = AE_SEL32_LL(f0, f1); + AE_MULAAFD32RA_HH_LL(a0, sample10, coef32); + } + + /* Scale FIR output with right shifts, round/saturate Q17.47 + * to Q1.31, and store 32 bit output. Advance write + * pointer to next sample. + */ + f0 = AE_ROUND32F48SASYM(AE_SRAA64(a0, shift)); + AE_S32_L_XP(f0, wp, sizeof(int32_t)); + } +} + +#endif /* 32bit coefficients version */ + +#if CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE +void src_polyphase_stage_cir(struct src_stage_prm *s) +{ + /* This function uses + * 1x 64 bit registers + * 16x integers + * 11x address pointers, + */ + ae_int32x2 q; + ae_f32 *rp; + ae_f32 *wp; + int i; + int n; + int m; + int n_wrap_buf; + int n_min; + struct src_state *fir = s->state; + const struct src_stage *cfg = s->stage; + int32_t *fir_end = &fir->fir_delay[fir->fir_delay_size]; + int32_t *out_delay_end = &fir->out_delay[fir->out_delay_size]; + const void *cp; /* Can be int32_t or int16_t */ + const size_t out_size = fir->out_delay_size * sizeof(int32_t); + const int nch = s->nch; + const int nch_x_odm = cfg->odm * nch; + const int blk_in_words = nch * cfg->blk_in; + const int blk_out_words = nch * cfg->num_of_subfilters; + const int sz = sizeof(int32_t); + const int n_sz = -sizeof(int32_t); + const int rewind_sz = sz * nch * (cfg->blk_in + (cfg->num_of_subfilters - 1) * cfg->idm); + const int nch_x_idm_sz = -nch * cfg->idm * sizeof(int32_t); + const int taps_div_4 = cfg->subfilter_length >> 2; + int32_t *x_rptr = (int32_t *)s->x_rptr; + int32_t *y_wptr = (int32_t *)s->y_wptr; + int32_t *x_end_addr = (int32_t *)s->x_end_addr; + int32_t *y_end_addr = (int32_t *)s->y_end_addr; + const size_t subfilter_size = cfg->subfilter_length * SRC_COEF_SIZE; + + for (n = 0; n < s->times; n++) { + /* Input data to filter */ + + /* Setup circular buffer for FIR input data delay */ + AE_SETCBEGIN0(fir->fir_delay); + AE_SETCEND0(fir_end); + + for (m = blk_in_words; m > 0; m -= n_min) { + /* Number of words until circular wrap */ + n_wrap_buf = x_end_addr - x_rptr; + n_min = MIN(m, n_wrap_buf); + for (i = 0; i < n_min; i++) { + /* Load 32 bits sample to accumulator, + * advance pointer, shift left with saturate. + */ + AE_L32_XP(q, (ae_int32 *)x_rptr, sz); + q = AE_SLAA32(q, s->shift); + + /* Store to circular buffer, advance pointer */ + AE_S32_L_XC(q, (ae_int32 *)fir->fir_wp, n_sz); + } + + /* Check for wrap */ + src_inc_wrap(&x_rptr, x_end_addr, s->x_size); + } + + /* Do filter */ + cp = cfg->coefs; /* Reset to 1st coefficient */ + rp = (ae_f32 *)fir->fir_wp; + + /* Do circular modification to pointer rp by amount of + * rewind to data start. Loaded value q is discarded. + */ + AE_L32_XC(q, rp, rewind_sz); + + /* Reset FIR write pointer and compute all polyphase + * sub-filters. + */ + wp = (ae_f32 *)fir->out_rp; + if (nch == 2) { + for (i = 0; i < cfg->num_of_subfilters; i++) { + fir_filter_2ch(rp, cp, wp, taps_div_4, cfg->shift); + wp += nch_x_odm; + cp = (uint8_t *)cp + subfilter_size; + src_inc_wrap((int32_t **)&wp, out_delay_end, out_size); + /* Circular advance pointer rp by number of channels x input + * delay multiplier. Loaded value q is discarded. + */ + AE_L32_XC(q, rp, nch_x_idm_sz); + } + } else { + for (i = 0; i < cfg->num_of_subfilters; i++) { + fir_filter(rp, cp, wp, taps_div_4, cfg->shift, nch); + wp += nch_x_odm; + cp = (uint8_t *)cp + subfilter_size; + src_inc_wrap((int32_t **)&wp, out_delay_end, out_size); + AE_L32_XC(q, rp, nch_x_idm_sz); + } + } + + /* Output */ + + /* Setup circular buffer for SRC out delay access */ + AE_SETCBEGIN0(fir->out_delay); + AE_SETCEND0(out_delay_end); + for (m = blk_out_words; m > 0; m -= n_min) { + n_wrap_buf = y_end_addr - y_wptr; + n_min = MIN(m, n_wrap_buf); + for (i = 0; i < n_min; i++) { + /* Circular load, shift right, linear store, + * and advance read and write pointers. + */ + AE_L32_XC(q, (ae_int32 *)fir->out_rp, sz); + q = AE_SRAA32(q, s->shift); + AE_S32_L_XP(q, (ae_int32 *)y_wptr, sz); + } + + /* Check wrap */ + src_inc_wrap(&y_wptr, y_end_addr, s->y_size); + } + } + s->x_rptr = x_rptr; + s->y_wptr = y_wptr; +} +#endif /* CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE */ + +#if CONFIG_FORMAT_S16LE +void src_polyphase_stage_cir_s16(struct src_stage_prm *s) +{ + /* This function uses + * 2x 64 bit registers + * 16x integers + * 11x address pointers, + */ + ae_int32x2 q = AE_ZERO32(); + ae_int16x4 d = AE_ZERO16(); + ae_f32 *rp; + ae_f32 *wp; + int i; + int n; + int m; + int n_wrap_buf; + int n_min; + + struct src_state *fir = s->state; + const struct src_stage *cfg = s->stage; + int32_t *fir_end = &fir->fir_delay[fir->fir_delay_size]; + int32_t *out_delay_end = &fir->out_delay[fir->out_delay_size]; + const void *cp; /* Can be int32_t or int16_t */ + const size_t out_size = fir->out_delay_size * sizeof(int32_t); + const int nch = s->nch; + const int nch_x_odm = cfg->odm * nch; + const int blk_in_words = nch * cfg->blk_in; + const int blk_out_words = nch * cfg->num_of_subfilters; + const int sz = sizeof(int32_t); + const int n_sz = -sizeof(int32_t); + const int rewind_sz = sz * nch * (cfg->blk_in + (cfg->num_of_subfilters - 1) * cfg->idm); + const int nch_x_idm_sz = -nch * cfg->idm * sizeof(int32_t); + const int taps_div_4 = cfg->subfilter_length >> 2; + int16_t *x_rptr = (int16_t *)s->x_rptr; + int16_t *y_wptr = (int16_t *)s->y_wptr; + int16_t *x_end_addr = (int16_t *)s->x_end_addr; + int16_t *y_end_addr = (int16_t *)s->y_end_addr; + const size_t subfilter_size = cfg->subfilter_length * SRC_COEF_SIZE; + + for (n = 0; n < s->times; n++) { + /* Input data */ + + /* Setup circular buffer for FIR input data delay */ + AE_SETCBEGIN0(fir->fir_delay); + AE_SETCEND0(fir_end); + for (m = blk_in_words; m > 0; m -= n_min) { + /* Number of words without circular wrap */ + n_wrap_buf = x_end_addr - x_rptr; + n_min = (m < n_wrap_buf) ? m : n_wrap_buf; + for (i = 0; i < n_min; i++) { + /* Load a 16 bits sample into d and left shift + * by 16 into q, advance read and write + * pointers. + */ + AE_L16_XP(d, (ae_int16 *)x_rptr, + sizeof(ae_int16)); + q = AE_CVT32X2F16_32(d); + AE_S32_L_XC(q, (ae_int32 *)fir->fir_wp, n_sz); + } + + /* Check for wrap */ + src_inc_wrap_s16(&x_rptr, x_end_addr, s->x_size); + } + + /* Do filter */ + cp = cfg->coefs; /* Reset to 1st coefficient */ + rp = (ae_f32 *)fir->fir_wp; + + /* Do circular modification to pointer rp by amount of + * rewind to data start. Loaded value q is discarded. + */ + AE_L32_XC(q, rp, rewind_sz); + + /* Reset FIR output write pointer and compute all polyphase + * sub-filters. + */ + wp = (ae_f32 *)fir->out_rp; + if (nch == 2) { + for (i = 0; i < cfg->num_of_subfilters; i++) { + fir_filter_2ch(rp, cp, wp, taps_div_4, cfg->shift); + wp += nch_x_odm; + cp = (uint8_t *)cp + subfilter_size; + src_inc_wrap((int32_t **)&wp, out_delay_end, out_size); + /* Circular advance pointer rp by number of channels x input delay + * multiplier. Loaded value q is discarded. + */ + AE_L32_XC(q, rp, nch_x_idm_sz); + } + } else { + for (i = 0; i < cfg->num_of_subfilters; i++) { + fir_filter(rp, cp, wp, taps_div_4, cfg->shift, nch); + wp += nch_x_odm; + cp = (uint8_t *)cp + subfilter_size; + src_inc_wrap((int32_t **)&wp, out_delay_end, out_size); + AE_L32_XC(q, rp, nch_x_idm_sz); + } + } + + /* Output */ + + /* Setup circular buffer for SRC out delay access */ + AE_SETCBEGIN0(fir->out_delay); + AE_SETCEND0(out_delay_end); + for (m = blk_out_words; m > 0; m -= n_min) { + n_wrap_buf = y_end_addr - y_wptr; + n_min = (m < n_wrap_buf) ? m : n_wrap_buf; + for (i = 0; i < n_min; i++) { + /* Circular load for 32 bit sample, + * advance read pointer. + */ + AE_L32_XC(q, (ae_int32 *)fir->out_rp, sz); + + /* Store Q1.31 value as Q1.15 and + * advance write pointer. + */ + d = AE_ROUND16X4F32SSYM(q, q); + AE_S16_0_XP(d, (ae_int16 *)y_wptr, + sizeof(ae_int16)); + } + + /* Check wrap */ + src_inc_wrap_s16(&y_wptr, y_end_addr, s->y_size); + } + } + s->x_rptr = x_rptr; + s->y_wptr = y_wptr; +} +#endif /* CONFIG_FORMAT_S16LE */ + +#endif diff --git a/src/audio/src/src_ipc3.c b/src/audio/src/src_ipc3.c index 175263deae7a..541efcdb24be 100644 --- a/src/audio/src/src_ipc3.c +++ b/src/audio/src/src_ipc3.c @@ -105,7 +105,7 @@ int src_prepare_general(struct processing_module *mod, enum sof_ipc_frame sink_format; /* set align requirements */ - src_set_alignment(source, sink); + src_set_alignment(source); /* get source/sink data format */ source_format = source_get_frm_fmt(source); @@ -113,7 +113,7 @@ int src_prepare_general(struct processing_module *mod, /* 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.", + comp_err(dev, "Source fmt %d and sink fmt %d are different.", source_format, sink_format); ret = -EINVAL; goto out; @@ -139,7 +139,7 @@ int src_prepare_general(struct processing_module *mod, break; #endif /* CONFIG_FORMAT_S32LE */ default: - comp_err(dev, "src_prepare(): invalid format %d", source_format); + comp_err(dev, "invalid format %d", source_format); ret = -EINVAL; goto out; } @@ -158,27 +158,27 @@ int src_init(struct processing_module *mod) struct comp_dev *dev = mod->dev; struct comp_data *cd = NULL; - comp_dbg(dev, "src_init()"); + comp_dbg(dev, "entry"); if (dev->ipc_config.type != SOF_COMP_SRC) { - comp_err(dev, "src_init(): Wrong IPC config type %u", + comp_err(dev, "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 (%zu) init data", + comp_err(dev, "Missing or bad size (%zu) 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"); + comp_err(dev, "SRC sink and source rate are not set"); return -EINVAL; } - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; diff --git a/src/audio/src/src_ipc4.c b/src/audio/src/src_ipc4.c index c1244801d1c1..91f286347a5f 100644 --- a/src/audio/src/src_ipc4.c +++ b/src/audio/src/src_ipc4.c @@ -16,10 +16,12 @@ #include <sof/audio/sink_api.h> #include <sof/audio/source_api.h> #include <sof/audio/sink_source_utils.h> +#include <sof/schedule/ll_schedule_domain.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> #include <rtos/alloc.h> #include <rtos/init.h> +#include <sof/lib/memory.h> #include <sof/lib/uuid.h> #include <sof/list.h> #include <sof/math/numbers.h> @@ -98,17 +100,22 @@ int src_set_params(struct processing_module *mod, struct sof_sink *sink) 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); + if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { + /* 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 + * + * calculate period using 64bit integer to avoid overflows + */ + dev->period = 1000000ULL * sink_get_min_free_space(sink) / + (sink_get_frame_bytes(sink) * sink_get_rate(sink)); + /* align down period to LL cycle time */ + dev->period /= LL_TIMER_PERIOD_US; + dev->period *= LL_TIMER_PERIOD_US; + + comp_info(dev, "SRC DP period calculated as: %u us", dev->period); + } component_set_nearest_period_frames(dev, src_params.rate); /* Update module stream_params */ @@ -144,7 +151,7 @@ int src_prepare_general(struct processing_module *mod, int ret = 0; /* set align requirements */ - src_set_alignment(source, sink); + src_set_alignment(source); switch (cd->ipc_config.base.audio_fmt.valid_bit_depth) { #if CONFIG_FORMAT_S16LE @@ -166,7 +173,7 @@ int src_prepare_general(struct processing_module *mod, break; #endif /* CONFIG_FORMAT_S32LE */ default: - comp_err(dev, "src_prepare(): Invalid depth %d", + comp_err(dev, "Invalid depth %d", cd->ipc_config.base.audio_fmt.depth); ret = -EINVAL; goto out; @@ -179,28 +186,30 @@ int src_prepare_general(struct processing_module *mod, return ret; } -int src_init(struct processing_module *mod) +__cold 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()"); + assert_can_be_cold(); + + comp_dbg(dev, "entry"); if (!cfg->init_data || cfg->size != sizeof(cd->ipc_config)) { - comp_err(dev, "src_init(): Missing or bad size (%u) init data", + comp_err(dev, "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"); + comp_err(dev, "SRC sink and source rate are not set"); return -EINVAL; } - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -212,10 +221,10 @@ int src_init(struct processing_module *mod) cd->polyphase_func = NULL; src_polyphase_reset(&cd->src); - comp_dbg(dev, "src_init(), channels_count = %d, depth = %d", + comp_dbg(dev, "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", + comp_dbg(dev, "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; @@ -229,9 +238,8 @@ int src_init(struct processing_module *mod) cd->sample_container_bytes = sizeof(int32_t); break; default: - comp_err(dev, "src_init(): Illegal sample depth %d", + comp_err(dev, "Illegal sample depth %d", cd->ipc_config.base.audio_fmt.depth); - rfree(cd); return -EINVAL; } diff --git a/src/audio/src/src_lite.c b/src/audio/src/src_lite.c index 35423dad9225..9d5593ff34ca 100644 --- a/src/audio/src/src_lite.c +++ b/src/audio/src/src_lite.c @@ -27,7 +27,7 @@ static int src_lite_prepare(struct processing_module *mod, struct src_param *a = &cd->param; int ret; - comp_info(mod->dev, "src_prepare()"); + comp_info(mod->dev, "entry"); if (num_of_sources != 1 || num_of_sinks != 1) return -EINVAL; @@ -43,8 +43,11 @@ static int src_lite_prepare(struct processing_module *mod, if (ret < 0) return ret; - a->stage1 = src_table1[a->idx_out][a->idx_in]; - a->stage2 = src_table2[a->idx_out][a->idx_in]; + ret = src_allocate_copy_stages(mod, a, + src_table1[a->idx_out][a->idx_in], + src_table2[a->idx_out][a->idx_in]); + if (ret < 0) + return ret; ret = src_params_general(mod, sources[0], sinks[0]); if (ret < 0) @@ -58,8 +61,6 @@ const struct module_interface src_lite_interface = { .prepare = src_lite_prepare, .process = src_process, .is_ready_to_process = src_is_ready_to_process, - .set_configuration = src_set_config, - .get_configuration = src_get_config, .reset = src_reset, .free = src_free, }; @@ -68,5 +69,7 @@ SOF_DEFINE_REG_UUID(src_lite); DECLARE_TR_CTX(src_lite_tr, SOF_UUID(src_lite_uuid), LOG_LEVEL_INFO); +#if !CONFIG_COMP_SRC_MODULE DECLARE_MODULE_ADAPTER(src_lite_interface, src_lite_uuid, src_lite_tr); SOF_MODULE_INIT(src_lite, sys_comp_module_src_lite_interface_init); +#endif diff --git a/src/audio/src/tune/sof_src_generate.m b/src/audio/src/tune/sof_src_generate.m index 3cccea514d89..85f79c94c9f6 100644 --- a/src/audio/src/tune/sof_src_generate.m +++ b/src/audio/src/tune/sof_src_generate.m @@ -49,6 +49,11 @@ error('Sample rates in/out matrix size mismatch!'); end +if exist('OCTAVE_VERSION', 'builtin') + pkg load signal +end + + %% Exported coefficients type int16, int24, int32, float switch cfg.ctype diff --git a/src/audio/src/tune/sof_src_ipc4_int32.m b/src/audio/src/tune/sof_src_ipc4_int32.m index e1563b37cfaa..6729d48e84d0 100644 --- a/src/audio/src/tune/sof_src_ipc4_int32.m +++ b/src/audio/src/tune/sof_src_ipc4_int32.m @@ -2,29 +2,32 @@ % SPDX-License-Identifier: BSD-3-Clause % -% Copyright(c) 2022 Intel Corporation. All rights reserved. +% Copyright(c) 2022-2025 Intel Corporation. fs1 = [ 8 11.025 12 16 18.9 22.05 24 32 37.8 44.1 48 64 88.2 96 176.4 192 ] * 1e3; - -fs2 = [8 16 24 32 44.1 48 88.2 96 176.4 192] * 1e3; +fs2 = [ 8 11.025 16 22.05 24 32 44.1 48 64 88.2 96 176.4 192 ] * 1e3; fs_matrix = [ - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 0 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 0 0 1 0 1 1 0 0 0 0 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 0 0 0 0 1 1 1 1 0 0 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 +% 1 1 +% 1 1 2 2 3 4 4 6 8 9 7 9 +% 8 1 6 2 4 2 4 8 4 8 6 6 2 +% + 1 0 1 0 1 1 1 1 1 1 1 1 1 % 8 + 1 0 1 0 1 1 1 1 1 1 1 1 0 % 11 + 1 0 1 0 1 1 1 1 1 1 1 1 1 % 12 + 1 0 1 0 1 1 1 1 1 1 1 1 1 % 16 + 0 0 0 0 1 0 1 1 0 0 0 0 0 % 18.9 + 1 0 1 0 1 1 1 1 1 1 1 1 1 % 22.05 + 1 0 1 0 1 1 1 1 1 1 1 1 1 % 24 + 1 0 1 0 1 1 1 1 1 1 1 1 1 % 32 + 0 0 0 0 0 0 1 1 0 1 1 0 0 % 37.8 + 1 0 1 0 1 1 1 1 1 1 1 1 1 % 44.1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 % 48 + 1 0 1 0 1 1 1 1 1 1 1 1 1 % 64 + 1 0 1 0 1 1 1 1 1 1 1 1 1 % 88.2 + 1 1 1 1 1 1 1 1 1 1 1 1 1 % 96 + 1 0 1 0 1 1 1 1 1 1 1 1 1 % 176.4 + 1 0 1 0 1 1 1 1 1 1 1 1 1 % 192 ]; cfg.ctype = 'int32'; diff --git a/src/audio/src/tune/src_export_coef.m b/src/audio/src/tune/src_export_coef.m index 873a3cb147cb..a8c8fcd4c9dd 100644 --- a/src/audio/src/tune/src_export_coef.m +++ b/src/audio/src/tune/src_export_coef.m @@ -83,7 +83,7 @@ src.blk_in, src.blk_out, src.halfband, ... src.gain, vfn); case { 'int16' 'int24' 'int32' } - fprintf(fh, 'const struct src_stage %s = {\n', sfn); + fprintf(fh, 'static const struct src_stage %s = {\n', sfn); fprintf(fh, '\t%d, %d, %d, %d, %d, %d, %d, %d, %d,\n\t%s};\n', ... src.idm, src.odm, src.num_of_subfilters, ... src.subfilter_length, src.filter_length, ... @@ -100,7 +100,7 @@ end function print_int_coef(src, fh, vtype, vfn, nbits) - fprintf(fh, 'const %s %s[%d] = {\n', ... + fprintf(fh, '__cold_rodata static const %s %s[%d] = {\n', ... vtype, vfn, src.filter_length); cint = coef_quant(src, nbits); diff --git a/src/audio/src/tune/src_export_table_2s.m b/src/audio/src/tune/src_export_table_2s.m index 108614596268..34342b2ca069 100644 --- a/src/audio/src/tune/src_export_table_2s.m +++ b/src/audio/src/tune/src_export_table_2s.m @@ -97,29 +97,29 @@ fprintf(fh, '/* SRC table */\n'); switch ctype case 'float' - fprintf(fh, 'const %s fir_one = 1.0;\n', vtype); - fprintf(fh, 'const struct src_stage src_double_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, 1.0, &fir_one };\n'); - fprintf(fh, 'const struct src_stage src_double_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0.0, &fir_one };\n'); + fprintf(fh, 'static const %s fir_one = 1.0;\n', vtype); + fprintf(fh, 'static const struct src_stage src_double_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, 1.0, &fir_one };\n'); + fprintf(fh, 'static const struct src_stage src_double_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0.0, &fir_one };\n'); case 'int16' scale16 = 2^15; - fprintf(fh, 'const %s fir_one = %d;\n', vtype, round(scale16*0.5)); - fprintf(fh, 'const struct src_stage src_int16_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n'); - fprintf(fh, 'const struct src_stage src_int16_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n'); + fprintf(fh, 'static const %s fir_one = %d;\n', vtype, round(scale16*0.5)); + fprintf(fh, 'static const struct src_stage src_int16_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n'); + fprintf(fh, 'static const struct src_stage src_int16_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n'); case 'int24' scale24 = 2^23; - fprintf(fh, 'const %s fir_one = %d;\n', vtype, round(scale24*0.5)); - fprintf(fh, 'const struct src_stage src_int24_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n'); - fprintf(fh, 'const struct src_stage src_int24_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n'); + fprintf(fh, 'static const %s fir_one = %d;\n', vtype, round(scale24*0.5)); + fprintf(fh, 'static const struct src_stage src_int24_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n'); + fprintf(fh, 'static const struct src_stage src_int24_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n'); case 'int32' scale32 = 2^31; - fprintf(fh, 'const %s fir_one = %d;\n', vtype, round(scale32*0.5)); - fprintf(fh, 'const struct src_stage src_int32_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n'); - fprintf(fh, 'const struct src_stage src_int32_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n'); + fprintf(fh, 'static const %s fir_one = %d;\n', vtype, round(scale32*0.5)); + fprintf(fh, 'static const struct src_stage src_int32_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n'); + fprintf(fh, 'static const struct src_stage src_int32_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n'); otherwise error('Unknown coefficient type!'); end -fprintf(fh, 'const int src_in_fs[%d] = {', n_in); +fprintf(fh, 'static const int src_in_fs[%d] = {', n_in); j = 1; for i=1:n_in fprintf(fh, ' %d', fs_in(i)); @@ -134,7 +134,7 @@ end fprintf(fh, '};\n'); -fprintf(fh, 'const int src_out_fs[%d] = {', n_out); +fprintf(fh, 'static const int src_out_fs[%d] = {', n_out); j = 1; for i=1:n_out fprintf(fh, ' %d', fs_out(i)); @@ -150,7 +150,7 @@ fprintf(fh, '};\n'); for n = 1:2 - fprintf(fh, 'const struct src_stage * const src_table%d[%d][%d] = {\n', ... + fprintf(fh, 'static const struct src_stage * const src_table%d[%d][%d] = {\n', ... n, n_out, n_in); i = 1; for b = 1:n_out diff --git a/src/audio/stft_process/CMakeLists.txt b/src/audio/stft_process/CMakeLists.txt new file mode 100644 index 000000000000..e3a13e17bb93 --- /dev/null +++ b/src/audio/stft_process/CMakeLists.txt @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_COMP_STFT_PROCESS STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/stft_process_llext) + add_dependencies(app stft_process) +else() + add_local_sources(sof stft_process.c) + add_local_sources(sof stft_process_setup.c) + add_local_sources(sof stft_process_common.c) + add_local_sources(sof stft_process-generic.c) + add_local_sources(sof stft_process-hifi3.c) + + if(CONFIG_IPC_MAJOR_4) + add_local_sources(sof stft_process-ipc4.c) + endif() +endif() diff --git a/src/audio/stft_process/Kconfig b/src/audio/stft_process/Kconfig new file mode 100644 index 000000000000..426d272477a9 --- /dev/null +++ b/src/audio/stft_process/Kconfig @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config COMP_STFT_PROCESS + tristate "STFT processing component" + default n + select MATH_FFT + select MATH_32BIT_FFT + select MATH_FFT_MULTI + help + Select for stft_process component. STFT acronym means + short term Fourier transform. It converts audio + to multiple FFTs with selected FFT size, hop, and + window function. Possible signal processing can be + done in it in frequency domain for FFTs that is + efficient for more complex signal processing techniques. + The component converts then the frequency domain + version of signal back to normal PCM audio stream + with inverse STFT. + +if COMP_STFT_PROCESS + +rsource "Kconfig.simd" + +config STFT_PROCESS_MAGNITUDE_PHASE + bool "Convert FFTs to polar magnitude and phase" + default n + help + Select for processing in polar magnitude and phase + domain. Such complex values format is common for + frequency domain signal processing. + +endif # COMP_STFT_PROCESS diff --git a/src/audio/stft_process/Kconfig.simd b/src/audio/stft_process/Kconfig.simd new file mode 100644 index 000000000000..0b981df583fa --- /dev/null +++ b/src/audio/stft_process/Kconfig.simd @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: BSD-3-Clause + +comment "STFT Process optimization level select" + +choice "COMP_STFT_PROCESS_SIMD_LEVEL_SELECT" + prompt "Choose which SIMD level is used for the STFT Process module" + depends on COMP_STFT_PROCESS + default COMP_STFT_PROCESS_HIFI_MAX + + config COMP_STFT_PROCESS_HIFI_MAX + prompt "SIMD will be selected by toolchain pre-defined header" + bool + help + When this is selected, the optimization level will be + determined by the toolchain pre-defined macros in the + core isa header file. + + config COMP_STFT_PROCESS_HIFI_3 + prompt "Choose HIFI3 intrinsic optimized STFT Process module" + bool + help + This option is used to build HIFI3 intrinsic optimized + STFT Process code. + + config COMP_STFT_PROCESS_HIFI_NONE + prompt "Choose generic C STFT Process module, no HIFI SIMD involved" + bool + help + This option is used to build STFT Process + with generic C code. +endchoice diff --git a/src/audio/stft_process/README.md b/src/audio/stft_process/README.md new file mode 100644 index 000000000000..074b2c0cf331 --- /dev/null +++ b/src/audio/stft_process/README.md @@ -0,0 +1,14 @@ +# STFT Process Architecture + +This directory provides Short-Time Fourier Transform (STFT) utilities. + +## Overview + +Converts time-domain audio slices into the frequency domain using FFTs, runs frequency-domain processing over those bins, and applies the inverse-STFT (Overlap-Add) back to the time-domain. + +## Configuration and Scripts + +- **Kconfig**: Manages the STFT processing component (`COMP_STFT_PROCESS`) and requires multi-channel 32-bit FFT math libraries (`MATH_FFT`, `MATH_32BIT_FFT`, `MATH_FFT_MULTI`). Also optionally supports converting pure FFTs into polar magnitude and phase domains (`STFT_PROCESS_MAGNITUDE_PHASE`). +- **CMakeLists.txt**: Compiles generic STFT operations (`stft_process.c`, `stft_process_common.c`, `stft_process-generic.c`) and IPC4 wrappers (`stft_process-ipc4.c`), fully supporting the `llext` format. +- **stft_process.toml**: Defines the default `STFTPROC` module layout with UUID `UUIDREG_STR_STFT_PROCESS`. +- **Topology (.conf)**: Instantiated from `tools/topology/topology2/include/components/stft_process.conf`, creating a `stft_process` widget type `effect` (UUID `a6:6e:11:0d:50:91:de:46:98:b8:b2:b3:a7:91:da:29`). diff --git a/src/audio/stft_process/llext/CMakeLists.txt b/src/audio/stft_process/llext/CMakeLists.txt new file mode 100644 index 000000000000..133330c4a69d --- /dev/null +++ b/src/audio/stft_process/llext/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +sof_llext_build("stft_process" + SOURCES ../stft_process.c + ../stft_process_setup.c + ../stft_process_common.c + ../stft_process-generic.c + ../stft_process-ipc4.c + LIB openmodules +) diff --git a/src/audio/stft_process/llext/llext.toml.h b/src/audio/stft_process/llext/llext.toml.h new file mode 100644 index 000000000000..e3988e4bb4ed --- /dev/null +++ b/src/audio/stft_process/llext/llext.toml.h @@ -0,0 +1,6 @@ +#include <tools/rimage/config/platform.toml> +#define LOAD_TYPE "2" +#include "../stft_process.toml" + +[module] +count = __COUNTER__ diff --git a/src/audio/stft_process/stft_process-generic.c b/src/audio/stft_process/stft_process-generic.c new file mode 100644 index 000000000000..5241c372261f --- /dev/null +++ b/src/audio/stft_process/stft_process-generic.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025-2026 Intel Corporation. + +#include <sof/audio/format.h> +#include <sof/common.h> +#include <assert.h> +#include <stdint.h> +#include "stft_process.h" + +#if SOF_USE_HIFI(NONE, COMP_STFT_PROCESS) +void stft_process_overlap_add_ifft_buffer(struct stft_process_state *state, int ch) +{ + struct stft_process_buffer *obuf = &state->obuf[ch]; + struct stft_process_fft *fft = &state->fft; + int32_t *w = obuf->w_ptr; + int32_t sample; + int i; + int n; + int samples_remain = fft->fft_size; + int idx = 0; + + while (samples_remain) { + n = stft_process_buffer_samples_without_wrap(obuf, w); + n = MIN(samples_remain, n); + + /* Abort if n is zero to avoid infinite loop. The assert can + * trigger only with incorrect usage of this function. + */ + assert(n); + for (i = 0; i < n; i++) { + sample = Q_MULTSR_32X32((int64_t)state->gain_comp, fft->fft_buf[idx].real, + 31, 31, 31); + *w = sat_int32((int64_t)*w + sample); + w++; + idx++; + } + w = stft_process_buffer_wrap(obuf, w); + samples_remain -= n; + } + + w = obuf->w_ptr + fft->fft_hop_size; + obuf->w_ptr = stft_process_buffer_wrap(obuf, w); + obuf->s_avail += fft->fft_hop_size; + obuf->s_free -= fft->fft_hop_size; +} + +void stft_process_apply_window(struct stft_process_state *state) +{ + struct stft_process_fft *fft = &state->fft; + int j; + + /* Multiply Q1.31 by Q1.15 gives Q2.46, shift right by 15 to get Q2.31, no saturate need */ + for (j = 0; j < fft->fft_size; j++) + fft->fft_buf[j].real = + sat_int32(Q_MULTSR_32X32((int64_t)fft->fft_buf[j].real, + state->window[j], 31, 31, 31)); +} +#endif /* SOF_USE_HIFI(NONE, COMP_STFT_PROCESS) */ diff --git a/src/audio/stft_process/stft_process-hifi3.c b/src/audio/stft_process/stft_process-hifi3.c new file mode 100644 index 000000000000..6cf7c3dc7e85 --- /dev/null +++ b/src/audio/stft_process/stft_process-hifi3.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025-2026 Intel Corporation. + +/** + * \file + * \brief HiFi3 SIMD-optimized helpers for the STFT processing component. + * + * This compilation unit provides HiFi3 intrinsic versions of selected + * hot-path helpers. It is guarded by SOF_USE_MIN_HIFI(3, COMP_STFT_PROCESS) + * so only one of the generic or hifi implementations is active. + */ + +#include <sof/audio/format.h> +#include <sof/common.h> +#include <assert.h> +#include <stdint.h> +#include "stft_process.h" + +#if SOF_USE_MIN_HIFI(3, COMP_STFT_PROCESS) + +#include <xtensa/tie/xt_hifi3.h> + +/** + * stft_process_apply_window() - Multiply FFT buffer by the analysis window. + * @state: STFT processing state that contains the FFT buffer and window. + * + * The real part of each icomplex32 sample in the FFT buffer is multiplied + * by the corresponding Q1.31 window coefficient. + */ +void stft_process_apply_window(struct stft_process_state *state) +{ + struct stft_process_fft *fft = &state->fft; + ae_int32 *buf; + const ae_int32x2 *win; + ae_f32x2 data01, data23; + ae_f32x2 win01, win23; + ae_int32x2 d0, d1; + int fft_size = fft->fft_size; + int j; + int n4; + + /* + * buf points to {real, imag} pairs (struct icomplex32). + * win points to scalar Q1.31 window coefficients. + * + * We load each complex pair, multiply only the real part by the + * window value, then store the pair back with the updated real. + * The imaginary part is left untouched. + * + * Stride for buf is sizeof(ae_int32x2) = 8 bytes per complex sample. + * Stride for win is sizeof(ae_int32) = 4 bytes per scalar window value. + */ + buf = (ae_int32 *)fft->fft_buf; + win = (const ae_int32x2 *)state->window; + + assert(!(fft_size & 3)); + + /* Main loop: process 4 samples per iteration */ + n4 = fft_size >> 2; + for (j = 0; j < n4; j++) { + /* Load four FFT real part values, combine into fft_data, + * buf[0] goes to data01 low, buf[1] goes to data01 high. + */ + d0 = AE_L32_I(buf, 0 * sizeof(ae_int32x2)); + d1 = AE_L32_I(buf, 1 * sizeof(ae_int32x2)); + data01 = AE_SEL32_HH(d0, d1); + d0 = AE_L32_I(buf, 2 * sizeof(ae_int32x2)); + d1 = AE_L32_I(buf, 3 * sizeof(ae_int32x2)); + data23 = AE_SEL32_HH(d0, d1); + + /* Load four window coefficients, + * win[0] goes to win01 low, win[1] goes to win01 high + */ + AE_L32X2_IP(win01, win, sizeof(ae_int32x2)); + AE_L32X2_IP(win23, win, sizeof(ae_int32x2)); + + /* Multiply with window function */ + data01 = AE_MULFP32X2RS(data01, win01); + data23 = AE_MULFP32X2RS(data23, win23); + + /* Store back the updated real parts */ + AE_S32_L_IP(AE_SEL32_LH(data01, data01), buf, sizeof(ae_int32x2)); + AE_S32_L_IP(data01, buf, sizeof(ae_int32x2)); + AE_S32_L_IP(AE_SEL32_LH(data23, data23), buf, sizeof(ae_int32x2)); + AE_S32_L_IP(data23, buf, sizeof(ae_int32x2)); + } +} + +/** + * stft_process_overlap_add_ifft_buffer() - Overlap-add IFFT output to circular output buffer. + * @state: STFT processing state. + * @ch: Channel index. + * + * Each IFFT output sample is multiplied by gain_comp (Q1.31 x Q1.31) and + * added with saturation to the existing content of the circular output + * buffer. HiFi3 AE_MULF32S_HH handles the multiply and + * AE_ADD32S provides the saturating accumulation. + * + * Note: obuf must be even number of samples and 64-bit aligned. + */ +void stft_process_overlap_add_ifft_buffer(struct stft_process_state *state, int ch) +{ + struct stft_process_buffer *obuf = &state->obuf[ch]; + struct stft_process_fft *fft = &state->fft; + ae_f32x2 gain = AE_MOVDA32(state->gain_comp); + ae_f32x2 buffer_data; + ae_f32x2 fft_data; + ae_f32x2 d0, d1; + ae_f32x2 *w = (ae_f32x2 *)obuf->w_ptr; + ae_f32 *fft_p = (ae_f32 *)fft->fft_buf; + int samples_remain = fft->fft_size; + int i, n; + + while (samples_remain) { + n = stft_process_buffer_samples_without_wrap(obuf, (int32_t *)w); + + /* The samples count must be even and not zero, the latter to avoid infinite + * loop. The assert can trigger only with incorrect usage of this function. + */ + assert(n && !(n & 1)); + n = MIN(samples_remain, n) >> 1; + for (i = 0; i < n; i++) { + /* Load two FFT real part values, combine into fft_data */ + AE_L32_IP(d0, fft_p, sizeof(ae_f32x2)); + AE_L32_IP(d1, fft_p, sizeof(ae_f32x2)); + fft_data = AE_SEL32_HH(d0, d1); + + /* Load buffer data, multiply fft_data with gain and accumulate, and + * store to output buffer. + */ + buffer_data = AE_L32X2_I(w, 0); + AE_MULAFP32X2RS(buffer_data, fft_data, gain); + AE_S32X2_IP(buffer_data, w, sizeof(ae_f32x2)); + } + w = (ae_f32x2 *)stft_process_buffer_wrap(obuf, (int32_t *)w); + samples_remain -= n << 1; + } + + obuf->w_ptr = stft_process_buffer_wrap(obuf, obuf->w_ptr + fft->fft_hop_size); + obuf->s_avail += fft->fft_hop_size; + obuf->s_free -= fft->fft_hop_size; +} + +#endif /* SOF_USE_MIN_HIFI(3, COMP_STFT_PROCESS) */ diff --git a/src/audio/stft_process/stft_process-ipc4.c b/src/audio/stft_process/stft_process-ipc4.c new file mode 100644 index 000000000000..ac6d9b5e56b5 --- /dev/null +++ b/src/audio/stft_process/stft_process-ipc4.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include "stft_process.h" + +LOG_MODULE_DECLARE(stft_process, CONFIG_SOF_LOG_LEVEL); + +/* IPC4 controls handler */ +__cold int stft_process_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 stft_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + + assert_can_be_cold(); + + switch (param_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + comp_err(dev, "Illegal control param_id %d.", param_id); + return -EINVAL; + } + + if (fragment_size != sizeof(struct sof_stft_process_config)) { + comp_err(dev, "Illegal fragment size %d, expect %d.", fragment_size, + sizeof(struct sof_stft_process_config)); + return -EINVAL; + } + + if (!cd->config) { + cd->config = mod_alloc(mod, sizeof(struct sof_stft_process_config)); + if (!cd->config) { + comp_err(dev, "Failed to allocate configuration."); + return -ENOMEM; + } + } + + memcpy_s(cd->config, sizeof(struct sof_stft_process_config), fragment, fragment_size); + return 0; +} + +/* Not used in IPC4 systems, if IPC4 only component, omit .get_configuration set */ +__cold int stft_process_get_config(struct processing_module *mod, uint32_t config_id, + uint32_t *data_offset_size, uint8_t *fragment, + size_t fragment_size) +{ + assert_can_be_cold(); + return 0; +} diff --git a/src/audio/stft_process/stft_process.c b/src/audio/stft_process/stft_process.c new file mode 100644 index 000000000000..5fb96a267f15 --- /dev/null +++ b/src/audio/stft_process/stft_process.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/source_api.h> +#include <rtos/init.h> +#include "stft_process.h" + +/* UUID identifies the components. Use e.g. command uuidgen from package + * uuid-runtime, add it to uuid-registry.txt in SOF top level. + */ +SOF_DEFINE_REG_UUID(stft_process); + +/* Creates logging data for the component */ +LOG_MODULE_REGISTER(stft_process, CONFIG_SOF_LOG_LEVEL); + +#if STFT_DEBUG +FILE *stft_debug_fft_in_fh; +FILE *stft_debug_fft_out_fh; +FILE *stft_debug_ifft_out_fh; +#endif + +/** + * stft_process_init() - Initialize the stft_process component. + * @mod: Pointer to module data. + * + * This function is called when the instance is created. The + * macro __cold informs that the code that is non-critical + * is loaded to slower but large DRAM. + * + * Return: Zero if success, otherwise error code. + */ +__cold static int stft_process_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct comp_dev *dev = mod->dev; + struct stft_comp_data *cd; + + assert_can_be_cold(); + + comp_info(dev, "entry"); + + cd = mod_alloc(mod, sizeof(*cd)); + if (!cd) + return -ENOMEM; + + md->private = cd; + memset(cd, 0, sizeof(*cd)); + +#if STFT_DEBUG + stft_debug_fft_in_fh = fopen("stft_debug_fft_in.txt", "w"); + if (!stft_debug_fft_in_fh) { + fprintf(stderr, "Debug file open failed.\n"); + return -EINVAL; + } + + stft_debug_fft_out_fh = fopen("stft_debug_fft_out.txt", "w"); + if (!stft_debug_fft_out_fh) { + fprintf(stderr, "Debug file open failed.\n"); + return -EINVAL; + } + + stft_debug_ifft_out_fh = fopen("stft_debug_ifft_out.txt", "w"); + if (!stft_debug_ifft_out_fh) { + fprintf(stderr, "Debug file open failed.\n"); + fclose(stft_debug_fft_out_fh); + return -EINVAL; + } +#endif + + return 0; +} + +/** + * stft_process_process() - The audio data processing function. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * This is the processing function that is called for scheduled + * pipelines. The processing is controlled by the enable switch. + * + * Return: Zero if success, otherwise error code. + */ +static int stft_process_process(struct processing_module *mod, + struct sof_source **sources, + int num_of_sources, + struct sof_sink **sinks, + int num_of_sinks) +{ + struct stft_comp_data *cd = module_get_private_data(mod); + struct sof_source *source = sources[0]; /* One input in this example */ + struct sof_sink *sink = sinks[0]; /* One output in this example */ + int frames = source_get_data_frames_available(source); + int sink_frames = sink_get_free_frames(sink); + int ret; + + frames = MIN(frames, sink_frames); + + /* Process the data with the channels swap example function. */ + ret = cd->stft_process_func(mod, source, sink, frames); + + return ret; +} + +/** + * stft_process_prepare() - Prepare the component for processing. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * Function prepare is called just before the pipeline is started. In + * this case the audio format parameters are for better code performance + * saved to component data to avoid to find out them in process. The + * processing function pointer is set to process the current audio format. + * + * Return: Value zero if success, otherwise error code. + */ +static int stft_process_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct stft_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + enum sof_ipc_frame source_format; + int ret; + + comp_dbg(dev, "prepare"); + + /* The processing example in this component supports one input and one + * output. Generally there can be more. + */ + if (num_of_sources != 1 || num_of_sinks != 1) { + comp_err(dev, "Only one source and one sink is supported."); + return -EINVAL; + } + + /* Initialize STFT, max_frames is set to dev->frames + 4 */ + if (!cd->config) { + comp_err(dev, "Can't prepare without bytes control configuration."); + return -EINVAL; + } + + /* get source data format */ + cd->max_frames = dev->frames + 2; + cd->frame_bytes = source_get_frame_bytes(sources[0]); + cd->channels = source_get_channels(sources[0]); + source_format = source_get_frm_fmt(sources[0]); + + ret = stft_process_setup(mod, cd->max_frames, source_get_rate(sources[0]), + source_get_channels(sources[0])); + if (ret < 0) { + comp_err(dev, "setup failed."); + return ret; + } + + cd->stft_process_func = stft_process_find_proc_func(source_format); + if (!cd->stft_process_func) { + comp_err(dev, "No processing function found for format %d.", + source_format); + return -EINVAL; + } + + return 0; +} + +/** + * stft_process_reset() - Reset the component. + * @mod: Pointer to module data. + * + * The component reset is called when pipeline is stopped. The reset + * should return the component to same state as init. + * + * Return: Value zero, always success. + */ +static int stft_process_reset(struct processing_module *mod) +{ + struct stft_comp_data *cd = module_get_private_data(mod); + + comp_dbg(mod->dev, "reset"); + + stft_process_free_buffers(mod); + memset(cd, 0, sizeof(*cd)); + return 0; +} + +/** + * stft_process_free() - Free dynamic allocations. + * @mod: Pointer to module data. + * + * Component free is called when the pipelines are deleted. All + * dynamic allocations need to be freed here. The macro __cold + * instructs the build to locate this performance wise non-critical + * function to large and slower DRAM. + * + * Return: Value zero, always success. + */ +__cold static int stft_process_free(struct processing_module *mod) +{ + struct stft_comp_data *cd = module_get_private_data(mod); + + assert_can_be_cold(); + + comp_dbg(mod->dev, "free"); + mod_free(mod, cd); + +#if STFT_DEBUG + fclose(stft_debug_fft_in_fh); + fclose(stft_debug_fft_out_fh); + fclose(stft_debug_ifft_out_fh); +#endif + return 0; +} + +/* This defines the module operations */ +static const struct module_interface stft_process_interface = { + .init = stft_process_init, + .prepare = stft_process_prepare, + .process = stft_process_process, + .set_configuration = stft_process_set_config, + .get_configuration = stft_process_get_config, + .reset = stft_process_reset, + .free = stft_process_free +}; + +/* This controls build of the module. If COMP_MODULE is selected in kconfig + * this is build as dynamically loadable module. + */ +#if CONFIG_COMP_STFT_PROCESS_MODULE + +#include <module/module/api_ver.h> +#include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> + +static const struct sof_man_module_manifest mod_manifest __section(".module") __used = + SOF_LLEXT_MODULE_MANIFEST("STFT_PROCESS", &stft_process_interface, 1, + SOF_REG_UUID(stft_process), 40); + +SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_TR_CTX(stft_process_tr, SOF_UUID(stft_process_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(stft_process_interface, stft_process_uuid, stft_process_tr); +SOF_MODULE_INIT(stft_process, sys_comp_module_stft_process_interface_init); + +#endif diff --git a/src/audio/stft_process/stft_process.h b/src/audio/stft_process/stft_process.h new file mode 100644 index 000000000000..558023ba55bc --- /dev/null +++ b/src/audio/stft_process/stft_process.h @@ -0,0 +1,339 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + * + */ +#ifndef __SOF_AUDIO_STFT_PROCESS_H__ +#define __SOF_AUDIO_STFT_PROCESS_H__ + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/math/auditory.h> +#include <sof/math/dct.h> +#include <sof/math/fft.h> + +#include <stdbool.h> +#include <stdint.h> + +#if CONFIG_LIBRARY +#define STFT_DEBUG 0 /* Keep zero, produces large files with fprintf() */ +#else +#define STFT_DEBUG 0 +#endif + +#define SOF_STFT_PROCESS_CONFIG_MAX_SIZE 256 /* Max size for configuration data in bytes */ + +enum sof_stft_process_fft_pad_type { + STFT_PAD_END = 0, + STFT_PAD_CENTER = 1, + STFT_PAD_START = 2, +}; + +enum sof_stft_process_fft_window_type { + STFT_RECTANGULAR_WINDOW = 0, + STFT_BLACKMAN_WINDOW = 1, + STFT_HAMMING_WINDOW = 2, + STFT_HANN_WINDOW = 3, + STFT_POVEY_WINDOW = 4, +}; + +struct sof_stft_process_config { + uint32_t size; /**< Size of this struct in bytes */ + uint32_t reserved[8]; + int32_t sample_frequency; /**< Hz. e.g. 16000 */ + int32_t window_gain_comp; /**< Q1.31 gain for IFFT */ + int32_t reserved_32; + int16_t channel; /**< -1 expect mono, 0 left, 1 right, ... */ + int16_t frame_length; /**< samples, e.g. 400 for 25 ms @ 16 kHz*/ + int16_t frame_shift; /**< samples, e.g. 160 for 10 ms @ 16 kHz */ + int16_t reserved_16; + enum sof_stft_process_fft_pad_type pad; /**< Use PAD_END, PAD_CENTER, PAD_START */ + enum sof_stft_process_fft_window_type window; /**< Use RECTANGULAR_WINDOW, etc. */ +} __attribute__((packed)); + +struct stft_process_buffer { + int32_t *addr; + int32_t *end_addr; + int32_t *r_ptr; + int32_t *w_ptr; + int s_avail; /**< samples count */ + int s_free; /**< samples count */ + int s_length; /**< length in samples for wrap */ +}; + +struct stft_process_fft { + struct icomplex32 *fft_buf; /**< fft_padded_size */ + struct icomplex32 *fft_out; /**< fft_padded_size */ + struct ipolar32 *fft_polar; + struct fft_multi_plan *fft_plan; + struct fft_multi_plan *ifft_plan; + int fft_size; + int fft_padded_size; + int fft_hop_size; + int fft_buf_size; + int half_fft_size; + size_t fft_buffer_size; /**< bytes */ +}; + +struct stft_process_state { + struct stft_process_buffer ibuf[PLATFORM_MAX_CHANNELS]; /**< Buffer for input data */ + struct stft_process_buffer obuf[PLATFORM_MAX_CHANNELS]; /**< Buffer for output data */ + struct stft_process_fft fft; /**< FFT related */ + int32_t *prev_data[PLATFORM_MAX_CHANNELS]; /**< prev_data_size */ + int32_t gain_comp; /**< Gain to compensate window gain */ + int32_t *buffers; + int32_t *window; /**< fft_size */ + int source_channel; + int prev_data_size; + int sample_rate; + bool waiting_fill; /**< booleans */ + bool prev_samples_valid; +}; + +/** + * struct stft_process_func - Function call pointer for process function + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + */ +typedef int (*stft_process_func)(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames); + +/** + * struct stft_comp_data + * @stft_process_func: Pointer to used processing function. + * @channels_order[]: Vector with desired sink channels order. + * @source_format: Source samples format. + * @frame_bytes: Number of bytes in an audio frame. + * @channels: Channels count. + * @enable: Control processing on/off, on - reorder channels + */ +struct stft_comp_data { + stft_process_func stft_process_func; /**< processing function */ + struct stft_process_state state; + struct sof_stft_process_config *config; + size_t frame_bytes; + int source_channel; + int max_frames; + int channels; + bool fft_done; +}; + +static inline int stft_process_buffer_samples_without_wrap(struct stft_process_buffer *buffer, + int32_t *ptr) +{ + return buffer->end_addr - ptr; +} + +static inline int32_t *stft_process_buffer_wrap(struct stft_process_buffer *buffer, int32_t *ptr) +{ + if (ptr >= buffer->end_addr) + ptr -= buffer->s_length; + + return ptr; +} + +/** + * struct stft_process_proc_fnmap - processing functions for frame formats + * @frame_fmt: Current frame format + * @stft_process_proc_func: Function pointer for the suitable processing function + */ +struct stft_process_proc_fnmap { + enum sof_ipc_frame frame_fmt; + stft_process_func stft_process_function; +}; + +/** + * stft_process_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +stft_process_func stft_process_find_proc_func(enum sof_ipc_frame src_fmt); + +#if CONFIG_IPC_MAJOR_4 +/** + * stft_process_set_config() - Handle controls set + * @mod: Pointer to module data. + * @param_id: Id to know control type, used to know ALSA control type. + * @pos: Position of the fragment in the large message. + * @data_offset_size: Size of the whole configuration if it is the first or only + * fragment. Otherwise it is offset of the fragment. + * @fragment: Message payload data. + * @fragment_size: Size of this fragment. + * @response_size: Size of response. + * + * This function handles the real-time controls. The ALSA controls have the + * param_id set to indicate the control type. The control ID, from topology, + * is used to separate the controls instances of same type. In control payload + * the num_elems defines to how many channels the control is applied to. + * + * Return: Zero if success, otherwise error code. + */ +int stft_process_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); +/** + * stft_process_set_config() - Handle controls get + * @mod: Pointer to module data. + * @config_id: Configuration ID. + * @data_offset_size: Size of the whole configuration if it is the first or only + * fragment. Otherwise it is offset of the fragment. + * @fragment: Message payload data. + * @fragment_size: Size of this fragment. + * + * This function is used for controls get. + * + * Return: Zero if success, otherwise error code. + */ +int stft_process_get_config(struct processing_module *mod, uint32_t config_id, + uint32_t *data_offset_size, uint8_t *fragment, size_t fragment_size); +#else +static inline int stft_process_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) +{ + return 0; +} + +static inline int stft_process_get_config(struct processing_module *mod, uint32_t config_id, + uint32_t *data_offset_size, uint8_t *fragment, + size_t fragment_size) +{ + return 0; +} +#endif + +/** + * stft_process_setup() - Initialize STFT processing state and allocate buffers. + * @mod: Pointer to processing module. + * @max_frames: Maximum number of frames per processing call. + * @rate: Audio sample rate in Hz. + * @channels: Number of audio channels. + * + * Configures FFT parameters, allocates aligned sample and FFT buffers, + * sets up window function, and creates FFT/IFFT plans based on the + * component configuration. + * + * Return: Zero on success, otherwise a negative error code. + */ +int stft_process_setup(struct processing_module *mod, int max_frames, int rate, int channels); + +/** + * stft_process_source_s16() - Copy S16_LE source data to STFT internal buffers. + * @cd: STFT component data. + * @source: Source for PCM samples data. + * @frames: Number of audio data frames to process. + * + * De-interleaves S16_LE audio frames from the source circular buffer + * into per-channel internal circular buffers. Each 16-bit sample is + * converted to Q1.31 format by left-shifting 16 bits. + * + * Return: Zero on success, otherwise an error code. + */ +int stft_process_source_s16(struct stft_comp_data *cd, struct sof_source *source, int frames); + +/** + * stft_process_sink_s16() - Copy STFT internal buffers to S16_LE sink. + * @cd: STFT component data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to produce. + * + * Interleaves per-channel STFT output buffers into the sink circular + * buffer in S16_LE format. Q1.31 samples are converted to Q1.15 with + * rounding and saturation. Output buffer samples are cleared after + * reading to prepare for the next overlap-add cycle. + * + * Return: Zero on success, otherwise an error code. + */ +int stft_process_sink_s16(struct stft_comp_data *cd, struct sof_sink *sink, int frames); + +/** + * stft_process_source_s32() - Copy S32_LE source data to STFT internal buffers. + * @cd: STFT component data. + * @source: Source for PCM samples data. + * @frames: Number of audio data frames to process. + * + * De-interleaves S32_LE audio frames from the source circular buffer + * into per-channel internal circular buffers. + * + * Return: Zero on success, otherwise an error code. + */ +int stft_process_source_s32(struct stft_comp_data *cd, struct sof_source *source, int frames); + +/** + * stft_process_sink_s32() - Copy STFT internal buffers to S32_LE sink. + * @cd: STFT component data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to produce. + * + * Interleaves per-channel STFT output buffers into the sink circular + * buffer in S32_LE format. The output buffer samples are cleared after + * reading to prepare for the next overlap-add cycle. + * + * Return: Zero on success, otherwise an error code. + */ +int stft_process_sink_s32(struct stft_comp_data *cd, struct sof_sink *sink, int frames); + +/** + * stft_process_free_buffers() - Free all STFT processing buffers. + * @mod: Pointer to processing module. + * + * Releases sample buffers, FFT buffers, and FFT/IFFT plans allocated + * during stft_process_setup(). + */ +void stft_process_free_buffers(struct processing_module *mod); + +/** + * stft_process_fill_prev_samples() - Save overlap samples for next STFT frame. + * @buf: Circular buffer to read overlap samples from. + * @prev_data: Destination array for the overlap data. + * @prev_data_length: Number of samples to copy. + * + * Copies prev_data_length samples from the circular buffer into the + * linear prev_data array, handling wrap-around as needed. + */ +void stft_process_fill_prev_samples(struct stft_process_buffer *buf, int32_t *prev_data, + int prev_data_length); + +/** + * stft_process_fill_fft_buffer() - Assemble FFT input from overlap and new data. + * @state: STFT processing state. + * @ch: Channel index. + * + * Constructs the FFT input buffer by concatenating the previous overlap + * samples and one hop of new samples from the input circular buffer. + * Imaginary parts are set to zero. The overlap buffer is updated with + * data for the next frame. + */ +void stft_process_fill_fft_buffer(struct stft_process_state *state, int ch); + +/** + * stft_process_apply_window() - Multiply FFT buffer by the analysis window. + * @state: STFT processing state that contains the FFT buffer and window. + * + * The real part of each complex sample in the FFT buffer is multiplied + * by the corresponding Q1.31 window coefficient. + */ +void stft_process_apply_window(struct stft_process_state *state); + +/** + * stft_process_overlap_add_ifft_buffer() - Overlap-add IFFT output to circular output buffer. + * @state: STFT processing state. + * @ch: Channel index. + * + * Each IFFT output sample is multiplied by the gain compensation value + * and added with saturation to the existing content of the circular + * output buffer. + */ +void stft_process_overlap_add_ifft_buffer(struct stft_process_state *state, int ch); + +#endif // __SOF_AUDIO_STFT_PROCESS_H__ diff --git a/src/audio/stft_process/stft_process.toml b/src/audio/stft_process/stft_process.toml new file mode 100644 index 000000000000..5e0f3b805c7d --- /dev/null +++ b/src/audio/stft_process/stft_process.toml @@ -0,0 +1,21 @@ +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + + REM # Template component module config + [[module.entry]] + name = "STFTPROC" + uuid = UUIDREG_STR_STFT_PROCESS + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = LOAD_TYPE + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + REM # 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] + + index = __COUNTER__ diff --git a/src/audio/stft_process/stft_process_common.c b/src/audio/stft_process/stft_process_common.c new file mode 100644 index 000000000000..6ab3199082de --- /dev/null +++ b/src/audio/stft_process/stft_process_common.c @@ -0,0 +1,623 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/component.h> +#include <sof/audio/audio_stream.h> +#include <sof/audio/format.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/source_api.h> +#include <sof/math/auditory.h> +#include <sof/math/icomplex32.h> +#include <sof/math/matrix.h> +#include <sof/math/sqrt.h> +#include <sof/math/trig.h> +#include <sof/math/window.h> +#include <sof/trace/trace.h> + +#include "stft_process.h" + +#include <errno.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#if STFT_DEBUG +extern FILE *stft_debug_fft_in_fh; +extern FILE *stft_debug_fft_out_fh; +extern FILE *stft_debug_ifft_out_fh; + +static void debug_print_to_file_real(FILE *fh, struct icomplex32 *c, int n) +{ + for (int i = 0; i < n; i++) + fprintf(fh, "%d\n", c[i].real); +} + +static void debug_print_to_file_complex(FILE *fh, struct icomplex32 *c, int n) +{ + for (int i = 0; i < n; i++) + fprintf(fh, "%d %d\n", c[i].real, c[i].imag); +} +#endif + +#if CONFIG_FORMAT_S32LE +int stft_process_source_s32(struct stft_comp_data *cd, struct sof_source *source, int frames) +{ + struct stft_process_state *state = &cd->state; + struct stft_process_buffer *ibuf; + int32_t const *x, *x_start, *x_end; + int x_size; + int bytes = frames * cd->frame_bytes; + int frames_left = frames; + int ret; + int n1; + int n2; + int channels = cd->channels; + int n; + int i; + int j; + + /* Get pointer to source data in circular buffer */ + ret = source_get_data_s32(source, bytes, &x, &x_start, &x_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + + while (frames_left) { + /* Find out samples to process before first wrap or end of data. */ + ibuf = &state->ibuf[0]; + n1 = (x_end - x) / cd->channels; + n2 = stft_process_buffer_samples_without_wrap(ibuf, ibuf->w_ptr); + n = MIN(n1, n2); + n = MIN(n, frames_left); + for (i = 0; i < n; i++) { + for (j = 0; j < channels; j++) { + ibuf = &state->ibuf[j]; + *ibuf->w_ptr++ = *x++; + } + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + for (j = 0; j < channels; j++) { + ibuf = &state->ibuf[j]; + ibuf->w_ptr = stft_process_buffer_wrap(ibuf, ibuf->w_ptr); + } + + if (x >= x_end) + x -= x_size; + + /* Update processed samples count for next loop iteration. */ + frames_left -= n; + } + + /* Update the source for bytes consumed. Return success. */ + source_release_data(source, bytes); + for (j = 0; j < channels; j++) { + ibuf = &state->ibuf[j]; + ibuf->s_avail += frames; + ibuf->s_free -= frames; + } + + return 0; +} + +int stft_process_sink_s32(struct stft_comp_data *cd, struct sof_sink *sink, int frames) +{ + struct stft_process_state *state = &cd->state; + struct stft_process_buffer *obuf; + int32_t *y, *y_start, *y_end; + int frames_remain = frames; + int channels = cd->channels; + int bytes = frames * cd->frame_bytes; + int y_size; + int ret; + int ch, n1, n, i; + + /* Get pointer to sink data in circular buffer */ + ret = sink_get_buffer_s32(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + y_end = y_start + y_size; + while (frames_remain) { + /* Find out samples to process before first wrap or end of data. */ + obuf = &state->obuf[0]; + n1 = (y_end - y) / cd->channels; + n = stft_process_buffer_samples_without_wrap(obuf, obuf->r_ptr); + n = MIN(n1, n); + n = MIN(n, frames_remain); + + for (i = 0; i < n; i++) { + for (ch = 0; ch < channels; ch++) { + obuf = &state->obuf[ch]; + *y++ = *obuf->r_ptr; + *obuf->r_ptr++ = 0; /* clear overlap add mix */ + } + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + for (ch = 0; ch < cd->channels; ch++) { + obuf = &state->obuf[ch]; + obuf->r_ptr = stft_process_buffer_wrap(obuf, obuf->r_ptr); + } + + if (y >= y_end) + y -= y_size; + + /* Update processed samples count for next loop iteration. */ + frames_remain -= n; + } + + /* Update the sink for bytes produced. Return success. */ + sink_commit_buffer(sink, bytes); + for (ch = 0; ch < channels; ch++) { + obuf = &state->obuf[ch]; + obuf->s_avail -= frames; + obuf->s_free += frames; + } + + return 0; +} +#endif /* CONFIG_FORMAT_S32LE */ + +#if CONFIG_FORMAT_S16LE +int stft_process_source_s16(struct stft_comp_data *cd, struct sof_source *source, int frames) +{ + struct stft_process_state *state = &cd->state; + struct stft_process_buffer *ibuf; + int16_t const *x, *x_start, *x_end; + int16_t in; + int x_size; + int channels = cd->channels; + int bytes = frames * cd->frame_bytes; + int frames_left = frames; + int ret; + int n1; + int n2; + int n; + int i; + int j; + + ret = source_get_data_s16(source, bytes, &x, &x_start, &x_size); + if (ret) + return ret; + + x_end = x_start + x_size; + + while (frames_left) { + ibuf = &state->ibuf[0]; + n1 = (x_end - x) / cd->channels; + n2 = stft_process_buffer_samples_without_wrap(ibuf, ibuf->w_ptr); + n = MIN(n1, n2); + n = MIN(n, frames_left); + for (i = 0; i < n; i++) { + for (j = 0; j < channels; j++) { + ibuf = &state->ibuf[j]; + in = *x++; + *ibuf->w_ptr++ = (int32_t)in << 16; + } + } + + for (j = 0; j < channels; j++) { + ibuf = &state->ibuf[j]; + ibuf->w_ptr = stft_process_buffer_wrap(ibuf, ibuf->w_ptr); + } + + if (x >= x_end) + x -= x_size; + + frames_left -= n; + } + + source_release_data(source, bytes); + for (j = 0; j < channels; j++) { + ibuf = &state->ibuf[j]; + ibuf->s_avail += frames; + ibuf->s_free -= frames; + } + return 0; +} + +int stft_process_sink_s16(struct stft_comp_data *cd, struct sof_sink *sink, int frames) +{ + struct stft_process_state *state = &cd->state; + struct stft_process_buffer *obuf; + int16_t *y, *y_start, *y_end; + int frames_remain = frames; + int channels = cd->channels; + int bytes = frames * cd->frame_bytes; + int y_size; + int ret; + int ch, n1, n, i; + + ret = sink_get_buffer_s16(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + y_end = y_start + y_size; + while (frames_remain) { + obuf = &state->obuf[0]; + n1 = (y_end - y) / cd->channels; + n = stft_process_buffer_samples_without_wrap(obuf, obuf->r_ptr); + n = MIN(n1, n); + n = MIN(n, frames_remain); + + for (i = 0; i < n; i++) { + for (ch = 0; ch < channels; ch++) { + obuf = &state->obuf[ch]; + *y++ = sat_int16(Q_SHIFT_RND(*obuf->r_ptr, 31, 15)); + *obuf->r_ptr++ = 0; /* clear overlap add mix */ + } + } + + for (ch = 0; ch < channels; ch++) { + obuf = &state->obuf[ch]; + obuf->r_ptr = stft_process_buffer_wrap(obuf, obuf->r_ptr); + } + + if (y >= y_end) + y -= y_size; + + frames_remain -= n; + } + + sink_commit_buffer(sink, bytes); + for (ch = 0; ch < channels; ch++) { + obuf = &state->obuf[ch]; + obuf->s_avail -= frames; + obuf->s_free += frames; + } + + return 0; +} +#endif /* CONFIG_FORMAT_S16LE */ + +void stft_process_fill_prev_samples(struct stft_process_buffer *buf, int32_t *prev_data, + int prev_data_length) +{ + int32_t *r = buf->r_ptr; + int32_t *p = prev_data; + int copied; + int nmax; + int n; + + for (copied = 0; copied < prev_data_length; copied += n) { + nmax = prev_data_length - copied; + n = stft_process_buffer_samples_without_wrap(buf, r); + n = MIN(n, nmax); + memcpy(p, r, sizeof(int32_t) * n); + p += n; + r += n; + r = stft_process_buffer_wrap(buf, r); + } + + buf->s_avail -= copied; + buf->s_free += copied; + buf->r_ptr = r; +} + +void stft_process_fill_fft_buffer(struct stft_process_state *state, int ch) +{ + struct stft_process_buffer *ibuf = &state->ibuf[ch]; + struct stft_process_fft *fft = &state->fft; + int32_t *prev_data = state->prev_data[ch]; + int32_t *r = ibuf->r_ptr; + int copied; + int nmax; + int idx; + int j; + int n; + + /* Copy overlapped samples from state buffer. Imaginary part of input + * remains zero. + */ + for (j = 0; j < state->prev_data_size; j++) { + fft->fft_buf[j].real = prev_data[j]; + fft->fft_buf[j].imag = 0; + } + + /* Copy hop size of new data from circular buffer */ + idx = state->prev_data_size; + for (copied = 0; copied < fft->fft_hop_size; copied += n) { + nmax = fft->fft_hop_size - copied; + n = stft_process_buffer_samples_without_wrap(ibuf, r); + n = MIN(n, nmax); + for (j = 0; j < n; j++) { + fft->fft_buf[idx].real = *r++; + fft->fft_buf[idx].imag = 0; + idx++; + } + r = stft_process_buffer_wrap(ibuf, r); + } + + ibuf->s_avail -= copied; + ibuf->s_free += copied; + ibuf->r_ptr = r; + + /* Copy for next time data back to overlap buffer */ + idx = fft->fft_hop_size; + for (j = 0; j < state->prev_data_size; j++) + prev_data[j] = fft->fft_buf[idx + j].real; +} + +LOG_MODULE_REGISTER(stft_process_common, CONFIG_SOF_LOG_LEVEL); + +/* + * The main processing function for STFT_PROCESS + */ + +static int stft_prepare_fft(struct stft_process_state *state, int channel) +{ + struct stft_process_buffer *ibuf = &state->ibuf[channel]; + struct stft_process_fft *fft = &state->fft; + + /* Wait for FFT hop size of new data */ + if (ibuf->s_avail < fft->fft_hop_size) + return 0; + + return 1; +} + +static void stft_do_fft(struct stft_process_state *state, int ch) +{ + struct stft_process_fft *fft = &state->fft; + + /* Copy data to FFT input buffer from overlap buffer and from new samples buffer */ + stft_process_fill_fft_buffer(state, ch); + + /* Window function */ + stft_process_apply_window(state); + +#if STFT_DEBUG + debug_print_to_file_real(stft_debug_fft_in_fh, fft->fft_buf, fft->fft_size); +#endif + + /* Compute FFT. A full scale s16 sine input with 2^N samples period in low + * part of s32 real part and zero imaginary part gives to output about 0.5 + * full scale 32 bit output to real and imaginary. The scaling is same for + * all FFT sizes. + */ + fft_multi_execute_32(fft->fft_plan, false); + +#if STFT_DEBUG + debug_print_to_file_complex(stft_debug_fft_out_fh, fft->fft_out, fft->fft_size); +#endif +} + +static void stft_do_ifft(struct stft_process_state *state, int ch) +{ + struct stft_process_fft *fft = &state->fft; + + /* Compute IFFT */ + fft_multi_execute_32(fft->ifft_plan, true); + +#if STFT_DEBUG + debug_print_to_file_complex(stft_debug_ifft_out_fh, fft->fft_buf, fft->fft_size); +#endif + + /* Window function */ + stft_process_apply_window(state); + + /* Copy to output buffer */ + stft_process_overlap_add_ifft_buffer(state, ch); +} + +#if CONFIG_STFT_PROCESS_MAGNITUDE_PHASE +static void stft_convert_to_polar(struct stft_process_fft *fft) +{ + int i; + + for (i = 0; i < fft->half_fft_size; i++) + sofm_icomplex32_to_polar(&fft->fft_out[i], &fft->fft_polar[i]); +} + +static void stft_convert_to_complex(struct stft_process_fft *fft) +{ + int i; + + for (i = 0; i < fft->half_fft_size; i++) + sofm_ipolar32_to_complex(&fft->fft_polar[i], &fft->fft_out[i]); +} + +static void stft_apply_fft_symmetry(struct stft_process_fft *fft) +{ + int i, j, k; + + j = 2 * fft->half_fft_size - 2; + for (i = fft->half_fft_size; i < fft->fft_size; i++) { + k = j - i; + fft->fft_out[i].real = fft->fft_out[k].real; + fft->fft_out[i].imag = -fft->fft_out[k].imag; + } +} +#endif + +static void stft_do_fft_ifft(const struct processing_module *mod) +{ + struct stft_comp_data *cd = module_get_private_data(mod); + struct stft_process_state *state = &cd->state; + int num_fft; + int ch; + + for (ch = 0; ch < cd->channels; ch++) { + num_fft = stft_prepare_fft(state, ch); + + if (num_fft) { + stft_do_fft(state, ch); + +#if CONFIG_STFT_PROCESS_MAGNITUDE_PHASE + /* Convert half-FFT to polar and back, and fix upper part */ + stft_convert_to_polar(&state->fft); + stft_convert_to_complex(&state->fft); + stft_apply_fft_symmetry(&state->fft); +#endif + + stft_do_ifft(state, ch); + cd->fft_done = true; + } + } +} + +#if CONFIG_FORMAT_S32LE +static int stft_process_output_zeros_s32(struct stft_comp_data *cd, struct sof_sink *sink, + int frames) +{ + int32_t *y, *y_start, *y_end; + int samples = frames * cd->channels; + size_t bytes = samples * sizeof(int32_t); + int samples_without_wrap; + int y_size; + int ret; + + /* Get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s32(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + y_end = y_start + y_size; + while (samples) { + /* Find out samples to process before first wrap or end of data. */ + samples_without_wrap = y_end - y; + samples_without_wrap = MIN(samples_without_wrap, samples); + memset(y, 0, samples_without_wrap * sizeof(int32_t)); + y += samples_without_wrap; + + /* Check for wrap */ + if (y >= y_end) + y -= y_size; + + /* Update processed samples count for next loop iteration. */ + samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + sink_commit_buffer(sink, bytes); + return 0; +} + +static int stft_process_s32(const struct processing_module *mod, struct sof_source *source, + struct sof_sink *sink, uint32_t frames) +{ + struct stft_comp_data *cd = module_get_private_data(mod); + + /* Get samples from source buffer */ + stft_process_source_s32(cd, source, frames); + + /* Do STFT, processing and inverse STFT */ + stft_do_fft_ifft(mod); + + /* Get samples from source buffer */ + if (cd->fft_done) + stft_process_sink_s32(cd, sink, frames); + else + stft_process_output_zeros_s32(cd, sink, frames); + + return 0; +} +#endif /* CONFIG_FORMAT_S32LE */ + +#if CONFIG_FORMAT_S16LE +static int stft_process_output_zeros_s16(struct stft_comp_data *cd, struct sof_sink *sink, + int frames) +{ + int16_t *y, *y_start, *y_end; + int samples = frames * cd->channels; + size_t bytes = samples * sizeof(int16_t); + int samples_without_wrap; + int y_size; + int ret; + + /* Get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s16(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + y_end = y_start + y_size; + while (samples) { + /* Find out samples to process before first wrap or end of data. */ + samples_without_wrap = y_end - y; + samples_without_wrap = MIN(samples_without_wrap, samples); + memset(y, 0, samples_without_wrap * sizeof(int16_t)); + y += samples_without_wrap; + + /* Check for wrap */ + if (y >= y_end) + y -= y_size; + + /* Update processed samples count for next loop iteration. */ + samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + sink_commit_buffer(sink, bytes); + return 0; +} + +static int stft_process_s16(const struct processing_module *mod, struct sof_source *source, + struct sof_sink *sink, uint32_t frames) +{ + struct stft_comp_data *cd = module_get_private_data(mod); + + /* Get samples from source buffer */ + stft_process_source_s16(cd, source, frames); + + /* Do STFT, processing and inverse STFT */ + stft_do_fft_ifft(mod); + + /* Get samples from source buffer */ + if (cd->fft_done) + stft_process_sink_s16(cd, sink, frames); + else + stft_process_output_zeros_s16(cd, sink, frames); + + return 0; +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S24LE +#endif /* CONFIG_FORMAT_S24LE */ + +/* This struct array defines the used processing functions for + * the PCM formats + */ +const struct stft_process_proc_fnmap stft_process_functions[] = { +#if CONFIG_FORMAT_S16LE + { SOF_IPC_FRAME_S16_LE, stft_process_s16 }, + { SOF_IPC_FRAME_S32_LE, stft_process_s32 }, +#endif +}; + +/** + * stft_process_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +stft_process_func stft_process_find_proc_func(enum sof_ipc_frame src_fmt) +{ + int i; + + /* Find suitable processing function from map */ + for (i = 0; i < ARRAY_SIZE(stft_process_functions); i++) + if (src_fmt == stft_process_functions[i].frame_fmt) + return stft_process_functions[i].stft_process_function; + + return NULL; +} diff --git a/src/audio/stft_process/stft_process_setup.c b/src/audio/stft_process/stft_process_setup.c new file mode 100644 index 000000000000..377d5feeabc8 --- /dev/null +++ b/src/audio/stft_process/stft_process_setup.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/component.h> +#include <sof/audio/audio_stream.h> +#include <sof/math/auditory.h> +#include <sof/math/trig.h> +#include <sof/math/window.h> +#include <sof/trace/trace.h> +#include "stft_process.h" + +#include <errno.h> +#include <stddef.h> +#include <stdint.h> + +/* Definitions for cepstral lifter */ +#define PI_Q23 Q_CONVERT_FLOAT(3.1415926536, 23) +#define TWO_PI_Q23 Q_CONVERT_FLOAT(6.2831853072, 23) +#define ONE_Q9 Q_CONVERT_FLOAT(1, 9) + +#define STFT_MAX_ALLOC_SIZE 65536 + +LOG_MODULE_REGISTER(stft_process_setup, CONFIG_SOF_LOG_LEVEL); + +static void stft_process_init_buffer(struct stft_process_buffer *buf, int32_t *base, int size) +{ + buf->addr = base; + buf->end_addr = base + size; + buf->r_ptr = base; + buf->w_ptr = base; + buf->s_free = size; + buf->s_avail = 0; + buf->s_length = size; +} + +static int stft_process_get_window(struct stft_process_state *state, + enum sof_stft_process_fft_window_type name) +{ + struct stft_process_fft *fft = &state->fft; + + switch (name) { + case STFT_RECTANGULAR_WINDOW: + win_rectangular_32b(state->window, fft->fft_size); + return 0; + case STFT_BLACKMAN_WINDOW: + win_blackman_32b(state->window, fft->fft_size, WIN_BLACKMAN_A0_Q31); + return 0; + case STFT_HAMMING_WINDOW: + win_hamming_32b(state->window, fft->fft_size); + return 0; + case STFT_HANN_WINDOW: + win_hann_32b(state->window, fft->fft_size); + return 0; + + default: + return -EINVAL; + } +} + +/* TODO stft_process setup needs to use the config blob, not hard coded parameters. + * Also this is a too long function. Split to STFT, Mel filter, etc. parts. + */ +int stft_process_setup(struct processing_module *mod, int max_frames, + int sample_rate, int channels) +{ + struct stft_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + struct sof_stft_process_config *config = cd->config; + struct stft_process_state *state = &cd->state; + struct stft_process_fft *fft = &state->fft; + size_t sample_buffers_size; + size_t ibuf_size; + size_t obuf_size; + size_t prev_size; + int32_t *addr; + int ret; + int i; + + comp_dbg(dev, "entry"); + + /* Check size */ + if (config->size != sizeof(struct sof_stft_process_config)) { + comp_err(dev, "Illegal configuration size %d.", config->size); + return -EINVAL; + } + + if (config->sample_frequency != sample_rate) { + comp_err(dev, "Config sample_frequency does not match stream"); + return -EINVAL; + } + + /* max_frames needs to be even for buffer size allocation for Xtensa HiFi SIMD. */ + max_frames = ALIGN_UP(max_frames, 2); + cd->max_frames = max_frames; + state->sample_rate = sample_rate; + + comp_info(dev, "source_channel = %d, stream_channels = %d", + config->channel, channels); + if (config->channel >= channels) { + comp_err(dev, "Illegal channel"); + return -EINVAL; + } + + if (config->channel < 0) + state->source_channel = 0; + else + state->source_channel = config->channel; + + fft->fft_size = config->frame_length; + fft->fft_padded_size = fft->fft_size; /* Same */ + fft->fft_hop_size = config->frame_shift; + fft->half_fft_size = (fft->fft_padded_size >> 1) + 1; + + /* FFT size needs to be a multiple of 4 for Xtensa HiFi SIMD, + * and FFT hop size needs to be a multiple of 2. Check also + * for otherwise sane values. + */ + if (fft->fft_size <= 0 || fft->fft_hop_size <= 0 || + fft->fft_hop_size > fft->fft_size || + (fft->fft_size & 3) || (fft->fft_hop_size & 1)) { + comp_err(dev, "FFT size %d or hop size %d are invalid.", + fft->fft_size, fft->fft_hop_size); + return -EINVAL; + } + + comp_info(dev, "fft_size = %d, fft_hop_size = %d, window = %d", + fft->fft_size, fft->fft_hop_size, config->window); + + /* Calculated parameters */ + state->prev_data_size = fft->fft_size - fft->fft_hop_size; + ibuf_size = fft->fft_hop_size + max_frames; + obuf_size = fft->fft_size + max_frames; + prev_size = state->prev_data_size; + + /* Allocate buffer input samples, overlap buffer, window */ + sample_buffers_size = sizeof(int32_t) * + (cd->channels * (ibuf_size + obuf_size + prev_size) + fft->fft_size); + + if (sample_buffers_size > STFT_MAX_ALLOC_SIZE) { + comp_err(dev, "Illegal allocation size"); + return -ENOMEM; + } + + state->buffers = mod_balloc_align(mod, sample_buffers_size, 2 * sizeof(int32_t)); + if (!state->buffers) { + comp_err(dev, "Failed buffer allocate"); + ret = -ENOMEM; + goto exit; + } + + bzero(state->buffers, sample_buffers_size); + addr = state->buffers; + for (i = 0; i < cd->channels; i++) { + stft_process_init_buffer(&state->ibuf[i], addr, ibuf_size); + addr += ibuf_size; + stft_process_init_buffer(&state->obuf[i], addr, obuf_size); + addr += obuf_size; + state->prev_data[i] = addr; + addr += prev_size; + } + state->window = addr; + + /* Allocate buffers for FFT input and output data */ + fft->fft_buffer_size = fft->fft_padded_size * sizeof(struct icomplex32); + fft->fft_buf = mod_balloc_align(mod, fft->fft_buffer_size, sizeof(struct icomplex32)); + if (!fft->fft_buf) { + comp_err(dev, "Failed FFT buffer allocate"); + ret = -ENOMEM; + goto free_buffers; + } + + fft->fft_out = mod_balloc_align(mod, fft->fft_buffer_size, sizeof(struct icomplex32)); + if (!fft->fft_out) { + comp_err(dev, "Failed FFT output allocate"); + ret = -ENOMEM; + goto free_fft_buf; + } + + /* Share the fft_out buffer for polar format */ + fft->fft_polar = (struct ipolar32 *)fft->fft_out; + + /* Setup FFT */ + fft->fft_plan = mod_fft_multi_plan_new(mod, fft->fft_buf, fft->fft_out, + fft->fft_padded_size, 32); + if (!fft->fft_plan) { + comp_err(dev, "Failed FFT init"); + ret = -EINVAL; + goto free_fft_out; + } + + fft->ifft_plan = mod_fft_multi_plan_new(mod, fft->fft_out, fft->fft_buf, + fft->fft_padded_size, 32); + if (!fft->ifft_plan) { + comp_err(dev, "Failed IFFT init"); + ret = -EINVAL; + goto free_ifft_out; + } + + /* Setup window */ + ret = stft_process_get_window(state, config->window); + if (ret < 0) { + comp_err(dev, "Failed Window function"); + goto free_window_out; + } + + /* Need to compensate the window function gain */ + state->gain_comp = config->window_gain_comp; + + /* Set initial state for STFT */ + state->waiting_fill = true; + state->prev_samples_valid = false; + + comp_dbg(dev, "done"); + return 0; + +free_window_out: + mod_free(mod, fft->ifft_plan); + +free_ifft_out: + mod_free(mod, fft->fft_plan); + +free_fft_out: + mod_free(mod, fft->fft_out); + +free_fft_buf: + mod_free(mod, fft->fft_buf); + +free_buffers: + mod_free(mod, state->buffers); + +exit: + return ret; +} + +void stft_process_free_buffers(struct processing_module *mod) +{ + struct stft_comp_data *cd = module_get_private_data(mod); + struct stft_process_state *state = &cd->state; + struct stft_process_fft *fft = &state->fft; + + mod_fft_multi_plan_free(mod, fft->ifft_plan); + mod_fft_multi_plan_free(mod, fft->fft_plan); + mod_free(mod, cd->state.fft.fft_buf); + mod_free(mod, cd->state.fft.fft_out); + mod_free(mod, cd->state.buffers); +} diff --git a/src/audio/stft_process/tune/setup_stft_process.m b/src/audio/stft_process/tune/setup_stft_process.m new file mode 100644 index 000000000000..4018a1d7aeb7 --- /dev/null +++ b/src/audio/stft_process/tune/setup_stft_process.m @@ -0,0 +1,185 @@ +% setup_stft_process() +% +% Create binary configuration blob for STFT_PROCESS component. The hex data +% is written to tools/topology/topology1/m4/stft_process/stft_process_config.m4 + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2025, Intel Corporation. + +function setup_stft_process(cfg) + + cfg.tools_path = '../../../../tools/'; + cfg.tplg_path = [cfg.tools_path 'topology/topology2/include/components/stft_process/']; + cfg.common_path = [cfg.tools_path 'tune/common']; + cfg.tplg_ver = 2; + cfg.ipc_ver = 4; + cfg.channel = 0; + cfg.sample_frequency = 48000; + + cfg.frame_length = 192; % 4 ms + cfg.frame_shift = 48; % 1 ms + cfg.window_type = 'hann'; + cfg.tplg_fn = 'hann_192_48.conf'; + export_stft_process_setup(cfg); + + cfg.frame_length = 512; % 10.7 ms + cfg.frame_shift = 128; % 2.7 ms + cfg.window_type = 'hann'; + cfg.tplg_fn = 'hann_512_128.conf'; + export_stft_process_setup(cfg); + + cfg.frame_length = 768; % 16 ms + cfg.frame_shift = 120; % 2.5 ms + cfg.window_type = 'hann'; + cfg.tplg_fn = 'hann_768_120.conf'; + export_stft_process_setup(cfg); + + cfg.frame_length = 1024; % 21.3 ms + cfg.frame_shift = 256; % 5.3 ms + cfg.window_type = 'hann'; + cfg.tplg_fn = 'hann_1024_256.conf'; + export_stft_process_setup(cfg); + + cfg.frame_length = 1536; % 32 ms + cfg.frame_shift = 240; % 5 ms + cfg.window_type = 'hann'; + cfg.tplg_fn = 'hann_1536_240.conf'; + export_stft_process_setup(cfg); + +end + +function export_stft_process_setup(cfg) + + % Use blob tool from EQ + addpath(cfg.common_path); + + % Blob size, size plus reserved(8) + current parameters + nbytes_data = 64; + + % Get ABI information + [abi_bytes, nbytes_abi] = sof_get_abi(nbytes_data, cfg.ipc_ver); + + % Initialize correct size uint8 array + nbytes = nbytes_abi + nbytes_data; + b8 = uint8(zeros(1,nbytes)); + + % Insert ABI header + fprintf(1, 'STFT_PROCESS blob size is %d, ABI header is %d, data is %d\n',nbytes, nbytes_abi, nbytes_data); + b8(1:nbytes_abi) = abi_bytes; + j = nbytes_abi + 1; + + % Apply default STFT_PROCESS configuration, first struct header and reserved, then data + [b8, j] = add_w32b(nbytes_data, b8, j); + for i = 1:8 + [b8, j] = add_w32b(0, b8, j); + end + + fft_length = cfg.frame_length; + fft_hop = cfg.frame_shift; + [window_idx, window_gain_comp] = get_window(cfg, fft_length, fft_hop); + + v = q_convert(cfg.sample_frequency, 0); [b8, j] = add_w32b(v, b8, j); + v = q_convert(window_gain_comp, 31); [b8, j] = add_w32b(v, b8, j); + v = 0; [b8, j] = add_w32b(v, b8, j); % reserved + v = cfg.channel; [b8, j] = add_w16b(v, b8, j); + v = fft_length; [b8, j] = add_w16b(v, b8, j); + v = fft_hop; [b8, j] = add_w16b(v, b8, j); + v = 0; [b8, j] = add_w16b(v, b8, j); % reserved + v = 0; [b8, j] = add_w32b(v, b8, j); % enum pad + v = window_idx; [b8, j] = add_w32b(v, b8, j); % enum window + + % Export + switch cfg.tplg_ver + case 2 + sof_tplg2_write([cfg.tplg_path cfg.tplg_fn], b8, "stft_process_config", ... + "Exported STFT_PROCESS configuration", ... + "cd tools/tune/stft_process; octave setup_stft_process.m"); + otherwise + error("Illegal cfg.tplg_ver, use 2 topology v2."); + end + + rmpath(cfg.common_path); + +end + +%% Helper functions + +function [idx, iwg] = get_window(cfg, len, hop) + switch lower(cfg.window_type) + case 'rectangular' + win = boxcar(len); + idx = 0; + case 'blackman' + win = blackman(len); + idx = 1; + case 'hamming' + win = hamming(len); + idx = 2; + case 'hann' + win = hann(len); + idx = 3; + case 'povey' + idx = 4; + n = 0:(len-1); + win = ((1 - cos(2 * pi * n / len)) / 2).^0.85; + otherwise + error('Unknown window type'); + end + iwg = hop / sum(win.^2); +end + +function bytes = w8b(word) + bytes = uint8(zeros(1,1)); + bytes(1) = bitand(word, 255); +end + +function bytes = w16b(word) + sh = [0 -8]; + bytes = uint8(zeros(1,2)); + bytes(1) = bitand(bitshift(word, sh(1)), 255); + bytes(2) = bitand(bitshift(word, sh(2)), 255); +end + +function bytes = w32b(word) + sh = [0 -8 -16 -24]; + bytes = uint8(zeros(1,4)); + bytes(1) = bitand(bitshift(word, sh(1)), 255); + bytes(2) = bitand(bitshift(word, sh(2)), 255); + bytes(3) = bitand(bitshift(word, sh(3)), 255); + bytes(4) = bitand(bitshift(word, sh(4)), 255); +end + +function n = q_convert(val, q) + n = round(val * 2^q); +end + +function [blob8, j] = add_w8b(v, blob8, j) + if j > length(blob8) + error('Blob size is not sufficient'); + end + blob8(j) = w8b(v); + j = j + 1; +end + +function [blob8, j] = add_w16b(v, blob8, j) + if j + 1 > length(blob8) + error('Blob size is not sufficient'); + end + if v < 0 + v = 2^16 + v; + end + blob8(j : j + 1) = w16b(v); + j = j + 2; +end + +function [blob8, j] = add_w32b(v, blob8, j) + if j + 3 > length(blob8) + error('Blob size is not sufficient'); + end + if v < 0 + v = 2^32 + v; + end + blob8(j : j + 3) = w32b(v); + j = j + 4; +end diff --git a/src/audio/tdfb/CMakeLists.txt b/src/audio/tdfb/CMakeLists.txt index a476cd5b9f1a..aaa61cacaa9f 100644 --- a/src/audio/tdfb/CMakeLists.txt +++ b/src/audio/tdfb/CMakeLists.txt @@ -1,8 +1,13 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof tdfb.c tdfb_generic.c tdfb_hifiep.c tdfb_hifi3.c tdfb_direction.c) -if(CONFIG_IPC_MAJOR_3) - add_local_sources(sof tdfb_ipc3.c) -elseif(CONFIG_IPC_MAJOR_4) - add_local_sources(sof tdfb_ipc4.c) +if(CONFIG_COMP_TDFB STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/tdfb_llext) + add_dependencies(app tdfb) +else() + add_local_sources(sof tdfb.c tdfb_generic.c tdfb_hifiep.c tdfb_hifi3.c tdfb_direction.c) + if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof tdfb_ipc3.c) + elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof tdfb_ipc4.c) + endif() endif() diff --git a/src/audio/tdfb/README.md b/src/audio/tdfb/README.md new file mode 100644 index 000000000000..cf3bc13dbe2d --- /dev/null +++ b/src/audio/tdfb/README.md @@ -0,0 +1,15 @@ +# Time Domain Filter Bank Architecture + +This directory contains the TDFB component. + +## Overview + +Generally used for operations like beamforming or highly directional microphone array processing in the time domain. + +## Configuration and Scripts + +- **Kconfig**: Manages the Time Domain Fixed Beamformer component (`COMP_TDFB`), requiring generic `COMP_MODULE_ADAPTER` integration along with high-precision math packages (`MATH_FIR`, `MATH_IIR_DF1`, `SQRT_FIXED`, `CORDIC_FIXED`). +- **CMakeLists.txt**: Builds the standard source set (`tdfb.c`, `tdfb_generic.c`, `tdfb_hifiep.c`, `tdfb_hifi3.c`, `tdfb_direction.c`) handling generic and HIFI implementations alongside IPC abstractions (`tdfb_ipc3.c`, `tdfb_ipc4.c`). Inherits out-of-tree loader (`llext`) generation. +- **tdfb.toml**: Generates ALSA properties mapping the component to `UUIDREG_STR_TDFB`. +- **Topology (.conf)**: Instantiated from `tools/topology/topology2/include/components/tdfb.conf`, creating a `tdfb` widget type `effect` (UUID `49:17:51:dd:fa:d9:5c:45:b3:a7:13:58:56:93:f1:af`). Provides multiple internal mixer controls spanning phase/direction toggles. +- **MATLAB Tuning (`tune/`)**: `sof_example_circular_array.m` and similar array topology scripts define spatial setups (e.g., circular, linear, L-shape, rectangular). They take microphone layout coordinates, compute beamforming angles (azimuth/elevation) and delays, and pack them into binary configuration blobs allowing microphones to "steer" their listening direction interactively. diff --git a/src/audio/tdfb/tdfb.c b/src/audio/tdfb/tdfb.c index dbb99bddb5aa..1cda385cae84 100644 --- a/src/audio/tdfb/tdfb.c +++ b/src/audio/tdfb/tdfb.c @@ -25,7 +25,6 @@ #include <ipc/control.h> #include <ipc/stream.h> #include <ipc/topology.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <rtos/panic.h> #include <rtos/string.h> @@ -44,8 +43,6 @@ LOG_MODULE_REGISTER(tdfb, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(tdfb); -DECLARE_TR_CTX(tdfb_tr, SOF_UUID(tdfb_uuid), LOG_LEVEL_INFO); - static inline int set_func(struct processing_module *mod, enum sof_ipc_frame fmt) { struct tdfb_comp_data *cd = module_get_private_data(mod); @@ -53,24 +50,24 @@ static inline int set_func(struct processing_module *mod, enum sof_ipc_frame fmt switch (fmt) { #if CONFIG_FORMAT_S16LE case SOF_IPC_FRAME_S16_LE: - comp_dbg(mod->dev, "set_func(), SOF_IPC_FRAME_S16_LE"); + comp_dbg(mod->dev, "SOF_IPC_FRAME_S16_LE"); cd->tdfb_func = tdfb_fir_s16; break; #endif /* CONFIG_FORMAT_S16LE */ #if CONFIG_FORMAT_S24LE case SOF_IPC_FRAME_S24_4LE: - comp_dbg(mod->dev, "set_func(), SOF_IPC_FRAME_S24_4LE"); + comp_dbg(mod->dev, "SOF_IPC_FRAME_S24_4LE"); cd->tdfb_func = tdfb_fir_s24; break; #endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE case SOF_IPC_FRAME_S32_LE: - comp_dbg(mod->dev, "set_func(), SOF_IPC_FRAME_S32_LE"); + comp_dbg(mod->dev, "SOF_IPC_FRAME_S32_LE"); cd->tdfb_func = tdfb_fir_s32; break; #endif /* CONFIG_FORMAT_S32LE */ default: - comp_err(mod->dev, "set_func(), invalid frame_fmt"); + comp_err(mod->dev, "invalid frame_fmt"); return -EINVAL; } return 0; @@ -234,24 +231,24 @@ static inline int set_pass_func(struct processing_module *mod, enum sof_ipc_fram switch (fmt) { #if CONFIG_FORMAT_S16LE case SOF_IPC_FRAME_S16_LE: - comp_dbg(mod->dev, "set_pass_func(), SOF_IPC_FRAME_S16_LE"); + comp_dbg(mod->dev, "SOF_IPC_FRAME_S16_LE"); cd->tdfb_func = tdfb_pass_s16; break; #endif /* CONFIG_FORMAT_S16LE */ #if CONFIG_FORMAT_S24LE case SOF_IPC_FRAME_S24_4LE: - comp_dbg(mod->dev, "set_pass_func(), SOF_IPC_FRAME_S24_4LE"); + comp_dbg(mod->dev, "SOF_IPC_FRAME_S24_4LE"); cd->tdfb_func = tdfb_pass_s24; break; #endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE case SOF_IPC_FRAME_S32_LE: - comp_dbg(mod->dev, "set_pass_func(), SOF_IPC_FRAME_S32_LE"); + comp_dbg(mod->dev, "SOF_IPC_FRAME_S32_LE"); cd->tdfb_func = tdfb_pass_s32; break; #endif /* CONFIG_FORMAT_S32LE */ default: - comp_err(mod->dev, "set_pass_func(), invalid frame_fmt"); + comp_err(mod->dev, "invalid frame_fmt"); return -EINVAL; } return 0; @@ -261,15 +258,16 @@ static inline int set_pass_func(struct processing_module *mod, enum sof_ipc_fram * Control code functions next. The processing is in fir_ C modules. */ -static void tdfb_free_delaylines(struct tdfb_comp_data *cd) +static void tdfb_free_delaylines(struct processing_module *mod) { + struct tdfb_comp_data *cd = module_get_private_data(mod); struct fir_state_32x16 *fir = cd->fir; int i = 0; /* Free the common buffer for all EQs and point then * each FIR channel delay line to NULL. */ - rfree(cd->fir_delay); + mod_free(mod, cd->fir_delay); cd->fir_delay = NULL; cd->fir_delay_size = 0; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) @@ -325,52 +323,57 @@ static int tdfb_init_coef(struct processing_module *mod, int source_nch, int i; /* Sanity checks */ + if (config->size != cd->config_size) { + comp_err(dev, "Incorrect configuration blob size"); + return -EINVAL; + } + if (config->num_output_channels > PLATFORM_MAX_CHANNELS || !config->num_output_channels) { - comp_err(dev, "tdfb_init_coef(), invalid num_output_channels %d", + comp_err(dev, "invalid num_output_channels %d", config->num_output_channels); return -EINVAL; } if (config->num_output_channels != sink_nch) { - comp_err(dev, "tdfb_init_coef(), stream output channels count %d does not match configuration %d", + comp_err(dev, "stream output channels count %d does not match configuration %d", sink_nch, config->num_output_channels); return -EINVAL; } if (config->num_filters > SOF_TDFB_FIR_MAX_COUNT) { - comp_err(dev, "tdfb_init_coef(), invalid num_filters %d", + comp_err(dev, "invalid num_filters %d", config->num_filters); return -EINVAL; } - if (config->num_angles > SOF_TDFB_MAX_ANGLES) { - comp_err(dev, "tdfb_init_coef(), invalid num_angles %d", + /* In SOF v1.6 - 1.8 based beamformer topologies the multiple angles, mic locations, + * and beam on/off switch were not defined. A most basic supported blob has num_angles + * equal to 1. Mic locations data is optional. + */ + if (config->num_angles == 0 || config->num_angles > SOF_TDFB_MAX_ANGLES) { + comp_err(dev, "invalid num_angles %d", config->num_angles); return -EINVAL; } + if (!config->angle_enum_mult) { + comp_err(dev, "invalid angle_enum_mult"); + return -EINVAL; + } + if (config->beam_off_defined > 1) { - comp_err(dev, "tdfb_init_coef(), invalid beam_off_defined %d", + comp_err(dev, "invalid beam_off_defined %d", config->beam_off_defined); return -EINVAL; } if (config->num_mic_locations > SOF_TDFB_MAX_MICROPHONES) { - comp_err(dev, "tdfb_init_coef(), invalid num_mic_locations %d", + comp_err(dev, "invalid num_mic_locations %d", config->num_mic_locations); return -EINVAL; } - /* In SOF v1.6 - 1.8 based beamformer topologies the multiple angles, mic locations, - * and beam on/off switch were not defined. Return error if such configuration is seen. - * A most basic blob has num_angles equals 1. Mic locations data is optional. - */ - if (config->num_angles == 0 && config->num_mic_locations == 0) { - comp_err(dev, "tdfb_init_coef(), ABI version less than 3.19.1 is not supported."); - return -EINVAL; - } - /* Skip filter coefficients */ num_filters = config->num_filters * (config->num_angles + config->beam_off_defined); coefp = tdfb_filter_seek(config, num_filters); @@ -395,7 +398,7 @@ static int tdfb_init_coef(struct processing_module *mod, int source_nch, (&cd->filter_angles[config->num_angles]); if ((uint8_t *)&cd->mic_locations[config->num_mic_locations] != (uint8_t *)config + config->size) { - comp_err(dev, "tdfb_init_coef(), invalid config size"); + comp_err(dev, "invalid config size"); return -EINVAL; } @@ -414,17 +417,23 @@ static int tdfb_init_coef(struct processing_module *mod, int source_nch, idx = cd->filter_angles[min_delta_idx].filter_index; if (cd->beam_on) { - comp_info(dev, "tdfb_init_coef(), angle request %d, found %d, idx %d", + comp_info(dev, "angle request %d, found %d, idx %d", target_az, cd->filter_angles[min_delta_idx].azimuth, idx); } else if (config->beam_off_defined) { cd->output_channel_mix = output_channel_mix_beam_off; idx = config->num_filters * config->num_angles; - comp_info(dev, "tdfb_init_coef(), configure beam off"); + comp_info(dev, "configure beam off"); } else { - comp_info(dev, "tdfb_init_coef(), beam off is not defined, using filter %d, idx %d", + comp_info(dev, "beam off is not defined, using filter %d, idx %d", cd->filter_angles[min_delta_idx].azimuth, idx); } + if (idx < 0 || idx + (int)config->num_filters > num_filters) { + comp_err(dev, "invalid filter_index %d for angle %d", + idx, cd->filter_angles[min_delta_idx].azimuth); + return -EINVAL; + } + /* Seek to proper filter for requested angle or beam off configuration */ coefp = tdfb_filter_seek(config, idx); @@ -436,7 +445,7 @@ static int tdfb_init_coef(struct processing_module *mod, int source_nch, if (s > 0) { size_sum += s; } else { - comp_err(dev, "tdfb_init_coef(), FIR length %d is invalid", + comp_err(dev, "FIR length %d is invalid", coef_data->length); return -EINVAL; } @@ -453,13 +462,18 @@ static int tdfb_init_coef(struct processing_module *mod, int source_nch, for (i = 0; i < config->num_filters; i++) { if (cd->input_channel_select[i] > max_ch) max_ch = cd->input_channel_select[i]; + + if (cd->input_channel_select[i] < 0) { + comp_err(dev, "invalid channel select for filter %d", i); + return -EINVAL; + } } /* The stream must contain at least the number of channels that is * used for filters input. */ if (max_ch + 1 > source_nch) { - comp_err(dev, "tdfb_init_coef(), stream input channels count %d is not sufficient for configuration %d", + comp_err(dev, "stream input channels count %d is not sufficient for configuration %d", source_nch, max_ch + 1); return -EINVAL; } @@ -511,12 +525,12 @@ static int tdfb_setup(struct processing_module *mod, int source_nch, int sink_nc if (delay_size > cd->fir_delay_size) { /* Free existing FIR channels data if it was allocated */ - tdfb_free_delaylines(cd); + tdfb_free_delaylines(mod); /* Allocate all FIR channels data in a big chunk and clear it */ - cd->fir_delay = rballoc(0, SOF_MEM_CAPS_RAM, delay_size); + cd->fir_delay = mod_balloc(mod, delay_size); if (!cd->fir_delay) { - comp_err(mod->dev, "tdfb_setup(), delay allocation failed for size %d", + comp_err(mod->dev, "delay allocation failed for size %d", delay_size); return -ENOMEM; } @@ -539,22 +553,13 @@ static int tdfb_init(struct processing_module *mod) { struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; - struct module_config *cfg = &md->cfg; struct tdfb_comp_data *cd; - size_t bs = cfg->size; int ret; int i; - comp_info(dev, "tdfb_init()"); - - /* Check first that configuration blob size is sane */ - if (bs > SOF_TDFB_MAX_SIZE) { - comp_err(dev, "tdfb_init() error: configuration blob size = %zu > %d", - bs, SOF_TDFB_MAX_SIZE); - return -EINVAL; - } + comp_info(dev, "entry"); - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -574,20 +579,13 @@ static int tdfb_init(struct processing_module *mod) goto err_free_cd; /* Handler for configuration data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "tdfb_init(): comp_data_blob_handler_new() failed."); + comp_err(dev, "mod_data_blob_handler_new() failed."); ret = -ENOMEM; goto err; } - /* Get configuration data and reset FIR filters */ - ret = comp_init_data_blob(cd->model_handler, bs, cfg->data); - if (ret < 0) { - comp_err(dev, "tdfb_init(): comp_init_data_blob() failed."); - goto err; - } - for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) fir_reset(&cd->fir[i]); @@ -599,11 +597,12 @@ static int tdfb_init(struct processing_module *mod) err: /* These are null if not used for IPC version */ - rfree(cd->ctrl_data); + mod_free(mod, cd->ctrl_data); ipc_msg_free(cd->msg); + mod_data_blob_handler_free(mod, cd->model_handler); err_free_cd: - rfree(cd); + mod_free(mod, cd); return ret; } @@ -612,14 +611,14 @@ static int tdfb_free(struct processing_module *mod) { struct tdfb_comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "tdfb_free()"); + comp_dbg(mod->dev, "entry"); ipc_msg_free(cd->msg); - tdfb_free_delaylines(cd); - comp_data_blob_handler_free(cd->model_handler); - tdfb_direction_free(cd); - rfree(cd->ctrl_data); - rfree(cd); + tdfb_free_delaylines(mod); + mod_data_blob_handler_free(mod, cd->model_handler); + tdfb_direction_free(mod); + mod_free(mod, cd->ctrl_data); + mod_free(mod, cd); return 0; } @@ -654,16 +653,21 @@ static int tdfb_process(struct processing_module *mod, int frame_count = input_buffers[0].size; int ret; - comp_dbg(dev, "tdfb_process()"); + comp_dbg(dev, "entry"); /* Check for changed configuration */ if (comp_is_new_data_blob_available(cd->model_handler)) { - cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); + cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL); + if (!cd->config || cd->config_size < sizeof(*cd->config) || + cd->config_size > SOF_TDFB_MAX_SIZE) { + comp_err(dev, "invalid configuration blob, size %zu", cd->config_size); + return -EINVAL; + } ret = tdfb_setup(mod, audio_stream_get_channels(source), audio_stream_get_channels(sink), audio_stream_get_frm_fmt(source)); if (ret < 0) { - comp_err(dev, "tdfb_process(), failed FIR setup"); + comp_err(dev, "failed FIR setup"); return ret; } } @@ -675,7 +679,7 @@ static int tdfb_process(struct processing_module *mod, audio_stream_get_channels(sink), audio_stream_get_frm_fmt(source)); if (ret < 0) { - comp_err(dev, "tdfb_process(), failed FIR setup"); + comp_err(dev, "failed FIR setup"); return ret; } } @@ -706,14 +710,12 @@ static int tdfb_process(struct processing_module *mod, return 0; } -static void tdfb_set_alignment(struct audio_stream *source, - struct audio_stream *sink) +static void tdfb_set_alignment(struct audio_stream *source) { - const uint32_t byte_align = 1; + const uint32_t byte_align = SOF_FRAME_BYTE_ALIGN; const uint32_t frame_align_req = 2; /* Process multiples of 2 frames */ audio_stream_set_align(byte_align, frame_align_req, source); - audio_stream_set_align(byte_align, frame_align_req, sink); } static int tdfb_prepare(struct processing_module *mod, @@ -729,7 +731,15 @@ static int tdfb_prepare(struct processing_module *mod, int rate; int ret; - comp_info(dev, "tdfb_prepare()"); + comp_info(dev, "entry"); + + /* Find source and sink buffers */ + sourceb = comp_dev_get_first_data_producer(dev); + sinkb = comp_dev_get_first_data_consumer(dev); + if (!sourceb || !sinkb) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } ret = tdfb_params(mod); if (ret) { @@ -737,10 +747,7 @@ static int tdfb_prepare(struct processing_module *mod, return ret; } - /* Find source and sink buffers */ - sourceb = comp_dev_get_first_data_producer(dev); - sinkb = comp_dev_get_first_data_consumer(dev); - tdfb_set_alignment(&sourceb->stream, &sinkb->stream); + tdfb_set_alignment(&sourceb->stream); frame_fmt = audio_stream_get_frm_fmt(&sourceb->stream); source_channels = audio_stream_get_channels(&sourceb->stream); @@ -748,15 +755,17 @@ static int tdfb_prepare(struct processing_module *mod, rate = audio_stream_get_rate(&sourceb->stream); /* Initialize filter */ - cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - if (!cd->config) { + cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL); + if (!cd->config || cd->config_size < sizeof(*cd->config) || + cd->config_size > SOF_TDFB_MAX_SIZE) { + comp_err(dev, "invalid configuration blob, size %zu", cd->config_size); ret = -EINVAL; goto out; } ret = tdfb_setup(mod, source_channels, sink_channels, frame_fmt); if (ret < 0) { - comp_err(dev, "tdfb_prepare() error: tdfb_setup failed."); + comp_err(dev, "error: tdfb_setup failed."); goto out; } @@ -775,7 +784,7 @@ static int tdfb_prepare(struct processing_module *mod, comp_dbg(dev, "dev_frames = %d, max_frames = %d", dev->frames, cd->max_frames); /* Initialize tracking */ - ret = tdfb_direction_init(cd, rate, source_channels); + ret = tdfb_direction_init(mod, rate, source_channels); if (!ret) { comp_info(dev, "max_lag = %d, xcorr_size = %zu", cd->direction.max_lag, cd->direction.d_size); @@ -796,9 +805,9 @@ static int tdfb_reset(struct processing_module *mod) struct tdfb_comp_data *cd = module_get_private_data(mod); int i; - comp_dbg(mod->dev, "tdfb_reset()"); + comp_dbg(mod->dev, "entry"); - tdfb_free_delaylines(cd); + tdfb_free_delaylines(mod); cd->tdfb_func = NULL; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) @@ -821,9 +830,6 @@ static const struct module_interface tdfb_interface = { .reset = tdfb_reset, }; -DECLARE_MODULE_ADAPTER(tdfb_interface, tdfb_uuid, tdfb_tr); -SOF_MODULE_INIT(tdfb, sys_comp_module_tdfb_interface_init); - #if CONFIG_COMP_TDFB_MODULE /* modular: llext dynamic link */ @@ -831,14 +837,15 @@ SOF_MODULE_INIT(tdfb, sys_comp_module_tdfb_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_TDFB 0x49, 0x17, 0x51, 0xdd, 0xfa, 0xd9, 0x5c, 0x45, 0xb3, 0xa7, \ - 0x13, 0x58, 0x56, 0x93, 0xf1, 0xaf - -SOF_LLEXT_MOD_ENTRY(tdfb, &tdfb_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("TDFB", tdfb_llext_entry, 1, UUID_TDFB, 40); + SOF_LLEXT_MODULE_MANIFEST("TDFB", &tdfb_interface, 1, SOF_REG_UUID(tdfb), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_TR_CTX(tdfb_tr, SOF_UUID(tdfb_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(tdfb_interface, tdfb_uuid, tdfb_tr); +SOF_MODULE_INIT(tdfb, sys_comp_module_tdfb_interface_init); + #endif diff --git a/src/audio/tdfb/tdfb.h b/src/audio/tdfb/tdfb.h index d5a09776301f..c6fd1ff0f97d 100644 --- a/src/audio/tdfb/tdfb.h +++ b/src/audio/tdfb/tdfb.h @@ -8,16 +8,17 @@ #ifndef __USER_TDFB_H__ #define __USER_TDFB_H__ +#include <sof/platform.h> #include <stdint.h> #define SOF_TDFB_NUM_INPUT_PINS 1 /* One source */ #define SOF_TDFB_NUM_OUTPUT_PINS 1 /* One sink */ -#define SOF_TDFB_MAX_SIZE 4096 /* Max size for coef data in bytes */ +#define SOF_TDFB_MAX_SIZE 16384 /* Max size for coef data in bytes */ #define SOF_TDFB_FIR_MAX_LENGTH 256 /* Max length for individual filter */ #define SOF_TDFB_FIR_MAX_COUNT 16 /* A blob can define max 16 FIR EQs */ #define SOF_TDFB_MAX_STREAMS 8 /* Support 1..8 sinks */ #define SOF_TDFB_MAX_ANGLES 360 /* Up to 1 degree precision for 360 degrees coverage */ -#define SOF_TDFB_MAX_MICROPHONES 16 /* Up to 16 microphone locations */ +#define SOF_TDFB_MAX_MICROPHONES PLATFORM_MAX_CHANNELS /* Bounded by direction state arrays */ /* The driver assigns running numbers for control index. If there's single control of * type switch, enum, binary they all have index 0. diff --git a/src/audio/tdfb/tdfb.toml b/src/audio/tdfb/tdfb.toml index 2fc0875ff5c7..ffd25a63d0c1 100644 --- a/src/audio/tdfb/tdfb.toml +++ b/src/audio/tdfb/tdfb.toml @@ -5,7 +5,7 @@ REM # TDFB module config [[module.entry]] name = "TDFB" - uuid = "DD511749-D9FA-455C-B3A7-13585693F1AF" + uuid = UUIDREG_STR_TDFB affinity_mask = "0x1" instance_count = "40" domain_types = "0" diff --git a/src/audio/tdfb/tdfb_comp.h b/src/audio/tdfb/tdfb_comp.h index e2d5075e06b5..9e0727474f4a 100644 --- a/src/audio/tdfb/tdfb_comp.h +++ b/src/audio/tdfb/tdfb_comp.h @@ -88,6 +88,7 @@ struct tdfb_comp_data { int16_t *output_stream_mix; /**< for each FIR define stream */ int16_t az_value; /**< beam steer azimuth as in control enum */ int16_t az_value_estimate; /**< beam steer azimuth as in control enum */ + size_t config_size; /**< size of the configuration blob */ size_t fir_delay_size; /**< allocated size */ unsigned int max_frames; /**< max frames to process */ bool direction_updates:1; /**< set true if direction angle control is updated */ @@ -118,10 +119,10 @@ void tdfb_fir_s32(struct tdfb_comp_data *cd, struct output_stream_buffer *bsink, int frames); #endif -int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int channels); +int tdfb_direction_init(struct processing_module *mod, int32_t fs, int channels); void tdfb_direction_copy_emphasis(struct tdfb_comp_data *cd, int channels, int *channel, int32_t x); void tdfb_direction_estimate(struct tdfb_comp_data *cd, int frames, int channels); -void tdfb_direction_free(struct tdfb_comp_data *cd); +void tdfb_direction_free(struct processing_module *mod); static inline void tdfb_cinc_s16(int16_t **ptr, int16_t *end, size_t size) { diff --git a/src/audio/tdfb/tdfb_direction.c b/src/audio/tdfb/tdfb_direction.c index 413a5ea5be36..bd435fa2ebd3 100644 --- a/src/audio/tdfb/tdfb_direction.c +++ b/src/audio/tdfb/tdfb_direction.c @@ -8,7 +8,6 @@ #include "tdfb_comp.h" #include <ipc/topology.h> -#include <rtos/alloc.h> #include <sof/math/iir_df1.h> #include <sof/math/trig.h> #include <sof/math/sqrt.h> @@ -109,7 +108,7 @@ static inline int16_t tdfb_mic_distance_sqrt(int32_t x) xs = Q_SHIFT_RND(x, 24, 12); xs = MIN(xs, UINT16_MAX); - return sqrt_int16((uint16_t)xs); + return sofm_sqrt_int16((uint16_t)xs); } static int16_t max_mic_distance(struct tdfb_comp_data *cd) @@ -176,8 +175,9 @@ static bool line_array_mode_check(struct tdfb_comp_data *cd) return true; } -int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int ch_count) +int tdfb_direction_init(struct processing_module *mod, int32_t fs, int ch_count) { + struct tdfb_comp_data *cd = module_get_private_data(mod); struct sof_eq_iir_header *filt; int32_t *delay; int32_t d_max; @@ -200,7 +200,7 @@ int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int ch_count) /* Allocate delay lines for IIR filters and initialize them */ size = ch_count * iir_delay_size_df1(filt); - delay = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, size); + delay = mod_zalloc(mod, size); if (!delay) return -ENOMEM; @@ -225,7 +225,7 @@ int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int ch_count) cd->direction.max_lag = Q_MULTSR_32X32((int64_t)fs, t_max, 0, 15, 0) + 1; n = (cd->max_frames + (2 * cd->direction.max_lag + 1)) * ch_count; cd->direction.d_size = n * sizeof(int16_t); - cd->direction.d = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, cd->direction.d_size); + cd->direction.d = mod_zalloc(mod, cd->direction.d_size); if (!cd->direction.d) goto err_free_iir; @@ -238,7 +238,7 @@ int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int ch_count) /* xcorr result is temporary but too large for stack so it is allocated here */ cd->direction.r_size = (2 * cd->direction.max_lag + 1) * sizeof(int32_t); - cd->direction.r = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, cd->direction.r_size); + cd->direction.r = mod_zalloc(mod, cd->direction.r_size); if (!cd->direction.r) goto err_free_all; @@ -251,20 +251,22 @@ int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int ch_count) return 0; err_free_all: - rfree(cd->direction.d); + mod_free(mod, cd->direction.d); cd->direction.d = NULL; err_free_iir: - rfree(cd->direction.df1_delay); + mod_free(mod, cd->direction.df1_delay); cd->direction.df1_delay = NULL; return -ENOMEM; } -void tdfb_direction_free(struct tdfb_comp_data *cd) +void tdfb_direction_free(struct processing_module *mod) { - rfree(cd->direction.df1_delay); - rfree(cd->direction.d); - rfree(cd->direction.r); + struct tdfb_comp_data *cd = module_get_private_data(mod); + + mod_free(mod, cd->direction.df1_delay); + mod_free(mod, cd->direction.d); + mod_free(mod, cd->direction.r); } /* Measure level of one channel */ @@ -384,7 +386,7 @@ static int16_t distance_from_source(struct tdfb_comp_data *cd, int mic_n, static void theoretical_time_differences(struct tdfb_comp_data *cd, int16_t az) { - int16_t d[PLATFORM_MAX_CHANNELS]; + int16_t d[SOF_TDFB_MAX_MICROPHONES]; int16_t src_x; int16_t src_y; int16_t sin_az; diff --git a/src/audio/tdfb/tdfb_hifi3.c b/src/audio/tdfb/tdfb_hifi3.c index 77225ceefbeb..f5484d337395 100644 --- a/src/audio/tdfb/tdfb_hifi3.c +++ b/src/audio/tdfb/tdfb_hifi3.c @@ -76,8 +76,7 @@ void tdfb_fir_s16(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource /* Compute FIR and mix as Q5.27*/ fir_core_setup_circular(f); - fir_32x16_2x_hifi3(f, cd->in[is], cd->in[is2], &y0, &y1, - shift); + fir_32x16_2x(f, cd->in[is], cd->in[is2], &y0, &y1, shift); for (k = 0; k < out_nch; k++) { if (om & 1) { cd->out[k] += (int32_t)y0 >> 4; @@ -167,8 +166,7 @@ void tdfb_fir_s24(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource /* Compute FIR and mix as Q5.27*/ fir_core_setup_circular(f); - fir_32x16_2x_hifi3(f, cd->in[is], cd->in[is2], &y0, &y1, - shift); + fir_32x16_2x(f, cd->in[is], cd->in[is2], &y0, &y1, shift); for (k = 0; k < out_nch; k++) { if (om & 1) { cd->out[k] += (int32_t)y0 >> 4; @@ -257,8 +255,7 @@ void tdfb_fir_s32(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource /* Compute FIR and mix as Q5.27*/ fir_core_setup_circular(f); - fir_32x16_2x_hifi3(f, cd->in[is], cd->in[is2], &y0, &y1, - shift); + fir_32x16_2x(f, cd->in[is], cd->in[is2], &y0, &y1, shift); for (k = 0; k < out_nch; k++) { if (om & 1) { cd->out[k] += (int32_t)y0 >> 4; diff --git a/src/audio/tdfb/tdfb_hifiep.c b/src/audio/tdfb/tdfb_hifiep.c index 1a8cdc4e397a..d6fea124b542 100644 --- a/src/audio/tdfb/tdfb_hifiep.c +++ b/src/audio/tdfb/tdfb_hifiep.c @@ -42,7 +42,7 @@ static inline void tdfb_core(struct tdfb_comp_data *cd, int in_nch, int out_nch) fir_hifiep_setup_circular(f); fir_get_lrshifts(f, &lshift, &rshift); /* Process two samples */ - fir_32x16_2x_hifiep(f, cd->in[is], cd->in[is2], &y0, &y1, lshift, rshift); + fir_32x16_2x(f, cd->in[is], cd->in[is2], &y0, &y1, lshift, rshift); /* Mix as Q5.27 */ for (k = 0; k < out_nch; k++) { if (om & 1) { diff --git a/src/audio/tdfb/tdfb_ipc3.c b/src/audio/tdfb/tdfb_ipc3.c index cbeba12a983d..1ebdb9641ccf 100644 --- a/src/audio/tdfb/tdfb_ipc3.c +++ b/src/audio/tdfb/tdfb_ipc3.c @@ -30,7 +30,7 @@ static int init_get_ctl_ipc(struct processing_module *mod) struct tdfb_comp_data *cd = module_get_private_data(mod); int comp_id = dev_comp_id(mod->dev); - cd->ctrl_data = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, TDFB_GET_CTRL_DATA_SIZE); + cd->ctrl_data = mod_zalloc(mod, TDFB_GET_CTRL_DATA_SIZE); if (!cd->ctrl_data) return -ENOMEM; @@ -112,18 +112,21 @@ static int tdfb_cmd_get_value(struct processing_module *mod, struct sof_ipc_ctrl { struct tdfb_comp_data *cd = module_get_private_data(mod); + if (cdata->num_elems == 0 || cdata->num_elems > SOF_IPC_MAX_CHANNELS) + return -EINVAL; + switch (cdata->cmd) { case SOF_CTRL_CMD_ENUM: - comp_dbg(mod->dev, "tdfb_cmd_get_value(), SOF_CTRL_CMD_ENUM index=%d", + comp_dbg(mod->dev, "SOF_CTRL_CMD_ENUM index=%d", cdata->index); return tdfb_cmd_enum_get(cdata, cd); case SOF_CTRL_CMD_SWITCH: - comp_dbg(mod->dev, "tdfb_cmd_get_value(), SOF_CTRL_CMD_SWITCH index=%d", + comp_dbg(mod->dev, "SOF_CTRL_CMD_SWITCH index=%d", cdata->index); return tdfb_cmd_switch_get(cdata, cd); } - comp_err(mod->dev, "tdfb_cmd_get_value() error: invalid cdata->cmd"); + comp_err(mod->dev, "error: invalid cdata->cmd"); return -EINVAL; } @@ -137,7 +140,7 @@ int tdfb_get_ipc_config(struct processing_module *mod, if (cdata->cmd != SOF_CTRL_CMD_BINARY) return tdfb_cmd_get_value(mod, cdata); - comp_dbg(mod->dev, "tdfb_get_ipc_config(), binary"); + comp_dbg(mod->dev, "binary"); return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); } @@ -190,16 +193,16 @@ static int tdfb_cmd_set_value(struct processing_module *mod, struct sof_ipc_ctrl switch (cdata->cmd) { case SOF_CTRL_CMD_ENUM: - comp_dbg(mod->dev, "tdfb_cmd_set_value(), SOF_CTRL_CMD_ENUM index=%d", + comp_dbg(mod->dev, "SOF_CTRL_CMD_ENUM index=%d", cdata->index); return tdfb_cmd_enum_set(cdata, cd); case SOF_CTRL_CMD_SWITCH: - comp_dbg(mod->dev, "tdfb_cmd_set_value(), SOF_CTRL_CMD_SWITCH index=%d", + comp_dbg(mod->dev, "SOF_CTRL_CMD_SWITCH index=%d", cdata->index); return tdfb_cmd_switch_set(cdata, cd); } - comp_err(mod->dev, "tdfb_cmd_set_value() error: invalid cdata->cmd"); + comp_err(mod->dev, "error: invalid cdata->cmd"); return -EINVAL; } @@ -215,7 +218,7 @@ int tdfb_set_ipc_config(struct processing_module *mod, uint32_t param_id, if (cdata->cmd != SOF_CTRL_CMD_BINARY) { ret = tdfb_cmd_set_value(mod, cdata); } else { - comp_info(mod->dev, "tdfb_set_ipc_config(), binary"); + comp_info(mod->dev, "binary"); ret = comp_data_blob_set(cd->model_handler, pos, data_offset_size, fragment, fragment_size); } diff --git a/src/audio/tdfb/tdfb_ipc4.c b/src/audio/tdfb/tdfb_ipc4.c index 176d9fa710b5..2f7e7e865214 100644 --- a/src/audio/tdfb/tdfb_ipc4.c +++ b/src/audio/tdfb/tdfb_ipc4.c @@ -109,7 +109,7 @@ int tdfb_get_ipc_config(struct processing_module *mod, uint32_t param_id, uint32_t *data_offset_size, uint8_t *fragment, size_t fragment_size) { - comp_err(mod->dev, "tdfb_get_ipc_config, Not supported, should not happen"); + comp_err(mod->dev, "Not supported, should not happen"); return -EINVAL; } @@ -175,7 +175,7 @@ int tdfb_set_ipc_config(struct processing_module *mod, uint32_t param_id, ctl->id, ctl->num_elems); return tdfb_cmd_enum_set(ctl, cd); default: - comp_info(mod->dev, "tdfb_set_ipc_config(), binary"); + comp_info(mod->dev, "binary"); return comp_data_blob_set(cd->model_handler, pos, data_offset_size, fragment, fragment_size); } @@ -199,6 +199,8 @@ int tdfb_params(struct processing_module *mod) ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); component_set_nearest_period_frames(dev, params->rate); + + /* The caller has verified source and sink buffer validity */ sourceb = comp_dev_get_first_data_producer(dev); ipc4_update_buffer_format(sourceb, &mod->priv.cfg.input_pins[0].audio_fmt); diff --git a/src/audio/tdfb/tune/sof_bf_blob_pack.m b/src/audio/tdfb/tune/sof_bf_blob_pack.m index 2717595aa10a..d1e91931f215 100644 --- a/src/audio/tdfb/tune/sof_bf_blob_pack.m +++ b/src/audio/tdfb/tune/sof_bf_blob_pack.m @@ -143,7 +143,7 @@ nbytes_data = nb16 * 2; %% Get ABI information -[abi_bytes, nbytes_abi] = get_abi(nbytes_data, ipc_version); +[abi_bytes, nbytes_abi] = sof_get_abi(nbytes_data, ipc_version); %% Initialize uint8 array with correct size nbytes = nbytes_abi + nbytes_data; diff --git a/src/audio/tdfb/tune/sof_bf_export.m b/src/audio/tdfb/tune/sof_bf_export.m index 874ac6f9f78b..a1856cc2a769 100644 --- a/src/audio/tdfb/tune/sof_bf_export.m +++ b/src/audio/tdfb/tune/sof_bf_export.m @@ -84,16 +84,14 @@ fprintf(1, 'No sof-ctl3 output file specified.\n'); else fprintf(1, 'Exporting to %s\n', bf.sofctl3_fn); - mkdir_check(bf.sofctl3_path); - alsactl_write(bf.sofctl3_fn, bp3); + sof_alsactl_write(bf.sofctl3_fn, bp3); end if isempty(bf.sofctl4_fn) fprintf(1, 'No sof-ctl4 output file specified.\n'); else fprintf(1, 'Exporting to %s\n', bf.sofctl4_fn); - mkdir_check(bf.sofctl4_path); - alsactl_write(bf.sofctl4_fn, bp4); + sof_alsactl_write(bf.sofctl4_fn, bp4); end if isempty(bf.export_note) @@ -106,27 +104,23 @@ fprintf(1, 'No topology1 output file specified.\n'); else fprintf(1, 'Exporting to %s\n', bf.tplg1_fn); - mkdir_check(bf.tplg1_path); - tplg_write(bf.tplg1_fn, bp3, 'DEF_TDFB_PRIV', export_note, bf.export_howto); + sof_tplg_write(bf.tplg1_fn, bp3, 'DEF_TDFB_PRIV', export_note, bf.export_howto); end if isempty(bf.tplg2_fn) fprintf(1, 'No topology2 output file specified.\n'); else fprintf(1, 'Exporting to %s\n', bf.tplg2_fn); - mkdir_check(bf.tplg2_path); - tplg2_write(bf.tplg2_fn, bp4, "tdfb_config", export_note, bf.export_howto); + sof_tplg2_write(bf.tplg2_fn, bp4, "tdfb_config", export_note, bf.export_howto); end if ~isempty(bf.ucmbin3_fn) fprintf(1, 'Exporting to %s\n', bf.ucmbin3_fn); - mkdir_check(bf.sofctl3_path); sof_ucm_blob_write(bf.ucmbin3_fn, bp3); end if ~isempty(bf.ucmbin4_fn) fprintf(1, 'Exporting to %s\n', bf.ucmbin4_fn); - mkdir_check(bf.sofctl4_path); sof_ucm_blob_write(bf.ucmbin4_fn, bp4); end diff --git a/src/audio/template/CMakeLists.txt b/src/audio/template/CMakeLists.txt new file mode 100644 index 000000000000..1dec4618ed5c --- /dev/null +++ b/src/audio/template/CMakeLists.txt @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_COMP_TEMPLATE STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/template_llext) + add_dependencies(app template) +else() + add_local_sources(sof template.c) + add_local_sources(sof template-generic.c) + + if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof template-ipc3.c) + elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof template-ipc4.c) + endif() +endif() diff --git a/src/audio/template/Kconfig b/src/audio/template/Kconfig new file mode 100644 index 000000000000..907749c5fa8e --- /dev/null +++ b/src/audio/template/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config COMP_TEMPLATE + tristate "Template example component" + default y + help + Select for template component. Reason for existence + is to provide a minimal component example and use as + placeholder in processing pipelines. As example processing + it swaps or reverses the channels when the switch control + is enabled. diff --git a/src/audio/template/README.md b/src/audio/template/README.md new file mode 100644 index 000000000000..93e48c80f2cc --- /dev/null +++ b/src/audio/template/README.md @@ -0,0 +1,14 @@ +# Template Component Architecture + +This directory contains template code. + +## Overview + +Provides a reference or stub implementation that developers can copy and modify to easily construct new custom audio components. + +## Configuration and Scripts + +- **Kconfig**: Exposes the `COMP_TEMPLATE` toggle to build the baseline framework plugin (internally swaps or reverses channels). +- **CMakeLists.txt**: Compiles generic operations (`template.c`, `template-generic.c`) and connects via either IPC major version. Generates a Zephyr `llext` by default. +- **template.toml**: Includes default setup arguments and UUID bindings (`UUIDREG_STR_TEMPLATE`). +- **Topology (.conf)**: Defined in `tools/topology/topology2/include/components/template_comp.conf`, registering the `template_comp` widget of type `effect` (UUID `af:e1:2d:a6:64:59:2e:4e:b1:67:7f:dc:97:27:9a:29`). diff --git a/src/audio/template/llext/CMakeLists.txt b/src/audio/template/llext/CMakeLists.txt new file mode 100644 index 000000000000..f84bd6daf916 --- /dev/null +++ b/src/audio/template/llext/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +sof_llext_build("template_comp" + SOURCES ../template.c + ../template-generic.c + ../template-ipc4.c + LIB openmodules +) diff --git a/src/audio/template/llext/llext.toml.h b/src/audio/template/llext/llext.toml.h new file mode 100644 index 000000000000..4808c9af8f42 --- /dev/null +++ b/src/audio/template/llext/llext.toml.h @@ -0,0 +1,6 @@ +#include <tools/rimage/config/platform.toml> +#define LOAD_TYPE "2" +#include "../template_comp.toml" + +[module] +count = __COUNTER__ diff --git a/src/audio/template/template-generic.c b/src/audio/template/template-generic.c new file mode 100644 index 000000000000..14b68c31d9c5 --- /dev/null +++ b/src/audio/template/template-generic.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/source_api.h> +#include <stdint.h> +#include "template.h" + +#if CONFIG_FORMAT_S16LE +/** + * template_s16() - Process S16_LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * This is the processing function for 16-bit signed integer PCM formats. The + * audio samples in every frame are re-order to channels order defined in + * component data channel_map[]. + * + * Return: Value zero for success, otherwise an error code. + */ +static int template_s16(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct template_comp_data *cd = module_get_private_data(mod); + int16_t const *x, *x_start, *x_end; + int16_t *y, *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int ch; + int i; + + /* Get pointer to source data in circular buffer, get buffer start and size to + * check for wrap. The size in bytes is converted to number of s16 samples to + * control the samples process loop. If the number of bytes requested is not + * possible, an error is returned. + */ + ret = source_get_data_s16(source, bytes, &x, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s16(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - x; + samples_without_wrap = y_end - y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, samples); + + /* Since the example processing is for frames of audio channels, process + * with step of channels count. + */ + for (i = 0; i < samples_without_wrap; i += cd->channels) { + /* In inner loop process the frame. As example re-arrange the channels + * as defined in array channel_map[]. + */ + for (ch = 0; ch < cd->channels; ch++) { + *y = *(x + cd->channel_map[ch]); + y++; + } + x += cd->channels; + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= x_end) ? x - x_size : x; + y = (y >= y_end) ? y - y_size : y; + + /* Update processed samples count for next loop iteration. */ + samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S24LE +/** + * template_s32() - Process S32_LE or S24_4LE format. + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * Processing function for signed integer 32-bit PCM formats. The same + * function works for s24 and s32 formats since the samples values are + * not modified in computation. The audio samples in every frame are + * re-order to channels order defined in component data channel_map[]. + * + * Return: Value zero for success, otherwise an error code. + */ +static int template_s32(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) +{ + struct template_comp_data *cd = module_get_private_data(mod); + int32_t const *x, *x_start, *x_end; + int32_t *y, *y_start, *y_end; + int x_size, y_size; + int source_samples_without_wrap; + int samples_without_wrap; + int samples = frames * cd->channels; + int bytes = frames * cd->frame_bytes; + int ret; + int ch; + int i; + + /* Get pointer to source data in circular buffer, get buffer start and size to + * check for wrap. The size in bytes is converted to number of s16 samples to + * control the samples process loop. If the number of bytes requested is not + * possible, an error is returned. + */ + ret = source_get_data_s32(source, bytes, &x, &x_start, &x_size); + if (ret) + return ret; + + /* Similarly get pointer to sink data in circular buffer, buffer start and size. */ + ret = sink_get_buffer_s32(sink, bytes, &y, &y_start, &y_size); + if (ret) + return ret; + + /* Set helper pointers to buffer end for wrap check. Then loop until all + * samples are processed. + */ + x_end = x_start + x_size; + y_end = y_start + y_size; + while (samples) { + /* Find out samples to process before first wrap or end of data. */ + source_samples_without_wrap = x_end - x; + samples_without_wrap = y_end - y; + samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); + samples_without_wrap = MIN(samples_without_wrap, samples); + + /* Since the example processing is for frames of audio channels, process + * with step of channels count. + */ + for (i = 0; i < samples_without_wrap; i += cd->channels) { + /* In inner loop process the frame. As example re-arrange the channels + * as defined in array channel_map[]. + */ + for (ch = 0; ch < cd->channels; ch++) { + *y = *(x + cd->channel_map[ch]); + y++; + } + x += cd->channels; + } + + /* One of the buffers needs a wrap (or end of data), so check for wrap */ + x = (x >= x_end) ? x - x_size : x; + y = (y >= y_end) ? y - y_size : y; + + /* Update processed samples count for next loop iteration. */ + samples -= samples_without_wrap; + } + + /* Update the source and sink for bytes consumed and produced. Return success. */ + source_release_data(source, bytes); + sink_commit_buffer(sink, bytes); + return 0; +} +#endif /* CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S24LE */ + +/* This struct array defines the used processing functions for + * the PCM formats + */ +const struct template_proc_fnmap template_proc_fnmap[] = { +#if CONFIG_FORMAT_S16LE + { SOF_IPC_FRAME_S16_LE, template_s16 }, +#endif +#if CONFIG_FORMAT_S24LE + { SOF_IPC_FRAME_S24_4LE, template_s32 }, +#endif +#if CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S32_LE, template_s32 }, +#endif +}; + +/** + * template_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +template_func template_find_proc_func(enum sof_ipc_frame src_fmt) +{ + int i; + + /* Find suitable processing function from map */ + for (i = 0; i < ARRAY_SIZE(template_proc_fnmap); i++) + if (src_fmt == template_proc_fnmap[i].frame_fmt) + return template_proc_fnmap[i].template_proc_func; + + return NULL; +} diff --git a/src/audio/template/template-ipc3.c b/src/audio/template/template-ipc3.c new file mode 100644 index 000000000000..ad35389341f6 --- /dev/null +++ b/src/audio/template/template-ipc3.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include "template.h" + +LOG_MODULE_DECLARE(template, CONFIG_SOF_LOG_LEVEL); + +/* This function handles the real-time controls. The ALSA controls have the + * param_id set to indicate the control type. The control ID, from topology, + * is used to separate the controls instances of same type. In control payload + * the num_elems defines to how many channels the control is applied to. + */ +__cold int template_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 sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + struct template_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + + assert_can_be_cold(); + + comp_dbg(dev, "entry"); + + switch (cdata->cmd) { + case SOF_CTRL_CMD_SWITCH: + if (cdata->index != 0) { + comp_err(dev, "Illegal switch control index = %d.", cdata->index); + return -EINVAL; + } + + if (cdata->num_elems != 1) { + comp_err(dev, "Illegal switch control num_elems = %d.", cdata->num_elems); + return -EINVAL; + } + + cd->enable = cdata->chanv[0].value; + comp_info(dev, "Setting enable = %d.", cd->enable); + return 0; + + case SOF_CTRL_CMD_ENUM: + comp_err(dev, "Illegal enum control, no support in this component."); + return -EINVAL; + case SOF_CTRL_CMD_BINARY: + comp_err(dev, "Illegal bytes control, no support in this component."); + return -EINVAL; + } + + comp_err(dev, "Illegal control, unknown type."); + return -EINVAL; +} + +__cold int template_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) +{ + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + struct template_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + + assert_can_be_cold(); + + comp_info(dev, "entry"); + + switch (cdata->cmd) { + case SOF_CTRL_CMD_SWITCH: + if (cdata->index != 0) { + comp_err(dev, "Illegal switch control index = %d.", cdata->index); + return -EINVAL; + } + + if (cdata->num_elems != 1) { + comp_err(dev, "Illegal switch control num_elems = %d.", cdata->num_elems); + return -EINVAL; + } + + cdata->chanv[0].value = cd->enable; + return 0; + + case SOF_CTRL_CMD_ENUM: + comp_err(dev, "Illegal enum control, no support in this component."); + return -EINVAL; + + case SOF_CTRL_CMD_BINARY: + comp_err(dev, "Illegal bytes control, no support in this component."); + return -EINVAL; + } + + comp_err(dev, "Illegal control, unknown type."); + return -EINVAL; +} diff --git a/src/audio/template/template-ipc4.c b/src/audio/template/template-ipc4.c new file mode 100644 index 000000000000..f66015d9041c --- /dev/null +++ b/src/audio/template/template-ipc4.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include "template.h" + +LOG_MODULE_DECLARE(template, CONFIG_SOF_LOG_LEVEL); + +/* IPC4 controls handler */ +__cold int template_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 sof_ipc4_control_msg_payload *ctl = (struct sof_ipc4_control_msg_payload *)fragment; + struct template_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + + assert_can_be_cold(); + + switch (param_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + comp_dbg(dev, "Switch control id = %d, num_elems = %d.", ctl->id, ctl->num_elems); + if (ctl->id != 0) { + comp_err(dev, "Illegal switch control id = %d.", ctl->id); + return -EINVAL; + } + + if (ctl->num_elems != 1) { + comp_err(dev, "Illegal switch control num_elems = %d.", ctl->num_elems); + return -EINVAL; + } + + cd->enable = ctl->chanv[0].value; + comp_info(dev, "Setting enable = %d.", cd->enable); + return 0; + + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + comp_err(dev, "Illegal enum control, no support in this component."); + return -EINVAL; + } + + comp_err(mod->dev, "Illegal bytes control, no support in this component."); + return -EINVAL; +} + +/* Not used in IPC4 systems, if IPC4 only component, omit .get_configuration set */ +__cold int template_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) +{ + assert_can_be_cold(); + return 0; +} diff --git a/src/audio/template/template.c b/src/audio/template/template.c new file mode 100644 index 000000000000..1bef6668b75e --- /dev/null +++ b/src/audio/template/template.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/sink_source_utils.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/source_api.h> +#include <rtos/init.h> +#include "template.h" + +/* UUID identifies the components. Use e.g. command uuidgen from package + * uuid-runtime, add it to uuid-registry.txt in SOF top level. + */ +SOF_DEFINE_REG_UUID(template); + +/* Creates logging data for the component */ +LOG_MODULE_REGISTER(template, CONFIG_SOF_LOG_LEVEL); + +/** + * template_init() - Initialize the template component. + * @mod: Pointer to module data. + * + * This function is called when the instance is created. The + * macro __cold informs that the code that is non-critical + * is loaded to slower but large DRAM. + * + * Return: Zero if success, otherwise error code. + */ +__cold static int template_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct comp_dev *dev = mod->dev; + struct template_comp_data *cd; + + comp_info(dev, "entry"); + + cd = mod_zalloc(mod, sizeof(*cd)); + if (!cd) + return -ENOMEM; + + md->private = cd; + return 0; +} + +/** + * template_process() - The audio data processing function. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * This is the processing function that is called for scheduled + * pipelines. The processing is controlled by the enable switch. + * + * Return: Zero if success, otherwise error code. + */ +static int template_process(struct processing_module *mod, + struct sof_source **sources, + int num_of_sources, + struct sof_sink **sinks, + int num_of_sinks) +{ + struct template_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + struct sof_source *source = sources[0]; /* One input in this example */ + struct sof_sink *sink = sinks[0]; /* One output in this example */ + int frames = source_get_data_frames_available(source); + int sink_frames = sink_get_free_frames(sink); + + comp_dbg(dev, "entry"); + + frames = MIN(frames, sink_frames); + if (cd->enable) + /* Process the data with the channels swap example function. */ + return cd->template_func(mod, source, sink, frames); + + /* Just copy from source to sink. */ + source_to_sink_copy(source, sink, true, frames * cd->frame_bytes); + return 0; +} + +/** + * template_prepare() - Prepare the component for processing. + * @mod: Pointer to module data. + * @sources: Pointer to audio samples data sources array. + * @num_of_sources: Number of sources in the array. + * @sinks: Pointer to audio samples data sinks array. + * @num_of_sinks: Number of sinks in the array. + * + * Function prepare is called just before the pipeline is started. In + * this case the audio format parameters are for better code performance + * saved to component data to avoid to find out them in process. The + * processing function pointer is set to process the current audio format. + * + * Return: Value zero if success, otherwise error code. + */ +static int template_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct template_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + enum sof_ipc_frame source_format; + int i; + + comp_dbg(dev, "entry"); + + /* The processing example in this component supports one input and one + * output. Generally there can be more. + */ + if (num_of_sources != 1 || num_of_sinks != 1) + return -EINVAL; + + /* get source data format */ + cd->frame_bytes = source_get_frame_bytes(sources[0]); + cd->channels = source_get_channels(sources[0]); + source_format = source_get_frm_fmt(sources[0]); + + /* Initialize channels order for reversing */ + for (i = 0; i < cd->channels; i++) + cd->channel_map[i] = cd->channels - i - 1; + + cd->template_func = template_find_proc_func(source_format); + if (!cd->template_func) { + comp_err(dev, "No processing function found for format %d.", + source_format); + return -EINVAL; + } + + return 0; +} + +/** + * template_reset() - Reset the component. + * @mod: Pointer to module data. + * + * The component reset is called when pipeline is stopped. The reset + * should return the component to same state as init. + * + * Return: Value zero, always success. + */ +static int template_reset(struct processing_module *mod) +{ + struct template_comp_data *cd = module_get_private_data(mod); + + comp_dbg(mod->dev, "entry"); + memset(cd, 0, sizeof(*cd)); + return 0; +} + +/** + * template_free() - Free dynamic allocations. + * @mod: Pointer to module data. + * + * Component free is called when the pipelines are deleted. All + * dynamic allocations need to be freed here. The macro __cold + * instructs the build to locate this performance wise non-critical + * function to large and slower DRAM. + * + * Return: Value zero, always success. + */ +__cold static int template_free(struct processing_module *mod) +{ + struct template_comp_data *cd = module_get_private_data(mod); + + assert_can_be_cold(); + + comp_dbg(mod->dev, "entry"); + mod_free(mod, cd); + return 0; +} + +/* This defines the module operations */ +static const struct module_interface template_interface = { + .init = template_init, + .prepare = template_prepare, + .process = template_process, + .set_configuration = template_set_config, + .get_configuration = template_get_config, + .reset = template_reset, + .free = template_free +}; + +/* This controls build of the module. If COMP_MODULE is selected in kconfig + * this is build as dynamically loadable module. + */ +#if CONFIG_COMP_TEMPLATE_MODULE + +#include <module/module/api_ver.h> +#include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> + +static const struct sof_man_module_manifest mod_manifest __section(".module") __used = + SOF_LLEXT_MODULE_MANIFEST("TEMPLATE", &template_interface, 1, + SOF_REG_UUID(template), 40); + +SOF_LLEXT_BUILDINFO; + +#else + +/* Only used for the module adapter trace context, soon to be deprecated */ +DECLARE_TR_CTX(template_tr, SOF_UUID(template_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(template_interface, template_uuid, template_tr); +SOF_MODULE_INIT(template, sys_comp_module_template_interface_init); + +#endif diff --git a/src/audio/template/template.h b/src/audio/template/template.h new file mode 100644 index 000000000000..c139a492e6c0 --- /dev/null +++ b/src/audio/template/template.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + * + */ +#ifndef __SOF_AUDIO_TEMPLATE_H__ +#define __SOF_AUDIO_TEMPLATE_H__ + +#include <sof/audio/module_adapter/module/generic.h> +#include <stdbool.h> +#include <stdint.h> + +/** + * struct template_func - Function call pointer for process function + * @mod: Pointer to module data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + */ +typedef int (*template_func)(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames); + +/* Template component private data */ + +/** + * struct template_comp_data + * @template_func: Pointer to used processing function. + * @channels_order[]: Vector with desired sink channels order. + * @source_format: Source samples format. + * @frame_bytes: Number of bytes in an audio frame. + * @channels: Channels count. + * @enable: Control processing on/off, on - reorder channels + */ +struct template_comp_data { + template_func template_func; + int channel_map[PLATFORM_MAX_CHANNELS]; + int source_format; + int frame_bytes; + int channels; + bool enable; +}; + +/** + * struct template_proc_fnmap - processing functions for frame formats + * @frame_fmt: Current frame format + * @template_proc_func: Function pointer for the suitable processing function + */ +struct template_proc_fnmap { + enum sof_ipc_frame frame_fmt; + template_func template_proc_func; +}; + +/** + * template_find_proc_func() - Find suitable processing function. + * @src_fmt: Enum value for PCM format. + * + * This function finds the suitable processing function to use for + * the used PCM format. If not found, return NULL. + * + * Return: Pointer to processing function for the requested PCM format. + */ +template_func template_find_proc_func(enum sof_ipc_frame src_fmt); + +/** + * template_set_config() - Handle controls set + * @mod: Pointer to module data. + * @param_id: Id to know control type, used to know ALSA control type. + * @pos: Position of the fragment in the large message. + * @data_offset_size: Size of the whole configuration if it is the first or only + * fragment. Otherwise it is offset of the fragment. + * @fragment: Message payload data. + * @fragment_size: Size of this fragment. + * @response_size: Size of response. + * + * This function handles the real-time controls. The ALSA controls have the + * param_id set to indicate the control type. The control ID, from topology, + * is used to separate the controls instances of same type. In control payload + * the num_elems defines to how many channels the control is applied to. + * + * Return: Zero if success, otherwise error code. + */ +int template_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); + +/** + * template_set_config() - Handle controls get + * @mod: Pointer to module data. + * @config_id: Configuration ID. + * @data_offset_size: Size of the whole configuration if it is the first or only + * fragment. Otherwise it is offset of the fragment. + * @fragment: Message payload data. + * @fragment_size: Size of this fragment. + * + * This function is used for controls get. + * + * Return: Zero if success, otherwise error code. + */ +int template_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size); + +#endif // __SOF_AUDIO_TEMPLATE_H__ diff --git a/src/audio/template/template.toml b/src/audio/template/template.toml new file mode 100644 index 000000000000..6d41f3a599f5 --- /dev/null +++ b/src/audio/template/template.toml @@ -0,0 +1,21 @@ +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + + REM # Template component module config + [[module.entry]] + name = "TEMPLATE" + uuid = UUIDREG_STR_TEMPLATE + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = LOAD_TYPE + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + REM # 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] + + index = __COUNTER__ diff --git a/src/audio/tensorflow/CMakeLists.txt b/src/audio/tensorflow/CMakeLists.txt new file mode 100644 index 000000000000..5cb3086f46b1 --- /dev/null +++ b/src/audio/tensorflow/CMakeLists.txt @@ -0,0 +1,465 @@ +# Copyright (c) 2025 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +# are we building the llext module ? +if(CONFIG_COMP_TENSORFLOW STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/tflm_llext) + add_dependencies(app tflm) + return() +endif() + +# TODO: detect Hifi4/5 for NN lib kernels +set(NN_HIFI_PATH ${sof_top_dir}/../nnlib-hifi4/xa_nnlib) + +# paths for dependencies +set(TFLM_PATH ${sof_top_dir}/../tflite-micro) +set(FLATBUFFERS_PATH ${sof_top_dir}/../flatbuffers) +set(GEMMLOWP_PATH ${sof_top_dir}/../gemmlowp) +set(RUY_PATH ${sof_top_dir}/../ruy) + +add_library(nn_hifi_lib STATIC + ${NN_HIFI_PATH}/algo/common/src/xa_nnlib_common_api.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_pad_8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_stride_slice_int16.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_batch_to_space_nd_8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_transpose_8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_depth_to_space_8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_pad_16.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_stride_slice_int32.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_space_to_batch_nd_8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_pad_32.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_stride_slice_int8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_space_to_depth_8.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_32_32.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_f32_f32.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_sym16_sym16.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_softmax_asym8_asym8.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_32_16.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_16_16.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_8_8.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_asym16_asym16.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_32_8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_16x16_16_circ_nb.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_16x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_16x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_transpose_conv_circ_buf.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_group_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_asym8xasym8_asym8_circ_nb.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_8x8_8_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_8x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_circ_buf.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_8x8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_16x16_16_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_transpose_conv_f32.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_f32.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_f32_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_circ_buf.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_transpose_conv_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_8x16_16_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_sym8sxsym16s_sym16s_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_8x8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_8x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_f32.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_f32_circ_nb.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_asym8xasym8_asym8_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_8x8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_transpose_conv_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_f32.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_8x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_8x8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_16x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_sym8sxasym8s_asym8s_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_circ_buf.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_8x16_16_circ_nb.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_16x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_8x8_8_circ_nb.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_sym4sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_f32.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_8x16.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_f32.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_asym8xasym8_batch.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_8x8.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_8x16.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_asym4sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_f32_batch.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_f32.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_16x16_batch.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_asym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_16x8.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_8x16.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_8x8.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_asym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_16x16.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_8x16_batch.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_16x16.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_8x8_batch.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_f32.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_8.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_asym8_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_f32_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_16_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_16.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_16_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_asym8.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_inv_256_tbl.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_8_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_16.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_8.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_f32_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_asym8_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_f32.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_asym8.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_8_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/norm/hifi4/xa_nn_l2_norm_asym8s.c + ${NN_HIFI_PATH}/algo/kernels/norm/hifi4/xa_nn_l2_norm_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_sqrt_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_mul_16x16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_add_quant8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_mul_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_lstm_utils.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_dot_prod_16x16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_sub_quant16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_round_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_mul_acc_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_cosine_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_reduce_asym8s_asym8s.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_memset_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_floor_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_squared_diff_quant8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_add_quant16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_reduce_asym16s_asym16s.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_minmax_8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_logn_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_div_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_sub_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_compare_quant8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_logical_bool.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_broadcast_8_8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_quantize.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_neg_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_mul_quant16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_add_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_vec_interpolation_q15.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_square_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_sine_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_abs_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_memmove.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_mul_quant8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_squared_diff_quant16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_memmove_16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_sub_quant8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_ceil_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_rsqrt_f32.c + ${NN_HIFI_PATH}/algo/kernels/fc/hifi4/xa_nn_fully_connected.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_tanh32x32_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/scl_sigmoidf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/inv2pif_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/nanf_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/pow2f_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_sigmoidf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_reluf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/expf_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_tanhf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_sigmoid32x32_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/lognf_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/sinf_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_cosinef_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_sinef_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_softmaxf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/scl_tanhf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_softmax32x32_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_lognf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/sqrt2f_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/inff_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_alognf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_relu32x32_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/tanhf_tbl.c +) + +target_include_directories(nn_hifi_lib PRIVATE + ${NN_HIFI_PATH}/include + ${NN_HIFI_PATH}/algo/common/include/ + ${NN_HIFI_PATH}/include/nnlib/ + ${NN_HIFI_PATH}/algo/ndsp/hifi4/include +) + +# TODO: Need to detect and add mul16/32 options. +#ifeq "$(has_mul16)" "0" +#CFLAGS += -mno-mul16 +#endif +#ifeq "$(has_mul32)" "0" +#CFLAGS += -mno-mul32 -mno-div32 +#endif +target_compile_options(nn_hifi_lib PRIVATE + -fsigned-char + -fno-exceptions + -mlongcalls + -INLINE:requested + -mcoproc + -fno-zero-initialized-in-bss + -mtext-section-literals + -Wsign-compare + -m32 + -DMODEL_INT16 + -DNNLIB_V2 + -Dhifi4 + -DTFLITE_SINGLE_ROUNDING=1 +) + +# TODO: complete sources have been added here from userspace build but +# not all are needed so this is a list of "needed" sources to build +# a memory and performance optimized TFLM for SOF. +# All sources have been left in for completeness now, but will be removed +# when support is mature. +add_library(tflm_lib STATIC + ${TFLM_PATH}/tensorflow/compiler/mlir/lite/core/api/error_reporter.cc + ${TFLM_PATH}/tensorflow/compiler/mlir/lite/schema/schema_utils.cc + ${TFLM_PATH}/tensorflow/lite/core/c/common.cc + ${TFLM_PATH}/tensorflow/lite/core/api/flatbuffer_conversions.cc + ${TFLM_PATH}/tensorflow/lite/core/api/tensor_utils.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/common.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/tensor_utils.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/runtime_shape.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/quantization_util.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/tensor_ctypes.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/portable_tensor_utils.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/reference/comparisons.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/reference/portable_tensor_utils.cc + ${TFLM_PATH}/tensorflow/lite/kernels/kernel_util.cc + # Stock micro kernels - not needed atm + #${TFLM_PATH}/tensorflow/lite/micro/kernels/activations_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/activations.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/add_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/add_n.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/arg_min_max.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/assign_variable.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/batch_matmul.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/batch_to_space_nd.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/broadcast_args.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/broadcast_to.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/call_once.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/cast.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/ceil.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/circular_buffer_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/circular_buffer.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/comparisons.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/concatenation.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/conv_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/cumsum.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/depth_to_space.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/depthwise_conv_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/dequantize_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/detection_postprocess.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/div.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/elementwise.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/elu.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/embedding_lookup.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/ethosu.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/expand_dims.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/exp.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/fill.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/floor_div.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/floor_mod.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/floor.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/fully_connected_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/gather_nd.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/gather.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/hard_swish_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/hard_swish.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/if.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/kernel_runner.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/kernel_util.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/l2norm.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/l2_pool_2d.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/leaky_relu_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/logical_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/logical.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/logistic_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/log_softmax.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/lstm_eval_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/maximum_minimum.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/micro_tensor_utils.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/mirror_pad.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/mul_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/mul.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/neg.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/pack.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/pooling_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/prelu_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/prelu.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/quantize_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/read_variable.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/reduce_common.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/reshape_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/resize_bilinear.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/resize_nearest_neighbor.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/round.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/select.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/shape.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/slice.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/softmax_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/space_to_batch_nd.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/space_to_depth.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/split.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/split_v.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/squared_difference.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/squeeze.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/strided_slice_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/sub_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/svdf_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/tanh.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/transpose.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/unpack.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/var_handle.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/while.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/zeros_like.cc + # xtensa kernels + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/sub.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_hifi.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/pooling_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/softmax_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/unidirectional_sequence_lstm.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/transpose_conv.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/fully_connected_common_xtensa.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/lstm_eval_hifi.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/add_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/depthwise_conv.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/reshape.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/softmax.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/depthwise_conv_hifi.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_int16_reference.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_int8_reference.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/fully_connected_int8.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/pad_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/fully_connected_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_int8_int16.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/softmax_int8_int16.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/logistic.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/reduce.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/lstm_eval.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/reshape_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/pad.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/reduce_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/dequantize.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/add.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/pooling_int8.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/depthwise_conv_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/strided_slice.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_common_xtensa.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/svdf.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/fully_connected.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/leaky_relu.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/quantize.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/pooling.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/mock_micro_graph.cc + ${TFLM_PATH}/tensorflow/lite/micro/flatbuffer_utils.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_interpreter_graph.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_resource_variable.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_interpreter_context.cc + ${TFLM_PATH}/tensorflow/lite/micro/fake_micro_context.cc + ${TFLM_PATH}/tensorflow/lite/micro/arena_allocator/persistent_arena_buffer_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/arena_allocator/recording_single_arena_buffer_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/arena_allocator/non_persistent_arena_buffer_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/tflite_bridge/flatbuffer_conversions_bridge.cc + ${TFLM_PATH}/tensorflow/lite/micro/tflite_bridge/micro_error_reporter.cc + ${TFLM_PATH}/tensorflow/lite/micro/system_setup.cc + #${TFLM_PATH}/tensorflow/lite/micro/span_test.cc + ${TFLM_PATH}/tensorflow/lite/micro/test_helper_custom_ops.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_context.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_log.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_profiler.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_time.cc + #${TFLM_PATH}/tensorflow/lite/micro/static_vector_test.cc + ${TFLM_PATH}/tensorflow/lite/micro/debug_log.cc + ${TFLM_PATH}/tensorflow/lite/micro/test_helpers.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_op_resolver.cc + ${TFLM_PATH}/tensorflow/lite/micro/recording_micro_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/memory_helpers.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_allocation_info.cc + ${TFLM_PATH}/tensorflow/lite/micro/memory_planner/greedy_memory_planner.cc + ${TFLM_PATH}/tensorflow/lite/micro/memory_planner/non_persistent_buffer_planner_shim.cc + ${TFLM_PATH}/tensorflow/lite/micro/memory_planner/linear_memory_planner.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_utils.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_interpreter.cc + micro_speech_quantized_model_data.cc + speech.cc +) + +target_include_directories(tflm_lib PRIVATE + ${TFLM_PATH} + ${FLATBUFFERS_PATH}/include + ${GEMMLOWP_PATH} + ${RUY_PATH} + ${NN_HIFI_PATH} + ${NN_HIFI_PATH}/include + ${sof_top_dir}/posix/include +) + +# TODO: Need to detect and add mul16/32 options. +#ifeq "$(has_mul16)" "0" +#CFLAGS += -mno-mul16 +#endif +#ifeq "$(has_mul32)" "0" +#CFLAGS += -mno-mul32 -mno-div32 +#endif +target_compile_options(tflm_lib PRIVATE + -std=c++17 + -stdlib=libc++ + -fno-rtti + -fno-exceptions + -fno-threadsafe-statics + -Wnon-virtual-dtor + -fno-unwind-tables + -fmessage-length=0 + -DTF_LITE_STATIC_MEMORY + -DTF_LITE_DISABLE_X86_NEON + -Wsign-compare + -Wdouble-promotion + -Wunused-variable + -Wswitch + -Wvla + -Wall + -Wextra + -Wmissing-field-initializers + -Wstrict-aliasing + -Wno-unused-parameter + -DXTENSA + -DKERNELS_OPTIMIZED_FOR_SPEED + -DTF_LITE_MCU_DEBUG_LOG + -DTF_LITE_USE_CTIME + --xtensa-core=ace10_LX7HiFi4_2022_10 + -mcoproc + -DHIFI4 + -mlongcalls + -DNNLIB_V2 + -Wno-shadow +) + +add_local_sources(sof tflm-classify.c llext-wrap.c) + +# Need to link libc++ and libc after tflm and nnlib +zephyr_link_libraries(tflm_lib nn_hifi_lib c++ c) +zephyr_include_directories(${TFLM_PATH}) diff --git a/src/audio/tensorflow/Kconfig b/src/audio/tensorflow/Kconfig new file mode 100644 index 000000000000..446f9add2849 --- /dev/null +++ b/src/audio/tensorflow/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config COMP_TENSORFLOW + tristate "Tensorflow Micro component" + depends on SOF_STAGING + depends on CPP + depends on STD_CPP17 + help + Select for Tensorflow component support. This module supports + Tensorflow Micro library. It is used for running machine learning + models on DSP. It is a lightweight version of Tensorflow library + designed for microcontrollers and embedded systems. diff --git a/src/audio/tensorflow/README.md b/src/audio/tensorflow/README.md new file mode 100644 index 000000000000..a8e3f59ba3ce --- /dev/null +++ b/src/audio/tensorflow/README.md @@ -0,0 +1,22 @@ +# TensorFlow Lite Micro (TFLM) Architecture + +This directory acts as the bridge for running ML models. + +## Overview + +Integrates TensorFlow Lite for Microcontrollers into the SOF audio pipeline. Evaluates pre-trained neural network topologies inline with the audio stream for tasks like wake-word, noise cancellation, or sound classification. + +## Architecture Diagram + +```mermaid +graph LR + Feat[Audio Features] --> TFLM[TFLM Inference Engine] + SubGraph[FlatBuffer Model] -.-> TFLM + TFLM --> Out[Inference Labels/Scores] +``` + +## Configuration and Scripts + +- **Kconfig**: Enforces requirements for C++17 support and core framework staging logic (`COMP_TENSORFLOW`). +- **CMakeLists.txt**: An intricate build specification linking the Tensilica neural network library block computations (`nn_hifi_lib`) and the TensorFlow Lite micro core engine (`tflm_lib`). Also hooks the `tflm-classify.c` SOF adapter via compiler flags explicitly enforcing memory, precision, and XTENSA optimizations. +- **tflmcly.toml**: Topology definition for the specific TFLM Classifier implementation binding the engine against the UUID `UUIDREG_STR_TFLMCLY`. diff --git a/src/audio/tensorflow/llext-wrap.c b/src/audio/tensorflow/llext-wrap.c new file mode 100644 index 000000000000..7d43dbe165ef --- /dev/null +++ b/src/audio/tensorflow/llext-wrap.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. + +#include <stdint.h> +#include <errno.h> +#include <assert.h> +#include <rtos/symbol.h> + +/* + * Stubs that are needed for linkage of some applications or libraries + * that come from porting userspace code. Anyone porting should + * make sure that any code does not depend on working copies of these + * reentrant functions. We will fail for any caller. + */ + +struct stat; +struct _reent; + +size_t _read_r(struct _reent *ptr, int fd, char *buf, size_t cnt) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +size_t _write_r(struct _reent *ptr, int fd, char *buf, size_t cnt) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +void *_sbrk_r(struct _reent *ptr, ptrdiff_t incr) +{ + errno = -ENOTSUP; + return NULL; +} + +int _lseek_r(struct _reent *ptr, int fd, int pos, int whence) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +int _kill_r(struct _reent *ptr, int pid, int sig) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +int _getpid_r(struct _reent *ptr) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +int _fstat_r(struct _reent *ptr, int fd, struct stat *pstat) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +int _close_r(struct _reent *ptr, int fd) +{ + errno = -ENOTSUP; + return -ENOTSUP; +} + +/* TFLM needs exit if build as a llext module only atm */ +#if CONFIG_COMP_TENSORFLOW == m +void _exit(int status) +{ + assert(0); + while (1) { + /* spin forever */ + } + /* NOTREACHED */ +} +#endif diff --git a/src/audio/tensorflow/llext/CMakeLists.txt b/src/audio/tensorflow/llext/CMakeLists.txt new file mode 100644 index 000000000000..22bfc22da748 --- /dev/null +++ b/src/audio/tensorflow/llext/CMakeLists.txt @@ -0,0 +1,465 @@ +# Copyright (c) 2025 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +# TODO: detect Hifi4/5 for NN lib kernels +set(NN_HIFI_PATH ${sof_top_dir}/../nnlib-hifi4/xa_nnlib) + +# paths for dependencies +set(TFLM_PATH ${sof_top_dir}/../tflite-micro) +set(FLATBUFFERS_PATH ${sof_top_dir}/../flatbuffers) +set(GEMMLOWP_PATH ${sof_top_dir}/../gemmlowp) +set(RUY_PATH ${sof_top_dir}/../ruy) + +add_library(nn_hifi_lib STATIC + ${NN_HIFI_PATH}/algo/common/src/xa_nnlib_common_api.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_pad_8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_stride_slice_int16.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_batch_to_space_nd_8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_transpose_8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_depth_to_space_8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_pad_16.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_stride_slice_int32.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_space_to_batch_nd_8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_pad_32.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_stride_slice_int8.c + ${NN_HIFI_PATH}/algo/kernels/reorg/hifi4/xa_nn_space_to_depth_8.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_32_32.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_f32_f32.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_sym16_sym16.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_softmax_asym8_asym8.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_32_16.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_16_16.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_8_8.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_asym16_asym16.c + ${NN_HIFI_PATH}/algo/kernels/activations/hifi4/xa_nn_activations_32_8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_16x16_16_circ_nb.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_16x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_16x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_transpose_conv_circ_buf.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_group_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_asym8xasym8_asym8_circ_nb.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_8x8_8_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_8x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_circ_buf.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_8x8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_16x16_16_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_transpose_conv_f32.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_f32.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_f32_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_circ_buf.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_transpose_conv_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_8x16_16_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_sym8sxsym16s_sym16s_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_8x8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_8x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_f32.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_f32_circ_nb.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_asym8xasym8_asym8_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_8x8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_transpose_conv_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_f32.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_8x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_8x8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_16x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_sym8sxasym8s_asym8s_circ.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_pointwise_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_circ_buf.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_8x16_16_circ_nb.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_16x16.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_matXvec_8x8_8_circ_nb.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_std_sym4sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv1d_std_f32.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/cnn/hifi4/xa_nn_conv2d_depthwise_8x16.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_f32.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_asym8xasym8_batch.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_8x8.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_8x16.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_asym4sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_f32_batch.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_f32.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_16x16_batch.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_sym8sxsym16s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_asym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_16x8.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_8x16.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_8x8.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_asym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matmul_16x16.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_8x16_batch.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_16x16.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_asym8xasym8.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_sym8sxasym8s.c + ${NN_HIFI_PATH}/algo/kernels/matXvec/hifi4/xa_nn_matXvec_8x8_batch.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_f32.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_8.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_asym8_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_f32_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_16_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_16.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_16_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_asym8.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_inv_256_tbl.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_8_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_16.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_8.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_f32_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_asym8_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_f32.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_maxpool_asym8.c + ${NN_HIFI_PATH}/algo/kernels/pool/hifi4/xa_nn_avgpool_8_nhwc.c + ${NN_HIFI_PATH}/algo/kernels/norm/hifi4/xa_nn_l2_norm_asym8s.c + ${NN_HIFI_PATH}/algo/kernels/norm/hifi4/xa_nn_l2_norm_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_sqrt_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_mul_16x16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_add_quant8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_mul_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_lstm_utils.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_dot_prod_16x16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_sub_quant16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_round_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_mul_acc_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_cosine_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_reduce_asym8s_asym8s.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_memset_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_floor_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_squared_diff_quant8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_add_quant16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_reduce_asym16s_asym16s.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_minmax_8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_logn_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_div_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_sub_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_compare_quant8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_logical_bool.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_broadcast_8_8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_quantize.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_neg_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_mul_quant16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_add_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_vec_interpolation_q15.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_square_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_sine_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_abs_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_memmove.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_mul_quant8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_squared_diff_quant16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_memmove_16.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_sub_quant8.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_ceil_f32.c + ${NN_HIFI_PATH}/algo/kernels/basic/hifi4/xa_nn_elm_rsqrt_f32.c + ${NN_HIFI_PATH}/algo/kernels/fc/hifi4/xa_nn_fully_connected.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_tanh32x32_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/scl_sigmoidf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/inv2pif_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/nanf_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/pow2f_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_sigmoidf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_reluf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/expf_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_tanhf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_sigmoid32x32_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/lognf_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/sinf_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_cosinef_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_sinef_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_softmaxf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/scl_tanhf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_softmax32x32_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_lognf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/sqrt2f_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/inff_tbl.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_alognf_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/vec_relu32x32_hifi4.c + ${NN_HIFI_PATH}/algo/ndsp/hifi4/src/tanhf_tbl.c +) + +target_include_directories(nn_hifi_lib PRIVATE + ${NN_HIFI_PATH}/include + ${NN_HIFI_PATH}/algo/common/include/ + ${NN_HIFI_PATH}/include/nnlib/ + ${NN_HIFI_PATH}/algo/ndsp/hifi4/include +) + +# TODO: Need to detect and add mul16/32 options. +#ifeq "$(has_mul16)" "0" +#CFLAGS += -mno-mul16 +#endif +#ifeq "$(has_mul32)" "0" +#CFLAGS += -mno-mul32 -mno-div32 +#endif +target_compile_options(nn_hifi_lib PRIVATE + -fsigned-char + -fno-exceptions + -mlongcalls + -INLINE:requested + -mcoproc + -fno-zero-initialized-in-bss + -mtext-section-literals + -Wsign-compare + -m32 + -DMODEL_INT16 + -DNNLIB_V2 + -Dhifi4 + -DTFLITE_SINGLE_ROUNDING=1 +) + +# TODO: complete sources have been added here from userspace build but +# not all are needed so this is a list of "needed" sources to build +# a memory and performance optimized TFLM for SOF. +# All sources have been left in for completeness now, but will be removed +# when support is mature. +add_library(tflm_lib STATIC + ${TFLM_PATH}/tensorflow/compiler/mlir/lite/core/api/error_reporter.cc + ${TFLM_PATH}/tensorflow/compiler/mlir/lite/schema/schema_utils.cc + ${TFLM_PATH}/tensorflow/lite/core/c/common.cc + ${TFLM_PATH}/tensorflow/lite/core/api/flatbuffer_conversions.cc + ${TFLM_PATH}/tensorflow/lite/core/api/tensor_utils.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/common.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/tensor_utils.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/runtime_shape.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/quantization_util.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/tensor_ctypes.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/portable_tensor_utils.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/reference/comparisons.cc + ${TFLM_PATH}/tensorflow/lite/kernels/internal/reference/portable_tensor_utils.cc + ${TFLM_PATH}/tensorflow/lite/kernels/kernel_util.cc + # Stock micro kernels - not needed atm + #${TFLM_PATH}/tensorflow/lite/micro/kernels/activations_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/activations.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/add_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/add_n.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/arg_min_max.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/assign_variable.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/batch_matmul.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/batch_to_space_nd.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/broadcast_args.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/broadcast_to.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/call_once.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/cast.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/ceil.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/circular_buffer_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/circular_buffer.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/comparisons.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/concatenation.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/conv_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/cumsum.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/depth_to_space.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/depthwise_conv_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/dequantize_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/detection_postprocess.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/div.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/elementwise.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/elu.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/embedding_lookup.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/ethosu.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/expand_dims.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/exp.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/fill.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/floor_div.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/floor_mod.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/floor.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/fully_connected_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/gather_nd.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/gather.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/hard_swish_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/hard_swish.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/if.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/kernel_runner.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/kernel_util.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/l2norm.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/l2_pool_2d.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/leaky_relu_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/logical_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/logical.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/logistic_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/log_softmax.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/lstm_eval_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/maximum_minimum.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/micro_tensor_utils.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/mirror_pad.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/mul_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/mul.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/neg.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/pack.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/pooling_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/prelu_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/prelu.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/quantize_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/read_variable.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/reduce_common.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/reshape_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/resize_bilinear.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/resize_nearest_neighbor.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/round.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/select.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/shape.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/slice.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/softmax_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/space_to_batch_nd.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/space_to_depth.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/split.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/split_v.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/squared_difference.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/squeeze.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/strided_slice_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/sub_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/svdf_common.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/tanh.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/transpose.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/unpack.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/var_handle.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/while.cc + #${TFLM_PATH}/tensorflow/lite/micro/kernels/zeros_like.cc + # xtensa kernels + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/sub.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_hifi.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/pooling_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/softmax_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/unidirectional_sequence_lstm.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/transpose_conv.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/fully_connected_common_xtensa.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/lstm_eval_hifi.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/add_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/depthwise_conv.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/reshape.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/softmax.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/depthwise_conv_hifi.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_int16_reference.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_int8_reference.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/fully_connected_int8.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/pad_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/fully_connected_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_int8_int16.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/softmax_int8_int16.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/logistic.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/reduce.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/lstm_eval.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/reshape_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/pad.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/reduce_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/dequantize.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/add.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/pooling_int8.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/depthwise_conv_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/strided_slice.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_common_xtensa.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/svdf.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/fully_connected.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/leaky_relu.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/quantize.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/pooling.cc + ${TFLM_PATH}/tensorflow/lite/micro/kernels/xtensa/conv_vision.cc + ${TFLM_PATH}/tensorflow/lite/micro/mock_micro_graph.cc + ${TFLM_PATH}/tensorflow/lite/micro/flatbuffer_utils.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_interpreter_graph.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_resource_variable.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_interpreter_context.cc + ${TFLM_PATH}/tensorflow/lite/micro/fake_micro_context.cc + ${TFLM_PATH}/tensorflow/lite/micro/arena_allocator/persistent_arena_buffer_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/arena_allocator/recording_single_arena_buffer_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/arena_allocator/non_persistent_arena_buffer_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/tflite_bridge/flatbuffer_conversions_bridge.cc + ${TFLM_PATH}/tensorflow/lite/micro/tflite_bridge/micro_error_reporter.cc + ${TFLM_PATH}/tensorflow/lite/micro/system_setup.cc + #${TFLM_PATH}/tensorflow/lite/micro/span_test.cc + ${TFLM_PATH}/tensorflow/lite/micro/test_helper_custom_ops.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_context.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_log.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_profiler.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_time.cc + #${TFLM_PATH}/tensorflow/lite/micro/static_vector_test.cc + ${TFLM_PATH}/tensorflow/lite/micro/debug_log.cc + ${TFLM_PATH}/tensorflow/lite/micro/test_helpers.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_op_resolver.cc + ${TFLM_PATH}/tensorflow/lite/micro/recording_micro_allocator.cc + ${TFLM_PATH}/tensorflow/lite/micro/memory_helpers.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_allocation_info.cc + ${TFLM_PATH}/tensorflow/lite/micro/memory_planner/greedy_memory_planner.cc + ${TFLM_PATH}/tensorflow/lite/micro/memory_planner/non_persistent_buffer_planner_shim.cc + ${TFLM_PATH}/tensorflow/lite/micro/memory_planner/linear_memory_planner.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_utils.cc + ${TFLM_PATH}/tensorflow/lite/micro/micro_interpreter.cc + ../micro_speech_quantized_model_data.cc + ../speech.cc +) + +target_include_directories(tflm_lib PRIVATE + ${TFLM_PATH} + ${FLATBUFFERS_PATH}/include + ${GEMMLOWP_PATH} + ${RUY_PATH} + ${NN_HIFI_PATH} + ${NN_HIFI_PATH}/include + ${sof_top_dir}/posix/include +) + +# TODO: Need to detect and add mul16/32 options. +#ifeq "$(has_mul16)" "0" +#CFLAGS += -mno-mul16 +#endif +#ifeq "$(has_mul32)" "0" +#CFLAGS += -mno-mul32 -mno-div32 +#endif +target_compile_options(tflm_lib PRIVATE + -std=c++17 + -stdlib=libc++ + -fno-rtti + -fno-exceptions + -fno-threadsafe-statics + -Wnon-virtual-dtor + -fno-unwind-tables + -fmessage-length=0 + -DTF_LITE_STATIC_MEMORY + -DTF_LITE_DISABLE_X86_NEON + -Wsign-compare + -Wdouble-promotion + -Wunused-variable + -Wswitch + -Wvla + -Wall + -Wextra + -Wmissing-field-initializers + -Wstrict-aliasing + -Wno-unused-parameter + -DXTENSA + -DKERNELS_OPTIMIZED_FOR_SPEED + -DTF_LITE_MCU_DEBUG_LOG + -DTF_LITE_USE_CTIME + --xtensa-core=ace10_LX7HiFi4_2022_10 + -mcoproc + -DHIFI4 + -mlongcalls + -DNNLIB_V2 + -Wno-shadow +) + +sof_llext_build("tflm" + SOURCES ../tflm-classify.c ../llext-wrap.c + + INCLUDES + ${TFLM_PATH} + + # TFLM is a C++ userspace application so hence we need to link + # userspace C++, C, maths and C runtime for llext module usage. + LIBS tflm_lib nn_hifi_lib c++ m c gcc hal + LIBS_PATH . +) + diff --git a/src/audio/tensorflow/llext/llext.toml.h b/src/audio/tensorflow/llext/llext.toml.h new file mode 100644 index 000000000000..521a0e5acf64 --- /dev/null +++ b/src/audio/tensorflow/llext/llext.toml.h @@ -0,0 +1,6 @@ +#include <tools/rimage/config/platform.toml> +#define LOAD_TYPE "2" +#include "../tflmcly.toml" + +[module] +count = __COUNTER__ diff --git a/src/audio/tensorflow/micro_speech_quantized_model_data.cc b/src/audio/tensorflow/micro_speech_quantized_model_data.cc new file mode 100644 index 000000000000..ce9cc5086804 --- /dev/null +++ b/src/audio/tensorflow/micro_speech_quantized_model_data.cc @@ -0,0 +1,5 @@ +#include <cstdint> + +#include "micro_speech_quantized_model_data.h" + +alignas(16) const unsigned char g_micro_speech_quantized_model_data[] = {0x20,0x0,0x0,0x0,0x54,0x46,0x4c,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x1c,0x0,0x4,0x0,0x8,0x0,0xc,0x0,0x10,0x0,0x14,0x0,0x0,0x0,0x18,0x0,0x12,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0xec,0x48,0x0,0x0,0x8c,0x42,0x0,0x0,0x74,0x42,0x0,0x0,0x3c,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x8,0x0,0xc,0x0,0x4,0x0,0x8,0x0,0x8,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0xb,0x0,0x0,0x0,0x13,0x0,0x0,0x0,0x6d,0x69,0x6e,0x5f,0x72,0x75,0x6e,0x74,0x69,0x6d,0x65,0x5f,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x0,0xc,0x0,0x0,0x0,0x28,0x42,0x0,0x0,0xfc,0x41,0x0,0x0,0x68,0x3,0x0,0x0,0x34,0x3,0x0,0x0,0x28,0x3,0x0,0x0,0x14,0x3,0x0,0x0,0xe8,0x2,0x0,0x0,0xdc,0x2,0x0,0x0,0x40,0x0,0x0,0x0,0x34,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0xbe,0xbc,0xff,0xff,0x4,0x0,0x0,0x0,0x5,0x0,0x0,0x0,0x31,0x2e,0x35,0x2e,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0xba,0xff,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x50,0xba,0xff,0xff,0x0,0x0,0x0,0x0,0xee,0xbc,0xff,0xff,0x4,0x0,0x0,0x0,0x80,0x2,0x0,0x0,0xfa,0xee,0x28,0xc4,0xee,0xfe,0xcf,0xf,0x1e,0xf7,0x1f,0x6,0xd,0xed,0xe9,0x83,0x5c,0xc9,0x18,0xe3,0xf9,0x14,0x28,0x2a,0x9,0xf2,0x18,0x34,0x62,0xea,0xef,0xd6,0x36,0xb7,0x1e,0xf7,0x3b,0x22,0x28,0x39,0xc2,0x9d,0xf1,0x7,0x5e,0xb,0x1e,0x2c,0x7,0xdd,0xfd,0xc3,0xd8,0x4a,0xf3,0x28,0xa7,0x16,0xd5,0xf1,0xc3,0x5,0xfd,0x27,0xcc,0xba,0x1e,0xcb,0xd7,0x3d,0xd4,0x29,0x0,0xfd,0x28,0x44,0xfb,0xf2,0xf3,0xb6,0x4f,0xcf,0x9,0xf0,0xfa,0x45,0x41,0x49,0x5,0xc5,0x17,0x5d,0x64,0x0,0xf8,0xee,0x48,0x17,0xf4,0xe9,0x2e,0x4b,0x2e,0x3f,0xdf,0xee,0xe4,0x8,0x38,0xf1,0x16,0x13,0x2f,0x2a,0xed,0xc2,0xbf,0x36,0xf4,0x2,0xcf,0xaa,0xd2,0xfa,0xac,0x13,0xf6,0xe8,0xb5,0x68,0x12,0xb6,0xce,0xe,0xdf,0x58,0xe4,0x49,0x14,0x15,0x3,0xed,0xfa,0xd4,0x40,0xa7,0xf6,0xca,0xfb,0x0,0x4d,0x5e,0xe4,0x55,0x1d,0x30,0x45,0xe2,0xfc,0x1,0x48,0x81,0xe9,0xf1,0x1e,0xfc,0x21,0x32,0xed,0x4b,0xed,0xfa,0x2f,0xd2,0xfa,0xfb,0x4d,0xa7,0xed,0xc7,0x92,0xdf,0xe6,0xdb,0xf8,0x1f,0xd9,0xfa,0x91,0xf5,0xe5,0xc5,0x8c,0x17,0xf,0xb9,0xd2,0xc7,0xfe,0x68,0xd3,0x51,0x2e,0x49,0x1f,0xbd,0x1,0xeb,0x31,0x17,0xf0,0xef,0xff,0xb8,0x5d,0x62,0x2,0xf,0x1f,0x78,0x6a,0xb0,0xf9,0xfe,0x4f,0xcc,0xd3,0xff,0xa,0x96,0x1e,0x2c,0xed,0xbc,0xf4,0xb,0x42,0xc8,0xf1,0xea,0x6e,0x58,0xec,0xc4,0x99,0xae,0xdc,0xd7,0x12,0x87,0xd8,0x6,0xa2,0xc2,0xe6,0xa2,0x81,0x24,0xe9,0xac,0xce,0xb6,0x15,0x6b,0xba,0x0,0x19,0x58,0x29,0xb6,0xfe,0x1,0x25,0x96,0xd2,0xec,0xe,0x9c,0x60,0x5f,0xe9,0xf4,0xf5,0x69,0x6b,0xb5,0xe1,0xf6,0x5e,0xb7,0xb1,0xe5,0x11,0x9b,0x18,0x10,0xe3,0xe1,0xe0,0xd,0x4f,0xa5,0xde,0xe5,0x6f,0xe2,0xfb,0x99,0x82,0xa5,0xc9,0xb6,0x1f,0x46,0xf3,0x4,0xc6,0xca,0xd6,0x97,0x90,0x1d,0xc0,0x95,0xf0,0x19,0x30,0x77,0xc2,0x3c,0xfa,0x24,0x2,0x4d,0x6,0x7,0x15,0x2,0xb0,0xe7,0x27,0x22,0x67,0x4d,0xf1,0xc2,0xf4,0x64,0x38,0x40,0xdf,0xf6,0x3a,0x43,0xb8,0xe1,0xd,0x15,0x11,0xfe,0xf5,0xec,0xf9,0xe5,0x22,0x36,0xe4,0xfd,0x6d,0xbf,0xd,0x8e,0xb7,0x15,0xbf,0x9f,0x16,0xad,0xa,0x2,0x8e,0x14,0xda,0x9b,0x8e,0xc3,0xa6,0xca,0xf5,0x7f,0x51,0x56,0xc1,0xb3,0xd9,0x35,0xf8,0x7f,0x4,0xa,0x3,0x3f,0xbe,0xee,0x19,0x68,0x78,0x50,0xf9,0xa7,0xf7,0x7f,0x1d,0x76,0xdb,0xe8,0x33,0xb9,0xd7,0xe7,0xe8,0x69,0x15,0xf7,0xf5,0xb2,0xfe,0xe8,0xf3,0x5b,0xe2,0x6,0x6e,0x9,0x36,0xb7,0xcc,0x38,0xbf,0x8a,0x28,0x14,0x2e,0x18,0xa7,0x26,0xcb,0xb2,0x95,0x37,0xac,0xcd,0xd7,0x51,0x67,0x44,0xcd,0x31,0xde,0x4,0xe9,0x6a,0x0,0x13,0xa,0xc,0xdd,0x16,0xe0,0x24,0x7e,0x49,0xf1,0xb5,0x4,0x52,0x1,0x50,0xdd,0xf5,0x26,0xc9,0xf4,0xf8,0xd6,0x31,0x1b,0xd0,0xef,0x3,0xa,0xc0,0xd4,0x4f,0xe2,0xfd,0x72,0xf4,0x5a,0xc9,0xd7,0x31,0xc0,0x8e,0x17,0x5e,0x57,0x0,0xb4,0x3a,0xc8,0xd2,0x92,0x32,0xcb,0xd8,0xc3,0xa6,0x63,0x26,0xcf,0xbc,0xe8,0x57,0x9b,0xe9,0xf7,0x1c,0xea,0x12,0xf1,0xf7,0xdb,0xb9,0x7f,0x16,0xf6,0xe0,0x8,0x70,0xa2,0xed,0xcc,0xf1,0x1e,0x10,0x4,0xf7,0xa9,0xb7,0x34,0xaa,0xa,0xdb,0x2a,0xa6,0xb6,0x10,0xea,0xf8,0x5e,0x6,0x72,0xdd,0xd0,0xb9,0xd6,0xa0,0x10,0x9f,0x5a,0x17,0xb1,0xe7,0xc0,0x1,0x9d,0x1,0xe0,0xe0,0xaf,0x9c,0x46,0xd8,0xaf,0xe8,0xce,0x2,0x8a,0xbb,0xe4,0xf6,0xf3,0x36,0x7,0xca,0xcb,0x87,0x6e,0xcc,0xd6,0x9e,0xa,0x2a,0x81,0xd7,0xcf,0xc0,0x4,0xeb,0x24,0xcc,0xc9,0x95,0x33,0x81,0xf7,0xad,0x1c,0x9c,0xa4,0xd6,0xf9,0xe6,0x3d,0x84,0x7f,0xcc,0xd4,0xb0,0xf4,0xa2,0xe9,0x3c,0x36,0xee,0xd5,0xcf,0xcd,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0xbc,0xff,0xff,0x0,0x0,0x0,0x0,0x8e,0xbf,0xff,0xff,0x4,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0xff,0xff,0xff,0xff,0x31,0x0,0x0,0x0,0x28,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0xbd,0xff,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0xbd,0xff,0xff,0x0,0x0,0x0,0x0,0xce,0xbf,0xff,0xff,0x4,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x8a,0xfe,0xff,0xff,0xa9,0x0,0x0,0x0,0xd0,0xff,0xff,0xff,0xd0,0x0,0x0,0x0,0x52,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x4f,0xfb,0xff,0xff,0x4a,0xfd,0xff,0xff,0x0,0x0,0x0,0x0,0xfe,0xbf,0xff,0xff,0x4,0x0,0x0,0x0,0x80,0x3e,0x0,0x0,0xff,0xf9,0xfd,0xa,0x7,0x8,0x7,0x3,0x7,0xf2,0xd1,0x9,0xf0,0xe9,0x28,0x9,0xdf,0x5,0xfa,0xf0,0xe8,0xe3,0x13,0xe,0x8,0xef,0xd3,0xee,0xf,0xe8,0xeb,0x14,0xf7,0xed,0xfd,0x1f,0xe8,0xd5,0xeb,0xfc,0xe,0xf4,0xf7,0x7,0x5,0xea,0xf6,0x1f,0xf8,0xdb,0xdc,0xb,0x3,0xdd,0xd8,0xf3,0xf,0x19,0xe1,0x9,0xfc,0xe4,0x2,0x4,0xf1,0x4,0xeb,0xf3,0x1e,0x6,0xfd,0x11,0xfc,0xfa,0xf6,0x1f,0xf,0x2,0xf5,0xf7,0xff,0x24,0xdf,0xf7,0xf8,0xf3,0xf6,0xe9,0xef,0x3,0xdd,0xf2,0x28,0xe1,0xf2,0x22,0xf4,0x9,0xf7,0xf9,0xf0,0xd4,0xf9,0xee,0xff,0x14,0xda,0xf3,0x11,0xe2,0xf6,0xc,0xf2,0xeb,0xf8,0xe8,0xe3,0x8,0x2,0x17,0xf4,0xb,0xc,0x27,0xe6,0x2,0x3,0xf9,0x14,0x18,0xf6,0xeb,0x1f,0xc,0xf1,0xee,0xfc,0x8,0xf0,0xfe,0xfd,0xee,0x17,0xfd,0x1c,0xef,0xfd,0xde,0x4,0x5,0xf0,0x31,0xfa,0xb,0xdc,0xd,0xed,0xf5,0xfa,0xf4,0x8,0xc,0xd7,0x1e,0x15,0x3,0xf5,0x2,0xf4,0xfb,0xed,0x1,0xfe,0xd6,0x1f,0xfd,0xfd,0xe,0xfa,0x6,0xf1,0xf9,0xe2,0x16,0xe9,0xf1,0x3,0xd,0xd,0xdf,0xf9,0x1a,0xe,0xf6,0xfc,0xa,0x19,0xe2,0xe0,0x9,0x15,0xf0,0xf1,0x6,0xf1,0xe1,0xef,0x1a,0x8,0xe8,0xfd,0x12,0x14,0x6,0xf1,0xfc,0xea,0xfb,0xf7,0xea,0x1d,0x9,0xfa,0xf6,0x8,0xf2,0xe7,0xf8,0xfc,0x16,0xf5,0xe,0x8,0xf9,0xa,0x3,0x26,0xd8,0x2,0xf5,0xf6,0xf6,0xef,0x1f,0xe4,0xe2,0xfb,0x2,0x1b,0xe6,0xde,0x0,0xf2,0xed,0xfb,0x18,0xe4,0x16,0x1a,0x1d,0xf1,0xf6,0xea,0x16,0x5,0xde,0xfb,0x18,0xf5,0xe4,0xfe,0xe2,0x1b,0x1c,0xc,0xe8,0x2,0xee,0xfb,0x7,0x24,0xf2,0xe9,0xfa,0xd,0x5,0xf1,0x3,0xfe,0xf6,0x19,0x6,0xff,0xf9,0x4,0xfb,0x15,0xef,0xf1,0xf8,0xe9,0xe1,0x10,0x4,0xfc,0xe6,0x1f,0xed,0xb,0xef,0x0,0x1e,0xe6,0x16,0xf3,0x9,0xfd,0x8,0x8,0x6,0x6,0x23,0xdf,0xfc,0x8,0xf4,0xea,0xc,0xf2,0xe6,0x18,0xf5,0x2,0xf9,0x50,0x9,0x1,0xda,0xb,0x5,0x12,0x18,0xef,0x4,0xe,0xd9,0xff,0xdc,0xf6,0x16,0xf9,0xf4,0xec,0xff,0xea,0xe6,0xfa,0xa,0xed,0xef,0x2,0xf0,0x25,0x21,0xf1,0x26,0xf5,0xed,0x9,0xea,0xea,0x24,0xfa,0x11,0xfc,0xdf,0xf3,0xa,0x28,0xc,0x19,0xff,0xf5,0xd6,0xe,0xe2,0x2a,0x6,0xfa,0x3,0xf9,0xe6,0xef,0x23,0xf9,0xfa,0xe6,0xfe,0xfc,0x3,0x6,0x1a,0xf9,0x8,0xe0,0xe5,0xff,0x5,0x1,0xe7,0x12,0x2,0x1d,0x5,0x3,0x5,0xb,0xee,0xed,0xfc,0xf,0xf3,0x2,0xe0,0x15,0xdf,0x2,0xed,0x10,0x26,0xef,0xd,0x6,0xee,0xef,0xf6,0xeb,0x11,0x9,0xf4,0xf7,0x6,0xf,0x1,0x2a,0xb,0x1,0xdd,0xfc,0xf4,0xf1,0x17,0x3,0x4,0x7,0xfc,0x22,0xfc,0xde,0xfe,0xb,0x3,0xf3,0xfb,0xc,0x25,0x4,0x19,0x4,0x3,0x1,0xfa,0xfb,0xf7,0xf6,0xe,0x15,0xe,0x9,0xff,0x6,0xfa,0xfb,0x1e,0xfb,0x5,0x22,0xf9,0xfe,0xf7,0x1d,0xed,0xdf,0x18,0x9,0xeb,0xef,0x4,0x12,0xea,0xdf,0xfb,0xda,0xf6,0xdf,0x17,0xef,0xef,0xe1,0x1a,0xd9,0xe2,0xe2,0xfc,0x5,0x11,0xf6,0xee,0xe8,0xf2,0xe1,0x8,0x26,0x4,0xed,0x3,0xe0,0xfb,0xee,0xc,0xee,0xf6,0x4,0x2d,0xf2,0xd3,0xf4,0xe0,0xf8,0xc,0xfe,0x11,0xb,0xd7,0xfd,0x18,0x7,0xd,0x7,0x8,0xf4,0xc6,0xa,0xa,0x1f,0xc,0xf4,0x1d,0x2,0xb,0x9,0xe,0x21,0xff,0x17,0xb,0xd,0xf2,0xed,0xd7,0xa,0xf8,0x3,0x6,0xfa,0xe5,0xfd,0x3,0x14,0xf,0xe9,0x1a,0xf4,0xda,0x1,0xe6,0x9,0x6,0x11,0xd,0xfd,0xeb,0x16,0x23,0xfa,0x0,0xb,0x17,0xf7,0xda,0xd7,0x1b,0xfa,0x1,0x3,0x5,0xfe,0xd6,0x2,0xee,0xee,0x2,0xf3,0x6,0xed,0x3,0xec,0x1,0xf2,0xf,0x5,0x17,0xb,0xfb,0xf,0x5,0x3,0x13,0xff,0x6,0x2,0xf5,0xf4,0x18,0x2b,0xf0,0x0,0x17,0xfc,0xfd,0x5,0xb,0xe,0x14,0xe1,0x24,0x8,0x24,0xe6,0xeb,0x21,0x12,0xfb,0x12,0xe7,0xf4,0xe8,0xe,0x18,0xee,0xf5,0xf3,0xd9,0xf3,0xdb,0xec,0xc,0x1e,0xcf,0x14,0xdb,0xe3,0xdc,0x2,0xc,0xfb,0xdb,0x1b,0xd0,0xfe,0xf9,0xfe,0x2a,0xf5,0x0,0xb,0xcd,0xe0,0xe2,0xe,0x4,0xf8,0xda,0x1c,0xe5,0xf,0xe8,0xf4,0xf7,0x15,0x6,0xf8,0x2,0xf7,0xf,0xfb,0x17,0xf9,0xda,0x1,0xda,0xd1,0xf6,0x2,0xfd,0x16,0xf1,0xe4,0xfa,0x7,0xee,0xa,0xf3,0xfd,0xf2,0x23,0xf0,0xe1,0xa,0x1a,0x12,0x1f,0xef,0x27,0x9,0xf1,0xc,0x13,0x23,0xfd,0xf5,0x3,0xfe,0x9,0xfd,0x16,0xf8,0x7,0x8,0x25,0x8,0xf8,0xf6,0xa,0xf1,0xf5,0x7,0x9,0x5,0xcc,0xf8,0x8,0x13,0xf9,0x1d,0x11,0xf,0xdc,0xee,0xf3,0x27,0xf9,0xf9,0x22,0xfa,0xd,0xe2,0x13,0xfb,0x11,0x3,0x1e,0xff,0xfb,0xed,0xf1,0xe,0xb,0xf,0x0,0x6,0xe0,0x15,0xf3,0x13,0xfc,0x18,0xf9,0xff,0x9,0xfa,0x1f,0x12,0xe5,0xe2,0x6,0xf9,0xf4,0x7,0x15,0xb,0x4,0xdb,0xd,0xeb,0xf3,0xe6,0x6,0xe5,0xee,0xd8,0x22,0xd8,0x10,0xea,0xf9,0x1c,0xf7,0xd3,0x11,0xc3,0xf8,0xde,0x5,0x0,0xe6,0x7,0xfd,0xd3,0x3,0xea,0xe0,0x13,0x14,0xcf,0xeb,0xcd,0xd3,0xde,0xf5,0xf0,0xc,0xc,0xfa,0xeb,0xd3,0xfb,0xfd,0x8,0xf9,0xf4,0x10,0xfa,0xd3,0xf4,0x11,0x11,0xf8,0xef,0xf8,0xf8,0xf1,0xfc,0xe1,0xf7,0x12,0x4,0xf4,0xfb,0xed,0xef,0xc,0xfd,0x1c,0xfe,0xe,0xfd,0xe2,0xfe,0xa,0x2,0xfe,0xe6,0x1f,0xef,0xe5,0xe6,0xf8,0x16,0x27,0xe8,0x20,0x5,0xe3,0xf1,0xef,0xee,0xed,0xd,0x11,0x16,0xfb,0xf3,0xff,0x14,0x1,0xff,0x15,0x10,0x2,0xe5,0x28,0x29,0x13,0x13,0x16,0xe6,0x0,0xd2,0x26,0xfd,0x3,0x4,0x5,0x7,0x6,0xf1,0xe,0x5,0xd,0xe2,0xf,0x2,0xe1,0x7,0xf7,0x1c,0xfa,0x14,0x30,0xf7,0xee,0x0,0xfa,0x3d,0x6,0x1c,0x4,0x6,0x7,0x5,0x1a,0x10,0xf6,0xee,0xa,0xeb,0x4,0xeb,0xdf,0x1d,0x9,0xd5,0xe8,0xd6,0xf4,0xf0,0xf,0x1d,0xea,0xf2,0xf8,0xa6,0xb,0xdc,0x9,0x8,0x24,0xee,0x24,0xaa,0xe4,0xcb,0x15,0xef,0xe7,0xe9,0xc,0xcf,0x6,0xe3,0x12,0x11,0x0,0x7,0x14,0xd7,0xde,0xf6,0xf,0xb,0x4,0xfb,0xd,0xf8,0xd,0xf6,0x1b,0xf1,0x21,0xdd,0xfc,0xf4,0xe9,0xf8,0xe8,0xf7,0x6,0x3,0x1e,0xce,0xe1,0xea,0xf6,0x5,0xf9,0x16,0x15,0x4,0xe0,0x14,0xf7,0x1e,0x1c,0xa,0x27,0xef,0xf3,0xf,0xf3,0xee,0x4,0xf8,0xf1,0x7,0xe3,0x5,0xb,0x0,0x1c,0x15,0x27,0x7,0xf7,0xfa,0xb,0xfa,0xfa,0x17,0x13,0xe1,0xf5,0xfb,0xc,0x21,0x2f,0xd7,0xfb,0xf5,0xfd,0xd3,0xf4,0x7,0xe,0xfd,0xb,0xfc,0xfa,0xf5,0xe,0x2,0xfa,0xfa,0x19,0xfd,0xfa,0xfc,0x13,0x24,0xc,0xe4,0x31,0xf8,0x12,0xf4,0x4,0x18,0x29,0x27,0x19,0xfc,0x8,0x11,0xe3,0x7,0xfe,0x26,0x40,0x5,0x2,0x4,0x2,0xf,0xee,0xf4,0x27,0xea,0xf4,0xf5,0x11,0x26,0xb,0xe7,0x5,0xd2,0xf6,0xea,0xfa,0xb,0xf9,0xfa,0x16,0xba,0x0,0xfb,0xd,0xb,0xf9,0xe6,0xf6,0xc5,0xf8,0xf6,0x1,0xf,0xed,0xed,0x13,0xcd,0xd,0xda,0x6,0x17,0xee,0x7,0x1d,0xb8,0xfa,0xe2,0xea,0xf2,0xee,0x4,0x0,0xdc,0xd0,0xfb,0xf5,0xec,0xfe,0xf1,0xd,0xf0,0xdb,0xf9,0xd,0x3,0x3,0xe,0xa,0xda,0xd6,0x1,0xf2,0x6,0x14,0x1c,0x1f,0xe8,0xe8,0xe,0xfd,0xc,0xf5,0xf3,0x3d,0xf3,0x5,0x10,0xfa,0x1b,0x18,0x8,0x36,0x9,0xf1,0xeb,0xf9,0x22,0x1,0xf3,0xf7,0xff,0xf0,0xc,0xe9,0x1,0x29,0x21,0x15,0x3,0xee,0xe9,0x1a,0xf7,0x15,0x6,0x25,0xfa,0xf0,0xe4,0xf1,0x1f,0x1,0xdc,0x2d,0xce,0xe9,0xea,0xb,0x6,0x2c,0xa,0x30,0xe7,0x9,0xf4,0xf0,0x10,0x29,0xf9,0x3d,0xe7,0xdc,0xe4,0xf7,0x3b,0x27,0x23,0x3a,0xa,0x6,0xe,0xfd,0x2c,0x7,0x2b,0x1c,0xfa,0x0,0xf9,0x11,0xea,0x14,0xeb,0xfc,0x18,0x3,0xf1,0x16,0x12,0x4,0xcf,0x12,0xdd,0xe4,0xe,0xf0,0x9,0xe8,0xf3,0xfb,0xa8,0xf9,0xee,0xfb,0x1e,0x1d,0xfd,0x5,0xab,0xe5,0xff,0x1,0xfe,0x4,0xf9,0x2,0xb9,0xdc,0xdf,0x5,0xf1,0xef,0xf1,0x1e,0xc7,0xee,0xf7,0x1e,0x0,0x0,0xf8,0x10,0xec,0xe8,0x4,0xf,0xf6,0xff,0x4,0x9,0xe0,0xa,0xe,0xe4,0xf0,0xf1,0x16,0x2b,0xd3,0xe1,0xa,0xef,0xf9,0xfe,0xb,0x22,0xf5,0x1,0xa,0xf8,0x2,0x0,0x17,0x19,0xf3,0x5,0x21,0xfa,0xee,0xee,0x12,0xf2,0xfa,0xf5,0x5,0x12,0xee,0xe4,0x28,0xfa,0xf1,0x3,0x15,0x16,0x18,0xfd,0xf,0x21,0x4,0xf4,0xe5,0xc,0x6,0x13,0xde,0x36,0xe8,0xfb,0xe7,0xfd,0xf6,0x12,0xe,0x1d,0xea,0xf8,0xd4,0xe8,0x19,0x7,0xe5,0x1c,0xf7,0xc,0xef,0x5,0xf,0x9,0xdd,0x1a,0xea,0xd7,0xf9,0xf9,0x12,0x17,0x2e,0x10,0x8,0xfe,0x14,0xf5,0x1d,0xfa,0x6,0x33,0xed,0xfe,0xf7,0x11,0xf0,0x15,0xe2,0x24,0xf6,0xa,0xe2,0xfc,0x23,0x12,0xdd,0x11,0xfd,0xe5,0x8,0xff,0x15,0xf6,0xf1,0x1b,0xae,0xfe,0xe6,0x15,0x2c,0x2d,0x15,0x15,0xc5,0xf8,0xea,0xe7,0x7,0x4,0xfe,0x28,0xa1,0xf2,0xe1,0xf9,0xf8,0xff,0xf4,0x22,0xb4,0xdb,0x3,0x20,0xe6,0xf3,0xe,0x19,0xe3,0xa,0xfa,0xee,0xf3,0xe5,0xd8,0xf9,0xf1,0xde,0x6,0x5,0xf2,0xf5,0xe7,0x16,0xd8,0xfe,0x7,0xea,0xee,0xe,0xfa,0xff,0xdb,0xe7,0x3,0xed,0x1,0xfd,0x9,0x1a,0xfa,0xe6,0x5,0x10,0xe9,0x1,0x1f,0x13,0xf7,0xf6,0xfb,0x13,0xff,0xdb,0xed,0xfe,0xa,0x10,0x9,0x29,0xf5,0x4,0xf5,0x26,0xd,0xc,0xf9,0x16,0xfa,0x2,0xf4,0x2e,0xde,0xf5,0xe1,0x1d,0xfb,0x2,0xb,0x23,0x7,0xea,0xd9,0xa,0xf3,0xa,0xf,0x1e,0xe7,0xf1,0xd7,0xb,0xf6,0xff,0xd,0x24,0xcc,0xa,0xee,0xda,0x14,0x12,0x11,0x29,0xf4,0x1a,0xef,0xb,0xfa,0xec,0xc,0x1b,0xf4,0xff,0xf5,0xef,0xf,0x10,0xd4,0x4,0xf9,0xf8,0xec,0xf9,0x21,0x5,0xd3,0x27,0xf3,0x17,0xff,0xf6,0x15,0xf9,0xed,0xa,0xac,0x2,0xfd,0xfb,0x4,0x29,0x6,0x3,0xb8,0xe6,0xd5,0x17,0x9,0x1b,0xf6,0x1b,0xab,0xdc,0xdf,0xfd,0x6,0x9,0x9,0x37,0xbb,0xed,0x19,0xd7,0xe2,0xdd,0x5,0x1,0xec,0xfb,0xe4,0xe,0xeb,0xf0,0x3,0x17,0x4,0xeb,0x9,0xee,0xeb,0xe7,0xc,0x16,0xcb,0xe,0x17,0xd8,0xe1,0xf8,0x2b,0x19,0xde,0xeb,0x10,0xf2,0xff,0xf8,0xee,0xe,0xe7,0xf0,0x15,0x8,0xf8,0xdf,0x6,0xd,0xf9,0x14,0xfa,0xb,0x4,0xfd,0x15,0x23,0x20,0xff,0xfd,0x1d,0xc,0xf1,0xfe,0x15,0xa,0x2,0xed,0xfe,0xfb,0x4,0xfb,0x1e,0xdd,0x5,0xe0,0x16,0xf9,0xf6,0xfd,0x32,0xdc,0xf2,0xd3,0x8,0xf4,0xec,0x17,0x25,0xe2,0xf0,0xee,0xf1,0xd,0xfe,0x13,0x2d,0x1,0x11,0xd4,0xe4,0x7,0xfb,0x32,0x11,0x14,0x7,0xd7,0x2,0x10,0xeb,0x2b,0x1d,0x1,0xfc,0xf3,0xf0,0x13,0x1a,0xdb,0x20,0x0,0xf0,0xf0,0x5,0x16,0x3,0xd4,0xe3,0xc2,0xf0,0x6,0x2,0x1e,0xa,0xec,0x1f,0xab,0xea,0xfa,0xe3,0x20,0x22,0x3,0x1b,0xb3,0xe,0xe3,0xf3,0x1d,0x27,0xe3,0x10,0xa7,0xda,0xf3,0x0,0xa,0xa,0x4,0xfb,0xb2,0xf,0xc,0xf5,0x7,0xff,0x13,0x1e,0xdb,0xf6,0xf9,0xef,0xe8,0xe7,0xfb,0x18,0xeb,0xec,0x9,0xda,0xf1,0xf0,0xb,0x4,0xe1,0xfa,0x1c,0x25,0xee,0x1,0xb,0x29,0xd7,0xc,0x4,0xb,0xef,0xfd,0x1c,0xfc,0xf1,0xfb,0xb,0xf,0xdf,0xed,0x17,0x38,0xc,0xd7,0xff,0xfd,0x1,0xfc,0xfb,0xfb,0x18,0x1a,0x18,0xe3,0xf9,0xf4,0xfa,0x20,0x6,0x9,0x11,0x8,0x1d,0xf8,0xfa,0x1d,0xf5,0x1c,0xf5,0xfe,0x3,0x7,0xe4,0x33,0xc8,0xc,0xe1,0x13,0xff,0xe5,0x10,0x2c,0xd3,0xf0,0xed,0x4,0x7,0x1,0xf1,0x16,0xe0,0x13,0xfa,0x11,0x7,0xfa,0x19,0x16,0x1,0x0,0x7,0x26,0x0,0xec,0x1d,0x23,0x5,0xf4,0x7,0x17,0x2c,0x1d,0xee,0xf0,0xc,0x9,0xe3,0x1a,0x24,0xb,0xf3,0x1e,0xce,0xfe,0xfe,0x12,0x21,0x1a,0xf6,0x23,0xc3,0x3,0xf4,0x10,0x1a,0x2a,0xf4,0x8,0xbf,0xff,0x4,0xf4,0xb,0x1d,0x1a,0xf8,0xcc,0x0,0xf7,0x13,0xf4,0xfd,0xf4,0x19,0xbd,0xef,0xc,0xd,0x2,0xfc,0x12,0x13,0xe9,0xe7,0xf5,0xfa,0xfa,0xf6,0x1a,0x2e,0xce,0xd4,0x1,0x12,0xfd,0xfc,0x26,0x10,0xcc,0xe7,0xee,0x13,0xee,0xff,0xef,0xea,0x0,0xe,0x1a,0x17,0x4,0xc,0x4,0xc,0xe6,0xf3,0xf6,0xdb,0xdd,0x4,0xf4,0x22,0x11,0x16,0xf3,0x7,0xec,0xf8,0xf2,0x7,0x3,0x2,0xf5,0xa,0xf6,0x2,0x1d,0x1b,0x11,0x6,0xf8,0x6,0x2,0xea,0xf3,0x1d,0xce,0x0,0xed,0xf9,0xef,0xf6,0xec,0x22,0xc7,0xf0,0xed,0xdb,0xe0,0x2,0x11,0x7,0xe8,0xf0,0xd1,0xed,0xff,0xfd,0xc,0x2e,0xd4,0xed,0xec,0xe,0xf1,0x7,0x1,0xe,0xe,0xfe,0xda,0xb,0xa,0xa,0x1f,0x2e,0x13,0x7,0x0,0x7,0x14,0x21,0xe9,0xfc,0xf0,0x1e,0xd7,0xea,0x34,0x7,0xc6,0xc,0xd4,0xec,0xfd,0x6,0x24,0xa,0xf3,0x15,0xaf,0xff,0xe9,0xf1,0xd,0x3e,0xe9,0x18,0xba,0x13,0xed,0xd7,0xb,0x31,0x5,0xe,0xaf,0x13,0xd6,0xe,0x10,0x2,0x2,0x14,0xcb,0xd5,0xf9,0xc,0xf9,0xe,0x1f,0x24,0xd5,0xeb,0xff,0xf1,0xf5,0xc,0x8,0x7,0xf4,0xd7,0x6,0x10,0xe8,0xef,0xfc,0x2f,0xee,0xf1,0x18,0xf8,0xf4,0x2,0x11,0x21,0xd3,0x12,0x14,0xe4,0xf4,0x2,0x5,0x24,0xca,0xf2,0xf3,0xeb,0xe7,0xf8,0x16,0x1a,0xeb,0xd,0x5,0x16,0xf1,0xec,0x11,0x1c,0x9,0x1e,0xe0,0xe6,0xfa,0xe,0xd,0x2a,0xea,0x2e,0xed,0xf9,0xf7,0x16,0x9,0x5,0xdd,0xd6,0x2,0xeb,0xf5,0xf3,0xe4,0x3b,0xed,0x4,0xe0,0xe,0xfd,0x9,0xfd,0x35,0xdc,0x18,0xf3,0x4,0xfa,0x5,0x15,0x34,0xe5,0xe1,0xe4,0xf4,0xe0,0xf9,0x8,0x32,0x4,0x8,0xf4,0xf,0xff,0x8,0x9,0x2f,0x6,0x2,0xfd,0x5,0xc,0x24,0xe3,0x1e,0xf5,0xc,0xdd,0xf8,0x18,0x20,0xd8,0x14,0xef,0xf4,0x17,0x8,0x25,0x14,0x4,0x6,0xb0,0xf5,0xf5,0x9,0xf,0x3e,0xff,0x28,0xb3,0xf5,0x19,0xd8,0x14,0x21,0xd9,0xf7,0xb7,0xe5,0xfe,0xe7,0x7,0x1e,0x4,0x15,0xc5,0xf9,0x14,0x20,0xeb,0x1,0x1,0x18,0xce,0x0,0xe6,0xe2,0xf7,0xfb,0xf3,0xd,0xd3,0xf3,0x4,0xf8,0xf0,0x3,0xf1,0x25,0xb5,0xef,0x5,0xe0,0x1,0xf6,0x4,0x16,0xd1,0x1,0xa,0x21,0x1,0x5,0xe,0x1,0xf0,0xa,0xf3,0x0,0x3,0xf8,0xfa,0x3,0xb,0xde,0xfe,0xff,0xfb,0xea,0x9,0x2,0xf5,0xe8,0xe7,0x8,0x0,0xf5,0xf8,0xf,0x13,0xfa,0xeb,0xe8,0xfb,0x1f,0x8,0x16,0xe6,0xfa,0xe1,0x0,0x3,0xdd,0xf1,0x26,0xe5,0x1d,0xd9,0xff,0xf2,0xf8,0xff,0x33,0xea,0xe5,0x3,0xc,0x7,0xf9,0xf8,0xf,0xe1,0x1e,0xdd,0xf,0x0,0xf1,0x6,0x21,0x9,0x5,0xf3,0xec,0xe6,0x4,0x7,0x32,0xf1,0xf9,0xf2,0x1,0x18,0x1f,0xd2,0xe2,0xa,0xf4,0xca,0xfc,0x28,0x16,0xc2,0x10,0xf2,0xfc,0x8,0xe9,0x2a,0xf,0xfa,0xf5,0xa9,0x7,0xec,0xe9,0x19,0x43,0xb,0x1c,0xa6,0xe9,0xf4,0x16,0xd,0x2b,0xfc,0x11,0x9a,0xe1,0xf1,0x1c,0xf5,0xf,0xe4,0x18,0xc0,0xd9,0x14,0x26,0xe6,0xf8,0xa,0x17,0xec,0xfb,0xe1,0x22,0xdf,0xf2,0xfe,0x1e,0xd4,0xeb,0xd7,0xe,0x8,0xf6,0xef,0xfc,0xe6,0xd4,0xf7,0xb,0xfb,0xf5,0x1,0x25,0xd7,0xfb,0xd,0xfe,0xff,0xf3,0x1d,0x32,0xfe,0xee,0x12,0xf2,0xc,0xec,0x2,0x10,0xef,0x1,0xf2,0xb,0xf3,0xf7,0xfa,0x25,0xfb,0xd,0x11,0x15,0x4,0xfc,0xc,0x21,0x12,0x29,0x0,0xfa,0xf6,0xf5,0x6,0x22,0xea,0xe2,0xee,0x0,0xfd,0xf0,0xb,0x1d,0xd3,0xe4,0xe4,0xa,0xfc,0xe8,0xea,0x2c,0xed,0xed,0xef,0xe8,0xf2,0x5,0xfd,0x15,0xd8,0xda,0xca,0xee,0xfa,0x0,0xfe,0xe,0xf2,0xf0,0xe,0xf5,0x4,0x3,0x1d,0x2b,0xee,0x5,0xf,0x10,0x13,0x35,0xe2,0x4,0x10,0xdf,0xcf,0xeb,0x40,0x26,0xe4,0x3,0xf3,0xf9,0xf5,0x14,0x24,0x2a,0xdf,0xfe,0xab,0xe5,0xfe,0x1c,0x27,0x35,0xdb,0xff,0xac,0x1,0xf6,0xfc,0x19,0x1a,0x11,0x1f,0xa8,0xf5,0x2,0xf,0x1a,0x1f,0xf7,0xf2,0xa2,0x0,0x15,0x22,0xe4,0x13,0x0,0x9,0xd9,0xd5,0x2,0x19,0xfd,0xf8,0xe7,0xff,0xfb,0xe0,0xef,0xf7,0xee,0xf3,0xf3,0x19,0xb0,0xdf,0x0,0xf,0x8,0xf3,0x15,0x17,0xec,0xf,0x11,0x14,0x2,0x8,0x10,0x17,0xe6,0x8,0xf7,0x0,0xed,0xf7,0x29,0x7,0x10,0x5,0x5,0xe7,0xed,0xf4,0xf9,0x15,0xf9,0xf0,0x8,0x0,0x3,0x9,0x21,0x28,0xf6,0xe,0xfb,0xf3,0x3,0xf7,0xf,0xc,0xf0,0xf5,0xe3,0xd8,0xf8,0xf2,0x9,0x1c,0xe7,0xfb,0xe4,0xf6,0xfa,0xf8,0xf1,0x42,0xf6,0xda,0xdd,0xd7,0xfa,0xff,0x2f,0x2c,0xda,0xa,0xde,0xec,0xf1,0x14,0xfb,0x1d,0xeb,0xee,0xf2,0xeb,0xf3,0xed,0xe,0x35,0xf0,0x6,0x19,0x4,0x2f,0x23,0xe2,0x7,0x13,0xf,0xe9,0xf0,0x22,0x2e,0xd9,0x1a,0xcb,0xed,0xfd,0x4,0x27,0x1e,0xf6,0x7,0x96,0xd6,0xd8,0x11,0x18,0x56,0xd2,0xfb,0x92,0xfc,0xb,0xa,0x17,0x2c,0xe5,0x4,0xa2,0xf8,0xe2,0x4,0x1a,0xd,0xeb,0x11,0xa2,0xe5,0xe5,0xf8,0x2,0xf7,0x17,0x3,0xca,0xe9,0xc,0x1f,0xfe,0xf5,0x18,0x12,0xdd,0x8,0x15,0xff,0xfc,0xf6,0xe1,0x1d,0xe2,0xe1,0xfe,0xfc,0x3,0xff,0xf2,0x23,0xd2,0x1,0x13,0xdd,0xf3,0xf4,0xf2,0x7,0xef,0x3,0x15,0x21,0xd8,0xf8,0x9,0xf3,0xe8,0xea,0xe8,0xf2,0x8,0xf0,0x4,0x1a,0xf2,0x19,0xfb,0x1b,0x15,0xfc,0x1d,0x30,0xe5,0x1e,0x9,0xe8,0xe9,0x9,0xf7,0x2a,0xe1,0xe,0x0,0x21,0xf3,0xff,0xfb,0x1,0xdf,0xf2,0xfe,0xf4,0xfc,0xf0,0xb,0xb,0xdd,0xe4,0xd2,0x14,0xf7,0xfe,0xb,0x39,0x1,0xe6,0xe4,0x27,0xfa,0xe4,0x4,0x2c,0xe2,0x4,0xf5,0x7,0xf2,0x3,0xf0,0x10,0xf5,0xf6,0xfc,0x16,0x22,0x1b,0xf8,0x11,0xe4,0x9,0xf6,0xf0,0x41,0x1e,0xcf,0x4,0xea,0xee,0xe,0xf6,0x1b,0x2f,0xc7,0xf1,0xba,0xef,0xf,0x16,0x1e,0x39,0x5,0x1e,0x90,0xe6,0xd,0xfa,0x22,0x3f,0xe3,0x23,0xa5,0xe3,0xe9,0xf,0x5,0x27,0x2,0x11,0x99,0x5,0xfa,0x5,0x3,0x1,0xff,0x26,0xd3,0xf7,0xf7,0xf9,0x5,0xf4,0xef,0x23,0xd2,0xdd,0x5,0x8,0xfa,0xff,0x3,0x4,0xbd,0xd7,0x14,0x6,0xef,0x6,0xe5,0x5,0xea,0xea,0x2,0xfd,0xd,0x0,0x8,0xff,0xe7,0xfb,0xfe,0x13,0xfe,0xec,0xf9,0x2,0xf3,0xff,0xff,0x8,0x4,0xed,0x19,0x1d,0xfa,0xa,0xd,0xf2,0xf,0xec,0x25,0x1c,0xec,0xb,0x1,0xff,0x1,0xf6,0x8,0x9,0xe8,0xe2,0xec,0x23,0xe5,0xe9,0xf0,0x2e,0xbd,0xe1,0xef,0x14,0xe9,0xf6,0xf5,0x1d,0xdc,0xe3,0xd7,0xfc,0xf9,0xf2,0xfe,0x24,0xf2,0x5,0xd5,0xed,0xe9,0xf9,0xfa,0x2d,0xf0,0xfe,0xee,0xf2,0xe8,0xf7,0x6,0x14,0x1,0x10,0x6,0xf3,0xe,0xe,0xc2,0x1d,0xf2,0x1c,0xed,0xe3,0x53,0x21,0xb8,0xc,0xde,0x3,0x15,0xeb,0x46,0x39,0xdf,0xf6,0xa3,0xee,0xf6,0xe0,0x33,0x50,0xdd,0x27,0x9f,0x7,0x13,0xe2,0x1f,0x35,0xed,0x1f,0xb7,0x7,0x11,0xed,0x17,0x28,0xf4,0x20,0xc1,0xec,0xef,0x16,0x2,0xfa,0xe0,0x1b,0xf7,0xdb,0xfd,0xa,0xe7,0xfb,0xe7,0x25,0xe2,0xe7,0xf8,0xf0,0xee,0xe9,0x2,0x6,0xc9,0xe4,0x14,0xe3,0xe2,0xf7,0xf8,0xfd,0xdd,0xe2,0x8,0xa,0xe4,0x5,0xf5,0x16,0xe7,0x1,0x0,0x1c,0xe7,0xf0,0xf6,0x19,0xfe,0xc,0xf2,0x6,0x3,0xe8,0xb,0xfe,0xe3,0x19,0x8,0x1a,0x10,0xfd,0x0,0x21,0xf0,0xeb,0x18,0x2,0xf3,0x4,0xf0,0x18,0xdb,0x5,0x1,0xde,0xed,0xe9,0x23,0x15,0xaf,0xe6,0xf1,0xa,0xe6,0xea,0x1,0x18,0xd8,0xfd,0xf1,0xe6,0xec,0xf5,0xe,0x1e,0xcc,0xfc,0xe7,0x0,0xe9,0x11,0x0,0x30,0xf9,0x14,0xf4,0x19,0xdd,0xf7,0xf7,0x2f,0xf4,0xf2,0xff,0x27,0x15,0x1c,0xbc,0x2f,0xe9,0x14,0xf5,0xe8,0x44,0x30,0xe8,0x1d,0xe4,0x18,0x11,0x0,0xc,0x2b,0xf3,0x29,0x96,0xe0,0x6,0xee,0x3e,0x55,0xdc,0x13,0x98,0xdf,0xf0,0xfe,0x17,0x33,0xe8,0x9,0xa3,0x7,0xef,0xe,0x1d,0x37,0xdd,0xfe,0xb5,0x0,0xf7,0xe0,0xea,0xfd,0xfd,0x19,0xbc,0xfd,0x15,0xfe,0x1,0xf3,0xd5,0x20,0xbf,0xe3,0x15,0xe,0xf0,0xf6,0xf2,0x14,0xcc,0xf0,0xf7,0x4,0xf2,0xff,0xb,0x2,0xd2,0xd8,0xfa,0xfc,0xe5,0x2,0x0,0xfb,0xf0,0xdc,0x1e,0x10,0x2,0x1,0x0,0x18,0xe9,0xdb,0x1e,0xf6,0xfc,0x3,0xef,0xa,0x0,0x16,0x0,0xf,0xf4,0x16,0xfa,0xb,0xe2,0xfa,0xe0,0x7,0xfb,0x2,0x21,0xe,0xdd,0xb,0xea,0xf0,0xeb,0xfb,0x19,0x9,0xd4,0xf2,0xef,0xb,0x0,0xeb,0x1a,0x2f,0xea,0x6,0x3,0xf6,0xf8,0xfb,0xfe,0x1d,0xea,0xdd,0xed,0xfd,0xfb,0xe7,0xfe,0x18,0xf4,0xfc,0xb,0xf6,0xfc,0xb,0xfb,0x28,0x7,0xff,0x7,0x1e,0x3,0x21,0xcf,0x22,0x5,0xe6,0xea,0xe7,0x43,0x2e,0xe7,0x14,0xfb,0xa,0x1e,0xfe,0x2c,0x24,0xd5,0xfd,0x9e,0xd1,0xf2,0x1c,0x32,0x51,0x1,0xf3,0xac,0xe1,0xf4,0xe5,0x1c,0x37,0xf1,0xf,0xa7,0xdb,0x0,0xf6,0xf,0x18,0xe1,0x10,0xc9,0xc5,0xe8,0xeb,0xf2,0xfd,0xf6,0x2,0xc2,0xff,0x0,0x19,0x3,0xf,0x2,0x22,0xd4,0xe7,0x7,0xf,0xe5,0x1a,0x9,0xb,0xdc,0xd2,0x0,0x5,0xee,0xf8,0xdc,0x14,0xd0,0xa,0xa,0xfa,0xeb,0x4,0xf3,0x6,0xde,0x5,0xfb,0xfd,0xe3,0xec,0xfd,0x14,0xd7,0x11,0xe,0xe6,0x6,0xec,0xde,0x22,0xd7,0x0,0x3,0xf5,0xf5,0xd,0x1,0x5,0xea,0xb,0x16,0x4,0xff,0x13,0xf3,0x12,0xd2,0xdf,0xb,0xe4,0x6,0xf6,0x8,0x2d,0xd3,0xd6,0xe7,0xa,0xec,0xff,0xfe,0x1,0xdf,0xf4,0xdf,0x1c,0xfe,0xf9,0xf7,0x13,0xca,0xff,0x3,0x6,0xe9,0xf7,0x6,0x8,0xd7,0xf3,0xed,0x8,0xe3,0xfd,0xc,0x11,0x15,0xfb,0x15,0x8,0x28,0x40,0xe7,0xd,0x8,0xec,0xe8,0x16,0x67,0x46,0xc8,0x16,0xf1,0x2,0x24,0x0,0x3a,0x43,0xd6,0x12,0xae,0xe7,0xf4,0xf8,0x3a,0x65,0xe4,0xc,0xb2,0xef,0x1f,0xe8,0x29,0x59,0xf8,0x11,0xc4,0xe1,0xfe,0xfa,0x27,0x43,0xc9,0x1e,0xbb,0xfb,0xf3,0x13,0x15,0xd,0xf1,0x13,0xcd,0xf0,0x7,0x19,0x7,0x0,0xd8,0xeb,0xbf,0xf0,0xfc,0xf6,0xef,0x16,0x1,0x2,0xc1,0xdf,0xfd,0xe9,0x6,0x6,0xf1,0x8,0xd7,0xcc,0xfb,0xe,0xfc,0x14,0xf2,0x1a,0xe2,0xd,0xeb,0x9,0x7,0x10,0xe6,0x13,0xeb,0xf5,0x15,0x14,0xeb,0xfe,0xf9,0x17,0xd2,0xe3,0x1e,0xf5,0x4,0xa,0xf1,0xe,0xde,0xe7,0x1,0x20,0xc,0xfc,0xdc,0xf9,0xe5,0xe9,0xff,0x1d,0xa,0xfe,0xec,0x25,0xaf,0xd2,0x1,0x16,0xfc,0x17,0xe8,0x1e,0xcd,0xd9,0xe2,0xf1,0xeb,0x8,0xff,0x33,0xe5,0xfb,0xeb,0x4,0xfe,0xf7,0xfd,0x1f,0xee,0xff,0xed,0xf8,0xe0,0xff,0xfd,0x2b,0xa,0xf5,0x15,0x1d,0xf3,0x3f,0x16,0xf6,0xf2,0xee,0xf4,0xef,0xf0,0x56,0xa,0x1a,0xbc,0xfc,0x2f,0xfb,0xf0,0x56,0x1e,0xe,0xc6,0xe8,0x6,0xb,0x11,0x62,0x3e,0xf9,0xb8,0xc9,0xed,0xeb,0x2,0x63,0x2c,0xfd,0xc5,0xe9,0x0,0x17,0xf,0x37,0xfe,0x20,0xcc,0xe0,0xe0,0xe,0xe6,0x20,0xa,0xfd,0xdf,0xee,0xb,0x2,0xee,0x1f,0xfb,0x6,0xd2,0xed,0xfe,0xeb,0xfc,0x12,0xfd,0x14,0x0,0xd8,0x8,0xf6,0xec,0x17,0xf9,0x10,0x0,0xd9,0x18,0xf1,0xee,0xf,0xf4,0x3,0xee,0xeb,0xf0,0xef,0xf2,0x6,0x4,0x0,0xf4,0xf,0x9,0x6,0xf7,0xb,0xfd,0x1,0x3,0x3,0xf4,0xf6,0xdd,0x14,0x1c,0xef,0xf1,0xdd,0xf7,0x13,0xd9,0x15,0xef,0x2,0xd2,0xe7,0x5,0x5,0xe2,0x9,0xf2,0x11,0xf5,0xba,0xf0,0x4,0xe0,0x1,0x6,0x10,0xe6,0xef,0xfc,0x12,0xf9,0xf4,0x1b,0x2f,0xe3,0xf,0xd7,0xf6,0xb,0x11,0xf7,0xc,0x0,0x6,0x18,0xef,0x6,0x3,0xa,0x9,0xf6,0x1a,0xd,0xed,0xfe,0x2c,0x43,0xf4,0xe5,0xde,0xf5,0x2,0x25,0x5a,0x49,0xd4,0xe6,0x24,0x1e,0xf7,0xe,0x5c,0x5d,0xf0,0xf9,0xe4,0x1c,0xeb,0x28,0x7f,0x5b,0xec,0xfa,0xdb,0xc,0xf5,0x20,0x49,0x51,0xe1,0xed,0xe6,0xe,0x26,0x28,0x33,0x35,0x5,0xe1,0xe4,0x1f,0xfc,0xf9,0x39,0x18,0x4,0xed,0xed,0x1,0xe7,0xe6,0x8,0x9,0x3,0xe7,0xf9,0xe,0x6,0xec,0x8,0x12,0x1a,0xda,0xef,0xdf,0xf9,0xe2,0x1e,0x1c,0x0,0x12,0xd7,0x1,0xf7,0x21,0x17,0x13,0x19,0xde,0xe0,0xec,0x16,0x1,0x1b,0x6,0xc,0xf0,0xe8,0x18,0x3,0x6,0xe,0x9,0xfa,0x3,0xf3,0xdd,0x1,0xfb,0xa,0x2a,0xf4,0xf6,0xda,0xe9,0xfe,0xe9,0x12,0x19,0xe9,0x5,0xdf,0x0,0xeb,0xf2,0x10,0xc,0xe1,0xcd,0xcb,0xf2,0x1f,0xd9,0xc,0xfa,0xfb,0xe8,0xde,0x0,0xfc,0xe5,0x0,0x11,0x2,0xe6,0x17,0x14,0x0,0xf2,0xfd,0x0,0xe1,0x10,0x24,0x12,0xec,0xed,0x1e,0x9,0x18,0x3,0xc,0x4,0xf4,0x15,0xf,0x10,0x18,0xd6,0x29,0x10,0x4,0x1c,0xef,0xf,0xc,0xc7,0x4,0xfe,0xeb,0xff,0xf5,0xe3,0x15,0xfe,0xcb,0x10,0xff,0x12,0xfb,0xe4,0xeb,0xf9,0x0,0x2,0xf1,0x14,0x13,0x1,0x2,0xf9,0x1,0x6,0xc,0xf5,0xa,0x1e,0x1,0x19,0xe,0x5,0xf5,0xa,0xff,0xff,0xf2,0xfb,0xdb,0xf8,0x6,0x17,0xf2,0xf7,0xd,0xe,0xf4,0xfa,0xf7,0x14,0xdb,0xe0,0xfd,0x8,0x16,0xf7,0x16,0xfc,0x9,0x27,0x7,0x9,0xfb,0xa,0xfc,0xc,0xe4,0xdb,0xee,0xff,0x10,0xf3,0x9,0xfa,0xf4,0x23,0xf3,0xf4,0x19,0xff,0xfa,0xff,0x19,0xf,0x11,0xed,0xec,0xf8,0xf,0x10,0xf3,0xff,0xb,0xf7,0x6,0xb,0xe,0x7,0xe4,0x18,0xa,0x8,0xe,0x2,0xa,0x5,0x19,0x2,0xf3,0xfe,0xfe,0xb,0xf,0xfc,0xfa,0x5,0xf9,0xe2,0xf9,0x1b,0xf7,0xf,0x7,0xfc,0x12,0xfe,0x1,0xfd,0xf0,0x4,0xf4,0xfd,0x7,0xf2,0x4,0x4,0x7,0xef,0xc,0xed,0xe,0xf6,0xef,0x8,0x7,0x4,0xe9,0xf3,0x20,0xda,0x15,0xf8,0xff,0xec,0xe0,0xf6,0xff,0xe9,0x8,0x1,0x10,0xf0,0xfc,0xe9,0x8,0xe8,0xf5,0xf8,0xe5,0x17,0xe6,0x3,0xfc,0x9,0xf5,0xdd,0xf2,0xff,0x5,0xf6,0xf8,0xf5,0x7,0xfc,0xf1,0x4,0xf3,0x13,0xe1,0xf,0xf2,0xa,0xf9,0xfd,0x1c,0xe0,0x11,0x1b,0xe6,0xef,0x5,0x5,0xc,0x23,0x10,0x9,0xfe,0xf7,0x1a,0xf1,0xfc,0x11,0x1d,0xff,0x3,0x3,0xe6,0x7,0x11,0xc,0xd,0x16,0x5,0x5,0x25,0xf3,0x10,0x10,0x6,0x9,0xe8,0x1a,0xf0,0xee,0x9,0xff,0x24,0xf7,0xfb,0xe6,0x6,0xfa,0x8,0x3,0x0,0xf2,0x4,0xf0,0xeb,0x14,0x1c,0x3,0x21,0x14,0x1d,0xfe,0x3,0xf6,0x2,0x9,0xff,0x0,0x13,0xef,0x10,0x1e,0xb,0x1d,0x1c,0xf1,0xf6,0xe7,0xfd,0x14,0x1,0xff,0x13,0xf7,0xfc,0x0,0x21,0xe3,0xeb,0x7,0xe,0x9,0xf1,0xf8,0xfd,0x3,0xee,0x19,0xfd,0xff,0xfb,0xff,0xea,0xfb,0x7,0xf0,0xa,0x4,0x4,0xb,0x12,0xfe,0xb,0xe0,0xff,0xf6,0xe5,0xfc,0x11,0xed,0xfd,0x15,0x3,0xdd,0xdb,0x4,0xfe,0xff,0xe,0xff,0xfa,0xfb,0xe5,0xef,0xf6,0xfe,0x22,0xf,0xe8,0xfe,0xf4,0xfd,0xd9,0x3,0xa,0xdf,0xcf,0xf1,0x14,0x5,0xfd,0xfb,0xf3,0xfb,0xfb,0xf,0xf8,0x5,0x9,0x3,0xf7,0x5,0x5,0x13,0xfb,0xeb,0x23,0xe7,0x18,0xfb,0x0,0xfe,0xdd,0xe9,0xea,0xd3,0xe8,0x1a,0xef,0x1,0xf1,0x9,0x1d,0xd8,0xfc,0xda,0x19,0x3,0xec,0xe5,0xf3,0xed,0xa,0xf4,0x13,0xb,0xf7,0xc,0x0,0xf9,0xea,0xe3,0xfe,0xff,0xd,0xa,0x1b,0xd7,0x17,0xeb,0xe9,0x0,0xe,0xee,0x24,0xef,0x9,0x7,0xf0,0xf5,0x7,0xf5,0xf5,0x10,0x17,0x6,0xf7,0xfc,0x2,0xfb,0xf9,0xe7,0xa,0x26,0xf3,0x1,0x1,0x9,0xb,0x2,0x27,0xf8,0xee,0xfd,0x1c,0xf8,0xf2,0xf,0xfc,0xd,0xe0,0xea,0x2,0xb,0x0,0xe0,0x8,0xfe,0x10,0x4,0xfe,0xeb,0x13,0x1,0xc,0xe,0xed,0x9,0x1,0xc,0xe3,0x10,0xdf,0xd1,0x14,0xf3,0xef,0x9,0xf0,0xee,0xe5,0x11,0xf4,0xf6,0x0,0xe8,0x20,0xa,0xfc,0xea,0xf7,0x2,0x16,0xe7,0xf3,0xd,0xe4,0x4,0xe6,0xef,0xf8,0xf,0x23,0x2,0xe0,0x1,0x1,0x1,0x5,0xf5,0xd,0xf5,0xf5,0xe1,0xff,0x4,0x0,0xf4,0xd,0xee,0xf1,0xef,0xf7,0xb,0xff,0x1b,0xec,0x5,0xe7,0xf3,0x13,0x12,0xf2,0xf3,0xfc,0xea,0x6,0xfe,0x13,0x12,0xdb,0x11,0xe2,0xfc,0xd,0x1c,0xe8,0x1d,0xfc,0xf2,0xe2,0x13,0x1d,0xda,0xf6,0x1c,0x18,0x1e,0xf4,0xfa,0x3,0xdc,0xf,0xff,0xff,0x18,0xb,0xed,0xf1,0xf8,0x2,0xf4,0x10,0xf9,0xeb,0xb,0xe,0xf,0x1,0x2,0x1b,0x6,0x10,0x0,0xe7,0x23,0xd,0xf6,0x11,0x8,0xf5,0xf,0x5,0x13,0xf7,0x1,0x1,0xc,0xf6,0xf9,0xf0,0x29,0x1,0xe9,0x11,0x2,0xfa,0xeb,0x16,0xe,0x10,0x9,0xe,0x1c,0xa,0xe3,0xd3,0x1,0xe3,0x0,0x6,0xe2,0xe9,0x19,0xef,0x12,0xf3,0xfc,0x2,0xb,0xc,0xd,0xed,0xfd,0xf6,0xf9,0xe9,0xf2,0x28,0xfe,0x3,0xec,0x3,0x0,0xf8,0xde,0xd,0x25,0x7,0x1a,0xe7,0xfd,0x29,0xd8,0xf7,0xfb,0xde,0xc,0x8,0x6,0x22,0xee,0x1d,0x5,0x7,0xf0,0xfb,0xfe,0x7,0xf1,0x4,0xe9,0x1,0xfc,0xf1,0x0,0xeb,0xe3,0x8,0xec,0xfe,0x4,0xeb,0xfc,0x1,0xf6,0xe,0xdf,0xf8,0x12,0xe3,0x16,0xdc,0x21,0xa,0xe6,0x6,0xe5,0x10,0x7,0xf7,0x1e,0xde,0xe3,0x7,0x16,0xed,0x23,0xf2,0x12,0xd,0xe9,0xf9,0xe8,0xfe,0xe,0x2,0x18,0xa,0xea,0xec,0xfb,0xfe,0xc,0x1b,0x19,0x20,0xfa,0x7,0xe5,0xc,0x4,0x27,0xdb,0xe6,0xfe,0xd,0xa,0xa,0xfe,0x39,0xdd,0xde,0x5,0xec,0x9,0x5,0xa,0x2c,0xf4,0x2,0x1f,0xd3,0x24,0xee,0xf,0x3c,0xf5,0xfd,0xf8,0xf8,0x12,0xf5,0xf3,0x19,0xf9,0xda,0xf6,0xa,0xa,0xf4,0x9,0xf,0xfc,0x0,0x1,0x1,0xf3,0xf8,0x5,0xf3,0xc,0x19,0xe,0xfd,0xfa,0xe1,0xfc,0xc,0x3,0xfb,0x1b,0x6,0xcc,0xe4,0x8,0xf9,0x10,0xe9,0x6,0x0,0x17,0xe8,0xd,0x12,0xca,0xf5,0x23,0xe4,0x21,0xf6,0x19,0x33,0xdd,0xfa,0xc,0x1,0x14,0x7,0x0,0x34,0xda,0x5,0x7,0x1,0x7,0xe4,0x6,0x24,0x2,0xff,0xf0,0x9,0xfc,0xf4,0x3,0x6,0xee,0x8,0xe2,0x1d,0xfa,0xc,0xfc,0x2,0x3,0xe5,0xf0,0xe2,0xa,0x18,0x12,0xc,0x1e,0x20,0xed,0x20,0xe4,0x1,0x2a,0x9,0xd,0xe,0xd0,0xf4,0xdd,0xfd,0x2b,0xf2,0x8,0xc,0xf8,0xf7,0xfc,0xf9,0x15,0xef,0x19,0x1c,0x1,0xff,0xe2,0x1,0xf3,0x30,0xe,0xfb,0x15,0xe8,0x1c,0x0,0xfa,0x16,0xef,0xea,0xfb,0x5,0xf0,0xe,0x2,0x13,0xf4,0x1,0x3,0xe5,0x29,0x7,0x9,0x24,0xf9,0xe3,0xf8,0xde,0x2d,0xf4,0xf5,0x40,0xed,0xdf,0x7,0xef,0xf,0xa,0xb,0x32,0xd,0xe8,0x0,0xe6,0xf6,0xfc,0xfd,0x19,0x11,0x9,0xf3,0x3,0xea,0xf1,0xfb,0x2,0xfd,0x6,0xff,0xfe,0x9,0xec,0x6,0xc,0x15,0xf9,0x6,0xd7,0xe3,0xf7,0xed,0x1,0x3,0xfd,0x14,0x1,0xe,0xe0,0x37,0xd,0xd2,0x18,0x2f,0xea,0x12,0xd,0x5,0x3a,0xd5,0x7,0x1e,0xf2,0x21,0x11,0xf9,0x36,0xd3,0xf5,0x12,0xf6,0xfb,0xf6,0x6,0xf,0xde,0xf9,0x6,0x9,0xdf,0xff,0xb,0xf3,0xf5,0x1,0xf1,0xea,0xf2,0x2,0x12,0xfc,0xe,0xee,0xf8,0xeb,0x0,0xef,0x21,0xf,0x9,0xef,0xeb,0x1e,0xef,0xf2,0x26,0xf9,0x17,0xf1,0xf1,0xf0,0xc,0x10,0x1d,0xff,0x1d,0x6,0x3,0xf6,0xfb,0x14,0x1b,0x3,0x22,0xfd,0xec,0x3,0xfa,0xf8,0x1,0x2b,0x1e,0x1b,0x9,0x9,0x7,0xff,0xf0,0x20,0xee,0x14,0xfb,0xf6,0xf8,0x11,0xd9,0x29,0xf4,0xfa,0x7,0xef,0x20,0xf9,0xf2,0x30,0xee,0xf0,0xf3,0xd6,0xd,0xfe,0x3,0x36,0xf5,0xd7,0x1,0xe6,0x4,0xf0,0x5,0x1f,0xf,0xdd,0xff,0xf8,0x1f,0xf2,0x4,0x37,0xfa,0x0,0xfd,0xf8,0x10,0xe1,0xfb,0xd,0xed,0xf6,0xe2,0xfe,0x8,0xfe,0x7,0x8,0x8,0x11,0xa,0xf0,0xf8,0xf5,0x4,0xea,0x8,0x12,0x6,0xd,0xf,0x10,0x40,0x28,0xc0,0xfb,0x3f,0x8,0x1d,0x9,0x1b,0x3d,0xee,0xf4,0x29,0x13,0x20,0xfc,0x11,0x4c,0xdb,0x2,0x15,0x5,0xec,0xeb,0xa,0x22,0xe7,0x0,0x2,0x1,0xd4,0xea,0xa,0xf3,0xe3,0xf8,0xf5,0xfa,0x1,0xd,0x19,0x6,0x24,0x13,0x2,0xf5,0xf1,0xf1,0x1b,0xf,0x19,0x4,0xe3,0xf9,0xe7,0x2,0x29,0xfc,0x29,0xec,0xe9,0x4,0xdc,0x22,0x1d,0xfd,0x1f,0x1,0xec,0xe8,0xf5,0x14,0x1b,0x19,0x6,0xe,0x2,0xd,0xf9,0x6,0xfc,0x15,0x7,0xfa,0xc,0xe1,0x18,0x1a,0xe8,0x1b,0xe9,0xef,0xa,0x18,0xfc,0x5,0xf9,0x14,0xdc,0x4,0x1,0xff,0x7,0xfd,0xf0,0x2c,0xf2,0xec,0xe,0xe7,0x1a,0x5,0xe8,0x35,0x13,0x9,0xf9,0x7,0xfe,0xfa,0xd,0x40,0xc,0xea,0xf4,0x4,0x1,0x11,0xfc,0x23,0xeb,0xf4,0xe9,0x4,0xeb,0xe7,0x7,0x9,0xfb,0xf1,0xf6,0xfd,0x2,0xfa,0x2,0xff,0x0,0xff,0xf1,0xf1,0x1a,0xe9,0x10,0xe3,0xb,0xc,0x8,0x4,0x1b,0xa,0x2b,0x10,0xe1,0x1,0x1f,0x6,0x4,0xec,0x19,0x49,0xee,0xf8,0x22,0xc,0x20,0x2,0x7,0x31,0xe7,0xff,0xf,0xf0,0xfd,0xea,0x13,0x26,0xce,0xfa,0xff,0xee,0xe9,0xfe,0x15,0x8,0x4,0x5,0xd,0xfa,0xdd,0xf8,0x7,0xb,0x33,0xef,0xec,0xf9,0xd9,0xe6,0x1d,0x10,0x41,0xf6,0xdf,0x11,0xe3,0x14,0x1d,0xfb,0x2b,0x15,0xdc,0x9,0xf6,0x5,0x16,0x0,0x1c,0x27,0xe4,0xfc,0xf7,0x16,0x8,0x8,0x2f,0xdd,0xf8,0xfa,0xe9,0xe,0xb,0xb,0x2,0x12,0x2,0xfd,0x19,0x3,0xeb,0x11,0xf4,0x9,0x9,0x15,0x12,0xd,0xef,0x1c,0xe4,0xfe,0x17,0xc,0x9,0x4,0xea,0x2f,0xf2,0x1e,0x2,0xfb,0xfe,0xe3,0x0,0x2e,0x4,0xf9,0xc,0x5,0x27,0xc,0x7,0x2d,0xf7,0xb,0xfb,0xf9,0x1c,0xdf,0x11,0x36,0x5,0xf2,0x2,0xf8,0xb,0x7,0x5,0xfb,0xfc,0xe,0x13,0xfa,0xfb,0x9,0xf5,0xfd,0x6,0x15,0xf9,0x3,0x18,0xfd,0x1a,0xa,0x3,0xe2,0xfb,0x0,0x1e,0xfe,0x4f,0x27,0xe1,0xf7,0x31,0xf0,0x1b,0xec,0x7,0x5f,0xe2,0xf8,0x40,0x5,0x17,0x24,0xc,0x3c,0xf3,0x10,0x13,0xf8,0xb,0xf3,0xf9,0x36,0xe1,0xf3,0xf4,0xe8,0xef,0xf8,0xfc,0xeb,0xe3,0xfb,0xf0,0xee,0xdb,0x6,0xc,0x11,0x1e,0x10,0xe2,0xe9,0xeb,0xd,0x34,0xf,0x43,0xd9,0xef,0x8,0xec,0x5,0x1d,0x2,0x33,0xef,0xf4,0xf7,0xe6,0xf9,0x22,0x7,0x4,0x6,0xe9,0x2,0xf0,0xfc,0x24,0x20,0x24,0x17,0xe6,0xf,0x5,0xf6,0xfc,0x1f,0xf2,0x1,0xd,0xe7,0xff,0x1d,0xf0,0xfa,0xd0,0x0,0xff,0xe,0x23,0xf9,0xf3,0x11,0xde,0xd,0x5,0x4,0xb,0xb,0xfb,0x26,0xd,0xd,0xff,0xe8,0x16,0xe8,0xb,0x3c,0x18,0xe4,0x4,0xff,0xfa,0xf3,0xff,0x40,0xee,0x6,0xfc,0xd,0x0,0xf7,0x13,0x3f,0xf7,0x13,0x6,0x8,0xf9,0x13,0xf2,0x19,0xfd,0xf9,0xf3,0xe6,0xfc,0x7,0xf6,0xfd,0xa,0x22,0x0,0x1,0x19,0xff,0xe7,0xff,0x8,0xfd,0x3,0xfd,0x1f,0xe7,0x28,0x8,0xde,0xf3,0x43,0xf6,0xc,0xfe,0x1e,0x52,0xf2,0x4,0x17,0xf2,0x8,0xd,0x4,0x38,0xde,0xc,0x10,0xef,0xdf,0xf,0x1,0x24,0xde,0xe1,0xd,0xfd,0xd4,0xf6,0x12,0xe,0xed,0x1,0xf0,0xf3,0xfd,0xff,0x18,0xf3,0x36,0xda,0xf6,0xef,0xe8,0xef,0x37,0x27,0x4e,0xf8,0xf4,0xff,0xe5,0xf3,0x32,0xb,0x36,0x8,0xe9,0xf6,0xe2,0x13,0x21,0xfe,0x12,0xed,0xdd,0xfb,0xf8,0x5,0xf,0x3,0x1c,0x4,0xfc,0xf2,0x23,0xe,0x3,0xfc,0xf9,0x18,0xf7,0x1,0x1b,0x3,0xf5,0xfd,0xde,0xf3,0x19,0xfc,0x11,0x2,0xe7,0x13,0xde,0xd8,0xf2,0x5,0x28,0x2,0x2,0x27,0x7,0x8,0xff,0x7,0x27,0xe,0x19,0x40,0xfb,0x2,0xc,0xf6,0xd,0x7,0xf,0x47,0xf8,0x5,0xe,0xfd,0x3,0x1e,0x7,0x32,0xe7,0xf6,0x24,0x1,0x1,0x2,0xa,0xff,0xf6,0x26,0x15,0xf0,0x4,0x13,0x3,0xfa,0xfe,0xf6,0xf1,0x9,0x2a,0xe6,0xea,0xf6,0x17,0x13,0xeb,0xff,0x15,0xeb,0x23,0x6,0xc8,0xf6,0x33,0xeb,0xf4,0xe7,0x12,0x2a,0xe3,0xe6,0x32,0xfa,0x16,0x15,0x17,0x40,0xf1,0x8,0x1a,0xf3,0xf6,0xc,0xc,0x11,0xd0,0x22,0x2,0xee,0xea,0xf4,0xf8,0xf9,0x13,0x10,0x17,0xf5,0xf1,0xa,0xe,0xfd,0x32,0xda,0xf1,0xe2,0xdb,0xf2,0x34,0x1f,0x53,0xfc,0xe4,0xf2,0xf6,0xf2,0x1d,0x4,0x4a,0xec,0xee,0x6,0xdf,0x1,0x1a,0x4,0x27,0xfc,0xe6,0xfd,0xd9,0xfd,0xe,0x0,0xc,0x16,0xf3,0x3,0xf7,0xfc,0xe,0xf,0x9,0x6,0x6,0x4,0x8,0x2,0xed,0xf5,0xe4,0xe6,0x7,0x6,0x3,0x18,0xea,0x13,0xe2,0xfa,0x10,0xf2,0x2,0xec,0x3,0x3c,0xf6,0xf6,0xa,0x10,0x9,0xf8,0x15,0x24,0xfd,0xd,0x9,0x1,0x0,0xff,0x0,0x1a,0xf0,0xee,0x8,0x3,0x1d,0x5,0x16,0x46,0xe6,0xf8,0x8,0x0,0x9,0x9,0xff,0x1,0xfc,0x20,0xfc,0xec,0x5,0x1b,0x3,0xf1,0x12,0xe4,0xfa,0x24,0x1c,0xf5,0xf2,0x5,0x11,0xe7,0xfa,0x2,0x20,0xea,0x31,0x10,0xcf,0xd8,0x33,0xee,0xff,0x9,0x20,0x3f,0xe2,0xa,0x29,0xee,0x3a,0xf2,0x1e,0x39,0x2,0x1e,0xfe,0xf2,0xef,0xe2,0xd,0xf,0xf1,0x19,0x2,0xe7,0xec,0xff,0xfe,0xe4,0xfe,0xfb,0x2,0xf6,0xf1,0xf4,0x7,0x1a,0x2a,0xf9,0x6,0xf9,0xda,0xf4,0x22,0x2,0x4f,0xa,0xf3,0xfc,0xf3,0xf6,0x25,0xa,0x28,0x1,0xf7,0x9,0xe6,0x5,0x28,0xf7,0x1e,0xf2,0xee,0x13,0xee,0x5,0xf,0xa,0x9,0xe8,0xe8,0xe,0x5,0x12,0xf,0x15,0x2,0xec,0xf8,0x2,0xf7,0x5,0xf8,0xff,0xdc,0x0,0x1,0x0,0x12,0x17,0xec,0x19,0xfa,0x9,0xfa,0xf3,0x1d,0xb,0x7,0x25,0xea,0xc,0xf5,0xfa,0x4,0xf7,0xfe,0x33,0xfe,0x14,0xef,0x4,0xf0,0x0,0x0,0x3a,0xea,0xfa,0x10,0x1,0xe4,0x0,0xff,0x23,0xe9,0x26,0x15,0x10,0x4,0x14,0xd,0x8,0xf8,0xfd,0x10,0xfb,0x0,0x21,0x6,0xfa,0xf,0x8,0xf1,0x9,0x28,0xf0,0xd8,0xd,0x8,0x9,0x2,0xfb,0x12,0x3,0xe,0xfb,0xce,0xf0,0x39,0xe5,0x9,0xf6,0x1f,0x35,0xdd,0x1c,0x25,0xef,0x17,0xc,0xf6,0x3e,0xf0,0x21,0x8,0xff,0xd7,0xfc,0xfd,0x1f,0xe5,0x18,0x12,0xe9,0xf5,0xe9,0x12,0xf6,0x2,0x13,0xf4,0xa,0xfd,0x3,0x9,0x8,0x2f,0x7,0xee,0xfd,0xd7,0x0,0x2b,0x29,0x3b,0xdb,0xde,0xf1,0xe1,0xf7,0x47,0x12,0x35,0xc,0xe4,0x9,0xef,0x17,0x2b,0xea,0x2d,0xf8,0xe8,0x18,0xef,0x3,0x11,0xa,0x10,0xff,0xe8,0x7,0xc,0x7,0x3,0x18,0x5,0x8,0xf8,0xf8,0x6,0x18,0xe9,0xf9,0xe0,0xf,0xd,0x18,0x4,0x1,0xf0,0x1c,0xf6,0x14,0xfd,0x12,0xc,0xc,0x2,0x34,0xf6,0xe6,0xfd,0xf9,0xf9,0xfd,0x0,0x2a,0xfc,0xf9,0xff,0xa,0xfe,0x1b,0xf5,0x34,0xdc,0xf9,0x15,0x13,0xe7,0x1b,0xf7,0x25,0xfd,0x9,0x8,0xa,0xf0,0x17,0xf,0x4,0xf4,0xe9,0x6,0x7,0xf5,0x2,0xfc,0xf5,0x9,0xee,0xf1,0x7,0x38,0x3,0x5,0xf,0x16,0xf,0xed,0xff,0x21,0xf8,0x34,0x7,0xd1,0xf9,0x27,0x0,0xc,0x21,0x18,0x42,0xe6,0x2,0x1a,0xf1,0x2f,0xf1,0xe,0x3b,0xee,0xf8,0x8,0xea,0xfe,0xf9,0x3,0x18,0xf5,0xf8,0xd,0xeb,0x1,0x10,0x9,0x2,0x15,0xfb,0xf1,0xb,0xf2,0x6,0x8,0x9,0x2f,0x19,0x2,0xfe,0xe4,0x6,0x1f,0x17,0x49,0xf2,0xe2,0x2,0xef,0x4,0x26,0x16,0x3f,0x8,0xf1,0xa,0xfd,0xf9,0x28,0x1,0x15,0xb,0xf9,0x10,0xdc,0x2,0x20,0xf7,0x16,0xe6,0x9,0x3,0xf1,0xf5,0x12,0x1c,0xfb,0x2a,0x8,0xfa,0xa,0x16,0xf6,0x15,0xf0,0x6,0x11,0xfd,0xe,0xf9,0xf6,0x12,0xed,0xf3,0xfd,0x1f,0xb,0xfa,0x8,0x30,0xf8,0xff,0xb,0xeb,0x10,0xff,0x7,0x22,0xd,0x7,0x9,0x3,0xf6,0xf8,0xfc,0x26,0xf8,0xee,0x11,0x2,0x3,0xa,0xef,0x38,0xfe,0x13,0x1b,0x9,0xfe,0x6,0x5,0xf3,0x4,0xdf,0xfc,0x0,0xe7,0x15,0xec,0xf1,0xf8,0xfc,0xed,0x5,0xe,0xf3,0x15,0x9,0x1,0xd,0xfd,0x0,0x24,0xe2,0x31,0x13,0xd5,0x1b,0x2b,0xe8,0x3,0x8,0x1d,0x33,0xdc,0xfd,0x24,0xe4,0x20,0xfa,0x7,0x33,0x1,0x12,0x6,0xf5,0xef,0xf7,0xfa,0x13,0x1,0xec,0xee,0xe0,0xfd,0xd,0xff,0x9,0xf6,0x0,0xed,0x7,0xea,0xe,0xff,0xe,0x26,0xfc,0xf0,0xe7,0xe7,0xfe,0x30,0xff,0x24,0x4,0x6,0xf4,0xf5,0xf8,0x23,0xe,0x3d,0xf2,0xfd,0x4,0xe8,0xfb,0x23,0xfe,0x33,0xe1,0x1,0xfd,0xdc,0xfb,0xe,0xfa,0x22,0xfb,0x11,0xfa,0xff,0x8,0x21,0x30,0x13,0x3,0xf2,0x3,0xf8,0xf,0xec,0xd,0xef,0xf,0x10,0x10,0xf,0xf6,0xf9,0x1e,0xf7,0xe5,0x8,0xfa,0x9,0xff,0x0,0x15,0x2,0x0,0x8,0xfe,0xfb,0xe,0x15,0x28,0xfa,0xfb,0x13,0x6,0xfb,0x5,0xf6,0x11,0xf6,0xb,0x6,0x15,0xe1,0x0,0xe9,0xf,0xe1,0x1d,0x18,0xfd,0xb,0xf,0xff,0xf2,0xf5,0xfd,0x14,0xff,0xf4,0xfe,0xe2,0xf8,0x14,0xb,0xeb,0x7,0x35,0xe2,0xeb,0xb,0x4,0x22,0xfe,0xe,0x1d,0xf2,0x24,0x11,0xcc,0xec,0x25,0xf7,0xff,0xf9,0x6,0x29,0xe4,0x7,0x1c,0xdb,0xf8,0x1d,0xfa,0x44,0xf2,0x1,0xf,0xe6,0x11,0x3,0xee,0x17,0x6,0xe0,0xc,0xd8,0xe9,0xfd,0x11,0xfe,0x7,0xdd,0xea,0xff,0xde,0xdd,0xa,0x9,0x30,0xf2,0x1,0xe4,0xe0,0xeb,0x2d,0x12,0x2d,0xeb,0xfc,0xf0,0xe8,0xf9,0x1f,0x8,0x3f,0xeb,0xe,0x13,0xf9,0xc,0x1c,0x2,0x25,0xec,0xf6,0x5,0xf3,0xf4,0x18,0x8,0x12,0xe9,0xfb,0xfd,0xf9,0x8,0x13,0x1c,0x8,0xec,0xfe,0x2,0xf1,0x19,0xf3,0x1d,0xf1,0x7,0x11,0x12,0xfa,0xf2,0xf6,0xd,0xff,0x17,0xa,0xfb,0x1f,0xf8,0x11,0x24,0xf6,0xfc,0xfe,0x7,0xed,0x5,0x1c,0x21,0xfe,0xfe,0x16,0xd,0x8,0xf,0x9,0x33,0xf4,0x1f,0x14,0xc,0xfe,0xf5,0xeb,0x2a,0xee,0xf3,0x12,0x19,0xec,0x1,0x6,0xf7,0x5,0x22,0xb,0xeb,0xeb,0x6,0xe1,0xf5,0xd,0xee,0xfb,0xa,0x31,0xff,0xe3,0xea,0x18,0x9,0xe3,0x7,0x1a,0xf8,0x15,0xfc,0xcc,0xf2,0x2a,0xe5,0x1,0xea,0x10,0x1f,0xd9,0x2,0x13,0xf6,0x16,0x1,0xe,0x3c,0x2,0x17,0x4,0xf1,0xf7,0x2,0x7,0xc,0x2,0x1f,0xf4,0xe6,0xf0,0xe9,0x5,0xf4,0xfd,0xe4,0xf7,0xe9,0xfc,0xef,0x6,0x2,0x26,0xf1,0xf1,0xeb,0xe9,0xe6,0x30,0x1c,0x38,0xf,0x3,0xf1,0x10,0x4,0x30,0x19,0x1f,0xfb,0xfc,0x5,0xe2,0xfe,0x18,0xf2,0x1c,0xf2,0xf5,0xe,0xf2,0x5,0x1d,0x28,0x12,0xf0,0xf0,0xf,0xa,0x3,0x1a,0x1a,0xf3,0x8,0x13,0xef,0xf5,0x1c,0x6,0x0,0xee,0x12,0x1d,0x3,0x18,0x6,0xa,0xe,0xf0,0xeb,0xfa,0xd,0x8,0xff,0x6,0x24,0xf,0x3,0xa,0xf,0xe,0xff,0x8,0x33,0xfc,0x0,0xe,0xfb,0xfb,0x5,0x7,0x19,0xe8,0xe7,0x12,0x11,0x15,0xf7,0xc,0x1a,0xf6,0x28,0x8,0xeb,0xf2,0x25,0xee,0x1,0x3,0xec,0xed,0xfa,0xf0,0xf2,0xef,0xf1,0x2,0x23,0xef,0x1,0x41,0xfa,0xf4,0xf4,0x15,0xf5,0xf5,0xf9,0x28,0xde,0x20,0xf6,0xc7,0xde,0x21,0xe4,0xfe,0xec,0xd,0x2c,0xee,0x24,0x10,0xf0,0x1d,0x12,0xe,0x2b,0x6,0xf8,0xfd,0x1,0x8,0xef,0xfd,0xf,0xeb,0xed,0xe1,0xdf,0xf1,0xe5,0x16,0xe3,0x8,0xfc,0xf6,0xf6,0xd8,0xf0,0x23,0xfc,0x2b,0xf5,0xff,0xe7,0xf4,0xe9,0x29,0x9,0x2b,0xc,0xff,0x8,0xb,0xed,0x29,0x14,0x3c,0xf5,0xeb,0x18,0xf6,0x10,0x22,0xf9,0x17,0x23,0x2,0xc,0xf6,0xfa,0x2f,0xfe,0x1e,0xeb,0xfd,0x3,0xf0,0x7,0x1c,0x9,0xfa,0xe1,0xd,0xf,0x18,0x3,0xfe,0xf0,0xec,0xb,0x10,0x2,0x14,0x6,0xef,0xf7,0xea,0xb,0x5,0xfe,0x1f,0x6,0xe,0x7,0x0,0xe1,0x1,0x1,0x7,0x5,0x9,0xf7,0xef,0x15,0xf7,0x12,0x5,0x3,0x4,0x1d,0x4,0x10,0x12,0x6,0x5,0x0,0x8,0x18,0xd6,0xf2,0xfa,0x7,0xf8,0x12,0x7,0xfd,0xdd,0x0,0x4,0xfb,0xf8,0x9,0xf3,0x9,0xfb,0xf0,0xe8,0x9,0x27,0xf5,0xf8,0x6,0x1,0x2,0xe,0xf6,0x1f,0xfa,0x29,0xf8,0xd6,0x1,0x22,0xf8,0x1d,0xe3,0x1a,0x39,0xa,0xd,0x19,0xf5,0x12,0xfb,0x1d,0x2a,0x3,0xf6,0xc,0xf2,0xfd,0xec,0x18,0x13,0xfe,0x1a,0xe8,0xdd,0x1,0xf8,0x30,0x1,0xf8,0xfe,0xe4,0xe7,0xff,0xeb,0x23,0xfa,0x2c,0xf0,0xfc,0xe7,0xa,0xf8,0x18,0x10,0x23,0x1,0xfa,0xe8,0xf1,0xfa,0x1d,0xe,0x17,0xe7,0xe4,0xf5,0xf9,0xc,0x17,0xc,0x13,0xe8,0xe1,0x17,0x19,0x5,0xb,0xf,0x23,0xed,0xff,0xfe,0xe0,0x14,0x16,0x0,0xd,0x1c,0xb,0xf5,0xfb,0x18,0xee,0xff,0xff,0xf3,0x18,0xc,0x5,0xfa,0xf6,0xfe,0xfe,0xf8,0xf8,0x9,0xef,0xf8,0xe,0xf0,0x0,0xf8,0xc,0xf8,0xf6,0x7,0x16,0x11,0xf8,0xea,0xff,0xff,0x1,0x20,0x7,0x8,0xfd,0x1c,0xfc,0x6,0xed,0xd,0x8,0x15,0xf0,0x25,0x1,0x1b,0x0,0x2,0xfe,0x1,0x5,0x1,0xfd,0xf1,0xe5,0xc,0xe4,0xe1,0xf0,0xfa,0xee,0xe,0x35,0xee,0x15,0xef,0xa,0xf9,0x1,0xf5,0x1f,0x5,0x1f,0xd,0xe1,0xf4,0xff,0xf5,0x23,0x2,0x18,0x30,0xfc,0xf0,0xd,0x4,0xd,0x6,0x29,0x1d,0xf9,0x8,0x6,0xe5,0x13,0xfd,0xd,0x26,0xef,0x9,0xdc,0xf2,0x5,0xdf,0xc,0xf6,0xf3,0xd9,0xf8,0x8,0xef,0xeb,0xf,0xf9,0x3a,0x3,0xff,0xe0,0xf7,0xf0,0x15,0x12,0x41,0xb,0xf1,0x4,0x4,0xe2,0xe,0xb,0x2c,0x3,0xea,0x2,0xfb,0xe7,0x8,0xe9,0x22,0xf3,0xf2,0x1c,0xfa,0xf3,0x11,0x4,0x1f,0xf5,0x2,0xf,0x1a,0x1f,0x24,0xb,0x6,0x1f,0xf3,0x6,0x0,0x2,0xe8,0xf6,0xf4,0xe8,0x7,0x2e,0xfb,0xf8,0x10,0x9,0xf0,0xe,0xff,0xfe,0x1c,0x14,0x17,0x6,0xe2,0xf1,0xfa,0x1,0x11,0x13,0x12,0x29,0xf1,0xf,0x1f,0xfa,0xfd,0xfd,0x2,0x7,0xe,0xfb,0xe,0x4,0x1,0x1,0xed,0xfe,0xde,0xfd,0x8,0xef,0xf6,0xa,0xff,0xf,0xe7,0xf2,0xf,0x2,0xea,0x10,0xf9,0xec,0xfd,0x9,0xea,0x1f,0x46,0xdd,0xe2,0xf7,0x8,0xf5,0xf7,0xe9,0x33,0xfb,0x2f,0xf6,0xb5,0x1d,0x15,0xeb,0x11,0xf7,0x2a,0x2e,0x8,0x1d,0xf4,0xfb,0x15,0xfa,0x22,0x34,0xff,0x6,0xf6,0xfd,0xfa,0xf9,0x3,0xf5,0xf4,0xf4,0xd5,0xea,0x1,0x8,0x22,0xf1,0xf2,0x6,0xd1,0xe5,0xc,0xef,0x12,0x3,0x8,0x2,0xf7,0x5,0x1b,0x7,0x39,0x34,0x21,0xe2,0xe3,0xb,0xc,0xf6,0x29,0xf7,0x24,0xa,0xfc,0xff,0x1a,0xfd,0x5,0xff,0xff,0xe,0xa,0x1a,0x9,0xfb,0x15,0x4,0x3,0xf7,0xfe,0x0,0xfc,0xfb,0x11,0xfa,0x1d,0xe,0x6,0xed,0xfc,0x23,0xd8,0xf2,0x4,0xe5,0xf,0x16,0x29,0xfe,0xf5,0xec,0xe2,0xe,0xeb,0x9,0x1d,0x11,0x5,0x11,0xe4,0x29,0x12,0x2,0x12,0x19,0xe,0x1a,0xee,0xf9,0x5,0x9,0xf5,0xfd,0x5,0x4,0xe4,0xf1,0x17,0x1,0xf2,0xfe,0xb,0xf4,0xd,0x4,0x6,0xfe,0xff,0xec,0xe9,0x0,0xff,0x3,0x3,0xfd,0xf1,0x15,0xfc,0xf3,0xff,0xfe,0x9,0xee,0x3c,0x1,0xec,0x2,0xf0,0xf6,0x20,0xeb,0x16,0x7,0x32,0xf3,0xce,0xf0,0x2,0xd4,0x11,0xe6,0x28,0xe,0xe3,0x21,0xee,0xce,0x1e,0xd9,0x23,0x26,0x6,0xfa,0xf9,0xf1,0x1,0xe6,0xb,0x7,0xdc,0x21,0xbc,0xe3,0xef,0xf8,0x12,0xfc,0xe6,0xfe,0xf5,0xd4,0x15,0xa,0x0,0x13,0xfc,0xec,0xf3,0xd6,0x1a,0xe3,0x21,0x36,0x2a,0x3,0xe9,0xe3,0xff,0x0,0x13,0x1c,0xe,0x20,0xe5,0xf5,0x24,0xb,0x20,0x14,0x13,0xf8,0x4,0x1b,0x2f,0xa,0x15,0x0,0xf4,0x1a,0x11,0xd,0x3,0x18,0xf,0x18,0x4,0x1f,0xfb,0xf2,0x1f,0x15,0x3,0xfb,0xb,0x17,0xfb,0xb,0x1b,0x1f,0xf4,0x7,0xf9,0xf9,0xf8,0xf4,0x14,0xf,0xf6,0xfe,0xdd,0xb,0xff,0x1,0x18,0x4,0x1b,0xa,0xed,0xe7,0xf9,0x16,0x2,0x1,0x0,0xf7,0xf1,0x7,0xf0,0x6,0xf8,0xb,0x2,0xf3,0xff,0x20,0xfd,0x1,0x4,0xf5,0xd9,0xf4,0xf4,0xf2,0xe8,0xff,0x4,0x0,0xf0,0xe2,0xfe,0xed,0x1b,0xef,0x20,0xfa,0xfb,0xf4,0x2,0x18,0x7,0xfb,0xef,0xe4,0x8,0xd,0xe1,0xe,0x25,0xc6,0xfd,0xc,0x1c,0xb,0xf0,0x1,0x1c,0xd4,0x11,0xf5,0x1b,0x9,0xfb,0xda,0x13,0xe3,0xf9,0x10,0x14,0xf0,0xf0,0xfd,0x1f,0xcf,0xf4,0xe4,0xfb,0xe,0xa,0x11,0xed,0xdc,0xfc,0xe6,0xf7,0xfc,0x13,0xe1,0xb,0xe4,0x4,0x11,0xee,0x21,0x14,0xe1,0x7,0xe4,0xfb,0x8,0x3,0x2b,0x27,0xf6,0xd,0x2,0x1b,0x9,0x9,0xf8,0x14,0x19,0xf,0xb,0x1,0x10,0x9,0x12,0x3,0xf5,0x18,0xf3,0xfb,0xf5,0x2,0xe,0xd,0x0,0x7,0xfc,0x18,0x25,0xb,0xf0,0xf9,0xe6,0x8,0x1,0x24,0x14,0xfa,0xed,0xe5,0x1f,0x9,0xfe,0x8,0xee,0x1a,0x1a,0x5,0x0,0xff,0xc,0xfe,0xf9,0x11,0x11,0xea,0xfe,0x8,0xf9,0xf0,0xe4,0x1,0xd,0xf1,0x0,0xb,0xea,0x19,0xea,0xf3,0xf8,0x8,0x12,0x1c,0x1f,0xfb,0xef,0xf0,0xf2,0x14,0xe1,0x3,0xfa,0xf9,0xda,0xe9,0xfc,0xf3,0xff,0x12,0x4,0xf7,0xfc,0x17,0xf,0xfc,0x29,0x3,0xe5,0xf2,0xee,0x1e,0xfa,0x4,0xed,0x25,0xf4,0xe1,0x15,0x10,0x1e,0xef,0x1c,0x4,0xde,0xe5,0x8,0x21,0xfd,0xfd,0xea,0x3,0xca,0xda,0x26,0x0,0xa,0xfd,0x5,0xf0,0xd4,0xe1,0x1a,0xe4,0xf5,0x7,0xe7,0xfa,0xdf,0xd4,0x3,0xf0,0x10,0x15,0xc,0xf4,0xed,0xe3,0xfb,0xf,0x1e,0x16,0x9,0x0,0xec,0xea,0x13,0x16,0xb,0x1,0xfb,0xff,0x0,0xfb,0x7,0x13,0x8,0xf4,0xe4,0x12,0x0,0xfb,0xfa,0xfc,0x8,0xeb,0x19,0x2,0x1c,0xe8,0x26,0xf3,0x10,0x9,0xf,0x19,0x2,0xfb,0xec,0xf7,0xe2,0xfb,0xfa,0x11,0xf3,0xb,0x8,0xff,0xd9,0xf8,0x12,0x18,0x6,0x7,0x22,0xff,0x19,0xf5,0xb,0xa,0x13,0xf2,0xfa,0x2,0x21,0xeb,0x11,0x17,0x17,0xec,0xe1,0xe,0xf7,0xe8,0xd8,0xe,0x1,0xf1,0xed,0xed,0xf0,0x9,0xf7,0xe7,0xfd,0xf0,0xf9,0xdb,0xee,0xdc,0xfb,0xf8,0xa,0xf5,0xb,0xd4,0xd7,0x8,0x6,0x18,0x6,0xc,0x13,0xfd,0x9,0x13,0x26,0x12,0xf4,0xef,0x0,0xf5,0x28,0x18,0xfe,0x4,0xe,0x21,0x1a,0xa,0x1e,0x9,0xf0,0xd,0xf,0xec,0xf3,0x17,0x22,0x0,0xec,0xe,0x1,0xe9,0x8,0x9,0xf2,0xf2,0x8,0xf0,0xb,0xd9,0x9,0x14,0xf5,0xf6,0x4,0x19,0xf4,0x11,0xe9,0xf2,0xd,0x20,0x17,0xa,0x5,0xc,0x4,0x1,0xfd,0xf4,0xfb,0x1b,0xc,0xf2,0xb,0xff,0xfe,0x1,0xd8,0xfa,0xe,0xf5,0x14,0xf9,0x1,0x4,0xf8,0xfa,0x2,0xe8,0xf9,0xf9,0xea,0xf1,0x7,0xff,0x1e,0x1,0xb,0xf7,0xa,0xf7,0xc,0xfd,0xec,0xf3,0x5,0xf8,0xda,0xb,0x15,0xf6,0xee,0xf9,0x10,0xfa,0xfe,0x8,0xf0,0xe6,0xec,0x5,0xff,0x15,0x19,0x1f,0x11,0xfc,0x9,0x8,0x1,0x6,0xfe,0x4,0x8,0xfb,0xfb,0x8,0xf4,0xf6,0x28,0x10,0xf9,0x28,0xb,0xf8,0xd,0x1,0x0,0xff,0x2,0x5,0x8,0xea,0xe9,0xf4,0xf6,0x1,0xea,0xdf,0x1f,0xfe,0xa,0xf9,0xf7,0xc,0x1b,0x6,0xed,0xf6,0xf2,0x3,0x3,0xfd,0x4,0xf5,0x10,0xa,0xb,0xf4,0xf8,0xf1,0xe7,0x5,0xfe,0xe7,0xb,0xf1,0xec,0xf4,0xec,0x6,0xee,0xde,0x5,0x1b,0xfe,0x13,0xf3,0xd9,0xea,0x4,0x10,0x5,0xed,0x15,0x2,0xb,0x10,0xfa,0x2,0x5,0xb,0x2,0x7,0xfc,0xf5,0x15,0x14,0x5,0xf7,0xc,0xfe,0xf6,0xf4,0xfa,0x6,0xfc,0x13,0xdc,0xe4,0x9,0xfa,0x2,0x23,0xec,0x6,0x11,0x13,0xf8,0xfa,0x27,0x28,0xb,0x23,0xec,0xf1,0x9,0x17,0xf,0x13,0xff,0xf2,0xfc,0xa,0xf5,0xd,0x3,0x26,0x1,0xf,0xfe,0xf1,0xfb,0xe6,0xf0,0x2,0xf2,0xff,0x2,0x11,0xff,0xfd,0x1c,0x2,0xb,0xf6,0x14,0xc,0xb,0x21,0x28,0xf0,0x11,0x5,0x6,0xed,0xf9,0xa,0xf2,0xef,0xf8,0xf1,0xfe,0xd,0xf9,0xf7,0xea,0x0,0x8,0xdb,0x2,0xf,0xfe,0x4,0xef,0x20,0x16,0x1,0xe8,0xed,0xe4,0x22,0xf6,0x19,0x0,0x4,0x1,0x13,0xeb,0xd,0xec,0x1,0x8,0x5,0xc,0xe,0xfe,0x2,0x12,0xf7,0x27,0xf9,0xfd,0x18,0xfe,0x24,0xf7,0x13,0xed,0x1e,0x9,0xff,0xd8,0xf4,0x12,0xf8,0x4,0xc,0x1c,0x11,0xfd,0x17,0x1d,0x1,0x13,0xee,0x11,0xf3,0xf8,0x6,0xf6,0x16,0xfe,0x15,0x16,0xdc,0x1f,0x0,0x25,0xee,0xff,0xf7,0xf6,0x2,0xdd,0x15,0xf1,0x14,0x8,0xe8,0xe5,0x21,0xea,0xf0,0x1a,0x7,0xea,0x8,0xea,0xe4,0x1e,0x0,0x13,0x17,0xec,0x11,0xd6,0x11,0x18,0x17,0x4,0x15,0x3,0x3a,0xd6,0x2,0x7,0x4,0xe6,0xe5,0xfe,0xe,0xff,0xed,0xfc,0xfb,0xff,0x1c,0x6,0xa,0xfb,0xf9,0xea,0x1a,0x21,0xf5,0x4,0x6,0xa,0xe3,0x16,0xea,0x4,0xe2,0xf9,0xf9,0xe6,0xfb,0xf,0xfc,0x6,0xfb,0x10,0x7,0x7,0x13,0x7,0xfc,0x16,0xef,0x7,0xdc,0x12,0x1f,0x8,0xf4,0xe9,0x14,0x6,0xf7,0xf1,0xc,0x1,0xc,0xe6,0x4,0xf3,0xf2,0xe5,0xf3,0xef,0x1d,0xf6,0x20,0x7,0xfe,0xf4,0x5,0xee,0x10,0xfd,0xe,0xb,0x2,0xd,0xd8,0x7,0xfb,0x26,0xa,0x1c,0x21,0x6,0x1f,0xf4,0x6,0x37,0x18,0xfa,0x16,0x1e,0x24,0xfb,0xf0,0x12,0xf9,0x2,0x9,0x17,0x16,0xf3,0xf9,0x17,0xf2,0x2,0xa,0x2d,0xe7,0xe3,0x25,0xf0,0xf9,0xf,0xdd,0x15,0xe6,0x4,0xfc,0xf1,0x17,0xa,0xea,0x24,0x7,0xf1,0x11,0x13,0x29,0xf4,0xc5,0xfb,0x7,0xef,0x13,0xb,0xe1,0xf1,0xeb,0xf8,0x1b,0x9,0x8,0x1f,0x15,0xf2,0x5,0x2,0xdd,0x9,0xf,0x16,0x10,0x1,0x30,0xf2,0xe0,0x27,0xfe,0xf1,0xe,0xe,0x7,0xe6,0x7,0xb,0x18,0xfe,0xf,0x1,0x7,0xf4,0x7,0x10,0xe7,0xfb,0xf3,0xf7,0xb,0xf9,0x15,0x18,0x25,0xc,0x14,0x2,0x8,0xa,0xf,0x10,0xec,0xee,0x1a,0x3,0x14,0xf,0xfa,0x25,0xff,0x18,0xd,0xb,0xea,0x1f,0x28,0x10,0xc,0xe7,0xee,0xf7,0xfa,0x3,0x15,0xc,0x1d,0x1,0x0,0x12,0xee,0x1,0xf1,0xf8,0xb,0xf3,0xfd,0x4,0xf8,0x2,0x1e,0xe,0xf3,0x2,0x10,0xfd,0x7,0xb,0x9,0x3,0x10,0x3e,0x8,0xe,0xc,0xf4,0xe7,0xfd,0x1c,0x27,0x1a,0xed,0xe1,0x8,0xdc,0xd9,0xf1,0x1e,0x7,0x12,0xf1,0x10,0xfb,0xc8,0x8,0xf,0x3,0x1d,0xdc,0x23,0x4,0xf9,0xa,0xff,0x8,0xe,0xc9,0x39,0xa,0x1,0x7,0xec,0xe0,0x5,0xe8,0x14,0xd8,0xe1,0xfa,0xd6,0xf8,0xed,0xdb,0xff,0x1d,0xf5,0x17,0xf,0x1c,0xdc,0xed,0xff,0xff,0x4,0x13,0xf5,0xe7,0xd2,0x12,0xdb,0xe1,0x13,0x11,0x23,0xe,0xf9,0x31,0xdc,0xef,0x7,0xa,0x20,0xf2,0xf9,0x13,0xff,0x1c,0x2a,0xdf,0xdb,0xe7,0x11,0xf2,0xfd,0xfb,0x28,0x0,0x15,0x3,0x2,0x20,0x7,0xf7,0x19,0x13,0x13,0xf6,0x9,0xfe,0xfd,0x20,0x14,0xf5,0xf5,0xfc,0x14,0xe,0x17,0xfe,0x15,0x4,0xf9,0xf6,0x1d,0xf6,0x1b,0xe4,0xee,0xfd,0x0,0xe9,0xee,0xce,0xf,0x20,0x5,0x2,0xd,0x6,0x5,0xf8,0xef,0xdf,0x16,0x17,0xe6,0xf1,0x10,0xf3,0x6,0x4,0xdb,0xfb,0xe7,0xf8,0x2,0x11,0xff,0xd,0xa,0xfa,0x27,0xa,0xfc,0xe8,0x11,0x17,0xf0,0xd,0xd,0xee,0xdf,0xdd,0xf1,0x15,0xd6,0xf7,0x0,0xef,0x2e,0xe6,0x24,0xfd,0xd5,0x4,0xf0,0x8,0x8,0xed,0x22,0x7,0xe1,0x9,0xd0,0xb,0x18,0xe6,0x3f,0xa,0xe5,0xe2,0xf9,0x8,0x2,0xd6,0x13,0x15,0xbd,0x0,0xe,0xf8,0xe2,0xca,0xec,0xe,0xe6,0xef,0x15,0x11,0xcb,0xdf,0xf9,0x3,0x22,0x10,0xfb,0xf9,0xe5,0x8,0xe1,0x11,0x10,0xfc,0xfa,0x0,0xf8,0x30,0xe5,0x8,0x14,0xe8,0x12,0xe2,0x4,0x19,0xb,0xfa,0x33,0xf3,0xec,0xfe,0xf8,0x25,0xf8,0x21,0x28,0xef,0x0,0xde,0xff,0x2b,0x3,0xfc,0x10,0xc,0xcf,0xfd,0x19,0xa,0xc,0xf2,0xf7,0xc,0xfd,0x2,0x1c,0xdf,0x26,0xd,0xf0,0xb,0xce,0x15,0xfb,0xec,0x27,0xf6,0xf9,0xe5,0xe2,0xfb,0xfd,0xd8,0x28,0xec,0xe9,0xf2,0xca,0x9,0x2,0x6,0xc,0xfa,0x5,0x1,0xd5,0xa,0x2,0xfb,0x4,0x17,0xdd,0xfe,0xeb,0xf1,0x9,0x10,0x12,0xff,0x0,0xe0,0x26,0xf7,0xed,0xf4,0x0,0xf2,0xfa,0x7,0x2,0xf5,0x6,0xe8,0x3,0xfd,0xdc,0xf2,0xc2,0xff,0xb,0xd6,0x25,0x4,0xe9,0xf0,0xd9,0x8,0x9,0xc5,0x23,0x12,0xf6,0x13,0x11,0xf3,0x18,0xf0,0x34,0xfe,0xfe,0xed,0xea,0x2,0x17,0xdc,0x1b,0x1b,0xea,0xfe,0xea,0xfe,0xf2,0xc4,0xfd,0x4,0xe9,0xd,0xd,0x9,0xca,0xd4,0xe1,0x4,0x1e,0xff,0xf,0xef,0xd6,0xf,0xd5,0xf8,0x26,0xd6,0x33,0xe8,0xf5,0x3b,0xf1,0xe8,0x39,0xe8,0x8,0xe5,0x1,0x2,0x4,0xf6,0x19,0xa,0xd0,0xeb,0xb,0x15,0xf7,0xe,0x23,0xf6,0xf4,0xd8,0xf4,0x17,0x23,0x25,0x14,0x1,0xd7,0xfd,0xf9,0x1f,0x1b,0x11,0xa,0x18,0xf5,0xf5,0xf,0xe0,0x2e,0x1,0xe5,0xdb,0xe2,0xf2,0x14,0xfa,0x2a,0x0,0xe2,0xea,0xfd,0xe,0xfc,0xc1,0x35,0x8,0xf6,0xf9,0xec,0x0,0x6,0x0,0xb,0xf6,0x1,0xfe,0xea,0xb,0x8,0x5,0xe4,0xea,0xd7,0xfd,0xee,0xf3,0xc,0xc,0xd,0x2,0xfd,0xee,0x17,0x10,0x13,0xfd,0x7,0x3,0xf8,0xc,0xd4,0xed,0xfe,0x7,0xf4,0xee,0xf4,0x3,0xc2,0x18,0x2c,0xd1,0x33,0xd8,0xdb,0xfa,0xed,0x10,0x1c,0xe3,0x37,0xa,0xea,0xfe,0xf6,0xef,0x20,0xed,0x32,0xf7,0xf5,0xf3,0xca,0xfd,0xa,0xcf,0xd,0x10,0xde,0x7,0x18,0x10,0xf0,0xd6,0xc,0x4,0xeb,0x1a,0xf9,0x8,0xc4,0xcb,0xe4,0xb,0x19,0xfc,0x29,0xf6,0xec,0x7,0xf3,0xed,0x2b,0xe9,0xfa,0x2,0xec,0x2b,0xf0,0xf2,0x2d,0xe8,0xed,0x0,0x12,0x13,0xed,0x1a,0x3d,0xf0,0x5,0x4,0xfc,0x13,0x10,0x1,0x40,0xf2,0x6,0x2,0xf9,0x22,0x24,0xff,0x18,0x0,0xeb,0xe8,0x14,0xf9,0x25,0xe0,0xff,0x3,0xe5,0xfd,0x8,0xea,0x2e,0xb,0x5,0xe7,0xde,0xe4,0xf5,0xea,0x3a,0xf4,0xf4,0xe7,0xed,0xec,0xf8,0xee,0x30,0xa,0xdb,0x5,0xf7,0x16,0xff,0xf7,0xfa,0x1f,0xef,0xe4,0xce,0xf8,0x13,0x4,0xf9,0x1,0xe1,0x3,0xf9,0xf9,0x8,0x4,0xfa,0xe4,0xe7,0xf7,0x28,0xfd,0xfd,0x0,0xfc,0xfb,0xef,0xa,0xec,0xc,0xa,0xd2,0x5,0xfb,0xcd,0xfb,0x9d,0xea,0x1c,0xe5,0x25,0xe8,0xea,0xb,0xf0,0xf3,0xd,0xab,0x49,0xe,0xeb,0x0,0xe2,0x3,0x29,0xe0,0x3d,0x6,0xf7,0xf8,0xcf,0xc,0x1a,0xd6,0x1f,0xef,0xfd,0xff,0xef,0xc,0xdb,0xe0,0x20,0x6,0xdf,0x1a,0xe7,0xfc,0xb2,0xd1,0xdf,0x13,0x7,0x1f,0xc,0xf7,0xde,0xa,0xdb,0xdf,0x1a,0xf5,0x29,0xd,0xeb,0x2c,0xcf,0xe,0x26,0xfe,0xef,0x4,0xf5,0x14,0x9,0x13,0x34,0xff,0xfe,0xe,0x6,0xe,0x10,0xf9,0x2a,0xb,0xe6,0xfe,0xf1,0x1a,0x36,0x29,0x29,0x5,0x5,0xd8,0x14,0x12,0x26,0xb,0x18,0xff,0xd7,0xdf,0xf,0xed,0x31,0xf7,0xfc,0xec,0xb,0xef,0xc,0xd2,0x30,0xf9,0x4,0xfe,0xef,0xe4,0xfb,0xd1,0x32,0xe5,0xee,0xf0,0xc,0xe6,0x13,0xed,0x1e,0xb,0xe4,0xe0,0xfa,0xf4,0x14,0xf4,0x18,0xf7,0xd9,0xf6,0xed,0xea,0xfc,0x6,0xfc,0xf5,0xed,0xeb,0x5,0x3,0x1b,0xb,0xff,0xb,0xef,0x1,0xf1,0x16,0x5,0x0,0xee,0xa,0xdb,0x10,0xb4,0x14,0xf,0xe1,0x1c,0xfd,0xf0,0xf8,0xc3,0x11,0x17,0xba,0x47,0x15,0xe6,0x1,0xea,0xf1,0xc,0x8,0x4a,0x15,0xf0,0xf7,0xea,0x0,0xf5,0xd4,0xf1,0xff,0xe0,0xc,0xf4,0x17,0xd8,0xea,0x3,0xff,0xd5,0x18,0xfb,0x7,0xc7,0xc9,0xdd,0xf3,0x15,0xd,0x22,0xea,0xdb,0xa,0xd6,0x9,0x1d,0xe5,0x2d,0x4,0xfc,0x35,0xc6,0xe,0x33,0xf1,0xd7,0xea,0x1,0x1b,0xe,0x1,0x2a,0xff,0xef,0xf1,0xf7,0xf,0xff,0x0,0x3b,0xe8,0xa,0xff,0xf4,0xd,0x1f,0x4,0x17,0xf7,0xdf,0xec,0x12,0x26,0x36,0x7,0xc,0x6,0xe7,0xd6,0x13,0xe3,0x30,0x9,0x0,0xf5,0xe0,0xf3,0x11,0xe2,0x38,0xd,0xf6,0x5,0xec,0x5,0x0,0xe5,0x24,0xef,0xfe,0xf8,0x0,0xd8,0x18,0xf1,0x26,0xb,0xf2,0xfc,0xe0,0xe4,0x6,0xb,0x1a,0x5,0xc6,0xf6,0xe8,0xde,0xfe,0xc,0x3,0x9,0xfe,0xe2,0x18,0x1b,0xfb,0xf7,0x6,0xf1,0xfe,0xf6,0xef,0x1b,0x7,0xd,0x1,0xa,0xed,0xf0,0xad,0x1a,0x17,0xd6,0x37,0xfd,0xd8,0xec,0xca,0xf1,0x15,0xc4,0x33,0xf1,0xed,0xf0,0xe9,0x15,0xd,0xf2,0x36,0xde,0xfd,0xe,0xfb,0x10,0xf,0xf6,0xf9,0xc,0xea,0xf0,0xe5,0xb,0xee,0xc1,0x10,0xf4,0xe8,0x1f,0xee,0x0,0xd0,0xe4,0xe7,0x13,0x7,0x27,0x12,0xea,0xea,0xf,0xea,0xf4,0x14,0xee,0xfe,0x9,0xfb,0x31,0xdb,0x1b,0x1c,0xe7,0xef,0xf5,0xf7,0x1a,0x6,0x1,0x2c,0xed,0xfb,0x4,0xfa,0x7,0x19,0xec,0x2b,0xd,0xfc,0xd8,0xfc,0xf,0x1f,0xfc,0x2d,0xf3,0xc9,0xda,0xa,0xfe,0x29,0x0,0xfa,0x9,0xe8,0xf6,0x21,0xf3,0x4a,0x1a,0xf8,0x0,0xe7,0xf0,0x21,0x1,0x22,0xf3,0x0,0xe9,0x6,0xe3,0x15,0xd7,0x3d,0xc,0x7,0xf1,0xf3,0xec,0x17,0xdf,0x29,0x1b,0xfd,0xfe,0xeb,0xed,0x17,0xf6,0x23,0xa,0xea,0xee,0xf9,0xf3,0xf,0xc,0xf8,0xf5,0xed,0xe8,0x1c,0x14,0x7,0x17,0xb,0xd,0xed,0xf7,0xed,0x10,0x7,0xd5,0xf2,0x9,0xd6,0xf7,0xb5,0xf6,0x19,0xc9,0x25,0x15,0xe8,0xf5,0xc4,0xf9,0x2a,0xb0,0x39,0xe,0x2,0x11,0xf0,0xf7,0x1d,0xeb,0x39,0x10,0x2,0x15,0xe0,0x8,0x1,0xee,0x1c,0x1e,0x8,0x4,0xf2,0x2,0xe8,0xda,0xfa,0xfb,0xe0,0xfe,0x5,0x2,0xd3,0xca,0xf4,0xec,0x10,0x16,0x5,0xd,0xd7,0x9,0xdc,0xf6,0x1e,0xf8,0x10,0xed,0xf7,0x27,0xf5,0x8,0x28,0xee,0xec,0xe0,0xf8,0x17,0xfb,0x23,0x2e,0xf1,0xfa,0xf5,0xfc,0x1a,0x10,0xf7,0x32,0xfb,0xfb,0xe8,0xf1,0x3,0x24,0xeb,0x25,0xf9,0xca,0xf1,0xfe,0x1,0x2e,0x7,0x18,0x3,0xe5,0xea,0x10,0xfa,0x3b,0x7,0xf,0x11,0x4,0xf7,0x1d,0xf1,0x24,0xd9,0x8,0xef,0x2,0xdd,0x7,0xc8,0x2c,0xd,0x6,0xec,0x17,0xda,0x21,0xdf,0x34,0xd9,0xfb,0xf2,0xf4,0xec,0xe,0xa,0xf,0xf,0xdb,0xf0,0xfb,0xe6,0xf,0x0,0x4,0xf9,0x1,0x5,0x5,0xfe,0x8,0xf3,0xe,0xf2,0xfb,0x1,0xfd,0x18,0x1d,0xf6,0xee,0x6,0xcf,0xfc,0xae,0x27,0x21,0xd2,0x33,0x3,0xe0,0xe0,0xc9,0xfb,0x3a,0xbd,0x4d,0x4,0xe8,0xf5,0xe6,0xeb,0x19,0xf2,0x4b,0x1d,0xfc,0xf7,0xd9,0xff,0xfe,0xea,0xf,0x4,0xe,0x0,0xed,0x19,0xe9,0xe9,0xff,0x11,0xef,0x14,0x1,0x17,0xbc,0xb5,0xef,0xc,0x22,0x27,0xf,0x1,0xd4,0x3,0xce,0x1,0x25,0xff,0xf9,0xf0,0xa,0x1c,0xe5,0xf,0x1c,0xee,0xf4,0xf1,0xf4,0xc,0x0,0x8,0x1c,0xf4,0xd5,0xf1,0xfc,0x1f,0x11,0x0,0x18,0x3,0xf7,0xe4,0xff,0x7,0x9,0x1a,0x18,0xff,0xea,0xec,0xfd,0x13,0x2b,0xf8,0xc,0xfa,0xdf,0xf6,0x11,0xda,0x2a,0xdc,0xfc,0xff,0xff,0xec,0x12,0xe1,0x37,0xfd,0xeb,0xfe,0xea,0xd1,0x12,0xfa,0x28,0x1a,0xd,0xf0,0xf7,0xe0,0xc,0xeb,0x35,0x14,0xeb,0x0,0xeb,0xe7,0x1b,0xfc,0x9,0x0,0xf2,0x4,0xf9,0xe5,0x1a,0xe,0x8,0x12,0xf8,0xfe,0x9,0xf,0xd,0xea,0x3,0xe1,0xfe,0xf2,0xec,0xd,0x2,0xdb,0x4,0x1d,0xd4,0x1,0xca,0x13,0x29,0xca,0x28,0x4,0xe2,0xf1,0xdb,0xb,0x2c,0xcd,0x44,0x0,0xe7,0xf4,0xd0,0x12,0x15,0xff,0x42,0x11,0x5,0xfd,0xd9,0x11,0x1c,0xf4,0x15,0xec,0xf2,0x24,0xd6,0x1d,0xec,0xda,0xf5,0xec,0xe5,0x22,0xf2,0xb,0xbd,0xd0,0xeb,0x5,0x7,0x1b,0x1,0xed,0xf5,0x2,0xcf,0x8,0x15,0xfd,0x1c,0xe5,0x4,0x19,0xc7,0x25,0x22,0xf3,0xde,0xfb,0xfb,0x20,0xf6,0xeb,0x25,0xfe,0xf5,0x8,0xf5,0x17,0xe,0x4,0x1c,0xf9,0xee,0xec,0xe1,0x6,0x12,0xff,0x2a,0x13,0xed,0xfe,0x5,0x18,0x25,0x20,0x9,0x13,0xea,0xd7,0x5,0x6,0x33,0x25,0xff,0xa,0xf0,0xea,0x17,0xe1,0x30,0xfa,0xd,0xa,0x4,0x0,0xe,0xe9,0x16,0x20,0xd,0x2,0xe8,0xed,0x7,0xe8,0x3c,0xf1,0xd9,0xfa,0xe1,0xed,0x18,0xfc,0xf0,0x9,0xe3,0x5,0xfe,0xd1,0xb,0xe,0xf5,0x25,0xfd,0xfb,0x30,0x1e,0x8,0xfc,0xc,0x21,0xea,0xfc,0xe5,0x1e,0x16,0xf5,0xf4,0xfc,0xf0,0xea,0xc4,0x21,0x27,0xe9,0x2b,0xdb,0xdb,0xec,0xe5,0xfe,0x37,0xe2,0x46,0x25,0xfa,0xec,0xe4,0xf3,0x19,0xf2,0x4c,0x6,0x0,0xfb,0xeb,0x10,0x10,0xf7,0x2a,0xf8,0xe9,0x18,0xee,0x21,0xe8,0xd5,0xf4,0xa,0xed,0x24,0xfe,0xf9,0xb2,0xbc,0xf3,0x1d,0x0,0x2f,0x7,0x8,0xe1,0xf1,0xed,0x27,0x27,0xfe,0x22,0xfd,0x2,0x20,0xd8,0x5,0x25,0xec,0xf1,0xff,0xa,0xf,0xe6,0xfe,0x46,0xfd,0xe1,0xca,0xf7,0x22,0x3,0x8,0x21,0xf5,0xf,0xf7,0xfb,0xc,0xfb,0x14,0x2d,0x3,0xe5,0xe4,0x9,0xb,0x1a,0xe6,0x1,0x28,0xe9,0xd6,0xb,0xf7,0x2c,0xfb,0x11,0xee,0xb,0xed,0x17,0xf0,0x3c,0xf5,0x8,0xfa,0xf8,0xcd,0x17,0xfa,0x39,0xea,0x11,0xf5,0xed,0xee,0xa,0xec,0x41,0xd6,0xe7,0xf9,0xfa,0xc8,0x15,0xf7,0x8,0xe,0xe3,0x8,0xe8,0xec,0xfd,0xfe,0xf1,0x0,0xe9,0xf4,0x9,0x26,0x2,0x16,0xf0,0x1,0xef,0x1,0xff,0x3,0x22,0xdb,0xfc,0xf5,0xde,0xe5,0xc4,0x1,0x28,0xd4,0x38,0x8,0xd0,0xec,0xd5,0x4,0x2f,0xce,0x4e,0xeb,0xf9,0xe7,0xdf,0xf0,0x1b,0xf5,0x42,0xf1,0xf6,0x9,0xd5,0xa,0xd,0x8,0x4,0x5,0xe2,0xe,0xd7,0x19,0xdb,0xda,0xe1,0x25,0xde,0x15,0xe,0x14,0xbd,0xb0,0xe3,0xe5,0x24,0x1e,0xf8,0xd,0xd8,0xf7,0xf2,0xff,0x18,0xf5,0x7,0xf0,0x2,0x25,0xd5,0x1e,0x2e,0xdf,0xe7,0x5,0xef,0x11,0xe8,0xe7,0x47,0xf4,0xe1,0xde,0x9,0x36,0x1a,0x11,0x11,0xf5,0x12,0xe5,0xe7,0x18,0x1,0x17,0x2a,0x3,0x5,0xea,0x9,0xb,0x12,0x4,0x17,0xf0,0xee,0xd7,0x11,0xed,0x3c,0x17,0x16,0xff,0x2,0xdc,0x21,0xf3,0x2e,0xe5,0x13,0xef,0xec,0xe2,0x10,0xd0,0x2e,0xee,0xff,0x1,0xe0,0xe5,0xb,0xda,0x1f,0xf8,0xf6,0xfb,0x7,0xdb,0x5,0xf6,0xc,0xf3,0xf0,0x10,0xf9,0xf5,0xf2,0xd,0x10,0xf7,0xf6,0xff,0x2b,0xd,0x6,0x1e,0xf3,0xc,0xe9,0x1,0xf2,0x23,0xfe,0xe9,0xdd,0x12,0xdd,0xf7,0xbb,0x22,0x1b,0xd4,0x38,0x29,0xd4,0xcf,0xf5,0xf9,0x27,0xdd,0x47,0x0,0xf2,0xe5,0x9,0xfc,0xe,0xf9,0x34,0xa,0x2,0xfd,0xec,0x25,0x1d,0x3,0x15,0x9,0xf1,0x1b,0xd0,0x17,0xda,0xda,0xe7,0x7,0xe3,0x15,0xf1,0x2,0xb9,0xce,0xe6,0xc,0x10,0x31,0xfe,0xf7,0xd9,0xfa,0xed,0xed,0x33,0xf4,0x19,0xe7,0xfe,0x3f,0xe5,0x6,0x2e,0xe6,0xf2,0xdc,0xf5,0x18,0xe6,0x1,0x2f,0xee,0xe7,0xe4,0xfe,0x2c,0x3,0xf7,0x20,0x5,0x7,0xe2,0x6,0x1e,0x5,0xed,0x2f,0x3,0xea,0xf8,0xe,0xc,0x1f,0xff,0x20,0xf4,0xe8,0xe1,0x1c,0xec,0x22,0x1e,0x5,0xfd,0xf5,0xca,0x30,0xe9,0x30,0xe4,0x14,0xff,0xf2,0xdc,0x17,0xf8,0x26,0xe1,0xb,0x1,0x11,0xc2,0x2,0xf1,0x36,0x10,0x2,0x5,0xed,0xf1,0x15,0xfa,0x17,0xf8,0xf7,0xf1,0xe8,0xd3,0xfd,0x8,0xfb,0x27,0xf5,0xf5,0x13,0x6,0xb,0xf0,0x1,0xf9,0xd7,0xe,0xec,0x12,0xfe,0xfd,0xee,0x25,0xd8,0xf1,0xb2,0x9,0x1c,0xbf,0x34,0xea,0xc8,0xea,0xdb,0xe,0x24,0xde,0x47,0xfe,0xdc,0xe0,0xf3,0x6,0x20,0xfe,0x2b,0xf6,0x18,0x14,0xcd,0x19,0x16,0xfe,0x1a,0x15,0xf8,0x11,0xf4,0x22,0xd7,0xcc,0xdd,0x15,0xdc,0x14,0xf9,0x2,0xbb,0xca,0xe3,0xf3,0xd,0x1e,0x2a,0xc,0xe4,0x5,0xe0,0x18,0x2a,0x7,0x20,0xed,0xf6,0x17,0xcf,0xf4,0x2a,0xd6,0xfb,0xce,0x3,0x37,0xe2,0xfd,0x1d,0xfb,0xe5,0xe0,0x5,0x29,0xef,0x16,0x23,0xf7,0x1,0xf4,0xc,0x14,0xff,0xee,0x31,0xf9,0x12,0xf9,0x14,0xf6,0xc,0xf6,0xb,0xf,0xd8,0xdc,0xfe,0xf,0x37,0xfa,0x1,0x9,0x4,0xd1,0xb,0xc,0x29,0xf3,0xa,0xf9,0xed,0xc2,0x18,0xf4,0x25,0x18,0xf,0x8,0xf7,0xed,0x1f,0xf7,0x4f,0xe,0xf0,0xe4,0x0,0xeb,0xfa,0x1a,0xc,0x3,0xe9,0xfc,0xf0,0xcc,0x6,0x5,0xf2,0x12,0x4,0xe2,0x16,0xa,0xa,0xf3,0xb,0xf3,0xdc,0xfd,0x10,0xfc,0xe,0xe2,0xe0,0xfe,0xf0,0xff,0xb1,0x6,0x1b,0xe4,0x30,0x13,0xc6,0xc3,0xfa,0xc,0x1e,0xd9,0x57,0x11,0xe1,0xd6,0xfa,0xee,0x1d,0xf7,0x37,0xea,0xf0,0x5,0xef,0x24,0x1e,0xf1,0x10,0xe8,0xeb,0x19,0xd1,0x18,0xf5,0xc8,0xf8,0xec,0xf5,0x1f,0xf2,0xff,0xb3,0xd2,0xe6,0xe,0x6,0x2e,0x7,0x17,0xe0,0xf5,0x2,0xf9,0x20,0x7,0x16,0x8,0xe8,0x1d,0xd3,0x8,0x34,0xda,0xf2,0xce,0xfb,0x1f,0xe1,0x0,0x2d,0xdb,0xdf,0xcc,0x5,0xfb,0xf7,0x0,0x33,0xf9,0xb,0x1,0x13,0x28,0xf8,0x7,0x24,0xf8,0xf,0x3,0xd,0xe9,0x6,0xfe,0x18,0xf9,0xed,0xf5,0xc,0xe0,0x2c,0xe,0xf9,0x6,0xfb,0xce,0x27,0xe8,0x29,0x19,0xf9,0x1,0xe,0xc8,0x25,0xed,0x30,0xeb,0x1,0xfe,0x10,0xdc,0x1e,0x0,0x1e,0x10,0xf9,0x0,0xfc,0xc8,0xe,0x4,0x13,0x4,0xf0,0x2,0xfe,0xd8,0xf,0x1b,0xf7,0xe1,0xf8,0xde,0x12,0xe2,0xef,0xa,0x2,0xe0,0xdd,0xf1,0xe,0x2a,0x25,0x15,0xeb,0x2,0xf4,0xf0,0xbf,0xfc,0x27,0xdc,0x42,0xf,0xe9,0xbf,0xe8,0x20,0x33,0xc9,0x3f,0x10,0xec,0xf3,0x3,0x2,0x2c,0x4,0x38,0x6,0xa,0xf9,0xe5,0x1c,0x3f,0xf,0xc,0x25,0xe2,0x6,0xe6,0x3,0xf4,0xd7,0xfe,0xf6,0xe7,0x2f,0xfa,0x3,0xb6,0xcb,0xf1,0x11,0xa,0x2c,0xfc,0x1e,0xe0,0xff,0xc2,0xdd,0x1d,0xf3,0x10,0xfa,0x7,0x1e,0xf6,0x20,0x7,0xe6,0xf1,0xa,0xe8,0x27,0xf1,0xf5,0x24,0xed,0xfd,0xee,0x13,0x15,0xe9,0xe2,0x22,0xe5,0xf9,0xdd,0x1d,0x32,0x4,0xfa,0x25,0x0,0xee,0xfd,0xb,0xe,0x23,0xfa,0xf,0x1,0xf8,0xf0,0x15,0xe4,0x21,0xf7,0x10,0xf9,0xe7,0xc3,0x19,0xe1,0x34,0xff,0xed,0xf4,0xef,0xd7,0x21,0x1,0x31,0xee,0xf7,0xf2,0xf3,0xe5,0xa,0xee,0x2e,0x1e,0xf2,0xc,0x7,0xc2,0x8,0xa,0x14,0x14,0x0,0xfc,0xf9,0xd6,0xfb,0xf8,0xe5,0xf1,0xfa,0xe0,0x15,0x21,0xef,0x6,0xf9,0x0,0xf5,0xf4,0xb,0xb,0x18,0x2,0xf5,0x4,0xdb,0xfd,0xcc,0x32,0x1d,0xc9,0x3b,0x12,0xd9,0xaf,0xcf,0xf,0x26,0xde,0x35,0xe4,0xdb,0xd3,0x22,0x11,0x2e,0xfb,0x36,0xfa,0xfd,0x2,0xeb,0xf,0x37,0xb,0x14,0x1d,0xdd,0x18,0xe0,0x10,0xe0,0xdf,0x14,0xf9,0xf0,0x19,0xf7,0xfb,0xc4,0xe5,0xe7,0x11,0x1,0x31,0x1a,0xf7,0xd8,0xf1,0xe9,0xf3,0x21,0xf9,0xfe,0xe4,0xe9,0x2,0xd0,0x6,0x14,0xd7,0xfc,0xec,0x6,0x10,0xfc,0xf0,0x1c,0xe7,0xec,0xe3,0x3,0x21,0xe4,0x4,0x12,0xf0,0xf3,0xed,0x16,0x36,0x2,0xfd,0x13,0x11,0xdf,0xeb,0x19,0x7,0x10,0xc,0xf9,0x8,0xf8,0xf4,0x1d,0xfd,0x1d,0x16,0xf4,0xa,0x8,0xec,0xc,0x9,0x3d,0xe0,0xb,0xee,0x10,0xd1,0x1e,0x15,0x43,0xeb,0xfa,0xf3,0x5,0xc7,0xf2,0xd9,0x25,0x20,0xee,0xe9,0xfd,0xce,0x16,0xc,0x27,0x6,0xa,0x6,0xf9,0xd6,0xb,0x5,0xe8,0x2,0xe8,0xd2,0x10,0x1,0xf2,0x15,0x9,0x4,0xd3,0xe2,0xfe,0xf0,0x32,0x1b,0xd9,0xf5,0xea,0xcc,0xcb,0x10,0x1c,0xf1,0x3b,0x2,0xd4,0xbf,0xca,0xfe,0x12,0xdb,0x3b,0xf8,0xd5,0xe7,0x13,0x10,0x1a,0xf4,0x38,0x9,0x8,0xee,0xf4,0xf4,0x3c,0xf7,0x15,0x4,0xe4,0xfa,0xf4,0x4,0xee,0xf4,0x7,0xf8,0xe9,0x3b,0xe2,0x1f,0xd5,0xed,0xe6,0xfd,0x18,0x49,0x21,0x6,0xd8,0xde,0xfa,0xf0,0x1b,0xfe,0xde,0x8,0xf7,0x14,0xc7,0xf,0x1d,0xcf,0x0,0xea,0xff,0x1b,0xd5,0x8,0xd,0xd9,0xf1,0xf4,0x16,0x23,0xd8,0xc,0x29,0xdc,0xf1,0xf2,0x21,0x49,0xfc,0xe2,0x8,0x1,0xf0,0xf8,0x17,0xf9,0xf,0xf5,0xfa,0x1a,0xef,0xec,0x9,0xeb,0x1a,0xc,0x17,0x9,0x11,0xe9,0x1a,0xf7,0x29,0xf9,0xfd,0x7,0x1,0xdd,0xa,0xec,0x22,0x15,0x3,0xfd,0xe2,0xd2,0x15,0xec,0x4d,0xd7,0xfc,0xf6,0xb,0xcc,0xe,0x4,0x3,0xf7,0xfb,0xfb,0xd,0xeb,0x19,0x7,0xf4,0xf4,0xe5,0xde,0x22,0x7,0xea,0xf7,0xeb,0x23,0xc8,0xee,0x3,0x4,0xf,0x19,0xc3,0xf8,0x6,0xd0,0xf7,0xfe,0xe,0xe7,0xa,0x2,0xb0,0xb8,0x0,0xfb,0x18,0xf,0x22,0xf7,0xe9,0xdc,0x9,0x15,0x23,0xd,0x22,0x13,0xe2,0xed,0xeb,0x18,0x20,0xb,0x12,0xfc,0x2,0xf1,0xdb,0xe,0xe1,0x4,0xdb,0xf,0xf3,0x1a,0x6,0xef,0xdb,0xdc,0xdd,0xfb,0x0,0x2a,0x20,0xfd,0xc1,0xe3,0xef,0x1,0x14,0xf2,0x14,0x0,0xf,0x28,0xd9,0xff,0xf4,0xdc,0x9,0xfa,0x1c,0x8,0xd1,0x3,0xa,0xf4,0xe4,0xdb,0x20,0x30,0xea,0x6,0x11,0xe2,0x26,0xf7,0x16,0x22,0xf9,0x7,0x2,0xf5,0xf6,0xfb,0x1d,0xc,0x16,0xa,0x7,0xf9,0x11,0xde,0x20,0x8,0x19,0x4,0xa,0xb,0xc,0xf7,0xf4,0xfc,0x41,0xf1,0xf8,0x16,0x9,0xdc,0xe,0x1a,0x2b,0x1f,0xe7,0xfe,0x1,0xe0,0xfd,0xe2,0x34,0xec,0xf3,0xf5,0x3,0xec,0xb,0xfb,0x4,0xf6,0xdd,0xfd,0x6,0x14,0xd,0xfa,0xfc,0xf1,0xa,0xca,0x1,0xec,0xe,0xe,0xec,0xd7,0xee,0xd4,0xf2,0xfe,0x16,0xfa,0xbd,0xd,0xef,0xcb,0xc4,0xee,0xed,0x13,0x10,0x19,0xf8,0xb1,0xf1,0xe3,0x0,0xf3,0xc,0xf6,0xde,0xc6,0x15,0x27,0x14,0x29,0x15,0xf6,0xf4,0xf5,0xe7,0x0,0xb,0x2f,0xc,0xef,0x3,0xf,0xfd,0x8,0xf3,0xf9,0xf9,0x5,0xd,0x34,0x15,0x1b,0xc8,0xd1,0xf2,0x1b,0xa,0x22,0x12,0x11,0xe9,0xf4,0xe1,0x2a,0x20,0x3,0xf2,0xf8,0x14,0xb,0xd0,0xf4,0xe,0xbf,0xc6,0xd8,0x4,0x5,0xf8,0xf4,0x4,0xc9,0xea,0xfd,0xf7,0xfa,0xe3,0x1b,0x11,0xde,0xc,0x11,0x25,0x29,0xe5,0x2,0xef,0xef,0x2,0xfa,0x1a,0x21,0x19,0x9,0x8,0x5,0x4,0xe5,0xfa,0xed,0x2d,0x26,0xfa,0x17,0xf6,0xe8,0x12,0x12,0x31,0xfc,0xd,0x0,0xf7,0xeb,0x19,0xf1,0x2a,0x6,0x14,0xec,0x8,0xd3,0x21,0x7,0x32,0xe3,0x2,0xb,0xfb,0xd8,0x27,0x7,0x5,0xe6,0xf5,0xf5,0xa,0xf7,0x2c,0x2a,0xd8,0x1b,0xda,0xf7,0xea,0xf6,0xf9,0xe,0xf8,0xc,0x5,0xc7,0xd6,0x6,0x12,0xe3,0xe1,0xe1,0xd8,0xdb,0xc6,0xf8,0xe6,0xfa,0xc,0x7,0xf8,0xe7,0xe1,0xf,0x0,0xf3,0x3,0xf0,0xde,0xcc,0xf5,0xfc,0xef,0x1e,0x16,0x13,0xfb,0xf4,0x3,0xe9,0xfc,0xfa,0x15,0xe8,0x15,0x9,0xf1,0xd,0xdb,0xa,0xe8,0x9,0xf5,0x1a,0x4,0xf8,0xd8,0xd4,0x4,0xee,0x25,0x29,0x9,0xfe,0xf3,0xf5,0xd4,0xa,0x15,0x19,0xf5,0x12,0xfe,0x4,0xe7,0x1,0xeb,0xde,0xbe,0xfe,0x9,0x12,0xdf,0x13,0xe0,0xef,0xc7,0xff,0x3,0x8,0xfe,0xf2,0x19,0xe0,0xe4,0xc,0x22,0x1e,0x5,0xf7,0x16,0xf2,0xf9,0x6,0x17,0xf6,0xc,0x1e,0x23,0x8,0xfe,0xdc,0xfd,0x17,0x11,0xdf,0xf5,0xf,0x1,0x3,0x8,0xee,0x1b,0x2,0xb,0x1b,0xc,0x16,0x1a,0x0,0xf,0x26,0x14,0xf8,0xf4,0xf3,0x19,0x16,0x22,0xa,0xd0,0xf9,0xf1,0x5,0x2b,0x1e,0x1e,0xef,0xf5,0x6,0x5,0xe7,0x3f,0x2a,0x6,0xf0,0x15,0x14,0x13,0x20,0x1b,0xde,0x10,0x5,0x33,0xf8,0x8,0x4,0x17,0xd,0xf,0xf6,0x1,0xed,0x28,0x25,0x1c,0x13,0xfb,0xea,0xfb,0xf3,0x1c,0xf9,0x1f,0xf0,0xfb,0x17,0xf8,0xff,0x10,0xf7,0xb,0x24,0x4,0x0,0xd,0xc,0xf7,0xa,0x16,0x13,0xf8,0x5,0xa,0xf1,0xf5,0xee,0xf8,0x14,0xe,0xed,0xfe,0x1b,0xfe,0x17,0x13,0x10,0x12,0x21,0x1c,0xfa,0xe5,0xb,0x8,0xc,0x10,0x1b,0x3,0xef,0xd,0x5,0xa,0xf0,0x4,0x11,0x15,0x0,0xfd,0xef,0x2,0x18,0xf4,0x9,0xfa,0xf6,0x2,0xf7,0xfd,0x13,0xef,0x13,0xf7,0xf9,0x17,0xf,0xfa,0xf8,0x15,0xff,0x4,0xef,0xf0,0x15,0xfa,0xfe,0xf0,0xf4,0xed,0x6,0x1c,0x2,0xfb,0xf7,0x5,0xfb,0xc,0xef,0xf4,0xf0,0xf6,0xec,0x17,0xf3,0xf5,0xef,0x2,0xfd,0xe5,0x21,0xc,0xf1,0x1e,0x8,0xf1,0xb,0xf7,0x9,0x1d,0xf2,0xf9,0xf2,0xfb,0xe,0xed,0xf8,0xfa,0xdd,0xf0,0xfd,0xdb,0x1a,0xf4,0xef,0xc,0x6,0xf,0xdf,0xe2,0x6,0x6,0xee,0xfa,0xd,0x17,0xfc,0xf9,0x15,0x1a,0xe4,0xfb,0xc,0x1a,0xfc,0x1b,0x4,0x7,0x20,0xff,0x9,0xf,0xf2,0x26,0x19,0x1f,0xd,0x2,0x16,0x3,0x3,0xfd,0x5,0x1,0x1b,0xa,0x11,0xfa,0x21,0x13,0xfb,0xc,0x5,0xf3,0xdd,0xe4,0xdc,0x22,0x1b,0x15,0x14,0xe,0xe8,0x0,0xf7,0xf8,0xf4,0xb,0xb,0xfd,0x21,0xe3,0xf,0xe1,0x22,0x1,0x21,0xb,0x1f,0x9,0x10,0xe2,0x18,0x11,0xe,0xed,0x1,0x14,0x12,0xfd,0x11,0xf6,0xe9,0x20,0xe1,0xf5,0x1b,0x27,0x22,0xfa,0xf7,0xfe,0x13,0xf6,0xdc,0x6,0xd,0xf4,0x5,0x20,0xd,0xb,0xe4,0x15,0x28,0xc,0x0,0xf5,0x7,0xc,0xa,0x6,0xe,0xf3,0xfb,0xfe,0x4,0x8,0xf4,0xef,0x3,0xe4,0xeb,0x6,0xee,0xed,0xdb,0xeb,0x1d,0xf4,0xfa,0xc,0xfc,0xfe,0x11,0xf7,0xf8,0xf5,0xef,0xe7,0xfc,0x1b,0xdc,0x17,0xfd,0xfe,0x0,0xea,0xf4,0xf1,0xf7,0xf,0x21,0x4,0xfd,0xd,0xc,0xa,0x14,0xfd,0x19,0x9,0x1,0xfd,0xe2,0xc,0xc,0xe0,0x25,0xfb,0xff,0xd,0x18,0xf6,0xb,0x19,0x12,0x10,0x9,0xb,0x6,0x12,0x1c,0x10,0x3,0x13,0xa,0x5,0xf,0x9,0x1,0x21,0xe4,0x1,0x26,0xf9,0xf4,0x5,0x19,0x0,0xff,0xb,0xff,0x16,0x9,0xe7,0xee,0xed,0xf5,0xf,0x2f,0xee,0x19,0x3,0xa,0x10,0xee,0xf7,0x2e,0xf4,0x8,0xf7,0xee,0x7,0x0,0xfc,0xe,0xf0,0x12,0x8,0x5,0xed,0x11,0xfc,0xfb,0xf7,0x25,0xf1,0x5,0xc,0xf9,0xfa,0x3,0xc,0x16,0x4,0x25,0xf8,0xe7,0xfc,0x11,0xd,0x19,0xd8,0xfa,0xb,0x6,0xfd,0xef,0x13,0xf6,0xff,0xe,0xf9,0x4,0xf1,0xdc,0xfb,0xe1,0xf6,0xb,0x15,0x7,0xf7,0x2,0xe,0xf1,0xfd,0xe3,0xeb,0x7,0xf1,0xef,0x3,0xfe,0xf8,0x7,0x10,0xf7,0x0,0xf9,0xf2,0xe,0xf9,0xf2,0x1d,0xf5,0xd8,0xff,0xe6,0x18,0x2a,0x1b,0x3,0x16,0xfe,0xf4,0xf5,0xfd,0x4,0x1,0xfe,0xfe,0x7,0xfc,0xe,0xfa,0x15,0xeb,0x2,0x15,0xea,0xfd,0x4,0xe5,0xfe,0xed,0xfe,0x1a,0x9,0x2a,0x1b,0xdf,0xfb,0xf8,0xf1,0x4,0x1a,0x34,0x7,0xf9,0xd,0xf5,0xef,0xec,0x10,0x1a,0xb,0xf,0x13,0xfe,0x10,0x22,0x1e,0x2,0xe6,0xf7,0x11,0xfa,0x11,0xfc,0x1b,0x21,0x12,0xf4,0x18,0x16,0x29,0xe4,0xc,0x2e,0x12,0x7,0x20,0xf6,0x1d,0xf4,0x12,0x33,0xf4,0xee,0xfe,0x5,0x6,0xfb,0x13,0xc,0xe,0xf0,0x0,0xf8,0xee,0xf3,0x17,0x0,0xf7,0xfb,0xfc,0xf,0xf4,0xd5,0xa,0xed,0xeb,0xf5,0xe9,0xef,0xd8,0xf0,0xf8,0xe2,0x19,0xf7,0xf8,0xa,0xb,0x9,0xfa,0xe7,0xf,0xfc,0xe8,0x2,0x0,0x1a,0xfe,0xfd,0x1b,0xe6,0xef,0xf,0xe3,0x10,0xf1,0xe2,0xb,0xe,0x6,0x29,0x0,0x1,0xf3,0x0,0x11,0x4,0xf2,0xf7,0xea,0xf8,0xe0,0x9,0xe,0x13,0xf4,0x0,0x9,0xfa,0xf5,0xc,0xff,0x18,0x8,0xd,0xfa,0xde,0xfa,0x3,0xf2,0xf3,0x1b,0xeb,0x6,0xea,0xfb,0xff,0xd,0xf5,0x10,0x17,0xf8,0xe8,0xf1,0xf1,0xf5,0x0,0x3,0xa,0x9,0xa,0xf3,0xfb,0x33,0x26,0xe7,0x17,0xe3,0xfa,0x1f,0x24,0xfc,0x7,0x2,0xe2,0xeb,0x8,0x2c,0xf8,0x2,0x1f,0x4,0xeb,0xb,0x4,0x17,0xf7,0xff,0x1c,0xed,0x0,0x3f,0xd5,0x17,0x1d,0xfe,0x3,0xf1,0x1c,0x17,0xec,0xe,0x54,0xee,0xf5,0x25,0xfa,0x8,0xee,0x13,0x32,0xe,0xd8,0x9,0xf,0xee,0xe5,0x6,0x10,0xf4,0xfb,0xe4,0xfb,0x9,0xde,0x13,0xff,0x2,0xf9,0xec,0xa,0x0,0xe9,0xfd,0xdc,0x6,0x4,0xdb,0x6,0x1,0xf8,0x9,0xe2,0xc,0x14,0xda,0xfe,0x20,0xe3,0x9,0xda,0x14,0x12,0xe1,0x5,0xff,0xf3,0x0,0x8,0xfb,0xf1,0xfd,0xf3,0x4,0xfa,0x8,0xff,0x1,0x1d,0xb,0xfd,0xa,0xf4,0xfb,0xfc,0xf9,0x19,0xed,0xfc,0xf2,0x6,0xe7,0x2,0xf6,0xc,0xfc,0xfb,0x1,0xc,0xeb,0x1b,0xff,0xff,0x8,0x1d,0xf7,0xe8,0xfc,0xf4,0xc,0xfa,0xf1,0xee,0xed,0xdd,0xfc,0x6,0x5,0xdc,0x1a,0xfc,0xf9,0x7,0xdf,0x1b,0x14,0xc,0xfc,0x1,0x16,0xe1,0xed,0x9,0x34,0xee,0xe4,0x1c,0x1b,0xfc,0x3b,0x3,0x15,0xf2,0xeb,0x14,0x0,0xdd,0x24,0x4,0xf1,0xed,0xfd,0xe6,0x32,0xf9,0x24,0x4,0xe,0x22,0x3,0x14,0x2f,0xf5,0x1a,0x37,0xf4,0x18,0x3,0xf,0x4b,0xe6,0xd,0x5c,0xf7,0x1f,0x1c,0xe6,0x23,0xc,0x15,0x4e,0xe0,0x5,0x1c,0xec,0xff,0x4,0x13,0x15,0xee,0x7,0xec,0xc,0xdd,0xf8,0xe,0x3,0xc,0x1f,0xe8,0xe,0xf5,0xec,0xfc,0xe2,0xe8,0xfb,0xf6,0x0,0xe5,0xea,0xf3,0xd3,0xf5,0xfd,0xd2,0xfd,0x1b,0xed,0x9,0xd1,0x23,0xfa,0xd4,0xf7,0xe9,0xf0,0xa,0xd6,0x14,0x3,0xe6,0x10,0xf4,0x18,0xfe,0xe1,0xb,0x25,0xf5,0xfc,0xe9,0xf2,0xe9,0xf4,0xd,0xf5,0x0,0xf9,0x17,0x2,0xfd,0x3,0x4,0xf8,0xf5,0x14,0xe3,0xd3,0xeb,0xe7,0x9,0xf3,0x14,0x17,0xee,0xe6,0xf6,0xff,0x11,0x26,0xf4,0xf7,0x2,0xfa,0x5,0x8,0x16,0xff,0xd,0xf7,0xf1,0xf7,0xe6,0xfb,0x4,0x4,0x7,0x2,0x4,0x9,0xf5,0xfc,0x5f,0xd6,0xe7,0x2a,0x23,0xf4,0x1b,0x6,0x1,0xea,0xe7,0x5,0x25,0xe3,0x25,0x7,0xea,0xfb,0xfb,0x9,0x25,0xde,0x37,0x4,0x7,0xe5,0xff,0x14,0x2f,0xa,0x30,0x23,0x4,0xf0,0x23,0xfe,0x1c,0xd2,0x2b,0x55,0x1,0xe5,0x26,0xfe,0x14,0xed,0x24,0x46,0xe6,0xee,0xf,0xfd,0xed,0xef,0xe,0x1e,0x5,0xa,0x12,0xff,0xe4,0xf5,0xc,0xed,0xfd,0xea,0xd,0x13,0x1a,0xe5,0xfc,0xc2,0xef,0xa,0xe2,0xf,0xfe,0xff,0xc,0xf0,0xff,0xdf,0xea,0x0,0xf6,0xe1,0x4,0xd8,0x26,0x20,0xdc,0xf4,0x19,0x6,0xe8,0xd2,0x10,0x4,0xf1,0x2,0xc,0x6,0xf0,0xf0,0x4,0x1f,0xf4,0xf5,0xed,0xf1,0xfa,0xf1,0x4,0x2,0xf8,0xfb,0x4,0xf1,0xe5,0xe4,0xa,0xf0,0xfe,0xef,0x1c,0xe3,0xeb,0xf3,0x0,0x17,0x1,0x13,0x19,0xda,0xf8,0x6,0xde,0x11,0xea,0xf7,0xf4,0xef,0x3,0x4,0xb,0xe8,0x8,0xe,0xe2,0xee,0xde,0x6,0xe,0x29,0xfb,0xfa,0x0,0x2,0xec,0x1b,0x52,0xff,0xde,0x3a,0x2f,0x13,0x30,0xe9,0xff,0xf6,0xe7,0x15,0x1d,0xd9,0x3c,0xf,0xe6,0x14,0xee,0x13,0x1f,0xe7,0x33,0x8,0xfc,0x6,0xc,0x8,0x19,0xd9,0x2b,0x1f,0x7,0x10,0x24,0x16,0x29,0xfc,0x31,0x4d,0xf0,0xd9,0x3f,0xf2,0x20,0xe2,0x25,0x49,0xe5,0xec,0xa,0xf5,0xf2,0xd9,0x22,0x1f,0xed,0x22,0x2,0xa,0x16,0x8,0xf7,0xfb,0xe,0xfb,0xfb,0x1d,0xf3,0x1c,0xf6,0xe1,0xcf,0x19,0xf4,0xf,0xee,0xf9,0x4,0xd1,0xf9,0xe2,0xda,0xf1,0x24,0xf5,0x7,0xdf,0x1d,0xf9,0xdb,0x18,0xb,0xea,0x8,0xca,0xf2,0xfa,0xec,0x4,0xe,0x17,0xed,0xf1,0x6,0x15,0xfc,0xfd,0x8,0xfa,0xe3,0xe4,0xa,0xfc,0xee,0x8,0xf5,0x9,0xef,0xee,0x6,0xef,0xe1,0x19,0x7,0xe8,0xe6,0xdf,0xea,0xd,0xf1,0x16,0xee,0xed,0xf8,0x9,0xfa,0xfb,0xc,0xf8,0xeb,0xda,0x0,0xfc,0x4,0xfe,0xf5,0xff,0xf6,0xe1,0xc,0xa,0x13,0xd,0xf6,0xf5,0x15,0x7,0xca,0xec,0x50,0xe,0xd0,0x26,0x4c,0xf8,0x23,0xeb,0xff,0x8,0xe3,0x11,0x2c,0xf9,0x2a,0xf1,0xe9,0xb,0xe9,0xf,0x15,0xec,0x33,0x11,0xc,0xd,0x1,0x1,0x32,0xe3,0x41,0x27,0x11,0x2,0x2e,0x7,0x9,0xe3,0x22,0x4d,0xf1,0x5,0x27,0x3,0x25,0xf5,0x2c,0x3b,0xf4,0x0,0x16,0xb,0xec,0xfe,0x17,0xd,0xff,0xe7,0xfe,0x24,0x6,0xee,0xf0,0xe9,0xfa,0x1c,0xf2,0x19,0x8,0xfa,0xff,0xd2,0x1,0x2,0xea,0x5,0xf2,0xf4,0xb,0xd2,0xf9,0xd,0xcd,0xd,0x12,0xf2,0xe,0xe1,0x1f,0x0,0xe7,0x14,0x4,0xff,0x9,0xdb,0xfc,0xd9,0x6,0xf9,0xeb,0x1,0xef,0xfa,0xfb,0xf5,0xfc,0xfb,0x14,0xe2,0xf9,0xf5,0x2,0xfd,0xfc,0x1,0xf7,0xf3,0x0,0xec,0xe7,0xf2,0x0,0xf1,0x11,0xec,0xf0,0xe9,0x11,0xa,0x7,0x4,0x1,0xee,0xfb,0xf2,0x14,0x1,0x12,0xf0,0xf2,0xf1,0xf0,0xfb,0x8,0x3,0xf8,0x1,0xe8,0xf9,0x17,0x26,0xf,0xea,0xf7,0xf8,0x1e,0xfe,0xf2,0xf8,0x3f,0x0,0xd4,0x1c,0x53,0xfe,0x1e,0xf,0xef,0xdd,0xed,0x10,0x19,0xe7,0x34,0xe,0xde,0xdf,0xfa,0xe,0x29,0xe3,0x16,0x9,0x6,0x12,0xeb,0xf9,0x32,0xe0,0x1a,0x1d,0xf3,0xed,0x10,0x7,0x31,0xf2,0x12,0x52,0xeb,0xf7,0x1e,0xf7,0x1a,0xdc,0x3e,0x33,0xe3,0xfb,0x1f,0xb,0x8,0xfe,0x13,0x1a,0xf4,0xf8,0xfe,0x8,0xfc,0xe9,0xfe,0xeb,0xe6,0xf6,0x2,0x18,0x2,0xe8,0xfb,0xf3,0x1,0x8,0xd7,0x13,0x4,0xe6,0x2,0xe6,0xd7,0x1,0xd4,0xf0,0xe,0x5,0x18,0xe5,0x8,0xe5,0xd2,0x16,0x12,0xfe,0xe,0xd3,0xfc,0x1f,0xe9,0xf8,0x11,0x6,0xf3,0xd5,0xf8,0xff,0xf0,0x4,0xa,0xd9,0xf8,0xfd,0xf5,0x12,0xff,0x6,0x1b,0xe6,0xfe,0xfe,0xde,0xee,0xf6,0x18,0xf1,0xf8,0x6,0xf3,0x2,0xea,0x4,0x14,0xfc,0xee,0xe6,0x9,0xf9,0xee,0xe3,0xe7,0xfc,0xd9,0xef,0xfc,0xa,0xc,0x3,0xf6,0xe2,0x11,0xf,0x19,0x18,0x10,0xef,0xe5,0x22,0xf5,0xe5,0xe9,0x4b,0xf7,0xdb,0xc,0x4f,0xde,0x22,0x16,0x9,0x16,0xd1,0xf8,0x19,0xe0,0x24,0xfe,0xb8,0xfb,0xe5,0x12,0x1c,0xe3,0x22,0x9,0x5,0x29,0xf7,0x10,0x31,0xe1,0x33,0x3f,0xfd,0xed,0x4,0x3,0x2e,0xed,0x30,0x36,0xee,0x16,0x2f,0xf5,0x1b,0xdc,0x3a,0x56,0xe5,0xef,0x26,0xff,0x3,0xd7,0x31,0x16,0xef,0xf1,0x8,0x13,0x1,0x2,0x3,0xf1,0xf2,0x8,0xff,0x5,0x12,0xf2,0xee,0xda,0xed,0xec,0xea,0xf7,0xc,0xf1,0x9,0xe6,0xe6,0x0,0xcc,0x10,0xd,0xd,0x20,0xf4,0x18,0x23,0xec,0xf9,0x0,0xe4,0x7,0xd4,0xfb,0x16,0xd2,0x1,0xe6,0x1,0x6,0xf0,0xfe,0x3,0xf3,0x9,0x1,0xd,0x5,0xf7,0xd4,0x2,0xfb,0xfb,0x8,0xf0,0x1f,0xf3,0xfe,0xeb,0x2,0xe,0x1b,0xf,0x4,0xf5,0xf0,0x1f,0x14,0xf7,0x6,0xdc,0xf9,0xe9,0x1,0xff,0x8,0xf2,0x6,0xff,0xff,0xf3,0x5,0x1a,0xfc,0xfa,0xeb,0xfb,0xfa,0x12,0x20,0xf6,0xe0,0xe8,0x1c,0xfa,0xd6,0xd,0x2c,0x4,0xe1,0x9,0x3b,0xd3,0x2a,0xee,0xf7,0xed,0xf1,0xf7,0xd,0xf0,0x32,0xf,0xc9,0xe,0x0,0x10,0x24,0xfb,0x31,0xf0,0xf4,0xdd,0xf5,0x4,0x25,0xc7,0x27,0x25,0x16,0x11,0x2e,0x9,0x30,0xd1,0x2c,0x34,0xe6,0xf0,0x21,0xf5,0x21,0xc8,0x40,0x39,0xde,0xf0,0x12,0xf3,0x10,0xe8,0x1f,0x18,0xfa,0xea,0x7,0x11,0xdf,0xed,0xfa,0xf0,0x7,0xef,0xf3,0x5,0x10,0xe5,0xf3,0xe9,0xe9,0xe8,0xd6,0x1,0xf9,0x5,0xb,0xee,0xf9,0x12,0xe3,0x5,0xfd,0xe6,0x16,0xe2,0x1b,0x12,0xc5,0x0,0xfd,0x2,0x4,0xd2,0xff,0xec,0xf6,0xfd,0x0,0xe4,0xf7,0xf3,0xeb,0xfa,0xf8,0xd,0x3,0xfa,0xfe,0xe4,0xdb,0xe3,0x6,0xff,0xf4,0xf2,0x1b,0xf1,0xf7,0x2,0x1,0x4,0x13,0xe5,0xc,0x5,0xf7,0xa,0x3,0x3,0xb,0x3,0xee,0xf7,0x21,0x20,0xff,0xf3,0x9,0xe5,0xff,0xec,0x17,0x0,0x6,0x14,0xeb,0xf2,0x18,0x16,0x1f,0xec,0xee,0xe1,0x1e,0x3,0xfa,0xfe,0x28,0x3,0xc9,0xc,0x3f,0xd8,0x30,0x16,0x3,0xf8,0xe9,0xfb,0x28,0xe1,0x36,0xa,0xdf,0xe5,0xeb,0x8,0x1c,0xcd,0x29,0xf2,0xfc,0xa,0xed,0x1,0x29,0xf1,0x20,0x13,0x4,0xec,0x17,0xa,0x35,0xc3,0x1a,0x46,0xe0,0xd7,0x3c,0x9,0x28,0xd1,0x22,0x20,0xd5,0xfa,0x28,0xfa,0xff,0xea,0x1d,0x23,0xe0,0x7,0x7,0xf,0xf1,0xf1,0x8,0xf0,0xf8,0xff,0x5,0x1b,0x5,0xfa,0xf0,0xfb,0xe3,0xe4,0xcc,0x1a,0xf9,0x9,0x6,0xee,0xf4,0x3,0xd0,0x14,0xf4,0xff,0x1d,0xe8,0x11,0xf4,0xd1,0xf4,0x4,0xb,0xfb,0xdc,0xa,0xc,0xeb,0xed,0x6,0xf3,0x4,0xdd,0xdf,0xf9,0xea,0xfc,0xf5,0xf2,0xfb,0xea,0xe3,0x3,0xee,0xe,0xff,0xdb,0x1e,0x4,0xf7,0x1a,0x4,0xc,0xd,0xda,0x4,0xe9,0xff,0x4,0x0,0xc,0xf9,0xe4,0xfb,0xf6,0x14,0xde,0x1b,0x0,0xb,0xfe,0x6,0xf8,0xf,0xdc,0x1,0xef,0xef,0xd,0xf8,0xf1,0xf,0xf9,0xf9,0xdf,0xd,0xe4,0xd9,0xf9,0x2b,0xee,0xe8,0x9,0x40,0xf9,0x2f,0xa,0xfa,0xe8,0xe9,0x1,0xe,0xe7,0x23,0xa,0xd0,0x19,0xd3,0xe,0x4,0xda,0x2b,0xf,0xe7,0xe6,0xf3,0xfb,0x2c,0xd3,0x36,0x19,0xe,0xfe,0x3,0x1a,0x2e,0xd0,0x23,0x32,0xf1,0xe1,0x2a,0x9,0x1b,0xf6,0x29,0x3e,0xce,0x15,0xa,0xe8,0xec,0xdf,0x44,0x28,0xd9,0xfd,0xfa,0x9,0xff,0xe7,0x8,0xec,0xf4,0xef,0x1,0x19,0x11,0xf3,0xeb,0xeb,0xed,0x1a,0xdd,0x15,0xf,0x7,0xfe,0xeb,0xff,0xd6,0xd5,0x4,0xf5,0x7,0x10,0xe6,0xc,0xe4,0xda,0xc,0x8,0xee,0x6,0xd8,0xf8,0xf1,0xe0,0x1,0x8,0xfe,0xf9,0xf3,0xdf,0x3,0xe6,0xf4,0xa,0xff,0xf2,0xe0,0xd9,0xeb,0x1,0x10,0x2,0xfc,0xd,0x14,0xea,0xf8,0x3,0x18,0xf3,0x9,0xfc,0xc,0xb,0x1f,0xf5,0x5,0xf7,0xf9,0x0,0xfd,0x4,0xfc,0x16,0x7,0x0,0xdf,0xf9,0xfa,0xc,0xfb,0xf4,0xf7,0xf0,0xeb,0x7,0x17,0x20,0xfb,0xf0,0xec,0x4,0x0,0xf8,0xf2,0x2d,0xf9,0xd9,0xb,0x55,0xec,0x33,0x26,0xf8,0xa,0xf2,0xb,0x25,0xdf,0x29,0x5,0xd1,0x14,0xe2,0xf2,0x12,0xdd,0x28,0xfc,0xec,0x8,0xfd,0x2,0x3a,0xe6,0x29,0x25,0xd,0x10,0x9,0xa,0x32,0xf5,0x17,0x2d,0xea,0xfb,0x35,0xfc,0x28,0xd0,0x29,0x2f,0xcb,0x6,0xf,0x4,0xf2,0xf3,0x34,0x1c,0xf4,0x8,0x5,0xfc,0xfd,0xed,0xf,0xf8,0xe9,0xf0,0x9,0x16,0xfe,0x2,0xff,0xd4,0xea,0xa,0xeb,0xc,0xf8,0xf4,0x9,0xf4,0xf2,0x7,0xd9,0xb,0xfd,0xe4,0x1a,0xef,0x14,0x8,0xd8,0xfc,0xf5,0xe1,0x3,0xcf,0xf1,0x11,0xdb,0x15,0x7,0x10,0xf8,0xfc,0xe2,0xf1,0xf5,0xde,0xff,0xe7,0x1,0xea,0xee,0xe9,0x2,0xa,0x18,0xec,0xfe,0xf9,0x9,0xf3,0xe,0x2,0xf1,0xfc,0xf9,0x16,0x5,0x7,0x9,0xd,0xe,0xf7,0x4,0xed,0x4,0xdb,0x4,0x4,0xf6,0xdc,0xee,0xec,0xf5,0xfe,0xf4,0x2,0xe4,0xb,0xe0,0x17,0xa,0xe0,0xf7,0xdc,0x11,0xd6,0xfe,0xfa,0x35,0xde,0xe6,0x6,0x44,0xf9,0x35,0xa,0xfb,0xff,0xec,0xfb,0x16,0xd9,0x23,0xf,0xd4,0xef,0xdf,0x6,0xb,0xd9,0x25,0xff,0xf8,0xeb,0xf4,0xa,0x20,0xe5,0x22,0x1c,0xeb,0xf4,0xd,0xc,0x19,0xe1,0x1e,0x31,0xe9,0xfb,0x20,0xf0,0x23,0xfe,0x35,0x28,0xb4,0x6,0x28,0xe7,0xfb,0xe9,0x2a,0x1a,0xef,0x15,0xc,0xed,0xf1,0x4,0xe,0xa,0xff,0x16,0x1,0x4,0x17,0xea,0xec,0xdc,0xf4,0xf7,0x4,0x16,0x1f,0xa,0x11,0xef,0x12,0xdf,0xd9,0xc,0xf5,0x10,0x2,0xf3,0x10,0x3,0xd3,0xf5,0xb,0x2,0x0,0xcb,0xf6,0x23,0xf6,0xf1,0x1f,0xf9,0xfc,0xf0,0xf6,0xfe,0xfa,0xf8,0xf9,0xf4,0xfb,0xa,0xd6,0x29,0x9,0x2,0x0,0xfc,0xfc,0xee,0xf5,0x5,0xfb,0x1e,0xf1,0xf1,0xf3,0x2,0xec,0x1c,0xc,0xe,0xb,0x4,0xf6,0xe7,0x14,0x8,0x27,0x1,0xfe,0xe5,0xe7,0x1,0x1b,0xf0,0xf6,0xff,0xf4,0xe7,0xee,0x18,0xd,0x8,0xf8,0xd6,0x7,0xf4,0x8,0xff,0x1d,0x13,0xe7,0xb,0x42,0xef,0x28,0x0,0xf9,0xf0,0xf3,0x0,0x15,0xfd,0x1a,0x22,0xc1,0xf5,0xe0,0xf8,0x9,0xe6,0xe,0x5,0xf9,0xf6,0x1,0x1,0x13,0xdc,0x1f,0xd,0xfb,0x4,0x8,0xb,0x15,0xdb,0x28,0x34,0xed,0xb,0x3a,0xed,0x16,0xe3,0x39,0x32,0xc4,0xb,0x20,0xe7,0xf7,0x2,0x35,0x24,0xfc,0xe8,0x1c,0xf8,0xf1,0xfa,0xc,0x1d,0xf2,0x5,0xff,0x12,0xf,0x1,0xec,0xea,0xf0,0x3,0xe7,0x15,0xfd,0x5,0x8,0xe0,0x1b,0xf8,0xe1,0x1e,0xed,0xdc,0x11,0xeb,0xfd,0x1a,0xeb,0x9,0xf9,0xf3,0x0,0xe8,0xe6,0x8,0xf7,0xde,0x1e,0x0,0x0,0x0,0xe4,0x9,0xf2,0xf8,0xe7,0xf2,0xd,0xfa,0xe2,0xf,0x4,0x8,0xf2,0x13,0xf8,0xf9,0xf1,0xff,0x3,0x11,0x12,0xe9,0xf4,0x13,0x7,0xc,0x13,0x2b,0xf7,0xdd,0xf9,0xe9,0xfa,0xdb,0x1d,0xf6,0xf6,0xf9,0xe4,0xf6,0xd,0xeb,0xd,0x8,0xe7,0xe7,0xf2,0x3,0x1d,0xd9,0xd8,0xe4,0xf7,0xea,0xdc,0xdc,0x26,0x2,0xee,0xfa,0x38,0xfc,0x1a,0xef,0xda,0xf1,0xdf,0xb,0x1a,0xe0,0x16,0x16,0xdc,0x4,0xfa,0xf7,0xee,0x2,0x25,0x2,0xf5,0xfb,0x8,0xf6,0x11,0xf5,0x12,0x8,0xf4,0xe3,0x1b,0xf5,0x3a,0xdc,0x20,0x2e,0xe0,0xf5,0x30,0xe4,0x9,0xf8,0x3c,0x45,0xd3,0x8,0x23,0xd8,0x9,0xe4,0x35,0x30,0xe4,0xfe,0x7,0xf6,0x5,0x1,0x5,0xff,0xf6,0xd,0x2,0xfd,0x3,0x5,0xd,0x0,0xf5,0xd6,0xcf,0x19,0x6,0xee,0xd,0xf2,0x1,0x18,0xef,0x12,0x4,0x2,0x21,0xd9,0x2,0xd,0xeb,0xe9,0x13,0x8,0x15,0xf0,0xee,0x3,0xec,0x6,0x17,0xed,0x0,0x1a,0xee,0xf2,0xfc,0x9,0xec,0xf8,0xf8,0x18,0xf4,0x13,0x4,0xf6,0x2,0xf0,0xfc,0xfe,0xe3,0x1,0xa,0x1c,0x1b,0xec,0xe,0x1,0xfb,0x8,0x11,0xf5,0x0,0x14,0xe6,0x12,0x7,0xf4,0x15,0x7,0xfc,0xfb,0xf5,0xf1,0x1,0x21,0x1,0xe9,0xe8,0xef,0xdb,0xdf,0x1f,0xa,0xdd,0xd1,0x16,0x4,0xfd,0xe1,0x24,0xf0,0xec,0xf4,0x38,0xe1,0x16,0xfd,0xe0,0xec,0xe7,0xc,0x2a,0x4,0xc,0x17,0xdc,0xe8,0xf2,0x3,0xec,0xfd,0x19,0xfe,0xf3,0xf0,0xf3,0xfb,0x18,0xdf,0x1c,0x0,0x9,0xf4,0x18,0xb,0x1f,0xf6,0x34,0x22,0xf4,0x22,0x45,0xeb,0x23,0xcf,0x32,0x34,0xf2,0xf9,0x29,0xd4,0xf7,0xb,0x38,0x2a,0x9,0xe6,0x5,0x1,0xb,0xfe,0x17,0xfb,0x0,0xeb,0x8,0xfd,0xc,0x2,0x1d,0xea,0xfa,0xb,0xeb,0x9,0xfe,0xfe,0x10,0xe0,0xf6,0x6,0xf0,0x15,0xf3,0x9,0x11,0xe4,0xf9,0x7,0xe1,0xed,0x17,0x5,0xc,0xe1,0xdb,0xf2,0xf8,0xea,0x22,0xe9,0x2,0x0,0xfd,0xe7,0xf2,0xf8,0xf9,0xfc,0xfa,0xe8,0xe8,0xeb,0xe9,0xd,0x4,0xf8,0xf8,0xf7,0xf8,0xd,0x3,0xc,0x13,0xf2,0xf,0xf9,0xe6,0xfd,0xf,0x19,0x8,0xf7,0xfa,0x1,0xf3,0x12,0x1e,0x5,0xa,0x9,0xfd,0xb,0x7,0x8,0x2,0xfc,0xd6,0xe8,0x14,0x1,0x13,0x19,0xef,0xda,0xe,0xa,0x7,0xef,0x34,0xe0,0x5,0x1e,0x4e,0xe9,0x19,0xff,0xe1,0x4,0xfb,0xe,0x11,0x5,0x1f,0x15,0xd4,0xec,0xf9,0xe7,0xf9,0xfc,0x25,0xff,0x6,0xf2,0x1,0xf6,0x2a,0x17,0x24,0x11,0xf3,0x1a,0x1f,0xfb,0x32,0xeb,0x33,0x2f,0x0,0x8,0x2c,0xf0,0x26,0xf4,0x25,0x36,0xd9,0xf1,0x1a,0xd5,0xec,0xf9,0x32,0x27,0xfc,0xf4,0xf0,0xe3,0xfa,0xc,0x16,0x17,0xfa,0xf9,0xe5,0x1f,0x1f,0xfa,0xff,0xfd,0xd,0x2,0xe9,0xe,0xf0,0x12,0x9,0xda,0x2,0xea,0xe5,0xa,0xff,0x3,0x13,0xf0,0xa,0xf9,0xe9,0xff,0x10,0xfc,0x1a,0xf3,0xf7,0xf,0xf4,0xfa,0xf4,0x5,0x10,0xa,0xdd,0x9,0xf7,0xf0,0xe5,0x7,0x7,0xfa,0x2,0xd7,0xf8,0xf7,0x1,0xfb,0xe,0xf8,0x7,0xf,0xfe,0x3,0x12,0x5,0x9,0x13,0xf8,0xdc,0xfd,0x27,0xf,0xec,0xf7,0x7,0x0,0xfc,0x12,0xf8,0xfb,0xea,0xe4,0xe9,0xe9,0xe0,0xff,0xdc,0xd6,0xeb,0xf2,0xf7,0xd,0x1b,0xe9,0xc4,0x6,0x0,0xfd,0x4,0x46,0xf9,0xe9,0x13,0x2d,0xc,0x1f,0xf8,0xd3,0xc,0x14,0x11,0x5,0xe5,0x27,0x8,0xc5,0xef,0xdf,0xdd,0x4,0xf8,0x11,0x10,0xf0,0xe7,0xfb,0x3,0x3c,0xe7,0x14,0xc,0xf4,0xf6,0x1b,0xa,0x23,0xf2,0x2d,0x1a,0x8,0xff,0x32,0xe7,0x1a,0x5,0x2b,0x34,0xf1,0xa,0x0,0xe8,0x2,0xdf,0x2c,0x2a,0x3,0xe6,0xfc,0xef,0xfc,0xe4,0x3,0x1,0x3,0xee,0xe9,0x15,0x5,0x3,0x13,0x11,0xe,0xee,0xf5,0x22,0x1b,0xe,0xfd,0xf3,0xa,0x2,0xdd,0x20,0xeb,0x6,0xf8,0xe2,0x6,0xe,0xde,0xd,0xf9,0x16,0x1c,0xc,0xe0,0xf0,0xec,0xc,0xf,0xf2,0x27,0x1d,0xde,0xe6,0xf0,0xf9,0xf0,0x2,0xa,0x7,0x6,0xf9,0xf,0xfa,0xf0,0xee,0xf1,0xf7,0xff,0x2,0xb,0xd,0x1b,0xee,0xf6,0x5,0xff,0x1c,0x17,0x4,0x5,0x17,0x0,0xff,0xd,0xf3,0x23,0x10,0xfd,0x5,0xfb,0xea,0x3,0x10,0x7,0xd7,0xf7,0xff,0xf3,0xf1,0x17,0xed,0xd3,0xcb,0x14,0x1c,0xf5,0x3,0x47,0xf6,0xf7,0xf2,0x3e,0xf2,0x22,0xf4,0xed,0xfc,0xee,0xb,0xf4,0xf1,0x25,0x10,0xd0,0xf6,0x0,0xef,0x10,0xfc,0x15,0xe5,0xdb,0xf3,0xea,0x10,0x22,0xf2,0x2b,0x11,0xf9,0xa,0xfc,0xf5,0x53,0x16,0x25,0x43,0xe0,0xe,0x13,0xfc,0x2d,0xe2,0x55,0x65,0xf4,0x8,0x1,0xdf,0xa,0x0,0x49,0x1c,0xfe,0xdf,0xef,0xf2,0xf9,0xf6,0xfd,0xff,0xf3,0x2,0xf6,0x14,0xb,0xe8,0x9,0xfc,0xfc,0xe2,0xe5,0x11,0x3,0x9,0xfb,0x6,0x10,0x1a,0xf3,0xd,0xfa,0xa,0xd5,0xf5,0x1a,0x11,0xf2,0xfc,0x1f,0xfe,0xe,0xe4,0xef,0xd7,0xee,0x6,0x1e,0x4,0x12,0x28,0xf7,0xe,0x6,0xf8,0xee,0xf0,0x1a,0x1,0xf7,0xfd,0x3,0x11,0x19,0x10,0x4,0xfb,0xd7,0xfa,0x16,0x6,0x7,0x23,0xfa,0x14,0x11,0xf1,0x12,0x10,0x4,0xe1,0xee,0xf7,0x21,0xe,0xa,0xa,0xf8,0x7,0xa,0xee,0x3,0x1f,0xfa,0xc4,0xec,0x12,0x1,0x1e,0xfd,0xf1,0xe8,0xcc,0xf4,0x17,0xff,0xdd,0x45,0x10,0xee,0xfa,0x3d,0xe7,0x27,0xdd,0xd7,0xf9,0xf4,0xf6,0x6,0xf8,0x1e,0x13,0xe7,0xe2,0xf1,0xe3,0xf3,0xf7,0x18,0x12,0xe4,0xa,0xdb,0xff,0xff,0xfe,0x20,0x9,0x0,0xf7,0x23,0xf6,0x2d,0x14,0x26,0x28,0xe5,0xff,0xf,0xe3,0x1d,0xe8,0x56,0x43,0xe7,0xfb,0xf9,0xe6,0xe9,0xe2,0x19,0x19,0x8,0xfa,0xf3,0xe5,0x23,0x7,0xf,0xf8,0xf8,0xf3,0xfc,0x11,0x2a,0x5,0xf4,0xf1,0xfa,0xfb,0xf1,0x1e,0x13,0xf,0xf9,0xf5,0xfa,0x9,0xf9,0x3,0xf0,0xf0,0xe7,0xec,0xf1,0xc,0xe6,0xee,0xf6,0x20,0xf,0xe9,0x0,0xf4,0xfe,0xf0,0x13,0xa,0x17,0x13,0xee,0x13,0xfb,0xff,0xf8,0xfd,0xf4,0xe2,0xe8,0x6,0xfc,0x14,0x3,0x17,0x0,0x3,0xe6,0xfd,0xf2,0x12,0x12,0x20,0xeb,0x10,0x2,0xf7,0x13,0xd,0x11,0xfd,0xde,0xf5,0x7,0xf3,0x4,0xff,0x6,0x5,0xfb,0xea,0xf0,0xa,0x0,0xb5,0xe8,0x1a,0x3,0xfe,0xd,0x1a,0xe7,0xc0,0xd6,0xdc,0xf6,0xf8,0x39,0xf5,0xd5,0xf8,0x22,0xfa,0x22,0x5,0xd0,0xf4,0x2d,0xfc,0x0,0xa,0x1b,0xfc,0xe6,0x9,0x14,0xfa,0x0,0x1d,0x1a,0xfd,0xf3,0x18,0xfc,0xeb,0x15,0xf5,0xe,0xa,0xf3,0xf1,0x1b,0x5,0x14,0x3,0x2d,0x27,0xfb,0x18,0x22,0xef,0xf6,0x6,0x28,0x2b,0xde,0xec,0xef,0xe8,0xd3,0xfe,0x17,0x12,0x1,0x13,0x5,0xf7,0x0,0xde,0xf3,0xe5,0x3,0xfb,0x7,0xb,0xfd,0xdc,0xdf,0x3,0xc,0x0,0xfa,0x6,0xe,0x2,0x5,0xfa,0xfd,0xed,0x9,0xc,0xfd,0xfb,0xc,0xf0,0xe4,0x4,0xd6,0xf3,0x9,0xa,0xf9,0xf8,0xe2,0xef,0xdf,0xf0,0xf8,0x3,0xf,0x20,0xf4,0xe3,0xf8,0x2,0xe2,0xe5,0x25,0xf,0xeb,0xf8,0xe9,0xfd,0x4,0xc,0xc,0xfe,0x1,0x8,0xfc,0xfc,0x1b,0x1,0xe5,0x13,0xf9,0xe8,0x7,0x20,0xfe,0x6,0xec,0xfe,0x9,0xef,0x14,0x4,0xb,0xf5,0xe7,0xff,0xa,0x2,0x9,0xe9,0xc4,0x16,0xd,0xe7,0x15,0x14,0xf1,0xd0,0xec,0xe7,0xf0,0xf0,0x33,0x5,0xda,0xf2,0xb,0x8,0x38,0x1,0x7,0xfd,0xd8,0x6,0xd9,0xf0,0x16,0x1f,0xff,0xf7,0xe0,0xd8,0xf3,0xf7,0x12,0x8,0xe,0x5,0xf6,0x3,0xef,0x1b,0x12,0xf4,0xe8,0xf,0x2,0xfd,0xf2,0x16,0x26,0x22,0xe0,0x7,0xf7,0xe6,0xeb,0x16,0x22,0x1a,0xb,0x1,0xf5,0xea,0xd2,0x22,0xf,0x13,0x15,0x8,0xf0,0xfb,0xed,0x11,0xf3,0xe9,0xff,0xde,0xa,0x18,0xf,0x2,0xfb,0xf9,0xfb,0xe8,0x12,0x18,0x1,0xf4,0xf6,0xf8,0xf0,0x1f,0x24,0x15,0xf5,0x0,0x1c,0xf9,0x1,0xa,0x11,0xd5,0x1,0x12,0x2,0xec,0xfd,0x7,0xf2,0xea,0xf9,0xff,0xf7,0xfb,0x15,0xec,0xe5,0x1,0xeb,0x5,0xf9,0x10,0xfe,0x28,0xe5,0xa,0xeb,0x1b,0xe,0xf9,0xde,0x2,0x15,0xa,0xff,0xfe,0x11,0x24,0x3,0xf8,0x0,0x8,0xfd,0xe,0xeb,0xf3,0xf6,0xf7,0x14,0xe,0xfc,0xf5,0xde,0xf5,0x0,0x0,0x0,0x0,0x8e,0xfe,0xff,0xff,0x4,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0xab,0x1,0x0,0x0,0xfa,0xfd,0xff,0xff,0xa2,0xff,0xff,0xff,0xba,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0xfc,0xff,0xff,0x0,0x0,0x0,0x0,0xf,0x0,0x0,0x0,0x54,0x4f,0x43,0x4f,0x20,0x43,0x6f,0x6e,0x76,0x65,0x72,0x74,0x65,0x64,0x2e,0x0,0x1,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x24,0xfb,0xff,0xff,0x68,0x1,0x0,0x0,0x5c,0x1,0x0,0x0,0x50,0x1,0x0,0x0,0x4,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0xf4,0x0,0x0,0x0,0x90,0x0,0x0,0x0,0x48,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0xce,0xff,0xff,0xff,0x0,0x0,0x0,0x9,0x3,0x0,0x0,0x0,0x1c,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1a,0xff,0xff,0xff,0x0,0x0,0x80,0x3f,0x1,0x0,0x0,0x0,0x9,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x18,0x0,0x8,0x0,0xc,0x0,0x10,0x0,0x7,0x0,0x14,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x1,0x0,0x0,0x0,0x18,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0xc4,0xfc,0xff,0xff,0x1,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x16,0x0,0x0,0x0,0x8,0x0,0xc,0x0,0x7,0x0,0x10,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x38,0x0,0x0,0x0,0x2c,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x14,0x0,0x0,0x0,0x8,0x0,0xc,0x0,0x10,0x0,0x7,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x1a,0x0,0x8,0x0,0xc,0x0,0x10,0x0,0x7,0x0,0x14,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x11,0x2,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x2c,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x8,0x0,0x4,0x0,0x6,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0xff,0xff,0xff,0xff,0x31,0x0,0x0,0x0,0x28,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x5,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x9,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0x34,0x4,0x0,0x0,0xcc,0x3,0x0,0x0,0x4c,0x3,0x0,0x0,0xdc,0x2,0x0,0x0,0x60,0x2,0x0,0x0,0x20,0x2,0x0,0x0,0xb0,0x1,0x0,0x0,0x44,0x1,0x0,0x0,0x70,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x2,0xfc,0xff,0xff,0x0,0x0,0x0,0x9,0x44,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x28,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0xf4,0xfb,0xff,0xff,0x14,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0x0,0x0,0x80,0x3b,0xe,0x0,0x0,0x0,0x6c,0x61,0x62,0x65,0x6c,0x73,0x5f,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x1a,0x0,0x8,0x0,0x7,0x0,0xc,0x0,0x10,0x0,0x14,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x9,0xb4,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x94,0x0,0x0,0x0,0x18,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0xc,0x0,0x12,0x0,0x0,0x0,0x50,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x11,0x1e,0x23,0x3a,0x9e,0xa1,0x15,0x39,0x23,0x69,0x45,0x3a,0x9,0xe4,0xe4,0x39,0x65,0xd7,0x13,0x3a,0xe0,0xb2,0xfd,0x39,0x1b,0xc1,0x53,0x3a,0xc2,0x50,0x2d,0x3a,0x12,0x0,0x0,0x0,0x66,0x69,0x72,0x73,0x74,0x5f,0x77,0x65,0x69,0x67,0x68,0x74,0x73,0x2f,0x72,0x65,0x61,0x64,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x3a,0xfd,0xff,0xff,0x0,0x0,0x0,0x9,0x54,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x28,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x2c,0xfd,0xff,0xff,0x14,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xb5,0xfa,0xfa,0x39,0x1f,0x0,0x0,0x0,0x66,0x69,0x6e,0x61,0x6c,0x5f,0x66,0x63,0x5f,0x77,0x65,0x69,0x67,0x68,0x74,0x73,0x2f,0x72,0x65,0x61,0x64,0x2f,0x74,0x72,0x61,0x6e,0x73,0x70,0x6f,0x73,0x65,0x0,0x2,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0xa0,0xf,0x0,0x0,0xa2,0xfd,0xff,0xff,0x0,0x0,0x0,0x9,0x58,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x44,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x74,0xfe,0xff,0xff,0x30,0x0,0x0,0x0,0x24,0x0,0x0,0x0,0x18,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xf2,0xdd,0xbb,0x3d,0x1,0x0,0x0,0x0,0x32,0xa3,0x25,0x41,0x1,0x0,0x0,0x0,0xf6,0xa0,0x50,0xc1,0x5,0x0,0x0,0x0,0x61,0x64,0x64,0x5f,0x31,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0xe,0xfe,0xff,0xff,0x0,0x0,0x0,0x2,0x2c,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x4,0x0,0x4,0x0,0x4,0x0,0x0,0x0,0xf,0x0,0x0,0x0,0x52,0x65,0x73,0x68,0x61,0x70,0x65,0x5f,0x32,0x2f,0x73,0x68,0x61,0x70,0x65,0x0,0x1,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x4a,0xfe,0xff,0xff,0x0,0x0,0x0,0x9,0x5c,0x0,0x0,0x0,0x5,0x0,0x0,0x0,0x44,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1c,0xff,0xff,0xff,0x30,0x0,0x0,0x0,0x24,0x0,0x0,0x0,0x18,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x50,0x50,0xd0,0x3d,0x1,0x0,0x0,0x0,0x0,0x80,0xcf,0x41,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x9,0x0,0x0,0x0,0x52,0x65,0x73,0x68,0x61,0x70,0x65,0x5f,0x32,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x31,0x0,0x0,0x0,0x28,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xc2,0xfe,0xff,0xff,0x0,0x0,0x0,0x9,0x58,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x94,0xff,0xff,0xff,0x2c,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0x50,0x50,0xd0,0x3d,0x1,0x0,0x0,0x0,0x0,0x80,0xcf,0x41,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x9,0x0,0x0,0x0,0x52,0x65,0x73,0x68,0x61,0x70,0x65,0x5f,0x31,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xa8,0x7,0x0,0x0,0x2e,0xff,0xff,0xff,0x0,0x0,0x0,0x9,0x60,0x0,0x0,0x0,0x9,0x0,0x0,0x0,0x4c,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0xc,0x0,0x14,0x0,0x4,0x0,0x8,0x0,0xc,0x0,0x10,0x0,0xc,0x0,0x0,0x0,0x2c,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0x3a,0x6a,0xac,0x3d,0x1,0x0,0x0,0x0,0xd0,0xbd,0xab,0x41,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x52,0x65,0x6c,0x75,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x19,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0xaa,0xff,0xff,0xff,0x0,0x0,0x0,0x2,0x44,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2c,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x9c,0xff,0xff,0xff,0x18,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x96,0x8,0x29,0x38,0xb,0x0,0x0,0x0,0x4d,0x61,0x74,0x4d,0x75,0x6c,0x5f,0x62,0x69,0x61,0x73,0x0,0x1,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x18,0x0,0x8,0x0,0x7,0x0,0xc,0x0,0x10,0x0,0x14,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0xa0,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x88,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0xc,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x8,0x0,0xc,0x0,0x0,0x0,0x4c,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x9a,0xbb,0x84,0x38,0x83,0x84,0x73,0x37,0x5b,0xa3,0xa0,0x38,0x16,0x41,0x3a,0x38,0xc7,0x9a,0x70,0x38,0xed,0x70,0x4e,0x38,0x54,0x4f,0xac,0x38,0xfd,0x7,0x8d,0x38,0xb,0x0,0x0,0x0,0x43,0x6f,0x6e,0x76,0x32,0x44,0x5f,0x62,0x69,0x61,0x73,0x0,0x1,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x4c,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x1c,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0xe6,0xff,0xff,0xff,0x0,0x0,0x0,0x19,0x2,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x6,0x0,0x5,0x0,0x6,0x0,0x0,0x0,0x0,0x16,0xa,0x0,0xe,0x0,0x7,0x0,0x0,0x0,0x8,0x0,0xa,0x0,0x0,0x0,0x0,0x0,0x0,0x9,0x4,0x0,0x0,0x0,0x0,0x0,0xa,0x0,0xc,0x0,0x7,0x0,0x0,0x0,0x8,0x0,0xa,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x3,0x0,0x0,0x0}; diff --git a/src/audio/tensorflow/micro_speech_quantized_model_data.h b/src/audio/tensorflow/micro_speech_quantized_model_data.h new file mode 100644 index 000000000000..3babbb703d36 --- /dev/null +++ b/src/audio/tensorflow/micro_speech_quantized_model_data.h @@ -0,0 +1,4 @@ +#include <cstdint> + +constexpr unsigned int g_micro_speech_quantized_model_data_size = 18800; +extern const unsigned char g_micro_speech_quantized_model_data[]; diff --git a/src/audio/tensorflow/speech.cc b/src/audio/tensorflow/speech.cc new file mode 100644 index 000000000000..82ffdf698141 --- /dev/null +++ b/src/audio/tensorflow/speech.cc @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. + +#include <algorithm> +#include <cstdint> +#include <iterator> + +#include "tensorflow/lite/core/c/common.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" +#include "tensorflow/lite/micro/testing/micro_test.h" +#include "speech.h" + +// hard code the model today +#include "micro_speech_quantized_model_data.h" + +// The following values are derived from values used during model training. +// If you change the way you preprocess the input, update all these constants. +//constexpr int kAudioSampleFrequency = TFLM_SAMPLE_RATE; +static constexpr int kFeatureSize = TFLM_FEATURE_SIZE; +static constexpr int kFeatureCount = TFLM_FEATURE_COUNT; +static constexpr int kFeatureElementCount = TFLM_FEATURE_ELEM_COUNT; + +// Arena size is a guesstimate, followed by use of +// MicroInterpreter::arena_used_bytes() on both the AudioPreprocessor and +// MicroSpeech models and using the larger of the two results. +static constexpr size_t kArenaSize = 28584; // xtensa p6 +alignas(16) static uint8_t g_arena[kArenaSize]; + +// type for features +using Features = int8_t[kFeatureCount][kFeatureSize]; + +// inference +static const tflite::Model *model; +static TfLiteTensor *input; +static TfLiteTensor *output; +static tflite::MicroInterpreter *interpreter; + +using MicroSpeechOpResolver = tflite::MicroMutableOpResolver<4>; +static MicroSpeechOpResolver *op_resolver; + +// Adding more kernels is quite efficient. TODO add more +int RegisterOps(MicroSpeechOpResolver *op_resolver) { + TF_LITE_ENSURE_STATUS(op_resolver->AddReshape()); + TF_LITE_ENSURE_STATUS(op_resolver->AddFullyConnected()); + TF_LITE_ENSURE_STATUS(op_resolver->AddDepthwiseConv2D()); + TF_LITE_ENSURE_STATUS(op_resolver->AddSoftmax()); + return 0; +} + +int TF_InitOps(struct tf_classify *tfc) +{ + op_resolver = new MicroSpeechOpResolver(); + if (RegisterOps(op_resolver) != 0) { + tfc->error = "register ops failed"; + return -EINVAL; + } + + // create the interpreter + interpreter = new tflite::MicroInterpreter(model, *op_resolver, + g_arena, kArenaSize); + + // and allocate the tensors + if (interpreter->AllocateTensors() != kTfLiteOk) { + tfc->error = "interpreter tensor allocate failed"; + delete interpreter; + delete op_resolver; + interpreter = nullptr; + op_resolver = nullptr; + return -EINVAL; + } + + return 0; +} + +static int Init_Interpreter(struct tf_classify *tfc) +{ + input = interpreter->input(0); + if (!input){ + tfc->error = "input interpreter NULL"; + return -EINVAL; + } + + // check input shape is compatible with our feature data size + if (kFeatureElementCount != input->dims->data[input->dims->size - 1]){ + tfc->error = "input interpreter shape incompatible"; + return -EINVAL; + } + + output = interpreter->output(0); + if (!output){ + tfc->error = "output interpreter NULL"; + return -EINVAL; + } + + // check output shape is compatible with our number of prediction categories + if (tfc->categories != output->dims->data[output->dims->size - 1]) { + tfc->error = "output shape != categories"; + return -EINVAL; + } + + return 0; +} + +int TF_SetModel(struct tf_classify *tfc, unsigned char *model_tflite) +{ + // ignore passed in model today until we can load via binary kcontrol + + // Map the model into a usable data structure. This doesn't involve any + // copying or parsing, it's a very lightweight operation. + model = tflite::GetModel(g_micro_speech_quantized_model_data); + if (model->version() != TFLITE_SCHEMA_VERSION) { + tfc->error = "failed to load model"; + return -EINVAL; + } + + return 0; +} + +int TF_ProcessClassify(struct tf_classify *tfc) +{ + Features *features = reinterpret_cast<Features *>(tfc->audio_features); + int ret; + + // initialise the interpreter for current feature block + ret = Init_Interpreter(tfc); + if (!ret) + return ret; + + float output_scale = output->params.scale; + int output_zero_point = output->params.zero_point; + + // copy features to input then invoke() + std::copy_n(features[0][0], kFeatureElementCount, + tflite::GetTensorData<int8_t>(input)); + + // run the interpreter + if (interpreter->Invoke() != kTfLiteOk) { + tfc->error = "invoke failed"; + return -EINVAL; + } + + // Dequantize output values + for (int i = 0; i < tfc->categories; i++) { + tfc->predictions[i] = + (tflite::GetTensorData<int8_t>(output)[i] - output_zero_point) * + output_scale; + } + +return 0; +} diff --git a/src/audio/tensorflow/speech.h b/src/audio/tensorflow/speech.h new file mode 100644 index 000000000000..7b45022e3564 --- /dev/null +++ b/src/audio/tensorflow/speech.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. + +#ifndef __TFLM_SPEECH_H__ +#define __TFLM_SPEECH_H__ + +#include "tensorflow/lite/core/c/common.h" + +/* default model configuration */ +#define TFLM_SAMPLE_RATE 16000 +#define TFLM_FEATURE_SIZE 40 +#define TFLM_FEATURE_COUNT 49 +#define TFLM_FEATURE_ELEM_COUNT (TFLM_FEATURE_SIZE * TFLM_FEATURE_COUNT) +#define TFLM_FEATURE_STRIDE_MS 20 +#define TFLM_FEATURE_DURATION_MS 30 + +#define TFLM_CATEGORY_COUNT 4 +#define TFLM_CATEGORY_DATA {"silence", "unknown", "yes", "no",} +struct tf_classify { + int8_t *audio_features; + size_t audio_data_size; + int categories; + const char *error; + float predictions[TFLM_CATEGORY_COUNT]; +}; + +/* Export of C++ APIs into C namespace for linkage */ +#ifdef __cplusplus +extern "C" +{ +#endif + + /* 1st - pass in tflite flatbuffer formatted model, size is included in + * model metadata. + */ + int TF_SetModel(struct tf_classify *tfc, unsigned char *model); + + /* 2nd - register the kernels and init TF micro for inference */ + int TF_InitOps(struct tf_classify *tfc); + + /* 3rd - perform the inference */ + int TF_ProcessClassify(struct tf_classify *tfc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/audio/tensorflow/tflm-classify.c b/src/audio/tensorflow/tflm-classify.c new file mode 100644 index 000000000000..9c93329bce1c --- /dev/null +++ b/src/audio/tensorflow/tflm-classify.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/component.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/source_api.h> +#include <sof/audio/data_blob.h> +#include <sof/audio/format.h> +#include <sof/audio/ipc-config.h> +#include <sof/audio/pipeline.h> +#include <sof/ipc/msg.h> +#include <sof/lib/memory.h> +#include <sof/lib/uuid.h> +#include <sof/math/numbers.h> +#include <sof/trace/trace.h> +#include <ipc/control.h> +#include <ipc/stream.h> +#include <ipc/topology.h> +#include <module/module/llext.h> +#include <rtos/init.h> +#include <rtos/panic.h> +#include <rtos/string.h> +#include <sof/common.h> +#include <sof/list.h> +#include <sof/platform.h> +#include <sof/ut.h> +#include <user/eq.h> +#include <user/trace.h> +#include <errno.h> +#include <stddef.h> +#include <stdint.h> + +#include "speech.h" + +SOF_DEFINE_REG_UUID(tflmcly); +LOG_MODULE_REGISTER(tflmcly, CONFIG_SOF_LOG_LEVEL); +EXPORT_SYMBOL(tflmcly_uuid); +EXPORT_SYMBOL(log_const_tflmcly); + +static const char * const prediction[] = TFLM_CATEGORY_DATA; + +struct tflm_comp_data { + struct comp_data_blob_handler *model_handler; + struct tf_classify tfc; +}; + +__cold static int tflm_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct comp_dev *dev = mod->dev; + struct module_config *cfg = &md->cfg; + struct tflm_comp_data *cd; + size_t bs = cfg->size; + int ret; + + assert_can_be_cold(); + + comp_info(dev, "entry"); + + cd = mod_zalloc(mod, sizeof(*cd)); + if (!cd) + return -ENOMEM; + + md->private = cd; + + /* Handler for configuration data */ + cd->model_handler = mod_data_blob_handler_new(mod); + if (!cd->model_handler) { + comp_err(dev, "mod_data_blob_handler_new() failed."); + ret = -ENOMEM; + goto fail; + } + + /* Get configuration data and reset DRC state */ + ret = comp_init_data_blob(cd->model_handler, bs, cfg->data); + if (ret < 0) { + comp_err(dev, "comp_init_data_blob() failed."); + goto fail; + } + + /* hard coded atm */ + cd->tfc.categories = TFLM_CATEGORY_COUNT; + + /* set default model for the moment*/ + ret = TF_SetModel(&cd->tfc, NULL); + if (!ret) { + comp_err(dev, "failed to set model"); + goto fail; + } + + /* initialise ops */ + ret = TF_InitOps(&cd->tfc); + if (!ret) { + comp_err(dev, "failed to init ops"); + goto fail; + } + + return ret; + +fail: + /* Passing NULL pointer to free functions is Ok */ + mod_data_blob_handler_free(mod, cd->model_handler); + mod_free(mod, cd); + return ret; +} + +__cold static int tflm_free(struct processing_module *mod) +{ + struct tflm_comp_data *cd = module_get_private_data(mod); + + assert_can_be_cold(); + + mod_data_blob_handler_free(mod, cd->model_handler); + mod_free(mod, cd); + return 0; +} + +__cold static int tflm_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 tflm_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + int ret; + + assert_can_be_cold(); + + comp_dbg(dev, "entry"); + + struct sof_ipc4_control_msg_payload *ctl = (struct sof_ipc4_control_msg_payload *)fragment; + + comp_info(dev, "bytes control"); + ret = comp_data_blob_set(cd->model_handler, pos, data_offset_size, fragment, + fragment_size); + + /* TODO: now load the model from the blob */ + + return ret; +} + +#if DEBUG + +/* The first feature for no and yes used in tflm_speech example */ + +int8_t expected_feature_no[TFLM_FEATURE_SIZE] = { + 126, 103, 124, 102, 124, 102, 123, 100, 118, 97, 118, 100, 118, 98, + 121, 100, 121, 98, 117, 91, 96, 74, 54, 87, 100, 87, 109, 92, + 91, 80, 64, 55, 83, 74, 74, 78, 114, 95, 101, 81, +}; + +int8_t expected_feature_yes[TFLM_FEATURE_SIZE] = { + 124, 105, 126, 103, 125, 101, 123, 100, 116, 98, 115, 97, 113, 90, + 91, 82, 104, 96, 117, 97, 121, 103, 126, 101, 125, 104, 126, 104, + 125, 101, 116, 90, 81, 74, 80, 71, 83, 76, 82, 71, +}; +#endif + +/* + * This expects features from 16kHz mono 16 bit input stream. + * + * Features must be processed using the following flow + * https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/micro_speech/images/audio_preprocessor_int8.png + * 1. Preprocess the audio data using MFCC to generate the features + * 2. Run the features through the model + * 3. Print the model output predictions + * + * Each call TF_ProcessClassify() needs 1470ms of audio features or + * TFLM_FEATURE_COUNT (49) features. We iterate over the feature count + * and increment starting feature one by one (a 30ms stride) and re + * call TF_ProcessClassify() until we have less than TFLM_FEATURE_COUNT + * features in the input buffer. + */ + +static int tflm_process(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct tflm_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + size_t frame_bytes = source_get_frame_bytes(sources[0]); + int features = source_get_data_frames_available(sources[0]); + const void *data_ptr, *buf_start; + size_t buf_size; + int ret; + + comp_dbg(dev, "entry"); + + /* Window size is TFLM_FEATURE_ELEM_COUNT and we increment + * by TFLM_FEATURE_SIZE until buffer empty. + */ + while (features >= TFLM_FEATURE_ELEM_COUNT) { + ret = source_get_data(sources[0], TFLM_FEATURE_ELEM_COUNT * frame_bytes, + &data_ptr, &buf_start, &buf_size); + if (ret) + return ret; + + cd->tfc.audio_features = data_ptr; + cd->tfc.audio_data_size = TFLM_FEATURE_ELEM_COUNT; + ret = TF_ProcessClassify(&cd->tfc); + if (!ret) { + comp_err(dev, "classify failed %s.", + cd->tfc.error); + source_release_data(sources[0], 0); + return ret; + } + + /* debug - dump the output */ + for (int i = 0; i < cd->tfc.categories; i++) { + comp_dbg(dev, "tf: predictions %1.3f %s", + cd->tfc.predictions[i], prediction[i]); + } + + /* advance by one stride */ + source_release_data(sources[0], TFLM_FEATURE_SIZE * frame_bytes); + features = source_get_data_frames_available(sources[0]); + } + + return ret; +} + +static int tflm_reset(struct processing_module *mod) +{ + //struct tflm_comp_data *cd = module_get_private_data(mod); + + return 0; +} + +static const struct module_interface tflmcly_interface = { + .init = tflm_init, +// .prepare = tflm_prepare, + .process = tflm_process, + .set_configuration = tflm_set_config, +// .get_configuration = tflm_get_config, + .reset = tflm_reset, + .free = tflm_free +}; + +DECLARE_TR_CTX(tflm_tr, SOF_UUID(tflmcly_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(tflmcly_interface, tflmcly_uuid, tflm_tr); +SOF_MODULE_INIT(tflmcly, sys_comp_module_tflmcly_interface_init); + +#if CONFIG_COMP_TENSORFLOW_MODULE +/* modular: llext dynamic link */ + +#include <module/module/api_ver.h> +#include <rimage/sof/user/manifest.h> + +static const struct sof_man_module_manifest mod_manifest __section(".module") __used = + SOF_LLEXT_MODULE_MANIFEST("TFLMCLY", &tflmcly_interface, 1, SOF_REG_UUID(tflmcly), 40); + +SOF_LLEXT_BUILDINFO; + +#endif diff --git a/src/audio/tensorflow/tflmcly.toml b/src/audio/tensorflow/tflmcly.toml new file mode 100644 index 000000000000..1c88bff533ee --- /dev/null +++ b/src/audio/tensorflow/tflmcly.toml @@ -0,0 +1,22 @@ + +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + + REM # TFLM Classifier module config + [[module.entry]] + name = "TFLMCLY" + uuid = UUIDREG_STR_TFLMCLY + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = LOAD_TYPE + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + REM # 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] + + index = __COUNTER__ diff --git a/src/audio/tone.c b/src/audio/tone.c deleted file mode 100644 index c07be0302b8c..000000000000 --- a/src/audio/tone.c +++ /dev/null @@ -1,738 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2016 Intel Corporation. All rights reserved. -// -// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> -// Liam Girdwood <liam.r.girdwood@linux.intel.com> -// Keyon Jie <yang.jie@linux.intel.com> - -#include <sof/audio/buffer.h> -#include <sof/audio/component.h> -#include <sof/audio/format.h> -#include <sof/audio/pipeline.h> -#include <sof/audio/ipc-config.h> -#include <sof/common.h> -#include <rtos/panic.h> -#include <sof/ipc/msg.h> -#include <rtos/alloc.h> -#include <rtos/init.h> -#include <sof/lib/memory.h> /* for SHARED_DATA */ -#include <sof/lib/uuid.h> -#include <sof/list.h> -#include <sof/math/trig.h> -#include <sof/platform.h> -#include <rtos/string.h> -#include <sof/trace/trace.h> -#include <sof/ut.h> -#include <ipc/control.h> -#include <ipc/stream.h> -#include <ipc/topology.h> -#include <user/tone.h> -#include <user/trace.h> -#include <errno.h> -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -/* Convert float frequency in Hz to Q16.16 fractional format */ -#define TONE_FREQ(f) Q_CONVERT_FLOAT(f, 16) - -/* Convert float gain to Q1.31 fractional format */ -#define TONE_GAIN(v) Q_CONVERT_FLOAT(v, 31) - -/* Set default tone amplitude and frequency */ -#define TONE_AMPLITUDE_DEFAULT TONE_GAIN(0.1) /* -20 dB */ -#define TONE_FREQUENCY_DEFAULT TONE_FREQ(997.0) -#define TONE_NUM_FS 13 /* Table size for 8-192 kHz range */ - -static const struct comp_driver comp_tone; - -LOG_MODULE_REGISTER(tone, CONFIG_SOF_LOG_LEVEL); - -SOF_DEFINE_REG_UUID(tone); - -DECLARE_TR_CTX(tone_tr, SOF_UUID(tone_uuid), LOG_LEVEL_INFO); - -/* 2*pi/Fs lookup tables in Q1.31 for each Fs */ -static const int32_t tone_fs_list[TONE_NUM_FS] = { - 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, - 64000, 88200, 96000, 176400, 192000 -}; - -static const int32_t tone_pi2_div_fs[TONE_NUM_FS] = { - 1686630, 1223858, 843315, 611929, 562210, 421657, 305965, - 281105, 210829, 152982, 140552, 76491, 70276 -}; - -/* tone component private data */ - -struct tone_state { - int mute; - int32_t a; /* Current amplitude Q1.31 */ - int32_t a_target; /* Target amplitude Q1.31 */ - int32_t ampl_coef; /* Amplitude multiplier Q2.30 */ - int32_t c; /* Coefficient 2*pi/Fs Q1.31 */ - int32_t f; /* Frequency Q16.16 */ - int32_t freq_coef; /* Frequency multiplier Q2.30 */ - int32_t fs; /* Sample rate in Hertz Q32.0 */ - int32_t ramp_step; /* Amplitude ramp step Q1.31 */ - int32_t w; /* Angle radians Q4.28 */ - int32_t w_step; /* Angle step Q4.28 */ - uint32_t block_count; - uint32_t repeat_count; - uint32_t repeats; /* Number of repeats for tone (sweep steps) */ - uint32_t sample_count; - uint32_t samples_in_block; /* Samples in 125 us block */ - uint32_t tone_length; /* Active length in 125 us blocks */ - uint32_t tone_period; /* Active + idle time in 125 us blocks */ -}; - -struct comp_data { - uint32_t period_bytes; - uint32_t channels; - uint32_t frame_bytes; - uint32_t rate; - struct tone_state sg[PLATFORM_MAX_CHANNELS]; - void (*tone_func)(struct comp_dev *dev, struct audio_stream *sink, - uint32_t frames); -}; - -static int32_t tonegen(struct tone_state *sg); -static void tonegen_control(struct tone_state *sg); -static void tonegen_update_f(struct tone_state *sg, int32_t f); - -/* - * Tone generator algorithm code - */ - -static inline void tone_circ_inc_wrap(int32_t **ptr, int32_t *end, size_t size) -{ - if (*ptr >= end) - *ptr = (int32_t *)((size_t)*ptr - size); -} - -static void tone_s32_default(struct comp_dev *dev, struct audio_stream *sink, - uint32_t frames) -{ - struct comp_data *cd = comp_get_drvdata(dev); - int32_t *dest = audio_stream_get_wptr(sink); - int i; - int n; - int n_wrap_dest; - int n_min; - int nch = cd->channels; - - n = frames * nch; - while (n > 0) { - n_wrap_dest = (int32_t *)audio_stream_get_end_addr(sink) - dest; - n_min = (n < n_wrap_dest) ? n : n_wrap_dest; - /* Process until wrap or completed n */ - while (n_min > 0) { - n -= nch; - n_min -= nch; - for (i = 0; i < nch; i++) { - tonegen_control(&cd->sg[i]); - *dest = tonegen(&cd->sg[i]); - dest++; - } - } - tone_circ_inc_wrap(&dest, audio_stream_get_end_addr(sink), - audio_stream_get_size(sink)); - } -} - -static int32_t tonegen(struct tone_state *sg) -{ - int64_t sine; - int64_t w; - /* sg->w is angle in Q4.28 radians format, sin() returns Q1.31 */ - /* sg->a is amplitude as Q1.31 */ - sine = - q_mults_32x32(sin_fixed_32b(sg->w), sg->a, - Q_SHIFT_BITS_64(31, 31, 31)); - - /* Next point */ - w = (int64_t)sg->w + sg->w_step; - sg->w = (w > PI_MUL2_Q4_28) - ? (int32_t)(w - PI_MUL2_Q4_28) : (int32_t)w; - - if (sg->mute) - return 0; - else - return (int32_t)sine; /* Q1.31 no saturation need */ -} - -static void tonegen_control(struct tone_state *sg) -{ - int64_t a; - int64_t p; - - /* Count samples, 125 us blocks */ - sg->sample_count++; - if (sg->sample_count < sg->samples_in_block) - return; - - sg->sample_count = 0; - if (sg->block_count < INT32_MAX) - sg->block_count++; - - /* Fade-in ramp during tone */ - if (sg->block_count < sg->tone_length) { - if (sg->a == 0) - sg->w = 0; /* Reset phase to have less clicky ramp */ - - if (sg->a > sg->a_target) { - a = (int64_t)sg->a - sg->ramp_step; - if (a < sg->a_target) - a = sg->a_target; - - } else { - a = (int64_t)sg->a + sg->ramp_step; - if (a > sg->a_target) - a = sg->a_target; - } - sg->a = (int32_t)a; - } - - /* Fade-out ramp after tone*/ - if (sg->block_count > sg->tone_length) { - a = (int64_t)sg->a - sg->ramp_step; - if (a < 0) - a = 0; - - sg->a = (int32_t)a; - } - - /* New repeated tone, update for frequency or amplitude sweep */ - if ((sg->block_count > sg->tone_period) && - (sg->repeat_count + 1 < sg->repeats)) { - sg->block_count = 0; - if (sg->ampl_coef > 0) { - sg->a_target = - sat_int32(q_multsr_32x32(sg->a_target, - sg->ampl_coef, Q_SHIFT_BITS_64(31, 30, 31))); - sg->a = (sg->ramp_step > sg->a_target) - ? sg->a_target : sg->ramp_step; - } - if (sg->freq_coef > 0) { - /* f is Q16.16, freq_coef is Q2.30 */ - p = q_multsr_32x32(sg->f, sg->freq_coef, - Q_SHIFT_BITS_64(16, 30, 16)); - tonegen_update_f(sg, (int32_t)p); /* No saturation */ - } - sg->repeat_count++; - } -} - -/* Set sine amplitude */ -static inline void tonegen_set_a(struct tone_state *sg, int32_t a) -{ - sg->a_target = a; -} - -/* Repeated number of beeps */ -static void tonegen_set_repeats(struct tone_state *sg, uint32_t r) -{ - sg->repeats = r; -} - -/* The next functions support zero as shortcut for defaults to get - * make a nicer API without need to remember the neutral steady - * non-swept tone settings. - */ - -/* Multiplication factor for frequency as Q2.30 for logarithmic change */ -static void tonegen_set_freq_mult(struct tone_state *sg, int32_t fm) -{ - sg->freq_coef = (fm > 0) ? fm : ONE_Q2_30; /* Set freq mult to 1.0 */ -} - -/* Multiplication factor for amplitude as Q2.30 for logarithmic change */ -static void tonegen_set_ampl_mult(struct tone_state *sg, int32_t am) -{ - sg->ampl_coef = (am > 0) ? am : ONE_Q2_30; /* Set ampl mult to 1.0 */ -} - -/* Tone length in samples, this is the active length of tone */ -static void tonegen_set_length(struct tone_state *sg, uint32_t tl) -{ - sg->tone_length = (tl > 0) ? tl : INT32_MAX; /* Count rate 125 us */ -} - -/* Tone period in samples, this is the length including the pause after beep */ -static void tonegen_set_period(struct tone_state *sg, uint32_t tp) -{ - sg->tone_period = (tp > 0) ? tp : INT32_MAX; /* Count rate 125 us */ -} - -/* Tone ramp parameters: - * step - Value that is added or subtracted to amplitude. A zero or negative - * number disables the ramp and amplitude is immediately modified to - * final value. - */ - -static inline void tonegen_set_linramp(struct tone_state *sg, int32_t step) -{ - sg->ramp_step = (step > 0) ? step : INT32_MAX; -} - -static inline int32_t tonegen_get_f(struct tone_state *sg) -{ - return sg->f; -} - -static inline int32_t tonegen_get_a(struct tone_state *sg) -{ - return sg->a_target; -} - -static inline void tonegen_mute(struct tone_state *sg) -{ - sg->mute = 1; -} - -static inline void tonegen_unmute(struct tone_state *sg) -{ - sg->mute = 0; -} - -static void tonegen_update_f(struct tone_state *sg, int32_t f) -{ - int64_t w_tmp; - int64_t f_max; - - /* Calculate Fs/2, fs is Q32.0, f is Q16.16 */ - f_max = Q_SHIFT_LEFT((int64_t)sg->fs, 0, 16 - 1); - f_max = (f_max > INT32_MAX) ? INT32_MAX : f_max; - sg->f = (f > f_max) ? f_max : f; - /* Q16 x Q31 -> Q28 */ - w_tmp = q_multsr_32x32(sg->f, sg->c, Q_SHIFT_BITS_64(16, 31, 28)); - w_tmp = (w_tmp > PI_Q4_28) ? PI_Q4_28 : w_tmp; /* Limit to pi Q4.28 */ - sg->w_step = (int32_t)w_tmp; -} - -static void tonegen_reset(struct tone_state *sg) -{ - sg->mute = 1; - sg->a = 0; - sg->a_target = TONE_AMPLITUDE_DEFAULT; - sg->c = 0; - sg->f = TONE_FREQUENCY_DEFAULT; - sg->w = 0; - sg->w_step = 0; - - sg->block_count = 0; - sg->repeat_count = 0; - sg->repeats = 0; - sg->sample_count = 0; - sg->samples_in_block = 0; - - /* Continuous tone */ - sg->freq_coef = ONE_Q2_30; /* Set freq multiplier to 1.0 */ - sg->ampl_coef = ONE_Q2_30; /* Set ampl multiplier to 1.0 */ - sg->tone_length = INT32_MAX; - sg->tone_period = INT32_MAX; - sg->ramp_step = ONE_Q1_31; /* Set lin ramp modification to max */ -} - -static int tonegen_init(struct tone_state *sg, int32_t fs, int32_t f, int32_t a) -{ - int idx; - int i; - - sg->a_target = a; - sg->a = (sg->ramp_step > sg->a_target) ? sg->a_target : sg->ramp_step; - - idx = -1; - sg->mute = 1; - sg->fs = 0; - - /* Find index of current sample rate and then get from lookup table the - * corresponding 2*pi/Fs value. - */ - for (i = 0; i < TONE_NUM_FS; i++) { - if (fs == tone_fs_list[i]) - idx = i; - } - - if (idx < 0) { - sg->w_step = 0; - return -EINVAL; - } - - sg->fs = fs; - sg->c = tone_pi2_div_fs[idx]; /* Store 2*pi/Fs */ - sg->mute = 0; - tonegen_update_f(sg, f); - - /* 125us as Q1.31 is 268435, calculate fs * 125e-6 in Q31.0 */ - sg->samples_in_block = - (int32_t) q_multsr_32x32(fs, 268435, Q_SHIFT_BITS_64(0, 31, 0)); - - return 0; -} - -/* - * End of algorithm code. Next the standard component methods. - */ - -static struct comp_dev *tone_new(const struct comp_driver *drv, - const struct comp_ipc_config *config, - const void *spec) -{ - struct comp_dev *dev; - const struct ipc_config_tone *ipc_tone = spec; - struct comp_data *cd; - int i; - - comp_cl_info(&comp_tone, "tone_new()"); - - dev = comp_alloc(drv, sizeof(*dev)); - if (!dev) - return NULL; - dev->ipc_config = *config; - - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); - if (!cd) { - rfree(dev); - return NULL; - } - - comp_set_drvdata(dev, cd); - cd->tone_func = tone_s32_default; - - cd->rate = ipc_tone->sample_rate; - - /* Reset tone generator and set channels volumes to default */ - for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) - tonegen_reset(&cd->sg[i]); - - dev->state = COMP_STATE_READY; - return dev; -} - -static void tone_free(struct comp_dev *dev) -{ - struct tone_data *td = comp_get_drvdata(dev); - - comp_info(dev, "tone_free()"); - - rfree(td); - rfree(dev); -} - -/* set component audio stream parameters */ -static int tone_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) -{ - struct comp_data *cd = comp_get_drvdata(dev); - struct comp_buffer *sourceb, *sinkb; - - sourceb = comp_dev_get_first_data_producer(dev); - - sinkb = comp_dev_get_first_data_consumer(dev); - - comp_info(dev, "tone_params(), config->frame_fmt = %u", - dev->ipc_config.frame_fmt); - - /* Tone supports only S32_LE PCM format atm */ - if (dev->ipc_config.frame_fmt != SOF_IPC_FRAME_S32_LE) - return -EINVAL; - - 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(&sourceb->stream); - - return 0; -} - -#if CONFIG_IPC_MAJOR_3 -static int tone_cmd_get_value(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata, int max_size) -{ - struct comp_data *cd = comp_get_drvdata(dev); - int j; - - comp_info(dev, "tone_cmd_get_value()"); - - if (cdata->type != SOF_CTRL_TYPE_VALUE_CHAN_GET) { - comp_err(dev, "tone_cmd_get_value(): wrong cdata->type: %u", - cdata->type); - return -EINVAL; - } - - if (cdata->cmd == SOF_CTRL_CMD_SWITCH) { - for (j = 0; j < cdata->num_elems; j++) { - cdata->chanv[j].channel = j; - cdata->chanv[j].value = !cd->sg[j].mute; - comp_info(dev, "tone_cmd_get_value(), j = %u, cd->sg[j].mute = %u", - j, cd->sg[j].mute); - } - } - return 0; -} - -static int tone_cmd_set_value(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata) -{ - struct comp_data *cd = comp_get_drvdata(dev); - int j; - uint32_t ch; - bool val; - - if (cdata->type != SOF_CTRL_TYPE_VALUE_CHAN_SET) { - comp_err(dev, "tone_cmd_set_value(): wrong cdata->type: %u", - cdata->type); - return -EINVAL; - } - - if (cdata->cmd == SOF_CTRL_CMD_SWITCH) { - comp_info(dev, "tone_cmd_set_value(), SOF_CTRL_CMD_SWITCH"); - for (j = 0; j < cdata->num_elems; j++) { - ch = cdata->chanv[j].channel; - val = cdata->chanv[j].value; - comp_info(dev, "tone_cmd_set_value(), SOF_CTRL_CMD_SWITCH, ch = %u, val = %u", - ch, val); - if (ch >= PLATFORM_MAX_CHANNELS) { - comp_err(dev, "tone_cmd_set_value(): ch >= PLATFORM_MAX_CHANNELS"); - return -EINVAL; - } - - if (val) - tonegen_unmute(&cd->sg[ch]); - else - tonegen_mute(&cd->sg[ch]); - } - } else { - comp_err(dev, "tone_cmd_set_value(): invalid cdata->cmd"); - return -EINVAL; - } - - return 0; -} - -static int tone_cmd_set_data(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata) -{ - struct comp_data *cd = comp_get_drvdata(dev); - struct sof_ipc_ctrl_value_comp *compv; - int i; - uint32_t ch; - uint32_t val; - - comp_info(dev, "tone_cmd_set_data()"); - - if (cdata->type != SOF_CTRL_TYPE_VALUE_COMP_SET) { - comp_err(dev, "tone_cmd_set_data(): wrong cdata->type: %u", - cdata->type); - return -EINVAL; - } - - switch (cdata->cmd) { - case SOF_CTRL_CMD_ENUM: - comp_info(dev, "tone_cmd_set_data(), SOF_CTRL_CMD_ENUM, cdata->index = %u", - cdata->index); - compv = (struct sof_ipc_ctrl_value_comp *)ASSUME_ALIGNED(&cdata->data->data, 4); - - for (i = 0; i < (int)cdata->num_elems; i++) { - ch = compv[i].index; - val = compv[i].svalue; - comp_info(dev, "tone_cmd_set_data(), SOF_CTRL_CMD_ENUM, ch = %u, val = %u", - ch, val); - switch (cdata->index) { - case SOF_TONE_IDX_FREQUENCY: - comp_info(dev, "tone_cmd_set_data(), SOF_TONE_IDX_FREQUENCY"); - tonegen_update_f(&cd->sg[ch], val); - break; - case SOF_TONE_IDX_AMPLITUDE: - comp_info(dev, "tone_cmd_set_data(), SOF_TONE_IDX_AMPLITUDE"); - tonegen_set_a(&cd->sg[ch], val); - break; - case SOF_TONE_IDX_FREQ_MULT: - comp_info(dev, "tone_cmd_set_data(), SOF_TONE_IDX_FREQ_MULT"); - tonegen_set_freq_mult(&cd->sg[ch], val); - break; - case SOF_TONE_IDX_AMPL_MULT: - comp_info(dev, "tone_cmd_set_data(), SOF_TONE_IDX_AMPL_MULT"); - tonegen_set_ampl_mult(&cd->sg[ch], val); - break; - case SOF_TONE_IDX_LENGTH: - comp_info(dev, "tone_cmd_set_data(), SOF_TONE_IDX_LENGTH"); - tonegen_set_length(&cd->sg[ch], val); - break; - case SOF_TONE_IDX_PERIOD: - comp_info(dev, "tone_cmd_set_data(), SOF_TONE_IDX_PERIOD"); - tonegen_set_period(&cd->sg[ch], val); - break; - case SOF_TONE_IDX_REPEATS: - comp_info(dev, "tone_cmd_set_data(), SOF_TONE_IDX_REPEATS"); - tonegen_set_repeats(&cd->sg[ch], val); - break; - case SOF_TONE_IDX_LIN_RAMP_STEP: - comp_info(dev, "tone_cmd_set_data(), SOF_TONE_IDX_LIN_RAMP_STEP"); - tonegen_set_linramp(&cd->sg[ch], val); - break; - default: - comp_err(dev, "tone_cmd_set_data(): invalid cdata->index"); - return -EINVAL; - } - } - break; - default: - comp_err(dev, "tone_cmd_set_data(): invalid cdata->cmd"); - return -EINVAL; - } - - return 0; -} - -/* used to pass standard and bespoke commands (with data) to component */ -static int tone_cmd(struct comp_dev *dev, int cmd, void *data, - int max_data_size) -{ - struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4); - int ret = 0; - - comp_info(dev, "tone_cmd()"); - - switch (cmd) { - case COMP_CMD_SET_DATA: - ret = tone_cmd_set_data(dev, cdata); - break; - case COMP_CMD_SET_VALUE: - ret = tone_cmd_set_value(dev, cdata); - break; - case COMP_CMD_GET_VALUE: - ret = tone_cmd_get_value(dev, cdata, max_data_size); - break; - } - - return ret; -} -#endif - -static int tone_trigger(struct comp_dev *dev, int cmd) -{ - comp_info(dev, "tone_trigger()"); - - return comp_set_state(dev, cmd); -} - -/* copy and process stream data from source to sink buffers */ -static int tone_copy(struct comp_dev *dev) -{ - struct comp_buffer *sink; - struct comp_data *cd = comp_get_drvdata(dev); - uint32_t free; - int ret = 0; - - comp_dbg(dev, "tone_copy()"); - - /* tone component sink buffer */ - sink = list_first_item(&dev->bsink_list, struct comp_buffer, - source_list); - - 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->stream, dev->frames); - buffer_stream_writeback(sink, cd->period_bytes); - - /* calc new free and available */ - comp_update_buffer_produce(sink, cd->period_bytes); - - ret = dev->frames; - } - - return ret; -} - -static int tone_prepare(struct comp_dev *dev) -{ - struct comp_data *cd = comp_get_drvdata(dev); - struct comp_buffer *sourceb; - int32_t f; - int32_t a; - int ret; - int i; - - comp_info(dev, "tone_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; - - sourceb = comp_dev_get_first_data_producer(dev); - - cd->channels = audio_stream_get_channels(&sourceb->stream); - comp_info(dev, "tone_prepare(), cd->channels = %u, cd->rate = %u", - cd->channels, cd->rate); - - for (i = 0; i < cd->channels; i++) { - f = tonegen_get_f(&cd->sg[i]); - a = tonegen_get_a(&cd->sg[i]); - if (tonegen_init(&cd->sg[i], cd->rate, f, a) < 0) { - comp_set_state(dev, COMP_TRIGGER_RESET); - return -EINVAL; - } - } - - return 0; -} - -static int tone_reset(struct comp_dev *dev) -{ - struct comp_data *cd = comp_get_drvdata(dev); - int i; - - comp_info(dev, "tone_reset()"); - - /* Initialize with the defaults */ - for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) - tonegen_reset(&cd->sg[i]); - - comp_set_state(dev, COMP_TRIGGER_RESET); - - return 0; -} - -static const struct comp_driver comp_tone = { - .type = SOF_COMP_TONE, - .uid = SOF_RT_UUID(tone_uuid), - .tctx = &tone_tr, - .ops = { - .create = tone_new, - .free = tone_free, - .params = tone_params, -#if CONFIG_IPC_MAJOR_3 - .cmd = tone_cmd, -#endif - .trigger = tone_trigger, - .copy = tone_copy, - .prepare = tone_prepare, - .reset = tone_reset, - }, -}; - -static SHARED_DATA struct comp_driver_info comp_tone_info = { - .drv = &comp_tone, -}; - -UT_STATIC void sys_comp_tone_init(void) -{ - comp_register(platform_shared_get(&comp_tone_info, - sizeof(comp_tone_info))); -} - -DECLARE_MODULE(sys_comp_tone_init); -SOF_MODULE_INIT(tone, sys_comp_tone_init); diff --git a/src/audio/tone/CMakeLists.txt b/src/audio/tone/CMakeLists.txt new file mode 100644 index 000000000000..58f22ec6c59e --- /dev/null +++ b/src/audio/tone/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_COMP_TONE STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/tone_llext) + add_dependencies(app tone) +else() + if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof tone.c tone-ipc3.c) + elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof tone.c tone-ipc4.c) + endif() +endif() diff --git a/src/audio/tone/Kconfig b/src/audio/tone/Kconfig new file mode 100644 index 000000000000..8cb6f7302497 --- /dev/null +++ b/src/audio/tone/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config COMP_TONE + tristate "Tone component" + default m if LIBRARY_DEFAULT_MODULAR + default y + depends on COMP_MODULE_ADAPTER + depends on IPC_MAJOR_4 + select CORDIC_FIXED + help + Select for Tone component. This component is used to generate + audio tones (sine waves) at specified frequencies when the Tone + mode is enabled. The two other modes it supports are silence where + it generates 0s and passthrough where the input is passed to the + output. Warning: This component is untested with IPC_MAJOR_3 and + is unavailable. diff --git a/src/audio/tone/README.md b/src/audio/tone/README.md new file mode 100644 index 000000000000..e2435c2e2b3a --- /dev/null +++ b/src/audio/tone/README.md @@ -0,0 +1,13 @@ +# Tone Generator Architecture + +This directory contains the Tone component. + +## Overview + +Synthesizes simple sine-waves or beep sequences, generally used for internal testing, diagnostics, or system alert sounds. + +## Configuration and Scripts + +- **Kconfig**: Controls compilation inclusion via `COMP_TONE` acting securely on top of the generic `COMP_MODULE_ADAPTER` and `IPC_MAJOR_4`. Depends on the `CORDIC_FIXED` library for sine approximations. +- **CMakeLists.txt**: Links `tone.c` to respective system-level pipelines (`tone-ipc3.c` or `tone-ipc4.c`) and allows execution seamlessly as a zephyr `llext`. +- **tone.toml**: Describes module structure mappings assigning `UUIDREG_STR_TONE` up to multi-instance capacities. diff --git a/src/audio/tone/llext/CMakeLists.txt b/src/audio/tone/llext/CMakeLists.txt new file mode 100644 index 000000000000..39b0894a013a --- /dev/null +++ b/src/audio/tone/llext/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2025 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +sof_llext_build("tone" + SOURCES ../tone.c ../tone-ipc4.c + LIB openmodules +) diff --git a/src/audio/tone/llext/llext.toml.h b/src/audio/tone/llext/llext.toml.h new file mode 100644 index 000000000000..20f5940c3555 --- /dev/null +++ b/src/audio/tone/llext/llext.toml.h @@ -0,0 +1,6 @@ +#include <tools/rimage/config/platform.toml> +#define LOAD_TYPE "2" +#include "../tone.toml" + +[module] +count = __COUNTER__ diff --git a/src/audio/tone/tone-ipc3.c b/src/audio/tone/tone-ipc3.c new file mode 100644 index 000000000000..db36b9a88cbe --- /dev/null +++ b/src/audio/tone/tone-ipc3.c @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2016 Intel Corporation. All rights reserved. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> +// Liam Girdwood <liam.r.girdwood@linux.intel.com> +// Keyon Jie <yang.jie@linux.intel.com> + +#include <sof/audio/buffer.h> +#include <sof/audio/component.h> +#include <sof/audio/format.h> +#include <sof/audio/pipeline.h> +#include <sof/audio/ipc-config.h> +#include <sof/common.h> +#include <rtos/panic.h> +#include <sof/ipc/msg.h> +#include <rtos/alloc.h> +#include <rtos/init.h> +#include <sof/lib/memory.h> /* for SHARED_DATA */ +#include <sof/lib/uuid.h> +#include <sof/list.h> +#include <sof/math/trig.h> +#include <sof/platform.h> +#include <rtos/string.h> +#include <sof/trace/trace.h> +#include <sof/ut.h> +#include <ipc/control.h> +#include <ipc/stream.h> +#include <ipc/topology.h> +#include <user/tone.h> +#include <user/trace.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include "tone.h" + +SOF_DEFINE_REG_UUID(tone); +LOG_MODULE_DECLARE(tone, CONFIG_SOF_LOG_LEVEL); + +static const struct comp_driver comp_tone; + +static struct comp_dev *tone_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec) +{ + struct comp_dev *dev; + const struct ipc_config_tone *ipc_tone = spec; + struct comp_data *cd; + int i; + + comp_cl_info(&comp_tone, "tone_new()"); + + dev = comp_alloc(drv, sizeof(*dev)); + if (!dev) + return NULL; + dev->ipc_config = *config; + + cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + if (!cd) { + comp_free_device(dev); + return NULL; + } + + comp_set_drvdata(dev, cd); + cd->tone_func = tone_s32_default; + + cd->rate = ipc_tone->sample_rate; + + /* Reset tone generator and set channels volumes to default */ + for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) + tonegen_reset(&cd->sg[i]); + + dev->state = COMP_STATE_READY; + return dev; +} + +static void tone_free(struct comp_dev *dev) +{ + struct tone_data *td = comp_get_drvdata(dev); + + comp_info(dev, "entry"); + + rfree(td); + comp_free_device(dev); +} + +/* set component audio stream parameters */ +static int tone_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params) +{ + struct comp_data *cd = comp_get_drvdata(dev); + struct comp_buffer *sourceb, *sinkb; + + sourceb = comp_dev_get_first_data_producer(dev); + sinkb = comp_dev_get_first_data_consumer(dev); + if (!sourceb || !sinkb) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } + + comp_info(dev, "config->frame_fmt = %u", + dev->ipc_config.frame_fmt); + + /* Tone supports only S32_LE PCM format atm */ + if (dev->ipc_config.frame_fmt != SOF_IPC_FRAME_S32_LE) + return -EINVAL; + + 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(&sourceb->stream); + + return 0; +} + +#if CONFIG_IPC_MAJOR_3 +static int tone_cmd_get_value(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata, int max_size) +{ + struct comp_data *cd = comp_get_drvdata(dev); + int j; + + comp_info(dev, "entry"); + + if (cdata->type != SOF_CTRL_TYPE_VALUE_CHAN_GET) { + comp_err(dev, "wrong cdata->type: %u", + cdata->type); + return -EINVAL; + } + + if (cdata->cmd == SOF_CTRL_CMD_SWITCH) { + for (j = 0; j < cdata->num_elems; j++) { + cdata->chanv[j].channel = j; + cdata->chanv[j].value = !cd->sg[j].mute; + comp_info(dev, "j = %u, cd->sg[j].mute = %u", + j, cd->sg[j].mute); + } + } + return 0; +} + +static int tone_cmd_set_value(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + struct comp_data *cd = comp_get_drvdata(dev); + int j; + uint32_t ch; + bool val; + + if (cdata->type != SOF_CTRL_TYPE_VALUE_CHAN_SET) { + comp_err(dev, "wrong cdata->type: %u", + cdata->type); + return -EINVAL; + } + + if (cdata->cmd == SOF_CTRL_CMD_SWITCH) { + comp_info(dev, "SOF_CTRL_CMD_SWITCH"); + for (j = 0; j < cdata->num_elems; j++) { + ch = cdata->chanv[j].channel; + val = cdata->chanv[j].value; + comp_info(dev, "SOF_CTRL_CMD_SWITCH, ch = %u, val = %u", + ch, val); + if (ch >= PLATFORM_MAX_CHANNELS) { + comp_err(dev, "ch >= PLATFORM_MAX_CHANNELS"); + return -EINVAL; + } + + if (val) + tonegen_unmute(&cd->sg[ch]); + else + tonegen_mute(&cd->sg[ch]); + } + } else { + comp_err(dev, "invalid cdata->cmd"); + return -EINVAL; + } + + return 0; +} + +static int tone_cmd_set_data(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + struct comp_data *cd = comp_get_drvdata(dev); + struct sof_ipc_ctrl_value_comp *compv; + int i; + uint32_t ch; + uint32_t val; + + comp_info(dev, "entry"); + + if (cdata->type != SOF_CTRL_TYPE_VALUE_COMP_SET) { + comp_err(dev, "wrong cdata->type: %u", + cdata->type); + return -EINVAL; + } + + switch (cdata->cmd) { + case SOF_CTRL_CMD_ENUM: + comp_info(dev, "SOF_CTRL_CMD_ENUM, cdata->index = %u", + cdata->index); + compv = (struct sof_ipc_ctrl_value_comp *)ASSUME_ALIGNED(&cdata->data->data, 4); + + for (i = 0; i < (int)cdata->num_elems; i++) { + ch = compv[i].index; + val = compv[i].svalue; + comp_info(dev, "SOF_CTRL_CMD_ENUM, ch = %u, val = %u", + ch, val); + switch (cdata->index) { + case SOF_TONE_IDX_FREQUENCY: + comp_info(dev, "SOF_TONE_IDX_FREQUENCY"); + tonegen_update_f(&cd->sg[ch], val); + break; + case SOF_TONE_IDX_AMPLITUDE: + comp_info(dev, "SOF_TONE_IDX_AMPLITUDE"); + tonegen_set_a(&cd->sg[ch], val); + break; + case SOF_TONE_IDX_FREQ_MULT: + comp_info(dev, "SOF_TONE_IDX_FREQ_MULT"); + tonegen_set_freq_mult(&cd->sg[ch], val); + break; + case SOF_TONE_IDX_AMPL_MULT: + comp_info(dev, "SOF_TONE_IDX_AMPL_MULT"); + tonegen_set_ampl_mult(&cd->sg[ch], val); + break; + case SOF_TONE_IDX_LENGTH: + comp_info(dev, "SOF_TONE_IDX_LENGTH"); + tonegen_set_length(&cd->sg[ch], val); + break; + case SOF_TONE_IDX_PERIOD: + comp_info(dev, "SOF_TONE_IDX_PERIOD"); + tonegen_set_period(&cd->sg[ch], val); + break; + case SOF_TONE_IDX_REPEATS: + comp_info(dev, "SOF_TONE_IDX_REPEATS"); + tonegen_set_repeats(&cd->sg[ch], val); + break; + case SOF_TONE_IDX_LIN_RAMP_STEP: + comp_info(dev, "SOF_TONE_IDX_LIN_RAMP_STEP"); + tonegen_set_linramp(&cd->sg[ch], val); + break; + default: + comp_err(dev, "invalid cdata->index"); + return -EINVAL; + } + } + break; + default: + comp_err(dev, "invalid cdata->cmd"); + return -EINVAL; + } + + return 0; +} + +/* used to pass standard and bespoke commands (with data) to component */ +static int tone_cmd(struct comp_dev *dev, int cmd, void *data, + int max_data_size) +{ + struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4); + int ret = 0; + + comp_info(dev, "entry"); + + switch (cmd) { + case COMP_CMD_SET_DATA: + ret = tone_cmd_set_data(dev, cdata); + break; + case COMP_CMD_SET_VALUE: + ret = tone_cmd_set_value(dev, cdata); + break; + case COMP_CMD_GET_VALUE: + ret = tone_cmd_get_value(dev, cdata, max_data_size); + break; + } + + return ret; +} +#endif + +static int tone_trigger(struct comp_dev *dev, int cmd) +{ + comp_info(dev, "entry"); + + return comp_set_state(dev, cmd); +} + +/* copy and process stream data from source to sink buffers */ +static int tone_copy(struct comp_dev *dev) +{ + struct comp_buffer *sink; + struct comp_data *cd = comp_get_drvdata(dev); + uint32_t free; + int ret = 0; + + comp_dbg(dev, "entry"); + + /* tone component sink buffer */ + sink = comp_dev_get_first_data_consumer(dev); + 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->stream, dev->frames); + buffer_stream_writeback(sink, cd->period_bytes); + + /* calc new free and available */ + comp_update_buffer_produce(sink, cd->period_bytes); + + ret = dev->frames; + } + + return ret; +} + +static int tone_prepare(struct comp_dev *dev) +{ + struct comp_data *cd = comp_get_drvdata(dev); + struct comp_buffer *sourceb; + int32_t f; + int32_t a; + int ret; + int i; + + comp_info(dev, "entry"); + + 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; + + sourceb = comp_dev_get_first_data_producer(dev); + if (!sourceb) { + comp_err(dev, "no source buffer"); + return -ENOTCONN; + } + + cd->channels = audio_stream_get_channels(&sourceb->stream); + comp_info(dev, "cd->channels = %u, cd->rate = %u", + cd->channels, cd->rate); + + for (i = 0; i < cd->channels; i++) { + f = tonegen_get_f(&cd->sg[i]); + a = tonegen_get_a(&cd->sg[i]); + if (tonegen_init(&cd->sg[i], cd->rate, f, a) < 0) { + comp_set_state(dev, COMP_TRIGGER_RESET); + return -EINVAL; + } + } + + return 0; +} + +static int tone_reset(struct comp_dev *dev) +{ + struct comp_data *cd = comp_get_drvdata(dev); + int i; + + comp_info(dev, "entry"); + + /* Initialize with the defaults */ + for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) + tonegen_reset(&cd->sg[i]); + + comp_set_state(dev, COMP_TRIGGER_RESET); + + return 0; +} + +DECLARE_TR_CTX(tone_tr, SOF_UUID(tone_uuid), LOG_LEVEL_INFO); + +static const struct comp_driver comp_tone = { + .type = SOF_COMP_TONE, + .uid = SOF_RT_UUID(tone_uuid), + .tctx = &tone_tr, + .ops = { + .create = tone_new, + .free = tone_free, + .params = tone_params, +#if CONFIG_IPC_MAJOR_3 + .cmd = tone_cmd, +#endif + .trigger = tone_trigger, + .copy = tone_copy, + .prepare = tone_prepare, + .reset = tone_reset, + }, +}; + +static SHARED_DATA struct comp_driver_info comp_tone_info = { + .drv = &comp_tone, +}; + +UT_STATIC void sys_comp_tone_init(void) +{ + comp_register(&comp_tone_info); +} + +DECLARE_MODULE(sys_comp_tone_init); +SOF_MODULE_INIT(tone, sys_comp_tone_init); diff --git a/src/audio/tone/tone-ipc4.c b/src/audio/tone/tone-ipc4.c new file mode 100644 index 000000000000..30d99058a3d6 --- /dev/null +++ b/src/audio/tone/tone-ipc4.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2016 Intel Corporation. All rights reserved. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> +// Liam Girdwood <liam.r.girdwood@linux.intel.com> +// Keyon Jie <yang.jie@linux.intel.com> + +#include <sof/audio/buffer.h> +#include <sof/audio/component.h> +#include <sof/audio/format.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/pipeline.h> +#include <sof/audio/ipc-config.h> +#include <sof/common.h> +#include <rtos/panic.h> +#include <sof/ipc/msg.h> +#include <rtos/alloc.h> +#include <rtos/init.h> +#include <sof/lib/memory.h> /* for SHARED_DATA */ +#include <sof/lib/uuid.h> +#include <sof/list.h> +#include <sof/math/trig.h> +#include <sof/platform.h> +#include <rtos/string.h> +#include <sof/trace/trace.h> +#include <sof/ut.h> +#include <ipc/control.h> +#include <ipc/stream.h> +#include <ipc/topology.h> +#include <user/tone.h> +#include <user/trace.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <ipc4/base-config.h> +#include <sof/audio/sink_api.h> +#include "tone.h" + +SOF_DEFINE_REG_UUID(tone); +LOG_MODULE_DECLARE(tone, CONFIG_SOF_LOG_LEVEL); + +static int tone_init(struct processing_module *mod) +{ + struct module_data *mod_data = &mod->priv; + struct module_config *mod_config = &mod->priv.cfg; + struct comp_dev *dev = mod->dev; + struct comp_data *cd; + int i; + + cd = mod_alloc(mod, sizeof(*cd)); + if (!cd) + return -ENOMEM; + + mod_data->private = cd; + + /* Tnoe only supports 32-bit format */ + cd->tone_func = tone_s32_default; + + /* + * set direction for the comp. In the case of the tone generator being used for + * echo reference, the number of input pins will be non-zero + */ + if (mod_config->nb_input_pins > 0) { + dev->direction = SOF_IPC_STREAM_CAPTURE; + cd->mode = TONE_MODE_SILENCE; + + } else { + dev->direction = SOF_IPC_STREAM_PLAYBACK; + cd->mode = TONE_MODE_TONEGEN; + } + + dev->direction_set = true; + + /* Reset tone generator and set channels volumes to default */ + for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) + tonegen_reset(&cd->sg[i]); + + return 0; +} + +static int tone_free(struct processing_module *mod) +{ + struct comp_data *cd = module_get_private_data(mod); + + comp_info(mod->dev, "entry"); + + mod_free(mod, cd); + return 0; +} + +/* set component audio stream parameters */ +static int tone_params(struct processing_module *mod) +{ + struct comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + struct comp_buffer *sinkb; + enum sof_ipc_frame frame_fmt, valid_fmt; + + sinkb = comp_dev_get_first_data_consumer(dev); + if (!sinkb) { + comp_err(dev, "no sink buffer found for tone component"); + return -ENOTCONN; + } + + 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); + cd->rate = mod->priv.cfg.base_cfg.audio_fmt.sampling_frequency; + + /* Tone supports only S32_LE PCM format atm */ + if (frame_fmt != SOF_IPC_FRAME_S32_LE) { + comp_err(dev, "unsupported frame_fmt = %u", frame_fmt); + return -EINVAL; + } + + return 0; +} + +/* copy and process stream data from source to sink buffers */ +static int tone_process(struct processing_module *mod, + 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); + + if (num_of_sources > 0) + return cd->tone_func(mod, sinks[0], sources[0]); + + return cd->tone_func(mod, sinks[0], NULL); +} + +static int tone_prepare(struct processing_module *mod, 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); + int32_t f; + int32_t a; + int ret; + int i; + + ret = tone_params(mod); + if (ret < 0) + return ret; + + cd->channels = mod->priv.cfg.base_cfg.audio_fmt.channels_count; + + for (i = 0; i < cd->channels; i++) { + f = tonegen_get_f(&cd->sg[i]); + a = tonegen_get_a(&cd->sg[i]); + if (tonegen_init(&cd->sg[i], cd->rate, f, a) < 0) + return -EINVAL; + } + + return 0; +} + +static int tone_reset(struct processing_module *mod) +{ + struct comp_data *cd = module_get_private_data(mod); + int i; + + /* Initialize with the defaults */ + for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) + tonegen_reset(&cd->sg[i]); + + return 0; +} + +static int tone_bind(struct processing_module *mod, struct bind_info *bind_data) +{ + struct comp_data *cd = module_get_private_data(mod); + + /* nothing to do when tone is not the sink */ + if (bind_data->bind_type != COMP_BIND_TYPE_SOURCE) + return 0; + + /* set passthrough mode when tone generator is bound as a sink */ + cd->mode = TONE_MODE_PASSTHROUGH; + + return 0; +} + +static int tone_unbind(struct processing_module *mod, struct bind_info *unbind_data) +{ + struct comp_data *cd = module_get_private_data(mod); + + /* nothing to do when tone is not the sink */ + if (unbind_data->bind_type != COMP_BIND_TYPE_SOURCE) + return 0; + + /* set silence mode when tone generator is unbound from a source module */ + cd->mode = TONE_MODE_SILENCE; + + return 0; +} + +static const struct module_interface tone_interface = { + .init = tone_init, + .prepare = tone_prepare, + .process = tone_process, + .reset = tone_reset, + .free = tone_free, + .bind = tone_bind, + .unbind = tone_unbind, +}; + +#if CONFIG_COMP_TONE_MODULE +/* modular: llext dynamic link */ + +#include <module/module/api_ver.h> +#include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> + +static const struct sof_man_module_manifest mod_manifest[] __section(".module") __used = { + SOF_LLEXT_MODULE_MANIFEST("TONE", &tone_interface, 1, SOF_REG_UUID(tone), 30), +}; + +SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_TR_CTX(tone_tr, SOF_UUID(tone_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(tone_interface, tone_uuid, tone_tr); +SOF_MODULE_INIT(tone, sys_comp_module_tone_interface_init); + +#endif diff --git a/src/audio/tone/tone.c b/src/audio/tone/tone.c new file mode 100644 index 000000000000..975e4ee06bc8 --- /dev/null +++ b/src/audio/tone/tone.c @@ -0,0 +1,355 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2016 Intel Corporation. All rights reserved. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> +// Liam Girdwood <liam.r.girdwood@linux.intel.com> +// Keyon Jie <yang.jie@linux.intel.com> + +#include <sof/audio/buffer.h> +#include <sof/audio/component.h> +#include <sof/audio/format.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/pipeline.h> +#include <sof/audio/ipc-config.h> +#include <sof/common.h> +#include <rtos/panic.h> +#include <sof/ipc/msg.h> +#include <rtos/alloc.h> +#include <rtos/init.h> +#include <sof/lib/memory.h> /* for SHARED_DATA */ +#include <sof/lib/uuid.h> +#include <sof/list.h> +#include <sof/math/trig.h> +#include <sof/platform.h> +#include <rtos/string.h> +#include <sof/trace/trace.h> +#include <sof/ut.h> +#include <ipc/control.h> +#include <ipc/stream.h> +#include <ipc/topology.h> +#include <user/tone.h> +#include <user/trace.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <ipc4/base-config.h> +#include <sof/audio/sink_api.h> +#include "tone.h" + +LOG_MODULE_REGISTER(tone, CONFIG_SOF_LOG_LEVEL); + +static int32_t tonegen(struct tone_state *sg) +{ + int64_t sine; + int64_t w; + /* sg->w is angle in Q4.28 radians format, sin() returns Q1.31 */ + /* sg->a is amplitude as Q1.31 */ + sine = + q_mults_32x32(sin_fixed_32b(sg->w), sg->a, + Q_SHIFT_BITS_64(31, 31, 31)); + + /* Next point */ + w = (int64_t)sg->w + sg->w_step; + sg->w = (w > PI_MUL2_Q4_28) + ? (int32_t)(w - PI_MUL2_Q4_28) : (int32_t)w; + + if (sg->mute) + return 0; + else + return (int32_t)sine; /* Q1.31 no saturation need */ +} + +static void tonegen_control(struct tone_state *sg) +{ + int64_t a; + int64_t p; + + /* Count samples, 125 us blocks */ + sg->sample_count++; + if (sg->sample_count < sg->samples_in_block) + return; + + sg->sample_count = 0; + if (sg->block_count < INT32_MAX) + sg->block_count++; + + /* Fade-in ramp during tone */ + if (sg->block_count < sg->tone_length) { + if (sg->a == 0) + sg->w = 0; /* Reset phase to have less clicky ramp */ + + if (sg->a > sg->a_target) { + a = (int64_t)sg->a - sg->ramp_step; + if (a < sg->a_target) + a = sg->a_target; + + } else { + a = (int64_t)sg->a + sg->ramp_step; + if (a > sg->a_target) + a = sg->a_target; + } + sg->a = (int32_t)a; + } + + /* Fade-out ramp after tone*/ + if (sg->block_count > sg->tone_length) { + a = (int64_t)sg->a - sg->ramp_step; + if (a < 0) + a = 0; + + sg->a = (int32_t)a; + } + + /* New repeated tone, update for frequency or amplitude sweep */ + if (sg->block_count > sg->tone_period && + (sg->repeat_count + 1 < sg->repeats)) { + sg->block_count = 0; + if (sg->ampl_coef > 0) { + sg->a_target = + sat_int32(q_multsr_32x32(sg->a_target, + sg->ampl_coef, + Q_SHIFT_BITS_64(31, 30, 31))); + sg->a = (sg->ramp_step > sg->a_target) + ? sg->a_target : sg->ramp_step; + } + if (sg->freq_coef > 0) { + /* f is Q16.16, freq_coef is Q2.30 */ + p = q_multsr_32x32(sg->f, sg->freq_coef, + Q_SHIFT_BITS_64(16, 30, 16)); + tonegen_update_f(sg, (int32_t)p); /* No saturation */ + } + sg->repeat_count++; + } +} + +static int tone_s32_passthrough(struct processing_module *mod, struct sof_sink *sink, + struct sof_source *source) +{ + struct comp_data *cd = module_get_private_data(mod); + size_t output_frame_bytes, output_frames; + size_t input_frame_bytes, input_frames; + int32_t *output_pos, *output_start, output_cirbuf_size; + int32_t const *input_pos, *input_start, *input_end; + int32_t *output_end, input_cirbuf_size; + uint32_t frames, bytes; + int nch = cd->channels; + int n; + int ret; + + /* tone generator only ever has 1 sink */ + output_frames = sink_get_free_frames(sink); + output_frame_bytes = sink_get_frame_bytes(sink); + output_frames = mod->period_bytes / output_frame_bytes; + + ret = sink_get_buffer_s32(sink, output_frames * output_frame_bytes, + &output_pos, &output_start, &output_cirbuf_size); + if (ret) { + comp_err(mod->dev, "sink_get_buffer_s32() failed"); + return -ENODATA; + } + + input_frames = source_get_data_frames_available(source); + input_frame_bytes = source_get_frame_bytes(source); + + ret = source_get_data_s32(source, input_frames * input_frame_bytes, + &input_pos, &input_start, &input_cirbuf_size); + if (ret) { + comp_err(mod->dev, "source_get_data_s32() failed"); + return -ENODATA; + } + input_end = input_start + input_cirbuf_size; + + frames = MIN(output_frames, input_frames); + + if (frames * output_frame_bytes >= mod->period_bytes) + frames = mod->period_bytes / output_frame_bytes; + bytes = frames * output_frame_bytes; + + output_end = output_start + output_cirbuf_size; + + n = frames * nch; + + while (n > 0) { + int n_wrap_source, n_wrap_dest, n_min; + int i; + + n_wrap_dest = output_end - output_pos; + n_wrap_source = input_end - input_pos; + + /* Process until source/dest wrap or completed n */ + n_min = (n < n_wrap_dest) ? n : n_wrap_dest; + n_min = (n_min < n_wrap_source) ? n_min : n_wrap_source; + while (n_min > 0) { + n -= nch; + n_min -= nch; + for (i = 0; i < nch; i++) { + *output_pos = *input_pos; + output_pos++; + input_pos++; + } + } + + /* Wrap destination/source buffer */ + if (output_pos >= output_end) + output_pos = output_start; + if (input_pos >= input_end) + input_pos = input_start; + } + + ret = sink_commit_buffer(sink, bytes); + if (ret) + return ret; + + return source_release_data(source, bytes); +} + +/* + * Tone generator algorithm code + */ +int tone_s32_default(struct processing_module *mod, struct sof_sink *sink, + struct sof_source *source) +{ + struct comp_data *cd = module_get_private_data(mod); + size_t output_frame_bytes, output_frames; + int32_t *output_pos, *output_start, output_cirbuf_size; + int32_t *output_end; + uint32_t frames, bytes; + int nch = cd->channels; + int i; + int n; + int n_wrap_dest; + int n_min; + int ret; + + if (cd->mode == TONE_MODE_PASSTHROUGH) + return tone_s32_passthrough(mod, sink, source); + + /* tone generator only ever has 1 sink */ + output_frames = sink_get_free_frames(sink); + output_frame_bytes = sink_get_frame_bytes(sink); + output_frames = mod->period_bytes / output_frame_bytes; + + ret = sink_get_buffer_s32(sink, output_frames * output_frame_bytes, + &output_pos, &output_start, &output_cirbuf_size); + if (ret) + return -ENODATA; + + frames = output_frames; + + if (frames * output_frame_bytes >= mod->period_bytes) + frames = mod->period_bytes / output_frame_bytes; + bytes = frames * output_frame_bytes; + + output_end = output_start + output_cirbuf_size; + + n = frames * nch; + if (!source) { + while (n > 0) { + n_wrap_dest = output_end - output_pos; + + /* Process until wrap or completed n */ + n_min = (n < n_wrap_dest) ? n : n_wrap_dest; + while (n_min > 0) { + n -= nch; + n_min -= nch; + for (i = 0; i < nch; i++) { + switch (cd->mode) { + case TONE_MODE_TONEGEN: + tonegen_control(&cd->sg[i]); + *output_pos = tonegen(&cd->sg[i]); + break; + case TONE_MODE_SILENCE: + *output_pos = 0; + break; + default: + break; + } + output_pos++; + } + } + + /* Wrap destination buffer */ + output_pos = output_start; + } + } + + return sink_commit_buffer(sink, bytes); +} + +void tonegen_update_f(struct tone_state *sg, int32_t f) +{ + int64_t w_tmp; + int64_t f_max; + + /* Calculate Fs/2, fs is Q32.0, f is Q16.16 */ + f_max = Q_SHIFT_LEFT((int64_t)sg->fs, 0, 16 - 1); + f_max = (f_max > INT32_MAX) ? INT32_MAX : f_max; + sg->f = (f > f_max) ? f_max : f; + /* Q16 x Q31 -> Q28 */ + w_tmp = q_multsr_32x32(sg->f, sg->c, Q_SHIFT_BITS_64(16, 31, 28)); + w_tmp = (w_tmp > PI_Q4_28) ? PI_Q4_28 : w_tmp; /* Limit to pi Q4.28 */ + sg->w_step = (int32_t)w_tmp; +} + +void tonegen_reset(struct tone_state *sg) +{ + sg->mute = 1; + sg->a = 0; + sg->a_target = TONE_AMPLITUDE_DEFAULT; + sg->c = 0; + sg->f = TONE_FREQUENCY_DEFAULT; + sg->w = 0; + sg->w_step = 0; + + sg->block_count = 0; + sg->repeat_count = 0; + sg->repeats = 0; + sg->sample_count = 0; + sg->samples_in_block = 0; + + /* Continuous tone */ + sg->freq_coef = ONE_Q2_30; /* Set freq multiplier to 1.0 */ + sg->ampl_coef = ONE_Q2_30; /* Set ampl multiplier to 1.0 */ + sg->tone_length = INT32_MAX; + sg->tone_period = INT32_MAX; + sg->ramp_step = ONE_Q1_31; /* Set lin ramp modification to max */ +} + +int tonegen_init(struct tone_state *sg, int32_t fs, int32_t f, int32_t a) +{ + int idx; + int i; + + sg->a_target = a; + sg->a = (sg->ramp_step > sg->a_target) ? sg->a_target : sg->ramp_step; + + idx = -1; + sg->mute = 1; + sg->fs = 0; + + /* Find index of current sample rate and then get from lookup table the + * corresponding 2*pi/Fs value. + */ + for (i = 0; i < TONE_NUM_FS; i++) { + if (fs == tone_fs_list[i]) + idx = i; + } + + if (idx < 0) { + sg->w_step = 0; + return -EINVAL; + } + + sg->fs = fs; + sg->c = tone_pi2_div_fs[idx]; /* Store 2*pi/Fs */ + sg->mute = 0; + tonegen_update_f(sg, f); + + /* 125us as Q1.31 is 268435, calculate fs * 125e-6 in Q31.0 */ + sg->samples_in_block = + (int32_t)q_multsr_32x32(fs, 268435, Q_SHIFT_BITS_64(0, 31, 0)); + + return 0; +} diff --git a/src/audio/tone/tone.h b/src/audio/tone/tone.h new file mode 100644 index 000000000000..4183543e0beb --- /dev/null +++ b/src/audio/tone/tone.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. + * + */ + +#include <sof/audio/buffer.h> +#include <sof/audio/component.h> +#include <sof/audio/format.h> +#include <sof/audio/pipeline.h> +#include <sof/audio/ipc-config.h> +#include <sof/common.h> +#include <rtos/panic.h> +#include <sof/ipc/msg.h> +#include <rtos/alloc.h> +#include <rtos/init.h> +#include <sof/lib/memory.h> /* for SHARED_DATA */ +#include <sof/lib/uuid.h> +#include <sof/list.h> +#include <sof/math/trig.h> +#include <sof/platform.h> +#include <rtos/string.h> +#include <sof/trace/trace.h> +#include <sof/ut.h> +#include <ipc/control.h> +#include <ipc/stream.h> +#include <ipc/topology.h> +#include <user/tone.h> +#include <user/trace.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +/* Convert float frequency in Hz to Q16.16 fractional format */ +#define TONE_FREQ(f) Q_CONVERT_FLOAT(f, 16) + +/* Convert float gain to Q1.31 fractional format */ +#define TONE_GAIN(v) Q_CONVERT_FLOAT(v, 31) + +/* Set default tone amplitude and frequency */ +#define TONE_AMPLITUDE_DEFAULT TONE_GAIN(0.1) /* -20 dB */ +#define TONE_FREQUENCY_DEFAULT TONE_FREQ(997.0) +#define TONE_NUM_FS 13 /* Table size for 8-192 kHz range */ + +#define TONE_MODE_TONEGEN 0 +#define TONE_MODE_PASSTHROUGH 1 +#define TONE_MODE_SILENCE 2 + +extern struct tr_ctx tone_tr; +extern const struct sof_uuid tone; + +/* 2*pi/Fs lookup tables in Q1.31 for each Fs */ +static const int32_t tone_fs_list[TONE_NUM_FS] = { + 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, + 64000, 88200, 96000, 176400, 192000 +}; + +static const int32_t tone_pi2_div_fs[TONE_NUM_FS] = { + 1686630, 1223858, 843315, 611929, 562210, 421657, 305965, + 281105, 210829, 152982, 140552, 76491, 70276 +}; + +/* tone component private data */ + +struct tone_state { + int mute; + int32_t a; /* Current amplitude Q1.31 */ + int32_t a_target; /* Target amplitude Q1.31 */ + int32_t ampl_coef; /* Amplitude multiplier Q2.30 */ + int32_t c; /* Coefficient 2*pi/Fs Q1.31 */ + int32_t f; /* Frequency Q16.16 */ + int32_t freq_coef; /* Frequency multiplier Q2.30 */ + int32_t fs; /* Sample rate in Hertz Q32.0 */ + int32_t ramp_step; /* Amplitude ramp step Q1.31 */ + int32_t w; /* Angle radians Q4.28 */ + int32_t w_step; /* Angle step Q4.28 */ + uint32_t block_count; + uint32_t repeat_count; + uint32_t repeats; /* Number of repeats for tone (sweep steps) */ + uint32_t sample_count; + uint32_t samples_in_block; /* Samples in 125 us block */ + uint32_t tone_length; /* Active length in 125 us blocks */ + uint32_t tone_period; /* Active + idle time in 125 us blocks */ +}; + +struct comp_data { + uint32_t channels; + uint32_t rate; + struct tone_state sg[PLATFORM_MAX_CHANNELS]; + int (*tone_func)(struct processing_module *mod, struct sof_sink *sink, + struct sof_source *source); + int mode; +}; + +void tonegen_reset(struct tone_state *sg); +int tonegen_init(struct tone_state *sg, int32_t fs, int32_t f, int32_t a); +void tonegen_update_f(struct tone_state *sg, int32_t f); +int tone_s32_default(struct processing_module *mod, struct sof_sink *sink, + struct sof_source *source); + +/* Set sine amplitude */ +static inline void tonegen_set_a(struct tone_state *sg, int32_t a) +{ + sg->a_target = a; +} + +/* Repeated number of beeps */ +static inline void tonegen_set_repeats(struct tone_state *sg, uint32_t r) +{ + sg->repeats = r; +} + +/* The next functions support zero as shortcut for defaults to get + * make a nicer API without need to remember the neutral steady + * non-swept tone settings. + */ + +/* Multiplication factor for frequency as Q2.30 for logarithmic change */ +static inline void tonegen_set_freq_mult(struct tone_state *sg, int32_t fm) +{ + sg->freq_coef = (fm > 0) ? fm : ONE_Q2_30; /* Set freq mult to 1.0 */ +} + +/* Multiplication factor for amplitude as Q2.30 for logarithmic change */ +static inline void tonegen_set_ampl_mult(struct tone_state *sg, int32_t am) +{ + sg->ampl_coef = (am > 0) ? am : ONE_Q2_30; /* Set ampl mult to 1.0 */ +} + +/* Tone length in samples, this is the active length of tone */ +static inline void tonegen_set_length(struct tone_state *sg, uint32_t tl) +{ + sg->tone_length = (tl > 0) ? tl : INT32_MAX; /* Count rate 125 us */ +} + +/* Tone period in samples, this is the length including the pause after beep */ +static inline void tonegen_set_period(struct tone_state *sg, uint32_t tp) +{ + sg->tone_period = (tp > 0) ? tp : INT32_MAX; /* Count rate 125 us */ +} + +/* Tone ramp parameters: + * step - Value that is added or subtracted to amplitude. A zero or negative + * number disables the ramp and amplitude is immediately modified to + * final value. + */ + +static inline void tonegen_set_linramp(struct tone_state *sg, int32_t step) +{ + sg->ramp_step = (step > 0) ? step : INT32_MAX; +} + +static inline int32_t tonegen_get_f(struct tone_state *sg) +{ + return sg->f; +} + +static inline int32_t tonegen_get_a(struct tone_state *sg) +{ + return sg->a_target; +} + +static inline void tonegen_mute(struct tone_state *sg) +{ + sg->mute = 1; +} + +static inline void tonegen_unmute(struct tone_state *sg) +{ + sg->mute = 0; +} diff --git a/src/audio/tone/tone.toml b/src/audio/tone/tone.toml new file mode 100644 index 000000000000..02d6e5dca96b --- /dev/null +++ b/src/audio/tone/tone.toml @@ -0,0 +1,22 @@ +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + + REM # Template component module config + [[module.entry]] + name = "TONE" + uuid = UUIDREG_STR_TONE + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = LOAD_TYPE + init_config = "1" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + REM # 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] + + index = __COUNTER__ diff --git a/src/audio/up_down_mixer/Kconfig b/src/audio/up_down_mixer/Kconfig index 38ce5adafb51..be3cf794061e 100644 --- a/src/audio/up_down_mixer/Kconfig +++ b/src/audio/up_down_mixer/Kconfig @@ -2,7 +2,6 @@ config COMP_UP_DOWN_MIXER bool "UP_DOWN_MIXER component" - default n depends on IPC_MAJOR_4 help Select for Up Down Mixer component Conversions supported: diff --git a/src/audio/up_down_mixer/README.md b/src/audio/up_down_mixer/README.md new file mode 100644 index 000000000000..723d5cc609fc --- /dev/null +++ b/src/audio/up_down_mixer/README.md @@ -0,0 +1,13 @@ +# Up/Down Mixer Architecture + +This directory contains the Up/Down channel mixer. + +## Overview + +Converts the spatial format of audio (e.g., Stereo up to 5.1 surround, or 5.1 mixed down to Stereo) natively. + +## Configuration and Scripts + +- **Kconfig**: Enabled via `COMP_UP_DOWN_MIXER`, specifically tuned for `IPC_MAJOR_4`. Supports heavy format transformations up to 7.1 endpoints. +- **CMakeLists.txt**: Implements the base `up_down_mixer.c` component along with highly-optimized architecture primitives (`up_down_mixer_hifi3.c`). +- **up_down_mixer.toml**: Robust configuration map controlling `UPDWMIX` deployment against variable system arrays depending on Meteor Lake, Lunar Lake, or ACE platform parameters (UUID binding `UUIDREG_STR_UP_DOWN_MIXER`). diff --git a/src/audio/up_down_mixer/up_down_mixer.c b/src/audio/up_down_mixer/up_down_mixer.c index e1cb4d9e13bc..4a9a644434e7 100644 --- a/src/audio/up_down_mixer/up_down_mixer.c +++ b/src/audio/up_down_mixer/up_down_mixer.c @@ -11,7 +11,6 @@ #include <sof/audio/pipeline.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/cache.h> #include <rtos/init.h> #include <sof/lib/notifier.h> @@ -33,9 +32,6 @@ LOG_MODULE_REGISTER(up_down_mixer, CONFIG_SOF_LOG_LEVEL); /* these ids aligns windows driver requirement to support windows driver */ SOF_DEFINE_REG_UUID(up_down_mixer); -DECLARE_TR_CTX(up_down_mixer_comp_tr, SOF_UUID(up_down_mixer_uuid), - LOG_LEVEL_INFO); - int32_t custom_coeffs[UP_DOWN_MIX_COEFFS_LENGTH]; static int set_downmix_coefficients(struct processing_module *mod, @@ -100,7 +96,7 @@ static int set_downmix_coefficients(struct processing_module *mod, cd->downmix_coefficients = k_scaled_lo_ro_downmix32bit; break; default: - comp_err(dev, "set_downmix_coefficients(): invalid channel config."); + comp_err(dev, "invalid channel config."); return -EINVAL; } @@ -128,7 +124,7 @@ static up_down_mixer_routine select_mix_out_stereo(struct comp_dev *dev, return downmix16bit_5_1; case IPC4_CHANNEL_CONFIG_INVALID: default: - comp_err(dev, "select_mix_out_stereo(): invalid channel config."); + comp_err(dev, "invalid channel config."); /* * This is a strange situation. We will allow to process it * in the release code (hoping for the best) with downmix16bit, @@ -161,7 +157,7 @@ static up_down_mixer_routine select_mix_out_stereo(struct comp_dev *dev, return downmix32bit_7_1; case IPC4_CHANNEL_CONFIG_INVALID: default: - comp_err(dev, "select_mix_out_stereo(): invalid channel config."); + comp_err(dev, "invalid channel config."); /* * This is a strange situation. We will allow to process it * in the release code (hoping for the best) with downmix32bit, @@ -185,7 +181,7 @@ static up_down_mixer_routine select_mix_out_mono(struct comp_dev *dev, return downmix16bit_4ch_mono; case IPC4_CHANNEL_CONFIG_INVALID: default: - comp_err(dev, "select_mix_out_mono(): invalid channel config."); + comp_err(dev, "invalid channel config."); /* * This is a strange situation. We will allow to process it * in the release code (hoping for the best) with downmix16bit, @@ -212,7 +208,7 @@ static up_down_mixer_routine select_mix_out_mono(struct comp_dev *dev, return downmix32bit_7_1_mono; case IPC4_CHANNEL_CONFIG_INVALID: default: - comp_err(dev, "select_mix_out_mono(): invalid channel config."); + comp_err(dev, "invalid channel config."); /* * This is a strange situation. We will allow to process it * in the release code (hoping for the best) with downmix32bit, @@ -234,7 +230,7 @@ static up_down_mixer_routine select_mix_out_5_1(struct comp_dev *dev, return upmix16bit_2_0_to_5_1; case IPC4_CHANNEL_CONFIG_INVALID: default: - comp_err(dev, "select_mix_out_5_1(): invalid channel config."); + comp_err(dev, "invalid channel config."); return NULL; } } else { @@ -251,7 +247,7 @@ static up_down_mixer_routine select_mix_out_5_1(struct comp_dev *dev, return downmix32bit_7_1_to_5_1; case IPC4_CHANNEL_CONFIG_INVALID: default: - comp_err(dev, "select_mix_out_5_1(): invalid channel config."); + comp_err(dev, "invalid channel config."); return NULL; } } @@ -311,6 +307,13 @@ static int init_mix(struct processing_module *mod, return -EINVAL; } + /* select_mix_out_*() return NULL for unsupported in/out combos */ + if (!cd->mix_routine) { + comp_err(dev, "unsupported channel configuration (in=%d out=%d)", + format->ch_cfg, out_channel_config); + return -EINVAL; + } + /* Update audio format. */ cd->out_fmt[0].valid_bit_depth = IPC4_DEPTH_24BIT; cd->out_fmt[0].depth = IPC4_DEPTH_32BIT; @@ -326,9 +329,9 @@ static int up_down_mixer_free(struct processing_module *mod) { struct up_down_mixer_data *cd = module_get_private_data(mod); - rfree(cd->buf_in); - rfree(cd->buf_out); - rfree(cd); + mod_free(mod, cd->buf_in); + mod_free(mod, cd->buf_out); + mod_free(mod, cd); return 0; } @@ -342,7 +345,7 @@ static int up_down_mixer_init(struct processing_module *mod) struct up_down_mixer_data *cd; int ret; - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) { comp_free(dev); return -ENOMEM; @@ -350,8 +353,8 @@ static int up_down_mixer_init(struct processing_module *mod) mod_data->private = cd; - cd->buf_in = rballoc(0, SOF_MEM_CAPS_RAM, mod->priv.cfg.base_cfg.ibs); - cd->buf_out = rballoc(0, SOF_MEM_CAPS_RAM, mod->priv.cfg.base_cfg.obs); + cd->buf_in = mod_balloc(mod, mod->priv.cfg.base_cfg.ibs); + cd->buf_out = mod_balloc(mod, mod->priv.cfg.base_cfg.obs); if (!cd->buf_in || !cd->buf_out) { ret = -ENOMEM; goto err; @@ -379,13 +382,13 @@ static int up_down_mixer_init(struct processing_module *mod) up_down_mixer->out_channel_config, up_down_mixer->coefficients); break; default: - comp_err(dev, "up_down_mixer_init(): unsupported coefficient type"); + comp_err(dev, "unsupported coefficient type"); ret = -EINVAL; break; } if (ret < 0) { - comp_err(dev, "up_down_mixer_init(): failed to initialize up_down_mix"); + comp_err(dev, "failed to initialize up_down_mix"); goto err; } @@ -408,7 +411,7 @@ up_down_mixer_process(struct processing_module *mod, const uint8_t *input0_pos, *input0_start; uint8_t *output_pos, *output_start; - comp_dbg(dev, "up_down_mixer_process()"); + comp_dbg(dev, "entry"); output_frames = sink_get_free_frames(output_buffers[0]); input_frames = source_get_data_frames_available(input_buffers[0]); @@ -448,5 +451,6 @@ static const struct module_interface up_down_mixer_interface = { .free = up_down_mixer_free }; +DECLARE_TR_CTX(up_down_mixer_comp_tr, SOF_UUID(up_down_mixer_uuid), LOG_LEVEL_INFO); DECLARE_MODULE_ADAPTER(up_down_mixer_interface, up_down_mixer_uuid, up_down_mixer_comp_tr); SOF_MODULE_INIT(up_down_mixer, sys_comp_module_up_down_mixer_interface_init); diff --git a/src/audio/up_down_mixer/up_down_mixer.toml b/src/audio/up_down_mixer/up_down_mixer.toml index 34a1bf586188..713cff7a87d8 100644 --- a/src/audio/up_down_mixer/up_down_mixer.toml +++ b/src/audio/up_down_mixer/up_down_mixer.toml @@ -1,6 +1,6 @@ [[module.entry]] name = "UPDWMIX" - uuid = "42F8060C-832F-4DBF-B247-51E961997B34" + uuid = UUIDREG_STR_UP_DOWN_MIXER affinity_mask = "0x1" instance_count = "15" domain_types = "0" @@ -15,45 +15,76 @@ REM # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] #if CONFIG_METEORLAKE - 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, + mod_cfg = [0, 0, 0, 0, 216, 5044000, 384, 192, 0, 5044, 0, + 1, 0, 0, 0, 216, 2660000, 384, 384, 0, 2660, 0, + 2, 0, 0, 0, 216, 3164000, 576, 384, 0, 3164, 0, + 3, 0, 0, 0, 216, 3316000, 768, 384, 0, 3316, 0, + 4, 0, 0, 0, 216, 5264000, 768, 384, 0, 5264, 0, + 5, 0, 0, 0, 216, 5440000, 768, 384, 0, 5440, 0, + 6, 0, 0, 0, 216, 2888000, 768, 192, 0, 2888, 0, + 7, 0, 0, 0, 216, 2856000, 768, 192, 0, 2856, 0, + 8, 0, 0, 0, 216, 2876000, 768, 192, 0, 2876, 0, + 9, 0, 0, 0, 216, 2956000, 960, 192, 0, 2956, 0, + 10, 0, 0, 0, 216, 2888000, 1152, 192, 0, 2888, 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, + 12, 0, 0, 0, 216, 2816000, 1536, 192, 0, 2816, 0, + 13, 0, 0, 0, 216, 2468000, 192, 384, 0, 2468, 0, + 14, 0, 0, 0, 216, 3084000, 576, 384, 0, 3084, 0, + 15, 0, 0, 0, 216, 3442000, 960, 384, 0, 3442, 0, + 16, 0, 0, 0, 216, 3478000, 1152, 384, 0, 3478, 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, + 18, 0, 0, 0, 216, 3736000, 1536, 384, 0, 3736, 0, + 19, 0, 0, 0, 216, 3216000, 192, 1152, 0, 3216, 0, + 20, 0, 0, 0, 216, 3308000, 384, 1152, 0, 3308, 0, + 21, 0, 0, 0, 216, 3616000, 768, 1152, 0, 3616, 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] -#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_PANTHERLAKE) - 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] + 23, 0, 0, 0, 216, 4916000, 1536, 1152, 0, 4916, 0, + 24, 0, 0, 0, 216, 3228000, 192, 1152, 0, 3228, 0, + 25, 0, 0, 0, 216, 3452000, 384, 1152, 0, 3452, 0, + 26, 0, 0, 0, 216, 4016000, 768, 1152, 0, 4016, 0, + 27, 0, 0, 0, 216, 5080000, 1536, 1152, 0, 5080, 0, + 28, 0, 0, 0, 216, 3552000, 384, 1536, 0, 3552, 0, + 29, 0, 0, 0, 216, 3728000, 768, 1152, 0, 3728, 0] +#elif CONFIG_LUNARLAKE + mod_cfg = [0, 0, 0, 0, 216, 4153000, 384, 192, 0, 4153, 0, + 1, 0, 0, 0, 216, 3604000, 384, 384, 0, 3604, 0, + 2, 0, 0, 0, 216, 4320000, 576, 384, 0, 4320, 0, + 3, 0, 0, 0, 216, 4436000, 768, 384, 0, 4436, 0, + 4, 0, 0, 0, 216, 7792000, 768, 384, 0, 7792, 0, + 5, 0, 0, 0, 216, 4332000, 768, 384, 0, 4332, 0, + 6, 0, 0, 0, 216, 4412000, 768, 192, 0, 4412, 0, + 7, 0, 0, 0, 216, 4404000, 960, 192, 0, 4404, 0, + 8, 0, 0, 0, 216, 4420000, 1152, 192, 0, 4420, 0, + 9, 0, 0, 0, 216, 4464000, 1536, 192, 0, 4464, 0, + 10, 0, 0, 0, 216, 3616000, 192, 384, 0, 3616, 0, + 11, 0, 0, 0, 216, 4300000, 960, 384, 0, 4300, 0, + 12, 0, 0, 0, 216, 4740000, 1152, 384, 0, 4740, 0, + 13, 0, 0, 0, 216, 4844000, 1536, 384, 0, 4844, 0, + 14, 0, 0, 0, 216, 4660000, 192, 1152, 0, 4660, 0, + 15, 0, 0, 0, 216, 4548000, 384, 1152, 0, 4548, 0, + 16, 0, 0, 0, 216, 4596000, 768, 1152, 0, 4596, 0, + 17, 0, 0, 0, 216, 5572000, 1536, 1152, 0, 5572, 0, + 18, 0, 0, 0, 216, 4896000, 384, 1536, 0, 4896, 0] +#elif CONFIG_SOC_ACE30 || CONFIG_SOC_ACE40 + mod_cfg = [0, 0, 0, 0, 216, 4841000, 384, 192, 0, 4841, 0, + 1, 0, 0, 0, 216, 4355000, 384, 384, 0, 4355, 0, + 2, 0, 0, 0, 216, 5079000, 576, 384, 0, 5079, 0, + 3, 0, 0, 0, 216, 5275000, 768, 384, 0, 5275, 0, + 4, 0, 0, 0, 216, 9177000, 768, 384, 0, 9177, 0, + 5, 0, 0, 0, 216, 5175000, 768, 384, 0, 5175, 0, + 6, 0, 0, 0, 216, 5141000, 768, 192, 0, 5141, 0, + 7, 0, 0, 0, 216, 5207000, 960, 192, 0, 5207, 0, + 8, 0, 0, 0, 216, 5367000, 1152, 192, 0, 5367, 0, + 9, 0, 0, 0, 216, 5485000, 1536, 192, 0, 5485, 0, + 10, 0, 0, 0, 216, 4469000, 192, 384, 0, 4469, 0, + 11, 0, 0, 0, 216, 5185000, 960, 384, 0, 5185, 0, + 12, 0, 0, 0, 216, 5405000, 1152, 384, 0, 5405, 0, + 13, 0, 0, 0, 216, 5691000, 1536, 384, 0, 5691, 0, + 14, 0, 0, 0, 216, 5577000, 192, 1152, 0, 5577, 0, + 15, 0, 0, 0, 216, 5311000, 384, 1152, 0, 5311, 0, + 16, 0, 0, 0, 216, 5323000, 768, 1152, 0, 5323, 0, + 17, 0, 0, 0, 216, 6269000, 1536, 1152, 0, 6269, 0, + 18, 0, 0, 0, 216, 5699000, 384, 1536, 0, 5699, 0] #endif index = __COUNTER__ diff --git a/src/audio/up_down_mixer/up_down_mixer_hifi3.c b/src/audio/up_down_mixer/up_down_mixer_hifi3.c index 259cf5128b9f..87540d02e8e3 100644 --- a/src/audio/up_down_mixer/up_down_mixer_hifi3.c +++ b/src/audio/up_down_mixer/up_down_mixer_hifi3.c @@ -1247,7 +1247,7 @@ void downmix16bit_4ch_mono(struct up_down_mixer_data *cd, const uint8_t * const uint32_t idx3 = get_channel_index(cd->in_channel_map, 2); uint32_t idx4 = get_channel_index(cd->in_channel_map, 3); - uint16_t coeffs[4] = {cd->downmix_coefficients[idx1], + uint16_t coeffs[4] __attribute__((aligned(8))) = {cd->downmix_coefficients[idx1], cd->downmix_coefficients[idx2], cd->downmix_coefficients[idx3], cd->downmix_coefficients[idx4] diff --git a/src/audio/volume/CMakeLists.txt b/src/audio/volume/CMakeLists.txt index 5c5b764b5912..34491132ee2c 100644 --- a/src/audio/volume/CMakeLists.txt +++ b/src/audio/volume/CMakeLists.txt @@ -1,19 +1,22 @@ # SPDX-License-Identifier: BSD-3-Clause -if(CONFIG_COMP_VOLUME) - add_local_sources(sof - volume_generic.c - volume_hifi3.c - volume_hifi4.c - volume_hifi5.c - volume_generic_with_peakvol.c - volume_hifi3_with_peakvol.c - volume_hifi4_with_peakvol.c - volume_hifi5_with_peakvol.c - volume.c) - if(CONFIG_IPC_MAJOR_3) - add_local_sources(sof volume_ipc3.c) - elseif(CONFIG_IPC_MAJOR_4) - add_local_sources(sof volume_ipc4.c) - endif() -endif() \ No newline at end of file +if(CONFIG_COMP_VOLUME STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/volume_llext) + add_dependencies(app volume) +else() + add_local_sources(sof + volume_generic.c + volume_hifi3.c + volume_hifi4.c + volume_hifi5.c + volume_generic_with_peakvol.c + volume_hifi3_with_peakvol.c + volume_hifi4_with_peakvol.c + volume_hifi5_with_peakvol.c + volume.c) + if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof volume_ipc3.c) + elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof volume_ipc4.c) + endif() +endif() diff --git a/src/audio/volume/README.md b/src/audio/volume/README.md new file mode 100644 index 000000000000..c044d73fd11d --- /dev/null +++ b/src/audio/volume/README.md @@ -0,0 +1,24 @@ +# Volume Component Architecture + +This directory contains the Volume control component. + +## Overview + +Applies amplitude modifications to the stream, supporting smooth ramping and muting interfaces configurable by the host. + +## Architecture Diagram + +```mermaid +graph LR + In[Audio Input] --> Mult[Multiplier] + IPC[IPC Control] -.-> Ramp[Ramp Generator] + Ramp --> Mult + Mult --> Out[Audio Output] +``` + +## Configuration and Scripts + +- **Kconfig**: Extensive tuning for the standard volume framework (`COMP_VOLUME`), selecting underlying algorithms (e.g., `COMP_VOLUME_WINDOWS_FADE`, `COMP_VOLUME_LINEAR_RAMP`). Manages sub-settings like querying host telemetry (`COMP_PEAK_VOL`, `PEAK_METER_UPDATE_PERIOD_CHOICE`). +- **CMakeLists.txt**: Extremely versatile linkage resolving general pathways (`volume_generic.c`), custom optimized builds across HIFI pipelines (`volume_hifi3.c`, `volume_hifi4.c`, `volume_hifi5.c`), and dual-path execution logic (`*_with_peakvol.c`). +- **volume.toml**: Registers independent modules `PEAKVOL` (`UUIDREG_STR_VOLUME4`) and `GAIN` (`UUIDREG_STR_GAIN`), outlining explicit memory mapping parameters via platform-dependent constraints. +- **Topology (.conf)**: Derived from `tools/topology/topology2/include/components/volume.conf`, configuring a standard `pga` widget (UUID `7e:67:7e:b7:f4:5f:88:41:af:14:fb:a8:bd:bf:86:82`). Outlines parameters for ramp steps interpolation methods and binds specific ALSA interface elements. diff --git a/src/audio/volume/llext/CMakeLists.txt b/src/audio/volume/llext/CMakeLists.txt index ca33117f0a67..edaeec449450 100644 --- a/src/audio/volume/llext/CMakeLists.txt +++ b/src/audio/volume/llext/CMakeLists.txt @@ -5,9 +5,11 @@ sof_llext_build("volume" SOURCES ../volume_generic.c ../volume_hifi3.c ../volume_hifi4.c + ../volume_hifi5.c ../volume_generic_with_peakvol.c ../volume_hifi3_with_peakvol.c ../volume_hifi4_with_peakvol.c + ../volume_hifi5_with_peakvol.c ../volume.c ../volume_ipc4.c LIB openmodules diff --git a/src/audio/volume/volume.c b/src/audio/volume/volume.c index b3cf42cf116a..a6cff8a09083 100644 --- a/src/audio/volume/volume.c +++ b/src/audio/volume/volume.c @@ -24,7 +24,6 @@ #include <sof/common.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/cpu.h> #include <sof/lib/uuid.h> @@ -222,7 +221,7 @@ static inline int32_t volume_linear_ramp(struct vol_data *cd, int32_t ramp_time, if (!cd->initial_ramp) return cd->tvolume[channel]; - return cd->rvolume[channel] + ramp_time * cd->ramp_coef[channel]; + return sat_int32((int64_t)ramp_time * cd->ramp_coef[channel] + cd->rvolume[channel]); } #endif @@ -415,24 +414,6 @@ void volume_prepare_ramp(struct comp_dev *dev, struct vol_data *cd) cd->vol_ramp_frames = dev->frames / (dev->period / ramp_update_us); } -/** - * \brief Frees volume component. - * \param[in,out] mod Volume processing module handle - - */ -static int volume_free(struct processing_module *mod) -{ - struct vol_data *cd = module_get_private_data(mod); - - comp_dbg(mod->dev, "volume_free()"); - - volume_peak_free(cd); - rfree(cd->vol); - rfree(cd); - - return 0; -} - static void set_linear_ramp_coef(struct vol_data *cd, int chan, bool constant_rate_ramp) { int32_t delta; @@ -469,7 +450,7 @@ static void set_linear_ramp_coef(struct vol_data *cd, int chan, bool constant_ra * be some accumulated error in ramp time the longer * the ramp and the smaller the transition is. */ - coef = (2 * coef / cd->initial_ramp + 1) >> 1; + coef = ((int64_t)coef * 2 / cd->initial_ramp + 1) >> 1; /* Scale coefficient by 1/8, round */ coef = ((coef >> 2) + 1) >> 1; @@ -508,14 +489,14 @@ int volume_set_chan(struct processing_module *mod, int chan, */ if (v < cd->vol_min) { /* No need to fail, just trace the event. */ - comp_warn(mod->dev, "volume_set_chan: Limited request %d to min. %d", + comp_warn(mod->dev, "Limited request %d to min. %d", v, cd->vol_min); v = cd->vol_min; } if (v > cd->vol_max) { /* No need to fail, just trace the event. */ - comp_warn(mod->dev, "volume_set_chan: Limited request %d to max. %d", + comp_warn(mod->dev, "Limited request %d to max. %d", v, cd->vol_max); v = cd->vol_max; } @@ -537,7 +518,6 @@ int volume_set_chan(struct processing_module *mod, int chan, /** * \brief Mutes channel. * \param[in,out] mod Volume processing module handle - * \param[in] chan Channel number. */ void volume_set_chan_mute(struct processing_module *mod, int chan) @@ -554,7 +534,6 @@ void volume_set_chan_mute(struct processing_module *mod, int chan) /** * \brief Unmutes channel. * \param[in,out] mod Volume processing module handle - * \param[in] chan Channel number. */ void volume_set_chan_unmute(struct processing_module *mod, int chan) @@ -570,7 +549,6 @@ void volume_set_chan_unmute(struct processing_module *mod, int chan) /* * \brief Copies and processes stream data. * \param[in,out] mod Volume processing module handle - * \return Error code. */ static int volume_process(struct processing_module *mod, @@ -578,11 +556,12 @@ static int volume_process(struct processing_module *mod, struct output_stream_buffer *output_buffers, int num_output_buffers) { struct vol_data *cd = module_get_private_data(mod); + struct audio_stream *source = input_buffers[0].data; uint32_t avail_frames = input_buffers[0].size; uint32_t frames; int64_t prev_sum = 0; - comp_dbg(mod->dev, "volume_process()"); + comp_dbg(mod->dev, "entry"); while (avail_frames) { #if CONFIG_COMP_PEAK_VOL @@ -593,12 +572,27 @@ static int volume_process(struct processing_module *mod, frames = avail_frames; } else if (cd->ramp_type == SOF_VOLUME_LINEAR_ZC) { /* with ZC ramping look for next ZC offset */ - frames = cd->zc_get(input_buffers[0].data, cd->vol_ramp_frames, &prev_sum); + frames = cd->zc_get(source, cd->vol_ramp_frames, &prev_sum); + /* Align frames count to audio stream constraints. If it rounds to zero + * round it up to smallest nonzero aligned frames count. + */ + frames = audio_stream_align_frames_round_nearest(source, frames); + if (!frames) + frames = audio_stream_align_frames_round_up(source, 1); } else { - /* without ZC process max ramp chunk */ - frames = cd->vol_ramp_frames; + /* During volume ramp align the number of frames used in this + * gain step. Align up since with low rates this would typically + * become zero. + */ + frames = audio_stream_align_frames_round_up(source, cd->vol_ramp_frames); } + /* Cancel the gain step for ZC or smaller ramp step if it exceeds + * the available frames. + */ + if (frames > avail_frames) + frames = avail_frames; + if (!cd->ramp_finished) { volume_ramp(mod); cd->vol_ramp_elapsed_frames += frames; @@ -645,30 +639,37 @@ static vol_zc_func vol_get_zc_function(struct comp_dev *dev, /** * \brief Set volume frames alignment limit. * \param[in,out] source Structure pointer of source. - * \param[in,out] sink Structure pointer of sink. */ -static void volume_set_alignment(struct audio_stream *source, - struct audio_stream *sink) +static void volume_set_alignment(struct audio_stream *source) { - /* Both source and sink buffer in HiFi5 processing version, - * xtensa intrinsics ask for 16-byte aligned. + const int channels = audio_stream_get_channels(source); + + /* The source buffer in HiFi5 processing version needs 16 bytes alignment. The + * macro SOF_FRAME_BYTE_ALIGN is set in common.h to the requirement align. + * The VOLUME_HIFI3_HIFI4_FRAME_BYTE_ALIGN_6CH also has the value 16 and the + * same align for 5.1 channels works for HiFi5 too. * - * Both source and sink buffer in HiFi3 or HiFi4 processing version, - * xtensa intrinsics ask for 8-byte aligned. 5.1 format SSE audio - * requires 16-byte aligned. + * In HiFi4 processing version the source align requirement is 8 bytes. While + * the 5.1 format SSE audio requires 16 bytes alignment. + */ + const uint32_t byte_align = + (channels == 6) ? VOLUME_HIFI3_HIFI4_FRAME_BYTE_ALIGN_6CH : SOF_FRAME_BYTE_ALIGN; + + /* On HiFi5 the number of samples to process must be multiple of four for s24/s32 + * and multiple of eight for s16. For HiFi4 and HiFi3 the number of samples + * need to be multiple of two for s32 and multiple of four for s16. + * E.g. for s32 format for channels counts of 1, 2, 4, 6, ... the + * frame align need to be 4, 2, 1, 2, ... */ -#if SOF_USE_HIFI(3, VOLUME) || SOF_USE_HIFI(4, VOLUME) - const uint32_t byte_align = audio_stream_get_channels(source) == 6 ? - VOLUME_HIFI3_HIFI4_FRAME_BYTE_ALIGN_6CH : SOF_FRAME_BYTE_ALIGN; +#if SOF_USE_HIFI(5, VOLUME) + const int n = (audio_stream_get_valid_fmt(source) == SOF_IPC_FRAME_S16_LE) ? 8 : 4; #else - const uint32_t byte_align = SOF_FRAME_BYTE_ALIGN; + const int n = (audio_stream_get_valid_fmt(source) == SOF_IPC_FRAME_S16_LE) ? 4 : 2; #endif - /*There is no limit for frame number, so both source and sink set it to be 1*/ - const uint32_t frame_align_req = 1; + const uint32_t frame_align_req = (uint32_t)(n / gcd(n, channels)); audio_stream_set_align(byte_align, frame_align_req, source); - audio_stream_set_align(byte_align, frame_align_req, sink); } /** @@ -692,22 +693,26 @@ static int volume_prepare(struct processing_module *mod, int ret; int i; - comp_dbg(dev, "volume_prepare()"); - - ret = volume_peak_prepare(cd, mod); + comp_dbg(dev, "entry"); /* volume component will only ever have 1 sink and source buffer */ sinkb = comp_dev_get_first_data_consumer(dev); sourceb = comp_dev_get_first_data_producer(dev); + if (!sourceb || !sinkb) { + comp_err(dev, "no source or sink buffer"); + return -ENOTCONN; + } + + ret = volume_peak_prepare(cd, mod); - volume_set_alignment(&sourceb->stream, &sinkb->stream); + volume_set_alignment(&sourceb->stream); /* get sink period bytes */ sink_period_bytes = audio_stream_period_bytes(&sinkb->stream, dev->frames); if (audio_stream_get_size(&sinkb->stream) < sink_period_bytes) { - comp_err(dev, "volume_prepare(): sink buffer size %d is insufficient < %d", + comp_err(dev, "sink buffer size %d is insufficient < %d", audio_stream_get_size(&sinkb->stream), sink_period_bytes); ret = -ENOMEM; goto err; @@ -716,7 +721,7 @@ static int volume_prepare(struct processing_module *mod, set_volume_process(cd, dev, false); if (!cd->scale_vol) { - comp_err(dev, "volume_prepare(): invalid cd->scale_vol"); + comp_err(dev, "invalid cd->scale_vol"); ret = -EINVAL; goto err; @@ -724,7 +729,7 @@ static int volume_prepare(struct processing_module *mod, cd->zc_get = vol_get_zc_function(dev, sinkb); if (!cd->zc_get) { - comp_err(dev, "volume_prepare(): invalid cd->zc_get"); + comp_err(dev, "invalid cd->zc_get"); ret = -EINVAL; goto err; } @@ -772,18 +777,34 @@ static int volume_prepare(struct processing_module *mod, /** * \brief Resets volume component. * \param[in,out] mod Volume processing module handle - * \return Error code. */ static int volume_reset(struct processing_module *mod) { struct vol_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "volume_reset()"); + comp_dbg(mod->dev, "entry"); volume_reset_state(cd); return 0; } +/** + * \brief Frees volume component. + * \param[in,out] mod Volume processing module handle + */ +static int volume_free(struct processing_module *mod) +{ + struct vol_data *cd = module_get_private_data(mod); + + comp_dbg(mod->dev, "entry"); + + volume_peak_free(mod); + mod_free(mod, cd->vol); + mod_free(mod, cd); + + return 0; +} + static const struct module_interface volume_interface = { .init = volume_init, .prepare = volume_prepare, @@ -794,9 +815,6 @@ static const struct module_interface volume_interface = { .free = volume_free }; -DECLARE_MODULE_ADAPTER(volume_interface, volume_uuid, volume_tr); -SOF_MODULE_INIT(volume, sys_comp_module_volume_interface_init); - #if CONFIG_COMP_GAIN static const struct module_interface gain_interface = { .init = volume_init, @@ -807,9 +825,6 @@ static const struct module_interface gain_interface = { .reset = volume_reset, .free = volume_free }; - -DECLARE_MODULE_ADAPTER(gain_interface, gain_uuid, gain_tr); -SOF_MODULE_INIT(gain, sys_comp_module_gain_interface_init); #endif #if CONFIG_COMP_VOLUME_MODULE @@ -819,26 +834,25 @@ SOF_MODULE_INIT(gain, sys_comp_module_gain_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#if CONFIG_COMP_PEAK_VOL -#define UUID_PEAKVOL 0x23, 0x13, 0x17, 0x8a, 0xa3, 0x94, 0x1d, 0x4e, \ - 0xaf, 0xe9, 0xfe, 0x5d, 0xba, 0xa4, 0xc3, 0x93 -SOF_LLEXT_MOD_ENTRY(peakvol, &volume_interface); -#endif - -#if CONFIG_COMP_GAIN -#define UUID_GAIN 0xa8, 0xa9, 0xbc, 0x61, 0xd0, 0x18, 0x18, 0x4a, \ - 0x8e, 0x7b, 0x26, 0x39, 0x21, 0x98, 0x04, 0xb7 -SOF_LLEXT_MOD_ENTRY(gain, &gain_interface); -#endif - static const struct sof_man_module_manifest mod_manifest[] __section(".module") __used = { #if CONFIG_COMP_PEAK_VOL - SOF_LLEXT_MODULE_MANIFEST("PEAKVOL", peakvol_llext_entry, 1, UUID_PEAKVOL, 10), + SOF_LLEXT_MODULE_MANIFEST("PEAKVOL", &volume_interface, 1, SOF_REG_UUID(volume4), 10), #endif #if CONFIG_COMP_GAIN - SOF_LLEXT_MODULE_MANIFEST("GAIN", gain_llext_entry, 1, UUID_GAIN, 40), + SOF_LLEXT_MODULE_MANIFEST("GAIN", &gain_interface, 1, SOF_REG_UUID(gain), 40), #endif }; SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_MODULE_ADAPTER(volume_interface, volume_uuid, volume_tr); +SOF_MODULE_INIT(volume, sys_comp_module_volume_interface_init); + +#if CONFIG_COMP_GAIN +DECLARE_MODULE_ADAPTER(gain_interface, gain_uuid, gain_tr); +SOF_MODULE_INIT(gain, sys_comp_module_gain_interface_init); +#endif + #endif diff --git a/src/audio/volume/volume.h b/src/audio/volume/volume.h index 19d23798b962..9d1d08a280fe 100644 --- a/src/audio/volume/volume.h +++ b/src/audio/volume/volume.h @@ -43,17 +43,24 @@ struct sof_ipc_ctrl_value_chan; //** \brief Volume gain Qx.y */ #define COMP_VOLUME_Q8_16 1 -//** \brief Volume gain Qx.y integer x number of bits including sign bit. */ -#define VOL_QXY_X 8 - -//** \brief Volume gain Qx.y fractional y number of bits. */ -#define VOL_QXY_Y 16 - #else //** \brief Volume gain Qx.y */ -#define COMP_VOLUME_Q1_23 1 +#define COMP_VOLUME_Q1_31 1 + +#endif +#if COMP_VOLUME_Q1_31 +/** \brief Volume gain Qx.y integer x number of bits including sign bit. + * With Q8.23 format the gain range is -138.47 to +42.14 dB. + */ +#define VOL_QXY_X 1 + +//** \brief Volume gain Qx.y fractional y number of bits. */ +#define VOL_QXY_Y 31 + +#define VOLUME_Q17_47_SHIFT 0 +#elif COMP_VOLUME_Q1_23 /** \brief Volume gain Qx.y integer x number of bits including sign bit. * With Q8.23 format the gain range is -138.47 to +42.14 dB. */ @@ -62,6 +69,19 @@ struct sof_ipc_ctrl_value_chan; //** \brief Volume gain Qx.y fractional y number of bits. */ #define VOL_QXY_Y 23 +#define VOLUME_Q17_47_SHIFT 8 + +#elif COMP_VOLUME_Q8_16 +//** \brief Volume gain Qx.y integer x number of bits including sign bit. */ +#define VOL_QXY_X 8 + +//** \brief Volume gain Qx.y fractional y number of bits. */ +#define VOL_QXY_Y 16 + +#define VOLUME_Q17_47_SHIFT 15 + +#else +#error "Need CONFIG_COMP_VOLUME_Qx_y" #endif /** @@ -92,16 +112,22 @@ struct sof_ipc_ctrl_value_chan; */ #define PEAK_16S_32C_ADJUST 16 -/** - * \brief Volume maximum value. - * TODO: This should be 1 << (VOL_QX_BITS + VOL_QY_BITS - 1) - 1 but - * the current volume code cannot handle the full Q1.16 range correctly. - */ +#if COMP_VOLUME_Q1_31 +/** \brief Volume maximum value. */ +#define VOL_MAX INT32_MAX + +/** \brief Volume 0dB value. */ +#define VOL_ZERO_DB INT32_MAX + +#else +/** \brief Volume maximum value. */ #define VOL_MAX ((1 << (VOL_QXY_X + VOL_QXY_Y - 1)) - 1) /** \brief Volume 0dB value. */ #define VOL_ZERO_DB BIT(VOL_QXY_Y) +#endif + /** \brief Volume minimum value. */ #define VOL_MIN 0 @@ -238,7 +264,7 @@ static inline vol_scale_func vol_get_processing_function(struct comp_dev *dev, case IPC4_DEPTH_32BIT: return volume_func_map[2].passthrough_func; default: - comp_err(dev, "vol_get_processing_function(): unsupported depth %d", + comp_err(dev, "unsupported depth %d", mod->priv.cfg.base_cfg.audio_fmt.depth); return NULL; } @@ -251,7 +277,7 @@ static inline vol_scale_func vol_get_processing_function(struct comp_dev *dev, case IPC4_DEPTH_32BIT: return volume_func_map[2].func; default: - comp_err(dev, "vol_get_processing_function(): unsupported depth %d", + comp_err(dev, "unsupported depth %d", mod->priv.cfg.base_cfg.audio_fmt.depth); return NULL; } @@ -274,7 +300,7 @@ void sys_comp_module_volume_interface_init(void); /* source_or_sink, true means source, false means sink */ void set_volume_process(struct vol_data *cd, struct comp_dev *dev, bool source_or_sink); -void volume_peak_free(struct vol_data *cd); +void volume_peak_free(struct processing_module *mod); int volume_peak_prepare(struct vol_data *cd, struct processing_module *mod); diff --git a/src/audio/volume/volume.toml b/src/audio/volume/volume.toml index 7ba4fc53ae83..0c30281def81 100644 --- a/src/audio/volume/volume.toml +++ b/src/audio/volume/volume.toml @@ -5,7 +5,7 @@ #if CONFIG_COMP_PEAK_VOL [[module.entry]] name = "PEAKVOL" - uuid = "8A171323-94A3-4E1D-AFE9-FE5DBAA4C393" + uuid = UUIDREG_STR_VOLUME4 affinity_mask = "0x1" instance_count = "10" domain_types = "0" @@ -20,19 +20,23 @@ REM # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] #if CONFIG_METEORLAKE - 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] -#elif CONFIG_LUNARLAKE || CONFIG_PANTHERLAKE - 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] + mod_cfg = [0, 0, 0, 0, 480, 11667000, 384, 384, 0, 11667, 0, + 1, 0, 0, 0, 480, 5943000, 192, 192, 0, 5943, 0, + 2, 0, 0, 0, 480, 12567000, 720, 720, 0, 12567, 0, + 3, 0, 0, 0, 480, 7360000, 768, 768, 0, 7360, 0, + 4, 0, 0, 0, 480, 12236000, 1536, 1536, 0, 12236, 0] +#elif CONFIG_LUNARLAKE + mod_cfg = [0, 0, 0, 0, 480, 5546000, 384, 384, 0, 5546, 0, + 1, 0, 0, 0, 480, 4966000, 192, 192, 0, 4966, 0, + 2, 0, 0, 0, 480, 6846000, 720, 720, 0, 6846, 0, + 3, 0, 0, 0, 480, 7212000, 768, 768, 0, 7212, 0, + 4, 0, 0, 0, 480, 9532000, 1536, 1536, 0, 9532, 0] +#elif CONFIG_SOC_ACE30 || CONFIG_SOC_ACE40 + mod_cfg = [0, 0, 0, 0, 480, 6993000, 384, 384, 0, 6993, 0, + 1, 0, 0, 0, 480, 6385000, 192, 192, 0, 6385, 0, + 2, 0, 0, 0, 480, 10887000, 720, 720, 0, 10887, 0, + 3, 0, 0, 0, 480, 10575000, 768, 768, 0, 10575, 0, + 4, 0, 0, 0, 480, 11897000, 1536, 1536, 0, 11897, 0] #endif index = __COUNTER__ @@ -41,7 +45,7 @@ #if CONFIG_COMP_GAIN [[module.entry]] name = "GAIN" - uuid = "61BCA9A8-18D0-4A18-8E7B-2639219804B7" + uuid = UUIDREG_STR_GAIN affinity_mask = "0x1" instance_count = "40" domain_types = "0" @@ -56,19 +60,22 @@ REM # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] #if CONFIG_METEORLAKE - 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] -#elif CONFIG_LUNARLAKE || CONFIG_PANTHERLAKE - 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] + mod_cfg = [0, 0, 0, 0, 416, 12100000, 1536, 1536, 0, 12100, 0, + 1, 0, 0, 0, 416, 10183000, 384, 384, 0, 10183, 0, + 2, 0, 0, 0, 416, 8192000, 512, 512, 0, 8192, 0, + 3, 0, 0, 0, 416, 10091000, 128, 128, 0, 10091, 0, + 4, 0, 0, 0, 416, 5908000, 768, 768, 0, 5908, 0] +#elif CONFIG_LUNARLAKE + mod_cfg = [0, 0, 0, 0, 416, 9525000, 1536, 1536, 0, 9525, 0, + 1, 0, 0, 0, 416, 6266000, 384, 384, 0, 6266, 0, + 2, 0, 0, 0, 416, 7882000, 512, 512, 0, 7882, 0, + 3, 0, 0, 0, 416, 5170000, 128, 128, 0, 5170, 0, + 4, 0, 0, 0, 416, 5908000, 768, 768, 0, 0, 0] +#elif CONFIG_SOC_ACE30 || CONFIG_SOC_ACE40 + mod_cfg = [0, 0, 0, 0, 416, 11865000, 1536, 1536, 0, 11865, 0, + 1, 0, 0, 0, 416, 7797000, 384, 384, 1, 7797, 1, + 2, 0, 0, 0, 416, 12083000, 512, 512, 2, 12083, 2, + 3, 0, 0, 0, 416, 7163000, 128, 128, 3, 7163, 3] #endif index = __COUNTER__ diff --git a/src/audio/volume/volume_hifi3.c b/src/audio/volume/volume_hifi3.c index 5f3d7f2275f3..afbb8ff44c02 100644 --- a/src/audio/volume/volume_hifi3.c +++ b/src/audio/volume/volume_hifi3.c @@ -63,14 +63,14 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea struct vol_data *cd = module_get_private_data(mod); 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(); + ae_f32x2 in_sample; + ae_f32x2 out_sample; + ae_f32x2 volume; ae_f32x2 *buf; ae_f32x2 *buf_end; int i, n, m; ae_f32x2 *vol; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f32x2 *in = (ae_f32x2 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); @@ -114,14 +114,15 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea /* Multiply the input sample */ #if COMP_VOLUME_Q8_16 out_sample = AE_MULFP32X2RS(AE_SLAI32S(volume, 7), AE_SLAI32(in_sample, 8)); + out_sample = AE_SLAI32S(out_sample, 8); #elif COMP_VOLUME_Q1_23 out_sample = AE_MULFP32X2RS(volume, AE_SLAI32(in_sample, 8)); -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" + out_sample = AE_SLAI32S(out_sample, 8); +#elif COMP_VOLUME_Q1_31 + out_sample = AE_MULFP32X2RS(volume, AE_SLAI32(in_sample, 8)); #endif - /* Shift for S24_LE */ - out_sample = AE_SLAI32S(out_sample, 8); + /* Shift to S24_LE */ out_sample = AE_SRAI32(out_sample, 8); /* Store the output sample */ @@ -149,9 +150,9 @@ static void vol_passthrough_s24_to_s24_s32(struct processing_module *mod, { struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f32x2 in_sample = AE_ZERO32(); + ae_f32x2 in_sample; int i, n, m; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f32x2 *in = (ae_f32x2 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); @@ -200,16 +201,14 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea struct vol_data *cd = module_get_private_data(mod); 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(); + ae_f32x2 in_sample; + ae_f32x2 out_sample; + ae_f32x2 volume; int i, n, m; - ae_f64 mult0; - ae_f64 mult1; ae_f32x2 *buf; ae_f32x2 *buf_end; ae_f32x2 *vol; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); const int channels_count = audio_stream_get_channels(sink); const int inc = sizeof(ae_f32x2); @@ -249,23 +248,19 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea /* Load the input sample */ AE_LA32X2_IP(in_sample, inu, in); - -#if COMP_VOLUME_Q8_16 - /* Q8.16 x Q1.31 << 1 -> Q9.48 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 1); /* Q9.47 */ - mult1 = AE_MULF32S_LL(volume, in_sample); - mult1 = AE_SRAI64(mult1, 1); - out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q9.47 -> Q1.31 */ -#elif COMP_VOLUME_Q1_23 - /* Q1.23 x Q1.31 << 1 -> Q2.55 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 8); /* Q2.47 */ - mult1 = AE_MULF32S_LL(volume, in_sample); - mult1 = AE_SRAI64(mult1, 8); - out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ +#if COMP_VOLUME_Q1_31 + out_sample = AE_MULFP32X2RS(volume, in_sample); #else -#error "Need CONFIG_COMP_VOLUME_Qx_y" + /* With Q1.31 x Q1.31 -> Q17.47 HiFi multiplications the result is + * Q8.16 x Q1.31 << 1 >> 16 -> Q9.32, shift left by 15 for Q17.47 + * Q1.23 x Q1.31 << 1 >> 16 -> Q2.39, shift left by 8 for Q17.47 + */ + ae_f64 mult0 = AE_MULF32R_HH(volume, in_sample); + ae_f64 mult1 = AE_MULF32R_LL(volume, in_sample); + + mult0 = AE_SLAI64(mult0, VOLUME_Q17_47_SHIFT); + mult1 = AE_SLAI64(mult1, VOLUME_Q17_47_SHIFT); + out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ #endif AE_SA32X2_IP(out_sample, outu, out); } @@ -291,9 +286,9 @@ static void vol_passthrough_s32_to_s24_s32(struct processing_module *mod, { struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f32x2 in_sample = AE_ZERO32(); + ae_f32x2 in_sample; int i, n, m; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); const int channels_count = audio_stream_get_channels(sink); int samples = channels_count * frames; @@ -341,17 +336,17 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu struct vol_data *cd = module_get_private_data(mod); 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(); - ae_f32x2 out_sample1 = AE_ZERO32(); - ae_f16x4 in_sample = AE_ZERO16(); - ae_f16x4 out_sample = AE_ZERO16(); + ae_f32x2 volume0; + ae_f32x2 volume1; + ae_f32x2 out_sample0; + ae_f32x2 out_sample1; + ae_f16x4 in_sample; + ae_f16x4 out_sample; int i, n, m; ae_f32x2 *buf; ae_f32x2 *buf_end; ae_f32x2 *vol; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f16x4 *in = (ae_f16x4 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); @@ -389,18 +384,20 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu /* load second two volume gain */ AE_L32X2_XC(volume1, vol, inc); + /* Load the input sample */ + AE_LA16X4_IP(in_sample, inu, in); + +#if COMP_VOLUME_Q1_31 + out_sample0 = AE_MULFP32X16X2RS_H(volume0, in_sample); + out_sample1 = AE_MULFP32X16X2RS_L(volume1, in_sample); +#else #if COMP_VOLUME_Q8_16 - /* Q8.16 to Q9.23 */ + /* Shift Q8.16 to Q9.23 + * No need to shift Q1.23, it is OK as such + */ volume0 = AE_SLAI32S(volume0, 7); volume1 = AE_SLAI32S(volume1, 7); -#elif COMP_VOLUME_Q1_23 - /* No need to shift, Q1.23 is OK as such */ -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" #endif - /* Load the input sample */ - AE_LA16X4_IP(in_sample, inu, in); - /* Multiply the input sample */ out_sample0 = AE_MULFP32X16X2RS_H(volume0, in_sample); out_sample1 = AE_MULFP32X16X2RS_L(volume1, in_sample); @@ -408,6 +405,7 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu /* Q9.23 to Q1.31 */ out_sample0 = AE_SLAI32S(out_sample0, 8); out_sample1 = AE_SLAI32S(out_sample1, 8); +#endif /* store the output */ out_sample = AE_ROUND16X4F32SSYM(out_sample0, out_sample1); @@ -438,9 +436,9 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, { struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f16x4 in_sample = AE_ZERO16(); + ae_f16x4 in_sample; int i, n, m; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f16x4 *in = (ae_f16x4 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); diff --git a/src/audio/volume/volume_hifi3_with_peakvol.c b/src/audio/volume/volume_hifi3_with_peakvol.c index f645c5a903a1..4f89330baca7 100644 --- a/src/audio/volume/volume_hifi3_with_peakvol.c +++ b/src/audio/volume/volume_hifi3_with_peakvol.c @@ -43,9 +43,9 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea struct vol_data *cd = module_get_private_data(mod); 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(); + ae_f32x2 in_sample; + ae_f32x2 out_sample; + ae_f32x2 volume; int channel, n, i, m; ae_f32 *in0 = (ae_f32 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); @@ -78,17 +78,20 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea AE_L32_XP(in_sample, in, inc); /* calc peak vol */ peak_vol = AE_MAXABS32S(in_sample, peak_vol); -#if COMP_VOLUME_Q8_16 + /* Multiply the input sample */ +#if COMP_VOLUME_Q8_16 out_sample = AE_MULFP32X2RS(AE_SLAI32S(volume, 7), AE_SLAI32(in_sample, 8)); + out_sample = AE_SLAI32S(out_sample, 8); #elif COMP_VOLUME_Q1_23 - out_sample = AE_MULFP32X2RS(volume, AE_SLAI32S(in_sample, 8)); -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" -#endif - /* Shift for S24_LE */ + out_sample = AE_MULFP32X2RS(volume, AE_SLAI32(in_sample, 8)); out_sample = AE_SLAI32S(out_sample, 8); +#elif COMP_VOLUME_Q1_31 + out_sample = AE_MULFP32X2RS(volume, AE_SLAI32(in_sample, 8)); +#endif + + /* Shift to S24_LE */ out_sample = AE_SRAI32(out_sample, 8); /* Store the output sample */ AE_S32_L_XP(out_sample, out, inc); @@ -118,7 +121,7 @@ static void vol_passthrough_s24_to_s24_s32(struct processing_module *mod, struct vol_data *cd = module_get_private_data(mod); struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f32x2 in_sample = AE_ZERO32(); + ae_f32x2 in_sample; int channel, n, i, m; ae_f32 *in0 = (ae_f32 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); @@ -178,11 +181,10 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea struct vol_data *cd = module_get_private_data(mod); 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(); + ae_f32x2 in_sample; + ae_f32x2 out_sample; + ae_f32x2 volume; int i, n, channel, m; - ae_f64 mult0; const int channels_count = audio_stream_get_channels(sink); const int inc = sizeof(ae_f32) * channels_count; int samples = channels_count * frames; @@ -214,19 +216,20 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea AE_L32_XP(in_sample, in, inc); /* calc peak vol */ peak_vol = AE_MAXABS32S(in_sample, peak_vol); -#if COMP_VOLUME_Q8_16 - /* Q8.16 x Q1.31 << 1 -> Q9.48 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 1); /* Q9.47 */ - out_sample = AE_ROUND32F48SASYM(mult0); /* Q9.47 -> Q1.31 */ -#elif COMP_VOLUME_Q1_23 - /* Q1.23 x Q1.31 << 1 -> Q2.55 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 8); /* Q2.47 */ - out_sample = AE_ROUND32F48SSYM(mult0); /* Q2.47 -> Q1.31 */ + +#if COMP_VOLUME_Q1_31 + out_sample = AE_MULFP32X2RS(volume, in_sample); #else -#error "Need CONFIG_COMP_VOLUME_Qx_y" + /* With Q1.31 x Q1.31 -> Q17.47 HiFi multiplications the result is + * Q8.16 x Q1.31 << 1 >> 16 -> Q9.32, shift left by 15 for Q17.47 + * Q1.23 x Q1.31 << 1 >> 16 -> Q2.39, shift left by 8 for Q17.47 + */ + ae_f64 mult0 = AE_MULF32R_HH(volume, in_sample); + + mult0 = AE_SLAI64(mult0, VOLUME_Q17_47_SHIFT); + out_sample = AE_ROUND32F48SSYM(mult0); /* Q2.47 -> Q1.31 */ #endif + AE_S32_L_XP(out_sample, out, inc); } peak_vol = AE_SLAA32S(peak_vol, attenuation); @@ -254,7 +257,7 @@ static void vol_passthrough_s32_to_s24_s32(struct processing_module *mod, struct vol_data *cd = module_get_private_data(mod); struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f32x2 in_sample = AE_ZERO32(); + ae_f32x2 in_sample; int i, n, channel, m; const int channels_count = audio_stream_get_channels(sink); const int inc = sizeof(ae_f32) * channels_count; @@ -314,10 +317,10 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu struct vol_data *cd = module_get_private_data(mod); 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(); - ae_f16x4 out_sample = AE_ZERO16(); + ae_f32x2 volume; + ae_f32x2 out_sample0; + ae_f16x4 in_sample; + ae_f16x4 out_sample; int i, n, channel, m; ae_f16 *in; ae_f16 *out; @@ -345,12 +348,10 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu /* Load volume */ volume = (ae_f32x2)cd->volume[channel]; #if COMP_VOLUME_Q8_16 - /* Q8.16 to Q9.23 */ + /* Shift Q8.16 to Q9.23 + * No need to shift Q1.23, it is OK as such + */ volume = AE_SLAI32S(volume, 7); -#elif COMP_VOLUME_Q1_23 - /* No need to shift, Q1.23 is OK as such */ -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" #endif for (i = 0; i < n; i += channels_count) { /* Load the input sample */ @@ -361,8 +362,12 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu /* Multiply the input sample */ out_sample0 = AE_MULFP32X16X2RS_H(volume, in_sample); +#if COMP_VOLUME_Q1_31 + /* No shift need, the product is Q1.31 */ +#else /* Q9.23 to Q1.31 */ out_sample0 = AE_SLAI32S(out_sample0, 8); +#endif /* store the output */ out_sample = AE_ROUND16X4F32SSYM(out_sample0, out_sample0); @@ -396,7 +401,7 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, struct vol_data *cd = module_get_private_data(mod); struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f16x4 in_sample = AE_ZERO16(); + ae_f16x4 in_sample; int i, n, channel, m; ae_f16 *in; ae_f16 *out; diff --git a/src/audio/volume/volume_hifi4.c b/src/audio/volume/volume_hifi4.c index 6acecb2fb9b5..2f879a31ec0e 100644 --- a/src/audio/volume/volume_hifi4.c +++ b/src/audio/volume/volume_hifi4.c @@ -63,14 +63,14 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea struct vol_data *cd = module_get_private_data(mod); 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(); + ae_f32x2 in_sample; + ae_f32x2 out_sample; + ae_f32x2 volume; ae_f32x2 *buf; ae_f32x2 *buf_end; int i, n, m; ae_f32x2 *vol; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f32x2 *in = (ae_f32x2 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); @@ -114,14 +114,15 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea /* Multiply the input sample */ #if COMP_VOLUME_Q8_16 out_sample = AE_MULFP32X2RS(AE_SLAI32S(volume, 7), AE_SLAI32(in_sample, 8)); + out_sample = AE_SLAI32S(out_sample, 8); #elif COMP_VOLUME_Q1_23 out_sample = AE_MULFP32X2RS(volume, AE_SLAI32(in_sample, 8)); -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" + out_sample = AE_SLAI32S(out_sample, 8); +#elif COMP_VOLUME_Q1_31 + out_sample = AE_MULFP32X2RS(volume, AE_SLAI32(in_sample, 8)); #endif - /* Shift for S24_LE */ - out_sample = AE_SLAI32S(out_sample, 8); + /* Shift to S24_LE */ out_sample = AE_SRAI32(out_sample, 8); /* Store the output sample */ @@ -149,9 +150,9 @@ static void vol_passthrough_s24_to_s24_s32(struct processing_module *mod, { struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f32x2 in_sample = AE_ZERO32(); + ae_f32x2 in_sample; int i, n, m; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f32x2 *in = (ae_f32x2 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); @@ -200,16 +201,14 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea struct vol_data *cd = module_get_private_data(mod); 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(); + ae_f32x2 in_sample; + ae_f32x2 out_sample; + ae_f32x2 volume; int i, n, m; - ae_f64 mult0; - ae_f64 mult1; ae_f32x2 *buf; ae_f32x2 *buf_end; ae_f32x2 *vol; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); const int channels_count = audio_stream_get_channels(sink); const int inc = sizeof(ae_f32x2); @@ -250,23 +249,21 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea /* Load the input sample */ AE_LA32X2_IP(in_sample, inu, in); -#if COMP_VOLUME_Q8_16 - /* Q8.16 x Q1.31 << 1 -> Q9.48 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 1); /* Q9.47 */ - mult1 = AE_MULF32S_LL(volume, in_sample); - mult1 = AE_SRAI64(mult1, 1); - out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q9.47 -> Q1.31 */ -#elif COMP_VOLUME_Q1_23 - /* Q1.23 x Q1.31 << 1 -> Q2.55 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 8); /* Q2.47 */ - mult1 = AE_MULF32S_LL(volume, in_sample); - mult1 = AE_SRAI64(mult1, 8); - out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ +#if COMP_VOLUME_Q1_31 + out_sample = AE_MULFP32X2RS(volume, in_sample); #else -#error "Need CONFIG_COMP_VOLUME_Qx_y" + /* With Q1.31 x Q1.31 -> Q17.47 HiFi multiplications the result is + * Q8.16 x Q1.31 << 1 >> 16 -> Q9.32, shift left by 15 for Q17.47 + * Q1.23 x Q1.31 << 1 >> 16 -> Q2.39, shift left by 8 for Q17.47 + */ + ae_f64 mult0 = AE_MULF32R_HH(volume, in_sample); + ae_f64 mult1 = AE_MULF32R_LL(volume, in_sample); + + mult0 = AE_SLAI64(mult0, VOLUME_Q17_47_SHIFT); + mult1 = AE_SLAI64(mult1, VOLUME_Q17_47_SHIFT); + out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ #endif + AE_SA32X2_IP(out_sample, outu, out); } AE_SA64POS_FP(outu, out); @@ -291,9 +288,9 @@ static void vol_passthrough_s32_to_s24_s32(struct processing_module *mod, { struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f32x2 in_sample = AE_ZERO32(); + ae_f32x2 in_sample; int i, n, m; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); const int channels_count = audio_stream_get_channels(sink); int samples = channels_count * frames; @@ -340,17 +337,17 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu struct vol_data *cd = module_get_private_data(mod); 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(); - ae_f32x2 out_sample1 = AE_ZERO32(); - ae_f16x4 in_sample = AE_ZERO16(); - ae_f16x4 out_sample = AE_ZERO16(); + ae_f32x2 volume0; + ae_f32x2 volume1; + ae_f32x2 out_sample0; + ae_f32x2 out_sample1; + ae_f16x4 in_sample; + ae_f16x4 out_sample; int i, n, m, left; ae_f32x2 *buf; ae_f32x2 *buf_end; ae_f32x2 *vol; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f16x4 *in = (ae_f16x4 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); @@ -391,18 +388,20 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu /* load second two volume gain */ AE_L32X2_XC(volume1, vol, inc); + /* Load the input sample */ + AE_LA16X4_IP(in_sample, inu, in); + +#if COMP_VOLUME_Q1_31 + out_sample0 = AE_MULFP32X16X2RS_H(volume0, in_sample); + out_sample1 = AE_MULFP32X16X2RS_L(volume1, in_sample); +#else #if COMP_VOLUME_Q8_16 - /* Q8.16 to Q9.23 */ + /* Shift Q8.16 to Q9.23 + * No need to shift Q1.23, it is OK as such + */ volume0 = AE_SLAI32S(volume0, 7); volume1 = AE_SLAI32S(volume1, 7); -#elif COMP_VOLUME_Q1_23 - /* No need to shift, Q1.23 is OK as such */ -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" #endif - /* Load the input sample */ - AE_LA16X4_IP(in_sample, inu, in); - /* Multiply the input sample */ out_sample0 = AE_MULFP32X16X2RS_H(volume0, in_sample); out_sample1 = AE_MULFP32X16X2RS_L(volume1, in_sample); @@ -410,6 +409,7 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu /* Q9.23 to Q1.31 */ out_sample0 = AE_SLAI32S(out_sample0, 8); out_sample1 = AE_SLAI32S(out_sample1, 8); +#endif /* store the output */ out_sample = AE_ROUND16X4F32SSYM(out_sample0, out_sample1); @@ -421,16 +421,21 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu for (i = 0; i < left; i++) { /* load volume gain */ AE_L32_XC(volume0, (ae_f32 *)vol, sizeof(ae_f32)); + /* Load the input sample */ + AE_L16_IP(in_sample, (ae_f16 *)in, sizeof(ae_f16)); +#if COMP_VOLUME_Q1_31 + /* Multiply the input sample */ + out_sample0 = AE_MULFP32X16X2RS_H(volume0, in_sample); +#else #if COMP_VOLUME_Q8_16 /* Q8.16 to Q9.23 */ volume0 = AE_SLAI32S(volume0, 7); #endif - /* Load the input sample */ - AE_L16_IP(in_sample, (ae_f16 *)in, sizeof(ae_f16)); /* Multiply the input sample */ out_sample0 = AE_MULFP32X16X2RS_H(volume0, in_sample); /* Q9.23 to Q1.31 */ out_sample0 = AE_SLAI32S(out_sample0, 8); +#endif /* store the output */ out_sample = AE_ROUND16X4F32SSYM(out_sample0, out_sample0); AE_S16_0_IP(out_sample, (ae_f16 *)out, sizeof(ae_f16)); @@ -459,9 +464,9 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, { struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f16x4 in_sample = AE_ZERO16(); + ae_f16x4 in_sample; int i, n, m, left; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f16x4 *in = (ae_f16x4 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); diff --git a/src/audio/volume/volume_hifi4_with_peakvol.c b/src/audio/volume/volume_hifi4_with_peakvol.c index 75e95d2e7dca..f3908ee1a8a0 100644 --- a/src/audio/volume/volume_hifi4_with_peakvol.c +++ b/src/audio/volume/volume_hifi4_with_peakvol.c @@ -56,12 +56,12 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea struct vol_data *cd = module_get_private_data(mod); 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(); + ae_f32x2 in_sample; + ae_f32x2 out_sample; + ae_f32x2 volume; int i, n, m; ae_f32x2 *vol; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f32x2 *in = (ae_f32x2 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); @@ -109,17 +109,18 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea AE_L32X2_XC1(temp, peakvol, 0); temp = AE_MAXABS32S(in_sample, temp); AE_S32X2_XC1(temp, peakvol, inc); - /* Multiply the input sample */ + #if COMP_VOLUME_Q8_16 out_sample = AE_MULFP32X2RS(AE_SLAI32S(volume, 7), AE_SLAI32(in_sample, 8)); + out_sample = AE_SLAI32S(out_sample, 8); #elif COMP_VOLUME_Q1_23 out_sample = AE_MULFP32X2RS(volume, AE_SLAI32(in_sample, 8)); -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" + out_sample = AE_SLAI32S(out_sample, 8); +#elif COMP_VOLUME_Q1_31 + out_sample = AE_MULFP32X2RS(volume, AE_SLAI32(in_sample, 8)); #endif - /* Shift for S24_LE */ - out_sample = AE_SLAI32S(out_sample, 8); + /* Shift to S24_LE */ out_sample = AE_SRAI32(out_sample, 8); /* Store the output sample */ @@ -152,10 +153,10 @@ static void vol_passthrough_s24_to_s24_s32(struct processing_module *mod, struct vol_data *cd = module_get_private_data(mod); struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f32x2 in_sample = AE_ZERO32(); + ae_f32x2 in_sample; int i, n, m; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f32x2 *in = (ae_f32x2 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); @@ -219,16 +220,14 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea struct vol_data *cd = module_get_private_data(mod); 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(); + ae_f32x2 in_sample; + ae_f32x2 out_sample; + ae_f32x2 volume; int i, n, m; - ae_f64 mult0; - ae_f64 mult1; ae_f32x2 *buf; ae_f32x2 *buf_end; ae_f32x2 *vol; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); const int channels_count = audio_stream_get_channels(sink); const int inc = sizeof(ae_f32x2); @@ -278,23 +277,22 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea AE_L32X2_XC1(temp, peakvol, 0); temp = AE_MAXABS32S(in_sample, temp); AE_S32X2_XC1(temp, peakvol, inc); -#if COMP_VOLUME_Q8_16 - /* Q8.16 x Q1.31 << 1 -> Q9.48 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 1); /* Q9.47 */ - mult1 = AE_MULF32S_LL(volume, in_sample); - mult1 = AE_SRAI64(mult1, 1); - out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q9.47 -> Q1.31 */ -#elif COMP_VOLUME_Q1_23 - /* Q1.23 x Q1.31 << 1 -> Q2.55 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 8); /* Q2.47 */ - mult1 = AE_MULF32S_LL(volume, in_sample); - mult1 = AE_SRAI64(mult1, 8); - out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ + +#if COMP_VOLUME_Q1_31 + out_sample = AE_MULFP32X2RS(volume, in_sample); #else -#error "Need CONFIG_COMP_VOLUME_Qx_y" + /* With Q1.31 x Q1.31 -> Q17.47 HiFi multiplications the result is + * Q8.16 x Q1.31 << 1 >> 16 -> Q9.32, shift left by 15 for Q17.47 + * Q1.23 x Q1.31 << 1 >> 16 -> Q2.39, shift left by 8 for Q17.47 + */ + ae_f64 mult0 = AE_MULF32R_HH(volume, in_sample); + ae_f64 mult1 = AE_MULF32R_LL(volume, in_sample); + + mult0 = AE_SLAI64(mult0, VOLUME_Q17_47_SHIFT); + mult1 = AE_SLAI64(mult1, VOLUME_Q17_47_SHIFT); + out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ #endif + AE_SA32X2_IP(out_sample, outu, out); } AE_SA64POS_FP(outu, out); @@ -323,9 +321,9 @@ static void vol_passthrough_s32_to_s24_s32(struct processing_module *mod, struct vol_data *cd = module_get_private_data(mod); struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f32x2 in_sample = AE_ZERO32(); + ae_f32x2 in_sample; int i, n, m; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); const int channels_count = audio_stream_get_channels(sink); const int inc = sizeof(ae_f32x2); @@ -387,17 +385,17 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu struct vol_data *cd = module_get_private_data(mod); 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(); - ae_f32x2 out_sample1 = AE_ZERO32(); - ae_f16x4 in_sample = AE_ZERO16(); - ae_f16x4 out_sample = AE_ZERO16(); + ae_f32x2 volume0; + ae_f32x2 volume1; + ae_f32x2 out_sample0; + ae_f32x2 out_sample1; + ae_f16x4 in_sample; + ae_f16x4 out_sample; int i, n, m, left; ae_f32x2 *buf; ae_f32x2 *buf_end; ae_f32x2 *vol; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f16x4 *in = (ae_f16x4 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); @@ -443,15 +441,6 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu /* load second two volume gain */ AE_L32X2_XC(volume1, vol, inc); -#if COMP_VOLUME_Q8_16 - /* Q8.16 to Q9.23 */ - volume0 = AE_SLAI32S(volume0, 7); - volume1 = AE_SLAI32S(volume1, 7); -#elif COMP_VOLUME_Q1_23 - /* No need to shift, Q1.23 is OK as such */ -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" -#endif /* Load the input sample */ AE_LA16X4_IP(in_sample, inu, in); /* calculate the peak volume*/ @@ -462,6 +451,18 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu AE_L32X2_XC1(temp, peakvol, 0); temp = AE_MAXABS32S(AE_SEXT32X2D16_10(in_sample), temp); AE_S32X2_XC1(temp, peakvol, inc); + +#if COMP_VOLUME_Q1_31 + out_sample0 = AE_MULFP32X16X2RS_H(volume0, in_sample); + out_sample1 = AE_MULFP32X16X2RS_L(volume1, in_sample); +#else +#if COMP_VOLUME_Q8_16 + /* Shift Q8.16 to Q9.23 + * No need to shift Q1.23, it is OK as such + */ + volume0 = AE_SLAI32S(volume0, 7); + volume1 = AE_SLAI32S(volume1, 7); +#endif /* Multiply the input sample */ out_sample0 = AE_MULFP32X16X2RS_H(volume0, in_sample); out_sample1 = AE_MULFP32X16X2RS_L(volume1, in_sample); @@ -469,6 +470,7 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu /* Q9.23 to Q1.31 */ out_sample0 = AE_SLAI32S(out_sample0, 8); out_sample1 = AE_SLAI32S(out_sample1, 8); +#endif /* store the output */ out_sample = AE_ROUND16X4F32SSYM(out_sample0, out_sample1); @@ -480,20 +482,27 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu for (i = 0; i < left; i++) { /* load first volume gain */ AE_L32_XC(volume0, (ae_f32 *)vol, sizeof(ae_f32)); -#if COMP_VOLUME_Q8_16 - /* Q8.16 to Q9.23 */ - volume0 = AE_SLAI32S(volume0, 7); -#endif + /* Load the input sample */ AE_L16_IP(in_sample, (ae_f16 *)in, sizeof(ae_f16)); /* calculate the peak volume*/ AE_L32_XC1(temp, (ae_f32 *)peakvol, 0); temp = AE_MAXABS32S(AE_SEXT32X2D16_32(in_sample), temp); AE_S32_L_XC1(temp, (ae_f32 *)peakvol, sizeof(ae_f32)); + +#if COMP_VOLUME_Q1_31 + /* Multiply the input sample */ + out_sample0 = AE_MULFP32X16X2RS_H(volume0, in_sample); +#else +#if COMP_VOLUME_Q8_16 + /* Q8.16 to Q9.23 */ + volume0 = AE_SLAI32S(volume0, 7); +#endif /* Multiply the input sample */ out_sample0 = AE_MULFP32X16X2RS_H(volume0, in_sample); /* Q9.23 to Q1.31 */ out_sample0 = AE_SLAI32S(out_sample0, 8); +#endif /* store the output */ out_sample = AE_ROUND16X4F32SSYM(out_sample0, out_sample0); AE_S16_0_IP(out_sample, (ae_f16 *)out, sizeof(ae_f16)); @@ -529,9 +538,9 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, struct vol_data *cd = module_get_private_data(mod); struct audio_stream *source = bsource->data; struct audio_stream *sink = bsink->data; - ae_f16x4 in_sample = AE_ZERO16(); + ae_f16x4 in_sample; int i, n, m, left; - ae_valign inu = AE_ZALIGN64(); + ae_valign inu; ae_valign outu = AE_ZALIGN64(); ae_f16x4 *in = (ae_f16x4 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed); diff --git a/src/audio/volume/volume_hifi5.c b/src/audio/volume/volume_hifi5.c index 33ffc691bce5..794330cddd9b 100644 --- a/src/audio/volume/volume_hifi5.c +++ b/src/audio/volume/volume_hifi5.c @@ -69,7 +69,7 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea ae_int32x4 *buf_end; int i, n, m; ae_int32x4 *vol; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); ae_int32x4 *in = (ae_int32x4 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) @@ -117,17 +117,20 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea AE_MULF2P32X4RS(out_sample, out_sample1, AE_SLAI32S(volume, 7), AE_SLAI32S(volume1, 7), AE_SLAI32(in_sample, 8), AE_SLAI32(in_sample1, 8)); + out_sample = AE_SLAI32S(out_sample, 8); + out_sample1 = AE_SLAI32S(out_sample1, 8); #elif COMP_VOLUME_Q1_23 AE_MULF2P32X4RS(out_sample, out_sample1, volume, volume1, AE_SLAI32(in_sample, 8), AE_SLAI32(in_sample1, 8)); -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" + out_sample = AE_SLAI32S(out_sample, 8); + out_sample1 = AE_SLAI32S(out_sample1, 8); +#elif COMP_VOLUME_Q1_31 + AE_MULF2P32X4RS(out_sample, out_sample1, volume, volume1, + AE_SLAI32(in_sample, 8), AE_SLAI32(in_sample1, 8)); #endif /* Shift for S24_LE */ - out_sample = AE_SLAI32S(out_sample, 8); out_sample = AE_SRAI32(out_sample, 8); - out_sample1 = AE_SLAI32S(out_sample1, 8); out_sample1 = AE_SRAI32(out_sample1, 8); /* Store the output sample */ @@ -157,7 +160,7 @@ static void vol_passthrough_s24_to_s24_s32(struct processing_module *mod, struct audio_stream *sink = bsink->data; ae_int32x2 in_sample, in_sample1; int i, n, m; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); ae_int32x4 *in = (ae_int32x4 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) @@ -212,12 +215,10 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea ae_int32x2 out_sample, out_sample1; ae_int32x2 volume, volume1; int i, n, m; - ae_int64 mult0; - ae_int64 mult1; ae_int32x4 *buf; ae_int32x4 *buf_end; ae_int32x4 *vol; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); const int channels_count = audio_stream_get_channels(sink); const int inc = sizeof(ae_int32x4); @@ -259,35 +260,26 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea /* Load the input sample */ AE_LA32X2X2_IP(in_sample, in_sample1, inu, in); - -#if COMP_VOLUME_Q8_16 - /* Q8.16 x Q1.31 << 1 -> Q9.48 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 1); /* Q9.47 */ - mult1 = AE_MULF32S_LL(volume, in_sample); - mult1 = AE_SRAI64(mult1, 1); - out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q9.47 -> Q1.31 */ - - mult0 = AE_MULF32S_HH(volume1, in_sample1); - mult0 = AE_SRAI64(mult0, 1); /* Q9.47 */ - mult1 = AE_MULF32S_LL(volume1, in_sample1); - mult1 = AE_SRAI64(mult1, 1); - out_sample1 = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q9.47 -> Q1.31 */ -#elif COMP_VOLUME_Q1_23 - /* Q1.23 x Q1.31 << 1 -> Q2.55 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 8); /* Q2.47 */ - mult1 = AE_MULF32S_LL(volume, in_sample); - mult1 = AE_SRAI64(mult1, 8); +#if COMP_VOLUME_Q1_31 + AE_MULF2P32X4RS(out_sample, out_sample1, + volume, volume1, + in_sample, in_sample1); +#else + /* With Q1.31 x Q1.31 -> Q17.47 HiFi multiplications the result is + * Q8.16 x Q1.31 << 1 >> 16 -> Q9.32, shift left by 15 for Q17.47 + * Q1.23 x Q1.31 << 1 >> 16 -> Q2.39, shift left by 8 for Q17.47 + */ + ae_int64 mult0, mult1; + + AE_MULF32X2R_HH_LL(mult0, mult1, volume, in_sample); + mult0 = AE_SLAI64(mult0, VOLUME_Q17_47_SHIFT); + mult1 = AE_SLAI64(mult1, VOLUME_Q17_47_SHIFT); out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ - mult0 = AE_MULF32S_HH(volume1, in_sample1); - mult0 = AE_SRAI64(mult0, 8); /* Q2.47 */ - mult1 = AE_MULF32S_LL(volume1, in_sample1); - mult1 = AE_SRAI64(mult1, 8); - out_sample1 = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" + AE_MULF32X2R_HH_LL(mult0, mult1, volume1, in_sample1); + mult0 = AE_SLAI64(mult0, VOLUME_Q17_47_SHIFT); + mult1 = AE_SLAI64(mult1, VOLUME_Q17_47_SHIFT); + out_sample1 = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ #endif AE_SA32X2X2_IP(out_sample, out_sample1, outu, out); } @@ -315,7 +307,7 @@ static void vol_passthrough_s32_to_s24_s32(struct processing_module *mod, struct audio_stream *sink = bsink->data; ae_int32x2 in_sample, in_sample1; int i, n, m; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); const int channels_count = audio_stream_get_channels(sink); int samples = channels_count * frames; @@ -372,7 +364,7 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu ae_int32x4 *buf; ae_int32x4 *buf_end; ae_int32x4 *vol; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); ae_int16x8 *in = (ae_int16x8 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) @@ -411,20 +403,24 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu AE_L32X2X2_XC(volume2, volume3, vol, inc); + /* Load the input sample */ + AE_LA16X4X2_IP(in_sample, in_sample1, inu, in); + +#if COMP_VOLUME_Q1_31 + AE_MULF2P32X16X4RS(out_temp, out_temp1, volume, volume1, in_sample); + out_sample = AE_ROUND16X4F32SSYM(out_temp, out_temp1); + AE_MULF2P32X16X4RS(out_temp, out_temp1, volume2, volume3, in_sample1); + out_sample1 = AE_ROUND16X4F32SSYM(out_temp, out_temp1); +#else #if COMP_VOLUME_Q8_16 - /* Q8.16 to Q9.23 */ + /* Shift Q8.16 to Q9.23 + * No need to shift Q1.23, it is OK as such + */ volume = AE_SLAI32S(volume, 7); volume1 = AE_SLAI32S(volume1, 7); - volume2 = AE_SLAI32S(volume2, 7); volume3 = AE_SLAI32S(volume3, 7); -#elif COMP_VOLUME_Q1_23 - /* No need to shift, Q1.23 is OK as such */ -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" #endif - /* Load the input sample */ - AE_LA16X4X2_IP(in_sample, in_sample1, inu, in); AE_MULF2P32X16X4RS(out_temp, out_temp1, volume, volume1, in_sample); /* Q9.23 to Q1.31 */ @@ -436,9 +432,10 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu /* Q9.23 to Q1.31 */ out_temp = AE_SLAI32S(out_temp, 8); out_temp1 = AE_SLAI32S(out_temp1, 8); - /* store the output */ out_sample1 = AE_ROUND16X4F32SSYM(out_temp, out_temp1); +#endif + /* store the output */ AE_SA16X4X2_IP(out_sample, out_sample1, outu, out); } AE_SA128POS_FP(outu, out); @@ -467,7 +464,7 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, struct audio_stream *sink = bsink->data; ae_int16x4 in_sample, in_sample1; int i, n, m; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); ae_int16x8 *in = (ae_int16x8 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) diff --git a/src/audio/volume/volume_hifi5_with_peakvol.c b/src/audio/volume/volume_hifi5_with_peakvol.c index d05838586136..16d2f7cb8bf9 100644 --- a/src/audio/volume/volume_hifi5_with_peakvol.c +++ b/src/audio/volume/volume_hifi5_with_peakvol.c @@ -21,6 +21,13 @@ LOG_MODULE_DECLARE(volume, CONFIG_SOF_LOG_LEVEL); #include "volume.h" +/* With Q1.31 x Q1.31 -> Q17.47 HiFi multiplications the result is + * Q8.16 x Q1.31 << 1 >> 16 -> Q9.32, shift left by 15 for Q17.47 + * + * With Q1.31 x Q1.31 -> Q17.47 HiFi multiplications the result is + * Q1.23 x Q1.31 << 1 >> 16 -> Q2.39, shift left by 8 for Q17.47 + */ + #if SOF_USE_HIFI(5, VOLUME) #if CONFIG_COMP_PEAK_VOL @@ -60,7 +67,7 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea ae_int32x2 volume, volume1; int i, n, m; ae_int32x4 *vol; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); ae_int32x4 *in = (ae_int32x4 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) @@ -111,23 +118,26 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea temp = AE_MAXABS32S(in_sample, temp); temp1 = AE_MAXABS32S(in_sample1, temp1); AE_S32X2X2_XC1(temp, temp1, peakvol, inc); + /* Multiply the input sample */ #if COMP_VOLUME_Q8_16 - AE_MULF2P32X4RS(out_sample, out_sample1, AE_SLAI32S(volume, 7), - AE_SLAI32S(volume1, 7), + AE_MULF2P32X4RS(out_sample, out_sample1, + AE_SLAI32S(volume, 7), AE_SLAI32S(volume1, 7), AE_SLAI32(in_sample, 8), AE_SLAI32(in_sample1, 8)); + out_sample = AE_SLAI32S(out_sample, 8); + out_sample1 = AE_SLAI32S(out_sample1, 8); #elif COMP_VOLUME_Q1_23 AE_MULF2P32X4RS(out_sample, out_sample1, volume, volume1, - AE_SLAI32(in_sample, 8), - AE_SLAI32(in_sample1, 8)); -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" + AE_SLAI32(in_sample, 8), AE_SLAI32(in_sample1, 8)); + out_sample = AE_SLAI32S(out_sample, 8); + out_sample1 = AE_SLAI32S(out_sample1, 8); +#elif COMP_VOLUME_Q1_31 + AE_MULF2P32X4RS(out_sample, out_sample1, volume, volume1, + AE_SLAI32(in_sample, 8), AE_SLAI32(in_sample1, 8)); #endif /* Shift for S24_LE */ - out_sample = AE_SLAI32S(out_sample, 8); out_sample = AE_SRAI32(out_sample, 8); - out_sample1 = AE_SLAI32S(out_sample1, 8); out_sample1 = AE_SRAI32(out_sample1, 8); /* Store the output sample */ @@ -165,7 +175,7 @@ static void vol_passthrough_s24_to_s24_s32(struct processing_module *mod, struct audio_stream *sink = bsink->data; ae_int32x2 in_sample, in_sample1; int i, n, m; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); ae_int32x4 *in = (ae_int32x4 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) @@ -238,12 +248,10 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea ae_int32x2 out_sample, out_sample1; ae_int32x2 volume, volume1; int i, n, m; - ae_int64 mult0; - ae_int64 mult1; ae_int32x4 *buf; ae_int32x4 *buf_end; ae_int32x4 *vol; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); const int channels_count = audio_stream_get_channels(sink); const int inc = sizeof(ae_int32x4); @@ -296,34 +304,26 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea temp = AE_MAXABS32S(in_sample, temp); temp1 = AE_MAXABS32S(in_sample1, temp1); AE_S32X2X2_XC1(temp, temp1, peakvol, inc); -#if COMP_VOLUME_Q8_16 - /* Q8.16 x Q1.31 << 1 -> Q9.48 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 1); /* Q9.47 */ - mult1 = AE_MULF32S_LL(volume, in_sample); - mult1 = AE_SRAI64(mult1, 1); - out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q9.47 -> Q1.31 */ - - mult0 = AE_MULF32S_HH(volume1, in_sample1); - mult0 = AE_SRAI64(mult0, 1); /* Q9.47 */ - mult1 = AE_MULF32S_LL(volume1, in_sample1); - mult1 = AE_SRAI64(mult1, 1); - out_sample1 = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q9.47 -> Q1.31 */ -#elif COMP_VOLUME_Q1_23 - /* Q1.23 x Q1.31 << 1 -> Q2.55 */ - mult0 = AE_MULF32S_HH(volume, in_sample); - mult0 = AE_SRAI64(mult0, 8); /* Q2.47 */ - mult1 = AE_MULF32S_LL(volume, in_sample); - mult1 = AE_SRAI64(mult1, 8); +#if COMP_VOLUME_Q1_31 + AE_MULF2P32X4RS(out_sample, out_sample1, + volume, volume1, + in_sample, in_sample1); +#else + /* With Q1.31 x Q1.31 -> Q17.47 HiFi multiplications the result is + * Q8.16 x Q1.31 << 1 >> 16 -> Q9.32, shift left by 15 for Q17.47 + * Q1.23 x Q1.31 << 1 >> 16 -> Q2.39, shift left by 8 for Q17.47 + */ + ae_f64 mult0, mult1; + + AE_MULF32X2R_HH_LL(mult0, mult1, volume, in_sample); + mult0 = AE_SLAI64(mult0, VOLUME_Q17_47_SHIFT); + mult1 = AE_SLAI64(mult1, VOLUME_Q17_47_SHIFT); out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ - mult0 = AE_MULF32S_HH(volume1, in_sample1); - mult0 = AE_SRAI64(mult0, 8); /* Q2.47 */ - mult1 = AE_MULF32S_LL(volume1, in_sample1); - mult1 = AE_SRAI64(mult1, 8); - out_sample1 = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" + AE_MULF32X2R_HH_LL(mult0, mult1, volume1, in_sample1); + mult0 = AE_SLAI64(mult0, VOLUME_Q17_47_SHIFT); + mult1 = AE_SLAI64(mult1, VOLUME_Q17_47_SHIFT); + out_sample1 = AE_ROUND32X2F48SSYM(mult0, mult1); /* Q2.47 -> Q1.31 */ #endif AE_SA32X2X2_IP(out_sample, out_sample1, outu, out); } @@ -358,7 +358,7 @@ static void vol_passthrough_s32_to_s24_s32(struct processing_module *mod, struct audio_stream *sink = bsink->data; ae_int32x2 in_sample, in_sample1; int i, n, m; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); const int channels_count = audio_stream_get_channels(sink); const int inc = sizeof(ae_int32x4); @@ -434,7 +434,7 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu ae_int32x4 *buf; ae_int32x4 *buf_end; ae_int32x4 *vol; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); ae_int16x8 *in = (ae_int16x8 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) @@ -478,17 +478,6 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu AE_L32X2X2_XC(volume, volume1, vol, inc); AE_L32X2X2_XC(volume2, volume3, vol, inc); -#if COMP_VOLUME_Q8_16 - /* Q8.16 to Q9.23 */ - volume = AE_SLAI32S(volume, 7); - volume1 = AE_SLAI32S(volume1, 7); - volume2 = AE_SLAI32S(volume2, 7); - volume3 = AE_SLAI32S(volume3, 7); -#elif COMP_VOLUME_Q1_23 - /* No need to shift, Q1.23 is OK as such */ -#else -#error "Need CONFIG_COMP_VOLUME_Qx_y" -#endif /* Load the input sample */ AE_LA16X4X2_IP(in_sample, in_sample1, inu, in); /* calculate the peak volume*/ @@ -502,7 +491,22 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu temp1 = AE_MAXABS32S(AE_SEXT32X2D16_10(in_sample1), temp1); AE_S32X2X2_XC1(temp, temp1, peakvol, inc); - /* Multiply the input sample */ +#if COMP_VOLUME_Q1_31 + AE_MULF2P32X16X4RS(out_temp, out_temp1, volume, volume1, in_sample); + out_sample = AE_ROUND16X4F32SSYM(out_temp, out_temp1); + AE_MULF2P32X16X4RS(out_temp, out_temp1, volume2, volume3, in_sample1); + out_sample1 = AE_ROUND16X4F32SSYM(out_temp, out_temp1); +#else +#if COMP_VOLUME_Q8_16 + /* Shift Q8.16 to Q9.23 + * No need to shift Q1.23, it is OK as such + */ + volume = AE_SLAI32S(volume, 7); + volume1 = AE_SLAI32S(volume1, 7); + volume2 = AE_SLAI32S(volume2, 7); + volume3 = AE_SLAI32S(volume3, 7); +#endif + AE_MULF2P32X16X4RS(out_temp, out_temp1, volume, volume1, in_sample); /* Q9.23 to Q1.31 */ out_temp = AE_SLAI32S(out_temp, 8); @@ -513,9 +517,9 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu /* Q9.23 to Q1.31 */ out_temp = AE_SLAI32S(out_temp, 8); out_temp1 = AE_SLAI32S(out_temp1, 8); - /* store the output */ out_sample1 = AE_ROUND16X4F32SSYM(out_temp, out_temp1); - +#endif + /* store the output */ AE_SA16X4X2_IP(out_sample, out_sample1, outu, out); } AE_SA128POS_FP(outu, out); @@ -551,7 +555,7 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, struct audio_stream *sink = bsink->data; ae_int16x4 in_sample, in_sample1; int i, n, m; - ae_valignx2 inu = AE_ZALIGN128(); + ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); ae_int16x8 *in = (ae_int16x8 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) diff --git a/src/audio/volume/volume_ipc3.c b/src/audio/volume/volume_ipc3.c index 0e599a0dabd6..053b41e32152 100644 --- a/src/audio/volume/volume_ipc3.c +++ b/src/audio/volume/volume_ipc3.c @@ -14,7 +14,6 @@ #include <sof/common.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/cpu.h> #include <sof/lib/uuid.h> @@ -76,12 +75,12 @@ int volume_init(struct processing_module *mod) int i; if (!vol || cfg->size != sizeof(*vol)) { - comp_err(dev, "volume_init(): No configuration data or bad data size %zu", + comp_err(dev, "No configuration data or bad data size %zu", cfg->size); return -EINVAL; } - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(struct vol_data)); + cd = mod_zalloc(mod, sizeof(struct vol_data)); if (!cd) return -ENOMEM; @@ -89,10 +88,10 @@ int volume_init(struct processing_module *mod) * malloc memory to store current volume 4 times to ensure the address * is 8-byte aligned for multi-way xtensa intrinsic operations. */ - cd->vol = rmalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, vol_size); + cd->vol = mod_alloc_align(mod, vol_size, SOF_FRAME_BYTE_ALIGN); if (!cd->vol) { - rfree(cd); - comp_err(dev, "volume_init(): Failed to allocate %zu", vol_size); + mod_free(mod, cd); + comp_err(dev, "Failed to allocate %zu", vol_size); return -ENOMEM; } @@ -108,7 +107,7 @@ int volume_init(struct processing_module *mod) if (vol->min_value < VOL_MIN) { /* Use VOL_MIN instead, no need to stop new(). */ cd->vol_min = VOL_MIN; - comp_err(dev, "volume_new(): vol->min_value was limited to VOL_MIN."); + comp_err(dev, "vol->min_value was limited to VOL_MIN."); } else { cd->vol_min = vol->min_value; } @@ -116,7 +115,7 @@ int volume_init(struct processing_module *mod) if (vol->max_value > VOL_MAX) { /* Use VOL_MAX instead, no need to stop new(). */ cd->vol_max = VOL_MAX; - comp_err(dev, "volume_new(): vol->max_value was limited to VOL_MAX."); + comp_err(dev, "vol->max_value was limited to VOL_MAX."); } else { cd->vol_max = vol->max_value; } @@ -157,9 +156,9 @@ int volume_init(struct processing_module *mod) cd->initial_ramp = vol->initial_ramp; break; default: - comp_err(dev, "volume_new(): invalid ramp type %d", vol->ramp); - rfree(cd); - rfree(cd->vol); + comp_err(dev, "invalid ramp type %d", vol->ramp); + mod_free(mod, cd->vol); + mod_free(mod, cd); return -EINVAL; } @@ -168,7 +167,7 @@ int volume_init(struct processing_module *mod) return 0; } -void volume_peak_free(struct vol_data *cd) +void volume_peak_free(struct processing_module *mod) { } @@ -185,26 +184,26 @@ int volume_set_config(struct processing_module *mod, uint32_t config_id, int j; int ret = 0; - comp_dbg(dev, "volume_set_config()"); + comp_dbg(dev, "entry"); /* validate */ if (cdata->num_elems == 0 || cdata->num_elems > SOF_IPC_MAX_CHANNELS) { - comp_err(dev, "volume_set_config(): invalid cdata->num_elems"); + comp_err(dev, "invalid cdata->num_elems"); return -EINVAL; } switch (cdata->cmd) { case SOF_CTRL_CMD_VOLUME: - comp_dbg(dev, "volume_set_config(), SOF_CTRL_CMD_VOLUME, cdata->comp_id = %u", + comp_dbg(dev, "SOF_CTRL_CMD_VOLUME, cdata->comp_id = %u", cdata->comp_id); for (j = 0; j < cdata->num_elems; j++) { ch = cdata->chanv[j].channel; val = cdata->chanv[j].value; - comp_dbg(dev, "volume_set_config(), channel = %d, value = %u", + comp_dbg(dev, "channel = %d, value = %u", ch, val); if (ch >= SOF_IPC_MAX_CHANNELS) { - comp_err(dev, "volume_set_config(), illegal channel = %d", + comp_err(dev, "illegal channel = %d", ch); return -EINVAL; } @@ -220,18 +219,23 @@ int volume_set_config(struct processing_module *mod, uint32_t config_id, volume_set_ramp_channel_counter(cd, cd->channels); volume_ramp_check(mod); + /* Update function pointer after all volume changes */ + if (comp_dev_get_first_data_consumer(dev) != NULL) { + cd->is_passthrough = false; + set_volume_process(cd, dev, false); + } break; case SOF_CTRL_CMD_SWITCH: - comp_dbg(dev, "volume_set_config(), SOF_CTRL_CMD_SWITCH, cdata->comp_id = %u", + comp_dbg(dev, "SOF_CTRL_CMD_SWITCH, cdata->comp_id = %u", cdata->comp_id); for (j = 0; j < cdata->num_elems; j++) { ch = cdata->chanv[j].channel; val = cdata->chanv[j].value; - comp_dbg(dev, "volume_set_config(), channel = %d, value = %u", + comp_dbg(dev, "channel = %d, value = %u", ch, val); if (ch >= SOF_IPC_MAX_CHANNELS) { - comp_err(dev, "volume_set_config(), illegal channel = %d", + comp_err(dev, "illegal channel = %d", ch); return -EINVAL; } @@ -246,7 +250,7 @@ int volume_set_config(struct processing_module *mod, uint32_t config_id, break; default: - comp_err(dev, "volume_set_config(): invalid cdata->cmd"); + comp_err(dev, "invalid cdata->cmd"); return -EINVAL; } @@ -262,11 +266,11 @@ int volume_get_config(struct processing_module *mod, struct comp_dev *dev = mod->dev; int j; - comp_dbg(dev, "volume_get_config()"); + comp_dbg(dev, "entry"); /* validate */ if (cdata->num_elems == 0 || cdata->num_elems > SOF_IPC_MAX_CHANNELS) { - comp_err(dev, "volume_get_config(): invalid cdata->num_elems %u", + comp_err(dev, "invalid cdata->num_elems %u", cdata->num_elems); return -EINVAL; } @@ -276,7 +280,7 @@ int volume_get_config(struct processing_module *mod, for (j = 0; j < cdata->num_elems; j++) { cdata->chanv[j].channel = j; cdata->chanv[j].value = cd->tvolume[j]; - comp_dbg(dev, "volume_get_config(), channel = %u, value = %u", + comp_dbg(dev, "channel = %u, value = %u", cdata->chanv[j].channel, cdata->chanv[j].value); } @@ -285,13 +289,13 @@ int volume_get_config(struct processing_module *mod, for (j = 0; j < cdata->num_elems; j++) { cdata->chanv[j].channel = j; cdata->chanv[j].value = !cd->muted[j]; - comp_dbg(dev, "volume_get_config(), channel = %u, value = %u", + comp_dbg(dev, "channel = %u, value = %u", cdata->chanv[j].channel, cdata->chanv[j].value); } break; default: - comp_err(dev, "volume_get_config(): invalid cdata->cmd"); + comp_err(dev, "invalid cdata->cmd"); return -EINVAL; } diff --git a/src/audio/volume/volume_ipc4.c b/src/audio/volume/volume_ipc4.c index 5db67be04cb5..e111752d2b78 100644 --- a/src/audio/volume/volume_ipc4.c +++ b/src/audio/volume/volume_ipc4.c @@ -14,7 +14,6 @@ #include <sof/common.h> #include <rtos/panic.h> #include <sof/ipc/msg.h> -#include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/cpu.h> #include <sof/lib/uuid.h> @@ -65,7 +64,11 @@ static int set_volume_ipc4(struct vol_data *cd, uint32_t const channel, */ static uint32_t convert_volume_ipc4_to_ipc3(struct comp_dev *dev, uint32_t volume) { +#if COMP_VOLUME_Q1_31 + return volume; +#else return sat_int32(Q_SHIFT_RND((int64_t)volume, 31, VOL_QXY_Y)); +#endif } static uint32_t convert_volume_ipc3_to_ipc4(uint32_t volume) @@ -73,7 +76,11 @@ static uint32_t convert_volume_ipc3_to_ipc4(uint32_t volume) /* In IPC4 volume is converted into Q1.23 format to be processed by firmware. * Now convert it back to Q1.31 */ +#if COMP_VOLUME_Q1_31 + return volume; +#else return sat_int32(Q_SHIFT_LEFT((int64_t)volume, VOL_QXY_Y, 31)); +#endif } static void init_ramp(struct vol_data *cd, uint32_t curve_duration, uint32_t target_volume) @@ -108,6 +115,7 @@ int volume_init(struct processing_module *mod) uint32_t channels_count; uint8_t channel_cfg; uint8_t channel; + bool all_channels; uint32_t instance_id = IPC4_INST_ID(dev_comp_id(dev)); if (instance_id >= IPC4_MAX_PEAK_VOL_REG_SLOTS) { @@ -116,11 +124,31 @@ int volume_init(struct processing_module *mod) } channels_count = mod->priv.cfg.base_cfg.audio_fmt.channels_count; if (channels_count > SOF_IPC_MAX_CHANNELS || !channels_count) { - comp_err(dev, "volume_init(): Invalid channels count %u", channels_count); + comp_err(dev, "Invalid channels count %u", channels_count); + return -EINVAL; + } + + /* The payload must hold at least one config entry, which is read below + * to detect the all-channels form. + */ + if (cfg->size < sizeof(*vol) + sizeof(vol->config[0])) { + comp_err(dev, "Invalid init payload size %zu", cfg->size); + return -EINVAL; + } + + /* In the all-channels form a single entry applies to every channel; + * otherwise the payload must hold one entry per channel as they are + * each read below. + */ + all_channels = vol->config[0].channel_id == IPC4_ALL_CHANNELS_MASK; + if (!all_channels && + cfg->size < sizeof(*vol) + channels_count * sizeof(vol->config[0])) { + comp_err(dev, "Invalid init payload size %zu for %u channels", + cfg->size, channels_count); return -EINVAL; } - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(struct vol_data)); + cd = mod_zalloc(mod, sizeof(struct vol_data)); if (!cd) return -ENOMEM; @@ -128,37 +156,34 @@ int volume_init(struct processing_module *mod) * malloc memory to store current volume 4 times to ensure the address * is 8-byte aligned for multi-way xtensa intrinsic operations. */ - cd->vol = rmalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, vol_size); + cd->vol = mod_alloc_align(mod, vol_size, SOF_FRAME_BYTE_ALIGN); if (!cd->vol) { - rfree(cd); - comp_err(dev, "volume_init(): Failed to allocate %d", vol_size); + mod_free(mod, cd); + comp_err(dev, "Failed to allocate %d", vol_size); return -ENOMEM; } /* malloc memory to store temp peak volume 4 times to ensure the address * is 8-byte aligned for multi-way xtensa intrinsic operations. */ - cd->peak_vol = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, vol_size); + cd->peak_vol = mod_zalloc(mod, vol_size); if (!cd->peak_vol) { - rfree(cd->vol); - rfree(cd); - comp_err(dev, "volume_init(): Failed to allocate %d for peak_vol", vol_size); + mod_free(mod, cd->vol); + mod_free(mod, cd); + comp_err(dev, "Failed to allocate %d for peak_vol", vol_size); return -ENOMEM; } md->private = cd; for (channel = 0; channel < channels_count; channel++) { - if (vol->config[0].channel_id == IPC4_ALL_CHANNELS_MASK) - channel_cfg = 0; - else - channel_cfg = channel; + channel_cfg = all_channels ? 0 : channel; target_volume[channel] = - convert_volume_ipc4_to_ipc3(dev, vol->config[channel].target_volume); + convert_volume_ipc4_to_ipc3(dev, vol->config[channel_cfg].target_volume); set_volume_ipc4(cd, channel, - target_volume[channel_cfg], + target_volume[channel], vol->config[channel_cfg].curve_type, vol->config[channel_cfg].curve_duration); @@ -181,14 +206,15 @@ int volume_init(struct processing_module *mod) return 0; } -void volume_peak_free(struct vol_data *cd) +void volume_peak_free(struct processing_module *mod) { + struct vol_data *cd = module_get_private_data(mod); struct ipc4_peak_volume_regs regs; /* clear mailbox */ memset_s(®s, sizeof(regs), 0, sizeof(regs)); mailbox_sw_regs_write(cd->mailbox_offset, ®s, sizeof(regs)); - rfree(cd->peak_vol); + mod_free(mod, cd->peak_vol); } static int volume_set_volume(struct processing_module *mod, const uint8_t *data, int data_size) @@ -260,8 +286,10 @@ static int volume_set_attenuation(struct processing_module *mod, const uint8_t * struct comp_dev *dev = mod->dev; uint32_t attenuation; - /* only support attenuation in format of 32bit */ - if (data_size > sizeof(uint32_t)) { + /* only support attenuation in format of 32bit; the payload is + * dereferenced as a uint32_t below so it must be exactly that size + */ + if (data_size != (int)sizeof(uint32_t)) { comp_err(dev, "attenuation data size %d is incorrect", data_size); return -EINVAL; } @@ -343,7 +371,7 @@ int volume_set_config(struct processing_module *mod, uint32_t config_id, struct comp_dev *dev = mod->dev; int ret; - comp_dbg(dev, "volume_set_config()"); + comp_dbg(dev, "entry"); ret = module_set_configuration(mod, config_id, pos, data_offset_size, fragment, fragment_size, response, response_size); @@ -405,13 +433,16 @@ static int volume_params(struct processing_module *mod) struct comp_buffer *sinkb, *sourceb; struct comp_dev *dev = mod->dev; - comp_dbg(dev, "volume_params()"); + comp_dbg(dev, "entry"); ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); component_set_nearest_period_frames(dev, params->rate); - /* volume component will only ever have 1 sink buffer */ + /* + * volume component will only ever have 1 sink buffer, the caller has + * verified their validity + */ sinkb = comp_dev_get_first_data_consumer(dev); ipc4_update_buffer_format(sinkb, &mod->priv.cfg.base_cfg.audio_fmt); diff --git a/src/debug/CMakeLists.txt b/src/debug/CMakeLists.txt index 394895f58c9e..5cb8e8bd9c6c 100644 --- a/src/debug/CMakeLists.txt +++ b/src/debug/CMakeLists.txt @@ -4,4 +4,14 @@ if(CONFIG_GDB_DEBUG) add_subdirectory(gdb) endif() -add_local_sources(sof panic.c) +add_subdirectory(tester) + +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + +add_subdirectory(debug_stream) +add_subdirectory(telemetry) + +zephyr_library_sources_ifdef(CONFIG_COLD_STORE_EXECUTE_DEBUG dram.c) + +endif() # Zephyr diff --git a/src/debug/debug_stream/CMakeLists.txt b/src/debug/debug_stream/CMakeLists.txt index 4d353128a819..36de0d24a46d 100644 --- a/src/debug/debug_stream/CMakeLists.txt +++ b/src/debug/debug_stream/CMakeLists.txt @@ -3,3 +3,5 @@ add_local_sources_ifdef(CONFIG_SOF_DEBUG_STREAM_SLOT sof debug_stream_slot.c) add_local_sources_ifdef(CONFIG_SOF_DEBUG_STREAM_THREAD_INFO sof debug_stream_thread_info.c) + +add_local_sources_ifdef(CONFIG_SOF_DEBUG_STREAM_TEXT_MSG sof debug_stream_text_msg.c) diff --git a/src/debug/debug_stream/Kconfig b/src/debug/debug_stream/Kconfig index 3a5f3d1f49cf..6ac6280c611c 100644 --- a/src/debug/debug_stream/Kconfig +++ b/src/debug/debug_stream/Kconfig @@ -7,7 +7,8 @@ config SOF_DEBUG_STREAM_SLOT information from SOF system that are streamed from SOF DSP to the host side for decoding and presentation. This option enables transferring the records from DSP to host over a - debug window slot. + debug window slot. To extract the debugstream see + tools/debug_stream/debug_stream.py. if SOF_DEBUG_STREAM_SLOT @@ -44,4 +45,43 @@ config SOF_DEBUG_STREAM_THREAD_INFO_INTERVAL Decides how often thread info runs and checks execution cycle statistics and stack usage. +config SOF_DEBUG_STREAM_THREAD_INFO_TOTAL_CPU_LOAD_TO_LOG + bool "Print summarized total CPU load to log subsystem" + depends on SOF_DEBUG_STREAM_THREAD_INFO + default y + help + In addition to printing thread statistics to debug stream, + print the total CPU load (sum of all threads) to + the logging system. + +config SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS + int "Number of cpu sections slot is divided to" + default CORE_COUNT + range 1 MP_MAX_NUM_CPUS + help + In some situations a high number of cpu sections shrinks the + circular buffer size so much that it limit debugging. With + this option its possible to use fewer sections. The downside + is that the cpus above the number of sections can not send + any debug stream messages. + +config SOF_DEBUG_STREAM_TEXT_MSG + bool "Enable text message sending through Debug-Stream" + help + Enable debug message sending over debug stream. To use this + feature one only needs to enable debug stream with this + config option and print the debug messages with + ds_msg(). See include/user/debug_stream_text_msg.h for + prototype. + +config SOF_DEBUG_STREAM_TEXT_MSG_ASSERT_PRINT + bool "Enable assert print sending through Debug-Stream" + depends on EXCEPTION_DUMP_HOOK && (ASSERT || ASSERT_VERBOSE) + select SOF_DEBUG_STREAM_TEXT_MSG + help + Enable assert print sending over debug stream as text + message. This feature is also sensitive to Zephyr option + CONFIG_EXCEPTION_DUMP_HOOK_ONLY. If that is set then the + asserts are not printed through printk interface. + endif diff --git a/src/debug/debug_stream/README.md b/src/debug/debug_stream/README.md new file mode 100644 index 000000000000..592edef8a719 --- /dev/null +++ b/src/debug/debug_stream/README.md @@ -0,0 +1,61 @@ +# SOF Debug Stream + +The `debug_stream` framework is an abstract logging and live-data streaming mechanism allowing the DSP to asynchronously push structured or freeform diagnostic records immediately out to the host. + +## Feature Overview + +Unlike standard tracing (`mtrace`), which requires buffering and complex host parsing logic often tied directly to pipeline topologies or ALSA interfaces, the `debug_stream` bypasses the audio framework entirely. It utilizes the dedicated IPC Memory Windows (specifically the debug slot) to write data. + +The stream is particularly useful for reporting: + +1. **Thread Information:** Real-time data from Zephyr OS threads (like CPU runtime, context switch frequencies, or stack high-water marks). +2. **Text Messages (`ds_msg`):** Lightweight string prints that bypass the standard heavily-formatted logger. + +## How to Enable + +These features are disabled by default to save firmware footprint. You can enable them via Kconfig: + +* `CONFIG_SOF_DEBUG_STREAM_SLOT=y` : Master switch. Reserves exactly one Memory Window 4k block (default Slot 3) mapping to host space. +* `CONFIG_SOF_DEBUG_STREAM_THREAD_INFO=y` : Activates the Zephyr thread statistics compiler integration (`INIT_STACKS`, `THREAD_MONITOR`). +* `CONFIG_SOF_DEBUG_STREAM_TEXT_MSG=y` : Allows calling `ds_msg("...", ...)` scattered throughout DSP C code to emit plain strings. + +## Architecture + +The architecture revolves around a "Slot" abstraction where data is copied sequentially over a ringbuffer into the ADSP debug window slot used for the debug stream (mapped over PCIe/SPI for the Host to read non-destructively). + +```mermaid +graph TD + subgraph SOF Firmware + SysEvent["System Event / OS Timer"] --> |Triggers| DSThread["Thread Info Collector"] + DevCode["Developer Code"] --> |"ds_msg()"| Text["Text Subsystem"] + + DSThread --> Formatter[DS Formatter] + Text --> Formatter + + Formatter --> Slot[Memory Window Slot 3] + end + + subgraph Host System + PyTool[tools/debug_stream/debug_stream.py] + Slot -.->|PCIe DMA / IPC Memory| PyTool + PyTool --> |Stdout| User[Developer Terminal] + end +``` + +## Usage Example + +If you enable `CONFIG_SOF_DEBUG_STREAM_TEXT_MSG=y`, developers can insert rapid debug markers without setting up topology traces: + +```c +#include <user/debug_stream_text_msg.h> + +void my_function() { + ds_msg("Reached tricky initialization state! Value: %d", some_val); +} +``` + +On the host machine, you extract this continuous output stream by running the provided SOF tooling: + +```bash +python3 tools/debug_stream/debug_stream.py +``` diff --git a/src/debug/debug_stream/debug_stream_slot.c b/src/debug/debug_stream/debug_stream_slot.c index 349eb2693137..db27490a98a4 100644 --- a/src/debug/debug_stream/debug_stream_slot.c +++ b/src/debug/debug_stream/debug_stream_slot.c @@ -10,21 +10,41 @@ #include <rtos/string.h> #include <user/debug_stream.h> #include <user/debug_stream_slot.h> +#include <zephyr/kernel.h> -LOG_MODULE_REGISTER(debug_strem_slot); +#ifdef CONFIG_USERSPACE +#include <zephyr/internal/syscall_handler.h> +#endif + +LOG_MODULE_REGISTER(debug_stream_slot); struct cpu_mutex { - struct k_mutex m; + struct k_spinlock l; } __aligned(CONFIG_DCACHE_LINE_SIZE); /* CPU specific mutexes for each circular buffer */ -static struct cpu_mutex cpu_mutex[CONFIG_MP_MAX_NUM_CPUS]; +static struct cpu_mutex cpu_mutex[CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS]; +#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER +static struct debug_stream_slot_hdr *dbg_stream_slot; +#else static const int debug_stream_slot = CONFIG_SOF_DEBUG_STREAM_SLOT_NUMBER; +#endif static struct debug_stream_slot_hdr *debug_stream_get_slot(void) { +#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER + if (!dbg_stream_slot) { + struct adsp_dw_desc slot_desc = { .type = ADSP_DW_SLOT_DEBUG_STREAM, }; + + dbg_stream_slot = (struct debug_stream_slot_hdr *) + adsp_dw_request_slot(&slot_desc, NULL); + } + + return dbg_stream_slot; +#else return (struct debug_stream_slot_hdr *)ADSP_DW->slots[debug_stream_slot]; +#endif } static @@ -38,21 +58,28 @@ debug_stream_get_circular_buffer(struct debug_stream_section_descriptor *desc, u return NULL; } + if (core >= CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS) { + LOG_DBG("No section for cpu %u >= %u ", core, + CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS); + return NULL; + } + *desc = hdr->section_desc[core]; LOG_DBG("Section %u (desc %u %u %u)", core, desc->core_id, desc->buf_words, desc->offset); return (struct debug_stream_circular_buf *) (((uint8_t *)hdr) + desc->offset); } -int debug_stream_slot_send_record(struct debug_stream_record *rec) +int z_impl_debug_stream_slot_send_record(struct debug_stream_record *rec) { struct debug_stream_section_descriptor desc = { 0 }; struct debug_stream_circular_buf *buf = debug_stream_get_circular_buffer(&desc, arch_proc_id()); uint32_t record_size = rec->size_words; uint32_t record_start, buf_remain; + k_spinlock_key_t key; - LOG_DBG("Sending record %u id %u len %u\n", rec->seqno, rec->id, rec->size_words); + LOG_DBG("Sending record %u id %u len %u", rec->seqno, rec->id, rec->size_words); if (!buf) return -ENODEV; @@ -62,7 +89,7 @@ int debug_stream_slot_send_record(struct debug_stream_record *rec) desc.buf_words, desc.core_id, desc.buf_words, desc.offset); return -ENOMEM; } - k_mutex_lock(&cpu_mutex[arch_proc_id()].m, K_FOREVER); + key = k_spin_lock(&cpu_mutex[arch_proc_id()].l); rec->seqno = buf->next_seqno++; rec->size_words = record_size + 1; /* +1 for size at the end of record */ @@ -90,65 +117,71 @@ int debug_stream_slot_send_record(struct debug_stream_record *rec) buf->data[buf->w_ptr] = record_size + 1; buf->w_ptr = (buf->w_ptr + 1) % desc.buf_words; - k_mutex_unlock(&cpu_mutex[arch_proc_id()].m); + k_spin_unlock(&cpu_mutex[arch_proc_id()].l, key); - LOG_DBG("Record %u id %u len %u sent\n", rec->seqno, rec->id, record_size); + LOG_DBG("Record %u id %u len %u sent", rec->seqno, rec->id, record_size); return 0; } +#ifdef CONFIG_USERSPACE +static inline int z_vrfy_debug_stream_slot_send_record(struct debug_stream_record *rec) +{ + K_OOPS(K_SYSCALL_MEMORY_READ(rec, sizeof(*rec))); + K_OOPS(K_SYSCALL_MEMORY_READ(rec, rec->size_words * sizeof(uint32_t))); + return z_impl_debug_stream_slot_send_record(rec); +} +#include <zephyr/syscalls/debug_stream_slot_send_record_mrsh.c> +#endif + static int debug_stream_slot_init(void) { struct debug_stream_slot_hdr *hdr = debug_stream_get_slot(); - size_t hdr_size = ALIGN_UP(offsetof(struct debug_stream_slot_hdr, - section_desc[CONFIG_MP_MAX_NUM_CPUS]), - CONFIG_DCACHE_LINE_SIZE); + size_t hdr_size = ALIGN_UP( + offsetof(struct debug_stream_slot_hdr, + section_desc[CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS]), + CONFIG_DCACHE_LINE_SIZE); size_t section_area_size = ADSP_DW_SLOT_SIZE - hdr_size; size_t section_size = ALIGN_DOWN(section_area_size / - CONFIG_MP_MAX_NUM_CPUS, + CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS, CONFIG_DCACHE_LINE_SIZE); size_t offset = hdr_size; int i; - LOG_INF("%u sections of %u bytes, hdr %u, section area %u\n", - CONFIG_MP_MAX_NUM_CPUS, section_size, hdr_size, + LOG_INF("%u sections of %u bytes, hdr %u, section area %u", + CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS, section_size, hdr_size, section_area_size); +#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER + if (!hdr) + return -ENOMEM; +#else if (ADSP_DW->descs[debug_stream_slot].type != 0) LOG_WRN("Slot %d was not free: %u", debug_stream_slot, ADSP_DW->descs[debug_stream_slot].type); ADSP_DW->descs[debug_stream_slot].type = ADSP_DW_SLOT_DEBUG_STREAM; +#endif hdr->hdr.magic = DEBUG_STREAM_IDENTIFIER; hdr->hdr.hdr_size = hdr_size; - hdr->total_size = hdr_size + CONFIG_MP_MAX_NUM_CPUS * section_size; - hdr->num_sections = CONFIG_MP_MAX_NUM_CPUS; - for (i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) { + hdr->total_size = hdr_size + CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS * section_size; + hdr->num_sections = CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS; + for (i = 0; i < CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS; i++) { hdr->section_desc[i].core_id = i; hdr->section_desc[i].buf_words = - (section_size - offsetof(struct debug_stream_circular_buf, data[0]))/ + (section_size - offsetof(struct debug_stream_circular_buf, data[0])) / sizeof(uint32_t); hdr->section_desc[i].offset = offset; - LOG_INF("sections %u, size %u, offset %u\n", - i, section_size, offset); + LOG_DBG("sections %u, size %u, offset %u", i, section_size, offset); offset += section_size; } - for (i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) { + for (i = 0; i < CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS; i++) { struct debug_stream_section_descriptor desc = { 0 }; - struct debug_stream_circular_buf *buf = - debug_stream_get_circular_buffer(&desc, i); + struct debug_stream_circular_buf *buf = debug_stream_get_circular_buffer(&desc, i); buf->next_seqno = 0; buf->w_ptr = 0; - k_mutex_init(&cpu_mutex[i].m); - /* The core specific mutexes are now .bss which is uncached so the - * following line is commented out. However, since the mutexes are - * core specific there should be nothing preventing from having them - * in cached memory. - * - * sys_cache_data_flush_range(&cpu_mutex[i], sizeof(cpu_mutex[i])); - */ } - LOG_INF("Debug stream slot initialized\n"); + LOG_DBG("Debug stream slot initialized"); return 0; } diff --git a/src/debug/debug_stream/debug_stream_text_msg.c b/src/debug/debug_stream/debug_stream_text_msg.c new file mode 100644 index 000000000000..f4b67d4d307a --- /dev/null +++ b/src/debug/debug_stream/debug_stream_text_msg.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Intel Corporation. + +#include <sys/types.h> +#include <stdarg.h> +#include <stdio.h> +#include <soc.h> +#include <adsp_debug_window.h> +#include <sof/common.h> +#include <zephyr/logging/log.h> +#include <zephyr/arch/exception.h> + +#include <user/debug_stream_text_msg.h> + +LOG_MODULE_REGISTER(debug_stream_text_msg); + +void ds_vamsg(const char *format, va_list args) +{ + struct { + struct debug_stream_text_msg msg; + char text[128]; + } __packed buf = { 0 }; + ssize_t len; + + len = vsnprintf(buf.text, sizeof(buf.text), format, args); + + if (len < 0) + return; + len = MIN(len, sizeof(buf.text)); + + buf.msg.hdr.id = DEBUG_STREAM_RECORD_ID_TEXT_MSG; + buf.msg.hdr.size_words = SOF_DIV_ROUND_UP(sizeof(buf.msg) + len, + sizeof(buf.msg.hdr.data[0])); + debug_stream_slot_send_record(&buf.msg.hdr); +} + +void ds_msg(const char *format, ...) +{ + va_list args; + + va_start(args, format); + ds_vamsg(format, args); + va_end(args); +} +EXPORT_SYMBOL(ds_msg); + +#if defined(CONFIG_EXCEPTION_DUMP_HOOK) +/* The debug stream debug window slot is 4k, and when it is split + * between the cores and the header/other overhead is removed, with 5 + * cores the size is 768 bytes. The dump record must be smaller than + * that to get through to the host side. + * + * Also, because of the limited circular buffer size, we should only + * send one exception record. On some situations the exceptions happen + * in bursts, and sending more than one record in short time makes the + * host-side decoder lose track of things. + */ + +/* Per-CPU state for exception dump and assert_print(). Static data is + * currently placed in .bss and its ATM uncached so the ds_cpu table + * elements do not need to be cache aligned, but if this changes we + * need __aligned(CONFIG_DCACHE_LINE_SIZE) here. + */ +static struct ds_cpu_state { + struct { + struct debug_stream_text_msg msg; + char text[640]; + } __packed buf; + int reports_sent; + size_t pos; +} ds_cpu[CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS]; + +static void ds_exception_drain(bool flush) +{ + unsigned int cpu = arch_proc_id(); + struct ds_cpu_state *cs = &ds_cpu[cpu]; + + if (flush) { + cs->pos = 0; + return; + } + + if (cs->pos == 0) + return; + + if (cs->reports_sent > 0) + return; + + cs->buf.msg.hdr.id = DEBUG_STREAM_RECORD_ID_TEXT_MSG; + cs->buf.msg.hdr.size_words = + SOF_DIV_ROUND_UP(sizeof(cs->buf.msg) + cs->pos, + sizeof(cs->buf.msg.hdr.data[0])); + + /* Make sure the possible up to 3 extra bytes at end of msg are '\0' */ + memset(cs->buf.text + cs->pos, 0, + cs->buf.msg.hdr.size_words * sizeof(cs->buf.msg.hdr.data[0]) - cs->pos); + debug_stream_slot_send_record(&cs->buf.msg.hdr); + cs->reports_sent = 1; + cs->pos = 0; +} + +static void ds_exception_dump(const char *format, va_list args) +{ + ssize_t len; + size_t avail; + size_t written; + unsigned int cpu = arch_proc_id(); + struct ds_cpu_state *cs = &ds_cpu[cpu]; + + if (cs->reports_sent > 0) + return; + + avail = sizeof(cs->buf.text) - cs->pos; + if (avail == 0) { + ds_exception_drain(false); + return; + } + + if (format[0] == '\0') + return; + + /* Skip useless " ** " prefix to save bytes */ + if (strlen(format) >= 4 && + format[0] == ' ' && format[1] == '*' && format[2] == '*' && format[3] == ' ') + format += 4; + + len = vsnprintf(cs->buf.text + cs->pos, avail, format, args); + if (len < 0) { + cs->pos = 0; + return; + } + + if (len == 0) + return; + + if ((size_t)len >= avail) + written = avail - 1; + else + written = (size_t)len; + + cs->pos += written; + + if (cs->pos >= sizeof(cs->buf.text)) + ds_exception_drain(false); +} + +static int init_exception_dump_hook(void) +{ + arch_exception_set_dump_hook(ds_exception_dump, ds_exception_drain); + LOG_DBG("exception_dump_hook set"); + return 0; +} + +SYS_INIT(init_exception_dump_hook, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +#if defined(CONFIG_SOF_DEBUG_STREAM_TEXT_MSG_ASSERT_PRINT) +void assert_print(const char *fmt, ...) +{ + va_list ap; + + /* Do not print assert after exception has been dumped */ + if (ds_cpu[arch_proc_id()].reports_sent > 0) + return; + + va_start(ap, fmt); +#if !defined(CONFIG_EXCEPTION_DUMP_HOOK_ONLY) + { + va_list ap2; + + va_copy(ap2, ap); +#endif + ds_vamsg(fmt, ap); +#if !defined(CONFIG_EXCEPTION_DUMP_HOOK_ONLY) + vprintk(fmt, ap2); + va_end(ap2); + } +#endif + ds_vamsg(fmt, ap); + va_end(ap); +} +EXPORT_SYMBOL(assert_print); +#endif +#endif diff --git a/src/debug/debug_stream/debug_stream_thread_info.c b/src/debug/debug_stream/debug_stream_thread_info.c index a4cb056ec2ac..5c0d1bd7ffb1 100644 --- a/src/debug/debug_stream/debug_stream_thread_info.c +++ b/src/debug/debug_stream/debug_stream_thread_info.c @@ -22,6 +22,9 @@ LOG_MODULE_REGISTER(thread_info); /* Data structure to store the cycle counter values from the previous * round. The numbers are used to calculate what the load was on this * round. + * Static data is currently placed in .bss and its ATM uncached so the + * ds_cpu table elements do not need to be cache aligned, but if this + * changes we need __aligned(CONFIG_DCACHE_LINE_SIZE) here. */ static struct previous_counters { /* Cached data from previous round */ uint64_t active; /* All execution cycles */ @@ -30,7 +33,7 @@ static struct previous_counters { /* Cached data from previous round */ void *tid; /* thread ID (the thread struct ptr) */ uint64_t cycles; /* cycle counter value */ } threads[THREAD_INFO_MAX_THREADS]; /* The max amount of threads we follow */ -} __aligned(CONFIG_DCACHE_LINE_SIZE) previous[CONFIG_MP_MAX_NUM_CPUS]; +} previous[CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS]; #endif /* @@ -173,7 +176,7 @@ static int thread_info_buf_realloc(struct record_buf *bufd, size_t req_size) size *= 2; if (size != bufd->size) { - uint8_t *buf = rmalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, size); + uint8_t *buf = rmalloc(SOF_MEM_FLAG_USER, size); if (!buf) return -ENOMEM; @@ -225,6 +228,13 @@ static void thread_info_cb(const struct k_thread *cthread, void *user_data) tinfo->name, tinfo->stack_usage * 100U / 255, tinfo->cpu_usage * 100U / 255); + /* .is_idle depends on CONFIG_SMP */ +#if defined(CONFIG_SOF_DEBUG_STREAM_THREAD_INFO_TOTAL_CPU_LOAD_TO_LOG) && defined(CONFIG_SMP) + if (thread->base.is_idle) + LOG_INF("core %u utilization %u%%", ud->core, + 100U - tinfo->cpu_usage * 100U / 255); +#endif + ud->thread_count++; } @@ -321,7 +331,7 @@ static void thread_info_run(void *cnum, void *a, void *b) .w_ptr = 0, }; - bufd.buf = rmalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, bufd.size); + bufd.buf = rmalloc(SOF_MEM_FLAG_USER, bufd.size); if (!bufd.buf) { LOG_ERR("malloc failed"); return; @@ -334,9 +344,10 @@ static void thread_info_run(void *cnum, void *a, void *b) } #define THREAD_STACK_SIZE (2048) -static K_THREAD_STACK_ARRAY_DEFINE(info_thread_stacks, CONFIG_MP_MAX_NUM_CPUS, +static K_THREAD_STACK_ARRAY_DEFINE(info_thread_stacks, + CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS, THREAD_STACK_SIZE); -static struct k_thread info_thread[CONFIG_MP_MAX_NUM_CPUS]; +static struct k_thread info_thread[CONFIG_SOF_DEBUG_STREAM_SLOT_FORCE_MAX_CPUS]; static int thread_info_start(void) { @@ -356,12 +367,14 @@ static int thread_info_start(void) LOG_ERR("k_thread_create() failed for core %u", i); continue; } +#ifdef CONFIG_SCHED_CPU_MASK ret = k_thread_cpu_pin(tid, i); if (ret < 0) { LOG_ERR("Pinning thread to code core %u", i); k_thread_abort(tid); continue; } +#endif snprintf(name, sizeof(name), "%u thread info", i); ret = k_thread_name_set(tid, name); if (ret < 0) diff --git a/src/debug/dram.c b/src/debug/dram.c new file mode 100644 index 000000000000..5721a8b73e87 --- /dev/null +++ b/src/debug/dram.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <rtos/kernel.h> +#include <rtos/symbol.h> +#include <zephyr/logging/log.h> +#include <zephyr/sys/__assert.h> + +LOG_MODULE_REGISTER(dbg_path, CONFIG_SOF_LOG_LEVEL); + +static struct k_spinlock hot_path_lock; +static unsigned int hot_path_depth; +static const char *cold_path_fn; +static bool hot_path_confirmed; + +void dbg_path_cold_enter(const char *fn) +{ + k_spinlock_key_t key = k_spin_lock(&hot_path_lock); + + cold_path_fn = fn; + + k_spin_unlock(&hot_path_lock, key); +} +EXPORT_SYMBOL(dbg_path_cold_enter); + +void dbg_path_hot_start_watching(void) +{ + k_spinlock_key_t key = k_spin_lock(&hot_path_lock); + + if (!hot_path_depth++) { + cold_path_fn = NULL; + hot_path_confirmed = false; + } + + k_spin_unlock(&hot_path_lock, key); +} + +void dbg_path_hot_confirm(void) +{ + k_spinlock_key_t key = k_spin_lock(&hot_path_lock); + + hot_path_confirmed = true; + + k_spin_unlock(&hot_path_lock, key); +} + +void dbg_path_hot_stop_watching(void) +{ + bool underrun, error; + k_spinlock_key_t key = k_spin_lock(&hot_path_lock); + + if (hot_path_depth) { + underrun = false; + hot_path_depth--; + error = hot_path_confirmed && cold_path_fn; + } else { + error = underrun = true; + } + + k_spin_unlock(&hot_path_lock, key); + + if (underrun) + LOG_ERR("Hot path depth underrun!"); + else + __ASSERT(!error, "Cold function %s() has run while on hot path!", cold_path_fn); +} diff --git a/src/debug/gdb/CMakeLists.txt b/src/debug/gdb/CMakeLists.txt index 3cd0fe5f2d2b..4ca1af254b05 100644 --- a/src/debug/gdb/CMakeLists.txt +++ b/src/debug/gdb/CMakeLists.txt @@ -1,5 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause +# Common to Zephyr and XTOS add_local_sources(sof gdb.c ringbuffer.c diff --git a/src/debug/gdb/README.md b/src/debug/gdb/README.md new file mode 100644 index 000000000000..33b6a31915c1 --- /dev/null +++ b/src/debug/gdb/README.md @@ -0,0 +1,65 @@ +# GDB Remote Debugging Stub + +The Sound Open Firmware (SOF) project carries a GNU Debugger (GDB) stub directly integrated with the framework's exception handlers. This translates commands sent by a GDB client (running on the host Linux machine) into architecture-specific logic. + +## Feature Overview + +Instead of completely relying on complex JTAG setups, developers can use this stub to dynamically introspect panic states, stack traces, and variable states during firmware execution, particularly inside isolated SoC DSP cores. + +When the firmware faults or hits a defined breakpoint, the exception vector routes control into this stub. It then waits for GDB Remote Protocol packet streams (ASCII formatted over the SOF mailbox/shared memory window). The Host reads these mailbox slots and pushes/pulls responses to its active GNU Debugger session. + +## Architecture + +Data moves between the Host GDB environment, the physical mailboxes bounding the DSP domain, the DSP firmware's built-in stub, and the active exception state. + +```mermaid +sequenceDiagram + participant GdbSession as Host GDB Client + participant IPC as SOF Driver / ALSA + participant Stub as Firmware GDB Stub (gdb_parser) + participant HW as DSP Context Registers + + HW-->>Stub: Hard Fault / Breakpoint Hit + activate Stub + + Note over Stub: Stores fault context (sregs/aregs) + + Stub-->>IPC: Write Mailbox: Breakpoint Notification + + GdbSession->>IPC: Send Packet (e.g., $g#67 to Read Regs) + IPC->>Stub: Passes 'g' string + + Stub->>HW: Reads requested register values + HW-->>Stub: Values + + Stub->>Stub: mem_to_hex() formatting + Stub-->>GdbSession: Returns hex payload via Mailbox + + GdbSession->>IPC: Send Packet ($c#63 to Continue) + IPC->>Stub: Process 'c' + Stub->>HW: Restores Context, Retains Execution + deactivate Stub +``` + +## How to Enable + +A basic GDB debugging configuration is exposed via Kconfig and must be explicitly bound: + +* `CONFIG_GDB_DEBUG`: Needs to be toggled `=y` to compile `src/debug/gdb/gdb.c` into the main application. + +Additionally, the overarching architecture requires the corresponding Exception vectors to be rewritten. In Zephyr OS based builds (which currently drive native architectures), fatal exception handling must be configured to pass register dumps recursively to `gdb_handle_exception()`. + +## Usage and Protocols + +The protocol adheres precisely to the standard GDB remote serial specification. Each string packet expects the format: + +`$<packet-data>#<check-sum>` + +Supported Command Handlers inside the Stub: + +* `g` (Read all registers) / `G` (Write all registers) +* `m` (Read memory) / `M` (Write memory) +* `p` (Read specific register) / `P` (Write specific register) +* `v` (Query architecture/support details like `vCont`) +* `c` / `s` (Continue execution / Single-step) +* `z` / `Z` (Insert/Remove breakpoints) diff --git a/src/debug/telemetry/Kconfig b/src/debug/telemetry/Kconfig index 6e6a55d18f3c..f380a90e1808 100644 --- a/src/debug/telemetry/Kconfig +++ b/src/debug/telemetry/Kconfig @@ -3,6 +3,7 @@ config SOF_TELEMETRY bool "enable telemetry" default n + depends on !SOF_USERSPACE_LL help Enables telemetry. Enables performance measurements and debug utilities that use memory window 2 (debug window) as interface. Measurements include diff --git a/src/debug/telemetry/README.md b/src/debug/telemetry/README.md new file mode 100644 index 000000000000..19664ad2be8c --- /dev/null +++ b/src/debug/telemetry/README.md @@ -0,0 +1,48 @@ +# Telemetry and Performance Measurements + +The SOF Telemetry subsystem is a suite of built-in diagnostics measuring code execution efficiencies, cycle overheads, and hardware I/O throughput. + +## Feature Overview + +Latency and real-time execution bounds are critical in DSP firmware. The telemetry feature provides mechanisms to monitor these bounds accurately without intrusive breakpoints or slowing down the pipeline too aggressively. + +Capabilities include: + +1. **Component Performance Tracking**: For every instantiated component in the graph, it measures the pure execution time bounds (min/max/average) of that component's `comp_copy()` routines. +2. **I/O Throughput Tracking**: Measures hardware bus speeds or message handling by counting bytes, state changes, or tokens across distinct interfaces: IPC, DMIC, I2S, HD/A, I2C, SPI, etc. +3. **Zephyr Systick Measurement**: Specifically tracks the overall scheduler overhead bounding RTOS ticks. + +Measurements are batched into a ringbuffer locally, then synced across mapped ADSP memory windows into user space, limiting the impact on the active instruction cache. + +## Architecture + +The architecture bridges the component layer (like pure IPC or Audio Component wrappers) directly into independent statistics accumulators. + +```mermaid +graph TD + subgraph DSP Environment + Comp[Audio Component X] --> |"comp_copy() Execution"| Telemetry[perf_measure_execute] + HW[I2S / DMIC HW Driver] --> |"State Change Count"| Telemetry + + Telemetry --> RingBuffer[Statistics Ringbuffer] + RingBuffer --> Sync["Memory Window 3 (perf_data_sync)"] + end + + subgraph Host Userspace + Dev[sof-logger / IPC Tooling] --> |Reads/Queries| Sync + end +``` + +## How to Enable + +Telemetry depends strictly on NOT being built inside a host-userspace environment simulator (`depends on !SOF_USERSPACE_LL`). Ensure your target is a physical or emulated DSP target. + +Settings to configure in `Kconfig`: + +* `CONFIG_SOF_TELEMETRY=y` : Enable the overarching telemetry interfaces, giving you systick and basic task metrics over Memory Window 2 interfaces. +* `CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS=y` : Adds granular tracking to audio components (creating the explicit `telemetry.c` ringbuffer maps via Memory Window 3 slots). Be aware that only a specific configured amount (`PERFORMANCE_DATA_ENTRIES_COUNT`) can be actively tracked due to RAM constraints. +* `CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS=y` : Instructs hardware and communication buses to start pumping data into the metrics collector. + +## Extracting Data + +You can fetch these metrics via `sof-logger` or standard IPC interrogation tools that support polling the corresponding debug window slots mapped for your particular platform's `ADSP_MW`. diff --git a/src/debug/telemetry/performance_monitor.c b/src/debug/telemetry/performance_monitor.c index dc5e80c7c253..f84b122b4d8a 100644 --- a/src/debug/telemetry/performance_monitor.c +++ b/src/debug/telemetry/performance_monitor.c @@ -8,6 +8,7 @@ #include <sof/debug/telemetry/performance_monitor.h> #include <sof/debug/telemetry/telemetry.h> #include <sof/lib/cpu.h> +#include <sof/lib/memory.h> #include <sof/lib_manager.h> #include <zephyr/sys/bitarray.h> @@ -128,7 +129,7 @@ static bool perf_bitmap_is_bit_clear(struct perf_bitmap * const bitmap, size_t b struct perf_data_item_comp *perf_data_getnext(void) { - int idx; + size_t idx; int ret = perf_bitmap_alloc(&performance_data_bitmap, &idx); if (ret < 0) @@ -138,8 +139,10 @@ struct perf_data_item_comp *perf_data_getnext(void) * ,and always set bit on bitmap alloc. */ ret = perf_bitmap_setbit(&performance_data_bitmap, idx); - if (ret < 0) + if (ret < 0) { + perf_bitmap_free(&performance_data_bitmap, idx); return NULL; + } return &perf_data[idx]; } @@ -211,10 +214,17 @@ int get_performance_data(struct global_perf_data * const global_perf_data) size_t slots_count; size_t slot_idx = 0; +#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER + struct system_tick_info *systick_info = telemetry_get_systick_info_ptr(); + + if (!systick_info) + return 0; +#else struct telemetry_wnd_data *wnd_data = (struct telemetry_wnd_data *)ADSP_DW->slots[SOF_DW_TELEMETRY_SLOT]; struct system_tick_info *systick_info = (struct system_tick_info *)wnd_data->system_tick_info; +#endif /* Fill one performance record with performance stats per core */ for (int core_id = 0; core_id < CONFIG_MAX_CORE_COUNT; ++core_id) { @@ -337,7 +347,7 @@ int enable_performance_counters(void) desc = basefw_vendor_get_manifest(); } else { #if CONFIG_LIBRARY_MANAGER - desc = (struct sof_man_fw_desc *)lib_manager_get_library_manifest(lib_id); + desc = lib_manager_get_library_manifest(LIB_MANAGER_PACK_LIB_ID(lib_id)); #else desc = NULL; #endif @@ -369,10 +379,17 @@ int reset_performance_counters(void) if (perf_measurements_state == IPC4_PERF_MEASUREMENTS_DISABLED) return -EINVAL; +#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER + struct system_tick_info *systick_info = telemetry_get_systick_info_ptr(); + + if (!systick_info) + return 0; +#else struct telemetry_wnd_data *wnd_data = (struct telemetry_wnd_data *)ADSP_DW->slots[SOF_DW_TELEMETRY_SLOT]; struct system_tick_info *systick_info = (struct system_tick_info *)wnd_data->system_tick_info; +#endif for (int core_id = 0; core_id < CONFIG_MAX_CORE_COUNT; ++core_id) { if (!(cpu_enabled_cores() & BIT(core_id))) @@ -411,11 +428,13 @@ SYS_BITARRAY_DEFINE_STATIC(io_performance_data_bit_array, PERFORMANCE_DATA_ENTRI static struct io_perf_monitor_ctx perf_monitor_ctx; static struct io_perf_data_item io_perf_data_items[IO_PERFORMANCE_MAX_ENTRIES]; -int io_perf_monitor_init(void) +__cold int io_perf_monitor_init(void) { int ret; struct io_perf_monitor_ctx *self = &perf_monitor_ctx; + assert_can_be_cold(); + k_spinlock_init(&self->lock); k_spinlock_key_t key = k_spin_lock(&self->lock); @@ -431,24 +450,30 @@ int io_perf_monitor_init(void) static struct io_perf_data_item *io_perf_monitor_get_next_slot(struct io_perf_monitor_ctx *self) { - int idx; + size_t idx; int ret; k_spinlock_key_t key = k_spin_lock(&self->lock); ret = perf_bitmap_alloc(&self->io_performance_data_bitmap, &idx); if (ret < 0) - return NULL; + goto out_unlock; /* ref. FW did not set the bits, but here we do it to not have to use * isFree() check that the bitarray does not provide yet. Instead we will use isClear * ,and always set bit on bitmap alloc. */ ret = perf_bitmap_setbit(&self->io_performance_data_bitmap, idx); - if (ret < 0) - return NULL; + if (ret < 0) { + perf_bitmap_free(&self->io_performance_data_bitmap, idx); + goto out_unlock; + } k_spin_unlock(&self->lock, key); return &self->io_perf_data[idx]; + +out_unlock: + k_spin_unlock(&self->lock, key); + return NULL; } int io_perf_monitor_release_slot(struct io_perf_data_item *item) diff --git a/src/debug/telemetry/telemetry.c b/src/debug/telemetry/telemetry.c index 3cbd28774543..1e4c522dfee0 100644 --- a/src/debug/telemetry/telemetry.c +++ b/src/debug/telemetry/telemetry.c @@ -27,6 +27,10 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); /* Systic variables, one set per core */ static int telemetry_systick_counter[CONFIG_MAX_CORE_COUNT]; +#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER +static struct telemetry_wnd_data *wnd_data; +#endif + #ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS static int telemetry_prev_ccount[CONFIG_MAX_CORE_COUNT]; static int telemetry_perf_period_sum[CONFIG_MAX_CORE_COUNT]; @@ -68,19 +72,45 @@ static size_t telemetry_perf_queue_avg(struct telemetry_perf_queue *q) } #endif +#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER +struct system_tick_info *telemetry_get_systick_info_ptr(void) +{ + if (!wnd_data) + return NULL; + + return (struct system_tick_info *)wnd_data->system_tick_info; +} +#endif + int telemetry_init(void) { /* systick_init */ +#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER + struct adsp_dw_desc slot_desc = { .type = ADSP_DW_SLOT_TELEMETRY, }; + struct system_tick_info *systick_info; + + if (wnd_data) + return 0; + + wnd_data = (struct telemetry_wnd_data *)adsp_dw_request_slot(&slot_desc, + NULL); + if (!wnd_data) + return -ENOMEM; + + systick_info = (struct system_tick_info *)wnd_data->system_tick_info; +#else uint8_t slot_num = SOF_DW_TELEMETRY_SLOT; volatile struct adsp_debug_window *window = ADSP_DW; struct telemetry_wnd_data *wnd_data = (struct telemetry_wnd_data *)ADSP_DW->slots[slot_num]; struct system_tick_info *systick_info = (struct system_tick_info *)wnd_data->system_tick_info; - tr_info(&ipc_tr, "Telemetry enabled. May affect performance"); - window->descs[slot_num].type = ADSP_DW_SLOT_TELEMETRY; window->descs[slot_num].resource_id = 0; +#endif + + tr_info(&ipc_tr, "Telemetry enabled. May affect performance"); + wnd_data->separator_1 = 0x0000C0DE; /* Zero values per core */ @@ -101,13 +131,19 @@ int telemetry_init(void) void telemetry_update(uint32_t begin_stamp, uint32_t current_stamp) { int prid = cpu_get_id(); +#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER + struct system_tick_info *systick_info = telemetry_get_systick_info_ptr(); - ++telemetry_systick_counter[prid]; - + if (!systick_info) + return; +#else struct telemetry_wnd_data *wnd_data = (struct telemetry_wnd_data *)ADSP_DW->slots[SOF_DW_TELEMETRY_SLOT]; struct system_tick_info *systick_info = (struct system_tick_info *)wnd_data->system_tick_info; +#endif + + ++telemetry_systick_counter[prid]; systick_info[prid].count = telemetry_systick_counter[prid]; systick_info[prid].last_time_elapsed = current_stamp - begin_stamp; diff --git a/src/debug/tester/CMakeLists.txt b/src/debug/tester/CMakeLists.txt new file mode 100644 index 000000000000..85bf026b5ed3 --- /dev/null +++ b/src/debug/tester/CMakeLists.txt @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: BSD-3-Clause + +set(base_files + tester.c + tester_dummy_test.c + tester_simple_dram_test.c +) + +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + if(CONFIG_COMP_TESTER STREQUAL "m" AND DEFINED CONFIG_LLEXT) + + add_subdirectory(llext ${PROJECT_BINARY_DIR}/tester_llext) + add_dependencies(app tester) + + elseif(CONFIG_COMP_TESTER STREQUAL "y") + + zephyr_library_sources(${base_files}) + + endif() + +endif() diff --git a/src/debug/tester/Kconfig b/src/debug/tester/Kconfig new file mode 100644 index 000000000000..66a5140a097c --- /dev/null +++ b/src/debug/tester/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config COMP_TESTER + tristate "tester module" + default n + depends on IPC_MAJOR_4 + help + Build a tester module. To be used in continuous + integration process for special test cases that + require a test code injected into the system itself \ No newline at end of file diff --git a/src/debug/tester/README.md b/src/debug/tester/README.md new file mode 100644 index 000000000000..bd558fd80a4d --- /dev/null +++ b/src/debug/tester/README.md @@ -0,0 +1,54 @@ +# Tester Component + +The `tester` directory implements a pseudo-component inside the SOF architecture. Instead of processing audio like an EQ or Mixer, it acts as a test execution harness designed specifically for Continuous Integration (CI) and automated system verifications. + +## Feature Overview + +Continuous integration often requires validating low-level system interactions that cannot be reached or easily triggered via standard ALSA driver behaviors. To overcome this, the `tester` component can be instantiated via Topologies or explicit IPC commands. Once bound, the host can send configuration blobs triggering embedded testing subroutines compiled directly into the firmware. + +Currently, it supports functionalities like: + +* **Dummy Operations**: Echoing parameters to verify full-stack serialization roundtrips. +* **DRAM Verification**: Stress-testing memory allocation arrays within the `LLB`/`L2` domains to detect caching bugs or out-of-bounds pointer crashes (`tester_simple_dram_test`). + +## Architecture + +The architecture functions identical to an IPC Version 4 standard module, containing `comp_driver`, `comp_dev`, `comp_buffer` wrappers and implementing `tester_params()` handlers. + +```mermaid +graph TD + subgraph Host Automation + Testbench[CI Testbench / ALSA Tool] + Testbench -->> |Topology Payload: CMD_TEST| IPC + end + + subgraph SOF Firmware + IPC[IPC4 Handler] -->> |ipc4_set_module_params| Tester[Tester Component] + + Tester -->> |Switch on Test Type| Dummy[tester_dummy_test.c] + Tester -->> |Switch on Test Type| DRAM[tester_simple_dram_test.c] + + Dummy -->> IPC + DRAM -->> |Runs Data Verifications| ExtMemory[SoC DRAM / Caches] + DRAM -->> IPC + end +``` + +## How to Enable + +Because the tester artificially exposes internal memory bounds limits and allows arbitrary firmware injection tests, it is locked out of standard release payloads. + +To compile it into your build, you must append: + +* `CONFIG_COMP_TESTER=y` + +**Constraints:** +It strictly `depends on IPC_MAJOR_4`. You cannot instantiate this tester under the legacy IPC3 streaming mechanisms. + +## Creating New Tests + +Developers diagnosing tricky hardware bugs can extend the tester by: + +1. Adding a new case to the test selection switch in `tester.c:tester_init()` (and, if needed, extending runtime handling in `tester_set_configuration()`). +2. Defining a new `test_runner()` C file implementing their data patterns. +3. Adding the target configurations in `tester.toml` to automatically sync with the module offset calculators (`llext_offset_calc`). diff --git a/src/debug/tester/llext/CMakeLists.txt b/src/debug/tester/llext/CMakeLists.txt new file mode 100644 index 000000000000..096cbf65d853 --- /dev/null +++ b/src/debug/tester/llext/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +sof_llext_build("tester" + SOURCES ../tester.c + ../tester_dummy_test.c + ../tester_simple_dram_test.c +) diff --git a/src/debug/tester/llext/llext.toml.h b/src/debug/tester/llext/llext.toml.h new file mode 100644 index 000000000000..764d6e743506 --- /dev/null +++ b/src/debug/tester/llext/llext.toml.h @@ -0,0 +1,6 @@ +#include <tools/rimage/config/platform.toml> +#define LOAD_TYPE "2" +#include "../tester.toml" + +[module] +count = __COUNTER__ diff --git a/src/debug/tester/tester.c b/src/debug/tester/tester.c new file mode 100644 index 000000000000..161b90a7d3f3 --- /dev/null +++ b/src/debug/tester/tester.c @@ -0,0 +1,255 @@ +//SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// Author: Marcin Szkudlinski <marcin.szkudlinski@linux.intel.com> + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <rtos/init.h> +#include <sof/lib/uuid.h> +#include <sof/audio/component.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/sink_api.h> +#include <sof/audio/source_api.h> +#include <sof/audio/sink_source_utils.h> +#include "tester.h" +#include "tester_dummy_test.h" +#include "tester_simple_dram_test.h" + +/** + * Tester module is a framework for a runtime testing that need a special test code + * injected into the SOF system, i.e. + * - provide an extra load to CPU by running additional thread + * - execute some incorrect operations + * + * The idea is to allow using of special cases in testing like Continuous Integration or pre-release + * testing using a standard, production build. + * + * In order to have only one testing module (in meaning of a SOF module with separate UUID), + * a framework is introduced, where a test to be executed is selected by IPC parameter + * + * In production, module should be compiled as a loadable module, as it should not needed to be + * loaded and used on customers' boards. + * During developing, however, the module may be built in to keep debugging simpler + * + */ + +LOG_MODULE_REGISTER(tester, CONFIG_SOF_LOG_LEVEL); + +SOF_DEFINE_REG_UUID(tester); + +struct tester_init_config { + struct ipc4_base_module_cfg ipc4_cfg; + int32_t test_type; +} __attribute__((packed, aligned(4))); + +static int tester_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct comp_dev *dev = mod->dev; + struct module_config *cfg = &md->cfg; + size_t bs = cfg->size; + struct tester_module_data *cd = NULL; + int ret = 0; + + if (bs != sizeof(struct tester_init_config)) { + comp_err(dev, "Invalid config"); + return -EINVAL; + } + + /* allocate ctx for test module in shared memory - to allow all non-standard operations + * without problems with cache + */ + cd = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*cd)); + if (!cd) { + comp_err(dev, "Out of memory"); + return -ENOMEM; + } + + struct tester_init_config *init_cfg = (struct tester_init_config *)cfg->init_data; + + cd->test_case_type = init_cfg->test_type; + switch (cd->test_case_type) { + case TESTER_MODULE_CASE_DUMMY_TEST: + cd->tester_case_interface = &tester_interface_dummy_test; + break; + case TESTER_MODULE_CASE_SIMPLE_DRAM_TEST: + cd->tester_case_interface = &tester_interface_simple_dram_test; + break; + + default: + comp_err(dev, "Invalid config, unknown test type"); + rfree(cd); + return -EINVAL; + } + + module_set_private_data(mod, cd); + + if (cd->tester_case_interface->init) + ret = cd->tester_case_interface->init(mod, &cd->test_case_ctx); + + if (ret) { + module_set_private_data(mod, NULL); + rfree(cd); + } + + return ret; +} + +static int tester_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct tester_module_data *cd = module_get_private_data(mod); + int ret = 0; + + if (cd->tester_case_interface->prepare) + ret = cd->tester_case_interface->prepare(cd->test_case_ctx, mod, + sources, num_of_sources, + sinks, num_of_sinks); + + return ret; +} + +int tester_set_configuration(struct processing_module *mod, + uint32_t config_id, + enum module_cfg_fragment_position pos, uint32_t data_offset_size, + const uint8_t *fragment, size_t fragment_size, uint8_t *response, + size_t response_size) +{ + struct tester_module_data *cd = module_get_private_data(mod); + int ret = 0; + + if (cd->tester_case_interface->set_configuration) + ret = cd->tester_case_interface->set_configuration(cd->test_case_ctx, mod, + config_id, pos, data_offset_size, + fragment, fragment_size, + response, response_size); + + return ret; +} + +static int tester_process(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct tester_module_data *cd = module_get_private_data(mod); + int ret = 0; + bool do_copy = true; + + if (cd->tester_case_interface->process) + ret = cd->tester_case_interface->process(cd->test_case_ctx, mod, + sources, num_of_sources, + sinks, num_of_sinks, &do_copy); + + if (!ret) { + size_t sink_free = sink_get_free_size(sinks[0]); + size_t source_avail = source_get_data_available(sources[0]); + size_t to_copy = MIN(sink_free, source_avail); + + if (do_copy) { + /* copy data from input to output */ + source_to_sink_copy(sources[0], sinks[0], true, to_copy); + } else { + /* drop data and generate silence */ + source_drop_data(sources[0], to_copy); + sink_fill_with_silence(sinks[0], to_copy); + } + } + + return ret; +} + +static int tester_reset(struct processing_module *mod) +{ + struct tester_module_data *cd = module_get_private_data(mod); + int ret = 0; + + if (cd->tester_case_interface->reset) + ret = cd->tester_case_interface->reset(cd->test_case_ctx, mod); + + return ret; +} + +static int tester_free(struct processing_module *mod) +{ + struct tester_module_data *cd = module_get_private_data(mod); + int ret = 0; + + if (cd->tester_case_interface->free) + ret = cd->tester_case_interface->free(cd->test_case_ctx, mod); + + rfree(cd); + module_set_private_data(mod, NULL); + return ret; +} + +static int tester_bind(struct processing_module *mod, struct bind_info *bind_data) +{ + struct tester_module_data *cd = module_get_private_data(mod); + int ret = 0; + + if (cd->tester_case_interface->bind) + ret = cd->tester_case_interface->bind(cd->test_case_ctx, mod, bind_data); + + return ret; +} + +static int tester_unbind(struct processing_module *mod, struct bind_info *unbind_data) +{ + struct tester_module_data *cd = module_get_private_data(mod); + int ret = 0; + + if (cd->tester_case_interface->unbind) + ret = cd->tester_case_interface->unbind(cd->test_case_ctx, mod, unbind_data); + + return ret; +} + +static int tester_trigger(struct processing_module *mod, int cmd) +{ + struct tester_module_data *cd = module_get_private_data(mod); + int ret = 0; + + if (cd->tester_case_interface->trigger) + ret = cd->tester_case_interface->trigger(cd->test_case_ctx, mod, cmd); + + if (!ret) + ret = module_adapter_set_state(mod, mod->dev, cmd); + + return ret; +} + +static const struct module_interface tester_interface = { + .init = tester_init, + .prepare = tester_prepare, + .set_configuration = tester_set_configuration, + .process = tester_process, + .reset = tester_reset, + .free = tester_free, + .bind = tester_bind, + .unbind = tester_unbind, + .trigger = tester_trigger +}; + +#if CONFIG_COMP_TESTER_MODULE +/* modular: llext dynamic link */ + +#include <module/module/api_ver.h> +#include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> + +static const struct sof_man_module_manifest mod_manifest __section(".module") __used = + SOF_LLEXT_MODULE_MANIFEST("TESTER", &tester_interface, 1, SOF_REG_UUID(tester), 40); + +SOF_LLEXT_BUILDINFO; + +#else + +DECLARE_TR_CTX(tester_tr, SOF_UUID(tester_uuid), LOG_LEVEL_INFO); +DECLARE_MODULE_ADAPTER(tester_interface, tester_uuid, tester_tr); +SOF_MODULE_INIT(tester, sys_comp_module_tester_interface_init); + +#endif diff --git a/src/debug/tester/tester.h b/src/debug/tester/tester.h new file mode 100644 index 000000000000..79a65b65a7b2 --- /dev/null +++ b/src/debug/tester/tester.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + * + * Author: Marcin Szkudlinski <marcin.szkudlinski@linux.intel.com> + */ + +#ifndef COMP_TESTER +#define COMP_TESTER + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <module/module/interface.h> + +#define TESTER_MODULE_CASE_NO_TEST 0 +#define TESTER_MODULE_CASE_DUMMY_TEST 1 +#define TESTER_MODULE_CASE_SIMPLE_DRAM_TEST 2 + +/** + * API of a test case + * it is mostly a replica of module interface, with some additional parameters and functions + * + * all methods are optional + */ +struct tester_test_case_interface { + /** + * test initialization procedure, + * called in module init method + * It should allocate all required structures and return pointer to context + * in ctx param + */ + int (*init)(struct processing_module *mod, void **ctx); + + /** + * copy of module prepare method, with additional ctx param + */ + int (*prepare)(void *ctx, struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks); + + /** + * copy of module set_configuration method, with additional ctx param + */ + int (*set_configuration)(void *ctx, struct processing_module *mod, + uint32_t config_id, + enum module_cfg_fragment_position pos, uint32_t data_offset_size, + const uint8_t *fragment, size_t fragment_size, uint8_t *response, + size_t response_size); + + /** + * copy of module process method, with additional + * - ctx param + * - do_copy return flag. If is set to true, the tester base will do copy all samples + * from source to sink. + * May be used to indicate if the test has failed without any messages, just by stopping + * data stream + */ + int (*process)(void *ctx, struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks, + bool *do_copy); + + /** + * copy of module reset method, with additional ctx param + */ + int (*reset)(void *ctx, struct processing_module *mod); + + /** + * copy of module free method, with additional ctx param + * must free all data allocated during test + */ + int (*free)(void *ctx, struct processing_module *mod); + + /** + * copy of module bind method, with additional ctx param + */ + int (*bind)(void *ctx, struct processing_module *mod, struct bind_info *bind_data); + + /** + * copy of module unbind method, with additional ctx param + */ + int (*unbind)(void *ctx, struct processing_module *mod, struct bind_info *unbind_data); + + /** + * copy of module trigger method, with additional ctx param + */ + int (*trigger)(void *ctx, struct processing_module *mod, int cmd); + +}; + +struct tester_module_data { + const struct tester_test_case_interface *tester_case_interface; + uint32_t test_case_type; + void *test_case_ctx; +}; + +#endif /* COMP_TESTER */ diff --git a/src/debug/tester/tester.toml b/src/debug/tester/tester.toml new file mode 100644 index 000000000000..586bf2c3046b --- /dev/null +++ b/src/debug/tester/tester.toml @@ -0,0 +1,75 @@ +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + + [[module.entry]] + name = "TESTER" + uuid = UUIDREG_STR_TESTER + affinity_mask = "0x1" + REM #instance_count = "10" + domain_types = "0" + load_type = LOAD_TYPE + module_type = "7" + auto_start = "0" + sched_caps = [1, 0x00008000] + + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xffff, 0xc, 0x8, 0x05ff, + 1, 0, 0xf6c9, 0xc, 0x8, 0x05ff] + + REM # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] +#if CONFIG_METEORLAKE + mod_cfg = [0, 0, 0, 0, 12832, 15976000, 128, 512, 0, 15976, 0, + 1, 0, 0, 0, 12832, 15340000, 64, 256, 0, 15340, 0, + 2, 0, 0, 0, 12832, 21880000, 96, 512, 0, 21880, 0, + 3, 0, 0, 0, 12832, 19968000, 48, 256, 0, 19968, 0, + 4, 0, 0, 0, 12832, 18236000, 64, 256, 0, 18236, 0, + 5, 0, 0, 0, 12832, 15244000, 32, 256, 0, 15244, 0, + 6, 0, 0, 0, 12832, 56028000, 1536, 512, 0, 56028, 0, + 7, 0, 0, 0, 12832, 46740000, 768, 256, 0, 46740, 0, + 8, 0, 0, 0, 12832, 24656000, 768, 512, 0, 24656, 0, + 9, 0, 0, 0, 12832, 23516000, 384, 256, 0, 23516, 0, + 10, 0, 0, 0, 12832, 29368000, 384, 488, 0, 29368, 0, + 11, 0, 0, 0, 12832, 27164000, 192, 244, 0, 27164, 0, + 12, 0, 0, 0, 12832, 15892000, 384, 384, 0, 15892, 0, + 13, 0, 0, 0, 12832, 19916000, 192, 512, 0, 19916, 0, + 14, 0, 0, 0, 12832, 19176000, 96, 256, 0, 19176, 0, + 15, 0, 0, 0, 12832, 12676000, 192, 192, 0, 12676, 0, + 16, 0, 0, 0, 12832, 16280000, 384, 320, 0, 16280, 0, + 17, 0, 0, 0, 12832, 13076000, 192, 160, 0, 13076, 0, + 18, 0, 0, 0, 12832, 11440000, 384, 256, 0, 11440, 0, + 19, 0, 0, 0, 12832, 10996000, 192, 128, 0, 10996, 0, + 20, 0, 0, 0, 12832, 11428000, 384, 192, 0, 11428, 0, + 21, 0, 0, 0, 12832, 10740000, 192, 96, 0, 10740, 0, + 22, 0, 0, 0, 12832, 29936000, 360, 512, 0, 29936, 0, + 23, 0, 0, 0, 12832, 27696000, 180, 256, 0, 27696, 0, + 24, 0, 0, 0, 12832, 18368000, 256, 512, 0, 18368, 0, + 25, 0, 0, 0, 12832, 15204000, 128, 256, 0, 15204, 0] +#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_SOC_ACE30) || \ + defined(CONFIG_SOC_ACE40) + 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] +#endif + + index = __COUNTER__ diff --git a/src/debug/tester/tester_dummy_test.c b/src/debug/tester/tester_dummy_test.c new file mode 100644 index 000000000000..6d9e2596b3f4 --- /dev/null +++ b/src/debug/tester/tester_dummy_test.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// Author: Marcin Szkudlinski <marcin.szkudlinski@linux.intel.com> + +#include "tester_dummy_test.h" +#include <sof/audio/component.h> +#include <sof/audio/module_adapter/module/generic.h> + +/* + * This is a dummy test case + * The test case will copy every 2nd frame of data + * by setting do_copy flag to true/false + */ + +struct tester_module_dummy_test_data { + bool do_copy_data; +}; + +static int dummy_test_case_init(struct processing_module *mod, void **ctx) +{ + struct tester_module_dummy_test_data *data = + rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*data)); + + if (!data) + return -ENOMEM; + + data->do_copy_data = false; + *ctx = data; + return 0; +} + +int dummy_test_case_process(void *ctx, struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks, + bool *do_copy) +{ + struct tester_module_dummy_test_data *data = ctx; + + /* copy every second cycle */ + *do_copy = data->do_copy_data; + data->do_copy_data = !data->do_copy_data; + + return 0; +} + +int dummy_test_free(void *ctx, struct processing_module *mod) +{ + rfree(ctx); + return 0; +} + +const struct tester_test_case_interface tester_interface_dummy_test = { + .init = dummy_test_case_init, + .process = dummy_test_case_process, + .free = dummy_test_free +}; diff --git a/src/debug/tester/tester_dummy_test.h b/src/debug/tester/tester_dummy_test.h new file mode 100644 index 000000000000..55a53266d243 --- /dev/null +++ b/src/debug/tester/tester_dummy_test.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + * + * Author: Marcin Szkudlinski <marcin.szkudlinski@linux.intel.com> + */ + +#ifndef TESTER_DUMMY_TEST +#define TESTER_DUMMY_TEST + +#include <stddef.h> +#include <stdint.h> + +#include "tester.h" + +extern const struct tester_test_case_interface tester_interface_dummy_test; + +#endif /* TESTER_DUMMY_TEST */ diff --git a/src/debug/tester/tester_simple_dram_test.c b/src/debug/tester/tester_simple_dram_test.c new file mode 100644 index 000000000000..1a32e0ff6440 --- /dev/null +++ b/src/debug/tester/tester_simple_dram_test.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// Author: Adrian Bonislawski <adrian.bonislawski@intel.com> + +#include "tester_simple_dram_test.h" +#include <sof/audio/component.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/lib/memory.h> + +/* + * This is a simple test case for DRAM execution + * The test case will copy every 2nd frame of data + * by setting do_copy flag to true/false + */ + +struct tester_module_simple_dram_test_data { + bool do_copy_data; +}; + +static int validate_l3_memory(void *ptr) +{ + if (!((POINTER_TO_UINT(ptr) >= L3_MEM_BASE_ADDR) && + (POINTER_TO_UINT(ptr) < L3_MEM_BASE_ADDR + L3_MEM_SIZE))) + return -EINVAL; + + return 0; +} + +__cold static int simple_dram_test_case_init(struct processing_module *mod, void **ctx) +{ +#if !CONFIG_L3_HEAP + return -EINVAL; +#endif + struct tester_module_simple_dram_test_data *data = + rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_L3, sizeof(*data)); + + assert_can_be_cold(); + + if (!data) + return -ENOMEM; + + if (validate_l3_memory(data) != 0) { + rfree(data); + return -EINVAL; + } + + if (validate_l3_memory(tester_interface_simple_dram_test.init) != 0 || + validate_l3_memory(tester_interface_simple_dram_test.process) != 0 || + validate_l3_memory(tester_interface_simple_dram_test.free) != 0) { + rfree(data); + return -EINVAL; + } + + data->do_copy_data = false; + *ctx = data; + return 0; +} + +__cold static int simple_dram_test_case_process(void *ctx, struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks, + bool *do_copy) +{ + struct tester_module_simple_dram_test_data *data = ctx; + + assert_can_be_cold(); + + /* copy every second cycle */ + *do_copy = data->do_copy_data; + data->do_copy_data = !data->do_copy_data; + + return 0; +} + +__cold static int simple_dram_test_free(void *ctx, struct processing_module *mod) +{ + assert_can_be_cold(); + + rfree(ctx); + return 0; +} + +const struct tester_test_case_interface tester_interface_simple_dram_test = { + .init = simple_dram_test_case_init, + .process = simple_dram_test_case_process, + .free = simple_dram_test_free +}; diff --git a/src/debug/tester/tester_simple_dram_test.h b/src/debug/tester/tester_simple_dram_test.h new file mode 100644 index 000000000000..86febb54c06e --- /dev/null +++ b/src/debug/tester/tester_simple_dram_test.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + * + * Author: Adrian Bonislawski <adrian.bonislawski@intel.com> + */ + +#ifndef TESTER_SIMPLE_DRAM_TEST +#define TESTER_SIMPLE_DRAM_TEST + +#include <stddef.h> +#include <stdint.h> + +#include "tester.h" + +extern const struct tester_test_case_interface tester_interface_simple_dram_test; + +#endif /* TESTER_DUMMY_TEST */ diff --git a/src/drivers/amd/CMakeLists.txt b/src/drivers/amd/CMakeLists.txt index a6ece5e3a0ed..8b58af2b3017 100644 --- a/src/drivers/amd/CMakeLists.txt +++ b/src/drivers/amd/CMakeLists.txt @@ -1,9 +1,13 @@ # SPDX-License-Identifier: BSD-3-Clause -add_subdirectory(common) +if(CONFIG_RENOIR OR CONFIG_VANGOGH OR CONFIG_REMBRANDT OR CONFIG_ACP_6_3 OR CONFIG_ACP_7_0) + add_subdirectory(common) +endif() if(CONFIG_RENOIR) add_subdirectory(renoir) elseif(CONFIG_REMBRANDT OR CONFIG_ACP_6_3 OR CONFIG_ACP_7_0) add_subdirectory(rembrandt) elseif(CONFIG_VANGOGH) add_subdirectory(vangogh) +elseif(CONFIG_ACP_7_X) + add_subdirectory(acp_7_x) endif() diff --git a/src/drivers/amd/acp_7_x/CMakeLists.txt b/src/drivers/amd/acp_7_x/CMakeLists.txt new file mode 100644 index 000000000000..5dd81656d1ea --- /dev/null +++ b/src/drivers/amd/acp_7_x/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources(sof + ipc.c +) diff --git a/src/drivers/amd/acp_7_x/ipc.c b/src/drivers/amd/acp_7_x/ipc.c new file mode 100644 index 000000000000..777ad3e08494 --- /dev/null +++ b/src/drivers/amd/acp_7_x/ipc.c @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2026 AMD. All rights reserved. + * + * Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> + * Sneha Voona <sneha.voona@amd.com> + * DineshKumar Kalva <DineshKumar.Kalva@amd.com> + */ + +#include <rtos/panic.h> +#include <rtos/interrupt.h> +#include <sof/ipc/driver.h> +#include <sof/ipc/msg.h> +#include <sof/ipc/schedule.h> +#include <rtos/alloc.h> +#include <sof/lib/dma.h> +#include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <sof/lib/uuid.h> +#include <rtos/wait.h> +#include <sof/list.h> +#include <sof/platform.h> +#include <sof/schedule/edf_schedule.h> +#include <sof/schedule/schedule.h> +#include <rtos/task.h> +#include <rtos/spinlock.h> +#include <ipc/header.h> +#include <ipc/topology.h> +#include <errno.h> +#include <stddef.h> +#include <stdint.h> +#include <platform/platform.h> +#include <platform/ipc.h> +#include <zephyr/logging/log.h> + +volatile acp_scratch_mem_config_t *pscratch_mem_cfg = + (volatile acp_scratch_mem_config_t *)(PU_SCRATCH_REG_BASE + + SCRATCH_REG_OFFSET); + +SOF_DEFINE_REG_UUID(ipc_task_amd); +LOG_MODULE_REGISTER(ipc_handler_file, LOG_LEVEL_DBG); + +#define HOST_TO_DSP_INTR 1 +#define INTERRUPT_DISABLE 0 +#define IRQ_NUM_EXT_LEVEL3 3 +#define IRQ_EXT_IPC_LEVEL_3 3 + +/* This function triggers a host interrupt from ACP DSP */ +void acp_dsp_to_host_intr_trig(void) +{ + acp_sw_intr_trig_t sw_intr_trig; + /* Read the Software Interrupt controller register and update */ + sw_intr_trig = (acp_sw_intr_trig_t) io_reg_read(PU_REGISTER_BASE + ACP_SW_INTR_TRIG); + /* Configures the trigger bit in ACP_DSP_SW_INTR_TRIG register */ + sw_intr_trig.bits.trig_dsp0_to_host_intr = INTERRUPT_ENABLE; + /* Write the Software Interrupt controller register */ + io_reg_write((PU_REGISTER_BASE + ACP_SW_INTR_TRIG), sw_intr_trig.u32all); +} + +/* Clear the Acknowledge ( status) for the host to DSP interrupt */ +static void acp_ack_intr_from_host(void) +{ + /* acknowledge the host interrupt */ + acp_dsp_sw_intr_stat_t sw_intr_stat; + + sw_intr_stat.u32all = 0; + sw_intr_stat.bits.host_to_dsp0_intr1_stat = INTERRUPT_ENABLE; + io_reg_write((PU_REGISTER_BASE + ACP_DSP_SW_INTR_STAT), sw_intr_stat.u32all); +} + +inline uint32_t sof_ipc_host_status(void) +{ + return (pscratch_mem_cfg->acp_host_ack_write | pscratch_mem_cfg->acp_host_msg_write); +} + +inline uint32_t sof_ipc_host_msg_flag(void) +{ + return pscratch_mem_cfg->acp_host_msg_write; +} + +inline uint32_t sof_ipc_host_ack_flag(void) +{ + return pscratch_mem_cfg->acp_host_ack_write; +} + +inline uint32_t sof_ipc_dsp_status(void) +{ + return (pscratch_mem_cfg->acp_dsp_msg_write | pscratch_mem_cfg->acp_dsp_ack_write); +} + +inline void sof_ipc_host_ack_clear(void) +{ + pscratch_mem_cfg->acp_host_ack_write = 0; +} + +inline void sof_ipc_host_msg_clear(void) +{ + pscratch_mem_cfg->acp_host_msg_write = 0; +} + +inline void sof_ipc_dsp_ack_set(void) +{ + pscratch_mem_cfg->acp_dsp_ack_write = 1; +} + +inline void sof_ipc_dsp_msg_set(void) +{ + pscratch_mem_cfg->acp_dsp_msg_write = 1; +} + +enum task_state ipc_platform_do_cmd(struct ipc *ipc) +{ + struct ipc_cmd_hdr *hdr; + + hdr = mailbox_validate(); + ipc_cmd(hdr); + return SOF_TASK_STATE_COMPLETED; +} + +int platform_ipc_init(struct ipc *ipc) +{ + ipc_set_drvdata(ipc, NULL); + /* schedule */ + schedule_task_init_edf(&ipc->ipc_task, SOF_UUID(ipc_task_amd_uuid), + &ipc_task_ops, ipc, 0, 0); + interrupt_disable(IRQ_EXT_IPC_LEVEL_3, ipc); + interrupt_unregister(IRQ_EXT_IPC_LEVEL_3, ipc); + interrupt_register(IRQ_EXT_IPC_LEVEL_3, amd_irq_handler, ipc); + /* Enabling software interuppts */ + interrupt_enable(IRQ_EXT_IPC_LEVEL_3, ipc); + return 0; +} + +void amd_irq_handler(void *arg) +{ + struct ipc *ipc = arg; + uint32_t status; + uint32_t lock; + acp_dsp_sw_intr_stat_t swintrstat; + acp_sw_intr_trig_t swintrtrig; + + swintrstat = (acp_dsp_sw_intr_stat_t)io_reg_read(PU_REGISTER_BASE + ACP_DSP_SW_INTR_STAT); + status = swintrstat.u32all & HOST_TO_DSP_INTR; + if (status) { + /* Interrupt source */ + lock = io_reg_read(PU_REGISTER_BASE + ACP_AXI2DAGB_SEM_0); + /* Removed unbounded while(lock) loop - using bounded loop below instead */ + int timeout = 20000; + + while (lock && --timeout > 0) { + lock = io_reg_read(PU_REGISTER_BASE + ACP_AXI2DAGB_SEM_0); + } + if (timeout == 0) { + /* Give up, don't block forever */ + LOG_ERR("ACP semaphore timeout in IRQ handler"); + return; + } + /***************************************************** */ + /* Configures the trigger bit in ACP_DSP_SW_INTR_TRIG register */ + swintrtrig = (acp_sw_intr_trig_t) + io_reg_read(PU_REGISTER_BASE + ACP_SW_INTR_TRIG); + swintrtrig.bits.trig_host_to_dsp0_intr1 = INTERRUPT_DISABLE; + swintrtrig.bits.trig_dsp0_to_host_intr = INTERRUPT_DISABLE; + io_reg_write((PU_REGISTER_BASE + ACP_SW_INTR_TRIG), + swintrtrig.u32all); + + /* Clear the Host to DSP Status Register */ + acp_ack_intr_from_host(); + /********************************************* */ + + if (sof_ipc_host_status()) { + if (sof_ipc_host_ack_flag()) { + /* Clear the ACK from host */ + sof_ipc_host_ack_clear(); + } + /* Check if new message from host */ + if (sof_ipc_host_msg_flag()) { + /* Clear the msg bit from host*/ + sof_ipc_host_msg_clear(); + ipc_schedule_process(ipc); + } + } else { + tr_err(&ipc_tr, "IPC:interrupt without setting flags host status 0x%x", sof_ipc_host_status()); + io_reg_write((PU_REGISTER_BASE + ACP_AXI2DAGB_SEM_0), 0); + } + } +} + +void ipc_platform_complete_cmd(struct ipc *ipc) +{ + acp_sw_intr_trig_t sw_intr_trig; + + /* Set Dsp Ack for msg from host */ + sof_ipc_dsp_ack_set(); + /* Configures the trigger bit in ACP_DSP_SW_INTR_TRIG register */ + sw_intr_trig = (acp_sw_intr_trig_t) + io_reg_read(PU_REGISTER_BASE + ACP_SW_INTR_TRIG); + sw_intr_trig.bits.trig_host_to_dsp0_intr1 = INTERRUPT_DISABLE; + sw_intr_trig.bits.trig_dsp0_to_host_intr = INTERRUPT_DISABLE; + io_reg_write((PU_REGISTER_BASE + ACP_SW_INTR_TRIG), sw_intr_trig.u32all); + /* now interrupt host to tell it we have sent a message */ + acp_dsp_to_host_intr_trig(); + /* Disable the trigger bit in ACP_DSP_SW_INTR_TRIG register */ + sw_intr_trig = (acp_sw_intr_trig_t)io_reg_read(PU_REGISTER_BASE + ACP_SW_INTR_TRIG); + sw_intr_trig.bits.trig_dsp0_to_host_intr = INTERRUPT_DISABLE; + io_reg_write((PU_REGISTER_BASE + ACP_SW_INTR_TRIG), sw_intr_trig.u32all); + io_reg_write((PU_REGISTER_BASE + ACP_AXI2DAGB_SEM_0), 0); + LOG_DBG("IPC cmd completed"); + if (ipc->pm_prepare_D3) { + while (1) { + wait_for_interrupt(0); + } + } +} + +int ipc_platform_send_msg(const struct ipc_msg *msg) +{ + int ret = 0; + acp_sw_intr_trig_t sw_intr_trig; + acp_dsp_sw_intr_stat_t sw_intr_stat; + uint32_t status; + uint32_t lock; + /* Check if host cleared the status for previous messages */ + sw_intr_stat = (acp_dsp_sw_intr_stat_t) + io_reg_read(PU_REGISTER_BASE + ACP_DSP_SW_INTR_STAT); + status = sw_intr_stat.bits.dsp0_to_host_intr_stat; + if (sof_ipc_dsp_status() || status) { + return -EBUSY; + } + lock = io_reg_read(PU_REGISTER_BASE + ACP_AXI2DAGB_SEM_0); + int timeout = 20000; + + while (lock && --timeout > 0) { + lock = io_reg_read(PU_REGISTER_BASE + ACP_AXI2DAGB_SEM_0); + } + if (timeout == 0) { + /* Give up, don't block forever */ + LOG_ERR("ACP semaphore timeout in IPC send"); + return -EBUSY; + } + + /* Write new message in the mailbox */ + mailbox_dspbox_write(0, msg->tx_data, msg->tx_size); + /* Need to set DSP message flag */ + sof_ipc_dsp_msg_set(); + /* Trigger host interrupt to notify new message from DSP */ + /* Configures the trigger bit in ACP_DSP_SW_INTR_TRIG register */ + sw_intr_trig = (acp_sw_intr_trig_t) + io_reg_read(PU_REGISTER_BASE + ACP_SW_INTR_TRIG); + sw_intr_trig.bits.trig_host_to_dsp0_intr1 = INTERRUPT_DISABLE; + sw_intr_trig.bits.trig_dsp0_to_host_intr = INTERRUPT_DISABLE; + io_reg_write((PU_REGISTER_BASE + ACP_SW_INTR_TRIG), sw_intr_trig.u32all); + acp_dsp_to_host_intr_trig(); + /* Disable the trigger bit in ACP_DSP_SW_INTR_TRIG register */ + sw_intr_trig = (acp_sw_intr_trig_t)io_reg_read(PU_REGISTER_BASE + ACP_SW_INTR_TRIG); + sw_intr_trig.bits.trig_dsp0_to_host_intr = INTERRUPT_DISABLE; + io_reg_write((PU_REGISTER_BASE + ACP_SW_INTR_TRIG), sw_intr_trig.u32all); + io_reg_write((PU_REGISTER_BASE + ACP_AXI2DAGB_SEM_0), lock); + return ret; +} + +void ipc_platform_send_msg_direct(const struct ipc_msg *msg) +{ + acp_sw_intr_trig_t sw_intr_trig; + + /* Write message directly to mailbox - no status checks for emergency */ + mailbox_dspbox_write(0, msg->tx_data, msg->tx_size); + + /* Set DSP message flag */ + sof_ipc_dsp_msg_set(); + + /* Interrupt host immediately */ + acp_dsp_to_host_intr_trig(); + + /* Disable the trigger bit */ + sw_intr_trig = (acp_sw_intr_trig_t)io_reg_read(PU_REGISTER_BASE + ACP_SW_INTR_TRIG); + sw_intr_trig.bits.trig_dsp0_to_host_intr = INTERRUPT_DISABLE; + io_reg_write((PU_REGISTER_BASE + ACP_SW_INTR_TRIG), sw_intr_trig.u32all); +} diff --git a/src/drivers/amd/common/acp_bt_dai.c b/src/drivers/amd/common/acp_bt_dai.c index 0cb751cbbfe8..9f5a79ce15f8 100644 --- a/src/drivers/amd/common/acp_bt_dai.c +++ b/src/drivers/amd/common/acp_bt_dai.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // -//Copyright(c) 2023 AMD. All rights reserved. +//Copyright(c) 2023, 2026 AMD. All rights reserved. // //Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> // SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> +// Sivasubramanian <sravisar@amd.com> #include <sof/audio/component.h> #include <sof/drivers/acp_dai_dma.h> @@ -79,8 +80,8 @@ const struct dai_driver acp_btdai_driver = { .type = SOF_DAI_AMD_BT, .uid = SOF_UUID(btdai_uuid), .tctx = &btdai_tr, - .dma_dev = DMA_DEV_BT, - .dma_caps = DMA_CAP_BT, + .dma_dev = SOF_DMA_DEV_BT, + .dma_caps = SOF_DMA_CAP_BT, .ops = { .trigger = btdai_trigger, .set_config = btdai_set_config, diff --git a/src/drivers/amd/common/acp_dma.c b/src/drivers/amd/common/acp_dma.c index b6f8a7f116e3..df68b8bebfb6 100644 --- a/src/drivers/amd/common/acp_dma.c +++ b/src/drivers/amd/common/acp_dma.c @@ -299,7 +299,7 @@ static int acp_dma_probe(struct dma *dma) tr_err(&acpdma_tr, "DMA: Already probe"); return -EEXIST; } - dma->chan = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { @@ -310,11 +310,11 @@ static int acp_dma_probe(struct dma *dma) dma->chan[channel].dma = dma; dma->chan[channel].index = channel; dma->chan[channel].status = COMP_STATE_INIT; - acp_dma_chan = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, - SOF_MEM_CAPS_RAM, + acp_dma_chan = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(struct acp_dma_chan_data)); if (!acp_dma_chan) { rfree(dma->chan); + dma->chan = NULL; tr_err(&acpdma_tr, "acp-dma: %d channel %d private data alloc failed", dma->plat_data.id, channel); return -ENOMEM; diff --git a/src/drivers/amd/common/acp_dmic_dai.c b/src/drivers/amd/common/acp_dmic_dai.c index bce741cd92d3..18851843f005 100644 --- a/src/drivers/amd/common/acp_dmic_dai.c +++ b/src/drivers/amd/common/acp_dmic_dai.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // -//Copyright(c) 2023 AMD. All rights reserved. +//Copyright(c) 2023, 2026 AMD. All rights reserved. // // Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> // SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> +// Sivasubramanian <sravisar@amd.com> #include <sof/audio/component.h> #include <sof/drivers/acp_dai_dma.h> @@ -87,7 +88,7 @@ static int acp_dmic_dai_probe(struct dai *dai) dai_info(dai, "dmic dai probe"); /* allocate private data */ - acp = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*acp)); + acp = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*acp)); if (!acp) { dai_err(dai, "dmic dai probe alloc failed"); return -ENOMEM; @@ -157,8 +158,8 @@ const struct dai_driver acp_dmic_dai_driver = { .type = SOF_DAI_AMD_DMIC, .uid = SOF_UUID(acp_dmic_dai_uuid), .tctx = &acp_dmic_dai_tr, - .dma_dev = DMA_DEV_DMIC, - .dma_caps = DMA_CAP_DMIC, + .dma_dev = SOF_DMA_DEV_DMIC, + .dma_caps = SOF_DMA_CAP_DMIC, .ops = { .trigger = acp_dmic_dai_trigger, .set_config = acp_dmic_dai_set_config, diff --git a/src/drivers/amd/common/acp_dmic_dma.c b/src/drivers/amd/common/acp_dmic_dma.c index 962ce7314c59..70d371d62784 100644 --- a/src/drivers/amd/common/acp_dmic_dma.c +++ b/src/drivers/amd/common/acp_dmic_dma.c @@ -152,8 +152,8 @@ static int acp_dmic_dma_probe(struct dma *dma) tr_err(&acp_dmic_dma_tr, "Repeated probe"); return -EEXIST; } - dma->chan = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, - SOF_MEM_CAPS_RAM, dma->plat_data.channels * + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, + dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { tr_err(&acp_dmic_dma_tr, "unable to allocate channel descriptors"); diff --git a/src/drivers/amd/common/acp_sp_dma.c b/src/drivers/amd/common/acp_sp_dma.c index aaa40076c069..fd431ba7b4b7 100644 --- a/src/drivers/amd/common/acp_sp_dma.c +++ b/src/drivers/amd/common/acp_sp_dma.c @@ -113,8 +113,8 @@ static int acp_dai_sp_dma_probe(struct dma *dma) tr_err(&acp_sp_tr, "Repeated probe"); return -EEXIST; } - dma->chan = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, - SOF_MEM_CAPS_RAM, dma->plat_data.channels * + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, + dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { tr_err(&acp_sp_tr, "Probe failure,unable to allocate channel descriptors"); diff --git a/src/drivers/amd/common/ipc.c b/src/drivers/amd/common/ipc.c index 36ae6a7d17fb..fbb0ebdb1492 100644 --- a/src/drivers/amd/common/ipc.c +++ b/src/drivers/amd/common/ipc.c @@ -1,13 +1,12 @@ // SPDX-License-Identifier: BSD-3-Clause // -//Copyright(c) 2023 AMD. All rights reserved. +//Copyright(c) 2023, 2026 AMD. All rights reserved. // //Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> // SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> +// Sivasubramanian <sravisar@amd.com> #include <rtos/panic.h> -#include <platform/chip_offset_byte.h> -#include <platform/chip_registers.h> #include <rtos/interrupt.h> #include <sof/ipc/driver.h> #include <sof/ipc/msg.h> @@ -91,7 +90,7 @@ int platform_ipc_init(struct ipc *ipc) /* schedule */ schedule_task_init_edf(&ipc->ipc_task, SOF_UUID(ipc_task_amd_uuid), &ipc_task_ops, ipc, 0, 0); - arch_interrupt_clear(IRQ_NUM_EXT_LEVEL3); + interrupt_disable(IRQ_NUM_EXT_LEVEL3, ipc); interrupt_register(IRQ_NUM_EXT_LEVEL3, amd_irq_handler, ipc); /* Enabling software interuppts */ interrupt_enable(IRQ_NUM_EXT_LEVEL3, ipc); diff --git a/src/drivers/amd/rembrandt/acp_bt_dma.c b/src/drivers/amd/rembrandt/acp_bt_dma.c index 4275a21331c7..ecf85027528a 100644 --- a/src/drivers/amd/rembrandt/acp_bt_dma.c +++ b/src/drivers/amd/rembrandt/acp_bt_dma.c @@ -297,8 +297,8 @@ static int acp_dai_bt_dma_probe(struct dma *dma) tr_err(&acp_bt_dma_tr, "Repeated probe"); return -EEXIST; } - dma->chan = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, - SOF_MEM_CAPS_RAM, dma->plat_data.channels * + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, + dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { tr_err(&acp_bt_dma_tr, "Probe failure, unable to allocate channel descriptors"); diff --git a/src/drivers/amd/rembrandt/acp_hs_dai.c b/src/drivers/amd/rembrandt/acp_hs_dai.c index 6b51a1a248e5..bc1579d3f4d8 100644 --- a/src/drivers/amd/rembrandt/acp_hs_dai.c +++ b/src/drivers/amd/rembrandt/acp_hs_dai.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // -//Copyright(c) 2022 AMD. All rights reserved. +//Copyright(c) 2022, 2026 AMD. All rights reserved. // //Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> // Bala Kishore <balakishore.pati@amd.com> +// Sivasubramanian <sravisar@amd.com> #include <sof/audio/component.h> #include <sof/drivers/acp_dai_dma.h> @@ -60,7 +61,7 @@ static inline int hsdai_set_config(struct dai *dai, struct ipc_config_dai *commo i2stdm_mstrclkgen.bits.i2stdm_bclk_div_val = 0x20; break; default: - dai_err(dai, "hsdai_set_config unsupported slots"); + dai_err(dai, "unsupported slots"); return -EINVAL; } break; @@ -70,7 +71,7 @@ static inline int hsdai_set_config(struct dai *dai, struct ipc_config_dai *commo i2stdm_mstrclkgen.bits.i2stdm_bclk_div_val = 0x80; break; default: - dai_err(dai, "hsdai_set_config invalid format"); + dai_err(dai, "invalid format"); return -EINVAL; } @@ -109,7 +110,7 @@ static inline int hsdai_set_config(struct dai *dai, struct ipc_config_dai *commo io_reg_write((PU_REGISTER_BASE + ACP_HSTDM_IRER), hs_irer.u32all); break; default: - dai_err(dai, "hsdai_set_config invalid format"); + dai_err(dai, "invalid format"); return -EINVAL; } return 0; @@ -127,7 +128,7 @@ static int hsdai_probe(struct dai *dai) dai_info(dai, "HS dai probe"); /* allocate private data */ - acp = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*acp)); + acp = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*acp)); if (!acp) { dai_err(dai, "HS dai probe alloc failed"); return -ENOMEM; @@ -193,8 +194,8 @@ const struct dai_driver acp_hsdai_driver = { .type = SOF_DAI_AMD_HS, .uid = SOF_UUID(hsdai_uuid), .tctx = &hsdai_tr, - .dma_dev = DMA_DEV_SP, - .dma_caps = DMA_CAP_SP, + .dma_dev = SOF_DMA_DEV_SP, + .dma_caps = SOF_DMA_CAP_SP, .ops = { .trigger = hsdai_trigger, .set_config = hsdai_set_config, diff --git a/src/drivers/amd/rembrandt/acp_hs_dma.c b/src/drivers/amd/rembrandt/acp_hs_dma.c index 68b729af0fea..fbed6593ad55 100644 --- a/src/drivers/amd/rembrandt/acp_hs_dma.c +++ b/src/drivers/amd/rembrandt/acp_hs_dma.c @@ -294,8 +294,8 @@ static int acp_dai_hs_dma_probe(struct dma *dma) tr_err(&acp_hs_tr, "Repeated probe"); return -EEXIST; } - dma->chan = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, - SOF_MEM_CAPS_RAM, dma->plat_data.channels * + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, + dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { tr_err(&acp_hs_tr, "Probe failure,unable to allocate channel descriptors"); diff --git a/src/drivers/amd/rembrandt/acp_sp_dai.c b/src/drivers/amd/rembrandt/acp_sp_dai.c index 800fff08efcd..1dc5facc1533 100644 --- a/src/drivers/amd/rembrandt/acp_sp_dai.c +++ b/src/drivers/amd/rembrandt/acp_sp_dai.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // -//Copyright(c) 2022 AMD. All rights reserved. +//Copyright(c) 2022, 2026 AMD. All rights reserved. // //Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> // Bala Kishore <balakishore.pati@amd.com> +// Sivasubramanian <sravisar@amd.com> #include <sof/audio/component.h> #include <sof/drivers/acp_dai_dma.h> @@ -79,8 +80,8 @@ const struct dai_driver acp_spdai_driver = { .type = SOF_DAI_AMD_SP, .uid = SOF_UUID(spdai_uuid), .tctx = &spdai_tr, - .dma_dev = DMA_DEV_SP, - .dma_caps = DMA_CAP_SP, + .dma_dev = SOF_DMA_DEV_SP, + .dma_caps = SOF_DMA_CAP_SP, .ops = { .trigger = spdai_trigger, .set_config = spdai_set_config, diff --git a/src/drivers/amd/rembrandt/acp_sw_audio_dai.c b/src/drivers/amd/rembrandt/acp_sw_audio_dai.c index 5523a5717d20..bcee323a2303 100644 --- a/src/drivers/amd/rembrandt/acp_sw_audio_dai.c +++ b/src/drivers/amd/rembrandt/acp_sw_audio_dai.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // -//Copyright(c) 2023 AMD. All rights reserved. +//Copyright(c) 2023, 2026 AMD. All rights reserved. // //Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> // Maruthi Machani <maruthi.machani@amd.com> +// Sivasubramanian <sravisar@amd.com> #include <sof/drivers/acp_dai_dma.h> #include <sof/lib/uuid.h> @@ -37,7 +38,7 @@ static int swaudiodai_probe(struct dai *dai) dai_info(dai, "#$AMD$# SW dai probe"); /* allocate private data */ - acp = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*acp)); + acp = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*acp)); if (!acp) { dai_err(dai, "SW dai probe alloc failed"); return -ENOMEM; @@ -51,7 +52,7 @@ static int swaudiodai_remove(struct dai *dai) { struct acp_pdata *acp = dai_get_drvdata(dai); - dai_info(dai, "swaudiodai_remove"); + dai_info(dai, "entry"); rfree(acp); dai_set_drvdata(dai, NULL); @@ -95,7 +96,7 @@ static int swaudiodai_get_hw_params(struct dai *dai, } const struct dai_driver acp_swaudiodai_driver = { - .type = SOF_DAI_AMD_SW_AUDIO, + .type = SOF_DAI_AMD_SDW, .uid = SOF_UUID(swaudiodai_uuid), .tctx = &swaudiodai_tr, .dma_dev = DMA_DEV_SW, diff --git a/src/drivers/amd/rembrandt/acp_sw_audio_dma.c b/src/drivers/amd/rembrandt/acp_sw_audio_dma.c index a2a20f6aa820..25c72c9c0fff 100644 --- a/src/drivers/amd/rembrandt/acp_sw_audio_dma.c +++ b/src/drivers/amd/rembrandt/acp_sw_audio_dma.c @@ -12,12 +12,18 @@ #include <sof/lib/uuid.h> #include <sof/trace/trace.h> -#ifdef CONFIG_ACP_6_3 +#if defined(CONFIG_ACP_6_3) || defined(CONFIG_ACP_7_0) SOF_DEFINE_REG_UUID(acp_sw_audio); DECLARE_TR_CTX(acp_sw_audio_tr, SOF_UUID(acp_sw_audio_uuid), LOG_LEVEL_INFO); +#if defined(CONFIG_ACP_6_3) +#define DMA_CH_COUNT 8 +#elif defined(CONFIG_ACP_7_0) +#define DMA_CH_COUNT 12 +#endif + //initialization of soundwire-0 fifos(Audio, BT and HS) #define SW0_AUDIO_FIFO_SIZE 128 #define SW0_AUDIO_TX_FIFO_ADDR 0 @@ -31,10 +37,18 @@ DECLARE_TR_CTX(acp_sw_audio_tr, SOF_UUID(acp_sw_audio_uuid), LOG_LEVEL_INFO); #define SW0_HS_TX_FIFO_ADDR (SW0_BT_RX_FIFO_ADDR + SW0_BT_FIFO_SIZE) #define SW0_HS_RX_FIFO_ADDR (SW0_HS_TX_FIFO_ADDR + SW0_HS_FIFO_SIZE) -//initialization of soundwire-1 fifo -#define SW1_FIFO_SIZE 128 -#define SW1_TX_FIFO_ADDR (SW0_HS_RX_FIFO_ADDR + SW1_FIFO_SIZE) -#define SW1_RX_FIFO_ADDR (SW1_TX_FIFO_ADDR + SW1_FIFO_SIZE) +//initialization of soundwire-1 fifos(Audio, BT and HS) +#define SW1_AUDIO_FIFO_SIZE 128 +#define SW1_AUDIO_TX_FIFO_ADDR (SW0_HS_RX_FIFO_ADDR + SW0_HS_FIFO_SIZE) +#define SW1_AUDIO_RX_FIFO_ADDR (SW1_AUDIO_TX_FIFO_ADDR + SW1_AUDIO_FIFO_SIZE) + +#define SW1_BT_FIFO_SIZE 128 +#define SW1_BT_TX_FIFO_ADDR (SW1_AUDIO_RX_FIFO_ADDR + SW1_AUDIO_FIFO_SIZE) +#define SW1_BT_RX_FIFO_ADDR (SW1_BT_TX_FIFO_ADDR + SW1_BT_FIFO_SIZE) + +#define SW1_HS_FIFO_SIZE 128 +#define SW1_HS_TX_FIFO_ADDR (SW1_BT_RX_FIFO_ADDR + SW1_BT_FIFO_SIZE) +#define SW1_HS_RX_FIFO_ADDR (SW1_HS_TX_FIFO_ADDR + SW1_HS_FIFO_SIZE) static uint32_t sw_audio_buff_size_playback; static uint32_t sw_audio_buff_size_capture; @@ -55,7 +69,7 @@ struct sw_dev_register { uint32_t statusindex; }; -static struct sw_dev_register sw_dev[8] = { +static struct sw_dev_register sw_dev[DMA_CH_COUNT] = { {ACP_SW_HS_RX_EN, ACP_SW_HS_RX_EN_STATUS, ACP_HS_RX_FIFOADDR, SW0_HS_RX_FIFO_ADDR, ACP_HS_RX_FIFOSIZE, SW0_HS_FIFO_SIZE, ACP_HS_RX_RINGBUFADDR, ACP_HS_RX_RINGBUFSIZE, ACP_HS_RX_DMA_SIZE, ACP_HS_RX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_INTR_CNTL, 0}, @@ -64,13 +78,13 @@ ACP_HS_RX_DMA_SIZE, ACP_HS_RX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_ ACP_HS_TX_FIFOSIZE, SW0_HS_FIFO_SIZE, ACP_HS_TX_RINGBUFADDR, ACP_HS_TX_RINGBUFSIZE, ACP_HS_TX_DMA_SIZE, ACP_HS_TX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_INTR_CNTL, 1}, -{ACP_P1_SW_BT_RX_EN, ACP_P1_SW_BT_RX_EN_STATUS, ACP_P1_BT_RX_FIFOADDR, SW1_RX_FIFO_ADDR, -ACP_P1_BT_RX_FIFOSIZE, SW1_FIFO_SIZE, ACP_P1_BT_RX_RINGBUFADDR, ACP_P1_BT_RX_RINGBUFSIZE, +{ACP_P1_SW_BT_RX_EN, ACP_P1_SW_BT_RX_EN_STATUS, ACP_P1_BT_RX_FIFOADDR, SW1_BT_RX_FIFO_ADDR, +ACP_P1_BT_RX_FIFOSIZE, SW1_BT_FIFO_SIZE, ACP_P1_BT_RX_RINGBUFADDR, ACP_P1_BT_RX_RINGBUFSIZE, ACP_P1_BT_RX_DMA_SIZE, ACP_P1_BT_RX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT1, ACP_DSP0_INTR_CNTL1, 2}, -{ACP_P1_SW_BT_TX_EN, ACP_P1_SW_BT_TX_EN_STATUS, ACP_P1_BT_TX_FIFOADDR, SW1_TX_FIFO_ADDR, -ACP_P1_BT_TX_FIFOSIZE, SW1_FIFO_SIZE, ACP_P1_BT_TX_RINGBUFADDR, ACP_P1_BT_TX_RINGBUFSIZE, +{ACP_P1_SW_BT_TX_EN, ACP_P1_SW_BT_TX_EN_STATUS, ACP_P1_BT_TX_FIFOADDR, SW1_BT_TX_FIFO_ADDR, +ACP_P1_BT_TX_FIFOSIZE, SW1_BT_FIFO_SIZE, ACP_P1_BT_TX_RINGBUFADDR, ACP_P1_BT_TX_RINGBUFSIZE, ACP_P1_BT_TX_DMA_SIZE, ACP_P1_BT_TX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT1, ACP_DSP0_INTR_CNTL1, 3}, @@ -88,7 +102,29 @@ ACP_BT_RX_DMA_SIZE, ACP_BT_RX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_ {ACP_SW_BT_TX_EN, ACP_SW_BT_TX_EN_STATUS, ACP_BT_TX_FIFOADDR, SW0_BT_TX_FIFO_ADDR, ACP_BT_TX_FIFOSIZE, SW0_BT_FIFO_SIZE, ACP_BT_TX_RINGBUFADDR, ACP_BT_TX_RINGBUFSIZE, -ACP_BT_TX_DMA_SIZE, ACP_BT_TX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_INTR_CNTL, 3} +ACP_BT_TX_DMA_SIZE, ACP_BT_TX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_INTR_CNTL, 3}, + +#if defined(CONFIG_ACP_7_0) +{ACP_P1_SW_AUDIO_RX_EN, ACP_P1_SW_AUDIO_RX_EN_STATUS, ACP_P1_AUDIO_RX_FIFOADDR, +SW1_AUDIO_RX_FIFO_ADDR, ACP_P1_AUDIO_RX_FIFOSIZE, SW1_AUDIO_FIFO_SIZE, +ACP_P1_AUDIO_RX_RINGBUFADDR, ACP_P1_AUDIO_RX_RINGBUFSIZE, ACP_P1_AUDIO_RX_DMA_SIZE, +ACP_P1_AUDIO_RX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT1, ACP_DSP0_INTR_CNTL1, 4}, + +{ACP_P1_SW_AUDIO_TX_EN, ACP_P1_SW_AUDIO_TX_EN_STATUS, ACP_P1_AUDIO_TX_FIFOADDR, +SW1_AUDIO_TX_FIFO_ADDR, ACP_P1_AUDIO_TX_FIFOSIZE, SW1_AUDIO_FIFO_SIZE, +ACP_P1_AUDIO_TX_RINGBUFADDR, ACP_P1_AUDIO_TX_RINGBUFSIZE, ACP_P1_AUDIO_TX_DMA_SIZE, +ACP_P1_AUDIO_TX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT1, ACP_DSP0_INTR_CNTL1, 5}, + +{ACP_P1_SW_HEADSET_RX_EN, ACP_P1_SW_HEADSET_RX_EN_STATUS, ACP_P1_HS_RX_FIFOADDR, +SW1_HS_RX_FIFO_ADDR, ACP_P1_HS_RX_FIFOSIZE, SW1_HS_FIFO_SIZE, +ACP_P1_HS_RX_RINGBUFADDR, ACP_P1_HS_RX_RINGBUFSIZE, ACP_P1_HS_RX_DMA_SIZE, +ACP_P1_HS_RX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT1, ACP_DSP0_INTR_CNTL1, 0}, + +{ACP_P1_SW_HEADSET_TX_EN, ACP_P1_SW_HEADSET_TX_EN_STATUS, ACP_P1_HS_TX_FIFOADDR, +SW1_HS_TX_FIFO_ADDR, ACP_P1_HS_TX_FIFOSIZE, SW1_HS_FIFO_SIZE, +ACP_P1_HS_TX_RINGBUFADDR, ACP_P1_HS_TX_RINGBUFSIZE, ACP_P1_HS_TX_DMA_SIZE, +ACP_P1_HS_TX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT1, ACP_DSP0_INTR_CNTL1, 1}, +#endif }; /* allocate next free DMA channel */ @@ -136,7 +172,7 @@ static int acp_dai_sw_audio_dma_start(struct dma_chan_data *channel) uint32_t acp_pdm_en; int i; - for (i = 0; i < 8; i += 2) { + for (i = 0; i < DMA_CH_COUNT; i += 2) { sw0_audio_tx_en |= io_reg_read(PU_REGISTER_BASE + sw_dev[i].sw_dev_en); sw0_audio_rx_en |= io_reg_read(PU_REGISTER_BASE + sw_dev[i + 1].sw_dev_en); } @@ -208,7 +244,7 @@ static int acp_dai_sw_audio_dma_stop(struct dma_chan_data *channel) return -EINVAL; } - for (i = 0; i < 8; i += 2) { + for (i = 0; i < DMA_CH_COUNT; i += 2) { sw0_audio_tx_en |= io_reg_read(PU_REGISTER_BASE + sw_dev[i].sw_dev_en); sw0_audio_rx_en |= io_reg_read(PU_REGISTER_BASE + sw_dev[i + 1].sw_dev_en); } @@ -337,8 +373,8 @@ static int acp_dai_sw_audio_dma_probe(struct dma *dma) tr_err(&acp_sw_audio_tr, "Repeated probe"); return -EEXIST; } - dma->chan = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, - SOF_MEM_CAPS_RAM, dma->plat_data.channels * + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, + dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { tr_err(&acp_sw_audio_tr, "Probe failure,unable to allocate channel descriptors"); @@ -420,6 +456,10 @@ static int acp_dai_sw_audio_dma_interrupt(struct dma_chan_data *channel, enum dm switch (channel->index) { case SDW1_ACP_P1_SW_BT_TX_EN_CH: case SDW1_ACP_P1_SW_BT_RX_EN_CH: + case SDW1_ACP_P1_SW_AUDIO_RX_EN_CH: + case SDW1_ACP_P1_SW_AUDIO_TX_EN_CH: + case SDW1_ACP_P1_SW_HS_RX_EN_CH: + case SDW1_ACP_P1_SW_HS_TX_EN_CH: acp_intr_stat1 = (acp_dsp0_intr_stat1_t)dma_reg_read(channel->dma, sw_dev[channel->index].sw_dev_dma_intr_status); status = acp_intr_stat1.bits.audio_buffer_int_stat; @@ -435,6 +475,10 @@ static int acp_dai_sw_audio_dma_interrupt(struct dma_chan_data *channel, enum dm switch (channel->index) { case SDW1_ACP_P1_SW_BT_TX_EN_CH: case SDW1_ACP_P1_SW_BT_RX_EN_CH: + case SDW1_ACP_P1_SW_AUDIO_RX_EN_CH: + case SDW1_ACP_P1_SW_AUDIO_TX_EN_CH: + case SDW1_ACP_P1_SW_HS_RX_EN_CH: + case SDW1_ACP_P1_SW_HS_TX_EN_CH: acp_intr_stat1.u32all = 0; acp_intr_stat1.bits.audio_buffer_int_stat = (1 << sw_dev[channel->index].statusindex); @@ -456,6 +500,10 @@ static int acp_dai_sw_audio_dma_interrupt(struct dma_chan_data *channel, enum dm switch (channel->index) { case SDW1_ACP_P1_SW_BT_TX_EN_CH: case SDW1_ACP_P1_SW_BT_RX_EN_CH: + case SDW1_ACP_P1_SW_AUDIO_RX_EN_CH: + case SDW1_ACP_P1_SW_AUDIO_TX_EN_CH: + case SDW1_ACP_P1_SW_HS_RX_EN_CH: + case SDW1_ACP_P1_SW_HS_TX_EN_CH: acp_intr_cntl1 = (acp_dsp0_intr_cntl1_t)dma_reg_read(channel->dma, sw_dev[channel->index].sw_dev_dma_intr_cntl); acp_intr_cntl1.bits.audio_buffer_int_mask &= @@ -479,6 +527,10 @@ static int acp_dai_sw_audio_dma_interrupt(struct dma_chan_data *channel, enum dm switch (channel->index) { case SDW1_ACP_P1_SW_BT_TX_EN_CH: case SDW1_ACP_P1_SW_BT_RX_EN_CH: + case SDW1_ACP_P1_SW_AUDIO_RX_EN_CH: + case SDW1_ACP_P1_SW_AUDIO_TX_EN_CH: + case SDW1_ACP_P1_SW_HS_RX_EN_CH: + case SDW1_ACP_P1_SW_HS_TX_EN_CH: acp_intr_cntl1 = (acp_dsp0_intr_cntl1_t)dma_reg_read(channel->dma, sw_dev[channel->index].sw_dev_dma_intr_cntl); acp_intr_cntl1.bits.audio_buffer_int_mask |= diff --git a/src/drivers/amd/rembrandt/ipc.c b/src/drivers/amd/rembrandt/ipc.c index d32c80c34e3b..ffc13987bb13 100644 --- a/src/drivers/amd/rembrandt/ipc.c +++ b/src/drivers/amd/rembrandt/ipc.c @@ -1,13 +1,11 @@ // SPDX-License-Identifier: BSD-3-Clause // -//Copyright(c) 2022 AMD. All rights reserved. +//Copyright(c) 2022, 2026 AMD. All rights reserved. // //Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> // Bala Kishore <balakishore.pati@amd.com> - +// Sivasubramanian <sravisar@amd.com> #include <rtos/panic.h> -#include <platform/chip_offset_byte.h> -#include <platform/chip_registers.h> #include <rtos/interrupt.h> #include <sof/ipc/driver.h> #include <sof/ipc/msg.h> @@ -32,9 +30,39 @@ #include <platform/platform.h> #include <platform/ipc.h> +#define HOST_TO_DSP_INTR 1 +#define INTERRUPT_DISABLE 0 +LOG_MODULE_REGISTER(ipc1, CONFIG_SOF_LOG_LEVEL); volatile acp_scratch_mem_config_t *pscratch_mem_cfg = (volatile acp_scratch_mem_config_t *) (PU_SCRATCH_REG_BASE + SCRATCH_REG_OFFSET); +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS +/* Clear the Acknowledge ( status) for the host to DSP interrupt */ +void acp_ack_intr_from_host(void) +{ + /* acknowledge the host interrupt */ + acp_dsp_sw_intr_stat_t sw_intr_stat; + + sw_intr_stat.u32all = 0; + sw_intr_stat.bits.host_to_dsp0_intr1_stat = INTERRUPT_ENABLE; + io_reg_write((PU_REGISTER_BASE + ACP_DSP_SW_INTR_STAT), sw_intr_stat.u32all); +} + +/* This function triggers a host interrupt from ACP DSP */ +void acp_dsp_to_host_intr_trig(void) +{ + acp_sw_intr_trig_t sw_intr_trig; + + /* Read the Software Interrupt controller register and update */ + sw_intr_trig = (acp_sw_intr_trig_t)io_reg_read(PU_REGISTER_BASE + + ACP_SW_INTR_TRIG); + /* Configures the trigger bit in ACP_DSP_SW_INTR_TRIG register */ + sw_intr_trig.bits.trig_dsp0_to_host_intr = INTERRUPT_ENABLE; + /* Write the Software Interrupt controller register */ + io_reg_write((PU_REGISTER_BASE + ACP_SW_INTR_TRIG), sw_intr_trig.u32all); +} +#endif /* CONFIG_ZEPHYR_NATIVE_DRIVERS */ + void amd_irq_handler(void *arg) { struct ipc *ipc = arg; diff --git a/src/drivers/amd/renoir/acp_bt_dma.c b/src/drivers/amd/renoir/acp_bt_dma.c index cab4d696ba46..d3e05fd77810 100644 --- a/src/drivers/amd/renoir/acp_bt_dma.c +++ b/src/drivers/amd/renoir/acp_bt_dma.c @@ -294,8 +294,8 @@ static int acp_dai_bt_dma_probe(struct dma *dma) tr_err(&acp_bt_dma_tr, "Repeated probe"); return -EEXIST; } - dma->chan = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, - SOF_MEM_CAPS_RAM, dma->plat_data.channels * + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, + dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { tr_err(&acp_bt_dma_tr, "Probe failure, unable to allocate channel descriptors"); diff --git a/src/drivers/amd/renoir/acp_sp_dai.c b/src/drivers/amd/renoir/acp_sp_dai.c index 26932d00044a..fbff87105ced 100644 --- a/src/drivers/amd/renoir/acp_sp_dai.c +++ b/src/drivers/amd/renoir/acp_sp_dai.c @@ -85,7 +85,7 @@ static int spdai_probe(struct dai *dai) dai_info(dai, "SP dai probe"); /* allocate private data */ - acp = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*acp)); + acp = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*acp)); if (!acp) { dai_err(dai, "SP dai probe alloc failed"); return -ENOMEM; @@ -110,7 +110,7 @@ static int spdai_get_fifo(struct dai *dai, int direction, int stream_id) case DAI_DIR_CAPTURE: return dai_fifo(dai, direction); default: - dai_err(dai, "spdai_get_fifo(): Invalid direction"); + dai_err(dai, "Invalid direction"); return -EINVAL; } } diff --git a/src/drivers/amd/vangogh/acp_bt_dma.c b/src/drivers/amd/vangogh/acp_bt_dma.c index 1dee67b6b0ec..4f08bc69abee 100644 --- a/src/drivers/amd/vangogh/acp_bt_dma.c +++ b/src/drivers/amd/vangogh/acp_bt_dma.c @@ -292,8 +292,8 @@ static int acp_dai_bt_dma_probe(struct dma *dma) tr_err(&acp_bt_dma_tr, "Repeated probe"); return -EEXIST; } - dma->chan = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, - SOF_MEM_CAPS_RAM, dma->plat_data.channels * + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, + dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { tr_err(&acp_bt_dma_tr, "Probe failure, unable to allocate channel descriptors"); diff --git a/src/drivers/amd/vangogh/acp_hs_dma.c b/src/drivers/amd/vangogh/acp_hs_dma.c index 532f53e32749..b15a7f5e51b3 100644 --- a/src/drivers/amd/vangogh/acp_hs_dma.c +++ b/src/drivers/amd/vangogh/acp_hs_dma.c @@ -279,7 +279,7 @@ static int acp_dai_hs_dma_copy(struct dma_chan_data *channel, int bytes, .channel = channel, .elem.size = bytes, }; - tr_info(&acp_hs_tr, "acp_dai_hs_dma_copy "); + tr_info(&acp_hs_tr, "entry"); notifier_event(channel, NOTIFIER_ID_DMA_COPY, NOTIFIER_TARGET_CORE_LOCAL, &next, sizeof(next)); return 0; @@ -293,8 +293,8 @@ static int acp_dai_hs_dma_probe(struct dma *dma) tr_err(&acp_hs_tr, "Repeated probe"); return -EEXIST; } - dma->chan = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, - SOF_MEM_CAPS_RAM, dma->plat_data.channels * + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, + dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { tr_err(&acp_hs_tr, "Probe failure,unable to allocate channel descriptors"); diff --git a/src/drivers/dw/dma.c b/src/drivers/dw/dma.c index 8edd898eb25a..005980454798 100644 --- a/src/drivers/dw/dma.c +++ b/src/drivers/dw/dma.c @@ -254,7 +254,7 @@ static void dw_dma_channel_put(struct dma_chan_data *channel) { k_spinlock_key_t key; - tr_info(&dwdma_tr, "dw_dma_channel_put(): dma %d channel %d put", + tr_info(&dwdma_tr, "dma %d channel %d put", channel->dma->plat_data.id, channel->index); key = k_spin_lock(&channel->dma->lock); @@ -273,7 +273,7 @@ static int dw_dma_start(struct dma_chan_data *channel) uint32_t words_per_tfr = 0; #endif - tr_dbg(&dwdma_tr, "dw_dma_start(): dma %d channel %d start", + tr_dbg(&dwdma_tr, "dma %d channel %d start", channel->dma->plat_data.id, channel->index); irq_local_disable(flags); @@ -282,7 +282,7 @@ static int dw_dma_start(struct dma_chan_data *channel) if ((channel->status != COMP_STATE_PREPARE && channel->status != COMP_STATE_PAUSED) || (dma_reg_read(dma, DW_DMA_CHAN_EN) & DW_CHAN(channel->index))) { - tr_err(&dwdma_tr, "dw_dma_start(): dma %d channel %d not ready ena 0x%x status 0x%x", + tr_err(&dwdma_tr, "dma %d channel %d not ready ena 0x%x status 0x%x", dma->plat_data.id, channel->index, dma_reg_read(dma, DW_DMA_CHAN_EN), channel->status); @@ -292,7 +292,7 @@ static int dw_dma_start(struct dma_chan_data *channel) /* is valid stream */ if (!dw_chan->lli) { - tr_err(&dwdma_tr, "dw_dma_start(): dma %d channel %d invalid stream", + tr_err(&dwdma_tr, "dma %d channel %d invalid stream", dma->plat_data.id, channel->index); ret = -EINVAL; goto out; @@ -348,7 +348,7 @@ static int dw_dma_release(struct dma_chan_data *channel) struct dw_dma_chan_data *dw_chan = dma_chan_get_data(channel); uint32_t flags; - tr_info(&dwdma_tr, "dw_dma_release(): dma %d channel %d release", + tr_info(&dwdma_tr, "dma %d channel %d release", channel->dma->plat_data.id, channel->index); irq_local_disable(flags); @@ -370,7 +370,7 @@ static int dw_dma_pause(struct dma_chan_data *channel) struct dma *dma = channel->dma; uint32_t flags; - tr_info(&dwdma_tr, "dw_dma_pause(): dma %d channel %d pause", + tr_info(&dwdma_tr, "dma %d channel %d pause", channel->dma->plat_data.id, channel->index); irq_local_disable(flags); @@ -405,7 +405,7 @@ static int dw_dma_stop(struct dma_chan_data *channel) int i; #endif - tr_info(&dwdma_tr, "dw_dma_stop(): dma %d channel %d stop", + tr_info(&dwdma_tr, "dma %d channel %d stop", dma->plat_data.id, channel->index); irq_local_disable(flags); @@ -428,7 +428,7 @@ static int dw_dma_stop(struct dma_chan_data *channel) DW_CFGL_FIFO_EMPTY, DW_DMA_TIMEOUT); if (ret < 0) - tr_err(&dwdma_tr, "dw_dma_stop(): dma %d channel %d timeout", + tr_err(&dwdma_tr, "dma %d channel %d timeout", dma->plat_data.id, channel->index); #endif @@ -438,7 +438,7 @@ static int dw_dma_stop(struct dma_chan_data *channel) ret = poll_for_register_delay(dma_base(dma) + DW_DMA_CHAN_EN, DW_CHAN(channel->index), 0, DW_DMA_TIMEOUT); if (ret < 0) { - tr_err(&dwdma_tr, "dw_dma_stop(): dma %d channel %d disable timeout", + tr_err(&dwdma_tr, "dma %d channel %d disable timeout", dma->plat_data.id, channel->index); return -ETIMEDOUT; } @@ -499,7 +499,7 @@ static int dw_dma_set_config(struct dma_chan_data *channel, int ret = 0; int i; - tr_dbg(&dwdma_tr, "dw_dma_set_config(): dma %d channel %d config", + tr_dbg(&dwdma_tr, "dma %d channel %d config", channel->dma->plat_data.id, channel->index); irq_local_disable(flags); @@ -514,7 +514,7 @@ static int dw_dma_set_config(struct dma_chan_data *channel, dw_chan->cfg_hi = DW_CFG_HIGH_DEF; if (!config->elem_array.count) { - tr_err(&dwdma_tr, "dw_dma_set_config(): dma %d channel %d no elems", + tr_err(&dwdma_tr, "dma %d channel %d no elems", channel->dma->plat_data.id, channel->index); ret = -EINVAL; goto out; @@ -522,7 +522,7 @@ static int dw_dma_set_config(struct dma_chan_data *channel, if (config->irq_disabled && config->elem_array.count < DW_DMA_CFG_NO_IRQ_MIN_ELEMS) { - tr_err(&dwdma_tr, "dw_dma_set_config(): dma %d channel %d not enough elems for config with irq disabled %d", + tr_err(&dwdma_tr, "dma %d channel %d not enough elems for config with irq disabled %d", channel->dma->plat_data.id, channel->index, config->elem_array.count); ret = -EINVAL; @@ -532,8 +532,6 @@ static int dw_dma_set_config(struct dma_chan_data *channel, /* do we need to realloc descriptors */ if (config->elem_array.count != channel->desc_count) { - channel->desc_count = config->elem_array.count; - /* * Allocate descriptors for channel. They must be cache-line * size aligned to avoid corrupting adjacent memory when @@ -542,19 +540,25 @@ static int dw_dma_set_config(struct dma_chan_data *channel, * allocations on Zephyr to always force cache-line size * alignment. */ - if (dw_chan->lli) - rfree(dw_chan->lli); + rfree(dw_chan->lli); - dw_chan->lli = rmalloc(SOF_MEM_ZONE_RUNTIME, SOF_MEM_FLAG_COHERENT, - SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, - sizeof(struct dw_lli) * channel->desc_count); + dw_chan->lli = rmalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT | SOF_MEM_FLAG_DMA, + sizeof(struct dw_lli) * config->elem_array.count); if (!dw_chan->lli) { - tr_err(&dwdma_tr, "dw_dma_set_config(): dma %d channel %d lli alloc failed", + tr_err(&dwdma_tr, "dma %d channel %d lli alloc failed", channel->dma->plat_data.id, channel->index); + /* allocation failed, so dw_chan->lli is now NULL; reset + * the count to match it so a later config does not + * bzero() a NULL pointer using a stale count + */ + channel->desc_count = 0; ret = -ENOMEM; goto out; } + + /* only commit the new count once the buffer is allocated */ + channel->desc_count = config->elem_array.count; } /* initialise descriptors */ @@ -601,7 +605,7 @@ static int dw_dma_set_config(struct dma_chan_data *channel, lli_desc->ctrl_lo |= DW_CTLL_SRC_WIDTH(2); break; default: - tr_err(&dwdma_tr, "dw_dma_set_config(): dma %d channel %d invalid src width %d", + tr_err(&dwdma_tr, "dma %d channel %d invalid src width %d", channel->dma->plat_data.id, channel->index, config->src_width); ret = -EINVAL; @@ -629,7 +633,7 @@ static int dw_dma_set_config(struct dma_chan_data *channel, lli_desc->ctrl_lo |= DW_CTLL_DST_WIDTH(2); break; default: - tr_err(&dwdma_tr, "dw_dma_set_config(): dma %d channel %d invalid dest width %d", + tr_err(&dwdma_tr, "dma %d channel %d invalid dest width %d", channel->dma->plat_data.id, channel->index, config->dest_width); ret = -EINVAL; @@ -707,7 +711,7 @@ static int dw_dma_set_config(struct dma_chan_data *channel, DW_CFGH_DST(config->dest_dev); break; default: - tr_err(&dwdma_tr, "dw_dma_set_config(): dma %d channel %d invalid direction %d", + tr_err(&dwdma_tr, "dma %d channel %d invalid direction %d", channel->dma->plat_data.id, channel->index, config->direction); ret = -EINVAL; @@ -718,7 +722,7 @@ static int dw_dma_set_config(struct dma_chan_data *channel, lli_desc->dar = sg_elem->dest; if (sg_elem->size > DW_CTLH_BLOCK_TS_MASK) { - tr_err(&dwdma_tr, "dw_dma_set_config(): dma %d channel %d block size too big %d", + tr_err(&dwdma_tr, "dma %d channel %d block size too big %d", channel->dma->plat_data.id, channel->index, sg_elem->size); ret = -EINVAL; @@ -840,7 +844,7 @@ static int dw_dma_copy(struct dma_chan_data *channel, int bytes, }; k_spinlock_key_t key; - tr_dbg(&dwdma_tr, "dw_dma_copy(): dma %d channel %d copy", + tr_dbg(&dwdma_tr, "dma %d channel %d copy", channel->dma->plat_data.id, channel->index); notifier_event(channel, NOTIFIER_ID_DMA_COPY, @@ -860,7 +864,7 @@ static int dw_dma_copy(struct dma_chan_data *channel, int bytes, DW_CHAN(channel->index), 0, DW_DMA_TIMEOUT); if (ret < 0) { - tr_dbg(&dwdma_tr, "dw_dma_copy(): poll_for_register_delay timeout"); + tr_dbg(&dwdma_tr, "poll_for_register_delay timeout"); return ret; } } @@ -889,7 +893,7 @@ static int dw_dma_setup(struct dma *dma) break; if (!i) { - tr_err(&dwdma_tr, "dw_dma_setup(): dma %d setup failed", + tr_err(&dwdma_tr, "dma %d setup failed", dma->plat_data.id); return -EIO; } @@ -937,11 +941,11 @@ static int dw_dma_probe(struct dma *dma) pm_runtime_get_sync(DW_DMAC_CLK, dma->plat_data.id); /* allocate dma channels */ - dma->chan = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(struct dma_chan_data) * dma->plat_data.channels); if (!dma->chan) { - tr_err(&dwdma_tr, "dw_dma_probe(): dma %d allocaction of channels failed", + tr_err(&dwdma_tr, "dma %d allocation of channels failed", dma->plat_data.id); goto out; } @@ -958,11 +962,11 @@ static int dw_dma_probe(struct dma *dma) chan->index = i; chan->core = DMA_CORE_INVALID; - dw_chan = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + dw_chan = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*dw_chan)); if (!dw_chan) { - tr_err(&dwdma_tr, "dw_dma_probe(): dma %d allocaction of channel %d private data failed", + tr_err(&dwdma_tr, "dma %d allocation of channel %d private data failed", dma->plat_data.id, i); goto out; } @@ -990,7 +994,7 @@ static int dw_dma_remove(struct dma *dma) { int i; - tr_dbg(&dwdma_tr, "dw_dma_remove(): dma %d remove", dma->plat_data.id); + tr_dbg(&dwdma_tr, "dma %d remove", dma->plat_data.id); pm_runtime_put_sync(DW_DMAC_CLK, dma->plat_data.id); @@ -1025,7 +1029,7 @@ static int dw_dma_avail_data_size(struct dma_chan_data *channel) if (delta) size = dw_chan->ptr_data.buffer_bytes; else - tr_info(&dwdma_tr, "dw_dma_avail_data_size() size is 0!"); + tr_info(&dwdma_tr, "size is 0!"); } tr_dbg(&dwdma_tr, "DAR %x reader 0x%x free 0x%x avail 0x%x", write_ptr, @@ -1056,7 +1060,7 @@ static int dw_dma_free_data_size(struct dma_chan_data *channel) if (delta) size = dw_chan->ptr_data.buffer_bytes; else - tr_info(&dwdma_tr, "dw_dma_free_data_size() size is 0!"); + tr_info(&dwdma_tr, "size is 0!"); } tr_dbg(&dwdma_tr, "SAR %x writer 0x%x free 0x%x avail 0x%x", read_ptr, @@ -1072,7 +1076,7 @@ static int dw_dma_get_data_size(struct dma_chan_data *channel, k_spinlock_key_t key; int ret = 0; - tr_dbg(&dwdma_tr, "dw_dma_get_data_size(): dma %d channel %d get data size", + tr_dbg(&dwdma_tr, "dma %d channel %d get data size", channel->dma->plat_data.id, channel->index); key = k_spin_lock(&channel->dma->lock); @@ -1091,7 +1095,7 @@ static int dw_dma_get_data_size(struct dma_chan_data *channel, #if CONFIG_DMA_HW_LLI if (!(dma_reg_read(channel->dma, DW_DMA_CHAN_EN) & DW_CHAN(channel->index))) { - tr_err(&dwdma_tr, "dw_dma_get_data_size(): xrun detected"); + tr_err(&dwdma_tr, "xrun detected"); return -ENODATA; } #endif diff --git a/src/drivers/dw/ssi-spi.c b/src/drivers/dw/ssi-spi.c index 2ed54fe8ceee..364ea9d19b9c 100644 --- a/src/drivers/dw/ssi-spi.c +++ b/src/drivers/dw/ssi-spi.c @@ -451,14 +451,14 @@ int spi_probe(struct spi *spi) /* configure the spi clock */ io_reg_write(SSI_SLAVE_CLOCK_CTL, 0x00000001); - spi->rx_buffer = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_DMA, + spi->rx_buffer = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_DMA, SPI_BUFFER_SIZE); if (!spi->rx_buffer) { tr_err(&ipc_tr, "eSp"); return -ENOMEM; } - spi->tx_buffer = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_DMA, + spi->tx_buffer = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_DMA, SPI_BUFFER_SIZE); spi->buffer_size = SPI_BUFFER_SIZE; if (!spi->tx_buffer) { @@ -508,7 +508,7 @@ int spi_install(const struct spi_platform_data *plat, size_t n) goto unlock; } - spi_devices = rmalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, + spi_devices = rmalloc(SOF_MEM_FLAG_KERNEL, sizeof(*spi) * n); if (!spi_devices) { ret = -ENOMEM; diff --git a/src/drivers/generic/dummy-dma.c b/src/drivers/generic/dummy-dma.c index 8b710d31b930..c088d9415d55 100644 --- a/src/drivers/generic/dummy-dma.c +++ b/src/drivers/generic/dummy-dma.c @@ -421,7 +421,7 @@ static int dummy_dma_probe(struct dma *dma) return -EEXIST; /* already created */ } - dma->chan = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, dma->plat_data.channels * sizeof(dma->chan[0])); if (!dma->chan) { tr_err(&ddma_tr, "dummy-dmac %d: Out of memory!", @@ -429,7 +429,7 @@ static int dummy_dma_probe(struct dma *dma) return -ENOMEM; } - chanp = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_RAM, + chanp = rzalloc(SOF_MEM_FLAG_KERNEL, dma->plat_data.channels * sizeof(chanp[0])); if (!chanp) { rfree(dma->chan); diff --git a/src/drivers/imx/edma.c b/src/drivers/imx/edma.c index a7b75efab7d7..b21c58bcb02c 100644 --- a/src/drivers/imx/edma.c +++ b/src/drivers/imx/edma.c @@ -391,7 +391,7 @@ static int edma_set_config(struct dma_chan_data *channel, doff = config->dest_width; break; default: - tr_err(&edma_tr, "edma_set_config() unsupported config direction"); + tr_err(&edma_tr, "unsupported config direction"); return -EINVAL; } @@ -420,7 +420,7 @@ static int edma_probe(struct dma *dma) } tr_info(&edma_tr, "EDMA: probe"); - dma->chan = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { @@ -541,7 +541,7 @@ static int edma_get_data_size(struct dma_chan_data *channel, *avail = ABS(capture_data_size) / 2; break; default: - tr_err(&edma_tr, "edma_get_data_size() unsupported direction %d", + tr_err(&edma_tr, "unsupported direction %d", channel->direction); return -EINVAL; } diff --git a/src/drivers/imx/esai.c b/src/drivers/imx/esai.c index d917b814893d..60af9bef9e5a 100644 --- a/src/drivers/imx/esai.c +++ b/src/drivers/imx/esai.c @@ -338,7 +338,7 @@ static int esai_probe(struct dai *dai) dai_err(dai, "ESAI: Repeated probe, skipping"); return -EEXIST; } - pdata = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*pdata)); + pdata = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*pdata)); if (!pdata) { dai_err(dai, "ESAI probe failure, out of memory"); return -ENOMEM; @@ -367,7 +367,7 @@ static int esai_remove(struct dai *dai) { struct esai_pdata *pdata = dai_get_drvdata(dai); - dai_info(dai, "esai_remove()"); + dai_info(dai, "entry"); rfree(pdata); dai_set_drvdata(dai, NULL); @@ -391,7 +391,7 @@ static int esai_get_fifo(struct dai *dai, int direction, int stream_id) case DAI_DIR_CAPTURE: return dai_fifo(dai, direction); /* stream_id is unused */ default: - dai_err(dai, "esai_get_fifo(): Invalid direction"); + dai_err(dai, "Invalid direction"); return -EINVAL; } } @@ -403,7 +403,7 @@ static int esai_get_fifo_depth(struct dai *dai, int direction) case DAI_DIR_CAPTURE: return dai->plat_data.fifo[direction].depth; default: - dai_err(dai, "esai_get_fifo_depth(): Invalid direction"); + dai_err(dai, "Invalid direction"); return -EINVAL; } } @@ -420,7 +420,7 @@ static int esai_get_hw_params(struct dai *dai, params->buffer_fmt = 0; params->frame_fmt = SOF_IPC_FRAME_S24_4LE; - dai_info(dai, "esai_get_hw_params(): params->rate = %d, fsync_rate = %d", + dai_info(dai, "params->rate = %d, fsync_rate = %d", params->rate, esai->params.fsync_rate); return 0; diff --git a/src/drivers/imx/interrupt-irqsteer.c b/src/drivers/imx/interrupt-irqsteer.c index da45b4f109ba..e42dce923bc9 100644 --- a/src/drivers/imx/interrupt-irqsteer.c +++ b/src/drivers/imx/interrupt-irqsteer.c @@ -348,7 +348,7 @@ static inline void irq_handler(void *data, uint32_t line_index) if (!--tries) { tries = IRQ_MAX_TRIES; - tr_err(&irq_i_tr, "irq_handler(): IRQ storm, status 0x%08x%08x", + tr_err(&irq_i_tr, "IRQ storm, status 0x%08x%08x", (uint32_t)(status >> 32), (uint32_t)status); } } diff --git a/src/drivers/imx/ipc.c b/src/drivers/imx/ipc.c index 1b398088cb1c..a124d20a9028 100644 --- a/src/drivers/imx/ipc.c +++ b/src/drivers/imx/ipc.c @@ -184,7 +184,7 @@ int platform_ipc_init(struct ipc *ipc) #if CONFIG_HOST_PTABLE struct ipc_data *iipc; - iipc = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, sizeof(*iipc)); + iipc = rzalloc(SOF_MEM_FLAG_USER, sizeof(*iipc)); if (!iipc) { tr_err(&ipc_tr, "Unable to allocate IPC private data"); return -ENOMEM; @@ -200,11 +200,11 @@ int platform_ipc_init(struct ipc *ipc) #if CONFIG_HOST_PTABLE /* allocate page table buffer */ - iipc->dh_buffer.page_table = rzalloc(SOF_MEM_ZONE_SYS, 0, - SOF_MEM_CAPS_RAM, + iipc->dh_buffer.page_table = rzalloc(SOF_MEM_FLAG_USER, PLATFORM_PAGE_TABLE_SIZE); - if (iipc->dh_buffer.page_table) - bzero(iipc->dh_buffer.page_table, PLATFORM_PAGE_TABLE_SIZE); + if (!iipc->dh_buffer.page_table) + sof_panic(SOF_IPC_PANIC_IPC); + bzero(iipc->dh_buffer.page_table, PLATFORM_PAGE_TABLE_SIZE); #if CONFIG_ZEPHYR_NATIVE_DRIVERS iipc->dh_buffer.dmac = sof_dma_get(SOF_DMA_DIR_HMEM_TO_LMEM, 0, SOF_DMA_DEV_HOST, SOF_DMA_ACCESS_SHARED); diff --git a/src/drivers/imx/micfil.c b/src/drivers/imx/micfil.c index 66cc88639e15..0946ca165c57 100644 --- a/src/drivers/imx/micfil.c +++ b/src/drivers/imx/micfil.c @@ -50,7 +50,7 @@ static int micfil_get_hw_params(struct dai *dai, { struct micfil_pdata *micfil = dai_get_drvdata(dai); - dai_info(dai, "micfil_get_hw_params()"); + dai_info(dai, "entry"); params->rate = micfil->params.pdm_rate; params->channels = micfil->params.pdm_ch; @@ -184,7 +184,7 @@ static int micfil_set_config(struct dai *dai, struct ipc_config_dai *common_conf micfil->params = config->micfil; - dai_info(dai, "micfil_set_config() dai_idx %d channels %d sampling_freq %d", + dai_info(dai, "dai_idx %d channels %d sampling_freq %d", common_config->dai_index, micfil->params.pdm_ch, micfil->params.pdm_rate); /* disable the module */ @@ -232,7 +232,7 @@ static int micfil_get_fifo_depth(struct dai *dai, int direction) static void micfil_start(struct dai *dai) { - dai_info(dai, "micfil_start()"); + dai_info(dai, "entry"); micfil_reset(dai); @@ -252,7 +252,7 @@ static void micfil_start(struct dai *dai) static void micfil_stop(struct dai *dai) { - dai_info(dai, "micfil_stop()"); + dai_info(dai, "entry"); /* Disable the module */ dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_PDMIEN, 0); @@ -263,7 +263,7 @@ static void micfil_stop(struct dai *dai) static int micfil_trigger(struct dai *dai, int cmd, int direction) { - dai_info(dai, "micfil_trigger() cmd %d dir %d", cmd, direction); + dai_info(dai, "cmd %d dir %d", cmd, direction); switch (cmd) { case COMP_TRIGGER_START: @@ -288,9 +288,9 @@ static int micfil_probe(struct dai *dai) { struct micfil_pdata *micfil; - dai_info(dai, "micfil_probe()"); + dai_info(dai, "entry"); - micfil = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*micfil)); + micfil = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*micfil)); if (!micfil) { dai_err(dai, "micfil probe failed"); return -ENOMEM; @@ -307,7 +307,7 @@ static int micfil_remove(struct dai *dai) { struct micfil_pdata *micfil = dai_get_drvdata(dai); - dai_info(dai, "micfil_remove()"); + dai_info(dai, "entry"); rfree(micfil); dai_set_drvdata(dai, NULL); diff --git a/src/drivers/imx/sai.c b/src/drivers/imx/sai.c index 7971b76a8b7f..1d748c44a6e0 100644 --- a/src/drivers/imx/sai.c +++ b/src/drivers/imx/sai.c @@ -29,7 +29,7 @@ DECLARE_TR_CTX(sai_tr, SOF_UUID(sai_uuid), LOG_LEVEL_INFO); static void sai_start(struct dai *dai, int direction) { - dai_info(dai, "SAI: sai_start"); + dai_info(dai, "SAI: entry"); struct sai_pdata *sai = dai_get_drvdata(dai); int chan_idx = 0; @@ -139,7 +139,7 @@ static void sai_start(struct dai *dai, int direction) static void sai_release(struct dai *dai, int direction) { - dai_info(dai, "SAI: sai_release"); + dai_info(dai, "SAI: entry"); int chan_idx = 0; #ifdef CONFIG_IMX8ULP @@ -171,7 +171,7 @@ static void sai_release(struct dai *dai, int direction) static void sai_stop(struct dai *dai, int direction) { - dai_info(dai, "SAI: sai_stop"); + dai_info(dai, "SAI: entry"); uint32_t xcsr = 0U; int ret = 0; @@ -222,7 +222,7 @@ static void sai_stop(struct dai *dai, int direction) static inline int sai_set_config(struct dai *dai, struct ipc_config_dai *common_config, const void *spec_config) { - dai_info(dai, "SAI: sai_set_config"); + dai_info(dai, "SAI: entry"); const struct sof_ipc_dai_config *config = spec_config; uint32_t val_cr2 = 0, val_cr4 = 0, val_cr5 = 0; uint32_t mask_cr2 = 0, mask_cr4 = 0, mask_cr5 = 0; @@ -438,7 +438,7 @@ static inline int sai_set_config(struct dai *dai, struct ipc_config_dai *common_ static int sai_trigger(struct dai *dai, int cmd, int direction) { - dai_info(dai, "SAI: sai_trigger"); + dai_info(dai, "SAI: entry"); switch (cmd) { case COMP_TRIGGER_START: @@ -465,12 +465,12 @@ static int sai_probe(struct dai *dai) { struct sai_pdata *sai; - dai_info(dai, "SAI: sai_probe"); + dai_info(dai, "SAI: entry"); /* allocate private data */ - sai = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*sai)); + sai = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*sai)); if (!sai) { - dai_err(dai, "sai_probe(): alloc failed"); + dai_err(dai, "alloc failed"); return -ENOMEM; } dai_set_drvdata(dai, sai); @@ -504,7 +504,7 @@ static int sai_remove(struct dai *dai) { struct sai_pdata *sai = dai_get_drvdata(dai); - dai_info(dai, "sai_remove()"); + dai_info(dai, "entry"); rfree(sai); dai_set_drvdata(dai, NULL); @@ -524,7 +524,7 @@ static int sai_get_fifo(struct dai *dai, int direction, int stream_id) case DAI_DIR_CAPTURE: return dai_fifo(dai, direction); /* stream_id is unused */ default: - dai_err(dai, "sai_get_fifo(): Invalid direction"); + dai_err(dai, "Invalid direction"); return -EINVAL; } } @@ -536,7 +536,7 @@ static int sai_get_fifo_depth(struct dai *dai, int direction) case DAI_DIR_CAPTURE: return dai->plat_data.fifo[direction].depth; default: - dai_err(dai, "esai_get_fifo_depth(): Invalid direction"); + dai_err(dai, "Invalid direction"); return -EINVAL; } } diff --git a/src/drivers/imx/sdma.c b/src/drivers/imx/sdma.c index 6f24e9c0c8b4..e14db9e6796e 100644 --- a/src/drivers/imx/sdma.c +++ b/src/drivers/imx/sdma.c @@ -85,8 +85,7 @@ struct sdma_pdata { static void sdma_set_overrides(struct dma_chan_data *channel, bool event_override, bool host_override) { - tr_dbg(&sdma_tr, "sdma_set_overrides(%d, %d)", event_override, - host_override); + tr_dbg(&sdma_tr, "event %d, host %d", event_override, host_override); dma_reg_update_bits(channel->dma, SDMA_EVTOVR, BIT(channel->index), event_override ? BIT(channel->index) : 0); dma_reg_update_bits(channel->dma, SDMA_HOSTOVR, BIT(channel->index), @@ -110,7 +109,7 @@ static int sdma_run_c0(struct dma *dma, uint8_t cmd, uint32_t buf_addr, struct sdma_chan *c0data = dma_chan_get_data(c0); int ret; - tr_dbg(&sdma_tr, "sdma_run_c0 cmd %d buf_addr 0x%08x sdma_addr 0x%04x count %d", + tr_dbg(&sdma_tr, "cmd %d buf_addr 0x%08x sdma_addr 0x%04x count %d", cmd, buf_addr, sdma_addr, count); c0data->desc[0].config = SDMA_BD_CMD(cmd) | SDMA_BD_COUNT(count) @@ -150,7 +149,7 @@ static int sdma_run_c0(struct dma *dma, uint8_t cmd, uint32_t buf_addr, dma_reg_update_bits(dma, SDMA_CONFIG, SDMA_CONFIG_CSM_MSK, SDMA_CONFIG_CSM_DYN); - tr_dbg(&sdma_tr, "sdma_run_c0 done, ret = %d", ret); + tr_dbg(&sdma_tr, "done, ret = %d", ret); return ret; } @@ -161,7 +160,7 @@ static int sdma_register_init(struct dma *dma) struct sdma_pdata *pdata = dma_get_drvdata(dma); int i; - tr_dbg(&sdma_tr, "sdma_register_init"); + tr_dbg(&sdma_tr, "entry"); dma_reg_write(dma, SDMA_RESET, 1); /* Wait for 10us */ ret = poll_for_register_delay(dma_base(dma) + SDMA_RESET, 1, 0, 1000); @@ -216,7 +215,7 @@ static void sdma_init_c0(struct dma *dma) struct sdma_pdata *sdma_pdata = dma_get_drvdata(dma); struct sdma_chan *pdata = &sdma_pdata->chan_pdata[0]; - tr_dbg(&sdma_tr, "sdma_init_c0"); + tr_dbg(&sdma_tr, "entry"); c0->status = COMP_STATE_READY; /* Reset channel 0 private data */ @@ -233,14 +232,14 @@ static int sdma_boot(struct dma *dma) { int ret; - tr_dbg(&sdma_tr, "sdma_boot"); + tr_dbg(&sdma_tr, "entry"); ret = sdma_register_init(dma); if (ret < 0) return ret; sdma_init_c0(dma); - tr_dbg(&sdma_tr, "sdma_boot done"); + tr_dbg(&sdma_tr, "done"); return 0; } @@ -251,7 +250,7 @@ static int sdma_upload_context(struct dma_chan_data *chan) /* Ensure context is ready for upload */ dcache_writeback_region(pdata->ctx, sizeof(*pdata->ctx)); - tr_dbg(&sdma_tr, "sdma_upload_context for channel %d", chan->index); + tr_dbg(&sdma_tr, "for channel %d", chan->index); /* Last parameters are unneeded for this command and are ignored; * set to 0. @@ -289,7 +288,7 @@ static int sdma_probe(struct dma *dma) tr_info(&sdma_tr, "SDMA: probe"); - dma->chan = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { @@ -297,7 +296,7 @@ static int sdma_probe(struct dma *dma) return -ENOMEM; } - pdata = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + pdata = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(*pdata)); if (!pdata) { rfree(dma->chan); @@ -313,7 +312,7 @@ static int sdma_probe(struct dma *dma) dma->chan[channel].dma = dma; } - pdata->chan_pdata = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + pdata->chan_pdata = rzalloc(SOF_MEM_FLAG_KERNEL, dma->plat_data.channels * sizeof(struct sdma_chan)); if (!pdata->chan_pdata) { @@ -322,7 +321,7 @@ static int sdma_probe(struct dma *dma) goto err; } - pdata->contexts = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + pdata->contexts = rzalloc(SOF_MEM_FLAG_KERNEL, dma->plat_data.channels * sizeof(struct sdma_context)); if (!pdata->contexts) { @@ -331,7 +330,7 @@ static int sdma_probe(struct dma *dma) goto err; } - pdata->ccb_array = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + pdata->ccb_array = rzalloc(SOF_MEM_FLAG_KERNEL, dma->plat_data.channels * sizeof(struct sdma_ccb)); if (!pdata->ccb_array) { @@ -382,7 +381,7 @@ static int sdma_remove(struct dma *dma) return 0; } - tr_dbg(&sdma_tr, "sdma_remove"); + tr_dbg(&sdma_tr, "entry"); /* Prevent all channels except channel 0 from running */ dma_reg_write(dma, SDMA_HOSTOVR, 1); @@ -442,9 +441,9 @@ static void sdma_enable_event(struct dma_chan_data *channel, int eventnum) { struct sdma_chan *pdata = dma_chan_get_data(channel); - tr_dbg(&sdma_tr, "sdma_enable_event(%d, %d)", channel->index, eventnum); + tr_dbg(&sdma_tr, "channel %d, event %d", channel->index, eventnum); - if (eventnum < 0 || eventnum > SDMA_HWEVENTS_COUNT) + if (eventnum < 0 || eventnum >= SDMA_HWEVENTS_COUNT) return; /* No change if request is invalid */ dma_reg_update_bits(channel->dma, SDMA_CHNENBL(eventnum), @@ -460,9 +459,9 @@ static void sdma_enable_event(struct dma_chan_data *channel, int eventnum) static void sdma_disable_event(struct dma_chan_data *channel, int eventnum) { - tr_dbg(&sdma_tr, "sdma_disable_event(%d, %d)", channel->index, eventnum); + tr_dbg(&sdma_tr, "channel %d, event %d", channel->index, eventnum); - if (eventnum < 0 || eventnum > SDMA_HWEVENTS_COUNT) + if (eventnum < 0 || eventnum >= SDMA_HWEVENTS_COUNT) return; /* No change if request is invalid */ dma_reg_update_bits(channel->dma, SDMA_CHNENBL(eventnum), @@ -475,7 +474,7 @@ static void sdma_channel_put(struct dma_chan_data *channel) if (channel->status == COMP_STATE_INIT) return; /* Channel was already free */ - tr_dbg(&sdma_tr, "sdma_channel_put(%d)", channel->index); + tr_dbg(&sdma_tr, "channel %d", channel->index); dma_interrupt_legacy(channel, DMA_IRQ_CLEAR); sdma_disable_event(channel, pdata->hw_event); @@ -485,7 +484,7 @@ static void sdma_channel_put(struct dma_chan_data *channel) static int sdma_start(struct dma_chan_data *channel) { - tr_dbg(&sdma_tr, "sdma_start(%d)", channel->index); + tr_dbg(&sdma_tr, "channel %d", channel->index); if (channel->status != COMP_STATE_PREPARE && channel->status != COMP_STATE_PAUSED) @@ -507,7 +506,7 @@ static int sdma_stop(struct dma_chan_data *channel) channel->status = COMP_STATE_READY; - tr_dbg(&sdma_tr, "sdma_stop(%d)", channel->index); + tr_dbg(&sdma_tr, "channel %d", channel->index); sdma_disable_channel(channel->dma, channel->index); @@ -553,7 +552,7 @@ static int sdma_copy(struct dma_chan_data *channel, int bytes, uint32_t flags) }; int idx; - tr_dbg(&sdma_tr, "sdma_copy"); + tr_dbg(&sdma_tr, "entry"); idx = (pdata->next_bd + 1) % 2; pdata->next_bd = idx; @@ -581,7 +580,7 @@ static int sdma_status(struct dma_chan_data *channel, struct sdma_chan *pdata = dma_chan_get_data(channel); struct sdma_bd *bd; - tr_dbg(&sdma_tr, "sdma_status"); + tr_dbg(&sdma_tr, "entry"); if (channel->status == COMP_STATE_INIT) return -EINVAL; status->state = channel->status; @@ -689,13 +688,13 @@ static int sdma_read_config(struct dma_chan_data *channel, for (i = 0; i < config->elem_array.count; i++) { if (config->direction == SOF_DMA_DIR_MEM_TO_DEV && pdata->fifo_paddr != config->elem_array.elems[i].dest) { - tr_err(&sdma_tr, "sdma_read_config: FIFO changes address!"); + tr_err(&sdma_tr, "FIFO changes address!"); return -EINVAL; } if (config->direction == SOF_DMA_DIR_DEV_TO_MEM && pdata->fifo_paddr != config->elem_array.elems[i].src) { - tr_err(&sdma_tr, "sdma_read_config: FIFO changes address!"); + tr_err(&sdma_tr, "FIFO changes address!"); return -EINVAL; } @@ -868,7 +867,7 @@ static int sdma_set_config(struct dma_chan_data *channel, struct sdma_chan *pdata = dma_chan_get_data(channel); int ret; - tr_dbg(&sdma_tr, "sdma_set_config channel %d", channel->index); + tr_dbg(&sdma_tr, "channel %d", channel->index); ret = sdma_read_config(channel, config); if (ret < 0) @@ -925,7 +924,7 @@ static int sdma_interrupt(struct dma_chan_data *channel, enum dma_irq_cmd cmd) */ return 0; default: - tr_err(&sdma_tr, "sdma_interrupt unknown cmd %d", cmd); + tr_err(&sdma_tr, "unknown cmd %d", cmd); return -EINVAL; } } @@ -966,7 +965,7 @@ static int sdma_get_data_size(struct dma_chan_data *channel, uint32_t *avail, uint32_t result_data = 0; int i; - tr_dbg(&sdma_tr, "sdma_get_data_size(%d)", channel->index); + tr_dbg(&sdma_tr, "channel %d", channel->index); if (channel->index == 0) { /* Channel 0 shouldn't have this called anyway */ tr_err(&sdma_tr, "Please do not call get_data_size on SDMA channel 0!"); @@ -992,7 +991,7 @@ static int sdma_get_data_size(struct dma_chan_data *channel, uint32_t *avail, *avail = result_data; break; default: - tr_err(&sdma_tr, "sdma_get_data_size channel invalid direction"); + tr_err(&sdma_tr, "channel invalid direction"); return -EINVAL; } return 0; diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index dd208a3cfb4e..afa07c4d1d46 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -73,7 +73,12 @@ int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl) } - *cascade = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(**cascade)); + *cascade = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(**cascade)); + if (!*cascade) { + ret = -ENOMEM; + tr_err(&irq_tr, "cascading IRQ controller allocation failed!"); + goto unlock; + } k_spinlock_init(&(*cascade)->lock); @@ -163,8 +168,7 @@ struct irq_cascade_desc *interrupt_get_parent(uint32_t irq) void interrupt_init(struct sof *sof) { - sof->cascade_root = platform_shared_get(&cascade_root, - sizeof(cascade_root)); + sof->cascade_root = &cascade_root; sof->cascade_root->last_irq = PLATFORM_IRQ_FIRST_CHILD - 1; k_spinlock_init(&sof->cascade_root->lock); @@ -205,7 +209,7 @@ static int irq_register_child(struct irq_cascade_desc *cascade, int irq, /* init child from run-time, may be registered and unregistered * many times at run-time */ - child = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + child = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(struct irq_desc)); if (!child) { ret = -ENOMEM; diff --git a/src/drivers/mediatek/CMakeLists.txt b/src/drivers/mediatek/CMakeLists.txt index f1090111e5d6..4362b62ec7cb 100644 --- a/src/drivers/mediatek/CMakeLists.txt +++ b/src/drivers/mediatek/CMakeLists.txt @@ -7,3 +7,9 @@ endif() if(CONFIG_MT8186 OR CONFIG_MT8188) add_subdirectory(mt818x) endif() +if(CONFIG_MT8196) + add_subdirectory(mt8196) +endif() +if(CONFIG_MT8365) + add_subdirectory(mt8365) +endif() diff --git a/src/drivers/mediatek/afe/CMakeLists.txt b/src/drivers/mediatek/afe/CMakeLists.txt index 76116c07c28f..228a6555d2c8 100644 --- a/src/drivers/mediatek/afe/CMakeLists.txt +++ b/src/drivers/mediatek/afe/CMakeLists.txt @@ -10,3 +10,9 @@ endif() if(CONFIG_MT8195) add_subdirectory(mt8195) endif() +if(CONFIG_MT8196) + add_subdirectory(mt8196) +endif() +if(CONFIG_MT8365) + add_subdirectory(mt8365) +endif() diff --git a/src/drivers/mediatek/afe/afe-drv.c b/src/drivers/mediatek/afe/afe-drv.c index c5b27f772b7b..5f09359117e6 100644 --- a/src/drivers/mediatek/afe/afe-drv.c +++ b/src/drivers/mediatek/afe/afe-drv.c @@ -251,7 +251,7 @@ int afe_dai_set_config(struct mtk_base_afe *afe, int id, unsigned int channel, u if (id >= afe->dais_size) return -EINVAL; - tr_info(&afedrv_tr, "afe_dai_set_config, id:%d\n", id); + tr_info(&afedrv_tr, "id:%d\n", id); dai = &afe->dais[id]; dai->channel = channel; @@ -271,10 +271,10 @@ int afe_dai_get_config(struct mtk_base_afe *afe, int id, unsigned int *channel, /* TODO 1. if need use dai->id to search target dai */ /* TODO 1. if need a status to control the dai status */ - tr_info(&afedrv_tr, "afe_dai_get_config, id:%d\n", id); + tr_info(&afedrv_tr, "id:%d\n", id); if (id >= afe->dais_size || id < 0) { - tr_err(&afedrv_tr, "afe_dai_get_config , invalid id:%d\n", id); + tr_err(&afedrv_tr, ", invalid id:%d\n", id); return -EINVAL; } dai = &afe->dais[id]; @@ -362,7 +362,7 @@ int afe_probe(struct mtk_base_afe *afe) tr_dbg(&afedrv_tr, "afe_base:0x%x\n", afe->base); /* TODO how to get the memif number, how to sync with dmac lib */ afe->memifs_size = platform->memif_size; - afe->memif = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + afe->memif = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(struct mtk_base_afe_memif) * afe->memifs_size); if (!afe->memif) return -ENOMEM; @@ -372,14 +372,14 @@ int afe_probe(struct mtk_base_afe *afe) /* TODO how to get the dai number, how to sync with dai lib*/ afe->dais_size = platform->dais_size; - afe->dais = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + afe->dais = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(struct mtk_base_afe_dai) * afe->dais_size); if (!afe->dais) goto err_alloc_memif; /* TODO how to get the irq number */ afe->irqs_size = platform->irqs_size; - afe->irqs = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + afe->irqs = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(struct mtk_base_afe_irq) * afe->irqs_size); if (!afe->irqs && afe->irqs_size) goto err_alloc_dais; diff --git a/src/drivers/mediatek/afe/afe-memif.c b/src/drivers/mediatek/afe/afe-memif.c index 9fb691622a92..1e57f5cf0289 100644 --- a/src/drivers/mediatek/afe/afe-memif.c +++ b/src/drivers/mediatek/afe/afe-memif.c @@ -192,7 +192,7 @@ static int memif_copy(struct dma_chan_data *channel, int bytes, uint32_t flags) memif->wptr = (memif->wptr + bytes) % memif->dma_size; else memif->rptr = (memif->rptr + bytes) % memif->dma_size; - tr_dbg(&memif_tr, "memif_copy: wptr:%u, rptr:%u", memif->wptr, memif->rptr); + tr_dbg(&memif_tr, "wptr:%u, rptr:%u", memif->wptr, memif->rptr); notifier_event(channel, NOTIFIER_ID_DMA_COPY, NOTIFIER_TARGET_CORE_LOCAL, &next, sizeof(next)); @@ -241,7 +241,7 @@ static int memif_set_config(struct dma_chan_data *channel, struct dma_sg_config channel->direction = config->direction; direction = afe_memif_get_direction(memif->afe, memif->memif_id); - tr_info(&memif_tr, "memif_set_config, direction:%d, afe_dir:%d", config->direction, + tr_info(&memif_tr, "direction:%d, afe_dir:%d", config->direction, direction); switch (config->direction) { @@ -263,7 +263,7 @@ static int memif_set_config(struct dma_chan_data *channel, struct dma_sg_config tr_dbg(&memif_tr, "capture: dai_id:%d, dma_addr:%u\n", dai_id, dma_addr); break; default: - tr_err(&memif_tr, "afe_memif_set_config() unsupported config direction"); + tr_err(&memif_tr, "afe_unsupported config direction"); return -EINVAL; } @@ -360,7 +360,7 @@ static int memif_probe(struct dma *dma) return ret; } - dma->chan = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + dma->chan = rzalloc(SOF_MEM_FLAG_KERNEL, dma->plat_data.channels * sizeof(struct dma_chan_data)); if (!dma->chan) { tr_err(&memif_tr, "MEMIF: Probe failure, unable to allocate channel descriptors"); @@ -373,7 +373,7 @@ static int memif_probe(struct dma *dma) dma->chan[channel].index = channel; dma->chan[channel].status = COMP_STATE_INIT; - memif = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_RAM, + memif = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(struct afe_memif_dma)); if (!memif) { tr_err(&memif_tr, "afe-memif: %d channel %d private data alloc failed", @@ -437,7 +437,11 @@ static int memif_get_attribute(struct dma *dma, uint32_t type, uint32_t *value) *value = 4; break; case DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT: +#if defined(CONFIG_SOC_SERIES_MT818X) || defined(CONFIG_SOC_MT8195) + *value = 64; +#else *value = 16; +#endif break; case DMA_ATTR_BUFFER_PERIOD_COUNT: *value = 4; diff --git a/src/drivers/mediatek/afe/mt8196/CMakeLists.txt b/src/drivers/mediatek/afe/mt8196/CMakeLists.txt new file mode 100755 index 000000000000..3f0653684edf --- /dev/null +++ b/src/drivers/mediatek/afe/mt8196/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_TEST_SGEN) +add_local_sources(sof afe-sgen.c) +endif() diff --git a/src/drivers/mediatek/afe/mt8196/afe-sgen.c b/src/drivers/mediatek/afe/mt8196/afe-sgen.c new file mode 100755 index 000000000000..f78b8e4a5d8d --- /dev/null +++ b/src/drivers/mediatek/afe/mt8196/afe-sgen.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Darren Ye <darren.ye@mediatek.com> + */ + +#include <stdint.h> + +#include <sof/drivers/afe-sgen.h> +#include <sof/lib/io.h> +#include <sof/lib/uuid.h> +#include <sof/trace/trace.h> +#include <mt8196-afe-reg.h> +#include <mt8196-afe-common.h> + +void afe_sinegen_enable(void) +{ +} + +void afe_sinegen_disable(void) +{ +} diff --git a/src/drivers/mediatek/afe/mt8365/CMakeLists.txt b/src/drivers/mediatek/afe/mt8365/CMakeLists.txt new file mode 100644 index 000000000000..3f0653684edf --- /dev/null +++ b/src/drivers/mediatek/afe/mt8365/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: BSD-3-Clause + +if(CONFIG_TEST_SGEN) +add_local_sources(sof afe-sgen.c) +endif() diff --git a/src/drivers/mediatek/afe/mt8365/afe-sgen.c b/src/drivers/mediatek/afe/mt8365/afe-sgen.c new file mode 100644 index 000000000000..e632f7ca6676 --- /dev/null +++ b/src/drivers/mediatek/afe/mt8365/afe-sgen.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#include <stdint.h> + +#include <sof/drivers/afe-sgen.h> +#include <sof/lib/io.h> +#include <sof/lib/uuid.h> +#include <sof/trace/trace.h> + +#include <mt8365-afe-regs.h> +#include <mt8365-afe-common.h> + +SOF_DEFINE_REG_UUID(sgen_mt8365); + +DECLARE_TR_CTX(sgen_tr, SOF_UUID(sgen_mt8365_uuid), LOG_LEVEL_INFO); + +/* + * Note: TEST_SGEN for test only + * Define this TEST_SGEN to enable sine tone generator + * then output data to audio memory interface(memif), + * you can set TEST_SGEN_ID to choose output to which memif. + * e.g. set TEST_SGEN as '1' and TEST_SGEN_ID as "MT8365_MEMIF_DL1", + * the data source of DL2 will from sine generator. + */ +#define TEST_SGEN_ID MT8365_MEMIF_DL1 +#define AUDIO_TML_PD_MASK 1 +#define AUDIO_TML_PD_SHIFT 27 + +#define AFE_SGEN_FREQ_DIV_CH1_MASK 0x1f +#define AFE_SGEN_FREQ_DIV_CH1_SHIFT 0 +#define AFE_SGEN_FREQ_DIV_CH2_MASK 0x1f +#define AFE_SGEN_FREQ_DIV_CH2_SHIFT 12 +#define AFE_SGEN_AMP_DIV_CH1_MASK 0x7 +#define AFE_SGEN_AMP_DIV_CH1_SHIFT 5 +#define AFE_SGEN_AMP_DIV_CH2_MASK 0x7 +#define AFE_SGEN_AMP_DIV_CH2_SHIFT 17 +#define AFE_SGEN_MUTE_CH1_MASK 0x1 +#define AFE_SGEN_MUTE_CH1_SHIFT 24 +#define AFE_SGEN_MUTE_CH2_MASK 0x1 +#define AFE_SGEN_MUTE_CH2_SHIFT 25 +#define AFE_SGEN_ENABLE_MASK 0x1 +#define AFE_SGEN_ENABLE_SHIFT 26 + +#define AFE_SGEN_TIMING_CH1_MASK 0x0f +#define AFE_SGEN_TIMING_CH1_SHIFT 8 +#define AFE_SGEN_TIMING_CH2_MASK 0x0f +#define AFE_SGEN_TIMING_CH2_SHIFT 20 + +#define AFE_SINEGEN_LB_MODE_MSK 0x1f +#define AFE_SINEGEN_LB_MODE_SHIFT 27 + +enum { + MT8365_SGEN_AWB = (0x3 << 1) | 1, // o5 + o6 + SGEN to out + MT8365_SGEN_VUL = (0x5 << 1) | 1, // o9 + o10 + SGEN to out + MT8365_SGEN_DL1 = (0x3 << 1) | 0, // i5 + i6 + SGEN to in + MT8365_SGEN_DL2 = (0x4 << 1) | 0 // i7 + i8 + SGEN to in +}; + +/*sgen freq div*/ +enum { + SGEN_FREQ_64D1 = 1, + SGEN_FREQ_64D2 = 2, + SGEN_FREQ_64D3 = 3, + SGEN_FREQ_64D4 = 4, + SGEN_FREQ_64D5 = 5, + SGEN_FREQ_64D6 = 6, + SGEN_FREQ_64D7 = 7, + SGEN_FREQ_64D8 = 8, +}; + +/*sgen amp div*/ +enum { + SGEN_AMP_D1 = 0, + SGEN_AMP_D2 = 1, + SGEN_AMP_D4 = 2, + SGEN_AMP_D8 = 3, + SGEN_AMP_D16 = 4, + SGEN_AMP_D32 = 5, + SGEN_AMP_D64 = 6, + SGEN_AMP_D128 = 7, +}; + +enum { + SGEN_CH_TIMING_8K = 0, + SGEN_CH_TIMING_11P025K = 1, + SGEN_CH_TIMING_12K = 2, + SGEN_CH_TIMING_16K = 4, + SGEN_CH_TIMING_22P05K = 5, + SGEN_CH_TIMING_24K = 6, + SGEN_CH_TIMING_32K = 8, + SGEN_CH_TIMING_44P1K = 9, + SGEN_CH_TIMING_48K = 10, + SGEN_CH_TIMING_88P2K = 11, + SGEN_CH_TIMING_96K = 12, + SGEN_CH_TIMING_176P4K = 13, + SGEN_CH_TIMING_192K = 14, +}; + +static uint32_t mt8365_sinegen_timing(uint32_t rate) +{ + uint32_t sinegen_timing; + + switch (rate) { + case 8000: + sinegen_timing = SGEN_CH_TIMING_8K; + break; + case 11025: + sinegen_timing = SGEN_CH_TIMING_11P025K; + break; + case 12000: + sinegen_timing = SGEN_CH_TIMING_12K; + break; + case 16000: + sinegen_timing = SGEN_CH_TIMING_16K; + break; + case 22050: + sinegen_timing = SGEN_CH_TIMING_22P05K; + break; + case 24000: + sinegen_timing = SGEN_CH_TIMING_24K; + break; + case 32000: + sinegen_timing = SGEN_CH_TIMING_32K; + break; + case 44100: + sinegen_timing = SGEN_CH_TIMING_44P1K; + break; + case 48000: + sinegen_timing = SGEN_CH_TIMING_48K; + break; + case 88200: + sinegen_timing = SGEN_CH_TIMING_88P2K; + break; + case 96000: + sinegen_timing = SGEN_CH_TIMING_96K; + break; + case 176400: + sinegen_timing = SGEN_CH_TIMING_176P4K; + break; + case 192000: + sinegen_timing = SGEN_CH_TIMING_192K; + break; + default: + sinegen_timing = SGEN_CH_TIMING_48K; + tr_err(&sgen_tr, "invalid rate %d, set default 48k ", rate); + } + tr_dbg(&sgen_tr, "rate %d, sinegen_timing %d ", rate, sinegen_timing); + return sinegen_timing; +} + +static void mtk_afe_reg_update_bits(uint32_t addr_offset, uint32_t mask, uint32_t val, int shift) +{ + io_reg_update_bits(AFE_REG_BASE + addr_offset, mask << shift, val << shift); +} + +static uint32_t mtk_afe_reg_read(uint32_t addr_offset) +{ + return io_reg_read(AFE_REG_BASE + addr_offset); +} + +static void mt8365_afe_sinegen_enable(uint32_t sgen_id, uint32_t rate, int enable) +{ + uint32_t loopback_mode, reg_1, sinegen_timing; + + tr_dbg(&sgen_tr, "sgen_id %d, enable %d", sgen_id, enable); + + sinegen_timing = mt8365_sinegen_timing(rate); + + if (enable == 1) { + /* set loopback mode */ + switch (sgen_id) { + case MT8365_MEMIF_AWB: + loopback_mode = MT8365_SGEN_AWB; + break; + case MT8365_MEMIF_VUL: + loopback_mode = MT8365_SGEN_VUL; + break; + case MT8365_MEMIF_DL1: + loopback_mode = MT8365_SGEN_DL1; + break; + case MT8365_MEMIF_DL2: + loopback_mode = MT8365_SGEN_DL2; + break; + default: + tr_err(&sgen_tr, "invalid sgen_id %d", sgen_id); + return; + } + /* enable sinegen clock*/ + mtk_afe_reg_update_bits(AUDIO_TOP_CON0, AUDIO_TML_PD_MASK, 0, AUDIO_TML_PD_SHIFT); + + /*loopback source*/ + mtk_afe_reg_update_bits(AFE_SGEN_CON0, AFE_SINEGEN_LB_MODE_MSK, loopback_mode, + AFE_SINEGEN_LB_MODE_SHIFT); + + /* sine gen timing*/ + mtk_afe_reg_update_bits(AFE_SGEN_CON0, AFE_SGEN_TIMING_CH1_MASK, + sinegen_timing, AFE_SGEN_TIMING_CH1_SHIFT); + mtk_afe_reg_update_bits(AFE_SGEN_CON0, AFE_SGEN_TIMING_CH2_MASK, + sinegen_timing, AFE_SGEN_TIMING_CH2_SHIFT); + + /*freq div*/ + mtk_afe_reg_update_bits(AFE_SGEN_CON0, AFE_SGEN_FREQ_DIV_CH1_MASK, + SGEN_FREQ_64D1, AFE_SGEN_FREQ_DIV_CH1_SHIFT); + mtk_afe_reg_update_bits(AFE_SGEN_CON0, AFE_SGEN_FREQ_DIV_CH2_MASK, + SGEN_FREQ_64D2, AFE_SGEN_FREQ_DIV_CH2_SHIFT); + + /*amp div*/ + mtk_afe_reg_update_bits(AFE_SGEN_CON0, AFE_SGEN_AMP_DIV_CH1_MASK, SGEN_AMP_D2, + AFE_SGEN_AMP_DIV_CH1_SHIFT); + mtk_afe_reg_update_bits(AFE_SGEN_CON0, AFE_SGEN_AMP_DIV_CH2_MASK, SGEN_AMP_D2, + AFE_SGEN_AMP_DIV_CH2_SHIFT); + /* enable sgen*/ + mtk_afe_reg_update_bits(AFE_SGEN_CON0, AFE_SGEN_ENABLE_MASK, 1, + AFE_SGEN_ENABLE_SHIFT); + } else { + /* disable sgen*/ + mtk_afe_reg_update_bits(AFE_SGEN_CON0, AFE_SGEN_ENABLE_MASK, 0, + AFE_SGEN_ENABLE_SHIFT); + + /* disable sgen clock */ + mtk_afe_reg_update_bits(AUDIO_TOP_CON0, AUDIO_TML_PD_MASK, 1, AUDIO_TML_PD_SHIFT); + } + + reg_1 = mtk_afe_reg_read(AFE_SGEN_CON0); + tr_dbg(&sgen_tr, "AFE_SGEN_CON0 0x%x", reg_1); +} + +void afe_sinegen_enable(void) +{ + mt8365_afe_sinegen_enable(TEST_SGEN_ID, 48000, 1); +} + +void afe_sinegen_disable(void) +{ + mt8365_afe_sinegen_enable(TEST_SGEN_ID, 48000, 0); +} diff --git a/src/drivers/mediatek/afe/zephyr_mtk_afe_memif.c b/src/drivers/mediatek/afe/zephyr_mtk_afe_memif.c new file mode 100644 index 000000000000..910e497f827e --- /dev/null +++ b/src/drivers/mediatek/afe/zephyr_mtk_afe_memif.c @@ -0,0 +1,418 @@ +/* + * Copyright 2026 MediaTek + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <zephyr/drivers/dma.h> +#include <zephyr/logging/log.h> +#include <sof/drivers/afe-drv.h> +#include <sof/drivers/afe-dai.h> +#include <ipc/dai.h> + +#define DT_DRV_COMPAT mediatek_afe_memif_dma + +LOG_MODULE_REGISTER(mtk_afe, CONFIG_SOF_LOG_LEVEL); + +struct mtk_memif_chan_data { + int direction; /* 1 = downlink/playback, 0 = uplink/capture */ + int memif_id; + int dai_id; + int irq_id; + struct mtk_base_afe *afe; + + uint32_t dma_base; + uint32_t dma_size; + uint32_t rptr; + uint32_t wptr; + uint32_t period_size; + + unsigned int channel; + unsigned int rate; + unsigned int format; + + enum { + MEMIF_STATE_INIT = 0, + MEMIF_STATE_CONFIGURED, + MEMIF_STATE_ACTIVE, + MEMIF_STATE_PAUSED, + } state; +}; + +struct mtk_memif_dma_cfg { + uint32_t afe_base_reg; + uint32_t num_channels; +}; + +struct mtk_memif_dma_data { + struct dma_context ctx; + atomic_t channel_flags; + struct mtk_memif_chan_data *channels; + struct mtk_base_afe *afe; + bool afe_probed; +}; + +static int mtk_memif_config(const struct device *dev, uint32_t chan_id, + struct dma_config *config) +{ + struct mtk_memif_dma_data *data = dev->data; + struct mtk_memif_chan_data *chan; + int direction, dai_id, irq_id, ret; + uint32_t dma_addr = 0; + uint32_t dma_size = 0; + + if (chan_id >= data->ctx.dma_channels) { + LOG_ERR("channel %d out of range", chan_id); + return -EINVAL; + } + + if (!config->head_block) { + LOG_ERR("no block config provided"); + return -EINVAL; + } + + if (!config->cyclic) { + LOG_ERR("only cyclic configurations are supported"); + return -ENOTSUP; + } + + if (config->block_count == 0 || config->head_block->block_size == 0) { + LOG_ERR("invalid block_count %u or block_size %u", + config->block_count, config->head_block->block_size); + return -EINVAL; + } + + if (config->channel_direction != MEMORY_TO_PERIPHERAL && + config->channel_direction != PERIPHERAL_TO_MEMORY) { + LOG_ERR("unsupported direction: %d", config->channel_direction); + return -EINVAL; + } + + if (!data->afe_probed) { + struct mtk_base_afe *afe = afe_get(); + + ret = afe_probe(afe); + if (ret < 0) { + LOG_ERR("afe_probe failed: %d", ret); + return ret; + } + data->afe = afe; + data->afe_probed = true; + /* Initialize all channels with afe reference */ + for (uint32_t i = 0; i < data->ctx.dma_channels; i++) { + data->channels[i].afe = afe; + data->channels[i].memif_id = i; + } + } + + chan = &data->channels[chan_id]; + direction = afe_memif_get_direction(chan->afe, chan->memif_id); + + /* dma_slot is only 8 bits in Zephyr's struct dma_config, so only the + * low byte of the AFE handshake fits. The low byte contains the + * dai_id (AFE_HS_GET_DAI extracts bits [7:0]). The memif_index + * (bits [23:16]) doesn't fit but isn't needed here since chan_id + * already maps to the correct memif via chan_filter. + */ + dai_id = config->dma_slot & 0xFF; /* AFE_HS_GET_DAI equivalent */ + irq_id = 0; /* IRQ not used in Zephyr mode */ + + switch (config->channel_direction) { + case MEMORY_TO_PERIPHERAL: + if (direction != 1) { + LOG_ERR("channel %d is not a playback memif", chan_id); + return -EINVAL; + } + dma_addr = config->head_block->source_address; + break; + case PERIPHERAL_TO_MEMORY: + if (direction != 0) { + LOG_ERR("channel %d is not a capture memif", chan_id); + return -EINVAL; + } + dma_addr = config->head_block->dest_address; + break; + } + + dma_size = config->head_block->block_size * config->block_count; + + chan->dai_id = dai_id; + chan->irq_id = irq_id; + chan->dma_base = dma_addr; + chan->dma_size = dma_size; + chan->direction = direction; + chan->rptr = 0; + chan->wptr = 0; + chan->period_size = config->head_block->block_size; + + ret = afe_dai_get_config(chan->afe, dai_id, + &chan->channel, &chan->rate, &chan->format); + if (ret < 0) { + LOG_ERR("failed to get DAI config for dai %d", dai_id); + return ret; + } + + switch (config->source_data_size) { + case 2: + chan->format = SOF_IPC_FRAME_S16_LE; + break; + case 4: + chan->format = SOF_IPC_FRAME_S32_LE; + break; + default: + LOG_ERR("unsupported data width: %d", config->source_data_size); + return -ENOTSUP; + } + + ret = afe_memif_set_params(chan->afe, chan->memif_id, + chan->channel, chan->rate, chan->format); + if (ret < 0) { + return ret; + } + + ret = afe_memif_set_addr(chan->afe, chan->memif_id, + chan->dma_base, chan->dma_size); + if (ret < 0) { + return ret; + } + + chan->state = MEMIF_STATE_CONFIGURED; + + LOG_DBG("channel %d configured: memif=%d dai=%d base=0x%x size=%u", + chan_id, chan->memif_id, dai_id, dma_addr, dma_size); + + return 0; +} + +static int mtk_memif_start(const struct device *dev, uint32_t chan_id) +{ + struct mtk_memif_dma_data *data = dev->data; + struct mtk_memif_chan_data *chan; + + if (chan_id >= data->ctx.dma_channels) { + return -EINVAL; + } + + chan = &data->channels[chan_id]; + + if (chan->state != MEMIF_STATE_CONFIGURED && + chan->state != MEMIF_STATE_PAUSED) { + LOG_ERR("channel %d not in valid state for start: %d", + chan_id, chan->state); + return -EINVAL; + } + + chan->state = MEMIF_STATE_ACTIVE; + return afe_memif_set_enable(chan->afe, chan->memif_id, 1); +} + +static int mtk_memif_stop(const struct device *dev, uint32_t chan_id) +{ + struct mtk_memif_dma_data *data = dev->data; + struct mtk_memif_chan_data *chan; + + if (chan_id >= data->ctx.dma_channels) { + return -EINVAL; + } + + chan = &data->channels[chan_id]; + + switch (chan->state) { + case MEMIF_STATE_CONFIGURED: + return 0; + case MEMIF_STATE_PAUSED: + case MEMIF_STATE_ACTIVE: + break; + default: + return -EINVAL; + } + + chan->state = MEMIF_STATE_CONFIGURED; + return afe_memif_set_enable(chan->afe, chan->memif_id, 0); +} + +static int mtk_memif_suspend(const struct device *dev, uint32_t chan_id) +{ + struct mtk_memif_dma_data *data = dev->data; + struct mtk_memif_chan_data *chan; + + if (chan_id >= data->ctx.dma_channels) { + return -EINVAL; + } + + chan = &data->channels[chan_id]; + + if (chan->state != MEMIF_STATE_ACTIVE) { + return -EINVAL; + } + + chan->state = MEMIF_STATE_PAUSED; + return afe_memif_set_enable(chan->afe, chan->memif_id, 0); +} + +static int mtk_memif_resume(const struct device *dev, uint32_t chan_id) +{ + struct mtk_memif_dma_data *data = dev->data; + struct mtk_memif_chan_data *chan; + + if (chan_id >= data->ctx.dma_channels) { + return -EINVAL; + } + + chan = &data->channels[chan_id]; + + if (chan->state != MEMIF_STATE_PAUSED) { + return -EINVAL; + } + + chan->state = MEMIF_STATE_ACTIVE; + return afe_memif_set_enable(chan->afe, chan->memif_id, 1); +} + +static int mtk_memif_reload(const struct device *dev, uint32_t chan_id, + uint32_t src, uint32_t dst, size_t size) +{ + struct mtk_memif_dma_data *data = dev->data; + struct mtk_memif_chan_data *chan; + + if (chan_id >= data->ctx.dma_channels) { + return -EINVAL; + } + + chan = &data->channels[chan_id]; + + /* update software pointer tracking */ + if (chan->direction) { + chan->wptr = (chan->wptr + size) % chan->dma_size; + } else { + chan->rptr = (chan->rptr + size) % chan->dma_size; + } + + return 0; +} + +static int mtk_memif_get_status(const struct device *dev, uint32_t chan_id, + struct dma_status *stat) +{ + struct mtk_memif_dma_data *data = dev->data; + struct mtk_memif_chan_data *chan; + uint32_t hw_ptr; + + if (chan_id >= data->ctx.dma_channels) { + return -EINVAL; + } + + chan = &data->channels[chan_id]; + + hw_ptr = afe_memif_get_cur_position(chan->afe, chan->memif_id); + if (!hw_ptr) { + stat->read_position = 0; + stat->write_position = 0; + return -EINVAL; + } + + hw_ptr -= chan->dma_base; + + /* Validate hw_ptr is within buffer range */ + if (hw_ptr >= chan->dma_size) { + LOG_WRN("hw_ptr 0x%x out of range (size %u), clamping", + hw_ptr, chan->dma_size); + hw_ptr %= chan->dma_size; + } + + if (chan->direction) { + chan->rptr = hw_ptr; + } else { + chan->wptr = hw_ptr; + } + + stat->read_position = chan->rptr + chan->dma_base; + stat->write_position = chan->wptr + chan->dma_base; + stat->busy = (chan->state == MEMIF_STATE_ACTIVE); + + uint32_t avail = (chan->wptr + chan->dma_size - chan->rptr) % chan->dma_size; + + stat->pending_length = avail; + stat->free = chan->dma_size - avail; + + return 0; +} + +static int mtk_memif_get_attribute(const struct device *dev, + uint32_t type, uint32_t *value) +{ + switch (type) { + case DMA_ATTR_COPY_ALIGNMENT: + case DMA_ATTR_BUFFER_SIZE_ALIGNMENT: + *value = 4; + break; + case DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT: + *value = CONFIG_DCACHE_LINE_SIZE; + break; + case DMA_ATTR_MAX_BLOCK_COUNT: + *value = 4; + break; + default: + return -ENOENT; + } + return 0; +} + +/* Channel filter: ensures dma_request_channel() returns the specific + * channel (memif index) requested via the stream_tag parameter, rather + * than an arbitrary free channel. Each AFE MEMIF channel corresponds to + * a specific hardware MEMIF, so channel IDs must match memif indices. + */ +static bool mtk_memif_chan_filter(const struct device *dev, int channel, + void *filter_param) +{ + uint32_t requested = *(uint32_t *)filter_param; + + return channel == requested; +} + +static DEVICE_API(dma, mtk_afe_memif_api) = { + .config = mtk_memif_config, + .start = mtk_memif_start, + .stop = mtk_memif_stop, + .suspend = mtk_memif_suspend, + .resume = mtk_memif_resume, + .reload = mtk_memif_reload, + .get_status = mtk_memif_get_status, + .get_attribute = mtk_memif_get_attribute, + .chan_filter = mtk_memif_chan_filter, +}; + +static int mtk_memif_init(const struct device *dev) +{ + struct mtk_memif_dma_data *data = dev->data; + + data->channel_flags = ATOMIC_INIT(0); + data->ctx.atomic = &data->channel_flags; + return 0; +} + +#define MTK_AFE_MEMIF_CHAN_DECLARE(idx) {} + +#define MTK_AFE_MEMIF_INIT(inst) \ + static struct mtk_memif_chan_data \ + mtk_memif_channels_##inst[DT_INST_PROP(inst, dma_channels)]; \ + \ + static struct mtk_memif_dma_data mtk_memif_data_##inst = { \ + .ctx.magic = DMA_MAGIC, \ + .ctx.dma_channels = DT_INST_PROP(inst, dma_channels), \ + .channels = mtk_memif_channels_##inst, \ + }; \ + \ + static const struct mtk_memif_dma_cfg mtk_memif_cfg_##inst = { \ + .afe_base_reg = DT_INST_REG_ADDR(inst), \ + .num_channels = DT_INST_PROP(inst, dma_channels), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, mtk_memif_init, NULL, \ + &mtk_memif_data_##inst, \ + &mtk_memif_cfg_##inst, \ + PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, \ + &mtk_afe_memif_api); + +DT_INST_FOREACH_STATUS_OKAY(MTK_AFE_MEMIF_INIT) diff --git a/src/drivers/mediatek/afe/zephyr_mtk_dai.c b/src/drivers/mediatek/afe/zephyr_mtk_dai.c new file mode 100644 index 000000000000..3e8fe0fa7dbe --- /dev/null +++ b/src/drivers/mediatek/afe/zephyr_mtk_dai.c @@ -0,0 +1,162 @@ +/* + * Copyright 2026 MediaTek + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <zephyr/device.h> +#include <zephyr/drivers/dai.h> +#include <zephyr/logging/log.h> +#include <sof/drivers/afe-drv.h> +#include <ipc/stream.h> +#include <ipc/dai.h> +#include <ipc/dai-mediatek.h> + +#define DT_DRV_COMPAT mediatek_afe + +LOG_MODULE_REGISTER(dai_mtk_afe); + +struct dai_mtk_afe_cfg { + uint32_t dai_index; + uint32_t memif_index; + bool downlink; +}; + +struct dai_mtk_afe_data { + struct dai_config cfg; + struct dai_properties tx_props; + struct dai_properties rx_props; +}; + +static int dai_mtk_afe_probe(const struct device *dev) +{ + LOG_DBG("%s: probe", dev->name); + return 0; +} + +static int dai_mtk_afe_remove(const struct device *dev) +{ + LOG_DBG("%s: remove", dev->name); + return 0; +} + +static int dai_mtk_afe_config_set(const struct device *dev, + const struct dai_config *cfg, + const void *bespoke_cfg, size_t size) +{ + const struct dai_mtk_afe_cfg *dev_cfg = dev->config; + struct dai_mtk_afe_data *data = dev->data; + const struct sof_ipc_dai_afe_params *afe_cfg = bespoke_cfg; + struct mtk_base_afe *afe; + int ret; + + if (cfg) { + data->cfg.channels = cfg->channels; + data->cfg.rate = cfg->rate; + data->cfg.format = cfg->format; + data->cfg.word_size = cfg->word_size; + } + + if (afe_cfg) { + int probe_ret; + + afe = afe_get(); + probe_ret = afe_probe(afe); + if (probe_ret < 0) { + LOG_ERR("%s: afe_probe failed: %d", dev->name, probe_ret); + return probe_ret; + } + ret = afe_dai_set_config(afe, dev_cfg->dai_index, + afe_cfg->dai_channels, + afe_cfg->dai_rate, + afe_cfg->dai_format); + if (ret < 0) { + LOG_ERR("%s: afe_dai_set_config failed: %d", + dev->name, ret); + return ret; + } + + LOG_DBG("%s: config_set dai=%u ch=%u rate=%u fmt=%u", + dev->name, dev_cfg->dai_index, + afe_cfg->dai_channels, + afe_cfg->dai_rate, + afe_cfg->dai_format); + } + + return 0; +} + +static int dai_mtk_afe_config_get(const struct device *dev, + struct dai_config *cfg, enum dai_dir dir) +{ + const struct dai_mtk_afe_cfg *dev_cfg = dev->config; + struct dai_mtk_afe_data *data = dev->data; + + if (!cfg) { + return -EINVAL; + } + + *cfg = data->cfg; + cfg->type = DAI_MEDIATEK_AFE; + cfg->dai_index = dev_cfg->dai_index; + + return 0; +} + +static const struct dai_properties *dai_mtk_afe_get_properties( + const struct device *dev, enum dai_dir dir, int stream_id) +{ + const struct dai_mtk_afe_data *data = dev->data; + + if (dir == DAI_DIR_TX) { + return &data->tx_props; + } + return &data->rx_props; +} + +static int dai_mtk_afe_trigger(const struct device *dev, + enum dai_dir dir, enum dai_trigger_cmd cmd) +{ + LOG_DBG("%s: trigger dir=%d cmd=%d", dev->name, dir, cmd); + return 0; +} + +static DEVICE_API(dai, dai_mtk_afe_api) = { + .probe = dai_mtk_afe_probe, + .remove = dai_mtk_afe_remove, + .config_set = dai_mtk_afe_config_set, + .config_get = dai_mtk_afe_config_get, + .get_properties = dai_mtk_afe_get_properties, + .trigger = dai_mtk_afe_trigger, +}; + +#define DAI_MTK_AFE_HANDSHAKE(inst) \ + ((inst) << 16) | DT_INST_PROP(inst, dai_id) + +#define DAI_MTK_AFE_INIT(inst) \ + static struct dai_mtk_afe_data dai_mtk_afe_data_##inst = { \ + .cfg = { \ + .type = DAI_MEDIATEK_AFE, \ + .dai_index = DT_INST_PROP(inst, dai_id), \ + }, \ + .tx_props = { \ + .dma_hs_id = DAI_MTK_AFE_HANDSHAKE(inst), \ + }, \ + .rx_props = { \ + .dma_hs_id = DAI_MTK_AFE_HANDSHAKE(inst), \ + }, \ + }; \ + \ + static const struct dai_mtk_afe_cfg dai_mtk_afe_cfg_##inst = { \ + .dai_index = DT_INST_PROP(inst, dai_id), \ + .memif_index = inst, \ + .downlink = DT_INST_PROP(inst, downlink), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, \ + &dai_mtk_afe_data_##inst, \ + &dai_mtk_afe_cfg_##inst, \ + POST_KERNEL, CONFIG_DAI_INIT_PRIORITY, \ + &dai_mtk_afe_api); + +DT_INST_FOREACH_STATUS_OKAY(DAI_MTK_AFE_INIT) diff --git a/src/drivers/mediatek/afe/zephyr_mtk_host_dma.c b/src/drivers/mediatek/afe/zephyr_mtk_host_dma.c new file mode 100644 index 000000000000..67673e55a87e --- /dev/null +++ b/src/drivers/mediatek/afe/zephyr_mtk_host_dma.c @@ -0,0 +1,221 @@ +/* + * Copyright 2026 MediaTek + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <zephyr/drivers/dma.h> +#include <zephyr/logging/log.h> +#include <zephyr/cache.h> +#include <platform/lib/memory.h> + +/* used for driver binding */ +#define DT_DRV_COMPAT mediatek_sof_host_dma + +/* macros used to parse DTS properties */ +#define IDENTITY_VARGS(V, ...) IDENTITY(V) + +#define _SOF_HOST_DMA_CHANNEL_INDEX_ARRAY(inst)\ + LISTIFY(DT_INST_PROP_OR(inst, dma_channels, 0), IDENTITY_VARGS, (,)) + +#define _SOF_HOST_DMA_CHANNEL_DECLARE(idx) {} + +#define SOF_HOST_DMA_CHANNELS_DECLARE(inst)\ + FOR_EACH(_SOF_HOST_DMA_CHANNEL_DECLARE,\ + (,), _SOF_HOST_DMA_CHANNEL_INDEX_ARRAY(inst)) + +LOG_MODULE_REGISTER(mtk_sof_host_dma); + +/* Software-based DMA driver for MTK SOF host component. + * MTK DSP can access host memory directly, so this driver + * implements DMA transfers using memcpy + cache management. + */ + +enum channel_state { + CHAN_STATE_INIT = 0, + CHAN_STATE_CONFIGURED, +}; + +struct sof_host_dma_channel { + uint32_t src; + uint32_t dest; + uint32_t size; + uint32_t direction; + enum channel_state state; +}; + +struct sof_host_dma_data { + struct dma_context ctx; + atomic_t channel_flags; + struct sof_host_dma_channel *channels; +}; + +static int channel_change_state(struct sof_host_dma_channel *chan, + enum channel_state next) +{ + switch (chan->state) { + case CHAN_STATE_INIT: + case CHAN_STATE_CONFIGURED: + if (next != CHAN_STATE_CONFIGURED) { + return -EPERM; + } + break; + default: + LOG_ERR("invalid channel previous state: %d", chan->state); + return -EINVAL; + } + + chan->state = next; + return 0; +} + +static int mtk_host_dma_reload(const struct device *dev, uint32_t chan_id, + uint32_t src, uint32_t dst, size_t size) +{ + return 0; +} + +static int mtk_host_dma_config(const struct device *dev, uint32_t chan_id, + struct dma_config *config) +{ + struct sof_host_dma_data *data = dev->data; + struct sof_host_dma_channel *chan; + int ret; + + if (chan_id >= data->ctx.dma_channels) { + LOG_ERR("channel %d is not a valid channel ID", chan_id); + return -EINVAL; + } + + chan = &data->channels[chan_id]; + + ret = channel_change_state(chan, CHAN_STATE_CONFIGURED); + if (ret < 0) { + LOG_ERR("failed to change channel %d's state to CONFIGURED", chan_id); + return ret; + } + + if (config->block_count != 1) { + LOG_ERR("invalid number of blocks: %d", config->block_count); + return -EINVAL; + } + + if (!config->head_block->source_address) { + LOG_ERR("got NULL source address"); + return -EINVAL; + } + + if (!config->head_block->dest_address) { + LOG_ERR("got NULL destination address"); + return -EINVAL; + } + + if (!config->head_block->block_size) { + LOG_ERR("got 0 bytes to copy"); + return -EINVAL; + } + + if (config->channel_direction != HOST_TO_MEMORY && + config->channel_direction != MEMORY_TO_HOST) { + LOG_ERR("invalid channel direction: %d", config->channel_direction); + return -EINVAL; + } + + chan->src = config->head_block->source_address; + chan->dest = config->head_block->dest_address; + chan->size = config->head_block->block_size; + chan->direction = config->channel_direction; + + if (chan->direction == MEMORY_TO_HOST) { + sys_cache_data_invd_range(UINT_TO_POINTER(chan->src), chan->size); + } + + memcpy(UINT_TO_POINTER(chan->dest), UINT_TO_POINTER(chan->src), chan->size); + + if (chan->direction == HOST_TO_MEMORY) { + sys_cache_data_flush_range(UINT_TO_POINTER(chan->dest), chan->size); + } + + return 0; +} + +static int mtk_host_dma_start(const struct device *dev, uint32_t chan_id) +{ + return 0; +} + +static int mtk_host_dma_stop(const struct device *dev, uint32_t chan_id) +{ + return 0; +} + +static int mtk_host_dma_suspend(const struct device *dev, uint32_t chan_id) +{ + return 0; +} + +static int mtk_host_dma_resume(const struct device *dev, uint32_t chan_id) +{ + return 0; +} + +static int mtk_host_dma_get_status(const struct device *dev, + uint32_t chan_id, struct dma_status *stat) +{ + return 0; +} + +static int mtk_host_dma_get_attribute(const struct device *dev, + uint32_t type, uint32_t *val) +{ + switch (type) { + case DMA_ATTR_COPY_ALIGNMENT: + case DMA_ATTR_BUFFER_SIZE_ALIGNMENT: + *val = sizeof(uint32_t); + break; + case DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT: + *val = PLATFORM_DCACHE_ALIGN; + break; + default: + LOG_ERR("invalid attribute type: %d", type); + return -EINVAL; + } + + return 0; +} + +static DEVICE_API(dma, mtk_host_dma_api) = { + .reload = mtk_host_dma_reload, + .config = mtk_host_dma_config, + .start = mtk_host_dma_start, + .stop = mtk_host_dma_stop, + .suspend = mtk_host_dma_suspend, + .resume = mtk_host_dma_resume, + .get_status = mtk_host_dma_get_status, + .get_attribute = mtk_host_dma_get_attribute, +}; + +static int mtk_host_dma_init(const struct device *dev) +{ + struct sof_host_dma_data *data = dev->data; + + data->channel_flags = ATOMIC_INIT(0); + data->ctx.atomic = &data->channel_flags; + + return 0; +} + +static struct sof_host_dma_channel channels[] = { + SOF_HOST_DMA_CHANNELS_DECLARE(0), +}; + +static struct sof_host_dma_data mtk_host_dma_data = { + .ctx.magic = DMA_MAGIC, + .ctx.dma_channels = ARRAY_SIZE(channels), + .channels = channels, +}; + +DEVICE_DT_INST_DEFINE(0, mtk_host_dma_init, NULL, + &mtk_host_dma_data, NULL, + PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, + &mtk_host_dma_api); diff --git a/src/drivers/mediatek/mt818x/ipc.c b/src/drivers/mediatek/mt818x/ipc.c index 20fc54c20f4a..e8a7ab3c22e5 100644 --- a/src/drivers/mediatek/mt818x/ipc.c +++ b/src/drivers/mediatek/mt818x/ipc.c @@ -127,7 +127,11 @@ int platform_ipc_init(struct ipc *ipc) #if CONFIG_HOST_PTABLE struct ipc_data *iipc; - iipc = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, sizeof(*iipc)); + iipc = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(*iipc)); + if (!iipc) { + tr_err(&ipc_tr, "Unable to allocate memory for IPC data"); + sof_panic(SOF_IPC_PANIC_IPC); + } ipc_set_drvdata(ipc, iipc); #else ipc_set_drvdata(ipc, NULL); @@ -142,7 +146,11 @@ int platform_ipc_init(struct ipc *ipc) #if CONFIG_HOST_PTABLE /* allocate page table buffer */ iipc->dh_buffer.page_table = - rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, PLATFORM_PAGE_TABLE_SIZE); + rzalloc(SOF_MEM_FLAG_KERNEL, PLATFORM_PAGE_TABLE_SIZE); + if (!iipc->dh_buffer.page_table) { + tr_err(&ipc_tr, "Unable to allocate host page table buffer"); + sof_panic(SOF_IPC_PANIC_IPC); + } iipc->dh_buffer.dmac = dma_get(DMA_DIR_HMEM_TO_LMEM, 0, DMA_DEV_HOST, DMA_ACCESS_SHARED); if (!iipc->dh_buffer.dmac) { diff --git a/src/drivers/mediatek/mt8195/ipc.c b/src/drivers/mediatek/mt8195/ipc.c index a5766d68f385..cb3734d0fbc3 100644 --- a/src/drivers/mediatek/mt8195/ipc.c +++ b/src/drivers/mediatek/mt8195/ipc.c @@ -126,7 +126,11 @@ int platform_ipc_init(struct ipc *ipc) #if CONFIG_HOST_PTABLE struct ipc_data *iipc; - iipc = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, sizeof(*iipc)); + iipc = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(*iipc)); + if (!iipc) { + tr_err(&ipc_tr, "Unable to allocate memory for IPC data"); + sof_panic(SOF_IPC_PANIC_IPC); + } ipc_set_drvdata(ipc, iipc); #else ipc_set_drvdata(ipc, NULL); @@ -140,7 +144,11 @@ int platform_ipc_init(struct ipc *ipc) #if CONFIG_HOST_PTABLE /* allocate page table buffer */ iipc->dh_buffer.page_table = - rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, PLATFORM_PAGE_TABLE_SIZE); + rzalloc(SOF_MEM_FLAG_KERNEL, PLATFORM_PAGE_TABLE_SIZE); + if (!iipc->dh_buffer.page_table) { + tr_err(&ipc_tr, "Unable to allocate host page table buffer"); + sof_panic(SOF_IPC_PANIC_IPC); + } iipc->dh_buffer.dmac = dma_get(DMA_DIR_HMEM_TO_LMEM, 0, DMA_DEV_HOST, DMA_ACCESS_SHARED); if (!iipc->dh_buffer.dmac) { diff --git a/src/drivers/mediatek/mt8196/CMakeLists.txt b/src/drivers/mediatek/mt8196/CMakeLists.txt new file mode 100644 index 000000000000..0d5d85f72215 --- /dev/null +++ b/src/drivers/mediatek/mt8196/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources(sof interrupt.c intc.c intc_map.c ipc.c timer.c) + diff --git a/src/drivers/mediatek/mt8196/intc.c b/src/drivers/mediatek/mt8196/intc.c new file mode 100644 index 000000000000..472d6ad8e7d7 --- /dev/null +++ b/src/drivers/mediatek/mt8196/intc.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#include <rtos/interrupt.h> +#include <sof/lib/memory.h> +#include <sof/platform.h> +#include <sof/lib/uuid.h> +#include <platform/drivers/interrupt.h> +#include <platform/drivers/intc.h> +#include <errno.h> +#include <stdint.h> + +SOF_DEFINE_REG_UUID(intc_mt8196); +DECLARE_TR_CTX(intc_tr, SOF_UUID(intc_mt8196_uuid), LOG_LEVEL_INFO); + +static struct intc_desc_t intc_desc; + +void intc_init(void) +{ + uint32_t word, group, irq; + + for (group = 0; group < INTC_GRP_NUM; group++) { + for (word = 0; word < INTC_GRP_LEN; word++) + intc_desc.grp_irqs[group][word] = 0x0; + } + + for (word = 0; word < INTC_GRP_LEN; word++) + intc_desc.int_en[word] = 0x0; + + for (irq = 0; irq < IRQ_MAX_CHANNEL; irq++) { + intc_desc.irqs[irq].id = irq; + intc_desc.irqs[irq].group = irq2grp_map[irq]; + intc_desc.irqs[irq].pol = INTC_POL_LOW; + } + + for (word = 0; word < INTC_GRP_LEN; word++) { + io_reg_write(INTC_IRQ_EN(word), 0x0); + io_reg_write(INTC_IRQ_WAKE_EN(word), 0x0); + io_reg_write(INTC_IRQ_STAGE1_EN(word), 0x0); + io_reg_write(INTC_IRQ_POL(word), 0xFFFFFFFF); + } + + for (group = 0; group < INTC_GRP_NUM; group++) { + for (word = 0; word < INTC_GRP_LEN; word++) + io_reg_write(INTC_IRQ_GRP(group, word), 0x0); + } +} + +void intc_irq_unmask(enum IRQn_Type irq) +{ + uint32_t word; + + if (irq < IRQ_MAX_CHANNEL && intc_desc.irqs[irq].group < INTC_GRP_NUM) { + word = INTC_WORD(irq); + io_reg_update_bits(INTC_IRQ_EN(word), INTC_BIT(irq), INTC_BIT(irq)); + } else { + tr_err(&intc_tr, "Invalid INTC interrupt %d", irq); + } +} + +void intc_irq_mask(enum IRQn_Type irq) +{ + uint32_t word; + + if (irq < IRQ_MAX_CHANNEL) { + word = INTC_WORD(irq); + io_reg_update_bits(INTC_IRQ_EN(word), INTC_BIT(irq), 0); + } else { + tr_err(&intc_tr, "Invalid INTC interrupt %d", irq); + } +} + +int intc_irq_enable(enum IRQn_Type irq) +{ + uint32_t word, irq_b, group, pol; + int ret; + + if (irq < IRQ_MAX_CHANNEL && intc_desc.irqs[irq].group < INTC_GRP_NUM && + intc_desc.irqs[irq].pol < INTC_POL_NUM) { + word = INTC_WORD(irq); + irq_b = INTC_BIT(irq); + group = intc_desc.irqs[irq].group; + pol = intc_desc.irqs[irq].pol; + + intc_desc.int_en[word] |= irq_b; + intc_desc.grp_irqs[group][word] |= irq_b; + io_reg_update_bits(INTC_IRQ_EN(word), irq_b, 0); + if (pol == INTC_POL_HIGH) + io_reg_update_bits(INTC_IRQ_POL(word), irq_b, 0); + else + io_reg_update_bits(INTC_IRQ_POL(word), irq_b, irq_b); + + io_reg_update_bits(INTC_IRQ_GRP(group, word), irq_b, irq_b); + io_reg_update_bits(INTC_IRQ_EN(word), irq_b, irq_b); + + ret = 1; + } else { + tr_err(&intc_tr, "Invalid INTC interrupt %d", irq); + ret = 0; + } + + return ret; +} + +int intc_irq_disable(enum IRQn_Type irq) +{ + uint32_t word, irq_b, group; + int ret; + + if (irq < IRQ_MAX_CHANNEL && intc_desc.irqs[irq].group < INTC_GRP_NUM) { + word = INTC_WORD(irq); + irq_b = INTC_BIT(irq); + group = intc_desc.irqs[irq].group; + + intc_desc.int_en[word] &= ~irq_b; + intc_desc.grp_irqs[group][word] &= ~irq_b; + io_reg_update_bits(INTC_IRQ_EN(word), irq_b, 0); + io_reg_update_bits(INTC_IRQ_GRP(group, word), irq_b, 0); + + ret = 1; + } else { + tr_err(&intc_tr, "INTC fail to disable irq %u\n", irq); + ret = 0; + } + + return ret; +} + diff --git a/src/drivers/mediatek/mt8196/intc_map.c b/src/drivers/mediatek/mt8196/intc_map.c new file mode 100644 index 000000000000..2c3fcbba965d --- /dev/null +++ b/src/drivers/mediatek/mt8196/intc_map.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#include <sof/audio/component_ext.h> +#include <rtos/interrupt.h> +#include <sof/lib/memory.h> +#include <sof/platform.h> +#include <platform/drivers/timer.h> +#include <platform/drivers/interrupt.h> +#include <ipc/stream.h> +#include <errno.h> +#include <stdint.h> + +const unsigned char grp_pri[INTC_GRP_NUM] = { + INTC_GRP0_LEVEL, INTC_GRP1_LEVEL, INTC_GRP2_LEVEL, INTC_GRP3_LEVEL, + INTC_GRP4_LEVEL, INTC_GRP5_LEVEL, INTC_GRP6_LEVEL, INTC_GRP7_LEVEL, + INTC_GRP8_LEVEL, INTC_GRP9_LEVEL, INTC_GRP10_LEVEL, INTC_GRP11_LEVEL, + INTC_GRP12_LEVEL, INTC_GRP13_LEVEL, INTC_GRP14_LEVEL, INTC_GRP15_LEVEL, +}; + +const uint8_t irq2grp_map[IRQ_MAX_CHANNEL] = { + [CCU_IRQn] = INTC_GRP1, + [SCP_IRQn] = INTC_GRP1, + [SPM_IRQn] = INTC_GRP1, + [PCIE_IRQn] = INTC_GRP1, + [INFRA_HANG_IRQn] = INTC_GRP1, + [PERI_TIMEOUT_IRQn] = INTC_GRP1, + [MBOX_C0_IRQn] = INTC_GRP2, + [MBOX_C1_IRQn] = INTC_GRP2, + [TIMER0_IRQn] = INTC_GRP1, + [TIMER1_IRQn] = INTC_GRP1, + [IPC_C0_IRQn] = INTC_GRP1, + [IPC_C1_IRQn] = INTC_GRP1, + [IPC1_RSV_IRQn] = INTC_GRP1, + [C2C_SW_C0_IRQn] = INTC_GRP1, + [C2C_SW_C1_IRQn] = INTC_GRP1, + [UART_IRQn] = INTC_GRP12, + [UART_BT_IRQn] = INTC_GRP12, + [LATENCY_MON_IRQn] = INTC_GRP11, + [BUS_TRACKER_IRQn] = INTC_GRP13, + [USB0_IRQn] = INTC_GRP8, + [USB1_IRQn] = INTC_GRP8, + [SCPVOW_IRQn] = NO_GRP, + [CCIF3_C0_IRQn] = INTC_GRP8, + [CCIF3_C1_IRQn] = INTC_GRP8, + [PWR_CTRL_IRQn] = NO_GRP, + [DMA_C0_IRQn] = INTC_GRP10, + [DMA_C1_IRQn] = NO_GRP, + [AXI_DMA0_IRQn] = INTC_GRP9, + [AXI_DMA1_IRQn] = NO_GRP, + [AUDIO_C0_IRQn] = INTC_GRP10, + [AUDIO_C1_IRQn] = INTC_GRP10, + [HIFI5_WDT_C0_IRQn] = INTC_GRP13, + [HIFI5_WDT_C1_IRQn] = INTC_GRP13, + [APU_MBOX_C0_IRQn] = INTC_GRP0, + [APU_MBOX_C1_IRQn] = INTC_GRP0, + [TIMER2_IRQn] = INTC_GRP13, + [PWR_ON_C0_IRQ] = INTC_GRP13, + [PWR_ON_C1_IRQ] = INTC_GRP13, + [WAKEUP_SRC_C0_IRQn] = INTC_GRP13, + [WAKEUP_SRC_C1_IRQn] = INTC_GRP13, + [WDT_IRQn] = NO_GRP, + [CONNSYS1_IRQn] = INTC_GRP3, + [CONNSYS3_IRQn] = INTC_GRP3, + [CONNSYS4_IRQn] = INTC_GRP3, + [CONNSYS2_IRQn] = INTC_GRP3, + [IPIC_IRQn] = INTC_GRP1, + [AXI_DMA2_IRQn] = INTC_GRP9, + [AXI_DMA3_IRQn] = NO_GRP, + [APSRC_DDREN_IRQn] = INTC_GRP4, + [LAT_MON_EMI_IRQn] = INTC_GRP11, + [LAT_MON_INFRA_IRQn] = INTC_GRP11, + [DEVAPC_VIO_IRQn] = INTC_GRP11, + [AO_INFRA_HANG_IRQn] = NO_GRP, + [BUS_TRA_EMI_IRQn] = INTC_GRP13, + [BUS_TRA_INFRA_IRQn] = INTC_GRP13, + [L2SRAM_VIO_IRQn] = INTC_GRP11, + [L2SRAM_SETERR_IRQn] = INTC_GRP11, + [PCIERC_GRP2_IRQn] = INTC_GRP8, + [PCIERC_GRP3_IRQn] = INTC_GRP8, +}; + +const uint8_t grp2hifi_irq_map[INTC_GRP_NUM] = { + [INTC_GRP0] = 0, + [INTC_GRP1] = 1, + [INTC_GRP2] = 2, + [INTC_GRP3] = 3, + [INTC_GRP4] = 4, + [INTC_GRP5] = 5, + [INTC_GRP6] = 7, + [INTC_GRP7] = 8, + [INTC_GRP8] = 9, + [INTC_GRP9] = 10, + [INTC_GRP10] = 11, + [INTC_GRP11] = 16, + [INTC_GRP12] = 17, + [INTC_GRP13] = 18, + [INTC_GRP14] = 20, + [INTC_GRP15] = 21, +}; diff --git a/src/drivers/mediatek/mt8196/interrupt.c b/src/drivers/mediatek/mt8196/interrupt.c new file mode 100644 index 000000000000..d329544cb5ae --- /dev/null +++ b/src/drivers/mediatek/mt8196/interrupt.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#include <errno.h> +#include <inttypes.h> +#include <rtos/bit.h> +#include <sof/common.h> +#include <rtos/interrupt.h> +#include <sof/lib/cpu.h> +#include <sof/lib/io.h> +#include <sof/lib/memory.h> +#include <sof/lib/uuid.h> +#include <sof/list.h> +#include <rtos/spinlock.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#define PENDING_IRQ_INDEX_MAX 32 + +SOF_DEFINE_REG_UUID(irq_mt8196); + +DECLARE_TR_CTX(int_tr, SOF_UUID(irq_mt8196_uuid), LOG_LEVEL_INFO); + +static void mtk_irq_init(void) +{ + intc_init(); +} + +static void mtk_irq_mask(struct irq_desc *desc, uint32_t irq, unsigned int core) +{ + if (!desc) { + if (irq >= 0 && irq < IRQ_MAX_CHANNEL) + intc_irq_disable(irq); + else + tr_err(&int_tr, "Invalid interrupt num%d", irq); + } else { + switch (desc->irq) { + case MTK_DSP_IRQ_MBOX_C0: + intc_irq_disable(6); + break; + default: + tr_err(&int_tr, "Invalid interrupt %d", desc->irq); + return; + } + } +} + +static void mtk_irq_unmask(struct irq_desc *desc, uint32_t irq, unsigned int core) +{ + if (!desc) { + if (irq >= 0 && irq < IRQ_MAX_CHANNEL) + intc_irq_enable(irq); + else + tr_err(&int_tr, "Invalid interrupt num%d", irq); + } else { + switch (desc->irq) { + case MTK_DSP_IRQ_MBOX_C0: + intc_irq_enable(6); + break; + default: + tr_err(&int_tr, "Invalid interrupt %d", desc->irq); + return; + } + } +} + +static uint32_t mtk_irq_group_pending_status(uint32_t irq) +{ + uint32_t irq_status = 0; + + if (irq == MTK_DSP_IRQ_MBOX_C0 && + (io_reg_read(INTC_IRQ_STA0) & BIT(6))) { + irq_status = io_reg_read(MTK_MBOX_IRQ_IN) & MTK_DSP_MBOX_MASK; + } + + return irq_status; +} + +static uint32_t mtk_get_pending_index(uint32_t current, uint32_t *next) +{ + uint32_t index; + + if (current == 0) + return PENDING_IRQ_INDEX_MAX; + + /* ffs returns one plus the index of the least significant 1-bit of input int */ + index = ffs(current) - 1; + + /* remove the handling index from current pending status */ + *next = current & ~(1ull << index); + + return index; +} + +static inline void mtk_handle_group_pending_irq(struct irq_cascade_desc *cascade, + uint32_t line_index, uint32_t status) +{ + int core = cpu_get_id(); + struct list_item *clist; + struct irq_desc *child = NULL; + uint32_t idx; + uint32_t next_status; + bool handled; + k_spinlock_key_t key; + + idx = mtk_get_pending_index(status, &next_status); + while (idx < PENDING_IRQ_INDEX_MAX) { + handled = false; + + key = k_spin_lock(&cascade->lock); + list_for_item(clist, &cascade->child[idx].list) { + child = container_of(clist, struct irq_desc, irq_list); + + if (child->handler && (child->cpu_mask & 1 << core)) { + child->handler(child->handler_arg); + handled = true; + } + } + k_spin_unlock(&cascade->lock, key); + + if (!handled) { + tr_err(&int_tr, "Not handle irq %u in group %u", + idx, line_index); + } + + idx = mtk_get_pending_index(next_status, &next_status); + } +} + +static inline void mtk_irq_group_handler(void *data, uint32_t line_index) +{ + struct irq_desc *parent = data; + struct irq_cascade_desc *cascade = + container_of(parent, struct irq_cascade_desc, desc); + uint32_t status; + + status = mtk_irq_group_pending_status(line_index); + if (status) + mtk_handle_group_pending_irq(cascade, line_index, status); + else + tr_err(&int_tr, "No pending irq in group %d", line_index); +} + +#define DEFINE_IRQ_HANDLER(n) \ + static void irqhandler_##n(void *arg) \ + { \ + mtk_irq_group_handler(arg, n); \ + } + +DEFINE_IRQ_HANDLER(2) + +static const char mtk_irq_mailbox[] = "mtk_irq_mailbox"; + +static const struct irq_cascade_ops irq_ops = { + .mask = mtk_irq_mask, + .unmask = mtk_irq_unmask, +}; + +static const struct irq_cascade_tmpl dsp_irq[] = { + { + .name = mtk_irq_mailbox, + .irq = MTK_DSP_IRQ_MBOX_C0, + .handler = irqhandler_2, + .ops = &irq_ops, + .global_mask = false, + }, +}; + +int mtk_irq_group_id(uint32_t in_irq) +{ + if (in_irq >= MTK_MAX_IRQ_NUM) + in_irq -= MTK_MAX_IRQ_NUM; + + return interrupt_get_irq(in_irq, dsp_irq[0].name); +} + +void platform_interrupt_init(void) +{ + int i; + + mtk_irq_init(); + for (i = 0; i < ARRAY_SIZE(dsp_irq); i++) + interrupt_cascade_register(dsp_irq + i); +} + +void platform_interrupt_set(uint32_t irq) +{ + if (interrupt_is_dsp_direct(irq)) + arch_interrupt_set(irq); +} + +void platform_interrupt_clear(uint32_t irq, uint32_t mask) +{ + if (interrupt_is_dsp_direct(irq)) + arch_interrupt_clear(irq); +} + +uint32_t platform_interrupt_get_enabled(void) +{ + return 0; +} + +void interrupt_mask(uint32_t irq, unsigned int cpu) +{ + struct irq_cascade_desc *cascade = interrupt_get_parent(irq); + + if (cascade && cascade->ops->mask) + cascade->ops->mask(&cascade->desc, irq - cascade->irq_base, + cpu); + else + mtk_irq_mask(NULL, irq, 0); +} + +void interrupt_unmask(uint32_t irq, unsigned int cpu) +{ + struct irq_cascade_desc *cascade = interrupt_get_parent(irq); + + if (cascade && cascade->ops->unmask) + cascade->ops->unmask(&cascade->desc, irq - cascade->irq_base, + cpu); + else + mtk_irq_unmask(NULL, irq, 0); +} diff --git a/src/drivers/mediatek/mt8196/ipc.c b/src/drivers/mediatek/mt8196/ipc.c new file mode 100644 index 000000000000..dda51b495ab8 --- /dev/null +++ b/src/drivers/mediatek/mt8196/ipc.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#include <rtos/panic.h> +#include <rtos/interrupt.h> +#include <sof/ipc/driver.h> +#include <sof/ipc/msg.h> +#include <sof/ipc/schedule.h> +#include <rtos/alloc.h> +#include <sof/lib/dma.h> +#include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <sof/lib/uuid.h> +#include <rtos/wait.h> +#include <sof/list.h> +#include <sof/platform.h> +#include <sof/schedule/edf_schedule.h> +#include <sof/schedule/schedule.h> +#include <rtos/task.h> +#include <rtos/spinlock.h> +#include <ipc/header.h> +#include <ipc/topology.h> +#include <ipc/trace.h> +#include <platform/drivers/mt_reg_base.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#define IPC_DSPMBOX_DSP_RSP 0 +#define IPC_DSPMBOX_DSP_REQ 1 + +SOF_DEFINE_REG_UUID(ipc_task_mt8196); + +static struct ipc *local_ipc; + +struct ipc_data { + struct ipc_data_host_buffer dh_buffer; +}; + +static void mbox0_handler(void *args) +{ + uint32_t op = io_reg_read(MTK_ADSP_MBOX_IN_CMD(0)); + + /* clear interrupt */ + io_reg_write(MTK_ADSP_MBOX_IN_CMD_CLR(0), op); + ipc_schedule_process(local_ipc); +} + +static void mbox1_handler(void *args) +{ + uint32_t op = io_reg_read(MTK_ADSP_MBOX_IN_CMD(1)); + + /* clear interrupt */ + io_reg_write(MTK_ADSP_MBOX_IN_CMD_CLR(1), op); + local_ipc->is_notification_pending = false; +} + +void trigger_irq_to_host_rsp(void) +{ + io_reg_write(MTK_ADSP_MBOX_OUT_CMD(0), ADSP_IPI_OP_RSP); +} + +void trigger_irq_to_host_req(void) +{ + io_reg_write(MTK_ADSP_MBOX_OUT_CMD(1), ADSP_IPI_OP_REQ); +} + +enum task_state ipc_platform_do_cmd(struct ipc *ipc) +{ + struct ipc_cmd_hdr *hdr; + + hdr = mailbox_validate(); + ipc_cmd(hdr); + + return SOF_TASK_STATE_COMPLETED; +} + +void ipc_platform_complete_cmd(struct ipc *ipc) +{ + trigger_irq_to_host_rsp(); + while (ipc->pm_prepare_D3) + wait_for_interrupt(0); +} + +int ipc_platform_send_msg(const struct ipc_msg *msg) +{ + struct ipc *ipc = ipc_get(); + + if (ipc->is_notification_pending) + return -EBUSY; + + /* now send the message */ + mailbox_dspbox_write(0, msg->tx_data, msg->tx_size); + + ipc->is_notification_pending = true; + + /* now interrupt host to tell it we have sent a message */ + trigger_irq_to_host_req(); + return 0; +} + +void ipc_platform_send_msg_direct(const struct ipc_msg *msg) +{ + /* TODO: add support */ +} + +#if CONFIG_HOST_PTABLE +struct ipc_data_host_buffer *ipc_platform_get_host_buffer(struct ipc *ipc) +{ + struct ipc_data *iipc = ipc_get_drvdata(ipc); + + return &iipc->dh_buffer; +} +#endif + +int platform_ipc_init(struct ipc *ipc) +{ + int mbox_irq0, mbox_irq1; + int ret; + +#if CONFIG_HOST_PTABLE + struct ipc_data *iipc; + + iipc = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(*iipc)); + if (!iipc) { + tr_err(&ipc_tr, "Unable to allocate memory for IPC data"); + sof_panic(SOF_IPC_PANIC_IPC); + } + ipc_set_drvdata(ipc, iipc); +#else + ipc_set_drvdata(ipc, NULL); +#endif + + local_ipc = ipc; + + /* schedule */ + schedule_task_init_edf(&ipc->ipc_task, SOF_UUID(ipc_task_mt8196_uuid), + &ipc_task_ops, ipc, 0, 0); + +#if CONFIG_HOST_PTABLE + /* allocate page table buffer */ + iipc->dh_buffer.page_table = + rzalloc(SOF_MEM_FLAG_KERNEL, PLATFORM_PAGE_TABLE_SIZE); + if (!iipc->dh_buffer.page_table) { + tr_err(&ipc_tr, "Unable to allocate host page table buffer"); + sof_panic(SOF_IPC_PANIC_IPC); + } + + iipc->dh_buffer.dmac = dma_get(DMA_DIR_HMEM_TO_LMEM, 0, DMA_DEV_HOST, DMA_ACCESS_SHARED); + if (!iipc->dh_buffer.dmac) { + tr_err(&ipc_tr, "Unable to find DMA for host page table"); + sof_panic(SOF_IPC_PANIC_IPC); + } +#endif + + /* + * AP req -- mbox0 --> DSP + * AP <-- mbox0 -- DSP rsp + * AP <-- mbox1 -- DSP req + * AP rsp -- mbox1 --> DSP + */ + mbox_irq0 = mtk_irq_group_id(MTK_DSP_IRQ_MBOX0); + if (mbox_irq0 < 0) { + tr_err(&ipc_tr, "Invalid ipc mbox 0 IRQ:%d", mbox_irq0); + sof_panic(SOF_IPC_PANIC_IPC); + } + + mbox_irq1 = mtk_irq_group_id(MTK_DSP_IRQ_MBOX1); + if (mbox_irq1 < 0) { + tr_err(&ipc_tr, "Invalid ipc mbox 1 IRQ:%d", mbox_irq1); + sof_panic(SOF_IPC_PANIC_IPC); + } + + ret = interrupt_register(mbox_irq0, mbox0_handler, ipc); + if (ret < 0) { + tr_err(&ipc_tr, "Unable to register ipc mbox 0 IRQ"); + sof_panic(SOF_IPC_PANIC_IPC); + } + + ret = interrupt_register(mbox_irq1, mbox1_handler, ipc); + if (ret < 0) { + tr_err(&ipc_tr, "Unable to register ipc mbox 1 IRQ"); + sof_panic(SOF_IPC_PANIC_IPC); + } + + interrupt_enable(mbox_irq0, ipc); + interrupt_enable(mbox_irq1, ipc); + + return 0; +} diff --git a/src/drivers/mediatek/mt8196/timer.c b/src/drivers/mediatek/mt8196/timer.c new file mode 100644 index 000000000000..211cd45fe19d --- /dev/null +++ b/src/drivers/mediatek/mt8196/timer.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#include <sof/audio/component_ext.h> +#include <rtos/interrupt.h> +#include <sof/lib/memory.h> +#include <sof/platform.h> +#include <platform/drivers/timer.h> +#include <platform/drivers/interrupt.h> +#include <platform/drivers/intc.h> +#include <ipc/stream.h> +#include <errno.h> +#include <stdint.h> + +void platform_timer_start(struct timer *timer) +{ + /* set 26m clksrc */ + io_reg_update_bits(MTK_TIMER_CON(timer->id), MTK_TIMER_ENABLE_BIT, 0); + io_reg_update_bits(MTK_TIMER_CON(timer->id), MTK_TIMER_CLKSRC_BIT, + MTK_TIMER_CLK_SRC_CLK_26M); + + /* enable timer */ + io_reg_update_bits(MTK_TIMER_CON(timer->id), MTK_TIMER_ENABLE_BIT, + MTK_TIMER_ENABLE_BIT); + + /* enable system boot time timer */ + io_reg_update_bits(MTK_OSTIMER_CON, MTK_OSTIMER_EN_BIT, + MTK_OSTIMER_EN_BIT); +} + +void platform_timer_stop(struct timer *timer) +{ + if (timer->id > NR_TMRS) + return; + + io_reg_update_bits(MTK_TIMER_CON(timer->id), MTK_TIMER_ENABLE_BIT, 0); + io_reg_update_bits(MTK_TIMER_IRQ_ACK(timer->id), MTK_TIMER_IRQ_ENABLE, 0); +} + +/* IRQs off in arch_timer_get_system() */ +uint64_t platform_timer_get_atomic(struct timer *timer) +{ + return platform_timer_get(timer); +} + +int64_t platform_timer_set(struct timer *timer, uint64_t ticks) +{ + uint64_t time; + uint32_t flags; + uint32_t low, high; + uint32_t ticks_set; + + if (timer->id > NR_TMRS) + return -EINVAL; + + flags = arch_interrupt_global_disable(); + + low = io_reg_read(MTK_OSTIMER_CUR_L); + high = io_reg_read(MTK_OSTIMER_CUR_H); + + /* ostimer 13M counter to 26M interrupt */ + time = (((uint64_t)high << 32) | low) << 1; + + ticks_set = (ticks > time) ? ticks - time : UINT64_MAX - time + ticks; + + timer->hitimeout = ticks >> 32; + timer->lowtimeout = ticks_set; + + /* disable timer before config it */ + io_reg_update_bits(MTK_TIMER_CON(timer->id), MTK_TIMER_ENABLE_BIT, 0); + + /* set 26m clksrc */ + io_reg_update_bits(MTK_TIMER_CON(timer->id), MTK_TIMER_CLKSRC_BIT, + MTK_TIMER_CLK_SRC_CLK_26M); + /* timer reset value */ + io_reg_write(MTK_TIMER_RST_VAL(timer->id), ticks_set); + + /* clear and enable irq */ + io_reg_update_bits(MTK_TIMER_IRQ_ACK(timer->id), MTK_TIMER_IRQ_CLEAR, + MTK_TIMER_IRQ_CLEAR); + io_reg_update_bits(MTK_TIMER_IRQ_ACK(timer->id), MTK_TIMER_IRQ_ENABLE, + MTK_TIMER_IRQ_ENABLE); + + /* enable timer */ + io_reg_update_bits(MTK_TIMER_CON(timer->id), MTK_TIMER_ENABLE_BIT, + MTK_TIMER_ENABLE_BIT); + + arch_interrupt_global_enable(flags); + + return ticks; +} + +void platform_timer_clear(struct timer *timer) +{ + if (timer->id > NR_TMRS) + return; + + io_reg_update_bits(MTK_TIMER_IRQ_ACK(timer->id), MTK_TIMER_IRQ_CLEAR, + MTK_TIMER_IRQ_CLEAR); +} + +uint64_t platform_timer_get(struct timer *timer) +{ + uint64_t time; + uint32_t low; + uint32_t high0; + uint32_t high1; + + if (timer->id > NR_TMRS) + return -EINVAL; + + /* 64bit reads are non atomic on xtensa so we must + * read a stable value where there is no bit 32 flipping. + */ + do { + high0 = io_reg_read(MTK_OSTIMER_CUR_H); + low = io_reg_read(MTK_OSTIMER_CUR_L); + high1 = io_reg_read(MTK_OSTIMER_CUR_H); + + /* worst case is we perform this twice so 6 * 32b clock reads */ + } while (high0 != high1); + + /* convert 13M ostimer counter value to 26M */ + time = (((uint64_t)high0 << 32) | low) << 1; + + return time; +} + +/* get timestamp for host stream DMA position */ +void platform_host_timestamp(struct comp_dev *host, struct sof_ipc_stream_posn *posn) +{ + int err; + + /* get host position */ + err = comp_position(host, posn); + if (err == 0) + posn->flags |= SOF_TIME_HOST_VALID | SOF_TIME_HOST_64; +} + +/* get timestamp for DAI stream DMA position */ +void platform_dai_timestamp(struct comp_dev *dai, + struct sof_ipc_stream_posn *posn) +{ + int err; + + /* get DAI position */ + err = comp_position(dai, posn); + if (err == 0) + posn->flags |= SOF_TIME_DAI_VALID; + + posn->wallclock = timer_get_system(timer_get()) - posn->wallclock; + posn->flags |= SOF_TIME_WALL_VALID | SOF_TIME_WALL_64; +} + +/* get current wallclock for componnent */ +void platform_dai_wallclock(struct comp_dev *dai, uint64_t *wallclock) +{ + *wallclock = platform_timer_get(timer_get()); +} + +static void platform_timer_handler(void *arg) +{ + struct timer *timer = arg; + + io_reg_update_bits(MTK_TIMER_IRQ_ACK(timer->id), MTK_TIMER_IRQ_CLEAR, + MTK_TIMER_IRQ_CLEAR); + + io_reg_update_bits(MTK_TIMER_CON(timer->id), MTK_TIMER_ENABLE_BIT, 0); + + io_reg_update_bits(MTK_TIMER_IRQ_ACK(timer->id), MTK_TIMER_IRQ_ENABLE, 0); + + timer->handler(timer->data); +} + +static int platform_timer_register(struct timer *timer, void (*handler)(void *arg), void *arg) +{ + timer->handler = handler; + timer->data = arg; + timer->hitime = 0; + timer->hitimeout = 0; + + return interrupt_register(timer->irq, platform_timer_handler, timer); +} + +int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) +{ + switch (timer->id) { + case OSTIMER0: + case OSTIMER1: + case OSTIMER2: + case OSTIMER3: + return platform_timer_register(timer, handler, arg); + default: + return -EINVAL; + } +} + +void timer_unregister(struct timer *timer, void *arg) +{ + interrupt_unregister(timer->irq, arg); +} + +void timer_enable(struct timer *timer, void *arg, int core) +{ + /* enable timer interrupt */ + interrupt_enable(timer->irq, arg); + + interrupt_unmask(8, cpu_get_id()); +} + +void timer_disable(struct timer *timer, void *arg, int core) +{ + /* enable timer interrupt */ + interrupt_disable(timer->irq, arg); + interrupt_mask(8, cpu_get_id()); +} diff --git a/src/drivers/mediatek/mt8365/CMakeLists.txt b/src/drivers/mediatek/mt8365/CMakeLists.txt new file mode 100644 index 000000000000..0c8e351f06b5 --- /dev/null +++ b/src/drivers/mediatek/mt8365/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources(sof ipc.c timer.c interrupt.c) + diff --git a/src/drivers/mediatek/mt8365/interrupt.c b/src/drivers/mediatek/mt8365/interrupt.c new file mode 100644 index 000000000000..1e341ab87a28 --- /dev/null +++ b/src/drivers/mediatek/mt8365/interrupt.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#include <errno.h> +#include <inttypes.h> +#include <rtos/bit.h> +#include <sof/common.h> +#include <rtos/interrupt.h> +#include <sof/lib/cpu.h> +#include <sof/lib/io.h> +#include <sof/lib/memory.h> +#include <sof/lib/uuid.h> +#include <sof/list.h> +#include <rtos/spinlock.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#define PENDING_IRQ_INDEX_MAX 10 + +SOF_DEFINE_REG_UUID(interrupt); + +DECLARE_TR_CTX(int_tr, SOF_UUID(interrupt_uuid), LOG_LEVEL_INFO); + +static void mtk_irq_init(void) +{ + /* disable all ADSP IRQ */ + io_reg_write(RG_DSP_IRQ_EN, 0x0); +} + +static void mtk_irq_mask(struct irq_desc *desc, uint32_t irq, unsigned int core) +{ + if (!desc) { + io_reg_update_bits(RG_DSP_IRQ_EN, BIT(irq + IRQ_EXT_BIT_OFFSET), 0); + } else { + switch (desc->irq) { + case IRQ_EXT_GROUP1_BASE: + io_reg_update_bits(RG_DSP_IRQ_EN, BIT(irq + IRQ_EXT_GROUP1_BIT_OFFSET), 0); + break; + default: + tr_err(&int_tr, "Invalid interrupt %d", irq); + return; + } + } +} + +static void mtk_irq_unmask(struct irq_desc *desc, uint32_t irq, unsigned int core) +{ + if (!desc) { + io_reg_update_bits(RG_DSP_IRQ_EN, BIT(irq + IRQ_EXT_BIT_OFFSET), + BIT(irq + IRQ_EXT_BIT_OFFSET)); + } else { + switch (desc->irq) { + case IRQ_EXT_GROUP1_BASE: + io_reg_update_bits(RG_DSP_IRQ_EN, BIT(irq + IRQ_EXT_GROUP1_BIT_OFFSET), + BIT(irq + IRQ_EXT_GROUP1_BIT_OFFSET)); + break; + default: + tr_err(&int_tr, "Invalid interrupt %d", irq); + return; + } + } +} + +static uint32_t mtk_irq_group_pending_status(uint32_t irq) +{ + uint32_t irq_status = 0; + + if (irq == IRQ_EXT_GROUP1_BASE) { + irq_status = io_reg_read(RG_DSP_IRQ_STATUS); + irq_status &= IRQ_EXT_MASK; + } + + return irq_status; +} + +static uint32_t mtk_get_pending_index(uint32_t current, uint32_t *next) +{ + uint32_t index; + + if (current == 0) + return PENDING_IRQ_INDEX_MAX; + + /* ffs returns one plus the index of the least significant 1-bit of input int */ + index = ffs(current) - 1; + + /* remove the handling index from current pending status */ + *next = current & ~(1ull << index); + + return index; +} + +static inline void mtk_handle_group_pending_irq(struct irq_cascade_desc *cascade, + uint32_t line_index, uint32_t status) +{ + int core = cpu_get_id(); + struct list_item *clist; + struct irq_desc *child = NULL; + uint32_t idx; + uint32_t next_status; + bool handled; + k_spinlock_key_t key; + + idx = mtk_get_pending_index(status, &next_status); + while (idx < PENDING_IRQ_INDEX_MAX) { + handled = false; + + key = k_spin_lock(&cascade->lock); + list_for_item(clist, &cascade->child[idx - IRQ_EXT_GROUP1_BIT_OFFSET].list) { + child = container_of(clist, struct irq_desc, irq_list); + + if (child->handler && (child->cpu_mask & 1 << core)) { + child->handler(child->handler_arg); + handled = true; + } + } + k_spin_unlock(&cascade->lock, key); + + if (!handled) { + tr_err(&int_tr, "Not handle irq %u in group %u", + idx, line_index); + } + + idx = mtk_get_pending_index(next_status, &next_status); + } +} + +static inline void mtk_irq_group_handler(void *data, uint32_t line_index) +{ + struct irq_desc *parent = data; + struct irq_cascade_desc *cascade = + container_of(parent, struct irq_cascade_desc, desc); + uint32_t status; + + status = mtk_irq_group_pending_status(line_index); + if (status) + mtk_handle_group_pending_irq(cascade, line_index, status); + else + tr_err(&int_tr, "No pending irq in group %d", line_index); +} + +#define DEFINE_IRQ_HANDLER(n) \ + static void irqhandler_##n(void *arg) \ + { \ + mtk_irq_group_handler(arg, n); \ + } + +DEFINE_IRQ_HANDLER(1) + +static const char mtk_ext_irq[] = "mtk_ext_irq"; + +static const struct irq_cascade_ops irq_ops = { + .mask = mtk_irq_mask, + .unmask = mtk_irq_unmask, +}; + +static const struct irq_cascade_tmpl dsp_irq[] = { + { + .name = mtk_ext_irq, + .irq = IRQ_EXT_GROUP1_BASE, + .handler = irqhandler_1, + .ops = &irq_ops, + .global_mask = false, + }, +}; + +int mtk_irq_group_id(uint32_t in_irq) +{ + if (in_irq >= PLATFORM_IRQ_HW_NUM) + in_irq -= PLATFORM_IRQ_HW_NUM; + + return interrupt_get_irq(in_irq, dsp_irq[0].name); +} + +void platform_interrupt_init(void) +{ + int i; + + mtk_irq_init(); + for (i = 0; i < ARRAY_SIZE(dsp_irq); i++) + interrupt_cascade_register(dsp_irq + i); +} + +void platform_interrupt_set(uint32_t irq) +{ + if (interrupt_is_dsp_direct(irq)) + arch_interrupt_set(irq); +} + +void platform_interrupt_clear(uint32_t irq, uint32_t mask) +{ + if (interrupt_is_dsp_direct(irq)) + arch_interrupt_clear(irq); +} + +uint32_t platform_interrupt_get_enabled(void) +{ + return 0; +} + +void interrupt_mask(uint32_t irq, unsigned int cpu) +{ + struct irq_cascade_desc *cascade = interrupt_get_parent(irq); + + if (cascade && cascade->ops->mask) + cascade->ops->mask(&cascade->desc, irq - cascade->irq_base, + cpu); + else + mtk_irq_mask(NULL, irq, 0); +} + +void interrupt_unmask(uint32_t irq, unsigned int cpu) +{ + struct irq_cascade_desc *cascade = interrupt_get_parent(irq); + + if (cascade && cascade->ops->unmask) + cascade->ops->unmask(&cascade->desc, irq - cascade->irq_base, + cpu); + else + mtk_irq_unmask(NULL, irq, 0); +} diff --git a/src/drivers/mediatek/mt8365/ipc.c b/src/drivers/mediatek/mt8365/ipc.c new file mode 100644 index 000000000000..348cd6a51f45 --- /dev/null +++ b/src/drivers/mediatek/mt8365/ipc.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#include <rtos/panic.h> +#include <rtos/interrupt.h> +#include <sof/ipc/driver.h> +#include <sof/ipc/msg.h> +#include <sof/ipc/schedule.h> +#include <rtos/alloc.h> +#include <sof/lib/dma.h> +#include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <sof/lib/uuid.h> +#include <rtos/wait.h> +#include <sof/list.h> +#include <sof/platform.h> +#include <sof/schedule/edf_schedule.h> +#include <sof/schedule/schedule.h> +#include <rtos/task.h> +#include <rtos/spinlock.h> +#include <ipc/header.h> +#include <ipc/topology.h> +#include <ipc/trace.h> +#include <platform/drivers/mt_reg_base.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +SOF_DEFINE_REG_UUID(ipc_task); + +static struct ipc *local_ipc; + +struct ipc_data { + struct ipc_data_host_buffer dh_buffer; +}; + +static void irq_handler(void *args) +{ + uint32_t status; + + /* Interrupt arrived, check src */ + status = mailbox_sw_reg_read(SRAM_REG_OP_CPU2DSP); + + tr_dbg(&ipc_tr, "ipc: irq isr 0x%x", status); + + /* reply message(done) from host */ + if (status == ADSP_IPI_OP_RSP) { + /* clear interrupt */ + io_reg_update_bits(DSP_RG_INT2CIRQ, CPU2DSP_IRQ, 0); + local_ipc->is_notification_pending = false; + } + + /* new message from host */ + if (status == ADSP_IPI_OP_REQ) { + /* clear interrupt */ + io_reg_update_bits(DSP_RG_INT2CIRQ, CPU2DSP_IRQ, 0); + ipc_schedule_process(local_ipc); + } +} + +/* DSP -> HOST RSP */ +void trigger_irq_to_host_rsp(void) +{ + mailbox_sw_reg_write(SRAM_REG_OP_DSP2CPU, ADSP_IPI_OP_RSP); + /* trigger host irq */ + io_reg_update_bits(DSP_RG_INT2CIRQ, DSP2SPM_IRQ_B, 0); + io_reg_update_bits(DSP_RG_INT2CIRQ, DSP2CPU_IRQ, DSP2CPU_IRQ); +} + +/* DSP -> HOST REQ */ +void trigger_irq_to_host_req(void) +{ + mailbox_sw_reg_write(SRAM_REG_OP_DSP2CPU, ADSP_IPI_OP_REQ); + /* trigger host irq */ + io_reg_update_bits(DSP_RG_INT2CIRQ, DSP2SPM_IRQ_B, 0); + io_reg_update_bits(DSP_RG_INT2CIRQ, DSP2CPU_IRQ, DSP2CPU_IRQ); +} + +enum task_state ipc_platform_do_cmd(struct ipc *ipc) +{ + struct ipc_cmd_hdr *hdr; + + hdr = mailbox_validate(); + ipc_cmd(hdr); + + return SOF_TASK_STATE_COMPLETED; +} + +void ipc_platform_complete_cmd(struct ipc *ipc) +{ + trigger_irq_to_host_rsp(); + while (ipc->pm_prepare_D3) { + clock_set_freq(CLK_CPU(cpu_get_id()), CLK_SUSPEND_CPU_HZ); + asm volatile("waiti 15"); + } +} + +int ipc_platform_send_msg(const struct ipc_msg *msg) +{ + struct ipc *ipc = ipc_get(); + + if (ipc->is_notification_pending) + return -EBUSY; + + /* now send the message */ + mailbox_dspbox_write(0, msg->tx_data, msg->tx_size); + + tr_dbg(&ipc_tr, "ipc: msg tx -> 0x%x", msg->header); + + ipc->is_notification_pending = true; + + /* now interrupt host to tell it we have sent a message */ + trigger_irq_to_host_req(); + return 0; +} + +void ipc_platform_send_msg_direct(const struct ipc_msg *msg) +{ + /* TODO: add support */ +} + +#if CONFIG_HOST_PTABLE +struct ipc_data_host_buffer *ipc_platform_get_host_buffer(struct ipc *ipc) +{ + struct ipc_data *iipc = ipc_get_drvdata(ipc); + + return &iipc->dh_buffer; +} +#endif + +int platform_ipc_init(struct ipc *ipc) +{ + uint32_t ipi_irq; + +#if CONFIG_HOST_PTABLE + struct ipc_data *iipc; + + iipc = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(*iipc)); + if (!iipc) { + tr_err(&ipc_tr, "Unable to allocate IPC private data"); + sof_panic(SOF_IPC_PANIC_IPC); + } + ipc_set_drvdata(ipc, iipc); +#else + ipc_set_drvdata(ipc, NULL); +#endif + + local_ipc = ipc; + + /* schedule */ + schedule_task_init_edf(&ipc->ipc_task, SOF_UUID(ipc_task_uuid), &ipc_task_ops, ipc, 0, 0); + +#if CONFIG_HOST_PTABLE + /* allocate page table buffer */ + iipc->dh_buffer.page_table = + rzalloc(SOF_MEM_FLAG_KERNEL, PLATFORM_PAGE_TABLE_SIZE); + if (!iipc->dh_buffer.page_table) { + tr_err(&ipc_tr, "Unable to allocate host page table buffer"); + sof_panic(SOF_IPC_PANIC_IPC); + } + + iipc->dh_buffer.dmac = dma_get(DMA_DIR_HMEM_TO_LMEM, 0, DMA_DEV_HOST, DMA_ACCESS_SHARED); + if (!iipc->dh_buffer.dmac) { + tr_err(&ipc_tr, "Unable to find DMA for host page table"); + sof_panic(SOF_IPC_PANIC_IPC); + } +#endif + + ipi_irq = mtk_irq_group_id(LX_MCU_IRQ_B); + interrupt_register(ipi_irq, irq_handler, ipc); + interrupt_enable(ipi_irq, ipc); + + return 0; +} diff --git a/src/drivers/mediatek/mt8365/timer.c b/src/drivers/mediatek/mt8365/timer.c new file mode 100644 index 000000000000..40d33a6d1b50 --- /dev/null +++ b/src/drivers/mediatek/mt8365/timer.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#include <sof/audio/component_ext.h> +#include <rtos/interrupt.h> +#include <sof/lib/memory.h> +#include <sof/platform.h> +#include <platform/drivers/timer.h> +#include <ipc/stream.h> +#include <errno.h> +#include <stdint.h> + +void platform_timer_start(struct timer *timer) +{ + if (timer->id >= NR_TMRS) + return; + + /*timer use 13M clksrc*/ + /*clear irq, if pending and enable timer*/ + io_reg_write(TIMER_CON(timer->id), TIMER_IRQ_CLEAR | TIMER_ENABLE_BIT); +} + +void platform_timer_stop(struct timer *timer) +{ + if (timer->id >= NR_TMRS) + return; + + io_reg_write(TIMER_CON(timer->id), TIMER_IRQ_CLEAR | TIMER_ENABLE_BIT); + io_reg_write(TIMER_CON(timer->id), 0); + +} + +/* IRQs off in arch_timer_get_system() */ +uint64_t platform_timer_get_atomic(struct timer *timer) +{ + return platform_timer_get(timer); +} + +int64_t platform_timer_set(struct timer *timer, uint64_t ticks) +{ + uint64_t time; + uint32_t flags; + uint32_t ticks_set; + + if (timer->id >= NR_TMRS) + return -EINVAL; + + flags = arch_interrupt_global_disable(); + + time = platform_timer_get(timer); + ticks_set = (ticks > time) ? ticks - time : UINT64_MAX - time + ticks; + timer->hitimeout = ticks >> 32; + timer->lowtimeout = ticks_set; + + io_reg_write(TIMER_CNT_VAL(timer->id), ticks_set); + io_reg_write(TIMER_CON(timer->id), TIMER_IRQ_ENABLE | TIMER_ENABLE_BIT); + + arch_interrupt_global_enable(flags); + + return ticks; +} + +void platform_timer_clear(struct timer *timer) +{ + if (timer->id >= NR_TMRS) + return; + + io_reg_write(TIMER_CON(timer->id), TIMER_IRQ_CLEAR | TIMER_ENABLE_BIT); +} + +uint64_t platform_timer_get(struct timer *timer) +{ + uint64_t time; + uint32_t low, high; + + if (timer->id >= NR_TMRS) + return -EINVAL; + + /* CNTCV_H is only updated when the CNTCV_L is read. + * Always read CNTCV_L before CNTCV_H to get a valid 64-bit timestamp. + */ + low = io_reg_read(CNTCV_L); + high = io_reg_read(CNTCV_H); + time = ((uint64_t)high << 32) | low; + + return time; +} + +/* get timestamp for host stream DMA position */ +void platform_host_timestamp(struct comp_dev *host, + struct sof_ipc_stream_posn *posn) +{ + int err; + + /* get host position */ + err = comp_position(host, posn); + if (err == 0) + posn->flags |= SOF_TIME_HOST_VALID | SOF_TIME_HOST_64; +} + +/* get timestamp for DAI stream DMA position */ +void platform_dai_timestamp(struct comp_dev *dai, + struct sof_ipc_stream_posn *posn) +{ + int err; + + /* get DAI position */ + err = comp_position(dai, posn); + if (err == 0) + posn->flags |= SOF_TIME_DAI_VALID; + + posn->wallclock = timer_get_system(timer_get()) - posn->wallclock; + posn->flags |= SOF_TIME_WALL_VALID | SOF_TIME_WALL_64; +} + +/* get current wallclock for componnent */ +void platform_dai_wallclock(struct comp_dev *dai, uint64_t *wallclock) +{ + *wallclock = platform_timer_get(timer_get()); +} + +static void platform_timer_handler(void *arg) +{ + struct timer *timer = arg; + + timer->handler(timer->data); +} + +static int platform_timer_register(struct timer *timer, void (*handler)(void *arg), void *arg) +{ + timer->handler = handler; + timer->data = arg; + timer->hitime = 0; + timer->hitimeout = 0; + + return interrupt_register(timer->irq, platform_timer_handler, timer); +} + +int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) +{ + switch (timer->id) { + case OSTIMER0: + return platform_timer_register(timer, handler, arg); + default: + return -EINVAL; + } +} + +void timer_unregister(struct timer *timer, void *arg) +{ + interrupt_unregister(timer->irq, arg); +} + +void timer_enable(struct timer *timer, void *arg, int core) +{ + interrupt_unmask(timer->irq, cpu_get_id()); + interrupt_enable(timer->irq, arg); +} + +void timer_disable(struct timer *timer, void *arg, int core) +{ + interrupt_disable(timer->irq, arg); + interrupt_mask(timer->irq, cpu_get_id()); +} diff --git a/src/idc/CMakeLists.txt b/src/idc/CMakeLists.txt index d43a557e182d..1cedc1f739f4 100644 --- a/src/idc/CMakeLists.txt +++ b/src/idc/CMakeLists.txt @@ -1,3 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof idc.c ) +is_zephyr(zephyr) +if(zephyr) + add_local_sources_ifdef(CONFIG_SMP sof idc.c) + add_local_sources(sof zephyr_idc.c) +endif() diff --git a/src/idc/Kconfig b/src/idc/Kconfig new file mode 100644 index 000000000000..d2e74c066b4d --- /dev/null +++ b/src/idc/Kconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config IDC_TIMEOUT_US + int "Timeout for blocking IDC call, microseconds" + default 15000 + help + It may be beneficial to have different timeout values + for fast platforms (manufactured silicon) and at least + 10 times slower FPGA platforms. diff --git a/src/idc/idc.c b/src/idc/idc.c index 7fe0988788ea..145a22abfa1c 100644 --- a/src/idc/idc.c +++ b/src/idc/idc.c @@ -15,6 +15,7 @@ #include <rtos/alloc.h> #include <rtos/clk.h> #include <sof/lib/cpu.h> +#include <sof/lib/memory.h> #include <sof/lib/notifier.h> #include <sof/lib/pm_runtime.h> #include <sof/lib/uuid.h> @@ -46,10 +47,6 @@ DECLARE_TR_CTX(idc_tr, SOF_UUID(idc_uuid), LOG_LEVEL_INFO); SOF_DEFINE_REG_UUID(idc_task); -#ifndef __ZEPHYR__ -SOF_DEFINE_REG_UUID(idc_cmd_task); -#endif - /** * \brief Sets IDC command status after execution. * \param[in] status Status to be set. @@ -76,35 +73,6 @@ int idc_msg_status_get(uint32_t core) return *(uint32_t *)payload->data; } -/** - * \brief Waits until status condition is true. - * \param[in] target_core Id of the core receiving the message. - * \param[in] cond Pointer to condition function. - * \return Error code. - */ -int idc_wait_in_blocking_mode(uint32_t target_core, bool (*cond)(int)) -{ - uint64_t deadline = sof_cycle_get_64() + k_us_to_cyc_ceil64(IDC_TIMEOUT); - - while (!cond(target_core)) { - /* spin here so other core can access IO and timers freely */ - wait_delay(8192); - - if (deadline < sof_cycle_get_64()) - break; - } - - /* safe check in case we've got preempted - * after read - */ - if (cond(target_core)) - return 0; - - tr_err(&idc_tr, "idc_wait_in_blocking_mode() error: timeout, target_core %u", - target_core); - return -ETIME; -} - /** * \brief Executes IDC IPC processing message. */ @@ -115,19 +83,18 @@ static void idc_ipc(void) ipc_cmd(ipc->comp_data); } -#if CONFIG_IPC_MAJOR_4 static int idc_ipc4_bind(uint32_t comp_id) { struct ipc_comp_dev *ipc_dev; struct idc_payload *payload; - struct ipc4_module_bind_unbind *bu; + struct bind_info *bu; ipc_dev = ipc_get_comp_by_id(ipc_get(), comp_id); if (!ipc_dev) return -ENODEV; payload = idc_payload_get(*idc_get(), cpu_get_id()); - bu = (struct ipc4_module_bind_unbind *)payload; + bu = (struct bind_info *)payload; return comp_bind(ipc_dev->cd, bu); } @@ -136,14 +103,14 @@ static int idc_ipc4_unbind(uint32_t comp_id) { struct ipc_comp_dev *ipc_dev; struct idc_payload *payload; - struct ipc4_module_bind_unbind *bu; + struct bind_info *bu; ipc_dev = ipc_get_comp_by_id(ipc_get(), comp_id); if (!ipc_dev) return -ENODEV; payload = idc_payload_get(*idc_get(), cpu_get_id()); - bu = (struct ipc4_module_bind_unbind *)payload; + bu = (struct bind_info *)payload; return comp_unbind(ipc_dev->cd, bu); } @@ -163,7 +130,6 @@ static int idc_get_attribute(uint32_t comp_id) return comp_get_attribute(ipc_dev->cd, get_attr_payload->type, get_attr_payload->value); } -#endif /* CONFIG_IPC_MAJOR_4 */ /** * \brief Executes IDC component params message. @@ -219,20 +185,22 @@ static int idc_prepare(uint32_t comp_id) /* 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)); + dev->task = sof_heap_alloc(dev->drv->user_heap, SOF_MEM_FLAG_USER, + sizeof(*dev->task), 0); if (!dev->task) { ret = -ENOMEM; goto out; } + memset(dev->task, 0, sizeof(*dev->task)); ret = schedule_task_init_ll(dev->task, SOF_UUID(idc_task_uuid), SOF_SCHEDULE_LL_TIMER, dev->priority, comp_task, dev, dev->ipc_config.core, 0); if (ret < 0) { - rfree(dev->task); + sof_heap_free(dev->drv->user_heap, dev->task); + dev->task = NULL; goto out; } } @@ -256,32 +224,12 @@ static int idc_trigger(uint32_t comp_id) struct idc *idc = *idc_get(); struct idc_payload *payload = idc_payload_get(idc, cpu_get_id()); uint32_t cmd = *(uint32_t *)payload; - int ret; ipc_dev = ipc_get_comp_by_id(ipc, comp_id); if (!ipc_dev) return -ENODEV; - ret = comp_trigger(ipc_dev->cd, cmd); - if (ret < 0) - goto out; - - /* schedule or cancel task */ - switch (cmd) { - case COMP_TRIGGER_START: - case COMP_TRIGGER_RELEASE: - schedule_task(ipc_dev->cd->task, 0, ipc_dev->cd->period); - break; - case COMP_TRIGGER_XRUN: - case COMP_TRIGGER_PAUSE: - case COMP_TRIGGER_STOP: - schedule_task_cancel(ipc_dev->cd->task); - break; - } - -out: - - return ret; + return comp_trigger(ipc_dev->cd, cmd); } /** @@ -330,7 +278,6 @@ static int idc_comp_free(uint32_t comp_id) */ static int idc_ppl_state(uint32_t ppl_id, uint32_t phase) { -#if CONFIG_IPC_MAJOR_4 struct ipc *ipc = ipc_get(); struct idc *idc = *idc_get(); struct idc_payload *payload = idc_payload_get(idc, cpu_get_id()); @@ -361,7 +308,6 @@ static int idc_ppl_state(uint32_t ppl_id, uint32_t phase) return ipc4_pipeline_trigger(ppl_icd, cmd, &delayed); } -#endif return 0; } @@ -380,7 +326,7 @@ static void idc_process_async_msg(uint32_t slot) #if CONFIG_AMS process_incoming_message(slot); #else - tr_err(&idc_tr, "idc_cmd(): AMS not enabled"); + tr_err(&idc_tr, "AMS not enabled"); #endif } @@ -425,9 +371,10 @@ void idc_cmd(struct idc_msg *msg) notifier_notify_remote(); break; case iTS(IDC_MSG_IPC): + dbg_path_hot_start_watching(); idc_ipc(); + dbg_path_hot_stop_watching(); break; -#if CONFIG_IPC_MAJOR_4 case iTS(IDC_MSG_BIND): ret = idc_ipc4_bind(msg->extension); break; @@ -440,7 +387,6 @@ void idc_cmd(struct idc_msg *msg) case iTS(IDC_MSG_FREE): ret = idc_comp_free(msg->extension); break; -#endif case iTS(IDC_MSG_PARAMS): ret = idc_params(msg->extension); break; @@ -467,55 +413,24 @@ void idc_cmd(struct idc_msg *msg) idc_process_async_msg(IDC_HEADER_TO_AMS_SLOT_MASK(msg->header)); break; default: - tr_err(&idc_tr, "idc_cmd(): invalid msg->header = %u", + tr_err(&idc_tr, "invalid msg->header = %u", msg->header); } idc_msg_status_set(ret, cpu_get_id()); } -#ifndef __ZEPHYR__ -static void idc_complete(void *data) -{ - struct ipc *ipc = ipc_get(); - struct idc *idc = data; - uint32_t type = iTS(idc->received_msg.header); - k_spinlock_key_t key; - -#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS - /* Increment performance counters */ - io_perf_monitor_update_data(idc->io_perf_out_msg_count, 1); -#endif - - switch (type) { - case iTS(IDC_MSG_IPC): - /* Signal the host */ - key = k_spin_lock(&ipc->lock); - ipc->task_mask &= ~IPC_TASK_SECONDARY_CORE; - ipc_complete_cmd(ipc); - k_spin_unlock(&ipc->lock, key); - } -} -#endif - /* Runs on each CPU */ -int idc_init(void) +__cold int idc_init(void) { struct idc **idc = idc_get(); -#ifndef __ZEPHYR__ - struct task_ops ops = { - .run = idc_do_cmd, - .get_deadline = ipc_task_deadline, - .complete = idc_complete, - }; - - *idc = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, sizeof(**idc)); -#endif - tr_dbg(&idc_tr, "idc_init()"); + assert_can_be_cold(); + + tr_dbg(&idc_tr, "entry"); /* initialize idc data */ - (*idc)->payload = platform_shared_get(static_payload, sizeof(static_payload)); + (*idc)->payload = static_payload; #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS struct io_perf_data_item init_data = {IO_PERF_IDC_ID, @@ -530,23 +445,16 @@ int idc_init(void) #endif /* process task */ -#ifndef __ZEPHYR__ - schedule_task_init_edf(&(*idc)->idc_task, SOF_UUID(idc_cmd_task_uuid), - &ops, *idc, cpu_get_id(), 0); - - return platform_idc_init(); -#else idc_init_thread(); return 0; -#endif } int idc_restore(void) { struct idc **idc __unused = idc_get(); - tr_info(&idc_tr, "idc_restore()"); + tr_info(&idc_tr, "entry"); /* idc_restore() is invoked during D0->D0ix/D0ix->D0 flow. In that * case basic core structures e.g. idc struct should be already @@ -555,9 +463,5 @@ int idc_restore(void) */ assert(*idc); -#ifndef __ZEPHYR__ - return platform_idc_restore(); -#endif - return 0; } diff --git a/src/idc/zephyr_idc.c b/src/idc/zephyr_idc.c index 664d09a260ca..771ae967bfb1 100644 --- a/src/idc/zephyr_idc.c +++ b/src/idc/zephyr_idc.c @@ -115,33 +115,49 @@ static void idc_handler(struct k_p4wq_work *work) /* * Used for *target* CPUs, since the initiator (usually core 0) can launch - * several IDC messages at once + * several IDC messages at once. Also we need 2 work items per target core, + * because the p4wq thread might just have returned from the work handler, but + * hasn't released the work buffer yet (hasn't set thread pointer to NULL). + * Then submitting the same work item again can result in an assertion failure. */ -static struct zephyr_idc_msg idc_work[CONFIG_CORE_COUNT]; +static struct zephyr_idc_msg idc_work[CONFIG_CORE_COUNT * 2]; +/* Protect the above array */ +static K_MUTEX_DEFINE(idc_mutex); int idc_send_msg(struct idc_msg *msg, uint32_t mode) { struct idc *idc = *idc_get(); struct idc_payload *payload = idc_payload_get(idc, msg->core); unsigned int target_cpu = msg->core; - struct zephyr_idc_msg *zmsg = idc_work + target_cpu; + struct zephyr_idc_msg *zmsg = idc_work + target_cpu * 2; struct idc_msg *msg_cp = &zmsg->msg; struct k_p4wq_work *work = &zmsg->work; int ret; int idc_send_memcpy_err __unused; + if (!cpu_is_core_enabled(target_cpu)) { + tr_err(&zephyr_idc_tr, "Core %u is down, cannot send IDC message", target_cpu); + return -EACCES; + } + + k_mutex_lock(&idc_mutex, K_FOREVER); + + if (unlikely(work->thread)) { + /* See comment above the idc_work[] array. */ + zmsg++; + work = &zmsg->work; + msg_cp = &zmsg->msg; + } + idc_send_memcpy_err = memcpy_s(msg_cp, sizeof(*msg_cp), msg, sizeof(*msg)); assert(!idc_send_memcpy_err); + /* Same priority as the IPC thread which is an EDF task and under Zephyr */ - work->priority = EDF_ZEPHYR_PRIORITY; + work->priority = CONFIG_EDF_THREAD_PRIORITY; work->deadline = 0; work->handler = idc_handler; work->sync = mode == IDC_BLOCKING; - if (!cpu_is_core_enabled(target_cpu)) { - tr_err(&zephyr_idc_tr, "Core %u is down, cannot sent IDC message", target_cpu); - return -EACCES; - } if (msg->payload) { idc_send_memcpy_err = memcpy_s(payload->data, sizeof(payload->data), msg->payload, msg->size); @@ -158,6 +174,8 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode) k_p4wq_submit(q_zephyr_idc + target_cpu, work); + k_mutex_unlock(&idc_mutex); + #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS /* Increment performance counters */ io_perf_monitor_update_data(idc->io_perf_out_msg_count, 1); @@ -165,7 +183,7 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode) switch (mode) { case IDC_BLOCKING: - ret = k_p4wq_wait(work, K_USEC(IDC_TIMEOUT)); + ret = k_p4wq_wait(work, K_USEC(CONFIG_IDC_TIMEOUT_US)); if (!ret) /* message was sent and executed successfully, get status code */ ret = idc_msg_status_get(msg->core); @@ -179,12 +197,23 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode) return ret; } -void idc_init_thread(void) +__cold void idc_init_thread(void) { + char thread_name[] = "idc_p4wq0"; int cpu = cpu_get_id(); + assert_can_be_cold(); + k_p4wq_enable_static_thread(q_zephyr_idc + cpu, _p4threads_q_zephyr_idc + cpu, BIT(cpu)); + + thread_name[sizeof(thread_name) - 2] = '0' + cpu; + k_thread_name_set(_p4threads_q_zephyr_idc + cpu, thread_name); + /* + * Assign SOF system heap to the IDC thread. Otherwise by default it + * uses the Zephyr heap for DP stack allocation + */ + k_thread_heap_assign(_p4threads_q_zephyr_idc + cpu, sof_sys_heap_get()); } #endif /* CONFIG_MULTICORE */ diff --git a/src/include/Readme.md b/src/include/README.md similarity index 100% rename from src/include/Readme.md rename to src/include/README.md diff --git a/src/include/ipc/dai-amd.h b/src/include/ipc/dai-amd.h index ceeb870c163e..4bfa10b150e8 100644 --- a/src/include/ipc/dai-amd.h +++ b/src/include/ipc/dai-amd.h @@ -23,6 +23,8 @@ struct sof_ipc_dai_acp_params { uint32_t reserved0; uint32_t fsync_rate; uint32_t tdm_slots; + uint32_t tdm_mode; + uint32_t format; } __attribute__((packed, aligned(4))); /* ACP Configuration Request - SOF_IPC_DAI_AMD_SDW_CONFIG */ diff --git a/src/include/ipc/dai.h b/src/include/ipc/dai.h index b5b29316f9e6..49ffa5d5fa94 100644 --- a/src/include/ipc/dai.h +++ b/src/include/ipc/dai.h @@ -21,6 +21,7 @@ #include <ipc/dai-mediatek.h> #include <ipc/dai-amd.h> #include <ipc/header.h> +#include <stddef.h> #include <stdint.h> /* @@ -94,9 +95,13 @@ enum sof_ipc_dai_type { SOF_DAI_AMD_SP_VIRTUAL, /**<Amd SP VIRTUAL */ SOF_DAI_AMD_HS_VIRTUAL, /**<Amd HS VIRTUAL */ SOF_DAI_IMX_MICFIL, /**< i.MX MICFIL */ - SOF_DAI_AMD_SW_AUDIO /**<Amd SW AUDIO */ + SOF_DAI_AMD_SDW, /**< Amd SDW */ + SOF_DAI_INTEL_UAOL, /**< Intel UAOL */ + SOF_DAI_AMD_TDM /**< Amd TDM */ }; +#define SOF_DAI_CONFIG_HW_SPEC_OFFSET offsetof(struct sof_ipc_dai_config, ssp) + /* general purpose DAI configuration */ struct sof_ipc_dai_config { struct sof_ipc_cmd_hdr hdr; @@ -122,7 +127,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_acp_params acpbt; struct sof_ipc_dai_acp_params acpsp; struct sof_ipc_dai_acpdmic_params acpdmic; - struct sof_ipc_dai_acp_params acphs; + struct sof_ipc_dai_acp_params acptdm; struct sof_ipc_dai_afe_params afe; struct sof_ipc_dai_micfil_params micfil; struct sof_ipc_dai_acp_sdw_params acpsdw; diff --git a/src/include/ipc4/alh.h b/src/include/ipc4/alh.h index c15578514b2a..7691b9fe0a11 100644 --- a/src/include/ipc4/alh.h +++ b/src/include/ipc4/alh.h @@ -37,7 +37,7 @@ #endif #if defined(CONFIG_SOC_SERIES_INTEL_ADSP_CAVS) || \ - defined(CONFIG_SOC_INTEL_ACE15_MTPM) + defined(CONFIG_SOC_ACE15_MTPM) #define IPC4_DAI_NUM_ALH_BI_DIR_LINKS 16 #define IPC4_DAI_NUM_ALH_BI_DIR_LINKS_GROUP 4 #else diff --git a/src/include/ipc4/base-config.h b/src/include/ipc4/base-config.h index 07a35a47e9aa..0c89d534637a 100644 --- a/src/include/ipc4/base-config.h +++ b/src/include/ipc4/base-config.h @@ -23,14 +23,15 @@ #ifndef __SOF_IPC4_BASE_CONFIG_H__ #define __SOF_IPC4_BASE_CONFIG_H__ -#ifndef __SOF_MODULE_SERVICE_BUILD__ + #include <sof/compiler_attributes.h> -#endif #include <module/ipc4/base-config.h> struct sof_ipc_stream_params; void ipc4_base_module_cfg_to_stream_params(const struct ipc4_base_module_cfg *base_cfg, struct sof_ipc_stream_params *params); +void ipc4_audio_format_to_stream_params(const struct ipc4_audio_format *audio_fmt, + struct sof_ipc_stream_params *params); struct comp_buffer; void ipc4_update_buffer_format(struct comp_buffer *buf_c, const struct ipc4_audio_format *fmt); diff --git a/src/include/ipc4/base_fw.h b/src/include/ipc4/base_fw.h index ab98fad44160..2ae358010c2d 100644 --- a/src/include/ipc4/base_fw.h +++ b/src/include/ipc4/base_fw.h @@ -17,14 +17,18 @@ #ifndef __SOF_IPC4_BASE_FW_H__ #define __SOF_IPC4_BASE_FW_H__ -/* Three clk src states :low power XTAL, low power ring - * and high power ring oscillator +/* SOF FW performs autonomous management of clock sources. + * Set MAX_CLK_STATES to 0 in order to propagate this information through IPC and thus + * prevent reception of unsupported clock configuration. */ -#define IPC4_MAX_CLK_STATES 3 +#define IPC4_MAX_CLK_STATES 0 -/* Max src queue count count supported by ipc4 */ +/* Max src queue count supported by ipc4 */ #define IPC4_MAX_SRC_QUEUE 8 +/* Max dst queue count supported by ipc4 */ +#define IPC4_MAX_DST_QUEUE 8 + /* Max module instance for single module count supported by ipc4 */ #define IPC4_MAX_MODULE_INSTANCES 256 @@ -288,6 +292,12 @@ enum ipc4_basefw_params { /* Use LARGE_CONFIG_SET to change SDW ownership */ IPC4_SDW_OWNERSHIP = 31, + + /* This command is used by SW to notify FW for changing state of Mic Privacy */ + IPC4_MIC_PRIVACY_HW_MANAGED_STATE_CHANGE = 35, + + /* Set policy mask for mic privacy in FW managed mode */ + IPC4_SET_MIC_PRIVACY_FW_MANAGED_POLICY_MASK = 36, }; enum ipc4_fw_config_params { @@ -367,12 +377,30 @@ enum ipc4_fw_config_params { IPC4_DMI_FORCE_L1_EXIT = 28, /* FW context save on D3 entry */ IPC4_FW_CONTEXT_SAVE = 29, + /* Minimum size of host buffer in ms */ + IPC4_FW_MIN_HOST_BUFFER_PERIODS = 33, + /* decoder/encoder codec information */ + IPC4_FW_SOF_INFO = 35, /* Total number of FW config parameters */ IPC4_FW_CFG_PARAMS_COUNT, /* Max config parameter id */ IPC4_MAX_FW_CFG_PARAM = IPC4_FW_CFG_PARAMS_COUNT - 1, }; +/* + * tuple based array for SOF specific information under IPC4_FW_SOF_INFO + * tuple of fw_config + */ +enum ipc4_fw_sof_info_params { + /* decoder/encoder codec information */ + IPC4_SOF_CODEC_INFO = 0, + + /* Total number of SOF config parameters */ + IPC4_SOF_CFG_PARAMS_COUNT, + /* Max config parameter id */ + IPC4_MAX_SOF_CFG_PARAM = IPC4_SOF_CFG_PARAMS_COUNT - 1, +}; + enum ipc4_hw_config_params { /* Version of cAVS implemented by FW (from ROMInfo) */ IPC4_CAVS_VER_HW_CFG = 0, @@ -399,7 +427,9 @@ enum ipc4_hw_config_params { /* Size of a single memory bank (EBB) in bytes */ IPC4_EBB_SIZE_BYTES_HW_CFG = 9, /* UAOL capabilities */ - IPC4_UAOL_CAPS_HW_CFG = 10 + IPC4_UAOL_CAPS_HW_CFG = 10, + /* Mic privacy capabilities */ + IPC4_INTEL_MIC_PRIVACY_CAPS_HW_CFG = 11 }; enum ipc4_memory_type { diff --git a/src/include/ipc4/gateway.h b/src/include/ipc4/gateway.h index f78c21caf979..9398bb44be0e 100644 --- a/src/include/ipc4/gateway.h +++ b/src/include/ipc4/gateway.h @@ -162,8 +162,8 @@ struct ipc4_ipc_gateway_config_blob { uint32_t buffer_size; /**< Flags */ - union flags { - struct bits { + union { + struct { /**< Activates high threshold notification */ /*! * Indicates whether notification should be sent to the host diff --git a/src/include/ipc4/handler.h b/src/include/ipc4/handler.h new file mode 100644 index 000000000000..b25cb98e9427 --- /dev/null +++ b/src/include/ipc4/handler.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + */ + +#ifndef __SOF_IPC4_HANDLER_H__ +#define __SOF_IPC4_HANDLER_H__ + +struct ipc4_message_request; + +/** + * \brief Processes IPC4 userspace module message. + * @param[in] ipc4 IPC4 message request. + * @param[in] reply IPC message reply structure. + * @return IPC4_SUCCESS on success, error code otherwise. + */ +int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, struct ipc_msg *reply); + +/** + * \brief Processes IPC4 userspace global message. + * @param[in] ipc4 IPC4 message request. + * @param[in] reply IPC message reply structure. + * @return IPC4_SUCCESS on success, error code otherwise. + */ +int ipc4_user_process_glb_message(struct ipc4_message_request *ipc4, struct ipc_msg *reply); + +/** + * \brief Increment the IPC compound message pre-start counter. + * @param[in] msg_id IPC message ID. + */ +void ipc_compound_pre_start(int msg_id); + +/** + * \brief Decrement the IPC compound message pre-start counter on return value status. + * @param[in] msg_id IPC message ID. + * @param[in] ret Return value of the IPC command. + * @param[in] delayed True if the reply is delayed. + */ +void ipc_compound_post_start(uint32_t msg_id, int ret, bool delayed); + +/** + * \brief Complete the IPC compound message. + * @param[in] msg_id IPC message ID. + * @param[in] error Error code of the IPC command. + */ +void ipc_compound_msg_done(uint32_t msg_id, int error); + +/** + * \brief Wait for the IPC compound message to complete. + * @return 0 on success, error code otherwise on timeout. + */ +int ipc_wait_for_compound_msg(void); + +#endif /* __SOF_IPC4_HANDLER_H__ */ diff --git a/src/include/ipc4/header.h b/src/include/ipc4/header.h index 5abef50342b0..6a6eb59d02e5 100644 --- a/src/include/ipc4/header.h +++ b/src/include/ipc4/header.h @@ -88,9 +88,11 @@ enum ipc4_message_type { /**< Notification (FW to SW driver) */ SOF_IPC4_GLB_NOTIFICATION = 27, /* GAP HERE- DO NOT USE - size 3 (28 .. 30) */ + /**< Enter GDB stub to wait for commands in memory window */ + SOF_IPC4_GLB_ENTER_GDB = 31, /**< Maximum message number */ - SOF_IPC4_GLB_MAX_IXC_MESSAGE_TYPE = 31 + SOF_IPC4_GLB_MAX_IXC_MESSAGE_TYPE = 32 }; /** @@ -171,9 +173,11 @@ 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_SWITCH_CONTROL_PARAM_ID 200 +#define SOF_IPC4_ENUM_CONTROL_PARAM_ID 201 +#define SOF_IPC4_BYTES_CONTROL_PARAM_ID 202 #define SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL ((uint32_t)(0xA15A << 16)) +#define SOF_IPC4_NOTIFY_MODULE_EVENTID_COMPR_MAGIC_VAL ((uint32_t)(0xC0C0 << 16)) /** * struct sof_ipc4_ctrl_value_chan: generic channel mapped value data @@ -188,15 +192,19 @@ struct sof_ipc4_ctrl_value_chan { /** * 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 + * @num_elems: Number of elements in the chanv array or number of bytes in data * @reserved: reserved for future use, must be set to 0 * @chanv: channel ID and value array + * @data: binary payload */ struct sof_ipc4_control_msg_payload { uint16_t id; uint16_t num_elems; uint32_t reserved[4]; - struct sof_ipc4_ctrl_value_chan chanv[]; + union { + struct sof_ipc4_ctrl_value_chan chanv[0]; + uint8_t data[0]; + }; } __attribute((packed, aligned(4))); /** diff --git a/src/include/ipc4/module.h b/src/include/ipc4/module.h index 432d704fb2dd..4e60ebc9bc13 100644 --- a/src/include/ipc4/module.h +++ b/src/include/ipc4/module.h @@ -73,6 +73,29 @@ struct ipc4_vendor_error { uint32_t err_code; }; +/* IDs for all global object types in struct ipc4_module_init_ext_object */ +enum ipc4_mod_init_data_glb_id { + IPC4_MOD_INIT_DATA_ID_INVALID = 0, + IPC4_MOD_INIT_DATA_ID_DP_DATA = 1, + IPC4_MOD_INIT_DATA_ID_MODULE_DATA = 2, + IPC4_MOD_INIT_DATA_ID_MAX = IPC4_MOD_INIT_DATA_ID_MODULE_DATA, +}; + +/* data object for vendor bespoke data with ABI growth and backwards compat */ +struct ipc4_module_init_ext_object { + uint32_t last_object : 1; /* object is last in array if 1 else object follows. */ + uint32_t object_id : 15; /* unique ID for this object or globally */ + uint32_t object_words : 16; /* size in dwords (excluding this structure) */ +} __attribute__((packed, aligned(4))); +/* the object data will be placed in memory here and will have size "object_words" */ + +/* Ext init array data object for Data Processing module memory requirements */ +struct ipc4_module_init_ext_obj_dp_data { + uint32_t domain_id; /* userspace domain ID */ + uint32_t stack_bytes; /* required stack size in bytes */ + uint32_t heap_bytes; /* required heap size in bytes */ +} __attribute__((packed, aligned(4))); + /* * Host Driver sends this message to create a new module instance. */ @@ -83,7 +106,8 @@ struct ipc4_module_init_ext_init { /**< Indicates that GNA is used by a module and additional information */ /* (gna_config) is passed after ExtendedData. */ uint32_t gna_used : 1; - uint32_t rsvd_0 : 30; + uint32_t data_obj_array : 1; /* struct ipc4_module_init_ext_object data */ + uint32_t rsvd_0 : 29; uint32_t rsvd_1[2]; } __attribute__((packed, aligned(4))); @@ -225,6 +249,80 @@ struct ipc4_module_bind_unbind { } extension; } __attribute__((packed, aligned(4))); +/* + * Using Module Config Get / Set command, host driver may send a parameter + * that fits into the header (a very short one), packed along with parameter id. + * Larger parameters require fragmentation and a series of Large Config Set + * commands. + * + * param_id_data specifies both ID of the parameter, defined by the module + * and value of the parameter. + * It is up to the module how to distribute bits to ID and value of the parameter. + * If there are more bits required than available to value, then Input Data may + * be used to pass the value + * + * NOTE: Module Config Get/Set commands are used internally by the driver + * for small parameters defined by Intel components. While all externally + * developed components communicates with host using Large Config commands + * no matter what the size of parameter is. + */ +struct ipc4_module_config { + union { + uint32_t dat; + + struct { + uint32_t module_id : 16; /* module id */ + uint32_t instance_id : 8; /* instance id */ + /* SOF_IPC4_MOD_CONFIG_GET / SOF_IPC4_MOD_CONFIG_SET */ + uint32_t type : 5; + uint32_t rsp : 1; /* SOF_IPC4_MESSAGE_DIR_MSG_REQUEST */ + uint32_t msg_tgt : 1; /* SOF_IPC4_MESSAGE_TARGET_MODULE_MSG */ + uint32_t _reserved_0 : 1; + } r; + } primary; + + union { + uint32_t dat; + + struct { + /* Param id and data */ + uint32_t param_id_data : 30; + uint32_t _reserved_2 : 2; + } r; + } extension; +} __attribute__((packed, aligned(4))); + +/* + * Sent by FW in response to Module Config Get. + */ +struct ipc4_module_config_reply { + union { + uint32_t dat; + + struct { + uint32_t status : IPC4_IXC_STATUS_BITS; + uint32_t type : 5; /* SOF_IPC4_MOD_CONFIG_GET */ + uint32_t rsp : 1; /* SOF_IPC4_MESSAGE_DIR_MSG_REPLY */ + uint32_t msg_tgt : 1; /* SOF_IPC4_MESSAGE_TARGET_MODULE_MSG */ + uint32_t _reserved_0 : 1; + } r; + } primary; + + union { + uint32_t dat; + + struct { + /* + * Value of this field may be changed by the module + * if parameter value fits into the available bits, + * or stay intact if the value is copied to the Output Data. + */ + uint32_t param_id_data : 30; + uint32_t _reserved_2 : 2; + } r; + } extension; +} __attribute__((packed, aligned(4))); + struct ipc4_module_large_config { union { uint32_t dat; diff --git a/src/include/ipc4/notification.h b/src/include/ipc4/notification.h index 658cbcc50ce1..614a926d16ad 100644 --- a/src/include/ipc4/notification.h +++ b/src/include/ipc4/notification.h @@ -25,6 +25,7 @@ #include <stdint.h> #include <ipc/header.h> +#include <sof/ipc/msg.h> #include <sof/compiler_attributes.h> /* ipc4 notification msg */ @@ -37,7 +38,7 @@ enum sof_ipc4_notification_type { SOF_IPC4_FW_AUD_CLASS_RESULT = 9, SOF_IPC4_EXCEPTION_CAUGHT = 10, SOF_IPC4_MODULE_NOTIFICATION = 12, - SOF_IPC4_UAOL_RSVD_ = 13, + SOF_IPC4_UAOL_EVENT = 13, SOF_IPC4_PROBE_DATA_AVAILABLE = 14, SOF_IPC4_WATCHDOG_TIMEOUT = 15, SOF_IPC4_MANAGEMENT_SERVICE = 16, @@ -87,7 +88,7 @@ enum sof_ipc4_resource_event_type { /* SNDW debug notification e.g. external VAD detected */ SOF_IPC4_SNDW_DEBUG_INFO = 18, /* Invalid type */ - SOF_IPC4_INVALID_RESORUCE_EVENT_TYPE = 19, + SOF_IPC4_INVALID_RESOURCE_EVENT_TYPE = 19, }; /* Resource Type - source of the event */ @@ -113,12 +114,12 @@ enum sof_ipc4_resource_type { (((SOF_IPC4_NOTIFY_FW_READY) << (SOF_IPC4_GLB_NOTIFY_TYPE_SHIFT)) |\ ((SOF_IPC4_GLB_NOTIFICATION) << (SOF_IPC4_GLB_NOTIFY_MSG_TYPE_SHIFT))) +#define SOF_IPC4_FW_READY_LIB_RESTORED BIT(15) + #define SOF_IPC4_NOTIF_HEADER(notif_type) \ ((notif_type) << (SOF_IPC4_GLB_NOTIFY_TYPE_SHIFT) | \ ((SOF_IPC4_GLB_NOTIFICATION) << (SOF_IPC4_GLB_NOTIFY_MSG_TYPE_SHIFT))) -#endif - /** * \brief IPC MAJOR 4 notification header. All IPC4 notifications use this header. */ @@ -231,6 +232,31 @@ static inline void ipc4_notification_watchdog_init(struct ipc4_watchdog_timeout_ notif->primary.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG; } +/** + * \brief This notification is sent by a shim of module instance on error raised by data processing + * function. + * + * In case of 3rd party IP error_code is set to its native error code returned by the 3rd party + * library. + */ +struct ipc4_process_data_error_event_data { + /* Error code returned by data processing function */ + uint32_t error_code; +}; + +/** + * \brief This notification is sent by the mixer on stream underrun detection. The frequency of + * sending this notification by Mixer depends on the MixIn settings. + */ +struct ipc4_mixer_underrun_event_data { + /* Indicates EndOfStream */ + uint32_t eos_flag; + /* Data processed by module (in bytes) */ + uint32_t data_mixed; + /* Expected data to be processed (in bytes) */ + uint32_t expected_data_mixed; +}; + /** * \brief Input data payload is reserved field in parent technical spec which can be easily * extendable if needed by specific resource event types in the future. For backward compatibility @@ -239,6 +265,10 @@ static inline void ipc4_notification_watchdog_init(struct ipc4_watchdog_timeout_ union ipc4_resource_event_data { /* Raw data */ uint32_t dws[6]; + /* Process Data Error Data (res type = MODULE_INSTANCE) */ + struct ipc4_process_data_error_event_data process_data_error; + /* Mixer Underrun Detected Data (res type = PIPELINE) */ + struct ipc4_mixer_underrun_event_data mixer_underrun; }; struct ipc4_resource_event_data_notification { @@ -255,3 +285,16 @@ struct ipc4_resource_event_data_notification { /* Detailed event data */ union ipc4_resource_event_data event_data; } __packed __aligned(8); + +#define IPC4_RESOURCE_EVENT_SIZE sizeof(struct ipc4_resource_event_data_notification) + +void send_process_data_error_notif_msg(uint32_t resource_id, uint32_t error_code); + +bool send_copier_gateway_xrun_notif_msg(uint32_t pipeline_id, enum sof_ipc_stream_direction dir); +bool send_gateway_xrun_notif_msg(uint32_t resource_id, enum sof_ipc_stream_direction dir); + +void send_mixer_underrun_notif_msg(uint32_t resource_id, uint32_t eos_flag, uint32_t data_mixed, + uint32_t expected_data_mixed); +void ipc4_update_notification_mask(uint32_t ntfy_mask, uint32_t enabled_mask); + +#endif /* __IPC4_NOTIFICATION_H__ */ diff --git a/src/include/ipc4/pipeline.h b/src/include/ipc4/pipeline.h index 219c36a89a3d..1e85072fd15c 100644 --- a/src/include/ipc4/pipeline.h +++ b/src/include/ipc4/pipeline.h @@ -69,6 +69,39 @@ enum ipc4_pipeline_state { SOF_IPC4_PIPELINE_STATE_SAVED }; +/* IDs for all pipeline ext data types in struct ipc4_pipeline_init_ext_object */ +enum ipc4_pipeline_ext_obj_id { + IPC4_GLB_PIPE_EXT_OBJ_ID_INVALID = 0, + IPC4_GLB_PIPE_EXT_OBJ_ID_MEM_DATA = 1, + IPC4_GLB_PIPE_EXT_OBJ_ID_MAX = IPC4_GLB_PIPE_EXT_OBJ_ID_MEM_DATA, +}; + +/* data object for vendor bespoke data with ABI growth and backwards compat */ +struct ipc4_pipeline_ext_object { + uint32_t last_object : 1; /* object is last in array if 1 else object follows. */ + uint32_t object_id : 15; /* unique ID for this object or globally */ + uint32_t object_words : 16; /* size in dwords (excluding this structure) */ +} __packed __aligned(4); +/* the object data will be placed in memory here and will have size "object_words" */ + +/* Ext array data object for pipeline instance's memory requirements */ +struct ipc4_pipeline_ext_obj_mem_data { + uint32_t domain_id; /* userspace domain ID */ + uint32_t stack_bytes; /* required stack size in bytes */ + uint32_t heap_bytes; /* required heap size in bytes */ +} __packed __aligned(4); + +/* + * Host Driver sends this message to create a new pipeline instance. + */ +struct ipc4_pipeline_ext_payload { + uint32_t payload_words : 24; /* size in dwords (excluding this structure) */ + uint32_t data_obj_array : 1; /* struct ipc4_pipeline_ext_object data */ + uint32_t rsvd0 : 7; + uint32_t rsvd1; + uint32_t rsvd2; +} __packed __aligned(4); + /*! * lp - indicates whether the pipeline should be kept on running in low power * mode. On BXT the driver should set this flag to 1 for WoV pipeline. @@ -106,7 +139,8 @@ struct ipc4_pipeline_create { uint32_t rsvd1 : 3; uint32_t attributes : 16; uint32_t core_id : 4; - uint32_t rsvd2 : 6; + uint32_t rsvd2 : 5; + uint32_t payload : 1; uint32_t _reserved_2 : 2; } r; } extension; diff --git a/src/include/module/audio/audio_stream.h b/src/include/module/audio/audio_stream.h index f66fc414e865..e032ef322f85 100644 --- a/src/include/module/audio/audio_stream.h +++ b/src/include/module/audio/audio_stream.h @@ -13,6 +13,24 @@ #include <stdbool.h> #include "../ipc/stream.h" + +/** + * @enum sof_audio_buffer_state + * @brief Define states of an audio stream buffer connecting two components. + * + * This enum represents the lifecycle of an audio stream, including its + * initialization, readiness, and end-of-stream handling. It is used to + * track and manage the state transitions of the stream during audio processing. + */ +enum sof_audio_buffer_state { + AUDIOBUF_STATE_INITIAL, /* Initial state, hw params not configured. */ + AUDIOBUF_STATE_READY, /* Stream ready, hw params configured */ + AUDIOBUF_STATE_END_OF_STREAM, /* Detected End Of Stream */ + AUDIOBUF_STATE_END_OF_STREAM_FLUSH, /* Detected End Of Stream, generating silence + * to flush buffers in dp modules. + */ +}; + /** * set of parameters describing audio stream * this structure is shared between audio_stream.h and sink/source interface @@ -53,7 +71,7 @@ struct sof_audio_stream_params { uint16_t chmap[SOF_IPC_MAX_CHANNELS]; /**< channel map - SOF_CHMAP_ */ - bool hw_params_configured; /**< indicates whether hw params were set */ + enum sof_audio_buffer_state state; /**< audio stream state */ }; #endif /* __MODULE_AUDIO_AUDIO_STREAM_H__ */ diff --git a/src/include/module/audio/format.h b/src/include/module/audio/format.h index df6e58b4a9d5..7fccef12f49e 100644 --- a/src/include/module/audio/format.h +++ b/src/include/module/audio/format.h @@ -22,6 +22,8 @@ static inline uint32_t get_sample_bytes(enum sof_ipc_frame fmt) case SOF_IPC_FRAME_S24_3LE: return 3; case SOF_IPC_FRAME_U8: + case SOF_IPC_FRAME_A_LAW: + case SOF_IPC_FRAME_MU_LAW: return 1; default: return 4; @@ -37,6 +39,8 @@ static inline uint32_t get_sample_bitdepth(enum sof_ipc_frame fmt) case SOF_IPC_FRAME_S24_3LE: return 24; case SOF_IPC_FRAME_U8: + case SOF_IPC_FRAME_A_LAW: + case SOF_IPC_FRAME_MU_LAW: return 8; default: return 32; diff --git a/src/include/module/audio/sink_api.h b/src/include/module/audio/sink_api.h index 98129b229f17..920087d6f8b3 100644 --- a/src/include/module/audio/sink_api.h +++ b/src/include/module/audio/sink_api.h @@ -51,6 +51,7 @@ struct sof_sink; struct sof_audio_stream_params; struct sof_ipc_stream_params; +struct processing_module; /** * this is a definition of internals of sink API @@ -76,6 +77,12 @@ struct sink_ops { */ int (*commit_buffer)(struct sof_sink *sink, size_t commit_size); + /** + * get latest feeding time for this sink, result is a number of microseconds since "NOW" + * where "now" means a start of last LL cycle, as described in zephyr_dp_schedule.c + */ + uint32_t (*get_lft)(struct sof_sink *sink); + /** * OPTIONAL: Notification to the sink implementation about changes in audio format * @@ -101,6 +108,14 @@ struct sink_ops { int (*set_alignment_constants)(struct sof_sink *sink, const uint32_t byte_align, const uint32_t frame_align_req); + + /** + * OPTIONAL + * events called when a module is starting / finishing using of the API + * on the core that the module and API will executed on + */ + int (*on_bind)(struct sof_sink *sink, struct processing_module *module); + int (*on_unbind)(struct sof_sink *sink); }; /** internals of sink API. NOT TO BE MODIFIED OUTSIDE OF sink_api.c */ @@ -111,6 +126,7 @@ struct sof_sink { 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 processing_module *bound_module; /* a pointer module that is using sink API */ struct sof_audio_stream_params *audio_stream_params; /** pointer to audio params */ }; @@ -170,6 +186,44 @@ size_t sink_get_free_frames(struct sof_sink *sink); int sink_get_buffer(struct sof_sink *sink, size_t req_size, void **data_ptr, void **buffer_start, size_t *buffer_size); +/** + * Get a circular buffer to operate on (to write). + * + * Same as sink_get_buffer() except that the size of circular buffer is returned as + * 16 bit samples count. The returned samples count simplifies pointer arithmetic in a + * samples process function. The data pointers are int16_t type. + * + * @param sink a handler to sink + * @param [in] req_size requested size of space + * @param [out] data_ptr a pointer to the space will be provided there + * @param [out] buffer_start pointer to circular buffer start + * @param [out] buffer_samples number of s16 samples total in circular buffer + * + * @retval -ENODATA if req_size is bigger than free space + * + */ +int sink_get_buffer_s16(struct sof_sink *sink, size_t req_size, int16_t **data_ptr, + int16_t **buffer_start, int *buffer_samples); + +/** + * Get a circular buffer to operate on (to write). + * + * Same as sink_get_buffer() except that the size of circular buffer is returned as + * 32 bit samples count. The returned samples count simplifies pointer arithmetic in a + * samples process function. The data pointers are int32_t type. + * + * @param sink a handler to sink + * @param [in] req_size requested size of space + * @param [out] data_ptr a pointer to the space will be provided there + * @param [out] buffer_start pointer to circular buffer start + * @param [out] buffer_samples number of s32 samples total in circular buffer + * + * @retval -ENODATA if req_size is bigger than free space + * + */ +int sink_get_buffer_s32(struct sof_sink *sink, size_t req_size, int32_t **data_ptr, + int32_t **buffer_start, int *buffer_samples); + /** * Commits that the buffer previously obtained by get_buffer is filled with data * and ready to be used @@ -253,4 +307,56 @@ static inline uint32_t sink_get_pipeline_id(struct sof_sink *sink) return sink->audio_stream_params->pipeline_id; } +/** + * @brief hook to be called when a module connects to the API + * + * NOTE! it MUST be called at core that a module is bound to + */ +static inline int sink_bind(struct sof_sink *sink, struct processing_module *module) +{ + int ret = 0; + + if (sink->bound_module) + return -EBUSY; + + if (sink->ops->on_bind) + ret = sink->ops->on_bind(sink, module); + + if (!ret) + sink->bound_module = module; + + return ret; +} + +/** + * @brief hook to be called when a module disconnects from the API + * + * NOTE! it MUST be called at core that a module is bound to + */ +static inline int sink_unbind(struct sof_sink *sink) +{ + int ret = 0; + + if (!sink->bound_module) + return -EINVAL; + + if (sink->ops->on_unbind) + ret = sink->ops->on_unbind(sink); + + if (!ret) + sink->bound_module = NULL; + + return ret; +} + +static inline struct processing_module *sink_get_bound_module(struct sof_sink *sink) +{ + return sink->bound_module; +} + +static inline uint32_t sink_get_last_feeding_time(struct sof_sink *sink) +{ + return sink->ops->get_lft(sink); +} + #endif /* __MODULE_AUDIO_SINK_API_H__ */ diff --git a/src/include/module/audio/source_api.h b/src/include/module/audio/source_api.h index 0925fb251bd2..556dead4a583 100644 --- a/src/include/module/audio/source_api.h +++ b/src/include/module/audio/source_api.h @@ -51,6 +51,7 @@ struct sof_source; struct sof_audio_stream_params; struct sof_ipc_stream_params; +struct processing_module; /** * this is a definition of internals of source API @@ -101,6 +102,14 @@ struct source_ops { int (*set_alignment_constants)(struct sof_source *source, const uint32_t byte_align, const uint32_t frame_align_req); + + /** + * OPTIONAL + * events called when a module is starting / finishing using of the API + * on the core that the module and API will executed on + */ + int (*on_bind)(struct sof_source *source, struct processing_module *module); + int (*on_unbind)(struct sof_source *source); }; /** internals of source API. NOT TO BE MODIFIED OUTSIDE OF source_api.c */ @@ -112,7 +121,7 @@ struct sof_source { * source * it is module's IBS as declared in module bind IPC */ - + struct processing_module *bound_module; /* a pointer module that is using source API */ struct sof_audio_stream_params *audio_stream_params; }; @@ -184,6 +193,42 @@ size_t source_get_data_frames_available(struct sof_source *source); int source_get_data(struct sof_source *source, size_t req_size, void const **data_ptr, void const **buffer_start, size_t *buffer_size); +/** + * Retrieves a fragment of circular data (to read) + * + * Same as source_get_data() except that the size of circular buffer is returned as + * 16 bit samples count. The returned samples count simplifies pointer arithmetic in a + * samples process function. The data pointers are int16_t type. + * + * @param source a handler to source + * @param [in] req_size requested size of data. + * @param [out] data_ptr a pointer to data will be provided there + * @param [out] buffer_start pointer to circular buffer start + * @param [out] buffer_samples number of 16 bit samples total in circular buffer + * + * @retval -ENODATA if req_size is bigger than available data + */ +int source_get_data_s16(struct sof_source *source, size_t req_size, int16_t const **data_ptr, + int16_t const **buffer_start, int *buffer_samples); + +/** + * Retrieves a fragment of circular data (to read) + * + * Same as source_get_data() except that the size of circular buffer is returned as + * 32 bit samples count. The returned samples count simplifies pointer arithmetic in a + * samples process function. The data pointers are int32_t type. + * + * @param source a handler to source + * @param [in] req_size requested size of data. + * @param [out] data_ptr a pointer to data will be provided there + * @param [out] buffer_start pointer to circular buffer start + * @param [out] buffer_samples number of 32 bit samples total in circular buffer + * + * @retval -ENODATA if req_size is bigger than available data + */ +int source_get_data_s32(struct sof_source *source, size_t req_size, int32_t const **data_ptr, + int32_t const **buffer_start, int *buffer_samples); + /** * Releases fragment previously obtained by source_get_data() * Once called, the data are no longer available for the caller @@ -231,4 +276,56 @@ static inline uint32_t source_get_pipeline_id(struct sof_source *source) return source->audio_stream_params->pipeline_id; } +/** + * @brief hook to be called when a module connects to the API + * + * NOTE! it MUST be called at core that a module is bound to + */ +static inline int source_bind(struct sof_source *source, struct processing_module *module) +{ + int ret = 0; + + if (source->bound_module) + return -EBUSY; + + if (source->ops->on_bind) + ret = source->ops->on_bind(source, module); + + if (!ret) + source->bound_module = module; + + return ret; +} + +/** + * @brief hook to be called when a module disconnects from the API + * + * NOTE! it MUST be called at core that a module is bound to + */ +static inline int source_unbind(struct sof_source *source) +{ + int ret = 0; + + if (!source->bound_module) + return -EINVAL; + + if (source->ops->on_unbind) + ret = source->ops->on_unbind(source); + + if (!ret) + source->bound_module = NULL; + + return ret; +} + +static inline struct processing_module *source_get_bound_module(struct sof_source *source) +{ + return source->bound_module; +} + +static inline enum sof_audio_buffer_state source_get_state(const struct sof_source *source) +{ + return source->audio_stream_params->state; +} + #endif /* __MODULE_AUDIO_SOURCE_API_H__ */ diff --git a/src/include/module/crossover/crossover_common.h b/src/include/module/crossover/crossover_common.h index 6cd4acddf85d..d238ff7c1008 100644 --- a/src/include/module/crossover/crossover_common.h +++ b/src/include/module/crossover/crossover_common.h @@ -8,7 +8,8 @@ #ifndef __SOF_CROSSOVER_COMMON_H__ #define __SOF_CROSSOVER_COMMON_H__ -#include <sof/math/iir_df2t.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/math/iir_df1.h> #include <user/eq.h> /* Number of sinks for a 2 way crossover filter */ @@ -29,8 +30,8 @@ */ struct crossover_state { /* Store the state for each LR4 filter. */ - struct iir_state_df2t lowpass[CROSSOVER_MAX_LR4]; - struct iir_state_df2t highpass[CROSSOVER_MAX_LR4]; + struct iir_state_df1 lowpass[CROSSOVER_MAX_LR4]; + struct iir_state_df1 highpass[CROSSOVER_MAX_LR4]; }; typedef void (*crossover_split)(int32_t in, int32_t out[], @@ -39,17 +40,19 @@ typedef void (*crossover_split)(int32_t in, int32_t out[], extern const crossover_split crossover_split_fnmap[]; /* crossover init function */ -int crossover_init_coef_ch(struct sof_eq_iir_biquad *coef, +int crossover_init_coef_ch(struct processing_module *mod, + struct sof_eq_iir_biquad *coef, struct crossover_state *ch_state, int32_t num_sinks); /** * \brief Reset the state of an LR4 filter. */ -static inline void crossover_reset_state_lr4(struct iir_state_df2t *lr4) +static inline void crossover_reset_state_lr4(struct processing_module *mod, + struct iir_state_df1 *lr4) { - rfree(lr4->coef); - rfree(lr4->delay); + mod_free(mod, lr4->coef); + mod_free(mod, lr4->delay); lr4->coef = NULL; lr4->delay = NULL; @@ -59,13 +62,14 @@ static inline void crossover_reset_state_lr4(struct iir_state_df2t *lr4) * \brief Reset the state (coefficients and delay) of the crossover filter * of a single channel. */ -static inline void crossover_reset_state_ch(struct crossover_state *ch_state) +static inline void crossover_reset_state_ch(struct processing_module *mod, + struct crossover_state *ch_state) { int i; for (i = 0; i < CROSSOVER_MAX_LR4; i++) { - crossover_reset_state_lr4(&ch_state->lowpass[i]); - crossover_reset_state_lr4(&ch_state->highpass[i]); + crossover_reset_state_lr4(mod, &ch_state->lowpass[i]); + crossover_reset_state_lr4(mod, &ch_state->highpass[i]); } } diff --git a/src/include/module/ipc/stream.h b/src/include/module/ipc/stream.h index 4fbbb801689e..6e49d9f75cf2 100644 --- a/src/include/module/ipc/stream.h +++ b/src/include/module/ipc/stream.h @@ -22,7 +22,10 @@ enum sof_ipc_frame { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_U8, - SOF_IPC_FRAME_S16_4LE /* 16-bit in 32-bit container */ + SOF_IPC_FRAME_S16_4LE, /* 16-bit in 32-bit container */ + SOF_IPC_FRAME_A_LAW, + SOF_IPC_FRAME_MU_LAW, + SOF_IPC_FRAME_INVALID, /* keep last */ }; #endif /* __MODULE_IPC_STREAM_H__ */ diff --git a/src/include/module/ipc4/base-config.h b/src/include/module/ipc4/base-config.h index 0a535dd60be3..e5a5b49effd5 100644 --- a/src/include/module/ipc4/base-config.h +++ b/src/include/module/ipc4/base-config.h @@ -97,7 +97,9 @@ enum ipc4_sample_type { IPC4_TYPE_LSB_INTEGER = 1, /**< integer with Least Significant Byte first */ IPC4_TYPE_SIGNED_INTEGER = 2, IPC4_TYPE_UNSIGNED_INTEGER = 3, - IPC4_TYPE_FLOAT = 4 + IPC4_TYPE_FLOAT = 4, + IPC4_TYPE_A_LAW = 5, + IPC4_TYPE_MU_LAW = 6, }; enum ipc4_stream_type { diff --git a/src/include/module/module/api_ver.h b/src/include/module/module/api_ver.h index 680745f8c323..35aedb0305d7 100644 --- a/src/include/module/module/api_ver.h +++ b/src/include/module/module/api_ver.h @@ -21,7 +21,7 @@ #define SOF_MODULE_API_MAJOR_VERSION 5 #define SOF_MODULE_API_MIDDLE_VERSION 0 -#define SOF_MODULE_API_MINOR_VERSION 0 +#define SOF_MODULE_API_MINOR_VERSION 1 #define SOF_MODULE_API_CURRENT_VERSION MODULE_API_VERSION_ENCODE(SOF_MODULE_API_MAJOR_VERSION, \ SOF_MODULE_API_MIDDLE_VERSION, SOF_MODULE_API_MINOR_VERSION) diff --git a/src/include/module/module/base.h b/src/include/module/module/base.h index d3f912957791..8818ffb9f212 100644 --- a/src/include/module/module/base.h +++ b/src/include/module/module/base.h @@ -16,9 +16,27 @@ #include "interface.h" #include "../ipc4/base-config.h" +#ifdef SOF_MODULE_API_PRIVATE +#include <sof/list.h> +#endif + #define module_get_private_data(mod) ((mod)->priv.private) #define module_set_private_data(mod, data) ((mod)->priv.private = data) +/** + * \struct module_ext_init_data + * \brief Container for found ext init object pointers + * This struct contains pointers that point to IPC payload directly. The + * module should store what it needs in its init() callback as the data + * is not valid after that. + */ +struct ipc4_module_init_ext_obj_dp_data; +struct module_ext_init_data { + const struct ipc4_module_init_ext_obj_dp_data *dp_data; + const void *module_data; + size_t module_data_size; +}; + /** * \struct module_config * \brief Module config container, used for both config types. @@ -34,11 +52,10 @@ struct module_config { uint8_t nb_output_pins; struct ipc4_input_pin_format *input_pins; struct ipc4_output_pin_format *output_pins; + struct module_ext_init_data *ext_data; /**< IPC payload pointers, NULL after init() */ #endif }; -struct llext; - /* * A structure containing a module's private data, intended for its exclusive use. * @@ -58,9 +75,8 @@ struct module_data { enum module_state state; size_t new_cfg_size; /**< size of new module config data */ void *runtime_params; - struct module_memory memory; /**< memory allocated by module */ + struct module_resources resources; /**< resources allocated by module */ struct module_processing_data mpd; /**< shared data comp <-> module */ - struct llext *llext; /**< Zephyr loadable extension context */ #endif /* SOF_MODULE_PRIVATE */ }; @@ -70,6 +86,9 @@ enum module_processing_type { MODULE_PROCESS_TYPE_RAW, }; +struct userspace_context; +struct k_mem_domain; + /* * A pointer to this structure is passed to module API functions (from struct module_interface). * This structure should contain only fields that should be available to a module. @@ -86,7 +105,10 @@ struct processing_module { */ #ifdef SOF_MODULE_API_PRIVATE struct sof_ipc_stream_params *stream_params; - struct list_item sink_buffer_list; /* list of sink buffers to save produced output */ + /* list of sink buffers to save produced output, to be used in Raw data + * processing mode + */ + struct list_item raw_data_buffers_list; /* * This is a temporary change in order to support the trace messages in the modules. This @@ -101,8 +123,8 @@ struct processing_module { uint32_t num_of_sinks; /* sink and source handlers for the module */ - struct sof_sink *sinks[MODULE_MAX_SOURCES]; - struct sof_source *sources[MODULE_MAX_SOURCES]; + struct sof_sink *sinks[CONFIG_MODULE_MAX_CONNECTIONS]; + struct sof_source *sources[CONFIG_MODULE_MAX_CONNECTIONS]; /* this is used in case of raw data or audio_stream mode * number of buffers described by fields: @@ -177,6 +199,17 @@ struct processing_module { uint32_t max_sinks; enum module_processing_type proc_type; +#if CONFIG_USERSPACE + struct userspace_context *user_ctx; + struct k_mem_domain *mdom; +#endif /* CONFIG_USERSPACE */ + + /* total size of a fragmented runtime-params (get/set) transfer, kept + * per instance so concurrent transfers to different components do not + * corrupt each other's reassembly state. Appended here to avoid shifting + * the offsets of the fields above. + */ + uint32_t runtime_params_size; #endif /* SOF_MODULE_PRIVATE */ }; diff --git a/src/include/module/module/interface.h b/src/include/module/module/interface.h index 21332dd08898..26c176aee9b1 100644 --- a/src/include/module/module/interface.h +++ b/src/include/module/module/interface.h @@ -65,20 +65,44 @@ struct output_stream_buffer { struct processing_module; struct sof_source; struct sof_sink; +struct bind_info; +struct bind_info; + +/* + * This structure may be used by modules to carry short 16bit parameters. + */ +union config_param_id_data { + uint32_t dw; + struct { + uint32_t data16 : 16; /* Input/Output small config data */ + uint32_t id : 14; /* input parameter ID */ + uint32_t _rsvd : 2; + } f; +}; /** * \struct module_interface * \brief 3rd party processing module interface + * + * Module operations can be optimized for performance (default - no action) or + * for memory and power efficiency (opt in using __cold). It is recommended that + * module authors review their modules for non time sensitive code and mark it + * using __cold based on the descriptions below. This will ensure modules + * maintain peak performance and peak power/memory efficiency. Similarly cold + * read-only data can be marked with __cold_rodata. In cases where a subset of + * cold data has to be accessed from hot paths, it can be copied to fast memory, + * using the \c fast_get() API and then released using \c fast_put(). */ struct module_interface { /** * Module specific initialization procedure, called as part of - * module_adapter component creation in .new() + * module_adapter component creation in .new(). Usually can be __cold */ int (*init)(struct processing_module *mod); + /** * (optional) Module specific prepare procedure, called as part of module_adapter - * component preparation in .prepare() + * component preparation in .prepare(). Usually can be __cold */ int (*prepare)(struct processing_module *mod, struct sof_source **sources, int num_of_sources, @@ -97,7 +121,7 @@ struct module_interface { * at least IBS bytes of data on first source and at least OBS free space on first sink * * In case more sophisticated check is needed the method should be implemented in - * the module + * the module. Usually shouldn't be __cold */ bool (*is_ready_to_process)(struct processing_module *mod, struct sof_source **sources, int num_of_sources, @@ -121,6 +145,8 @@ struct module_interface { * process * - sources are handlers to source API struct source*[] * - sinks are handlers to sink API struct sink*[] + * + * Usually shouldn't be __cold */ int (*process)(struct processing_module *mod, struct sof_source **sources, int num_of_sources, @@ -134,6 +160,8 @@ struct module_interface { * - sinks[].data is a pointer to audio_stream structure * * It can be used by modules that support 1:1, 1:N, N:1 sources:sinks configuration. + * + * Usually shouldn't be __cold */ int (*process_audio_stream)(struct processing_module *mod, struct input_stream_buffer *input_buffers, @@ -147,6 +175,8 @@ struct module_interface { * - sources[].data is a pointer to raw audio data * - sinks are output_stream_buffer[] * - sinks[].data is a pointer to raw audio data + * + * Usually shouldn't be __cold */ int (*process_raw_data)(struct processing_module *mod, struct input_stream_buffer *input_buffers, @@ -154,6 +184,30 @@ struct module_interface { struct output_stream_buffer *output_buffers, int num_output_buffers); + /** + * (optional) Set module configuration parameter + * + * Using Module Config Set command, host driver may send a parameter + * that fits into the header (a very short one), packed along with parameter id. + * + * param_id_data specifies both ID of the parameter, defined by the module + * and value of the parameter. + * It is up to the module how to distribute bits to ID and value of the parameter. + */ + int (*set_config_param)(struct processing_module *mod, uint32_t param_id_data); + + /** + * (optional) Get module configuration parameter + * + * Using Module Config Get command, host driver may send a parameter + * that fits into the header (a very short one), packed along with parameter id. + * + * param_id_data specifies both ID of the parameter, defined by the module + * and value of the parameter. + * It is up to the module how to distribute bits to ID and value of the parameter. + */ + int (*get_config_param)(struct processing_module *mod, uint32_t *param_id_data); + /** * (optional) Set module configuration for the given configuration ID * @@ -162,7 +216,7 @@ struct module_interface { * In this case the ADSP System will perform multiple calls to SetConfiguration() until * completion of the configuration message sending. * \note config_id indicates ID of the configuration message only on the first fragment - * sending, otherwise it is set to 0. + * sending, otherwise it is set to 0. Usually can be __cold */ int (*set_configuration)(struct processing_module *mod, uint32_t config_id, @@ -178,7 +232,7 @@ struct module_interface { * In this case the ADSP System will perform multiple calls to GetConfiguration() until * completion of the configuration message retrieval. * \note config_id indicates ID of the configuration message only on the first fragment - * retrieval, otherwise it is set to 0. + * retrieval, otherwise it is set to 0. Usually can be __cold */ int (*get_configuration)(struct processing_module *mod, uint32_t config_id, uint32_t *data_offset_size, @@ -198,26 +252,35 @@ struct module_interface { /** * (optional) Module specific reset procedure, called as part of module_adapter component * reset in .reset(). This should reset all parameters to their initial stage - * and free all memory allocated during prepare(). + * and free all memory allocated during prepare(). Usually shouldn't be __cold since it's + * called from pipeline_reset() from ipc4_pipeline_trigger() */ int (*reset)(struct processing_module *mod); + /** * (optional) Module specific free procedure, called as part of module_adapter component * free in .free(). This should free all memory allocated during module initialization. + * Usually can be __cold */ int (*free)(struct processing_module *mod); + /** - * (optional) Module specific bind procedure, called when modules are bound with each other + * (optional) Module specific bind procedure, called when modules are bound with each other. + * Usually can be __cold */ - int (*bind)(struct processing_module *mod, void *data); + int (*bind)(struct processing_module *mod, struct bind_info *bind_data); + /** * (optional) Module specific unbind procedure, called when modules are disconnected from - * one another + * one another. Usually can be __cold */ - int (*unbind)(struct processing_module *mod, void *data); + int (*unbind)(struct processing_module *mod, struct bind_info *unbind_data); /** - * (optional) Module specific trigger procedure, called when modules are triggered + * (optional) Module specific trigger procedure, called when modules are triggered. Usually + * shouldn't be __cold. If a module implements this method, even if it only handles + * commands, running in non-LL context, it will still be called from the high priority + * LL context, which will cause a short jump to DRAM to check for supported commands. */ int (*trigger)(struct processing_module *mod, int cmd); diff --git a/src/include/module/module/llext.h b/src/include/module/module/llext.h index 05b8f0ffb5f5..2ef0d47d77cc 100644 --- a/src/include/module/module/llext.h +++ b/src/include/module/module/llext.h @@ -6,26 +6,33 @@ #ifndef MODULE_LLEXT_H #define MODULE_LLEXT_H -#define SOF_LLEXT_MODULE_MANIFEST(manifest_name, entry, affinity, mod_uuid, instances) \ +#define SOF_LLEXT_MODULE_MANIFEST(manifest_name, entry, affinity, mod_uuid, instances, ...) \ { \ .module = { \ .name = manifest_name, \ - .uuid = {mod_uuid}, \ + .uuid = mod_uuid, \ .entry_point = (uint32_t)(entry), \ .instance_max_count = instances, \ .type = { \ .load_type = SOF_MAN_MOD_TYPE_LLEXT, \ .domain_ll = 1, \ + .user_mode = COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), (0), \ + (GET_ARG_N(1, __VA_ARGS__))), \ }, \ .affinity_mask = (affinity), \ } \ } -#define SOF_LLEXT_MOD_ENTRY(name, interface) \ -static const struct module_interface *name##_llext_entry(void *mod_cfg, \ - void *parent_ppl, void **mod_ptr) \ +#define SOF_LLEXT_AUX_MANIFEST(manifest_name, entry, mod_uuid) \ { \ - return interface; \ + .module = { \ + .name = manifest_name, \ + .uuid = mod_uuid, \ + .entry_point = (uint32_t)(entry), \ + .type = { \ + .load_type = SOF_MAN_MOD_TYPE_LLEXT_AUX, \ + }, \ + } \ } #define SOF_LLEXT_BUILDINFO \ diff --git a/src/include/sof/audio/audio_buffer.h b/src/include/sof/audio/audio_buffer.h index 4984c3dee99a..95317e5dc964 100644 --- a/src/include/sof/audio/audio_buffer.h +++ b/src/include/sof/audio/audio_buffer.h @@ -21,8 +21,8 @@ struct sof_audio_buffer; struct audio_buffer_ops { /** * @brief this method must free all structures allocated by buffer implementation - * it must not free the buffer memory itself - * OPTIONAL + * and the buffer itself + * OBLIGATORY */ void (*free)(struct sof_audio_buffer *buffer); @@ -60,6 +60,7 @@ struct audio_buffer_ops { const uint32_t frame_align_req); }; +struct mod_alloc_ctx; /* base class for all buffers, all buffers must inherit from it */ struct sof_audio_buffer { CORE_CHECK_STRUCT_FIELD; @@ -110,6 +111,8 @@ struct sof_audio_buffer { * should not be in struct sof_audio_buffer at all, kept for pipeline2.0 transition */ bool walking; /**< indicates if the buffer is being walked */ + + struct mod_alloc_ctx *alloc; }; #if CONFIG_PIPELINE_2_0 @@ -214,17 +217,34 @@ static inline bool audio_buffer_is_shared(struct sof_audio_buffer *buffer) static inline bool audio_buffer_hw_params_configured(struct sof_audio_buffer *buffer) { - return buffer->audio_stream_params->hw_params_configured; + return buffer->audio_stream_params->state != AUDIOBUF_STATE_INITIAL; } static inline void audio_buffer_set_hw_params_configured(struct sof_audio_buffer *buffer) { - buffer->audio_stream_params->hw_params_configured = true; + buffer->audio_stream_params->state = AUDIOBUF_STATE_READY; } static inline void audio_buffer_reset_params(struct sof_audio_buffer *buffer) { - buffer->audio_stream_params->hw_params_configured = false; + buffer->audio_stream_params->state = AUDIOBUF_STATE_INITIAL; +} + +static inline enum sof_audio_buffer_state audio_buffer_get_state( + const struct sof_audio_buffer *buffer) +{ + return buffer->audio_stream_params->state; +} + +static inline void audio_buffer_set_state(struct sof_audio_buffer *buffer, + enum sof_audio_buffer_state state) +{ + buffer->audio_stream_params->state = state; +} + +static inline void audio_buffer_set_eos(struct sof_audio_buffer *buffer) +{ + buffer->audio_stream_params->state = AUDIOBUF_STATE_END_OF_STREAM; } static inline uint16_t audio_buffer_get_chmap(struct sof_audio_buffer *buffer, size_t index) @@ -287,7 +307,7 @@ static inline struct sof_audio_buffer *sof_audio_buffer_from_source(struct sof_s * audio_buffer_ops operations */ void audio_buffer_init(struct sof_audio_buffer *buffer, uint32_t buffer_type, bool is_shared, - struct source_ops *source_ops, struct sink_ops *sink_ops, + const struct source_ops *source_ops, const struct sink_ops *sink_ops, const struct audio_buffer_ops *audio_buffer_ops, struct sof_audio_stream_params *audio_stream_params); @@ -305,6 +325,29 @@ void audio_buffer_reset(struct sof_audio_buffer *buffer) { if (buffer->ops->reset) buffer->ops->reset(buffer); + +#if CONFIG_PIPELINE_2_0 + if (buffer->secondary_buffer_sink && buffer->secondary_buffer_sink->ops->reset) + buffer->secondary_buffer_sink->ops->reset(buffer->secondary_buffer_sink); + + if (buffer->secondary_buffer_source && buffer->secondary_buffer_source->ops->reset) + buffer->secondary_buffer_source->ops->reset(buffer->secondary_buffer_source); +#endif } +/* Audio-buffer wrappers for the source-sink API */ +int audio_buffer_source_set_ipc_params(struct sof_source *source, + struct sof_ipc_stream_params *params, bool force_update); +int audio_buffer_source_on_audio_format_set(struct sof_source *source); +int audio_buffer_source_set_alignment_constants(struct sof_source *source, + const uint32_t byte_align, + const uint32_t frame_align_req); +int audio_buffer_sink_set_ipc_params(struct sof_sink *sink, struct sof_ipc_stream_params *params, + bool force_update); +int audio_buffer_sink_on_audio_format_set(struct sof_sink *sink); +int audio_buffer_sink_set_alignment_constants(struct sof_sink *sink, + const uint32_t byte_align, + const uint32_t frame_align_req); +uint32_t audio_buffer_sink_get_lft(struct sof_sink *sink); + #endif /* __SOF_AUDIO_BUFFER__ */ diff --git a/src/include/sof/audio/audio_stream.h b/src/include/sof/audio/audio_stream.h index f930c7af3d8a..5c6f15392800 100644 --- a/src/include/sof/audio/audio_stream.h +++ b/src/include/sof/audio/audio_stream.h @@ -20,6 +20,7 @@ #include <sof/compiler_attributes.h> #include <rtos/panic.h> #include <sof/math/numbers.h> +#include <sof/lib/dma.h> #include <rtos/alloc.h> #include <rtos/cache.h> #include <ipc/stream.h> @@ -65,6 +66,15 @@ struct audio_stream { struct sof_audio_stream_params runtime_stream_params; }; +/* A pointer to data in a ring buffer. Just for convenience to reduce the number of typical + * processing function parameters: e.g., just 3 parameters (in, out ptr, and size) instead of 7. + */ +struct cir_buf_ptr { + void *buf_start; + void *buf_end; + void *ptr; +}; + void audio_stream_recalc_align(struct audio_stream *stream); static inline void *audio_stream_get_rptr(const struct audio_stream *buf) @@ -590,9 +600,55 @@ audio_stream_avail_frames(const struct audio_stream *source, } /** - * Computes maximum number of frames aligned that can be copied from - * source buffer to sink buffer, verifying number of available source - * frames vs. free space available in sink. + * Rounds down a frame count to meet the alignment constraint of the stream. + * @param stream Audio stream with alignment requirements set. + * @param frames Frame count to round down. + * @return Largest aligned frame count less than or equal to frames. + */ +static inline uint32_t audio_stream_align_frames_round_down(const struct audio_stream *stream, + uint32_t frames) +{ + uint16_t align = stream->runtime_stream_params.align_frame_cnt; + + return ROUND_DOWN(frames, align); +} + +/** + * Rounds up a frame count to meet the alignment constraint of the stream. + * @param stream Audio stream with alignment requirements set. + * @param frames Frame count to round up. + * @return Smallest aligned frame count greater than or equal to frames. + */ +static inline uint32_t audio_stream_align_frames_round_up(const struct audio_stream *stream, + uint32_t frames) +{ + uint16_t align = stream->runtime_stream_params.align_frame_cnt; + uint32_t aligned_frames = ROUND_DOWN(frames, align); + + if (aligned_frames < frames) + aligned_frames += align; + + return aligned_frames; +} + +/** + * Rounds to nearest a frame count to meet the alignment constraint of the stream. + * @param stream Audio stream with alignment requirements set. + * @param frames Frame count to round to nearest. + * @return Aligned frame count. + */ +static inline uint32_t audio_stream_align_frames_round_nearest(const struct audio_stream *stream, + uint32_t frames) +{ + uint16_t align = stream->runtime_stream_params.align_frame_cnt; + + return ROUND_DOWN(frames + (align >> 1), align); +} + +/** + * Computes maximum number of frames aligned with source align criteria + * that can be copied from source buffer to sink buffer, verifying number + * of available source frames vs. free space available in sink. * @param source Buffer of source. * @param sink Buffer of sink. * @return Number of frames. @@ -601,14 +657,11 @@ static inline uint32_t 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) * - source->runtime_stream_params.align_frame_cnt; - uint32_t sink_frames = (audio_stream_get_free_bytes(sink) >> - sink->runtime_stream_params.align_shift_idx) * - sink->runtime_stream_params.align_frame_cnt; + uint32_t src_frames = audio_stream_get_avail_frames(source); + uint32_t sink_frames = audio_stream_get_free_frames(sink); + uint32_t n = MIN(src_frames, sink_frames); - return MIN(src_frames, sink_frames); + return audio_stream_align_frames_round_down(source, n); } /** @@ -661,6 +714,35 @@ static inline void audio_stream_consume(struct audio_stream *buffer, uint32_t by buffer->free = buffer->size - buffer->avail; } +#ifdef __ZEPHYR__ +/** + * Replicates the hardware state of the DMA buffer as a struct audio_stream. + * @param stream Stream to update. + * @param dma_status DMA buffer hardware state (struct dma_status from Zephyr). + */ +static inline void audio_stream_sync_to_hw(struct audio_stream *stream, + const struct dma_status *dma_status) +{ + uintptr_t buf_start = (uintptr_t)audio_stream_get_addr(stream); + + /* Note: It is assumed here that dma_status values are reported as bytes. However, + * this is actually platform-specific. Although unlikely, they could be, for example, + * words on some particular platform, and changes should be made here to address + * such case. + */ + + assert(dma_status->write_position < audio_stream_get_size(stream)); + assert(dma_status->read_position < audio_stream_get_size(stream)); + assert(dma_status->pending_length <= audio_stream_get_size(stream)); + assert(dma_status->free <= audio_stream_get_size(stream)); + + audio_stream_set_wptr(stream, (void *)(buf_start + dma_status->write_position)); + audio_stream_set_rptr(stream, (void *)(buf_start + dma_status->read_position)); + audio_stream_set_avail(stream, dma_status->pending_length); + audio_stream_set_free(stream, dma_status->free); +} +#endif /* __ZEPHYR__ */ + /** * Resets the buffer. * @param buffer Buffer to reset. @@ -977,40 +1059,74 @@ static inline void cir_buf_set_zero(void *ptr, void *buf_addr, void *buf_end, ui memset(buf_addr, 0, tail_size); } -static inline void audio_stream_fmt_conversion(enum ipc4_bit_depth depth, - enum ipc4_bit_depth valid, - enum sof_ipc_frame *frame_fmt, - enum sof_ipc_frame *valid_fmt, - enum ipc4_sample_type type) +static inline int audio_stream_fmt_conversion(enum ipc4_bit_depth depth, + enum ipc4_bit_depth valid, + enum sof_ipc_frame *frame_fmt, + enum sof_ipc_frame *valid_fmt, + enum ipc4_sample_type type) { - /* IPC4_DEPTH_16BIT (16) <---> SOF_IPC_FRAME_S16_LE (0) - * IPC4_DEPTH_24BIT (24) <---> SOF_IPC_FRAME_S24_4LE (1) - * IPC4_DEPTH_32BIT (32) <---> SOF_IPC_FRAME_S32_LE (2) - */ - *frame_fmt = (enum sof_ipc_frame)((depth >> 3) - 2); - *valid_fmt = (enum sof_ipc_frame)((valid >> 3) - 2); - -#ifdef CONFIG_FORMAT_U8 - if (depth == 8) - *frame_fmt = SOF_IPC_FRAME_U8; - - if (valid == 8) - *valid_fmt = SOF_IPC_FRAME_U8; -#endif /* CONFIG_FORMAT_U8 */ - - if (valid == 24) { + int ret = -EINVAL; + *frame_fmt = SOF_IPC_FRAME_INVALID; + *valid_fmt = SOF_IPC_FRAME_INVALID; + + switch (type) { + case IPC4_TYPE_FLOAT: +#ifdef CONFIG_FORMAT_FLOAT + if (depth == 32 && valid == 32) { + *frame_fmt = SOF_IPC_FRAME_FLOAT; + *valid_fmt = SOF_IPC_FRAME_FLOAT; + ret = 0; + } +#endif + break; + case IPC4_TYPE_MSB_INTEGER: + case IPC4_TYPE_LSB_INTEGER: + case IPC4_TYPE_SIGNED_INTEGER: + if (depth == 24 && valid == 24) { #ifdef CONFIG_FORMAT_S24_3LE - if (depth == 24) { *frame_fmt = SOF_IPC_FRAME_S24_3LE; *valid_fmt = SOF_IPC_FRAME_S24_3LE; + ret = 0; +#endif + } else { + /* IPC4_DEPTH_16BIT (16) <---> SOF_IPC_FRAME_S16_LE (0) + * IPC4_DEPTH_24BIT (24) <---> SOF_IPC_FRAME_S24_4LE (1) + * IPC4_DEPTH_32BIT (32) <---> SOF_IPC_FRAME_S32_LE (2) + */ + *frame_fmt = (enum sof_ipc_frame)((depth >> 3) - 2); + *valid_fmt = (enum sof_ipc_frame)((valid >> 3) - 2); + ret = 0; + } + break; + case IPC4_TYPE_UNSIGNED_INTEGER: +#ifdef CONFIG_FORMAT_U8 + if (depth == 8 && valid == 8) { + *frame_fmt = SOF_IPC_FRAME_U8; + *valid_fmt = SOF_IPC_FRAME_U8; + ret = 0; + } +#endif /* CONFIG_FORMAT_U8 */ + break; + case IPC4_TYPE_A_LAW: +#ifdef CONFIG_FORMAT_A_LAW + if (depth == 8 && valid == 8) { + *frame_fmt = SOF_IPC_FRAME_A_LAW; + *valid_fmt = SOF_IPC_FRAME_A_LAW; + ret = 0; } #endif + break; + case IPC4_TYPE_MU_LAW: +#ifdef CONFIG_FORMAT_MU_LAW + if (depth == 8 && valid == 8) { + *frame_fmt = SOF_IPC_FRAME_MU_LAW; + *valid_fmt = SOF_IPC_FRAME_MU_LAW; + ret = 0; + } +#endif + break; } - - if (type == IPC4_TYPE_FLOAT && depth == 32) { - *frame_fmt = SOF_IPC_FRAME_FLOAT; - *valid_fmt = SOF_IPC_FRAME_FLOAT; - } + return ret; } /** @}*/ diff --git a/src/include/sof/audio/buffer.h b/src/include/sof/audio/buffer.h index eafe9d1cd190..517f229e5420 100644 --- a/src/include/sof/audio/buffer.h +++ b/src/include/sof/audio/buffer.h @@ -16,7 +16,6 @@ #include <rtos/panic.h> #include <rtos/alloc.h> #include <rtos/cache.h> -#include <sof/lib/uuid.h> #include <sof/list.h> #include <sof/coherent.h> #include <sof/math/numbers.h> @@ -33,6 +32,7 @@ #include <stdint.h> struct comp_dev; +struct buffer_cb_transact; /** \name Trace macros * @{ @@ -117,6 +117,10 @@ extern struct tr_ctx buffer_tr; #define BUFF_PARAMS_RATE BIT(2) #define BUFF_PARAMS_CHANNELS BIT(3) +/* buffer usage */ +#define BUFFER_USAGE_SHARED true /* buffer used by multiple DSP core and/or HW blocks */ +#define BUFFER_USAGE_NOT_SHARED false /* buffer only used by one HW block */ + /* * audio component buffer - connects 2 audio components together in pipeline. * @@ -130,7 +134,7 @@ struct comp_buffer { struct audio_stream stream; /* configuration */ - uint32_t caps; + uint32_t flags; uint32_t core; struct tr_ctx tctx; /* trace settings */ @@ -141,6 +145,18 @@ struct comp_buffer { /* lists */ struct list_item source_list; /* list in comp buffers */ struct list_item sink_list; /* list in comp buffers */ + + /* list of buffers, to be used i.e. in raw data processing mode*/ + struct list_item buffers_list; + +#if CONFIG_PROBE + /** probe produce callback, called on buffer produce */ + void (*probe_cb_produce)(void *arg, struct buffer_cb_transact *cb_data); + /** probe free callback, called on buffer free */ + void (*probe_cb_free)(void *arg); + /** opaque argument passed to probe callbacks */ + void *probe_cb_arg; +#endif }; /* @@ -159,21 +175,35 @@ static inline struct comp_dev *comp_buffer_get_sink_component(const struct comp_ return buffer->sink; } -/* Only to be used for synchronous same-core notifications! */ +static inline +void comp_buffer_set_source_component(struct comp_buffer *buffer, struct comp_dev *comp) +{ + buffer->source = comp; +} + +static inline +void comp_buffer_set_sink_component(struct comp_buffer *buffer, struct comp_dev *comp) +{ + buffer->sink = comp; +} + +static inline void comp_buffer_reset_source_list(struct comp_buffer *buffer) +{ + list_init(&buffer->source_list); +} + +static inline void comp_buffer_reset_sink_list(struct comp_buffer *buffer) +{ + list_init(&buffer->sink_list); +} + +/* Used as parameter for probe produce callback */ struct buffer_cb_transact { struct comp_buffer *buffer; uint32_t transaction_amount; void *transaction_begin_address; }; -struct buffer_cb_free { - struct comp_buffer *buffer; -}; - -#define buffer_comp_list(buffer, dir) \ - ((dir) == PPL_DIR_DOWNSTREAM ? &buffer->source_list : \ - &buffer->sink_list) - #define buffer_from_list(ptr, dir) \ ((dir) == PPL_DIR_DOWNSTREAM ? \ container_of(ptr, struct comp_buffer, source_list) : \ @@ -186,12 +216,16 @@ struct buffer_cb_free { buffer->cb_type = type; \ } while (0) +struct mod_alloc_ctx; + /* pipeline buffer creation and destruction */ -struct comp_buffer *buffer_alloc(size_t size, uint32_t caps, uint32_t flags, uint32_t align, - bool is_shared); -struct comp_buffer *buffer_alloc_range(size_t preferred_size, size_t minimum_size, uint32_t caps, +struct comp_buffer *buffer_alloc(struct mod_alloc_ctx *alloc, size_t size, uint32_t flags, + uint32_t align, bool is_shared); +struct comp_buffer *buffer_alloc_range(struct mod_alloc_ctx *alloc, size_t preferred_size, + size_t minimum_size, uint32_t flags, uint32_t align, bool is_shared); -struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc, bool is_shared); +struct comp_buffer *buffer_new(struct mod_alloc_ctx *alloc, const struct sof_ipc_buffer *desc, + bool is_shared); int buffer_set_size(struct comp_buffer *buffer, uint32_t size, uint32_t alignment); int buffer_set_size_range(struct comp_buffer *buffer, size_t preferred_size, size_t minimum_size, @@ -255,8 +289,11 @@ static inline void buffer_stream_writeback(struct comp_buffer *buffer, uint32_t * really be the head of the list, not a list head within another buffer. We * don't synchronise its cache, so it must not be embedded in an object, using * the coherent API. The caller takes care to protect list heads. + * + * Returns -EINVAL if the buffer is already linked in this direction + * (re-attaching would create a self-loop and corrupt the list). */ -void buffer_attach(struct comp_buffer *buffer, struct list_item *head, int dir); +int buffer_attach(struct comp_buffer *buffer, struct list_item *head, int dir); /* * Detach a buffer from anywhere in the list. "head" is again the head of the diff --git a/src/include/sof/audio/cadence/mp3_enc/xa_mp3_enc_api.h b/src/include/sof/audio/cadence/mp3_enc/xa_mp3_enc_api.h new file mode 100644 index 000000000000..aac961e63cf9 --- /dev/null +++ b/src/include/sof/audio/cadence/mp3_enc/xa_mp3_enc_api.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022-2025 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. + */ + + + +#ifndef __XA_MP3ENC_CONFIG_PARAMS_H__ +#define __XA_MP3ENC_CONFIG_PARAMS_H__ + +/* mp3_enc-specific configuration parameters */ +enum xa_config_param_mp3_enc { + XA_MP3ENC_CONFIG_PARAM_PCM_WDSZ = 0, + XA_MP3ENC_CONFIG_PARAM_SAMP_FREQ = 1, + XA_MP3ENC_CONFIG_PARAM_NUM_CHANNELS = 2, + XA_MP3ENC_CONFIG_PARAM_BITRATE = 3 +#ifdef ENABLE_CUT_OFF_FREQ_CONFIG + , XA_MP3ENC_CONFIG_FATAL_FRAC_BANDWIDTH = 4 +#endif // ENABLE_CUT_OFF_FREQ_CONFIG +}; + +/* commands */ +#include "xa_apicmd_standards.h" + +/* mp3_enc-specific commands */ +/* (none) */ + +/* mp3_enc-specific command types */ +/* (none) */ + +/* error codes */ +#include "xa_error_standards.h" + +#define XA_CODEC_MP3_ENC 2 + +/* mp3_enc-specific error_codes */ +/*****************************************************************************/ +/* Class 0: API Errors */ +/*****************************************************************************/ +/* Nonfatal Errors */ +/* (none) */ +/* Fatal Errors */ +/* (none) */ + +/*****************************************************************************/ +/* Class 1: Configuration Errors */ +/*****************************************************************************/ +/* Nonfatal Errors */ +enum xa_error_nonfatal_config_mp3_enc { + XA_MP3ENC_CONFIG_NONFATAL_INVALID_BITRATE = XA_ERROR_CODE(xa_severity_nonfatal, xa_class_config, XA_CODEC_MP3_ENC, 0) +}; + +/* Fatal Errors */ +enum xa_error_fatal_config_mp3_enc { + XA_MP3ENC_CONFIG_FATAL_SAMP_FREQ = XA_ERROR_CODE(xa_severity_fatal, xa_class_config, XA_CODEC_MP3_ENC, 0), + XA_MP3ENC_CONFIG_FATAL_NUM_CHANNELS = XA_ERROR_CODE(xa_severity_fatal, xa_class_config, XA_CODEC_MP3_ENC, 1), + XA_MP3ENC_CONFIG_FATAL_PCM_WDSZ = XA_ERROR_CODE(xa_severity_fatal, xa_class_config, XA_CODEC_MP3_ENC, 2) +#ifdef ENABLE_CUT_OFF_FREQ_CONFIG + , XA_MP3ENC_CONFIG_PARAM_FRAC_BANDWIDTH = XA_ERROR_CODE(xa_severity_fatal, xa_class_config, XA_CODEC_MP3_ENC, 3) +#endif // ENABLE_CUT_OFF_FREQ_CONFIG +}; +/* (none) */ + +#include "xa_type_def.h" + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ +xa_codec_func_t xa_mp3_enc; +#if defined(__cplusplus) +} +#endif /* __cplusplus */ +#endif /* __XA_MP3ENC_CONFIG_PARAMS_H__ */ diff --git a/src/include/sof/audio/coefficients/fft/twiddle_3072_32.h b/src/include/sof/audio/coefficients/fft/twiddle_3072_32.h new file mode 100644 index 000000000000..3024c7b49cff --- /dev/null +++ b/src/include/sof/audio/coefficients/fft/twiddle_3072_32.h @@ -0,0 +1,4120 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + */ + +/* Twiddle factors in Q1.31 format */ + +#ifndef __INCLUDE_TWIDDLE_3072_32_H__ +#define __INCLUDE_TWIDDLE_3072_32_H__ + +#include <stdint.h> + +#define FFT_MULTI_TWIDDLE_SIZE 2048 + +/* in Q1.31, generated from cos(i * 2 * pi / FFT_SIZE_MAX) */ +const int32_t multi_twiddle_real_32[FFT_MULTI_TWIDDLE_SIZE] = { + 2147483647, + 2147479156, + 2147465681, + 2147443222, + 2147411780, + 2147371355, + 2147321946, + 2147263555, + 2147196181, + 2147119825, + 2147034487, + 2146940167, + 2146836866, + 2146724584, + 2146603322, + 2146473080, + 2146333858, + 2146185658, + 2146028480, + 2145862324, + 2145687192, + 2145503083, + 2145310000, + 2145107942, + 2144896910, + 2144676905, + 2144447929, + 2144209982, + 2143963065, + 2143707180, + 2143442326, + 2143168506, + 2142885721, + 2142593971, + 2142293258, + 2141983583, + 2141664948, + 2141337354, + 2141000801, + 2140655293, + 2140300829, + 2139937412, + 2139565043, + 2139183723, + 2138793455, + 2138394240, + 2137986079, + 2137568974, + 2137142927, + 2136707940, + 2136264015, + 2135811153, + 2135349356, + 2134878626, + 2134398966, + 2133910377, + 2133412861, + 2132906420, + 2132391057, + 2131866773, + 2131333572, + 2130791454, + 2130240422, + 2129680480, + 2129111628, + 2128533869, + 2127947206, + 2127351642, + 2126747178, + 2126133817, + 2125511562, + 2124880416, + 2124240380, + 2123591458, + 2122933653, + 2122266967, + 2121591402, + 2120906963, + 2120213651, + 2119511470, + 2118800422, + 2118080511, + 2117351739, + 2116614110, + 2115867626, + 2115112291, + 2114348108, + 2113575080, + 2112793210, + 2112002502, + 2111202959, + 2110394584, + 2109577380, + 2108751352, + 2107916502, + 2107072834, + 2106220352, + 2105359059, + 2104488958, + 2103610054, + 2102722350, + 2101825849, + 2100920556, + 2100006474, + 2099083608, + 2098151960, + 2097211535, + 2096262337, + 2095304370, + 2094337637, + 2093362143, + 2092377892, + 2091384888, + 2090383135, + 2089372638, + 2088353400, + 2087325426, + 2086288720, + 2085243286, + 2084189130, + 2083126254, + 2082054665, + 2080974365, + 2079885360, + 2078787655, + 2077681253, + 2076566160, + 2075442379, + 2074309917, + 2073168777, + 2072018965, + 2070860485, + 2069693342, + 2068517540, + 2067333086, + 2066139983, + 2064938237, + 2063727853, + 2062508835, + 2061281190, + 2060044922, + 2058800036, + 2057546537, + 2056284431, + 2055013723, + 2053734418, + 2052446522, + 2051150040, + 2049844978, + 2048531340, + 2047209133, + 2045878362, + 2044539032, + 2043191150, + 2041834720, + 2040469748, + 2039096241, + 2037714204, + 2036323642, + 2034924562, + 2033516969, + 2032100869, + 2030676269, + 2029243173, + 2027801589, + 2026351522, + 2024892978, + 2023425963, + 2021950484, + 2020466546, + 2018974156, + 2017473321, + 2015964045, + 2014446336, + 2012920201, + 2011385644, + 2009842674, + 2008291295, + 2006731516, + 2005163342, + 2003586779, + 2002001835, + 2000408516, + 1998806829, + 1997196780, + 1995578377, + 1993951625, + 1992316532, + 1990673105, + 1989021350, + 1987361274, + 1985692885, + 1984016189, + 1982331193, + 1980637905, + 1978936331, + 1977226479, + 1975508355, + 1973781967, + 1972047323, + 1970304428, + 1968553292, + 1966793920, + 1965026321, + 1963250501, + 1961466469, + 1959674231, + 1957873796, + 1956065170, + 1954248361, + 1952423377, + 1950590226, + 1948748914, + 1946899451, + 1945041843, + 1943176098, + 1941302225, + 1939420231, + 1937530123, + 1935631910, + 1933725600, + 1931811201, + 1929888720, + 1927958166, + 1926019547, + 1924072871, + 1922118145, + 1920155379, + 1918184581, + 1916205758, + 1914218919, + 1912224073, + 1910221227, + 1908210390, + 1906191570, + 1904164776, + 1902130017, + 1900087301, + 1898036636, + 1895978031, + 1893911494, + 1891837035, + 1889754661, + 1887664383, + 1885566207, + 1883460144, + 1881346202, + 1879224389, + 1877094716, + 1874957189, + 1872811820, + 1870658615, + 1868497586, + 1866328740, + 1864152086, + 1861967634, + 1859775393, + 1857575372, + 1855367581, + 1853152028, + 1850928722, + 1848697674, + 1846458892, + 1844212386, + 1841958164, + 1839696238, + 1837426615, + 1835149306, + 1832864320, + 1830571667, + 1828271356, + 1825963397, + 1823647799, + 1821324572, + 1818993726, + 1816655271, + 1814309216, + 1811955572, + 1809594347, + 1807225553, + 1804849198, + 1802465294, + 1800073849, + 1797674873, + 1795268378, + 1792854372, + 1790432867, + 1788003871, + 1785567396, + 1783123452, + 1780672048, + 1778213194, + 1775746903, + 1773273182, + 1770792044, + 1768303498, + 1765807555, + 1763304224, + 1760793518, + 1758275445, + 1755750017, + 1753217244, + 1750677137, + 1748129707, + 1745574963, + 1743012918, + 1740443581, + 1737866963, + 1735283075, + 1732691928, + 1730093532, + 1727487899, + 1724875040, + 1722254965, + 1719627685, + 1716993211, + 1714351555, + 1711702727, + 1709046739, + 1706383601, + 1703713325, + 1701035922, + 1698351403, + 1695659779, + 1692961062, + 1690255263, + 1687542393, + 1684822463, + 1682095486, + 1679361471, + 1676620432, + 1673872378, + 1671117323, + 1668355276, + 1665586251, + 1662810258, + 1660027308, + 1657237415, + 1654440588, + 1651636841, + 1648826185, + 1646008631, + 1643184191, + 1640352877, + 1637514702, + 1634669676, + 1631817811, + 1628959121, + 1626093616, + 1623221309, + 1620342211, + 1617456335, + 1614563692, + 1611664296, + 1608758157, + 1605845289, + 1602925703, + 1599999411, + 1597066426, + 1594126760, + 1591180426, + 1588227435, + 1585267800, + 1582301533, + 1579328647, + 1576349155, + 1573363068, + 1570370399, + 1567371161, + 1564365367, + 1561353028, + 1558334157, + 1555308768, + 1552276872, + 1549238483, + 1546193612, + 1543142274, + 1540084480, + 1537020244, + 1533949577, + 1530872494, + 1527789007, + 1524699129, + 1521602872, + 1518500250, + 1515391276, + 1512275962, + 1509154322, + 1506026369, + 1502892116, + 1499751576, + 1496604762, + 1493451687, + 1490292364, + 1487126808, + 1483955030, + 1480777044, + 1477592864, + 1474402503, + 1471205974, + 1468003290, + 1464794466, + 1461579514, + 1458358447, + 1455131280, + 1451898025, + 1448658697, + 1445413309, + 1442161874, + 1438904406, + 1435640919, + 1432371426, + 1429095941, + 1425814478, + 1422527051, + 1419233672, + 1415934356, + 1412629117, + 1409317969, + 1406000925, + 1402678000, + 1399349206, + 1396014559, + 1392674072, + 1389327759, + 1385975633, + 1382617710, + 1379254004, + 1375884527, + 1372509294, + 1369128320, + 1365741619, + 1362349204, + 1358951090, + 1355547292, + 1352137822, + 1348722696, + 1345301929, + 1341875533, + 1338443524, + 1335005916, + 1331562723, + 1328113960, + 1324659641, + 1321199781, + 1317734393, + 1314263493, + 1310787095, + 1307305214, + 1303817864, + 1300325060, + 1296826816, + 1293323147, + 1289814068, + 1286299593, + 1282779738, + 1279254516, + 1275723942, + 1272188032, + 1268646800, + 1265100260, + 1261548429, + 1257991320, + 1254428948, + 1250861329, + 1247288478, + 1243710408, + 1240127136, + 1236538675, + 1232945043, + 1229346252, + 1225742318, + 1222133257, + 1218519084, + 1214899813, + 1211275460, + 1207646039, + 1204011567, + 1200372058, + 1196727527, + 1193077991, + 1189423463, + 1185763960, + 1182099496, + 1178430087, + 1174755748, + 1171076495, + 1167392344, + 1163703308, + 1160009405, + 1156310649, + 1152607055, + 1148898640, + 1145185419, + 1141467408, + 1137744621, + 1134017074, + 1130284784, + 1126547765, + 1122806034, + 1119059606, + 1115308496, + 1111552721, + 1107792296, + 1104027237, + 1100257559, + 1096483278, + 1092704411, + 1088920972, + 1085132978, + 1081340445, + 1077543388, + 1073741824, + 1069935768, + 1066125236, + 1062310244, + 1058490808, + 1054666944, + 1050838668, + 1047005996, + 1043168945, + 1039327529, + 1035481766, + 1031631671, + 1027777260, + 1023918550, + 1020055556, + 1016188296, + 1012316784, + 1008441038, + 1004561072, + 1000676905, + 996788551, + 992896028, + 988999351, + 985098537, + 981193602, + 977284562, + 973371434, + 969454234, + 965532978, + 961607684, + 957678367, + 953745043, + 949807730, + 945866443, + 941921200, + 937972016, + 934018909, + 930061894, + 926100989, + 922136209, + 918167572, + 914195094, + 910218791, + 906238681, + 902254780, + 898267104, + 894275671, + 890280497, + 886281598, + 882278992, + 878272695, + 874262724, + 870249095, + 866231826, + 862210934, + 858186435, + 854158345, + 850126682, + 846091463, + 842052705, + 838010424, + 833964638, + 829915362, + 825862615, + 821806413, + 817746774, + 813683713, + 809617249, + 805547397, + 801474176, + 797397602, + 793317693, + 789234464, + 785147934, + 781058120, + 776965038, + 772868706, + 768769141, + 764666360, + 760560380, + 756451218, + 752338892, + 748223418, + 744104815, + 739983099, + 735858287, + 731730397, + 727599446, + 723465451, + 719328430, + 715188400, + 711045377, + 706899381, + 702750427, + 698598533, + 694443717, + 690285996, + 686125387, + 681961908, + 677795576, + 673626408, + 669454423, + 665279637, + 661102068, + 656921734, + 652738651, + 648552838, + 644364312, + 640173090, + 635979190, + 631782630, + 627583426, + 623381598, + 619177161, + 614970135, + 610760536, + 606548381, + 602333690, + 598116479, + 593896765, + 589674567, + 585449903, + 581222789, + 576993244, + 572761285, + 568526931, + 564290197, + 560051104, + 555809667, + 551565905, + 547319836, + 543071478, + 538820847, + 534567963, + 530312842, + 526055503, + 521795963, + 517534240, + 513270353, + 509004318, + 504736154, + 500465878, + 496193509, + 491919064, + 487642562, + 483364019, + 479083454, + 474800886, + 470516330, + 466229807, + 461941333, + 457650927, + 453358607, + 449064389, + 444768294, + 440470337, + 436170538, + 431868915, + 427565485, + 423260266, + 418953276, + 414644534, + 410334058, + 406021865, + 401707973, + 397392401, + 393075166, + 388756287, + 384435782, + 380113669, + 375789965, + 371464690, + 367137861, + 362809495, + 358479612, + 354148230, + 349815365, + 345481038, + 341145265, + 336808065, + 332469456, + 328129457, + 323788084, + 319445358, + 315101295, + 310755913, + 306409232, + 302061269, + 297712042, + 293361570, + 289009871, + 284656963, + 280302863, + 275947592, + 271591166, + 267233603, + 262874923, + 258515144, + 254154282, + 249792358, + 245429388, + 241065392, + 236700388, + 232334393, + 227967426, + 223599506, + 219230650, + 214860878, + 210490206, + 206118654, + 201746240, + 197372981, + 192998897, + 188624006, + 184248325, + 179871874, + 175494670, + 171116733, + 166738079, + 162358728, + 157978697, + 153598006, + 149216672, + 144834714, + 140452151, + 136068999, + 131685278, + 127301007, + 122916203, + 118530885, + 114145071, + 109758779, + 105372028, + 100984837, + 96597223, + 92209205, + 87820801, + 83432030, + 79042909, + 74653459, + 70263695, + 65873638, + 61483306, + 57092716, + 52701887, + 48310838, + 43919586, + 39528151, + 35136551, + 30744804, + 26352928, + 21960942, + 17568864, + 13176712, + 8784505, + 4392262, + 0, + -4392262, + -8784505, + -13176712, + -17568864, + -21960942, + -26352928, + -30744804, + -35136551, + -39528151, + -43919586, + -48310838, + -52701887, + -57092716, + -61483306, + -65873638, + -70263695, + -74653459, + -79042909, + -83432030, + -87820801, + -92209205, + -96597223, + -100984837, + -105372028, + -109758779, + -114145071, + -118530885, + -122916203, + -127301007, + -131685278, + -136068999, + -140452151, + -144834714, + -149216672, + -153598006, + -157978697, + -162358728, + -166738079, + -171116733, + -175494670, + -179871874, + -184248325, + -188624006, + -192998897, + -197372981, + -201746240, + -206118654, + -210490206, + -214860878, + -219230650, + -223599506, + -227967426, + -232334393, + -236700388, + -241065392, + -245429388, + -249792358, + -254154282, + -258515144, + -262874923, + -267233603, + -271591166, + -275947592, + -280302863, + -284656963, + -289009871, + -293361570, + -297712042, + -302061269, + -306409232, + -310755913, + -315101295, + -319445358, + -323788084, + -328129457, + -332469456, + -336808065, + -341145265, + -345481038, + -349815365, + -354148230, + -358479612, + -362809495, + -367137861, + -371464690, + -375789965, + -380113669, + -384435782, + -388756287, + -393075166, + -397392401, + -401707973, + -406021865, + -410334058, + -414644534, + -418953276, + -423260266, + -427565485, + -431868915, + -436170538, + -440470337, + -444768294, + -449064389, + -453358607, + -457650927, + -461941333, + -466229807, + -470516330, + -474800886, + -479083454, + -483364019, + -487642562, + -491919064, + -496193509, + -500465878, + -504736154, + -509004318, + -513270353, + -517534240, + -521795963, + -526055503, + -530312842, + -534567963, + -538820847, + -543071478, + -547319836, + -551565905, + -555809667, + -560051104, + -564290197, + -568526931, + -572761285, + -576993244, + -581222789, + -585449903, + -589674567, + -593896765, + -598116479, + -602333690, + -606548381, + -610760536, + -614970135, + -619177161, + -623381598, + -627583426, + -631782630, + -635979190, + -640173090, + -644364312, + -648552838, + -652738651, + -656921734, + -661102068, + -665279637, + -669454423, + -673626408, + -677795576, + -681961908, + -686125387, + -690285996, + -694443717, + -698598533, + -702750427, + -706899381, + -711045377, + -715188400, + -719328430, + -723465451, + -727599446, + -731730397, + -735858287, + -739983099, + -744104815, + -748223418, + -752338892, + -756451218, + -760560380, + -764666360, + -768769141, + -772868706, + -776965038, + -781058120, + -785147934, + -789234464, + -793317693, + -797397602, + -801474176, + -805547397, + -809617249, + -813683713, + -817746774, + -821806413, + -825862615, + -829915362, + -833964638, + -838010424, + -842052705, + -846091463, + -850126682, + -854158345, + -858186435, + -862210934, + -866231826, + -870249095, + -874262724, + -878272695, + -882278992, + -886281598, + -890280497, + -894275671, + -898267104, + -902254780, + -906238681, + -910218791, + -914195094, + -918167572, + -922136209, + -926100989, + -930061894, + -934018909, + -937972016, + -941921200, + -945866443, + -949807730, + -953745043, + -957678367, + -961607684, + -965532978, + -969454234, + -973371434, + -977284562, + -981193602, + -985098537, + -988999351, + -992896028, + -996788551, + -1000676905, + -1004561072, + -1008441038, + -1012316784, + -1016188296, + -1020055556, + -1023918550, + -1027777260, + -1031631671, + -1035481766, + -1039327529, + -1043168945, + -1047005996, + -1050838668, + -1054666944, + -1058490808, + -1062310244, + -1066125236, + -1069935768, + -1073741824, + -1077543388, + -1081340445, + -1085132978, + -1088920972, + -1092704411, + -1096483278, + -1100257559, + -1104027237, + -1107792296, + -1111552721, + -1115308496, + -1119059606, + -1122806034, + -1126547765, + -1130284784, + -1134017074, + -1137744621, + -1141467408, + -1145185419, + -1148898640, + -1152607055, + -1156310649, + -1160009405, + -1163703308, + -1167392344, + -1171076495, + -1174755748, + -1178430087, + -1182099496, + -1185763960, + -1189423463, + -1193077991, + -1196727527, + -1200372058, + -1204011567, + -1207646039, + -1211275460, + -1214899813, + -1218519084, + -1222133257, + -1225742318, + -1229346252, + -1232945043, + -1236538675, + -1240127136, + -1243710408, + -1247288478, + -1250861329, + -1254428948, + -1257991320, + -1261548429, + -1265100260, + -1268646800, + -1272188032, + -1275723942, + -1279254516, + -1282779738, + -1286299593, + -1289814068, + -1293323147, + -1296826816, + -1300325060, + -1303817864, + -1307305214, + -1310787095, + -1314263493, + -1317734393, + -1321199781, + -1324659641, + -1328113960, + -1331562723, + -1335005916, + -1338443524, + -1341875533, + -1345301929, + -1348722696, + -1352137822, + -1355547292, + -1358951090, + -1362349204, + -1365741619, + -1369128320, + -1372509294, + -1375884527, + -1379254004, + -1382617710, + -1385975633, + -1389327759, + -1392674072, + -1396014559, + -1399349206, + -1402678000, + -1406000925, + -1409317969, + -1412629117, + -1415934356, + -1419233672, + -1422527051, + -1425814478, + -1429095941, + -1432371426, + -1435640919, + -1438904406, + -1442161874, + -1445413309, + -1448658697, + -1451898025, + -1455131280, + -1458358447, + -1461579514, + -1464794466, + -1468003290, + -1471205974, + -1474402503, + -1477592864, + -1480777044, + -1483955030, + -1487126808, + -1490292364, + -1493451687, + -1496604762, + -1499751576, + -1502892116, + -1506026369, + -1509154322, + -1512275962, + -1515391276, + -1518500250, + -1521602872, + -1524699129, + -1527789007, + -1530872494, + -1533949577, + -1537020244, + -1540084480, + -1543142274, + -1546193612, + -1549238483, + -1552276872, + -1555308768, + -1558334157, + -1561353028, + -1564365367, + -1567371161, + -1570370399, + -1573363068, + -1576349155, + -1579328647, + -1582301533, + -1585267800, + -1588227435, + -1591180426, + -1594126760, + -1597066426, + -1599999411, + -1602925703, + -1605845289, + -1608758157, + -1611664296, + -1614563692, + -1617456335, + -1620342211, + -1623221309, + -1626093616, + -1628959121, + -1631817811, + -1634669676, + -1637514702, + -1640352877, + -1643184191, + -1646008631, + -1648826185, + -1651636841, + -1654440588, + -1657237415, + -1660027308, + -1662810258, + -1665586251, + -1668355276, + -1671117323, + -1673872378, + -1676620432, + -1679361471, + -1682095486, + -1684822463, + -1687542393, + -1690255263, + -1692961062, + -1695659779, + -1698351403, + -1701035922, + -1703713325, + -1706383601, + -1709046739, + -1711702727, + -1714351555, + -1716993211, + -1719627685, + -1722254965, + -1724875040, + -1727487899, + -1730093532, + -1732691928, + -1735283075, + -1737866963, + -1740443581, + -1743012918, + -1745574963, + -1748129707, + -1750677137, + -1753217244, + -1755750017, + -1758275445, + -1760793518, + -1763304224, + -1765807555, + -1768303498, + -1770792044, + -1773273182, + -1775746903, + -1778213194, + -1780672048, + -1783123452, + -1785567396, + -1788003871, + -1790432867, + -1792854372, + -1795268378, + -1797674873, + -1800073849, + -1802465294, + -1804849198, + -1807225553, + -1809594347, + -1811955572, + -1814309216, + -1816655271, + -1818993726, + -1821324572, + -1823647799, + -1825963397, + -1828271356, + -1830571667, + -1832864320, + -1835149306, + -1837426615, + -1839696238, + -1841958164, + -1844212386, + -1846458892, + -1848697674, + -1850928722, + -1853152028, + -1855367581, + -1857575372, + -1859775393, + -1861967634, + -1864152086, + -1866328740, + -1868497586, + -1870658615, + -1872811820, + -1874957189, + -1877094716, + -1879224389, + -1881346202, + -1883460144, + -1885566207, + -1887664383, + -1889754661, + -1891837035, + -1893911494, + -1895978031, + -1898036636, + -1900087301, + -1902130017, + -1904164776, + -1906191570, + -1908210390, + -1910221227, + -1912224073, + -1914218919, + -1916205758, + -1918184581, + -1920155379, + -1922118145, + -1924072871, + -1926019547, + -1927958166, + -1929888720, + -1931811201, + -1933725600, + -1935631910, + -1937530123, + -1939420231, + -1941302225, + -1943176098, + -1945041843, + -1946899451, + -1948748914, + -1950590226, + -1952423377, + -1954248361, + -1956065170, + -1957873796, + -1959674231, + -1961466469, + -1963250501, + -1965026321, + -1966793920, + -1968553292, + -1970304428, + -1972047323, + -1973781967, + -1975508355, + -1977226479, + -1978936331, + -1980637905, + -1982331193, + -1984016189, + -1985692885, + -1987361274, + -1989021350, + -1990673105, + -1992316532, + -1993951625, + -1995578377, + -1997196780, + -1998806829, + -2000408516, + -2002001835, + -2003586779, + -2005163342, + -2006731516, + -2008291295, + -2009842674, + -2011385644, + -2012920201, + -2014446336, + -2015964045, + -2017473321, + -2018974156, + -2020466546, + -2021950484, + -2023425963, + -2024892978, + -2026351522, + -2027801589, + -2029243173, + -2030676269, + -2032100869, + -2033516969, + -2034924562, + -2036323642, + -2037714204, + -2039096241, + -2040469748, + -2041834720, + -2043191150, + -2044539032, + -2045878362, + -2047209133, + -2048531340, + -2049844978, + -2051150040, + -2052446522, + -2053734418, + -2055013723, + -2056284431, + -2057546537, + -2058800036, + -2060044922, + -2061281190, + -2062508835, + -2063727853, + -2064938237, + -2066139983, + -2067333086, + -2068517540, + -2069693342, + -2070860485, + -2072018965, + -2073168777, + -2074309917, + -2075442379, + -2076566160, + -2077681253, + -2078787655, + -2079885360, + -2080974365, + -2082054665, + -2083126254, + -2084189130, + -2085243286, + -2086288720, + -2087325426, + -2088353400, + -2089372638, + -2090383135, + -2091384888, + -2092377892, + -2093362143, + -2094337637, + -2095304370, + -2096262337, + -2097211535, + -2098151960, + -2099083608, + -2100006474, + -2100920556, + -2101825849, + -2102722350, + -2103610054, + -2104488958, + -2105359059, + -2106220352, + -2107072834, + -2107916502, + -2108751352, + -2109577380, + -2110394584, + -2111202959, + -2112002502, + -2112793210, + -2113575080, + -2114348108, + -2115112291, + -2115867626, + -2116614110, + -2117351739, + -2118080511, + -2118800422, + -2119511470, + -2120213651, + -2120906963, + -2121591402, + -2122266967, + -2122933653, + -2123591458, + -2124240380, + -2124880416, + -2125511562, + -2126133817, + -2126747178, + -2127351642, + -2127947206, + -2128533869, + -2129111628, + -2129680480, + -2130240422, + -2130791454, + -2131333572, + -2131866773, + -2132391057, + -2132906420, + -2133412861, + -2133910377, + -2134398966, + -2134878626, + -2135349356, + -2135811153, + -2136264015, + -2136707940, + -2137142927, + -2137568974, + -2137986079, + -2138394240, + -2138793455, + -2139183723, + -2139565043, + -2139937412, + -2140300829, + -2140655293, + -2141000801, + -2141337354, + -2141664948, + -2141983583, + -2142293258, + -2142593971, + -2142885721, + -2143168506, + -2143442326, + -2143707180, + -2143963065, + -2144209982, + -2144447929, + -2144676905, + -2144896910, + -2145107942, + -2145310000, + -2145503083, + -2145687192, + -2145862324, + -2146028480, + -2146185658, + -2146333858, + -2146473080, + -2146603322, + -2146724584, + -2146836866, + -2146940167, + -2147034487, + -2147119825, + -2147196181, + -2147263555, + -2147321946, + -2147371355, + -2147411780, + -2147443222, + -2147465681, + -2147479156, + -2147483647, + -2147479156, + -2147465681, + -2147443222, + -2147411780, + -2147371355, + -2147321946, + -2147263555, + -2147196181, + -2147119825, + -2147034487, + -2146940167, + -2146836866, + -2146724584, + -2146603322, + -2146473080, + -2146333858, + -2146185658, + -2146028480, + -2145862324, + -2145687192, + -2145503083, + -2145310000, + -2145107942, + -2144896910, + -2144676905, + -2144447929, + -2144209982, + -2143963065, + -2143707180, + -2143442326, + -2143168506, + -2142885721, + -2142593971, + -2142293258, + -2141983583, + -2141664948, + -2141337354, + -2141000801, + -2140655293, + -2140300829, + -2139937412, + -2139565043, + -2139183723, + -2138793455, + -2138394240, + -2137986079, + -2137568974, + -2137142927, + -2136707940, + -2136264015, + -2135811153, + -2135349356, + -2134878626, + -2134398966, + -2133910377, + -2133412861, + -2132906420, + -2132391057, + -2131866773, + -2131333572, + -2130791454, + -2130240422, + -2129680480, + -2129111628, + -2128533869, + -2127947206, + -2127351642, + -2126747178, + -2126133817, + -2125511562, + -2124880416, + -2124240380, + -2123591458, + -2122933653, + -2122266967, + -2121591402, + -2120906963, + -2120213651, + -2119511470, + -2118800422, + -2118080511, + -2117351739, + -2116614110, + -2115867626, + -2115112291, + -2114348108, + -2113575080, + -2112793210, + -2112002502, + -2111202959, + -2110394584, + -2109577380, + -2108751352, + -2107916502, + -2107072834, + -2106220352, + -2105359059, + -2104488958, + -2103610054, + -2102722350, + -2101825849, + -2100920556, + -2100006474, + -2099083608, + -2098151960, + -2097211535, + -2096262337, + -2095304370, + -2094337637, + -2093362143, + -2092377892, + -2091384888, + -2090383135, + -2089372638, + -2088353400, + -2087325426, + -2086288720, + -2085243286, + -2084189130, + -2083126254, + -2082054665, + -2080974365, + -2079885360, + -2078787655, + -2077681253, + -2076566160, + -2075442379, + -2074309917, + -2073168777, + -2072018965, + -2070860485, + -2069693342, + -2068517540, + -2067333086, + -2066139983, + -2064938237, + -2063727853, + -2062508835, + -2061281190, + -2060044922, + -2058800036, + -2057546537, + -2056284431, + -2055013723, + -2053734418, + -2052446522, + -2051150040, + -2049844978, + -2048531340, + -2047209133, + -2045878362, + -2044539032, + -2043191150, + -2041834720, + -2040469748, + -2039096241, + -2037714204, + -2036323642, + -2034924562, + -2033516969, + -2032100869, + -2030676269, + -2029243173, + -2027801589, + -2026351522, + -2024892978, + -2023425963, + -2021950484, + -2020466546, + -2018974156, + -2017473321, + -2015964045, + -2014446336, + -2012920201, + -2011385644, + -2009842674, + -2008291295, + -2006731516, + -2005163342, + -2003586779, + -2002001835, + -2000408516, + -1998806829, + -1997196780, + -1995578377, + -1993951625, + -1992316532, + -1990673105, + -1989021350, + -1987361274, + -1985692885, + -1984016189, + -1982331193, + -1980637905, + -1978936331, + -1977226479, + -1975508355, + -1973781967, + -1972047323, + -1970304428, + -1968553292, + -1966793920, + -1965026321, + -1963250501, + -1961466469, + -1959674231, + -1957873796, + -1956065170, + -1954248361, + -1952423377, + -1950590226, + -1948748914, + -1946899451, + -1945041843, + -1943176098, + -1941302225, + -1939420231, + -1937530123, + -1935631910, + -1933725600, + -1931811201, + -1929888720, + -1927958166, + -1926019547, + -1924072871, + -1922118145, + -1920155379, + -1918184581, + -1916205758, + -1914218919, + -1912224073, + -1910221227, + -1908210390, + -1906191570, + -1904164776, + -1902130017, + -1900087301, + -1898036636, + -1895978031, + -1893911494, + -1891837035, + -1889754661, + -1887664383, + -1885566207, + -1883460144, + -1881346202, + -1879224389, + -1877094716, + -1874957189, + -1872811820, + -1870658615, + -1868497586, + -1866328740, + -1864152086, + -1861967634, + -1859775393, + -1857575372, + -1855367581, + -1853152028, + -1850928722, + -1848697674, + -1846458892, + -1844212386, + -1841958164, + -1839696238, + -1837426615, + -1835149306, + -1832864320, + -1830571667, + -1828271356, + -1825963397, + -1823647799, + -1821324572, + -1818993726, + -1816655271, + -1814309216, + -1811955572, + -1809594347, + -1807225553, + -1804849198, + -1802465294, + -1800073849, + -1797674873, + -1795268378, + -1792854372, + -1790432867, + -1788003871, + -1785567396, + -1783123452, + -1780672048, + -1778213194, + -1775746903, + -1773273182, + -1770792044, + -1768303498, + -1765807555, + -1763304224, + -1760793518, + -1758275445, + -1755750017, + -1753217244, + -1750677137, + -1748129707, + -1745574963, + -1743012918, + -1740443581, + -1737866963, + -1735283075, + -1732691928, + -1730093532, + -1727487899, + -1724875040, + -1722254965, + -1719627685, + -1716993211, + -1714351555, + -1711702727, + -1709046739, + -1706383601, + -1703713325, + -1701035922, + -1698351403, + -1695659779, + -1692961062, + -1690255263, + -1687542393, + -1684822463, + -1682095486, + -1679361471, + -1676620432, + -1673872378, + -1671117323, + -1668355276, + -1665586251, + -1662810258, + -1660027308, + -1657237415, + -1654440588, + -1651636841, + -1648826185, + -1646008631, + -1643184191, + -1640352877, + -1637514702, + -1634669676, + -1631817811, + -1628959121, + -1626093616, + -1623221309, + -1620342211, + -1617456335, + -1614563692, + -1611664296, + -1608758157, + -1605845289, + -1602925703, + -1599999411, + -1597066426, + -1594126760, + -1591180426, + -1588227435, + -1585267800, + -1582301533, + -1579328647, + -1576349155, + -1573363068, + -1570370399, + -1567371161, + -1564365367, + -1561353028, + -1558334157, + -1555308768, + -1552276872, + -1549238483, + -1546193612, + -1543142274, + -1540084480, + -1537020244, + -1533949577, + -1530872494, + -1527789007, + -1524699129, + -1521602872, + -1518500250, + -1515391276, + -1512275962, + -1509154322, + -1506026369, + -1502892116, + -1499751576, + -1496604762, + -1493451687, + -1490292364, + -1487126808, + -1483955030, + -1480777044, + -1477592864, + -1474402503, + -1471205974, + -1468003290, + -1464794466, + -1461579514, + -1458358447, + -1455131280, + -1451898025, + -1448658697, + -1445413309, + -1442161874, + -1438904406, + -1435640919, + -1432371426, + -1429095941, + -1425814478, + -1422527051, + -1419233672, + -1415934356, + -1412629117, + -1409317969, + -1406000925, + -1402678000, + -1399349206, + -1396014559, + -1392674072, + -1389327759, + -1385975633, + -1382617710, + -1379254004, + -1375884527, + -1372509294, + -1369128320, + -1365741619, + -1362349204, + -1358951090, + -1355547292, + -1352137822, + -1348722696, + -1345301929, + -1341875533, + -1338443524, + -1335005916, + -1331562723, + -1328113960, + -1324659641, + -1321199781, + -1317734393, + -1314263493, + -1310787095, + -1307305214, + -1303817864, + -1300325060, + -1296826816, + -1293323147, + -1289814068, + -1286299593, + -1282779738, + -1279254516, + -1275723942, + -1272188032, + -1268646800, + -1265100260, + -1261548429, + -1257991320, + -1254428948, + -1250861329, + -1247288478, + -1243710408, + -1240127136, + -1236538675, + -1232945043, + -1229346252, + -1225742318, + -1222133257, + -1218519084, + -1214899813, + -1211275460, + -1207646039, + -1204011567, + -1200372058, + -1196727527, + -1193077991, + -1189423463, + -1185763960, + -1182099496, + -1178430087, + -1174755748, + -1171076495, + -1167392344, + -1163703308, + -1160009405, + -1156310649, + -1152607055, + -1148898640, + -1145185419, + -1141467408, + -1137744621, + -1134017074, + -1130284784, + -1126547765, + -1122806034, + -1119059606, + -1115308496, + -1111552721, + -1107792296, + -1104027237, + -1100257559, + -1096483278, + -1092704411, + -1088920972, + -1085132978, + -1081340445, + -1077543388, +}; + +/* in Q1.31, generated from sin(i * 2 * pi / FFT_SIZE_MAX) */ +const int32_t multi_twiddle_imag_32[FFT_MULTI_TWIDDLE_SIZE] = { + 0, + -4392262, + -8784505, + -13176712, + -17568864, + -21960942, + -26352928, + -30744804, + -35136551, + -39528151, + -43919586, + -48310838, + -52701887, + -57092716, + -61483306, + -65873638, + -70263695, + -74653459, + -79042909, + -83432030, + -87820801, + -92209205, + -96597223, + -100984837, + -105372028, + -109758779, + -114145071, + -118530885, + -122916203, + -127301007, + -131685278, + -136068999, + -140452151, + -144834714, + -149216672, + -153598006, + -157978697, + -162358728, + -166738079, + -171116733, + -175494670, + -179871874, + -184248325, + -188624006, + -192998897, + -197372981, + -201746240, + -206118654, + -210490206, + -214860878, + -219230650, + -223599506, + -227967426, + -232334393, + -236700388, + -241065392, + -245429388, + -249792358, + -254154282, + -258515144, + -262874923, + -267233603, + -271591166, + -275947592, + -280302863, + -284656963, + -289009871, + -293361570, + -297712042, + -302061269, + -306409232, + -310755913, + -315101295, + -319445358, + -323788084, + -328129457, + -332469456, + -336808065, + -341145265, + -345481038, + -349815365, + -354148230, + -358479612, + -362809495, + -367137861, + -371464690, + -375789965, + -380113669, + -384435782, + -388756287, + -393075166, + -397392401, + -401707973, + -406021865, + -410334058, + -414644534, + -418953276, + -423260266, + -427565485, + -431868915, + -436170538, + -440470337, + -444768294, + -449064389, + -453358607, + -457650927, + -461941333, + -466229807, + -470516330, + -474800886, + -479083454, + -483364019, + -487642562, + -491919064, + -496193509, + -500465878, + -504736154, + -509004318, + -513270353, + -517534240, + -521795963, + -526055503, + -530312842, + -534567963, + -538820847, + -543071478, + -547319836, + -551565905, + -555809667, + -560051104, + -564290197, + -568526931, + -572761285, + -576993244, + -581222789, + -585449903, + -589674567, + -593896765, + -598116479, + -602333690, + -606548381, + -610760536, + -614970135, + -619177161, + -623381598, + -627583426, + -631782630, + -635979190, + -640173090, + -644364312, + -648552838, + -652738651, + -656921734, + -661102068, + -665279637, + -669454423, + -673626408, + -677795576, + -681961908, + -686125387, + -690285996, + -694443717, + -698598533, + -702750427, + -706899381, + -711045377, + -715188400, + -719328430, + -723465451, + -727599446, + -731730397, + -735858287, + -739983099, + -744104815, + -748223418, + -752338892, + -756451218, + -760560380, + -764666360, + -768769141, + -772868706, + -776965038, + -781058120, + -785147934, + -789234464, + -793317693, + -797397602, + -801474176, + -805547397, + -809617249, + -813683713, + -817746774, + -821806413, + -825862615, + -829915362, + -833964638, + -838010424, + -842052705, + -846091463, + -850126682, + -854158345, + -858186435, + -862210934, + -866231826, + -870249095, + -874262724, + -878272695, + -882278992, + -886281598, + -890280497, + -894275671, + -898267104, + -902254780, + -906238681, + -910218791, + -914195094, + -918167572, + -922136209, + -926100989, + -930061894, + -934018909, + -937972016, + -941921200, + -945866443, + -949807730, + -953745043, + -957678367, + -961607684, + -965532978, + -969454234, + -973371434, + -977284562, + -981193602, + -985098537, + -988999351, + -992896028, + -996788551, + -1000676905, + -1004561072, + -1008441038, + -1012316784, + -1016188296, + -1020055556, + -1023918550, + -1027777260, + -1031631671, + -1035481766, + -1039327529, + -1043168945, + -1047005996, + -1050838668, + -1054666944, + -1058490808, + -1062310244, + -1066125236, + -1069935768, + -1073741824, + -1077543388, + -1081340445, + -1085132978, + -1088920972, + -1092704411, + -1096483278, + -1100257559, + -1104027237, + -1107792296, + -1111552721, + -1115308496, + -1119059606, + -1122806034, + -1126547765, + -1130284784, + -1134017074, + -1137744621, + -1141467408, + -1145185419, + -1148898640, + -1152607055, + -1156310649, + -1160009405, + -1163703308, + -1167392344, + -1171076495, + -1174755748, + -1178430087, + -1182099496, + -1185763960, + -1189423463, + -1193077991, + -1196727527, + -1200372058, + -1204011567, + -1207646039, + -1211275460, + -1214899813, + -1218519084, + -1222133257, + -1225742318, + -1229346252, + -1232945043, + -1236538675, + -1240127136, + -1243710408, + -1247288478, + -1250861329, + -1254428948, + -1257991320, + -1261548429, + -1265100260, + -1268646800, + -1272188032, + -1275723942, + -1279254516, + -1282779738, + -1286299593, + -1289814068, + -1293323147, + -1296826816, + -1300325060, + -1303817864, + -1307305214, + -1310787095, + -1314263493, + -1317734393, + -1321199781, + -1324659641, + -1328113960, + -1331562723, + -1335005916, + -1338443524, + -1341875533, + -1345301929, + -1348722696, + -1352137822, + -1355547292, + -1358951090, + -1362349204, + -1365741619, + -1369128320, + -1372509294, + -1375884527, + -1379254004, + -1382617710, + -1385975633, + -1389327759, + -1392674072, + -1396014559, + -1399349206, + -1402678000, + -1406000925, + -1409317969, + -1412629117, + -1415934356, + -1419233672, + -1422527051, + -1425814478, + -1429095941, + -1432371426, + -1435640919, + -1438904406, + -1442161874, + -1445413309, + -1448658697, + -1451898025, + -1455131280, + -1458358447, + -1461579514, + -1464794466, + -1468003290, + -1471205974, + -1474402503, + -1477592864, + -1480777044, + -1483955030, + -1487126808, + -1490292364, + -1493451687, + -1496604762, + -1499751576, + -1502892116, + -1506026369, + -1509154322, + -1512275962, + -1515391276, + -1518500250, + -1521602872, + -1524699129, + -1527789007, + -1530872494, + -1533949577, + -1537020244, + -1540084480, + -1543142274, + -1546193612, + -1549238483, + -1552276872, + -1555308768, + -1558334157, + -1561353028, + -1564365367, + -1567371161, + -1570370399, + -1573363068, + -1576349155, + -1579328647, + -1582301533, + -1585267800, + -1588227435, + -1591180426, + -1594126760, + -1597066426, + -1599999411, + -1602925703, + -1605845289, + -1608758157, + -1611664296, + -1614563692, + -1617456335, + -1620342211, + -1623221309, + -1626093616, + -1628959121, + -1631817811, + -1634669676, + -1637514702, + -1640352877, + -1643184191, + -1646008631, + -1648826185, + -1651636841, + -1654440588, + -1657237415, + -1660027308, + -1662810258, + -1665586251, + -1668355276, + -1671117323, + -1673872378, + -1676620432, + -1679361471, + -1682095486, + -1684822463, + -1687542393, + -1690255263, + -1692961062, + -1695659779, + -1698351403, + -1701035922, + -1703713325, + -1706383601, + -1709046739, + -1711702727, + -1714351555, + -1716993211, + -1719627685, + -1722254965, + -1724875040, + -1727487899, + -1730093532, + -1732691928, + -1735283075, + -1737866963, + -1740443581, + -1743012918, + -1745574963, + -1748129707, + -1750677137, + -1753217244, + -1755750017, + -1758275445, + -1760793518, + -1763304224, + -1765807555, + -1768303498, + -1770792044, + -1773273182, + -1775746903, + -1778213194, + -1780672048, + -1783123452, + -1785567396, + -1788003871, + -1790432867, + -1792854372, + -1795268378, + -1797674873, + -1800073849, + -1802465294, + -1804849198, + -1807225553, + -1809594347, + -1811955572, + -1814309216, + -1816655271, + -1818993726, + -1821324572, + -1823647799, + -1825963397, + -1828271356, + -1830571667, + -1832864320, + -1835149306, + -1837426615, + -1839696238, + -1841958164, + -1844212386, + -1846458892, + -1848697674, + -1850928722, + -1853152028, + -1855367581, + -1857575372, + -1859775393, + -1861967634, + -1864152086, + -1866328740, + -1868497586, + -1870658615, + -1872811820, + -1874957189, + -1877094716, + -1879224389, + -1881346202, + -1883460144, + -1885566207, + -1887664383, + -1889754661, + -1891837035, + -1893911494, + -1895978031, + -1898036636, + -1900087301, + -1902130017, + -1904164776, + -1906191570, + -1908210390, + -1910221227, + -1912224073, + -1914218919, + -1916205758, + -1918184581, + -1920155379, + -1922118145, + -1924072871, + -1926019547, + -1927958166, + -1929888720, + -1931811201, + -1933725600, + -1935631910, + -1937530123, + -1939420231, + -1941302225, + -1943176098, + -1945041843, + -1946899451, + -1948748914, + -1950590226, + -1952423377, + -1954248361, + -1956065170, + -1957873796, + -1959674231, + -1961466469, + -1963250501, + -1965026321, + -1966793920, + -1968553292, + -1970304428, + -1972047323, + -1973781967, + -1975508355, + -1977226479, + -1978936331, + -1980637905, + -1982331193, + -1984016189, + -1985692885, + -1987361274, + -1989021350, + -1990673105, + -1992316532, + -1993951625, + -1995578377, + -1997196780, + -1998806829, + -2000408516, + -2002001835, + -2003586779, + -2005163342, + -2006731516, + -2008291295, + -2009842674, + -2011385644, + -2012920201, + -2014446336, + -2015964045, + -2017473321, + -2018974156, + -2020466546, + -2021950484, + -2023425963, + -2024892978, + -2026351522, + -2027801589, + -2029243173, + -2030676269, + -2032100869, + -2033516969, + -2034924562, + -2036323642, + -2037714204, + -2039096241, + -2040469748, + -2041834720, + -2043191150, + -2044539032, + -2045878362, + -2047209133, + -2048531340, + -2049844978, + -2051150040, + -2052446522, + -2053734418, + -2055013723, + -2056284431, + -2057546537, + -2058800036, + -2060044922, + -2061281190, + -2062508835, + -2063727853, + -2064938237, + -2066139983, + -2067333086, + -2068517540, + -2069693342, + -2070860485, + -2072018965, + -2073168777, + -2074309917, + -2075442379, + -2076566160, + -2077681253, + -2078787655, + -2079885360, + -2080974365, + -2082054665, + -2083126254, + -2084189130, + -2085243286, + -2086288720, + -2087325426, + -2088353400, + -2089372638, + -2090383135, + -2091384888, + -2092377892, + -2093362143, + -2094337637, + -2095304370, + -2096262337, + -2097211535, + -2098151960, + -2099083608, + -2100006474, + -2100920556, + -2101825849, + -2102722350, + -2103610054, + -2104488958, + -2105359059, + -2106220352, + -2107072834, + -2107916502, + -2108751352, + -2109577380, + -2110394584, + -2111202959, + -2112002502, + -2112793210, + -2113575080, + -2114348108, + -2115112291, + -2115867626, + -2116614110, + -2117351739, + -2118080511, + -2118800422, + -2119511470, + -2120213651, + -2120906963, + -2121591402, + -2122266967, + -2122933653, + -2123591458, + -2124240380, + -2124880416, + -2125511562, + -2126133817, + -2126747178, + -2127351642, + -2127947206, + -2128533869, + -2129111628, + -2129680480, + -2130240422, + -2130791454, + -2131333572, + -2131866773, + -2132391057, + -2132906420, + -2133412861, + -2133910377, + -2134398966, + -2134878626, + -2135349356, + -2135811153, + -2136264015, + -2136707940, + -2137142927, + -2137568974, + -2137986079, + -2138394240, + -2138793455, + -2139183723, + -2139565043, + -2139937412, + -2140300829, + -2140655293, + -2141000801, + -2141337354, + -2141664948, + -2141983583, + -2142293258, + -2142593971, + -2142885721, + -2143168506, + -2143442326, + -2143707180, + -2143963065, + -2144209982, + -2144447929, + -2144676905, + -2144896910, + -2145107942, + -2145310000, + -2145503083, + -2145687192, + -2145862324, + -2146028480, + -2146185658, + -2146333858, + -2146473080, + -2146603322, + -2146724584, + -2146836866, + -2146940167, + -2147034487, + -2147119825, + -2147196181, + -2147263555, + -2147321946, + -2147371355, + -2147411780, + -2147443222, + -2147465681, + -2147479156, + -2147483647, + -2147479156, + -2147465681, + -2147443222, + -2147411780, + -2147371355, + -2147321946, + -2147263555, + -2147196181, + -2147119825, + -2147034487, + -2146940167, + -2146836866, + -2146724584, + -2146603322, + -2146473080, + -2146333858, + -2146185658, + -2146028480, + -2145862324, + -2145687192, + -2145503083, + -2145310000, + -2145107942, + -2144896910, + -2144676905, + -2144447929, + -2144209982, + -2143963065, + -2143707180, + -2143442326, + -2143168506, + -2142885721, + -2142593971, + -2142293258, + -2141983583, + -2141664948, + -2141337354, + -2141000801, + -2140655293, + -2140300829, + -2139937412, + -2139565043, + -2139183723, + -2138793455, + -2138394240, + -2137986079, + -2137568974, + -2137142927, + -2136707940, + -2136264015, + -2135811153, + -2135349356, + -2134878626, + -2134398966, + -2133910377, + -2133412861, + -2132906420, + -2132391057, + -2131866773, + -2131333572, + -2130791454, + -2130240422, + -2129680480, + -2129111628, + -2128533869, + -2127947206, + -2127351642, + -2126747178, + -2126133817, + -2125511562, + -2124880416, + -2124240380, + -2123591458, + -2122933653, + -2122266967, + -2121591402, + -2120906963, + -2120213651, + -2119511470, + -2118800422, + -2118080511, + -2117351739, + -2116614110, + -2115867626, + -2115112291, + -2114348108, + -2113575080, + -2112793210, + -2112002502, + -2111202959, + -2110394584, + -2109577380, + -2108751352, + -2107916502, + -2107072834, + -2106220352, + -2105359059, + -2104488958, + -2103610054, + -2102722350, + -2101825849, + -2100920556, + -2100006474, + -2099083608, + -2098151960, + -2097211535, + -2096262337, + -2095304370, + -2094337637, + -2093362143, + -2092377892, + -2091384888, + -2090383135, + -2089372638, + -2088353400, + -2087325426, + -2086288720, + -2085243286, + -2084189130, + -2083126254, + -2082054665, + -2080974365, + -2079885360, + -2078787655, + -2077681253, + -2076566160, + -2075442379, + -2074309917, + -2073168777, + -2072018965, + -2070860485, + -2069693342, + -2068517540, + -2067333086, + -2066139983, + -2064938237, + -2063727853, + -2062508835, + -2061281190, + -2060044922, + -2058800036, + -2057546537, + -2056284431, + -2055013723, + -2053734418, + -2052446522, + -2051150040, + -2049844978, + -2048531340, + -2047209133, + -2045878362, + -2044539032, + -2043191150, + -2041834720, + -2040469748, + -2039096241, + -2037714204, + -2036323642, + -2034924562, + -2033516969, + -2032100869, + -2030676269, + -2029243173, + -2027801589, + -2026351522, + -2024892978, + -2023425963, + -2021950484, + -2020466546, + -2018974156, + -2017473321, + -2015964045, + -2014446336, + -2012920201, + -2011385644, + -2009842674, + -2008291295, + -2006731516, + -2005163342, + -2003586779, + -2002001835, + -2000408516, + -1998806829, + -1997196780, + -1995578377, + -1993951625, + -1992316532, + -1990673105, + -1989021350, + -1987361274, + -1985692885, + -1984016189, + -1982331193, + -1980637905, + -1978936331, + -1977226479, + -1975508355, + -1973781967, + -1972047323, + -1970304428, + -1968553292, + -1966793920, + -1965026321, + -1963250501, + -1961466469, + -1959674231, + -1957873796, + -1956065170, + -1954248361, + -1952423377, + -1950590226, + -1948748914, + -1946899451, + -1945041843, + -1943176098, + -1941302225, + -1939420231, + -1937530123, + -1935631910, + -1933725600, + -1931811201, + -1929888720, + -1927958166, + -1926019547, + -1924072871, + -1922118145, + -1920155379, + -1918184581, + -1916205758, + -1914218919, + -1912224073, + -1910221227, + -1908210390, + -1906191570, + -1904164776, + -1902130017, + -1900087301, + -1898036636, + -1895978031, + -1893911494, + -1891837035, + -1889754661, + -1887664383, + -1885566207, + -1883460144, + -1881346202, + -1879224389, + -1877094716, + -1874957189, + -1872811820, + -1870658615, + -1868497586, + -1866328740, + -1864152086, + -1861967634, + -1859775393, + -1857575372, + -1855367581, + -1853152028, + -1850928722, + -1848697674, + -1846458892, + -1844212386, + -1841958164, + -1839696238, + -1837426615, + -1835149306, + -1832864320, + -1830571667, + -1828271356, + -1825963397, + -1823647799, + -1821324572, + -1818993726, + -1816655271, + -1814309216, + -1811955572, + -1809594347, + -1807225553, + -1804849198, + -1802465294, + -1800073849, + -1797674873, + -1795268378, + -1792854372, + -1790432867, + -1788003871, + -1785567396, + -1783123452, + -1780672048, + -1778213194, + -1775746903, + -1773273182, + -1770792044, + -1768303498, + -1765807555, + -1763304224, + -1760793518, + -1758275445, + -1755750017, + -1753217244, + -1750677137, + -1748129707, + -1745574963, + -1743012918, + -1740443581, + -1737866963, + -1735283075, + -1732691928, + -1730093532, + -1727487899, + -1724875040, + -1722254965, + -1719627685, + -1716993211, + -1714351555, + -1711702727, + -1709046739, + -1706383601, + -1703713325, + -1701035922, + -1698351403, + -1695659779, + -1692961062, + -1690255263, + -1687542393, + -1684822463, + -1682095486, + -1679361471, + -1676620432, + -1673872378, + -1671117323, + -1668355276, + -1665586251, + -1662810258, + -1660027308, + -1657237415, + -1654440588, + -1651636841, + -1648826185, + -1646008631, + -1643184191, + -1640352877, + -1637514702, + -1634669676, + -1631817811, + -1628959121, + -1626093616, + -1623221309, + -1620342211, + -1617456335, + -1614563692, + -1611664296, + -1608758157, + -1605845289, + -1602925703, + -1599999411, + -1597066426, + -1594126760, + -1591180426, + -1588227435, + -1585267800, + -1582301533, + -1579328647, + -1576349155, + -1573363068, + -1570370399, + -1567371161, + -1564365367, + -1561353028, + -1558334157, + -1555308768, + -1552276872, + -1549238483, + -1546193612, + -1543142274, + -1540084480, + -1537020244, + -1533949577, + -1530872494, + -1527789007, + -1524699129, + -1521602872, + -1518500250, + -1515391276, + -1512275962, + -1509154322, + -1506026369, + -1502892116, + -1499751576, + -1496604762, + -1493451687, + -1490292364, + -1487126808, + -1483955030, + -1480777044, + -1477592864, + -1474402503, + -1471205974, + -1468003290, + -1464794466, + -1461579514, + -1458358447, + -1455131280, + -1451898025, + -1448658697, + -1445413309, + -1442161874, + -1438904406, + -1435640919, + -1432371426, + -1429095941, + -1425814478, + -1422527051, + -1419233672, + -1415934356, + -1412629117, + -1409317969, + -1406000925, + -1402678000, + -1399349206, + -1396014559, + -1392674072, + -1389327759, + -1385975633, + -1382617710, + -1379254004, + -1375884527, + -1372509294, + -1369128320, + -1365741619, + -1362349204, + -1358951090, + -1355547292, + -1352137822, + -1348722696, + -1345301929, + -1341875533, + -1338443524, + -1335005916, + -1331562723, + -1328113960, + -1324659641, + -1321199781, + -1317734393, + -1314263493, + -1310787095, + -1307305214, + -1303817864, + -1300325060, + -1296826816, + -1293323147, + -1289814068, + -1286299593, + -1282779738, + -1279254516, + -1275723942, + -1272188032, + -1268646800, + -1265100260, + -1261548429, + -1257991320, + -1254428948, + -1250861329, + -1247288478, + -1243710408, + -1240127136, + -1236538675, + -1232945043, + -1229346252, + -1225742318, + -1222133257, + -1218519084, + -1214899813, + -1211275460, + -1207646039, + -1204011567, + -1200372058, + -1196727527, + -1193077991, + -1189423463, + -1185763960, + -1182099496, + -1178430087, + -1174755748, + -1171076495, + -1167392344, + -1163703308, + -1160009405, + -1156310649, + -1152607055, + -1148898640, + -1145185419, + -1141467408, + -1137744621, + -1134017074, + -1130284784, + -1126547765, + -1122806034, + -1119059606, + -1115308496, + -1111552721, + -1107792296, + -1104027237, + -1100257559, + -1096483278, + -1092704411, + -1088920972, + -1085132978, + -1081340445, + -1077543388, + -1073741824, + -1069935768, + -1066125236, + -1062310244, + -1058490808, + -1054666944, + -1050838668, + -1047005996, + -1043168945, + -1039327529, + -1035481766, + -1031631671, + -1027777260, + -1023918550, + -1020055556, + -1016188296, + -1012316784, + -1008441038, + -1004561072, + -1000676905, + -996788551, + -992896028, + -988999351, + -985098537, + -981193602, + -977284562, + -973371434, + -969454234, + -965532978, + -961607684, + -957678367, + -953745043, + -949807730, + -945866443, + -941921200, + -937972016, + -934018909, + -930061894, + -926100989, + -922136209, + -918167572, + -914195094, + -910218791, + -906238681, + -902254780, + -898267104, + -894275671, + -890280497, + -886281598, + -882278992, + -878272695, + -874262724, + -870249095, + -866231826, + -862210934, + -858186435, + -854158345, + -850126682, + -846091463, + -842052705, + -838010424, + -833964638, + -829915362, + -825862615, + -821806413, + -817746774, + -813683713, + -809617249, + -805547397, + -801474176, + -797397602, + -793317693, + -789234464, + -785147934, + -781058120, + -776965038, + -772868706, + -768769141, + -764666360, + -760560380, + -756451218, + -752338892, + -748223418, + -744104815, + -739983099, + -735858287, + -731730397, + -727599446, + -723465451, + -719328430, + -715188400, + -711045377, + -706899381, + -702750427, + -698598533, + -694443717, + -690285996, + -686125387, + -681961908, + -677795576, + -673626408, + -669454423, + -665279637, + -661102068, + -656921734, + -652738651, + -648552838, + -644364312, + -640173090, + -635979190, + -631782630, + -627583426, + -623381598, + -619177161, + -614970135, + -610760536, + -606548381, + -602333690, + -598116479, + -593896765, + -589674567, + -585449903, + -581222789, + -576993244, + -572761285, + -568526931, + -564290197, + -560051104, + -555809667, + -551565905, + -547319836, + -543071478, + -538820847, + -534567963, + -530312842, + -526055503, + -521795963, + -517534240, + -513270353, + -509004318, + -504736154, + -500465878, + -496193509, + -491919064, + -487642562, + -483364019, + -479083454, + -474800886, + -470516330, + -466229807, + -461941333, + -457650927, + -453358607, + -449064389, + -444768294, + -440470337, + -436170538, + -431868915, + -427565485, + -423260266, + -418953276, + -414644534, + -410334058, + -406021865, + -401707973, + -397392401, + -393075166, + -388756287, + -384435782, + -380113669, + -375789965, + -371464690, + -367137861, + -362809495, + -358479612, + -354148230, + -349815365, + -345481038, + -341145265, + -336808065, + -332469456, + -328129457, + -323788084, + -319445358, + -315101295, + -310755913, + -306409232, + -302061269, + -297712042, + -293361570, + -289009871, + -284656963, + -280302863, + -275947592, + -271591166, + -267233603, + -262874923, + -258515144, + -254154282, + -249792358, + -245429388, + -241065392, + -236700388, + -232334393, + -227967426, + -223599506, + -219230650, + -214860878, + -210490206, + -206118654, + -201746240, + -197372981, + -192998897, + -188624006, + -184248325, + -179871874, + -175494670, + -171116733, + -166738079, + -162358728, + -157978697, + -153598006, + -149216672, + -144834714, + -140452151, + -136068999, + -131685278, + -127301007, + -122916203, + -118530885, + -114145071, + -109758779, + -105372028, + -100984837, + -96597223, + -92209205, + -87820801, + -83432030, + -79042909, + -74653459, + -70263695, + -65873638, + -61483306, + -57092716, + -52701887, + -48310838, + -43919586, + -39528151, + -35136551, + -30744804, + -26352928, + -21960942, + -17568864, + -13176712, + -8784505, + -4392262, + 0, + 4392262, + 8784505, + 13176712, + 17568864, + 21960942, + 26352928, + 30744804, + 35136551, + 39528151, + 43919586, + 48310838, + 52701887, + 57092716, + 61483306, + 65873638, + 70263695, + 74653459, + 79042909, + 83432030, + 87820801, + 92209205, + 96597223, + 100984837, + 105372028, + 109758779, + 114145071, + 118530885, + 122916203, + 127301007, + 131685278, + 136068999, + 140452151, + 144834714, + 149216672, + 153598006, + 157978697, + 162358728, + 166738079, + 171116733, + 175494670, + 179871874, + 184248325, + 188624006, + 192998897, + 197372981, + 201746240, + 206118654, + 210490206, + 214860878, + 219230650, + 223599506, + 227967426, + 232334393, + 236700388, + 241065392, + 245429388, + 249792358, + 254154282, + 258515144, + 262874923, + 267233603, + 271591166, + 275947592, + 280302863, + 284656963, + 289009871, + 293361570, + 297712042, + 302061269, + 306409232, + 310755913, + 315101295, + 319445358, + 323788084, + 328129457, + 332469456, + 336808065, + 341145265, + 345481038, + 349815365, + 354148230, + 358479612, + 362809495, + 367137861, + 371464690, + 375789965, + 380113669, + 384435782, + 388756287, + 393075166, + 397392401, + 401707973, + 406021865, + 410334058, + 414644534, + 418953276, + 423260266, + 427565485, + 431868915, + 436170538, + 440470337, + 444768294, + 449064389, + 453358607, + 457650927, + 461941333, + 466229807, + 470516330, + 474800886, + 479083454, + 483364019, + 487642562, + 491919064, + 496193509, + 500465878, + 504736154, + 509004318, + 513270353, + 517534240, + 521795963, + 526055503, + 530312842, + 534567963, + 538820847, + 543071478, + 547319836, + 551565905, + 555809667, + 560051104, + 564290197, + 568526931, + 572761285, + 576993244, + 581222789, + 585449903, + 589674567, + 593896765, + 598116479, + 602333690, + 606548381, + 610760536, + 614970135, + 619177161, + 623381598, + 627583426, + 631782630, + 635979190, + 640173090, + 644364312, + 648552838, + 652738651, + 656921734, + 661102068, + 665279637, + 669454423, + 673626408, + 677795576, + 681961908, + 686125387, + 690285996, + 694443717, + 698598533, + 702750427, + 706899381, + 711045377, + 715188400, + 719328430, + 723465451, + 727599446, + 731730397, + 735858287, + 739983099, + 744104815, + 748223418, + 752338892, + 756451218, + 760560380, + 764666360, + 768769141, + 772868706, + 776965038, + 781058120, + 785147934, + 789234464, + 793317693, + 797397602, + 801474176, + 805547397, + 809617249, + 813683713, + 817746774, + 821806413, + 825862615, + 829915362, + 833964638, + 838010424, + 842052705, + 846091463, + 850126682, + 854158345, + 858186435, + 862210934, + 866231826, + 870249095, + 874262724, + 878272695, + 882278992, + 886281598, + 890280497, + 894275671, + 898267104, + 902254780, + 906238681, + 910218791, + 914195094, + 918167572, + 922136209, + 926100989, + 930061894, + 934018909, + 937972016, + 941921200, + 945866443, + 949807730, + 953745043, + 957678367, + 961607684, + 965532978, + 969454234, + 973371434, + 977284562, + 981193602, + 985098537, + 988999351, + 992896028, + 996788551, + 1000676905, + 1004561072, + 1008441038, + 1012316784, + 1016188296, + 1020055556, + 1023918550, + 1027777260, + 1031631671, + 1035481766, + 1039327529, + 1043168945, + 1047005996, + 1050838668, + 1054666944, + 1058490808, + 1062310244, + 1066125236, + 1069935768, + 1073741824, + 1077543388, + 1081340445, + 1085132978, + 1088920972, + 1092704411, + 1096483278, + 1100257559, + 1104027237, + 1107792296, + 1111552721, + 1115308496, + 1119059606, + 1122806034, + 1126547765, + 1130284784, + 1134017074, + 1137744621, + 1141467408, + 1145185419, + 1148898640, + 1152607055, + 1156310649, + 1160009405, + 1163703308, + 1167392344, + 1171076495, + 1174755748, + 1178430087, + 1182099496, + 1185763960, + 1189423463, + 1193077991, + 1196727527, + 1200372058, + 1204011567, + 1207646039, + 1211275460, + 1214899813, + 1218519084, + 1222133257, + 1225742318, + 1229346252, + 1232945043, + 1236538675, + 1240127136, + 1243710408, + 1247288478, + 1250861329, + 1254428948, + 1257991320, + 1261548429, + 1265100260, + 1268646800, + 1272188032, + 1275723942, + 1279254516, + 1282779738, + 1286299593, + 1289814068, + 1293323147, + 1296826816, + 1300325060, + 1303817864, + 1307305214, + 1310787095, + 1314263493, + 1317734393, + 1321199781, + 1324659641, + 1328113960, + 1331562723, + 1335005916, + 1338443524, + 1341875533, + 1345301929, + 1348722696, + 1352137822, + 1355547292, + 1358951090, + 1362349204, + 1365741619, + 1369128320, + 1372509294, + 1375884527, + 1379254004, + 1382617710, + 1385975633, + 1389327759, + 1392674072, + 1396014559, + 1399349206, + 1402678000, + 1406000925, + 1409317969, + 1412629117, + 1415934356, + 1419233672, + 1422527051, + 1425814478, + 1429095941, + 1432371426, + 1435640919, + 1438904406, + 1442161874, + 1445413309, + 1448658697, + 1451898025, + 1455131280, + 1458358447, + 1461579514, + 1464794466, + 1468003290, + 1471205974, + 1474402503, + 1477592864, + 1480777044, + 1483955030, + 1487126808, + 1490292364, + 1493451687, + 1496604762, + 1499751576, + 1502892116, + 1506026369, + 1509154322, + 1512275962, + 1515391276, + 1518500250, + 1521602872, + 1524699129, + 1527789007, + 1530872494, + 1533949577, + 1537020244, + 1540084480, + 1543142274, + 1546193612, + 1549238483, + 1552276872, + 1555308768, + 1558334157, + 1561353028, + 1564365367, + 1567371161, + 1570370399, + 1573363068, + 1576349155, + 1579328647, + 1582301533, + 1585267800, + 1588227435, + 1591180426, + 1594126760, + 1597066426, + 1599999411, + 1602925703, + 1605845289, + 1608758157, + 1611664296, + 1614563692, + 1617456335, + 1620342211, + 1623221309, + 1626093616, + 1628959121, + 1631817811, + 1634669676, + 1637514702, + 1640352877, + 1643184191, + 1646008631, + 1648826185, + 1651636841, + 1654440588, + 1657237415, + 1660027308, + 1662810258, + 1665586251, + 1668355276, + 1671117323, + 1673872378, + 1676620432, + 1679361471, + 1682095486, + 1684822463, + 1687542393, + 1690255263, + 1692961062, + 1695659779, + 1698351403, + 1701035922, + 1703713325, + 1706383601, + 1709046739, + 1711702727, + 1714351555, + 1716993211, + 1719627685, + 1722254965, + 1724875040, + 1727487899, + 1730093532, + 1732691928, + 1735283075, + 1737866963, + 1740443581, + 1743012918, + 1745574963, + 1748129707, + 1750677137, + 1753217244, + 1755750017, + 1758275445, + 1760793518, + 1763304224, + 1765807555, + 1768303498, + 1770792044, + 1773273182, + 1775746903, + 1778213194, + 1780672048, + 1783123452, + 1785567396, + 1788003871, + 1790432867, + 1792854372, + 1795268378, + 1797674873, + 1800073849, + 1802465294, + 1804849198, + 1807225553, + 1809594347, + 1811955572, + 1814309216, + 1816655271, + 1818993726, + 1821324572, + 1823647799, + 1825963397, + 1828271356, + 1830571667, + 1832864320, + 1835149306, + 1837426615, + 1839696238, + 1841958164, + 1844212386, + 1846458892, + 1848697674, + 1850928722, + 1853152028, + 1855367581, + 1857575372, +}; + +#endif diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 03f37ac884ad..db8a69e63646 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -21,6 +21,8 @@ #include <sof/audio/pipeline.h> #include <sof/debug/telemetry/telemetry.h> #include <rtos/idc.h> +#include <rtos/mutex.h> +#include <rtos/userspace_helper.h> #include <sof/lib/dai.h> #include <sof/schedule/schedule.h> #include <ipc/control.h> @@ -119,6 +121,7 @@ enum { #define COMP_ATTR_COPY_DIR 2 /**< Comp copy direction */ #define COMP_ATTR_VDMA_INDEX 3 /**< Comp index of the virtual DMA at the gateway. */ #define COMP_ATTR_BASE_CONFIG 4 /**< Component base config */ +#define COMP_ATTR_IPC4_CONFIG 5 /**< Component ipc4 set/get config */ /** @}*/ /** \name Trace macros @@ -270,6 +273,40 @@ enum comp_copy_type { struct comp_driver; struct comp_ipc_config; union ipc_config_specific; +struct ipc4_module_bind_unbind; + +enum bind_type { + COMP_BIND_TYPE_SOURCE, + COMP_BIND_TYPE_SINK +}; + +struct bind_info { + /* pointer to IPC4 bind/unbind data */ + struct ipc4_module_bind_unbind *ipc4_data; + + /* type of binding + * bind call will be called twice for every component, first when binding a data source, + * than when binding data sink. + * + * bind_type is indicating type of binding + */ + enum bind_type bind_type; + + /* pointers to sink or source API of the data provider/consumer + * that is being bound to the module + * + * if bind_type == COMP_BIND_TYPE_SOURCE, the pointer points to source being bound/unbound + * if bind_type == COMP_BIND_TYPE_SINK, the pointer points to sink being bound/unbound + * + * NOTE! As in pipeline2.0 there may be a binding between modules, + * without a buffer in between, it cannot be a pointer to any buffer type, module should + * use sink/source API + */ + union { + struct sof_source *source; + struct sof_sink *sink; + }; +}; /** * Audio component operations. @@ -286,13 +323,12 @@ struct comp_ops { * @param spec Pointer to initialization data * @return Pointer to the new component device. * - * All required data objects should be allocated from the run-time - * heap (SOF_MEM_ZONE_RUNTIME). * Any component-specific private data is allocated separately and * pointer is connected to the comp_dev::private by using * comp_set_drvdata() and later retrieved by comp_get_drvdata(). * * All parameters should be initialized to their default values. + * Usually can be __cold. */ struct comp_dev *(*create)(const struct comp_driver *drv, const struct comp_ipc_config *ipc_config, @@ -304,6 +340,7 @@ struct comp_ops { * * All data structures previously allocated on the run-time heap * must be freed by the implementation of <code>free()</code>. + * Usually can be __cold. */ void (*free)(struct comp_dev *dev); @@ -315,6 +352,7 @@ struct comp_ops { * Infrastructure calls comp_verify_params() if this handler is not * defined, therefore it should be left NULL if no extra steps are * required. + * Usually shouldn't be __cold. */ int (*params)(struct comp_dev *dev, struct sof_ipc_stream_params *params); @@ -327,6 +365,7 @@ struct comp_ops { * @param dir Stream direction (see enum sof_ipc_stream_direction). * * Mandatory for components that allocate DAI. + * Usually can be __cold. */ int (*dai_get_hw_params)(struct comp_dev *dev, struct sof_ipc_stream_params *params, int dir); @@ -337,6 +376,7 @@ struct comp_ops { * @param dai_config DAI configuration. * * Mandatory for components that allocate DAI. + * Usually can be __cold. */ int (*dai_config)(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai *dai_config, const void *dai_spec_config); @@ -358,6 +398,8 @@ struct comp_ops { * Trigger, atomic - used to start/stop/pause stream operations. * @param dev Component device. * @param cmd Command, one of COMP_TRIGGER_... + * + * Usually shouldn't be __cold. */ int (*trigger)(struct comp_dev *dev, int cmd); @@ -367,6 +409,7 @@ struct comp_ops { * * Prepare should be used to get the component ready for starting * processing after it's hw_params are known or after an XRUN. + * Usually shouldn't be __cold. */ int (*prepare)(struct comp_dev *dev); @@ -376,6 +419,7 @@ struct comp_ops { * * Resets the component state and any hw_params to default component * state. Should also free any resources acquired during hw_params. + * Usually shouldn't be __cold. */ int (*reset)(struct comp_dev *dev); @@ -383,6 +427,8 @@ struct comp_ops { * Copy and process stream data from source to sink buffers. * @param dev Component device. * @return Number of copied frames. + * + * Usually shouldn't be __cold. */ int (*copy)(struct comp_dev *dev); @@ -390,6 +436,8 @@ struct comp_ops { * Retrieves component rendering position. * @param dev Component device. * @param posn Receives reported position. + * + * Usually shouldn't be __cold. */ int (*position)(struct comp_dev *dev, struct sof_ipc_stream_posn *posn); @@ -400,6 +448,8 @@ struct comp_ops { * @param type Attribute type. * @param value Attribute value. * @return 0 if succeeded, error code otherwise. + * + * Usually can be __cold. */ int (*get_attribute)(struct comp_dev *dev, uint32_t type, void *value); @@ -410,6 +460,8 @@ struct comp_ops { * @param type Attribute type. * @param value Attribute value. * @return 0 if succeeded, error code otherwise. + * + * Usually can be __cold. */ int (*set_attribute)(struct comp_dev *dev, uint32_t type, void *value); @@ -419,6 +471,7 @@ struct comp_ops { * @param dev Component device. * * Mandatory for components that allocate DAI. + * Usually can be __cold. */ int (*dai_ts_config)(struct comp_dev *dev); @@ -427,6 +480,7 @@ struct comp_ops { * @param dev Component device. * * Mandatory for components that allocate DAI. + * Usually can be __cold. */ int (*dai_ts_start)(struct comp_dev *dev); @@ -435,6 +489,7 @@ struct comp_ops { * @param dev Component device. * * Mandatory for components that allocate DAI. + * Usually can be __cold. */ int (*dai_ts_stop)(struct comp_dev *dev); @@ -444,6 +499,7 @@ struct comp_ops { * @param tsd Receives timestamp data. * * Mandatory for components that allocate DAI. + * Usually shouldn't be __cold. */ #if CONFIG_ZEPHYR_NATIVE_DRIVERS int (*dai_ts_get)(struct comp_dev *dev, struct dai_ts_data *tsd); @@ -456,15 +512,19 @@ struct comp_ops { * Bind, atomic - used to notify component of bind event. * @param dev Component device. * @param data Bind info + * + * Usually can be __cold. */ - int (*bind)(struct comp_dev *dev, void *data); + int (*bind)(struct comp_dev *dev, struct bind_info *bind_data); /** * Unbind, atomic - used to notify component of unbind event. * @param dev Component device. * @param data unBind info + * + * Usually can be __cold. */ - int (*unbind)(struct comp_dev *dev, void *data); + int (*unbind)(struct comp_dev *dev, struct bind_info *unbind_data); /** * Gets config in component. @@ -478,6 +538,7 @@ struct comp_ops { * * Callee fills up *data with config data and save the config * size in *data_offset for host to reconstruct the config + * Usually can be __cold. */ int (*get_large_config)(struct comp_dev *dev, uint32_t param_id, bool first_block, @@ -498,6 +559,7 @@ struct comp_ops { * Host divides large block into small blocks and sends them * to fw. The data_offset indicates the offset in the large * block data. + * Usually can be __cold. */ int (*set_large_config)(struct comp_dev *dev, uint32_t param_id, bool first_block, @@ -511,6 +573,8 @@ struct comp_ops { * @param stream_no Index of input/output stream * @param input Selects between input (true) or output (false) stream direction * @return total data processed if succeeded, 0 otherwise. + * + * Usually shouldn't be __cold. */ uint64_t (*get_total_data_processed)(struct comp_dev *dev, uint32_t stream_no, bool input); }; @@ -528,12 +592,14 @@ struct comp_driver { * Intended to replace the ops field. * Currently used by module_adapter. */ + struct k_heap *user_heap; /**< Userspace heap */ }; /** \brief Holds constant pointer to component driver */ struct comp_driver_info { - const struct comp_driver *drv; /**< pointer to component driver */ - struct list_item list; /**< list of component drivers */ + const struct comp_driver *drv; /**< pointer to component driver */ + const struct module_interface **adapter_ops; /**< pointer for updating ops */ + struct list_item list; /**< list of component drivers */ }; #define COMP_PROCESSING_DOMAIN_LL 0 @@ -553,6 +619,7 @@ struct comp_ipc_config { uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */ uint32_t xrun_action; /**< action we should take on XRUN */ #if CONFIG_IPC_MAJOR_4 + bool ipc_extended_init; /**< true if extended init is included in ipc payload */ uint32_t ipc_config_size; /**< size of a config received by ipc */ #endif }; @@ -649,6 +716,7 @@ static inline struct comp_buffer *comp_dev_get_first_data_producer(struct comp_d /** * Get a pointer to the next comp_buffer object providing data to the component * The function will return NULL if there're no more data providers + * _save version also checks if producer != NULL */ static inline struct comp_buffer *comp_dev_get_next_data_producer(struct comp_dev *component, struct comp_buffer *producer) @@ -657,6 +725,12 @@ static inline struct comp_buffer *comp_dev_get_next_data_producer(struct comp_de list_item(producer->sink_list.next, struct comp_buffer, sink_list); } +static inline struct comp_buffer *comp_dev_get_next_data_producer_safe(struct comp_dev *component, + struct comp_buffer *producer) +{ + return producer ? comp_dev_get_next_data_producer(component, producer) : NULL; +} + /** * Get a pointer to the first comp_buffer object receiving data from the component * The function will return NULL if there's no data consumers @@ -670,6 +744,7 @@ static inline struct comp_buffer *comp_dev_get_first_data_consumer(struct comp_d /** * Get a pointer to the next comp_buffer object receiving data from the component * The function will return NULL if there're no more data consumers + * _safe version also checks if consumer is != NULL */ static inline struct comp_buffer *comp_dev_get_next_data_consumer(struct comp_dev *component, struct comp_buffer *consumer) @@ -678,6 +753,12 @@ static inline struct comp_buffer *comp_dev_get_next_data_consumer(struct comp_de list_item(consumer->source_list.next, struct comp_buffer, source_list); } +static inline struct comp_buffer *comp_dev_get_next_data_consumer_safe(struct comp_dev *component, + struct comp_buffer *consumer) +{ + return consumer ? comp_dev_get_next_data_consumer(component, consumer) : NULL; +} + /* * a macro for easy iteration through component's list of producers */ @@ -686,13 +767,39 @@ static inline struct comp_buffer *comp_dev_get_next_data_consumer(struct comp_de _producer != NULL; \ _producer = comp_dev_get_next_data_producer(_dev, _producer)) +/* + * a macro for easy iteration through component's list of producers + * allowing deletion of a buffer during iteration + * + * additional "safe storage" pointer to struct comp_buffer must be provided + */ +#define comp_dev_for_each_producer_safe(_dev, _producer, _next_producer) \ + for (_producer = comp_dev_get_first_data_producer(_dev), \ + _next_producer = comp_dev_get_next_data_producer_safe(_dev, _producer); \ + _producer != NULL; \ + _producer = _next_producer, \ + _next_producer = comp_dev_get_next_data_producer_safe(_dev, _producer)) + /* * a macro for easy iteration through component's list of consumers */ -#define comp_dev_for_each_consumer(_dev, _consumer) \ - for (_consumer = comp_dev_get_first_data_consumer(_dev); \ - _consumer != NULL; \ - _consumer = comp_dev_get_next_data_consumer(_dev, _consumer)) +#define comp_dev_for_each_consumer(_dev, _consumer) \ + for (_consumer = comp_dev_get_first_data_consumer(_dev); \ + _consumer != NULL; \ + _consumer = comp_dev_get_next_data_consumer(_dev, _consumer)) \ + +/* + * a macro for easy iteration through component's list of consumers + * allowing deletion of a buffer during iteration + * + * additional "safe storage" pointer to struct comp_buffer must be provided + */ +#define comp_dev_for_each_consumer_safe(_dev, _consumer, _next_consumer) \ + for (_consumer = comp_dev_get_first_data_consumer(_dev), \ + _next_consumer = comp_dev_get_next_data_consumer_safe(_dev, _consumer); \ + _consumer != NULL; \ + _consumer = _next_consumer, \ + _next_consumer = comp_dev_get_next_data_consumer_safe(_dev, _consumer)) /** @}*/ @@ -743,35 +850,64 @@ static inline enum sof_comp_type dev_comp_type(const struct comp_dev *dev) return dev->ipc_config.type; } +/** + * Initialize common part of a component device + * @param drv Parent component driver. + * @param dev Device. + * @param bytes Size of the component device in bytes. + */ +static inline void comp_init(const struct comp_driver *drv, + struct comp_dev *dev, size_t bytes) +{ + dev->size = bytes; + dev->drv = drv; + dev->state = COMP_STATE_INIT; + list_init(&dev->bsink_list); + list_init(&dev->bsource_list); +#ifndef __ZEPHYR__ + memcpy_s(&dev->tctx, sizeof(dev->tctx), + trace_comp_drv_get_tr_ctx(dev->drv), sizeof(struct tr_ctx)); +#endif +} + /** * Allocates memory for the component device and initializes common part. * @param drv Parent component driver. * @param bytes Size of the component device in bytes. * @return Pointer to the component device. */ -static inline struct comp_dev *comp_alloc(const struct comp_driver *drv, - size_t bytes) +static inline struct comp_dev *comp_alloc(const struct comp_driver *drv, size_t bytes) { - struct comp_dev *dev = NULL; - /* * Use uncached address everywhere to access components to rule out * 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); + struct comp_dev *dev = sof_heap_alloc(drv->user_heap, + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + bytes, 0); + if (!dev) return NULL; - dev->size = bytes; - dev->drv = drv; - dev->state = COMP_STATE_INIT; - list_init(&dev->bsink_list); - list_init(&dev->bsource_list); - memcpy_s(&dev->tctx, sizeof(struct tr_ctx), - trace_comp_drv_get_tr_ctx(dev->drv), sizeof(struct tr_ctx)); + + memset(dev, 0, sizeof(*dev)); + comp_init(drv, dev, bytes); return dev; } +/** + * Frees memory allocated for component device. + * + * This is a counterpart to comp_alloc() and not to be confused with + * comp_free(). + * + * @param dev Pointer to the component device. + */ +static inline void comp_free_device(struct comp_dev *dev) +{ + sof_heap_free(dev->drv->user_heap, dev); +} + /** * \brief Module adapter associated with a component * @param dev Component device @@ -806,11 +942,14 @@ void sys_comp_host_init(void); void sys_comp_kpb_init(void); void sys_comp_selector_init(void); +/* Start of modules in alphabetical order */ void sys_comp_module_aria_interface_init(void); +void sys_comp_module_asrc_interface_init(void); void sys_comp_module_copier_interface_init(void); void sys_comp_module_crossover_interface_init(void); void sys_comp_module_dcblock_interface_init(void); void sys_comp_module_demux_interface_init(void); +void sys_comp_module_dolby_dax_audio_processing_interface_init(void); void sys_comp_module_drc_interface_init(void); void sys_comp_module_dts_interface_init(void); void sys_comp_module_eq_fir_interface_init(void); @@ -819,18 +958,27 @@ void sys_comp_module_gain_interface_init(void); void sys_comp_module_google_rtc_audio_processing_interface_init(void); void sys_comp_module_google_ctc_audio_processing_interface_init(void); void sys_comp_module_igo_nr_interface_init(void); +void sys_comp_module_level_multiplier_interface_init(void); void sys_comp_module_mfcc_interface_init(void); void sys_comp_module_mixer_interface_init(void); void sys_comp_module_mixin_interface_init(void); void sys_comp_module_mixout_interface_init(void); void sys_comp_module_multiband_drc_interface_init(void); void sys_comp_module_mux_interface_init(void); -void sys_comp_module_asrc_interface_init(void); +void sys_comp_module_nxp_eap_interface_init(void); +void sys_comp_module_phase_vocoder_interface_init(void); void sys_comp_module_rtnr_interface_init(void); void sys_comp_module_selector_interface_init(void); +void sys_comp_module_sound_dose_interface_init(void); void sys_comp_module_src_interface_init(void); +void sys_comp_module_src_lite_interface_init(void); +void sys_comp_module_stft_process_interface_init(void); void sys_comp_module_tdfb_interface_init(void); +void sys_comp_module_tone_interface_init(void); +void sys_comp_module_template_interface_init(void); +void sys_comp_module_tester_interface_init(void); void sys_comp_module_volume_interface_init(void); +/* End of modules in alphabetical order */ #elif CONFIG_LIBRARY /* In case of shared libs components are initialised in dlopen */ @@ -861,6 +1009,15 @@ int comp_register(struct comp_driver_info *drv); */ void comp_unregister(struct comp_driver_info *drv); +/** + * Set adapter ops for a dynamically created driver. + * + * @param drv Component driver to update. + * @param ops Module interface operations. + * @return 0 or a negative error code + */ +int comp_set_adapter_ops(const struct comp_driver *drv, const struct module_interface *ops); + /** @}*/ /** @@ -1075,4 +1232,12 @@ void comp_init_performance_data(struct comp_dev *dev); */ bool comp_update_performance_data(struct comp_dev *dev, uint32_t cycles_used); +static inline int user_get_buffer_memory_region(const struct comp_driver *drv) +{ +#if CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP + return drv->user_heap ? SOF_MEM_FLAG_USER_SHARED_BUFFER : SOF_MEM_FLAG_USER; +#else + return SOF_MEM_FLAG_USER; +#endif +} #endif /* __SOF_AUDIO_COMPONENT_H__ */ diff --git a/src/include/sof/audio/component_ext.h b/src/include/sof/audio/component_ext.h index d66854f4b27d..70324175fea8 100644 --- a/src/include/sof/audio/component_ext.h +++ b/src/include/sof/audio/component_ext.h @@ -26,7 +26,6 @@ /** \brief Holds list of registered components' drivers */ struct comp_driver_list { struct list_item list; /**< list of component drivers */ - struct k_spinlock lock; /**< list lock */ }; /** \brief Retrieves the component device buffer list. */ @@ -44,17 +43,15 @@ struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init); /** See comp_ops::free */ static inline void comp_free(struct comp_dev *dev) { - assert(dev->drv->ops.free); - - /* free task if shared component or DP task*/ - if ((dev->is_shared || dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) && - dev->task) { - schedule_task_free(dev->task); - rfree(dev->task); - dev->task = NULL; - } + const struct comp_driver *drv = dev->drv; + + assert(drv->ops.free); - dev->drv->ops.free(dev); + /* + * In DP case this will run in DP thread context, so the task can only + * be freed after this. + */ + drv->ops.free(dev); } /** @@ -152,19 +149,20 @@ static inline int comp_trigger_local(struct comp_dev *dev, int cmd) int ret; ret = dev->drv->ops.trigger(dev, cmd); + if (ret) + return ret; /* start a thread in case of shared component or DP scheduling */ if (dev->task) { /* schedule or cancel task */ switch (cmd) { case COMP_TRIGGER_START: - case COMP_TRIGGER_RELEASE: - schedule_task(dev->task, 0, dev->period); + ret = schedule_task(dev->task, 0, dev->period); break; + case COMP_TRIGGER_RELEASE: case COMP_TRIGGER_XRUN: case COMP_TRIGGER_PAUSE: case COMP_TRIGGER_STOP: - schedule_task_cancel(dev->task); break; } } @@ -227,7 +225,7 @@ static inline int comp_ipc4_get_attribute_remote(struct comp_dev *dev, uint32_t if (type != COMP_ATTR_BASE_CONFIG) return -EINVAL; - base_cfg = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*base_cfg)); + base_cfg = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*base_cfg)); if (!base_cfg) return -ENOMEM; @@ -432,58 +430,59 @@ static inline struct comp_driver_list *comp_drivers_get(void) } #if CONFIG_IPC_MAJOR_4 -static inline int comp_ipc4_bind_remote(struct comp_dev *dev, void *data) +static inline int comp_ipc4_bind_remote(struct comp_dev *dev, struct bind_info *bind_data) { struct idc_msg msg = { IDC_MSG_BIND, IDC_EXTENSION(dev->ipc_config.id), dev->ipc_config.core, - sizeof(struct ipc4_module_bind_unbind), data}; + sizeof(*bind_data), bind_data}; return idc_send_msg(&msg, IDC_BLOCKING); } #endif -static inline int comp_bind(struct comp_dev *dev, void *data) +static inline int comp_bind(struct comp_dev *dev, struct bind_info *bind_data) { #if CONFIG_IPC_MAJOR_4 if (dev->drv->ops.bind) return cpu_is_me(dev->ipc_config.core) ? - dev->drv->ops.bind(dev, data) : comp_ipc4_bind_remote(dev, data); + dev->drv->ops.bind(dev, bind_data) : comp_ipc4_bind_remote(dev, bind_data); return 0; #else int ret = 0; if (dev->drv->ops.bind) - ret = dev->drv->ops.bind(dev, data); + ret = dev->drv->ops.bind(dev, bind_data); return ret; #endif } #if CONFIG_IPC_MAJOR_4 -static inline int comp_ipc4_unbind_remote(struct comp_dev *dev, void *data) +static inline int comp_ipc4_unbind_remote(struct comp_dev *dev, struct bind_info *unbind_data) { struct idc_msg msg = { IDC_MSG_UNBIND, IDC_EXTENSION(dev->ipc_config.id), dev->ipc_config.core, - sizeof(struct ipc4_module_bind_unbind), data}; + sizeof(*unbind_data), unbind_data}; return idc_send_msg(&msg, IDC_BLOCKING); } #endif -static inline int comp_unbind(struct comp_dev *dev, void *data) +static inline int comp_unbind(struct comp_dev *dev, struct bind_info *unbind_data) { #if CONFIG_IPC_MAJOR_4 if (dev->drv->ops.unbind) return cpu_is_me(dev->ipc_config.core) ? - dev->drv->ops.unbind(dev, data) : comp_ipc4_unbind_remote(dev, data); + dev->drv->ops.unbind(dev, unbind_data) : + comp_ipc4_unbind_remote(dev, unbind_data); return 0; #else int ret = 0; if (dev->drv->ops.unbind) - ret = dev->drv->ops.unbind(dev, data); + ret = dev->drv->ops.unbind(dev, unbind_data); return ret; #endif diff --git a/src/include/sof/audio/format.h b/src/include/sof/audio/format.h index 8174e53a4163..a468278531f3 100644 --- a/src/include/sof/audio/format.h +++ b/src/include/sof/audio/format.h @@ -70,6 +70,9 @@ /* Convert fractional Qnx.ny number x to float */ #define Q_CONVERT_QTOF(x, ny) ((float)(x) / ((int64_t)1 << (ny))) +/* Convert fractional Qnx.ny number x to double */ +#define Q_CONVERT_QTOD(x, ny) ((double)(x) / ((int64_t)1 << (ny))) + /* A more clever macro for Q-shifts */ #define Q_SHIFT(x, src_q, dst_q) ((x) >> ((src_q) - (dst_q))) #define Q_SHIFT_RND(x, src_q, dst_q) \ diff --git a/src/include/sof/audio/intel_uaol.h b/src/include/sof/audio/intel_uaol.h new file mode 100644 index 000000000000..e8964d2d7450 --- /dev/null +++ b/src/include/sof/audio/intel_uaol.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 Intel Corporation. All rights reserved. + */ + +#ifndef __SOF_AUDIO_INTEL_UAOL_H__ +#define __SOF_AUDIO_INTEL_UAOL_H__ + +#include <stdint.h> +#include <sof/lib/memory.h> + +struct sof_tlv; + +#if !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY +__cold void tlv_value_set_uaol_caps(struct sof_tlv *tuple, uint32_t type); +#endif /* !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY */ + +__cold int uaol_stream_id_to_hda_link_stream_id(int uaol_stream_id); + +#endif /* __SOF_AUDIO_INTEL_UAOL_H__ */ diff --git a/src/include/sof/audio/ipc-config.h b/src/include/sof/audio/ipc-config.h index 49dbb9eac217..1eb6b9cca555 100644 --- a/src/include/sof/audio/ipc-config.h +++ b/src/include/sof/audio/ipc-config.h @@ -77,7 +77,7 @@ struct ipc_config_dai { */ /**< DMA configs - required for ACE 2.0 and newer */ struct ipc_dma_config *host_dma_config[GTW_DMA_DEVICE_MAX_COUNT]; - const struct ipc4_audio_format *out_fmt;/**< audio format for output pin 0 - required + const struct ipc4_audio_format *gtw_fmt;/**< audio format for gateway DMA data - required * for ACE 2.0 and newer */ /* Gain feature flag */ diff --git a/src/include/sof/audio/kpb.h b/src/include/sof/audio/kpb.h index 7cf786796ed8..14c7b33a38e9 100644 --- a/src/include/sof/audio/kpb.h +++ b/src/include/sof/audio/kpb.h @@ -42,7 +42,7 @@ struct comp_buffer; #define KPB_MAX_BUFFER_SIZE(sw, channels_number) ((KPB_SAMPLNG_FREQUENCY / 1000) * \ (KPB_SAMPLE_CONTAINER_SIZE(sw) / 8) * KPB_MAX_BUFF_TIME * \ (channels_number)) -#define KPB_MAX_NO_OF_CLIENTS 2 +#define KPB_MAX_NO_OF_CLIENTS 4 #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 @@ -146,14 +146,22 @@ struct draining_data { struct comp_buffer *sink; struct history_buffer *hb; size_t drain_req; + size_t drained; uint8_t is_draining_active; size_t sample_width; size_t buffered_while_draining; + uint64_t draining_time_start; size_t drain_interval; + uint64_t period_copy_start; size_t pb_limit; /**< Period bytes limit */ + size_t period_bytes; + uint64_t next_copy_time; struct comp_dev *dev; bool sync_mode_on; enum comp_copy_type copy_type; + size_t task_iteration; + uint64_t prev_adjustment_time; + size_t prev_adjustment_drained; }; struct history_data { diff --git a/src/include/sof/audio/mfcc/mfcc_comp.h b/src/include/sof/audio/mfcc/mfcc_comp.h index bbc01030e157..885339004fc0 100644 --- a/src/include/sof/audio/mfcc/mfcc_comp.h +++ b/src/include/sof/audio/mfcc/mfcc_comp.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2022 Intel Corporation. All rights reserved. + * Copyright(c) 2022-2026 Intel Corporation. * * Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> */ @@ -9,16 +9,19 @@ #define __SOF_AUDIO_MFCC_MFCC_COMP_H__ #include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/data_blob.h> #include <sof/math/auditory.h> #include <sof/math/dct.h> #include <sof/math/fft.h> +#include <sof/audio/mfcc/mfcc_vad.h> +#include <sof/ipc/msg.h> #include <stddef.h> #include <stdint.h> /* __XCC__ is both for xt_xcc and xt_clang */ #if defined(__XCC__) # include <xtensa/config/core-isa.h> -# if XCHAL_HAVE_HIFI4 +# if XCHAL_HAVE_HIFI4 || XCHAL_HAVE_HIFI5 # define MFCC_HIFI4 # elif XCHAL_HAVE_HIFI3 # define MFCC_HIFI3 @@ -30,36 +33,25 @@ #endif #define MFCC_MAGIC 0x6d666363 /* ASCII for "mfcc" */ +#define MFCC_FFT_BITS 32 +#define MFCC_MAX_SAMPLE_RATE 64000 /* Max sample rate in Hz, limited by int16_t Mel scale */ -/* Set to 16 for lower RAM and MCPS with slightly lower quality. Set to 32 for best - * quality but higher MCPS and RAM. The MFCC input is currently 16 bits. With this option - * set to 32 the FFT and Mel filterbank are computed with better 32 bit precision. There - * is also need to enable 32 bit FFT from Kconfig if set. - */ -#define MFCC_FFT_BITS 16 +/** \brief Switch control index for VAD notification to user space */ +#define MFCC_CTRL_INDEX_VAD 0 -/* MFCC with 16 bit FFT benefits from data normalize, for 32 bits there's no - * significant impact. The amount of left shifts for FFT input is limited to - * 10 that equals about 60 dB boost. The boost is compensated in Mel energy - * calculation. +/** + * \brief Data header prepended to every MFCC output frame. + * + * Written before the Mel spectrum or cepstral coefficient data in each + * output frame. */ -#if MFCC_FFT_BITS == 16 -#define MFCC_NORMALIZE_FFT -#else -#undef MFCC_NORMALIZE_FFT -#endif -#define MFCC_NORMALIZE_MAX_SHIFT 10 - -/** \brief Type definition for processing function select return value. */ -typedef void (*mfcc_func)(struct processing_module *mod, - struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, - int frames); - -/** \brief MFCC processing functions map item. */ -struct mfcc_func_map { - uint8_t source; /**< source frame format */ - mfcc_func func; /**< processing function */ +struct mfcc_data_header { + uint32_t magic; /**< Magic word MFCC_MAGIC (0x6d666363) */ + uint32_t frame_number; /**< Frame number, counting calculated frames starting from 0 */ + int32_t reserved; /**< Reserved for future use, set to 0 */ + int32_t energy; /**< Weighted signal energy in Q9.23 */ + int32_t noise_energy; /**< Weighted noise floor energy in Q9.23 */ + int32_t vad_flag; /**< VAD decision: 1 = speech, 0 = silence */ }; struct mfcc_buffer { @@ -78,16 +70,13 @@ struct mfcc_pre_emph { int enable; }; +/** \brief Type definition for source/sink based input copy function. */ +typedef void (*mfcc_source_func)(struct sof_source *source, struct mfcc_buffer *buf, + struct mfcc_pre_emph *emph, int frames, int source_channel); + struct mfcc_fft { -#if MFCC_FFT_BITS == 16 - struct icomplex16 *fft_buf; /**< fft_padded_size */ - struct icomplex16 *fft_out; /**< fft_padded_size */ -#elif MFCC_FFT_BITS == 32 struct icomplex32 *fft_buf; /**< fft_padded_size */ struct icomplex32 *fft_out; /**< fft_padded_size */ -#else -#error "MFCC_FFT_BITS needs to be 16 or 32" -#endif struct fft_plan *fft_plan; int fft_fill_start_idx; /**< Set to 0 for pad left, etc. */ int fft_size; @@ -114,6 +103,8 @@ struct mfcc_state { struct mat_matrix_16b *mel_spectra; /**< Pointer to scratch */ struct mat_matrix_16b *cepstral_coef; /**< Pointer to scratch */ int32_t *power_spectra; /**< Pointer to scratch */ + int32_t *mel_log_32; /**< Pointer to scratch for 32-bit Mel output Q9.23 */ + int32_t mmax; /**< Maximum Mel value in Q9.23 */ int16_t buf_avail; int16_t *buffers; int16_t *prev_data; /**< prev_data_size */ @@ -125,18 +116,34 @@ struct mfcc_state { int low_freq; int high_freq; int sample_rate; + bool mel_only; /**< When true, output Mel spectra instead of cepstral coefficients */ bool waiting_fill; /**< booleans */ bool prev_samples_valid; + bool header_pending; /**< True when data header not yet written for current output */ + struct mfcc_data_header header; /**< Data header for current output frame */ size_t sample_buffers_size; /**< bytes */ + int32_t *out_data_ptr; /**< Read pointer into staging data for multi-period output */ + int out_remain; /**< Remaining int32_t samples to write to sink from staging */ + int32_t *out_stage; /**< Dedicated staging buffer for pending output, decoupled from STFT scratch */ + int out_stage_size; /**< Capacity of out_stage in int32_t samples */ + uint32_t hop_count; /**< FFT hop counter, increments every processed hop */ + int vad_silence_count; /**< Consecutive VAD=0 hops since last speech */ + int16_t dtx_trailing_silence; /**< Number of trailing silence hops to send, from config */ + int16_t dtx_silence_interval; /**< Send silence frame every Nth hop, 0 = disable */ + int dtx_silence_counter; /**< Counter for periodic silence frame send */ }; /* MFCC component private data */ struct mfcc_comp_data { struct mfcc_state state; + struct mfcc_vad_state vad; struct comp_data_blob_handler *model_handler; struct sof_mfcc_config *config; + struct ipc_msg *msg; /**< IPC notification for VAD switch control */ int max_frames; - mfcc_func mfcc_func; /**< processing function */ + enum sof_ipc_frame source_format; /**< Source audio format for output sizing */ + bool vad_prev; /**< Previous VAD state for edge detection */ + mfcc_source_func source_func; /**< source copy function */ }; static inline int mfcc_buffer_samples_without_wrap(struct mfcc_buffer *buffer, int16_t *ptr) @@ -154,35 +161,92 @@ static inline int16_t *mfcc_buffer_wrap(struct mfcc_buffer *buffer, int16_t *ptr int mfcc_setup(struct processing_module *mod, int max_frames, int rate, int channels); -void mfcc_free_buffers(struct mfcc_comp_data *cd); - -void mfcc_s16_default(struct processing_module *mod, struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, int frames); - -void mfcc_source_copy_s16(struct input_stream_buffer *bsource, struct mfcc_buffer *buf, - struct mfcc_pre_emph *emph, int frames, int source_channel); +void mfcc_free_buffers(struct processing_module *mod); void mfcc_fill_prev_samples(struct mfcc_buffer *buf, int16_t *prev_data, int prev_data_length); void mfcc_fill_fft_buffer(struct mfcc_state *state); -#ifdef MFCC_NORMALIZE_FFT -int mfcc_normalize_fft_buffer(struct mfcc_state *state); -#endif - void mfcc_apply_window(struct mfcc_state *state, int input_shift); +/** + * \brief Run STFT and Mel/DCT processing. + * \return Number of output coefficients produced, or 0 if not enough data. + */ +int mfcc_stft_process(struct processing_module *mod, struct mfcc_comp_data *cd); + +/** + * \brief Prepare and commit MFCC output data after STFT processing. + * + * This handles the output data conversion and dispatches to either the + * compress-output or legacy PCM-output path. + * + * \return 0 on success or a negative error code. + */ +int mfcc_process_output(struct processing_module *mod, struct mfcc_comp_data *cd, + struct sof_source **sources, struct sof_sink **sinks, + int num_ceps, int frames); + #if CONFIG_FORMAT_S16LE +void mfcc_source_copy_s16(struct sof_source *source, struct mfcc_buffer *buf, + struct mfcc_pre_emph *emph, int frames, int source_channel); +#endif + +#if CONFIG_FORMAT_S24LE +void mfcc_source_copy_s24(struct sof_source *source, struct mfcc_buffer *buf, + struct mfcc_pre_emph *emph, int frames, int source_channel); +#endif + +#if CONFIG_FORMAT_S32LE +void mfcc_source_copy_s32(struct sof_source *source, struct mfcc_buffer *buf, + struct mfcc_pre_emph *emph, int frames, int source_channel); +#endif + +#if CONFIG_IPC_MAJOR_4 +int mfcc_ipc_notification_init(struct processing_module *mod); -int16_t *mfcc_sink_copy_zero_s16(const struct audio_stream *sink, - int16_t *w_ptr, int samples); +void mfcc_send_vad_notification(struct processing_module *mod, uint32_t val); -int16_t *mfcc_sink_copy_data_s16(const struct audio_stream *sink, int16_t *w_ptr, - int samples, int16_t *r_ptr); +int mfcc_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size); + +int mfcc_set_config(struct processing_module *mod, uint32_t config_id, + enum module_cfg_fragment_position pos, uint32_t data_offset_size, + const uint8_t *fragment, size_t fragment_size, uint8_t *response, + size_t response_size); + +#else +static inline int mfcc_ipc_notification_init(struct processing_module *mod) +{ + return 0; +} -void mfcc_s16_default(struct processing_module *mod, struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, int frames); +static inline void mfcc_send_vad_notification(struct processing_module *mod, uint32_t val) +{ +} + +static inline int mfcc_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) +{ + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + struct mfcc_comp_data *cd = module_get_private_data(mod); + + return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); +} + +static inline int mfcc_set_config(struct processing_module *mod, uint32_t config_id, + enum module_cfg_fragment_position pos, uint32_t data_offset_size, + const uint8_t *fragment, size_t fragment_size, uint8_t *response, + size_t response_size) +{ + struct mfcc_comp_data *cd = module_get_private_data(mod); + + return comp_data_blob_set(cd->model_handler, pos, data_offset_size, + fragment, fragment_size); +} #endif #ifdef UNIT_TEST diff --git a/src/include/sof/audio/mfcc/mfcc_vad.h b/src/include/sof/audio/mfcc/mfcc_vad.h new file mode 100644 index 000000000000..6873343d334e --- /dev/null +++ b/src/include/sof/audio/mfcc/mfcc_vad.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + * + * Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + */ + +/** + * \file mfcc_vad.h + * \brief Voice Activity Detection based on Mel spectrum energy. + * + * This VAD operates on the Q9.23 Mel log spectrum values produced by + * the MFCC component. It tracks a per-bin noise floor that follows + * the signal downward instantly and rises slowly, then computes a + * speech-weighted energy delta above the floor. + */ + +#ifndef __SOF_AUDIO_MFCC_MFCC_VAD_H__ +#define __SOF_AUDIO_MFCC_MFCC_VAD_H__ + +#include <stdint.h> +#include <stdbool.h> + +struct processing_module; + +/** + * \brief Number of frames for fast noise floor convergence at startup (~1 s at 10 ms/frame). + */ +#define MFCC_VAD_NOISE_INIT_FRAMES 100 + +/** + * \brief Slow noise floor rise coefficient in Q1.15 (0.003 * 2^15). + */ +#define MFCC_VAD_NOISE_RISE_ALPHA 98 + +/** + * \brief Fast noise floor rise coefficient in Q1.15 (0.020 * 2^15). + */ +#define MFCC_VAD_NOISE_RISE_ALPHA_FAST 655 + +/** + * \brief Energy threshold for speech detection in Q9.23 (0.30 * 2^23). + */ +#define MFCC_VAD_ENERGY_THRESHOLD 2516582 + +/** + * \brief Hangover frame count to keep VAD active after last speech detection. + */ +#define MFCC_VAD_HANGOVER_FRAMES 20 + +/** + * \brief VAD state structure. + */ +struct mfcc_vad_state { + int32_t *noise_floor; /**< Per-bin noise floor in Q9.23 */ + int16_t *weights; /**< Speech-frequency emphasis weights Q1.15 */ + int32_t energy; /**< Weighted signal energy in Q9.23 */ + int32_t energy_threshold; /**< Energy threshold Q9.23 */ + int32_t noise_energy; /**< Weighted noise floor energy in Q9.23 */ + int16_t frame_count; /**< Initial convergence frames processed */ + int16_t hangover_counter; /**< Current hangover counter */ + int16_t hangover_max; /**< Maximum hangover frames */ + int16_t init_frames; /**< Number of initial frames for fast convergence */ + int16_t noise_rise_alpha_fast; /**< Fast rise alpha Q1.15 */ + int16_t noise_rise_alpha_slow; /**< Slow rise alpha Q1.15 */ + int16_t num_mel_bins; /**< Number of Mel bins in use */ + bool initialized; /**< True after first frame processed */ + bool is_speech; /**< Current VAD decision */ +}; + +/** + * \brief Initialize VAD state. + * + * \param[out] vad Pointer to VAD state to initialize. + * \param[in] num_mel_bins Number of Mel bins. + * \param[in] sample_rate Audio sample rate in Hz. + * \param[in] mod Processing module for memory allocation. + * \return 0 on success, negative error code on failure. + */ +int mfcc_vad_init(struct mfcc_vad_state *vad, int num_mel_bins, int32_t sample_rate, + struct processing_module *mod); + +/** + * \brief Process one Mel spectrum frame and update VAD decision. + * + * \param[in,out] vad Pointer to VAD state. + * \param[in] mel_log Mel log spectrum in Q9.23, array of num_mel_bins values. + * \return 1 if speech detected, 0 if silence. + */ +int mfcc_vad_update(struct mfcc_vad_state *vad, const int32_t *mel_log); + +#endif /* __SOF_AUDIO_MFCC_MFCC_VAD_H__ */ diff --git a/src/include/sof/audio/mic_privacy_manager.h b/src/include/sof/audio/mic_privacy_manager.h new file mode 100644 index 000000000000..61689343a37e --- /dev/null +++ b/src/include/sof/audio/mic_privacy_manager.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + */ + +#ifndef ADSP_FW_MIC_PRIVACY_MANAGER_H +#define ADSP_FW_MIC_PRIVACY_MANAGER_H + +#include <zephyr/drivers/mic_privacy/intel/mic_privacy.h> +#include <sof/lib/notifier.h> +#include <ipc4/base-config.h> +#include "../audio/copier/copier_gain.h" + +#define ADSP_RTC_FREQUENCY 32768 + +struct mic_privacy_data { + enum ipc4_sampling_frequency audio_freq; + uint32_t mic_privacy_state; + bool dma_data_zeroing; + uint32_t fade_in_out_bytes; + uint32_t max_ramp_time_in_ms; + + struct copier_gain_params mic_priv_gain_params; +}; + +struct mic_privacy_settings { + enum mic_privacy_policy mic_privacy_mode; + /* 0-Mic Unmute, 1-Mic Mute */ + uint32_t mic_privacy_state; + uint32_t max_ramp_time; + union mic_privacy_mask privacy_mask_bits; +}; + +struct privacy_capabilities { + uint32_t privacy_version; + uint32_t capabilities_length; + uint32_t capabilities[1]; +}; + +enum mic_privacy_state { + MIC_PRIV_UNMUTED, + MIC_PRIV_FADE_IN, + MIC_PRIV_FADE_OUT, + MIC_PRIV_MUTED, +}; + +int mic_privacy_manager_init(void); +int mic_privacy_manager_get_policy(void); +uint32_t mic_privacy_get_policy_register(void); +void mic_privacy_propagate_settings(struct mic_privacy_settings *settings); +uint32_t mic_privacy_get_dma_zeroing_wait_time(void); +uint32_t mic_privacy_get_privacy_mask(void); +uint32_t mic_privacy_get_mic_disable_status(void); +void mic_privacy_enable_dmic_irq(bool enable_irq); +void mic_privacy_fill_settings(struct mic_privacy_settings *settings, uint32_t mic_disable_status); +void mic_privacy_set_gtw_mic_state(struct mic_privacy_data *mic_priv_data, + uint32_t mic_disable_status); +void mic_privacy_update_gtw_mic_state(struct mic_privacy_data *mic_priv_data, + uint32_t hw_mic_disable_status); +void mic_privacy_process(struct comp_dev *dev, struct mic_privacy_data *mic_priv, + struct comp_buffer *buffer, uint32_t copy_samples); +void mic_privacy_gain_input(uint8_t *buff, uint32_t buff_size, uint32_t mic_priv_state, + const struct ipc4_audio_format *in_fmt); + +#endif /* ADSP_FW_MIC_PRIVACY_MANAGER_H */ diff --git a/src/include/sof/audio/module_adapter/iadk/iadk_module_adapter.h b/src/include/sof/audio/module_adapter/iadk/iadk_module_adapter.h index 67ac69f46d08..e01a51f8805b 100644 --- a/src/include/sof/audio/module_adapter/iadk/iadk_module_adapter.h +++ b/src/include/sof/audio/module_adapter/iadk/iadk_module_adapter.h @@ -91,9 +91,9 @@ namespace dsp_fw AdspErrorCode IadkModuleAdapter_GetConfiguration(uint32_t config_id, enum module_cfg_fragment_position fragment_position, - uint32_t data_offset_size, + uint32_t &data_offset_size, uint8_t *fragment_buffer, - size_t fragment_size); + size_t &fragment_size); /** * Module specific reset procedure, called as part of codec_adapter component * reset in .reset(). This should reset all parameters to their initial stage @@ -144,10 +144,22 @@ int iadk_wrapper_set_configuration(void *md, uint32_t config_id, const uint8_t *fragment, size_t fragment_size, uint8_t *response, size_t response_size); +/* + * \brief Retrieve module configuration + * \param[in] md - struct IadkModuleAdapter pointer + * \param[in] config_id - Configuration ID + * \param[in] pos - position of the fragment in the large message + * \param[in] data_offset_size: size of the whole configuration if it is the first fragment or the + * only fragment. Otherwise, it is the offset of the fragment in the whole configuration. + * \param[in] fragment: configuration fragment buffer + * \param[in,out] fragment_size: size of @fragment + * + * \return: 0 upon success or error upon failure + */ int iadk_wrapper_get_configuration(void *md, uint32_t config_id, enum module_cfg_fragment_position pos, - uint32_t data_offset_size, - uint8_t *fragment, size_t fragment_size); + uint32_t *data_offset_size, + uint8_t *fragment, size_t *fragment_size); int iadk_wrapper_process(void *md, struct sof_source **sources, int num_of_sources, diff --git a/src/include/sof/audio/module_adapter/iadk/system_agent.h b/src/include/sof/audio/module_adapter/iadk/system_agent.h index 65afd2f82c14..e7aab98c748c 100644 --- a/src/include/sof/audio/module_adapter/iadk/system_agent.h +++ b/src/include/sof/audio/module_adapter/iadk/system_agent.h @@ -107,8 +107,9 @@ extern "C" { * method (the variant with 7 parameters) via a parameter that initially contained the address to * the agent system. The system_agent_start function returns it in the variable adapter. */ -int system_agent_start(uint32_t entry_point, uint32_t module_id, uint32_t instance_id, - uint32_t core_id, uint32_t log_handle, void *mod_cfg, void **adapter); +struct system_agent_params; + +int system_agent_start(const struct system_agent_params *params, const void **adapter); #ifdef __cplusplus } #endif diff --git a/src/include/sof/audio/module_adapter/library/native_system_agent.h b/src/include/sof/audio/module_adapter/library/native_system_agent.h index 7faf802debe1..70c0f6b1aad1 100644 --- a/src/include/sof/audio/module_adapter/library/native_system_agent.h +++ b/src/include/sof/audio/module_adapter/library/native_system_agent.h @@ -11,6 +11,18 @@ #include <sof/audio/module_adapter/module/module_interface.h> #include <native_system_service.h> +struct system_agent_params { + uintptr_t entry_point; /* The module entry point function address. */ + uint32_t module_id; /* The identifier for the module. */ + uint32_t instance_id; /* The instance identifier of the module. */ + uint32_t core_id; /* Core on which the module will run. */ + uint32_t log_handle; /* The handle for logging purposes. */ + void *mod_cfg; /* Pointer to the module configuration data. */ +}; + +typedef int (*system_agent_start_fn)(const struct system_agent_params *params, + const void **adapter); + struct native_system_agent { struct system_service system_service; uint32_t log_handle; @@ -20,7 +32,17 @@ struct native_system_agent { uint32_t module_size; }; -void *native_system_agent_start(uint32_t entry_point, uint32_t module_id, uint32_t instance_id, - uint32_t core_id, uint32_t log_handle, void *mod_cfg); +/** + * @brief Starts the native system agent. + * + * This function initializes and starts the native system agent with the provided parameters. + * + * @param[in] params - Pointer to the system agent parameter structure + * @param[out] iface - Pointer to the module interface. + * + * @return Returns 0 on success or an error code on failure. + */ +int native_system_agent_start(const struct system_agent_params *params, + const void **iface); #endif /* __NATIVE_SYSTEM_AGENT_H__ */ diff --git a/src/include/sof/audio/module_adapter/library/native_system_service.h b/src/include/sof/audio/module_adapter/library/native_system_service.h index db054cfd821c..ab8188a2eca4 100644 --- a/src/include/sof/audio/module_adapter/library/native_system_service.h +++ b/src/include/sof/audio/module_adapter/library/native_system_service.h @@ -7,7 +7,6 @@ #define NATIVE_SYSTEM_SERVICE_H #include <stdint.h> -#include <adsp_stddef.h> #ifdef __cplusplus extern "C" { diff --git a/src/include/sof/audio/module_adapter/library/userspace_proxy.h b/src/include/sof/audio/module_adapter/library/userspace_proxy.h new file mode 100644 index 000000000000..482590caf67f --- /dev/null +++ b/src/include/sof/audio/module_adapter/library/userspace_proxy.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + * Author: Jaroslaw Stelter <jaroslaw.stelter@intel.com> + * Author: Adrian Warecki <adrian.warecki@intel.com> + */ + +#ifndef __SOF_AUDIO_USERSPACE_PROXY_H__ +#define __SOF_AUDIO_USERSPACE_PROXY_H__ + +#if CONFIG_USERSPACE +#include <stdint.h> +#include <stdbool.h> + +#include <zephyr/kernel.h> +#include <zephyr/app_memory/app_memdomain.h> +#include <utilities/array.h> + +#include <native_system_agent.h> +#include <module/module/interface.h> +#include <sof/audio/module_adapter/library/userspace_proxy_user.h> + +struct module_interface; +struct comp_driver; +struct sof_man_module; +struct system_agent_params; + +/* Processing module structure fields needed for user mode */ +struct userspace_context { + struct k_mem_domain *comp_dom; /* Module specific memory domain */ + const struct module_interface *interface; /* Userspace module interface */ + struct user_work_item *work_item; /* work item for user worker thread */ + struct k_event *dp_event; /* DP thread event */ +}; +#endif /* CONFIG_USERSPACE */ + +#if CONFIG_SOF_USERSPACE_PROXY +/** + * Creates userspace module proxy + * + * @param user_ctx - pointer to pointer of userspace module context + * @param drv - pointer to component driver + * @param manifest - pointer to module manifest + * @param start_fn - pointer to system agent start function + * @param agent_params - pointer to system_agent_params + * @param agent_interface - pointer to variable to store module interface created by agent + * @param ops - Pointer to a variable that will hold the address of the module interface + * structure. The function stores a pointer to its own userspace proxy + * interface structure in this variable. + * + * @return 0 for success, error otherwise. + */ +int userspace_proxy_create(struct userspace_context **user_ctx, const struct comp_driver *drv, + const struct sof_man_module *manifest, system_agent_start_fn start_fn, + const struct system_agent_params *agent_params, + const void **agent_interface, const struct module_interface **ops); + +/** + * Destroy userspace module proxy + * + * @param drv - pointer to component driver + * @param user_ctx - pointer to userspace module context + */ +void userspace_proxy_destroy(const struct comp_driver *drv, struct userspace_context *user_ctx); + +#if IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) +/** + * Register a k_event object used to notify the DP thread about a pending userspace module IPC + * request to process. + * + * @param mod Pointer to the processing module. + * @param event Pointer to the event to signal incoming IPC. + * + * @return Pointer to a k_work_user work item for userspace modules, or NULL for non-userspace + * modules. + */ +struct k_work_user *userspace_proxy_register_ipc_handler(struct processing_module *mod, + struct k_event *event); +#endif + +#endif /* CONFIG_SOF_USERSPACE_PROXY */ + +#endif /* __SOF_AUDIO_USERSPACE_PROXY_H__ */ diff --git a/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h b/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h new file mode 100644 index 000000000000..e571705cec17 --- /dev/null +++ b/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + * Author: Adrian Warecki <adrian.warecki@intel.com> + */ + +#ifndef __SOF_AUDIO_USERSPACE_PROXY_USER_H__ +#define __SOF_AUDIO_USERSPACE_PROXY_USER_H__ + +#if CONFIG_SOF_USERSPACE_PROXY +struct module_agent_params { + system_agent_start_fn start_fn; + struct system_agent_params params; + byte_array_t mod_cfg; + const void *out_interface; +}; + +struct module_large_cfg_set_params { + uint32_t config_id; + enum module_cfg_fragment_position pos; + uint32_t data_off_size; + const uint8_t *fragment; + size_t fragment_size; + uint8_t *response; + size_t response_size; +}; + +struct module_large_cfg_get_params { + uint32_t config_id; + uint32_t *data_off_size; + uint8_t *fragment; + size_t fragment_size; +}; + +struct module_processing_mode_params { + enum module_processing_mode mode; +}; + +struct module_process_params { + struct sof_source **sources; + int num_of_sources; + struct sof_sink **sinks; + int num_of_sinks; +}; + +enum userspace_proxy_cmd { + USER_PROXY_MOD_CMD_AGENT_START, + USER_PROXY_MOD_CMD_INIT, + USER_PROXY_MOD_CMD_PREPARE, + USER_PROXY_MOD_CMD_PROC_READY, + USER_PROXY_MOD_CMD_SET_PROCMOD, + USER_PROXY_MOD_CMD_GET_PROCMOD, + USER_PROXY_MOD_CMD_SET_CONF, + USER_PROXY_MOD_CMD_GET_CONF, + USER_PROXY_MOD_CMD_BIND, + USER_PROXY_MOD_CMD_UNBIND, + USER_PROXY_MOD_CMD_RESET, + USER_PROXY_MOD_CMD_FREE, + USER_PROXY_MOD_CMD_TRIGGER +}; + +struct module_params { + enum userspace_proxy_cmd cmd; + int status; + struct processing_module *mod; + struct userspace_context *context; + /* The field used in the union depends on the value of cmd */ + union { + struct module_agent_params agent; + struct module_large_cfg_set_params set_conf; + struct module_large_cfg_get_params get_conf; + struct module_processing_mode_params proc_mode; + struct module_process_params proc; + struct bind_info *bind_data; + int trigger_data; + } ext; +}; + +struct user_work_item { + struct k_work_user work_item; /* ipc worker workitem */ + struct k_event *event; /* ipc worker done event */ + struct module_params params; +}; + +void userspace_proxy_handle_request(struct processing_module *mod, struct module_params *params); + +void userspace_proxy_worker_handler(struct k_work_user *work_item); + +#endif /* CONFIG_SOF_USERSPACE_PROXY */ + +#endif /* __SOF_AUDIO_USERSPACE_PROXY_USER_H__ */ diff --git a/src/include/sof/audio/module_adapter/module/cadence.h b/src/include/sof/audio/module_adapter/module/cadence.h index 954594f80aa3..08319a9b3d10 100644 --- a/src/include/sof/audio/module_adapter/module/cadence.h +++ b/src/include/sof/audio/module_adapter/module/cadence.h @@ -17,6 +17,7 @@ #define LIB_NO_ERROR XA_NO_ERROR #define LIB_IS_FATAL_ERROR(e) ((e) & XA_FATAL_ERROR) #define CODEC_GET_API_ID(id) ((id) & 0xFF) +#define CADENCE_MP3_ENCODER_DEFAULT_BITRATE 320 /*****************************************************************************/ /* Cadence API functions */ @@ -32,6 +33,16 @@ extern xa_codec_func_t xa_sbc_dec; extern xa_codec_func_t xa_vorbis_dec; extern xa_codec_func_t xa_src_pp; +#define DEFAULT_CODEC_ID CADENCE_CODEC_WRAPPER_ID + +#define API_CALL(cd, cmd, sub_cmd, value, ret) \ + do { \ + ret = (cd)->api((cd)->self, \ + (cmd), \ + (sub_cmd), \ + (value)); \ + } while (0) + /*****************************************************************************/ /* Cadence private data types */ /*****************************************************************************/ @@ -40,15 +51,37 @@ struct cadence_api { xa_codec_func_t *api; }; +struct ipc_msg; + struct cadence_codec_data { +#if CONFIG_IPC_MAJOR_4 + struct ipc4_base_module_cfg base_cfg; + uint32_t direction; + struct ipc_msg *msg; +#endif char name[LIB_NAME_MAX_LEN]; void *self; xa_codec_func_t *api; void *mem_tabs; + size_t mem_to_be_freed_len; + void **mem_to_be_freed; uint32_t api_id; struct module_config setup_cfg; }; +enum cadence_api_id { + CADENCE_CODEC_WRAPPER_ID = 0x01, + CADENCE_CODEC_AAC_DEC_ID = 0x02, + CADENCE_CODEC_BSAC_DEC_ID = 0x03, + CADENCE_CODEC_DAB_DEC_ID = 0x04, + CADENCE_CODEC_DRM_DEC_ID = 0x05, + CADENCE_CODEC_MP3_DEC_ID = 0x06, + CADENCE_CODEC_SBC_DEC_ID = 0x07, + CADENCE_CODEC_VORBIS_DEC_ID = 0x08, + CADENCE_CODEC_SRC_PP_ID = 0x09, + CADENCE_CODEC_MP3_ENC_ID = 0x0A, +}; + #if CONFIG_IPC_MAJOR_4 struct ipc4_cadence_module_cfg { struct ipc4_base_module_cfg base_cfg; @@ -57,4 +90,30 @@ struct ipc4_cadence_module_cfg { } __packed __aligned(4); #endif +extern struct cadence_api cadence_api_table[]; + +int cadence_codec_set_configuration(struct processing_module *mod, uint32_t config_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, const uint8_t *fragment, + size_t fragment_size, uint8_t *response, size_t response_size); +int cadence_codec_resolve_api_with_id(struct processing_module *mod, uint32_t codec_id, + uint32_t direction); +int cadence_codec_apply_params(struct processing_module *mod, int size, void *data); +int cadence_codec_process_data(struct processing_module *mod, + XA_ERRORCODE *api_error_code); +int cadence_codec_apply_config(struct processing_module *mod); +void cadence_codec_free_memory_tables(struct processing_module *mod); +int cadence_codec_init_memory_tables(struct processing_module *mod); +unsigned int cadence_codec_get_samples(struct processing_module *mod); +int cadence_codec_init_process(struct processing_module *mod); +int cadence_init_codec_object(struct processing_module *mod); +int cadence_codec_resolve_api(struct processing_module *mod); +int cadence_codec_free(struct processing_module *mod); +size_t cadence_api_table_size(void); +void cadence_copy_data_from_buffer(void *dest, const void *buffer_ptr, size_t bytes_to_copy, + size_t buffer_size, void const *buffer_start); +void cadence_copy_data_to_buffer(void *buffer_ptr, size_t bytes_to_copy, + size_t buffer_size, void *buffer_start, + const void *src); + #endif /* __SOF_AUDIO_CADENCE_CODEC__ */ diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index f8081c6b4c6a..6740593a7cf1 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -13,12 +13,16 @@ #ifndef __SOF_AUDIO_MODULE_GENERIC__ #define __SOF_AUDIO_MODULE_GENERIC__ -#include <sof/audio/component.h> +#include <rtos/mutex.h> +#include <sof/objpool.h> #include <sof/ut.h> +#include <sof/audio/component.h> #include <sof/audio/sink_api.h> #include <sof/audio/source_api.h> #include "module_interface.h" +#include <sof/compiler_attributes.h> + /* * helpers to determine processing type * Needed till all the modules use PROCESSING_MODE_SINK_SOURCE @@ -27,23 +31,22 @@ #define IS_PROCESSING_MODE_RAW_DATA(mod) ((mod)->proc_type == MODULE_PROCESS_TYPE_RAW) #define IS_PROCESSING_MODE_SINK_SOURCE(mod) ((mod)->proc_type == MODULE_PROCESS_TYPE_SOURCE_SINK) -#define MAX_BLOB_SIZE 8192 -#define MODULE_MAX_SOURCES 8 - -#define API_CALL(cd, cmd, sub_cmd, value, ret) \ - do { \ - ret = (cd)->api((cd)->self, \ - (cmd), \ - (sub_cmd), \ - (value)); \ - } while (0) - #if CONFIG_IPC_MAJOR_4 #define IPC_MOD_CMD(v) #elif CONFIG_IPC_MAJOR_3 #define IPC_MOD_CMD(v) .cmd = v, #endif +/* + * \brief Macro to declare a module adapter component. + * \param adapter - name of the module. + * \param uuid - UUID of the module. + * \param tr - trace context for the module. + * + * This macro declares a module component with the specified name, UUID, and trace context. + * It initializes the component module structure with the appropriate type, UID, and + * struct module_interface operations. + */ #define DECLARE_MODULE_ADAPTER(adapter, uuid, tr) \ static const struct comp_driver comp_##adapter##_module = { \ .type = SOF_COMP_MODULE_ADAPTER, \ @@ -61,6 +64,7 @@ static const struct comp_driver comp_##adapter##_module = { \ .set_large_config = module_set_large_config,\ .get_large_config = module_get_large_config,\ .get_attribute = module_adapter_get_attribute,\ + .set_attribute = module_adapter_set_attribute,\ .bind = module_adapter_bind,\ .unbind = module_adapter_unbind,\ .get_total_data_processed = module_adapter_get_total_data_processed,\ @@ -80,8 +84,7 @@ static SHARED_DATA struct comp_driver_info comp_module_##adapter##_info = { \ \ UT_STATIC void sys_comp_module_##adapter##_init(void) \ { \ - comp_register(platform_shared_get(&comp_module_##adapter##_info, \ - sizeof(comp_module_##adapter##_info))); \ + comp_register(&comp_module_##adapter##_info); \ } \ \ DECLARE_MODULE(sys_comp_module_##adapter##_init) @@ -91,10 +94,10 @@ DECLARE_MODULE(sys_comp_module_##adapter##_init) * \brief Module-specific states */ enum module_state { - MODULE_DISABLED, /**< Module isn't initialized yet or has been freed.*/ - MODULE_INITIALIZED, /**< Module initialized or reset. */ - MODULE_IDLE, /**< Module is idle now. */ - MODULE_PROCESSING, /**< Module is processing samples now. */ + MODULE_DISABLED, /**< Module isn't initialized yet or has been freed.*/ + MODULE_INITIALIZED, /**< Module initialized or reset. */ + MODULE_IDLE, /**< Module is idle now. */ + MODULE_PROCESSING, /**< Module is processing samples now. */ }; /** @@ -111,17 +114,44 @@ struct module_param { * sample_rate may have an id of 0x01. */ uint32_t id; - uint32_t size; /**< The size of whole parameter - id + size + data */ - int32_t data[]; /**< A pointer to memory where config is stored.*/ + uint32_t size; /**< The size of whole parameter - id + size + data */ + int32_t data[]; /**< A pointer to memory where config is stored.*/ +}; + +/** + * \struct module_resources + * \brief module resources block - used for module allocation records + * The allocations are recorded so that they can be automatically freed + * when the module unloads. + */ +struct module_resources { + struct k_mutex lock; + struct objpool_head objpool; + size_t heap_usage; + size_t heap_high_water_mark; + struct mod_alloc_ctx *alloc; +}; + +enum mod_resource_type { + MOD_RES_UNINITIALIZED = 0, + MOD_RES_HEAP, + MOD_RES_BLOB_HANDLER, + MOD_RES_FAST_GET, }; /** - * \struct module_memory - * \brief module memory block - used for every memory allocated by module + * \struct module_resource + * \brief module memory container - used for every memory allocated by module */ -struct module_memory { - void *ptr; /**< A pointr to particular memory block */ - struct list_item mem_list; /**< list of memory allocated by module */ +struct module_resource { + union { + void *ptr; /**< Pointer to heap allocated memory */ + struct comp_data_blob_handler *bhp; /**< Blob handler ptr */ + const void *sram_ptr; /**< SRAM ptr from fast_get() */ + }; + struct list_item list; /**< list element */ + size_t size; /**< Size of allocated heap memory, 0 if not from heap */ + enum mod_resource_type type; /**< Resource type */ }; /** @@ -135,6 +165,8 @@ struct module_processing_data { uint32_t produced; /**< Specifies how much data the module produced in its last task.*/ uint32_t consumed; /**< Specified how much data the module consumed in its last task */ uint32_t init_done; /**< Specifies if the module initialization is finished */ + bool eos_reached; /**< End of stream processing is reached */ + bool eos_notification_sent; /**< EOS notification is sent to host */ void *in_buff; /**< A pointer to module input buffer. */ void *out_buff; /**< A pointer to module output buffer. */ }; @@ -153,13 +185,105 @@ struct module_processing_data { /*****************************************************************************/ int module_load_config(struct comp_dev *dev, const void *cfg, size_t size); int module_init(struct processing_module *mod); -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); +#if defined(__ZEPHYR__) && defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) +__syscall void *mod_balloc_align(struct processing_module *mod, size_t size, size_t alignment); +#else +void *z_impl_mod_balloc_align(struct processing_module *mod, size_t size, size_t alignment); +#define mod_balloc_align z_impl_mod_balloc_align +#endif +void mod_resource_init(struct processing_module *mod); +void mod_heap_info(struct processing_module *mod, size_t *size, uintptr_t *start); +#if defined(__ZEPHYR__) && defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) +__syscall void *mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size, + size_t alignment); +__syscall int mod_free(struct processing_module *mod, const void *ptr); +#else +void *z_impl_mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size, + size_t alignment); +int z_impl_mod_free(struct processing_module *mod, const void *ptr); +#define mod_alloc_ext z_impl_mod_alloc_ext +#define mod_free z_impl_mod_free +#endif + +/** + * Allocates aligned memory block for module. + * @param mod Pointer to the module this memory block is allocated for. + * @param size Size in bytes. + * @param alignment Alignment in bytes. + * @return Pointer to the allocated memory or NULL if failed. + * + * The allocated memory is automatically freed when the module is unloaded. + */ +static inline void *mod_alloc_align(struct processing_module *mod, size_t size, size_t alignment) +{ + return mod_alloc_ext(mod, SOF_MEM_FLAG_USER, size, alignment); +} + +static inline void *mod_balloc(struct processing_module *mod, size_t size) +{ + return mod_balloc_align(mod, size, 0); +} + +static inline void *mod_alloc(struct processing_module *mod, size_t size) +{ + return mod_alloc_align(mod, size, 0); +} + +static inline void *mod_zalloc(struct processing_module *mod, size_t size) +{ + void *ret = mod_alloc(mod, size); + + if (ret) + memset(ret, 0, size); + + return ret; +} + +#if CONFIG_COMP_BLOB +#if defined(__ZEPHYR__) && defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) +__syscall struct comp_data_blob_handler *mod_data_blob_handler_new(struct processing_module *mod); +#else +struct comp_data_blob_handler *z_impl_mod_data_blob_handler_new(struct processing_module *mod); +#define mod_data_blob_handler_new z_impl_mod_data_blob_handler_new +#endif +void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_blob_handler *dbh); +#endif +#if CONFIG_FAST_GET +#if defined(__ZEPHYR__) && defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) +__syscall const void *mod_fast_get(struct processing_module *mod, const void * const dram_ptr, + size_t size); +#else +const void *z_impl_mod_fast_get(struct processing_module *mod, const void * const dram_ptr, + size_t size); +#define mod_fast_get z_impl_mod_fast_get +#endif +void mod_fast_put(struct processing_module *mod, const void *sram_ptr); +#endif +void mod_free_all(struct processing_module *mod); int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks); +static inline +bool generic_module_is_ready_to_process(struct processing_module *mod, + struct sof_source **sources, + int num_of_sources, + struct sof_sink **sinks, + int num_of_sinks) +{ + int i; + + for (i = 0; i < num_of_sources; i++) + if (source_get_data_available(sources[i]) < source_get_min_available(sources[i])) + return false; + + for (i = 0; i < num_of_sinks; i++) + if (sink_get_free_size(sinks[i]) < sink_get_min_free_space(sinks[i])) + return false; + + return true; +} + static inline bool module_is_ready_to_process(struct processing_module *mod, struct sof_source **sources, @@ -167,7 +291,6 @@ bool module_is_ready_to_process(struct processing_module *mod, struct sof_sink **sinks, int num_of_sinks) { - int i; const struct module_interface *const ops = mod->dev->drv->adapter_ops; /* LL module has to be always ready for processing */ @@ -179,15 +302,8 @@ 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 */ - for (i = 0; i < num_of_sources; i++) - if (source_get_data_available(sources[i]) < source_get_min_available(sources[i])) - return false; - - for (i = 0; i < num_of_sinks; i++) - if (sink_get_free_size(sinks[i]) < sink_get_min_free_space(sinks[i])) - return false; - - return true; + return generic_module_is_ready_to_process(mod, sources, num_of_sources, sinks, + num_of_sinks); } int module_process_sink_src(struct processing_module *mod, @@ -204,11 +320,16 @@ int module_set_configuration(struct processing_module *mod, enum module_cfg_fragment_position pos, size_t data_offset_size, const uint8_t *fragment, size_t fragment_size, uint8_t *response, size_t response_size); -int module_bind(struct processing_module *mod, void *data); -int module_unbind(struct processing_module *mod, void *data); +int module_bind(struct processing_module *mod, struct bind_info *bind_data); +int module_unbind(struct processing_module *mod, struct bind_info *unbind_data); struct comp_dev *module_adapter_new(const struct comp_driver *drv, const struct comp_ipc_config *config, const void *spec); +struct userspace_context; +struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, + const struct comp_ipc_config *config, const void *spec, + void *mod_priv, struct userspace_context *user_ctx, + const struct module_interface *ops); 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); @@ -217,6 +338,8 @@ 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); +size_t module_adapter_heap_usage(struct processing_module *mod, size_t *hwm); + #if CONFIG_IPC_MAJOR_3 static inline int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value) @@ -224,6 +347,12 @@ int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *valu return -EINVAL; } +static inline +int module_adapter_set_attribute(struct comp_dev *dev, uint32_t type, void *value) +{ + return -EINVAL; +} + 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) @@ -239,13 +368,13 @@ int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ } static inline -int module_adapter_bind(struct comp_dev *dev, void *data) +int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data) { return 0; } static inline -int module_adapter_unbind(struct comp_dev *dev, void *data) +int module_adapter_unbind(struct comp_dev *dev, struct bind_info *unbind_data) { return 0; } @@ -273,8 +402,9 @@ int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ 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); +int module_adapter_set_attribute(struct comp_dev *dev, uint32_t type, void *value); +int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data); +int module_adapter_unbind(struct comp_dev *dev, struct bind_info *unbind_data); uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, uint32_t stream_no, bool input); @@ -307,7 +437,18 @@ int module_adapter_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd); void module_update_buffer_position(struct input_stream_buffer *input_buffers, struct output_stream_buffer *output_buffers, uint32_t frames); - +struct module_ext_init_data; +#if CONFIG_IPC_MAJOR_4 +int module_ext_init_decode(const struct comp_driver *drv, struct module_ext_init_data *ext_data, + struct ipc_config_process *spec); +#else +static inline +int module_ext_init_decode(const struct comp_driver *drv, struct module_ext_init_data *ext_data, + struct ipc_config_process *spec) +{ + return 0; +} +#endif int module_adapter_init_data(struct comp_dev *dev, struct module_config *dst, const struct comp_ipc_config *config, @@ -319,4 +460,33 @@ void module_adapter_set_params(struct processing_module *mod, struct sof_ipc_str int module_adapter_set_state(struct processing_module *mod, struct comp_dev *dev, int cmd); int module_adapter_sink_src_prepare(struct comp_dev *dev); + +/** + * Get a deadline based on current LFT reported by all sinks + * it returns a value >= UINT32_MAX / 2 in case the deadline cannot be calculated: + * - if a module is in a dealayed start + * - if there's no sink - i.e. DP module is a pure data consumer (like key phrare detector) + * + * @return a deadline the module must finish processing since NOW [in us] + */ +uint32_t module_get_deadline(struct processing_module *mod); + +/** + * Get a Longest Processing Time estimation for the module, in us + * It is either + * - a value taken from the manifest or estimated from module period (TODO) + * - or a value taken from IPC call (TODO) + * - a worst case - module period + * note that module period may be calculated reasonably late, i.e. in prepare() method + */ +static inline uint32_t module_get_lpt(struct processing_module *mod) +{ + /* return worst case of LPT - a module period. See zephyr_dp_schedule.c for description */ + return mod->dev->period; +} + +#if defined(__ZEPHYR__) && defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) +#include <zephyr/syscalls/generic.h> +#endif + #endif /* __SOF_AUDIO_MODULE_GENERIC__ */ diff --git a/src/include/sof/audio/nxp/eap/EAP_Parameter_presets.h b/src/include/sof/audio/nxp/eap/EAP_Parameter_presets.h new file mode 100644 index 000000000000..745db5579fd0 --- /dev/null +++ b/src/include/sof/audio/nxp/eap/EAP_Parameter_presets.h @@ -0,0 +1,25 @@ +#ifndef EAP_PARAMETER_PRESETS_H_ +#define EAP_PARAMETER_PRESETS_H_ + +#include <nxp/eap/EAP_Includes/EAP16.h> + +#ifndef CONFIG_COMP_NXP_EAP_STUB +#include <Example_Application/CONFIG_HEADER/EAP_Parameter_AllEffectOff.h> +#include <Example_Application/CONFIG_HEADER/EAP_Parameter_AutoVolumeLeveler.h> +#include <Example_Application/CONFIG_HEADER/EAP_Parameter_ConcertSound.h> +#include <Example_Application/CONFIG_HEADER/EAP_Parameter_LoudnessMaximiser.h> +#include <Example_Application/CONFIG_HEADER/EAP_Parameter_MusicEnhancerRMSLimiter.h> +#include <Example_Application/CONFIG_HEADER/EAP_Parameter_VoiceEnhancer.h> + +#else + +uint8_t InstParams_allEffectOff[28] = {}; +uint8_t ControlParamSet_allEffectOff[216] = {}; +uint8_t ControlParamSet_autoVolumeLeveler[216] = {}; +uint8_t ControlParamSet_concertSound[216] = {}; +uint8_t ControlParamSet_loudnessMaximiser[216] = {}; +uint8_t ControlParamSet_musicEnhancerRmsLimiter[216] = {}; +uint8_t ControlParamSet_voiceEnhancer[216] = {}; +#endif + +#endif /* EAP_PARAMETER_PRESETS_H_ */ diff --git a/src/include/sof/audio/nxp/eap/eap_lib_defines.h b/src/include/sof/audio/nxp/eap/eap_lib_defines.h new file mode 100644 index 000000000000..5ccee83c5605 --- /dev/null +++ b/src/include/sof/audio/nxp/eap/eap_lib_defines.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2025 NXP + */ + +#ifndef EAP_LIB_DEFINES_H_ +#define EAP_LIB_DEFINES_H_ + +#define LVCS_MS_COEFFS_SMALL 1 +#define ALGORITHM_CS 1 +#define ALGORITHM_DBE 1 +#define ALGORITHM_EQNB 1 +#define ALGORITHM_PR_EQNB 1 +#define ALGORITHM_LM 1 +#define ALGORITHM_TE 1 +#define ALGORITHM_TG 1 +#define ALGORITHM_AVL 1 +#define ALGORITHM_PSA 1 +#define ALGORITHM_VC 1 +#define ALGORITHM_LIMP 1 +#define ALGORITHM_LIMR 1 +#define ALGORITHM_XO 1 +#define NXP_PLATFORM_PROTECTION 0 + +#endif /* EAP_LIB_DEFINES_H_ */ diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index f7ca0e999e2c..913a569c208c 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -25,6 +25,7 @@ struct comp_buffer; struct comp_dev; struct ipc; struct ipc_msg; +struct k_heap; /* * Pipeline status to stop execution of current path, but to keep the @@ -52,6 +53,7 @@ struct ipc_msg; * Audio pipeline. */ struct pipeline { + struct k_heap *heap; /**< heap used for allocating this pipeline */ uint32_t comp_id; /**< component id for pipeline */ uint32_t pipeline_id; /**< pipeline id */ uint32_t sched_id; /**< Scheduling component id */ @@ -68,6 +70,7 @@ struct pipeline { int32_t xrun_bytes; /* last xrun length */ uint32_t status; /* pipeline status */ struct tr_ctx tctx; /* trace settings */ + bool expect_eos; /* pipeline is expecting end of stream */ /* scheduling */ struct task *pipe_task; /* pipeline processing task */ @@ -133,6 +136,13 @@ struct pipeline_task { struct comp_dev *sched_comp; /**< pipeline scheduling component */ }; +struct ipc4_pipeline_ext_obj_mem_data; + +/** \brief For storing IPC payload data. */ +struct create_pipeline_params { + const struct ipc4_pipeline_ext_obj_mem_data *mem_data; +}; + #define pipeline_task_get(t) container_of(t, struct pipeline_task, task) /* @@ -144,12 +154,15 @@ struct pipeline_task { /** * \brief Creates a new pipeline. + * \param[in] heap Heap to allocate the pipeline on, or NULL for default. * \param[in] pipeline_id Pipeline ID number. * \param[in] priority Pipeline scheduling priority. * \param[in] comp_id Pipeline component ID number. + * \param[in] pparams Pipeline parameters from IPC payload, maybe NULL. * \return New pipeline pointer or NULL. */ -struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t comp_id); +struct pipeline *pipeline_new(struct k_heap *heap, uint32_t pipeline_id, uint32_t priority, + uint32_t comp_id, struct create_pipeline_params *pparams); /** * \brief Free's a pipeline. @@ -256,7 +269,7 @@ int pipeline_params(struct pipeline *p, struct comp_dev *cd, struct sof_ipc_pcm_params *params); /** - * \brief Creates a new pipeline. + * \brief Prepares pipeline for processing. * \param[in] p pipeline. * \param[in,out] cd Pipeline component device. * \return 0 on success. @@ -356,9 +369,9 @@ int pipeline_comp_ll_task_init(struct pipeline *p); int pipeline_comp_dp_task_init(struct comp_dev *comp); /** - * \brief Free's a pipeline. + * \brief Schedule a pipeline copy to run after a delay * \param[in] p pipeline. - * \param[in] start Pipelien start time in microseconds. + * \param[in] start Pipeline start time in microseconds. */ void pipeline_schedule_copy(struct pipeline *p, uint64_t start); @@ -431,4 +444,11 @@ void pipeline_xrun(struct pipeline *p, struct comp_dev *dev, int32_t bytes); */ int pipeline_xrun_set_limit(struct pipeline *p, uint32_t xrun_limit_usecs); +/** + * \brief Sends an ipc notification that an error occurred in the module's processing function. + * \param[in] component The component in which the error occurred. + * \param[in] error_code Error code. + */ +void pipeline_comp_copy_error_notify(const struct comp_dev *component, int error_code); + #endif /* __SOF_AUDIO_PIPELINE_H__ */ diff --git a/src/include/sof/audio/ring_buffer.h b/src/include/sof/audio/ring_buffer.h index 222b102f2ae9..1ef712a56743 100644 --- a/src/include/sof/audio/ring_buffer.h +++ b/src/include/sof/audio/ring_buffer.h @@ -97,6 +97,7 @@ * always means "buffer full" */ +struct comp_dev; struct ring_buffer; struct sof_audio_stream_params; @@ -114,6 +115,7 @@ struct ring_buffer { /** * + * @param dev pointer to the DP module device structure * @param min_available minimum data available in queue required by the module using * ring_buffer's source api * @param min_free_space minimum buffer space in queue required by the module using @@ -122,7 +124,8 @@ struct ring_buffer { * @param id a stream ID, accessible later by sink_get_id/source_get_id * */ -struct ring_buffer *ring_buffer_create(size_t min_available, size_t min_free_space, bool is_shared, +struct ring_buffer *ring_buffer_create(struct comp_dev *dev, size_t min_available, + size_t min_free_space, bool is_shared, uint32_t id); #endif /* __SOF_RING_BUFFER_H__ */ diff --git a/src/include/sof/audio/selector.h b/src/include/sof/audio/selector.h index cd4aa926c7f4..fd413badab7f 100644 --- a/src/include/sof/audio/selector.h +++ b/src/include/sof/audio/selector.h @@ -27,8 +27,12 @@ struct comp_buffer; struct comp_dev; +/** \brief Default mix gain. */ +#define SEL_COEF_ONE_Q10 1024 /* int16(1 * 2^10) */ + #if CONFIG_IPC_MAJOR_3 /** \brief Supported channel count on input. */ +#define SEL_SOURCE_1CH 1 #define SEL_SOURCE_2CH 2 #define SEL_SOURCE_4CH 4 @@ -43,6 +47,9 @@ struct comp_dev; /** \brief Maximum supported channel count on output. */ #define SEL_SINK_CHANNELS_MAX 8 +/** \brief Maximum number of configurations in the blob received with set_config() */ +#define SEL_MAX_NUM_CONFIGS 8 + #define SEL_NUM_IN_PIN_FMTS 1 #define SEL_NUM_OUT_PIN_FMTS 1 @@ -60,8 +67,10 @@ enum ipc4_selector_config_id { /** \brief IPC4 mixing coefficients configuration. */ struct ipc4_selector_coeffs_config { - uint16_t rsvd0; /**< Unused field, keeps the structure aligned with common layout */ - uint16_t rsvd1; /**< Unused field, keeps the structure aligned with common layout */ + uint8_t source_channels_count; /**< Used when multiple profiles are packed into one blob. */ + uint8_t sink_channels_count; /**< Used when multiple profiles are packed into one blob. */ + uint8_t source_channel_config; /**< Used when multiple profiles are packed into one blob. */ + uint8_t sink_channel_config; /**< Used when multiple profiles are packed into one blob. */ /** Mixing coefficients in Q10 fixed point format */ int16_t coeffs[SEL_SINK_CHANNELS_MAX][SEL_SOURCE_CHANNELS_MAX]; @@ -109,6 +118,8 @@ struct comp_data { #if CONFIG_IPC_MAJOR_4 struct sof_selector_ipc4_config sel_ipc4_cfg; struct ipc4_selector_coeffs_config coeffs_config; + struct ipc4_selector_coeffs_config *multi_coeffs_config; + size_t multi_coeffs_config_size; #endif uint32_t source_period_bytes; /**< source number of period bytes */ @@ -117,6 +128,9 @@ struct comp_data { enum sof_ipc_frame sink_format; /**< sink frame format */ struct sof_sel_config config; /**< component configuration data */ sel_func sel_func; /**< channel selector processing function */ + int num_configs; /**< Number of coefficients sets in configuration blob. */ + bool passthrough; /**< Use a passthrough copy function when no up/down mix. */ + bool new_config; /**< True if new configuration has been received */ }; /** \brief Selector processing functions map. */ diff --git a/src/include/sof/audio/sink_source_utils.h b/src/include/sof/audio/sink_source_utils.h index ca8752f07294..818f29444c22 100644 --- a/src/include/sof/audio/sink_source_utils.h +++ b/src/include/sof/audio/sink_source_utils.h @@ -22,4 +22,20 @@ int source_to_sink_copy(struct sof_source *source, struct sof_sink *sink, bool free, size_t size); +/** + * fill sink with silence (zeros) + * + * @param sink the target to be filled with silence + * @param size number of bytes to be filled + */ +int sink_fill_with_silence(struct sof_sink *sink, size_t size); + +/** + * drop data from source + * + * @param source the source of data to be dropped + * @param size number of bytes to be dropped + */ +int source_drop_data(struct sof_source *source, 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 a7fead002ec4..e6007bf28729 100644 --- a/src/include/sof/audio/smart_amp/smart_amp.h +++ b/src/include/sof/audio/smart_amp/smart_amp.h @@ -86,7 +86,7 @@ struct inner_model_ops; * 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)); + * foo = rzalloc(SOF_MEM_FLAG_USER, sizeof(*foo)); * assert(foo); * foo->base.dev = dev; * foo->base.mod_ops = foo_ops; // declared somewhere as static const diff --git a/src/include/sof/boot_test.h b/src/include/sof/boot_test.h index 965eec06a6a9..dfa8671ee55f 100644 --- a/src/include/sof/boot_test.h +++ b/src/include/sof/boot_test.h @@ -6,8 +6,16 @@ #ifndef __SOF_BOOT_TEST_H__ #define __SOF_BOOT_TEST_H__ +#if !CONFIG_LIBRARY +#include <zephyr/logging/log.h> +#else +#define LOG_ERR(...) do {} while (0) +#endif #include <stdbool.h> +struct k_thread; + +#if CONFIG_SOF_BOOT_TEST #define TEST_RUN_ONCE(fn, ...) do { \ static bool once; \ if (!once) { \ @@ -15,6 +23,9 @@ fn(__VA_ARGS__); \ } \ } while (0) +#else +#define TEST_RUN_ONCE(fn, ...) do {} while (0) +#endif #define TEST_CHECK_RET(ret, testname) do { \ if ((ret) < 0) { \ @@ -25,4 +36,20 @@ } \ } while (0) +void sof_run_boot_tests(void); + +/** + * Mark a boot-test thread as expected to trigger a fatal error. + * + * @param thread Thread that is allowed to fault once, or NULL to clear. + */ +#if CONFIG_SOF_BOOT_TEST +void sof_boot_test_set_fault_valid(struct k_thread *thread); +#else +static inline void sof_boot_test_set_fault_valid(struct k_thread *thread) +{ + (void)thread; +} +#endif + #endif diff --git a/src/include/sof/coherent.h b/src/include/sof/coherent.h index d98739b92c6f..172e45b4ed92 100644 --- a/src/include/sof/coherent.h +++ b/src/include/sof/coherent.h @@ -182,7 +182,7 @@ static inline void *__coherent_init(size_t offset, const size_t size) * line boundary to avoid sharing a cache line with the adjacent * allocation */ - void *object = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + void *object = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, ALIGN_UP(size, PLATFORM_DCACHE_ALIGN)); struct coherent *c; @@ -272,7 +272,7 @@ static inline void coherent_release_thread(struct coherent __sparse_cache *c, static inline void *__coherent_init_thread(size_t offset, const size_t size) { /* As above - prevent cache line sharing */ - void *object = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + void *object = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, ALIGN_UP(size, PLATFORM_DCACHE_ALIGN)); struct coherent *c; @@ -348,7 +348,7 @@ static inline void coherent_release(struct coherent __sparse_cache *c, static inline void *__coherent_init(size_t offset, const size_t size) { /* As in CONFIG_INCOHERENT case - prevent cache line sharing */ - void *object = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + void *object = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, ALIGN_UP(size, PLATFORM_DCACHE_ALIGN)); struct coherent *c; @@ -401,7 +401,7 @@ static inline void coherent_release_thread(struct coherent __sparse_cache *c, static inline void *__coherent_init_thread(size_t offset, const size_t size) { /* As above - prevent cache line sharing */ - void *object = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + void *object = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, ALIGN_UP(size, PLATFORM_DCACHE_ALIGN)); struct coherent *c; diff --git a/src/include/sof/common.h b/src/include/sof/common.h index 4bb279b039aa..d7aa9a7989cb 100644 --- a/src/include/sof/common.h +++ b/src/include/sof/common.h @@ -223,6 +223,9 @@ # define SOF_FRAME_BYTE_ALIGN 4 #endif +/* Default frame-count alignment is 1 */ +#define SOF_FRAME_COUNT_ALIGN 1 + #ifndef __GLIBC_USE #define __GLIBC_USE(x) 0 #endif diff --git a/src/include/sof/debug/debug.h b/src/include/sof/debug/debug.h index 8103da3012b8..76eec7062de3 100644 --- a/src/include/sof/debug/debug.h +++ b/src/include/sof/debug/debug.h @@ -33,8 +33,6 @@ #define DEBUG_SET_FW_READY_FLAGS \ ( \ SOF_IPC_INFO_BUILD | \ - (IS_ENABLED(CONFIG_DEBUG_LOCKS) ? SOF_IPC_INFO_LOCKS : 0) | \ - (IS_ENABLED(CONFIG_DEBUG_LOCKS_VERBOSE) ? SOF_IPC_INFO_LOCKSV : 0) | \ (IS_ENABLED(CONFIG_GDB_DEBUG) ? SOF_IPC_INFO_GDB : 0) \ ) @@ -124,8 +122,6 @@ #define DEBUG_SET_FW_READY_FLAGS \ ( \ - (IS_ENABLED(CONFIG_DEBUG_LOCKS) ? SOF_IPC_INFO_LOCKS : 0) | \ - (IS_ENABLED(CONFIG_DEBUG_LOCKS_VERBOSE) ? SOF_IPC_INFO_LOCKSV : 0) | \ (IS_ENABLED(CONFIG_GDB_DEBUG) ? SOF_IPC_INFO_GDB : 0) \ ) diff --git a/src/include/sof/debug/gdb/gdb.h b/src/include/sof/debug/gdb/gdb.h index c27e60e64290..338b97b27541 100644 --- a/src/include/sof/debug/gdb/gdb.h +++ b/src/include/sof/debug/gdb/gdb.h @@ -38,8 +38,9 @@ void gdb_handle_exception(void); void gdb_debug_info(unsigned char *str); void gdb_init_debug_exception(void); -void gdb_init(void); #endif /* CONFIG_GDB_DEBUG */ +void gdb_init(void); + #endif /* __SOF_DEBUG_GDB_GDB_H__ */ diff --git a/src/include/sof/debug/telemetry/telemetry.h b/src/include/sof/debug/telemetry/telemetry.h index 4f8a869a9dd6..6c2d5fdf8cb7 100644 --- a/src/include/sof/debug/telemetry/telemetry.h +++ b/src/include/sof/debug/telemetry/telemetry.h @@ -11,8 +11,11 @@ #include <zephyr/timing/timing.h> #endif +#ifndef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER /* Slot in memory window 2 (Debug Window) to be used as telemetry slot */ #define SOF_DW_TELEMETRY_SLOT 1 +#endif + /* Memory of average algorithm of performance queue */ #define SOF_AVG_PERF_MEAS_DEPTH 64 /* Number of runs taken to calculate average (algorithm resolution) */ @@ -87,6 +90,9 @@ struct telemetry_perf_queue { }; void telemetry_update(uint32_t begin_ccount, uint32_t current_ccount); +#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER +struct system_tick_info *telemetry_get_systick_info_ptr(void); +#endif #ifdef CONFIG_TIMING_FUNCTIONS #define telemetry_timestamp timing_counter_get diff --git a/src/include/sof/ipc/common.h b/src/include/sof/ipc/common.h index 43ad023da1ef..e46fc10b9521 100644 --- a/src/include/sof/ipc/common.h +++ b/src/include/sof/ipc/common.h @@ -68,7 +68,11 @@ struct ipc { struct list_item comp_list; /* list of component devices */ /* processing task */ +#if CONFIG_TWB_IPC_TASK + struct task *ipc_task; +#else struct task ipc_task; +#endif #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS /* io performance measurement */ @@ -78,6 +82,7 @@ struct ipc { #ifdef __ZEPHYR__ struct k_work_delayable z_delayed_work; + struct k_work_q ipc_send_wq; #endif void *private; @@ -120,7 +125,11 @@ void ipc_free(struct ipc *ipc); */ struct ipc_data_host_buffer { /* DMA */ +#if CONFIG_ZEPHYR_NATIVE_DRIVERS + struct sof_dma *dmac; +#else struct dma *dmac; +#endif uint8_t *page_table; }; @@ -238,4 +247,7 @@ void ipc_msg_reply(struct sof_ipc_reply *reply); */ void ipc_complete_cmd(struct ipc *ipc); +/* GDB stub: should enter GDB after completing the IPC processing */ +extern bool ipc_enter_gdb; + #endif /* __SOF_DRIVERS_IPC_H__ */ diff --git a/src/include/sof/ipc/driver.h b/src/include/sof/ipc/driver.h index 348300a5a6ff..9b6506a7c1e8 100644 --- a/src/include/sof/ipc/driver.h +++ b/src/include/sof/ipc/driver.h @@ -112,4 +112,9 @@ int ipc_platform_poll_is_host_ready(void); */ int ipc_platform_poll_tx_host_msg(struct ipc_msg *msg); +/** + * \brief wait for host acknowledgment to an IPC message + */ +void ipc_platform_wait_ack(struct ipc *ipc); + #endif diff --git a/src/include/sof/ipc/msg.h b/src/include/sof/ipc/msg.h index 20dfaf6eb519..160a9be9ec7c 100644 --- a/src/include/sof/ipc/msg.h +++ b/src/include/sof/ipc/msg.h @@ -34,9 +34,9 @@ struct ipc_msg { uint32_t header; /* specific to platform */ uint32_t extension; /* extension specific to platform */ uint32_t tx_size; /* payload size in bytes */ - void *tx_data; /* pointer to payload data */ - bool is_shared; /* the message is shared cross-core */ + void *tx_data; /* pointer to payload data, must be in a non-cached memory */ struct list_item list; + void (*callback)(struct ipc_msg *msg); /* Function called after sending the message */ }; /** @@ -51,12 +51,12 @@ static inline struct ipc_msg *ipc_msg_w_ext_init(uint32_t header, uint32_t exten { struct ipc_msg *msg; - msg = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*msg)); + msg = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*msg)); if (!msg) return NULL; if (size) { - msg->tx_data = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, size); + msg->tx_data = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, size); if (!msg->tx_data) { rfree(msg); return NULL; diff --git a/src/include/sof/ipc/notification_pool.h b/src/include/sof/ipc/notification_pool.h new file mode 100644 index 000000000000..835399307ae2 --- /dev/null +++ b/src/include/sof/ipc/notification_pool.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + * Author: Adrian Warecki <adrian.warecki@intel.com> + */ + +#ifndef __SOF_IPC_NOTIFICATION_POOL_H__ +#define __SOF_IPC_NOTIFICATION_POOL_H__ + +#include <stdint.h> +#include <sof/ipc/msg.h> + +/** + * @brief Retrieves an IPC notification message from the pool. + * + * This function retrieves and returns an IPC notification message + * of the specified size from the notification pool. The size of the + * message is limited by the maximum size available in the pool. + * + * @param size The size of the IPC message to retrieve. + * @return A pointer to the retrieved IPC message, or NULL if retrieval fails. + */ +struct ipc_msg *ipc_notification_pool_get(size_t size); + +#if CONFIG_LIBRARY +/** + * @brief Frees all IPC notification messages in the pool. + * + * This function frees all notification messages currently held in + * the pool free list and resets the pool depth counter. It is + * required only in library (testbench) build. + */ +void ipc_notification_pool_free(void); +#endif /* CONFIG_LIBRARY */ + +#endif /* __SOF_IPC_NOTIFICATION_POOL_H__ */ diff --git a/src/include/sof/ipc/topology.h b/src/include/sof/ipc/topology.h index 5726b7055b32..84df84abb069 100644 --- a/src/include/sof/ipc/topology.h +++ b/src/include/sof/ipc/topology.h @@ -49,8 +49,6 @@ typedef uint32_t ipc_comp; struct ipc_comp_dev; const struct comp_driver *ipc4_get_comp_drv(uint32_t module_id); struct comp_dev *ipc4_get_comp_dev(uint32_t comp_id); -int ipc4_add_comp_dev(struct comp_dev *dev); -const struct comp_driver *ipc4_get_drv(const uint8_t *uuid); int ipc4_chain_manager_create(struct ipc4_chain_dma *cdma); 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); @@ -58,6 +56,8 @@ int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma, bool *d int ipc4_process_on_core(uint32_t core, bool blocking); int ipc4_pipeline_complete(struct ipc *ipc, uint32_t comp_id, uint32_t cmd); int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint32_t size); +int ipc4_find_all_dma_configs_tlvs_only(struct ipc_config_dai *dai, + uint8_t *data_buffer, size_t size); int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd); int ipc4_pipeline_trigger(struct ipc_comp_dev *ppl_icd, uint32_t cmd, bool *delayed); int ipc4_find_dma_config_multiple(struct ipc_config_dai *dai, uint8_t *data_buffer, diff --git a/src/include/sof/lib/ams.h b/src/include/sof/lib/ams.h index 8cb3ae217400..e43d6208f875 100644 --- a/src/include/sof/lib/ams.h +++ b/src/include/sof/lib/ams.h @@ -29,10 +29,6 @@ /* Space allocated for async message content*/ #define AMS_MAX_MSG_SIZE 0x1000 -/* Size of slots message, module id and instance id */ -#define AMS_SLOT_SIZE(msg) (AMS_MESSAGE_SIZE(msg) + sizeof(uint16_t) * 2) -#define AMS_MESSAGE_SIZE(msg) (sizeof(*msg) - sizeof(char) + (sizeof(char) * (msg->message_length))) - /** * \brief IXC message payload * diff --git a/src/include/sof/lib/dai-legacy.h b/src/include/sof/lib/dai-legacy.h index 9408b6c27414..c1b7c0a28653 100644 --- a/src/include/sof/lib/dai-legacy.h +++ b/src/include/sof/lib/dai-legacy.h @@ -76,7 +76,7 @@ struct sof_ipc_stream_params; * If a single DAI instance can have multiple DMA links and/or there is * some other possibility of the same instance being used in multiple * contexts at the same time, the private data should be allocated in the - * SOF_MEM_ZONE_SHARED. + * SOF_MEM_FLAG_COHERENT. */ struct dai_ops { int (*set_config)(struct dai *dai, struct ipc_config_dai *config, @@ -419,7 +419,7 @@ void dai_put(struct dai *dai); * \brief Digital Audio interface formatting */ static inline int dai_set_config(struct dai *dai, struct ipc_config_dai *config, - const void *spec_config) + const void *spec_config, size_t size) { return dai->drv->ops.set_config(dai, config, spec_config); } diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index 84b834138eae..a0c42bff351e 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -28,6 +28,8 @@ #include <sof/ipc/topology.h> #include <sof/audio/pcm_converter.h> #include <sof/audio/ipc-config.h> +#include <sof/audio/component.h> +#include <ipc/dai.h> #include <errno.h> #include <stddef.h> #include <stdint.h> @@ -116,7 +118,7 @@ typedef int (*channel_copy_func)(const struct audio_stream *src, unsigned int sr */ struct dai_data { /* local DMA config */ - struct dma_chan_data *chan; + int chan_index; uint32_t stream_id; struct dma_sg_config config; struct dma_config *z_config; @@ -125,7 +127,7 @@ struct dai_data { struct comp_buffer *local_buffer; struct dai_ts_cfg ts_config; struct dai *dai; - struct dma *dma; + struct sof_dma *dma; struct dai_group *group; /* NULL if no group assigned */ int xrun; /* true if we are doing xrun recovery */ @@ -158,12 +160,17 @@ struct dai_data { struct llp_slot_info slot_info; /* fast mode, use one byte memory to save repreated cycles */ bool fast_mode; +#if CONFIG_XRUN_NOTIFICATIONS_ENABLE + bool xrun_notification_sent; +#endif #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS /* io performance measurement */ - struct io_perf_data_item *io_perf_bytes_count; + struct io_perf_data_item *io_perf_dai_byte_count; #endif /* Copier gain params */ struct copier_gain_params *gain_data; + + struct mod_alloc_ctx alloc_ctx; }; /* these 3 are here to satisfy clk.c and ssp.h interconnection, will be removed leter */ @@ -234,7 +241,8 @@ void dai_put(struct dai *dai); /** * \brief Digital Audio interface formatting */ -int dai_set_config(struct dai *dai, struct ipc_config_dai *config, const void *spec_config); +int dai_set_config(struct dai *dai, struct ipc_config_dai *config, + const void *spec_config, size_t size); /** * \brief Get Digital Audio interface DMA Handshake @@ -301,7 +309,16 @@ void dai_release_llp_slot(struct dai_data *dd); /** * \brief Retrieve a pointer to the Zephyr device structure for a DAI of a given type and index. */ -const struct device *dai_get_device(uint32_t type, uint32_t index); +__syscall const struct device *dai_get_device(enum sof_ipc_dai_type type, uint32_t index); + +/** + * \brief Retrieve the list of all DAI devices. + * \param count Pointer to store the number of devices in the list. + * \return Pointer to the array of device pointers. + */ +const struct device **dai_get_device_list(size_t *count); /** @}*/ +#include <zephyr/syscalls/dai-zephyr.h> + #endif /* __SOF_LIB_DAI_ZEPHYR_H__ */ diff --git a/src/include/sof/lib/fast-get.h b/src/include/sof/lib/fast-get.h new file mode 100644 index 000000000000..05f098a752cc --- /dev/null +++ b/src/include/sof/lib/fast-get.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2024 Intel Corporation. All rights reserved. + * + * Author: Jyri Sarha <jyri.sarha@linux.intel.com> + */ + +#ifndef __SOF_LIB_FAST_GET_H__ +#define __SOF_LIB_FAST_GET_H__ + +#include <stddef.h> + +struct k_mem_domain; +struct mod_alloc_ctx; + +/* + * When built for SOF, fast_get() and fast_put() are only needed when DRAM + * storage and execution is enabled (CONFIG_COLD_STORE_EXECUTE_DRAM=y), but not + * when building LLEXT extensions (!defined(LL_EXTENSION_BUILD)), using Zephyr + * SDK (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE=n while + * CONFIG_LLEXT_TYPE_ELF_SHAREDLIB=y). + * For unit-testing full versions of fast_get() and fast_put() are checked by + * test/ztest/unit/fast-get/ and test/cmocka/src/lib/fast-get/ + */ +#if (CONFIG_COLD_STORE_EXECUTE_DRAM && \ + (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE || !defined(LL_EXTENSION_BUILD))) || \ + !CONFIG_SOF_FULL_ZEPHYR_APPLICATION +const void *fast_get(struct mod_alloc_ctx *alloc, const void * const dram_ptr, size_t size); +void fast_put(struct mod_alloc_ctx *alloc, struct k_mem_domain *mdom, const void *sram_ptr); +#else +static inline const void *fast_get(struct mod_alloc_ctx *alloc, const void * const dram_ptr, + size_t size) +{ + return dram_ptr; +} +static inline void fast_put(struct mod_alloc_ctx *alloc, struct k_mem_domain *mdom, + const void *sram_ptr) {} +#endif + +#endif /* __SOF_LIB_FAST_GET_H__ */ diff --git a/src/include/sof/lib/mailbox.h b/src/include/sof/lib/mailbox.h index 06e2659a5847..ae667f0d0c4c 100644 --- a/src/include/sof/lib/mailbox.h +++ b/src/include/sof/lib/mailbox.h @@ -100,6 +100,14 @@ void mailbox_hostbox_read(void *dest, size_t dest_size, assert(!host_read_err); } +#if CONFIG_IPC_MAJOR_4 +static inline +void mailbox_stream_write(size_t offset, const void *src, size_t bytes) +{ + /* in IPC4, the stream mailbox must not be used */ + assert(false); +} +#else static inline void mailbox_stream_write(size_t offset, const void *src, size_t bytes) { @@ -110,5 +118,6 @@ void mailbox_stream_write(size_t offset, const void *src, size_t bytes) dcache_writeback_region((__sparse_force void __sparse_cache *)(MAILBOX_STREAM_BASE + offset), bytes); } +#endif #endif /* __SOF_LIB_MAILBOX_H__ */ diff --git a/src/include/sof/lib/notifier.h b/src/include/sof/lib/notifier.h index abf893281f70..87ca2cd40265 100644 --- a/src/include/sof/lib/notifier.h +++ b/src/include/sof/lib/notifier.h @@ -27,13 +27,11 @@ enum notify_id { NOTIFIER_ID_SSP_FREQ, /* struct clock_notify_data * */ NOTIFIER_ID_KPB_CLIENT_EVT, /* struct kpb_event_data * */ NOTIFIER_ID_DMA_DOMAIN_CHANGE, /* struct dma_chan_data * */ - NOTIFIER_ID_BUFFER_PRODUCE, /* struct buffer_cb_transact* */ - NOTIFIER_ID_BUFFER_CONSUME, /* struct buffer_cb_transact* */ - NOTIFIER_ID_BUFFER_FREE, /* struct buffer_cb_free* */ NOTIFIER_ID_DMA_COPY, /* struct dma_cb_data* */ NOTIFIER_ID_LL_POST_RUN, /* NULL */ NOTIFIER_ID_DMA_IRQ, /* struct dma_chan_data * */ NOTIFIER_ID_DAI_TRIGGER, /* struct dai_group * */ + NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE, /* struct mic_privacy_settings * */ NOTIFIER_ID_COUNT }; diff --git a/src/include/sof/lib/uuid.h b/src/include/sof/lib/uuid.h index 7c7691bfff38..d45f821613d7 100644 --- a/src/include/sof/lib/uuid.h +++ b/src/include/sof/lib/uuid.h @@ -50,13 +50,19 @@ * pass UUIDs as a linear array of bytes, only one endianness will * work. If SOF ever ships on a BE system all use of sof_uuid will * need to be modified to byte swap the a/b/c values. + * + * Some identifiers are taken from the module manifest. Since the module + * manifest structure (sof_man_module) is marked as packed, the pointer + * to the sof_uuid structure may not be properly aligned. To avoid possible + * problems with accessing fields of this structure from unaligned addresses, + * it has been marked as packed. */ struct sof_uuid { uint32_t a; uint16_t b; uint16_t c; uint8_t d[8]; -}; +} __packed; #define _UUID_INIT(va, vb, vc, d0, d1, d2, d3, d4, d5, d6, d7) \ { va, vb, vc, { d0, d1, d2, d3, d4, d5, d6, d7 } } @@ -126,6 +132,14 @@ struct sof_uuid_entry { _DEF_UUID(entity_name, uuid_name, \ _UUID_INIT(va, vb, vc, vd0, vd1, vd2, vd3, vd4, vd5, vd6, vd7)) +/** \brief Get UUID value sourced from the fixed SOF registry + * + * The ID value is sourced by name from the uuid-registry.txt file distributed with the source tree. + * + * \param name Name of the UUID, must match an entry in uuid-registry.txt + */ +#define SOF_REG_UUID(name) _UUIDREG_##name + /** \brief Defines UUID sourced from the fixed SOF registry * * As for SOF_DEFINE_UUID(), but the ID value is sourced by name from @@ -136,7 +150,7 @@ struct sof_uuid_entry { * * \param name Name of the UUID, must match an entry in uuid-registry.txt */ -#define SOF_DEFINE_REG_UUID(name) _DEF_UUID(#name, name##_uuid, _UUIDREG_##name) +#define SOF_DEFINE_REG_UUID(name) _DEF_UUID(#name, name##_uuid, SOF_REG_UUID(name)) /** \brief Creates local unique 32-bit representation of UUID structure. * diff --git a/src/include/sof/lib/vregion.h b/src/include/sof/lib/vregion.h new file mode 100644 index 000000000000..5c066c90dbc8 --- /dev/null +++ b/src/include/sof/lib/vregion.h @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright(c) 2025 Intel Corporation. + +/* Pre Allocated Contiguous Virtual Region */ +#ifndef __SOF_LIB_VREGION_H__ +#define __SOF_LIB_VREGION_H__ + +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct vregion; + +/** + * @brief Memory types for virtual region allocations. + * Used to specify the type of memory allocation within a virtual region. + * + * @note + * - interim: allocation that can be freed i.e. get/set large config, kcontrols. + * - lifetime: allocation that cannot be freed i.e. init data, pipeline data. + */ +enum vregion_mem_type { + VREGION_MEM_TYPE_INTERIM, /* interim allocation that can be freed */ + VREGION_MEM_TYPE_LIFETIME, /* lifetime allocation */ + VREGION_MEM_TYPE_INVALID, /* Interim heap initialization failed */ +}; + +#if CONFIG_SOF_VREGIONS + +/** + * @brief Create a new virtual region instance. + * + * Create a new virtual region instance with specified memory size. + * Allocations start in LIFETIME mode. + * + * @param[in] memsize Total size of the virtual region memory. + * @return struct vregion* Pointer to the new virtual region instance, or NULL on failure. + */ +struct vregion *vregion_create(size_t memsize); + +/** + * @brief Switch virtual region allocations to interim mode. + * + * After this call, all allocations from this vregion will use the interim + * heap. The interim heap is created lazily from remaining lifetime space. + * Multiple calls are allowed but log a warning. + * + * @param[in] vr Pointer to the virtual region instance. + */ +void vregion_set_interim(struct vregion *vr); + +/** + * @brief Increment virtual region's user count. + * + * The creator of the virtual region is its first user, for any additional users + * increment the region's use-count. + * + * @param[in] vr Pointer to the virtual region instance to release. + * @return struct vregion* Pointer to the virtual region instance. + */ +struct vregion *vregion_get(struct vregion *vr); + +/** + * @brief Decrement virtual region's user count or destroy it. + * + * Decrement virtual region's user count, when it reaches 0 free all associated + * resources. + * + * @param[in] vr Pointer to the virtual region instance to release. + * @return struct vregion* Pointer to the virtual region instance or NULL if it has been destroyed. + */ +struct vregion *vregion_put(struct vregion *vr); + +/** + * @brief Allocate memory from the specified virtual region. + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] size Size of memory to allocate in bytes. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *vregion_alloc(struct vregion *vr, size_t size); + +/** + * @brief like vregion_alloc() but allocates coherent memory + */ +void *vregion_alloc_coherent(struct vregion *vr, size_t size); + +/** + * @brief Allocate aligned memory from the specified virtual region. + * + * Allocate aligned memory from the specified virtual region using the + * current allocation mode (lifetime or interim). + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] size Size of memory to allocate in bytes. + * @param[in] alignment Alignment of memory to allocate in bytes. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment); + +/** + * @brief like vregion_alloc_align() but allocates coherent memory + */ +void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment); + +/** + * @brief Free memory allocated from the specified virtual region. + * + * Free memory previously allocated from the specified virtual region. + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] ptr Pointer to the memory to free. + */ +void vregion_free(struct vregion *vr, void *ptr); + +/** + * @brief Log virtual region memory usage. + * + * @param[in] vr Pointer to the virtual region instance. + */ +void vregion_info(struct vregion *vr); + +/** + * @brief Get virtual region memory start and size. + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] size Pointer to size + * @param[in] start Pointer to start + */ +void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t *start); + +#else /* CONFIG_SOF_VREGIONS */ + +struct vregion { + unsigned int use_count; +}; + +static inline struct vregion *vregion_create(size_t memsize) +{ + return NULL; +} +static inline void vregion_set_interim(struct vregion *vr) {} +static inline struct vregion *vregion_get(struct vregion *vr) +{ + return vr; +} +static inline struct vregion *vregion_put(struct vregion *vr) +{ + return vr; +} +static inline void *vregion_alloc(struct vregion *vr, size_t size) +{ + return NULL; +} +static inline void *vregion_alloc_coherent(struct vregion *vr, size_t size) +{ + return NULL; +} +static inline void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment) +{ + return NULL; +} +static inline void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, + size_t alignment) +{ + return NULL; +} +static inline void vregion_free(struct vregion *vr, void *ptr) {} +static inline void vregion_info(struct vregion *vr) {} +static inline void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t *start) +{ + if (size) + *size = 0; +} + +#endif /* CONFIG_SOF_VREGIONS */ + +#ifdef __cplusplus +} +#endif + +#endif /* __SOF_LIB_VREGION_H__ */ diff --git a/src/include/sof/lib_manager.h b/src/include/sof/lib_manager.h index ba1f8eadbfb0..29c226eb61a7 100644 --- a/src/include/sof/lib_manager.h +++ b/src/include/sof/lib_manager.h @@ -63,17 +63,23 @@ #define __SOF_LIB_MANAGER_H__ #include <stdint.h> +#include <sof/list.h> +#include <sof/audio/component.h> #include <rimage/sof/user/manifest.h> #if CONFIG_LIBRARY_AUTH_SUPPORT #include <sof/auth_api_iface.h> #endif +#include <sof/list.h> #define LIB_MANAGER_MAX_LIBS 16 #define LIB_MANAGER_LIB_ID_SHIFT 12 -#define LIB_MANAGER_LIB_NOTIX_MAX_COUNT 4 +#define LIB_MANAGER_LIB_NOTIX_MAX_COUNT 4 -#define LIB_MANAGER_GET_LIB_ID(module_id) ((module_id) >> LIB_MANAGER_LIB_ID_SHIFT) +#define LIB_MANAGER_GET_LIB_ID(module_id) (((module_id) & 0xF000) >> LIB_MANAGER_LIB_ID_SHIFT) #define LIB_MANAGER_GET_MODULE_INDEX(module_id) ((module_id) & 0xFFF) +#define LIB_MANAGER_PACK_MODULE_ID(lib_index, module_index) (((module_index) & 0xFFF) | \ + (((lib_index) << LIB_MANAGER_LIB_ID_SHIFT) & 0xF000)) +#define LIB_MANAGER_PACK_LIB_ID(lib_index) LIB_MANAGER_PACK_MODULE_ID(lib_index, 0x0) #ifdef CONFIG_LIBRARY_MANAGER struct ipc_lib_msg { @@ -87,6 +93,9 @@ enum { LIB_MANAGER_TEXT, LIB_MANAGER_DATA, LIB_MANAGER_RODATA, + LIB_MANAGER_BSS, + LIB_MANAGER_COLD, + LIB_MANAGER_COLDRODATA, LIB_MANAGER_N_SEGMENTS, }; @@ -95,14 +104,22 @@ struct lib_manager_segment_desc { size_t size; }; +struct llext; +struct llext_buf_loader; + struct lib_manager_module { - unsigned int start_idx; + unsigned int start_idx; /* Index of the first driver from this module in + * the library-global driver list */ const struct sof_man_module_manifest *mod_manifest; + struct llext *llext; /* Zephyr loadable extension context */ + struct llext_buf_loader *ebl; /* Zephyr loadable extension buffer loader */ + unsigned int n_dependent; /* For auxiliary modules: number of dependents */ + bool mapped; struct lib_manager_segment_desc segment[LIB_MANAGER_N_SEGMENTS]; }; struct lib_manager_mod_ctx { - void *base_addr; + void *base_addr; /* library cold storage address (e.g. DRAM) */ unsigned int n_mod; struct lib_manager_module *mod; }; @@ -116,11 +133,8 @@ struct ext_library { struct ipc_lib_msg *lib_notif_pool; uint32_t lib_notif_count; + /* Only needed from SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE to SOF_IPC4_GLB_LOAD_LIBRARY */ void *runtime_data; -#if CONFIG_LIBRARY_AUTH_SUPPORT - struct auth_api_ctx auth_ctx; - void *auth_buffer; -#endif }; /* lib manager context, used by lib_notification */ @@ -136,7 +150,7 @@ static inline struct lib_manager_mod_ctx *lib_manager_get_mod_ctx(int module_id) uint32_t lib_id = LIB_MANAGER_GET_LIB_ID(module_id); struct ext_library *_ext_lib = ext_lib_get(); - if (!_ext_lib) + if (!_ext_lib || lib_id >= LIB_MANAGER_MAX_LIBS) return NULL; return _ext_lib->desc[lib_id]; @@ -177,30 +191,18 @@ int lib_manager_register_module(const uint32_t component_id); */ const struct sof_man_fw_desc *lib_manager_get_library_manifest(int module_id); -struct processing_module; /* - * \brief Allocate module + * \brief Get address and size of the bss section for given module instance * - * param[in] drv - component driver - * param[in] ipc_config - audio component base configuration from IPC at creation - * param[in] ipc_specific_config - ipc4 base configuration - * - * Function is responsible to allocate module in available free memory and assigning proper address. - * (WIP) These feature will contain module validation and proper memory management. + * param[in] instance_id - instance id + * param[in] mod - module manifest + * param[out] va_addr - address of the bss section + * param[out] size - size of the bss section */ -uintptr_t lib_manager_allocate_module(struct processing_module *proc, - const struct comp_ipc_config *ipc_config, - const void *ipc_specific_config); +void lib_manager_get_instance_bss_address(uint32_t instance_id, + const struct sof_man_module *mod, + void __sparse_cache **va_addr, size_t *size); -/* - * \brief Free module - * - * param[in] component_id - component id coming from ipc config. This function reguires valid - * lib_id and module_id fields of component id. - * - * Function is responsible to free module resources in HP memory. - */ -int lib_manager_free_module(const uint32_t component_id); /* * \brief Load library * diff --git a/src/include/sof/llext_manager.h b/src/include/sof/llext_manager.h index c963ef4adfd6..525fa50b1506 100644 --- a/src/include/sof/llext_manager.h +++ b/src/include/sof/llext_manager.h @@ -15,25 +15,40 @@ struct comp_dev; struct comp_driver; struct comp_ipc_config; +struct k_mem_domain; static inline bool module_is_llext(const struct sof_man_module *mod) { - return mod->type.load_type == SOF_MAN_MOD_TYPE_LLEXT; + return mod->type.load_type == SOF_MAN_MOD_TYPE_LLEXT || + mod->type.load_type == SOF_MAN_MOD_TYPE_LLEXT_AUX; } -uintptr_t llext_manager_allocate_module(struct processing_module *proc, - const struct comp_ipc_config *ipc_config, +uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config, const void *ipc_specific_config); int llext_manager_free_module(const uint32_t component_id); +int llext_manager_add_library(uint32_t module_id); + +int llext_manager_add_domain(const uint32_t component_id, struct k_mem_domain *domain); +int llext_manager_rm_domain(const uint32_t component_id, struct k_mem_domain *domain); + bool comp_is_llext(struct comp_dev *comp); #else #define module_is_llext(mod) false -#define llext_manager_allocate_module(proc, ipc_config, ipc_specific_config) 0 +#define llext_manager_allocate_module(ipc_config, ipc_specific_config) 0 #define llext_manager_free_module(component_id) 0 -#define llext_unload(ext) 0 +#define llext_manager_add_library(module_id) 0 +#define llext_manager_add_domain(component_id, domain) 0 #define comp_is_llext(comp) false #endif +#if CONFIG_LLEXT_EXPERIMENTAL && !CONFIG_ADSP_IMR_CONTEXT_SAVE +int llext_manager_store_to_dram(void); +int llext_manager_restore_from_dram(void); +#else +#define llext_manager_store_to_dram() 0 +#define llext_manager_restore_from_dram() -ENOSYS +#endif + #endif diff --git a/src/include/sof/math/a_law.h b/src/include/sof/math/a_law.h new file mode 100644 index 000000000000..1b7cac744438 --- /dev/null +++ b/src/include/sof/math/a_law.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +#ifndef __SOF_MATH_A_LAW_H__ +#define __SOF_MATH_A_LAW_H__ + +#include <stdint.h> + +/** + * sofm_a_law_encode() - Encode sample with A-law coding + * @param sample: A s16 sample value + * + * The A-law codec is defined in ITU-T G.711 standard and has been used + * in telecommunications in e.g. Europe. The A-law coding compresses 13 bit + * samples to 8 bit data stream. In SOF the high 13 bits of s16 format are + * used for compatibility with normal audios. + * + * @return: Compressed 8 bit code value + */ +uint8_t sofm_a_law_encode(int16_t sample); + +/** + * sofm_a_law_decode() - Decode A-law encoded code word + * @param byte: Encoded code word + * + * The A-law decoder expands a 8 bit code word into a 13 bit sample value. + * In the SOF the high 13 bits are aligned to the most significant bits + * to be compatible with normal s16 Q1.15 samples. + * + * @return: Sample value in s16 format + */ +int16_t sofm_a_law_decode(int8_t byte); + +#endif /* __SOF_MATH_A_LAW_H__ */ diff --git a/src/include/sof/math/auditory.h b/src/include/sof/math/auditory.h index eef073092e22..a68f0468d591 100644 --- a/src/include/sof/math/auditory.h +++ b/src/include/sof/math/auditory.h @@ -14,6 +14,7 @@ #include <sof/math/log.h> #include <stdint.h> +#define AUDITORY_MAX_MEL_BANDS 256 #define AUDITORY_EPS_Q31 1 /* Smallest nonzero Q1.31 value */ #define AUDITORY_LOG2_2P25_Q16 Q_CONVERT_FLOAT(25.0, 16) /* log2(2^25) */ @@ -76,7 +77,9 @@ int16_t psy_mel_to_hz(int16_t mel); * filter coefficients. * \return Zero when success, otherwise error code. */ -int psy_get_mel_filterbank(struct psy_mel_filterbank *mel_fb); +struct processing_module; +int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *mel_fb); +int mod_psy_free_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *mel_fb); /** * \brief Convert linear complex spectra from FFT into Mel band energies in desired @@ -101,11 +104,11 @@ void psy_apply_mel_filterbank_16(struct psy_mel_filterbank *mel_fb, struct icomp * \param[in] fft_out Array of complex numbers from FFT in Q1.31 format. * \param[out] power_spectra Array of linear power spectra, needed scratch are that is half + 1 * side of fft_out. The data can be discarded after if no use. - * \param[out] mel_log Array of Q9.7 log/log10/10log10 format Mel band energies. + * \param[out] mel_log Array of Q9.23 log/log10/10log10 format Mel band energies. * \param[in] bitshift A shift left scale that has been possibly applied to FFT. This will * be subtracted from the log or decibels notation. */ void psy_apply_mel_filterbank_32(struct psy_mel_filterbank *mel_fb, struct icomplex32 *fft_out, - int32_t *power_spectra, int16_t *mel_log, int bitshift); + int32_t *power_spectra, int32_t *mel_log, int bitshift); #endif /* __SOF_MATH_AUDITORY_H__ */ diff --git a/src/include/sof/math/dct.h b/src/include/sof/math/dct.h index bb3aca81b202..7c754f448c21 100644 --- a/src/include/sof/math/dct.h +++ b/src/include/sof/math/dct.h @@ -29,6 +29,8 @@ struct dct_plan_16 { bool ortho; }; -int dct_initialize_16(struct dct_plan_16 *dct); +int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct); + +int mod_dct_free_16(struct processing_module *mod, struct dct_plan_16 *dct); #endif /* __SOF_MATH_DCT_H__ */ diff --git a/src/include/sof/math/exp_fcn.h b/src/include/sof/math/exp_fcn.h index 425f400b23de..40acd347ed1f 100644 --- a/src/include/sof/math/exp_fcn.h +++ b/src/include/sof/math/exp_fcn.h @@ -1,10 +1,12 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2022 Intel Corporation. All rights reserved. + * Copyright(c) 2022-2025 Intel Corporation. * * Author: Shriram Shastry <malladi.sastry@linux.intel.com> - * + * Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + * Pasca, Bogdan <bogdan.pasca@intel.com> */ + #ifndef __SOFM_EXP_FCN_H__ #define __SOFM_EXP_FCN_H__ @@ -26,40 +28,40 @@ #endif -/* TODO: Is there a MCPS difference */ -#define USING_QCONVERT 1 - -#if USING_QCONVERT +/* Q5.27 int32(round(log((2^31 - 1)/2^20) * 2^27)) */ +#define SOFM_EXP_FIXED_INPUT_MAX 1023359037 -#include <sof/audio/format.h> -#define SOFM_EXP_FIXED_INPUT_MIN Q_CONVERT_FLOAT(-11.5, 27) /* Q5.27 */ -#define SOFM_EXP_FIXED_INPUT_MAX Q_CONVERT_FLOAT(7.6245, 27) /* Q5.27 */ -#define SOFM_EXP_TWO_Q27 Q_CONVERT_FLOAT(2.0, 27) /* Q5.27 */ -#define SOFM_EXP_MINUS_TWO_Q27 Q_CONVERT_FLOAT(-2.0, 27) /* Q5.27 */ -#define SOFM_EXP_ONE_Q20 Q_CONVERT_FLOAT(1.0, 20) /* Q12.20 */ -#define SOFM_EXP_MINUS_100_Q24 Q_CONVERT_FLOAT(-100.0, 24) /* Q8.24 */ -#define SOFM_EXP_LOG10_DIV20_Q27 Q_CONVERT_FLOAT(0.1151292546, 27) /* Q5.27 */ +/* Q8.24 int32(round((log((2^31 - 1)/2^20) * 20 / log(10)) * 2^24)) */ +#define SOFM_DB2LIN_INPUT_MAX 1111097957 -#else - -#define SOFM_EXP_FIXED_INPUT_MIN -1543503872 /* Q_CONVERT_FLOAT(-11.5, 27) */ -#define SOFM_EXP_FIXED_INPUT_MAX 1023343067 /* Q_CONVERT_FLOAT(7.6245, 27) */ -#define SOFM_EXP_TWO_Q27 268435456 /* Q_CONVERT_FLOAT(2.0, 27) */ -#define SOFM_EXP_MINUS_TWO_Q27 -268435456 /* Q_CONVERT_FLOAT(-2.0, 27) */ -#define SOFM_EXP_ONE_Q20 1048576 /* Q_CONVERT_FLOAT(1.0, 20) */ -#define SOFM_EXP_MINUS_100_Q24 -1677721600 /* Q_CONVERT_FLOAT(-100.0, 24) */ -#define SOFM_EXP_LOG10_DIV20_Q27 15452387 /* Q_CONVERT_FLOAT(0.1151292546, 27) */ +/** + * Calculates exponent function exp(x) = e^x with accurate and efficient technique that + * includes range reduction operations, approximation with Taylor series, and reconstruction + * operations to compensate the range reductions. + * @param x The input argument as Q4.28 from -8 to +8 + * @return The calculated e^x value as Q13.19 from 3.3546e-04 to 2981.0 + */ +int32_t sofm_exp_approx(int32_t x); -#endif +/** + * Calculated exponent function exp(x) = e^x by using sofm_exp_approx(). The input range for + * large arguments is internally reduced to -8 to +8 with rule exp(x) = exp(x/2) * exp(x/2) + * and reconstructed back. This function is essentially a wrapper for compatibility with + * existing usage of exp() function and Q-format choice. Note that the return value saturates + * to INT32_MAX with input arguments larger than 7.6246. + * @param x The input argument as Q5.27 from -16 to +16 + * @return The calculated e^x value as Q12.20 + */ +int32_t sofm_exp_fixed(int32_t x); -#define SOFM_EXP_BIT_MASK_LOW_Q27P5 0x0000000008000000 -#define SOFM_EXP_BIT_MASK_Q62P2 0x4000000000000000LL -#define SOFM_EXP_QUOTIENT_SCALE 0x40000000 -#define SOFM_EXP_TERMS_Q23P9 0x800000 -#define SOFM_EXP_LSHIFT_BITS 0x2000 -int32_t sofm_exp_int32(int32_t x); -int32_t sofm_exp_fixed(int32_t x); +/** + * Converts a decibels value to liner amplitude lin = 10^(db/20) value with optimized + * equation exp(db * log(10)/20). Note that due to range limitation of sofm_exp_fixed() + * the output saturates to maximum with about +66 dB input. + * @param db Decibels value in Q8.24 format, from -128 to +66.226 + * @return Linear value in Q12.20 format, from 3.9811e-07 to 2048 + */ int32_t sofm_db2lin_fixed(int32_t db); #endif /* __SOFM_EXP_FCN_H__ */ diff --git a/src/include/sof/math/fft.h b/src/include/sof/math/fft.h index 504465401cad..df06baf47c81 100644 --- a/src/include/sof/math/fft.h +++ b/src/include/sof/math/fft.h @@ -9,7 +9,9 @@ #ifndef __SOF_FFT_H__ #define __SOF_FFT_H__ +#include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/format.h> +#include <sof/math/icomplex32.h> #include <sof/common.h> #include <stdbool.h> #include <stdint.h> @@ -25,21 +27,9 @@ #endif -#define FFT_SIZE_MAX 1024 - -struct icomplex32 { - int32_t real; - int32_t imag; -}; - -/* Note: the add of packed attribute to icmplex16 would significantly increase - * processing time of fft_execute_16() so it is not done. The optimized versions of - * FFT for HiFi will need a different packed data structure vs. generic C. - */ -struct icomplex16 { - int16_t real; - int16_t imag; -}; +#define FFT_SIZE_MIN 1 +#define FFT_SIZE_MAX 1024 +#define FFT_MULTI_COUNT_MAX 3 struct fft_plan { uint32_t size; /* fft size */ @@ -51,10 +41,69 @@ struct fft_plan { struct icomplex16 *outb16; /* pointer to output integer complex buffer */ }; +struct fft_multi_plan { + struct fft_plan *fft_plan[FFT_MULTI_COUNT_MAX]; + struct icomplex32 *tmp_i32[FFT_MULTI_COUNT_MAX]; /* pointer to input buffer */ + struct icomplex32 *tmp_o32[FFT_MULTI_COUNT_MAX]; /* pointer to output buffer */ + struct icomplex32 *inb32; /* pointer to input integer complex buffer */ + struct icomplex32 *outb32; /* pointer to output integer complex buffer */ + uint16_t *bit_reverse_idx; + uint32_t total_size; + uint32_t fft_size; + int num_ffts; +}; + /* interfaces of the library */ -struct fft_plan *fft_plan_new(void *inb, void *outb, uint32_t size, int bits); +struct fft_plan *mod_fft_plan_new(struct processing_module *mod, void *inb, + void *outb, uint32_t size, int bits); void fft_execute_16(struct fft_plan *plan, bool ifft); void fft_execute_32(struct fft_plan *plan, bool ifft); -void fft_plan_free(struct fft_plan *plan16); +void mod_fft_plan_free(struct processing_module *mod, struct fft_plan *plan); + +/** + * mod_fft_multi_plan_new() - Prepare FFT for 2^N size and some other FFT sizes + * @param mod: Pointer to module + * @param inb: Buffer to use for complex input data + * @param outb: Buffer to use for complex output data + * @param size: Size of FFT as number of bins + * @param bits: World length of FFT. Currently only 32 is supported. + * @return Pointer to allocated FFT plan + * + * This function does the preparations to calculate FFT. If the size is power of two + * the operation is similar to mod_fft_plan_new(). Some other FFT sizes like 1536 is + * supported by allocated multiple FFT plans and by wrapping all needed for similar + * usage as power of two size FFT. + */ + +struct fft_multi_plan *mod_fft_multi_plan_new(struct processing_module *mod, void *inb, + void *outb, uint32_t size, int bits); +/** + * fft_multi_execute_32() - Calculate Fast Fourier Transform (FFT) for 2^size and other + * @param plan: Pointer to FFT plan created with mod_fft_multi_plan_new() + * @param ifft: Value 0 calculates FFT, value 1 calculates IFFT + * + * This function calculates the FFT with the buffers defined with mod_fft_multi_plan_new(). + */ +void fft_multi_execute_32(struct fft_multi_plan *plan, bool ifft); + +/** + * mod_fft_multi_plan_free() - Free the FFT plan + * @param mod: Pointer to module + * @param plan: Pointe to FFT plan + * + * This function frees the allocations done internally by the function mod_fft_multi_plan_new(). + * The input and output buffers need to be freed separately. + */ +void mod_fft_multi_plan_free(struct processing_module *mod, struct fft_multi_plan *plan); + +/** + * dft3_32() - Discrete Fourier Transform (DFT) for size 3. + * @param input: Pointer to complex values input array, Q1.31. + * @param output: Pointer to complex values output array, Q1.31, scaled down by 1/3. + * + * This function is useful for calculating some non power of two FFTs. E.g. the + * FFT for size 1536 is done with three 512 size FFTs and one 3 size DFT. + */ +void dft3_32(struct icomplex32 *input, struct icomplex32 *output); #endif /* __SOF_FFT_H__ */ diff --git a/src/include/sof/math/fir_hifi2ep.h b/src/include/sof/math/fir_hifi2ep.h index 85561c770c23..f3625104b3dc 100644 --- a/src/include/sof/math/fir_hifi2ep.h +++ b/src/include/sof/math/fir_hifi2ep.h @@ -30,7 +30,6 @@ struct fir_state_32x16 { ae_p16x2s *coef; /* Pointer to FIR coefficients */ int taps; /* Number of FIR taps */ int length; /* Number of FIR taps plus input length (even) */ - int in_shift; /* Amount of right shifts at input */ int out_shift; /* Amount of right shifts at output */ }; @@ -53,10 +52,10 @@ static inline void fir_hifiep_setup_circular(struct fir_state_32x16 *fir) void fir_get_lrshifts(struct fir_state_32x16 *fir, int *lshift, int *rshift); -void fir_32x16_hifiep(struct fir_state_32x16 *fir, int32_t x, int32_t *y, int lshift, int rshift); +void fir_32x16(struct fir_state_32x16 *fir, int32_t x, int32_t *y, int lshift, int rshift); -void fir_32x16_2x_hifiep(struct fir_state_32x16 *fir, int32_t x0, int32_t x1, - int32_t *y0, int32_t *y1, int lshift, int rshift); +void fir_32x16_2x(struct fir_state_32x16 *fir, int32_t x0, int32_t x1, + int32_t *y0, int32_t *y1, int lshift, int rshift); #endif #endif /* __SOF_MATH_FIR_HIFI2EP_H__ */ diff --git a/src/include/sof/math/fir_hifi3.h b/src/include/sof/math/fir_hifi3.h index 1a9e626247d7..abcf46df5f6f 100644 --- a/src/include/sof/math/fir_hifi3.h +++ b/src/include/sof/math/fir_hifi3.h @@ -28,7 +28,6 @@ struct fir_state_32x16 { ae_f16x4 *coef; /* Pointer to FIR coefficients */ int taps; /* Number of FIR taps */ int length; /* Number of FIR taps plus input length (even) */ - int in_shift; /* Amount of right shifts at input */ int out_shift; /* Amount of right shifts at output */ }; @@ -55,14 +54,12 @@ static inline void fir_comp_setup_circular(const struct audio_stream *buffer) AE_SETCEND0(audio_stream_get_end_addr(buffer)); } -void fir_get_lrshifts(struct fir_state_32x16 *fir, int *lshift, - int *rshift); +void fir_get_lrshifts(struct fir_state_32x16 *fir, int *lshift, int *rshift); -void fir_32x16_hifi3(struct fir_state_32x16 *fir, ae_int32 x, ae_int32 *y, - int shift); +void fir_32x16(struct fir_state_32x16 *fir, ae_int32 x, ae_int32 *y, int shift); -void fir_32x16_2x_hifi3(struct fir_state_32x16 *fir, ae_int32 x0, ae_int32 x1, - ae_int32 *y0, ae_int32 *y1, int shift); +void fir_32x16_2x(struct fir_state_32x16 *fir, ae_int32 x0, ae_int32 x1, + ae_int32 *y0, ae_int32 *y1, int shift); #endif #endif /* __SOF_MATH_FIR_HIFI3_H__ */ diff --git a/src/include/sof/math/icomplex16.h b/src/include/sof/math/icomplex16.h new file mode 100644 index 000000000000..a2ade94660ba --- /dev/null +++ b/src/include/sof/math/icomplex16.h @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2020-2026 Intel Corporation. +// +// Author: Amery Song <chao.song@intel.com> +// Keyon Jie <yang.jie@linux.intel.com> + +#include <sof/audio/format.h> +#include <sof/common.h> +#include <stdint.h> + +#ifndef __SOF_ICOMPLEX16_H__ +#define __SOF_ICOMPLEX16_H__ + +/* Note: the add of packed attribute to icmplex16 would significantly increase + * processing time of fft_execute_16() so it is not done. The optimized versions of + * FFT for HiFi will need a different packed data structure vs. generic C. + * + * TODO: Use with care with other than 16-bit FFT internals. Access with intrinsics + * will requires packed and aligned data. Currently there is no such usage in SOF. + */ + +/** + * struct icomplex16 - Storage for a normal complex number. + * @param real The real part in Q1.15 fractional format. + * @param imag The imaginary part in Q1.15 fractional format. + */ +struct icomplex16 { + int16_t real; + int16_t imag; +}; + +/* + * Helpers for 16 bit FFT calculation + */ +static inline void icomplex16_add(const struct icomplex16 *in1, const struct icomplex16 *in2, + struct icomplex16 *out) +{ + out->real = in1->real + in2->real; + out->imag = in1->imag + in2->imag; +} + +static inline void icomplex16_sub(const struct icomplex16 *in1, const struct icomplex16 *in2, + struct icomplex16 *out) +{ + out->real = in1->real - in2->real; + out->imag = in1->imag - in2->imag; +} + +static inline void icomplex16_mul(const struct icomplex16 *in1, const struct icomplex16 *in2, + struct icomplex16 *out) +{ + int32_t real = (int32_t)in1->real * in2->real - (int32_t)in1->imag * in2->imag; + int32_t imag = (int32_t)in1->real * in2->imag + (int32_t)in1->imag * in2->real; + + out->real = Q_SHIFT_RND(real, 30, 15); + out->imag = Q_SHIFT_RND(imag, 30, 15); +} + +/* complex conjugate */ +static inline void icomplex16_conj(struct icomplex16 *comp) +{ + comp->imag = sat_int16(-((int32_t)comp->imag)); +} + +/* shift a complex n bits, n > 0: left shift, n < 0: right shift */ +static inline void icomplex16_shift(const struct icomplex16 *input, int16_t n, + struct icomplex16 *output) +{ + int n1, n2; + + if (n >= 0) { + /* need saturation handling */ + output->real = sat_int16((int32_t)input->real << n); + output->imag = sat_int16((int32_t)input->imag << n); + } else { + n1 = -n; + n2 = 1 << (n1 - 1); + output->real = sat_int16(((int32_t)input->real + n2) >> n1); + output->imag = sat_int16(((int32_t)input->imag + n2) >> n1); + } +} + +#endif /* __SOF_ICOMPLEX16_H__ */ diff --git a/src/include/sof/math/icomplex32.h b/src/include/sof/math/icomplex32.h new file mode 100644 index 000000000000..29d22daadab8 --- /dev/null +++ b/src/include/sof/math/icomplex32.h @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2020-2026 Intel Corporation. +// +// Author: Amery Song <chao.song@intel.com> +// Keyon Jie <yang.jie@linux.intel.com> + +#include <sof/audio/format.h> +#include <sof/math/exp_fcn.h> +#include <sof/math/log.h> +#include <sof/math/trig.h> +#include <sof/common.h> +#include <stdint.h> + +#ifndef __SOF_ICOMPLEX32_H__ +#define __SOF_ICOMPLEX32_H__ + +/** + * struct icomplex32 - Storage for a normal complex number. + * @param real The real part in Q1.31 fractional format. + * @param imag The imaginary part in Q1.31 fractional format. + */ +struct icomplex32 { + int32_t real; + int32_t imag; +}; + +/** + * struct ipolar32 - Storage for complex number in polar format. + * @param magnitude The length of vector in Q2.30 format. + * @param angle The phase angle of the vector -pi to +pi in Q3.29 format. + */ +struct ipolar32 { + int32_t magnitude; + int32_t angle; +}; + +/* + * These helpers are optimized for FFT calculation only. + * e.g. _add/sub() assume the output won't be saturate so no check needed, + * and _mul() assumes Q1.31 * Q1.31 so the output will be shifted to be Q1.31. + */ + +static inline void icomplex32_add(const struct icomplex32 *in1, const struct icomplex32 *in2, + struct icomplex32 *out) +{ + out->real = in1->real + in2->real; + out->imag = in1->imag + in2->imag; +} + +static inline void icomplex32_adds(const struct icomplex32 *in1, const struct icomplex32 *in2, + struct icomplex32 *out) +{ + out->real = sat_int32((int64_t)in1->real + in2->real); + out->imag = sat_int32((int64_t)in1->imag + in2->imag); +} + +static inline void icomplex32_sub(const struct icomplex32 *in1, const struct icomplex32 *in2, + struct icomplex32 *out) +{ + out->real = in1->real - in2->real; + out->imag = in1->imag - in2->imag; +} + +static inline void icomplex32_mul(const struct icomplex32 *in1, const struct icomplex32 *in2, + struct icomplex32 *out) +{ + out->real = ((int64_t)in1->real * in2->real - (int64_t)in1->imag * in2->imag) >> 31; + out->imag = ((int64_t)in1->real * in2->imag + (int64_t)in1->imag * in2->real) >> 31; +} + +/* complex conjugate */ +static inline void icomplex32_conj(struct icomplex32 *comp) +{ + comp->imag = SATP_INT32((int64_t)-1 * comp->imag); +} + +/* shift a complex n bits, n > 0: left shift, n < 0: right shift */ +static inline void icomplex32_shift(const struct icomplex32 *input, int32_t n, + struct icomplex32 *output) +{ + if (n > 0) { + /* need saturation handling */ + output->real = SATP_INT32(SATM_INT32((int64_t)input->real << n)); + output->imag = SATP_INT32(SATM_INT32((int64_t)input->imag << n)); + } else { + output->real = input->real >> -n; + output->imag = input->imag >> -n; + } +} + +/** + * sofm_icomplex32_to_polar() - Convert (re, im) complex number to polar. + * @param complex Pointer to input complex number in Q1.31 format. + * @param polar Pointer to output complex number in Q2.30 format for + * magnitude and Q3.29 for phase angle. + * + * The function can be used to convert data in-place with same address for + * input and output. It can be useful to save scratch memory. + */ +void sofm_icomplex32_to_polar(struct icomplex32 *complex, struct ipolar32 *polar); + +/** + * sofm_ipolar32_to_complex() - Convert complex number from polar to normal (re, im) format. + * @param polar Pointer to input complex number in polar format. + * @param complex Pointer to output complex number in normal format in Q1.31. + * + * This function can be used to convert data in-place with same address for input + * and output. It can be useful to save scratch memory. + */ +void sofm_ipolar32_to_complex(struct ipolar32 *polar, struct icomplex32 *complex); + +#endif /* __SOF_ICOMPLEX32_H__ */ diff --git a/src/include/sof/math/iir_df1.h b/src/include/sof/math/iir_df1.h index fc5e034b3b4b..24653f690ea3 100644 --- a/src/include/sof/math/iir_df1.h +++ b/src/include/sof/math/iir_df1.h @@ -13,6 +13,7 @@ #include <sof/common.h> #define IIR_DF1_NUM_STATE 4 +#define SOF_IIR_DF1_4TH_NUM_BIQUADS 2 struct iir_state_df1 { unsigned int biquads; /* Number of IIR 2nd order sections total */ @@ -34,8 +35,24 @@ void iir_init_delay_df1(struct iir_state_df1 *iir, int32_t **state); void iir_reset_df1(struct iir_state_df1 *iir); +/** + * Calculate IIR filter consisting of biquads + * @param iir IIR state with configured biquad coefficients and delay lines data + * @param x Single s32 Q1.31 format input sample + * @return Single s32 Q1.31 format output samples + */ int32_t iir_df1(struct iir_state_df1 *iir, int32_t x); +/** + * Calculate IIR filter consisting of biquads, special simplified version for + * 4th order filter with two biquads in series. Note: There are no checks for + * iir struct members. + * @param iir IIR state with configured biquad coefficients and delay lines data + * @param x Single s32 Q1.31 format input sample + * @return Single s32 Q1.31 format output samples + */ +int32_t iir_df1_4th(struct iir_state_df1 *iir, int32_t x); + /* Inline functions */ #if SOF_USE_MIN_HIFI(3, FILTER) #include "iir_df1_hifi3.h" diff --git a/src/include/sof/math/matrix.h b/src/include/sof/math/matrix.h index 67ce88c3fbde..f48f1ca4960d 100644 --- a/src/include/sof/math/matrix.h +++ b/src/include/sof/math/matrix.h @@ -10,6 +10,7 @@ #ifndef __SOF_MATH_MATRIX_H__ #define __SOF_MATH_MATRIX_H__ +#include <sof/audio/module_adapter/module/generic.h> #include <rtos/alloc.h> #include <ipc/topology.h> #include <stdint.h> @@ -37,7 +38,21 @@ static inline struct mat_matrix_16b *mat_matrix_alloc_16b(int16_t rows, int16_t struct mat_matrix_16b *mat; const int mat_size = sizeof(int16_t) * rows * columns + sizeof(struct mat_matrix_16b); - mat = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, mat_size); + mat = rzalloc(SOF_MEM_FLAG_USER, mat_size); + if (mat) + mat_init_16b(mat, rows, columns, fractions); + + return mat; +} + +static inline struct mat_matrix_16b *mod_mat_matrix_alloc_16b(struct processing_module *mod, + int16_t rows, int16_t columns, + int16_t fractions) +{ + struct mat_matrix_16b *mat; + const int mat_size = sizeof(int16_t) * rows * columns + sizeof(struct mat_matrix_16b); + + mat = mod_zalloc(mod, mat_size); if (mat) mat_init_16b(mat, rows, columns, fractions); diff --git a/src/include/sof/math/mu_law.h b/src/include/sof/math/mu_law.h new file mode 100644 index 000000000000..b8aaec5b5e3b --- /dev/null +++ b/src/include/sof/math/mu_law.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +#ifndef __SOF_MATH_MU_LAW_H__ +#define __SOF_MATH_MU_LAW_H__ + +#include <stdint.h> + +/** + * sofm_mu_law_encode() - Encode sample with mu-law coding + * @param sample: A s16 sample value + * + * The mu-law codec is defined in ITU-T G.711 standard and has been used + * in telecommunications in USA and Japan. The mu-law coding compresses + * 14 bit samples to 8 bit data stream. In SOF the high 14 bits of s16 + * format are used for compatibility with normal audios. + * + * @return: Compressed 8 bit code value + */ +uint8_t sofm_mu_law_encode(int16_t sample); + +/** + * sofm_mu_law_decode() - Decode mu-law encoded code word + * @param byte: Encoded code word + * + * The mu-law decoder expands a 8 bit code word into a 14 bit sample value. + * In the SOF the high 14 bits are aligned to the most significant bits + * to be compatible with normal s16 Q1.15 samples. + * + * @return: Sample value in s16 format + */ +int16_t sofm_mu_law_decode(int8_t byte); + +#endif /* __SOF_MATH_MU_LAW_H__ */ diff --git a/src/include/sof/math/numbers.h b/src/include/sof/math/numbers.h index 0cd9314f4859..80d4eba1a639 100644 --- a/src/include/sof/math/numbers.h +++ b/src/include/sof/math/numbers.h @@ -36,7 +36,11 @@ __a > 0 ? 1 : 0; \ }) +/* Zephyr added gcd() in 2025/Nov to sys/util.h */ +#ifndef gcd +#define USE_SOF_GCD 1 int gcd(int a, int b); /* Calculate greatest common divisor for a and b */ +#endif /* This is a divide function that returns ceil of the quotient. * E.g. ceil_divide(9, 3) returns 3, ceil_divide(10, 3) returns 4. diff --git a/src/include/sof/math/sqrt.h b/src/include/sof/math/sqrt.h index 1cdb82afe9a0..3d8fd0df72fe 100644 --- a/src/include/sof/math/sqrt.h +++ b/src/include/sof/math/sqrt.h @@ -1,15 +1,32 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2021 Intel Corporation. All rights reserved. + * Copyright(c) 2021-2026 Intel Corporation. * * Author: Shriram Shastry <malladi.sastry@linux.intel.com> * */ -#ifndef __SOF_MATH__SQRTLOOKUP__H -#define __SOF_MATH__SQRTLOOKUP__H +#ifndef __SOF_MATH_SQRT_H__ +#define __SOF_MATH_SQRT_H__ #include <stdint.h> -uint16_t sqrt_int16(uint16_t u); -#endif +/** + * sofm_sqrt_int16() - Calculate 16-bit fractional square root function. + * @param u Input value in Q4.12 format, from 0 to 16.0. + * @return Calculated square root of n in Q4.12 format, from 0 to 4.0. + */ +uint16_t sofm_sqrt_int16(uint16_t u); + +/** + * sofm_sqrt_int32() - Calculate 32-bit fractional square root function. + * @param n Input value in Q2.30 format, from 0 to 2.0. + * @return Calculated square root of n in Q2.30 format. + * + * The input range of square root function is matched with Q1.31 + * complex numbers range where the magnitude squared can be to 2.0. + * The function returns zero for non-positive input values. + */ +int32_t sofm_sqrt_int32(int32_t n); + +#endif /* __SOF_MATH_SQRT_H__ */ diff --git a/src/include/sof/math/trig.h b/src/include/sof/math/trig.h index 0c0b2d23a388..67428cac494a 100644 --- a/src/include/sof/math/trig.h +++ b/src/include/sof/math/trig.h @@ -13,14 +13,17 @@ #include <stdint.h> -#define PI_DIV2_Q4_28 421657428 -#define PI_DIV2_Q3_29 843314856 -#define PI_Q4_28 843314857 -#define PI_MUL2_Q4_28 1686629713 -#define CORDIC_31B_TABLE_SIZE 31 -#define CORDIC_15B_TABLE_SIZE 15 -#define CORDIC_30B_ITABLE_SIZE 30 -#define CORDIC_16B_ITABLE_SIZE 16 +#define PI_Q4_28 843314857 /* int32(pi * 2^28) */ +#define PI_MUL2_Q4_28 1686629713 /* int32(2 * pi * 2^28) */ +#define PI_DIV2_Q3_29 843314857 /* int32(pi / 2 * 2^29) */ +#define PI_Q3_29 1686629713 /* int32(pi * 2^29) */ + +#define CORDIC_31B_TABLE_SIZE 31 +#define CORDIC_15B_TABLE_SIZE 15 +#define CORDIC_30B_ITABLE_SIZE 30 +#define CORDIC_16B_ITABLE_SIZE 16 +#define CORDIC_31B_ITERATIONS (CORDIC_31B_TABLE_SIZE - 1) +#define CORDIC_16B_ITERATIONS (CORDIC_16B_ITABLE_SIZE - 1) typedef enum { EN_32B_CORDIC_SINE, @@ -36,13 +39,49 @@ struct cordic_cmpx { int32_t im; }; +/** + * cordic_approx() - CORDIC-based approximation of sine and cosine + * @param th_rad_fxp Input angle in radian Q4.28 format. + * @param a_idx Used LUT size. + * @param sign Output pointer to sine/cosine sign. + * @param b_yn Output pointer to sine value in Q2.30 format. + * @param xn Output pointer to cosine value in Q2.30 format. + * @param th_cdc_fxp Output pointer to the residual angle in Q2.30 format. + */ void cordic_approx(int32_t th_rad_fxp, int32_t a_idx, int32_t *sign, int32_t *b_yn, int32_t *xn, int32_t *th_cdc_fxp); -int32_t is_scalar_cordic_acos(int32_t realvalue, int16_t numiters); -int32_t is_scalar_cordic_asin(int32_t realvalue, int16_t numiters); + +/** + * is_scalar_cordic_acos() - CORDIC-based approximation for inverse cosine + * @param realvalue Input cosine value in Q2.30 format. + * @param numiters_minus_one Number of iterations minus one. + * @return Inverse cosine angle in Q3.29 format. + */ +int32_t is_scalar_cordic_acos(int32_t realvalue, int numiters_minus_one); + +/** + * is_scalar_cordic_asin() - CORDIC-based approximation for inverse sine + * @param realvalue Input sine value in Q2.30 format. + * @param numiters_minus_one Number of iterations minus one. + * @return Inverse sine angle in Q2.30 format. + */ +int32_t is_scalar_cordic_asin(int32_t realvalue, int numiters_minus_one); + +/** + * cmpx_cexp() - CORDIC-based approximation of complex exponential e^(j*THETA) + * @param sign Sine sign + * @param b_yn Sine value in Q2.30 format + * @param xn Cosine value in Q2.30 format + * @param type CORDIC type + * @param cexp Output pointer to complex result in struct cordic_cmpx + */ void cmpx_cexp(int32_t sign, int32_t b_yn, int32_t xn, cordic_cfg type, struct cordic_cmpx *cexp); -/* Input is Q4.28, output is Q1.31 */ + /** + * sin_fixed_32b() - Sine function using CORDIC algorithm + * @param th_rad_fxp Input angle in radian Q4.28 format. + * @return Sine value in Q1.31 format. + * * Compute fixed point cordicsine with table lookup and interpolation * The cordic sine algorithm converges, when the angle is in the range * [-pi/2, pi/2).If an angle is outside of this range, then a multiple of @@ -71,6 +110,10 @@ static inline int32_t sin_fixed_32b(int32_t th_rad_fxp) } /** + * cos_fixed_32b() - Cosine function using CORDIC algorithm + * @param th_rad_fxp Input angle in radian Q4.28 format. + * @return Cosine value in Q1.31 format. + * * Compute fixed point cordicsine with table lookup and interpolation * The cordic cosine algorithm converges, when the angle is in the range * [-pi/2, pi/2).If an angle is outside of this range, then a multiple of @@ -98,8 +141,11 @@ static inline int32_t cos_fixed_32b(int32_t th_rad_fxp) return sat_int32(Q_SHIFT_LEFT((int64_t)th_cdc_fxp, 30, 31)); } -/* Input is Q4.28, output is Q1.15 */ /** + * sin_fixed_16b() - Sine function using CORDIC algorithm + * @param th_rad_fxp Input angle in radian Q4.28 format. + * @return Sine value in Q1.15 format + * * Compute fixed point cordic sine with table lookup and interpolation * The cordic sine algorithm converges, when the angle is in the range * [-pi/2, pi/2).If an angle is outside of this range, then a multiple of @@ -129,6 +175,10 @@ static inline int16_t sin_fixed_16b(int32_t th_rad_fxp) } /** + * cos_fixed_16b() - Cosine function using CORDIC algorithm + * @param th_rad_fxp Input angle in radian Q4.28 format. + * @return Cosine value in Q1.15 format. + * * Compute fixed point cordic cosine with table lookup and interpolation * The cordic cos algorithm converges, when the angle is in the range * [-pi/2, pi/2).If an angle is outside of this range, then a multiple of @@ -158,7 +208,10 @@ static inline int16_t cos_fixed_16b(int32_t th_rad_fxp) } /** - * CORDIC-based approximation of complex exponential e^(j*THETA). + * cmpx_exp_32b() - CORDIC-based approximation of complex exponential e^(j*THETA). + * @param th_rad_fxp Input angle in radian Q4.28 format. + * @param cexp Output pointer to complex result in struct cordic_cmpx in Q2.30 format. + * * computes COS(THETA) + j*SIN(THETA) using CORDIC algorithm * approximation and returns the complex result. * THETA values must be in the range [-2*pi, 2*pi). The cordic @@ -190,7 +243,10 @@ static inline void cmpx_exp_32b(int32_t th_rad_fxp, struct cordic_cmpx *cexp) } /** - * CORDIC-based approximation of complex exponential e^(j*THETA). + * cmpx_exp_16b() - CORDIC-based approximation of complex exponential e^(j*THETA). + * @param th_rad_fxp Input angle in radian Q4.28 format. + * @param cexp Output pointer to complex result in struct cordic_cmpx in Q1.15 format. + * * computes COS(THETA) + j*SIN(THETA) using CORDIC algorithm * approximation and returns the complex result. * THETA values must be in the range [-2*pi, 2*pi). The cordic @@ -223,7 +279,10 @@ static inline void cmpx_exp_16b(int32_t th_rad_fxp, struct cordic_cmpx *cexp) } /** - * CORDIC-based approximation of inverse sine + * asin_fixed_32b() - CORDIC-based approximation of inverse sine + * @param cdc_asin_th Input value in Q2.30 format. + * @return Inverse sine angle in Q2.30 format. + * * inverse sine of cdc_asin_theta based on a CORDIC approximation. * asin(cdc_asin_th) inverse sine angle values in radian produces using the DCORDIC * (Double CORDIC) algorithm. @@ -238,17 +297,18 @@ static inline int32_t asin_fixed_32b(int32_t cdc_asin_th) int32_t th_asin_fxp; if (cdc_asin_th >= 0) - th_asin_fxp = is_scalar_cordic_asin(cdc_asin_th, - CORDIC_31B_TABLE_SIZE); + th_asin_fxp = is_scalar_cordic_asin(cdc_asin_th, CORDIC_31B_ITERATIONS); else - th_asin_fxp = -is_scalar_cordic_asin(-cdc_asin_th, - CORDIC_31B_TABLE_SIZE); + th_asin_fxp = -is_scalar_cordic_asin(-cdc_asin_th, CORDIC_31B_ITERATIONS); return th_asin_fxp; /* Q2.30 */ } /** - * CORDIC-based approximation of inverse cosine + * acos_fixed_32b() - CORDIC-based approximation of inverse cosine + * @param cdc_acos_th Input value in Q2.30 format. + * @return Inverse cosine angle in Q3.29 format. + * * inverse cosine of cdc_acos_theta based on a CORDIC approximation * acos(cdc_acos_th) inverse cosine angle values in radian produces using the DCORDIC * (Double CORDIC) algorithm. @@ -262,18 +322,18 @@ static inline int32_t acos_fixed_32b(int32_t cdc_acos_th) int32_t th_acos_fxp; if (cdc_acos_th >= 0) - th_acos_fxp = is_scalar_cordic_acos(cdc_acos_th, - CORDIC_31B_TABLE_SIZE); + th_acos_fxp = is_scalar_cordic_acos(cdc_acos_th, CORDIC_31B_ITERATIONS); else - th_acos_fxp = - PI_MUL2_Q4_28 - is_scalar_cordic_acos(-cdc_acos_th, - CORDIC_31B_TABLE_SIZE); + th_acos_fxp = PI_Q3_29 - is_scalar_cordic_acos(-cdc_acos_th, CORDIC_31B_ITERATIONS); return th_acos_fxp; /* Q3.29 */ } /** - * CORDIC-based approximation of inverse sine + * asin_fixed_16b() - CORDIC-based approximation of inverse sine + * @param cdc_asin_th Input value in Q2.30 format. + * @return Inverse sine angle in Q2.14 format. + * * inverse sine of cdc_asin_theta based on a CORDIC approximation. * asin(cdc_asin_th) inverse sine angle values in radian produces using the DCORDIC * (Double CORDIC) algorithm. @@ -289,17 +349,18 @@ static inline int16_t asin_fixed_16b(int32_t cdc_asin_th) int32_t th_asin_fxp; if (cdc_asin_th >= 0) - th_asin_fxp = is_scalar_cordic_asin(cdc_asin_th, - CORDIC_16B_ITABLE_SIZE); + th_asin_fxp = is_scalar_cordic_asin(cdc_asin_th, CORDIC_16B_ITERATIONS); else - th_asin_fxp = -is_scalar_cordic_asin(-cdc_asin_th, - CORDIC_16B_ITABLE_SIZE); + th_asin_fxp = -is_scalar_cordic_asin(-cdc_asin_th, CORDIC_16B_ITERATIONS); /*convert Q2.30 to Q2.14 format*/ return sat_int16(Q_SHIFT_RND(th_asin_fxp, 30, 14)); } /** - * CORDIC-based approximation of inverse cosine + * acos_fixed_16b() - CORDIC-based approximation of inverse cosine + * @param cdc_acos_th Input value in Q2.30 format. + * @return Inverse cosine angle in Q3.13 format. + * * inverse cosine of cdc_acos_theta based on a CORDIC approximation * acos(cdc_acos_th) inverse cosine angle values in radian produces using the DCORDIC * (Double CORDIC) algorithm. @@ -314,15 +375,26 @@ static inline int16_t acos_fixed_16b(int32_t cdc_acos_th) int32_t th_acos_fxp; if (cdc_acos_th >= 0) - th_acos_fxp = is_scalar_cordic_acos(cdc_acos_th, - CORDIC_16B_ITABLE_SIZE); + th_acos_fxp = is_scalar_cordic_acos(cdc_acos_th, CORDIC_16B_ITERATIONS); else - th_acos_fxp = - PI_MUL2_Q4_28 - is_scalar_cordic_acos(-cdc_acos_th, - CORDIC_16B_ITABLE_SIZE); + th_acos_fxp = PI_Q3_29 - is_scalar_cordic_acos(-cdc_acos_th, CORDIC_16B_ITERATIONS); /*convert Q3.29 to Q3.13 format*/ return sat_int16(Q_SHIFT_RND(th_acos_fxp, 29, 13)); } +/** + * sofm_atan2_32b() - Four-quadrant arctangent using degree-9 Remez minimax polynomial + * @param y Imaginary component (sine) in Q1.31 format. + * @param x Real component (cosine) in Q1.31 format. + * @return Angle in Q3.29 radians, range [-pi, +pi]. + * + * Uses the Horner-form polynomial: + * atan(z) = z * (C0 + z^2 * (C1 + z^2 * (C2 + z^2 * (C3 + z^2 * C4)))) + * + * with Remez minimax coefficients on [0, 1]. + * Maximum error ~0.001 degrees (1.94e-5 radians). + */ +int32_t sofm_atan2_32b(int32_t y, int32_t x); + #endif /* __SOF_MATH_TRIG_H__ */ diff --git a/src/include/sof/math/window.h b/src/include/sof/math/window.h index bd04317b96ee..d72d00b3bd87 100644 --- a/src/include/sof/math/window.h +++ b/src/include/sof/math/window.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2022 Intel Corporation. All rights reserved. + * Copyright(c) 2022-2025 Intel Corporation. * * Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> */ @@ -13,40 +13,85 @@ #include <sof/audio/format.h> #include <stdint.h> -#define WIN_BLACKMAN_A0 Q_CONVERT_FLOAT(7938.0 / 18608.0, 15) /* For "exact" blackman */ +#define WIN_BLACKMAN_A0_Q15 Q_CONVERT_FLOAT(7938.0 / 18608.0, 15) /* For "exact" blackman 16bit */ +#define WIN_BLACKMAN_A0_Q31 Q_CONVERT_FLOAT(7938.0 / 18608.0, 31) /* For "exact" blackman 32bit */ /** - * \brief Return rectangular window, simply values of one - * \param[in,out] win Output vector with coefficients - * \param[in] length Length of coefficients vector + * Returns a rectangular window with 16 bits, simply a values of ones vector + * @param win Pointer to output vector with Q1.15 coefficients + * @param length Length of coefficients vector */ void win_rectangular_16b(int16_t win[], int length); /** - * \brief Calculate Blackman window function, reference + * Returns a rectangular window with 32 bits, simply a values of ones vector + * @param win Pointer to output vector with Q1.31 coefficients + * @param length Length of coefficients vector + */ +void win_rectangular_32b(int32_t win[], int length); + +/** + * Calculates a Blackman window function with 16 bits, reference * https://en.wikipedia.org/wiki/Window_function#Blackman_window * - * \param[in,out] win Output vector with coefficients - * \param[in] length Length of coefficients vector - * \param[in] a0 Parameter for window shape, use e.g. 0.42 as Q1.15 + * @param win Pointer to output vector with Q1.15 coefficients + * @param length Length of coefficients vector + * @param a0 Parameter for window shape, use e.g. 0.42 as Q1.15 */ void win_blackman_16b(int16_t win[], int length, int16_t a0); /** - * \brief Calculate Hamming window function, reference + * Calculates a Blackman window function with 32 bits, reference + * https://en.wikipedia.org/wiki/Window_function#Blackman_window + * + * @param win Pointer to output vector with Q1.31 coefficients + * @param length Length of coefficients vector + * @param a0 Parameter for window shape, use e.g. 0.42 as Q1.31 + */ +void win_blackman_32b(int32_t win[], int length, int32_t a0); + +/** + * Calculates a Hann window function with 16 bits, reference * https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows * - * \param[in,out] win Output vector with coefficients - * \param[in] length Length of coefficients vector + * @param win Pointer to output vector with Q1.15 coefficients + * @param length Length of coefficients vector + */ +void win_hann_16b(int16_t win[], int length); + +/** + * Calculates a Hann window function with 32 bits, reference + * https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows + * + * @param win Pointer to output vector with Q1.31 coefficients + * @param length Length of coefficients vector + */ +void win_hann_32b(int32_t win[], int length); + +/** + * Calculates a Hamming window function with 16 bits, reference + * https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows + * + * @param win Pointer to output vector with Q1.15 coefficients + * @param length Length of coefficients vector */ void win_hamming_16b(int16_t win[], int length); /** - * \brief Calculate Povey window function. It's a window function - * from Pytorch. + * Calculates a Hamming window function with 32 bits, reference + * https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows + * + * @param win Pointer to output vector with Q1.31 coefficients + * @param length Length of coefficients vector + */ +void win_hamming_32b(int32_t win[], int length); + +/** + * Calculates a Povey window function with 16 bits. It's a window function + * used in Pytorch and Kaldi. * - * \param[in,out] win Output vector with coefficients - * \param[in] length Length of coefficients vector + * @param win Output vector with coefficients + * @param length Length of coefficients vector */ void win_povey_16b(int16_t win[], int length); diff --git a/src/include/sof/objpool.h b/src/include/sof/objpool.h new file mode 100644 index 000000000000..0821fec8786b --- /dev/null +++ b/src/include/sof/objpool.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +#ifndef __ZEPHYR_OBJPOOL_H__ +#define __ZEPHYR_OBJPOOL_H__ + +#include <sof/list.h> + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +struct vregion; +struct k_heap; +struct objpool_head { + struct list_item list; + struct vregion *vreg; + struct k_heap *heap; + uint32_t flags; +}; + +/** + * Allocate memory tracked as part of an object pool. + * + * @param head Pointer to the object pool head. + * @param size Size in bytes of memory blocks to allocate. + * @param flags Memory allocation flags. + * + * @return a pointer to the allocated memory on success, NULL on failure. + * + * Allocate a memory block of @a size bytes. @a size is used upon the first + * invocation to allocate memory on the heap, all consequent allocations with + * the same @a head must use the same @a size value. First allocation with an + * empty @a head allocates 2 blocks. After both blocks are taken and a third one + * is requested, the next call allocates 4 blocks, then 8, 16 and 32. After that + * 32 blocks are allocated every time. Note, that by design allocated blocks are + * never freed. See more below. + * TODO: @a flags are currently only used when allocating new object sets. + * Should add a check that they're consistent with already allocated objects. + */ +void *objpool_alloc(struct objpool_head *head, size_t size, uint32_t flags); + +/** + * Return a block to the object pool + * + * @param head Pointer to the object pool head. + * @param data Pointer to the object to return (can be NULL) + * + * @return 0 on success or a negative error code. + * + * Return a block to the object pool. Memory is never freed by design, unused + * blocks are kept in the object pool for future re-use. + */ +int objpool_free(struct objpool_head *head, void *data); + +/** + * Free all of the object pool memory + * + * @param head Pointer to the object pool head. + */ +void objpool_prune(struct objpool_head *head); + +/* returns true to stop */ +typedef bool (*objpool_iterate_cb)(void *data, void *arg); + +/** + * Iterate over object pool entries until stopped + * + * @param head Pointer to the object pool head. + * @param cb Callback function + * @param arg Callback function argument + * + * @return 0 on success or a negative error code. + * + * Call the callback function for each entry in the pool, until it returns true. + * If the callback never returns true, return an error. + */ +int objpool_iterate(struct objpool_head *head, objpool_iterate_cb cb, void *arg); + +#endif diff --git a/src/include/sof/probe/probe.h b/src/include/sof/probe/probe.h index f3f01435902b..de8873ad0a67 100644 --- a/src/include/sof/probe/probe.h +++ b/src/include/sof/probe/probe.h @@ -9,11 +9,12 @@ #define __SOF_PROBE_PROBE_H__ #include <ipc/probe.h> +#include <sys/types.h> /** * A buffer of logging data is available for processing. */ -typedef void(*probe_logging_hook_t)(uint8_t *buffer, size_t length); +typedef ssize_t(*probe_logging_hook_t)(uint8_t *buffer, size_t length); #if CONFIG_LOG_BACKEND_SOF_PROBE const struct log_backend *log_backend_probe_get(void); diff --git a/src/include/sof/samples/audio/smart_amp_test.h b/src/include/sof/samples/audio/smart_amp_test.h index c5ddd8032d99..3feda5005125 100644 --- a/src/include/sof/samples/audio/smart_amp_test.h +++ b/src/include/sof/samples/audio/smart_amp_test.h @@ -8,10 +8,8 @@ #ifndef __SOF_AUDIO_SMART_AMP_H__ #define __SOF_AUDIO_SMART_AMP_H__ -#ifndef __SOF_MODULE_SERVICE_BUILD__ #include <sof/audio/component.h> #include <sof/audio/data_blob.h> -#endif #if CONFIG_IPC_MAJOR_4 #include <ipc4/base-config.h> @@ -21,20 +19,10 @@ #define SMART_AMP_MAX_STREAM_CHAN 8 -/* Max channels for all intel platforms are 8 */ -#define MAX_CHANNELS 8 - /** IPC blob types */ #define SOF_SMART_AMP_CONFIG 0 #define SOF_SMART_AMP_MODEL 1 -#ifdef __SOF_MODULE_SERVICE_BUILD__ -#define LOG_ERR(...) -#define LOG_WRN(...) -#define LOG_DBG(...) -#define LOG_INF(...) -#endif - struct smart_amp_model_data { uint32_t data_size; void *data; @@ -95,8 +83,8 @@ struct smart_amp_model_data { struct sof_smart_amp_config { uint32_t size; uint32_t feedback_channels; - int8_t source_ch_map[MAX_CHANNELS]; - int8_t feedback_ch_map[MAX_CHANNELS]; + int8_t source_ch_map[PLATFORM_MAX_CHANNELS]; + int8_t feedback_ch_map[PLATFORM_MAX_CHANNELS]; }; #if CONFIG_IPC_MAJOR_4 diff --git a/src/include/sof/schedule/dp_schedule.h b/src/include/sof/schedule/dp_schedule.h index 0a064204e8d1..2267d676fb8a 100644 --- a/src/include/sof/schedule/dp_schedule.h +++ b/src/include/sof/schedule/dp_schedule.h @@ -13,6 +13,8 @@ #include <user/trace.h> #include <stdint.h> #include <ipc4/base_fw.h> +#include <ipc4/module.h> +#include <ipc4/pipeline.h> struct processing_module; @@ -67,13 +69,15 @@ int scheduler_dp_init(void); * \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] options task options used for creation */ int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid, const struct task_ops *ops, struct processing_module *mod, uint16_t core, - size_t stack_size); + size_t stack_size, + uint32_t options); /** * \brief Extract information about scheduler's tasks @@ -84,4 +88,47 @@ int scheduler_dp_task_init(struct task **task, void scheduler_get_task_info_dp(struct scheduler_props *scheduler_props, uint32_t *data_off_size); +enum { + DP_TASK_EVENT_PROCESS = BIT(0), /* Need to process data */ + DP_TASK_EVENT_CANCEL = BIT(1), /* Thread cancellation */ + DP_TASK_EVENT_IPC = BIT(2), /* IPC message */ + DP_TASK_EVENT_IPC_DONE = BIT(3), /* IPC processing has completed. */ +}; + +struct bind_info; +struct sof_source; +struct sof_sink; +/* + * Keeps the scheduler_dp_thread_ipc() flow simple - just one call that does all + * the IPC-message specific parameter packing internally. This is slightly + * suboptimal because IPC parameters first have to be collected in this + * structure and then packed in DP-accessible memory inside + * scheduler_dp_thread_ipc(). This could be split into two levels, by adding + * IPC-specific functions like ipc_flatten_pipeline_state() and similar, but + * that would add multiple functions to the API. + */ +union scheduler_dp_thread_ipc_param { + struct bind_info *bind_data; + struct { + unsigned int trigger_cmd; + enum ipc4_pipeline_state state; + int n_sources; + struct sof_source **sources; + int n_sinks; + struct sof_sink **sinks; + } pipeline_state; +}; + +#if CONFIG_ZEPHYR_DP_SCHEDULER +int scheduler_dp_thread_ipc(struct processing_module *pmod, unsigned int cmd, + const union scheduler_dp_thread_ipc_param *param); +#else +static inline int scheduler_dp_thread_ipc(struct processing_module *pmod, + unsigned int cmd, + const union scheduler_dp_thread_ipc_param *param) +{ + return 0; +} +#endif + #endif /* __SOF_SCHEDULE_DP_SCHEDULE_H__ */ diff --git a/src/include/sof/schedule/edf_schedule.h b/src/include/sof/schedule/edf_schedule.h index 013183eb01cd..aeb10d5b57c3 100644 --- a/src/include/sof/schedule/edf_schedule.h +++ b/src/include/sof/schedule/edf_schedule.h @@ -13,8 +13,6 @@ #include <user/trace.h> #include <stdint.h> -#define EDF_ZEPHYR_PRIORITY 1 - #define edf_sch_set_pdata(task, data) \ (task->priv_data = data) diff --git a/src/include/sof/schedule/ll_schedule_domain.h b/src/include/sof/schedule/ll_schedule_domain.h index 9765df5ef0bc..9b0fd46b371e 100644 --- a/src/include/sof/schedule/ll_schedule_domain.h +++ b/src/include/sof/schedule/ll_schedule_domain.h @@ -22,7 +22,11 @@ #include <stdbool.h> #include <stdint.h> +#if defined(CONFIG_AMD) +#define LL_TIMER_PERIOD_US 500ULL /* 500us period for AMD ACP platforms */ +#else #define LL_TIMER_PERIOD_US 1000ULL /* default period in microseconds */ +#endif /* Default ll watchdog timeout in microseconds. * It was decided to have a timeout of two periods to give a safe margin of time between the start @@ -35,6 +39,7 @@ struct dma; struct ll_schedule_domain; struct task; struct timer; +struct comp_dev; struct ll_schedule_domain_ops { int (*domain_register)(struct ll_schedule_domain *domain, @@ -42,6 +47,20 @@ struct ll_schedule_domain_ops { void (*handler)(void *arg), void *arg); int (*domain_unregister)(struct ll_schedule_domain *domain, struct task *task, uint32_t num_tasks); +#if CONFIG_SOF_USERSPACE_LL + /* + * Initialize the scheduling thread and perform all privileged setup + * (thread creation, timer init, access grants). Called once from + * kernel context before any user-space domain_register() calls. + */ + int (*domain_thread_init)(struct ll_schedule_domain *domain, + struct task *task); + /* Free resources acquired by domain_thread_init(). Called from + * kernel context when the scheduling context is being torn down. + */ + void (*domain_thread_free)(struct ll_schedule_domain *domain, + uint32_t num_tasks); +#endif void (*domain_enable)(struct ll_schedule_domain *domain, int core); void (*domain_disable)(struct ll_schedule_domain *domain, int core); #if CONFIG_CROSS_CORE_STREAM @@ -65,7 +84,11 @@ struct ll_schedule_domain_ops { struct ll_schedule_domain { uint64_t next_tick; /**< ticks just set for next run */ uint64_t new_target_tick; /**< for the next set, used during the reschedule stage */ - struct k_spinlock lock; /**< standard lock */ +#ifdef CONFIG_SOF_USERSPACE_LL + struct k_mutex *lock; /**< standard lock */ +#else + struct k_spinlock lock; /**< standard lock */ +#endif atomic_t total_num_tasks; /**< total number of registered tasks */ atomic_t enabled_cores; /**< number of enabled cores */ uint32_t ticks_per_ms; /**< number of clock ticks per ms */ @@ -92,13 +115,37 @@ static inline struct ll_schedule_domain *dma_domain_get(void) return sof_get()->platform_dma_domain; } +#ifdef CONFIG_SOF_USERSPACE_LL +struct task *zephyr_ll_task_alloc(void); +struct k_heap *zephyr_ll_user_heap(void); +bool zephyr_ll_user_heap_verify(struct k_heap *heap); +void zephyr_ll_user_resources_init(void); +void user_ll_lock_sched(int core); +void user_ll_unlock_sched(int core); +#ifdef CONFIG_ASSERT +/* Assert that the calling context already holds the LL lock for 'core'. */ +void user_ll_assert_locked(int core); +#else +static inline void user_ll_assert_locked(int core) { ARG_UNUSED(core); } +#endif +#endif /* CONFIG_SOF_USERSPACE_LL */ + static inline struct ll_schedule_domain *domain_init (int type, int clk, bool synchronous, const struct ll_schedule_domain_ops *ops) { struct ll_schedule_domain *domain; - domain = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*domain)); +#ifdef CONFIG_SOF_USERSPACE_LL + domain = sof_heap_alloc(zephyr_ll_user_heap(), SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*domain), sizeof(void *)); + if (domain) + memset(domain, 0, sizeof(*domain)); +#else + domain = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*domain)); +#endif + if (!domain) + return NULL; domain->type = type; domain->clk = clk; domain->synchronous = synchronous; @@ -113,7 +160,17 @@ static inline struct ll_schedule_domain *domain_init domain->next_tick = UINT64_MAX; domain->new_target_tick = UINT64_MAX; +#ifdef CONFIG_SOF_USERSPACE_LL + /* Allocate mutex dynamically for userspace access */ + domain->lock = k_object_alloc(K_OBJ_MUTEX); + if (!domain->lock) { + sof_heap_free(zephyr_ll_user_heap(), domain); + return NULL; + } + k_mutex_init(domain->lock); +#else k_spinlock_init(&domain->lock); +#endif atomic_init(&domain->total_num_tasks, 0); atomic_init(&domain->enabled_cores, 0); @@ -147,6 +204,31 @@ static inline void domain_task_cancel(struct ll_schedule_domain *domain, domain->ops->domain_task_cancel(domain, task); } +#if CONFIG_SOF_USERSPACE_LL +/* + * Initialize the scheduling thread and do all privileged setup. + * Must be called from kernel context before user-space tasks register. + */ +static inline int domain_thread_init(struct ll_schedule_domain *domain, + struct task *task) +{ + assert(domain->ops->domain_thread_init); + + return domain->ops->domain_thread_init(domain, task); +} + +/* + * Free resources acquired by domain_thread_init(). + * Must be called from kernel context. + */ +static inline void domain_thread_free(struct ll_schedule_domain *domain, + uint32_t num_tasks) +{ + if (domain->ops->domain_thread_free) + domain->ops->domain_thread_free(domain, num_tasks); +} +#endif + static inline int domain_register(struct ll_schedule_domain *domain, struct task *task, void (*handler)(void *arg), void *arg) @@ -240,9 +322,14 @@ struct ll_schedule_domain *zephyr_dma_domain_init(struct dma *dma_array, uint32_t num_dma, int clk); #endif /* CONFIG_DMA_DOMAIN */ +struct ll_schedule_domain *zephyr_ll_domain(void); struct ll_schedule_domain *zephyr_domain_init(int clk); #define timer_domain_init(timer, clk) zephyr_domain_init(clk) -#endif +#ifdef CONFIG_SOF_USERSPACE_LL +struct k_thread *zephyr_domain_thread_tid(struct ll_schedule_domain *domain); +struct k_mem_domain *zephyr_ll_mem_domain(void); +#endif /* CONFIG_SOF_USERSPACE_LL */ +#endif /* __ZEPHYR__ */ struct ll_schedule_domain *dma_multi_chan_domain_init(struct dma *dma_array, uint32_t num_dma, int clk, diff --git a/src/include/sof/schedule/schedule.h b/src/include/sof/schedule/schedule.h index ab110997cfcb..1e7d6b3842e9 100644 --- a/src/include/sof/schedule/schedule.h +++ b/src/include/sof/schedule/schedule.h @@ -38,6 +38,10 @@ enum { * and will be unified with SOF_SCHEDULE_EDF for Zephyr builds * current implementation of Zephyr based EDF is depreciated now */ + SOF_SCHEDULE_TWB, /**< Tasks With Budget scheduler based on Zephyr peemptive threads + * for each SOF task that has pre-allocated MCPS budget + * renewed with every system tick. + */ SOF_SCHEDULE_COUNT /**< indicates number of scheduler types */ }; @@ -147,13 +151,14 @@ struct scheduler_ops { void (*scheduler_free)(void *data, uint32_t flags); /** - * Restores scheduler's resources. + * Initializes context * @param data Private data of selected scheduler. - * @return 0 if succeeded, error code otherwise. + * @param task task that needs to be scheduled + * @return thread that will be used to run the scheduled task * * This operation is optional. */ - int (*scheduler_restore)(void *data); + struct k_thread *(*scheduler_init_context)(void *data, struct task *task); }; /** \brief Holds information about scheduler. */ @@ -175,6 +180,10 @@ struct schedulers { */ struct schedulers **arch_schedulers_get(void); +struct schedulers **arch_user_schedulers_get(void); + +struct schedulers **arch_user_schedulers_get_for_core(int core); + /** * Retrieves scheduler's data. * @param type SOF_SCHEDULE_ type. @@ -198,149 +207,106 @@ static inline void *scheduler_get_data(uint16_t type) /** See scheduler_ops::schedule_task_running */ static inline int schedule_task_running(struct task *task) { - struct schedulers *schedulers = *arch_schedulers_get(); struct schedule_data *sch; - struct list_item *slist; - list_for_item(slist, &schedulers->list) { - sch = container_of(slist, struct schedule_data, list); - if (task->type == sch->type) { - /* optional operation */ - if (!sch->ops->schedule_task_running) - return 0; + assert(task); + sch = task->sch; - return sch->ops->schedule_task_running(sch->data, task); - } - } + if (!sch->ops->schedule_task_running) + return 0; - return -ENODEV; + return sch->ops->schedule_task_running(sch->data, task); } /** See scheduler_ops::schedule_task */ static inline int schedule_task(struct task *task, uint64_t start, uint64_t period) { - struct schedulers *schedulers = *arch_schedulers_get(); struct schedule_data *sch; - struct list_item *slist; if (!task) return -EINVAL; - list_for_item(slist, &schedulers->list) { - sch = container_of(slist, struct schedule_data, list); - if (task->type == sch->type) - return sch->ops->schedule_task(sch->data, task, start, - period); - } + sch = task->sch; - return -ENODEV; + return sch->ops->schedule_task(sch->data, task, start, period); } /** See scheduler_ops::schedule_task_before */ static inline int schedule_task_before(struct task *task, uint64_t start, uint64_t period, struct task *before) { - struct schedulers *schedulers = *arch_schedulers_get(); struct schedule_data *sch; - struct list_item *slist; if (!task || !before) return -EINVAL; - list_for_item(slist, &schedulers->list) { - sch = container_of(slist, struct schedule_data, list); - if (task->type == sch->type) { - if (sch->ops->schedule_task_before) - return sch->ops->schedule_task_before(sch->data, task, start, - period, before); - - return sch->ops->schedule_task(sch->data, task, start, - period); - } - } + sch = task->sch; + + if (sch->ops->schedule_task_before) + return sch->ops->schedule_task_before(sch->data, task, start, + period, before); - return -ENODEV; + return sch->ops->schedule_task(sch->data, task, start, period); } /** See scheduler_ops::schedule_task_after */ static inline int schedule_task_after(struct task *task, uint64_t start, uint64_t period, struct task *after) { - struct schedulers *schedulers = *arch_schedulers_get(); struct schedule_data *sch; - struct list_item *slist; if (!task || !after) return -EINVAL; - list_for_item(slist, &schedulers->list) { - sch = container_of(slist, struct schedule_data, list); - if (task->type == sch->type) { - if (sch->ops->schedule_task_after) - return sch->ops->schedule_task_after(sch->data, task, start, - period, after); - - return sch->ops->schedule_task(sch->data, task, start, - period); - } - } + sch = task->sch; + + if (sch->ops->schedule_task_after) + return sch->ops->schedule_task_after(sch->data, task, start, + period, after); - return -ENODEV; + return sch->ops->schedule_task(sch->data, task, start, period); } /** See scheduler_ops::reschedule_task */ static inline int reschedule_task(struct task *task, uint64_t start) { - struct schedulers *schedulers = *arch_schedulers_get(); struct schedule_data *sch; - struct list_item *slist; - list_for_item(slist, &schedulers->list) { - sch = container_of(slist, struct schedule_data, list); - if (task->type == sch->type) { - /* optional operation */ - if (!sch->ops->reschedule_task) - return 0; - - return sch->ops->reschedule_task(sch->data, task, - start); - } - } + assert(task); + sch = task->sch; + + /* optional operation */ + if (!sch->ops->reschedule_task) + return 0; - return -ENODEV; + return sch->ops->reschedule_task(sch->data, task, start); } /** See scheduler_ops::schedule_task_cancel */ static inline int schedule_task_cancel(struct task *task) { - struct schedulers *schedulers = *arch_schedulers_get(); struct schedule_data *sch; - struct list_item *slist; - list_for_item(slist, &schedulers->list) { - sch = container_of(slist, struct schedule_data, list); - if (task->type == sch->type) - return sch->ops->schedule_task_cancel(sch->data, task); - } + if (!task || !task->sch) + return -EINVAL; + + sch = task->sch; - return -ENODEV; + return sch->ops->schedule_task_cancel(sch->data, task); } /** See scheduler_ops::schedule_task_free */ static inline int schedule_task_free(struct task *task) { - struct schedulers *schedulers = *arch_schedulers_get(); struct schedule_data *sch; - struct list_item *slist; - list_for_item(slist, &schedulers->list) { - sch = container_of(slist, struct schedule_data, list); - if (task->type == sch->type) - return sch->ops->schedule_task_free(sch->data, task); - } + if (!task || !task->sch) + return -EINVAL; + + sch = task->sch; - return -ENODEV; + return sch->ops->schedule_task_free(sch->data, task); } /** See scheduler_ops::scheduler_free */ @@ -357,22 +323,18 @@ static inline void schedule_free(uint32_t flags) } } -/** See scheduler_ops::scheduler_restore */ -static inline int schedulers_restore(void) +/** See scheduler_ops::scheduler_init_context */ +static inline struct k_thread *scheduler_init_context(struct task *task) { - struct schedulers *schedulers = *arch_schedulers_get(); struct schedule_data *sch; - struct list_item *slist; - assert(schedulers); + assert(task && task->sch); + sch = task->sch; - list_for_item(slist, &schedulers->list) { - sch = container_of(slist, struct schedule_data, list); - if (sch->ops->scheduler_restore) - return sch->ops->scheduler_restore(sch->data); - } + if (sch->ops->scheduler_init_context) + return sch->ops->scheduler_init_context(sch->data, task); - return 0; + return NULL; } /** diff --git a/src/include/sof/schedule/twb_schedule.h b/src/include/sof/schedule/twb_schedule.h new file mode 100644 index 000000000000..be7c06d0706f --- /dev/null +++ b/src/include/sof/schedule/twb_schedule.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Adrian Bonislawski <adrian.bonislawski@intel.com> + */ + +#ifndef __SOF_SCHEDULE_TWB_SCHEDULE_H__ +#define __SOF_SCHEDULE_TWB_SCHEDULE_H__ + +#include <rtos/task.h> +#include <stdint.h> + +/** + * @brief Task With Budget (TWB) Scheduler + * + * TWB scheduler is a scheduler that creates a separate preemptible Zephyr thread + * for each SOF task that has a pre-allocated MCPS budget renewed with every system tick. + * The TWB scheduler assigns either MEDIUM_PRIORITY or LOW_PRIORITY to the task thread + * based on the budget left in the current system tick. + * It allows for opportunistic execution if there is no other ready task + * with a higher priority while the budget is already spent. + * + * Examples of tasks with budget include IPC Task and IDC Task. + * + * The TWB scheduler has two key parameters assigned: + * - cycles granted: the budget per system tick + * - cycles consumed: the number of cycles consumed in a given system tick for task execution + * + * The number of cycles consumed is reset to 0 at the beginning of each system tick, + * renewing the TWB budget. + * When the number of cycles consumed exceeds the cycles granted, + * the task is switchedfrom MEDIUM to LOW priority. + * When the task with budget thread is created, the MPP Scheduling is responsible + * for setting the thread time slice equal to the task budget, along with + * setting a callback on time slice timeout. + * Thread time slicing guarantees that the Zephyr scheduler will interrupt execution + * when the budget is spent, + * so the MPP Scheduling timeout callback can re-evaluate the task priority. + * + * If there is a budget left in some system tick + * (i.e., the task spent less time or started executing closeto the system tick + * that preempts execution), it is reset and not carried over to the next tick. + * + * More info: + * https://thesofproject.github.io/latest/architectures/firmware/sof-zephyr/mpp_layer/mpp_scheduling.html + */ + +/** + * \brief default static stack size for each TWB thread + */ +#define ZEPHYR_TWB_STACK_SIZE 8192 + +/** + * \brief max budget limit + */ +#define ZEPHYR_TWB_BUDGET_MAX (CONFIG_SYS_CLOCK_TICKS_PER_SEC / 1000) + +#define SYS_TICKS_TO_HW_CYCLES(x) (x * CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC) +#define HW_CYCLES_TO_SYS_TICKS(x) (x * CONFIG_SYS_CLOCK_TICKS_PER_SEC / CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) + +/** + * \brief Init the Tasks with Budget scheduler + */ +int scheduler_twb_init(void); + +/** + * \brief initialize a TWB task and add it to scheduling + * It must be called on core the task is declared to run on + * + * \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 task data + * \param[in] core CPU the thread should run on + * \param[in] name zephyr thread name + * \param[in] stack_size size of stack for a zephyr thread + * \param[in] thread_priority priority of the zephyr thread + * \param[in] cycles_granted cycles budget for the zephyr thread + */ +int scheduler_twb_task_init(struct task **task, + const struct sof_uuid_entry *uid, + const struct task_ops *ops, + void *data, + int32_t core, + const char *name, + size_t stack_size, + int32_t thread_priority, + uint32_t cycles_granted); + +#endif /* __SOF_SCHEDULE_TWB_SCHEDULE_H__ */ diff --git a/src/include/sof/tlv.h b/src/include/sof/tlv.h index 24155707dfd4..442c03a5fc69 100644 --- a/src/include/sof/tlv.h +++ b/src/include/sof/tlv.h @@ -91,7 +91,7 @@ static inline void tlv_value_get(const void *data, const struct sof_tlv *tlv = (const struct sof_tlv *)data; const uint32_t end_addr = (uint32_t)data + size; - while ((uint32_t)tlv < end_addr) { + while (tlv && (uint32_t)tlv < end_addr) { if (tlv->type == type) { *value = (void *)tlv->value; *length = tlv->length; diff --git a/src/include/sof/trace/dma-trace.h b/src/include/sof/trace/dma-trace.h index 93148ec0ecac..dbc9e666da47 100644 --- a/src/include/sof/trace/dma-trace.h +++ b/src/include/sof/trace/dma-trace.h @@ -30,9 +30,6 @@ struct dma_trace_buf { struct dma_trace_data { struct dma_sg_config config; struct dma_trace_buf dmatb; -#if CONFIG_DMA_GW - struct dma_sg_config gw_config; -#endif struct dma_copy dc; struct sof_ipc_dma_trace_posn posn; struct ipc_msg *msg; diff --git a/src/include/sof/trace/trace.h b/src/include/sof/trace/trace.h index ce8a12ed83c2..fc3aa324f847 100644 --- a/src/include/sof/trace/trace.h +++ b/src/include/sof/trace/trace.h @@ -31,6 +31,9 @@ #endif #include <sof/common.h> +#if CONFIG_ZEPHYR_LOG || CONFIG_LIBRARY || CONFIG_ARCH_POSIX_LIBFUZZER +#include <sof/lib/uuid.h> +#endif #include <sof/trace/preproc.h> #include <sof/trace/trace-boot.h> @@ -128,6 +131,7 @@ static inline void mtrace_printf(int log_level, const char *format_str, ...) /** * Trace context. */ +struct sof_uuid_entry; struct tr_ctx { const struct sof_uuid_entry *uuid_p; /**< UUID pointer, use SOF_UUID() to init */ uint32_t level; /**< Default log level */ diff --git a/src/include/user/audio_feature.h b/src/include/user/audio_feature.h new file mode 100644 index 000000000000..8e7791c0f3db --- /dev/null +++ b/src/include/user/audio_feature.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + * + */ + +#ifndef __USER_AUDIO_FEATURE_H__ +#define __USER_AUDIO_FEATURE_H__ + +/** \brief Audio feature data types. */ +enum sof_audio_feature_type { + SOF_AUDIO_FEATURE_MFCC, /**< For Mel Frequency Cepstral Coefficients */ + SOF_AUDIO_FEATURE_SOUND_DOSE_MEL, /**< For Sound Dose MEL (loudness) values */ +}; + +/** \brief Header for audio features data. */ +struct sof_audio_feature { + uint64_t stream_time_us; /**< Timestamp, relative time in microseconds */ + enum sof_audio_feature_type type; /**< Type of audio feature, as above*/ + uint32_t num_audio_features; /**< Number of audio feature structs in data */ + size_t data_size; /**< Size of data without this header */ + uint32_t reserved[4]; /**< Reserved for future use */ + int32_t data[]; /**< Start of data */ +} __attribute__((packed)); + +#endif /* __USER_AUDIO_FEATURE_H__ */ diff --git a/src/include/user/debug_stream.h b/src/include/user/debug_stream.h index 60f731622478..b6d8c08cf43a 100644 --- a/src/include/user/debug_stream.h +++ b/src/include/user/debug_stream.h @@ -48,5 +48,6 @@ struct debug_stream_record { /* Debug Stream record identifiers */ #define DEBUG_STREAM_RECORD_ID_UNINITIALIZED 0 /* invalid record marker */ #define DEBUG_STREAM_RECORD_ID_THREAD_INFO 1 /* Thread info record */ +#define DEBUG_STREAM_RECORD_ID_TEXT_MSG 2 /* Text message */ #endif /* __SOC_DEBUG_STREAM_H__ */ diff --git a/src/include/user/debug_stream_slot.h b/src/include/user/debug_stream_slot.h index 4464c9ed56b8..926b7f9634c8 100644 --- a/src/include/user/debug_stream_slot.h +++ b/src/include/user/debug_stream_slot.h @@ -127,6 +127,8 @@ struct debug_stream_record; * -ENODEV if debug stream slot is not configured * -ENOMEM if the record is too big */ -int debug_stream_slot_send_record(struct debug_stream_record *rec); +__syscall int debug_stream_slot_send_record(struct debug_stream_record *rec); + +#include <zephyr/syscalls/debug_stream_slot.h> #endif /* __SOC_DEBUG_WINDOW_SLOT_H__ */ diff --git a/src/include/user/debug_stream_text_msg.h b/src/include/user/debug_stream_text_msg.h new file mode 100644 index 000000000000..debfaad7042e --- /dev/null +++ b/src/include/user/debug_stream_text_msg.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2024 Intel Corporation. + */ + +#ifndef __SOC_DEBUG_STREAM_TEXT_MSG_H__ +#define __SOC_DEBUG_STREAM_TEXT_MSG_H__ + +#include <user/debug_stream_slot.h> +#include <stdarg.h> + +/* + * Debug Stream text message. + */ +struct debug_stream_text_msg { + struct debug_stream_record hdr; + char msg[]; +} __packed; + +/* + * To send debug messages over debug stream. Enable + * CONFIG_SOF_DEBUG_STREAM_TEXT_MSG to enable this function. + */ +void ds_msg(const char *format, ...); +void ds_vamsg(const char *format, va_list ap); + +#endif /* __SOC_DEBUG_STREAM_TEXT_MSG_H__ */ diff --git a/src/include/user/mfcc.h b/src/include/user/mfcc.h index 7a5b7fcca98e..286ee4f5e985 100644 --- a/src/include/user/mfcc.h +++ b/src/include/user/mfcc.h @@ -50,7 +50,13 @@ enum sof_mfcc_dct_type { */ struct sof_mfcc_config { uint32_t size; /**< Size of this struct in bytes */ - uint32_t reserved[8]; + int16_t mel_offset; /**< Q8.7 default 0, use 4.0 for Whisper */ + int16_t mel_scale; /**< Q4.12 default 1.0, use 0.25 for Whisper */ + int16_t mmax_init; /**< Q8.7 default 0, with dynamic_mmax false, can sim. Whisper mmax */ + int16_t mmax_coef; /**< Q1.15 decay coefficient for dynamic mmax, a small value for slow */ + uint16_t dtx_trailing_silence_hops; /**< DTX: number of silence hops to send after speech, 0 = send first only */ + uint16_t dtx_silence_hops_interval; /**< DTX: send silence frame every Nth hop during VAD=0, 0 = disable */ + uint32_t reserved[5]; int32_t sample_frequency; /**< Hz. e.g. 16000 */ int32_t pmin; /**< Q1.31 linear power, limit minimum Mel energy, e.g. 1e-9 */ enum sof_mfcc_mel_log_type mel_log; /**< Use MEL_LOG_IS_LOG, LOG10 or DB*/ @@ -69,10 +75,11 @@ struct sof_mfcc_config { int16_t num_ceps; /**< Number of cepstral coefficients, e.g. 13 */ int16_t num_mel_bins; /**< Number of internal Mel bands, e.g. 23 */ int16_t preemphasis_coefficient; /**< Q1.15, e.g. 0.97, or 0 for disable */ - int16_t top_db; /**< Q8.7 dB, limit Mel energies to this value e.g. 200 */ + int16_t top_db; /**< Q8.7 dB, limit min. Mel energies to chunk max - top_dB, e.g. 80 */ int16_t vtln_high; /**< Reserved, no support */ int16_t vtln_low; /**< Reserved, no support */ int16_t vtln_warp; /**< Reserved, no support */ + int16_t reserved16[3]; /**< Reserved for future 16-bit fields, set to 0 */ bool htk_compat; /**< Must be false */ bool raw_energy; /**< Reserved, no support */ bool remove_dc_offset; /**< Reserved, no support */ @@ -80,9 +87,12 @@ struct sof_mfcc_config { bool snip_edges; /**< Must be true (1) */ bool subtract_mean; /**< Must be false (0) */ bool use_energy; /**< Must be false (0) */ - bool reserved_bool1; - bool reserved_bool2; - bool reserved_bool3; + bool dynamic_mmax; /**< Track max Mel value for clamp with top_db value */ + bool enable_vad; /**< Run VAD algorithm */ + bool enable_dtx; /**< Discontinuous transmission: suppress silence after trailing frames */ + bool update_controls; /**< Update controls with VAD decision */ + bool compress_output; /**< Use compress PCM output: variable size, no zero padding */ + bool reserved_bool[4]; /* Reserved for future boolean flags, set to false (0) */ } __attribute__((packed)); #endif /* __USER_MFCC_H__ */ diff --git a/src/include/user/sound_dose.h b/src/include/user/sound_dose.h new file mode 100644 index 000000000000..a2479eb79951 --- /dev/null +++ b/src/include/user/sound_dose.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + * + */ + +#include <kernel/abi.h> +#include <kernel/header.h> +#include <user/audio_feature.h> + +#ifndef __USER_SOUND_DOSE_H__ +#define __USER_SOUND_DOSE_H__ + +#define SOF_SOUND_DOSE_SETUP_PARAM_ID 0 +#define SOF_SOUND_DOSE_VOLUME_PARAM_ID 1 +#define SOF_SOUND_DOSE_GAIN_PARAM_ID 2 +#define SOF_SOUND_DOSE_PAYLOAD_PARAM_ID 3 + +#define SOF_SOUND_DOSE_SENS_MIN_DB (-10 * 100) /* -10 to +130 dB */ +#define SOF_SOUND_DOSE_SENS_MAX_DB (130 * 100) +#define SOF_SOUND_DOSE_VOLUME_MIN_DB (-100 * 100) /* -100 to +40 dB */ +#define SOF_SOUND_DOSE_VOLUME_MAX_DB (40 * 100) +#define SOF_SOUND_DOSE_GAIN_MIN_DB (-100 * 100) /* -100 to 0 dB */ +#define SOF_SOUND_DOSE_GAIN_MAX_DB (0 * 100) + +struct sof_sound_dose { + int16_t mel_value; /* Decibels x100, e.g. 85 dB is 8500 */ + int16_t dbfs_value; /* Decibels x100 */ + int16_t current_sens_dbfs_dbspl; /* Decibels x100 */ + int16_t current_volume_offset; /* Decibels x100 */ + int16_t current_gain; /* Decibels x100 */ + uint16_t reserved16; /**< reserved for future use */ + uint32_t reserved32[4]; /**< reserved for future use */ +} __attribute__((packed)); + +struct sound_dose_setup_config { + int16_t sens_dbfs_dbspl; /* Decibels x100 */ + int16_t reserved; +} __attribute__((packed)); + +struct sound_dose_volume_config { + int16_t volume_offset; /* Decibels x100 */ + int16_t reserved; +} __attribute__((packed)); + +struct sound_dose_gain_config { + int16_t gain; /* Decibels x100 */ + int16_t reserved; +} __attribute__((packed)); + +#endif /* __USER_SOUND_DOSE_H__ */ diff --git a/src/init/CMakeLists.txt b/src/init/CMakeLists.txt index efa155793621..5bf15761fa29 100644 --- a/src/init/CMakeLists.txt +++ b/src/init/CMakeLists.txt @@ -1,39 +1,11 @@ # SPDX-License-Identifier: BSD-3-Clause -is_zephyr(it_is) -if(it_is) ### Zephyr ### - +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### zephyr_library_sources( init.c ext_manifest.c ) - -else() ### Not Zephyr ### - - -add_local_sources(sof init.c) - -add_library(ext_manifest STATIC "") - -# define compiler version -set_property(TARGET ext_manifest APPEND - PROPERTY COMPILE_DEFINITIONS - XCC_TOOLS_VERSION="${XCC_TOOLS_VERSION}") - -# and optimization settings -get_optimization_flag(optimization_flag) -set_property(TARGET ext_manifest APPEND - PROPERTY COMPILE_DEFINITIONS - CC_OPTIMIZE_FLAGS="-${optimization_flag}") - -add_local_sources(ext_manifest - ext_manifest.c) -sof_append_relative_path_definitions(ext_manifest) - -target_link_libraries(ext_manifest sof_options) -target_link_libraries(sof_static_libraries INTERFACE ext_manifest) - - endif() # Zephyr diff --git a/src/init/README.md b/src/init/README.md new file mode 100644 index 000000000000..1df29a7b6223 --- /dev/null +++ b/src/init/README.md @@ -0,0 +1,156 @@ +# DSP Initialization (`src/init`) + +The `src/init` directory contains the generic digital signal processor (DSP) initialization code and firmware metadata structures for Sound Open Firmware (SOF). It acts as the bridge between the underlying RTOS (Zephyr) boot phase and the SOF-specific task scheduling and processing pipelines. + +## Architecture and Boot Flow + +The firmware initialization architecture relies on the Zephyr RTOS boot sequence. Zephyr handles the very early hardware setup and kernel initialization before invoking SOF-specific routines via Zephyr's `SYS_INIT` macros. + +### Primary Core Boot Sequence + +The primary entry point for SOF system initialization is `sof_init()`, registered to run at Zephyr's `POST_KERNEL` initialization level. This ensures basic OS primitives (like memory allocators and threads) are available before SOF starts. + +`sof_init()` delegates to `primary_core_init()`, which executes the following sequence: + +```mermaid +sequenceDiagram + participant Zephyr as Zephyr RTOS + participant sof_init as sof_init (src/init.c) + participant primary_core as primary_core_init + participant trace as trace_init + participant notify as init_system_notify + participant pm as pm_runtime_init + participant platform as platform_init + participant ams as ams_init + participant mbox as mailbox (IPC4) + participant task as task_main_start + + Zephyr->>sof_init: SYS_INIT (POST_KERNEL) + sof_init->>primary_core: Initialize Primary Core Context + + primary_core->>trace: Setup DMA Tracing & Logging + primary_core->>notify: Setup System Notifiers + primary_core->>pm: Initialize Runtime Power Management + + primary_core->>platform: Platform-Specific HW Config + note right of platform: e.g., interrupts, IPC windows (Intel, i.MX) + + primary_core->>ams: Init Asynchronous Messaging Service + + primary_core->>mbox: Set Firmware Registers ABI Version + + primary_core->>task: Start SOF Main Processing Task Loop +``` + +1. **Context Initialization**: Sets up the global `struct sof` context. +2. **Logging and Tracing**: Initializes Zephyr's logging timestamps and SOF's DMA trace infrastructure (`trace_init()`), printing the firmware version and ABI banner. +3. **System Subsystems**: + - Initializes the system notifier (`init_system_notify()`) for inter-component messaging. + - Sets up runtime power management (`pm_runtime_init()`). +4. **Platform-Specific Initialization**: Calls `platform_init()` to allow the specific hardware platform (e.g., Intel cAVS, i.MX) to configure its hardware IPs, interrupts, and IPC mailbox memory windows. +5. **Architectural Handoff**: For IPC4, it sets the Firmware Registers ABI version in the mailbox. It may also unpack boot manifests if configured. +6. **Task Scheduler**: Finally, it calls `task_main_start()` to kick off the main SOF processing task loop. + +### Secondary Core Boot Sequence + +For multi-core DSP platforms, secondary cores execute `secondary_core_init()`: + +```mermaid +sequenceDiagram + participant ZephyrN as Zephyr RTOS (Core N) + participant sci as secondary_core_init + participant check as check_restore + participant notify as init_system_notify + participant ll as scheduler_init_ll + participant dp as scheduler_dp_init + participant idc as idc_init + + ZephyrN->>sci: Core Wake/Boot + sci->>check: Cold boot or power restore? + + alt is Power Restore (e.g. D0ix wake) + sci->>sci: secondary_core_restore()<br>(Skip full init) + else is Cold Boot + sci->>notify: Setup Local Core Notifiers + + sci->>ll: Init Low-Latency (LL) Timer Domain + sci->>ll: Init LL DMA Domain (if applicable) + sci->>dp: Init Data Processing (DP) Scheduler + + sci->>idc: Init Inter-Domain Communication (IDC) + end +``` + +1. **Power State Checking**: It checks if the core is cold booting or resuming from a low-power retention/restore state (e.g., D0ix) via `check_restore()`. In the restore case, it restores state without re-allocating core structures; in the cold-boot case, it follows the full initialization path described below. +2. **Local Subsystem Setup**: Sets up system notifiers for the local core. +3. **Scheduler Setup**: Initializes the Low-Latency (LL) and Data Processing (DP) schedulers on the secondary core. +4. **Inter-Core Communication**: Initializes the Inter-Domain Communication (IDC) mechanism (`idc_init()`), allowing cross-core messaging. + +### Firmware Extended Manifest (`ext_manifest.c`) + +This directory also provides the extended manifest implementation. The manifest consists of structured metadata embedded into the `.fw_metadata` section of the firmware binary. + +```mermaid +classDiagram + direction LR + + class fw_metadata { + <<Section>> + +ext_man_fw_ver + +ext_man_cc_ver + +ext_man_probe + +ext_man_dbg_info + +ext_man_config + } + + class ext_man_elem_header { + +uint32_t type + +uint32_t elem_size + } + + class ext_man_fw_version { + +ext_man_elem_header hdr + +sof_ipc_fw_version version + +uint32_t flags + } + + class ext_man_cc_version { + +ext_man_elem_header hdr + +sof_ipc_cc_version cc_version + } + + class ext_man_probe_support { + +ext_man_elem_header hdr + +sof_ipc_probe_support probe + } + + class ext_man_dbg_abi { + +ext_man_elem_header hdr + +sof_ipc_user_abi_version dbg_abi + } + + class ext_man_config_data { + +ext_man_elem_header hdr + +config_elem elems[] + } + + fw_metadata *-- ext_man_fw_version + fw_metadata *-- ext_man_cc_version + fw_metadata *-- ext_man_probe_support + fw_metadata *-- ext_man_dbg_abi + fw_metadata *-- ext_man_config_data + + ext_man_fw_version *-- ext_man_elem_header + ext_man_cc_version *-- ext_man_elem_header + ext_man_probe_support *-- ext_man_elem_header + ext_man_dbg_abi *-- ext_man_elem_header + ext_man_config_data *-- ext_man_elem_header +``` + +When the host OS (e.g., Linux SOF driver) parses the firmware binary before loading it, it reads these manifest structures to discover firmware capabilities dynamically. The manifest includes: + +- **Firmware Version**: Major, minor, micro, tag, and build hashes (`ext_man_fw_ver`). +- **Compiler Version**: Details of the toolchain used to compile the firmware (`ext_man_cc_ver`). +- **Probe Info**: Extraction probe configurations and limits (`ext_man_probe`). +- **Debug ABI**: Supported debugger ABI versions (`ext_man_dbg_info`). +- **Configuration Dictionary**: Compile-time enabled features and sizing parameters (e.g., `SOF_IPC_MSG_MAX_SIZE`). diff --git a/src/init/init.c b/src/init/init.c index 9ff13c5d8b12..9a99c2d9c27b 100644 --- a/src/init/init.c +++ b/src/init/init.c @@ -90,8 +90,6 @@ static inline void lp_sram_unpack(void) #if CONFIG_MULTICORE -#ifdef __ZEPHYR__ - static bool check_restore(void) { struct idc *idc = *idc_get(); @@ -107,75 +105,13 @@ static bool check_restore(void) static inline int secondary_core_restore(void) { return 0; }; -#else - -static bool check_restore(void) -{ - struct idc *idc = *idc_get(); - struct task *task = *task_main_get(); - struct notify *notifier = *arch_notify_get(); - struct schedulers *schedulers = *arch_schedulers_get(); - - /* check whether basic core structures has been already allocated. If they - * are available in memory, it means that this is not cold boot and memory - * has not been powered off. - */ - return !!idc && !!task && !!notifier && !!schedulers; -} - -static int secondary_core_restore(void) -{ - int err; - - trace_point(TRACE_BOOT_PLATFORM_IRQ); - - /* initialize interrupts */ - platform_interrupt_init(); - - /* As the memory was not turned of in D0->D0ix and basic structures are - * already allocated, in restore process (D0ix->D0) we have only to - * register and enable required interrupts (it is done in - * schedulers_restore() and idc_restore()). - */ - - /* restore schedulers i.e. register and enable scheduler interrupts */ - trace_point(TRACE_BOOT_PLATFORM_SCHED); - err = schedulers_restore(); - if (err < 0) - return err; - - /* restore idc i.e. register and enable idc interrupts */ - trace_point(TRACE_BOOT_PLATFORM_IDC); - err = idc_restore(); - if (err < 0) - return err; - - trace_point(TRACE_BOOT_PLATFORM); - - /* In restore case (D0ix->D0 flow) we do not have to invoke here - * schedule_task(*task_main_get(), 0, UINT64_MAX) as it is done in - * cold boot process (see end of secondary_core_init() function), - * because in restore case memory has not been powered off and task_main - * is already added into scheduler list. - */ - while (1) - wait_for_interrupt(0); -} - -#endif - -int secondary_core_init(struct sof *sof) +__cold int secondary_core_init(struct sof *sof) { int err; struct ll_schedule_domain *dma_domain; -#ifndef __ZEPHYR__ - /* init architecture */ - trace_point(TRACE_BOOT_ARCH); - err = arch_init(); - if (err < 0) - sof_panic(SOF_IPC_PANIC_ARCH); -#endif + assert_can_be_cold(); + /* check whether we are in a cold boot process or not (e.g. D0->D0ix * flow when primary core disables all secondary cores). If not, we do * not have allocate basic structures like e.g. schedulers, notifier, @@ -188,13 +124,6 @@ int secondary_core_init(struct sof *sof) trace_point(TRACE_BOOT_SYS_NOTIFIER); init_system_notify(sof); -#ifndef __ZEPHYR__ - /* interrupts need to be initialized before any usage */ - trace_point(TRACE_BOOT_PLATFORM_IRQ); - platform_interrupt_init(); - - scheduler_init_edf(); -#endif trace_point(TRACE_BOOT_PLATFORM_SCHED); scheduler_init_ll(timer_domain_get()); @@ -227,18 +156,17 @@ int secondary_core_init(struct sof *sof) trace_point(TRACE_BOOT_PLATFORM); -#ifndef __ZEPHYR__ - /* task initialized in edf_scheduler_init */ - schedule_task(*task_main_get(), 0, UINT64_MAX); -#endif + LOG_INF("init done"); return err; } #endif -static void print_version_banner(void) +__cold static void print_version_banner(void) { + assert_can_be_cold(); + /* * Non-Zephyr builds emit the version banner in DMA-trace * init and this is done at a later time as otherwise the @@ -267,26 +195,14 @@ static log_timestamp_t default_get_timestamp(void) } #endif -static int primary_core_init(int argc, char *argv[], struct sof *sof) +__cold static int primary_core_init(int argc, char *argv[], struct sof *sof) { + assert_can_be_cold(); + /* setup context */ sof->argc = argc; sof->argv = argv; -#ifndef __ZEPHYR__ - /* init architecture */ - trace_point(TRACE_BOOT_ARCH); - if (arch_init() < 0) - sof_panic(SOF_IPC_PANIC_ARCH); - - /* initialise system services */ - trace_point(TRACE_BOOT_SYS_HEAP); - platform_init_memmap(sof); - init_heap(sof); - - interrupt_init(sof); -#endif /* __ZEPHYR__ */ - #if defined(CONFIG_ZEPHYR_LOG) && !defined(CONFIG_LOG_MODE_MINIMAL) log_set_timestamp_func(default_get_timestamp, sys_clock_hw_cycles_per_sec()); @@ -310,6 +226,10 @@ static int primary_core_init(int argc, char *argv[], struct sof *sof) io_perf_monitor_init(); #endif +#if CONFIG_SOF_USERSPACE_LL + zephyr_ll_user_resources_init(); +#endif + /* init the platform */ if (platform_init(sof) < 0) sof_panic(SOF_IPC_PANIC_PLATFORM); @@ -324,8 +244,6 @@ static int primary_core_init(int argc, char *argv[], struct sof *sof) size_t ipc4_abi_ver_offset = offsetof(struct ipc4_fw_registers, abi_ver); mailbox_sw_reg_write(ipc4_abi_ver_offset, IPC4_FW_REGS_ABI_VER); - - k_spinlock_init(&sof->fw_reg_lock); #endif trace_point(TRACE_BOOT_PLATFORM); @@ -338,27 +256,6 @@ static int primary_core_init(int argc, char *argv[], struct sof *sof) return task_main_start(sof); } -#ifndef __ZEPHYR__ -int main(int argc, char *argv[]) -{ - int err = 0; - - trace_point(TRACE_BOOT_START); - - if (cpu_get_id() == PLATFORM_PRIMARY_CORE_ID) - err = primary_core_init(argc, argv, &sof); -#if CONFIG_MULTICORE - else - err = secondary_core_init(&sof); -#endif - - /* should never get here */ - sof_panic(SOF_IPC_PANIC_TASK); - return err; -} - -#else - int sof_main(int argc, char *argv[]) { trace_point(TRACE_BOOT_START); @@ -372,4 +269,3 @@ static int sof_init(void) } SYS_INIT(sof_init, POST_KERNEL, 99); -#endif diff --git a/src/ipc/CMakeLists.txt b/src/ipc/CMakeLists.txt index 1f70f1050154..15fab54b3c30 100644 --- a/src/ipc/CMakeLists.txt +++ b/src/ipc/CMakeLists.txt @@ -10,10 +10,11 @@ endif() add_local_sources(sof ipc-common.c ipc-helper.c + notification_pool.c ) -is_zephyr(it_is) -if(it_is) ### Zephyr ### +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### # dma-copy only used for dma-trace zephyr_library_sources_ifdef(CONFIG_TRACE dma-copy.c) @@ -24,18 +25,11 @@ if (CONFIG_SOC_SERIES_INTEL_CAVS_V25 OR CONFIG_SOC_SERIES_INTEL_ADSP_ACE) ) endif() - else() ### Not Zephyr ### - if (CONFIG_TRACE) add_local_sources(sof dma-copy.c) endif() -if (CONFIG_LIBRARY) - return() -endif() - - endif() # Zephyr diff --git a/src/ipc/Kconfig b/src/ipc/Kconfig index 84e186b6bb08..3cde2ddeabfe 100644 --- a/src/ipc/Kconfig +++ b/src/ipc/Kconfig @@ -14,6 +14,7 @@ config IPC_MAJOR_3 config IPC_MAJOR_4 bool "IPC Major Version 4" + depends on ZEPHYR_NATIVE_DRIVERS || LIBRARY help This is an IPC version used by certain middleware on some IOT Intel devices. Not for general use. diff --git a/src/ipc/README.md b/src/ipc/README.md new file mode 100644 index 000000000000..7389e6ae4a54 --- /dev/null +++ b/src/ipc/README.md @@ -0,0 +1,98 @@ +# Inter-Processor Communication (IPC) Core Architecture + +This directory contains the common foundation for all Inter-Processor Communication (IPC) within the Sound Open Firmware (SOF) project. It bridges the gap between hardware mailbox interrupts and the version-specific (IPC3/IPC4) message handlers. + +## Overview + +The Core IPC layer is completely agnostic to the specific structure or content of the messages (whether they are IPC3 stream commands or IPC4 pipeline messages). Its primary responsibilities are: + +1. **Message State Management**: Tracking if a message is being processed, queued, or completed. +2. **Interrupt Bridging**: Routing incoming platform interrupts into the Zephyr or SOF thread-domain scheduler. +3. **Queueing**: Safe traversal and delayed processing capabilities via `k_work` items or SOF scheduler tasks. +4. **Platform Acknowledgment**: Signaling the hardware mailbox layers to confirm receipt or signal completion out entirely. + +## Architecture Diagram + +The basic routing of any IPC message moves from a hardware interrupt, through the platform driver, into the core IPC handlers, and ultimately up to version-specific handlers. + +```mermaid +graph TD + Platform[Platform / Mailbox HW] -->|IRQ| CoreIPC[Core IPC Framework] + + subgraph CoreIPC [src/ipc/ipc-common.c] + Queue[Msg Queue / Worker Task] + Dispatcher[IPC Message Dispatcher] + PM[Power Management Wait/Wake] + + Queue --> Dispatcher + Dispatcher --> PM + end + + Dispatcher -->|Version Specific Parsing| IPC3[IPC3 Handler] + Dispatcher -->|Version Specific Parsing| IPC4[IPC4 Handler] + + IPC3 -.-> CoreIPC + IPC4 -.-> CoreIPC + CoreIPC -.->|Ack| Platform +``` + +## Processing Flow + +When the host writes a command to the IPC mailbox and triggers an interrupt, the hardware-specific driver (`src/platform/...`) catches the IRQ and eventually calls down into the IPC framework. + +Different RTOS environments (Zephyr vs. bare metal SOF native) handle the thread handoff differently. In Zephyr, this leverages the `k_work` queues heavily for `ipc_work_handler`. + +### Receiving Messages (Host -> DSP) + +```mermaid +sequenceDiagram + participant Host + participant Platform as Platform Mailbox (IRQ) + participant CoreIPC as Core IPC Worker + participant Handler as Version-Specific Handler (IPC3/4) + + Host->>Platform: Writes Mailbox, Triggers Interrupt + activate Platform + Platform->>CoreIPC: ipc_schedule_process() + deactivate Platform + + Note over CoreIPC: Worker thread wakes up + + activate CoreIPC + CoreIPC->>Platform: ipc_platform_wait_ack() (Optional blocking) + CoreIPC->>Handler: version_specific_command_handler() + + Handler-->>CoreIPC: Command Processed (Status Header) + CoreIPC->>Platform: ipc_complete_cmd() + Platform-->>Host: Signals Completion Mailbox / IRQ + deactivate CoreIPC +``` + +### Sending Messages (DSP -> Host) + +Firmware-initiated messages (like notifications for position updates, traces, or XRUNs) rely on a queue if the hardware is busy. + +```mermaid +sequenceDiagram + participant DSP as DSP Component (e.g. Pipeline Tracker) + participant Queue as IPC Message Queue + participant Platform as Platform Mailbox + + DSP->>Queue: ipc_msg_send() / ipc_msg_send_direct() + activate Queue + Queue-->>Queue: Add to Tx list (if BUSY) + Queue->>Platform: Copy payload to mailbox and send + + alt If host is ready + Platform-->>Queue: Success + Queue->>Platform: Triggers IRQ to Host + else If host requires delayed ACKs + Queue-->>DSP: Queued pending prior completion + end + deactivate Queue +``` + +## Global IPC Objects and Helpers + +* `ipc_comp_dev`: Wrapper structure linking generic devices (`comp_dev`) specifically to their IPC pipeline and endpoint identifiers. +* `ipc_get_comp_dev` / `ipc_get_ppl_comp`: Lookup assistants utilizing the central graph tracking to find specific components either directly by component ID or by traversing the pipeline graph starting from a given `pipeline_id` and direction (upstream/downstream). diff --git a/src/ipc/dma-copy.c b/src/ipc/dma-copy.c index beac3f3b391c..3e8834474e82 100644 --- a/src/ipc/dma-copy.c +++ b/src/ipc/dma-copy.c @@ -23,7 +23,6 @@ SOF_DEFINE_REG_UUID(dma_copy); DECLARE_TR_CTX(dmacpy_tr, SOF_UUID(dma_copy_uuid), LOG_LEVEL_INFO); -#if !CONFIG_DMA_GW static struct dma_sg_elem *sg_get_elem_at(struct dma_sg_config *host_sg, int32_t *offset) { @@ -46,46 +45,14 @@ static struct dma_sg_elem *sg_get_elem_at(struct dma_sg_config *host_sg, } /* host offset in beyond end of SG buffer */ - tr_err(&dmacpy_tr, "sg_get_elem_at(): host offset in beyond end of SG buffer"); + tr_err(&dmacpy_tr, "host offset in beyond end of SG buffer"); return NULL; } -#endif /* Copy DSP memory to host memory. * Copies DSP memory to host in a single PAGE_SIZE or smaller block. Does not * waits/sleeps and can be used in IRQ context. */ -#if CONFIG_DMA_GW - -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 ret; - - /* tell gateway to copy */ - ret = dma_copy_legacy(dc->chan, size, DMA_COPY_BLOCKING); - if (ret < 0) - return ret; - - /* bytes copied */ - return 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 ret; - - /* tell gateway to copy */ - ret = dma_copy_legacy(dc->chan, size, 0); - if (ret < 0) - return ret; - - /* bytes copied */ - return size; -} - -#else /* CONFIG_DMA_GW */ static int dma_copy_to_host_flags(struct dma_copy *dc, struct dma_sg_config *host_sg, @@ -153,8 +120,6 @@ int dma_copy_to_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg, DMA_COPY_ONE_SHOT); } -#endif /* CONFIG_DMA_GW */ - int dma_copy_new(struct dma_copy *dc) { uint32_t dir, cap, dev; @@ -165,18 +130,16 @@ int dma_copy_new(struct dma_copy *dc) cap = 0; dc->dmac = dma_get(dir, cap, dev, DMA_ACCESS_SHARED); if (!dc->dmac) { - tr_err(&dmacpy_tr, "dma_copy_new(): dc->dmac = NULL"); + tr_err(&dmacpy_tr, "dc->dmac = NULL"); return -ENODEV; } -#if !CONFIG_DMA_GW /* get DMA channel from DMAC0 */ dc->chan = dma_channel_get_legacy(dc->dmac, CONFIG_TRACE_CHANNEL); if (!dc->chan) { - tr_err(&dmacpy_tr, "dma_copy_new(): dc->chan is NULL"); + tr_err(&dmacpy_tr, "dc->chan is NULL"); return -ENODEV; } -#endif return 0; } @@ -186,7 +149,7 @@ int dma_copy_set_stream_tag(struct dma_copy *dc, uint32_t stream_tag) /* get DMA channel from DMAC */ dc->chan = dma_channel_get_legacy(dc->dmac, stream_tag - 1); if (!dc->chan) { - tr_err(&dmacpy_tr, "dma_copy_set_stream_tag(): dc->chan is NULL"); + tr_err(&dmacpy_tr, "dc->chan is NULL"); return -EINVAL; } diff --git a/src/ipc/ipc-common.c b/src/ipc/ipc-common.c index e9de1efdd2a0..d0d248c9ec77 100644 --- a/src/ipc/ipc-common.c +++ b/src/ipc/ipc-common.c @@ -9,6 +9,7 @@ #include <sof/audio/component_ext.h> #include <sof/audio/pipeline.h> #include <sof/common.h> +#include <sof/debug/gdb/gdb.h> #include <rtos/idc.h> #include <rtos/symbol.h> #include <sof/ipc/topology.h> @@ -20,6 +21,7 @@ #include <rtos/cache.h> #include <sof/lib/cpu.h> #include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> #include <sof/list.h> #include <sof/platform.h> #include <rtos/sof.h> @@ -49,13 +51,15 @@ int ipc_process_on_core(uint32_t core, bool blocking) /* check if requested core is enabled */ if (!cpu_is_core_enabled(core)) { - tr_err(&ipc_tr, "ipc_process_on_core(): core #%d is disabled", core); + tr_err(&ipc_tr, "core #%d is disabled", core); return -EACCES; } +#if CONFIG_IPC_MAJOR_3 /* The other core will write there its response */ dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, ((struct sof_ipc_cmd_hdr *)ipc->comp_data)->size); +#endif /* * If the primary core is waiting for secondary cores to complete, it @@ -161,6 +165,9 @@ void ipc_send_queued_msg(void) if (ipc_platform_send_msg(msg) == 0) { /* Remove the message from the list if it has been successfully sent. */ list_item_del(&msg->list); + /* Invoke a callback to notify that the message has been sent. */ + if (msg->callback) + msg->callback(msg); #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS /* Increment performance counters */ io_perf_monitor_update_data(ipc->io_perf_out_msg_count, 1); @@ -170,6 +177,10 @@ void ipc_send_queued_msg(void) k_spin_unlock(&ipc->lock, key); } +#ifdef __ZEPHYR__ +static K_THREAD_STACK_DEFINE(ipc_send_wq_stack, CONFIG_STACK_SIZE_IPC_TX); +#endif + static void schedule_ipc_worker(void) { /* @@ -179,20 +190,22 @@ static void schedule_ipc_worker(void) #ifdef __ZEPHYR__ struct ipc *ipc = ipc_get(); - k_work_schedule(&ipc->z_delayed_work, K_USEC(IPC_PERIOD_USEC)); + k_work_schedule_for_queue(&ipc->ipc_send_wq, &ipc->z_delayed_work, K_USEC(IPC_PERIOD_USEC)); #endif } -void ipc_msg_send_direct(struct ipc_msg *msg, void *data) +__cold void ipc_msg_send_direct(struct ipc_msg *msg, void *data) { struct ipc *ipc = ipc_get(); k_spinlock_key_t key; int ret; + assert_can_be_cold(); + key = k_spin_lock(&ipc->lock); /* copy mailbox data to message if not already copied */ - if (msg->tx_size > 0 && msg->tx_size <= SOF_IPC_MSG_MAX_SIZE && + if (data && msg->tx_size > 0 && msg->tx_size <= SOF_IPC_MSG_MAX_SIZE && msg->tx_data != data) { ret = memcpy_s(msg->tx_data, msg->tx_size, data, msg->tx_size); assert(!ret); @@ -212,19 +225,10 @@ void ipc_msg_send(struct ipc_msg *msg, void *data, bool high_priority) key = k_spin_lock(&ipc->lock); /* copy mailbox data to message if not already copied */ - if ((msg->tx_size > 0 && msg->tx_size <= SOF_IPC_MSG_MAX_SIZE) && + if (data && (msg->tx_size > 0 && msg->tx_size <= SOF_IPC_MSG_MAX_SIZE) && msg->tx_data != data) { ret = memcpy_s(msg->tx_data, msg->tx_size, data, msg->tx_size); assert(!ret); - if (!cpu_is_primary(cpu_get_id())) { - /* Write back data to memory to maintain coherence between cores. - * The response was prepared on a secondary core but will be sent - * to the host from the primary core. - */ - dcache_writeback_region((__sparse_force void __sparse_cache *)msg->tx_data, - msg->tx_size); - msg->is_shared = true; - } } /* @@ -256,6 +260,7 @@ void ipc_msg_send(struct ipc_msg *msg, void *data, bool high_priority) k_spin_unlock(&ipc->lock, key); } +EXPORT_SYMBOL(ipc_msg_send); #ifdef __ZEPHYR__ static void ipc_work_handler(struct k_work *work) @@ -276,17 +281,37 @@ static void ipc_work_handler(struct k_work *work) void ipc_schedule_process(struct ipc *ipc) { +#if CONFIG_TWB_IPC_TASK + schedule_task(ipc->ipc_task, 0, IPC_PERIOD_USEC); +#else schedule_task(&ipc->ipc_task, 0, IPC_PERIOD_USEC); +#endif } -int ipc_init(struct sof *sof) +__cold int ipc_init(struct sof *sof) { - tr_dbg(&ipc_tr, "ipc_init()"); + assert_can_be_cold(); + + tr_dbg(&ipc_tr, "entry"); + +#if CONFIG_SOF_BOOT_TEST_STANDALONE + LOG_INF("SOF_BOOT_TEST_STANDALONE, disabling IPC."); + return 0; +#endif /* init ipc data */ - sof->ipc = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*sof->ipc)); - sof->ipc->comp_data = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, - SOF_MEM_CAPS_RAM, SOF_IPC_MSG_MAX_SIZE); + sof->ipc = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*sof->ipc)); + if (!sof->ipc) { + tr_err(&ipc_tr, "Unable to allocate IPC data"); + return -ENOMEM; + } + sof->ipc->comp_data = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + SOF_IPC_MSG_MAX_SIZE); + if (!sof->ipc->comp_data) { + tr_err(&ipc_tr, "Unable to allocate IPC component data"); + rfree(sof->ipc); + return -ENOMEM; + } k_spinlock_init(&sof->ipc->lock); list_init(&sof->ipc->msg_list); @@ -305,6 +330,20 @@ int ipc_init(struct sof *sof) #endif #ifdef __ZEPHYR__ + struct k_thread *thread = &sof->ipc->ipc_send_wq.thread; + + k_work_queue_start(&sof->ipc->ipc_send_wq, ipc_send_wq_stack, + K_THREAD_STACK_SIZEOF(ipc_send_wq_stack), 1, NULL); + + k_thread_suspend(thread); + +#ifdef CONFIG_SCHED_CPU_MASK + k_thread_cpu_pin(thread, PLATFORM_PRIMARY_CORE_ID); +#endif + k_thread_name_set(thread, "ipc_send_wq"); + + k_thread_resume(thread); + k_work_init_delayable(&sof->ipc->z_delayed_work, ipc_work_handler); #endif @@ -332,6 +371,13 @@ void ipc_complete_cmd(struct ipc *ipc) ipc_platform_complete_cmd(ipc); } +bool ipc_enter_gdb; + +__attribute__((weak)) void ipc_platform_wait_ack(struct ipc *ipc) +{ + k_msleep(1); +} + static void ipc_complete_task(void *data) { struct ipc *ipc = data; @@ -341,6 +387,13 @@ static void ipc_complete_task(void *data) ipc->task_mask &= ~IPC_TASK_INLINE; ipc_complete_cmd(ipc); k_spin_unlock(&ipc->lock, key); +#if CONFIG_GDBSTUB + if (ipc_enter_gdb) { + ipc_enter_gdb = false; + ipc_platform_wait_ack(ipc); + gdb_init(); + } +#endif } static enum task_state ipc_do_cmd(void *data) diff --git a/src/ipc/ipc-helper.c b/src/ipc/ipc-helper.c index 1e27c701899f..1a2fcef4194e 100644 --- a/src/ipc/ipc-helper.c +++ b/src/ipc/ipc-helper.c @@ -17,10 +17,12 @@ #include <sof/ipc/msg.h> #include <sof/ipc/driver.h> #include <sof/ipc/schedule.h> +#include <sof/schedule/ll_schedule_domain.h> #include <rtos/alloc.h> #include <rtos/cache.h> #include <sof/lib/cpu.h> #include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> #include <sof/list.h> #include <sof/platform.h> #include <rtos/sof.h> @@ -37,8 +39,10 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); -static bool valid_ipc_buffer_desc(const struct sof_ipc_buffer *desc) +__cold static bool valid_ipc_buffer_desc(const struct sof_ipc_buffer *desc) { + assert_can_be_cold(); + if (desc->caps >= SOF_MEM_CAPS_LOWEST_INVALID) return false; @@ -47,9 +51,13 @@ static bool valid_ipc_buffer_desc(const struct sof_ipc_buffer *desc) } /* create a new component in the pipeline */ -struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc, bool is_shared) +__cold struct comp_buffer *buffer_new(struct mod_alloc_ctx *alloc, + const struct sof_ipc_buffer *desc, bool is_shared) { struct comp_buffer *buffer; + uint32_t flags = desc->flags; + + assert_can_be_cold(); tr_info(&buffer_tr, "buffer new size 0x%x id %d.%d flags 0x%x", desc->size, desc->comp.pipeline_id, desc->comp.id, desc->flags); @@ -60,8 +68,21 @@ struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc, bool is_shared return NULL; } +#if CONFIG_IPC_MAJOR_3 + /* memory zones and caps are deprecated - convert to flags */ + if (desc->caps & SOF_MEM_CAPS_DMA) + flags |= SOF_MEM_FLAG_DMA; + if (desc->caps & SOF_MEM_CAPS_LP) + flags |= SOF_MEM_FLAG_LOW_POWER; + if (desc->caps & SOF_MEM_CAPS_L3) + flags |= SOF_MEM_FLAG_L3; + if (desc->caps) + tr_warn(&buffer_tr, "Deprecated buffer caps 0x%x used, convert to flags 0x%x", + desc->caps, flags); +#endif + /* allocate buffer */ - buffer = buffer_alloc(desc->size, desc->caps, desc->flags, PLATFORM_DCACHE_ALIGN, + buffer = buffer_alloc(alloc, desc->size, flags, PLATFORM_DCACHE_ALIGN, is_shared); if (buffer) { buffer->stream.runtime_stream_params.id = desc->comp.id; @@ -75,6 +96,7 @@ struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc, bool is_shared return buffer; } +/* Called from multiple locations, including ipc_get_comp_by_ppl_id(), so cannot be cold */ int32_t ipc_comp_pipe_id(const struct ipc_comp_dev *icd) { switch (icd->type) { @@ -115,16 +137,14 @@ static void comp_update_params(uint32_t flag, int comp_verify_params(struct comp_dev *dev, uint32_t flag, struct sof_ipc_stream_params *params) { - struct list_item *buffer_list; struct list_item *source_list; struct list_item *sink_list; - struct list_item *clist; struct comp_buffer *sinkb; struct comp_buffer *buf; int dir = dev->direction; if (!params) { - comp_err(dev, "comp_verify_params(): !params"); + comp_err(dev, "!params"); return -EINVAL; } @@ -136,13 +156,9 @@ int comp_verify_params(struct comp_dev *dev, uint32_t flag, */ if (list_is_empty(source_list) != list_is_empty(sink_list)) { if (list_is_empty(sink_list)) - buf = list_first_item(source_list, - struct comp_buffer, - sink_list); + buf = comp_dev_get_first_data_producer(dev); else - buf = list_first_item(sink_list, - struct comp_buffer, - source_list); + buf = comp_dev_get_first_data_consumer(dev); /* update specific pcm parameter with buffer parameter if * specific flag is set. @@ -156,22 +172,33 @@ int comp_verify_params(struct comp_dev *dev, uint32_t flag, /* set component period frames */ component_set_nearest_period_frames(dev, audio_stream_get_rate(&buf->stream)); + } else if (list_is_empty(source_list)) { + /* + * both lists are empty, e.g. if it's the single component in a + * pipeline and no other pipelines are currently connected, then + * there's just nothing to update + */ + comp_dbg(dev, "no connected buffers"); } else { /* for other components we iterate over all downstream buffers * (for playback) or upstream buffers (for capture). */ - buffer_list = comp_buffer_list(dev, dir); - - list_for_item(clist, buffer_list) { - buf = buffer_from_list(clist, dir); - comp_update_params(flag, params, buf); - buffer_set_params(buf, params, BUFFER_UPDATE_FORCE); + if (dir == PPL_DIR_DOWNSTREAM) { + comp_dev_for_each_consumer(dev, buf) { + comp_update_params(flag, params, buf); + buffer_set_params(buf, params, + BUFFER_UPDATE_FORCE); + } + } else { + comp_dev_for_each_producer(dev, buf) { + 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); - + sinkb = comp_dev_get_first_data_consumer(dev); component_set_nearest_period_frames(dev, audio_stream_get_rate(&sinkb->stream)); } @@ -179,9 +206,11 @@ int comp_verify_params(struct comp_dev *dev, uint32_t flag, } EXPORT_SYMBOL(comp_verify_params); -int comp_buffer_connect(struct comp_dev *comp, uint32_t comp_core, - struct comp_buffer *buffer, uint32_t dir) +__cold int comp_buffer_connect(struct comp_dev *comp, uint32_t comp_core, + struct comp_buffer *buffer, uint32_t dir) { + assert_can_be_cold(); + /* check if it's a connection between cores */ if (buffer->core != comp_core) { #if CONFIG_INCOHERENT @@ -209,7 +238,7 @@ int ipc_pipeline_complete(struct ipc *ipc, uint32_t comp_id) /* check whether pipeline exists */ ipc_pipe = ipc_get_pipeline_by_id(ipc, comp_id); if (!ipc_pipe) { - tr_err(&ipc_tr, "ipc: ipc_pipeline_complete looking for pipe component id 0x%x failed", + tr_err(&ipc_tr, "ipc: looking for pipe component id 0x%x failed", comp_id); return -EINVAL; } @@ -223,28 +252,28 @@ int ipc_pipeline_complete(struct ipc *ipc, uint32_t comp_id) /* get pipeline source component */ ipc_ppl_source = ipc_get_ppl_src_comp(ipc, p->pipeline_id); if (!ipc_ppl_source) { - tr_err(&ipc_tr, "ipc: ipc_pipeline_complete looking for pipeline source failed"); + tr_err(&ipc_tr, "ipc: looking for pipeline source failed"); return -EINVAL; } /* get pipeline sink component */ ipc_ppl_sink = ipc_get_ppl_sink_comp(ipc, p->pipeline_id); if (!ipc_ppl_sink) { - tr_err(&ipc_tr, "ipc: ipc_pipeline_complete looking for pipeline sink failed"); + tr_err(&ipc_tr, "ipc: looking for pipeline sink failed"); return -EINVAL; } /* find the scheduling component */ icd = ipc_get_comp_by_id(ipc, p->sched_id); if (!icd) { - tr_warn(&ipc_tr, "ipc_pipeline_complete(): no scheduling component specified, use comp 0x%x", + tr_warn(&ipc_tr, "no scheduling component specified, use comp 0x%x", ipc_ppl_sink->id); icd = ipc_ppl_sink; } if (icd->core != ipc_pipe->core) { - tr_err(&ipc_tr, "ipc_pipeline_complete(): icd->core (%d) != ipc_pipe->core (%d) for pipeline scheduling component icd->id 0x%x", + tr_err(&ipc_tr, "icd->core (%d) != ipc_pipe->core (%d) for pipeline scheduling component icd->id 0x%x", icd->core, ipc_pipe->core, icd->id); return -EINVAL; } @@ -260,16 +289,20 @@ int ipc_pipeline_complete(struct ipc *ipc, uint32_t comp_id) ipc_ppl_sink->cd); } -int ipc_comp_free(struct ipc *ipc, uint32_t comp_id) +__cold int ipc_comp_free(struct ipc *ipc, uint32_t comp_id) { struct ipc_comp_dev *icd; - struct list_item *clist, *tmp; + struct comp_buffer *buffer; + struct comp_buffer *safe; + struct list_item *clist; uint32_t flags; + assert_can_be_cold(); + /* check whether component exists */ icd = ipc_get_comp_by_id(ipc, comp_id); if (!icd) { - tr_err(&ipc_tr, "ipc_comp_free(): comp id: 0x%x is not found", + tr_err(&ipc_tr, "comp id: 0x%x is not found", comp_id); return -ENODEV; } @@ -280,7 +313,7 @@ int ipc_comp_free(struct ipc *ipc, uint32_t comp_id) /* check state */ if (icd->cd->state != COMP_STATE_READY) { - tr_err(&ipc_tr, "ipc_comp_free(): comp id: 0x%x state is %d cannot be freed", + tr_err(&ipc_tr, "comp id: 0x%x state is %d cannot be freed", comp_id, icd->cd->state); return -EINVAL; } @@ -299,34 +332,55 @@ int ipc_comp_free(struct ipc *ipc, uint32_t comp_id) * leak on error. Bug-free host drivers won't do * this, this was found via fuzzing. */ - tr_err(&ipc_tr, "ipc_comp_free(): uninitialized buffer lists on comp 0x%x\n", + tr_err(&ipc_tr, "uninitialized buffer lists on comp 0x%x\n", icd->id); return -EINVAL; } + /* Lock buffer lists to prevent racing with the LL scheduler. + * In user-space builds, use the LL scheduler's lock + * (re-entrant, so safe if caller already holds it). + */ +#ifdef CONFIG_SOF_USERSPACE_LL + user_ll_lock_sched(icd->core); +#else 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); - - 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)); +#endif + comp_dev_for_each_producer_safe(icd->cd, buffer, safe) { + comp_buffer_set_sink_component(buffer, NULL); /* This breaks the list, but we anyway delete all buffers */ - list_init(clist); + comp_buffer_reset_sink_list(buffer); } - list_for_item_safe(clist, tmp, &icd->cd->bsink_list) { - struct comp_buffer *buffer = container_of(clist, struct comp_buffer, source_list); - - 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)); + comp_dev_for_each_consumer_safe(icd->cd, buffer, safe) { + comp_buffer_set_source_component(buffer, NULL); /* This breaks the list, but we anyway delete all buffers */ - list_init(clist); + comp_buffer_reset_source_list(buffer); } + +#ifdef CONFIG_SOF_USERSPACE_LL + user_ll_unlock_sched(icd->core); +#else irq_local_enable(flags); +#endif + + /* + * A completed pipeline stores raw comp_dev pointers in its + * source_comp/sink_comp/sched_comp fields. + */ + list_for_item(clist, &ipc->comp_list) { + struct ipc_comp_dev *ppl_icd = container_of(clist, struct ipc_comp_dev, list); + + if (ppl_icd->type != COMP_TYPE_PIPELINE) + continue; + + if (ppl_icd->pipeline->source_comp == icd->cd) + ppl_icd->pipeline->source_comp = NULL; + if (ppl_icd->pipeline->sink_comp == icd->cd) + ppl_icd->pipeline->sink_comp = NULL; + if (ppl_icd->pipeline->sched_comp == icd->cd) + ppl_icd->pipeline->sched_comp = NULL; + } /* free component and remove from list */ comp_free(icd->cd); diff --git a/src/ipc/ipc-zephyr.c b/src/ipc/ipc-zephyr.c index a410e03123d6..66ada4ddaa05 100644 --- a/src/ipc/ipc-zephyr.c +++ b/src/ipc/ipc-zephyr.c @@ -11,7 +11,13 @@ #include <autoconf.h> +#include <zephyr/kernel.h> +#include <zephyr/ipc/ipc_service.h> +#ifdef CONFIG_INTEL_ADSP_IPC +#include <zephyr/ipc/backends/intel_adsp_host_ipc.h> #include <intel_adsp_ipc.h> +#endif + #include <sof/ipc/common.h> #include <sof/ipc/schedule.h> @@ -31,6 +37,7 @@ #include <sof/list.h> #include <sof/platform.h> #include <sof/schedule/edf_schedule.h> +#include <sof/schedule/twb_schedule.h> #include <sof/schedule/schedule.h> #include <rtos/task.h> #include <rtos/spinlock.h> @@ -55,25 +62,32 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); * When IPC message is read fills ipc_cmd_hdr. */ static uint32_t g_last_data, g_last_ext_data; +static struct ipc_ept sof_ipc_ept; +static struct ipc_ept_cfg sof_ipc_ept_cfg; + +BUILD_ASSERT(sizeof(struct ipc_cmd_hdr) == sizeof(uint32_t) * 2, + "ipc_cmd_hdr must be exactly two 32-bit words"); /** - * @brief cAVS IPC Message Handler Callback function. + * @brief SOF IPC receive callback for Zephyr IPC service. * - * See @ref (*intel_adsp_ipc_handler_t) for function signature description. - * @return false so BUSY on the other side will not be cleared immediately but - * will remain set until message would have been processed by scheduled task, i.e. - * until ipc_platform_complete_cmd() call. + * This callback is invoked by the Zephyr IPC service backend when a compact 2-word IPC message + * arrives from the host. It stores the raw header words in g_last_data/g_last_ext_data and + * schedules the SOF IPC task to process the command via ipc_platform_do_cmd(). */ -static bool message_handler(const struct device *dev, void *arg, uint32_t data, uint32_t ext_data) +static void sof_ipc_receive_cb(const void *data, size_t len, void *priv) { - struct ipc *ipc = (struct ipc *)arg; - + struct ipc *ipc = (struct ipc *)priv; + const uint32_t *msg = data; k_spinlock_key_t key; + __ASSERT(len == sizeof(uint32_t) * 2, "Unexpected IPC message length: %zu", len); + __ASSERT(data, "IPC data pointer is NULL"); + key = k_spin_lock(&ipc->lock); - g_last_data = data; - g_last_ext_data = ext_data; + g_last_data = msg[0]; + g_last_ext_data = msg[1]; #if CONFIG_DEBUG_IPC_COUNTERS increment_ipc_received_counter(); @@ -81,8 +95,6 @@ static bool message_handler(const struct device *dev, void *arg, uint32_t data, ipc_schedule_process(ipc); k_spin_unlock(&ipc->lock, key); - - return false; } #ifdef CONFIG_PM_DEVICE @@ -156,13 +168,15 @@ static int ipc_device_resume_handler(const struct device *dev, void *arg) ipc->task_mask = 0; ipc->pm_prepare_D3 = false; - /* attach handlers */ - intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, message_handler, ipc); - /* schedule task */ +#if CONFIG_TWB_IPC_TASK + scheduler_twb_task_init(&ipc->ipc_task, SOF_UUID(zipc_task_uuid), + &ipc_task_ops, ipc, 0, "IPC", ZEPHYR_TWB_STACK_SIZE, + CONFIG_TWB_THREAD_MEDIUM_PRIORITY, ZEPHYR_TWB_BUDGET_MAX / 2); +#else schedule_task_init_edf(&ipc->ipc_task, SOF_UUID(zipc_task_uuid), &ipc_task_ops, ipc, 0, 0); - +#endif return 0; } #endif /* CONFIG_PM_DEVICE */ @@ -211,11 +225,15 @@ enum task_state ipc_platform_do_cmd(struct ipc *ipc) { struct ipc_cmd_hdr *hdr; + dbg_path_hot_start_watching(); + hdr = ipc_compact_read_msg(); /* perform command */ ipc_cmd(hdr); + dbg_path_hot_stop_watching(); + if (ipc->task_mask & IPC_TASK_POWERDOWN || ipc_get()->pm_prepare_D3) { #if defined(CONFIG_PM) @@ -242,7 +260,10 @@ enum task_state ipc_platform_do_cmd(struct ipc *ipc) void ipc_platform_complete_cmd(struct ipc *ipc) { ARG_UNUSED(ipc); - intel_adsp_ipc_complete(INTEL_ADSP_IPC_HOST_DEV); + int ret = ipc_service_release_rx_buffer(&sof_ipc_ept, NULL); + + if (ret < 0) + tr_warn(&ipc_tr, "ipc_service_release_rx_buffer() failed: %d", ret); #if CONFIG_DEBUG_IPC_COUNTERS increment_ipc_processed_counter(); @@ -251,41 +272,63 @@ void ipc_platform_complete_cmd(struct ipc *ipc) int ipc_platform_send_msg(const struct ipc_msg *msg) { - if (!intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV)) + if (ipc_service_get_tx_buffer_size(&sof_ipc_ept) == 0) return -EBUSY; /* prepare the message and copy to mailbox */ struct ipc_cmd_hdr *hdr = ipc_prepare_to_send(msg); - return intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, hdr->pri, hdr->ext); + return ipc_service_send(&sof_ipc_ept, hdr, sizeof(*hdr)); } void ipc_platform_send_msg_direct(const struct ipc_msg *msg) { /* prepare the message and copy to mailbox */ struct ipc_cmd_hdr *hdr = ipc_prepare_to_send(msg); + int ret = ipc_service_send_critical(&sof_ipc_ept, hdr, sizeof(*hdr)); - intel_adsp_ipc_send_message_emergency(INTEL_ADSP_IPC_HOST_DEV, hdr->pri, hdr->ext); + if (ret < 0) + tr_err(&ipc_tr, "ipc_service_send_critical() failed: %d", ret); } int ipc_platform_poll_is_host_ready(void) { - return intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV); + return ipc_service_get_tx_buffer_size(&sof_ipc_ept) > 0; } int platform_ipc_init(struct ipc *ipc) { + int ret; + ipc_set_drvdata(ipc, NULL); /* schedule task */ +#if CONFIG_TWB_IPC_TASK + scheduler_twb_task_init(&ipc->ipc_task, SOF_UUID(zipc_task_uuid), + &ipc_task_ops, ipc, 0, "IPC", ZEPHYR_TWB_STACK_SIZE, + CONFIG_TWB_THREAD_MEDIUM_PRIORITY, ZEPHYR_TWB_BUDGET_MAX / 2); +#else schedule_task_init_edf(&ipc->ipc_task, SOF_UUID(zipc_task_uuid), &ipc_task_ops, ipc, 0, 0); - +#endif /* configure interrupt - work is done internally by Zephyr API */ - /* attach handlers */ - intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, message_handler, ipc); -#ifdef CONFIG_PM + sof_ipc_ept_cfg.name = "sof_ipc"; + sof_ipc_ept_cfg.prio = 0; + sof_ipc_ept_cfg.cb.received = sof_ipc_receive_cb; + sof_ipc_ept_cfg.priv = ipc; + + /* + * TODO: INTEL_ADSP_IPC_HOST_DEV is currently hardcoded for Intel ADSP platform. + * This needs to be made generic/configurable when additional vendor IPC backends + * become available (e.g., via devicetree, Kconfig, or platform-specific device selection). + */ + ret = ipc_service_register_endpoint(INTEL_ADSP_IPC_HOST_DEV, + &sof_ipc_ept, &sof_ipc_ept_cfg); + if (ret < 0) + return ret; + +#if defined(CONFIG_PM) && defined(CONFIG_INTEL_ADSP_IPC) intel_adsp_ipc_set_suspend_handler(INTEL_ADSP_IPC_HOST_DEV, ipc_device_suspend_handler, ipc); intel_adsp_ipc_set_resume_handler(INTEL_ADSP_IPC_HOST_DEV, @@ -294,3 +337,25 @@ int platform_ipc_init(struct ipc *ipc) return 0; } + +#ifdef CONFIG_INTEL_ADSP_IPC +static bool ipc_wait_complete(const struct device *dev, void *arg) +{ + k_sem_give(arg); + return false; +} + +void ipc_platform_wait_ack(struct ipc *ipc) +{ + static struct k_sem ipc_wait_sem; + + k_sem_init(&ipc_wait_sem, 0, 1); + + intel_adsp_ipc_set_done_handler(INTEL_ADSP_IPC_HOST_DEV, ipc_wait_complete, &ipc_wait_sem); + + if (k_sem_take(&ipc_wait_sem, Z_TIMEOUT_MS(10)) == -EAGAIN) + tr_err(&ipc_tr, "Timeout waiting for host ack!"); + + intel_adsp_ipc_set_done_handler(INTEL_ADSP_IPC_HOST_DEV, NULL, NULL); +} +#endif /* CONFIG_INTEL_ADSP_IPC */ diff --git a/src/ipc/ipc3/CMakeLists.txt b/src/ipc/ipc3/CMakeLists.txt index db1e6825085c..02a2d337c53d 100644 --- a/src/ipc/ipc3/CMakeLists.txt +++ b/src/ipc/ipc3/CMakeLists.txt @@ -7,18 +7,11 @@ add_local_sources(sof dai.c ) -is_zephyr(it_is) -if(it_is) ### Zephyr ### +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### zephyr_library_sources( host-page-table.c ) -else() ### Not Zephyr ### - -if (CONFIG_HOST_PTABLE) - add_local_sources(sof - host-page-table.c) -endif() - endif() # Zephyr diff --git a/src/ipc/ipc3/README.md b/src/ipc/ipc3/README.md new file mode 100644 index 000000000000..8f3f7c68a24d --- /dev/null +++ b/src/ipc/ipc3/README.md @@ -0,0 +1,113 @@ +# IPC3 Architecture + +This directory houses the Version 3 Inter-Processor Communication handling components. IPC3 is the older, legacy framework structure used extensively across initial Sound Open Firmware releases before the transition to IPC4 compound pipeline commands. + +## Overview + +The IPC3 architecture treats streaming, DAI configurations, and pipeline management as distinct scalar events. Messages arrive containing a specific `sof_ipc_cmd_hdr` denoting the "Global Message Type" (e.g., Stream, DAI, Trace, PM) and the targeted command within that type. + +## Command Structure and Routing + +Every message received is placed into an Rx buffer and initially routed to `ipc_cmd()`. Based on the `cmd` inside the `sof_ipc_cmd_hdr`, it delegates to one of the handler subsystems: + +* `ipc_glb_stream_message`: Stream/Pipeline configuration and states +* `ipc_glb_dai_message`: DAI parameters and formats +* `ipc_glb_pm_message`: Power Management operations + +```mermaid +graph TD + Mailbox[IPC Mailbox Interrupt] --> Valid[mailbox_validate] + Valid --> Disp[IPC Core Dispatcher] + + Disp -->|Global Type 1| StreamMsg[ipc_glb_stream_message] + Disp -->|Global Type 2| DAIMsg[ipc_glb_dai_message] + Disp -->|Global Type 3| PMMsg[ipc_glb_pm_message] + Disp -->|Global Type ...| TraceMsg[ipc_glb_trace_message] + + subgraph Stream Commands + StreamMsg --> StreamAlloc[ipc_stream_pcm_params] + StreamMsg --> StreamTrig[ipc_stream_trigger] + StreamMsg --> StreamFree[ipc_stream_pcm_free] + StreamMsg --> StreamPos[ipc_stream_position] + end + + subgraph DAI Commands + DAIMsg --> DAIConf[ipc_msg_dai_config] + end + + subgraph PM Commands + PMMsg --> PMCore[ipc_pm_core_enable] + PMMsg --> PMContext[ipc_pm_context_save / restore] + end +``` + +## Processing Flows + +### Stream Triggering (`ipc_stream_trigger`) + +Triggering is strictly hierarchical via IPC3. It expects pipelines built and components fully parsed prior to active streaming commands. + +1. **Validation**: The IPC fetches the host component ID. +2. **Device Lookup**: It searches the components list (`ipc_get_comp_dev`) for the PCM device matching the pipeline. +3. **Execution**: If valid, the pipeline graph is crawled recursively and its state altered via `pipeline_trigger`. + +```mermaid +sequenceDiagram + participant Host + participant IPC3 as IPC3 Handler (ipc_stream_trigger) + participant Pipe as Pipeline Framework + participant Comp as Connected Component + + Host->>IPC3: Send SOF_IPC_STREAM_TRIG_START + activate IPC3 + IPC3->>IPC3: ipc_get_comp_dev(stream_id) + IPC3->>Pipe: pipeline_trigger(COMP_TRIGGER_START) + activate Pipe + Pipe->>Comp: pipeline_for_each_comp(COMP_TRIGGER_START) + Comp-->>Pipe: Success (Component ACTIVE) + Pipe-->>IPC3: Return Status + deactivate Pipe + + alt If Success + IPC3-->>Host: Acknowledge Success Header + else If Error + IPC3-->>Host: Acknowledge Error Header (EINVAL / EIO) + end + deactivate IPC3 +``` + +### DAI Configuration (`ipc_msg_dai_config`) + +DAI (Digital Audio Interface) configuration involves setting up physical I2S, ALH, SSP, or HDA parameters. + +1. **Format Unpacking**: Converts the `sof_ipc_dai_config` payload sent from the ALSA driver into an internal DSP structure `ipc_config_dai`. +2. **Device Selection**: Identifies the exact DAI interface and finds its tracking device ID via `dai_get`. +3. **Hardware Config**: Applies the unpacked settings directly to the hardware via the specific DAI driver's `set_config` function. + +```mermaid +sequenceDiagram + participant Host + participant IPC3 as IPC3 Handler (ipc_msg_dai_config) + participant DAIDev as DAI Framework (dai_get) + participant HWDriver as HW Specific Driver (e.g. SSP) + + Host->>IPC3: Send SOF_IPC_DAI_CONFIG (e.g., SSP1, I2S Format) + activate IPC3 + + IPC3->>IPC3: build_dai_config() + IPC3->>DAIDev: dai_get(type, index) + DAIDev-->>IPC3: pointer to dai instance + + IPC3->>HWDriver: dai_set_config() + activate HWDriver + HWDriver-->>HWDriver: configures registers + HWDriver-->>IPC3: hardware configured + deactivate HWDriver + + IPC3-->>Host: Acknowledged Setting + deactivate IPC3 +``` + +## Mailbox and Validation (`mailbox_validate`) + +All commands passing through this layer enforce rigid payload boundaries. `mailbox_validate()` reads the first word directly from the mailbox memory, identifying the command type before parsing parameters out of shared RAM to prevent host/DSP mismatches from cascading. diff --git a/src/ipc/ipc3/dai.c b/src/ipc/ipc3/dai.c index a32d80392962..af06e21955cd 100644 --- a/src/ipc/ipc3/dai.c +++ b/src/ipc/ipc3/dai.c @@ -29,6 +29,8 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); +#define DAI_INDEX_INVALID 0xFFFF + void dai_set_link_hda_config(uint16_t *link_config, struct ipc_config_dai *common_config, const void *spec_config) @@ -73,6 +75,10 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void case SOF_DAI_IMX_MICFIL: channel = dai_get_handshake(dd->dai, dai->direction, dd->stream_id); +/* TODO: remove ifdef when transitioning to native drivers is complete on all NXP platforms */ +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + channel = channel & GENMASK(7, 0); +#endif break; case SOF_DAI_AMD_BT: channel = dai_get_handshake(dd->dai, dai->direction, @@ -89,10 +95,20 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void break; case SOF_DAI_AMD_HS: case SOF_DAI_AMD_HS_VIRTUAL: - case SOF_DAI_AMD_SW_AUDIO: + case SOF_DAI_AMD_TDM: + case SOF_DAI_AMD_SDW: { + struct dai_config *params = (struct dai_config *)dd->dai->dev->config; + + params->dai_index = dd->dai->index; channel = dai_get_handshake(dd->dai, dai->direction, dd->stream_id); +#if defined(CONFIG_SOC_ACP_7_0) + if (channel >= 64 && channel < 128) { + channel = channel - 64; + } +#endif break; + } case SOF_DAI_MEDIATEK_AFE: handshake = dai_get_handshake(dd->dai, dai->direction, dd->stream_id); @@ -100,7 +116,7 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void break; default: /* other types of DAIs not handled for now */ - comp_err(dev, "dai_config_dma_channel(): Unknown dai type %d", + comp_err(dev, "Unknown dai type %d", config->type); channel = SOF_DMA_CHAN_INVALID; break; @@ -115,7 +131,7 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) struct sof_ipc_dai_config *config = ipc_from_dai_config(dd->dai_spec_config); if (!config) { - comp_err(dev, "dai_data_config(): no config set for dai %d type %d", + comp_err(dev, "no config set for dai %d type %d", dai->dai_index, dai->type); return -EINVAL; } @@ -125,14 +141,14 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { - comp_info(dev, "dai_data_config(): Component is in active state."); + comp_info(dev, "Component is in active state."); return 0; } /* validate direction */ if (dai->direction != SOF_IPC_STREAM_PLAYBACK && dai->direction != SOF_IPC_STREAM_CAPTURE) { - comp_err(dev, "dai_data_config(): no direction set for dai %d type %d", + comp_err(dev, "no direction set for dai %d type %d", dai->dai_index, dai->type); return -EINVAL; } @@ -169,29 +185,93 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) case SOF_DAI_IMX_ESAI: dd->config.burst_elems = dai_get_fifo_depth(dd->dai, dai->direction); break; - case SOF_DAI_AMD_BT: - dev->ipc_config.frame_fmt = SOF_IPC_FRAME_S16_LE; - break; - case SOF_DAI_AMD_SP: - case SOF_DAI_AMD_SP_VIRTUAL: - dev->ipc_config.frame_fmt = SOF_IPC_FRAME_S16_LE; - break; case SOF_DAI_AMD_DMIC: dev->ipc_config.frame_fmt = SOF_IPC_FRAME_S32_LE; if (dd->dma_buffer) audio_stream_set_frm_fmt(&dd->dma_buffer->stream, dev->ipc_config.frame_fmt); break; + case SOF_DAI_AMD_BT: + case SOF_DAI_AMD_SP: + case SOF_DAI_AMD_SP_VIRTUAL: case SOF_DAI_AMD_HS: case SOF_DAI_AMD_HS_VIRTUAL: - case SOF_DAI_AMD_SW_AUDIO: - dev->ipc_config.frame_fmt = SOF_IPC_FRAME_S16_LE; + case SOF_DAI_AMD_TDM: +#if defined(CONFIG_AMD) && !defined(CONFIG_SOC_ACP_6_0) + { + struct acp_dma_dev_data *tdm_data = dd->dma->z_dev->data; + struct tdm_context *tdm_ctx; + + /* Allocate coherent memory for TDM context shared between + * IPC and DMA contexts. + */ + if (!tdm_data->dai_index_ptr) { + tdm_ctx = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*tdm_ctx)); + if (!tdm_ctx) + return -ENOMEM; + tdm_data->dai_index_ptr = tdm_ctx; + } else { + tdm_ctx = (struct tdm_context *)tdm_data->dai_index_ptr; + } + tdm_ctx->index = dd->dai->index; + tdm_ctx->frame_fmt = dev->ipc_config.frame_fmt; + /* AMD HW needs 24-bit data MSB-aligned in 32-bit word */ + if (dev->ipc_config.frame_fmt == SOF_IPC_FRAME_S24_4LE) { + dev->ipc_config.frame_fmt = SOF_IPC_FRAME_S24_4LE_MSB; + if (dd->dma_buffer) { + audio_stream_set_frm_fmt(&dd->dma_buffer->stream, + dev->ipc_config.frame_fmt); + } + } + } +#endif + break; + case SOF_DAI_AMD_SDW: +#if defined(CONFIG_AMD) && !defined(CONFIG_SOC_ACP_6_0) + { + /* AMD SDW/HS HW needs 24-bit data MSB-aligned in 32-bit word */ + if (dev->ipc_config.frame_fmt == SOF_IPC_FRAME_S24_4LE) + dev->ipc_config.frame_fmt = SOF_IPC_FRAME_S24_4LE_MSB; + if (dd->dma_buffer) + audio_stream_set_frm_fmt(&dd->dma_buffer->stream, + dev->ipc_config.frame_fmt); + + struct acp_dma_dev_data *dev_data = dd->dma->z_dev->data; + struct sdw_pin_data *pin_data; + + /* Allocate memory only if not already allocated */ + if (!dev_data->dai_index_ptr) { + pin_data = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*pin_data)); + dev_data->dai_index_ptr = pin_data; + } else { + pin_data = dev_data->dai_index_ptr; + } + pin_data->pin_num = dd->dai->index; + pin_data->pin_dir = dai->direction; +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + pin_data->dma_channel = dd->chan_index >= 0 ? dd->chan_index : DAI_INDEX_INVALID; +#else + pin_data->dma_channel = dd->chan ? dd->chan->index : DAI_INDEX_INVALID; +#endif +#if defined(CONFIG_SOC_ACP_7_X) + for (int i = 0; i < SDW_INSTANCES; i++) { + pin_data->index[i] = DAI_INDEX_INVALID; + } +#else + pin_data->index = DAI_INDEX_INVALID; +#endif + pin_data->instance = DAI_INDEX_INVALID; + dev_data->dai_index_ptr = pin_data; + } +#endif break; case SOF_DAI_MEDIATEK_AFE: break; default: /* other types of DAIs not handled for now */ - comp_warn(dev, "dai_data_config(): Unknown dai type %d", + comp_warn(dev, "Unknown dai type %d", config->type); break; } @@ -211,7 +291,7 @@ int ipc_comp_dai_config(struct ipc *ipc, struct ipc_config_dai *common_config, int ret = -ENODEV; int i; - tr_info(&ipc_tr, "ipc_comp_dai_config() dai type = %d index = %d", + tr_info(&ipc_tr, "dai type = %d index = %d", config->type, config->dai_index); /* for each component */ @@ -237,7 +317,7 @@ int ipc_comp_dai_config(struct ipc *ipc, struct ipc_config_dai *common_config, } if (ret < 0) { - tr_err(&ipc_tr, "ipc_comp_dai_config(): comp_dai_config() failed"); + tr_err(&ipc_tr, "comp_dai_config() failed"); return ret; } @@ -277,22 +357,40 @@ void dai_dma_release(struct dai_data *dd, struct comp_dev *dev) { /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { - comp_info(dev, "dai_config(): Component is in active state. Ignore resetting"); + comp_info(dev, "Component is in active state. Ignore resetting"); return; } +#if defined(CONFIG_AMD) + /* Free DAI-specific data allocated in ipc_dai_data_config() */ + if (dd->dma && dd->dma->z_dev && dd->dma->z_dev->data) { + struct acp_dma_dev_data *dev_data = dd->dma->z_dev->data; + + if (dev_data->dai_index_ptr) { + rfree(dev_data->dai_index_ptr); + dev_data->dai_index_ptr = NULL; + } + } +#endif + /* put the allocated DMA channel first */ +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + if (dd->chan_index >= 0) { + /* remove callback */ + notifier_unregister(dev, &dd->dma->chan[dd->chan_index], + NOTIFIER_ID_DMA_COPY); + dma_release_channel(dd->dma->z_dev, dd->chan_index); + dd->chan_index = -EINVAL; + } +#else if (dd->chan) { /* remove callback */ notifier_unregister(dev, dd->chan, NOTIFIER_ID_DMA_COPY); -#if CONFIG_ZEPHYR_NATIVE_DRIVERS - dma_release_channel(dd->chan->dma->z_dev, dd->chan->index); -#else dma_channel_put_legacy(dd->chan); -#endif dd->chan->dev_data = NULL; dd->chan = NULL; } +#endif } int dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai *common_config, @@ -306,12 +404,12 @@ int dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai dd->ipc_config.type != config->type) return 0; - comp_info(dev, "dai_config() dai type = %d index = %d dd %p", + comp_info(dev, "dai type = %d index = %d dd %p", config->type, config->dai_index, dd); /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { - comp_info(dev, "dai_config(): Component is in active state. Ignore config"); + comp_info(dev, "Component is in active state. Ignore config"); return 0; } @@ -323,20 +421,33 @@ int dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai if (SOF_DAI_QUIRK_IS_SET(config->flags, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP)) dd->delayed_dma_stop = true; +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + if (dd->chan_index >= 0) { + comp_info(dev, "Configured. dma channel index %d, ignore...", + dd->chan_index); + return 0; + } +#else if (dd->chan) { - comp_info(dev, "dai_config(): Configured. dma channel index %d, ignore...", + comp_info(dev, "Configured. dma channel index %d, ignore...", dd->chan->index); return 0; } +#endif break; case SOF_DAI_CONFIG_FLAGS_HW_FREE: +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + if (dd->chan_index < 0) + return 0; +#else if (!dd->chan) return 0; +#endif /* stop DMA and reset config for two-step stop DMA */ if (dd->delayed_dma_stop) { -#if CONFIG_ZEPHYR_NATIVE_DRIVERS - ret = dma_stop(dd->chan->dma->z_dev, dd->chan->index); +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + ret = dma_stop(dd->dma->z_dev, dd->chan_index); #else ret = dma_stop_delayed_legacy(dd->chan); #endif @@ -348,11 +459,13 @@ int dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai return 0; case SOF_DAI_CONFIG_FLAGS_PAUSE: - if (!dd->chan) +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + if (dd->chan_index < 0) return 0; -#if CONFIG_ZEPHYR_NATIVE_DRIVERS - return dma_stop(dd->chan->dma->z_dev, dd->chan->index); + return dma_stop(dd->dma->z_dev, dd->chan_index); #else + if (!dd->chan) + return 0; return dma_stop_delayed_legacy(dd->chan); #endif default: @@ -372,10 +485,10 @@ int dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai /* allocated dai_config if not yet */ if (!dd->dai_spec_config) { - dd->dai_spec_config = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + dd->dai_spec_config = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(struct sof_ipc_dai_config)); if (!dd->dai_spec_config) { - comp_err(dev, "dai_config(): No memory for dai_config."); + comp_err(dev, "No memory"); return -ENOMEM; } } diff --git a/src/ipc/ipc3/handler.c b/src/ipc/ipc3/handler.c index 12f2ba3a34a4..5bd5293c61b7 100644 --- a/src/ipc/ipc3/handler.c +++ b/src/ipc/ipc3/handler.c @@ -137,7 +137,7 @@ struct ipc_cmd_hdr *mailbox_validate(void) /* check if a pipeline is hostless when walking downstream */ static bool is_hostless_downstream(struct comp_dev *current) { - struct list_item *clist; + struct comp_buffer *buffer; /* check if current is a HOST comp */ if (current->ipc_config.type == SOF_COMP_HOST || @@ -145,22 +145,18 @@ static bool is_hostless_downstream(struct comp_dev *current) return false; /* check if the pipeline has a HOST comp downstream */ - list_for_item(clist, ¤t->bsink_list) { - struct comp_buffer *buffer; - - buffer = container_of(clist, struct comp_buffer, source_list); - + comp_dev_for_each_consumer(current, buffer) { /* don't go downstream if this component is not connected */ - if (!buffer->sink) + if (!comp_buffer_get_sink_component(buffer)) continue; /* dont go downstream if this comp belongs to another pipe */ - if (buffer->sink->ipc_config.pipeline_id != + if (comp_buffer_get_sink_component(buffer)->ipc_config.pipeline_id != current->ipc_config.pipeline_id) continue; /* return if there's a host comp downstream */ - if (!is_hostless_downstream(buffer->sink)) + if (!is_hostless_downstream(comp_buffer_get_sink_component(buffer))) return false; } @@ -170,7 +166,7 @@ static bool is_hostless_downstream(struct comp_dev *current) /* check if a pipeline is hostless when walking upstream */ static bool is_hostless_upstream(struct comp_dev *current) { - struct list_item *clist; + struct comp_buffer *buffer; /* check if current is a HOST comp */ if (current->ipc_config.type == SOF_COMP_HOST || @@ -178,22 +174,18 @@ static bool is_hostless_upstream(struct comp_dev *current) return false; /* check if the pipeline has a HOST comp upstream */ - list_for_item(clist, ¤t->bsource_list) { - struct comp_buffer *buffer; - - buffer = container_of(clist, struct comp_buffer, sink_list); - + comp_dev_for_each_producer(current, buffer) { /* don't go upstream if this component is not connected */ - if (!buffer->source) + if (!comp_buffer_get_source_component(buffer)) continue; /* dont go upstream if this comp belongs to another pipeline */ - if (buffer->source->ipc_config.pipeline_id != + if (comp_buffer_get_source_component(buffer)->ipc_config.pipeline_id != current->ipc_config.pipeline_id) continue; /* return if there is a host comp upstream */ - if (!is_hostless_upstream(buffer->source)) + if (!is_hostless_upstream(comp_buffer_get_source_component(buffer))) return false; } @@ -587,7 +579,7 @@ static int ipc_dai_config_set(struct sof_ipc_dai_config *config, } /* configure DAI */ - ret = dai_set_config(dai, config_dai, config); + ret = dai_set_config(dai, config_dai, config, sizeof(*config)); dai_put(dai); /* free ref immediately */ if (ret < 0) { ipc_cmd_err(&ipc_tr, "ipc: dai %d,%d config failed %d", config->type, @@ -680,7 +672,7 @@ static int ipc_pm_context_save(uint32_t header) /* do platform specific suspending */ platform_context_save(sof_get()); -#if !defined(CONFIG_LIBRARY) +#if !defined(CONFIG_LIBRARY) && !defined(CONFIG_ZEPHYR_POSIX) /* TODO: check we are inactive - all streams are suspended */ /* TODO: mask ALL platform interrupts except DMA */ @@ -837,7 +829,7 @@ static int ipc_dma_trace_config(uint32_t header) if (!dmat) { mtrace_printf(LOG_LEVEL_ERROR, - "ipc_dma_trace_config failed: dmat not initialized"); + "failed: dmat not initialized"); return -ENOMEM; } @@ -886,7 +878,7 @@ static int ipc_dma_trace_config(uint32_t header) error: #if CONFIG_HOST_PTABLE - dma_sg_free(&elem_array); + dma_sg_free(NULL, &elem_array); processing_error: #endif @@ -977,10 +969,14 @@ static int ipc_glb_trace_message(uint32_t header) static int ipc_glb_gdb_debug(uint32_t header) { - /* no furher information needs to be extracted form header */ + /* no further information needs to be extracted from header */ (void) header; -#if CONFIG_GDB_DEBUG +#if CONFIG_GDBSTUB + ipc_enter_gdb = true; + return 0; +// TODO: remove old GDB stub? +#elif CONFIG_GDB_DEBUG gdb_init_debug_exception(); gdb_init(); /* TODO: this asm should be in arch/include/debug/debug.h @@ -1000,10 +996,10 @@ static inline int ipc_probe_init(uint32_t header) struct sof_ipc_probe_dma_add_params *params = ipc_get()->comp_data; int dma_provided = params->num_elems; - tr_dbg(&ipc_tr, "ipc_probe_init()"); + tr_dbg(&ipc_tr, "entry"); if (dma_provided > 1 || dma_provided < 0) { - ipc_cmd_err(&ipc_tr, "ipc_probe_init(): Invalid amount of extraction DMAs specified = %d", + ipc_cmd_err(&ipc_tr, "Invalid amount of extraction DMAs specified = %d", dma_provided); return -EINVAL; } @@ -1013,7 +1009,7 @@ static inline int ipc_probe_init(uint32_t header) static inline int ipc_probe_deinit(uint32_t header) { - tr_dbg(&ipc_tr, "ipc_probe_deinit()"); + tr_dbg(&ipc_tr, "entry"); return probe_deinit(); } @@ -1023,17 +1019,17 @@ static inline int ipc_probe_dma_add(uint32_t header) struct sof_ipc_probe_dma_add_params *params = ipc_get()->comp_data; int dmas_count = params->num_elems; - tr_dbg(&ipc_tr, "ipc_probe_dma_add()"); + tr_dbg(&ipc_tr, "entry"); if (dmas_count > CONFIG_PROBE_DMA_MAX) { - ipc_cmd_err(&ipc_tr, "ipc_probe_dma_add(): Invalid amount of injection DMAs specified = %d. Max is " + ipc_cmd_err(&ipc_tr, "Invalid amount of injection DMAs specified = %d. Max is " STRINGIFY(CONFIG_PROBE_DMA_MAX) ".", dmas_count); return -EINVAL; } if (dmas_count <= 0) { - ipc_cmd_err(&ipc_tr, "ipc_probe_dma_add(): Inferred amount of incjection DMAs in payload is %d. This could indicate corrupt size reported in header or invalid IPC payload.", + ipc_cmd_err(&ipc_tr, "Inferred amount of incjection DMAs in payload is %d. This could indicate corrupt size reported in header or invalid IPC payload.", dmas_count); return -EINVAL; } @@ -1046,17 +1042,17 @@ static inline int ipc_probe_dma_remove(uint32_t header) struct sof_ipc_probe_dma_remove_params *params = ipc_get()->comp_data; int tags_count = params->num_elems; - tr_dbg(&ipc_tr, "ipc_probe_dma_remove()"); + tr_dbg(&ipc_tr, "entry"); if (tags_count > CONFIG_PROBE_DMA_MAX) { - ipc_cmd_err(&ipc_tr, "ipc_probe_dma_remove(): Invalid amount of injection DMAs specified = %d. Max is " + ipc_cmd_err(&ipc_tr, "Invalid amount of injection DMAs specified = %d. Max is " STRINGIFY(CONFIG_PROBE_DMA_MAX) ".", tags_count); return -EINVAL; } if (tags_count <= 0) { - ipc_cmd_err(&ipc_tr, "ipc_probe_dma_remove(): Inferred amount of incjection DMAs in payload is %d. This could indicate corrupt size reported in header or invalid IPC payload.", + ipc_cmd_err(&ipc_tr, "Inferred amount of incjection DMAs in payload is %d. This could indicate corrupt size reported in header or invalid IPC payload.", tags_count); return -EINVAL; } @@ -1069,17 +1065,17 @@ static inline int ipc_probe_point_add(uint32_t header) struct sof_ipc_probe_point_add_params *params = ipc_get()->comp_data; int probes_count = params->num_elems; - tr_dbg(&ipc_tr, "ipc_probe_point_add()"); + tr_dbg(&ipc_tr, "entry"); if (probes_count > CONFIG_PROBE_POINTS_MAX) { - ipc_cmd_err(&ipc_tr, "ipc_probe_point_add(): Invalid amount of Probe Points specified = %d. Max is " + ipc_cmd_err(&ipc_tr, "Invalid amount of Probe Points specified = %d. Max is " STRINGIFY(CONFIG_PROBE_POINT_MAX) ".", probes_count); return -EINVAL; } if (probes_count <= 0) { - ipc_cmd_err(&ipc_tr, "ipc_probe_point_add(): Inferred amount of Probe Points in payload is %d. This could indicate corrupt size reported in header or invalid IPC payload.", + ipc_cmd_err(&ipc_tr, "Inferred amount of Probe Points in payload is %d. This could indicate corrupt size reported in header or invalid IPC payload.", probes_count); return -EINVAL; } @@ -1092,17 +1088,17 @@ static inline int ipc_probe_point_remove(uint32_t header) struct sof_ipc_probe_point_remove_params *params = ipc_get()->comp_data; int probes_count = params->num_elems; - tr_dbg(&ipc_tr, "ipc_probe_point_remove()"); + tr_dbg(&ipc_tr, "entry"); if (probes_count > CONFIG_PROBE_POINTS_MAX) { - ipc_cmd_err(&ipc_tr, "ipc_probe_point_remove(): Invalid amount of Probe Points specified = %d. Max is " + ipc_cmd_err(&ipc_tr, "Invalid amount of Probe Points specified = %d. Max is " STRINGIFY(CONFIG_PROBE_POINT_MAX) ".", probes_count); return -EINVAL; } if (probes_count <= 0) { - ipc_cmd_err(&ipc_tr, "ipc_probe_point_remove(): Inferred amount of Probe Points in payload is %d. This could indicate corrupt size reported in header or invalid IPC payload.", + ipc_cmd_err(&ipc_tr, "Inferred amount of Probe Points in payload is %d. This could indicate corrupt size reported in header or invalid IPC payload.", probes_count); return -EINVAL; } @@ -1115,7 +1111,7 @@ static int ipc_probe_info(uint32_t header) struct sof_ipc_probe_info_params *params = ipc_get()->comp_data; int ret; - tr_dbg(&ipc_tr, "ipc_probe_get_data()"); + tr_dbg(&ipc_tr, "entry"); switch (cmd) { case SOF_IPC_PROBE_DMA_INFO: @@ -1125,13 +1121,13 @@ static int ipc_probe_info(uint32_t header) ret = probe_point_info(params, SOF_IPC_MSG_MAX_SIZE); break; default: - ipc_cmd_err(&ipc_tr, "ipc_probe_info(): Invalid probe INFO command = %u", + ipc_cmd_err(&ipc_tr, "Invalid probe INFO command = %u", cmd); ret = -EINVAL; } if (ret < 0) { - ipc_cmd_err(&ipc_tr, "ipc_probe_info(): cmd %u failed", cmd); + ipc_cmd_err(&ipc_tr, "cmd %u failed", cmd); return ret; } @@ -1142,7 +1138,7 @@ static int ipc_probe_info(uint32_t header) mailbox_hostbox_write(0, params, params->rhdr.hdr.size); ret = 1; } else { - ipc_cmd_err(&ipc_tr, "ipc_probe_get_data(): probes module returned too much payload for cmd %u - returned %d bytes, max %d", + ipc_cmd_err(&ipc_tr, "probes module returned too much payload for cmd %u - returned %d bytes, max %d", cmd, params->rhdr.hdr.size, MIN(MAILBOX_HOSTBOX_SIZE, SOF_IPC_MSG_MAX_SIZE)); ret = -EINVAL; @@ -1181,7 +1177,7 @@ static int ipc_glb_probe(uint32_t header) #else static inline int ipc_glb_probe(uint32_t header) { - ipc_cmd_err(&ipc_tr, "ipc_glb_probe(): Probes not enabled by Kconfig."); + ipc_cmd_err(&ipc_tr, "Probes not enabled by Kconfig."); return -EINVAL; } @@ -1430,85 +1426,12 @@ static int ipc_glb_tplg_message(uint32_t header) } } -#if CONFIG_DEBUG_MEMORY_USAGE_SCAN -static int fill_mem_usage_elems(enum mem_zone zone, enum sof_ipc_dbg_mem_zone ipc_zone, - int elem_number, struct sof_ipc_dbg_mem_usage_elem *elems) -{ - struct mm_info info; - int ret; - int i; - - for (i = 0; i < elem_number; ++i) { - ret = heap_info(zone, i, &info); - elems[i].zone = ipc_zone; - elems[i].id = i; - elems[i].used = ret < 0 ? UINT32_MAX : info.used; - elems[i].free = ret < 0 ? 0 : info.free; - } - - return elem_number; -} - -#if CONFIG_CORE_COUNT > 1 -#define PLATFORM_HEAP_SYSTEM_SHARED_CNT (PLATFORM_HEAP_SYSTEM_SHARED + PLATFORM_HEAP_RUNTIME_SHARED) -#else -#define PLATFORM_HEAP_SYSTEM_SHARED_CNT 0 -#endif - -static int ipc_glb_test_mem_usage(uint32_t header) -{ - /* count number heaps */ - int elem_cnt = PLATFORM_HEAP_SYSTEM + PLATFORM_HEAP_SYSTEM_RUNTIME + - PLATFORM_HEAP_RUNTIME + PLATFORM_HEAP_BUFFER + - PLATFORM_HEAP_SYSTEM_SHARED_CNT; - size_t size = sizeof(struct sof_ipc_dbg_mem_usage) + - elem_cnt * sizeof(struct sof_ipc_dbg_mem_usage_elem); - struct sof_ipc_dbg_mem_usage_elem *elems; - struct sof_ipc_dbg_mem_usage *mem_usage; - - mem_usage = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, 0, size); - if (!mem_usage) - return -ENOMEM; - - mem_usage->rhdr.hdr.cmd = header; - mem_usage->rhdr.hdr.size = size; - mem_usage->num_elems = elem_cnt; - - /* fill list of elems */ - elems = mem_usage->elems; - elems += fill_mem_usage_elems(SOF_MEM_ZONE_SYS, SOF_IPC_MEM_ZONE_SYS, - PLATFORM_HEAP_SYSTEM, elems); - elems += fill_mem_usage_elems(SOF_MEM_ZONE_SYS_RUNTIME, SOF_IPC_MEM_ZONE_SYS_RUNTIME, - PLATFORM_HEAP_SYSTEM_RUNTIME, elems); - elems += fill_mem_usage_elems(SOF_MEM_ZONE_RUNTIME, SOF_IPC_MEM_ZONE_RUNTIME, - PLATFORM_HEAP_RUNTIME, elems); - /* cppcheck-suppress unreadVariable */ - elems += fill_mem_usage_elems(SOF_MEM_ZONE_BUFFER, SOF_IPC_MEM_ZONE_BUFFER, - PLATFORM_HEAP_BUFFER, elems); -#if CONFIG_CORE_COUNT > 1 - elems += fill_mem_usage_elems(SOF_MEM_ZONE_SYS_SHARED, SOF_IPC_MEM_ZONE_SYS_SHARED, - PLATFORM_HEAP_SYSTEM_SHARED, elems); - elems += fill_mem_usage_elems(SOF_MEM_ZONE_RUNTIME_SHARED, SOF_IPC_MEM_ZONE_RUNTIME_SHARED, - PLATFORM_HEAP_RUNTIME_SHARED, elems); -#endif - - /* write component values to the outbox */ - mailbox_hostbox_write(0, mem_usage, mem_usage->rhdr.hdr.size); - - rfree(mem_usage); - return 1; -} -#endif - static int ipc_glb_debug_message(uint32_t header) { uint32_t cmd = iCS(header); switch (cmd) { -#if CONFIG_DEBUG_MEMORY_USAGE_SCAN - case SOF_IPC_DEBUG_MEM_USAGE: - return ipc_glb_test_mem_usage(header); -#endif + /* TODO: Zephyr heap debug needs to added for IPC3 using Zephyr APIs. */ default: ipc_cmd_err(&ipc_tr, "ipc: unknown debug header 0x%x", header); return -EINVAL; diff --git a/src/ipc/ipc3/helper.c b/src/ipc/ipc3/helper.c index 678d3306e4b1..e962a3670a86 100644 --- a/src/ipc/ipc3/helper.c +++ b/src/ipc/ipc3/helper.c @@ -81,7 +81,6 @@ static const struct comp_driver *get_drv(struct sof_ipc_comp *comp) struct comp_driver_info *info; struct sof_ipc_comp_ext *comp_ext; uintptr_t offset; - k_spinlock_key_t key; /* do we have extended data ? */ if (!comp->ext_data_length) { @@ -95,7 +94,7 @@ static const struct comp_driver *get_drv(struct sof_ipc_comp *comp) } if (!drv) - tr_err(&comp_tr, "get_drv(): driver not found, comp->type = %u", + tr_err(&comp_tr, "driver not found, comp->type = %u", comp->type); goto out; @@ -127,9 +126,10 @@ static const struct comp_driver *get_drv(struct sof_ipc_comp *comp) goto out; } - /* search driver list with UUID */ - key = k_spin_lock(&drivers->lock); - + /* + * search driver list with UUID; no locking needed as the driver + * list is only modified at boot and from the serialized IPC thread + */ list_for_item(clist, &drivers->list) { info = container_of(clist, struct comp_driver_info, list); @@ -142,14 +142,12 @@ static const struct comp_driver *get_drv(struct sof_ipc_comp *comp) if (!drv) tr_err(&comp_tr, - "get_drv(): the provided UUID (%8x%8x%8x%8x) doesn't match to any driver!", + "the provided UUID (%8x%8x%8x%8x) doesn't match to any driver!", *(uint32_t *)(&comp_ext->uuid[0]), *(uint32_t *)(&comp_ext->uuid[4]), *(uint32_t *)(&comp_ext->uuid[8]), *(uint32_t *)(&comp_ext->uuid[12])); - k_spin_unlock(&drivers->lock, key); - out: if (drv) tr_dbg(&comp_tr, "get_drv(), found driver type %d, uuid %pU", @@ -302,7 +300,11 @@ static int comp_specific_builder(struct sof_ipc_comp *comp, if (IPC_TAIL_IS_SIZE_INVALID(*proc)) return -EBADMSG; - if (proc->comp.hdr.size + proc->size > SOF_IPC_MSG_MAX_SIZE) + /* compare without adding the two host-supplied uint32_t values, + * which could wrap and let an oversized proc->size pass + */ + if (proc->comp.hdr.size > SOF_IPC_MSG_MAX_SIZE || + proc->size > SOF_IPC_MSG_MAX_SIZE - proc->comp.hdr.size) return -EBADMSG; config->process.type = proc->type; @@ -363,13 +365,13 @@ struct comp_dev *comp_new(struct sof_ipc_comp *comp) /* build the component */ if (comp_specific_builder(comp, &spec) < 0) { - comp_cl_err(drv, "comp_new(): component type not recognized"); + comp_cl_err(drv, "component type not recognized"); return NULL; } comp_common_builder(comp, &config); cdev = drv->ops.create(drv, &config, &spec); if (!cdev) { - comp_cl_err(drv, "comp_new(): unable to create the new component"); + comp_cl_err(drv, "unable to create the new component"); return NULL; } @@ -389,16 +391,16 @@ int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc) /* check whether the pipeline already exists */ ipc_pipe = ipc_get_pipeline_by_id(ipc, pipe_desc->comp_id); if (ipc_pipe != NULL) { - tr_err(&ipc_tr, "ipc_pipeline_new(): pipeline already exists, pipe_desc->comp_id = %u", + tr_err(&ipc_tr, "pipeline already exists, pipe_desc->comp_id = %u", pipe_desc->comp_id); return -EINVAL; } /* create the pipeline */ - pipe = pipeline_new(pipe_desc->pipeline_id, pipe_desc->priority, - pipe_desc->comp_id); + pipe = pipeline_new(NULL, pipe_desc->pipeline_id, pipe_desc->priority, + pipe_desc->comp_id, NULL); if (!pipe) { - tr_err(&ipc_tr, "ipc_pipeline_new(): pipeline_new() failed"); + tr_err(&ipc_tr, "pipeline_new() failed"); return -ENOMEM; } @@ -412,13 +414,13 @@ int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc) /* set xrun time limit */ ret = pipeline_xrun_set_limit(pipe, pipe_desc->xrun_limit_usecs); if (ret) { - tr_err(&ipc_tr, "ipc_pipeline_new(): pipeline_xrun_set_limit() failed"); + tr_err(&ipc_tr, "pipeline_xrun_set_limit() failed"); pipeline_free(pipe); return ret; } /* allocate the IPC pipeline container */ - ipc_pipe = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + ipc_pipe = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(struct ipc_comp_dev)); if (!ipc_pipe) { pipeline_free(pipe); @@ -439,6 +441,8 @@ int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc) int ipc_pipeline_free(struct ipc *ipc, uint32_t comp_id) { struct ipc_comp_dev *ipc_pipe; + struct ipc_comp_dev *icd; + struct list_item *clist; int ret; /* check whether pipeline exists */ @@ -448,7 +452,7 @@ int ipc_pipeline_free(struct ipc *ipc, uint32_t comp_id) /* check type */ if (ipc_pipe->type != COMP_TYPE_PIPELINE) { - tr_err(&ipc_tr, "ipc_pipeline_free(): comp id: %d is not a PIPELINE", + tr_err(&ipc_tr, "comp id: %d is not a PIPELINE", comp_id); return -EINVAL; } @@ -457,10 +461,23 @@ int ipc_pipeline_free(struct ipc *ipc, uint32_t comp_id) if (!cpu_is_me(ipc_pipe->core)) return ipc_process_on_core(ipc_pipe->core, false); + /* Clear stale cd->pipeline pointers on all components and buffers + * that still belong to this pipeline. A well-behaved host driver + * frees components before freeing the pipeline, but if it does not + * (or in fuzz/error paths) the dangling pointer would be a + * use-after-free on any subsequent IPC referencing that component. + */ + list_for_item(clist, &ipc->comp_list) { + icd = container_of(clist, struct ipc_comp_dev, list); + if (icd->type == COMP_TYPE_COMPONENT && + icd->cd && icd->cd->pipeline == ipc_pipe->pipeline) + icd->cd->pipeline = NULL; + } + /* free buffer and remove from list */ ret = pipeline_free(ipc_pipe->pipeline); if (ret < 0) { - tr_err(&ipc_tr, "ipc_pipeline_free(): pipeline_free() failed"); + tr_err(&ipc_tr, "pipeline_free() failed"); return ret; } ipc_pipe->pipeline = NULL; @@ -479,19 +496,19 @@ int ipc_buffer_new(struct ipc *ipc, const struct sof_ipc_buffer *desc) /* check whether buffer already exists */ ibd = ipc_get_buffer_by_id(ipc, desc->comp.id); if (ibd != NULL) { - tr_err(&ipc_tr, "ipc_buffer_new(): buffer already exists, desc->comp.id = %u", + tr_err(&ipc_tr, "buffer already exists, desc->comp.id = %u", desc->comp.id); return -EINVAL; } /* register buffer with pipeline */ - buffer = buffer_new(desc, false); + buffer = buffer_new(NULL, desc, BUFFER_USAGE_NOT_SHARED); if (!buffer) { - tr_err(&ipc_tr, "ipc_buffer_new(): buffer_new() failed"); + tr_err(&ipc_tr, "buffer_new() failed"); return -ENOMEM; } - ibd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + ibd = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(struct ipc_comp_dev)); if (!ibd) { buffer_free(buffer); @@ -535,15 +552,15 @@ int ipc_buffer_free(struct ipc *ipc, uint32_t buffer_id) continue; /* check comp state if sink and source are valid */ - if (ibd->cb->sink == icd->cd) { - sink = ibd->cb->sink; - if (ibd->cb->sink->state != COMP_STATE_READY) + if (comp_buffer_get_sink_component(ibd->cb) == icd->cd) { + sink = comp_buffer_get_sink_component(ibd->cb); + if (comp_buffer_get_sink_state(ibd->cb) != COMP_STATE_READY) sink_active = true; } - if (ibd->cb->source == icd->cd) { - source = ibd->cb->source; - if (ibd->cb->source->state != COMP_STATE_READY) + if (comp_buffer_get_source_component(ibd->cb) == icd->cd) { + source = comp_buffer_get_source_component(ibd->cb); + if (comp_buffer_get_source_state(ibd->cb) != COMP_STATE_READY) source_active = true; } } @@ -562,13 +579,19 @@ int ipc_buffer_free(struct ipc *ipc, uint32_t buffer_id) * core, the free must be run in the context of the active * pipeline. */ - active_comp = sink_active ? sink : source; + if (sink_active) + active_comp = sink; + else if (source_active) + active_comp = source; + else + active_comp = NULL; + if (active_comp) { core = active_comp->ipc_config.core; if (active_comp->state > COMP_STATE_READY && core != ibd->core && core != cpu_get_id()) { - tr_dbg(&ipc_tr, "ipc_buffer_free(): comp id: %d run on sink core %u", + tr_dbg(&ipc_tr, "comp id: %d run on sink core %u", buffer_id, core); ibd->core = core; return ipc_process_on_core(core, false); @@ -633,14 +656,14 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) /* check whether the components already exist */ icd_source = ipc_get_comp_dev(ipc, COMP_TYPE_ANY, connect->source_id); if (!icd_source) { - tr_err(&ipc_tr, "ipc_comp_connect(): source component does not exist, source_id = %u sink_id = %u", + tr_err(&ipc_tr, "source component does not exist, source_id = %u sink_id = %u", connect->source_id, connect->sink_id); return -EINVAL; } icd_sink = ipc_get_comp_dev(ipc, COMP_TYPE_ANY, connect->sink_id); if (!icd_sink) { - tr_err(&ipc_tr, "ipc_comp_connect(): sink component does not exist, source_id = %d sink_id = %u", + tr_err(&ipc_tr, "sink component does not exist, source_id = %d sink_id = %u", connect->sink_id, connect->source_id); return -EINVAL; } @@ -653,7 +676,7 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) icd_sink->type == COMP_TYPE_BUFFER) return ipc_comp_to_buffer_connect(icd_source, icd_sink); else { - tr_err(&ipc_tr, "ipc_comp_connect(): invalid source and sink types, connect->source_id = %u, connect->sink_id = %u", + tr_err(&ipc_tr, "invalid source and sink types, connect->source_id = %u, connect->sink_id = %u", connect->source_id, connect->sink_id); return -EINVAL; } @@ -667,29 +690,29 @@ int ipc_comp_new(struct ipc *ipc, ipc_comp *_comp) /* check core is valid */ if (comp->core >= CONFIG_CORE_COUNT) { - tr_err(&ipc_tr, "ipc_comp_new(): comp->core = %u", comp->core); + tr_err(&ipc_tr, "comp->core = %u", comp->core); return -EINVAL; } /* check whether component already exists */ icd = ipc_get_comp_by_id(ipc, comp->id); if (icd != NULL) { - tr_err(&ipc_tr, "ipc_comp_new(): comp->id = %u", comp->id); + tr_err(&ipc_tr, "comp->id = %u", comp->id); return -EINVAL; } /* create component */ cd = comp_new(comp); if (!cd) { - tr_err(&ipc_tr, "ipc_comp_new(): component cd = NULL"); + tr_err(&ipc_tr, "component cd = NULL"); return -EINVAL; } /* allocate the IPC component container */ - icd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + icd = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(struct ipc_comp_dev)); if (!icd) { - tr_err(&ipc_tr, "ipc_comp_new(): alloc failed"); + tr_err(&ipc_tr, "alloc failed"); rfree(cd); return -ENOMEM; } diff --git a/src/ipc/ipc3/host-page-table.c b/src/ipc/ipc3/host-page-table.c index 414dd4f57ef0..dbd0fd0fe030 100644 --- a/src/ipc/ipc3/host-page-table.c +++ b/src/ipc/ipc3/host-page-table.c @@ -16,6 +16,25 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); +/* + * Size in bytes of the DSP-side buffer that receives the compressed host page + * table. DSP targets define PLATFORM_PAGE_TABLE_SIZE; the host/library builds + * (e.g. testbench, fuzzer) allocate it as HOST_PAGE_SIZE in drivers/host/ipc.c + * and do not define PLATFORM_PAGE_TABLE_SIZE, so fall back to that. + */ +#ifndef PLATFORM_PAGE_TABLE_SIZE +#define PLATFORM_PAGE_TABLE_SIZE HOST_PAGE_SIZE +#endif + +/* + * The compressed page table stores one 20-bit entry per host page, so the + * number of pages whose entries fit in the page table buffer is + * (buffer bytes * 8 bits/byte) / 20 bits/page. + */ +#define HOST_PAGE_TABLE_BITS_PER_PAGE 20 +#define HOST_PAGE_TABLE_MAX_PAGES \ + (PLATFORM_PAGE_TABLE_SIZE * 8 / HOST_PAGE_TABLE_BITS_PER_PAGE) + /* * Parse the host page tables and create the audio DMA SG configuration * for host audio DMA buffer. This involves creating a dma_sg_elem for each @@ -38,14 +57,14 @@ static int ipc_parse_page_descriptors(uint8_t *page_table, if ((ring->size <= HOST_PAGE_SIZE * (ring->pages - 1)) || (ring->size > HOST_PAGE_SIZE * ring->pages)) { /* error buffer size */ - tr_err(&ipc_tr, "ipc_parse_page_descriptors(): error buffer size"); + tr_err(&ipc_tr, "error buffer size"); return -EINVAL; } - elem_array->elems = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + elem_array->elems = rzalloc(SOF_MEM_FLAG_USER, sizeof(struct dma_sg_elem) * ring->pages); if (!elem_array->elems) { - tr_err(&ipc_tr, "ipc_parse_page_descriptors(): There is no heap free with this block size: %zu", + tr_err(&ipc_tr, "There is no heap free with this block size: %zu", sizeof(struct dma_sg_elem) * ring->pages); return -ENOMEM; } @@ -85,7 +104,7 @@ static int ipc_parse_page_descriptors(uint8_t *page_table, /* * Copy the audio buffer page tables from the host to the DSP max of 4K. */ -static int ipc_get_page_descriptors(struct dma *dmac, uint8_t *page_table, +static int ipc_get_page_descriptors(struct sof_dma *dmac, uint8_t *page_table, struct sof_ipc_host_buffer *ring) { struct dma_config cfg; @@ -98,7 +117,8 @@ static int ipc_get_page_descriptors(struct dma *dmac, uint8_t *page_table, * reload() function which may not be the case for all * vendors. */ - if (!IS_ENABLED(CONFIG_DMA_NXP_SOF_HOST_DMA)) { + if (!IS_ENABLED(CONFIG_DMA_NXP_SOF_HOST_DMA) && + !IS_ENABLED(CONFIG_DMA_MTK_SOF_HOST_DMA)) { tr_err(&ipc_tr, "DMAC not supported for page transfer"); return -ENOTSUP; } @@ -157,7 +177,7 @@ static int ipc_get_page_descriptors(struct dma *dmac, uint8_t *page_table, /* get DMA channel from DMAC */ chan = dma_channel_get_legacy(dmac, 0); if (!chan) { - tr_err(&ipc_tr, "ipc_get_page_descriptors(): chan is NULL"); + tr_err(&ipc_tr, "chan is NULL"); return -ENODEV; } @@ -178,7 +198,7 @@ static int ipc_get_page_descriptors(struct dma *dmac, uint8_t *page_table, /* 20 bits for each page, round up to minimum DMA copy size */ ret = dma_get_attribute_legacy(dmac, DMA_ATTR_COPY_ALIGNMENT, &dma_copy_align); if (ret < 0) { - tr_err(&ipc_tr, "ipc_get_page_descriptors(): dma_get_attribute() failed"); + tr_err(&ipc_tr, "dma_get_attribute() failed"); goto out; } elem.size = SOF_DIV_ROUND_UP(ring->pages * 20, 8); @@ -188,14 +208,14 @@ static int ipc_get_page_descriptors(struct dma *dmac, uint8_t *page_table, ret = dma_set_config_legacy(chan, &config); if (ret < 0) { - tr_err(&ipc_tr, "ipc_get_page_descriptors(): dma_set_config() failed"); + tr_err(&ipc_tr, "dma_set_config() failed"); goto out; } /* start the copy of page table to DSP */ ret = dma_copy_legacy(chan, elem.size, DMA_COPY_ONE_SHOT | DMA_COPY_BLOCKING); if (ret < 0) { - tr_err(&ipc_tr, "ipc_get_page_descriptors(): dma_start() failed"); + tr_err(&ipc_tr, "dma_start() failed"); goto out; } @@ -215,6 +235,19 @@ int ipc_process_host_buffer(struct ipc *ipc, struct ipc_data_host_buffer *data_host_buffer; int err; + /* + * The host-supplied page count is used both to size DSP-side + * allocations and to compute the DMA transfer length for the + * compressed page table. Reject a count that would not fit in the + * page table buffer before doing any arithmetic that could overflow + * (ring->pages * 20). pages == 0 is also invalid and would underflow + * the ring->size sanity check in ipc_parse_page_descriptors(). + */ + if (ring->pages == 0 || ring->pages > HOST_PAGE_TABLE_MAX_PAGES) { + tr_err(&ipc_tr, "ipc: invalid page count %u", ring->pages); + return -EINVAL; + } + data_host_buffer = ipc_platform_get_host_buffer(ipc); dma_sg_init(elem_array); @@ -239,6 +272,6 @@ int ipc_process_host_buffer(struct ipc *ipc, return 0; error: - dma_sg_free(elem_array); + dma_sg_free(NULL, elem_array); return err; } diff --git a/src/ipc/ipc4/CMakeLists.txt b/src/ipc/ipc4/CMakeLists.txt index 5a4d271e7f13..360a4e988650 100644 --- a/src/ipc/ipc4/CMakeLists.txt +++ b/src/ipc/ipc4/CMakeLists.txt @@ -2,30 +2,28 @@ # Files common to Zephyr and XTOS add_local_sources(sof - dai.c - handler.c + handler-user.c + handler-kernel.c helper.c logging.c notification.c ) +# The DAI interface is not implemented in library builds and +# code depends on Zephyr DAI driver definitions to be available. +if(NOT CONFIG_LIBRARY) + add_local_sources(sof dai.c) +endif() -is_zephyr(it_is) -if(it_is) ### Zephyr ### +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### zephyr_library_sources_ifdef(CONFIG_AMS ams_helpers.c ) - else() ### Not Zephyr #### - -add_local_sources(sof - ams_helpers.c -) - target_include_directories(sof_options INTERFACE ${RIMAGE_TOP}/src/include) - endif() # Zephyr diff --git a/src/ipc/ipc4/README.md b/src/ipc/ipc4/README.md new file mode 100644 index 000000000000..1b40195085b9 --- /dev/null +++ b/src/ipc/ipc4/README.md @@ -0,0 +1,104 @@ +# IPC4 Architecture + +This directory holds the handlers and topology parsing logic for Inter-Processor Communication Version 4. IPC4 introduces a significantly denser, compound-command structure heavily based around the concept of "pipelines" and dynamic "modules" rather than static DSP stream roles. + +## Overview + +Unlike older iterations (IPC3) which trigger single components via scalar commands, IPC4 uses compound structures. A single host interrupt might contain batch operations like building an entire processing chain, setting module parameters sequentially, and triggering a start across multiple interconnected blocks simultaneously. + +## Message Handling and Dispatch + +IPC4 messages are received via the generic IPC handler entry point `ipc_cmd()`. `ipc_cmd()` determines the IPC target and dispatches the message appropriately. Global messages are dispatched to `ipc4_process_glb_message()`, while module-specific messages are routed directly to `ipc4_process_module_message()`. + +```mermaid +graph TD + Mailbox[IPC Mailbox Interrupt] --> CoreIPC[ipc_cmd] + + CoreIPC --> TypeSel{Decode IPC Message Target} + TypeSel -->|FW_GEN_MSG| Glb[ipc4_process_glb_message] + TypeSel -->|MODULE_MSG| Mod[ipc4_process_module_message] + + subgraph Global Handler + Glb --> NewPipe[ipc4_new_pipeline] + Glb --> DelPipe[ipc4_delete_pipeline] + Glb --> MemMap[ipc4_process_chain_dma] + Glb --> SetPipe[ipc4_set_pipeline_state] + end + + subgraph Module Handler + Mod --> InitMod[ipc4_init_module_instance] + Mod --> SetMod[ipc4_set_module_params] + Mod --> GetMod[ipc4_get_module_params] + Mod --> Bind[ipc4_bind] + Mod --> Unbind[ipc4_unbind] + end +``` + +## Processing Flows + +### Pipeline State Management (`ipc4_set_pipeline_state`) + +The core driver of graph execution in IPC4 is `ipc4_set_pipeline_state()`. This accepts a multi-stage request (e.g., `START`, `PAUSE`, `RESET`) and coordinates triggering the internal pipelines. + +1. **State Translation**: It maps the incoming IPC4 state request to an internal SOF state (e.g., `IPC4_PIPELINE_STATE_RUNNING` -> `COMP_TRIGGER_START`). +2. **Graph Traversal**: It fetches the pipeline object associated with the command and begins preparing it (`ipc4_pipeline_prepare`). +3. **Trigger Execution**: It executes `ipc4_pipeline_trigger()`, recursively changing states across the internal graphs and alerting either the LL scheduler or DP threads. + +```mermaid +sequenceDiagram + participant Host + participant IPC4Set as ipc4_set_pipeline_state + participant PPLPrep as ipc4_pipeline_prepare + participant PPLTrig as ipc4_pipeline_trigger + participant Comp as Graph Components + + Host->>IPC4Set: IPC4_PIPELINE_STATE_RUNNING + activate IPC4Set + + IPC4Set->>PPLPrep: Maps to COMP_TRIGGER_START + PPLPrep->>Comp: Applies PCM params & formatting + Comp-->>PPLPrep: Components ready + + IPC4Set->>PPLTrig: execute trigger + PPLTrig->>Comp: pipeline_trigger(COMP_TRIGGER_START) + Comp-->>PPLTrig: Success + + IPC4Set-->>Host: Reply: ipc4_send_reply() + deactivate IPC4Set +``` + +### Module Instantiation and Binding (`ipc4_bind`) + +In IPC4, modules (components) are bound together dynamically rather than constructed statically by the firmware at boot time. + +1. **Instantiation**: `ipc4_init_module_instance()` allocates the module via the DSP heap arrays based on UUIDs. +2. **Binding**: `ipc4_bind()` takes two module IDs and dynamically connects their sink and source pins using intermediate `comp_buffer` objects. + +```mermaid +sequenceDiagram + participant Host + participant IPC4Bind as ipc4_bind + participant SrcMod as Source Module + participant SinkMod as Sink Module + participant Buff as Connection Buffer + + Host->>IPC4Bind: Bind Src(ID) -> Sink(ID) + activate IPC4Bind + + IPC4Bind->>SrcMod: Locate by ID + IPC4Bind->>SinkMod: Locate by ID + + IPC4Bind->>Buff: buffer_new() (Create Intermediate Storage) + + IPC4Bind->>SrcMod: Bind source pin to Buff (via comp_bind/comp_buffer_connect) + IPC4Bind->>SinkMod: Bind sink pin to Buff (via comp_bind/comp_buffer_connect) + + IPC4Bind-->>Host: Reply: Linked + deactivate IPC4Bind +``` + +## Compound Messages (`ipc_wait_for_compound_msg`) + +To accelerate initialization, IPC4 enables Compound commands. A host can send multiple IPC messages chained back-to-back using a single mailbox trigger flag before waiting for ACKs. + +`ipc_compound_pre_start` and `ipc_compound_post_start` manage this batch execution safely without overflowing the Zephyr work queues or breaking hardware configurations during intermediate states. diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index 5c5a12ee8927..1540d95cf0f0 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -11,7 +11,9 @@ #include <sof/common.h> #include <rtos/idc.h> #include <rtos/alloc.h> +#include <rtos/mutex.h> #include <sof/lib/dai.h> +#include <sof/lib/memory.h> #include <sof/lib/notifier.h> #include <sof/platform.h> #include <rtos/sof.h> @@ -32,12 +34,14 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); +static APP_SYSUSER_BSS SYS_MUTEX_DEFINE(llp_reading_slots_lock); + void dai_set_link_hda_config(uint16_t *link_config, struct ipc_config_dai *common_config, const void *spec_config) { #if ACE_VERSION > ACE_VERSION_1_5 - const struct ipc4_audio_format *out_fmt = common_config->out_fmt; + const struct ipc4_audio_format *gtw_fmt = common_config->gtw_fmt; union hdalink_cfg link_cfg; switch (common_config->type) { @@ -48,17 +52,23 @@ void dai_set_link_hda_config(uint16_t *link_config, break; case SOF_DAI_INTEL_DMIC: link_cfg.full = 0; - if (out_fmt->depth == IPC4_DEPTH_16BIT) { + if (gtw_fmt->depth == IPC4_DEPTH_16BIT) { /* 16bit dmic packs two 16bit samples into single 32bit word * fw needs to adjust channel count to match final sample * group size */ - link_cfg.part.hchan = (out_fmt->channels_count - 1) / 2; + link_cfg.part.hchan = (gtw_fmt->channels_count - 1) / 2; } else { - link_cfg.part.hchan = out_fmt->channels_count - 1; + link_cfg.part.hchan = gtw_fmt->channels_count - 1; } link_cfg.part.stream = common_config->host_dma_config[0]->stream_id; break; + case SOF_DAI_INTEL_UAOL: + link_cfg.full = 0; + link_cfg.part.hchan = gtw_fmt->channels_count - 1; + link_cfg.part.dir = common_config->direction; + link_cfg.part.stream = common_config->host_dma_config[0]->stream_id; + break; default: /* other types of DAIs not need link_config */ return; @@ -90,13 +100,9 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); - if (!cd->gtw_cfg) { - comp_err(dev, "No gateway config found!"); - return SOF_DMA_CHAN_INVALID; - } - channel = SOF_DMA_CHAN_INVALID; - const struct sof_alh_configuration_blob *alh_blob = cd->gtw_cfg; + const struct sof_alh_configuration_blob *alh_blob = + (void *)cd->config.gtw_cfg.config_data; for (int i = 0; i < alh_blob->alh_cfg.count; i++) { if (dai->host_dma_config[i]->stream_id == dai->dai_index) { @@ -115,9 +121,16 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void */ channel = 0; break; +#if ACE_VERSION > ACE_VERSION_1_5 + case SOF_DAI_INTEL_UAOL: + channel = 0; + if (dai->host_dma_config[0]->pre_allocated_by_host) + channel = dai->host_dma_config[0]->dma_channel_id; + break; +#endif default: /* other types of DAIs not handled for now */ - comp_err(dev, "dai_config_dma_channel(): Unknown dai type %d", dai->type); + comp_err(dev, "Unknown dai type %d", dai->type); channel = SOF_DMA_CHAN_INVALID; break; } @@ -129,12 +142,10 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) { struct ipc_config_dai *dai = &dd->ipc_config; struct ipc4_copier_module_cfg *copier_cfg = dd->dai_spec_config; -#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS struct dai *dai_p = dd->dai; -#endif if (!dai) { - comp_err(dev, "dai_data_config(): no dai!\n"); + comp_err(dev, "no dai!\n"); return -EINVAL; } @@ -143,7 +154,7 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { - comp_info(dev, "dai_data_config(): Component is in active state."); + comp_info(dev, "Component is in active state."); return 0; } @@ -160,12 +171,7 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) case SOF_DAI_INTEL_HDA: break; case SOF_DAI_INTEL_ALH: -#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS dd->stream_id = dai_get_stream_id(dai_p, dai->direction); -#else - /* only native Zephyr driver supported */ - return -EINVAL; -#endif /* SDW HW FIFO always requires 32bit MSB aligned sample data for * all formats, such as 8/16/24/32 bits. */ @@ -176,10 +182,12 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) comp_dbg(dev, "dai_data_config() SOF_DAI_INTEL_ALH dev->ipc_config.frame_fmt: %d, stream_id: %d", dev->ipc_config.frame_fmt, dd->stream_id); + break; + case SOF_DAI_INTEL_UAOL: break; default: /* other types of DAIs not handled for now */ - comp_warn(dev, "dai_data_config(): Unknown dai type %d", dai->type); + comp_warn(dev, "Unknown dai type %d", dai->type); return -EINVAL; } @@ -198,26 +206,28 @@ int ipc_comp_dai_config(struct ipc *ipc, struct ipc_config_dai *common_config, void dai_dma_release(struct dai_data *dd, struct comp_dev *dev) { + int ret; + /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { - comp_info(dev, "dai_config(): Component is in active state. Ignore resetting"); + comp_info(dev, "Component is in active state. Ignore resetting"); return; } /* put the allocated DMA channel first */ - if (dd->chan) { + if (dd->chan_index >= 0) { struct ipc4_llp_reading_slot slot; if (dd->slot_info.node_id) { - k_spinlock_key_t key; - /* reset llp position to 0 in memory window for reset state. */ memset_s(&slot, sizeof(slot), 0, sizeof(slot)); slot.node_id = dd->slot_info.node_id; - key = k_spin_lock(&sof_get()->fw_reg_lock); + ret = sys_mutex_lock(&llp_reading_slots_lock, K_FOREVER); + assert(!ret); mailbox_sw_regs_write(dd->slot_info.reg_offset, &slot, sizeof(slot)); - k_spin_unlock(&sof_get()->fw_reg_lock, key); + ret = sys_mutex_unlock(&llp_reading_slots_lock); + assert(!ret); } /* The stop sequnece of host driver is first pause and then reset @@ -225,24 +235,18 @@ void dai_dma_release(struct dai_data *dd, struct comp_dev *dev) * pause to stop. * TODO: refine power management when stream is paused */ -#if CONFIG_ZEPHYR_NATIVE_DRIVERS /* if reset is after pause dma has already been stopped */ - dma_stop(dd->chan->dma->z_dev, dd->chan->index); + sof_dma_stop(dd->dma, dd->chan_index); - dma_release_channel(dd->chan->dma->z_dev, dd->chan->index); -#else - dma_stop_legacy(dd->chan); - dma_channel_put_legacy(dd->chan); -#endif - dd->chan->dev_data = NULL; - dd->chan = NULL; + sof_dma_release_channel(dd->dma, dd->chan_index); + dd->chan_index = -EINVAL; } } void dai_release_llp_slot(struct dai_data *dd) { struct ipc4_llp_reading_slot slot; - k_spinlock_key_t key; + int ret; if (!dd->slot_info.node_id) return; @@ -250,9 +254,11 @@ void dai_release_llp_slot(struct dai_data *dd) memset_s(&slot, sizeof(slot), 0, sizeof(slot)); /* clear node id for released llp slot */ - key = k_spin_lock(&sof_get()->fw_reg_lock); + ret = sys_mutex_lock(&llp_reading_slots_lock, K_FOREVER); + assert(!ret); mailbox_sw_regs_write(dd->slot_info.reg_offset, &slot, sizeof(slot)); - k_spin_unlock(&sof_get()->fw_reg_lock, key); + ret = sys_mutex_unlock(&llp_reading_slots_lock); + assert(!ret); dd->slot_info.reg_offset = 0; dd->slot_info.node_id = 0; @@ -262,9 +268,9 @@ static int dai_get_unused_llp_slot(struct comp_dev *dev, union ipc4_connector_node_id *node) { struct ipc4_llp_reading_slot slot; - k_spinlock_key_t key; uint32_t max_slot; uint32_t offset; + int ret; int i; /* sdw with multiple gateways uses sndw_reading_slots */ @@ -276,7 +282,8 @@ static int dai_get_unused_llp_slot(struct comp_dev *dev, max_slot = IPC4_MAX_LLP_GPDMA_READING_SLOTS; } - key = k_spin_lock(&sof_get()->fw_reg_lock); + ret = sys_mutex_lock(&llp_reading_slots_lock, K_FOREVER); + assert(!ret); /* find unused llp slot offset with node_id of zero */ for (i = 0; i < max_slot; i++, offset += sizeof(slot)) { @@ -289,7 +296,8 @@ static int dai_get_unused_llp_slot(struct comp_dev *dev, if (i >= max_slot) { comp_err(dev, "can't find free slot"); - k_spin_unlock(&sof_get()->fw_reg_lock, key); + ret = sys_mutex_unlock(&llp_reading_slots_lock); + assert(!ret); return -EINVAL; } @@ -297,7 +305,8 @@ static int dai_get_unused_llp_slot(struct comp_dev *dev, slot.node_id = node->dw & IPC4_NODE_ID_MASK; mailbox_sw_regs_write(offset, &slot, sizeof(slot)); - k_spin_unlock(&sof_get()->fw_reg_lock, key); + ret = sys_mutex_unlock(&llp_reading_slots_lock); + assert(!ret); return offset; } @@ -331,30 +340,32 @@ static int dai_init_llp_info(struct dai_data *dd, struct comp_dev *dev) return 0; } -int dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai *common_config, - const void *spec_config) +__cold int dai_config(struct dai_data *dd, struct comp_dev *dev, + struct ipc_config_dai *common_config, const void *spec_config) { const struct ipc4_copier_module_cfg *copier_cfg = spec_config; int size; int ret; + assert_can_be_cold(); + /* ignore if message not for this DAI id/type */ if (dd->ipc_config.dai_index != common_config->dai_index || dd->ipc_config.type != common_config->type) return 0; - comp_info(dev, "dai_config() dai type = %d index = %d dd %p", + comp_info(dev, "dai type = %d index = %d dd %p", common_config->type, common_config->dai_index, dd); /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { - comp_info(dev, "dai_config(): Component is in active state. Ignore config"); + comp_info(dev, "Component is in active state. Ignore config"); return 0; } - if (dd->chan) { - comp_info(dev, "dai_config(): Configured. dma channel index %d, ignore...", - dd->chan->index); + if (dd->chan_index >= 0) { + comp_info(dev, "Configured. dma channel index %d, ignore...", + dd->chan_index); return 0; } @@ -375,15 +386,17 @@ int dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai /* allocated dai_config if not yet */ if (!dd->dai_spec_config) { size = sizeof(*copier_cfg); - dd->dai_spec_config = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, size); + dd->dai_spec_config = sof_heap_alloc(dd->alloc_ctx.heap, SOF_MEM_FLAG_USER, size, 0); if (!dd->dai_spec_config) { - comp_err(dev, "dai_config(): No memory for dai_config size %d", size); + comp_err(dev, "No memory for size %d", size); return -ENOMEM; } + memset(dd->dai_spec_config, 0, size); + ret = memcpy_s(dd->dai_spec_config, size, copier_cfg, size); if (ret < 0) { - rfree(dd->dai_spec_config); + sof_heap_free(dd->alloc_ctx.heap, dd->dai_spec_config); dd->dai_spec_config = NULL; return -EINVAL; } @@ -393,10 +406,13 @@ int dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai if (ret < 0) return ret; - return dai_set_config(dd->dai, common_config, copier_cfg->gtw_cfg.config_data); + /* gtw_cfg.config_length is in words */ + size = copier_cfg->gtw_cfg.config_length << 2; + + return dai_set_config(dd->dai, common_config, + copier_cfg->gtw_cfg.config_data, size); } -#if CONFIG_ZEPHYR_NATIVE_DRIVERS int dai_common_position(struct dai_data *dd, struct comp_dev *dev, struct sof_ipc_stream_posn *posn) { @@ -409,7 +425,7 @@ int dai_common_position(struct dai_data *dd, struct comp_dev *dev, platform_dai_wallclock(dev, &dd->wallclock); posn->wallclock = dd->wallclock; - ret = dma_get_status(dd->dma->z_dev, dd->chan->index, &status); + ret = dma_get_status(dd->dma->z_dev, dd->chan_index, &status); if (ret < 0) return ret; @@ -434,7 +450,7 @@ void dai_dma_position_update(struct dai_data *dd, struct comp_dev *dev) if (!dd->slot_info.node_id) return; - ret = dma_get_status(dd->dma->z_dev, dd->chan->index, &status); + ret = sof_dma_get_status(dd->dma, dd->chan_index, &status); if (ret < 0) return; @@ -448,51 +464,3 @@ void dai_dma_position_update(struct dai_data *dd, struct comp_dev *dev) mailbox_sw_regs_write(dd->slot_info.reg_offset, &slot, sizeof(slot)); } -#else -int dai_common_position(struct dai_data *dd, struct comp_dev *dev, - struct sof_ipc_stream_posn *posn) -{ - struct dma_chan_status status; - - /* total processed bytes count */ - posn->dai_posn = dd->total_data_processed; - - platform_dai_wallclock(dev, &dd->wallclock); - posn->wallclock = dd->wallclock; - - status.ipc_posn_data = &posn->comp_posn; - dma_status_legacy(dd->chan, &status, dev->direction); - - return 0; -} - -int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) -{ - struct dai_data *dd = comp_get_drvdata(dev); - - return dai_common_position(dd, dev, posn); -} - -void dai_dma_position_update(struct dai_data *dd, struct comp_dev *dev) -{ - struct ipc4_llp_reading_slot slot; - struct dma_chan_status status; - uint32_t llp_data[2]; - - if (!dd->slot_info.node_id) - return; - - status.ipc_posn_data = llp_data; - dma_status_legacy(dd->chan, &status, dev->direction); - - platform_dai_wallclock(dev, &dd->wallclock); - - slot.node_id = dd->slot_info.node_id; - slot.reading.llp_l = llp_data[0]; - slot.reading.llp_u = llp_data[1]; - slot.reading.wclk_l = (uint32_t)dd->wallclock; - slot.reading.wclk_u = (uint32_t)(dd->wallclock >> 32); - - mailbox_sw_regs_write(dd->slot_info.reg_offset, &slot, sizeof(slot)); -} -#endif diff --git a/src/ipc/ipc4/handler-kernel.c b/src/ipc/ipc4/handler-kernel.c new file mode 100644 index 000000000000..d7d9f417806a --- /dev/null +++ b/src/ipc/ipc4/handler-kernel.c @@ -0,0 +1,660 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2021 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// Author: Rander Wang <rander.wang@linux.intel.com> +/* + * IPC (InterProcessor Communication) provides a method of two way + * communication between the host processor and the DSP. The IPC used here + * utilises a shared mailbox and door bell between the host and DSP. + * + */ + +#include <sof/audio/buffer.h> +#include <sof/audio/component_ext.h> +#include <sof/audio/pipeline.h> +#include <sof/common.h> +#include <sof/ipc/topology.h> +#include <sof/ipc/common.h> +#include <sof/ipc/msg.h> +#include <sof/ipc/driver.h> +#include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <sof/lib/pm_runtime.h> +#include <sof/llext_manager.h> +#include <sof/math/numbers.h> +#include <sof/tlv.h> +#include <sof/trace/trace.h> +#include <ipc4/error_status.h> +#include <ipc/header.h> +#include <ipc4/module.h> +#include <ipc4/pipeline.h> +#include <ipc4/notification.h> +#include <ipc4/handler.h> +#include <ipc/trace.h> +#include <user/trace.h> + +#include <rtos/atomic.h> +#include <rtos/kernel.h> +#include <rtos/string.h> +#include <sof/lib_manager.h> + +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include "../audio/copier/ipcgtw_copier.h" + +/* Command format errors during fuzzing are reported for virtually all + * commands, and the resulting flood of logging becomes a severe + * performance penalty (i.e. we get a lot less fuzzing done per CPU + * cycle). + */ +#ifdef CONFIG_ARCH_POSIX_LIBFUZZER +#define ipc_cmd_err(...) +#else +#define ipc_cmd_err(...) tr_err(__VA_ARGS__) +#endif + +LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); + +struct ipc4_msg_data { + struct ipc_cmd_hdr msg_in; /* local copy of current message from host header */ + struct ipc_cmd_hdr msg_out; /* local copy of current message to host header */ + atomic_t delayed_reply; + uint32_t delayed_error; +}; + +static struct ipc4_msg_data msg_data; + +/* fw sends a fw ipc message to send the status of the last host ipc message */ +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(); + int ret; + + /* copy the extension from the message reply */ + reply->extension.dat = msg_reply.extension; + ret = memcpy_s(ipc->comp_data, sizeof(*reply), reply, sizeof(*reply)); + assert(!ret); +} +#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); +} + +#endif + +__cold static bool is_any_ppl_active(void) +{ + struct ipc_comp_dev *icd; + struct list_item *clist; + + assert_can_be_cold(); + + list_for_item(clist, &ipc_get()->comp_list) { + icd = container_of(clist, struct ipc_comp_dev, list); + if (icd->type != COMP_TYPE_PIPELINE) + continue; + + if (icd->pipeline->status == COMP_STATE_ACTIVE) + return true; + } + + return false; +} + +void ipc_compound_pre_start(int msg_id) +{ + /* ipc thread will wait for all scheduled tasks to be complete + * Use a reference count to check status of these tasks. + */ + atomic_add(&msg_data.delayed_reply, 1); +} + +void ipc_compound_post_start(uint32_t msg_id, int ret, bool delayed) +{ + if (ret) { + ipc_cmd_err(&ipc_tr, "failed to process msg %d status %d", msg_id, ret); + atomic_set(&msg_data.delayed_reply, 0); + return; + } + + /* decrease counter if it is not scheduled by another thread */ + if (!delayed) + atomic_sub(&msg_data.delayed_reply, 1); +} + +void ipc_compound_msg_done(uint32_t msg_id, int error) +{ + if (!atomic_read(&msg_data.delayed_reply)) { + ipc_cmd_err(&ipc_tr, "unexpected delayed reply"); + return; + } + + atomic_sub(&msg_data.delayed_reply, 1); + + /* error reported in delayed pipeline task */ + if (error < 0) { + if (msg_id == SOF_IPC4_GLB_SET_PIPELINE_STATE) + msg_data.delayed_error = IPC4_PIPELINE_STATE_NOT_SET; + } +} + +#if CONFIG_LIBRARY +/* There is no parallel execution in testbench for scheduler and pipelines, so the result would + * be always IPC4_FAILURE. Therefore the compound messages handling is simplified. The pipeline + * triggers will require an explicit scheduler call to get the components to desired state. + */ +int ipc_wait_for_compound_msg(void) +{ + atomic_set(&msg_data.delayed_reply, 0); + return IPC4_SUCCESS; +} +#else +int ipc_wait_for_compound_msg(void) +{ + int try_count = 30; + + while (atomic_read(&msg_data.delayed_reply)) { + k_sleep(Z_TIMEOUT_US(250)); + + if (!try_count--) { + atomic_set(&msg_data.delayed_reply, 0); + ipc_cmd_err(&ipc_tr, "ipc4: failed to wait schedule thread"); + return IPC4_FAILURE; + } + } + + return IPC4_SUCCESS; +} +#endif + +#if CONFIG_LIBRARY_MANAGER +__cold static int ipc4_load_library(struct ipc4_message_request *ipc4) +{ + struct ipc4_module_load_library library; + int ret; + + assert_can_be_cold(); + + library.header.dat = ipc4->primary.dat; + + ret = lib_manager_load_library(library.header.r.dma_id, library.header.r.lib_id, + ipc4->primary.r.type); + if (ret != 0) + return (ret == -EINVAL) ? IPC4_ERROR_INVALID_PARAM : IPC4_FAILURE; + + return IPC4_SUCCESS; +} +#endif + +static int ipc4_process_glb_message(struct ipc4_message_request *ipc4) +{ + uint32_t type; + int ret; + + type = ipc4->primary.r.type; + + switch (type) { + + /* Loads library (using Code Load or HD/A Host Output DMA) */ +#ifdef CONFIG_LIBRARY_MANAGER + case SOF_IPC4_GLB_LOAD_LIBRARY: + ret = ipc4_load_library(ipc4); + break; + case SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE: + ret = ipc4_load_library(ipc4); + break; +#endif + /* not a kernel level IPC message */ + default: + /* try and handle as a user IPC message */ + ret = ipc4_user_process_glb_message(ipc4, &msg_reply); + break; + } + + return ret; +} + +/* disable power gating on core 0 */ +__cold static int ipc4_module_process_d0ix(struct ipc4_message_request *ipc4) +{ + struct ipc4_module_set_d0ix d0ix; + uint32_t module_id, instance_id; + + assert_can_be_cold(); + + int ret = memcpy_s(&d0ix, sizeof(d0ix), ipc4, sizeof(*ipc4)); + + if (ret < 0) + return IPC4_FAILURE; + + module_id = d0ix.primary.r.module_id; + instance_id = d0ix.primary.r.instance_id; + + tr_dbg(&ipc_tr, "%x : %x", module_id, instance_id); + + /* only module 0 can be used to set d0ix state */ + if (d0ix.primary.r.module_id || d0ix.primary.r.instance_id) { + ipc_cmd_err(&ipc_tr, "invalid resource id %x : %x", module_id, instance_id); + return IPC4_INVALID_RESOURCE_ID; + } + + if (d0ix.extension.r.prevent_power_gating) + pm_runtime_disable(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID); + else + pm_runtime_enable(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID); + + return 0; +} + +/* enable/disable cores according to the state mask */ +__cold static int ipc4_module_process_dx(struct ipc4_message_request *ipc4) +{ + struct ipc4_module_set_dx dx; + struct ipc4_dx_state_info dx_info; + uint32_t module_id, instance_id; + uint32_t core_id; + + assert_can_be_cold(); + + int ret = memcpy_s(&dx, sizeof(dx), ipc4, sizeof(*ipc4)); + + if (ret < 0) + return IPC4_FAILURE; + + module_id = dx.primary.r.module_id; + instance_id = dx.primary.r.instance_id; + + /* only module 0 can be used to set dx state */ + if (module_id || instance_id) { + ipc_cmd_err(&ipc_tr, "invalid resource id %x : %x", module_id, instance_id); + return IPC4_INVALID_RESOURCE_ID; + } + + dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, + sizeof(dx_info)); + ret = memcpy_s(&dx_info, sizeof(dx_info), + (const void *)MAILBOX_HOSTBOX_BASE, sizeof(dx_info)); + if (ret < 0) + return IPC4_FAILURE; + + /* check if core enable mask is valid */ + if (dx_info.core_mask > MASK(CONFIG_CORE_COUNT - 1, 0)) { + ipc_cmd_err(&ipc_tr, "CONFIG_CORE_COUNT: %d < core enable mask: %d", + CONFIG_CORE_COUNT, dx_info.core_mask); + return IPC4_ERROR_INVALID_PARAM; + } + + /* check primary core first */ + if ((dx_info.core_mask & BIT(PLATFORM_PRIMARY_CORE_ID)) && + (dx_info.dx_mask & BIT(PLATFORM_PRIMARY_CORE_ID))) { + /* core0 can't be activated more, it's already active since we got here */ + ipc_cmd_err(&ipc_tr, "Core0 is already active"); + return IPC4_BAD_STATE; + } + + /* Activate/deactivate requested cores */ + for (core_id = 1; core_id < CONFIG_CORE_COUNT; core_id++) { + if ((dx_info.core_mask & BIT(core_id)) == 0) + continue; + + if (dx_info.dx_mask & BIT(core_id)) { + ret = cpu_enable_core(core_id); + if (ret != 0) { + ipc_cmd_err(&ipc_tr, "failed to enable core %d", core_id); + return IPC4_FAILURE; + } + } else { + cpu_disable_core(core_id); + if (cpu_is_core_enabled(core_id)) { + ipc_cmd_err(&ipc_tr, "failed to disable core %d", core_id); + return IPC4_FAILURE; + } + } + } + + /* Deactivating primary core if requested. */ + if (dx_info.core_mask & BIT(PLATFORM_PRIMARY_CORE_ID)) { + if (cpu_enabled_cores() & ~BIT(PLATFORM_PRIMARY_CORE_ID)) { + ipc_cmd_err(&ipc_tr, "secondary cores 0x%x still active", + cpu_enabled_cores()); + return IPC4_BUSY; + } + + if (is_any_ppl_active()) { + ipc_cmd_err(&ipc_tr, "some pipelines are still active"); + return IPC4_BUSY; + } + +#if !CONFIG_ADSP_IMR_CONTEXT_SAVE + ret = llext_manager_store_to_dram(); + if (ret < 0) + ipc_cmd_err(&ipc_tr, "Error %d saving LLEXT context. Resume might fail.", + ret); + +#if CONFIG_L3_HEAP + l3_heap_save(); +#endif +#endif + +#if defined(CONFIG_PM) + ipc_get()->task_mask |= IPC_TASK_POWERDOWN; +#endif + /* do platform specific suspending */ + platform_context_save(sof_get()); + +#if !defined(CONFIG_LIBRARY) && !defined(CONFIG_ZEPHYR_NATIVE_DRIVERS) + arch_irq_lock(); + platform_timer_stop(timer_get()); +#endif + ipc_get()->pm_prepare_D3 = 1; + } + + return IPC4_SUCCESS; +} + +__cold static int ipc4_process_module_message(struct ipc4_message_request *ipc4) +{ + uint32_t type; + int ret; + + assert_can_be_cold(); + + type = ipc4->primary.r.type; + + switch (type) { + case SOF_IPC4_MOD_SET_D0IX: + ret = ipc4_module_process_d0ix(ipc4); + break; + case SOF_IPC4_MOD_SET_DX: + ret = ipc4_module_process_dx(ipc4); + break; + default: + /* try and handle as a user IPC message */ + ret = ipc4_user_process_module_message(ipc4, &msg_reply); + break; + } + + return ret; +} + +__cold struct ipc_cmd_hdr *mailbox_validate(void) +{ + struct ipc_cmd_hdr *hdr = ipc_get()->comp_data; + + assert_can_be_cold(); + + return hdr; +} + +struct ipc_cmd_hdr *ipc_compact_read_msg(void) +{ + int words; + + words = ipc_platform_compact_read_msg(&msg_data.msg_in, 2); + if (!words) + return mailbox_validate(); + + return &msg_data.msg_in; +} + +struct ipc_cmd_hdr *ipc_prepare_to_send(const struct ipc_msg *msg) +{ + msg_data.msg_out.pri = msg->header; + msg_data.msg_out.ext = msg->extension; + + if (msg->tx_size) + mailbox_dspbox_write(0, (uint32_t *)msg->tx_data, msg->tx_size); + + return &msg_data.msg_out; +} + +__cold void ipc_boot_complete_msg(struct ipc_cmd_hdr *header, uint32_t data) +{ + assert_can_be_cold(); + + header->pri = SOF_IPC4_FW_READY; + header->ext = 0; +} + +#if defined(CONFIG_PM_DEVICE) && defined(CONFIG_INTEL_ADSP_IPC) +__cold void ipc_send_failed_power_transition_response(void) +{ + struct ipc4_message_request *request = ipc_from_hdr(&msg_data.msg_in); + struct ipc4_message_reply response; + + assert_can_be_cold(); + + response.primary.r.status = IPC4_POWER_TRANSITION_FAILED; + response.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REPLY; + response.primary.r.msg_tgt = request->primary.r.msg_tgt; + response.primary.r.type = request->primary.r.type; + + msg_reply.header = response.primary.dat; + list_init(&msg_reply.list); + + ipc_msg_send_direct(&msg_reply, NULL); +} +#endif /* defined(CONFIG_PM_DEVICE) && defined(CONFIG_INTEL_ADSP_IPC) */ + +__cold void ipc_send_panic_notification(void) +{ + assert_can_be_cold(); + + msg_notify.header = SOF_IPC4_NOTIF_HEADER(SOF_IPC4_EXCEPTION_CAUGHT); + msg_notify.extension = cpu_get_id(); + msg_notify.tx_size = 0; + msg_notify.tx_data = NULL; + list_init(&msg_notify.list); + + ipc_msg_send_direct(&msg_notify, NULL); +} + +#ifdef CONFIG_LOG_BACKEND_ADSP_MTRACE + +static bool is_notification_queued(struct ipc_msg *msg) +{ + struct ipc *ipc = ipc_get(); + k_spinlock_key_t key; + bool queued = false; + + key = k_spin_lock(&ipc->lock); + if (!list_is_empty(&msg->list)) + queued = true; + k_spin_unlock(&ipc->lock, key); + + return queued; +} + +/* Called from ipc_send_buffer_status_notify(), which is currently "hot" */ +void ipc_send_buffer_status_notify(void) +{ + /* a single msg_notify object is used */ + if (is_notification_queued(&msg_notify)) + return; + + msg_notify.header = SOF_IPC4_NOTIF_HEADER(SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS); + msg_notify.extension = 0; + msg_notify.tx_size = 0; + + tr_dbg(&ipc_tr, "tx-notify\t: %#x|%#x", msg_notify.header, msg_notify.extension); + + ipc_msg_send(&msg_notify, NULL, true); +} +#endif + +void ipc_msg_reply(struct sof_ipc_reply *reply) +{ + struct ipc4_message_request in; + + in.primary.dat = msg_data.msg_in.pri; + ipc_compound_msg_done(in.primary.r.type, reply->error); +} + +void ipc_cmd(struct ipc_cmd_hdr *_hdr) +{ + struct ipc4_message_request *in = ipc4_get_message_request(); + enum ipc4_message_target target; +#ifdef CONFIG_DEBUG_IPC_TIMINGS + struct ipc4_message_request req; + uint64_t tstamp; +#endif + int err; + +#ifdef CONFIG_DEBUG_IPC_TIMINGS + req = *in; + tstamp = sof_cycle_get_64(); +#else + if (cpu_is_primary(cpu_get_id())) + tr_info(&ipc_tr, "rx\t: %#x|%#x", in->primary.dat, in->extension.dat); +#endif + /* no process on scheduled thread */ + atomic_set(&msg_data.delayed_reply, 0); + msg_data.delayed_error = 0; + msg_reply.tx_data = NULL; + msg_reply.tx_size = 0; + msg_reply.header = in->primary.dat; + msg_reply.extension = in->extension.dat; + + target = in->primary.r.msg_tgt; + + switch (target) { + case SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG: + err = ipc4_process_glb_message(in); + if (err) + ipc_cmd_err(&ipc_tr, "ipc4: FW_GEN_MSG failed with err %d", err); + break; + case SOF_IPC4_MESSAGE_TARGET_MODULE_MSG: + err = ipc4_process_module_message(in); + if (err) + ipc_cmd_err(&ipc_tr, "ipc4: MODULE_MSG failed with err %d", err); + break; + default: + /* should not reach here as we only have 2 message types */ + ipc_cmd_err(&ipc_tr, "ipc4: invalid target %d", target); + err = IPC4_UNKNOWN_MESSAGE_TYPE; + } + + /* 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(); + struct ipc4_message_reply reply = {{0}}; + + /* Process flow and time stamp for IPC4 msg processed on secondary core : + * core 0 (primary core) core x (secondary core) + * # IPC msg thread #IPC delayed worker #core x idc thread + * ipc_task_ops.run() + * ipc_do_cmd() + * msg_reply.header = in->primary.dat + * ipc4_process_on_core(x) + * mask |= SECONDARY_CORE + * idc_send_message() + * Case 1: + * // Ipc msg processed by secondary core idc_ipc() + * if ((mask & SECONDARY_CORE)) ipc_cmd() + * return; ipc_msg_send() + * mask &= ~SECONDARY_CORE + * + * ipc_platform_send_msg + * ---------------------------------------------------------------------------- + * Case 2: + * idc_ipc() + * ipc_cmd() + * //Prepare reply msg + * msg_reply.header = + * reply.primary.dat; + * ipc_msg_send() + * mask &= ~SECONDARY_CORE + * + * if ((mask & IPC_TASK_SECONDARY_CORE)) + * return; + * // Ipc reply msg was prepared, so return + * if (msg_reply.header != in->primary.dat) + * return; + * ipc_platform_send_msg + * ---------------------------------------------------------------------------- + * Case 3: + * idc_ipc() + * ipc_cmd() + * //Prepare reply msg + * msg_reply.header = + * reply.primary.dat; + * ipc_msg_send() + * mask &= ~SECONDARY_CORE + * + * ipc_platform_send_msg + * + * if ((mask & IPC_TASK_SECONDARY_CORE)) + * return; + * // Ipc reply msg was prepared, so return + * if (msg_reply.header != in->primary.dat) + * return; + */ + + /* Reply prepared by secondary core */ + if ((ipc->task_mask & IPC_TASK_SECONDARY_CORE) && cpu_is_primary(cpu_get_id())) + return; + /* Reply has been prepared by secondary core */ + if (msg_reply.header != in->primary.dat) + return; + + /* Do not send reply for SET_DX if we are going to enter D3 + * The reply is going to be sent as part of the power down + * sequence + */ + if (ipc->task_mask & IPC_TASK_POWERDOWN) + return; + + if (ipc_wait_for_compound_msg() != 0) { + ipc_cmd_err(&ipc_tr, "ipc4: failed to send delayed reply"); + err = IPC4_FAILURE; + } + + /* copy contents of message received */ + reply.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REPLY; + reply.primary.r.msg_tgt = in->primary.r.msg_tgt; + reply.primary.r.type = in->primary.r.type; + if (msg_data.delayed_error) + reply.primary.r.status = msg_data.delayed_error; + else + reply.primary.r.status = err; + + msg_reply.header = reply.primary.dat; + +#ifdef CONFIG_DEBUG_IPC_TIMINGS + tr_info(&ipc_tr, "tx-reply\t: %#x|%#x to %#x|%#x in %llu us", msg_reply.header, + msg_reply.extension, req.primary.dat, req.extension.dat, + k_cyc_to_us_near64(sof_cycle_get_64() - tstamp)); +#else + tr_dbg(&ipc_tr, "tx-reply\t: %#x|%#x", msg_reply.header, + msg_reply.extension); +#endif + ipc4_send_reply(&reply); + } +} diff --git a/src/ipc/ipc4/handler-user.c b/src/ipc/ipc4/handler-user.c new file mode 100644 index 000000000000..48131f2f6aae --- /dev/null +++ b/src/ipc/ipc4/handler-user.c @@ -0,0 +1,1334 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2021 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// Author: Rander Wang <rander.wang@linux.intel.com> +/* + * IPC (InterProcessor Communication) provides a method of two way + * communication between the host processor and the DSP. The IPC used here + * utilises a shared mailbox and door bell between the host and DSP. + * + */ + +#include <sof/audio/buffer.h> +#include <sof/audio/component_ext.h> +#include <sof/audio/pipeline.h> +#include <sof/common.h> +#include <sof/ipc/topology.h> +#include <sof/ipc/common.h> +#include <sof/ipc/msg.h> +#include <sof/ipc/driver.h> +#include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <sof/lib/pm_runtime.h> +#include <sof/llext_manager.h> +#include <sof/math/numbers.h> +#include <sof/tlv.h> +#include <sof/trace/trace.h> +#include <ipc4/error_status.h> +#include <ipc/header.h> +#include <ipc4/module.h> +#include <ipc4/pipeline.h> +#include <ipc4/notification.h> +#include <ipc4/handler.h> +#include <ipc/trace.h> +#include <user/trace.h> + +#include <rtos/atomic.h> +#include <rtos/kernel.h> +#include <sof/lib_manager.h> + +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include "../audio/copier/ipcgtw_copier.h" + +/* Command format errors during fuzzing are reported for virtually all + * commands, and the resulting flood of logging becomes a severe + * performance penalty (i.e. we get a lot less fuzzing done per CPU + * cycle). + */ +#ifdef CONFIG_ARCH_POSIX_LIBFUZZER +#define ipc_cmd_err(...) +#else +#define ipc_cmd_err(...) tr_err(__VA_ARGS__) +#endif + +LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); + +/* Userspace message context, copied in/out by kernel IPC thread. */ +/* fw sends a fw ipc message to send the status of the last host ipc message */ +static struct ipc_msg *msg_reply; + +#if CONFIG_LIBRARY + +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 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. + */ +__cold static int ipc4_new_pipeline(struct ipc4_message_request *ipc4) +{ + struct ipc *ipc = ipc_get(); + + assert_can_be_cold(); + + return ipc_pipeline_new(ipc, (ipc_pipe_new *)ipc4); +} + +__cold static int ipc4_delete_pipeline(struct ipc4_message_request *ipc4) +{ + struct ipc4_pipeline_delete *pipe; + struct ipc *ipc = ipc_get(); + + assert_can_be_cold(); + + pipe = (struct ipc4_pipeline_delete *)ipc4; + tr_dbg(&ipc_tr, "ipc4 delete pipeline %x:", (uint32_t)pipe->primary.r.instance_id); + + return ipc_pipeline_free(ipc, pipe->primary.r.instance_id); +} + +static int ipc4_pcm_params(struct ipc_comp_dev *pcm_dev) +{ + int err, reset_err; + + /* sanity check comp */ + if (!pcm_dev->cd->pipeline) { + ipc_cmd_err(&ipc_tr, "ipc: comp %d pipeline not found", pcm_dev->id); + return -EINVAL; + } + + /* prepare pipeline audio params */ + err = pipeline_prepare(pcm_dev->cd->pipeline, pcm_dev->cd); + if (err < 0) { + ipc_cmd_err(&ipc_tr, "ipc: pipe %d comp %d prepare failed %d", + pcm_dev->cd->pipeline->pipeline_id, + pcm_dev->cd->pipeline->comp_id, err); + goto error; + } + + return 0; + +error: + reset_err = pipeline_reset(pcm_dev->cd->pipeline, pcm_dev->cd); + if (reset_err < 0) + ipc_cmd_err(&ipc_tr, "ipc: pipe %d comp %d reset failed %d", + pcm_dev->cd->pipeline->pipeline_id, + pcm_dev->cd->pipeline->comp_id, reset_err); + + return err; +} + +static struct ipc_comp_dev *pipeline_get_host_dev(struct ipc_comp_dev *ppl_icd) +{ + struct ipc_comp_dev *host_dev; + struct ipc *ipc = ipc_get(); + int host_id; + + if (!ppl_icd->pipeline->source_comp || !ppl_icd->pipeline->sink_comp) { + ipc_cmd_err(&ipc_tr, "pipeline %d: source/sink comp freed", ppl_icd->id); + return NULL; + } + + /* If the source component's direction is not set but the sink's direction is, + * this block will copy the direction from the sink to the source component and + * mark the source's direction as set. + */ + if (!ppl_icd->pipeline->source_comp->direction_set && + ppl_icd->pipeline->sink_comp->direction_set) { + ppl_icd->pipeline->source_comp->direction = + ppl_icd->pipeline->sink_comp->direction; + ppl_icd->pipeline->source_comp->direction_set = true; + } + + /* If the sink component's direction is not set but the source's direction is, + * this block will copy the direction from the source to the sink component and + * mark the sink's direction as set. + */ + if (!ppl_icd->pipeline->sink_comp->direction_set && + ppl_icd->pipeline->source_comp->direction_set) { + ppl_icd->pipeline->sink_comp->direction = + ppl_icd->pipeline->source_comp->direction; + ppl_icd->pipeline->sink_comp->direction_set = true; + } + + if (ppl_icd->pipeline->source_comp->direction == SOF_IPC_STREAM_PLAYBACK) + host_id = ppl_icd->pipeline->source_comp->ipc_config.id; + else + host_id = ppl_icd->pipeline->sink_comp->ipc_config.id; + + host_dev = ipc_get_comp_by_id(ipc, host_id); + if (!host_dev) + ipc_cmd_err(&ipc_tr, "comp host with ID %d not found", host_id); + + return host_dev; +} + +/* Ipc4 pipeline message <------> ipc3 pipeline message + * RUNNING <-------> TRIGGER START + * INIT + PAUSED <-------> PIPELINE COMPLETE + * INIT + RESET <-------> PIPELINE COMPLETE + * PAUSED <-------> TRIGGER_PAUSE + * RESET <-------> TRIGGER_STOP + RESET + * EOS(end of stream) <-------> NOT SUPPORTED YET + * + * IPC4 pipeline state machine + * + * INIT + * | \ + * | __\| + * | + * | RESET + * | _ _ + * | /| |\ + * | / /\ + * \|/ |/_ / \ + * RUNNING <--> PAUSE _ / \ + * / \ /|\ |\ / \ + * / \ | \/ \ + * / \ | /\ \ + * / \ | / \ \ + * |/_ _\| | / \ _\| + * ERROR Stop EOS |______\ SAVE + * / + */ + +int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd) +{ + struct ipc_comp_dev *host = NULL; + struct ipc *ipc = ipc_get(); + int status; + int ret = 0; + + status = ppl_icd->pipeline->status; + tr_dbg(&ipc_tr, "pipeline %d: initial state: %d, cmd: %d", ppl_icd->id, + status, cmd); + + switch (cmd) { + case SOF_IPC4_PIPELINE_STATE_RUNNING: + if (ppl_icd->pipeline->expect_eos) { + ipc_cmd_err(&ipc_tr, "pipeline %d: Can't transition from EOS to RUNNING", + ppl_icd->id); + return IPC4_INVALID_REQUEST; + } + + /* init params when pipeline is complete or reset */ + switch (status) { + case COMP_STATE_ACTIVE: + case COMP_STATE_PAUSED: + /* No action needed */ + break; + case COMP_STATE_READY: + host = pipeline_get_host_dev(ppl_icd); + if (!host) + return IPC4_INVALID_RESOURCE_ID; + + tr_dbg(&ipc_tr, "pipeline %d: set params", ppl_icd->id); + ret = ipc4_pcm_params(host); + break; + default: + ipc_cmd_err(&ipc_tr, + "pipeline %d: Invalid state for RUNNING: %d", + ppl_icd->id, status); + return IPC4_INVALID_REQUEST; + } + break; + case SOF_IPC4_PIPELINE_STATE_RESET: + 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, cmd); + break; + case COMP_STATE_READY: + case COMP_STATE_ACTIVE: + case COMP_STATE_PAUSED: + /* No action needed */ + break; + default: + ipc_cmd_err(&ipc_tr, + "pipeline %d: Invalid state for RESET: %d", + ppl_icd->id, status); + return IPC4_INVALID_REQUEST; + } + + break; + case SOF_IPC4_PIPELINE_STATE_PAUSED: + 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, cmd); + break; + default: + /* No action needed */ + break; + } + + break; + case SOF_IPC4_PIPELINE_STATE_EOS: + if (status != COMP_STATE_ACTIVE) { + ipc_cmd_err(&ipc_tr, "pipeline %d: Invalid state for EOS: %d", + ppl_icd->id, status); + return IPC4_INVALID_REQUEST; + } + ppl_icd->pipeline->expect_eos = true; + return 0; /* Must return here. Any other transition clears expect_eos. */ + /* special case - TODO */ + case SOF_IPC4_PIPELINE_STATE_SAVED: + case SOF_IPC4_PIPELINE_STATE_ERROR_STOP: + default: + ipc_cmd_err(&ipc_tr, "pipeline %d: unsupported trigger cmd: %d", + ppl_icd->id, cmd); + return IPC4_INVALID_REQUEST; + } + + if (ret < 0) + return IPC4_INVALID_REQUEST; + + ppl_icd->pipeline->expect_eos = false; + + return ret; +} + +int ipc4_pipeline_trigger(struct ipc_comp_dev *ppl_icd, uint32_t cmd, bool *delayed) +{ + struct ipc_comp_dev *host; + int status; + int ret; + + status = ppl_icd->pipeline->status; + tr_dbg(&ipc_tr, "pipeline %d: initial state: %d, cmd: %d", ppl_icd->id, + status, cmd); + + if (status == COMP_STATE_INIT) + return 0; + + host = pipeline_get_host_dev(ppl_icd); + if (!host) + return IPC4_INVALID_RESOURCE_ID; + + switch (cmd) { + case SOF_IPC4_PIPELINE_STATE_RUNNING: + /* init params when pipeline is complete or reset */ + switch (status) { + case COMP_STATE_ACTIVE: + /* nothing to do if the pipeline is already running */ + return 0; + case COMP_STATE_READY: + case COMP_STATE_PREPARE: + cmd = COMP_TRIGGER_PRE_START; + break; + case COMP_STATE_PAUSED: + cmd = COMP_TRIGGER_PRE_RELEASE; + break; + default: + ipc_cmd_err(&ipc_tr, + "pipeline %d: Invalid state for RUNNING: %d", + ppl_icd->id, status); + return IPC4_INVALID_REQUEST; + } + break; + case SOF_IPC4_PIPELINE_STATE_RESET: + switch (status) { + case COMP_STATE_ACTIVE: + case COMP_STATE_PAUSED: + cmd = COMP_TRIGGER_STOP; + break; + default: + return 0; + } + break; + case SOF_IPC4_PIPELINE_STATE_PAUSED: + switch (status) { + case COMP_STATE_INIT: + case COMP_STATE_READY: + case COMP_STATE_PAUSED: + return 0; + default: + cmd = COMP_TRIGGER_PAUSE; + break; + } + + break; + case SOF_IPC4_PIPELINE_STATE_EOS: + /* EOS handled in ipc4_pipeline_prepare */ + return 0; + default: + ipc_cmd_err(&ipc_tr, "pipeline %d: unsupported trigger cmd: %d", + ppl_icd->id, cmd); + return IPC4_INVALID_REQUEST; + } + + /* + * We're handling a pipeline-trigger event, this means that we're in a + * performance-critical context. Set a marker, so that if any cold code, + * calling assert_can_be_cold() is called on this flow between the + * mem_hot_path_start_watching() - mem_hot_path_stop_watching() + * brackets, the latter will generate an error / trigger a panic. + */ + dbg_path_hot_confirm(); + + /* trigger the component */ + ret = pipeline_trigger(host->cd->pipeline, host->cd, cmd); + if (ret < 0) { + ipc_cmd_err(&ipc_tr, "pipeline %d: trigger cmd %d failed with: %d", + ppl_icd->id, cmd, ret); + ret = IPC4_PIPELINE_STATE_NOT_SET; + } else if (ret == PPL_STATUS_SCHEDULED) { + tr_dbg(&ipc_tr, "pipeline %d: trigger cmd %d is delayed", + ppl_icd->id, cmd); + *delayed = true; + ret = 0; + } else if (cmd == COMP_TRIGGER_STOP) { + /* + * reset the pipeline components if STOP trigger is executed in + * the same thread. + * Otherwise, the pipeline will be reset after the STOP trigger + * has finished executing in the pipeline task. + */ + ret = pipeline_reset(host->cd->pipeline, host->cd); + if (ret < 0) + ret = IPC4_INVALID_REQUEST; + } + + return ret; +} + +__cold const struct ipc4_pipeline_set_state_data *ipc4_get_pipeline_data_wrapper(void) +{ + assert_can_be_cold(); + + return ipc4_get_pipeline_data(); +} + +/* Entry point for ipc4_pipeline_trigger(), therefore cannot be cold */ +static int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) +{ + const struct ipc4_pipeline_set_state_data *ppl_data; + struct ipc4_pipeline_set_state state; + struct ipc_comp_dev *ppl_icd; + struct ipc *ipc = ipc_get(); + uint32_t cmd, ppl_count; + uint32_t id = 0; + const uint32_t *ppl_id; + bool use_idc = false; + uint32_t idx; + int ret = 0; + int i; + + state.primary.dat = ipc4->primary.dat; + state.extension.dat = ipc4->extension.dat; + cmd = state.primary.r.ppl_state; + ppl_data = ipc4_get_pipeline_data(); + + if (state.extension.r.multi_ppl) { + ppl_count = ppl_data->pipelines_count; + /* + * pipelines_count is read straight from the host-provided + * mailbox payload, so cap it at what the mailbox can + * physically hold. Anything larger means the host promised + * more ppl_id[] entries than fit in MAILBOX_HOSTBOX, and + * dereferencing the flex array would read out of bounds. + */ + if (ppl_count > (MAILBOX_HOSTBOX_SIZE - + sizeof(struct ipc4_pipeline_set_state_data)) / + sizeof(uint32_t)) { + ipc_cmd_err(&ipc_tr, + "ipc: pipelines_count %u exceeds mailbox bound", + ppl_count); + return IPC4_ERROR_INVALID_PARAM; + } + ppl_id = ppl_data->ppl_id; + dcache_invalidate_region((__sparse_force void __sparse_cache *)ppl_id, + sizeof(int) * ppl_count); + } else { + ppl_count = 1; + id = state.primary.r.ppl_id; + ppl_id = &id; + } + + for (i = 0; i < ppl_count; i++) { + ppl_icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, + ppl_id[i], IPC_COMP_IGNORE_REMOTE); + if (!ppl_icd) { + tr_err(&ipc_tr, "ipc: comp %d not found", ppl_id[i]); + return IPC4_INVALID_RESOURCE_ID; + } + + if (i) { + if (ppl_icd->core != idx) + use_idc = true; + } else { + idx = ppl_icd->core; + } + } + + /* Run the prepare phase on the pipelines */ + for (i = 0; i < ppl_count; i++) { + ppl_icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, + ppl_id[i], IPC_COMP_IGNORE_REMOTE); + if (!ppl_icd) { + ipc_cmd_err(&ipc_tr, "ipc: comp %d not found", ppl_id[i]); + return IPC4_INVALID_RESOURCE_ID; + } + + /* Pass IPC to target core + * or use idc if more than one core used + */ + if (!cpu_is_me(ppl_icd->core)) { + if (use_idc) { + struct idc_msg msg = { IDC_MSG_PPL_STATE, + IDC_MSG_PPL_STATE_EXT(ppl_id[i], + IDC_PPL_STATE_PHASE_PREPARE), + ppl_icd->core, + sizeof(cmd), &cmd, }; + + ret = idc_send_msg(&msg, IDC_BLOCKING); + } else { + return ipc4_process_on_core(ppl_icd->core, false); + } + } else { + ret = ipc4_pipeline_prepare(ppl_icd, cmd); + } + + if (ret != 0) + return ret; + } + + /* Run the trigger phase on the pipelines */ + for (i = 0; i < ppl_count; i++) { + bool delayed = false; + + ppl_icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, + ppl_id[i], IPC_COMP_IGNORE_REMOTE); + if (!ppl_icd) { + ipc_cmd_err(&ipc_tr, "ipc: comp %d not found", ppl_id[i]); + return IPC4_INVALID_RESOURCE_ID; + } + + /* Pass IPC to target core + * or use idc if more than one core used + */ + if (!cpu_is_me(ppl_icd->core)) { + if (use_idc) { + struct idc_msg msg = { IDC_MSG_PPL_STATE, + IDC_MSG_PPL_STATE_EXT(ppl_id[i], + IDC_PPL_STATE_PHASE_TRIGGER), + ppl_icd->core, + sizeof(cmd), &cmd, }; + + ret = idc_send_msg(&msg, IDC_BLOCKING); + } else { + return ipc4_process_on_core(ppl_icd->core, false); + } + } else { + ipc_compound_pre_start(state.primary.r.type); + ret = ipc4_pipeline_trigger(ppl_icd, cmd, &delayed); + ipc_compound_post_start(state.primary.r.type, ret, delayed); + if (delayed) { + /* To maintain pipeline order for triggers, we must + * do a blocking wait until trigger is processed. + * This will add a max delay of 'ppl_count' LL ticks + * to process the full trigger list. + */ + if (ipc_wait_for_compound_msg() != 0) { + ipc_cmd_err(&ipc_tr, "ipc4: fail with delayed trigger"); + return IPC4_FAILURE; + } + } + } + + if (ret != 0) + return ret; + } + + return ret; +} + +__cold static int ipc4_process_chain_dma(struct ipc4_message_request *ipc4) +{ + assert_can_be_cold(); + +#if CONFIG_COMP_CHAIN_DMA + struct ipc_comp_dev *cdma_comp; + struct ipc *ipc = ipc_get(); + struct ipc4_chain_dma cdma; + int comp_id; + int ret; + + ret = memcpy_s(&cdma, sizeof(cdma), ipc4, sizeof(*ipc4)); + if (ret < 0) + return IPC4_FAILURE; + + comp_id = IPC4_COMP_ID(cdma.primary.r.host_dma_id + IPC4_MAX_MODULE_COUNT, 0); + cdma_comp = ipc_get_comp_by_id(ipc, comp_id); + + if (!cdma_comp) { + /* + * Nothing to do when the chainDMA is not allocated and asked to + * be freed + */ + if (!cdma.primary.r.allocate && !cdma.primary.r.enable) + return IPC4_SUCCESS; + + ret = ipc4_chain_manager_create(&cdma); + if (ret < 0) + return IPC4_FAILURE; + + cdma_comp = ipc_get_comp_by_id(ipc, comp_id); + if (!cdma_comp) { + return IPC4_FAILURE; + } + + ret = ipc4_chain_dma_state(cdma_comp->cd, &cdma); + if (ret < 0) { + comp_free(cdma_comp->cd); + list_item_del(&cdma_comp->list); + rfree(cdma_comp); + return IPC4_FAILURE; + } + + return IPC4_SUCCESS; + } + + ret = ipc4_chain_dma_state(cdma_comp->cd, &cdma); + if (ret < 0) + return IPC4_INVALID_CHAIN_STATE_TRANSITION; + + return IPC4_SUCCESS; +#else + return IPC4_UNAVAILABLE; +#endif +} + +__cold static int ipc4_process_ipcgtw_cmd(struct ipc4_message_request *ipc4) +{ + assert_can_be_cold(); + +#if CONFIG_IPC4_GATEWAY + struct ipc *ipc = ipc_get(); + uint32_t reply_size = 0; + int err; + + err = copier_ipcgtw_process((const struct ipc4_ipcgtw_cmd *)ipc4, ipc->comp_data, + &reply_size); + /* reply size is returned in header extension dword */ + msg_reply->extension = reply_size; + + if (reply_size > 0) { + msg_reply->tx_data = ipc->comp_data; + msg_reply->tx_size = reply_size; + } + + return err < 0 ? IPC4_FAILURE : IPC4_SUCCESS; +#else + ipc_cmd_err(&ipc_tr, "CONFIG_IPC4_GATEWAY is disabled"); + return IPC4_UNAVAILABLE; +#endif +} + +static int ipc_glb_gdb_debug(struct ipc4_message_request *ipc4) +{ +#if CONFIG_GDBSTUB + ipc_enter_gdb = true; + return IPC4_SUCCESS; +#else + return IPC4_UNAVAILABLE; +#endif +} + +int ipc4_user_process_glb_message(struct ipc4_message_request *ipc4, + struct ipc_msg *reply) +{ + uint32_t type; + int ret; + + type = ipc4->primary.r.type; + msg_reply = reply; + + switch (type) { + case SOF_IPC4_GLB_BOOT_CONFIG: + case SOF_IPC4_GLB_ROM_CONTROL: + case SOF_IPC4_GLB_PERF_MEASUREMENTS_CMD: + case SOF_IPC4_GLB_LOAD_MULTIPLE_MODULES: + case SOF_IPC4_GLB_UNLOAD_MULTIPLE_MODULES: + ipc_cmd_err(&ipc_tr, "not implemented ipc message type %d", type); + ret = IPC4_UNAVAILABLE; + break; + + case SOF_IPC4_GLB_CHAIN_DMA: + ret = ipc4_process_chain_dma(ipc4); + break; + + /* pipeline settings */ + case SOF_IPC4_GLB_CREATE_PIPELINE: + ret = ipc4_new_pipeline(ipc4); + break; + case SOF_IPC4_GLB_DELETE_PIPELINE: + ret = ipc4_delete_pipeline(ipc4); + break; + case SOF_IPC4_GLB_SET_PIPELINE_STATE: + ret = ipc4_set_pipeline_state(ipc4); + break; + + case SOF_IPC4_GLB_GET_PIPELINE_STATE: + case SOF_IPC4_GLB_GET_PIPELINE_CONTEXT_SIZE: + case SOF_IPC4_GLB_SAVE_PIPELINE: + case SOF_IPC4_GLB_RESTORE_PIPELINE: + ipc_cmd_err(&ipc_tr, "not implemented ipc message type %d", type); + ret = IPC4_UNAVAILABLE; + break; + + case SOF_IPC4_GLB_INTERNAL_MESSAGE: + ipc_cmd_err(&ipc_tr, "not implemented ipc message type %d", type); + ret = IPC4_UNAVAILABLE; + break; + + /* Notification (FW to SW driver) */ + case SOF_IPC4_GLB_NOTIFICATION: + ipc_cmd_err(&ipc_tr, "not implemented ipc message type %d", type); + ret = IPC4_UNAVAILABLE; + break; + + case SOF_IPC4_GLB_IPCGATEWAY_CMD: + ret = ipc4_process_ipcgtw_cmd(ipc4); + break; + + case SOF_IPC4_GLB_ENTER_GDB: + ret = ipc_glb_gdb_debug(ipc4); + break; + + default: + ipc_cmd_err(&ipc_tr, "unsupported ipc message type %d", type); + ret = IPC4_UNAVAILABLE; + break; + } + + return ret; +} + +/* + * Ipc4 Module message <------> ipc3 module message + * init module <-------> create component + * bind modules <-------> connect components + * module set_large_config <-------> component cmd + * delete module <-------> free component + */ + +__cold static int ipc4_init_module_instance(struct ipc4_message_request *ipc4) +{ + struct ipc4_module_init_instance module_init; + struct comp_dev *dev; + + assert_can_be_cold(); + + /* 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)); + + if (ret < 0) + return IPC4_FAILURE; + + tr_dbg(&ipc_tr, + "%x : %x", + (uint32_t)module_init.primary.r.module_id, + (uint32_t)module_init.primary.r.instance_id); + + /* Pass IPC to target core */ + if (!cpu_is_me(module_init.extension.r.core_id)) + return ipc4_process_on_core(module_init.extension.r.core_id, false); + + dev = comp_new_ipc4(&module_init); + if (!dev) { + ipc_cmd_err(&ipc_tr, "error: failed to init module %x : %x", + (uint32_t)module_init.primary.r.module_id, + (uint32_t)module_init.primary.r.instance_id); + return IPC4_MOD_NOT_INITIALIZED; + } + + return 0; +} + +__cold static int ipc4_bind_module_instance(struct ipc4_message_request *ipc4) +{ + struct ipc4_module_bind_unbind bu; + struct ipc *ipc = ipc_get(); + + assert_can_be_cold(); + + int ret = memcpy_s(&bu, sizeof(bu), ipc4, sizeof(*ipc4)); + + if (ret < 0) + return IPC4_FAILURE; + + tr_dbg(&ipc_tr, "%x : %x with %x : %x", + (uint32_t)bu.primary.r.module_id, (uint32_t)bu.primary.r.instance_id, + (uint32_t)bu.extension.r.dst_module_id, (uint32_t)bu.extension.r.dst_instance_id); + + return ipc_comp_connect(ipc, (ipc_pipe_comp_connect *)&bu); +} + +__cold static int ipc4_unbind_module_instance(struct ipc4_message_request *ipc4) +{ + struct ipc4_module_bind_unbind bu; + struct ipc *ipc = ipc_get(); + + assert_can_be_cold(); + + int ret = memcpy_s(&bu, sizeof(bu), ipc4, sizeof(*ipc4)); + + if (ret < 0) + return IPC4_FAILURE; + + tr_dbg(&ipc_tr, "%x : %x with %x : %x", + (uint32_t)bu.primary.r.module_id, (uint32_t)bu.primary.r.instance_id, + (uint32_t)bu.extension.r.dst_module_id, (uint32_t)bu.extension.r.dst_instance_id); + + return ipc_comp_disconnect(ipc, (ipc_pipe_comp_connect *)&bu); +} + +static int ipc4_set_get_config_module_instance(struct ipc4_message_request *ipc4, bool set) +{ + struct ipc4_module_config *config = (struct ipc4_module_config *)ipc4; + int (*function)(struct comp_dev *dev, uint32_t type, void *value); + const struct comp_driver *drv; + struct comp_dev *dev = NULL; + int ret; + + tr_dbg(&ipc_tr, "%x : %x, set %d", + (uint32_t)config->primary.r.module_id, (uint32_t)config->primary.r.instance_id, + !!set); + + /* get component dev for non-basefw since there is no component dev for basefw */ + 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); + dev = ipc4_get_comp_dev(comp_id); + if (!dev) + return IPC4_INVALID_RESOURCE_ID; + + drv = dev->drv; + + /* Pass IPC to target core */ + if (!cpu_is_me(dev->ipc_config.core)) + return ipc4_process_on_core(dev->ipc_config.core, false); + } else { + /* BaseFW module has only 0th instance */ + if (config->primary.r.instance_id) + return IPC4_INVALID_RESOURCE_ID; + + drv = ipc4_get_comp_drv(config->primary.r.module_id); + } + + if (!drv) + return IPC4_INVALID_RESOURCE_ID; + + function = set ? drv->ops.set_attribute : drv->ops.get_attribute; + if (!function) + return IPC4_INVALID_REQUEST; + + ret = function(dev, COMP_ATTR_IPC4_CONFIG, &config->extension.dat); + if (ret < 0) { + ipc_cmd_err(&ipc_tr, "%x : %x failed %d, set %u, param %x", + (uint32_t)config->primary.r.module_id, + (uint32_t)config->primary.r.instance_id, ret, !!set, + (uint32_t)config->extension.dat); + ret = IPC4_INVALID_CONFIG_PARAM_ID; + } + + if (!set) + msg_reply->extension = config->extension.dat; + + return ret; +} + +__cold static void ipc4_prepare_for_kcontrol_get(struct comp_dev *dev, uint8_t param_id, + char *data_out, uint32_t data_size) +{ + const char *hostbox; + +#if CONFIG_LIBRARY + hostbox = (const char *)ipc_get()->comp_data + sizeof(struct ipc4_module_large_config); +#else + hostbox = (const char *)MAILBOX_HOSTBOX_BASE; +#endif + + assert_can_be_cold(); + + switch (param_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + case SOF_IPC4_BYTES_CONTROL_PARAM_ID: + /* We have payload in hostbox */ + dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, + data_size); + + /* Copy the control payload header from inbox to outbox */ + memcpy_s(data_out, data_size, hostbox, + sizeof(struct sof_ipc4_control_msg_payload)); + break; + default: + break; + } +} + +__cold static int ipc4_get_vendor_config_module_instance(struct comp_dev *dev, + const struct comp_driver *drv, + bool init_block, + bool final_block, + uint32_t *data_off_size, + char *data_out, + const char *data_in) +{ + const struct sof_tl * const input_tl = (struct sof_tl *)data_in; + int ret; + struct ipc4_vendor_error *error; + + assert_can_be_cold(); + + if (init_block && final_block) { + /* we use data_off_size as in/out, + * save value to new variable so it can be used as out size + */ + const int tl_count = *data_off_size / sizeof(struct sof_tl); + size_t produced_data = 0; + + for (int i = 0; i < tl_count; i++) { + /* we go to next output tlv with each iteration */ + uint32_t data_off_size_local; + struct sof_tlv *output_tlv = (struct sof_tlv *)(data_out + produced_data); + + if (produced_data + input_tl[i].max_length > MAILBOX_DSPBOX_SIZE) { + tr_err(&ipc_tr, "error: response payload bigger than DSPBOX size"); + return IPC4_FAILURE; + } + + /* local size is in/out: max msg len goes in, msg len goes out */ + data_off_size_local = input_tl[i].max_length; + ret = drv->ops.get_large_config(dev, input_tl[i].type, + true, + true, + &data_off_size_local, output_tlv->value); + if (ret) { + /* This is how the reference firmware handled error here. Currently + * no memory is allocated for output in case of error, + * so this may be obsolete. + */ + error = (struct ipc4_vendor_error *)data_out; + error->param_idx = input_tl[i].type; + error->err_code = IPC4_FAILURE; + *data_off_size = sizeof(*error); + ipc_cmd_err(&ipc_tr, "error: get_large_config returned %d", ret); + return IPC4_FAILURE; + } + + /* update header */ + output_tlv->type = input_tl[i].type; + output_tlv->length = data_off_size_local; + produced_data += data_off_size_local + sizeof(*output_tlv); + } + *data_off_size = produced_data; + } else { + char *output_buffer; + struct sof_tlv *tl_header; + + if (init_block) { + *data_off_size = input_tl->max_length; + output_buffer = data_out + sizeof(*tl_header); + } else { + output_buffer = data_out; + } + + ret = drv->ops.get_large_config(dev, input_tl->type, + init_block, + final_block, + data_off_size, output_buffer); + + /* on error report which param failed */ + if (ret) { + error = (struct ipc4_vendor_error *)data_out; + error->param_idx = input_tl->type; + error->err_code = IPC4_FAILURE; + *data_off_size = sizeof(*error); + ipc_cmd_err(&ipc_tr, "error: get_large_config returned %d", ret); + return IPC4_FAILURE; + } + + /* for initial block update TL header */ + if (init_block) { + /* we use tlv struct here for clarity, we have length not max_length */ + tl_header = (struct sof_tlv *)data_out; + tl_header->type = input_tl->type; + tl_header->length = *data_off_size; + /* for initial block data_off_size includes also size of TL */ + *data_off_size += sizeof(*tl_header); + } + } + return IPC4_SUCCESS; +} + +__cold static int ipc4_get_large_config_module_instance(struct ipc4_message_request *ipc4) +{ + struct ipc4_module_large_config_reply reply; + struct ipc4_module_large_config config; + char *data = ipc_get()->comp_data; + const struct comp_driver *drv; + struct comp_dev *dev = NULL; + uint32_t data_offset; + + assert_can_be_cold(); + + int ret = memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4)); + + if (ret < 0) + return IPC4_FAILURE; + + tr_dbg(&ipc_tr, "%x : %x", + (uint32_t)config.primary.r.module_id, (uint32_t)config.primary.r.instance_id); + + /* get component dev for non-basefw since there is no + * component dev for basefw + */ + 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); + dev = ipc4_get_comp_dev(comp_id); + if (!dev) + return IPC4_INVALID_RESOURCE_ID; + + drv = dev->drv; + + /* Pass IPC to target core */ + if (!cpu_is_me(dev->ipc_config.core)) + return ipc4_process_on_core(dev->ipc_config.core, false); + } else { + /* BaseFW module has only 0th instance */ + if (config.primary.r.instance_id) + return IPC4_INVALID_RESOURCE_ID; + + drv = ipc4_get_comp_drv(config.primary.r.module_id); + } + + if (!drv) + return IPC4_INVALID_RESOURCE_ID; + + if (!drv->ops.get_large_config) + return IPC4_INVALID_REQUEST; + + data_offset = config.extension.r.data_off_size; + + /* check for vendor param first */ + if (config.extension.r.large_param_id == VENDOR_CONFIG_PARAM) { + /* data_off_size is a 20-bit host-controlled field, so it can + * claim far more than the hostbox can physically hold. + */ + if (data_offset > MAILBOX_HOSTBOX_SIZE) { + ipc_cmd_err(&ipc_tr, "data_off_size %u exceeds mailbox bound", + data_offset); + return IPC4_INVALID_CONFIG_DATA_STRUCT; + } + /* For now only vendor_config case uses payload from hostbox */ + dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, + config.extension.r.data_off_size); + ret = ipc4_get_vendor_config_module_instance(dev, drv, + config.extension.r.init_block, + config.extension.r.final_block, + &data_offset, + data, + (const char *)MAILBOX_HOSTBOX_BASE); + } else { +#if CONFIG_LIBRARY + data += sizeof(reply); +#endif + ipc4_prepare_for_kcontrol_get(dev, config.extension.r.large_param_id, + data, data_offset); + + ret = drv->ops.get_large_config(dev, config.extension.r.large_param_id, + config.extension.r.init_block, + config.extension.r.final_block, + &data_offset, data); + } + + /* set up ipc4 error code for reply data */ + if (ret < 0) + ret = IPC4_INVALID_RESOURCE_ID; + + /* Copy host config and overwrite */ + reply.extension.dat = config.extension.dat; + reply.extension.r.data_off_size = data_offset; + + /* The last block, no more data */ + if (!config.extension.r.final_block && data_offset < SOF_IPC_MSG_MAX_SIZE) + reply.extension.r.final_block = 1; + + /* Indicate last block if error occurs */ + if (ret) + reply.extension.r.final_block = 1; + + /* no need to allocate memory for reply msg */ + if (ret) + return ret; + + msg_reply->extension = reply.extension.dat; + msg_reply->tx_size = data_offset; + msg_reply->tx_data = data; + return ret; +} + +__cold 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; + + assert_can_be_cold(); + + /* Validate host-controlled payload size before any use or arithmetic. */ + if (data_off_size > MAILBOX_HOSTBOX_SIZE) { + tr_err(&ipc_tr, "data_off_size greater than mailbox %u > %u", + data_off_size, (uint32_t)MAILBOX_HOSTBOX_SIZE); + return IPC4_INVALID_CONFIG_DATA_STRUCT; + } + if (init_block && data_off_size < sizeof(struct sof_tlv)) { + tr_err(&ipc_tr, "init_block data_off_size too small %u < %zu", + data_off_size, sizeof(struct sof_tlv)); + return IPC4_INVALID_CONFIG_DATA_STRUCT; + } + + /* Old FW comment: bursted configs */ + if (init_block && final_block) { + const struct sof_tlv *tlv = (struct sof_tlv *)data; + + /* ===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 = (const uint8_t *)data + data_off_size; + + while ((const uint8_t *)tlv < end_offset) { + size_t remaining = (size_t)(end_offset - (const uint8_t *)tlv); + + /* check for invalid length */ + if (!tlv->length) + return IPC4_INVALID_CONFIG_DATA_LEN; + + /* Validate TLV header + value fits within remaining + * payload to prevent OOB access and pointer wraparound + * on 32-bit arithmetic (CWE-190). Split into two checks + * to avoid overflow in the size_t addition itself. + */ + if (remaining < sizeof(struct sof_tlv) || + tlv->length > remaining - sizeof(struct sof_tlv)) + return IPC4_INVALID_REQUEST; + + 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 (aligned) */ + 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, data); +} + +__cold static int ipc4_set_large_config_module_instance(struct ipc4_message_request *ipc4) +{ + struct ipc4_module_large_config config; + struct comp_dev *dev = NULL; + const struct comp_driver *drv; + + assert_can_be_cold(); + + int ret = memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4)); + + if (ret < 0) + return IPC4_FAILURE; + + dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, + config.extension.r.data_off_size); + tr_dbg(&ipc_tr, "%x : %x", + (uint32_t)config.primary.r.module_id, (uint32_t)config.primary.r.instance_id); + + 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); + dev = ipc4_get_comp_dev(comp_id); + if (!dev) + return IPC4_INVALID_RESOURCE_ID; + + drv = dev->drv; + + /* Pass IPC to target core */ + if (!cpu_is_me(dev->ipc_config.core)) + return ipc4_process_on_core(dev->ipc_config.core, false); + } else { + /* BaseFW module has only 0th instance */ + if (config.primary.r.instance_id) + return IPC4_INVALID_RESOURCE_ID; + + drv = ipc4_get_comp_drv(config.primary.r.module_id); + } + + if (!drv) + return IPC4_INVALID_RESOURCE_ID; + + if (!drv->ops.set_large_config) + return IPC4_INVALID_REQUEST; + + /* 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 { +#if CONFIG_LIBRARY + struct ipc *ipc = ipc_get(); + const char *data = (const char *)ipc->comp_data + sizeof(config); +#else + const char *data = (const char *)MAILBOX_HOSTBOX_BASE; +#endif + 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, data); + 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; +} + +__cold static int ipc4_delete_module_instance(struct ipc4_message_request *ipc4) +{ + struct ipc4_module_delete_instance module; + struct ipc *ipc = ipc_get(); + uint32_t comp_id; + + assert_can_be_cold(); + + int ret = memcpy_s(&module, sizeof(module), ipc4, sizeof(*ipc4)); + + if (ret < 0) + return IPC4_FAILURE; + + tr_dbg(&ipc_tr, "%x : %x", (uint32_t)module.primary.r.module_id, + (uint32_t)module.primary.r.instance_id); + + comp_id = IPC4_COMP_ID(module.primary.r.module_id, module.primary.r.instance_id); + ret = ipc_comp_free(ipc, comp_id); + if (ret < 0) { + ipc_cmd_err(&ipc_tr, "failed to delete module instance %x : %x", + (uint32_t)module.primary.r.module_id, + (uint32_t)module.primary.r.instance_id); + ret = IPC4_INVALID_RESOURCE_ID; + } + + return ret; +} + +__cold int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, + struct ipc_msg *reply) +{ + uint32_t type; + int ret; + + assert_can_be_cold(); + + type = ipc4->primary.r.type; + msg_reply = reply; + + switch (type) { + case SOF_IPC4_MOD_INIT_INSTANCE: + ret = ipc4_init_module_instance(ipc4); + break; + case SOF_IPC4_MOD_CONFIG_GET: + ret = ipc4_set_get_config_module_instance(ipc4, false); + break; + case SOF_IPC4_MOD_CONFIG_SET: + ret = ipc4_set_get_config_module_instance(ipc4, true); + break; + case SOF_IPC4_MOD_LARGE_CONFIG_GET: + ret = ipc4_get_large_config_module_instance(ipc4); + break; + case SOF_IPC4_MOD_LARGE_CONFIG_SET: + ret = ipc4_set_large_config_module_instance(ipc4); + break; + case SOF_IPC4_MOD_BIND: + ret = ipc4_bind_module_instance(ipc4); + break; + case SOF_IPC4_MOD_UNBIND: + ret = ipc4_unbind_module_instance(ipc4); + break; + case SOF_IPC4_MOD_DELETE_INSTANCE: + ret = ipc4_delete_module_instance(ipc4); + break; + case SOF_IPC4_MOD_ENTER_MODULE_RESTORE: + case SOF_IPC4_MOD_EXIT_MODULE_RESTORE: + ret = IPC4_UNAVAILABLE; + break; + default: + ret = IPC4_UNKNOWN_MESSAGE_TYPE; + break; + } + + return ret; +} diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c deleted file mode 100644 index 2098475d4b49..000000000000 --- a/src/ipc/ipc4/handler.c +++ /dev/null @@ -1,1724 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> -// Author: Rander Wang <rander.wang@linux.intel.com> -/* - * IPC (InterProcessor Communication) provides a method of two way - * communication between the host processor and the DSP. The IPC used here - * utilises a shared mailbox and door bell between the host and DSP. - * - */ - -#include <sof/audio/buffer.h> -#include <sof/audio/component_ext.h> -#include <sof/audio/pipeline.h> -#include <sof/boot_test.h> -#include <sof/common.h> -#include <sof/ipc/topology.h> -#include <sof/ipc/common.h> -#include <sof/ipc/msg.h> -#include <sof/ipc/driver.h> -#include <sof/lib/mailbox.h> -#include <sof/lib/pm_runtime.h> -#include <sof/math/numbers.h> -#include <sof/tlv.h> -#include <sof/trace/trace.h> -#include <ipc4/error_status.h> -#include <ipc/header.h> -#include <ipc4/module.h> -#include <ipc4/pipeline.h> -#include <ipc4/notification.h> -#include <ipc/trace.h> -#include <user/trace.h> - -#include <rtos/atomic.h> -#include <rtos/kernel.h> -#include <sof/lib_manager.h> - -#if CONFIG_SOF_BOOT_TEST -/* CONFIG_SOF_BOOT_TEST depends on Zephyr */ -#include <zephyr/ztest.h> -#endif - -#include <errno.h> -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -#include "../audio/copier/ipcgtw_copier.h" - -/* Command format errors during fuzzing are reported for virtually all - * commands, and the resulting flood of logging becomes a severe - * performance penalty (i.e. we get a lot less fuzzing done per CPU - * cycle). - */ -#ifdef CONFIG_ARCH_POSIX_LIBFUZZER -#define ipc_cmd_err(...) -#else -#define ipc_cmd_err(...) tr_err(__VA_ARGS__) -#endif - -LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); - -struct ipc4_msg_data { - struct ipc_cmd_hdr msg_in; /* local copy of current message from host header */ - struct ipc_cmd_hdr msg_out; /* local copy of current message to host header */ - atomic_t delayed_reply; - uint32_t delayed_error; -}; - -static struct ipc4_msg_data msg_data; - -/* fw sends a fw ipc message to send the status of the last host ipc message */ -static struct ipc_msg msg_reply = {0, 0, 0, 0, false, LIST_INIT(msg_reply.list)}; - -static struct ipc_msg msg_notify = {0, 0, 0, 0, false, 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(); - - /* copy the extension from the message reply */ - reply->extension.dat = msg_reply.extension; - 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. - */ -static int ipc4_new_pipeline(struct ipc4_message_request *ipc4) -{ - struct ipc *ipc = ipc_get(); - - return ipc_pipeline_new(ipc, (ipc_pipe_new *)ipc4); -} - -static int ipc4_delete_pipeline(struct ipc4_message_request *ipc4) -{ - struct ipc4_pipeline_delete *pipe; - struct ipc *ipc = ipc_get(); - - pipe = (struct ipc4_pipeline_delete *)ipc4; - tr_dbg(&ipc_tr, "ipc4 delete pipeline %x:", (uint32_t)pipe->primary.r.instance_id); - - return ipc_pipeline_free(ipc, pipe->primary.r.instance_id); -} - -static int ipc4_comp_params(struct comp_dev *current, - struct comp_buffer *calling_buf, - struct pipeline_walk_context *ctx, int dir) -{ - struct pipeline_data *ppl_data = ctx->comp_data; - int err; - - /* don't do any params if current is running */ - if (current->state == COMP_STATE_ACTIVE) - return 0; - - /* Stay on the current pipeline */ - if (current->pipeline != ((struct pipeline_data *)ctx->comp_data)->p) - return 0; - - err = comp_params(current, &ppl_data->params->params); - if (err < 0 || err == PPL_STATUS_PATH_STOP) - return err; - - return pipeline_for_each_comp(current, ctx, dir); -} - -static int ipc4_pipeline_params(struct pipeline *p, struct comp_dev *host) -{ - struct sof_ipc_pcm_params hw_params = {{ 0 }}; - struct pipeline_data data = { - .start = host, - .params = &hw_params, - .p = p, - }; - - struct pipeline_walk_context param_ctx = { - .comp_func = ipc4_comp_params, - .comp_data = &data, - .skip_incomplete = true, - }; - - return param_ctx.comp_func(host, NULL, ¶m_ctx, host->direction); -} - -static int ipc4_pcm_params(struct ipc_comp_dev *pcm_dev) -{ - int err, reset_err; - - /* sanity check comp */ - if (!pcm_dev->cd->pipeline) { - ipc_cmd_err(&ipc_tr, "ipc: comp %d pipeline not found", pcm_dev->id); - return -EINVAL; - } - - /* configure pipeline audio params */ - err = ipc4_pipeline_params(pcm_dev->cd->pipeline, pcm_dev->cd); - if (err < 0) { - ipc_cmd_err(&ipc_tr, "ipc: pipe %d comp %d params failed %d", - pcm_dev->cd->pipeline->pipeline_id, - pcm_dev->cd->pipeline->comp_id, err); - goto error; - } - - /* prepare pipeline audio params */ - err = pipeline_prepare(pcm_dev->cd->pipeline, pcm_dev->cd); - if (err < 0) { - ipc_cmd_err(&ipc_tr, "ipc: pipe %d comp %d prepare failed %d", - pcm_dev->cd->pipeline->pipeline_id, - pcm_dev->cd->pipeline->comp_id, err); - goto error; - } - - return 0; - -error: - reset_err = pipeline_reset(pcm_dev->cd->pipeline, pcm_dev->cd); - if (reset_err < 0) - ipc_cmd_err(&ipc_tr, "ipc: pipe %d comp %d reset failed %d", - pcm_dev->cd->pipeline->pipeline_id, - pcm_dev->cd->pipeline->comp_id, reset_err); - - return err; -} - -static bool is_any_ppl_active(void) -{ - struct ipc_comp_dev *icd; - struct list_item *clist; - - list_for_item(clist, &ipc_get()->comp_list) { - icd = container_of(clist, struct ipc_comp_dev, list); - if (icd->type != COMP_TYPE_PIPELINE) - continue; - - if (icd->pipeline->status == COMP_STATE_ACTIVE) - return true; - } - - return false; -} - -static struct ipc_comp_dev *pipeline_get_host_dev(struct ipc_comp_dev *ppl_icd) -{ - struct ipc_comp_dev *host_dev; - struct ipc *ipc = ipc_get(); - int host_id; - - /* If the source component's direction is not set but the sink's direction is, - * this block will copy the direction from the sink to the source component and - * mark the source's direction as set. - */ - if (!ppl_icd->pipeline->source_comp->direction_set && - ppl_icd->pipeline->sink_comp->direction_set) { - ppl_icd->pipeline->source_comp->direction = - ppl_icd->pipeline->sink_comp->direction; - ppl_icd->pipeline->source_comp->direction_set = true; - } - - /* If the sink component's direction is not set but the source's direction is, - * this block will copy the direction from the source to the sink component and - * mark the sink's direction as set. - */ - if (!ppl_icd->pipeline->sink_comp->direction_set && - ppl_icd->pipeline->source_comp->direction_set) { - ppl_icd->pipeline->sink_comp->direction = - ppl_icd->pipeline->source_comp->direction; - ppl_icd->pipeline->sink_comp->direction_set = true; - } - - if (ppl_icd->pipeline->source_comp->direction == SOF_IPC_STREAM_PLAYBACK) - host_id = ppl_icd->pipeline->source_comp->ipc_config.id; - else - host_id = ppl_icd->pipeline->sink_comp->ipc_config.id; - - host_dev = ipc_get_comp_by_id(ipc, host_id); - if (!host_dev) - ipc_cmd_err(&ipc_tr, "comp host with ID %d not found", host_id); - - return host_dev; -} - -/* Ipc4 pipeline message <------> ipc3 pipeline message - * RUNNING <-------> TRIGGER START - * INIT + PAUSED <-------> PIPELINE COMPLETE - * INIT + RESET <-------> PIPELINE COMPLETE - * PAUSED <-------> TRIGGER_PAUSE - * RESET <-------> TRIGGER_STOP + RESET - * EOS(end of stream) <-------> NOT SUPPORTED YET - * - * IPC4 pipeline state machine - * - * INIT - * | \ - * | __\| - * | - * | RESET - * | _ _ - * | /| |\ - * | / /\ - * \|/ |/_ / \ - * RUNNING <--> PAUSE _ / \ - * / \ /|\ |\ / \ - * / \ | \/ \ - * / \ | /\ \ - * / \ | / \ \ - * |/_ _\| | / \ _\| - * ERROR Stop EOS |______\ SAVE - * / - */ - -int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd) -{ - struct ipc_comp_dev *host = NULL; - struct ipc *ipc = ipc_get(); - int status; - int ret = 0; - - status = ppl_icd->pipeline->status; - tr_dbg(&ipc_tr, "pipeline %d: initial state: %d, cmd: %d", ppl_icd->id, - status, cmd); - - switch (cmd) { - case SOF_IPC4_PIPELINE_STATE_RUNNING: - /* init params when pipeline is complete or reset */ - switch (status) { - case COMP_STATE_ACTIVE: - case COMP_STATE_PAUSED: - /* No action needed */ - break; - case COMP_STATE_READY: - host = pipeline_get_host_dev(ppl_icd); - if (!host) - return IPC4_INVALID_RESOURCE_ID; - - tr_dbg(&ipc_tr, "pipeline %d: set params", ppl_icd->id); - ret = ipc4_pcm_params(host); - if (ret < 0) - return IPC4_INVALID_REQUEST; - break; - default: - ipc_cmd_err(&ipc_tr, - "pipeline %d: Invalid state for RUNNING: %d", - ppl_icd->id, status); - return IPC4_INVALID_REQUEST; - } - break; - case SOF_IPC4_PIPELINE_STATE_RESET: - 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, cmd); - if (ret < 0) - ret = IPC4_INVALID_REQUEST; - - break; - case COMP_STATE_READY: - case COMP_STATE_ACTIVE: - case COMP_STATE_PAUSED: - /* No action needed */ - break; - default: - ipc_cmd_err(&ipc_tr, - "pipeline %d: Invalid state for RESET: %d", - ppl_icd->id, status); - return IPC4_INVALID_REQUEST; - } - - break; - case SOF_IPC4_PIPELINE_STATE_PAUSED: - 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, cmd); - if (ret < 0) - ret = IPC4_INVALID_REQUEST; - - break; - default: - /* No action needed */ - break; - } - - break; - /* special case- TODO */ - 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: - ipc_cmd_err(&ipc_tr, "pipeline %d: unsupported trigger cmd: %d", - ppl_icd->id, cmd); - return IPC4_INVALID_REQUEST; - } - - return ret; -} - -int ipc4_pipeline_trigger(struct ipc_comp_dev *ppl_icd, uint32_t cmd, bool *delayed) -{ - struct ipc_comp_dev *host; - int status; - int ret; - - status = ppl_icd->pipeline->status; - tr_dbg(&ipc_tr, "pipeline %d: initial state: %d, cmd: %d", ppl_icd->id, - status, cmd); - - if (status == COMP_STATE_INIT) - return 0; - - host = pipeline_get_host_dev(ppl_icd); - if (!host) - return IPC4_INVALID_RESOURCE_ID; - - switch (cmd) { - case SOF_IPC4_PIPELINE_STATE_RUNNING: - /* init params when pipeline is complete or reset */ - switch (status) { - case COMP_STATE_ACTIVE: - /* nothing to do if the pipeline is already running */ - return 0; - case COMP_STATE_READY: - case COMP_STATE_PREPARE: - cmd = COMP_TRIGGER_PRE_START; - break; - case COMP_STATE_PAUSED: - cmd = COMP_TRIGGER_PRE_RELEASE; - break; - default: - ipc_cmd_err(&ipc_tr, - "pipeline %d: Invalid state for RUNNING: %d", - ppl_icd->id, status); - return IPC4_INVALID_REQUEST; - } - break; - case SOF_IPC4_PIPELINE_STATE_RESET: - switch (status) { - case COMP_STATE_ACTIVE: - case COMP_STATE_PAUSED: - cmd = COMP_TRIGGER_STOP; - break; - default: - return 0; - } - break; - case SOF_IPC4_PIPELINE_STATE_PAUSED: - switch (status) { - case COMP_STATE_INIT: - case COMP_STATE_READY: - case COMP_STATE_PAUSED: - return 0; - default: - cmd = COMP_TRIGGER_PAUSE; - break; - } - - break; - default: - ipc_cmd_err(&ipc_tr, "pipeline %d: unsupported trigger cmd: %d", - ppl_icd->id, cmd); - return IPC4_INVALID_REQUEST; - } - - /* trigger the component */ - ret = pipeline_trigger(host->cd->pipeline, host->cd, cmd); - if (ret < 0) { - ipc_cmd_err(&ipc_tr, "pipeline %d: trigger cmd %d failed with: %d", - ppl_icd->id, cmd, ret); - ret = IPC4_PIPELINE_STATE_NOT_SET; - } else if (ret == PPL_STATUS_SCHEDULED) { - tr_dbg(&ipc_tr, "pipeline %d: trigger cmd %d is delayed", - ppl_icd->id, cmd); - *delayed = true; - ret = 0; - } else if (cmd == COMP_TRIGGER_STOP) { - /* - * reset the pipeline components if STOP trigger is executed in - * the same thread. - * Otherwise, the pipeline will be reset after the STOP trigger - * has finished executing in the pipeline task. - */ - ret = pipeline_reset(host->cd->pipeline, host->cd); - if (ret < 0) - ret = IPC4_INVALID_REQUEST; - } - - return ret; -} - -static void ipc_compound_pre_start(int msg_id) -{ - /* ipc thread will wait for all scheduled tasks to be complete - * Use a reference count to check status of these tasks. - */ - atomic_add(&msg_data.delayed_reply, 1); -} - -static void ipc_compound_post_start(uint32_t msg_id, int ret, bool delayed) -{ - if (ret) { - ipc_cmd_err(&ipc_tr, "failed to process msg %d status %d", msg_id, ret); - atomic_set(&msg_data.delayed_reply, 0); - return; - } - - /* decrease counter if it is not scheduled by another thread */ - if (!delayed) - atomic_sub(&msg_data.delayed_reply, 1); -} - -static void ipc_compound_msg_done(uint32_t msg_id, int error) -{ - if (!atomic_read(&msg_data.delayed_reply)) { - ipc_cmd_err(&ipc_tr, "unexpected delayed reply"); - return; - } - - atomic_sub(&msg_data.delayed_reply, 1); - - /* error reported in delayed pipeline task */ - if (error < 0) { - if (msg_id == SOF_IPC4_GLB_SET_PIPELINE_STATE) - msg_data.delayed_error = IPC4_PIPELINE_STATE_NOT_SET; - } -} - -#if CONFIG_LIBRARY -/* There is no parallel execution in testbench for scheduler and pipelines, so the result would - * be always IPC4_FAILURE. Therefore the compound messages handling is simplified. The pipeline - * triggers will require an explicit scheduler call to get the components to desired state. - */ -static int ipc_wait_for_compound_msg(void) -{ - atomic_set(&msg_data.delayed_reply, 0); - return IPC4_SUCCESS; -} -#else -static int ipc_wait_for_compound_msg(void) -{ - int try_count = 30; - - while (atomic_read(&msg_data.delayed_reply)) { - k_sleep(Z_TIMEOUT_US(250)); - - if (!try_count--) { - atomic_set(&msg_data.delayed_reply, 0); - ipc_cmd_err(&ipc_tr, "ipc4: failed to wait schedule thread"); - return IPC4_FAILURE; - } - } - - return IPC4_SUCCESS; -} -#endif - -const struct ipc4_pipeline_set_state_data *ipc4_get_pipeline_data_wrapper(void) -{ - const struct ipc4_pipeline_set_state_data *ppl_data; - - ppl_data = ipc4_get_pipeline_data(); - - return ppl_data; -} - -static int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) -{ - const struct ipc4_pipeline_set_state_data *ppl_data; - struct ipc4_pipeline_set_state state; - struct ipc_comp_dev *ppl_icd; - struct ipc *ipc = ipc_get(); - uint32_t cmd, ppl_count; - uint32_t id = 0; - const uint32_t *ppl_id; - bool use_idc = false; - uint32_t idx; - int ret = 0; - int i; - - state.primary.dat = ipc4->primary.dat; - state.extension.dat = ipc4->extension.dat; - cmd = state.primary.r.ppl_state; - ppl_data = ipc4_get_pipeline_data(); - - if (state.extension.r.multi_ppl) { - ppl_count = ppl_data->pipelines_count; - ppl_id = ppl_data->ppl_id; - dcache_invalidate_region((__sparse_force void __sparse_cache *)ppl_id, - sizeof(int) * ppl_count); - } else { - ppl_count = 1; - id = state.primary.r.ppl_id; - ppl_id = &id; - } - - for (i = 0; i < ppl_count; i++) { - ppl_icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, - ppl_id[i], IPC_COMP_IGNORE_REMOTE); - if (!ppl_icd) { - tr_err(&ipc_tr, "ipc: comp %d not found", ppl_id[i]); - return IPC4_INVALID_RESOURCE_ID; - } - - if (i) { - if (ppl_icd->core != idx) - use_idc = true; - } else { - idx = ppl_icd->core; - } - } - - /* Run the prepare phase on the pipelines */ - for (i = 0; i < ppl_count; i++) { - ppl_icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, - ppl_id[i], IPC_COMP_IGNORE_REMOTE); - if (!ppl_icd) { - ipc_cmd_err(&ipc_tr, "ipc: comp %d not found", ppl_id[i]); - return IPC4_INVALID_RESOURCE_ID; - } - - /* Pass IPC to target core - * or use idc if more than one core used - */ - if (!cpu_is_me(ppl_icd->core)) { - if (use_idc) { - struct idc_msg msg = { IDC_MSG_PPL_STATE, - IDC_MSG_PPL_STATE_EXT(ppl_id[i], - IDC_PPL_STATE_PHASE_PREPARE), - ppl_icd->core, - sizeof(cmd), &cmd, }; - - ret = idc_send_msg(&msg, IDC_BLOCKING); - } else { - return ipc4_process_on_core(ppl_icd->core, false); - } - } else { - ret = ipc4_pipeline_prepare(ppl_icd, cmd); - } - - if (ret != 0) - return ret; - } - - /* Run the trigger phase on the pipelines */ - for (i = 0; i < ppl_count; i++) { - bool delayed = false; - - ppl_icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, - ppl_id[i], IPC_COMP_IGNORE_REMOTE); - if (!ppl_icd) { - ipc_cmd_err(&ipc_tr, "ipc: comp %d not found", ppl_id[i]); - return IPC4_INVALID_RESOURCE_ID; - } - - /* Pass IPC to target core - * or use idc if more than one core used - */ - if (!cpu_is_me(ppl_icd->core)) { - if (use_idc) { - struct idc_msg msg = { IDC_MSG_PPL_STATE, - IDC_MSG_PPL_STATE_EXT(ppl_id[i], - IDC_PPL_STATE_PHASE_TRIGGER), - ppl_icd->core, - sizeof(cmd), &cmd, }; - - ret = idc_send_msg(&msg, IDC_BLOCKING); - } else { - return ipc4_process_on_core(ppl_icd->core, false); - } - } else { - ipc_compound_pre_start(state.primary.r.type); - ret = ipc4_pipeline_trigger(ppl_icd, cmd, &delayed); - ipc_compound_post_start(state.primary.r.type, ret, delayed); - if (delayed) { - /* To maintain pipeline order for triggers, we must - * do a blocking wait until trigger is processed. - * This will add a max delay of 'ppl_count' LL ticks - * to process the full trigger list. - */ - if (ipc_wait_for_compound_msg() != 0) { - ipc_cmd_err(&ipc_tr, "ipc4: fail with delayed trigger"); - return IPC4_FAILURE; - } - } - } - - if (ret != 0) - return ret; - } - - return ret; -} - -#if CONFIG_LIBRARY_MANAGER -static int ipc4_load_library(struct ipc4_message_request *ipc4) -{ - struct ipc4_module_load_library library; - int ret; - - library.header.dat = ipc4->primary.dat; - - ret = lib_manager_load_library(library.header.r.dma_id, library.header.r.lib_id, - ipc4->primary.r.type); - if (ret != 0) - return (ret == -EINVAL) ? IPC4_ERROR_INVALID_PARAM : IPC4_FAILURE; - - return IPC4_SUCCESS; -} -#endif - -static int ipc4_process_chain_dma(struct ipc4_message_request *ipc4) -{ -#if CONFIG_COMP_CHAIN_DMA - struct ipc_comp_dev *cdma_comp; - struct ipc *ipc = ipc_get(); - struct ipc4_chain_dma cdma; - int comp_id; - int ret; - - ret = memcpy_s(&cdma, sizeof(cdma), ipc4, sizeof(*ipc4)); - if (ret < 0) - return IPC4_FAILURE; - - comp_id = IPC4_COMP_ID(cdma.primary.r.host_dma_id + IPC4_MAX_MODULE_COUNT, 0); - cdma_comp = ipc_get_comp_by_id(ipc, comp_id); - - if (!cdma_comp) { - /* - * Nothing to do when the chainDMA is not allocated and asked to - * be freed - */ - if (!cdma.primary.r.allocate && !cdma.primary.r.enable) - return IPC4_SUCCESS; - - ret = ipc4_chain_manager_create(&cdma); - if (ret < 0) - return IPC4_FAILURE; - - cdma_comp = ipc_get_comp_by_id(ipc, comp_id); - if (!cdma_comp) { - return IPC4_FAILURE; - } - - ret = ipc4_chain_dma_state(cdma_comp->cd, &cdma); - if (ret < 0) { - comp_free(cdma_comp->cd); - return IPC4_FAILURE; - } - - return IPC4_SUCCESS; - } - - ret = ipc4_chain_dma_state(cdma_comp->cd, &cdma); - if (ret < 0) - return IPC4_INVALID_CHAIN_STATE_TRANSITION; - - if (!cdma.primary.r.allocate && !cdma.primary.r.enable) - list_item_del(&cdma_comp->list); - - return IPC4_SUCCESS; -#else - return IPC4_UNAVAILABLE; -#endif -} - -static int ipc4_process_ipcgtw_cmd(struct ipc4_message_request *ipc4) -{ -#if CONFIG_IPC4_GATEWAY - struct ipc *ipc = ipc_get(); - uint32_t reply_size = 0; - int err; - - /* NOTE: reply implementation is messy! First, reply payload is copied - * to ipc->comp_data buffer. Then, new buffer is allocated and assigned - * to msg_reply.tx_data. ipc_msg_send() copies payload from ipc->comp_data - * to msg_reply.tx_data. Then, ipc_prepare_to_send() copies payload from - * msg_reply.tx_data to memory window and frees msg_reply.tx_data. That is - * quite weird: seems one extra copying can be eliminated. - */ - - err = copier_ipcgtw_process((const struct ipc4_ipcgtw_cmd *)ipc4, ipc->comp_data, - &reply_size); - /* reply size is returned in header extension dword */ - msg_reply.extension = reply_size; - - if (reply_size > 0) { - msg_reply.tx_data = rballoc(0, SOF_MEM_CAPS_RAM, reply_size); - if (msg_reply.tx_data) { - msg_reply.tx_size = reply_size; - } else { - ipc_cmd_err(&ipc_tr, "failed to allocate %u bytes for msg_reply.tx_data", - reply_size); - msg_reply.extension = 0; - return IPC4_OUT_OF_MEMORY; - } - } - - return err < 0 ? IPC4_FAILURE : IPC4_SUCCESS; -#else - ipc_cmd_err(&ipc_tr, "CONFIG_IPC4_GATEWAY is disabled"); - return IPC4_UNAVAILABLE; -#endif -} - -static int ipc4_process_glb_message(struct ipc4_message_request *ipc4) -{ - uint32_t type; - int ret; - - type = ipc4->primary.r.type; - - switch (type) { - case SOF_IPC4_GLB_BOOT_CONFIG: - case SOF_IPC4_GLB_ROM_CONTROL: - case SOF_IPC4_GLB_PERF_MEASUREMENTS_CMD: - case SOF_IPC4_GLB_LOAD_MULTIPLE_MODULES: - case SOF_IPC4_GLB_UNLOAD_MULTIPLE_MODULES: - ipc_cmd_err(&ipc_tr, "not implemented ipc message type %d", type); - ret = IPC4_UNAVAILABLE; - break; - - case SOF_IPC4_GLB_CHAIN_DMA: - ret = ipc4_process_chain_dma(ipc4); - break; - - /* pipeline settings */ - case SOF_IPC4_GLB_CREATE_PIPELINE: - ret = ipc4_new_pipeline(ipc4); - break; - case SOF_IPC4_GLB_DELETE_PIPELINE: - ret = ipc4_delete_pipeline(ipc4); - break; - case SOF_IPC4_GLB_SET_PIPELINE_STATE: - ret = ipc4_set_pipeline_state(ipc4); - break; - - case SOF_IPC4_GLB_GET_PIPELINE_STATE: - case SOF_IPC4_GLB_GET_PIPELINE_CONTEXT_SIZE: - case SOF_IPC4_GLB_SAVE_PIPELINE: - case SOF_IPC4_GLB_RESTORE_PIPELINE: - ipc_cmd_err(&ipc_tr, "not implemented ipc message type %d", type); - ret = IPC4_UNAVAILABLE; - break; - - /* Loads library (using Code Load or HD/A Host Output DMA) */ -#ifdef CONFIG_LIBRARY_MANAGER - case SOF_IPC4_GLB_LOAD_LIBRARY: - ret = ipc4_load_library(ipc4); - break; - case SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE: - ret = ipc4_load_library(ipc4); - break; -#endif - case SOF_IPC4_GLB_INTERNAL_MESSAGE: - ipc_cmd_err(&ipc_tr, "not implemented ipc message type %d", type); - ret = IPC4_UNAVAILABLE; - break; - - /* Notification (FW to SW driver) */ - case SOF_IPC4_GLB_NOTIFICATION: - ipc_cmd_err(&ipc_tr, "not implemented ipc message type %d", type); - ret = IPC4_UNAVAILABLE; - break; - - case SOF_IPC4_GLB_IPCGATEWAY_CMD: - ret = ipc4_process_ipcgtw_cmd(ipc4); - break; - - default: - ipc_cmd_err(&ipc_tr, "unsupported ipc message type %d", type); - ret = IPC4_UNAVAILABLE; - break; - } - - return ret; -} - -/* - * Ipc4 Module message <------> ipc3 module message - * init module <-------> create component - * bind modules <-------> connect components - * module set_large_config <-------> component cmd - * delete module <-------> free component - */ - -__cold static int ipc4_init_module_instance(struct ipc4_message_request *ipc4) -{ - 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)); - - if (ret < 0) - return IPC4_FAILURE; - - tr_dbg(&ipc_tr, - "ipc4_init_module_instance %x : %x", - (uint32_t)module_init.primary.r.module_id, - (uint32_t)module_init.primary.r.instance_id); - - /* Pass IPC to target core */ - if (!cpu_is_me(module_init.extension.r.core_id)) - return ipc4_process_on_core(module_init.extension.r.core_id, false); - - dev = comp_new_ipc4(&module_init); - if (!dev) { - ipc_cmd_err(&ipc_tr, "error: failed to init module %x : %x", - (uint32_t)module_init.primary.r.module_id, - (uint32_t)module_init.primary.r.instance_id); - return IPC4_MOD_NOT_INITIALIZED; - } - - return 0; -} - -static int ipc4_bind_module_instance(struct ipc4_message_request *ipc4) -{ - struct ipc4_module_bind_unbind bu; - struct ipc *ipc = ipc_get(); - int ret = memcpy_s(&bu, sizeof(bu), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - - tr_dbg(&ipc_tr, "ipc4_bind_module_instance %x : %x with %x : %x", - (uint32_t)bu.primary.r.module_id, (uint32_t)bu.primary.r.instance_id, - (uint32_t)bu.extension.r.dst_module_id, (uint32_t)bu.extension.r.dst_instance_id); - - return ipc_comp_connect(ipc, (ipc_pipe_comp_connect *)&bu); -} - -static int ipc4_unbind_module_instance(struct ipc4_message_request *ipc4) -{ - struct ipc4_module_bind_unbind bu; - struct ipc *ipc = ipc_get(); - int ret = memcpy_s(&bu, sizeof(bu), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - - tr_dbg(&ipc_tr, "ipc4_unbind_module_instance %x : %x with %x : %x", - (uint32_t)bu.primary.r.module_id, (uint32_t)bu.primary.r.instance_id, - (uint32_t)bu.extension.r.dst_module_id, (uint32_t)bu.extension.r.dst_instance_id); - - return ipc_comp_disconnect(ipc, (ipc_pipe_comp_connect *)&bu); -} - -static int ipc4_get_vendor_config_module_instance(struct comp_dev *dev, - const struct comp_driver *drv, - bool init_block, - bool final_block, - uint32_t *data_off_size, - char *data_out, - const char *data_in) -{ - const struct sof_tl * const input_tl = (struct sof_tl *)data_in; - int ret; - struct ipc4_vendor_error *error; - - if (init_block && final_block) { - /* we use data_off_size as in/out, - * save value to new variable so it can be used as out size - */ - const int tl_count = *data_off_size / sizeof(struct sof_tl); - size_t produced_data = 0; - - for (int i = 0; i < tl_count; i++) { - /* we go to next output tlv with each iteration */ - uint32_t data_off_size_local; - struct sof_tlv *output_tlv = (struct sof_tlv *)(data_out + produced_data); - - if (produced_data + input_tl[i].max_length > MAILBOX_DSPBOX_SIZE) { - tr_err(&ipc_tr, "error: response payload bigger than DSPBOX size"); - return IPC4_FAILURE; - } - - /* local size is in/out: max msg len goes in, msg len goes out */ - data_off_size_local = input_tl[i].max_length; - ret = drv->ops.get_large_config(dev, input_tl[i].type, - true, - true, - &data_off_size_local, output_tlv->value); - if (ret) { - /* This is how the reference firmware handled error here. Currently - * no memory is allocated for output in case of error, - * so this may be obsolete. - */ - error = (struct ipc4_vendor_error *)data_out; - error->param_idx = input_tl[i].type; - error->err_code = IPC4_FAILURE; - *data_off_size = sizeof(*error); - ipc_cmd_err(&ipc_tr, "error: get_large_config returned %d", ret); - return IPC4_FAILURE; - } - - /* update header */ - output_tlv->type = input_tl[i].type; - output_tlv->length = data_off_size_local; - produced_data += data_off_size_local + sizeof(*output_tlv); - } - *data_off_size = produced_data; - } else { - char *output_buffer; - struct sof_tlv *tl_header; - - if (init_block) { - *data_off_size = input_tl->max_length; - output_buffer = data_out + sizeof(*tl_header); - } else { - output_buffer = data_out; - } - - ret = drv->ops.get_large_config(dev, input_tl->type, - init_block, - final_block, - data_off_size, output_buffer); - - /* on error report which param failed */ - if (ret) { - error = (struct ipc4_vendor_error *)data_out; - error->param_idx = input_tl->type; - error->err_code = IPC4_FAILURE; - *data_off_size = sizeof(*error); - ipc_cmd_err(&ipc_tr, "error: get_large_config returned %d", ret); - return IPC4_FAILURE; - } - - /* for initial block update TL header */ - if (init_block) { - /* we use tlv struct here for clarity, we have length not max_length */ - tl_header = (struct sof_tlv *)data_out; - tl_header->type = input_tl->type; - tl_header->length = *data_off_size; - /* for initial block data_off_size includes also size of TL */ - *data_off_size += sizeof(*tl_header); - } - } - return IPC4_SUCCESS; -} - -static int ipc4_get_large_config_module_instance(struct ipc4_message_request *ipc4) -{ - struct ipc4_module_large_config_reply reply; - struct ipc4_module_large_config config; - char *data = ipc_get()->comp_data; - const struct comp_driver *drv; - struct comp_dev *dev = NULL; - uint32_t data_offset; - void *response_buffer; - int ret = memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - - tr_dbg(&ipc_tr, "ipc4_get_large_config_module_instance %x : %x", - (uint32_t)config.primary.r.module_id, (uint32_t)config.primary.r.instance_id); - - /* get component dev for non-basefw since there is no - * component dev for basefw - */ - 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); - dev = ipc4_get_comp_dev(comp_id); - if (!dev) - return IPC4_MOD_INVALID_ID; - - drv = dev->drv; - - /* Pass IPC to target core */ - if (!cpu_is_me(dev->ipc_config.core)) - return ipc4_process_on_core(dev->ipc_config.core, false); - } else { - drv = ipc4_get_comp_drv(config.primary.r.module_id); - } - - if (!drv) - return IPC4_MOD_INVALID_ID; - - if (!drv->ops.get_large_config) - return IPC4_INVALID_REQUEST; - - data_offset = config.extension.r.data_off_size; - - /* check for vendor param first */ - if (config.extension.r.large_param_id == VENDOR_CONFIG_PARAM) { - /* For now only vendor_config case uses payload from hostbox */ - dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - config.extension.r.data_off_size); - ret = ipc4_get_vendor_config_module_instance(dev, drv, - config.extension.r.init_block, - config.extension.r.final_block, - &data_offset, - data, - (const char *)MAILBOX_HOSTBOX_BASE); - } else { -#if CONFIG_LIBRARY - data += sizeof(reply); -#endif - ret = drv->ops.get_large_config(dev, config.extension.r.large_param_id, - config.extension.r.init_block, - config.extension.r.final_block, - &data_offset, data); - } - - /* set up ipc4 error code for reply data */ - if (ret < 0) - ret = IPC4_MOD_INVALID_ID; - - /* Copy host config and overwrite */ - reply.extension.dat = config.extension.dat; - reply.extension.r.data_off_size = data_offset; - - /* The last block, no more data */ - if (!config.extension.r.final_block && data_offset < SOF_IPC_MSG_MAX_SIZE) - reply.extension.r.final_block = 1; - - /* Indicate last block if error occurs */ - if (ret) - reply.extension.r.final_block = 1; - - /* no need to allocate memory for reply msg */ - if (ret) - return ret; - - msg_reply.extension = reply.extension.dat; - response_buffer = rballoc(0, SOF_MEM_CAPS_RAM, data_offset); - if (response_buffer) { - msg_reply.tx_size = data_offset; - msg_reply.tx_data = response_buffer; - } else { - ipc_cmd_err(&ipc_tr, "error: failed to allocate tx_data"); - ret = IPC4_OUT_OF_MEMORY; - } - - 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 = (const uint8_t *)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, data); -} - -static int ipc4_set_large_config_module_instance(struct ipc4_message_request *ipc4) -{ - struct ipc4_module_large_config config; - struct comp_dev *dev = NULL; - const struct comp_driver *drv; - int ret = memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - - dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - config.extension.r.data_off_size); - tr_dbg(&ipc_tr, "ipc4_set_large_config_module_instance %x : %x", - (uint32_t)config.primary.r.module_id, (uint32_t)config.primary.r.instance_id); - - 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); - dev = ipc4_get_comp_dev(comp_id); - if (!dev) - return IPC4_MOD_INVALID_ID; - - drv = dev->drv; - - /* Pass IPC to target core */ - if (!cpu_is_me(dev->ipc_config.core)) - return ipc4_process_on_core(dev->ipc_config.core, false); - } else { - drv = ipc4_get_comp_drv(config.primary.r.module_id); - } - - if (!drv) - return IPC4_MOD_INVALID_ID; - - if (!drv->ops.set_large_config) - return IPC4_INVALID_REQUEST; - - /* 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 { -#if CONFIG_LIBRARY - struct ipc *ipc = ipc_get(); - const char *data = (const char *)ipc->comp_data + sizeof(config); -#else - const char *data = (const char *)MAILBOX_HOSTBOX_BASE; -#endif - 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, data); - 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; -} - -static int ipc4_delete_module_instance(struct ipc4_message_request *ipc4) -{ - struct ipc4_module_delete_instance module; - struct ipc *ipc = ipc_get(); - uint32_t comp_id; - int ret = memcpy_s(&module, sizeof(module), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - - tr_dbg(&ipc_tr, "ipc4_delete_module_instance %x : %x", (uint32_t)module.primary.r.module_id, - (uint32_t)module.primary.r.instance_id); - - comp_id = IPC4_COMP_ID(module.primary.r.module_id, module.primary.r.instance_id); - ret = ipc_comp_free(ipc, comp_id); - if (ret < 0) { - ipc_cmd_err(&ipc_tr, "failed to delete module instance %x : %x", - (uint32_t)module.primary.r.module_id, - (uint32_t)module.primary.r.instance_id); - ret = IPC4_INVALID_RESOURCE_ID; - } - - return ret; -} - -/* disable power gating on core 0 */ -static int ipc4_module_process_d0ix(struct ipc4_message_request *ipc4) -{ - struct ipc4_module_set_d0ix d0ix; - uint32_t module_id, instance_id; - int ret = memcpy_s(&d0ix, sizeof(d0ix), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - - module_id = d0ix.primary.r.module_id; - instance_id = d0ix.primary.r.instance_id; - - tr_dbg(&ipc_tr, "ipc4_module_process_d0ix %x : %x", module_id, instance_id); - - /* only module 0 can be used to set d0ix state */ - if (d0ix.primary.r.module_id || d0ix.primary.r.instance_id) { - ipc_cmd_err(&ipc_tr, "invalid resource id %x : %x", module_id, instance_id); - return IPC4_INVALID_RESOURCE_ID; - } - - if (d0ix.extension.r.prevent_power_gating) - pm_runtime_disable(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID); - else - pm_runtime_enable(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID); - - return 0; -} - -/* enable/disable cores according to the state mask */ -static int ipc4_module_process_dx(struct ipc4_message_request *ipc4) -{ - struct ipc4_module_set_dx dx; - struct ipc4_dx_state_info dx_info; - uint32_t module_id, instance_id; - uint32_t core_id; - int ret = memcpy_s(&dx, sizeof(dx), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - - module_id = dx.primary.r.module_id; - instance_id = dx.primary.r.instance_id; - - /* only module 0 can be used to set dx state */ - if (module_id || instance_id) { - ipc_cmd_err(&ipc_tr, "invalid resource id %x : %x", module_id, instance_id); - return IPC4_INVALID_RESOURCE_ID; - } - - dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - sizeof(dx_info)); - ret = memcpy_s(&dx_info, sizeof(dx_info), - (const void *)MAILBOX_HOSTBOX_BASE, sizeof(dx_info)); - if (ret < 0) - return IPC4_FAILURE; - - /* check if core enable mask is valid */ - if (dx_info.core_mask > MASK(CONFIG_CORE_COUNT - 1, 0)) { - ipc_cmd_err(&ipc_tr, "ipc4_module_process_dx: CONFIG_CORE_COUNT: %d < core enable mask: %d", - CONFIG_CORE_COUNT, dx_info.core_mask); - return IPC4_ERROR_INVALID_PARAM; - } - - /* check primary core first */ - if ((dx_info.core_mask & BIT(PLATFORM_PRIMARY_CORE_ID)) && - (dx_info.dx_mask & BIT(PLATFORM_PRIMARY_CORE_ID))) { - /* core0 can't be activated more, it's already active since we got here */ - ipc_cmd_err(&ipc_tr, "Core0 is already active"); - return IPC4_BAD_STATE; - } - - /* Activate/deactivate requested cores */ - for (core_id = 1; core_id < CONFIG_CORE_COUNT; core_id++) { - if ((dx_info.core_mask & BIT(core_id)) == 0) - continue; - - if (dx_info.dx_mask & BIT(core_id)) { - ret = cpu_enable_core(core_id); - if (ret != 0) { - ipc_cmd_err(&ipc_tr, "failed to enable core %d", core_id); - return IPC4_FAILURE; - } - } else { - cpu_disable_core(core_id); - if (cpu_is_core_enabled(core_id)) { - ipc_cmd_err(&ipc_tr, "failed to disable core %d", core_id); - return IPC4_FAILURE; - } - } - } - - /* Deactivating primary core if requested. */ - if (dx_info.core_mask & BIT(PLATFORM_PRIMARY_CORE_ID)) { - if (cpu_enabled_cores() & ~BIT(PLATFORM_PRIMARY_CORE_ID)) { - ipc_cmd_err(&ipc_tr, "secondary cores 0x%x still active", - cpu_enabled_cores()); - return IPC4_BUSY; - } - - if (is_any_ppl_active()) { - ipc_cmd_err(&ipc_tr, "some pipelines are still active"); - return IPC4_BUSY; - } - -#if defined(CONFIG_PM) - ipc_get()->task_mask |= IPC_TASK_POWERDOWN; -#endif - /* do platform specific suspending */ - platform_context_save(sof_get()); - -#if !defined(CONFIG_LIBRARY) && !defined(CONFIG_ZEPHYR_NATIVE_DRIVERS) - arch_irq_lock(); - platform_timer_stop(timer_get()); -#endif - ipc_get()->pm_prepare_D3 = 1; - } - - return IPC4_SUCCESS; -} - -static int ipc4_process_module_message(struct ipc4_message_request *ipc4) -{ - uint32_t type; - int ret; - - type = ipc4->primary.r.type; - - switch (type) { - case SOF_IPC4_MOD_INIT_INSTANCE: - ret = ipc4_init_module_instance(ipc4); - break; - case SOF_IPC4_MOD_CONFIG_GET: - case SOF_IPC4_MOD_CONFIG_SET: - ret = IPC4_UNAVAILABLE; - tr_info(&ipc_tr, "unsupported module CONFIG_GET"); - break; - case SOF_IPC4_MOD_LARGE_CONFIG_GET: - ret = ipc4_get_large_config_module_instance(ipc4); - break; - case SOF_IPC4_MOD_LARGE_CONFIG_SET: - ret = ipc4_set_large_config_module_instance(ipc4); - break; - case SOF_IPC4_MOD_BIND: - ret = ipc4_bind_module_instance(ipc4); - break; - case SOF_IPC4_MOD_UNBIND: - ret = ipc4_unbind_module_instance(ipc4); - break; - case SOF_IPC4_MOD_DELETE_INSTANCE: - ret = ipc4_delete_module_instance(ipc4); - break; - case SOF_IPC4_MOD_SET_D0IX: - ret = ipc4_module_process_d0ix(ipc4); - break; - case SOF_IPC4_MOD_SET_DX: - ret = ipc4_module_process_dx(ipc4); - break; - case SOF_IPC4_MOD_ENTER_MODULE_RESTORE: - case SOF_IPC4_MOD_EXIT_MODULE_RESTORE: - ret = IPC4_UNAVAILABLE; - break; - default: - ret = IPC4_UNAVAILABLE; - break; - } - - return ret; -} - -struct ipc_cmd_hdr *mailbox_validate(void) -{ - struct ipc_cmd_hdr *hdr = ipc_get()->comp_data; - return hdr; -} - -struct ipc_cmd_hdr *ipc_compact_read_msg(void) -{ - int words; - - words = ipc_platform_compact_read_msg(&msg_data.msg_in, 2); - if (!words) - return mailbox_validate(); - - return &msg_data.msg_in; -} - -struct ipc_cmd_hdr *ipc_prepare_to_send(const struct ipc_msg *msg) -{ - msg_data.msg_out.pri = msg->header; - msg_data.msg_out.ext = msg->extension; - - if (msg->tx_size) { - /* Invalidate cache to ensure we read the latest data from memory. - * The response was prepared on a secondary core but will be sent - * to the host from the primary core. - */ - if (msg->is_shared) { - dcache_invalidate_region((__sparse_force void __sparse_cache *)msg->tx_data, - msg->tx_size); - } - - mailbox_dspbox_write(0, (uint32_t *)msg->tx_data, msg->tx_size); - } - - /* free memory for get config function */ - if (msg == &msg_reply && msg_reply.tx_size > 0) { - rfree(msg_reply.tx_data); - msg_reply.tx_data = NULL; - msg_reply.tx_size = 0; - msg_reply.is_shared = false; - } - - return &msg_data.msg_out; -} - -void ipc_boot_complete_msg(struct ipc_cmd_hdr *header, uint32_t data) -{ - header->pri = SOF_IPC4_FW_READY; - header->ext = 0; -} - -#if defined(CONFIG_PM_DEVICE) && defined(CONFIG_INTEL_ADSP_IPC) -void ipc_send_failed_power_transition_response(void) -{ - struct ipc4_message_request *request = ipc_from_hdr(&msg_data.msg_in); - struct ipc4_message_reply response; - - response.primary.r.status = IPC4_POWER_TRANSITION_FAILED; - response.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REPLY; - response.primary.r.msg_tgt = request->primary.r.msg_tgt; - response.primary.r.type = request->primary.r.type; - - msg_reply.header = response.primary.dat; - list_init(&msg_reply.list); - - ipc_msg_send_direct(&msg_reply, NULL); -} -#endif /* defined(CONFIG_PM_DEVICE) && defined(CONFIG_INTEL_ADSP_IPC) */ - -void ipc_send_panic_notification(void) -{ - msg_notify.header = SOF_IPC4_NOTIF_HEADER(SOF_IPC4_EXCEPTION_CAUGHT); - msg_notify.extension = cpu_get_id(); - msg_notify.is_shared = !cpu_is_primary(cpu_get_id()); - msg_notify.tx_size = 0; - msg_notify.tx_data = NULL; - list_init(&msg_notify.list); - - ipc_msg_send_direct(&msg_notify, NULL); -} - -#ifdef CONFIG_LOG_BACKEND_ADSP_MTRACE - -static bool is_notification_queued(struct ipc_msg *msg) -{ - struct ipc *ipc = ipc_get(); - k_spinlock_key_t key; - bool queued = false; - - key = k_spin_lock(&ipc->lock); - if (!list_is_empty(&msg->list)) - queued = true; - k_spin_unlock(&ipc->lock, key); - - return queued; -} - -void ipc_send_buffer_status_notify(void) -{ - /* a single msg_notify object is used */ - if (is_notification_queued(&msg_notify)) - return; - - msg_notify.header = SOF_IPC4_NOTIF_HEADER(SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS); - msg_notify.extension = 0; - msg_notify.tx_size = 0; - msg_notify.is_shared = false; - - tr_dbg(&ipc_tr, "tx-notify\t: %#x|%#x", msg_notify.header, msg_notify.extension); - - ipc_msg_send(&msg_notify, NULL, true); -} -#endif - -void ipc_msg_reply(struct sof_ipc_reply *reply) -{ - struct ipc4_message_request in; - - in.primary.dat = msg_data.msg_in.pri; - ipc_compound_msg_done(in.primary.r.type, reply->error); -} - -void ipc_cmd(struct ipc_cmd_hdr *_hdr) -{ - struct ipc4_message_request *in = ipc4_get_message_request(); - enum ipc4_message_target target; - int err; - - if (cpu_is_primary(cpu_get_id())) - tr_info(&ipc_tr, "rx\t: %#x|%#x", in->primary.dat, in->extension.dat); - - /* no process on scheduled thread */ - atomic_set(&msg_data.delayed_reply, 0); - msg_data.delayed_error = 0; - msg_reply.tx_size = 0; - msg_reply.header = in->primary.dat; - msg_reply.extension = in->extension.dat; - - target = in->primary.r.msg_tgt; - - switch (target) { - case SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG: - err = ipc4_process_glb_message(in); - if (err) - ipc_cmd_err(&ipc_tr, "ipc4: FW_GEN_MSG failed with err %d", err); - break; - case SOF_IPC4_MESSAGE_TARGET_MODULE_MSG: - err = ipc4_process_module_message(in); - if (err) - ipc_cmd_err(&ipc_tr, "ipc4: MODULE_MSG failed with err %d", err); - break; - default: - /* should not reach here as we only have 2 message types */ - ipc_cmd_err(&ipc_tr, "ipc4: invalid target %d", target); - err = IPC4_UNKNOWN_MESSAGE_TYPE; - } - - /* 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(); - struct ipc4_message_reply reply = {{0}}; - - /* Process flow and time stamp for IPC4 msg processed on secondary core : - * core 0 (primary core) core x (secondary core) - * # IPC msg thread #IPC delayed worker #core x idc thread - * ipc_task_ops.run() - * ipc_do_cmd() - * msg_reply.header = in->primary.dat - * ipc4_process_on_core(x) - * mask |= SECONDARY_CORE - * idc_send_message() - * Case 1: - * // Ipc msg processed by secondary core idc_ipc() - * if ((mask & SECONDARY_CORE)) ipc_cmd() - * return; ipc_msg_send() - * mask &= ~SECONDARY_CORE - * - * ipc_platform_send_msg - * ---------------------------------------------------------------------------- - * Case 2: - * idc_ipc() - * ipc_cmd() - * //Prepare reply msg - * msg_reply.header = - * reply.primary.dat; - * ipc_msg_send() - * mask &= ~SECONDARY_CORE - * - * if ((mask & IPC_TASK_SECONDARY_CORE)) - * return; - * // Ipc reply msg was prepared, so return - * if (msg_reply.header != in->primary.dat) - * return; - * ipc_platform_send_msg - * ---------------------------------------------------------------------------- - * Case 3: - * idc_ipc() - * ipc_cmd() - * //Prepare reply msg - * msg_reply.header = - * reply.primary.dat; - * ipc_msg_send() - * mask &= ~SECONDARY_CORE - * - * ipc_platform_send_msg - * - * if ((mask & IPC_TASK_SECONDARY_CORE)) - * return; - * // Ipc reply msg was prepared, so return - * if (msg_reply.header != in->primary.dat) - * return; - */ - - /* Reply prepared by secondary core */ - if ((ipc->task_mask & IPC_TASK_SECONDARY_CORE) && cpu_is_primary(cpu_get_id())) - return; - /* Reply has been prepared by secondary core */ - if (msg_reply.header != in->primary.dat) - return; - - /* Do not send reply for SET_DX if we are going to enter D3 - * The reply is going to be sent as part of the power down - * sequence - */ - if (ipc->task_mask & IPC_TASK_POWERDOWN) - return; - - if (ipc_wait_for_compound_msg() != 0) { - ipc_cmd_err(&ipc_tr, "ipc4: failed to send delayed reply"); - err = IPC4_FAILURE; - } - - /* copy contents of message received */ - reply.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REPLY; - reply.primary.r.msg_tgt = in->primary.r.msg_tgt; - reply.primary.r.type = in->primary.r.type; - if (msg_data.delayed_error) - reply.primary.r.status = msg_data.delayed_error; - else - reply.primary.r.status = err; - - msg_reply.header = reply.primary.dat; - - tr_dbg(&ipc_tr, "tx-reply\t: %#x|%#x", msg_reply.header, - msg_reply.extension); - - ipc4_send_reply(&reply); - } -} diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 0dfb4bc73fc2..5881fbbfb0b5 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -20,8 +20,11 @@ #include <ipc/dai.h> #include <sof/ipc/msg.h> #include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <sof/lib/vregion.h> #include <sof/list.h> #include <sof/platform.h> +#include <sof/schedule/dp_schedule.h> #include <sof/schedule/ll_schedule_domain.h> #include <rtos/symbol.h> #include <rtos/wait.h> @@ -60,6 +63,9 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); extern struct tr_ctx comp_tr; +static const struct comp_driver *ipc4_get_drv(const void *uuid); +static int ipc4_add_comp_dev(struct comp_dev *dev); + void ipc_build_stream_posn(struct sof_ipc_stream_posn *posn, uint32_t type, uint32_t id) { @@ -93,15 +99,18 @@ static inline char *ipc4_get_comp_new_data(void) static const struct comp_driver *ipc4_library_get_comp_drv(char *data) { - return ipc4_get_drv((const uint8_t *)data); + return ipc4_get_drv(data); } #else -static inline char *ipc4_get_comp_new_data(void) +__cold static inline char *ipc4_get_comp_new_data(void) { + assert_can_be_cold(); + return (char *)MAILBOX_HOSTBOX_BASE; } #endif +/* Only called from ipc4_init_module_instance(), which is __cold */ __cold struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init) { struct comp_ipc_config ipc_config; @@ -110,6 +119,8 @@ __cold struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_i uint32_t comp_id; char *data; + assert_can_be_cold(); + comp_id = IPC4_COMP_ID(module_init->primary.r.module_id, module_init->primary.r.instance_id); @@ -128,12 +139,20 @@ __cold struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_i ipc_config.pipeline_id = module_init->extension.r.ppl_instance_id; ipc_config.core = module_init->extension.r.core_id; ipc_config.ipc_config_size = module_init->extension.r.param_block_size * sizeof(uint32_t); - - dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - MAILBOX_HOSTBOX_SIZE); - + ipc_config.ipc_extended_init = module_init->extension.r.extended_init; + if (ipc_config.ipc_config_size > MAILBOX_HOSTBOX_SIZE) { + tr_err(&ipc_tr, "IPC payload size %u too big for the message window", + ipc_config.ipc_config_size); + return NULL; + } +#ifdef CONFIG_DCACHE_LINE_SIZE + if (!IS_ENABLED(CONFIG_LIBRARY)) + sys_cache_data_invd_range((__sparse_force void __sparse_cache *) + MAILBOX_HOSTBOX_BASE, + ALIGN_UP(ipc_config.ipc_config_size, + CONFIG_DCACHE_LINE_SIZE)); +#endif data = ipc4_get_comp_new_data(); - #if CONFIG_LIBRARY ipc_config.ipc_config_size -= sizeof(struct sof_uuid); drv = ipc4_library_get_comp_drv(data + ipc_config.ipc_config_size); @@ -190,6 +209,7 @@ __cold struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_i return dev; } +/* Called from ipc4_set_pipeline_state(), so cannot be cold */ struct ipc_comp_dev *ipc_get_comp_by_ppl_id(struct ipc *ipc, uint16_t type, uint32_t ppl_id, uint32_t ignore_remote) @@ -218,12 +238,112 @@ struct ipc_comp_dev *ipc_get_comp_by_ppl_id(struct ipc *ipc, uint16_t type, return NULL; } -static int ipc4_create_pipeline(struct ipc4_pipeline_create *pipe_desc) +/* + * This function currently only decodes the payload and prints out + * data it finds, but it does not store it anywhere. + */ +__cold static int ipc4_create_pipeline_payload_decode(char *data, + struct create_pipeline_params *pparams) +{ + const struct ipc4_pipeline_ext_payload *hdr = + (struct ipc4_pipeline_ext_payload *)data; + const struct ipc4_pipeline_ext_object *obj; +#ifdef CONFIG_DCACHE_LINE_SIZE + size_t cache_line_size = CONFIG_DCACHE_LINE_SIZE; + size_t hdr_cache_size = ALIGN_UP(sizeof(*hdr), cache_line_size); +#endif + bool last_object; + size_t size; + +#ifdef CONFIG_DCACHE_LINE_SIZE + if (!IS_ENABLED(CONFIG_LIBRARY)) + sys_cache_data_invd_range((__sparse_force void __sparse_cache *)data, + hdr_cache_size); +#endif + size = hdr->payload_words * sizeof(uint32_t); + last_object = !hdr->data_obj_array; + + if (size < sizeof(*hdr)) { + tr_err(&ipc_tr, "Payload size too small: %u : %#x", hdr->payload_words, + *((uint32_t *)hdr)); + return -EINVAL; + } + if (size > MAILBOX_HOSTBOX_SIZE) { + tr_err(&ipc_tr, "Payload size too large: %u : %#x", hdr->payload_words, + *((uint32_t *)hdr)); + return -EINVAL; + } + tr_info(&ipc_tr, "payload size %u array %u: %#x", hdr->payload_words, hdr->data_obj_array, + *((uint32_t *)hdr)); + +#ifdef CONFIG_DCACHE_LINE_SIZE + if (!IS_ENABLED(CONFIG_LIBRARY) && ALIGN_UP(size, cache_line_size) > hdr_cache_size) + sys_cache_data_invd_range((__sparse_force void __sparse_cache *) + ((char *)data + hdr_cache_size), + ALIGN_UP(size, cache_line_size) - hdr_cache_size); +#endif + + obj = (const struct ipc4_pipeline_ext_object *)(hdr + 1); + while (!last_object) { + const struct ipc4_pipeline_ext_object *next_obj; + + /* Check if there is space for the object header */ + if ((char *)(obj + 1) - data > size) { + tr_err(&ipc_tr, "obj header overflow, %u > %zu", + (char *)(obj + 1) - data, size); + return -EINVAL; + } + + /* Calculate would be next object position and check if current object fits */ + next_obj = (const struct ipc4_pipeline_ext_object *) + (((const uint32_t *)(obj + 1)) + obj->object_words); + if ((char *)next_obj - data > size) { + tr_err(&ipc_tr, "object size overflow, %u > %zu", + (char *)next_obj - data, size); + return -EINVAL; + } + + switch (obj->object_id) { + case IPC4_GLB_PIPE_EXT_OBJ_ID_MEM_DATA: + { + /* Get mem_data struct that follows the obj struct */ + const struct ipc4_pipeline_ext_obj_mem_data *mem_data = + (const struct ipc4_pipeline_ext_obj_mem_data *)(obj + 1); + + if (obj->object_words * sizeof(uint32_t) < sizeof(*mem_data)) { + tr_err(&ipc_tr, "mem_data object does not fit %zu < %zu", + obj->object_words * sizeof(uint32_t), sizeof(*mem_data)); + break; + } + pparams->mem_data = mem_data; + tr_info(&ipc_tr, + "init_ext_obj_mem_data domain %u stack %u heap %u", + mem_data->domain_id, mem_data->stack_bytes, + mem_data->heap_bytes); + break; + } + default: + tr_warn(&ipc_tr, "Unknown ext init object id %u of %u words", + obj->object_id, obj->object_words); + } + /* Read the last object flag from obj header */ + last_object = obj->last_object; + /* Move to next object */ + obj = next_obj; + } + + return 0; +} + +__cold static int ipc4_create_pipeline(struct ipc4_pipeline_create *pipe_desc, + struct create_pipeline_params *pparams) { struct ipc_comp_dev *ipc_pipe; struct pipeline *pipe; struct ipc *ipc = ipc_get(); + assert_can_be_cold(); + /* check whether pipeline id is already taken or in use */ ipc_pipe = ipc_get_pipeline_by_id(ipc, pipe_desc->primary.r.instance_id); if (ipc_pipe) { @@ -233,7 +353,8 @@ static int ipc4_create_pipeline(struct ipc4_pipeline_create *pipe_desc) } /* create the pipeline */ - pipe = pipeline_new(pipe_desc->primary.r.instance_id, pipe_desc->primary.r.ppl_priority, 0); + pipe = pipeline_new(NULL, pipe_desc->primary.r.instance_id, + pipe_desc->primary.r.ppl_priority, 0, pparams); if (!pipe) { tr_err(&ipc_tr, "ipc: pipeline_new() failed"); return IPC4_OUT_OF_MEMORY; @@ -248,7 +369,7 @@ static int ipc4_create_pipeline(struct ipc4_pipeline_create *pipe_desc) pipe->core = pipe_desc->extension.r.core_id; /* allocate the IPC pipeline container */ - ipc_pipe = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + ipc_pipe = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(struct ipc_comp_dev)); if (!ipc_pipe) { pipeline_free(pipe); @@ -267,9 +388,30 @@ static int ipc4_create_pipeline(struct ipc4_pipeline_create *pipe_desc) return IPC4_SUCCESS; } -int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc) +#if CONFIG_LIBRARY +static inline char *ipc4_get_pipe_create_data(void) +{ + struct ipc *ipc = ipc_get(); + char *data = (char *)ipc->comp_data + sizeof(struct ipc4_pipeline_create); + + return data; +} +#else +__cold static inline char *ipc4_get_pipe_create_data(void) +{ + assert_can_be_cold(); + + return (char *)MAILBOX_HOSTBOX_BASE; +} +#endif + +/* Only called from ipc4_new_pipeline(), which is __cold */ +__cold int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc) { struct ipc4_pipeline_create *pipe_desc = ipc_from_pipe_new(_pipe_desc); + struct create_pipeline_params pparams = { 0 }; + bool valid_pparams = false; + assert_can_be_cold(); tr_dbg(&ipc_tr, "ipc: pipeline id = %u", (uint32_t)pipe_desc->primary.r.instance_id); @@ -277,35 +419,58 @@ int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc) if (!cpu_is_me(pipe_desc->extension.r.core_id)) return ipc4_process_on_core(pipe_desc->extension.r.core_id, false); - return ipc4_create_pipeline(pipe_desc); + if (pipe_desc->extension.r.payload) { + char *data; + int ret; + + data = ipc4_get_pipe_create_data(); + + ret = ipc4_create_pipeline_payload_decode(data, &pparams); + if (ret == 0) + valid_pparams = true; + } + + return ipc4_create_pipeline(pipe_desc, valid_pparams ? &pparams : NULL); } -static inline int ipc_comp_free_remote(struct comp_dev *dev) +__cold static inline int ipc_comp_free_remote(struct comp_dev *dev) { struct idc_msg msg = { IDC_MSG_FREE, IDC_MSG_FREE_EXT(dev->ipc_config.id), dev->ipc_config.core,}; + assert_can_be_cold(); + return idc_send_msg(&msg, IDC_BLOCKING); } -static int ipc_pipeline_module_free(uint32_t pipeline_id) +__cold static int ipc_pipeline_module_free(uint32_t pipeline_id) { struct ipc *ipc = ipc_get(); struct ipc_comp_dev *icd; int ret; +#ifdef CONFIG_SOF_USERSPACE_LL + int ppl_core; +#endif + + assert_can_be_cold(); icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_COMPONENT, pipeline_id, IPC_COMP_ALL); + if (!icd) + return IPC4_SUCCESS; + +#ifdef CONFIG_SOF_USERSPACE_LL + ppl_core = icd->core; + user_ll_lock_sched(ppl_core); +#endif + while (icd) { - struct list_item *list, *_list; struct comp_buffer *buffer; + struct comp_buffer *safe; /* free sink buffer allocated by current component in bind function */ - list_for_item_safe(list, _list, &icd->cd->bsink_list) { - struct comp_dev *sink; - - buffer = container_of(list, struct comp_buffer, source_list); + comp_dev_for_each_consumer_safe(icd->cd, buffer, safe) { pipeline_disconnect(icd->cd, buffer, PPL_CONN_DIR_COMP_TO_BUFFER); - sink = buffer->sink; + struct comp_dev *sink = comp_buffer_get_sink_component(buffer); /* free the buffer only when the sink module has also been disconnected */ if (!sink) @@ -313,12 +478,9 @@ 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_dev *source; - - buffer = container_of(list, struct comp_buffer, sink_list); + comp_dev_for_each_producer_safe(icd->cd, buffer, safe) { pipeline_disconnect(icd->cd, buffer, PPL_CONN_DIR_BUFFER_TO_COMP); - source = buffer->source; + struct comp_dev *source = comp_buffer_get_source_component(buffer); /* free the buffer only when the source module has also been disconnected */ if (!source) @@ -330,20 +492,31 @@ static int ipc_pipeline_module_free(uint32_t pipeline_id) else ret = ipc_comp_free(ipc, icd->id); - if (ret) + if (ret) { +#ifdef CONFIG_SOF_USERSPACE_LL + user_ll_unlock_sched(ppl_core); +#endif return IPC4_INVALID_RESOURCE_STATE; + } icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_COMPONENT, pipeline_id, IPC_COMP_ALL); } +#ifdef CONFIG_SOF_USERSPACE_LL + user_ll_unlock_sched(ppl_core); +#endif + return IPC4_SUCCESS; } -int ipc_pipeline_free(struct ipc *ipc, uint32_t comp_id) +/* Only called from ipc4_delete_pipeline(), which is __cold */ +__cold int ipc_pipeline_free(struct ipc *ipc, uint32_t comp_id) { struct ipc_comp_dev *ipc_pipe; int ret; + assert_can_be_cold(); + /* check whether pipeline exists */ ipc_pipe = ipc_get_pipeline_by_id(ipc, comp_id); if (!ipc_pipe) @@ -355,14 +528,14 @@ int ipc_pipeline_free(struct ipc *ipc, uint32_t comp_id) ret = ipc_pipeline_module_free(ipc_pipe->pipeline->pipeline_id); if (ret != IPC4_SUCCESS) { - tr_err(&ipc_tr, "ipc_pipeline_free(): module free () failed"); + tr_err(&ipc_tr, "module free () failed"); return ret; } /* free buffer, delete all tasks and remove from list */ ret = pipeline_free(ipc_pipe->pipeline); if (ret < 0) { - tr_err(&ipc_tr, "ipc_pipeline_free(): pipeline_free() failed"); + tr_err(&ipc_tr, "pipeline_free() failed"); return IPC4_INVALID_RESOURCE_STATE; } @@ -373,18 +546,20 @@ 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, bool is_shared, - uint32_t buf_size, uint32_t src_queue, - uint32_t dst_queue) +__cold 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 mod_alloc_ctx *alloc) { struct sof_ipc_buffer ipc_buf; + assert_can_be_cold(); + 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 = cpu_get_id(); - return buffer_new(&ipc_buf, is_shared); + return buffer_new(alloc, &ipc_buf, is_shared); } #if CONFIG_CROSS_CORE_STREAM @@ -404,21 +579,25 @@ static struct comp_buffer *ipc4_create_buffer(struct comp_dev *src, bool is_shar * disable any interrupts. */ -#define ll_block(cross_core_bind, flags) \ +#if CONFIG_SOF_USERSPACE_LL +#error "CONFIG_SOF_USERSPACE_LL not compatible with cross-core streams" +#else +#define ll_block(src_core, dst_core, flags) \ do { \ - if (cross_core_bind) \ + if (src_core != dst_core) \ domain_block(sof_get()->platform_timer_domain); \ else \ irq_local_disable(flags); \ } while (0) -#define ll_unblock(cross_core_bind, flags) \ +#define ll_unblock(src_core, dst_core, flags) \ do { \ - if (cross_core_bind) \ + if (src_core != dst_core) \ domain_unblock(sof_get()->platform_timer_domain); \ else \ irq_local_enable(flags); \ } while (0) +#endif /* Calling both ll_block() and ll_wait_finished_on_core() makes sure LL will not start its * next cycle and its current cycle on specified core has finished. @@ -450,14 +629,30 @@ static int ll_wait_finished_on_core(struct comp_dev *dev) #else -#define ll_block(cross_core_bind, flags) irq_local_disable(flags) -#define ll_unblock(cross_core_bind, flags) irq_local_enable(flags) +#if CONFIG_SOF_USERSPACE_LL +/* note: cross-core streams are disabled so src_core==dst_core */ +#define ll_block(src_core, dst_core, flags) \ + do { \ + user_ll_lock_sched(src_core); \ + ARG_UNUSED(flags); \ + } while(0) +#define ll_unblock(src_core, dst_core, flags) \ + do { \ + user_ll_unlock_sched(src_core); \ + ARG_UNUSED(flags); \ + } while(0) +#else +#define ll_block(src_core, dst_core, flags) irq_local_disable(flags) +#define ll_unblock(src_core, dst_core, flags) irq_local_enable(flags) +#endif #endif -int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) +/* Only called from ipc4_bind_module_instance(), which is __cold */ +__cold int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) { struct ipc4_module_bind_unbind *bu; + struct bind_info bind_data; struct comp_buffer *buffer; struct comp_dev *source; struct comp_dev *sink; @@ -470,6 +665,8 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) int src_id, sink_id; int ret; + assert_can_be_cold(); + bu = (struct ipc4_module_bind_unbind *)_connect; src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); sink_id = IPC4_COMP_ID(bu->extension.r.dst_module_id, bu->extension.r.dst_instance_id); @@ -481,6 +678,8 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) return IPC4_INVALID_RESOURCE_ID; } + struct mod_alloc_ctx *alloc; + #if CONFIG_ZEPHYR_DP_SCHEDULER if (source->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP && sink->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { @@ -488,6 +687,19 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) src_id, sink_id); return IPC4_INVALID_REQUEST; } + + struct comp_dev *dp; + + if (sink->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) + dp = sink; + else if (source->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) + dp = source; + else + dp = NULL; + + alloc = dp && dp->mod ? dp->mod->priv.resources.alloc : NULL; +#else + alloc = NULL; #endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ bool cross_core_bind = source->ipc_config.core != sink->ipc_config.core; @@ -541,22 +753,33 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) /* create a buffer * in case of LL -> LL or LL->DP - * size = 2*obs of source module (obs is single buffer size) + * The ibs / obs should be equal between components. However, some modules + * (like kpb) produce different data sizes on output pins. Unfortunately, only + * one ibs/obs can be specified in the modules configuration. To avoid creating + * too small a buffer, we choose the maximum value between ibs and obs. + * + * size = 2*max(obs of source module, ibs of destination module) + * (obs and ibs is single buffer size) * in case of DP -> LL * size = 2*ibs of destination (LL) module. DP queue will handle obs of DP module */ if (source->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) - buf_size = obs * 2; + buf_size = MAX(ibs, obs) * 2; else buf_size = ibs * 2; buffer = ipc4_create_buffer(source, cross_core_bind, buf_size, bu->extension.r.src_queue, - bu->extension.r.dst_queue); + bu->extension.r.dst_queue, alloc); if (!buffer) { - tr_err(&ipc_tr, "failed to allocate buffer to bind %d to %d", src_id, sink_id); + tr_err(&ipc_tr, "failed to allocate buffer to bind %#x to %#x", src_id, sink_id); return IPC4_OUT_OF_MEMORY; } +#if CONFIG_ZEPHYR_DP_SCHEDULER + if (alloc) + vregion_get(alloc->vreg); +#endif + /* * set min_free_space and min_available in sink/src api of created buffer. * buffer is connected like: @@ -575,32 +798,40 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) if (sink->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP || source->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { - struct sof_source *source = audio_buffer_get_source(&buffer->audio_buffer); - struct sof_sink *sink = audio_buffer_get_sink(&buffer->audio_buffer); - - ring_buffer = ring_buffer_create(source_get_min_available(source), - sink_get_min_free_space(sink), + struct processing_module *srcmod = comp_mod(source); + struct module_data *src_module_data = &srcmod->priv; + struct processing_module *dstmod = comp_mod(sink); + struct module_data *dst_module_data = &dstmod->priv; + + /* + * Handle cases where the size of the ring buffer depends on the + * in_buff_size/out_buff_size advertised by the module. E.g. in the case of the + * compressed decoder module, the in/out_buff_size is determined during module + * init based on the decoder implementation. Also note that the size passed here + * is only for the ring buffer. The size of intermediate buffer created above is + * unchanged. + */ + ring_buffer = ring_buffer_create(dp, MAX(ibs, dst_module_data->mpd.in_buff_size), + MAX(obs, src_module_data->mpd.out_buff_size), audio_buffer_is_shared(&buffer->audio_buffer), buf_get_id(buffer)); - if (!ring_buffer) - goto free; - } + if (!ring_buffer) { + buffer_free(buffer); + return IPC4_OUT_OF_MEMORY; + } - if (sink->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) /* data destination module needs to use ring_buffer */ - audio_buffer_attach_secondary_buffer(&buffer->audio_buffer, false, /* at_input */ - &ring_buffer->audio_buffer); - else if (source->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) - /* data source module needs to use ring_buffer */ - audio_buffer_attach_secondary_buffer(&buffer->audio_buffer, true, /* at_input */ + audio_buffer_attach_secondary_buffer(&buffer->audio_buffer, dp == source, &ring_buffer->audio_buffer); + } + #endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ /* * Connect and bind the buffer to both source and sink components with LL processing been * blocked on corresponding core(s) to prevent IPC or IDC task getting preempted which * could result in buffers being only half connected when a pipeline task gets executed. */ - ll_block(cross_core_bind, flags); + ll_block(source->ipc_config.core, sink->ipc_config.core, flags); if (cross_core_bind) { #if CONFIG_CROSS_CORE_STREAM @@ -620,23 +851,28 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) ret = comp_buffer_connect(source, source->ipc_config.core, buffer, PPL_CONN_DIR_COMP_TO_BUFFER); if (ret < 0) { - tr_err(&ipc_tr, "failed to connect src %d to internal buffer", src_id); + tr_err(&ipc_tr, "failed to connect src %#x to internal buffer", src_id); goto free; } ret = comp_buffer_connect(sink, sink->ipc_config.core, buffer, PPL_CONN_DIR_BUFFER_TO_COMP); if (ret < 0) { - tr_err(&ipc_tr, "failed to connect internal buffer to sink %d", sink_id); + tr_err(&ipc_tr, "failed to connect internal buffer to sink %#x", sink_id); goto e_sink_connect; } /* these might call comp_ipc4_bind_remote() if necessary */ - ret = comp_bind(source, bu); + bind_data.ipc4_data = bu; + bind_data.bind_type = COMP_BIND_TYPE_SINK; + bind_data.sink = audio_buffer_get_sink(&buffer->audio_buffer); + ret = comp_bind(source, &bind_data); if (ret < 0) goto e_src_bind; - ret = comp_bind(sink, bu); + bind_data.bind_type = COMP_BIND_TYPE_SOURCE; + bind_data.source = audio_buffer_get_source(&buffer->audio_buffer); + ret = comp_bind(sink, &bind_data); if (ret < 0) goto e_sink_bind; @@ -652,18 +888,21 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) source->direction_set = true; } - ll_unblock(cross_core_bind, flags); + ll_unblock(source->ipc_config.core, sink->ipc_config.core, flags); return IPC4_SUCCESS; e_sink_bind: - comp_unbind(source, bu); + /* sink bind was already called */ + bind_data.bind_type = COMP_BIND_TYPE_SINK; + bind_data.sink = audio_buffer_get_sink(&buffer->audio_buffer); + comp_unbind(source, &bind_data); e_src_bind: pipeline_disconnect(sink, buffer, PPL_CONN_DIR_BUFFER_TO_COMP); e_sink_connect: pipeline_disconnect(source, buffer, PPL_CONN_DIR_COMP_TO_BUFFER); free: - ll_unblock(cross_core_bind, flags); + ll_unblock(source->ipc_config.core, sink->ipc_config.core, flags); buffer_free(buffer); return IPC4_INVALID_RESOURCE_STATE; } @@ -673,16 +912,20 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) * during run-time. The only way to change pipeline topology is to delete the whole * pipeline and create it in modified form. */ -int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) +/* Only called from ipc4_unbind_module_instance(), which is __cold */ +__cold int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) { struct ipc4_module_bind_unbind *bu; struct comp_buffer *buffer = NULL; + struct comp_buffer *buf; struct comp_dev *src, *sink; - struct list_item *sink_list; uint32_t src_id, sink_id, buffer_id; uint32_t flags = 0; int ret, ret1; bool cross_core_unbind; + struct bind_info unbind_data; + + assert_can_be_cold(); bu = (struct ipc4_module_bind_unbind *)_connect; src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); @@ -694,11 +937,6 @@ int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) return IPC4_INVALID_RESOURCE_ID; } - if (src->pipeline == sink->pipeline) { - tr_warn(&ipc_tr, "ignoring unbinding of src %x and dst %x", src_id, sink_id); - return 0; - } - cross_core_unbind = src->ipc_config.core != sink->ipc_config.core; /* Pass IPC to target core if both modules has the same target core, @@ -708,10 +946,8 @@ int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) return ipc4_process_on_core(src->ipc_config.core, false); 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); + comp_dev_for_each_consumer(src, buf) { bool found = buf_get_id(buf) == buffer_id; - if (found) { buffer = buf; break; @@ -721,30 +957,42 @@ int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) if (!buffer) return IPC4_INVALID_RESOURCE_ID; + /* + * The buffer was located on the source's consumer list, but the sink was + * resolved solely from the host-supplied dst_module_id/dst_instance_id. + * Make sure the buffer is actually connected to that sink, otherwise an + * incorrect dst would leave the real sink bound to a buffer we are about + * to free, while unbinding an unrelated component instead. + */ + if (comp_buffer_get_sink_component(buffer) != sink) { + tr_err(&ipc_tr, "buffer %#x is not connected to sink %#x", buffer_id, sink_id); + return IPC4_INVALID_RESOURCE_ID; + } + /* * Disconnect and unbind buffer from source/sink components and continue to free the buffer * even in case of errors. Block LL processing during disconnect and unbinding to prevent * IPC or IDC task getting preempted which could result in buffers being only half connected * when a pipeline task gets executed. */ - ll_block(cross_core_unbind, flags); + ll_block(src->ipc_config.core, sink->ipc_config.core, flags); if (cross_core_unbind) { #if CONFIG_CROSS_CORE_STREAM /* Make sure LL has finished on both cores */ if (!cpu_is_me(src->ipc_config.core)) if (ll_wait_finished_on_core(src) < 0) { - ll_unblock(cross_core_unbind, flags); + ll_unblock(src->ipc_config.core, sink->ipc_config.core, flags); return IPC4_FAILURE; } if (!cpu_is_me(sink->ipc_config.core)) if (ll_wait_finished_on_core(sink) < 0) { - ll_unblock(cross_core_unbind, flags); + ll_unblock(src->ipc_config.core, sink->ipc_config.core, flags); return IPC4_FAILURE; } #else tr_err(&ipc_tr, "Cross-core binding is disabled"); - ll_unblock(cross_core_unbind, flags); + ll_unblock(src->ipc_config.core, sink->ipc_config.core, flags); return IPC4_FAILURE; #endif } @@ -752,10 +1000,16 @@ int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) pipeline_disconnect(src, buffer, PPL_CONN_DIR_COMP_TO_BUFFER); pipeline_disconnect(sink, buffer, PPL_CONN_DIR_BUFFER_TO_COMP); /* these might call comp_ipc4_bind_remote() if necessary */ - ret = comp_unbind(src, bu); - ret1 = comp_unbind(sink, bu); + unbind_data.ipc4_data = bu; + unbind_data.bind_type = COMP_BIND_TYPE_SINK; + unbind_data.sink = audio_buffer_get_sink(&buffer->audio_buffer); + ret = comp_unbind(src, &unbind_data); + + unbind_data.bind_type = COMP_BIND_TYPE_SOURCE; + unbind_data.source = audio_buffer_get_source(&buffer->audio_buffer); + ret1 = comp_unbind(sink, &unbind_data); - ll_unblock(cross_core_unbind, flags); + ll_unblock(src->ipc_config.core, sink->ipc_config.core, flags); buffer_free(buffer); @@ -766,14 +1020,16 @@ int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) } #if CONFIG_COMP_CHAIN_DMA -int ipc4_chain_manager_create(struct ipc4_chain_dma *cdma) +/* Only called from ipc4_process_chain_dma(), which is __cold */ +__cold int ipc4_chain_manager_create(struct ipc4_chain_dma *cdma) { - const struct sof_uuid uuid = {0x6a0a274f, 0x27cc, 0x4afb, {0xa3, 0xe7, 0x34, - 0x44, 0x72, 0x3f, 0x43, 0x2e}}; + const struct sof_uuid uuid = SOF_REG_UUID(chain_dma); const struct comp_driver *drv; struct comp_dev *dev; - drv = ipc4_get_drv((const uint8_t *)&uuid); + assert_can_be_cold(); + + drv = ipc4_get_drv(&uuid); if (!drv) return -EINVAL; @@ -791,7 +1047,8 @@ int ipc4_chain_manager_create(struct ipc4_chain_dma *cdma) return ipc4_add_comp_dev(dev); } -int ipc4_chain_dma_state(struct comp_dev *dev, struct ipc4_chain_dma *cdma) +/* Only called from ipc4_process_chain_dma(), which is __cold */ +__cold int ipc4_chain_dma_state(struct comp_dev *dev, struct ipc4_chain_dma *cdma) { const bool allocate = cdma->primary.r.allocate; const bool enable = cdma->primary.r.enable; @@ -800,6 +1057,8 @@ int ipc4_chain_dma_state(struct comp_dev *dev, struct ipc4_chain_dma *cdma) struct list_item *clist, *_tmp; int ret; + assert_can_be_cold(); + if (!dev) return -EINVAL; @@ -831,12 +1090,14 @@ int ipc4_chain_dma_state(struct comp_dev *dev, struct ipc4_chain_dma *cdma) } #endif -static int ipc4_update_comps_direction(struct ipc *ipc, uint32_t ppl_id) +__cold static int ipc4_update_comps_direction(struct ipc *ipc, uint32_t ppl_id) { struct ipc_comp_dev *icd; struct list_item *clist; struct comp_buffer *src_buf; + assert_can_be_cold(); + list_for_item(clist, &ipc->comp_list) { icd = container_of(clist, struct ipc_comp_dev, list); if (icd->type != COMP_TYPE_COMPONENT) @@ -851,9 +1112,9 @@ static int ipc4_update_comps_direction(struct ipc *ipc, uint32_t ppl_id) if (list_is_empty(&icd->cd->bsource_list)) continue; - src_buf = list_first_item(&icd->cd->bsource_list, struct comp_buffer, sink_list); - if (src_buf->source->direction_set) { - icd->cd->direction = src_buf->source->direction; + src_buf = comp_dev_get_first_data_producer(icd->cd); + if (comp_buffer_get_source_component(src_buf)->direction_set) { + icd->cd->direction = comp_buffer_get_source_component(src_buf)->direction; icd->cd->direction_set = true; continue; } @@ -870,7 +1131,7 @@ int ipc4_pipeline_complete(struct ipc *ipc, uint32_t comp_id, uint32_t cmd) ipc_pipe = ipc_get_pipeline_by_id(ipc, comp_id); if (!ipc_pipe) - return -IPC4_INVALID_RESOURCE_ID; + return -EINVAL; /* Pass IPC to target core */ if (!cpu_is_me(ipc_pipe->core)) @@ -912,15 +1173,14 @@ int ipc4_process_on_core(uint32_t core, bool blocking) return IPC4_SUCCESS; } -const struct comp_driver *ipc4_get_drv(const uint8_t *uuid) +__cold static const struct comp_driver *ipc4_search_for_drv(const void *uuid) { struct comp_driver_list *drivers = comp_drivers_get(); struct list_item *clist; const struct comp_driver *drv = NULL; struct comp_driver_info *info; - uint32_t flags; - irq_local_disable(flags); + assert_can_be_cold(); /* search driver list with UUID */ list_for_item(clist, &drivers->list) { @@ -932,28 +1192,46 @@ const struct comp_driver *ipc4_get_drv(const uint8_t *uuid) info->drv->type, info->drv->tctx->uuid_p); drv = info->drv; - goto out; + break; } } - tr_warn(&comp_tr, "get_drv(): the provided UUID (%08x %08x %08x %08x) can't be found!", - *(uint32_t *)(&uuid[0]), - *(uint32_t *)(&uuid[4]), - *(uint32_t *)(&uuid[8]), - *(uint32_t *)(&uuid[12])); + return drv; +} + +__cold static const struct comp_driver *ipc4_get_drv(const void *uuid) +{ + const struct sof_uuid *const __maybe_unused sof_uuid = (const struct sof_uuid *)uuid; + const struct comp_driver *drv; + + assert_can_be_cold(); + + drv = ipc4_search_for_drv(uuid); + if (!drv) + tr_err(&comp_tr, + "the provided UUID (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x) can't be found!", + sof_uuid->a, sof_uuid->b, sof_uuid->c, sof_uuid->d[0], sof_uuid->d[1], + sof_uuid->d[2], sof_uuid->d[3], sof_uuid->d[4], sof_uuid->d[5], + sof_uuid->d[6], sof_uuid->d[7]); -out: - irq_local_enable(flags); return drv; } -const struct comp_driver *ipc4_get_comp_drv(uint32_t module_id) +/* + * Called from + * - ipc4_get_large_config_module_instance() + * - ipc4_set_large_config_module_instance() + * - comp_new_ipc4() + * all of which are __cold + */ +__cold const struct comp_driver *ipc4_get_comp_drv(uint32_t module_id) { const struct sof_man_fw_desc *desc = NULL; - const struct comp_driver *drv; const struct sof_man_module *mod; uint32_t entry_index; + assert_can_be_cold(); + #ifdef RIMAGE_MANIFEST desc = (const struct sof_man_fw_desc *)IMR_BOOT_LDR_MANIFEST_BASE; #else @@ -987,7 +1265,7 @@ const struct comp_driver *ipc4_get_comp_drv(uint32_t module_id) mod = lib_manager_get_module_manifest(module_id); if (!mod) { - tr_err(&comp_tr, "Error: Couldn't find loadable module with id %d.", + tr_err(&comp_tr, "Error: Couldn't find loadable module with id %#x.", module_id); return NULL; } @@ -997,18 +1275,18 @@ const struct comp_driver *ipc4_get_comp_drv(uint32_t module_id) return NULL; #endif } - /* Check already registered components */ - drv = ipc4_get_drv(mod->uuid); #if CONFIG_LIBRARY_MANAGER - if (!drv) { - /* New module not registered yet. */ - lib_manager_register_module(module_id); - drv = ipc4_get_drv(mod->uuid); - } -#endif + /* Check already registered components */ + const struct comp_driver *drv = ipc4_search_for_drv(&mod->uuid); - return drv; + if (drv) + return drv; + + /* New module not registered yet. */ + lib_manager_register_module(module_id); +#endif + return ipc4_get_drv(&mod->uuid); } struct comp_dev *ipc4_get_comp_dev(uint32_t comp_id) @@ -1019,11 +1297,13 @@ struct comp_dev *ipc4_get_comp_dev(uint32_t comp_id) } EXPORT_SYMBOL(ipc4_get_comp_dev); -int ipc4_add_comp_dev(struct comp_dev *dev) +__cold static int ipc4_add_comp_dev(struct comp_dev *dev) { struct ipc *ipc = ipc_get(); struct ipc_comp_dev *icd; + assert_can_be_cold(); + /* check id for duplicates */ icd = ipc_get_comp_by_id(ipc, dev->ipc_config.id); if (icd) { @@ -1032,11 +1312,10 @@ int ipc4_add_comp_dev(struct comp_dev *dev) } /* allocate the IPC component container */ - icd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + icd = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(struct ipc_comp_dev)); if (!icd) { - tr_err(&ipc_tr, "ipc_comp_new(): alloc failed"); - rfree(icd); + tr_err(&ipc_tr, "alloc failed"); return IPC4_OUT_OF_MEMORY; } @@ -1045,7 +1324,7 @@ int ipc4_add_comp_dev(struct comp_dev *dev) icd->core = dev->ipc_config.core; icd->id = dev->ipc_config.id; - tr_dbg(&ipc_tr, "ipc4_add_comp_dev add comp 0x%x", icd->id); + tr_dbg(&ipc_tr, "add comp 0x%x", icd->id); /* add new component to the list */ list_item_append(&icd->list, &ipc->comp_list); @@ -1065,25 +1344,82 @@ int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint3 return IPC4_SUCCESS; } +/* Unlike the above ipc4_find_dma_config(), this can find multiple DMA configs. + * For example, a UAOL copier may use two DMA channels: one for audio and one + * for clock feedback. This function can only work when all data in data_buffer + * is in TLV format; however, this is not always the case for all gateway types. + * Therefore, the above ipc4_find_dma_config() is still used as it can skip non-TLV + * blob data at the beginning of data_buffer. + */ +int ipc4_find_all_dma_configs_tlvs_only(struct ipc_config_dai *dai, + uint8_t *data_buffer, size_t size) +{ + uintptr_t end_addr = (uintptr_t)data_buffer + size; + struct sof_tlv *tlvs; + struct ipc_dma_config *dma_cfg; + int count = 0; + + for (tlvs = (struct sof_tlv *)data_buffer; tlvs && (uintptr_t)tlvs < end_addr; + tlvs = tlv_next(tlvs)) { + if ((uintptr_t)tlvs->value + tlvs->length > end_addr) { + tr_err(&ipc_tr, "Unexpected TLV length %d: exceeds buffer size", tlvs->length); + return IPC4_INVALID_REQUEST; + } + + dma_cfg = tlv_value_ptr_get(tlvs, GTW_DMA_CONFIG_ID); + if (!dma_cfg) + continue; + + if (count >= GTW_DMA_DEVICE_MAX_COUNT) { + tr_err(&ipc_tr, "Unexpected DMA config count %d, max %d", + count, GTW_DMA_DEVICE_MAX_COUNT); + return IPC4_INVALID_REQUEST; + } + + dai->host_dma_config[count++] = dma_cfg; + } + + if (count == 0) { + tr_err(&ipc_tr, "No DMA config found"); + return IPC4_INVALID_REQUEST; + } + + return IPC4_SUCCESS; +} + int ipc4_find_dma_config_multiple(struct ipc_config_dai *dai, uint8_t *data_buffer, uint32_t size, uint32_t device_id, int dma_cfg_idx) { - uint32_t end_addr = (uint32_t)data_buffer + size; + uintptr_t end_addr = (uintptr_t)data_buffer + size; struct ipc_dma_config *dma_cfg; struct sof_tlv *tlvs; - for (tlvs = (struct sof_tlv *)data_buffer; (uint32_t)tlvs < end_addr; + for (tlvs = (struct sof_tlv *)data_buffer; tlvs && (uintptr_t)tlvs < end_addr; tlvs = tlv_next(tlvs)) { + /* Reject a host TLV that overruns the buffer or wraps tlv_next(). */ + uintptr_t remaining = end_addr - (uintptr_t)tlvs; + + if (remaining < sizeof(*tlvs) || tlvs->length > remaining - sizeof(*tlvs)) + return IPC4_INVALID_REQUEST; + dma_cfg = tlv_value_ptr_get(tlvs, GTW_DMA_CONFIG_ID); if (!dma_cfg) continue; + uint32_t device_count = dma_cfg->channel_map.device_count; + + if (device_count > GTW_DMA_DEVICE_MAX_COUNT) { + tr_err(&ipc_tr, "device_count %u exceeds max %u", + device_count, GTW_DMA_DEVICE_MAX_COUNT); + return IPC4_INVALID_REQUEST; + } + /* To be able to retrieve proper DMA config we need to check if * device_id value (which is alh_id) is equal to device_address. * They both contain SNDW master id and PDI. If they match then * proper config is found. */ - for (uint32_t i = 0; i < dma_cfg->channel_map.device_count; i++) { + for (uint32_t i = 0; i < device_count; i++) { if (dma_cfg->channel_map.map[i].device_address == device_id) { dai->host_dma_config[dma_cfg_idx] = dma_cfg; return IPC4_SUCCESS; @@ -1094,28 +1430,36 @@ int ipc4_find_dma_config_multiple(struct ipc_config_dai *dai, uint8_t *data_buff return IPC4_INVALID_REQUEST; } -void ipc4_base_module_cfg_to_stream_params(const struct ipc4_base_module_cfg *base_cfg, - struct sof_ipc_stream_params *params) +void ipc4_audio_format_to_stream_params(const struct ipc4_audio_format *audio_fmt, + struct sof_ipc_stream_params *params) { enum sof_ipc_frame frame_fmt, valid_fmt; int i; memset(params, 0, sizeof(struct sof_ipc_stream_params)); - params->channels = base_cfg->audio_fmt.channels_count; - params->rate = base_cfg->audio_fmt.sampling_frequency; - params->sample_container_bytes = base_cfg->audio_fmt.depth / 8; - params->sample_valid_bytes = base_cfg->audio_fmt.valid_bit_depth / 8; - params->buffer_fmt = base_cfg->audio_fmt.interleaving_style; - params->buffer.size = base_cfg->obs * 2; - - audio_stream_fmt_conversion(base_cfg->audio_fmt.depth, - base_cfg->audio_fmt.valid_bit_depth, + params->channels = audio_fmt->channels_count; + params->rate = audio_fmt->sampling_frequency; + params->sample_container_bytes = audio_fmt->depth / 8; + params->sample_valid_bytes = audio_fmt->valid_bit_depth / 8; + params->buffer_fmt = audio_fmt->interleaving_style; + + audio_stream_fmt_conversion(audio_fmt->depth, + audio_fmt->valid_bit_depth, &frame_fmt, &valid_fmt, - base_cfg->audio_fmt.s_type); + audio_fmt->s_type); params->frame_fmt = frame_fmt; for (i = 0; i < SOF_IPC_MAX_CHANNELS; i++) - params->chmap[i] = (base_cfg->audio_fmt.ch_map >> i * 4) & 0xf; + params->chmap[i] = (audio_fmt->ch_map >> i * 4) & 0xf; +} + +void ipc4_base_module_cfg_to_stream_params(const struct ipc4_base_module_cfg *base_cfg, + struct sof_ipc_stream_params *params) +{ + memset(params, 0, sizeof(struct sof_ipc_stream_params)); + params->buffer.size = base_cfg->obs * 2; + + ipc4_audio_format_to_stream_params(&base_cfg->audio_fmt, params); } EXPORT_SYMBOL(ipc4_base_module_cfg_to_stream_params); @@ -1158,6 +1502,7 @@ void ipc4_update_source_format(struct sof_source *source, source_set_valid_fmt(source, valid_fmt); source_set_buffer_fmt(source, fmt->interleaving_style); } +EXPORT_SYMBOL(ipc4_update_source_format); void ipc4_update_sink_format(struct sof_sink *sink, const struct ipc4_audio_format *fmt) diff --git a/src/ipc/ipc4/logging.c b/src/ipc/ipc4/logging.c index 01a981435e6e..b5361ff5944e 100644 --- a/src/ipc/ipc4/logging.c +++ b/src/ipc/ipc4/logging.c @@ -9,14 +9,16 @@ #endif #include <stdint.h> +#include <sof/boot_test.h> #include <sof/lib/uuid.h> #include <sof/ipc/common.h> #include <ipc4/base_fw.h> #include <ipc4/error_status.h> #include <ipc4/logging.h> +#include <rtos/kernel.h> #if !CONFIG_LIBRARY -#include <zephyr/logging/log_backend.h> #include <zephyr/logging/log.h> +#include <zephyr/logging/log_ctrl.h> #endif #if CONFIG_LOG_BACKEND_SOF_PROBE #include <sof/probe/probe.h> @@ -51,19 +53,18 @@ LOG_MODULE_REGISTER(mtrace, CONFIG_SOF_LOG_LEVEL); */ #define IPC4_MTRACE_AGING_TIMER_MIN_MS 100 -SOF_DEFINE_REG_UUID(mtrace_task); - static uint64_t mtrace_notify_last_sent; static uint32_t mtrace_bytes_pending; static uint32_t mtrace_aging_timer = IPC4_MTRACE_NOTIFY_AGING_TIMER_MS; -struct task mtrace_task; - #define MTRACE_IPC_CORE PLATFORM_PRIMARY_CORE_ID -static void mtrace_log_hook(size_t written, size_t space_left) +static K_MUTEX_DEFINE(log_mutex); +static struct k_work_delayable log_work; + +static void mtrace_log_hook_unlocked(size_t written, size_t space_left) { uint64_t delta; @@ -84,24 +85,34 @@ static void mtrace_log_hook(size_t written, size_t space_left) ipc_send_buffer_status_notify(); mtrace_notify_last_sent = k_uptime_get(); mtrace_bytes_pending = 0; + } else if (mtrace_bytes_pending) { + k_work_schedule_for_queue(&ipc_get()->ipc_send_wq, &log_work, + K_MSEC(mtrace_aging_timer - delta)); } } -static enum task_state mtrace_task_run(void *data) +static void mtrace_log_hook(size_t written, size_t space_left) { - if (k_uptime_get() - mtrace_notify_last_sent >= mtrace_aging_timer && - mtrace_bytes_pending) - mtrace_log_hook(0, 0); + k_mutex_lock(&log_mutex, K_FOREVER); - /* task will be re-run based on mtrace_task_deadline() */ - return SOF_TASK_STATE_RESCHEDULE; + mtrace_log_hook_unlocked(written, space_left); + + k_mutex_unlock(&log_mutex); } -static uint64_t mtrace_task_deadline(void *data) +static void log_work_handler(struct k_work *work) { - return k_uptime_ticks() + k_ms_to_ticks_ceil64(mtrace_aging_timer); + k_mutex_lock(&log_mutex, K_FOREVER); + + if (k_uptime_get() - mtrace_notify_last_sent >= mtrace_aging_timer && + mtrace_bytes_pending) + mtrace_log_hook_unlocked(0, 0); + + k_mutex_unlock(&log_mutex); } +static struct k_work_sync ipc4_log_work_sync; + int ipc4_logging_enable_logs(bool first_block, bool last_block, uint32_t data_offset_or_size, @@ -109,11 +120,6 @@ int ipc4_logging_enable_logs(bool first_block, { const struct log_backend *log_backend = log_backend_adsp_mtrace_get(); const struct ipc4_log_state_info *log_state; - struct task_ops ops = { - .run = mtrace_task_run, - .get_deadline = mtrace_task_deadline, - .complete = NULL, - }; if (!(first_block && last_block)) { LOG_ERR("log_state data is expected to be sent as one chunk"); @@ -134,9 +140,53 @@ int ipc4_logging_enable_logs(bool first_block, log_state = (const struct ipc4_log_state_info *)data; if (log_state->enable) { - adsp_mtrace_log_init(mtrace_log_hook); + uint32_t log_level = LOG_LEVEL_NONE; /* Default if no bits set */ + uint32_t mask = log_state->logs_mask[0]; + + /* TODO: Improve mask handling for better code maintainability + * The logs_mask bits should be defined using proper macros or a struct + * to improve readability and maintainability. Current hardcoded bit + * positions are sufficient for now but should be refactored in the future. + * Possible improvements: + * - Define IPC4_LOG_MASK_* macros for each bit position + * - Create a struct with bitfields for each priority level + * - Add proper documentation in IPC4 specification headers + */ + + /* Determine log level from mask bits 0-4 (priority levels) + * bit 0: critical & error -> LOG_LEVEL_ERR + * bit 1: high & warning -> LOG_LEVEL_WRN + * bit 2: medium -> LOG_LEVEL_INF + * bit 3: low & info -> LOG_LEVEL_INF + * bit 4: verbose & debug -> LOG_LEVEL_DBG + * Check highest bit set to determine maximum log level + */ + if (mask & BIT(4)) + log_level = LOG_LEVEL_DBG; + else if (mask & (BIT(3) | BIT(2))) + log_level = LOG_LEVEL_INF; + else if (mask & BIT(1)) + log_level = LOG_LEVEL_WRN; + else if (mask & BIT(0)) + log_level = LOG_LEVEL_ERR; - log_backend_activate(log_backend, mtrace_log_hook); + adsp_mtrace_log_init(mtrace_log_hook); + /* Initialize work queue if not already initialized */ + if (!log_work.work.handler) + k_work_init_delayable(&log_work, log_work_handler); + + /* Enable backend with determined log level + * + * Note: If CONFIG_LOG_RUNTIME_FILTERING is not enabled, the log_level + * parameter has no effect - all logs are filtered at compile-time only. + * + * Note: Setting log_level to LOG_LEVEL_NONE will result in no logs being + * output, as all runtime filters will be set to NONE. This behavior will + * be useful in the future when per-source filtering can be specified via + * IPC, allowing selective enabling of specific log sources while keeping + * others disabled. + */ + log_backend_enable(log_backend, mtrace_log_hook, log_level); mtrace_aging_timer = log_state->aging_timer_period; if (mtrace_aging_timer < IPC4_MTRACE_AGING_TIMER_MIN_MS) { @@ -145,13 +195,19 @@ int ipc4_logging_enable_logs(bool first_block, mtrace_aging_timer); } - schedule_task_init_edf(&mtrace_task, SOF_UUID(mtrace_task_uuid), - &ops, NULL, MTRACE_IPC_CORE, 0); - schedule_task(&mtrace_task, mtrace_aging_timer * 1000, 0); + /* Logs enabled, this is the best place to run boot-tests */ + TEST_RUN_ONCE(sof_run_boot_tests); } else { + /* Flush work queue if initialized */ + if (log_work.work.handler) { + k_work_flush_delayable(&log_work, &ipc4_log_work_sync); + log_work.work.handler = NULL; + } + adsp_mtrace_log_init(NULL); - log_backend_deactivate(log_backend); - schedule_task_cancel(&mtrace_task); + /* Disable backend if currently active */ + if (log_backend_is_active(log_backend)) + log_backend_disable(log_backend); } return 0; @@ -185,10 +241,10 @@ int ipc4_logging_enable_logs(bool first_block, if (!probe_is_backend_configured()) return -EINVAL; - log_backend_activate(log_backend, NULL); + log_backend_enable(log_backend, NULL, CONFIG_SOF_LOG_LEVEL); } else { - log_backend_deactivate(log_backend); + log_backend_disable(log_backend); } return 0; @@ -208,9 +264,7 @@ int ipc4_logging_enable_logs(bool first_block, int ipc4_logging_shutdown(void) { - struct ipc4_log_state_info log_state = { 0 }; - - /* log_state.enable set to 0 above */ + struct ipc4_log_state_info log_state = { .enable = 0, }; return ipc4_logging_enable_logs(true, true, sizeof(log_state), (char *)&log_state); } diff --git a/src/ipc/ipc4/notification.c b/src/ipc/ipc4/notification.c index df7277f7dbce..9fd566ee1f93 100644 --- a/src/ipc/ipc4/notification.c +++ b/src/ipc/ipc4/notification.c @@ -3,27 +3,126 @@ * Copyright(c) 2023 Intel Corporation. All rights reserved. * * Author: Piotr Makaruk <piotr.makaruk@intel.com> + * Adrian Warecki <adrian.warecki@intel.com> */ #include <sof/common.h> +#include <sof/ipc/msg.h> #include <stdbool.h> #include <ipc4/notification.h> +#include <sof/ipc/notification_pool.h> -#if CONFIG_XRUN_NOTIFICATIONS_ENABLE -void xrun_notif_msg_init(struct ipc_msg *msg_xrun, uint32_t resource_id, uint32_t event_type) +#include <rtos/symbol.h> + +static uint32_t notification_mask = 0xFFFFFFFF; + +static bool is_notif_filtered_out(uint32_t event_type) { - struct ipc4_resource_event_data_notification *notif_data = msg_xrun->tx_data; + uint32_t notif_idx; + + switch (event_type) { + case SOF_IPC4_GATEWAY_UNDERRUN_DETECTED: + notif_idx = IPC4_UNDERRUN_AT_GATEWAY_NOTIFICATION_MASK_IDX; + break; + case SOF_IPC4_MIXER_UNDERRUN_DETECTED: + notif_idx = IPC4_UNDERRUN_AT_MIXER_NOTIFICATION_MASK_IDX; + break; + case SOF_IPC4_GATEWAY_OVERRUN_DETECTED: + notif_idx = IPC4_OVERRUN_AT_GATEWAY_NOTIFICATION_MASK_IDX; + break; + default: + return false; + } + + return (notification_mask & BIT(notif_idx)) == 0; +} + +static bool send_resource_notif(uint32_t resource_id, uint32_t event_type, uint32_t resource_type, + void *data, uint32_t data_size) +{ + struct ipc_msg *msg; + + if (is_notif_filtered_out(event_type)) + return true; //silently ignore + + msg = ipc_notification_pool_get(IPC4_RESOURCE_EVENT_SIZE); + if (!msg) + return false; + + struct ipc4_resource_event_data_notification *notif = msg->tx_data; union ipc4_notification_header header; header.r.notif_type = SOF_IPC4_NOTIFY_RESOURCE_EVENT; header.r.type = SOF_IPC4_GLB_NOTIFICATION; header.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST; header.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG; - msg_xrun->header = header.dat; + msg->header = header.dat; + + notif->resource_id = resource_id; + notif->event_type = event_type; + notif->resource_type = resource_type; + memset(¬if->event_data, 0, sizeof(notif->event_data)); + if (data && data_size) { + int ret = memcpy_s(¬if->event_data, sizeof(notif->event_data), data, data_size); + + if (ret) { + /* Most likely a simple coding mistake: + * Using a data type that is not included in the event_data union. + * Return true to prevent an infinite re-try loop in non-debug builds + */ + assert(false); + return true; + } + } + + ipc_msg_send(msg, msg->tx_data, false); + + return true; +} + +static enum sof_ipc4_resource_event_type dir_to_xrun_event(enum sof_ipc_stream_direction dir) +{ + return (dir == SOF_IPC_STREAM_PLAYBACK) ? SOF_IPC4_GATEWAY_UNDERRUN_DETECTED : + SOF_IPC4_GATEWAY_OVERRUN_DETECTED; +} + +void ipc4_update_notification_mask(uint32_t ntfy_mask, uint32_t enabled_mask) +{ + notification_mask &= enabled_mask | (~ntfy_mask); + notification_mask |= enabled_mask & ntfy_mask; +} + +bool send_copier_gateway_xrun_notif_msg(uint32_t pipeline_id, enum sof_ipc_stream_direction dir) +{ + return send_resource_notif(pipeline_id, dir_to_xrun_event(dir), SOF_IPC4_PIPELINE, NULL, + 0); +} + +bool send_gateway_xrun_notif_msg(uint32_t resource_id, enum sof_ipc_stream_direction dir) +{ + return send_resource_notif(resource_id, dir_to_xrun_event(dir), SOF_IPC4_GATEWAY, NULL, 0); +} + +void send_mixer_underrun_notif_msg(uint32_t resource_id, uint32_t eos_flag, uint32_t data_mixed, + uint32_t expected_data_mixed) +{ + struct ipc4_mixer_underrun_event_data mixer_underrun_data; + + mixer_underrun_data.eos_flag = eos_flag; + mixer_underrun_data.data_mixed = data_mixed; + mixer_underrun_data.expected_data_mixed = expected_data_mixed; + + send_resource_notif(resource_id, SOF_IPC4_MIXER_UNDERRUN_DETECTED, SOF_IPC4_PIPELINE, + &mixer_underrun_data, sizeof(mixer_underrun_data)); +} +EXPORT_SYMBOL(send_mixer_underrun_notif_msg); + +void send_process_data_error_notif_msg(uint32_t resource_id, uint32_t error_code) +{ + struct ipc4_process_data_error_event_data error_data; + + error_data.error_code = error_code; - notif_data->resource_id = resource_id; - notif_data->event_type = event_type; - notif_data->resource_type = SOF_IPC4_GATEWAY; - memset(¬if_data->event_data, 0, sizeof(notif_data->event_data)); + send_resource_notif(resource_id, SOF_IPC4_PROCESS_DATA_ERROR, SOF_IPC4_MODULE_INSTANCE, + &error_data, sizeof(error_data)); } -#endif diff --git a/src/ipc/notification_pool.c b/src/ipc/notification_pool.c new file mode 100644 index 000000000000..5894fc499b99 --- /dev/null +++ b/src/ipc/notification_pool.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// Author: Adrian Warecki <adrian.warecki@intel.com> +// + +#include <stdint.h> +#include <sof/common.h> +#include <sof/list.h> +#include <sof/ipc/notification_pool.h> + +#include <rtos/symbol.h> + +#define NOTIFICATION_POOL_MAX_PAYLOAD_SIZE 40 /* IPC4 Resource Event needs 10dw */ +#define NOTIFICATION_POOL_MAX_DEPTH 8 /* Maximum number of notifications + * in the pool + */ + +LOG_MODULE_REGISTER(notification_pool, CONFIG_SOF_LOG_LEVEL); + +SOF_DEFINE_REG_UUID(notification_pool); + +DECLARE_TR_CTX(notif_tr, SOF_UUID(notification_pool_uuid), LOG_LEVEL_INFO); + +struct ipc_notif_pool_item { + struct ipc_msg msg; + uint32_t payload[SOF_DIV_ROUND_UP(NOTIFICATION_POOL_MAX_PAYLOAD_SIZE, sizeof(uint32_t))]; +}; + +static struct list_item pool_free_list = LIST_INIT(pool_free_list); +static struct k_spinlock pool_free_list_lock; +static int pool_depth; + +static void ipc_notif_free(struct ipc_msg *msg) +{ + struct ipc_notif_pool_item *item = container_of(msg, struct ipc_notif_pool_item, msg); + k_spinlock_key_t key; + + key = k_spin_lock(&pool_free_list_lock); + list_item_append(&item->msg.list, &pool_free_list); + k_spin_unlock(&pool_free_list_lock, key); +} + +static struct ipc_msg *ipc_notif_new(size_t size) +{ + struct ipc_notif_pool_item *item; + + item = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*item)); + if (!item) { + tr_err(¬if_tr, "Unable to allocate memory for notification message"); + return NULL; + } + + list_init(&item->msg.list); + item->msg.tx_data = item->payload; + item->msg.tx_size = size; + item->msg.callback = ipc_notif_free; + return &item->msg; +} + +struct ipc_msg *ipc_notification_pool_get(size_t size) +{ + struct ipc_notif_pool_item *item; + k_spinlock_key_t key; + struct ipc_msg *new_msg; + + if (size > NOTIFICATION_POOL_MAX_PAYLOAD_SIZE) { + tr_err(¬if_tr, "Requested size %zu exceeds maximum payload size %u", + size, NOTIFICATION_POOL_MAX_PAYLOAD_SIZE); + return NULL; + } + + /* check if we have a free message */ + key = k_spin_lock(&pool_free_list_lock); + if (list_is_empty(&pool_free_list)) { + /* allocate a new message */ + if (pool_depth >= NOTIFICATION_POOL_MAX_DEPTH) { + k_spin_unlock(&pool_free_list_lock, key); + tr_err(¬if_tr, "Pool depth exceeded"); + return NULL; + } + ++pool_depth; + k_spin_unlock(&pool_free_list_lock, key); + + new_msg = ipc_notif_new(size); + if (!new_msg) { + key = k_spin_lock(&pool_free_list_lock); + --pool_depth; + k_spin_unlock(&pool_free_list_lock, key); + } + return new_msg; + } + + /* take the first free message */ + item = list_first_item(&pool_free_list, struct ipc_notif_pool_item, msg.list); + list_item_del(&item->msg.list); + k_spin_unlock(&pool_free_list_lock, key); + + item->msg.tx_size = size; + return &item->msg; +} + +#if CONFIG_LIBRARY +void ipc_notification_pool_free(void) +{ + struct ipc_notif_pool_item *item; + k_spinlock_key_t key; + + key = k_spin_lock(&pool_free_list_lock); + while (!list_is_empty(&pool_free_list)) { + item = list_first_item(&pool_free_list, struct ipc_notif_pool_item, msg.list); + list_item_del(&item->msg.list); + --pool_depth; + k_spin_unlock(&pool_free_list_lock, key); + rfree(item); + key = k_spin_lock(&pool_free_list_lock); + } + k_spin_unlock(&pool_free_list_lock, key); +} +#endif /* CONFIG_LIBRARY */ diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index bfcb2613ced5..707753635f69 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,31 +1,35 @@ # SPDX-License-Identifier: BSD-3-Clause +set(common_files notifier.c dma.c dai.c objpool.c) + if(CONFIG_LIBRARY) - add_local_sources(sof - lib.c - dai.c - dma.c - notifier.c - agent.c) - return() + add_local_sources(sof + lib.c + agent.c + ${common_files} + ) + return() endif() if(CONFIG_HAVE_AGENT) - add_local_sources(sof agent.c) + add_local_sources(sof agent.c) endif() -add_local_sources(sof - lib.c - alloc.c - notifier.c - pm_runtime.c - clk.c - dma.c - dai.c - wait.c - cpu-clk-manager.c -) - if(CONFIG_AMS) -add_local_sources(sof ams.c) + add_local_sources(sof ams.c) +endif() + +if(CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL) + add_local_sources(sof cpu-clk-manager.c) +endif() + +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + add_local_sources(sof ${common_files}) + + if(NOT CONFIG_SOF_ZEPHYR_NO_SOF_CLOCK) + add_local_sources(sof clk.c) + endif() + endif() diff --git a/src/lib/agent.c b/src/lib/agent.c index 8edc6ccb3123..5679fbddfe59 100644 --- a/src/lib/agent.c +++ b/src/lib/agent.c @@ -81,9 +81,9 @@ static enum task_state validate(void *data) /* warning timeout */ if (delta > sa->warn_timeout) { if (delta > UINT_MAX) - tr_warn(&sa_tr, "validate(), ll drift detected, delta > %u", UINT_MAX); + tr_warn(&sa_tr, "ll drift detected, delta > %u", UINT_MAX); else - tr_warn(&sa_tr, "validate(), ll drift detected, delta = %u", + tr_warn(&sa_tr, "ll drift detected, delta = %u", (unsigned int)delta); } @@ -93,16 +93,18 @@ static enum task_state validate(void *data) return SOF_TASK_STATE_RESCHEDULE; } -void sa_init(struct sof *sof, uint64_t timeout) +__cold void sa_init(struct sof *sof, uint64_t timeout) { uint64_t ticks; + assert_can_be_cold(); + if (timeout > UINT_MAX) - tr_warn(&sa_tr, "sa_init(), timeout > %u", UINT_MAX); + tr_warn(&sa_tr, "timeout > %u", UINT_MAX); else - tr_info(&sa_tr, "sa_init(), timeout = %u", (unsigned int)timeout); + tr_info(&sa_tr, "timeout = %u", (unsigned int)timeout); - sof->sa = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*sof->sa)); + sof->sa = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*sof->sa)); /* set default timeouts */ ticks = k_us_to_cyc_ceil64(timeout); @@ -117,10 +119,10 @@ void sa_init(struct sof *sof, uint64_t timeout) if (ticks > UINT_MAX || sof->sa->warn_timeout > UINT_MAX || sof->sa->panic_timeout > UINT_MAX) tr_info(&sa_tr, - "sa_init(), some of the values are > %u", UINT_MAX); + "some of the values are > %u", UINT_MAX); else tr_info(&sa_tr, - "sa_init(), ticks = %u, sof->sa->warn_timeout = %u, sof->sa->panic_timeout = %u", + "ticks = %u, sof->sa->warn_timeout = %u, sof->sa->panic_timeout = %u", (unsigned int)ticks, (unsigned int)sof->sa->warn_timeout, (unsigned int)sof->sa->panic_timeout); diff --git a/src/lib/alloc.c b/src/lib/alloc.c index c2db42a3173c..aa7edeea95fd 100644 --- a/src/lib/alloc.c +++ b/src/lib/alloc.c @@ -5,1007 +5,37 @@ // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> // Keyon Jie <yang.jie@linux.intel.com> -#include <rtos/panic.h> #include <rtos/alloc.h> -#include <rtos/cache.h> -#include <sof/lib/cpu.h> -#include <sof/lib/dma.h> -#include <sof/lib/memory.h> #include <sof/lib/mm_heap.h> -#include <sof/lib/uuid.h> -#include <sof/math/numbers.h> -#include <rtos/spinlock.h> -#include <rtos/string.h> -#include <ipc/topology.h> -#include <ipc/trace.h> #include <errno.h> #include <stdbool.h> #include <stddef.h> #include <stdint.h> +#include <stdlib.h> -LOG_MODULE_REGISTER(memory, CONFIG_SOF_LOG_LEVEL); +void *aligned_alloc(size_t alignment, size_t size); +void free_heap(void); -SOF_DEFINE_REG_UUID(mem); - -DECLARE_TR_CTX(mem_tr, SOF_UUID(mem_uuid), LOG_LEVEL_INFO); - -/* debug to set memory value on every allocation */ -#if CONFIG_DEBUG_BLOCK_FREE -#define DEBUG_BLOCK_FREE_VALUE_8BIT ((uint8_t)0xa5) -#define DEBUG_BLOCK_FREE_VALUE_32BIT ((uint32_t)0xa5a5a5a5) -#endif - -/* We have 3 memory pools - * - * 1) System memory pool does not have a map and it's size is fixed at build - * time. Memory cannot be freed from this pool. Used by device drivers - * and any system core. Saved as part of PM context. - * 2) Runtime memory pool has variable size allocation map and memory is freed - * on calls to rfree(). Saved as part of PM context. Global size - * set at build time. - * 3) Buffer memory pool has fixed size allocation map and can be freed on - * module removal or calls to rfree(). Saved as part of PM context. - */ - -#if CONFIG_DEBUG_BLOCK_FREE -/* Check whole memory region for debug pattern to find if memory was freed - * second time - */ -static void validate_memory(void *ptr, size_t size) -{ - uint32_t *ptr_32 = ptr; - int i, not_matching = 0; - - for (i = 0; i < size / 4; i++) { - if (ptr_32[i] != DEBUG_BLOCK_FREE_VALUE_32BIT) - not_matching = 1; - } - - if (not_matching) { - tr_info(&mem_tr, "validate_memory() pointer: %p freed pattern not detected", - ptr); - } else { - tr_err(&mem_tr, "validate_memory() freeing pointer: %p double free detected", - ptr); - } -} -#endif - -#if CONFIG_DEBUG_BLOCK_FREE -static void write_pattern(struct mm_heap *heap_map, int heap_depth, - uint8_t pattern) -{ - struct mm_heap *heap; - struct block_map *current_map; - int i, j; - - for (i = 0; i < heap_depth; i++) { - heap = &heap_map[i]; - - for (j = 0; j < heap->blocks; j++) { - current_map = &heap->map[j]; - memset( - (void *)current_map->base, pattern, - current_map->count * current_map->block_size); - } - - } -} -#endif - -static void init_heap_map(struct mm_heap *heap, int count) +void *rmalloc(uint32_t flags, size_t bytes) { - struct block_map *next_map; - struct block_map *current_map; - int i; - int j; - - for (i = 0; i < count; i++) { - /* init the map[0] */ - current_map = &heap[i].map[0]; - current_map->base = heap[i].heap; - - /* map[j]'s base is calculated based on map[j-1] */ - for (j = 1; j < heap[i].blocks; j++) { - next_map = &heap[i].map[j]; - next_map->base = current_map->base + - current_map->block_size * - current_map->count; - - current_map = &heap[i].map[j]; - } - - } + return malloc(bytes); } -/* allocate from system memory pool */ -static void *rmalloc_sys(struct mm_heap *heap, uint32_t flags, int caps, size_t bytes) +void *rzalloc(uint32_t flags, size_t bytes) { - void *ptr; - size_t alignment = 0; - - if ((heap->caps & caps) != caps) - sof_panic(SOF_IPC_PANIC_MEM); - - /* align address to dcache line size */ - if (heap->info.used % PLATFORM_DCACHE_ALIGN) - alignment = PLATFORM_DCACHE_ALIGN - - (heap->info.used % PLATFORM_DCACHE_ALIGN); - - /* always succeeds or panics */ - if (alignment + bytes > heap->info.free) { - tr_err(&mem_tr, "rmalloc_sys(): core = %d, bytes = %d", - cpu_get_id(), bytes); - sof_panic(SOF_IPC_PANIC_MEM); - } - heap->info.used += alignment; - - ptr = (void *)(heap->heap + heap->info.used); - - heap->info.used += bytes; - heap->info.free -= alignment + bytes; - - return ptr; -} - -/* At this point the pointer we have should be unaligned - * (it was checked level higher) and be power of 2 - */ -static void *align_ptr(struct mm_heap *heap, uint32_t alignment, - void *ptr, struct block_hdr *hdr) -{ - /* Save unaligned ptr to block hdr */ - hdr->unaligned_ptr = ptr; - - /* If ptr is not already aligned we calculate alignment shift */ - if (alignment <= 1) - return ptr; - - return (void *)ALIGN_UP((uintptr_t)ptr, alignment); -} - -/* allocate single block */ -static void *alloc_block_index(struct mm_heap *heap, int level, - uint32_t alignment, int index) -{ - struct block_map *map = &heap->map[level]; - struct block_hdr *hdr; - void *ptr; - int i; - - if (index < 0) - index = map->first_free; - - map->free_count--; - - hdr = &map->block[index]; - ptr = (void *)(map->base + index * map->block_size); - ptr = align_ptr(heap, alignment, ptr, hdr); - - hdr->size = 1; - hdr->used = 1; - - heap->info.used += map->block_size; - heap->info.free -= map->block_size; - - if (index == map->first_free) - /* find next free */ - for (i = map->first_free; i < map->count; ++i) { - hdr = &map->block[i]; - - if (hdr->used == 0) { - map->first_free = i; - break; - } - } - - return ptr; -} - -static void *alloc_block(struct mm_heap *heap, int level, - uint32_t caps, uint32_t alignment) -{ - return alloc_block_index(heap, level, alignment, -1); -} - -/* allocates continuous blocks */ -static void *alloc_cont_blocks(struct mm_heap *heap, int level, - uint32_t caps, size_t bytes, uint32_t alignment) -{ - struct block_map *map = &heap->map[level]; - struct block_hdr *hdr; - void *ptr = NULL, *unaligned_ptr; - unsigned int current; - unsigned int count = 0; /* keep compiler quiet */ - unsigned int start = 0; /* keep compiler quiet */ - uintptr_t blk_start = 0, aligned = 0; /* keep compiler quiet */ - size_t found = 0, total_bytes = bytes; - - /* check if we have enough consecutive blocks for requested - * allocation size. - */ - if ((map->count - map->first_free) * map->block_size < bytes) - return NULL; - - /* - * Walk all blocks in the map, beginning with the first free one, until - * a sufficiently large sequence is found, in which the first block - * contains an address with the requested alignment. - */ - for (current = map->first_free, hdr = map->block + current; - current < map->count && found < total_bytes; - current++, hdr++) { - if (hdr->used) { - /* Restart the search */ - found = 0; - count = 0; - total_bytes = bytes; - continue; - } - - if (!found) { - /* A possible beginning of a sequence */ - blk_start = map->base + current * map->block_size; - start = current; - - /* Check if we can start a sequence here */ - if (alignment) { - aligned = ALIGN_UP(blk_start, alignment); - - if (blk_start & (alignment - 1) && - aligned >= blk_start + map->block_size) - /* - * This block doesn't contain an address - * with required alignment, it is useless - * as the beginning of the sequence - */ - continue; - - /* - * Found a potentially suitable beginning of a - * sequence, from here we'll check if we get - * enough blocks - */ - total_bytes += aligned - blk_start; - } else { - aligned = blk_start; - } - } - - count++; - found += map->block_size; - } - - if (found < total_bytes) { - tr_err(&mem_tr, "failed to allocate %u", total_bytes); - goto out; - } - - ptr = (void *)aligned; - - /* we found enough space, let's allocate it */ - map->free_count -= count; - unaligned_ptr = (void *)blk_start; - - hdr = &map->block[start]; - hdr->size = count; - - heap->info.used += count * map->block_size; - heap->info.free -= count * map->block_size; - - /* - * if .first_free has to be updated, set it to first free block or past - * the end of the map - */ - if (map->first_free == start) { - for (current = map->first_free + count, hdr = &map->block[current]; - current < map->count && hdr->used; - current++, hdr++) - ; - - map->first_free = current; - } - - /* update each block */ - for (current = start; current < start + count; current++) { - hdr = &map->block[current]; - hdr->used = 1; - hdr->unaligned_ptr = unaligned_ptr; - } - -out: - - return ptr; + return calloc(bytes, 1); } -static inline struct mm_heap *find_in_heap_arr(struct mm_heap *heap_arr, int arr_len, void *ptr) -{ - struct mm_heap *heap; - int i; - - for (i = 0; i < arr_len; i++) { - heap = &heap_arr[i]; - if ((uint32_t)ptr >= heap->heap && - (uint32_t)ptr < heap->heap + heap->size) - return heap; - } - return NULL; -} - -static struct mm_heap *get_heap_from_ptr(void *ptr) -{ - struct mm *memmap = memmap_get(); - struct mm_heap *heap; - - /* find mm_heap that ptr belongs to */ - heap = find_in_heap_arr(memmap->system_runtime + cpu_get_id(), 1, ptr); - if (heap) - goto out; - - heap = find_in_heap_arr(memmap->runtime, PLATFORM_HEAP_RUNTIME, ptr); - if (heap) - goto out; - -#if CONFIG_CORE_COUNT > 1 - heap = find_in_heap_arr(memmap->runtime_shared, PLATFORM_HEAP_RUNTIME_SHARED, ptr); - if (heap) - goto out; -#endif - - heap = find_in_heap_arr(memmap->buffer, PLATFORM_HEAP_BUFFER, ptr); - if (heap) - goto out; - - return NULL; - -out: - - return heap; -} - -static struct mm_heap *get_heap_from_caps(struct mm_heap *heap, int count, - uint32_t caps) -{ - uint32_t mask; - int i; - - /* find first heap that support type */ - for (i = 0; i < count; i++) { - mask = heap[i].caps & caps; - if (mask == caps) - return &heap[i]; - } - - return NULL; -} - -static void *get_ptr_from_heap(struct mm_heap *heap, uint32_t flags, - uint32_t caps, size_t bytes, uint32_t alignment) -{ - struct block_map *map; - int i, temp_bytes = bytes; - void *ptr = NULL; - - /* Only allow alignment as a power of 2 */ - if ((alignment & (alignment - 1)) != 0) - sof_panic(SOF_IPC_PANIC_MEM); - - for (i = 0; i < heap->blocks; i++) { - map = &heap->map[i]; - - /* size of requested buffer is adjusted for alignment purposes - * we check if first free block is already aligned if not - * we need to allocate bigger size for alignment - */ - if (alignment && - ((map->base + (map->block_size * map->first_free)) % - alignment)) - temp_bytes += alignment; - - /* is block big enough */ - if (map->block_size < temp_bytes) { - temp_bytes = bytes; - continue; - } - - /* does block have free space */ - if (map->free_count == 0) { - temp_bytes = bytes; - continue; - } - - /* free block space exists */ - ptr = alloc_block(heap, i, caps, alignment); - - break; - } - - return ptr; -} - -/* free block(s) */ -static void free_block(void *ptr) -{ - struct mm_heap *heap; - struct block_map *block_map = NULL; - struct block_hdr *hdr; - void *cached_ptr = uncache_to_cache(ptr); - void *uncached_ptr = cache_to_uncache(ptr); - void *free_ptr; - int i; - int block; - int used_blocks; - bool heap_is_full; - - /* try cached_ptr first */ - heap = get_heap_from_ptr(cached_ptr); - - /* try uncached_ptr if needed */ - if (!heap) { - heap = get_heap_from_ptr(uncached_ptr); - if (!heap) { - tr_err(&mem_tr, "free_block(): invalid heap, ptr = %p, cpu = %d", - ptr, cpu_get_id()); - return; - } - free_ptr = uncached_ptr; - } else { - free_ptr = cached_ptr; - } - - /* find block that ptr belongs to */ - for (i = 0; i < heap->blocks; i++) { - block_map = &heap->map[i]; - - /* is ptr in this block */ - if ((uint32_t)free_ptr < (block_map->base + - (block_map->block_size * block_map->count))) - break; - - } - - if (i == heap->blocks) { - - /* not found */ - tr_err(&mem_tr, "free_block(): invalid free_ptr = %p cpu = %d", - free_ptr, cpu_get_id()); - return; - } - - /* calculate block header */ - block = ((uint32_t)free_ptr - block_map->base) / block_map->block_size; - - hdr = &block_map->block[block]; - - /* bring back original unaligned pointer position - * and calculate correct hdr for free operation (it could - * be from different block since we got user pointer here - * or null if header was not set) - */ - if (hdr->unaligned_ptr != free_ptr && hdr->unaligned_ptr) { - free_ptr = hdr->unaligned_ptr; - block = ((uint32_t)free_ptr - block_map->base) - / block_map->block_size; - hdr = &block_map->block[block]; - } - - /* report an error if ptr is not aligned to block */ - if (block_map->base + block_map->block_size * block != (uint32_t)free_ptr) - sof_panic(SOF_IPC_PANIC_MEM); - - /* There may still be live dirty cache lines in the region - * on the current core. Those must be invalidated, otherwise - * they will be evicted from the cache at some point in the - * future, on top of the memory region now being used for - * different purposes on another core. - */ - dcache_writeback_invalidate_region(ptr, block_map->block_size * hdr->size); - - heap_is_full = !block_map->free_count; - - /* free block header and continuous blocks */ - used_blocks = block + hdr->size; - - for (i = block; i < used_blocks; i++) { - hdr = &block_map->block[i]; - hdr->size = 0; - hdr->used = 0; - hdr->unaligned_ptr = NULL; - block_map->free_count++; - heap->info.used -= block_map->block_size; - heap->info.free += block_map->block_size; - } - - /* set first free block */ - if (block < block_map->first_free || heap_is_full) - block_map->first_free = block; - -#if CONFIG_DEBUG_BLOCK_FREE - /* memset the whole block in case of unaligned ptr */ - validate_memory( - (void *)(block_map->base + block_map->block_size * block), - block_map->block_size * (i - block)); - memset( - (void *)(block_map->base + block_map->block_size * block), - DEBUG_BLOCK_FREE_VALUE_8BIT, block_map->block_size * - (i - block)); -#endif -} - -#if CONFIG_TRACE -void heap_trace(struct mm_heap *heap, int size) -{ - struct block_map *current_map; - int i; - int j; - - for (i = 0; i < size; i++) { - tr_info(&mem_tr, " heap: 0x%x size %d blocks %d caps 0x%x", - heap->heap, heap->size, heap->blocks, - heap->caps); - tr_info(&mem_tr, " (In Bytes) used %d free %d", heap->info.used, - heap->info.free); - - /* map[j]'s base is calculated based on map[j-1] */ - for (j = 0; j < heap->blocks; j++) { - current_map = &heap->map[j]; - - tr_info(&mem_tr, " %d Bytes blocks ID:%d base 0x%x", - current_map->block_size, j, current_map->base); - tr_info(&mem_tr, " Number of Blocks: total %d used %d free %d", - current_map->count, - (current_map->count - current_map->free_count), - current_map->free_count); - } - - heap++; - } -} - -void heap_trace_all(int force) -{ - struct mm *memmap = memmap_get(); - - /* has heap changed since last shown */ - if (memmap->heap_trace_updated || force) { - tr_info(&mem_tr, "heap: system status"); - heap_trace(memmap->system, PLATFORM_HEAP_SYSTEM); - tr_info(&mem_tr, "heap: system runtime status"); - heap_trace(memmap->system_runtime, PLATFORM_HEAP_SYSTEM_RUNTIME); - tr_info(&mem_tr, "heap: buffer status"); - heap_trace(memmap->buffer, PLATFORM_HEAP_BUFFER); - tr_info(&mem_tr, "heap: runtime status"); - heap_trace(memmap->runtime, PLATFORM_HEAP_RUNTIME); -#if CONFIG_CORE_COUNT > 1 - tr_info(&mem_tr, "heap: runtime shared status"); - heap_trace(memmap->runtime_shared, PLATFORM_HEAP_RUNTIME_SHARED); - tr_info(&mem_tr, "heap: system shared status"); - heap_trace(memmap->system_shared, PLATFORM_HEAP_SYSTEM_SHARED); -#endif - } - - memmap->heap_trace_updated = 0; - -} -#else -void heap_trace_all(int force) { } -void heap_trace(struct mm_heap *heap, int size) { } -#endif - -#define _ALLOC_FAILURE(bytes, zone, caps, flags) \ - tr_err(&mem_tr, \ - "failed to alloc 0x%x bytes zone 0x%x caps 0x%x flags 0x%x", \ - bytes, zone, caps, flags) - -#if CONFIG_DEBUG_HEAP -#define DEBUG_TRACE_PTR(ptr, bytes, zone, caps, flags) do { \ - if (trace_get()) { \ - if (!(ptr)) \ - _ALLOC_FAILURE(bytes, zone, caps, flags); \ - heap_trace_all(0); \ - } \ - } while (0) -#else -#define DEBUG_TRACE_PTR(ptr, bytes, zone, caps, flags) do { \ - if (trace_get()) { \ - if (!(ptr)) { \ - _ALLOC_FAILURE(bytes, zone, caps, flags); \ - heap_trace_all(0); \ - } \ - } \ - } while (0) -#endif - -/* allocate single block for system runtime */ -static void *rmalloc_sys_runtime(uint32_t flags, int caps, int core, - size_t bytes) -{ - struct mm *memmap = memmap_get(); - struct mm_heap *cpu_heap; - void *ptr; - - /* use the heap dedicated for the selected core */ - cpu_heap = memmap->system_runtime + core; - if ((cpu_heap->caps & caps) != caps) - sof_panic(SOF_IPC_PANIC_MEM); - - ptr = get_ptr_from_heap(cpu_heap, flags, caps, bytes, - PLATFORM_DCACHE_ALIGN); - - return ptr; -} - -/* allocate single block for runtime */ -static void *rmalloc_runtime(uint32_t flags, uint32_t caps, size_t bytes) -{ - struct mm *memmap = memmap_get(); - struct mm_heap *heap; - - /* check runtime heap for capabilities */ - heap = get_heap_from_caps(memmap->runtime, PLATFORM_HEAP_RUNTIME, caps); - if (!heap) { - /* next check buffer heap for capabilities */ - heap = get_heap_from_caps(memmap->buffer, PLATFORM_HEAP_BUFFER, - caps); - if (!heap) { - - tr_err(&mem_tr, "rmalloc_runtime(): caps = %x, bytes = %d", - caps, bytes); - - return NULL; - } - } - - return get_ptr_from_heap(heap, flags, caps, bytes, - PLATFORM_DCACHE_ALIGN); -} - -#if CONFIG_CORE_COUNT > 1 -/* allocate single block for shared */ -static void *rmalloc_runtime_shared(uint32_t flags, uint32_t caps, size_t bytes) -{ - struct mm *memmap = memmap_get(); - struct mm_heap *heap; - - /* check shared heap for capabilities */ - heap = get_heap_from_caps(memmap->runtime_shared, PLATFORM_HEAP_RUNTIME_SHARED, caps); - if (!heap) { - tr_err(&mem_tr, "rmalloc_runtime_shared(): caps = %x, bytes = %d", caps, bytes); - return NULL; - } - - return get_ptr_from_heap(heap, flags, caps, bytes, PLATFORM_DCACHE_ALIGN); -} -#endif - -static void *_malloc_unlocked(enum mem_zone zone, uint32_t flags, uint32_t caps, - size_t bytes) -{ - struct mm *memmap = memmap_get(); - void *ptr = NULL; - - switch (zone) { - case SOF_MEM_ZONE_SYS: - ptr = rmalloc_sys(memmap->system + cpu_get_id(), flags, caps, bytes); - break; - case SOF_MEM_ZONE_SYS_RUNTIME: - ptr = rmalloc_sys_runtime(flags, caps, cpu_get_id(), bytes); - break; - case SOF_MEM_ZONE_RUNTIME: - ptr = rmalloc_runtime(flags, caps, bytes); - break; -#if CONFIG_CORE_COUNT > 1 - case SOF_MEM_ZONE_RUNTIME_SHARED: - ptr = rmalloc_runtime_shared(flags, caps, bytes); - break; - case SOF_MEM_ZONE_SYS_SHARED: - ptr = rmalloc_sys(memmap->system_shared, flags, caps, bytes); - break; -#else - case SOF_MEM_ZONE_RUNTIME_SHARED: - ptr = rmalloc_runtime(flags, caps, bytes); - break; - case SOF_MEM_ZONE_SYS_SHARED: - ptr = rmalloc_sys(memmap->system, flags, caps, bytes); - break; -#endif - - default: - tr_err(&mem_tr, "rmalloc(): invalid zone"); - sof_panic(SOF_IPC_PANIC_MEM); /* logic non recoverable problem */ - break; - } - -#if CONFIG_DEBUG_BLOCK_FREE - if (ptr) - bzero(ptr, bytes); -#endif - - memmap->heap_trace_updated = 1; - - return ptr; -} - -void *rmalloc(enum mem_zone zone, uint32_t flags, uint32_t caps, size_t bytes) -{ - struct mm *memmap = memmap_get(); - k_spinlock_key_t key; - void *ptr = NULL; - - key = k_spin_lock(&memmap->lock); - - ptr = _malloc_unlocked(zone, flags, caps, bytes); - - k_spin_unlock(&memmap->lock, key); - - DEBUG_TRACE_PTR(ptr, bytes, zone, caps, flags); - return ptr; -} - -/* allocates and clears memory - not for direct use, clients use rzalloc() */ -void *rzalloc(enum mem_zone zone, uint32_t flags, uint32_t caps, size_t bytes) -{ - void *ptr; - - ptr = rmalloc(zone, flags, caps, bytes); - if (ptr) - bzero(ptr, bytes); - - return ptr; -} - -void *rzalloc_core_sys(int core, size_t bytes) -{ - struct mm *memmap = memmap_get(); - k_spinlock_key_t key; - void *ptr = NULL; - - key = k_spin_lock(&memmap->lock); - - ptr = rmalloc_sys(memmap->system + core, 0, 0, bytes); - if (ptr) - bzero(ptr, bytes); - - k_spin_unlock(&memmap->lock, key); - return ptr; -} - -/* allocates continuous buffers - not for direct use, clients use rballoc() */ -static void *alloc_heap_buffer(struct mm_heap *heap, uint32_t flags, - uint32_t caps, size_t bytes, uint32_t alignment) -{ - struct block_map *map; -#if CONFIG_DEBUG_BLOCK_FREE - unsigned int temp_bytes = bytes; -#endif - unsigned int j; - int i; - void *ptr = NULL; - - /* Only allow alignment as a power of 2 */ - if ((alignment & (alignment - 1)) != 0) - sof_panic(SOF_IPC_PANIC_MEM); - - /* - * There are several cases when a memory allocation request can be - * satisfied with one buffer: - * 1. allocate 30 bytes 32-byte aligned from 32 byte buffers. Any free - * buffer is acceptable, the beginning of the buffer is used. - * 2. allocate 30 bytes 256-byte aligned from 0x180 byte buffers. 1 - * buffer is also always enough, but in some buffers a part of the - * buffer has to be skipped. - * 3. allocate 200 bytes 256-byte aligned from 0x180 byte buffers. 1 - * buffer is enough, but not every buffer is suitable. - */ - - /* will request fit in single block */ - for (i = 0, map = heap->map; i < heap->blocks; i++, map++) { - struct block_hdr *hdr; - uintptr_t free_start; - - if (map->block_size < bytes || !map->free_count) - continue; - - if (alignment <= 1) { - /* found: grab a block */ - ptr = alloc_block(heap, i, caps, alignment); - break; - } - - /* - * Usually block sizes are a power of 2 and all blocks are - * respectively aligned. But it's also possible to have - * non-power of 2 sized blocks, e.g. to optimize for typical - * ALSA allocations a map with 0x180 byte buffers can be used. - * For performance reasons we could first check the power-of-2 - * case. This can be added as an optimization later. - */ - for (j = map->first_free, hdr = map->block + j, - free_start = map->base + map->block_size * j; - j < map->count; - j++, hdr++, free_start += map->block_size) { - uintptr_t aligned; - - if (hdr->used) - continue; - - aligned = ALIGN_UP(free_start, alignment); - - if (aligned + bytes > free_start + map->block_size) - continue; - - /* Found, alloc_block_index() cannot fail */ - ptr = alloc_block_index(heap, i, alignment, j); -#if CONFIG_DEBUG_BLOCK_FREE - temp_bytes += aligned - free_start; -#endif - break; - } - - if (ptr) - break; - } - - /* request spans > 1 block */ - if (!ptr) { - /* size of requested buffer is adjusted for alignment purposes - * since we span more blocks we have to assume worst case scenario - */ - bytes += alignment; - - if (heap->size < bytes) - return NULL; - - /* - * Find the best block size for request. We know, that we failed - * to find a single large enough block, so, skip those. - */ - for (i = heap->blocks - 1; i >= 0; i--) { - map = &heap->map[i]; - - /* allocate if block size is smaller than request */ - if (map->block_size < bytes) { - ptr = alloc_cont_blocks(heap, i, caps, - bytes, alignment); - if (ptr) - break; - } - } - } - -#if CONFIG_DEBUG_BLOCK_FREE - if (ptr) - bzero(ptr, temp_bytes); -#endif - - return ptr; -} - -static void *_balloc_unlocked(uint32_t flags, uint32_t caps, size_t bytes, - uint32_t alignment) -{ - struct mm *memmap = memmap_get(); - struct mm_heap *heap; - unsigned int i, n; - void *ptr = NULL; - - for (i = 0, n = PLATFORM_HEAP_BUFFER, heap = memmap->buffer; - i < PLATFORM_HEAP_BUFFER; - i = heap - memmap->buffer + 1, n = PLATFORM_HEAP_BUFFER - i, - heap++) { - heap = get_heap_from_caps(heap, n, caps); - if (!heap) - break; - - ptr = alloc_heap_buffer(heap, flags, caps, bytes, alignment); - if (ptr) - break; - - /* Continue from the next heap */ - } - - /* return directly if allocation failed */ - if (!ptr) - return ptr; - -#ifdef CONFIG_DEBUG_FORCE_COHERENT_BUFFER - return cache_to_uncache(ptr); -#else - return (flags & SOF_MEM_FLAG_COHERENT) && (CONFIG_CORE_COUNT > 1) ? - cache_to_uncache(ptr) : uncache_to_cache(ptr); -#endif -} - -/* allocates continuous buffers - not for direct use, clients use rballoc() */ -void *rballoc_align(uint32_t flags, uint32_t caps, size_t bytes, +void *rballoc_align(uint32_t flags, size_t bytes, uint32_t alignment) { - struct mm *memmap = memmap_get(); - void *ptr = NULL; - k_spinlock_key_t key; - - key = k_spin_lock(&memmap->lock); - - ptr = _balloc_unlocked(flags, caps, bytes, alignment); - - k_spin_unlock(&memmap->lock, key); - - DEBUG_TRACE_PTR(ptr, bytes, SOF_MEM_ZONE_BUFFER, caps, flags); - return ptr; -} - -static void _rfree_unlocked(void *ptr) -{ - struct mm *memmap = memmap_get(); - struct mm_heap *heap; - - /* sanity check - NULL ptrs are fine */ - if (!ptr) - return; - - /* prepare pointer if it's platform requirement */ - ptr = platform_rfree_prepare(ptr); - - /* use the heap dedicated for the core or shared memory */ -#if CONFIG_CORE_COUNT > 1 - if (is_uncached(ptr)) - heap = memmap->system_shared; - else - heap = memmap->system + cpu_get_id(); -#else - heap = memmap->system; -#endif - - /* panic if pointer is from system heap */ - if (ptr >= (void *)heap->heap && - (char *)ptr < (char *)heap->heap + heap->size) { - tr_err(&mem_tr, "rfree(): attempt to free system heap = %p, cpu = %d", - ptr, cpu_get_id()); - sof_panic(SOF_IPC_PANIC_MEM); - } - - /* free the block */ - free_block(ptr); - memmap->heap_trace_updated = 1; - + return aligned_alloc(alignment, bytes); } void rfree(void *ptr) { - struct mm *memmap = memmap_get(); - k_spinlock_key_t key; - - key = k_spin_lock(&memmap->lock); - _rfree_unlocked(ptr); - k_spin_unlock(&memmap->lock, key); -} - -void *rbrealloc_align(void *ptr, uint32_t flags, uint32_t caps, size_t bytes, - size_t old_bytes, uint32_t alignment) -{ - struct mm *memmap = memmap_get(); - void *new_ptr = NULL; - k_spinlock_key_t key; - size_t copy_bytes = MIN(bytes, old_bytes); - - if (!bytes) - return new_ptr; - - key = k_spin_lock(&memmap->lock); - - new_ptr = _balloc_unlocked(flags, caps, bytes, alignment); - - if (new_ptr && ptr && !(flags & SOF_MEM_FLAG_NO_COPY)) - memcpy_s(new_ptr, copy_bytes, ptr, copy_bytes); - - if (new_ptr) - _rfree_unlocked(ptr); - - k_spin_unlock(&memmap->lock, key); - - DEBUG_TRACE_PTR(ptr, bytes, SOF_MEM_ZONE_BUFFER, caps, flags); - return new_ptr; + free(ptr); } /* TODO: all mm_pm_...() routines to be implemented for IMR storage */ @@ -1014,113 +44,29 @@ uint32_t mm_pm_context_size(void) return 0; } -void free_heap(enum mem_zone zone) +void free_heap(void) { - struct mm *memmap = memmap_get(); - struct mm_heap *cpu_heap; - - /* to be called by secondary cores only for sys heap, - * otherwise this is critical flow issue. - */ - if (cpu_get_id() == PLATFORM_PRIMARY_CORE_ID || - zone != SOF_MEM_ZONE_SYS) { - tr_err(&mem_tr, "free_heap(): critical flow issue"); - sof_panic(SOF_IPC_PANIC_MEM); - } - - cpu_heap = memmap->system + cpu_get_id(); - cpu_heap->info.used = 0; - cpu_heap->info.free = cpu_heap->size; - } /* initialise map */ void init_heap(struct sof *sof) { - struct mm *memmap = sof->memory_map; - -#if !CONFIG_LIBRARY - extern uintptr_t _system_heap_start; - - /* sanity check for malformed images or loader issues */ - if (memmap->system[0].heap != (uintptr_t)&_system_heap_start) - sof_panic(SOF_IPC_PANIC_MEM); -#endif - - init_heap_map(memmap->system_runtime, PLATFORM_HEAP_SYSTEM_RUNTIME); - - init_heap_map(memmap->runtime, PLATFORM_HEAP_RUNTIME); - -#if CONFIG_CORE_COUNT > 1 - init_heap_map(memmap->runtime_shared, PLATFORM_HEAP_RUNTIME_SHARED); -#endif - - init_heap_map(memmap->buffer, PLATFORM_HEAP_BUFFER); - -#if CONFIG_DEBUG_BLOCK_FREE - write_pattern((struct mm_heap *)&memmap->buffer, PLATFORM_HEAP_BUFFER, - DEBUG_BLOCK_FREE_VALUE_8BIT); - write_pattern((struct mm_heap *)&memmap->runtime, PLATFORM_HEAP_RUNTIME, - DEBUG_BLOCK_FREE_VALUE_8BIT); -#endif - - k_spinlock_init(&memmap->lock); } #if CONFIG_DEBUG_MEMORY_USAGE_SCAN -int heap_info(enum mem_zone zone, int index, struct mm_info *out) +int heap_info(int index, struct mm_info *out) { - struct mm *memmap = memmap_get(); - struct mm_heap *heap; - k_spinlock_key_t key; - - if (!out) - goto error; - - switch (zone) { - case SOF_MEM_ZONE_SYS: - if (index >= PLATFORM_HEAP_SYSTEM) - goto error; - heap = memmap->system + index; - break; - case SOF_MEM_ZONE_SYS_RUNTIME: - if (index >= PLATFORM_HEAP_SYSTEM_RUNTIME) - goto error; - heap = memmap->system_runtime + index; - break; - case SOF_MEM_ZONE_RUNTIME: - if (index >= PLATFORM_HEAP_RUNTIME) - goto error; - heap = memmap->runtime + index; - break; - case SOF_MEM_ZONE_BUFFER: - if (index >= PLATFORM_HEAP_BUFFER) - goto error; - heap = memmap->buffer + index; - break; -#if CONFIG_CORE_COUNT > 1 - case SOF_MEM_ZONE_SYS_SHARED: - if (index >= PLATFORM_HEAP_SYSTEM_SHARED) - goto error; - heap = memmap->system_shared + index; - break; - case SOF_MEM_ZONE_RUNTIME_SHARED: - if (index >= PLATFORM_HEAP_RUNTIME_SHARED) - goto error; - heap = memmap->runtime_shared + index; - break; -#endif - default: - goto error; - } - - key = k_spin_lock(&memmap->lock); - *out = heap->info; - k_spin_unlock(&memmap->lock, key); return 0; -error: - tr_err(&mem_tr, "heap_info(): failed for zone 0x%x index %d out ptr 0x%x", zone, index, - (uint32_t)out); - return -EINVAL; } #endif + +void *sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, + size_t alignment) +{ + return malloc(bytes); +} + +void sof_heap_free(struct k_heap *heap, void *addr) +{ + free(addr); +} diff --git a/src/lib/ams.c b/src/lib/ams.c index 9d2dc2d7a102..7f4e6ebb8664 100644 --- a/src/lib/ams.c +++ b/src/lib/ams.c @@ -16,7 +16,6 @@ #include <sof/ipc/topology.h> #include <rtos/idc.h> #include <rtos/alloc.h> -#include <sof/lib/memory.h> #include <errno.h> #include <stdbool.h> #include <stddef.h> @@ -285,9 +284,13 @@ static uint32_t ams_push_slot(struct ams_shared_context __sparse_cache *ctx_shar for (uint32_t i = 0; i < ARRAY_SIZE(ctx_shared->slots); ++i) { if (ctx_shared->slot_uses[i] == 0) { + /* the slot only carries the payload struct (read back + * via u.msg); message points to a caller-owned buffer + * rather than inline data, so copy exactly the struct + */ err = memcpy_s((__sparse_force void *)ctx_shared->slots[i].u.msg_raw, sizeof(ctx_shared->slots[i].u.msg_raw), - msg, AMS_MESSAGE_SIZE(msg)); + msg, sizeof(*msg)); if (err != 0) return AMS_INVALID_SLOT; @@ -495,7 +498,7 @@ static int ams_process_slot(struct async_message_service *ams, uint32_t slot) instance_id = shared_c->slots[slot].instance_id; ams_release(shared_c); - tr_info(&ams_tr, "ams_process_slot slot %d msg %d from 0x%08x", + tr_info(&ams_tr, "slot %d msg %d from 0x%08x", slot, msg.message_type_id, msg.producer_module_id << 16 | msg.producer_instance_id); @@ -578,14 +581,16 @@ static int ams_create_shared_context(struct ams_shared_context *ctx) return 0; } -int ams_init(void) +__cold int ams_init(void) { struct ams_shared_context *ams_shared_ctx; struct async_message_service **ams = arch_ams_get(); struct sof *sof; int ret = 0; - *ams = rzalloc(SOF_MEM_ZONE_SYS, SOF_MEM_FLAG_COHERENT, SOF_MEM_CAPS_RAM, + assert_can_be_cold(); + + *ams = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(**ams)); if (!*ams) return -ENOMEM; diff --git a/src/lib/clk.c b/src/lib/clk.c index 779d8b76e03d..1b5025b616cb 100644 --- a/src/lib/clk.c +++ b/src/lib/clk.c @@ -83,42 +83,12 @@ void clock_low_power_mode(int clock, bool enable) clk_info->low_power_mode(clock, enable); } -#ifndef __ZEPHYR__ -uint64_t clock_ms_to_ticks(int clock, uint64_t ms) -{ - struct clock_info *clk_info = clocks_get() + clock; - uint64_t ticks; - - ticks = clk_info->freqs[clk_info->current_freq_idx].ticks_per_msec * ms; - - return ticks; -} - -uint64_t clock_us_to_ticks(int clock, uint64_t us) -{ - struct clock_info *clk_info = clocks_get() + clock; - uint64_t ticks; - - ticks = clk_info->freqs[clk_info->current_freq_idx].ticks_per_msec * us / 1000ULL; - - return ticks; -} - -uint64_t clock_ns_to_ticks(int clock, uint64_t ns) -{ - struct clock_info *clk_info = clocks_get() + clock; - - return clk_info->freqs[clk_info->current_freq_idx].ticks_per_msec * ns / 1000000ULL; -} -#endif /* __ZEPHYR__ */ - uint64_t clock_ticks_per_sample(int clock, uint32_t sample_rate) { struct clock_info *clk_info = clocks_get() + clock; uint32_t ticks_per_msec; uint64_t ticks_per_sample; - platform_shared_get(clk_info, sizeof(*clk_info)); ticks_per_msec = clk_info->freqs[clk_info->current_freq_idx].ticks_per_msec; ticks_per_sample = sample_rate ? ticks_per_msec * 1000 / sample_rate : 0; diff --git a/src/lib/cpu-clk-manager.c b/src/lib/cpu-clk-manager.c index ee92196aea2e..df917fab4f9d 100644 --- a/src/lib/cpu-clk-manager.c +++ b/src/lib/cpu-clk-manager.c @@ -11,9 +11,7 @@ #include <rtos/clk.h> #include <sof/math/numbers.h> #include <errno.h> -#ifdef __ZEPHYR__ #include <zephyr/sys/util.h> -#endif /* __ZEPHYR__ */ static struct kcps_budget_data kcps_data; @@ -30,6 +28,13 @@ static int request_freq_change(unsigned int core, int freq) break; } + /* if no entry was larger than the requested frequency the loop ends with + * selected_freq_id == clk->freqs_num; clamp to the last valid entry + * before indexing + */ + if (selected_freq_id == clk->freqs_num) + selected_freq_id = clk->freqs_num - 1; + /* don't change clock frequency if already using proper clock */ current_freq = clock_get_freq(core); if (clk->freqs[selected_freq_id].freq != current_freq) diff --git a/src/lib/dai.c b/src/lib/dai.c index 1a3a49ab3596..68163282adc1 100644 --- a/src/lib/dai.c +++ b/src/lib/dai.c @@ -11,6 +11,7 @@ #include <sof/lib/uuid.h> #include <rtos/spinlock.h> #include <sof/trace/trace.h> +#include <sof/schedule/ll_schedule_domain.h> /* for zephyr_ll_user_heap() */ #include <ipc/topology.h> #include <ipc/dai.h> #include <user/trace.h> @@ -34,13 +35,20 @@ struct dai_group_list { static struct dai_group_list *groups[CONFIG_CORE_COUNT]; -static struct dai_group_list *dai_group_list_get(int core_id) +__cold static struct dai_group_list *dai_group_list_get(int core_id) { struct dai_group_list *group_list = groups[core_id]; + assert_can_be_cold(); + if (!group_list) { - group_list = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, + group_list = rzalloc(SOF_MEM_FLAG_USER, sizeof(*group_list)); + if (!group_list) { + tr_err(&dai_tr, "dai_group_list_get(): failed to allocate group_list for core %d", + core_id); + return NULL; + } groups[core_id] = group_list; list_init(&group_list->list); @@ -49,13 +57,22 @@ static struct dai_group_list *dai_group_list_get(int core_id) return group_list; } -static struct dai_group *dai_group_find(uint32_t group_id) +__cold static struct dai_group *dai_group_find(uint32_t group_id) { struct list_item *dai_groups; + struct dai_group_list *group_list; struct list_item *group_item; struct dai_group *group = NULL; - dai_groups = &dai_group_list_get(cpu_get_id())->list; + assert_can_be_cold(); + + group_list = dai_group_list_get(cpu_get_id()); + if (!group_list) { + tr_err(&dai_tr, "dai_group_find(): failed to get group_list for core %d", + cpu_get_id()); + return NULL; + } + dai_groups = &group_list->list; list_for_item(group_item, dai_groups) { group = container_of(group_item, struct dai_group, list); @@ -69,23 +86,38 @@ static struct dai_group *dai_group_find(uint32_t group_id) return group; } -static struct dai_group *dai_group_alloc() +__cold static struct dai_group *dai_group_alloc(void) { - struct list_item *dai_groups = &dai_group_list_get(cpu_get_id())->list; + struct dai_group_list *group_list = dai_group_list_get(cpu_get_id()); + struct list_item *dai_groups; struct dai_group *group; - group = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, + assert_can_be_cold(); + if (!group_list) { + tr_err(&dai_tr, "dai_group_alloc(): failed to get group_list for core %d", + cpu_get_id()); + return NULL; + } + dai_groups = &group_list->list; + + group = rzalloc(SOF_MEM_FLAG_USER, sizeof(*group)); + if (!group) { + tr_err(&dai_tr, "dai_group_alloc(): failed to allocate dai group"); + return NULL; + } list_item_prepend(&group->list, dai_groups); return group; } -struct dai_group *dai_group_get(uint32_t group_id, uint32_t flags) +__cold struct dai_group *dai_group_get(uint32_t group_id, uint32_t flags) { struct dai_group *group; + assert_can_be_cold(); + if (!group_id) { tr_err(&dai_tr, "dai_group_get(): invalid group_id %u", group_id); @@ -117,8 +149,10 @@ struct dai_group *dai_group_get(uint32_t group_id, uint32_t flags) return group; } -void dai_group_put(struct dai_group *group) +__cold void dai_group_put(struct dai_group *group) { + assert_can_be_cold(); + group->num_dais--; /* Mark as unused if there are no more DAIs in this group */ @@ -149,20 +183,89 @@ const struct device *zephyr_dev[] = { #if CONFIG_DAI_NXP_ESAI DT_FOREACH_STATUS_OKAY(nxp_dai_esai, GET_DEVICE_LIST) #endif +#if CONFIG_DAI_NXP_MICFIL + DT_FOREACH_STATUS_OKAY(nxp_dai_micfil, GET_DEVICE_LIST) +#endif +#if CONFIG_DAI_AMD_SDW + DT_FOREACH_STATUS_OKAY(amd_acp_sdw_dai, GET_DEVICE_LIST) +#endif +#if CONFIG_DAI_AMD_TDM + DT_FOREACH_STATUS_OKAY(amd_tdm_dai, GET_DEVICE_LIST) +#endif +#if CONFIG_DAI_INTEL_UAOL + DT_FOREACH_STATUS_OKAY(intel_uaol_dai, GET_DEVICE_LIST) +#endif +#if DT_HAS_COMPAT_STATUS_OKAY(mediatek_afe) + DT_FOREACH_STATUS_OKAY(mediatek_afe, GET_DEVICE_LIST) +#endif }; -const struct device *dai_get_device(uint32_t type, uint32_t index) +const struct device **dai_get_device_list(size_t *count) +{ + __ASSERT_NO_MSG(count); + *count = ARRAY_SIZE(zephyr_dev); + + return zephyr_dev; +} + +/* convert sof_ipc_dai_type to Zephyr dai_type */ +static int sof_dai_type_to_zephyr(uint32_t type) +{ + switch (type) { + case SOF_DAI_INTEL_SSP: + return DAI_INTEL_SSP; + case SOF_DAI_INTEL_DMIC: + return DAI_INTEL_DMIC; + case SOF_DAI_INTEL_HDA: + return DAI_INTEL_HDA; + case SOF_DAI_INTEL_ALH: + return DAI_INTEL_ALH; + case SOF_DAI_INTEL_UAOL: + return DAI_INTEL_UAOL; + case SOF_DAI_IMX_SAI: + return DAI_IMX_SAI; + case SOF_DAI_IMX_ESAI: + return DAI_IMX_ESAI; + case SOF_DAI_AMD_DMIC: + return DAI_AMD_DMIC; + case SOF_DAI_MEDIATEK_AFE: + return DAI_MEDIATEK_AFE; + case SOF_DAI_IMX_MICFIL: + return DAI_IMX_MICFIL; + case SOF_DAI_AMD_SDW: + return DAI_AMD_SDW; + case SOF_DAI_AMD_HS: + case SOF_DAI_AMD_HS_VIRTUAL: + case SOF_DAI_AMD_SP: + case SOF_DAI_AMD_SP_VIRTUAL: + case SOF_DAI_AMD_BT: + case SOF_DAI_AMD_TDM: + return DAI_AMD_TDM; + default: + return -EINVAL; + } +} + +const struct device *z_impl_dai_get_device(enum sof_ipc_dai_type type, uint32_t index) { struct dai_config cfg; + int z_type; int dir; int i; dir = (type == SOF_DAI_INTEL_DMIC) ? DAI_DIR_RX : DAI_DIR_BOTH; + z_type = sof_dai_type_to_zephyr(type); + if (z_type < 0) { + tr_err(&dai_tr, "dai_get_device: no matching zephyr DAI type for %d ret = %d", + type, z_type); + return NULL; + } + for (i = 0; i < ARRAY_SIZE(zephyr_dev); i++) { if (dai_config_get(zephyr_dev[i], &cfg, dir)) continue; - if (cfg.type == type && cfg.dai_index == index) + if (cfg.type == z_type && cfg.dai_index == index) return zephyr_dev[i]; } @@ -197,9 +300,30 @@ static void dai_set_device_params(struct dai *d) #endif break; case SOF_DAI_INTEL_HDA: + case SOF_DAI_INTEL_UAOL: d->dma_dev = SOF_DMA_DEV_HDA; d->dma_caps = SOF_DMA_CAP_HDA; break; + case SOF_DAI_AMD_SDW: + d->dma_dev = SOF_DMA_DEV_SW; + d->dma_caps = SOF_DMA_CAP_SW; + break; + /* All TDM-capable AMD DAIs share acp_tdm_dma. */ + case SOF_DAI_AMD_HS: + case SOF_DAI_AMD_HS_VIRTUAL: + case SOF_DAI_AMD_SP: + case SOF_DAI_AMD_SP_VIRTUAL: + case SOF_DAI_AMD_BT: + d->dma_dev = SOF_DMA_DEV_HS | SOF_DMA_DEV_SP | SOF_DMA_DEV_BT; + d->dma_caps = SOF_DMA_CAP_HS | SOF_DMA_CAP_SP | SOF_DMA_CAP_BT; + break; + case SOF_DAI_AMD_TDM: + d->dma_dev = SOF_DMA_DEV_TDM; + d->dma_caps = SOF_DMA_CAP_TDM; + break; + case SOF_DAI_MEDIATEK_AFE: + d->dma_dev = SOF_DMA_DEV_AFE_MEMIF; + break; default: break; } @@ -210,6 +334,11 @@ struct dai *dai_get(uint32_t type, uint32_t index, uint32_t flags) { const struct device *dev; struct dai *d; + struct k_heap *heap = NULL; + +#ifdef CONFIG_SOF_USERSPACE_LL + heap = zephyr_ll_user_heap(); +#endif dev = dai_get_device(type, index); if (!dev) { @@ -218,10 +347,12 @@ struct dai *dai_get(uint32_t type, uint32_t index, uint32_t flags) return NULL; } - d = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(struct dai)); + d = sof_heap_alloc(heap, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(struct dai), 0); if (!d) return NULL; + memset(d, 0, sizeof(struct dai)); + d->index = index; d->type = type; d->dev = dev; @@ -231,7 +362,7 @@ struct dai *dai_get(uint32_t type, uint32_t index, uint32_t flags) if (dai_probe(d->dev)) { tr_err(&dai_tr, "dai_get: failed to probe dai with index %d type %d", index, type); - rfree(d); + sof_heap_free(heap, d); return NULL; } @@ -242,14 +373,19 @@ struct dai *dai_get(uint32_t type, uint32_t index, uint32_t flags) void dai_put(struct dai *dai) { int ret; + struct k_heap *heap = NULL; + +#ifdef CONFIG_SOF_USERSPACE_LL + heap = zephyr_ll_user_heap(); +#endif ret = dai_remove(dai->dev); if (ret < 0) { - tr_err(&dai_tr, "dai_put_zephyr: index %d failed ret = %d", + tr_err(&dai_tr, "index %d failed ret = %d", dai->index, ret); } - rfree(dai); + sof_heap_free(heap, dai); } #else static inline const struct dai_type_info *dai_find_type(uint32_t type) @@ -311,11 +447,11 @@ void dai_put(struct dai *dai) if (--dai->sref == 0) { ret = dai_remove(dai); if (ret < 0) { - tr_err(&dai_tr, "dai_put: type %d index %d dai_remove() failed ret = %d", + tr_err(&dai_tr, "type %d index %d dai_remove() failed ret = %d", dai->drv->type, dai->index, ret); } } - tr_info(&dai_tr, "dai_put type %d index %d new sref %d", + tr_info(&dai_tr, "type %d index %d new sref %d", dai->drv->type, dai->index, dai->sref); k_spin_unlock(&dai->lock, key); } diff --git a/src/lib/dma.c b/src/lib/dma.c index 552c487cb296..137dfb4e0fea 100644 --- a/src/lib/dma.c +++ b/src/lib/dma.c @@ -5,21 +5,27 @@ // Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> #include <rtos/atomic.h> +#include <rtos/kernel.h> #include <sof/audio/audio_stream.h> #include <sof/audio/buffer.h> +#include <sof/audio/component.h> +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include <sof/audio/mic_privacy_manager.h> +#endif #include <rtos/alloc.h> #include <rtos/cache.h> #include <sof/lib/dma.h> #include <sof/lib/memory.h> #include <sof/lib/uuid.h> #include <rtos/spinlock.h> -#include <rtos/symbol.h> #include <sof/trace/trace.h> #include <ipc/topology.h> #include <user/trace.h> #include <errno.h> #include <stddef.h> #include <stdint.h> +#include <module/module/base.h> +#include "../audio/copier/copier.h" LOG_MODULE_REGISTER(dma, CONFIG_SOF_LOG_LEVEL); @@ -28,14 +34,14 @@ SOF_DEFINE_REG_UUID(dma); DECLARE_TR_CTX(dma_tr, SOF_UUID(dma_uuid), LOG_LEVEL_INFO); #if CONFIG_ZEPHYR_NATIVE_DRIVERS -static int dma_init(struct dma *dma); +static int dma_init(struct sof_dma *dma); -struct dma *sof_dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags) +struct sof_dma *z_impl_sof_dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags) { const struct dma_info *info = dma_info_get(); int users, ret = 0; int min_users = INT32_MAX; - struct dma *d = NULL, *dmin = NULL; + struct sof_dma *d = NULL, *dmin = NULL; k_spinlock_key_t key; if (!info->num_dmas) { @@ -123,13 +129,13 @@ struct dma *sof_dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags return !ret ? dmin : NULL; } -void sof_dma_put(struct dma *dma) +void z_impl_sof_dma_put(struct sof_dma *dma) { k_spinlock_key_t key; key = k_spin_lock(&dma->lock); if (--dma->sref == 0) { - rfree(dma->chan); + sof_heap_free(dma->heap, dma->chan); dma->chan = NULL; } @@ -138,21 +144,23 @@ void sof_dma_put(struct dma *dma) k_spin_unlock(&dma->lock, key); } -static int dma_init(struct dma *dma) +static int dma_init(struct sof_dma *dma) { struct dma_chan_data *chan; + struct k_heap *heap = sof_sys_user_heap_get(); int i; /* allocate dma channels */ - dma->chan = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, - sizeof(struct dma_chan_data) * dma->plat_data.channels); - + dma->chan = sof_heap_alloc(heap, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(struct dma_chan_data) * dma->plat_data.channels, 0); if (!dma->chan) { - tr_err(&dma_tr, "dma_probe_sof(): dma %d allocaction of channels failed", + tr_err(&dma_tr, "dma %d allocation of channels failed", dma->plat_data.id); return -ENOMEM; } + dma->heap = heap; + memset(dma->chan, 0, sizeof(struct dma_chan_data) * dma->plat_data.channels); /* init work */ for (i = 0, chan = dma->chan; i < dma->plat_data.channels; i++, chan++) { @@ -162,8 +170,6 @@ static int dma_init(struct dma *dma) return 0; } -EXPORT_SYMBOL(sof_dma_get); -EXPORT_SYMBOL(sof_dma_put); #else struct dma *dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags) { @@ -272,31 +278,32 @@ void dma_put(struct dma *dma) if (--dma->sref == 0) { ret = dma_remove_legacy(dma); if (ret < 0) { - tr_err(&dma_tr, "dma_put(): dma_remove() failed id = %d, ret = %d", + tr_err(&dma_tr, "dma_remove() failed id = %d, ret = %d", dma->plat_data.id, ret); } } - tr_info(&dma_tr, "dma_put(), dma = %p, sref = %d", + tr_info(&dma_tr, "dma = %p, sref = %d", dma, dma->sref); k_spin_unlock(&dma->lock, key); } -EXPORT_SYMBOL(dma_get); -EXPORT_SYMBOL(dma_put); #endif -int dma_sg_alloc(struct dma_sg_elem_array *elem_array, - enum mem_zone zone, +int dma_sg_alloc(struct k_heap *heap, + struct dma_sg_elem_array *elem_array, + uint32_t flags, uint32_t direction, uint32_t buffer_count, uint32_t buffer_bytes, uintptr_t dma_buffer_addr, uintptr_t external_addr) { int i; - elem_array->elems = rzalloc(zone, 0, SOF_MEM_CAPS_RAM, - sizeof(struct dma_sg_elem) * buffer_count); + elem_array->elems = sof_heap_alloc(heap, SOF_MEM_FLAG_USER, + sizeof(struct dma_sg_elem) * buffer_count, 0); if (!elem_array->elems) return -ENOMEM; + memset(elem_array->elems, 0, sizeof(struct dma_sg_elem) * buffer_count); + for (i = 0; i < buffer_count; i++) { elem_array->elems[i].size = buffer_bytes; // TODO: may count offsets once @@ -318,12 +325,11 @@ int dma_sg_alloc(struct dma_sg_elem_array *elem_array, return 0; } -void dma_sg_free(struct dma_sg_elem_array *elem_array) +void dma_sg_free(struct k_heap *heap, struct dma_sg_elem_array *elem_array) { - rfree(elem_array->elems); + sof_heap_free(heap, elem_array->elems); dma_sg_init(elem_array); } -EXPORT_SYMBOL(dma_sg_free); int dma_buffer_copy_from(struct comp_buffer *source, struct comp_buffer *sink, @@ -453,7 +459,8 @@ int dma_buffer_copy_to(struct comp_buffer *source, return ret; } -int stream_copy_from_no_consume(struct comp_buffer *source, struct comp_buffer *sink, +int stream_copy_from_no_consume(struct comp_dev *dev, struct comp_buffer *source, + struct comp_buffer *sink, dma_process_func process, uint32_t source_bytes, uint32_t chmap) { int source_channels = audio_stream_get_channels(&source->stream); @@ -501,6 +508,14 @@ int stream_copy_from_no_consume(struct comp_buffer *source, struct comp_buffer * /* process data */ ret = process(istream, 0, &sink->stream, 0, source_samples, chmap); +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + struct processing_module *mod = comp_mod(dev); + struct copier_data *cd = module_get_private_data(mod); + + if (cd->mic_priv) + mic_privacy_process(dev, cd->mic_priv, sink, source_samples); +#endif + buffer_stream_writeback(sink, sink_bytes); comp_update_buffer_produce(sink, sink_bytes); diff --git a/src/lib/notifier.c b/src/lib/notifier.c index 4b096111019c..102dc55fc7b3 100644 --- a/src/lib/notifier.c +++ b/src/lib/notifier.c @@ -59,11 +59,11 @@ int notifier_register(void *receiver, void *caller, enum notify_id type, goto out; } - handle = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_RAM, + handle = rzalloc(SOF_MEM_FLAG_USER, sizeof(*handle)); if (!handle) { - tr_err(&nt_tr, "notifier_register(): callback handle allocation failed."); + tr_err(&nt_tr, "callback handle allocation failed."); ret = -ENOMEM; goto out; } @@ -190,20 +190,26 @@ void notifier_event(const void *caller, enum notify_id type, uint32_t core_mask, } } -void init_system_notify(struct sof *sof) +__cold void init_system_notify(struct sof *sof) { struct notify **notify = arch_notify_get(); int i; - *notify = rzalloc(SOF_MEM_ZONE_SYS, SOF_MEM_FLAG_COHERENT, SOF_MEM_CAPS_RAM, + + assert_can_be_cold(); + + *notify = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(**notify)); + if (!*notify) { + tr_err(&nt_tr, "allocation failed"); + sof_panic(SOF_IPC_PANIC_IPC); + } k_spinlock_init(&(*notify)->lock); for (i = NOTIFIER_ID_CPU_FREQ; i < NOTIFIER_ID_COUNT; i++) list_init(&(*notify)->list[i]); if (cpu_get_id() == PLATFORM_PRIMARY_CORE_ID) - sof->notify_data = platform_shared_get(notify_data_shared, - sizeof(notify_data_shared)); + sof->notify_data = notify_data_shared; } void free_system_notify(void) diff --git a/src/lib/objpool.c b/src/lib/objpool.c new file mode 100644 index 000000000000..9636e018d3d1 --- /dev/null +++ b/src/lib/objpool.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <rtos/alloc.h> +#include <rtos/bit.h> +#include <sof/objpool.h> +#include <sof/common.h> +#include <sof/list.h> +#include <sof/lib/vregion.h> + +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +struct objpool { + struct list_item list; + unsigned int n; + uint32_t mask; + size_t size; + uint8_t data[]; +}; + +#define OBJPOOL_BITS (sizeof(((struct objpool *)0)->mask) * 8) + +static int objpool_add(struct objpool_head *head, unsigned int n, size_t size, uint32_t flags) +{ + if (n > OBJPOOL_BITS) + return -ENOMEM; + + if (!is_power_of_2(n)) + return -EINVAL; + + size_t aligned_size = n * ALIGN_UP(size, sizeof(int)); + + if (!head->heap) + head->heap = sof_sys_heap_get(); + + struct objpool *pobjpool; + + if (!head->vreg) + pobjpool = sof_heap_alloc(head->heap, flags, + aligned_size + sizeof(*pobjpool), 0); + else if (flags & SOF_MEM_FLAG_COHERENT) + pobjpool = vregion_alloc_coherent(head->vreg, + aligned_size + sizeof(*pobjpool)); + else + pobjpool = vregion_alloc(head->vreg, + aligned_size + sizeof(*pobjpool)); + + if (!pobjpool) + return -ENOMEM; + + /* Initialize with 0 to give caller a chance to identify new allocations */ + memset(pobjpool->data, 0, aligned_size); + + pobjpool->n = n; + /* clear bit means free */ + pobjpool->mask = 0; + pobjpool->size = size; + + list_item_append(&pobjpool->list, &head->list); + + return 0; +} + +void *objpool_alloc(struct objpool_head *head, size_t size, uint32_t flags) +{ + size_t aligned_size = ALIGN_UP(size, sizeof(int)); + struct list_item *list; + struct objpool *pobjpool; + + /* Make sure size * 32 still fits in OBJPOOL_BITS bits */ + if (!size || aligned_size > (UINT_MAX >> 5) - sizeof(*pobjpool)) + return NULL; + + if (!list_is_empty(&head->list) && head->flags != flags) + /* List isn't empty, and flags don't match */ + return NULL; + + list_for_item(list, &head->list) { + pobjpool = container_of(list, struct objpool, list); + + uint32_t free_mask = MASK(pobjpool->n - 1, 0) & ~pobjpool->mask; + + /* sanity check */ + if (size != pobjpool->size) + return NULL; + + if (!free_mask) + continue; + + /* Find first free - guaranteed valid now */ + unsigned int bit = ffs(free_mask) - 1; + + pobjpool->mask |= BIT(bit); + + return pobjpool->data + aligned_size * bit; + } + + /* no free elements found */ + unsigned int new_n; + + if (list_is_empty(&head->list)) { + head->flags = flags; + new_n = 2; + } else { + /* Check the last one */ + pobjpool = container_of(head->list.prev, struct objpool, list); + + if (pobjpool->n == OBJPOOL_BITS) + new_n = OBJPOOL_BITS; + else + new_n = pobjpool->n << 1; + } + + if (objpool_add(head, new_n, size, flags) < 0) + return NULL; + + /* Return the first element of the new objpool, which is now the last one in the list */ + pobjpool = container_of(head->list.prev, struct objpool, list); + pobjpool->mask = 1; + + return pobjpool->data; +} + +int objpool_free(struct objpool_head *head, void *data) +{ + struct list_item *list; + struct objpool *pobjpool; + + if (!data) + return 0; + + list_for_item(list, &head->list) { + pobjpool = container_of(list, struct objpool, list); + + size_t aligned_size = ALIGN_UP(pobjpool->size, sizeof(int)); + + if ((uint8_t *)data >= pobjpool->data && + (uint8_t *)data < pobjpool->data + aligned_size * pobjpool->n) { + unsigned int n = ((uint8_t *)data - pobjpool->data) / aligned_size; + + if ((uint8_t *)data != pobjpool->data + n * aligned_size) + return -EINVAL; + + pobjpool->mask &= ~BIT(n); + + return 0; + } + } + + return -EINVAL; +} + +void objpool_prune(struct objpool_head *head) +{ + struct list_item *next, *tmp; + + list_for_item_safe(next, tmp, &head->list) { + struct objpool *pool = container_of(next, struct objpool, list); + + list_item_del(next); + if (head->vreg) + vregion_free(head->vreg, pool); + else + sof_heap_free(head->heap, pool); + } +} + +int objpool_iterate(struct objpool_head *head, objpool_iterate_cb cb, void *arg) +{ + struct list_item *list; + + list_for_item(list, &head->list) { + struct objpool *pobjpool = container_of(list, struct objpool, list); + size_t aligned_size = ALIGN_UP(pobjpool->size, sizeof(int)); + unsigned int bit; + + for (uint32_t mask = pobjpool->mask; mask; mask &= ~BIT(bit)) { + bit = ffs(mask) - 1; + + if (cb(pobjpool->data + bit * aligned_size, arg)) + return 0; + } + } + + return -ENOENT; +} diff --git a/src/lib/pm_runtime.c b/src/lib/pm_runtime.c deleted file mode 100644 index 1c2e54fe2da2..000000000000 --- a/src/lib/pm_runtime.c +++ /dev/null @@ -1,189 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - -/** - * \file - * \brief Runtime power management implementation - * \author Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#include <rtos/timer.h> -#include <rtos/alloc.h> -#include <sof/lib/memory.h> -#include <sof/lib/pm_runtime.h> -#include <sof/lib/uuid.h> -#include <rtos/sof.h> -#include <rtos/spinlock.h> -#include <ipc/topology.h> -#include <stdint.h> - -#if defined(__ZEPHYR__) -#include <zephyr/pm/policy.h> -#endif - -LOG_MODULE_REGISTER(pm_runtime, CONFIG_SOF_LOG_LEVEL); - -SOF_DEFINE_REG_UUID(pm_runtime); - -DECLARE_TR_CTX(pm_tr, SOF_UUID(pm_runtime_uuid), LOG_LEVEL_INFO); - -void pm_runtime_init(struct sof *sof) -{ - sof->prd = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*sof->prd)); - k_spinlock_init(&sof->prd->lock); - - platform_pm_runtime_init(sof->prd); -} - -/* Warning: the terms in this API (enable, active,... ) apply sometimes - * to power _management_ and other times to _power_ which can be - * confusing. They are however consistent with - * https://www.kernel.org/doc/Documentation/power/runtime_pm.txt and the - * long tradition of double and triple negations in power management. - */ - -/** Increase the usage counter of some PM context. In general this - * blocks low power state but there are exception(s), for instance the - * context for the PM_RUNTIME_HOST_DMA_L1 is reversed: usage blocks high - * power state. - * - * Warning: some (all?) platforms don't really implement any counter, in - * other words the "counter" is silently maxed at 1. - */ -void pm_runtime_get(enum pm_runtime_context context, uint32_t index) -{ - tr_dbg(&pm_tr, "pm_runtime_get() context %d index %d", context, index); - - switch (context) { - default: - platform_pm_runtime_get(context, index, RPM_ASYNC); - break; - } -} - -void pm_runtime_get_sync(enum pm_runtime_context context, uint32_t index) -{ - tr_dbg(&pm_tr, "pm_runtime_get_sync() context %d index %d", context, - index); - - switch (context) { - default: - platform_pm_runtime_get(context, index, 0); - break; - } -} - -/** Decreases the usage counter of some PM context, see pm_runtime_get() - */ -void pm_runtime_put(enum pm_runtime_context context, uint32_t index) -{ - tr_dbg(&pm_tr, "pm_runtime_put() context %d index %d", context, index); - - switch (context) { - default: - platform_pm_runtime_put(context, index, RPM_ASYNC); - break; - } -} - -void pm_runtime_put_sync(enum pm_runtime_context context, uint32_t index) -{ - tr_dbg(&pm_tr, "pm_runtime_put_sync() context %d index %d", context, - index); - - switch (context) { - default: - platform_pm_runtime_put(context, index, 0); - break; - } -} - -/** Enables power _management_. The management, not the power. */ -void pm_runtime_enable(enum pm_runtime_context context, uint32_t index) -{ - tr_dbg(&pm_tr, "pm_runtime_enable() context %d index %d", context, - index); - - switch (context) { - default: - platform_pm_runtime_enable(context, index); - break; - } -} - -/** Disables power _management_. The management, not the power. */ -void pm_runtime_disable(enum pm_runtime_context context, uint32_t index) -{ - tr_dbg(&pm_tr, "pm_runtime_disable() context %d index %d", context, - index); - - switch (context) { - default: - platform_pm_runtime_disable(context, index); - break; - } -} - -/** Is the _power_ active. The power, not its management. */ -bool pm_runtime_is_active(enum pm_runtime_context context, uint32_t index) -{ - tr_dbg(&pm_tr, "pm_runtime_is_active() context %d index %d", context, - index); -#if defined(__ZEPHYR__) && defined(CONFIG_PM) - return pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); -#else - switch (context) { - default: - return platform_pm_runtime_is_active(context, index); - } -#endif -} - -#if CONFIG_DSP_RESIDENCY_COUNTERS -void init_dsp_r_state(enum dsp_r_state r_state) -{ - struct pm_runtime_data *prd = pm_runtime_data_get(); - struct r_counters_data *r_counters; - - r_counters = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*r_counters)); - prd->r_counters = r_counters; - - r_counters->ts = sof_cycle_get_64(); - r_counters->cur_r_state = r_state; -} - -void report_dsp_r_state(enum dsp_r_state r_state) -{ - struct r_counters_data *r_counters = pm_runtime_data_get()->r_counters; - uint64_t ts, delta; - - /* It is possible to call report_dsp_r_state in early platform init from - * pm_runtime_disable so a safe check for r_counters is required - */ - if (!r_counters || r_counters->cur_r_state == r_state) - return; - - ts = sof_cycle_get_64(); - delta = ts - r_counters->ts; - - delta += mailbox_sw_reg_read64(SRAM_REG_R_STATE_TRACE_BASE + - r_counters->cur_r_state * - sizeof(uint64_t)); - - mailbox_sw_reg_write64(SRAM_REG_R_STATE_TRACE_BASE + r_counters->cur_r_state - * sizeof(uint64_t), delta); - - r_counters->cur_r_state = r_state; - r_counters->ts = ts; -} - -enum dsp_r_state get_dsp_r_state(void) -{ - struct r_counters_data *r_counters = pm_runtime_data_get()->r_counters; - - return r_counters ? r_counters->cur_r_state : 0; -} -#endif diff --git a/src/lib/wait.c b/src/lib/wait.c deleted file mode 100644 index 14c21d621209..000000000000 --- a/src/lib/wait.c +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2016 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - -/* - * Simple wait for event completion and signaling with timeouts. - */ - -#include <rtos/clk.h> -#include <sof/lib/io.h> -#include <sof/lib/uuid.h> -#include <rtos/wait.h> -#include <sof/platform.h> -#include <sof/schedule/schedule.h> -#include <sof/trace/trace.h> -#include <user/trace.h> -#include <errno.h> -#include <stdint.h> -#include <inttypes.h> - -LOG_MODULE_REGISTER(wait, CONFIG_SOF_LOG_LEVEL); - -SOF_DEFINE_REG_UUID(wait); - -DECLARE_TR_CTX(wait_tr, SOF_UUID(wait_uuid), LOG_LEVEL_INFO); - -#define DEFAULT_TRY_TIMES 8 - -int poll_for_register_delay(uint32_t reg, uint32_t mask, - uint32_t val, uint64_t us) -{ - uint64_t tick = k_us_to_cyc_ceil64(us); - uint32_t tries = DEFAULT_TRY_TIMES; - uint64_t delta = tick / tries; - - if (!delta) { - /* - * If we want to wait for less than DEFAULT_TRY_TIMES ticks then - * delta has to be set to 1 and number of tries to that of number - * of ticks. - */ - delta = 1; - tries = tick; - } - - while ((io_reg_read(reg) & mask) != val) { - if (!tries--) { - tr_err(&wait_tr, "poll timeout reg %u mask %u val %u us %u", - reg, mask, val, (uint32_t)us); - return -EIO; - } - wait_delay(delta); - } - return 0; -} - -void wait_delay(uint64_t number_of_clks) -{ - uint64_t timeout = sof_cycle_get_64() + number_of_clks; - - while (sof_cycle_get_64() < timeout) - idelay(PLATFORM_DEFAULT_DELAY); -} - -void wait_delay_ms(uint64_t ms) -{ - wait_delay(k_ms_to_cyc_ceil64(ms)); -} - -void wait_delay_us(uint64_t us) -{ - wait_delay(k_us_to_cyc_ceil64(us)); -} diff --git a/src/library_manager/CMakeLists.txt b/src/library_manager/CMakeLists.txt index 836b46d07fc6..e69ca4cca30c 100644 --- a/src/library_manager/CMakeLists.txt +++ b/src/library_manager/CMakeLists.txt @@ -1,5 +1,12 @@ # SPDX-License-Identifier: BSD-3-Clause if(CONFIG_LIBRARY_MANAGER) - add_local_sources(sof lib_manager.c, lib_notifications.c) + add_local_sources(sof lib_manager.c lib_notification.c) + + if (CONFIG_MM_DRV AND CONFIG_LLEXT) + add_local_sources(sof llext_manager.c) + if(CONFIG_LLEXT_EXPERIMENTAL AND NOT CONFIG_ADSP_IMR_CONTEXT_SAVE) + add_local_sources_ifdef(CONFIG_L3_HEAP sof llext_manager_dram.c) + endif() + endif() endif() diff --git a/src/library_manager/Kconfig b/src/library_manager/Kconfig index 598551a6c650..8eac39e59970 100644 --- a/src/library_manager/Kconfig +++ b/src/library_manager/Kconfig @@ -58,4 +58,10 @@ config LIBRARY_BASE_ADDRESS automatically but the beginning of that area is platform-specific and should be set by this option. +config LIBRARY_REGION_SIZE + hex "Size of memory region dedicated to loadable modules" + default 0x100000 + help + Size of the virtual memory region dedicated for loadable modules + endmenu diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index ae824d512dc5..19c317ed1089 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -3,7 +3,8 @@ // Copyright(c) 2022 Intel Corporation. All rights reserved. // // Author: Jaroslaw Stelter <jaroslaw.stelter@intel.com> -// Pawel Dobrowolski<pawelx.dobrowolski@intel.com> +// Pawel Dobrowolski <pawelx.dobrowolski@intel.com> +// Adrian Warecki <adrian.warecki@intel.com> /* * Dynamic module loading functions. @@ -18,12 +19,15 @@ #include <rtos/clk.h> #include <rtos/sof.h> #include <rtos/spinlock.h> +#include <rtos/userspace_helper.h> #include <sof/lib/cpu-clk-manager.h> #include <sof/lib_manager.h> #include <sof/llext_manager.h> #include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/module_adapter/module/modules.h> +#include <sof/audio/module_adapter/library/userspace_proxy.h> #include <utilities/array.h> +#include <system_agent.h> #include <native_system_agent.h> #include <api_version.h> #include <module/module/api_ver.h> @@ -33,9 +37,12 @@ #if CONFIG_LLEXT #include <zephyr/llext/llext.h> #endif +#include <zephyr/sys/math_extras.h> #if CONFIG_LIBRARY_AUTH_SUPPORT #include <auth/intel_auth_api.h> +#else +struct auth_api_ctx; #endif #include <errno.h> @@ -51,7 +58,7 @@ SOF_DEFINE_REG_UUID(lib_manager); DECLARE_TR_CTX(lib_manager_tr, SOF_UUID(lib_manager_uuid), LOG_LEVEL_INFO); struct lib_manager_dma_ext { - struct dma *dma; + struct sof_dma *dma; struct dma_chan_data *chan; uintptr_t dma_addr; /**< buffer start pointer */ uint32_t addr_align; @@ -60,49 +67,40 @@ struct lib_manager_dma_ext { static struct ext_library loader_ext_lib; #if CONFIG_LIBRARY_AUTH_SUPPORT -static int lib_manager_auth_init(void) +static int lib_manager_auth_init(struct auth_api_ctx *auth_ctx, void **auth_buffer) { - struct ext_library *ext_lib = ext_lib_get(); int ret; if (auth_api_version().major != AUTH_API_VERSION_MAJOR) return -EINVAL; - ext_lib->auth_buffer = rballoc_align(0, SOF_MEM_CAPS_RAM, - AUTH_SCRATCH_BUFF_SZ, CONFIG_MM_DRV_PAGE_SIZE); - if (!ext_lib->auth_buffer) + *auth_buffer = rballoc_align(SOF_MEM_FLAG_KERNEL, + AUTH_SCRATCH_BUFF_SZ, CONFIG_MM_DRV_PAGE_SIZE); + if (!*auth_buffer) return -ENOMEM; - ret = auth_api_init(&ext_lib->auth_ctx, ext_lib->auth_buffer, - AUTH_SCRATCH_BUFF_SZ, IMG_TYPE_LIB); + ret = auth_api_init(auth_ctx, *auth_buffer, AUTH_SCRATCH_BUFF_SZ, IMG_TYPE_LIB); if (ret != 0) { tr_err(&lib_manager_tr, "auth_api_init() failed with error: %d", ret); - rfree(ext_lib->auth_buffer); - ret = -EACCES; + rfree(*auth_buffer); + return -EACCES; } - return ret; + return 0; } -static void lib_manager_auth_deinit(void) +static void lib_manager_auth_deinit(struct auth_api_ctx *auth_ctx, void *auth_buffer) { - struct ext_library *ext_lib = ext_lib_get(); - - if (ext_lib->auth_buffer) - memset(ext_lib->auth_buffer, 0, AUTH_SCRATCH_BUFF_SZ); - - rfree(ext_lib->auth_buffer); - ext_lib->auth_buffer = NULL; - memset(&ext_lib->auth_ctx, 0, sizeof(struct auth_api_ctx)); + ARG_UNUSED(auth_ctx); + rfree(auth_buffer); } -static int lib_manager_auth_proc(const void *buffer_data, - size_t buffer_size, enum auth_phase phase) +static int lib_manager_auth_proc(const void *buffer_data, size_t buffer_size, + enum auth_phase phase, struct auth_api_ctx *auth_ctx) { - struct ext_library *ext_lib = ext_lib_get(); int ret; - ret = auth_api_init_auth_proc(&ext_lib->auth_ctx, buffer_data, buffer_size, phase); + ret = auth_api_init_auth_proc(auth_ctx, buffer_data, buffer_size, phase); if (ret != 0) { tr_err(&lib_manager_tr, "auth_api_init_auth_proc() failed with error: %d", ret); @@ -110,19 +108,20 @@ static int lib_manager_auth_proc(const void *buffer_data, } /* The auth_api_busy() will timeouts internally in case of failure */ - while (auth_api_busy(&ext_lib->auth_ctx)) + while (auth_api_busy(auth_ctx)) ; - ret = auth_api_result(&ext_lib->auth_ctx); + if (phase != AUTH_PHASE_LAST) + return 0; + + ret = auth_api_result(auth_ctx); + auth_api_cleanup(auth_ctx); if (ret != AUTH_IMAGE_TRUSTED) { tr_err(&lib_manager_tr, "Untrusted library!"); return -EACCES; } - if (phase == AUTH_PHASE_LAST) - auth_api_cleanup(&ext_lib->auth_ctx); - return 0; } #endif /* CONFIG_LIBRARY_AUTH_SUPPORT */ @@ -131,7 +130,7 @@ static int lib_manager_auth_proc(const void *buffer_data, #define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE -static int lib_manager_load_data_from_storage(void __sparse_cache *vma, void *s_addr, uint32_t size, +static int lib_manager_load_data_from_storage(void __sparse_cache *vma, void *s_addr, size_t size, uint32_t flags) { /* Region must be first mapped as writable in order to initialize its contents. */ @@ -149,17 +148,26 @@ static int lib_manager_load_data_from_storage(void __sparse_cache *vma, void *s_ return sys_mm_drv_update_region_flags((__sparse_force void *)vma, size, flags); } -static int lib_manager_load_module(const uint32_t module_id, - const struct sof_man_module *const mod) +static int lib_manager_load_module(const struct sof_man_fw_desc *const desc, + const uint32_t module_id, const struct sof_man_module *const mod) { struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); const uintptr_t load_offset = POINTER_TO_UINT(ctx->base_addr); + size_t lib_size; + size_t file_offset; void *src; void __sparse_cache *va_base; size_t size; uint32_t flags; int ret, idx; + /* + * ELF file segment offsets and sizes come from library files, so they + * have to be validated. + */ + if (size_mul_overflow(desc->header.preload_page_count, PAGE_SZ, &lib_size)) + return -EOVERFLOW; + for (idx = 0; idx < ARRAY_SIZE(mod->segment); ++idx) { if (!mod->segment[idx].flags.r.load) continue; @@ -171,9 +179,23 @@ static int lib_manager_load_module(const uint32_t module_id, else if (!mod->segment[idx].flags.r.readonly) flags = SYS_MM_MEM_PERM_RW; - src = UINT_TO_POINTER(mod->segment[idx].file_offset + load_offset); + file_offset = mod->segment[idx].file_offset; + if (size_mul_overflow(mod->segment[idx].flags.r.length, PAGE_SZ, &size)) { + ret = -EOVERFLOW; + goto err; + } + + /* Reject segments that would read outside the loaded library image. */ + if (file_offset > lib_size || size > lib_size - file_offset) { + tr_err(&lib_manager_tr, + "segment %d out of bounds: file_offset %#zx, size %#zx, total %#zx", + idx, file_offset, size, lib_size); + ret = -ENOSPC; + goto err; + } + + src = UINT_TO_POINTER(file_offset + load_offset); va_base = (void __sparse_cache *)UINT_TO_POINTER(mod->segment[idx].v_base_addr); - size = mod->segment[idx].flags.r.length * PAGE_SZ; ret = lib_manager_load_data_from_storage(va_base, src, size, flags); if (ret < 0) goto err; @@ -233,7 +255,8 @@ static int lib_manager_load_libcode_modules(const uint32_t module_id) for (idx = 0; idx < desc->header.num_module_entries; ++idx, ++module_entry) { if (module_entry->type.lib_code) { - ret = lib_manager_load_module(lib_id << LIB_MANAGER_LIB_ID_SHIFT | idx, + ret = lib_manager_load_module(desc, + lib_id << LIB_MANAGER_LIB_ID_SHIFT | idx, module_entry); if (ret < 0) goto err; @@ -280,31 +303,30 @@ static int lib_manager_unload_libcode_modules(const uint32_t module_id) } #endif /* CONFIG_LIBCODE_MODULE_SUPPORT */ -static void __sparse_cache *lib_manager_get_instance_bss_address(uint32_t module_id, - uint32_t instance_id, - const struct sof_man_module *mod) +void lib_manager_get_instance_bss_address(uint32_t instance_id, + const struct sof_man_module *mod, + void __sparse_cache **va_addr, size_t *size) { - uint32_t instance_bss_size = - mod->segment[SOF_MAN_SEGMENT_BSS].flags.r.length / mod->instance_max_count; - uint32_t inst_offset = instance_bss_size * PAGE_SZ * instance_id; - void __sparse_cache *va_base = - (void __sparse_cache *)(mod->segment[SOF_MAN_SEGMENT_BSS].v_base_addr + - inst_offset); + /* mod->instance_max_count should never be 0, assume 1 if that happens */ + unsigned int inst_cnt = mod->instance_max_count ? : 1; - tr_dbg(&lib_manager_tr, "instance_bss_size: %#x, pointer: %p", - instance_bss_size, (__sparse_force void *)va_base); + *size = mod->segment[SOF_MAN_SEGMENT_BSS].flags.r.length / inst_cnt * + PAGE_SZ; + size_t inst_offset = *size * instance_id; + *va_addr = (void __sparse_cache *)(mod->segment[SOF_MAN_SEGMENT_BSS].v_base_addr + + inst_offset); - return va_base; + tr_dbg(&lib_manager_tr, "instance_bss_size: %#zx, pointer: %p", *size, + (__sparse_force void *)*va_addr); } -static int lib_manager_allocate_module_instance(uint32_t module_id, uint32_t instance_id, - uint32_t is_pages, const struct sof_man_module *mod) +static int lib_manager_allocate_module_instance(uint32_t instance_id, uint32_t is_pages, + const struct sof_man_module *mod) { - uint32_t bss_size = - (mod->segment[SOF_MAN_SEGMENT_BSS].flags.r.length / mod->instance_max_count) - * PAGE_SZ; - void __sparse_cache *va_base = lib_manager_get_instance_bss_address(module_id, - instance_id, mod); + size_t bss_size; + void __sparse_cache *va_base; + + lib_manager_get_instance_bss_address(instance_id, mod, &va_base, &bss_size); if ((is_pages * PAGE_SZ) > bss_size) { tr_err(&lib_manager_tr, "invalid is_pages: %u, required: %u", @@ -324,41 +346,42 @@ static int lib_manager_allocate_module_instance(uint32_t module_id, uint32_t ins return 0; } -static int lib_manager_free_module_instance(uint32_t module_id, uint32_t instance_id, - const struct sof_man_module *mod) +static int lib_manager_free_module_instance(uint32_t instance_id, const struct sof_man_module *mod) { - uint32_t bss_size = - (mod->segment[SOF_MAN_SEGMENT_BSS].flags.r.length / mod->instance_max_count) - * PAGE_SZ; - void __sparse_cache *va_base = lib_manager_get_instance_bss_address(module_id, - instance_id, mod); + size_t bss_size; + void __sparse_cache *va_base; + + lib_manager_get_instance_bss_address(instance_id, mod, &va_base, &bss_size); /* * Unmap bss memory. */ return sys_mm_drv_unmap_region((__sparse_force void *)va_base, bss_size); } -uintptr_t lib_manager_allocate_module(struct processing_module *proc, - const struct comp_ipc_config *ipc_config, - const void *ipc_specific_config) +/* + * \brief Allocate module + * + * param[in] mod - module manifest + * param[in] ipc_config - audio component base configuration from IPC at creation + * param[in] ipc_specific_config - ipc4 base configuration + * + * Function is responsible to allocate module in available free memory and assigning proper address. + */ +static uintptr_t lib_manager_allocate_module(const struct sof_man_fw_desc *const desc, + const struct sof_man_module *mod, + const struct comp_ipc_config *ipc_config, + const void *ipc_specific_config) { - const struct sof_man_module *mod; const struct ipc4_base_module_cfg *base_cfg = ipc_specific_config; + const uint32_t module_id = IPC4_MOD_ID(ipc_config->id); int ret; - uint32_t module_id = IPC4_MOD_ID(ipc_config->id); tr_dbg(&lib_manager_tr, "mod_id: %#x", ipc_config->id); - mod = lib_manager_get_module_manifest(module_id); - if (!mod) { - tr_err(&lib_manager_tr, "failed to get module descriptor"); - return 0; - } - if (module_is_llext(mod)) - return llext_manager_allocate_module(proc, ipc_config, ipc_specific_config); + return llext_manager_allocate_module(ipc_config, ipc_specific_config); - ret = lib_manager_load_module(module_id, mod); + ret = lib_manager_load_module(desc, module_id, mod); if (ret < 0) return 0; @@ -368,8 +391,8 @@ uintptr_t lib_manager_allocate_module(struct processing_module *proc, goto err; #endif /* CONFIG_LIBCODE_MODULE_SUPPORT */ - ret = lib_manager_allocate_module_instance(module_id, IPC4_INST_ID(ipc_config->id), - base_cfg->is_pages, mod); + ret = lib_manager_allocate_module_instance(IPC4_INST_ID(ipc_config->id), base_cfg->is_pages, + mod); if (ret < 0) { tr_err(&lib_manager_tr, "module allocation failed: %d", ret); #ifdef CONFIG_LIBCODE_MODULE_SUPPORT @@ -384,7 +407,15 @@ uintptr_t lib_manager_allocate_module(struct processing_module *proc, return 0; } -int lib_manager_free_module(const uint32_t component_id) +/* + * \brief Free module + * + * param[in] component_id - component id coming from ipc config. This function reguires valid + * lib_id and module_id fields of component id. + * + * Function is responsible to free module resources in HP memory. + */ +static int lib_manager_free_module(const uint32_t component_id) { const struct sof_man_module *mod; const uint32_t module_id = IPC4_MOD_ID(component_id); @@ -393,6 +424,10 @@ int lib_manager_free_module(const uint32_t component_id) tr_dbg(&lib_manager_tr, "mod_id: %#x", component_id); mod = lib_manager_get_module_manifest(module_id); + if (!mod) { + tr_err(&lib_manager_tr, "failed to get module descriptor"); + return -EINVAL; + } if (module_is_llext(mod)) return llext_manager_free_module(component_id); @@ -407,7 +442,7 @@ int lib_manager_free_module(const uint32_t component_id) return ret; #endif /* CONFIG_LIBCODE_MODULE_SUPPORT */ - ret = lib_manager_free_module_instance(module_id, IPC4_INST_ID(component_id), mod); + ret = lib_manager_free_module_instance(IPC4_INST_ID(component_id), mod); if (ret < 0) { tr_err(&lib_manager_tr, "free module instance failed: %d", ret); return ret; @@ -419,15 +454,15 @@ int lib_manager_free_module(const uint32_t component_id) #define PAGE_SZ 4096 /* equals to MAN_PAGE_SIZE used by rimage */ -uintptr_t lib_manager_allocate_module(struct processing_module *proc, - const struct comp_ipc_config *ipc_config, - const void *ipc_specific_config, const void **buildinfo) +static uintptr_t lib_manager_allocate_module(const struct sof_man_fw_desc *const desc, + const struct comp_ipc_config *ipc_config, + const void *ipc_specific_config, const void **buildinfo) { tr_err(&lib_manager_tr, "Dynamic module allocation is not supported"); return 0; } -int lib_manager_free_module(const uint32_t component_id) +static int lib_manager_free_module(const uint32_t component_id) { /* Since we cannot allocate the freeing is not considered to be an error */ tr_warn(&lib_manager_tr, "Dynamic module freeing is not supported"); @@ -457,8 +492,12 @@ static void lib_manager_update_sof_ctx(void *base_addr, uint32_t lib_id) { struct ext_library *_ext_lib = ext_lib_get(); /* Never freed, will panic if fails */ - struct lib_manager_mod_ctx *ctx = rzalloc(SOF_MEM_ZONE_SYS, SOF_MEM_FLAG_COHERENT, - SOF_MEM_CAPS_RAM, sizeof(*ctx)); + struct lib_manager_mod_ctx *ctx = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + sizeof(*ctx)); + if (!ctx) { + tr_err(&lib_manager_tr, "allocation failed"); + sof_panic(SOF_IPC_PANIC_IPC); + } ctx->base_addr = base_addr; @@ -487,7 +526,122 @@ const struct sof_man_module *lib_manager_get_module_manifest(const uint32_t modu SOF_MAN_MODULE_OFFSET(entry_index)); } -#if CONFIG_INTEL_MODULES +/** + * \brief Starts system agent and returns module interface into agent_interface variable. + * + * \param[in] drv - Pointer to the component driver structure. + * \param[in] config - Pointer to component ipc config structure + * \param[in] args - Pointer to components' ipc configuration arguments. + * \param[in] module_entry_point - Entry point address of the module. + * \param[in] agent - Function pointer to the system agent start function. + * \param[out] agent_interface - Pointer to store the module interface returned by the system agent. + * \param[out] userspace - Pointer to store the userspace module proxy context. + * \param[out] ops - Pointer to store pointer to the module interface structure. + * + * \return Error code returned by the system agent, 0 on success. + */ +static int lib_manager_start_agent(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const struct sof_man_module *mod_manifest, + const struct ipc_config_process *args, + const uintptr_t module_entry_point, + const system_agent_start_fn agent, + const void **agent_interface, + struct userspace_context **userspace, + const struct module_interface **ops) +{ + struct system_agent_params agent_params; + byte_array_t mod_cfg; + int ret = 0; + + mod_cfg.data = (uint8_t *)args->data; + /* Intel modules expects DW size here */ + mod_cfg.size = args->size >> 2; + + agent_params.entry_point = module_entry_point; + agent_params.module_id = IPC4_MOD_ID(config->id); + agent_params.instance_id = IPC4_INST_ID(config->id); + agent_params.core_id = config->core; + agent_params.log_handle = (uint32_t)drv->tctx; + agent_params.mod_cfg = &mod_cfg; + +#if CONFIG_SOF_USERSPACE_PROXY + /* If drv->user_heap is allocated, it means the module is userspace. */ + if (drv->user_heap) { + ret = userspace_proxy_create(userspace, drv, mod_manifest, agent, &agent_params, + agent_interface, ops); + if (ret) + tr_err(&lib_manager_tr, "userspace_proxy_create failed! %d", ret); + } else +#endif /* CONFIG_SOF_USERSPACE_PROXY */ + if (agent) { + ret = agent(&agent_params, agent_interface); + if (ret) + tr_err(&lib_manager_tr, "System agent start failed %d!", ret); + } + + return ret; +} + +enum buildinfo_mod_type { MOD_TYPE_INVALID, MOD_TYPE_IADK, MOD_TYPE_LMDK, MOD_TYPE_LLEXT }; + +/** + * \brief Get module type based on its build information. + * + * \param[in] desc - Pointer to the firmware descriptor containing module information. + * \param[in] mod - Pointer to the module manifest structure. + * + * \return The type of the module as an enum value. + */ +static enum buildinfo_mod_type lib_manager_get_module_type(const struct sof_man_fw_desc *const desc, + const struct sof_man_module *mod) +{ + const struct sof_module_api_build_info *const build_info = + (const struct sof_module_api_build_info *)((const char *)desc - + SOF_MAN_ELF_TEXT_OFFSET + mod->segment[SOF_MAN_SEGMENT_TEXT].file_offset); + const size_t lib_size = (size_t)desc->header.preload_page_count * PAGE_SZ; + const uint32_t text_off = mod->segment[SOF_MAN_SEGMENT_TEXT].file_offset; + + /* + * llext modules store build info structure in separate section which is not accessible now. + */ + if (module_is_llext(mod)) + return MOD_TYPE_LLEXT; + + /* + * build_info is derived from a manifest-supplied file_offset; bound it + * against the library image size before dereferencing so a crafted + * offset cannot read outside the library buffer. + */ + if (text_off > lib_size || lib_size - text_off < sizeof(*build_info)) { + tr_err(&lib_manager_tr, "Invalid TEXT file_offset %u, lib_size %zu", + text_off, lib_size); + return MOD_TYPE_INVALID; + } + + tr_info(&lib_manager_tr, "Module API version: %u.%u.%u, format: 0x%x", + build_info->api_version_number.fields.major, + build_info->api_version_number.fields.middle, + build_info->api_version_number.fields.minor, + build_info->format); + + /* Check if module is IADK */ + if (IS_ENABLED(CONFIG_INTEL_MODULES) && + build_info->format == IADK_MODULE_API_BUILD_INFO_FORMAT && + build_info->api_version_number.full == IADK_MODULE_API_CURRENT_VERSION) { + return MOD_TYPE_IADK; + } else { + /* Check if module is NOT native */ + if (build_info->format != SOF_MODULE_API_BUILD_INFO_FORMAT || + build_info->api_version_number.full != SOF_MODULE_API_CURRENT_VERSION) { + tr_err(&lib_manager_tr, "Unsupported module API version"); + return MOD_TYPE_INVALID; + } + + return MOD_TYPE_LMDK; + } +} + /* * \brief Load module code, allocate its instance and create a module adapter component. * \param[in] drv - component driver pointer. @@ -500,73 +654,107 @@ static struct comp_dev *lib_manager_module_create(const struct comp_driver *drv, const struct comp_ipc_config *config, const void *spec) { - const struct ipc_config_process *args = (struct ipc_config_process *)spec; - const uint32_t module_id = IPC4_MOD_ID(config->id); - const uint32_t instance_id = IPC4_INST_ID(config->id); - const uint32_t log_handle = (uint32_t)drv->tctx; - byte_array_t mod_cfg; - - /* - * Variable used by llext_manager to temporary store llext handle before creation - * a instance of processing_module. - */ - struct processing_module tmp_proc; + const struct sof_man_fw_desc *const desc = lib_manager_get_library_manifest(config->id); + const struct ipc_config_process *args = (const struct ipc_config_process *)spec; + const uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(config->id); + struct userspace_context *userspace = NULL; + const struct module_interface *ops; + const struct sof_man_module *mod; + system_agent_start_fn agent; + void *adapter_priv = NULL; + const void **agent_iface; struct comp_dev *dev; + int ret; - /* At this point module resources are allocated and it is moved to L2 memory. */ - tmp_proc.priv.llext = NULL; - const uint32_t module_entry_point = lib_manager_allocate_module(&tmp_proc, config, - args->data); - - if (!module_entry_point) { - tr_err(&lib_manager_tr, "lib_manager_allocate_module() failed!"); +#ifdef CONFIG_SOF_USERSPACE_PROXY + if (drv->user_heap && config->proc_domain != COMP_PROCESSING_DOMAIN_DP) { + tr_err(&lib_manager_tr, "Userspace supports only DP modules."); return NULL; } +#endif + tr_dbg(&lib_manager_tr, "start"); + if (!desc) { + tr_err(&lib_manager_tr, "Error: Couldn't find loadable module with id %u.", + config->id); + return NULL; + } - mod_cfg.data = (uint8_t *)args->data; - /* Intel modules expects DW size here */ - mod_cfg.size = args->size >> 2; + if (entry_index >= desc->header.num_module_entries) { + tr_err(&lib_manager_tr, "Entry index %u out of bounds.", entry_index); + return NULL; + } + + mod = (const struct sof_man_module *) + ((const uint8_t *)desc + SOF_MAN_MODULE_OFFSET(entry_index)); - ((struct comp_driver *)drv)->adapter_ops = native_system_agent_start(module_entry_point, - module_id, instance_id, - 0, log_handle, - &mod_cfg); + const uintptr_t module_entry_point = lib_manager_allocate_module(desc, mod, config, + args->data); - if (!drv->adapter_ops) { - lib_manager_free_module(module_id); - tr_err(&lib_manager_tr, "native_system_agent_start failed!"); + if (!module_entry_point) { + tr_err(&lib_manager_tr, "lib_manager_allocate_module() failed!"); return NULL; } - dev = module_adapter_new(drv, config, spec); - if (dev) { - struct processing_module *mod = comp_mod(dev); + switch (lib_manager_get_module_type(desc, mod)) { + case MOD_TYPE_LLEXT: + agent = NULL; + ops = (const struct module_interface *)module_entry_point; + agent_iface = NULL; + break; + case MOD_TYPE_LMDK: + agent = &native_system_agent_start; + agent_iface = (const void **)&ops; + break; +#if CONFIG_INTEL_MODULES + case MOD_TYPE_IADK: + agent = &system_agent_start; + ops = &processing_module_adapter_interface; + agent_iface = (const void **)&adapter_priv; + break; +#endif + case MOD_TYPE_INVALID: + goto err; + } - mod->priv.llext = tmp_proc.priv.llext; - } else { - lib_manager_free_module(module_id); + if (agent || IS_ENABLED(CONFIG_SOF_USERSPACE_PROXY)) { + /* At this point module resources are allocated and it is moved to L2 memory. */ + ret = lib_manager_start_agent(drv, config, mod, args, module_entry_point, agent, + agent_iface, &userspace, &ops); + if (ret) + goto err; } + + if (comp_set_adapter_ops(drv, ops) < 0) + goto err; + + dev = module_adapter_new_ext(drv, config, spec, adapter_priv, userspace, NULL); + if (!dev) + goto err; + return dev; + +err: +#if CONFIG_SOF_USERSPACE_PROXY + if (userspace) + userspace_proxy_destroy(drv, userspace); +#endif /* CONFIG_SOF_USERSPACE_PROXY */ + lib_manager_free_module(config->id); + return NULL; } static void lib_manager_module_free(struct comp_dev *dev) { - struct processing_module *mod = comp_mod(dev); - struct llext *llext = mod->priv.llext; - const struct comp_ipc_config *const config = &mod->dev->ipc_config; - const uint32_t module_id = config->id; + uint32_t component_id = dev->ipc_config.id; int ret; /* This call invalidates dev, mod and config pointers! */ module_adapter_free(dev); - if (!llext || !llext_unload(&llext)) { - /* Free module resources allocated in L2 memory. */ - ret = lib_manager_free_module(module_id); - if (ret < 0) - comp_err(dev, "lib_manager_free_module() failed!"); - } + /* Free module resources allocated in L2 memory. */ + ret = lib_manager_free_module(component_id); + if (ret < 0) + tr_err(&lib_manager_tr, "lib_manager_free_module() failed!"); } static void lib_manager_prepare_module_adapter(struct comp_driver *drv, const struct sof_uuid *uuid) @@ -587,6 +775,7 @@ static void lib_manager_prepare_module_adapter(struct comp_driver *drv, const st drv->ops.set_large_config = module_set_large_config; drv->ops.get_large_config = module_get_large_config; drv->ops.get_attribute = module_adapter_get_attribute; + drv->ops.set_attribute = module_adapter_set_attribute; drv->ops.bind = module_adapter_bind; drv->ops.unbind = module_adapter_unbind; drv->ops.get_total_data_processed = module_adapter_get_total_data_processed; @@ -596,108 +785,71 @@ static void lib_manager_prepare_module_adapter(struct comp_driver *drv, const st drv->ops.dai_ts_start = module_adapter_ts_start_op; drv->ops.dai_ts_stop = module_adapter_ts_stop_op; drv->ops.dai_ts_get = module_adapter_ts_get_op; - drv->adapter_ops = &processing_module_adapter_interface; } int lib_manager_register_module(const uint32_t component_id) { - const struct sof_man_fw_desc *const desc = lib_manager_get_library_manifest(component_id); - const uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(component_id); - const struct sof_module_api_build_info *build_info; + const struct sof_man_module *mod = lib_manager_get_module_manifest(component_id); + const struct sof_uuid *uid = (struct sof_uuid *)&mod->uuid; struct comp_driver_info *new_drv_info; + struct k_heap *drv_heap = NULL; struct comp_driver *drv = NULL; - const struct sof_man_module *mod; - int ret; + int ret = -ENOMEM; - if (!desc) { + if (!mod) { tr_err(&lib_manager_tr, "Error: Couldn't find loadable module with id %u.", component_id); return -ENOENT; } - if (entry_index >= desc->header.num_module_entries) { - tr_err(&lib_manager_tr, "Entry index %u out of bounds.", entry_index); - return -ENOENT; - } - /* allocate new comp_driver_info */ - new_drv_info = rmalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, - SOF_MEM_CAPS_RAM | SOF_MEM_FLAG_COHERENT, + new_drv_info = rmalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(struct comp_driver_info)); if (!new_drv_info) { tr_err(&lib_manager_tr, "failed to allocate comp_driver_info"); - ret = -ENOMEM; - goto cleanup; + return -ENOMEM; + } + +#if CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP + if (mod->type.user_mode) { + drv_heap = module_driver_heap_init(); + if (!drv_heap) { + tr_err(&lib_manager_tr, "failed to allocate driver heap!"); + goto cleanup; + } } +#endif /* CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP */ - drv = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, - SOF_MEM_CAPS_RAM | SOF_MEM_FLAG_COHERENT, - sizeof(struct comp_driver)); + drv = sof_heap_alloc(drv_heap, SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + sizeof(struct comp_driver), 0); if (!drv) { tr_err(&lib_manager_tr, "failed to allocate comp_driver"); - ret = -ENOMEM; goto cleanup; } - mod = (struct sof_man_module *)((const uint8_t *)desc + SOF_MAN_MODULE_OFFSET(entry_index)); - const struct sof_uuid *uid = (struct sof_uuid *)&mod->uuid[0]; + memset(drv, 0, sizeof(*drv)); + drv->user_heap = drv_heap; lib_manager_prepare_module_adapter(drv, uid); - /* - * llext modules store build info structure in separate section which is not accessible now. - */ - if (!module_is_llext(mod)) { - build_info = (const struct sof_module_api_build_info *)((const char *)desc - - SOF_MAN_ELF_TEXT_OFFSET + - mod->segment[SOF_MAN_SEGMENT_TEXT].file_offset); - - tr_info(&lib_manager_tr, "Module API version: %u.%u.%u, format: 0x%x", - build_info->api_version_number.fields.major, - build_info->api_version_number.fields.middle, - build_info->api_version_number.fields.minor, - build_info->format); - - /* Check if module is IADK */ - if (build_info->format == IADK_MODULE_API_BUILD_INFO_FORMAT && - build_info->api_version_number.full == IADK_MODULE_API_CURRENT_VERSION) { - /* Use module_adapter functions */ - drv->ops.create = module_adapter_new; - drv->ops.prepare = module_adapter_prepare; - } else { - /* Check if module is NOT native */ - if (build_info->format != SOF_MODULE_API_BUILD_INFO_FORMAT || - build_info->api_version_number.full != SOF_MODULE_API_CURRENT_VERSION) { - tr_err(&lib_manager_tr, "Unsupported module API version"); - return -ENOEXEC; - } - } - } - /* Fill the new_drv_info structure with already known parameters */ new_drv_info->drv = drv; + new_drv_info->adapter_ops = &drv->adapter_ops; /* Register new driver in the list */ ret = comp_register(new_drv_info); cleanup: if (ret < 0) { - rfree(drv); rfree(new_drv_info); + sof_heap_free(drv_heap, drv); + module_driver_heap_remove(drv_heap); } return ret; } -#else /* CONFIG_INTEL_MODULES */ -int lib_manager_register_module(const uint32_t component_id) -{ - tr_err(&lib_manager_tr, "Dynamic module loading is not supported"); - return -ENOTSUP; -} -#endif /* CONFIG_INTEL_MODULES */ - static int lib_manager_dma_buffer_alloc(struct lib_manager_dma_ext *dma_ext, uint32_t size) { @@ -705,7 +857,7 @@ static int lib_manager_dma_buffer_alloc(struct lib_manager_dma_ext *dma_ext, * allocate new buffer: this is the actual DMA buffer but we * traditionally allocate a cached address for it */ - dma_ext->dma_addr = (uintptr_t)rballoc_align(SOF_MEM_FLAG_COHERENT, SOF_MEM_CAPS_DMA, size, + dma_ext->dma_addr = (uintptr_t)rballoc_align(SOF_MEM_FLAG_COHERENT | SOF_MEM_FLAG_DMA, size, dma_ext->addr_align); if (!dma_ext->dma_addr) { tr_err(&lib_manager_tr, "alloc failed"); @@ -737,6 +889,9 @@ static int lib_manager_dma_init(struct lib_manager_dma_ext *dma_ext, uint32_t dm } chan_index = dma_request_channel(dma_ext->dma->z_dev, &dma_id); + if (chan_index < 0) + return chan_index; + dma_ext->chan = &dma_ext->dma->chan[chan_index]; if (!dma_ext->chan) return -EINVAL; @@ -818,14 +973,14 @@ static void __sparse_cache *lib_manager_allocate_store_mem(uint32_t size, { void __sparse_cache *local_add; #if CONFIG_L3_HEAP - uint32_t caps = SOF_MEM_CAPS_L3 | SOF_MEM_CAPS_DMA; + uint32_t flags = SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_L3 | SOF_MEM_FLAG_DMA; #else - uint32_t caps = SOF_MEM_CAPS_DMA; + uint32_t flags = SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_DMA; #endif uint32_t addr_align = PAGE_SZ; /* allocate new buffer: cached alias */ - local_add = (__sparse_force void __sparse_cache *)rballoc_align(0, caps, size, addr_align); + local_add = (__sparse_force void __sparse_cache *)rballoc_align(flags, size, addr_align); if (!local_add) { tr_err(&lib_manager_tr, "alloc failed"); @@ -837,14 +992,22 @@ static void __sparse_cache *lib_manager_allocate_store_mem(uint32_t size, static int lib_manager_store_library(struct lib_manager_dma_ext *dma_ext, const void __sparse_cache *man_buffer, - uint32_t lib_id) + uint32_t lib_id, struct auth_api_ctx *auth_ctx) { void __sparse_cache *library_base_address; const struct sof_man_fw_desc *man_desc = (struct sof_man_fw_desc *) ((__sparse_force uint8_t *)man_buffer + SOF_MAN_ELF_TEXT_OFFSET); - uint32_t preload_size = man_desc->header.preload_page_count * PAGE_SZ; int ret; + /* Zephyr UINT_MAX is explicitly 32 bits, and so is preload_page_count */ + if (man_desc->header.preload_page_count >= UINT_MAX / PAGE_SZ) { + tr_err(&lib_manager_tr, "Invalid preload page count %u.", + man_desc->header.preload_page_count); + return -EINVAL; + } + + uint32_t preload_size = man_desc->header.preload_page_count * PAGE_SZ; + /* * The module manifest structure always has its maximum size regardless of * the actual size of the manifest. @@ -854,10 +1017,10 @@ static int lib_manager_store_library(struct lib_manager_dma_ext *dma_ext, return -EINVAL; } - /* Prepare storage memory, note: it is never freed, library unloading is unsupported */ /* - * Prepare storage memory, note: it is never freed, it is assumed, that this - * memory is abundant, so we store all loaded modules there permanently + * Prepare storage memory, note: it is never freed, it is assumed, that + * this memory is abundant, so we store all loaded modules there + * permanently, unloading is unsupported */ library_base_address = lib_manager_allocate_store_mem(preload_size, 0); if (!library_base_address) @@ -868,7 +1031,7 @@ static int lib_manager_store_library(struct lib_manager_dma_ext *dma_ext, #if CONFIG_LIBRARY_AUTH_SUPPORT /* AUTH_PHASE_FIRST - checks library manifest only. */ ret = lib_manager_auth_proc((__sparse_force const void *)man_buffer, - MAN_MAX_SIZE_V1_8, AUTH_PHASE_FIRST); + MAN_MAX_SIZE_V1_8, AUTH_PHASE_FIRST, auth_ctx); if (ret < 0) { rfree((__sparse_force void *)library_base_address); return ret; @@ -887,10 +1050,13 @@ static int lib_manager_store_library(struct lib_manager_dma_ext *dma_ext, return ret; } + /* Writeback entire library to ensure it's visible to other cores */ + dcache_writeback_region((__sparse_force void *)library_base_address, preload_size); + #if CONFIG_LIBRARY_AUTH_SUPPORT /* AUTH_PHASE_LAST - do final library authentication checks */ ret = lib_manager_auth_proc((__sparse_force void *)library_base_address, - preload_size - MAN_MAX_SIZE_V1_8, AUTH_PHASE_LAST); + preload_size - MAN_MAX_SIZE_V1_8, AUTH_PHASE_LAST, auth_ctx); if (ret < 0) { rfree((__sparse_force void *)library_base_address); return ret; @@ -923,7 +1089,7 @@ static int lib_manager_setup(uint32_t dma_id) if (_ext_lib->runtime_data) return 0; - dma_ext = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + dma_ext = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(*dma_ext)); if (!dma_ext) return -ENOMEM; @@ -1008,7 +1174,7 @@ int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id, uint32_t type) /* allocate temporary manifest buffer */ man_tmp_buffer = (__sparse_force void __sparse_cache *) - rballoc_align(0, SOF_MEM_CAPS_DMA, + rballoc_align(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA, MAN_MAX_SIZE_V1_8, CONFIG_MM_DRV_PAGE_SIZE); if (!man_tmp_buffer) { ret = -ENOMEM; @@ -1021,16 +1187,19 @@ int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id, uint32_t type) goto stop_dma; #if CONFIG_LIBRARY_AUTH_SUPPORT + struct auth_api_ctx auth_ctx; + void *auth_buffer; + /* Initialize authentication support */ - ret = lib_manager_auth_init(); + ret = lib_manager_auth_init(&auth_ctx, &auth_buffer); if (ret < 0) goto stop_dma; -#endif /* CONFIG_LIBRARY_AUTH_SUPPORT */ - ret = lib_manager_store_library(dma_ext, man_tmp_buffer, lib_id); + ret = lib_manager_store_library(dma_ext, man_tmp_buffer, lib_id, &auth_ctx); -#if CONFIG_LIBRARY_AUTH_SUPPORT - lib_manager_auth_deinit(); + lib_manager_auth_deinit(&auth_ctx, auth_buffer); +#else + ret = lib_manager_store_library(dma_ext, man_tmp_buffer, lib_id, NULL); #endif /* CONFIG_LIBRARY_AUTH_SUPPORT */ stop_dma: @@ -1044,16 +1213,24 @@ int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id, uint32_t type) rfree((__sparse_force void *)man_tmp_buffer); cleanup: -#if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL - core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000)); -#endif rfree((void *)dma_ext->dma_addr); lib_manager_dma_deinit(dma_ext, dma_id); rfree(dma_ext); _ext_lib->runtime_data = NULL; + uint32_t module_id = lib_id << LIB_MANAGER_LIB_ID_SHIFT; + const struct sof_man_module *mod = lib_manager_get_module_manifest(module_id); + + if (!ret && mod && module_is_llext(mod)) + /* Auxiliary LLEXT libraries need to be linked upon loading */ + ret = llext_manager_add_library(module_id); + +#if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL + core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000)); +#endif + if (!ret) - tr_info(&ipc_tr, "loaded library id: %u", lib_id); + tr_info(&lib_manager_tr, "loaded library id: %u", lib_id); return ret; } diff --git a/src/library_manager/lib_notification.c b/src/library_manager/lib_notification.c index 8c9b7f20367a..36aa85835e70 100644 --- a/src/library_manager/lib_notification.c +++ b/src/library_manager/lib_notification.c @@ -49,8 +49,8 @@ struct ipc_msg *lib_notif_msg_init(uint32_t header, uint32_t size) return NULL; } - msg_pool_elem = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, - SOF_MEM_CAPS_RAM, sizeof(*msg_pool_elem)); + msg_pool_elem = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*msg_pool_elem)); if (!msg_pool_elem) return NULL; msg = ipc_msg_init(header, SRAM_OUTBOX_SIZE); @@ -73,7 +73,6 @@ struct ipc_msg *lib_notif_msg_init(uint32_t header, uint32_t size) /* Update header and size, since message handle can be reused */ msg->header = header; msg->tx_size = size; - msg->is_shared = !cpu_is_primary(cpu_get_id()); return msg; } diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 0aaa0797419f..4c1e4f02d5b5 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -19,19 +19,26 @@ #include <rtos/spinlock.h> #include <sof/lib/cpu-clk-manager.h> #include <sof/lib_manager.h> +#include <sof/lib/regions_mm.h> #include <sof/llext_manager.h> #include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/module_adapter/module/modules.h> #include <zephyr/cache.h> +#include <zephyr/app_memory/mem_domain.h> #include <zephyr/drivers/mm/system_mm.h> #include <zephyr/llext/buf_loader.h> #include <zephyr/llext/loader.h> #include <zephyr/llext/llext.h> +#include <zephyr/logging/log_ctrl.h> +#include <zephyr/llext/inspect.h> +#include <zephyr/sys/math_extras.h> +#include <kernel_arch_interface.h> #include <rimage/sof/user/manifest.h> #include <module/module/api_ver.h> +#include <adsp_memory_regions.h> #include <errno.h> #include <stdbool.h> #include <stddef.h> @@ -52,13 +59,13 @@ static int llext_manager_update_flags(void __sparse_cache *vma, size_t size, uin ALIGN_UP(pre_pad_size + size, PAGE_SZ), flags); } -static int llext_manager_align_map(void __sparse_cache *vma, size_t size, uint32_t flags) +static int llext_manager_align_map(const struct sys_mm_drv_region *virtual_region, + void __sparse_cache *vma, size_t size, uint32_t flags) { size_t pre_pad_size = (uintptr_t)vma & (PAGE_SZ - 1); void *aligned_vma = (__sparse_force uint8_t *)vma - pre_pad_size; - - return sys_mm_drv_map_region(aligned_vma, POINTER_TO_UINT(NULL), - ALIGN_UP(pre_pad_size + size, PAGE_SZ), flags); + return sys_mm_drv_map_region_safe(virtual_region, aligned_vma, POINTER_TO_UINT(NULL), + ALIGN_UP(pre_pad_size + size, PAGE_SZ), flags); } static int llext_manager_align_unmap(void __sparse_cache *vma, size_t size) @@ -69,36 +76,79 @@ static int llext_manager_align_unmap(void __sparse_cache *vma, size_t size) return sys_mm_drv_unmap_region(aligned_vma, ALIGN_UP(pre_pad_size + size, PAGE_SZ)); } -static int llext_manager_load_data_from_storage(const struct llext *ext, +static void llext_manager_detached_update_flags(void __sparse_cache *vma, + size_t size, uint32_t flags) +{ +#ifdef CONFIG_MMU + size_t pre_pad_size = (uintptr_t)vma & (PAGE_SZ - 1); + void *aligned_vma = (__sparse_force uint8_t *)vma - pre_pad_size; + + /* Use cached virtual address */ + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(aligned_vma)); + + arch_mem_map(aligned_vma, va, ALIGN_UP(pre_pad_size + size, PAGE_SZ), flags); +#endif +} + +/* + * Map the memory range covered by 'vma' and 'size' as writable, copy all + * sections that belong to the specified 'region' and are contained in the + * memory range, then remap the same area according to the 'flags' parameter. + */ +static int llext_manager_load_data_from_storage(const struct sys_mm_drv_region *virtual_region, + const struct llext_loader *ldr, + const struct llext *ext, + enum llext_mem region, void __sparse_cache *vma, - const uint8_t *load_base, size_t size, uint32_t flags) { unsigned int i; - int ret = llext_manager_align_map(vma, size, SYS_MM_MEM_PERM_RW); - const elf_shdr_t *shdr; + const void *region_addr; + + /* check if there region to be mapped exists */ + if (size == 0) + return 0; + + int ret = llext_manager_align_map(virtual_region, vma, size, SYS_MM_MEM_PERM_RW); if (ret < 0) { tr_err(&lib_manager_tr, "cannot map %u of %p", size, (__sparse_force void *)vma); return ret; } - size_t init_offset = 0; + llext_get_region_info(ldr, ext, region, NULL, ®ion_addr, NULL); /* Need to copy sections within regions individually, offsets may differ */ - for (i = 0, shdr = llext_section_headers(ext); i < llext_section_count(ext); i++, shdr++) { - if ((uintptr_t)shdr->sh_addr < (uintptr_t)vma || - (uintptr_t)shdr->sh_addr >= (uintptr_t)vma + size) + for (i = 0; i < llext_section_count(ext); i++) { + const elf_shdr_t *shdr; + enum llext_mem s_region = LLEXT_MEM_COUNT; + size_t s_offset = 0; + int ret = llext_get_section_info(ldr, ext, i, &shdr, &s_region, &s_offset); + + if (ret < 0) { + tr_err(&lib_manager_tr, "no section info: %d", ret); continue; + } - if (!init_offset) - init_offset = shdr->sh_offset; + /* skip sections not in the requested region */ + if (s_region != region) + continue; - /* found a section within the region */ - size_t offset = shdr->sh_offset - init_offset; + /* skip detached sections (will be outside requested VMA area) */ + if ((uintptr_t)shdr->sh_addr < (uintptr_t)vma || + (uintptr_t)shdr->sh_addr >= (uintptr_t)vma + size) { + llext_manager_detached_update_flags((__sparse_cache void *) + ((uint8_t *)region_addr + s_offset), + shdr->sh_size, flags); + if (flags & SYS_MM_MEM_PERM_EXEC) + icache_invalidate_region((__sparse_cache void *) + ((uint8_t *)region_addr + s_offset), + shdr->sh_size); + continue; + } - ret = memcpy_s((__sparse_force void *)shdr->sh_addr, size - offset, - load_base + offset, shdr->sh_size); + ret = memcpy_s((__sparse_force void *)shdr->sh_addr, size - s_offset, + (const uint8_t *)region_addr + s_offset, shdr->sh_size); if (ret < 0) return ret; } @@ -116,8 +166,40 @@ static int llext_manager_load_data_from_storage(const struct llext *ext, return ret; } -static int llext_manager_load_module(const struct llext *ext, const struct llext_buf_loader *ebl, - const struct lib_manager_module *mctx) +static void llext_manager_unmap_detached_sections(const struct llext_loader *ldr, + const struct llext *ext, + enum llext_mem region, + void __sparse_cache *vma, + size_t size) +{ +#ifdef CONFIG_MMU + unsigned int i; + const void *region_addr; + + llext_get_region_info(ldr, ext, region, NULL, ®ion_addr, NULL); + + for (i = 0; i < llext_section_count(ext); i++) { + const elf_shdr_t *shdr; + enum llext_mem s_region = LLEXT_MEM_COUNT; + size_t s_offset = 0; + + llext_get_section_info(ldr, ext, i, &shdr, &s_region, &s_offset); + + /* skip sections not in the requested region */ + if (s_region != region) + continue; + + /* unmap detached sections (will be outside requested VMA area) */ + if ((uintptr_t)shdr->sh_addr < (uintptr_t)vma || + (uintptr_t)shdr->sh_addr >= (uintptr_t)vma + size) + llext_manager_detached_update_flags((__sparse_force void *) + ((uint8_t *)region_addr + s_offset), + shdr->sh_size, 0); + } +#endif +} + +static int llext_manager_load_module(struct lib_manager_module *mctx) { /* Executable code (.text) */ void __sparse_cache *va_base_text = (void __sparse_cache *) @@ -136,21 +218,26 @@ static int llext_manager_load_module(const struct llext *ext, const struct llext /* .bss, should be within writable data above */ void __sparse_cache *bss_addr = (void __sparse_cache *) - ebl->loader.sects[LLEXT_MEM_BSS].sh_addr; - size_t bss_size = ebl->loader.sects[LLEXT_MEM_BSS].sh_size; + mctx->segment[LIB_MANAGER_BSS].addr; + size_t bss_size = mctx->segment[LIB_MANAGER_BSS].size; int ret; /* Check, that .bss is within .data */ if (bss_size && ((uintptr_t)bss_addr + bss_size <= (uintptr_t)va_base_data || (uintptr_t)bss_addr >= (uintptr_t)va_base_data + data_size)) { - if ((uintptr_t)bss_addr + bss_size == (uintptr_t)va_base_data && - !((uintptr_t)bss_addr & (PAGE_SZ - 1))) { - /* .bss directly in front of writable data and properly aligned, prepend */ + size_t bss_align = MIN(PAGE_SZ, BIT(__builtin_ctz((uintptr_t)bss_addr))); + + if ((!data_size || (uintptr_t)bss_addr + bss_size == (uintptr_t)va_base_data) && + bss_align >= PAGE_SZ) { + /* + * .bss is properly aligned and either there's no writable data, + * or .bss is directly in front of writable data, prepend .bss + */ va_base_data = bss_addr; data_size += bss_size; } else if ((uintptr_t)bss_addr == (uintptr_t)va_base_data + - ALIGN_UP(data_size, ebl->loader.sects[LLEXT_MEM_BSS].sh_addralign)) { + ALIGN_UP(data_size, bss_align)) { /* .bss directly behind writable data, append */ data_size += bss_size; } else { @@ -161,38 +248,66 @@ static int llext_manager_load_module(const struct llext *ext, const struct llext } } + const struct llext_loader *ldr = &mctx->ebl->loader; + const struct llext *ext = mctx->llext; + + /* find dedicated virtual memory zone */ + const struct sys_mm_drv_region *virtual_memory_regions = sys_mm_drv_query_memory_regions(); + const struct sys_mm_drv_region *virtual_region; + + if (!virtual_memory_regions) + return -EFAULT; + + SYS_MM_DRV_MEMORY_REGION_FOREACH(virtual_memory_regions, virtual_region) { + if (virtual_region->attr == VIRTUAL_REGION_LLEXT_LIBRARIES_ATTR) + break; + } + + if (!virtual_region->size) + return -EFAULT; + /* Copy Code */ - ret = llext_manager_load_data_from_storage(ext, va_base_text, ext->mem[LLEXT_MEM_TEXT], - text_size, SYS_MM_MEM_PERM_EXEC); + ret = llext_manager_load_data_from_storage(virtual_region, ldr, ext, LLEXT_MEM_TEXT, + va_base_text, text_size, SYS_MM_MEM_PERM_EXEC); if (ret < 0) return ret; /* Copy read-only data */ - ret = llext_manager_load_data_from_storage(ext, va_base_rodata, ext->mem[LLEXT_MEM_RODATA], - rodata_size, 0); + ret = llext_manager_load_data_from_storage(virtual_region, ldr, ext, LLEXT_MEM_RODATA, + va_base_rodata, rodata_size, 0); if (ret < 0) goto e_text; /* Copy writable data */ - ret = llext_manager_load_data_from_storage(ext, va_base_data, ext->mem[LLEXT_MEM_DATA], - data_size, SYS_MM_MEM_PERM_RW); + /* + * NOTE: va_base_data and data_size refer to an address range that + * spans over the BSS area as well, so the mapping will cover + * both, but only LLEXT_MEM_DATA sections will be copied. + */ + ret = llext_manager_load_data_from_storage(virtual_region, ldr, ext, LLEXT_MEM_DATA, + va_base_data, data_size, SYS_MM_MEM_PERM_RW); if (ret < 0) goto e_rodata; memset((__sparse_force void *)bss_addr, 0, bss_size); + mctx->mapped = true; return 0; e_rodata: - llext_manager_align_unmap(va_base_rodata, rodata_size); + if (rodata_size) + llext_manager_align_unmap(va_base_rodata, rodata_size); e_text: llext_manager_align_unmap(va_base_text, text_size); return ret; } -static int llext_manager_unload_module(const struct lib_manager_module *mctx) +static int llext_manager_unload_module(struct lib_manager_module *mctx) { + const struct llext_loader *ldr = &mctx->ebl->loader; + const struct llext *ext = mctx->llext; + /* Executable code (.text) */ void __sparse_cache *va_base_text = (void __sparse_cache *) mctx->segment[LIB_MANAGER_TEXT].addr; @@ -206,21 +321,38 @@ static int llext_manager_unload_module(const struct lib_manager_module *mctx) /* Writable data (.data, .bss, etc.) */ void __sparse_cache *va_base_data = (void __sparse_cache *) mctx->segment[LIB_MANAGER_DATA].addr; - size_t data_size = mctx->segment[LIB_MANAGER_DATA].size; + void __sparse_cache *va_base_bss = (void __sparse_cache *) + mctx->segment[LIB_MANAGER_BSS].addr; + size_t data_size = mctx->segment[LIB_MANAGER_DATA].size + + mctx->segment[LIB_MANAGER_BSS].size; int err = 0, ret; + llext_manager_unmap_detached_sections(ldr, ext, LLEXT_MEM_TEXT, + va_base_text, text_size); ret = llext_manager_align_unmap(va_base_text, text_size); if (ret < 0) err = ret; + /* Mimic the logic from load_module where the .bss address is used for mapping + * in case of e.g. lack of writable .data section + */ + if (!va_base_data) + va_base_data = va_base_bss; + + llext_manager_unmap_detached_sections(ldr, ext, LLEXT_MEM_DATA, + va_base_data, data_size); ret = llext_manager_align_unmap(va_base_data, data_size); if (ret < 0 && !err) err = ret; + llext_manager_unmap_detached_sections(ldr, ext, LLEXT_MEM_RODATA, + va_base_rodata, rodata_size); ret = llext_manager_align_unmap(va_base_rodata, rodata_size); if (ret < 0 && !err) err = ret; + mctx->mapped = false; + return err; } @@ -229,67 +361,119 @@ static bool llext_manager_section_detached(const elf_shdr_t *shdr) return shdr->sh_addr < SOF_MODULE_DRAM_LINK_END; } -static int llext_manager_link(struct llext_buf_loader *ebl, const char *name, - struct lib_manager_module *mctx, struct module_data *md, - const void **buildinfo, +static int llext_manager_link(const char *name, + struct lib_manager_module *mctx, const void **buildinfo, const struct sof_man_module_manifest **mod_manifest) { - /* Identify if this is the first time loading this module */ - struct llext_load_param ldr_parm = { - .relocate_local = !mctx->segment[LIB_MANAGER_TEXT].size, - .pre_located = true, - .section_detached = llext_manager_section_detached, - }; - int ret = llext_load(&ebl->loader, name, &md->llext, &ldr_parm); + struct llext **llext = &mctx->llext; + struct llext_loader *ldr = &mctx->ebl->loader; + const elf_shdr_t *hdr; + int ret; - if (ret) - return ret; + if (*llext && !mctx->mapped) { + /* + * All module instances have been terminated, so we freed SRAM, + * but we kept the full Zephyr LLEXT context. Now a new instance + * is starting, so we just re-use all the configuration and only + * re-allocate SRAM and copy the module into it + */ + *mod_manifest = mctx->mod_manifest; - mctx->segment[LIB_MANAGER_TEXT].addr = ebl->loader.sects[LLEXT_MEM_TEXT].sh_addr; - mctx->segment[LIB_MANAGER_TEXT].size = ebl->loader.sects[LLEXT_MEM_TEXT].sh_size; + return 0; + } + + if (!*llext || mctx->mapped) { + /* + * Either the very first time loading this module, or the module + * is already mapped, we just call llext_load() to refcount it + */ + struct llext_load_param ldr_parm = { + .relocate_local = !*llext, + .pre_located = true, + .section_detached = llext_manager_section_detached, + .keep_section_info = true, + }; + + ret = llext_load(ldr, name, llext, &ldr_parm); + if (ret) + return ret; + } + + /* All code sections */ + llext_get_region_info(ldr, *llext, LLEXT_MEM_TEXT, &hdr, NULL, NULL); + mctx->segment[LIB_MANAGER_TEXT].addr = hdr->sh_addr; + mctx->segment[LIB_MANAGER_TEXT].size = hdr->sh_size; tr_dbg(&lib_manager_tr, ".text: start: %#lx size %#x", mctx->segment[LIB_MANAGER_TEXT].addr, mctx->segment[LIB_MANAGER_TEXT].size); /* All read-only data sections */ - mctx->segment[LIB_MANAGER_RODATA].addr = - ebl->loader.sects[LLEXT_MEM_RODATA].sh_addr; - mctx->segment[LIB_MANAGER_RODATA].size = ebl->loader.sects[LLEXT_MEM_RODATA].sh_size; + llext_get_region_info(ldr, *llext, LLEXT_MEM_RODATA, &hdr, NULL, NULL); + mctx->segment[LIB_MANAGER_RODATA].addr = hdr->sh_addr; + mctx->segment[LIB_MANAGER_RODATA].size = hdr->sh_size; tr_dbg(&lib_manager_tr, ".rodata: start: %#lx size %#x", mctx->segment[LIB_MANAGER_RODATA].addr, mctx->segment[LIB_MANAGER_RODATA].size); /* All writable data sections */ - mctx->segment[LIB_MANAGER_DATA].addr = - ebl->loader.sects[LLEXT_MEM_DATA].sh_addr; - mctx->segment[LIB_MANAGER_DATA].size = ebl->loader.sects[LLEXT_MEM_DATA].sh_size; + llext_get_region_info(ldr, *llext, LLEXT_MEM_DATA, &hdr, NULL, NULL); + mctx->segment[LIB_MANAGER_DATA].addr = hdr->sh_addr; + mctx->segment[LIB_MANAGER_DATA].size = hdr->sh_size; tr_dbg(&lib_manager_tr, ".data: start: %#lx size %#x", mctx->segment[LIB_MANAGER_DATA].addr, mctx->segment[LIB_MANAGER_DATA].size); - ssize_t binfo_o = llext_find_section(&ebl->loader, ".mod_buildinfo"); + /* Writable uninitialized data section */ + llext_get_region_info(ldr, *llext, LLEXT_MEM_BSS, &hdr, NULL, NULL); + mctx->segment[LIB_MANAGER_BSS].addr = hdr->sh_addr; + mctx->segment[LIB_MANAGER_BSS].size = hdr->sh_size; - if (binfo_o >= 0) - *buildinfo = llext_peek(&ebl->loader, binfo_o); + tr_dbg(&lib_manager_tr, ".bss: start: %#lx size %#x", + mctx->segment[LIB_MANAGER_BSS].addr, + mctx->segment[LIB_MANAGER_BSS].size); - ssize_t mod_o = llext_find_section(&ebl->loader, ".module"); + *buildinfo = NULL; + ret = llext_section_shndx(ldr, *llext, ".mod_buildinfo"); + if (ret >= 0) { + llext_get_section_info(ldr, *llext, ret, &hdr, NULL, NULL); + *buildinfo = llext_peek(ldr, hdr->sh_offset); + } - if (mod_o >= 0) - *mod_manifest = llext_peek(&ebl->loader, mod_o); + *mod_manifest = NULL; + ret = llext_section_shndx(ldr, *llext, ".module"); + if (ret >= 0) { + llext_get_section_info(ldr, *llext, ret, &hdr, NULL, NULL); + *mod_manifest = llext_peek(ldr, hdr->sh_offset); + } - return binfo_o >= 0 && mod_o >= 0 ? 0 : -EPROTO; + return *buildinfo && *mod_manifest ? 0 : -EPROTO; } +/* Count "module files" in the library, allocate and initialize memory for their descriptors */ static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx, - const struct sof_man_fw_desc *desc, - const struct sof_man_module *mod_array) + const struct sof_man_fw_desc *desc) { + struct sof_man_module *mod_array = (struct sof_man_module *)((uint8_t *)desc + + SOF_MAN_MODULE_OFFSET(0)); + /* preload_page_count was checked when library was loaded */ + size_t lib_size = desc->header.preload_page_count * PAGE_SZ; unsigned int i, n_mod; size_t offs; + /* We'll check overflows below */ + uintptr_t mod_end_addr = (uintptr_t)(mod_array + desc->header.num_module_entries); + uintptr_t img_end_addr = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET + lib_size; + + if (mod_end_addr < (uintptr_t)mod_array || img_end_addr < (uintptr_t)desc || + mod_end_addr >= img_end_addr) { + tr_err(&lib_manager_tr, "invalid module entry count: %u", + desc->header.num_module_entries); + return -EOVERFLOW; + } + /* count modules */ for (i = 0, n_mod = 0, offs = ~0; i < desc->header.num_module_entries; i++) if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != offs) { @@ -301,8 +485,8 @@ static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx, * Loadable modules are loaded to DRAM once and never unloaded from it. * Context, related to them, is never freed */ - ctx->mod = rmalloc(SOF_MEM_ZONE_RUNTIME_SHARED, SOF_MEM_FLAG_COHERENT, - SOF_MEM_CAPS_RAM, n_mod * sizeof(ctx->mod[0])); + ctx->mod = rmalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + n_mod * sizeof(ctx->mod[0])); if (!ctx->mod) return -ENOMEM; @@ -311,13 +495,17 @@ static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx, for (i = 0, n_mod = 0, offs = ~0; i < desc->header.num_module_entries; i++) if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != offs) { offs = mod_array[i].segment[LIB_MANAGER_TEXT].file_offset; - ctx->mod[n_mod].segment[LIB_MANAGER_TEXT].size = 0; + ctx->mod[n_mod].mapped = false; + ctx->mod[n_mod].llext = NULL; + ctx->mod[n_mod].ebl = NULL; + ctx->mod[n_mod].n_dependent = 0; ctx->mod[n_mod++].start_idx = i; } return 0; } +/* Find a module context, containing the driver with the supplied index */ static unsigned int llext_manager_mod_find(const struct lib_manager_mod_ctx *ctx, unsigned int idx) { unsigned int i; @@ -329,43 +517,28 @@ static unsigned int llext_manager_mod_find(const struct lib_manager_mod_ctx *ctx return i - 1; } -uintptr_t llext_manager_allocate_module(struct processing_module *proc, - const struct comp_ipc_config *ipc_config, - const void *ipc_specific_config) +static int llext_manager_link_single(uint32_t module_id, const struct sof_man_fw_desc *desc, + struct lib_manager_mod_ctx *ctx, const void **buildinfo, + const struct sof_man_module_manifest **mod_manifest) { - uint32_t module_id = IPC4_MOD_ID(ipc_config->id); - struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *)lib_manager_get_library_manifest(module_id); - struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); - - if (!ctx || !desc) { - tr_err(&lib_manager_tr, "failed to get module descriptor"); - return 0; - } - - struct sof_man_module *mod_array = (struct sof_man_module *)((char *)desc + + struct sof_man_module *mod_array = (struct sof_man_module *)((uint8_t *)desc + SOF_MAN_MODULE_OFFSET(0)); uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); size_t mod_offset = mod_array[entry_index].segment[LIB_MANAGER_TEXT].file_offset; - const struct sof_man_module_manifest *mod_manifest; - const struct sof_module_api_build_info *buildinfo; - struct module_data *md = &proc->priv; - size_t mod_size; - int i, inst_idx; int ret; - tr_dbg(&lib_manager_tr, "mod_id: %#x", ipc_config->id); - - if (!ctx->mod) - llext_manager_mod_init(ctx, desc, mod_array); + tr_dbg(&lib_manager_tr, "mod_id: %u", module_id); if (entry_index >= desc->header.num_module_entries) { tr_err(&lib_manager_tr, "Invalid driver index %u exceeds %d", entry_index, desc->header.num_module_entries - 1); - return 0; + return -EINVAL; } - unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); - struct lib_manager_module *mctx = ctx->mod + mod_idx; + unsigned int mod_ctx_idx = llext_manager_mod_find(ctx, entry_index); + struct lib_manager_module *mctx = ctx->mod + mod_ctx_idx; + size_t mod_size; + int i, inst_idx; /* * We don't know the number of ELF files that this library is built of. @@ -381,9 +554,9 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, * we need to find the matching manifest in ".module" because only it * contains the entry point. For safety we calculate the ELF driver * index and then also check the driver name. - * We also need the driver size. For this we search the manifest array - * for the next ELF file, then the difference between offsets gives us - * the driver size. + * We also need a module size. For this we search the manifest array for + * the next ELF file, then the difference between offsets gives us the + * module size. */ for (i = entry_index - 1; i >= 0; i--) if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != mod_offset) @@ -403,43 +576,419 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, mod_size = ALIGN_UP(mod_array[i].segment[LIB_MANAGER_TEXT].file_offset - mod_offset, PAGE_SZ); - uintptr_t dram_base = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET; - struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)dram_base + mod_offset, mod_size); + if (!mctx->ebl) { + /* allocate once, never freed */ + mctx->ebl = rmalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + sizeof(struct llext_buf_loader)); + if (!mctx->ebl) { + tr_err(&lib_manager_tr, "loader alloc failed"); + return -ENOMEM; + } + + uint8_t *dram_base = (uint8_t *)desc - SOF_MAN_ELF_TEXT_OFFSET; + + *mctx->ebl = (struct llext_buf_loader)LLEXT_BUF_LOADER(dram_base + mod_offset, + mod_size); + } - /* LLEXT linking is only needed once for all the drivers in each module */ - ret = llext_manager_link(&ebl, mod_array[entry_index - inst_idx].name, mctx, md, - (const void **)&buildinfo, &mod_manifest); + /* + * LLEXT linking is only needed once for all the "drivers" in the + * module. This calls llext_load(), which also takes references to any + * dependencies, sets up sections and retrieves buildinfo and + * mod_manifest + */ + ret = llext_manager_link(mod_array[entry_index - inst_idx].name, mctx, + buildinfo, mod_manifest); if (ret < 0) { tr_err(&lib_manager_tr, "linking failed: %d", ret); + return ret; + } + + /* if ret > 0, then the "driver" is already loaded */ + if (!ret) + /* mctx->mod_manifest points to a const array of module manifests */ + mctx->mod_manifest = *mod_manifest; + + /* Return the manifest, related to the specific instance */ + *mod_manifest = mctx->mod_manifest + inst_idx; + + if (strncmp(mod_array[entry_index].name, (*mod_manifest)->module.name, + sizeof(mod_array[0].name))) { + tr_err(&lib_manager_tr, "Name mismatch %s vs. %s", + mod_array[entry_index].name, (*mod_manifest)->module.name); + return -ENOEXEC; + } + + return mod_ctx_idx; +} + +static int llext_lib_find(const struct llext *llext, struct lib_manager_module **dep_ctx) +{ + struct ext_library *_ext_lib = ext_lib_get(); + unsigned int i, j; + + if (!llext) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(_ext_lib->desc); i++) { + if (!_ext_lib->desc[i]) + continue; + + for (j = 0; j < _ext_lib->desc[i]->n_mod; j++) + if (_ext_lib->desc[i]->mod[j].llext == llext) { + *dep_ctx = _ext_lib->desc[i]->mod + j; + return i; + } + } + + return -ENOENT; +} + +/* n can be -1 */ +static void llext_manager_depend_unlink_rollback(struct lib_manager_module *dep_ctx[], int n) +{ + for (; n >= 0; n--) + if (!dep_ctx[n]) + tr_err(&lib_manager_tr, "dependency %d NULL", n); + else if (!--dep_ctx[n]->n_dependent) + llext_manager_unload_module(dep_ctx[n]); +} + +uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config, + const void *ipc_specific_config) +{ + uint32_t module_id = IPC4_MOD_ID(ipc_config->id); + /* Library manifest */ + const struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *) + lib_manager_get_library_manifest(module_id); + /* Library context */ + struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); + + if (!ctx || !desc) { + tr_err(&lib_manager_tr, "failed to get module descriptor"); return 0; } - if (!ret) { + /* Array of all "module drivers" (manifests) in the library */ + const struct sof_man_module_manifest *mod_manifest; + const struct sof_module_api_build_info *buildinfo = NULL; + + /* "module file" index in the ctx->mod array */ + int mod_ctx_idx = llext_manager_link_single(module_id, desc, ctx, + (const void **)&buildinfo, &mod_manifest); + + if (mod_ctx_idx < 0) + return 0; + + struct lib_manager_module *mctx = ctx->mod + mod_ctx_idx; + + if (buildinfo) { /* First instance: check that the module is native */ if (buildinfo->format != SOF_MODULE_API_BUILD_INFO_FORMAT || buildinfo->api_version_number.full != SOF_MODULE_API_CURRENT_VERSION) { tr_err(&lib_manager_tr, "Unsupported module API version"); return 0; } + } + + if (!mctx->mapped) { + int i, ret; + + /* + * Check if any dependencies need to be mapped - collect + * pointers to library contexts + */ + struct lib_manager_module *dep_ctx[LLEXT_MAX_DEPENDENCIES] = {}; + + for (i = 0; i < ARRAY_SIZE(mctx->llext->dependency); i++) { + struct lib_manager_module *dep; + + /* Dependencies are filled from the beginning of the array upwards */ + if (!mctx->llext->dependency[i]) + break; + + ret = llext_lib_find(mctx->llext->dependency[i], &dep); + if (ret < 0) { + tr_err(&lib_manager_tr, + "Unmet dependency: cannot find dependency %u", i); + continue; + } + + tr_dbg(&lib_manager_tr, "%s depending on %s index %u, %u users", + mctx->llext->name, mctx->llext->dependency[i]->name, + dep->start_idx, dep->n_dependent); + + /* + * Protected by the IPC serialization, but maybe we should protect the + * dependent-count explicitly too. It is incremented when a new dependent + * is identified. If it's non-zero, then some other modules also depend + * on it and have already mapped it. + */ + if (dep->n_dependent++) + continue; + + /* First user of this dependency, load it into SRAM */ + ret = llext_manager_load_module(dep); + if (ret < 0) { + dep->n_dependent--; + llext_manager_depend_unlink_rollback(dep_ctx, i - 1); + return 0; + } + + dep_ctx[i] = dep; + } /* Map executable code and data */ - ret = llext_manager_load_module(md->llext, &ebl, mctx); + ret = llext_manager_load_module(mctx); if (ret < 0) return 0; + } - /* mctx->mod_manifest points to a const array of module manifests */ - mctx->mod_manifest = mod_manifest; + return mod_manifest->module.entry_point; +} + +#ifdef CONFIG_USERSPACE +static int llext_manager_add_partition(struct k_mem_domain *domain, + uintptr_t addr, size_t size, + k_mem_partition_attr_t attr) +{ + size_t pre_pad_size = addr & (PAGE_SZ - 1); + struct k_mem_partition part = { + .start = addr - pre_pad_size, + .size = ALIGN_UP(pre_pad_size + size, PAGE_SZ), + .attr = attr, + }; + + tr_dbg(&lib_manager_tr, "add %#zx @ %lx partition", part.size, part.start); + return k_mem_domain_add_partition(domain, &part); +} + +static int llext_manager_rm_partition(struct k_mem_domain *domain, + uintptr_t addr, size_t size, + k_mem_partition_attr_t attr) +{ + size_t pre_pad_size = addr & (PAGE_SZ - 1); + struct k_mem_partition part = { + .start = addr - pre_pad_size, + .size = ALIGN_UP(pre_pad_size + size, PAGE_SZ), + .attr = attr, + }; + + tr_dbg(&lib_manager_tr, "remove %#zx @ %lx partition", part.size, part.start); + return k_mem_domain_remove_partition(domain, &part); +} + +int llext_manager_add_domain(const uint32_t component_id, struct k_mem_domain *domain) +{ + const uint32_t module_id = IPC4_MOD_ID(component_id); + struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); + const uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); + const unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); + struct lib_manager_module *mctx = ctx->mod + mod_idx; + const struct llext *ext = mctx->llext; + const struct llext_loader *ldr = &mctx->ebl->loader; + + /* Executable code (.text) */ + uintptr_t va_base_text = mctx->segment[LIB_MANAGER_TEXT].addr; + size_t text_size = mctx->segment[LIB_MANAGER_TEXT].size; + + /* Read-only data (.rodata and others) */ + uintptr_t va_base_rodata = mctx->segment[LIB_MANAGER_RODATA].addr; + size_t rodata_size = mctx->segment[LIB_MANAGER_RODATA].size; + + /* Writable data (.data, .bss and others) */ + uintptr_t va_base_data = mctx->segment[LIB_MANAGER_DATA].addr; + size_t data_size = mctx->segment[LIB_MANAGER_DATA].size; + + int ret = llext_manager_add_partition(domain, va_base_text, text_size, + K_MEM_PARTITION_P_RX_U_RX | XTENSA_MMU_CACHED_WB); + + if (ret < 0) + return ret; + + if (rodata_size) { + ret = llext_manager_add_partition(domain, va_base_rodata, rodata_size, + K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB); + if (ret < 0) + goto e_text; } - if (strncmp(mod_array[entry_index].name, mctx->mod_manifest[inst_idx].module.name, - sizeof(mod_array[0].name))) { - tr_err(&lib_manager_tr, "Name mismatch %s vs. %s", - mod_array[entry_index].name, mctx->mod_manifest[inst_idx].module.name); - return 0; + if (data_size) { + ret = llext_manager_add_partition(domain, va_base_data, data_size, + K_MEM_PARTITION_P_RW_U_RW | XTENSA_MMU_CACHED_WB); + if (ret < 0) + goto e_rodata; + } + + elf_shdr_t shdr_cold, shdr_coldrodata; + bool rodata = false, text = false; + const void *rodata_addr = NULL, *text_addr = NULL; + size_t text_offset = 0, rodata_offset = 0; + + shdr_cold.sh_size = 0; + shdr_coldrodata.sh_size = 0; + + ret = llext_get_section_header(ldr, ext, ".cold", &shdr_cold); + if (ret < 0) + tr_warn(&lib_manager_tr, "couldn't get .cold header"); + else + llext_get_region_info(ldr, ext, LLEXT_MEM_TEXT, NULL, &text_addr, NULL); + + ret = llext_get_section_header(ldr, ext, ".coldrodata", &shdr_coldrodata); + if (ret < 0) + tr_warn(&lib_manager_tr, "couldn't get .coldrodata header"); + else + llext_get_region_info(ldr, ext, LLEXT_MEM_RODATA, NULL, &rodata_addr, NULL); + + for (unsigned int i = 0; i < llext_section_count(ext) && (!rodata || !text); i++) { + const elf_shdr_t *shdr; + enum llext_mem s_region = LLEXT_MEM_COUNT; + size_t s_offset = 0; + + ret = llext_get_section_info(ldr, ext, i, &shdr, &s_region, &s_offset); + if (ret < 0) + continue; + + switch (s_region) { + case LLEXT_MEM_TEXT: + if (shdr_cold.sh_size && + shdr->sh_name == shdr_cold.sh_name && + shdr->sh_offset == shdr_cold.sh_offset && !text) { + text = true; + text_offset = s_offset; + } + break; + case LLEXT_MEM_RODATA: + if (shdr_coldrodata.sh_size && + shdr->sh_name == shdr_coldrodata.sh_name && + shdr->sh_offset == shdr_coldrodata.sh_offset && !rodata) { + rodata = true; + rodata_offset = s_offset; + } + break; + default: + break; + } + } + + if (text) { + tr_dbg(&lib_manager_tr, ".cold %#x @ %#lx", + shdr_cold.sh_size, (uintptr_t)text_addr + text_offset); + ret = llext_manager_add_partition(domain, (uintptr_t)text_addr + text_offset, + shdr_cold.sh_size, + K_MEM_PARTITION_P_RX_U_RX | XTENSA_MMU_CACHED_WB); + if (ret < 0) + goto e_data; + mctx->segment[LIB_MANAGER_COLD].addr = (uintptr_t)text_addr + text_offset; + mctx->segment[LIB_MANAGER_COLD].size = shdr_cold.sh_size; + } + + if (rodata) { + tr_dbg(&lib_manager_tr, ".coldrodata %#x @ %#lx", + shdr_coldrodata.sh_size, (uintptr_t)rodata_addr + rodata_offset); + ret = llext_manager_add_partition(domain, (uintptr_t)rodata_addr + rodata_offset, + shdr_coldrodata.sh_size, + K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB); + if (ret < 0) + goto e_cold; + mctx->segment[LIB_MANAGER_COLDRODATA].addr = (uintptr_t)rodata_addr + rodata_offset; + mctx->segment[LIB_MANAGER_COLDRODATA].size = shdr_coldrodata.sh_size; + } + + return 0; + +e_cold: + llext_manager_rm_partition(domain, (uintptr_t)text_addr + text_offset, shdr_cold.sh_size, + K_MEM_PARTITION_P_RX_U_RX | XTENSA_MMU_CACHED_WB); + mctx->segment[LIB_MANAGER_COLD].addr = 0; + mctx->segment[LIB_MANAGER_COLD].size = 0; +e_data: + llext_manager_rm_partition(domain, va_base_data, data_size, + K_MEM_PARTITION_P_RW_U_RW | XTENSA_MMU_CACHED_WB); +e_rodata: + llext_manager_rm_partition(domain, va_base_rodata, rodata_size, + K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB); +e_text: + llext_manager_rm_partition(domain, va_base_text, text_size, + K_MEM_PARTITION_P_RX_U_RX | XTENSA_MMU_CACHED_WB); + return ret; +} + +int llext_manager_rm_domain(const uint32_t component_id, struct k_mem_domain *domain) +{ + const uint32_t module_id = IPC4_MOD_ID(component_id); + struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); + const uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); + const unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); + struct lib_manager_module *mctx = ctx->mod + mod_idx; + + /* Executable code (.text) */ + uintptr_t va_base_text = mctx->segment[LIB_MANAGER_TEXT].addr; + size_t text_size = mctx->segment[LIB_MANAGER_TEXT].size; + + /* Read-only data (.rodata and others) */ + uintptr_t va_base_rodata = mctx->segment[LIB_MANAGER_RODATA].addr; + size_t rodata_size = mctx->segment[LIB_MANAGER_RODATA].size; + + /* Writable data (.data, .bss and others) */ + uintptr_t va_base_data = mctx->segment[LIB_MANAGER_DATA].addr; + size_t data_size = mctx->segment[LIB_MANAGER_DATA].size; + + int err, ret = llext_manager_rm_partition(domain, va_base_text, text_size, + K_MEM_PARTITION_P_RX_U_RX | XTENSA_MMU_CACHED_WB); + + if (ret < 0) + tr_err(&lib_manager_tr, "failed to remove .text memory partition: %d", ret); + + if (rodata_size) { + err = llext_manager_rm_partition(domain, va_base_rodata, rodata_size, + K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB); + if (err < 0) { + tr_err(&lib_manager_tr, "failed to remove .rodata memory partition: %d", + err); + if (!ret) + ret = err; + } + } + + if (data_size) { + err = llext_manager_rm_partition(domain, va_base_data, data_size, + K_MEM_PARTITION_P_RW_U_RW | XTENSA_MMU_CACHED_WB); + if (err < 0) { + tr_err(&lib_manager_tr, "failed to remove .data memory partition: %d", err); + if (!ret) + ret = err; + } } - return mctx->mod_manifest[inst_idx].module.entry_point; + if (mctx->segment[LIB_MANAGER_COLD].addr) { + err = llext_manager_rm_partition(domain, + mctx->segment[LIB_MANAGER_COLD].addr, + mctx->segment[LIB_MANAGER_COLD].size, + K_MEM_PARTITION_P_RX_U_RX | XTENSA_MMU_CACHED_WB); + if (err < 0) { + tr_err(&lib_manager_tr, "failed to remove .cold memory partition: %d", err); + if (!ret) + ret = err; + } + } + + if (mctx->segment[LIB_MANAGER_COLDRODATA].addr) { + err = llext_manager_rm_partition(domain, + mctx->segment[LIB_MANAGER_COLDRODATA].addr, + mctx->segment[LIB_MANAGER_COLDRODATA].size, + K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB); + if (err < 0) { + tr_err(&lib_manager_tr, + "failed to remove .coldrodata memory partition: %d", err); + if (!ret) + ret = err; + } + } + + return ret; } +#endif int llext_manager_free_module(const uint32_t component_id) { @@ -454,14 +1003,97 @@ int llext_manager_free_module(const uint32_t component_id) return -ENOENT; } + if (!ctx->mod) { + tr_err(&lib_manager_tr, "NULL module array: ID %#x ctx %p", component_id, ctx); + return -ENOENT; + } + unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); struct lib_manager_module *mctx = ctx->mod + mod_idx; + /* Protected by IPC serialization */ + if (mctx->llext->use_count > 1) { + /* + * At least 2 users: llext_unload() will never actually free + * the extension but only reduce the refcount and return its + * new value (must be a positive number). + * NOTE: if this is modified to allow extension unload, the + * inspection data in the loader must be freed as well by + * calling the llext_free_inspection_data() function. + */ + int ret = llext_unload(&mctx->llext); + + if (ret <= 0) { + tr_err(&lib_manager_tr, + "mod_id: %#x: invalid return code from llext_unload(): %d", + component_id, ret); + return ret ? : -EPROTO; + } + + /* More users are active */ + return 0; + } + + struct lib_manager_module *dep_ctx[LLEXT_MAX_DEPENDENCIES] = {}; + int i; /* signed to match llext_manager_depend_unlink_rollback() */ + + for (i = 0; i < ARRAY_SIZE(mctx->llext->dependency); i++) + if (llext_lib_find(mctx->llext->dependency[i], &dep_ctx[i]) < 0) + break; + + /* Last user cleaning up, put dependencies */ + if (i) + llext_manager_depend_unlink_rollback(dep_ctx, i - 1); + + /* + * The last instance of the module has been destroyed and it can now be + * unloaded from SRAM + */ tr_dbg(&lib_manager_tr, "mod_id: %#x", component_id); + /* Since the LLEXT context now is preserved, we have to flush logs ourselves */ + log_flush(); + return llext_manager_unload_module(mctx); } +/* An auxiliary library has been loaded, need to read in its exported symbols */ +int llext_manager_add_library(uint32_t module_id) +{ + struct lib_manager_mod_ctx *const ctx = lib_manager_get_mod_ctx(module_id); + + if (ctx->mod) { + tr_err(&lib_manager_tr, "module_id: %#x: repeated load!", module_id); + return -EBUSY; + } + + const struct sof_man_fw_desc *desc = lib_manager_get_library_manifest(module_id); + unsigned int i; + int ret; + + if (!ctx->mod) { + ret = llext_manager_mod_init(ctx, desc); + if (ret < 0) + return ret; + } + + for (i = 0; i < ctx->n_mod; i++) { + const struct sof_man_module *mod = lib_manager_get_module_manifest(module_id + i); + + if (mod->type.load_type == SOF_MAN_MOD_TYPE_LLEXT_AUX) { + const struct sof_man_module_manifest *mod_manifest; + const struct sof_module_api_build_info *buildinfo; + + ret = llext_manager_link_single(module_id + i, desc, ctx, + (const void **)&buildinfo, &mod_manifest); + if (ret < 0) + return ret; + } + } + + return 0; +} + bool comp_is_llext(struct comp_dev *comp) { const uint32_t module_id = IPC4_MOD_ID(comp->ipc_config.id); @@ -471,3 +1103,17 @@ bool comp_is_llext(struct comp_dev *comp) return mod && module_is_llext(mod); } + +static int llext_memory_region_init(void) +{ + int ret; + + /* add a region for loadable libraries */ + ret = adsp_add_virtual_memory_region(CONFIG_LIBRARY_BASE_ADDRESS, + CONFIG_LIBRARY_REGION_SIZE, + VIRTUAL_REGION_LLEXT_LIBRARIES_ATTR); + + return ret; +} + +SYS_INIT(llext_memory_region_init, POST_KERNEL, 1); diff --git a/src/library_manager/llext_manager_dram.c b/src/library_manager/llext_manager_dram.c new file mode 100644 index 000000000000..2f6cff2b3501 --- /dev/null +++ b/src/library_manager/llext_manager_dram.c @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <rtos/alloc.h> + +#include <sof/lib_manager.h> +#include <ipc/topology.h> + +#include <zephyr/llext/buf_loader.h> +#include <zephyr/llext/llext.h> +#include <zephyr/llext/llext_internal.h> +#include <zephyr/logging/log_ctrl.h> + +LOG_MODULE_DECLARE(lib_manager, CONFIG_SOF_LOG_LEVEL); + +struct lib_manager_dram_storage { + struct ext_library ext_lib; + struct lib_manager_mod_ctx *ctx; + struct lib_manager_module *mod; + struct llext *llext; + struct llext_buf_loader *bldr; + struct llext_elf_sect_map *sect; + struct llext_symbol *sym; + unsigned int n_llext; + unsigned int n_mod; +}; + +/* + * This holds the complete LLEXT manager context in DRAM over DSP shut down to + * be restored during the next boot + */ +__imrdata static struct lib_manager_dram_storage lib_manager_dram; + +/* Store LLEXT manager context in DRAM to be restored during the next boot. */ +int llext_manager_store_to_dram(void) +{ + struct ext_library *_ext_lib = ext_lib_get(); + unsigned int i, j, k, l, n_lib, n_mod, n_llext, n_sect, n_sym; + size_t buf_size; + + if (lib_manager_dram.n_llext) { + tr_err(&lib_manager_tr, "context already saved"); + return 0; + } + + /* + * Count libraries, modules, instantiated extensions, sections and exported + * symbols in them. Allocate a buffer of required size. + */ + lib_manager_dram.ext_lib = *_ext_lib; + for (i = 0, n_lib = 0, n_mod = 0, n_llext = 0, n_sect = 0, n_sym = 0; + i < ARRAY_SIZE(_ext_lib->desc); i++) + if (_ext_lib->desc[i]) { + n_lib++; + n_mod += _ext_lib->desc[i]->n_mod; + for (k = 0; k < _ext_lib->desc[i]->n_mod; k++) + if (_ext_lib->desc[i]->mod[k].ebl) { + n_llext++; + n_sect += _ext_lib->desc[i]->mod[k].llext->sect_cnt; + n_sym += _ext_lib->desc[i]->mod[k].llext->exp_tab.sym_cnt; + tr_dbg(&lib_manager_tr, "add %u exported syms", + _ext_lib->desc[i]->mod[k].llext->exp_tab.sym_cnt); + } + } + + buf_size = sizeof(lib_manager_dram.ctx[0]) * n_lib + + sizeof(lib_manager_dram.mod[0]) * n_mod + + sizeof(lib_manager_dram.sect[0]) * n_sect + + sizeof(lib_manager_dram.sym[0]) * n_sym + + (sizeof(lib_manager_dram.llext[0]) + sizeof(lib_manager_dram.bldr[0])) * n_llext; + + lib_manager_dram.ctx = rmalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_L3, + buf_size); + if (!lib_manager_dram.ctx) + return -ENOMEM; + + /* Save pointers to buffer parts, holding parts of the context */ + lib_manager_dram.mod = (struct lib_manager_module *)(lib_manager_dram.ctx + n_lib); + lib_manager_dram.sect = (struct llext_elf_sect_map *)(lib_manager_dram.mod + n_mod); + lib_manager_dram.llext = (struct llext *)(lib_manager_dram.sect + n_sect); + lib_manager_dram.bldr = (struct llext_buf_loader *)(lib_manager_dram.llext + n_llext); + lib_manager_dram.sym = (struct llext_symbol *)(lib_manager_dram.bldr + n_llext); + + tr_dbg(&lib_manager_tr, "backup %u libs of %u modules with %u LLEXT with %u sections", + n_lib, n_mod, n_llext, n_sect); + + tr_dbg(&lib_manager_tr, "backup %p to %p, mod %p, loader %p", + lib_manager_dram.ctx, (void *)((uint8_t *)lib_manager_dram.ctx + buf_size), + lib_manager_dram.mod, lib_manager_dram.bldr); + + /* Walk all libraries */ + for (i = 0, j = 0, l = 0, n_mod = 0, n_sect = 0, n_sym = 0; + i < ARRAY_SIZE(_ext_lib->desc); i++) { + if (!_ext_lib->desc[i]) + continue; + + struct lib_manager_module *mod = _ext_lib->desc[i]->mod; + + /* Copy all modules in each library */ + lib_manager_dram.ctx[j++] = *_ext_lib->desc[i]; + memcpy(lib_manager_dram.mod + n_mod, mod, + sizeof(lib_manager_dram.mod[0]) * _ext_lib->desc[i]->n_mod); + tr_dbg(&lib_manager_tr, "lib %u base %p", j - 1, + lib_manager_dram.ctx[j - 1].base_addr); + n_mod += _ext_lib->desc[i]->n_mod; + + /* + * Copy instantiated extensions. Note that only modules, that + * were used, have their LLEXT context instantiated. + */ + for (k = 0; k < _ext_lib->desc[i]->n_mod; k++) { + if (!mod[k].llext) + continue; + + tr_dbg(&lib_manager_tr, "mod %u of %u sections", k, + mod[k].llext->sect_cnt); + + /* Copy the extension and the loader */ + lib_manager_dram.llext[l] = *mod[k].llext; + lib_manager_dram.bldr[l] = *mod[k].ebl; + + /* Copy the section map */ + memcpy(lib_manager_dram.sect + n_sect, mod[k].ebl->loader.sect_map, + mod[k].llext->sect_cnt * sizeof(lib_manager_dram.sect[0])); + n_sect += mod[k].llext->sect_cnt; + + /* Copy exported symbols */ + if (mod[k].llext->exp_tab.sym_cnt) { + memcpy(lib_manager_dram.sym + n_sym, mod[k].llext->exp_tab.syms, + mod[k].llext->exp_tab.sym_cnt * + sizeof(lib_manager_dram.sym[0])); + lib_manager_dram.llext[l].exp_tab.syms = lib_manager_dram.sym + + n_sym; + n_sym += mod[k].llext->exp_tab.sym_cnt; + } + + l++; + } + } + + /* Also flatten dependency lists */ + int ret = llext_relink_dependency(lib_manager_dram.llext, n_llext); + + if (ret < 0) { + tr_err(&lib_manager_tr, "Inconsistent dependencies!"); + return ret; + } + + lib_manager_dram.n_llext = n_llext; + lib_manager_dram.n_mod = n_mod; + + /* Make sure, that the data is actually in the DRAM, not just in data cache */ + dcache_writeback_region((__sparse_force void __sparse_cache *)&lib_manager_dram, + sizeof(lib_manager_dram)); + dcache_writeback_region((__sparse_force void __sparse_cache *)lib_manager_dram.ctx, + buf_size); + + return 0; +} + +int llext_manager_restore_from_dram(void) +{ + lib_manager_init(); + + struct ext_library *_ext_lib = ext_lib_get(); + unsigned int i, j, k, n_mod, n_llext, n_sect, n_sym; + struct llext_loader **ldr; + struct llext **llext; + + if (!lib_manager_dram.n_mod || !lib_manager_dram.ctx) { + tr_dbg(&lib_manager_tr, "No modules saved"); + dcache_writeback_region((__sparse_force void __sparse_cache *)&lib_manager_dram, + sizeof(lib_manager_dram)); + return 0; + } + + *_ext_lib = lib_manager_dram.ext_lib; + + if (lib_manager_dram.n_llext) { + /* arrays of pointers for llext_restore() */ + void **ptr_array = rmalloc(SOF_MEM_FLAG_KERNEL, + sizeof(*ptr_array) * lib_manager_dram.n_llext * 2); + + if (!ptr_array) + return -ENOMEM; + + ldr = (struct llext_loader **)ptr_array; + llext = (struct llext **)(ptr_array + lib_manager_dram.n_llext); + } else { + ldr = NULL; + llext = NULL; + } + + /* The external loop walks all the libraries */ + for (i = 0, j = 0, n_mod = 0, n_llext = 0, n_sect = 0, n_sym = 0; + i < ARRAY_SIZE(_ext_lib->desc); i++) { + if (!lib_manager_dram.ext_lib.desc[i]) { + _ext_lib->desc[i] = NULL; + continue; + } + + struct lib_manager_mod_ctx *ctx = rmalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + sizeof(*ctx)); + + if (!ctx) { + tr_err(&lib_manager_tr, "library context allocation failure"); + goto nomem; + } + + /* Restore the library context */ + *ctx = lib_manager_dram.ctx[j++]; + + /* Allocate and restore all the modules in the library */ + struct lib_manager_module *mod = rmalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + ctx->n_mod * sizeof(ctx->mod[0])); + + if (!mod) { + tr_err(&lib_manager_tr, "module allocation failure"); + goto nomem; + } + tr_dbg(&lib_manager_tr, "%u modules alloc %p base %p copy %#zx", + ctx->n_mod, (void *)mod, ctx->base_addr, ctx->n_mod * sizeof(ctx->mod[0])); + + memcpy(mod, lib_manager_dram.mod + n_mod, sizeof(mod[0]) * ctx->n_mod); + n_mod += ctx->n_mod; + ctx->mod = mod; + + /* Second level: enumerate modules in each library */ + for (k = 0; k < ctx->n_mod; k++) { + if (!mod[k].llext) + /* Not instantiated - nothing to restore */ + continue; + + /* Loaders are supplied by the caller */ + struct llext_buf_loader *bldr = rmalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + sizeof(*bldr)); + + if (!bldr) { + tr_err(&lib_manager_tr, "loader allocation failure"); + goto nomem; + } + + /* Extensions have to be restored by Zephyr, collect pointers first */ + llext[n_llext] = lib_manager_dram.llext + n_llext; + + *bldr = lib_manager_dram.bldr[n_llext]; + + bldr->loader.sect_map = lib_manager_dram.sect + n_sect; + + n_sect += llext[n_llext]->sect_cnt; + if (llext[n_llext]->exp_tab.sym_cnt) { + /* + * Just a check, that we're restoring exported + * symbols correctly + */ + tr_dbg(&lib_manager_tr, "got %u exported symbols", + llext[n_llext]->exp_tab.sym_cnt); + + if (llext[n_llext]->exp_tab.syms != lib_manager_dram.sym + n_sym) { + tr_err(&lib_manager_tr, + "bug detected! pointer mismatch %p vs. %p", + (void *)llext[n_llext]->exp_tab.syms, + (void *)(lib_manager_dram.sym + n_sym)); + goto nomem; + } + + n_sym += llext[n_llext]->exp_tab.sym_cnt; + } + + mod[k].ebl = bldr; + + ldr[n_llext++] = &bldr->loader; + } + + _ext_lib->desc[i] = ctx; + } + + if (lib_manager_dram.n_llext) { + /* Let Zephyr restore extensions and its own internal bookkeeping */ + int ret = llext_restore(llext, ldr, lib_manager_dram.n_llext); + + if (ret < 0) { + tr_err(&lib_manager_tr, "Zephyr failed to restore: %d", ret); + goto nomem; + } + + /* Rewrite to correct LLEXT pointers, created by Zephyr */ + for (i = 0, n_llext = 0; i < ARRAY_SIZE(_ext_lib->desc); i++) { + struct lib_manager_mod_ctx *ctx = _ext_lib->desc[i]; + + if (!ctx) + continue; + + struct lib_manager_module *mod = ctx->mod; + + for (k = 0; k < ctx->n_mod; k++) { + if (mod[k].llext) + mod[k].llext = llext[n_llext++]; + } + } + } + + tr_info(&lib_manager_tr, "restored %u modules with %u LLEXT", n_mod, n_llext); + + rfree(lib_manager_dram.ctx); + lib_manager_dram.ctx = NULL; + lib_manager_dram.sect = NULL; + lib_manager_dram.llext = NULL; + lib_manager_dram.bldr = NULL; + lib_manager_dram.sym = NULL; + rfree(ldr); + + lib_manager_dram.n_llext = 0; + + return 0; + +nomem: + tr_err(&lib_manager_tr, "Restore failed"); + for (i = 0; i < ARRAY_SIZE(_ext_lib->desc); i++) { + struct lib_manager_mod_ctx *ctx = _ext_lib->desc[i]; + + if (!ctx) + continue; + + struct lib_manager_module *mod = ctx->mod; + + if (!mod) + continue; + + for (k = 0; k < ctx->n_mod; k++) { + if (mod[k].llext) + llext_unload(&mod[k].llext); + + if (mod[k].ebl) + rfree(mod[k].ebl); + } + + rfree(mod); + rfree(ctx); + } + + /* at least create a sane empty lib-manager context */ + memset(_ext_lib->desc, 0, sizeof(_ext_lib->desc)); + + rfree(ldr); + + return -ENOMEM; +} diff --git a/src/logging/CMakeLists.txt b/src/logging/CMakeLists.txt new file mode 100644 index 000000000000..6114062e37c6 --- /dev/null +++ b/src/logging/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources_ifdef(CONFIG_LOG_BACKEND_SOF_PROBE sof log_backend_probe.c) diff --git a/src/logging/Kconfig b/src/logging/Kconfig deleted file mode 100644 index 9d854f68aae4..000000000000 --- a/src/logging/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -# Trace configs - -menu "Logging" - -config LOG_BACKEND_SOF_PROBE - bool "Logging backend with SOF probes" - depends on LOG - select LOG_OUTPUT - help - Enable backend for log output via SOF probe interface. - Probe interface allows to transmit logs and PCM data, muxed over - a shared DMA channel. - Logging is enabled by setting up a probe point with - probe purpose value of PROBE_PURPOSE_LOGGING. - -config LOG_BACKEND_SOF_PROBE_OUTPUT_DICTIONARY - bool "Dictionary" - select LOG_DICTIONARY_SUPPORT - help - Set output format of the SOF probe logging backend to - Zephyr log dictionary. - The resulting log file can be parsed with tools in - zephyr/scripts/logging/dictionary - A dictionary for the binary is created during build. - -config LOG_BACKEND_SOF_PROBE_OUTPUT - int "Set logging output format" - default 1 if LOG_MIPI_SYST_ENABLE - default 2 if LOG_BACKEND_SOF_PROBE_OUTPUT_DICTIONARY - default 0 # Text encoding is default - help - Set the logging format for SOF probe output. - -endmenu diff --git a/src/logging/log_backend_probe.c b/src/logging/log_backend_probe.c index b701fb88756b..0b852d780455 100644 --- a/src/logging/log_backend_probe.c +++ b/src/logging/log_backend_probe.c @@ -14,6 +14,10 @@ #include <sof/lib/notifier.h> #include <sof/probe/probe.h> +#ifdef PROBE_LOG_DEBUG +#include <stdio.h> +#endif + /* * A lock is needed as log_process() and log_panic() have no internal locks * to prevent concurrency. Meaning if log_process is called after @@ -33,10 +37,81 @@ static uint8_t log_buf[LOG_BUF_SIZE]; static probe_logging_hook_t probe_hook; +static void log_push(uint8_t *data, size_t length) +{ + size_t pos = 0; + + do { + int ret = probe_hook(data + pos, length - pos); + + if (ret < 0) + break; + pos += ret; + } while (pos < length); +} + +#define PRE_BUFFER_SIZE 4096 +static struct probe_pre_buffer { + uint8_t *buf; + size_t wpos; + size_t len; +} prebuf; + +static void pre_buffer_drain(void) +{ +#ifdef PROBE_LOG_DEBUG + /* NOTE: The debug code only works with ascii/text log output */ + uint64_t stamp = sof_cycle_get_64(); + char msg[80]; + int mlen; + + mlen = snprintf(msg, sizeof(msg), "[Drain %zu bytes of pre buffered logs]\n", prebuf.wpos); + if (prebuf.len > prebuf.wpos && mlen < sizeof(msg)) + mlen += snprintf(msg + mlen, sizeof(msg) - mlen, "[%zu bytes dropped]\n", + prebuf.len - prebuf.wpos); + log_push(msg, MIN(mlen, sizeof(msg))); +#endif + + log_push(prebuf.buf, prebuf.wpos); + rfree(prebuf.buf); + prebuf.buf = NULL; + prebuf.len = 0; + prebuf.wpos = 0; + +#ifdef PROBE_LOG_DEBUG + mlen = snprintf(msg, sizeof(msg), "[Buffer drained in %llu us]\n", + k_cyc_to_us_near64(sof_cycle_get_64() - stamp)); + + log_push(msg, MIN(mlen, sizeof(msg))); +#endif +} + +static void pre_buffer(uint8_t *data, size_t length) +{ + int ret; + + prebuf.len += length; + if (!prebuf.buf) { + prebuf.buf = rzalloc(SOF_MEM_FLAG_USER, PRE_BUFFER_SIZE); + if (!prebuf.buf) + return; + } + /* Protection against buffer over flow relies on memcpy_s() */ + ret = memcpy_s(&prebuf.buf[prebuf.wpos], PRE_BUFFER_SIZE - prebuf.wpos, data, length); + if (!ret) + prebuf.wpos += length; +} + static int probe_char_out(uint8_t *data, size_t length, void *ctx) { - if (probe_hook) - probe_hook(data, length); + if (!probe_hook) { + pre_buffer(data, length); + } else { + if (prebuf.wpos) + pre_buffer_drain(); + + log_push(data, length); + } return length; } diff --git a/src/math/CMakeLists.txt b/src/math/CMakeLists.txt index 9b506eb0b85e..a52263006295 100644 --- a/src/math/CMakeLists.txt +++ b/src/math/CMakeLists.txt @@ -1,58 +1,113 @@ # SPDX-License-Identifier: BSD-3-Clause if(BUILD_LIBRARY) - add_local_sources(sof numbers.c) - return() + add_local_sources(sof numbers.c) + return() endif() -add_local_sources(sof numbers.c) +set(base_files numbers.c gcc-builtins.c) if(CONFIG_CORDIC_FIXED) - add_local_sources(sof trig.c) + list(APPEND base_files trig.c) endif() -add_local_sources_ifdef(CONFIG_MATH_LUT_SINE_FIXED sof lut_trig.c) +if(CONFIG_MATH_ATAN2) + list(APPEND base_files atan2.c) +endif() + +if(CONFIG_MATH_LUT_SINE_FIXED) + list(APPEND base_files lut_trig.c) +endif() -add_local_sources_ifdef(CONFIG_SQRT_FIXED sof sqrt_int16.c) +if(CONFIG_SQRT_FIXED) + list(APPEND base_files sqrt_int16.c sqrt_int32.c) +endif() -add_local_sources_ifdef(CONFIG_MATH_EXP sof exp_fcn.c exp_fcn_hifi.c) +if(CONFIG_MATH_EXP) + list(APPEND base_files exp_fcn.c exp_fcn_hifi.c) +endif() if(CONFIG_MATH_DECIBELS) - add_local_sources(sof decibels.c) + list(APPEND base_files decibels.c) endif() -add_local_sources_ifdef(CONFIG_NATURAL_LOGARITHM_FIXED sof log_e.c) +if(CONFIG_NATURAL_LOGARITHM_FIXED) + list(APPEND base_files log_e.c) +endif() -add_local_sources_ifdef(CONFIG_COMMON_LOGARITHM_FIXED sof log_10.c) +if(CONFIG_COMMON_LOGARITHM_FIXED) + list(APPEND base_files log_10.c) +endif() -add_local_sources_ifdef(CONFIG_POWER_FIXED sof power.c) +if(CONFIG_POWER_FIXED) + list(APPEND base_files power.c) +endif() -add_local_sources_ifdef(CONFIG_BINARY_LOGARITHM_FIXED sof base2log.c) +if(CONFIG_BINARY_LOGARITHM_FIXED) + list(APPEND base_files base2log.c) +endif() -add_local_sources_ifdef(CONFIG_MATH_FIR sof fir_generic.c fir_hifi2ep.c fir_hifi3.c) +if(CONFIG_MATH_FIR STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(fir_llext ${PROJECT_BINARY_DIR}/aux1_fir_llext) + add_dependencies(app aux1_fir) +elseif(CONFIG_MATH_FIR) + list(APPEND base_files fir_generic.c fir_hifi2ep.c fir_hifi3.c fir_hifi5.c) +endif() if(CONFIG_MATH_FFT) - add_subdirectory(fft) + add_subdirectory(fft) endif() -add_local_sources_ifdef(CONFIG_MATH_IIR_DF2T sof - iir_df2t_generic.c iir_df2t_hifi3.c iir_df2t.c) - -add_local_sources_ifdef(CONFIG_MATH_IIR_DF1 sof - iir_df1_generic.c iir_df1_hifi3.c iir_df1_hifi4.c iir_df1_hifi5.c iir_df1.c) +if(CONFIG_MATH_IIR STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(iir_llext ${PROJECT_BINARY_DIR}/aux1_iir_llext) + add_dependencies(app aux1_iir) +elseif(CONFIG_MATH_IIR) + if(CONFIG_MATH_IIR_DF2T) + list(APPEND base_files iir_df2t_generic.c iir_df2t_hifi3.c iir_df2t.c) + endif() + + if(CONFIG_MATH_IIR_DF1) + list(APPEND base_files iir_df1_generic.c iir_df1_hifi3.c iir_df1_hifi4.c iir_df1_hifi5.c iir_df1.c) + endif() +endif() if(CONFIG_MATH_WINDOW) - add_local_sources(sof window.c) + list(APPEND base_files window.c) endif() if(CONFIG_MATH_MATRIX) - add_local_sources(sof matrix.c) + list(APPEND base_files matrix.c) endif() if(CONFIG_MATH_AUDITORY) - add_subdirectory(auditory) + add_subdirectory(auditory) endif() if(CONFIG_MATH_DCT) - add_local_sources(sof dct.c) + list(APPEND base_files dct.c) +endif() + +if(CONFIG_MATH_A_LAW_CODEC) + list(APPEND base_files a_law.c) +endif() + +if(CONFIG_MATH_MU_LAW_CODEC) + list(APPEND base_files mu_law.c) +endif() + +if(CONFIG_MATH_COMPLEX) + list(APPEND base_files complex.c) +endif() + +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + zephyr_library_sources( + ${base_files} + ) + +else() ### library, e.g. testbench or plugin ### + + add_local_sources(sof ${base_files}) + endif() diff --git a/src/math/Kconfig b/src/math/Kconfig index ccd7520f20a7..1feaab8f03d1 100644 --- a/src/math/Kconfig +++ b/src/math/Kconfig @@ -9,6 +9,16 @@ config CORDIC_FIXED Select this to enable sin(), cos(), asin(), acos(), and cexp() functions as 16 bit and 32 bit versions. +config MATH_ATAN2 + bool "Four-quadrant arctangent function" + default n + help + Select this to enable sofm_atan2_32b(y, x) function. It computes + the four-quadrant arctangent using a polynomial approximation. + Input arguments y and x are Q1.31 format and the output angle + is Q3.29 format with range [-pi, pi]. The maximum approximation + error is ~0.001 degrees. + config MATH_LUT_SINE_FIXED bool "Lookup table based sine function" default n @@ -95,13 +105,33 @@ config MATH_DECIBELS Select this to enable db2lin_fixed() and exp_fixed() functions. +config MATH_COMPLEX + bool "Operations for complex numbers" + default n + select CORDIC_FIXED + select MATH_ATAN2 + select SQRT_FIXED + help + Select this to enable functions for complex numbers + arithmetic such as conversions to/from polar format. + config MATH_FFT bool "FFT library" default n + select MATH_COMPLEX help Enable Fast Fourier Transform library, this should not be selected directly, please select it from other audio components where need it. +config MATH_FFT_MULTI + bool "FFT library for some non-power-of-two sizes" + depends on MATH_FFT + default n + help + Enable Fast Fourier Transform library for e.g. sizes 1536 and 3072, + this should not be selected directly, please select it from other + audio components where need it. + menu "Supported FFT word lengths" visible if MATH_FFT @@ -170,7 +200,7 @@ choice "FILTER_SIMD_LEVEL_SELECT" endchoice config MATH_FIR - bool "FIR filter library" + tristate "FIR filter library" default n help This option builds FIR (Finite Impulse Response) filter library. It @@ -178,8 +208,16 @@ config MATH_FIR filter calculates a convolution of input PCM sample and a configurable impulse response. +config MATH_IIR + tristate "Select IIR filter library build method" + default m if LIBRARY_DEFAULT_MODULAR + default y + help + A helper option for MATH_IIR_DF2T and MATH_IIR_DF1 + config MATH_IIR_DF2T bool "IIR DF2T filter library" + depends on MATH_IIR != "n" default n help Select this to build IIR (Infinite Impulse Response) filter @@ -187,6 +225,7 @@ config MATH_IIR_DF2T config MATH_IIR_DF1 bool "IIR DF1 filter library" + depends on MATH_IIR != "n" default n help Select this to build IIR (Infinite Impulse Response) filter @@ -260,4 +299,24 @@ config MATH_DCT transform for data is done as matrix multiply with the returned DCT matrix. +config MATH_A_LAW_CODEC + bool "A-law encoder and decoder" + help + This option enables functions sofm_a_law_encode() and + sofm_a_law_decode(). The A-law codec is defined in + ITU-T G.711 standard and has been used in telecommunications + in e.g. Europe. The A-law coding compresses 13 bit samples + to 8 bit coded data. A-law codec can be used in VoIP and + 8-bit wav formats. + +config MATH_MU_LAW_CODEC + bool "mu-law encoder and decoder" + help + This option enables functions sofm_mu_law_encode() and + sofm_mu_law_decode(). The mu-law codec is defined in + ITU-T G.711 standard and has been used in telecommunications + in USA and Japan. The mu-law coding compresses 14 bit samples + to 8 bit coded data. Mu-law codec can be used in VoIP and + 8-bit wav formats. + endmenu diff --git a/src/math/a_law.c b/src/math/a_law.c new file mode 100644 index 000000000000..7a0b906ec255 --- /dev/null +++ b/src/math/a_law.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +#include <sof/audio/format.h> +#include <sof/math/a_law.h> +#include <stdint.h> + +#define SOFM_ALAW_SIGN_BIT 0x80 +#define SOFM_ALAW_MAX 4095 +#define SOFM_ALAW_TOGGLE_EVEN_BITS 0x55 +#define SOFM_ALAW_MANTISSA_MASK 0x0f +#define SOFM_ALAW_MANTISSA_BITS 4 +#define SOFM_ALAW_SHIFT_MASK 0x07 +#define SOFM_ALAW_DEC_ONES_MASK 0x21 /* 0b100001 for "1abcd1", see below */ + +/* + * A-law encode table (sign bit is b12) + * + * Input values 11:0 Output values 6:0 + * + * 0 0 0 0 0 0 0 a b c d x 0 0 0 a b c d + * 0 0 0 0 0 0 1 a b c d x 0 0 1 a b c d + * 0 0 0 0 0 1 a b c d x x 0 1 0 a b c d + * 0 0 0 0 1 a b c d x x x 0 1 1 a b c d + * 0 0 0 1 a b c d x x x x 1 0 0 a b c d + * 0 0 1 a b c d x x x x x 1 0 1 a b c d + * 0 1 a b c d x x x x x x 1 1 0 a b c d + * 1 a b c d x x x x x x x 1 1 1 a b c d + * + * + * A-law decode table (sign bit is b7) + * + * Input values 6:0 Output values 11:0 + * + * 0 0 0 a b c d 0 0 0 0 0 0 0 a b c d 1 + * 0 0 1 a b c d 0 0 0 0 0 0 1 a b c d 1 + * 0 1 0 a b c d 0 0 0 0 0 1 a b c d 1 0 + * 0 1 1 a b c d 0 0 0 0 1 a b c d 1 0 0 + * 1 0 0 a b c d 0 0 0 1 a b c d 1 0 0 0 + * 1 0 1 a b c d 0 0 1 a b c d 1 0 0 0 0 + * 1 1 0 a b c d 0 1 a b c d 1 0 0 0 0 0 + * 1 1 1 a b c d 1 a b c d 1 0 0 0 0 0 0 + * + */ + +/* Shift values lookup table for above table for 7 + * highest sample value bits. + */ +static uint8_t alaw_encode_shifts[128] = { + 1, 1, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, +}; + +/** + * sofm_a_law_encode() - Encode sample with A-law coding + * @param sample: A s16 sample value + * + * The A-law codec is defined in ITU-T G.711 standard and has been used + * in telecommunications in e.g. Europe. The A-law coding compresses 13 bit + * samples to 8 bit data stream. In SOF the high 13 bits of s16 format are + * used for compatibility with normal audios. + * + * @return: Compressed 8 bit code value + */ + +uint8_t sofm_a_law_encode(int16_t sample) +{ + int sign = SOFM_ALAW_SIGN_BIT; + int shift = 0; + int low_bits; + uint8_t byte; + + /* Convert to 13 bits with shift */ + sample >>= 3; + + /* Negative samples are 1's complement with zero sign bit */ + if (sample < 0) { + sign = 0; + sample = -sample - 1; + } + + if (sample > SOFM_ALAW_MAX) + sample = SOFM_ALAW_MAX; + + if (sample > 31) { + shift = alaw_encode_shifts[sample >> 5]; + low_bits = (sample >> shift) & SOFM_ALAW_MANTISSA_MASK; + } else { + low_bits = (sample >> 1) & SOFM_ALAW_MANTISSA_MASK; + } + + byte = (shift << SOFM_ALAW_MANTISSA_BITS) | low_bits; + byte = (byte | sign) ^ SOFM_ALAW_TOGGLE_EVEN_BITS; + return byte; +} + +/** + * sofm_a_law_decode() - Decode A-law encoded code word + * @param byte: Encoded code word + * + * The A-law decoder expands a 8 bit code word into a 13 bit sample value. + * In the SOF the high 13 bits are aligned to the most significant bits + * to be compatible with normal s16 Q1.15 samples. + * + * @return: Sample value in s16 format + */ +int16_t sofm_a_law_decode(int8_t byte) +{ + int low_bits; + int shift; + int sign; + int16_t value; + + byte ^= SOFM_ALAW_TOGGLE_EVEN_BITS; + low_bits = byte & SOFM_ALAW_MANTISSA_MASK; + shift = (byte >> SOFM_ALAW_MANTISSA_BITS) & SOFM_ALAW_SHIFT_MASK; + sign = byte & SOFM_ALAW_SIGN_BIT; + + if (shift > 0) + value = (low_bits << shift) | (SOFM_ALAW_DEC_ONES_MASK << (shift - 1)); + else + value = (low_bits << 1) | 1; + + if (!sign) + value = -value; + + /* Shift 13 bit Q1.12 to 16 bit Q1.15 */ + return value << 3; +} diff --git a/src/math/atan2.c b/src/math/atan2.c new file mode 100644 index 000000000000..652f1d5c9cc7 --- /dev/null +++ b/src/math/atan2.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +/** + * \file math/atan2.c + * \brief Four-quadrant arctangent function using polynomial approximation + */ + +#include <rtos/symbol.h> +#include <sof/audio/format.h> +#include <sof/math/trig.h> +#include <stdint.h> + +/* + * Degree-9 Remez minimax polynomial for atan(z) in first octant, z in [0, 1]: + * + * atan(z) = z * (C0 + z^2 * (C1 + z^2 * (C2 + z^2 * (C3 + z^2 * C4)))) + * + * Coefficients are in Q3.29 format, computed via Remez exchange algorithm + * to minimize the maximum approximation error over [0, 1]. + * Maximum approximation error is ~0.0011 degrees (1.94e-5 radians). + */ +#define SOFM_ATAN2_C0 536890772 /* Q3.29, +1.000036992319 */ +#define SOFM_ATAN2_C1 -178298711 /* Q3.29, -0.332107229582 */ +#define SOFM_ATAN2_C2 99794340 /* Q3.29, +0.185881443393 */ +#define SOFM_ATAN2_C3 -49499604 /* Q3.29, -0.092200197922 */ +#define SOFM_ATAN2_C4 12781063 /* Q3.29, +0.023806584771 */ + +/** + * sofm_atan2_32b() - Compute four-quadrant arctangent of y/x + * @param y Imaginary component in Q1.31 format + * @param x Real component in Q1.31 format + * @return Angle in Q3.29 radians, range [-pi, +pi] + * + * Uses degree-9 Remez minimax polynomial for the core atan(z) computation + * where z = min(|y|,|x|) / max(|y|,|x|) is reduced to [0, 1] range. + * Octant and quadrant corrections extend the result to full [-pi, +pi]. + */ +int32_t sofm_atan2_32b(int32_t y, int32_t x) +{ + int32_t abs_x; + int32_t abs_y; + int32_t num; + int32_t den; + int32_t z; + int32_t z2; + int32_t acc; + int32_t angle; + int swap; + + /* Return zero for origin */ + if (x == 0 && y == 0) + return 0; + + /* Take absolute values, handle INT32_MIN overflow */ + abs_x = (x > 0) ? x : ((x == INT32_MIN) ? INT32_MAX : -x); + abs_y = (y > 0) ? y : ((y == INT32_MIN) ? INT32_MAX : -y); + + /* Reduce to first octant: z = min/max ensures z in [0, 1] */ + if (abs_y <= abs_x) { + num = abs_y; + den = abs_x; + swap = 0; + } else { + num = abs_x; + den = abs_y; + swap = 1; + } + + /* z = num / den in Q1.31, den is always > 0 here */ + z = sat_int32(((int64_t)num << 31) / den); + + /* + * Horner evaluation of degree-9 Remez minimax polynomial: + * atan(z) = z * (C0 + z^2 * (C1 + z^2 * (C2 + z^2 * (C3 + z^2 * C4)))) + * + * z is Q1.31, coefficients are Q3.29. + * Multiplications: Q1.31 * Q3.29 = Q4.60, >> 31 -> Q3.29. + */ + + /* z^2: Q1.31 * Q1.31 = Q2.62, >> 31 -> Q1.31 */ + z2 = (int32_t)(((int64_t)z * z) >> 31); + + /* Innermost: C3 + z^2 * C4 */ + acc = (int32_t)(((int64_t)z2 * SOFM_ATAN2_C4) >> 31) + SOFM_ATAN2_C3; + + /* C2 + z^2 * (C3 + z^2 * C4) */ + acc = (int32_t)(((int64_t)z2 * acc) >> 31) + SOFM_ATAN2_C2; + + /* C1 + z^2 * (C2 + z^2 * (C3 + z^2 * C4)) */ + acc = (int32_t)(((int64_t)z2 * acc) >> 31) + SOFM_ATAN2_C1; + + /* C0 + z^2 * (C1 + z^2 * (C2 + z^2 * (C3 + z^2 * C4))) */ + acc = (int32_t)(((int64_t)z2 * acc) >> 31) + SOFM_ATAN2_C0; + + /* angle = z * acc: Q1.31 * Q3.29 = Q4.60, >> 31 -> Q3.29 */ + angle = (int32_t)(((int64_t)z * acc) >> 31); + + /* If |y| > |x|, use identity: atan(y/x) = pi/2 - atan(x/y) */ + if (swap) + angle = PI_DIV2_Q3_29 - angle; + + /* Map to correct quadrant based on signs of x and y */ + if (x < 0) + angle = (y >= 0) ? PI_Q3_29 - angle : -(PI_Q3_29 - angle); + else if (y < 0) + angle = -angle; + + return angle; +} +EXPORT_SYMBOL(sofm_atan2_32b); diff --git a/src/math/auditory/CMakeLists.txt b/src/math/auditory/CMakeLists.txt index 2983e1eb4483..b24cf968f237 100644 --- a/src/math/auditory/CMakeLists.txt +++ b/src/math/auditory/CMakeLists.txt @@ -1,7 +1,24 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof auditory.c) +set(base_files auditory.c) -add_local_sources_ifdef(CONFIG_MATH_16BIT_MEL_FILTERBANK sof mel_filterbank_16.c) +if(CONFIG_MATH_16BIT_MEL_FILTERBANK) + list(APPEND base_files mel_filterbank_16.c) +endif() -add_local_sources_ifdef(CONFIG_MATH_32BIT_MEL_FILTERBANK sof mel_filterbank_32.c) +if(CONFIG_MATH_32BIT_MEL_FILTERBANK) + list(APPEND base_files mel_filterbank_32.c) +endif() + +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + zephyr_library_sources( + ${base_files} + ) + +else() ### library, e.g. testbench or plugin ### + + add_local_sources(sof ${base_files}) + +endif() diff --git a/src/math/auditory/auditory.c b/src/math/auditory/auditory.c index edff8d38e6e6..0abd10de9308 100644 --- a/src/math/auditory/auditory.c +++ b/src/math/auditory/auditory.c @@ -4,6 +4,7 @@ // // Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> +#include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/format.h> #include <rtos/alloc.h> #include <sof/math/auditory.h> @@ -11,10 +12,13 @@ #include <sof/math/fft.h> #include <sof/math/log.h> #include <sof/math/numbers.h> +#include <sof/trace/trace.h> #include <ipc/topology.h> #include <errno.h> #include <stdint.h> +LOG_MODULE_REGISTER(math_auditory, CONFIG_SOF_LOG_LEVEL); + #define ONE_Q16 Q_CONVERT_FLOAT(1, 16) #define ONE_Q20 Q_CONVERT_FLOAT(1, 20) #define ONE_Q30 Q_CONVERT_FLOAT(1, 30) @@ -85,7 +89,7 @@ int16_t psy_mel_to_hz(int16_t mel) return hz; } -int psy_get_mel_filterbank(struct psy_mel_filterbank *fb) +int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *fb) { int32_t up_slope; int32_t down_slope; @@ -116,6 +120,16 @@ int psy_get_mel_filterbank(struct psy_mel_filterbank *fb) if (!fb->scratch_data1 || !fb->scratch_data2) return -ENOMEM; + /* fb->mel_bins is used both as the loop bound and as part of the + * (mel_bins + 1) divisor below. Reject non-positive values up front to + * avoid a divide by zero (mel_bins == -1) and to keep mel_step + * meaningful. + */ + if (fb->mel_bins <= 0 || fb->mel_bins > AUDITORY_MAX_MEL_BANDS) { + comp_cl_err(mod->dev, "Invalid mel_bins %d", fb->mel_bins); + return -EINVAL; + } + /* Log power can be log, or log10 or dB, get multiply coef to convert * log to desired format. */ @@ -148,6 +162,17 @@ int psy_get_mel_filterbank(struct psy_mel_filterbank *fb) mel_start = psy_hz_to_mel(fb->start_freq); mel_end = psy_hz_to_mel(fb->end_freq); mel_step = (mel_end - mel_start) / (fb->mel_bins + 1); + /* delta_cl / delta_rc below are both equal to mel_step; guard against + * a non-positive step (start_freq >= end_freq, or so many bins that + * the integer division truncates to zero) before using them as + * divisors. + */ + if (mel_step <= 0) { + comp_cl_err(mod->dev, "Invalid mel_step %d (start_freq=%d end_freq=%d mel_bins=%d)", + mel_step, fb->start_freq, fb->end_freq, fb->mel_bins); + return -EINVAL; + } + for (i = 0; i < fb->mel_bins; i++) { left_mel = mel_start + i * mel_step; center_mel = mel_start + (i + 1) * mel_step; @@ -159,6 +184,11 @@ int psy_get_mel_filterbank(struct psy_mel_filterbank *fb) if (fb->slaney_normalize) { left_hz = psy_mel_to_hz(left_mel); right_hz = psy_mel_to_hz(right_mel); + if (right_hz <= left_hz) { + comp_cl_err(mod->dev, "Invalid Hz range left=%d right=%d at mel bin %d", + left_hz, right_hz, i); + return -EINVAL; + } scale = Q_SHIFT_RND(TWO_Q29 / (right_hz - left_hz), 29, 16); /* Q16.16*/ if (i == 0) { scale_inv = Q_SHIFT_LEFT(ONE_Q30 / scale, 14, 16); @@ -200,8 +230,7 @@ int psy_get_mel_filterbank(struct psy_mel_filterbank *fb) } fb->data_length = &fb->scratch_data2[base_idx] - &fb->scratch_data2[0]; - fb->data = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(int16_t) * fb->data_length); + fb->data = mod_zalloc(mod, sizeof(int16_t) * fb->data_length); if (!fb->data) return -ENOMEM; @@ -210,3 +239,8 @@ int psy_get_mel_filterbank(struct psy_mel_filterbank *fb) fb->scratch_data2, sizeof(int16_t) * fb->data_length); return 0; } + +int mod_psy_free_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *mel_fb) +{ + return mod_free(mod, mel_fb->data); +} diff --git a/src/math/auditory/mel_filterbank_16.c b/src/math/auditory/mel_filterbank_16.c index 2ed62c319d38..f5a18f052b77 100644 --- a/src/math/auditory/mel_filterbank_16.c +++ b/src/math/auditory/mel_filterbank_16.c @@ -6,7 +6,7 @@ #include <sof/audio/format.h> #include <sof/math/auditory.h> -#include <sof/math/fft.h> +#include <sof/math/icomplex16.h> #include <sof/math/log.h> #include <sof/math/numbers.h> #include <stdint.h> diff --git a/src/math/auditory/mel_filterbank_32.c b/src/math/auditory/mel_filterbank_32.c index 69b781817870..414ddf482f93 100644 --- a/src/math/auditory/mel_filterbank_32.c +++ b/src/math/auditory/mel_filterbank_32.c @@ -6,13 +6,13 @@ #include <sof/audio/format.h> #include <sof/math/auditory.h> -#include <sof/math/fft.h> +#include <sof/math/icomplex32.h> #include <sof/math/log.h> #include <sof/math/numbers.h> #include <stdint.h> void psy_apply_mel_filterbank_32(struct psy_mel_filterbank *fb, struct icomplex32 *fft_out, - int32_t *power_spectra, int16_t *mel_log, int bitshift) + int32_t *power_spectra, int32_t *mel_log, int bitshift) { int64_t pmax; int64_t p; @@ -79,8 +79,8 @@ void psy_apply_mel_filterbank_32(struct psy_mel_filterbank *fb, struct icomplex3 */ log -= ((int32_t)lshift + 2 * bitshift) << 16; - /* Scale for desired log */ - log = Q_MULTSR_32X32((int64_t)log, fb->log_mult, 16, 29, 7); - mel_log[i] = sat_int16(log); /* Q8.7 */ + /* Scale for desired log, output as Q9.23 */ + log = Q_MULTSR_32X32((int64_t)log, fb->log_mult, 16, 29, 23); + mel_log[i] = log; /* Q9.23 */ } } diff --git a/src/math/complex.c b/src/math/complex.c new file mode 100644 index 000000000000..ac2a59e91498 --- /dev/null +++ b/src/math/complex.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> +// + +#include <rtos/symbol.h> +#include <sof/audio/format.h> +#include <sof/math/icomplex32.h> +#include <sof/math/sqrt.h> +#include <sof/math/trig.h> +#include <stdint.h> + +/* sofm_icomplex32_to_polar() - Convert (re, im) complex number to polar. */ +void sofm_icomplex32_to_polar(struct icomplex32 *complex, struct ipolar32 *polar) +{ + struct icomplex32 c = *complex; + int64_t squares_sum; + int32_t sqrt_arg; + + /* Calculate square of magnitudes Q1.31, result is Q2.62 */ + squares_sum = (int64_t)c.real * c.real + (int64_t)c.imag * c.imag; + + /* Square root */ + sqrt_arg = Q_SHIFT_RND(squares_sum, 62, 30); + polar->magnitude = sofm_sqrt_int32(sqrt_arg); /* Q2.30 */ + + /* Angle */ + polar->angle = sofm_atan2_32b(c.imag, c.real); /* Q3.29 */ +} +EXPORT_SYMBOL(sofm_icomplex32_to_polar); + +/* sofm_ipolar32_to_complex() - Convert complex number from polar to normal (re, im) format. */ +void sofm_ipolar32_to_complex(struct ipolar32 *polar, struct icomplex32 *complex) +{ + struct cordic_cmpx cexp; + int32_t phase; + int32_t magnitude; + + /* The conversion can happen in-place, so load copies of the values first */ + magnitude = polar->magnitude; + phase = Q_SHIFT_RND(polar->angle, 29, 28); /* Q3.29 to Q2.28 */ + cmpx_exp_32b(phase, &cexp); /* Q2.30 */ + complex->real = sat_int32(Q_MULTSR_32X32((int64_t)magnitude, cexp.re, 30, 30, 31)); + complex->imag = sat_int32(Q_MULTSR_32X32((int64_t)magnitude, cexp.im, 30, 30, 31)); +} +EXPORT_SYMBOL(sofm_ipolar32_to_complex); diff --git a/src/math/dct.c b/src/math/dct.c index 15d23b67c7f9..e4bbe5623dd8 100644 --- a/src/math/dct.c +++ b/src/math/dct.c @@ -4,6 +4,7 @@ // // Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> +#include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/format.h> #include <sof/math/matrix.h> #include <sof/math/dct.h> @@ -31,7 +32,7 @@ * multiply with the returned matrix. * \param[in,out] dct In input provide DCT type and size, in output the DCT matrix */ -int dct_initialize_16(struct dct_plan_16 *dct) +int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct) { int16_t dct_val; int32_t arg; @@ -51,13 +52,13 @@ int dct_initialize_16(struct dct_plan_16 *dct) if (dct->num_in > DCT_MATRIX_SIZE_MAX || dct->num_out > DCT_MATRIX_SIZE_MAX) return -EINVAL; - dct->matrix = mat_matrix_alloc_16b(dct->num_in, dct->num_out, 15); + dct->matrix = mod_mat_matrix_alloc_16b(mod, dct->num_in, dct->num_out, 15); if (!dct->matrix) return -ENOMEM; c1 = PI_Q29 / dct->num_in; arg = Q_SHIFT_RND(TWO_Q29 / dct->num_in, 29, 12); - c2 = sqrt_int16(arg); /* Q4.12 */ + c2 = sofm_sqrt_int16(arg); /* Q4.12 */ for (n = 0; n < dct->num_in; n++) { for (k = 0; k < dct->num_out; k++) { /* Note: Current int16_t nk works up to DCT_MATRIX_SIZE_MAX = 91 */ @@ -77,3 +78,8 @@ int dct_initialize_16(struct dct_plan_16 *dct) return 0; } + +int mod_dct_free_16(struct processing_module *mod, struct dct_plan_16 *dct) +{ + return mod_free(mod, dct->matrix); +} diff --git a/src/math/exp_fcn.c b/src/math/exp_fcn.c index 6ada84202212..5ada3f708c7f 100644 --- a/src/math/exp_fcn.c +++ b/src/math/exp_fcn.c @@ -1,228 +1,170 @@ // SPDX-License-Identifier: BSD-3-Clause /* - * Copyright(c) 2022 Intel Corporation. All rights reserved. + * Copyright(c) 2022-2025 Intel Corporation. * * Author: Shriram Shastry <malladi.sastry@linux.intel.com> - * + * Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + * Pasca, Bogdan <bogdan.pasca@intel.com> */ #include <sof/audio/format.h> #include <sof/math/exp_fcn.h> #include <sof/math/numbers.h> -#include <sof/common.h> -#include <rtos/bit.h> #include <rtos/symbol.h> -#include <stdbool.h> +#include <sof/common.h> #include <stdint.h> -#include <stddef.h> -#include <errno.h> #if defined(EXPONENTIAL_GENERIC) -#define SOFM_CONVERG_ERROR 28823037607936LL // error smaller than 1e-4,1/2 ^ -44.7122876200884 - -/* inv multiplication lookup table */ -/* LUT = ceil(1/factorial(b_n) * 2 ^ 63) */ -static const int64_t exp_iv_ilookup[19] = { - 4611686018427387904LL, - 1537228672809129301LL, - 384307168202282325LL, - 76861433640456465LL, - 12810238940076077LL, - 1830034134296582LL, - 228754266787072LL, - 25417140754119LL, - 2541714075411LL, - 231064915946LL, - 19255409662LL, - 1481185358LL, - 105798954LL, - 7053264LL, - 440829LL, - 25931LL, - 1441LL, - 76LL, - 4LL -}; +#define SOFM_EXP_ONE_OVER_LOG2_Q30 1549082005 /* Q2.30 int32(round(1/log(2) * 2^30)) */ +#define SOFM_EXP_LOG2_Q31 1488522236 /* Q1.31 int32(round(log(2) * 2^31)) */ +#define SOFM_EXP_FIXED_INPUT_MINUS8 -1073741824 /* Q5.27 int32(-8 * 2^27) */ +#define SOFM_EXP_FIXED_INPUT_PLUS8 1073741823 /* Q5.27 int32(8 * 2^27) */ +#define SOFM_EXP_LOG10_DIV20_Q27 15452387 /* Q5.27 int32(round(log(10)/20*2^27)) */ -/* Function Declarations */ -/* - * Arguments : int64_t in_0 - * int64_t in_1 - * uint64_t *ptroutbitshi - * uint64_t *ptroutbitslo - * Multiplication of two signed int64 numbers - * Return Type : void - * Description:Perform element-wise multiplication on in_0 and in_1 - * while keeping the required product word length and fractional - * length in mind. mul_s64 function divide the 64-bit quantities - * into two 32-bit words, multiply the low words to produce the - * lowest and second-lowest words in the result, then both pairs - * of low and high words from different numbers to produce the - * second and third lowest words in the result, and finally both - * high words to produce the two highest words in the outcome. - * Add them all up, taking carry into consideration. - * - * The 64 x 64 bit multiplication of operands in_0 and in_1 is - * shown in the image below. The 64-bit operand in_0, in_1 is - * represented by the notation in0_H, in1_H for the top 32 bits - * and in0_L, in1_L for the bottom 32 bits. - * - * in0_H : in0_L - * x in1_H : in1_L - * --------------------- - * P0 in0_L x in1_L - * P1 in0_H x in1_L 64 bit inner multiplication - * P2 in0_L x in1_H 64 bit inner multiplication - * P3 in0_H x in1_H - * -------------------- - * [64 x 64 bit multiplication] sum of inner products - * All combinations are multiplied by one another and then added. - * Each inner product is moved into its proper power location, given the names - * of the inner products, redoing the addition where 000 represents 32 zero - * bits. The inner products can be added together in 64 bit addition. The sum - * of two 64-bit numbers yields a 65-bit output. - * (P0H:P0L) - * P1H(P1L:000) - * P2H(P2L:000) - * P3H:P3L(000:000) - * .......(aaa:P0L) - * By combining P0H:P0L and P1L:000. This can lead to a carry, denote as CRY0. - * The partial result is then multiplied by P2L:000. - * We call it CRY1 because it has the potential to carry again. - * (CRY0 + CRY1)P0H:P0L - * ( P1H)P1L:000 - * ( P2H)P2L:000 - * (P3H: P3L)000:000 - * -------------------- - * (ccc:bbb)aaa:P0L - * P1H, P2H, and P3H:P3L are added to the carry CRY0 + CRY1. This increase will - * not result in an overflow. +/* The table contains exponents of value v, where values of v + * are the 3 bit 2's complement signed values presented by bits + * of index 0..7. * + * v = [(0:3)/8 (-4:-1)/8]; + * uint32(round(exp(v) * 2^31)) */ -static inline void mul_s64(int64_t in_0, int64_t in_1, uint64_t *ptroutbitshi, - uint64_t *ptroutbitslo) -{ - uint64_t absin0 = ABS(in_0); - uint64_t absin1 = ABS(in_1); - uint64_t in0hi = absin0 >> 32; - uint64_t in0lo = absin0 & UINT32_MAX; - uint64_t in1hi = absin1 >> 32; - uint64_t prodhilo; - uint64_t prodlohi; - - absin0 = absin1 & UINT32_MAX; - /* multiplication */ - prodhilo = in0hi * absin0; - prodlohi = in0lo * in1hi; - absin0 *= in0lo; - - in0lo = absin0 + (prodlohi << 32); - absin1 = in0lo < absin0 ? 1 : 0; - absin0 = in0lo; - /* shift and add */ - in0lo += prodhilo << 32; - if (in0lo < absin0) - absin1++; - /* carry */ - absin0 = absin1 + in0hi * in1hi + (prodlohi >> 32) + (prodhilo >> 32); - /* 2's complement */ - if (in_0 && in_1 && (in_0 > 0) != (in_1 > 0)) { - /* bit inversion */ - absin0 = ~absin0; - in0lo = ~in0lo; - /* add to low byte */ - in0lo++; - if (!in0lo) - absin0++; - } - /* pointer- output high and low bytes */ - *ptroutbitshi = absin0; - *ptroutbitslo = in0lo; -} +static const uint32_t sofm_exp_3bit_lookup[8] = { + 2147483648, 2433417774, 2757423586, 3124570271, + 1302514674, 1475942488, 1672461947, 1895147668 +}; -/* - * Arguments : int64_t a - * int64_t b - * Return Type : int64_t +/* Taylor polynomial coefficients for x^3..x^6, calculated + * uint32(round(1 ./ factorial(3:6) * 2^32)) */ -static inline int64_t lomul_s64_sr_sat_near(int64_t a, int64_t b) -{ - uint64_t u64_rhi; - uint64_t u64_rlo; - - mul_s64(a, b, &u64_rhi, &u64_rlo); - const bool roundup = (u64_rlo & SOFM_EXP_BIT_MASK_LOW_Q27P5) != 0; - - u64_rlo = (u64_rhi << 36 | u64_rlo >> 28) + (roundup ? 1 : 0); - return u64_rlo; -} +static const uint32_t sofm_exp_taylor_coeffs[4] = { + 715827883, 178956971, 35791394, 5965232 +}; -/* function f(x) = a^x, x is variable and a is base +/* function f(x) = e^x * - * Arguments : int32_t x(Q4.28) - * input range -5 to 5 + * Arguments : int32_t x (Q4.28) + * input range -8 to 8 * - * Return Type : int32_t ts(Q9.23) - * output range 0.0067465305 to 148.4131488800 - *+------------------+-----------------+--------+--------+ - *| x | ts (returntype) | x | ts | - *+----+-----+-------+----+----+-------+--------+--------+ - *|WLen| FLen|Signbit|WLen|FLen|Signbit| Qformat| Qformat| - *+----+-----+-------+----+----+-------+--------+--------+ - *| 32 | 28 | 1 | 32 | 23 | 0 | 4.28 | 9.23 | - *+------------------+-----------------+--------+--------+ + * Return Type : int32_t (Q13.19) + * output range 3.3546e-04 to 2981.0 */ -int32_t sofm_exp_int32(int32_t x) +int32_t sofm_exp_approx(int32_t x) { - uint64_t ou0Hi; - uint64_t ou0Lo; - int64_t qt; - int32_t b_n; - int32_t ts = SOFM_EXP_TERMS_Q23P9; /* Q23.9 */ - int64_t dividend = (x + SOFM_EXP_LSHIFT_BITS) >> 14; /* x in Q50.14 */ - static const int32_t i_emin = -1342177280; /* Q4.28 */ - static const int32_t o_emin = 56601; /* Q9.23 */ - static const int32_t i_emax = 1342177280; /* Q4.28 */ - static const int32_t o_emax = 1244979733; /* Q9.23 */ + uint32_t taylor_first_2; + uint32_t exp_a_b_32bit; + uint32_t taylor_extra; + uint32_t rnd_one; + uint32_t b_f32; + uint32_t b_pow; + uint32_t exp_a; + uint32_t exp_b; + uint32_t term; + uint32_t b; + int32_t x_times_one_over_log2; + int32_t e_times_log2; + int32_t x_32bit; + int32_t y_32bit; + int32_t e; + int32_t r; + int shift_value; + int a; + + /* ------------------------------------------------------------------------- + * FIRST RANGE REDUCTION --------------------------------------------------- + * ------------------------------------------------------------------------- + */ + x_times_one_over_log2 = Q_MULTSR_32X32((int64_t)x, SOFM_EXP_ONE_OVER_LOG2_Q30, 28, 30, 26); + e = Q_SHIFT_RND(x_times_one_over_log2, 26, 0); - /* Out of range input(x>5, x<-5), */ - /* return clipped value x > 5= e^5, and x<-5 = e^-5 */ - if (x < i_emin) - return o_emin; /* 0.0067473649978638 in Q9.23 */ + /* Q6.31, but we only keep the bottom 31 bits */ + e_times_log2 = (uint32_t)e * SOFM_EXP_LOG2_Q31; - if (x > i_emax) - return o_emax; /* 148.4131494760513306 in Q9.23 */ + /* ------------------------------------------------------------------------- + * SECOND RANGE REDUCTION -------------------------------------------------- + * y = a + b + * ------------------------------------------------------------------------- + */ + x_32bit = (int32_t)((uint32_t)x << 3); /* S4.31 */ + y_32bit = x_32bit - e_times_log2; /* S0.31, in ~[-0.34, +0.34] */ + a = (y_32bit >> 28) & 7; /* just the 3 top bits of "y" */ + b = y_32bit & 0x0FFFFFFF; /* bottom 31-3 = 28 bits. format U-3.31 */ + exp_a = sofm_exp_3bit_lookup[a]; + b_f32 = (b << 1) | 0x4; /* U0.32, align b on 32-bits of fraction */ + + /* Taylor approximation : base part + iterations + * Base part : 1 + b + b^2/2! + * Iterative part : b^3/3! + b^4/4! + b^5/5! + b^6/6! + * : Term count determined dynamically using e. + * + * Base part: NOTE: delay adding the "1" in "1 + b + b^2/2" until after we + * add the iterative part in. This gives us one more guard bit. + * NOTE: u_int32 x u_int32 => {hi, lo}. We only need {hi} for b_pow. + */ + b_pow = (uint64_t)b_f32 * b_f32 >> 32; + taylor_first_2 = b_f32 + (b_pow >> 1); /* 0.32 */ + taylor_extra = 0; + term = 1; + if (e < -10) + goto ITER_END; + + b_pow = (uint64_t)b_f32 * b_pow >> 32; + term = (uint64_t)b_pow * sofm_exp_taylor_coeffs[0] >> 32; + taylor_extra += term; + if (e < -5) + goto ITER_END; + + b_pow = (uint64_t)b_f32 * b_pow >> 32; + term = (uint64_t)b_pow * sofm_exp_taylor_coeffs[1] >> 32; + taylor_extra += term; + if (e < 0) + goto ITER_END; + + b_pow = (uint64_t)b_f32 * b_pow >> 32; + term = (uint64_t)b_pow * sofm_exp_taylor_coeffs[2] >> 32; + taylor_extra += term; + if (e < 6) + goto ITER_END; + + b_pow = (uint64_t)b_f32 * b_pow >> 32; + term = (uint64_t)b_pow * sofm_exp_taylor_coeffs[3] >> 32; + taylor_extra += term; + +ITER_END: + + /* Implement rounding to 31 fractional bits.. */ + taylor_first_2 = taylor_first_2 + taylor_extra + 1; + + /* Add the missing "1" for the Taylor series "1+b+b^2/2+...." */ + exp_b = ((uint32_t)1 << 31) + (taylor_first_2 >> 1); /* U1.31 */ + + /* ------------------------------------------------------------------------- + * FIRST RECONSTRUCTION ---------------------------------------------------- + * ------------------------------------------------------------------------- + */ - /* pre-computation of 1st & 2nd terms */ - mul_s64(dividend, SOFM_EXP_BIT_MASK_Q62P2, &ou0Hi, &ou0Lo); - qt = (ou0Hi << 46) | (ou0Lo >> 18);/* Q6.26 */ - ts += (int32_t)((qt >> 35) + ((qt & SOFM_EXP_QUOTIENT_SCALE) >> 18)); - dividend = lomul_s64_sr_sat_near(dividend, x); - for (b_n = 0; b_n < ARRAY_SIZE(exp_iv_ilookup); b_n++) { - mul_s64(dividend, exp_iv_ilookup[b_n], &ou0Hi, &ou0Lo); - qt = (ou0Hi << 45) | (ou0Lo >> 19); + /* U1.31 * U1.31 = U2.62 */ + exp_a_b_32bit = (uint64_t)exp_a * exp_b >> 31; - /* sum of the remaining terms */ - ts += (int32_t)((qt >> 35) + ((qt & SOFM_EXP_QUOTIENT_SCALE) ? 1 : 0)); - dividend = lomul_s64_sr_sat_near(dividend, x); + /* ------------------------------------------------------------------------- + * SECOND RECONSTRUCTION --------------------------------------------------- + * ------------------------------------------------------------------------- + */ - qt = ABS(qt); - /* For inputs between -5 and 5, (qt < SOFM_CONVERG_ERROR) is always true */ - if (qt < SOFM_CONVERG_ERROR) - break; - } - return ts; + /* Rounding to nearest */ + shift_value = 12 - e; + rnd_one = (shift_value > 0 ? (1 << (shift_value - 1)) : 0); + exp_a_b_32bit += rnd_one; + r = (int32_t)(exp_a_b_32bit >> shift_value); + return r; } +EXPORT_SYMBOL(sofm_exp_approx); -/* Fixed point exponent function for approximate range -11.5 .. 7.6 - * that corresponds to decibels range -100 .. +66 dB. +/* Fixed point exponent function for approximate range -16 .. 7.6 + * that corresponds to decibels range -120 .. +66 dB. * * The functions uses rule exp(x) = exp(x/2) * exp(x/2) to reduce - * the input argument for private small value exp() function that is - * accurate with input range -2.0 .. +2.0. The number of possible - * divisions by 2 is computed into variable n. The returned value is - * exp()^(2^n). + * the input argument for the exponent function. * * Input is Q5.27, -16.0 .. +16.0, but note the input range limitation * Output is Q12.20, 0.0 .. +2048.0 @@ -230,39 +172,24 @@ int32_t sofm_exp_int32(int32_t x) int32_t sofm_exp_fixed(int32_t x) { - int32_t xs; - int32_t y; - int32_t y0; - int i; - int n = 0; - - if (x < SOFM_EXP_FIXED_INPUT_MIN) - return 0; + int32_t x0, y0, y1; if (x > SOFM_EXP_FIXED_INPUT_MAX) return INT32_MAX; - /* x is Q5.27 */ - xs = x; - while (xs >= SOFM_EXP_TWO_Q27 || xs <= SOFM_EXP_MINUS_TWO_Q27) { - xs >>= 1; - n++; + if (x < SOFM_EXP_FIXED_INPUT_MINUS8 || x > SOFM_EXP_FIXED_INPUT_PLUS8) { + /* Divide by 2, convert Q27 to Q28 is x as such */ + y0 = sofm_exp_approx(x); + y1 = Q_MULTSR_32X32((int64_t)y0, y0, 19, 19, 20); + return y1; } - /* sofm_exp_int32() input is Q4.28, while x1 is Q5.27 - * sofm_exp_int32() output is Q9.23, while y0 is Q12.20 - */ - y0 = Q_SHIFT_RND(sofm_exp_int32(Q_SHIFT_LEFT(xs, 27, 28)), 23, 20); - y = SOFM_EXP_ONE_Q20; - for (i = 0; i < (1 << n); i++) - y = (int32_t)Q_MULTSR_32X32((int64_t)y, y0, 20, 20, 20); - - return y; + x0 = sat_int32((int64_t)x << 1); + y0 = sofm_exp_approx(x0); + return sat_int32((int64_t)y0 << 1); } EXPORT_SYMBOL(sofm_exp_fixed); -#endif /* EXPONENTIAL_GENERIC */ - /* Decibels to linear conversion: The function uses exp() to calculate * the linear value. The argument is multiplied by log(10)/20 to * calculate equivalent of 10^(db/20). @@ -279,11 +206,13 @@ int32_t sofm_db2lin_fixed(int32_t db) { int32_t arg; - if (db < SOFM_EXP_MINUS_100_Q24) - return 0; + if (db > SOFM_DB2LIN_INPUT_MAX) + return INT32_MAX; /* Q8.24 x Q5.27, result needs to be Q5.27 */ arg = (int32_t)Q_MULTSR_32X32((int64_t)db, SOFM_EXP_LOG10_DIV20_Q27, 24, 27, 27); return sofm_exp_fixed(arg); } EXPORT_SYMBOL(sofm_db2lin_fixed); + +#endif /* EXPONENTIAL_GENERIC */ diff --git a/src/math/exp_fcn_hifi.c b/src/math/exp_fcn_hifi.c index d41071335fd9..7180ef2ae0e6 100644 --- a/src/math/exp_fcn_hifi.c +++ b/src/math/exp_fcn_hifi.c @@ -1,20 +1,17 @@ // SPDX-License-Identifier: BSD-3-Clause /* - *Copyright(c) 2023 Intel Corporation. All rights reserved. + *Copyright(c) 2023-2025 Intel Corporation. * * Author: Shriram Shastry <malladi.sastry@linux.intel.com> - * + * Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + * Pasca, Bogdan <bogdan.pasca@intel.com> */ +#include <sof/audio/format.h> #include <sof/math/exp_fcn.h> #include <sof/common.h> #include <rtos/symbol.h> -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> #include <stdint.h> -#include <stddef.h> -#include <errno.h> #if defined(SOFM_EXPONENTIAL_HIFI3) || defined(SOFM_EXPONENTIAL_HIFI4) || \ defined(SOFM_EXPONENTIAL_HIFI5) @@ -27,330 +24,219 @@ #include <xtensa/tie/xt_hifi3.h> #endif -#include <xtensa/tie/xt_hifi2.h> -#include <xtensa/tie/xt_FP.h> - -#define SOFM_CONVERG_ERROR 28823037624320LL /* error smaller than 1e-4,1/2 ^ -44.7122876209085 */ +#define SOFM_EXP_ONE_OVER_LOG2_Q30 1549082005 /* Q2.30 int32(round(1/log(2) * 2^30)) */ +#define SOFM_EXP_LOG2_Q31 1488522236 /* Q1.31 int32(round(log(2) * 2^31)) */ +#define SOFM_EXP_FIXED_INPUT_MINUS8 -1073741824 /* Q5.27 int32(-8 * 2^27) */ +#define SOFM_EXP_FIXED_INPUT_PLUS8 1073741823 /* Q5.27 int32(8 * 2^27) */ +#define SOFM_EXP_LOG10_DIV20_Q27 15452387 /* Q5.27 int32(round(log(10)/20*2^27)) */ -/* - * Arguments : int64_t in_0 - * int64_t in_1 - * uint64_t *ptroutbitshi - * uint64_t *ptroutbitslo - * Return Type : void - * Description:Perform element-wise multiplication on in_0 and in_1 - * while keeping the required product word length and fractional - * length in mind. mul_s64 function divide the 64-bit quantities - * into two 32-bit words,multiply the low words to produce the - * lowest and second-lowest words in the result, then both pairs - * of low and high words from different numbers to produce the - * second and third lowest words in the result, and finally both - * high words to produce the two highest words in the outcome. - * Add them all up, taking carry into consideration. - * - * The 64 x 64 bit multiplication of operands in_0 and in_1 is - * shown in the image below. The 64-bit operand in_0,in_1 is - * represented by the notation in0_H, in1_H for the top 32 bits - * and in0_L, in1_L for the bottom 32 bits. - * - * in0_H : in0_L - * x in1_H : in1_L - * --------------------- - * P0 in0_L x in1_L - * P1 in0_H x in1_L 64 bit inner multiplication - * P2 in0_L x in1_H 64 bit inner multiplication - * P3 in0_H x in1_H - * -------------------- - * [64 x 64 bit multiplication] sum of inner products - * All combinations are multiplied by one another and then added. - * Each inner product is moved into its proper power location.given the names - * of the inner products, redoing the addition where 000 represents 32 zero - * bits.The inner products can be added together in 64 bit addition.The sum - * of two 64-bit numbers yields a 65-bit output. - * (P0H:P0L) - * P1H(P1L:000) - * P2H(P2L:000) - * P3H:P3L(000:000) - * .......(aaa:P0L) - * By combining P0H:P0L and P1L:000. This can lead to a carry, denote as CRY0. - * The partial result is then multiplied by P2L:000. - * We call it CRY1 because it has the potential to carry again. - * (CRY0 + CRY1)P0H:P0L - * ( P1H)P1L:000 - * ( P2H)P2L:000 - * (P3H: P3L)000:000 - * -------------------- - * (ccc:bbb)aaa:P0L - * P1H, P2H, and P3H:P3L are added to the carry CRY0 + CRY1.This increase will - * not result in an overflow. +/* The table contains exponents of value v, where values of v + * are the 3 bit 2's complement signed values presented by bits + * of index 0..7. * + * v = [(0:3)/8 (-4:-1)/8]; + * uint32(round(exp(v) * 2^31)) */ -static void mul_s64(ae_int64 in_0, ae_int64 in_1, ae_int64 *__restrict__ ptroutbitshi, - ae_int64 *__restrict__ ptroutbitslo) -{ - ae_int64 producthihi, producthilo, productlolo; - ae_int64 producthi, product_hl_lh_h, product_hl_lh_l, carry; - -#if (SOFM_EXPONENTIAL_HIFI4 == 1 || SOFM_EXPONENTIAL_HIFI5 == 1) - - ae_int32x2 in0_32 = AE_MOVINT32X2_FROMINT64(in_0); - ae_int32x2 in1_32 = AE_MOVINT32X2_FROMINT64(in_1); - - ae_ep ep_lolo = AE_MOVEA(0); - ae_ep ep_hilo = AE_MOVEA(0); - ae_ep ep_HL_LH = AE_MOVEA(0); - - producthihi = AE_MUL32_HH(in0_32, in1_32); - - /* AE_MULZAAD32USEP.HL.LH - Unsigned lower parts and signed higher 32-bit parts dual */ - /* multiply and accumulate operation on two 32x2 operands with 72-bit output */ - /* Input-32x32-bit(in1_32xin0_32)into 72-bit multiplication operations */ - /* Output-lower 64 bits of the result are stored in producthilo */ - /* Output-upper eight bits are stored in ep_hilo */ - AE_MULZAAD32USEP_HL_LH(ep_hilo, producthilo, in1_32, in0_32); - productlolo = AE_MUL32U_LL(in0_32, in1_32); - - product_hl_lh_h = AE_SRAI72(ep_hilo, producthilo, 32); - product_hl_lh_l = AE_SLAI64(producthilo, 32); - - /* The AE_ADD72 procedure adds two 72-bit elements. The first 72-bit value is created */ - /* by concatenating the MSBs and LSBs of operands ep[7:0] and d[63:0]. Similarly, the */ - /* second value is created by concatenating bits from operands ep1[7:0] and d1[63:0]. */ - AE_ADD72(ep_lolo, productlolo, ep_HL_LH, product_hl_lh_l); - - carry = AE_SRAI72(ep_lolo, productlolo, 32); - - carry = AE_SRLI64(carry, 32); - producthi = AE_ADD64(producthihi, carry); - - producthi = AE_ADD64(producthi, product_hl_lh_h); - *ptroutbitslo = productlolo; -#elif SOFM_EXPONENTIAL_HIFI3 == 1 - - ae_int64 producthi_1c; - ae_int64 producthi_2c; - ae_int64 productlo_2c; - ae_int64 productlo; - - ae_int64 s0 = AE_SRLI64(in_0, 63); - ae_int64 s1 = AE_SRLI64(in_1, 63); - bool x_or = (bool)((int)(int64_t)s0 ^ (int)(int64_t)s1); - - ae_int32x2 in0_32 = AE_MOVINT32X2_FROMINT64(AE_ABS64(in_0)); - ae_int32x2 in1_32 = AE_MOVINT32X2_FROMINT64(AE_ABS64(in_1)); - - producthihi = AE_MUL32_HH(in0_32, in1_32); - producthilo = AE_MUL32U_LL(in1_32, AE_MOVINT32X2_FROMINT64 - ((AE_MOVINT64_FROMINT32X2(in0_32) >> 32))); - producthilo += AE_MUL32U_LL(AE_MOVINT32X2_FROMINT64 - ((AE_MOVINT64_FROMINT32X2(in1_32) >> 32)), in0_32); - productlolo = AE_MUL32U_LL(in0_32, in1_32); - - product_hl_lh_h = AE_SRAI64(producthilo, 32); - product_hl_lh_l = AE_SLAI64(producthilo, 32); - - productlo = AE_ADD64(productlolo, product_hl_lh_l); - producthi = AE_ADD64(producthihi, product_hl_lh_h); - - carry = AE_ADD64(AE_SRLI64(productlolo, 1), AE_SRLI64(product_hl_lh_l, 1)); - carry = AE_SRLI64(carry, 63); - producthi = AE_ADD64(producthi, carry); - - producthi_1c = AE_NOT64(producthi); - producthi_2c = AE_NEG64(producthi); - productlo_2c = AE_NEG64(productlo); - - if (x_or) { - if (productlo == (ae_int64)0) { - producthi = producthi_2c; - } else { - producthi = producthi_1c; - productlo = productlo_2c; - } - } - *ptroutbitslo = productlo; -#endif //(XCHAL_HAVE_HIFI4 || XCHAL_HAVE_HIFI5) - - *ptroutbitshi = producthi; -} +static const uint32_t sofm_exp_3bit_lookup[8] = { + 2147483648, 2433417774, 2757423586, 3124570271, + 1302514674, 1475942488, 1672461947, 1895147668 +}; -/* - * Arguments : int64_t a - * int64_t b - * Return Type : int64_t +/* Taylor polynomial coefficients for x^3..x^6, calculated + * uint32(round(1 ./ factorial(3:6) * 2^32)) */ -static int64_t lomul_s64_sr_sat_near(int64_t a, int64_t b) -{ - ae_int64 u64_chi; - ae_int64 u64_clo; - ae_int64 temp; - - mul_s64(a, b, &u64_chi, &u64_clo); - - ae_int64 roundup = AE_AND64(u64_clo, SOFM_EXP_BIT_MASK_LOW_Q27P5); - - roundup = AE_SRLI64(roundup, 27); - temp = AE_OR64(AE_SLAI64(u64_chi, 36), AE_SRLI64(u64_clo, 28)); - - return AE_ADD64(temp, roundup); -} - -static const int64_t onebyfact_Q63[19] = { - 4611686018427387904LL, - 1537228672809129301LL, - 384307168202282325LL, - 76861433640456465LL, - 12810238940076077LL, - 1830034134296582LL, - 228754266787072LL, - 25417140754119LL, - 2541714075411LL, - 231064915946LL, - 19255409662LL, - 1481185358LL, - 105798954LL, - 7053264LL, - 440829LL, - 25931LL, - 1441LL, - 76LL, - 4LL +static const uint32_t sofm_exp_taylor_coeffs[4] = { + 715827883, 178956971, 35791394, 5965232 }; -/* f(x) = a^x, x is variable and a is base +/* function f(x) = e^x * - * Arguments : int32_t x(Q4.28) - * input range -5 to 5 + * Arguments : int32_t x (Q4.28) + * input range -8 to 8 * - * Return Type : int32_t ts(Q9.23) - * output range 0.0067465305 to 148.4131488800 - *+------------------+-----------------+--------+--------+ - *| x | ts (returntype) | x | ts | - *+----+-----+-------+----+----+-------+--------+--------+ - *|WLen| FLen|Signbit|WLen|FLen|Signbit| Qformat| Qformat| - *+----+-----+-------+----+----+-------+--------+--------+ - *| 32 | 28 | 1 | 32 | 23 | 0 | 4.28 | 9.23 | - *+------------------+-----------------+--------+--------+ + * Return Type : int32_t (Q13.19) + * output range 3.3546e-04 to 2981.0 */ -int32_t sofm_exp_int32(int32_t x) +int32_t sofm_exp_approx(int32_t x) { - ae_int64 outhi; - ae_int64 outlo; - ae_int64 qt; - ae_int64 onebyfact; - ae_int64 temp; - - ae_int64 *ponebyfact_Q63 = (ae_int64 *)onebyfact_Q63; - ae_int64 ts = SOFM_EXP_TERMS_Q23P9; - ae_int64 mp = (x + SOFM_EXP_LSHIFT_BITS) >> 14; /* x in Q50.14 */; - xtbool flag; - int64_t b_n; - - mul_s64(mp, SOFM_EXP_BIT_MASK_Q62P2, &outhi, &outlo); - qt = AE_OR64(AE_SLAI64(outhi, 46), AE_SRLI64(outlo, 18)); - - temp = AE_SRAI64(AE_ADD64(qt, SOFM_EXP_QUOTIENT_SCALE), 35); - - ts = AE_ADD64(ts, temp); - - mp = lomul_s64_sr_sat_near(mp, (int64_t)x); - - for (b_n = 0; b_n < 64;) { - AE_L64_IP(onebyfact, ponebyfact_Q63, 8); + ae_int64 p; + uint32_t taylor_first_2; + uint32_t taylor_extra; + uint32_t b_f32; + uint32_t b_pow; + uint32_t exp_a; + uint32_t exp_b; + uint32_t term; + uint32_t b; + int32_t x_times_one_over_log2; + int32_t e_times_log2; + int32_t x_32bit; + int32_t y_32bit; + int32_t e; + int32_t r; + int a; + + //x = 843314857; + + /* ------------------------------------------------------------------------- + * FIRST RANGE REDUCTION --------------------------------------------------- + * ------------------------------------------------------------------------- + * Multiply gives q28 * q30 -> q58, without shift the rounded value + * would be q42 (58 - 16). For q26 result, shift right by 16 (42 - 26). + */ + p = AE_MUL32_LL(x, SOFM_EXP_ONE_OVER_LOG2_Q30); + x_times_one_over_log2 = (ae_int32)AE_ROUND32F48SASYM(AE_SRAI64(p, 16)); - mul_s64(mp, onebyfact, &outhi, &outlo); - qt = AE_OR64(AE_SLAI64(outhi, 45), AE_SRLI64(outlo, 19)); + /* Shift, round to q0 */ + e = AE_SRAI32R(x_times_one_over_log2, 26); - temp = AE_SRAI64(AE_ADD64(qt, SOFM_EXP_QUOTIENT_SCALE), 35); - ts = AE_ADD64(ts, temp); - mp = lomul_s64_sr_sat_near(mp, (int64_t)x); + /* Q6.31, but we only keep the bottom 31 bits */ + e_times_log2 = (uint32_t)e * SOFM_EXP_LOG2_Q31; - const ae_int64 sign = AE_NEG64(qt); + /* ------------------------------------------------------------------------- + * SECOND RANGE REDUCTION -------------------------------------------------- + * y = a + b + * ------------------------------------------------------------------------- + */ + x_32bit = AE_SLAI32(x, 3); /* S4.31, overflow to S1.31 */ + y_32bit = x_32bit - e_times_log2; /* S0.31, in ~[-0.34, +0.34] */ + a = (y_32bit >> 28) & 7; /* just the 3 top bits of "y" */ + b = y_32bit & 0x0FFFFFFF; /* bottom 31-3 = 28 bits. format U-3.31 */ + exp_a = sofm_exp_3bit_lookup[a]; + b_f32 = (b << 1) | 0x4; /* U0.32, align b on 32-bits of fraction */ + + /* Taylor approximation : base part + iterations + * Base part : 1 + b + b^2/2! + * Iterative part : b^3/3! + b^4/4! + b^5/5! + b^6/6! + * : Term count determined dynamically using e. + * + * Base part: NOTE: delay adding the "1" in "1 + b + b^2/2" until after we + * add the iterative part in. This gives us one more guard bit. + * NOTE: u_int32 x u_int32 => {hi, lo}. We only need {hi} for b_pow. + */ + b_pow = (uint64_t)b_f32 * b_f32 >> 32; + taylor_first_2 = b_f32 + (b_pow >> 1); /* 0.32 */ + taylor_extra = 0; + term = 1; + if (e < -10) + goto ITER_END; + + b_pow = (uint64_t)b_f32 * b_pow >> 32; + term = (uint64_t)b_pow * sofm_exp_taylor_coeffs[0] >> 32; + taylor_extra += term; + if (e < -5) + goto ITER_END; + + b_pow = (uint64_t)b_f32 * b_pow >> 32; + term = (uint64_t)b_pow * sofm_exp_taylor_coeffs[1] >> 32; + taylor_extra += term; + if (e < 0) + goto ITER_END; + + b_pow = (uint64_t)b_f32 * b_pow >> 32; + term = (uint64_t)b_pow * sofm_exp_taylor_coeffs[2] >> 32; + taylor_extra += term; + if (e < 6) + goto ITER_END; + + b_pow = (uint64_t)b_f32 * b_pow >> 32; + term = (uint64_t)b_pow * sofm_exp_taylor_coeffs[3] >> 32; + taylor_extra += term; + +ITER_END: + + /* Implement rounding to 31 fractional bits.. */ + taylor_first_2 = taylor_first_2 + taylor_extra + 1; + + /* Add the missing "1" for the Taylor series "1+b+b^2/2+...." */ + exp_b = ((uint32_t)1 << 31) + (taylor_first_2 >> 1); /* U1.31 */ + + /* ------------------------------------------------------------------------- + * FIRST RECONSTRUCTION ---------------------------------------------------- + * ------------------------------------------------------------------------- + */ - flag = AE_LT64(qt, 0); - AE_MOVT64(qt, sign, flag); + /* U1.31 * U1.31 = U2.62 */ + p = (ae_int64)((uint64_t)exp_a * exp_b); - if (!(qt < (ae_int64)SOFM_CONVERG_ERROR)) - b_n++; - else - b_n = 64; - } + /* ------------------------------------------------------------------------- + * SECOND RECONSTRUCTION --------------------------------------------------- + * ------------------------------------------------------------------------- + */ - return AE_MOVAD32_L(AE_MOVINT32X2_FROMINT64(ts)); + /* Rounding to nearest, + * using f48 round with shift value for right shift is negative + * q62 to q31 shift right is -31, for round instruction shift left is +16, + * compensate shift e by right shift is -12: 16 - 31 - 12 = -27 + */ + p = AE_SLAA64(p, e - 27); + r = (ae_int32)AE_ROUND32F48SASYM(p); + return r; } -/* Fixed point exponent function for approximate range -11.5 .. 7.6 - * that corresponds to decibels range -100 .. +66 dB. +/* Fixed point exponent function for approximate range -16 .. 7.6246. * * The functions uses rule exp(x) = exp(x/2) * exp(x/2) to reduce - * the input argument for private small value exp() function that is - * accurate with input range -2.0 .. +2.0. The number of possible - * divisions by 2 is computed into variable n. The returned value is - * exp()^(2^n). + * the input argument for function sofm_exp_approx() with input + * range from -8 to +8. * * Input is Q5.27, -16.0 .. +16.0, but note the input range limitation * Output is Q12.20, 0.0 .. +2048.0 */ - int32_t sofm_exp_fixed(int32_t x) { - ae_f64 p; - ae_int32 y0; - ae_int32 y; - ae_int32 xs; - int32_t n; - int shift; - int i; - - if (x < SOFM_EXP_FIXED_INPUT_MIN) - return 0; + ae_int32 x0, y0, y1; if (x > SOFM_EXP_FIXED_INPUT_MAX) return INT32_MAX; - /* This returns number of right shifts needed to scale value x to |x| < 2. - * The behavior differs slightly for positive and negative values but it - * is not problem for sofm_exp_int32() function. E.g. - * - * x = 268435455 (1.9999999925), shift = 0 - * x = 268435456 (2.0000000000), shift = 1 - * x = 268435457 (2.0000000075), shift = 1 - * - * x = -268435457 (-2.0000000075), shift = 1 - * x = -268435456 (-2.0000000000), shift = 0 - * x = -268435455 (-1.9999999925), shift = 0 - * - * If the shift is zero, just return result from sofm_exp_int32() with - * input Q format and output Q format adjusts. - */ - shift = (int)AE_MAX32(0, 3 - AE_NSAZ32_L(x)); - if (!shift) - return AE_SRAI32R(sofm_exp_int32(AE_MOVAD32_L(AE_SLAI32S(x, 1))), 3); + /* No need to check for > 8, the input max is lower, about 7.6 */ + if (x < SOFM_EXP_FIXED_INPUT_MINUS8) { + /* Divide by 2, convert Q27 to Q28 is x as such */ + y0 = sofm_exp_approx(x); + /* Multiply gives q19 * q19 -> q38, without shift the rounded value + * would be q22 (38 - 16). For q20 shift right by 2. + */ + y1 = (ae_int32)AE_ROUND32F48SASYM(AE_SRAI64(AE_MUL32_LL(y0, y0), 2)); + return y1; + } - /* Shifting x one less right to save an additional Q27 to Q28 conversion - * shift for sofm_exp_int32() - */ - n = 1 << shift; - xs = AE_SRAA32RS(x, shift - 1); + x0 = AE_SLAI32S(x, 1); + y0 = sofm_exp_approx((int32_t)x0); + return (ae_int32)AE_SLAI32S(y0, 1); +} +EXPORT_SYMBOL(sofm_exp_fixed); - /* sofm_exp_int32() input is Q4.28, while x1 is Q5.27 - * sofm_exp_int32() output is Q9.23, while y0 is Q12.20 - */ - y0 = AE_SRAI32R(sofm_exp_int32(xs), 3); - y = SOFM_EXP_ONE_Q20; +/* Decibels to linear conversion: The function uses exp() to calculate + * the linear value. The argument is multiplied by log(10)/20 to + * calculate equivalent of 10^(db/20). + * + * The error in conversion is less than 0.1 dB for -89..+66 dB range. Do not + * use the code for argument less than -100 dB. The code simply returns zero + * as linear value for such very small value. + * + * Input is Q8.24 (max 128.0) + * output is Q12.20 (max 2048.0) + */ - /* AE multiply returns Q41 from Q20 * Q20. To get Q20 it need to be - * shifted right by 21. Since the used round instruction is aligned - * to the high 32 bits it is shifted instead left by 32 - 21 = 11: - */ - for (i = 0; i < n; i++) { - p = AE_SLAI64S(AE_MULF32S_LL(y, y0), 11); - y = AE_ROUND32F64SASYM(p); - } +int32_t sofm_db2lin_fixed(int32_t db) +{ + ae_int64 p; + ae_int32 arg; - return y; + if (db > SOFM_DB2LIN_INPUT_MAX) + return INT32_MAX; + + /* Multiply gives Q8.24 * Q5.27 -> Q13.51 */ + p = AE_MUL32_LL(db, SOFM_EXP_LOG10_DIV20_Q27); + + /* Without shift the f48 rounded value would be Q35 (51 - 16). + * For Q5.27 result, shift right by 8 (35 - 27). + */ + arg = AE_ROUND32F48SASYM(AE_SRAI64(p, 8)); + return sofm_exp_fixed((int32_t)arg); } -EXPORT_SYMBOL(sofm_exp_fixed); +EXPORT_SYMBOL(sofm_db2lin_fixed); #endif diff --git a/src/math/fft/CMakeLists.txt b/src/math/fft/CMakeLists.txt index 8d422b93c5b1..c605886c335e 100644 --- a/src/math/fft/CMakeLists.txt +++ b/src/math/fft/CMakeLists.txt @@ -1,7 +1,28 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof fft_common.c) +set(base_files fft_common.c) -add_local_sources_ifdef(CONFIG_MATH_16BIT_FFT sof fft_16.c fft_16_hifi3.c) +if(CONFIG_MATH_16BIT_FFT) + list(APPEND base_files fft_16.c fft_16_hifi3.c) +endif() -add_local_sources_ifdef(CONFIG_MATH_32BIT_FFT sof fft_32.c fft_32_hifi3.c) +if(CONFIG_MATH_32BIT_FFT) + list(APPEND base_files fft_32.c fft_32_hifi3.c) +endif() + +if(CONFIG_MATH_FFT_MULTI) + list(APPEND base_files fft_multi.c fft_multi_generic.c fft_multi_hifi3.c) +endif() + +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + + zephyr_library_sources( + ${base_files} + ) + +else() ### library, e.g. testbench or plugin ### + + add_local_sources(sof ${base_files}) + +endif() diff --git a/src/math/fft/fft_16.c b/src/math/fft/fft_16.c index 7af6c1eb2768..7a8ffad26054 100644 --- a/src/math/fft/fft_16.c +++ b/src/math/fft/fft_16.c @@ -1,68 +1,19 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020-2026 Intel Corporation. // // Author: Amery Song <chao.song@intel.com> // Keyon Jie <yang.jie@linux.intel.com> #include <sof/audio/format.h> -#include <sof/common.h> #include <sof/math/fft.h> +#include <sof/math/icomplex16.h> +#include <sof/common.h> +#include <stdint.h> #ifdef FFT_GENERIC #include <sof/audio/coefficients/fft/twiddle_16.h> -/* - * Helpers for 16 bit FFT calculation - */ -static inline void icomplex16_add(const struct icomplex16 *in1, const struct icomplex16 *in2, - struct icomplex16 *out) -{ - out->real = in1->real + in2->real; - out->imag = in1->imag + in2->imag; -} - -static inline void icomplex16_sub(const struct icomplex16 *in1, const struct icomplex16 *in2, - struct icomplex16 *out) -{ - out->real = in1->real - in2->real; - out->imag = in1->imag - in2->imag; -} - -static inline void icomplex16_mul(const struct icomplex16 *in1, const struct icomplex16 *in2, - struct icomplex16 *out) -{ - int32_t real = (int32_t)in1->real * in2->real - (int32_t)in1->imag * in2->imag; - int32_t imag = (int32_t)in1->real * in2->imag + (int32_t)in1->imag * in2->real; - - out->real = Q_SHIFT_RND(real, 30, 15); - out->imag = Q_SHIFT_RND(imag, 30, 15); -} - -/* complex conjugate */ -static inline void icomplex16_conj(struct icomplex16 *comp) -{ - comp->imag = sat_int16(-((int32_t)comp->imag)); -} - -/* shift a complex n bits, n > 0: left shift, n < 0: right shift */ -static inline void icomplex16_shift(const struct icomplex16 *input, int16_t n, - struct icomplex16 *output) -{ - int n1, n2; - - if (n >= 0) { - /* need saturation handling */ - output->real = sat_int16((int32_t)input->real << n); - output->imag = sat_int16((int32_t)input->imag << n); - } else { - n1 = -n; - n2 = 1 << (n1 - 1); - output->real = sat_int16(((int32_t)input->real + n2) >> n1); - output->imag = sat_int16(((int32_t)input->imag + n2) >> n1); - } -} - /** * \brief Execute the 16-bits Fast Fourier Transform (FFT) or Inverse FFT (IFFT) * For the configured fft_pan. diff --git a/src/math/fft/fft_16_hifi3.c b/src/math/fft/fft_16_hifi3.c index 54e9cebc4a23..56d5bc177789 100644 --- a/src/math/fft/fft_16_hifi3.c +++ b/src/math/fft/fft_16_hifi3.c @@ -7,6 +7,8 @@ #include <sof/audio/format.h> #include <sof/common.h> #include <sof/math/fft.h> +#include <sof/math/icomplex16.h> + #ifdef FFT_HIFI3 #include <sof/audio/coefficients/fft/twiddle_16.h> @@ -33,12 +35,14 @@ void fft_execute_16(struct fft_plan *plan, bool ifft) ae_valign outu = AE_ZALIGN64(); int depth, top, bottom, index; int i, j, k, m, n; - int size = plan->size; - int len = plan->len; + int size, len; if (!plan || !plan->bit_reverse_idx) return; + size = plan->size; + len = plan->len; + outb = plan->outb16; if (!plan->inb16 || !outb) return; diff --git a/src/math/fft/fft_32.c b/src/math/fft/fft_32.c index 3806f37675b8..a6f8b2aa1ab3 100644 --- a/src/math/fft/fft_32.c +++ b/src/math/fft/fft_32.c @@ -6,60 +6,14 @@ // Keyon Jie <yang.jie@linux.intel.com> #include <sof/audio/format.h> -#include <sof/common.h> -#include <rtos/alloc.h> #include <sof/math/fft.h> +#include <sof/math/icomplex32.h> +#include <sof/common.h> +#include <stdint.h> #ifdef FFT_GENERIC #include <sof/audio/coefficients/fft/twiddle_32.h> -/* - * These helpers are optimized for FFT calculation only. - * e.g. _add/sub() assume the output won't be saturate so no check needed, - * and _mul() assumes Q1.31 * Q1.31 so the output will be shifted to be Q1.31. - */ - -static inline void icomplex32_add(const struct icomplex32 *in1, const struct icomplex32 *in2, - struct icomplex32 *out) -{ - out->real = in1->real + in2->real; - out->imag = in1->imag + in2->imag; -} - -static inline void icomplex32_sub(const struct icomplex32 *in1, const struct icomplex32 *in2, - struct icomplex32 *out) -{ - out->real = in1->real - in2->real; - out->imag = in1->imag - in2->imag; -} - -static inline void icomplex32_mul(const struct icomplex32 *in1, const struct icomplex32 *in2, - struct icomplex32 *out) -{ - out->real = ((int64_t)in1->real * in2->real - (int64_t)in1->imag * in2->imag) >> 31; - out->imag = ((int64_t)in1->real * in2->imag + (int64_t)in1->imag * in2->real) >> 31; -} - -/* complex conjugate */ -static inline void icomplex32_conj(struct icomplex32 *comp) -{ - comp->imag = SATP_INT32((int64_t)-1 * comp->imag); -} - -/* shift a complex n bits, n > 0: left shift, n < 0: right shift */ -static inline void icomplex32_shift(const struct icomplex32 *input, int32_t n, - struct icomplex32 *output) -{ - if (n > 0) { - /* need saturation handling */ - output->real = SATP_INT32(SATM_INT32((int64_t)input->real << n)); - output->imag = SATP_INT32(SATM_INT32((int64_t)input->imag << n)); - } else { - output->real = input->real >> -n; - output->imag = input->imag >> -n; - } -} - /** * \brief Execute the 32-bits Fast Fourier Transform (FFT) or Inverse FFT (IFFT) * For the configured fft_pan. @@ -97,7 +51,7 @@ void fft_execute_32(struct fft_plan *plan, bool ifft) } /* step 1: re-arrange input in bit reverse order, and shrink the level to avoid overflow */ - for (i = 1; i < plan->size; ++i) + for (i = 0; i < plan->size; ++i) icomplex32_shift(&inb[i], -(plan->len), &outb[plan->bit_reverse_idx[i]]); /* step 2: loop to do FFT transform in smaller size */ @@ -133,9 +87,11 @@ void fft_execute_32(struct fft_plan *plan, bool ifft) * for Q1.31 format. Instead, we need to multiply N to compensate * the shrink we did in the FFT transform. */ - for (i = 0; i < plan->size; i++) + for (i = 0; i < plan->size; i++) { + icomplex32_conj(&outb[i]); icomplex32_shift(&outb[i], plan->len, &outb[i]); + } } } -#endif +#endif /* FFT_GENERIC */ diff --git a/src/math/fft/fft_32_hifi3.c b/src/math/fft/fft_32_hifi3.c index 91cd18b6a3ed..1d00dacd1b7f 100644 --- a/src/math/fft/fft_32_hifi3.c +++ b/src/math/fft/fft_32_hifi3.c @@ -15,23 +15,21 @@ void fft_execute_32(struct fft_plan *plan, bool ifft) { - struct icomplex32 tmp1; - ae_int32x2 *inx; - ae_int32x2 *out; - ae_int32x2 *outtop; - ae_int32x2 *outbottom; - ae_int32x2 *outx; + ae_int64 res, res1; ae_int32x2 sample; ae_int32x2 sample1; ae_int32x2 sample2; - ae_int64 res, res1; - int depth, top, bottom, index; - int i, j, k, m, n; - ae_int32 *in; - ae_valign inu = AE_ZALIGN64(); - ae_valign outu = AE_ZALIGN64(); - int size = plan->size; - int len = plan->len; + ae_int32x2 tw; + ae_int32x2 *inx; + ae_int32x2 *outx; + ae_int32x2 *top_ptr; + ae_int32x2 *bot_ptr; + uint16_t *idx; + const int32_t *tw_r; + const int32_t *tw_i; + int depth, i; + int j, k, m, n; + int size, len; if (!plan || !plan->bit_reverse_idx) return; @@ -39,64 +37,104 @@ void fft_execute_32(struct fft_plan *plan, bool ifft) if (!plan->inb32 || !plan->outb32) return; - inx = (ae_int32x2 *)plan->inb32 + 1; + inx = (ae_int32x2 *)plan->inb32; outx = (ae_int32x2 *)plan->outb32; + idx = &plan->bit_reverse_idx[0]; + size = plan->size; + len = plan->len; - /* convert to complex conjugate for ifft */ + /* step 1: re-arrange input in bit reverse order, and shrink the level to avoid overflow */ if (ifft) { - in = (ae_int32 *)&plan->inb32->imag; - for (i = 0; i < size; i++) { - AE_L32_IP(sample, in, 0); - sample = AE_NEG32S(sample); - AE_S32_L_IP(sample, in, sizeof(struct icomplex32)); + /* convert to complex conjugate for ifft */ + for (i = 0; i < size; ++i) { + AE_L32X2_IP(sample, inx, sizeof(ae_int32x2)); + sample = AE_SRAA32S(sample, len); + sample1 = AE_NEG32S(sample); + sample = AE_SEL32_HL(sample, sample1); + AE_S32X2_X(sample, outx, idx[i] * sizeof(ae_int32x2)); + } + } else { + for (i = 0; i < size; ++i) { + AE_L32X2_IP(sample, inx, sizeof(ae_int32x2)); + sample = AE_SRAA32S(sample, len); + AE_S32X2_X(sample, outx, idx[i] * sizeof(ae_int32x2)); } } - /* step 1: re-arrange input in bit reverse order, and shrink the level to avoid overflow */ - inu = AE_LA64_PP(inx); - for (i = 1; i < size; ++i) { - AE_LA32X2_IP(sample, inu, inx); - sample = AE_SRAA32S(sample, len); - out = &outx[plan->bit_reverse_idx[i]]; - AE_SA32X2_IP(sample, outu, out); + /* + * Step 2a: First FFT stage (depth=1, m=2, n=1). + * All butterflies use twiddle factor W^0 = 1+0j, + * so the complex multiply is skipped entirely. + */ + top_ptr = outx; + bot_ptr = outx + 1; + for (k = 0; k < size; k += 2) { + sample1 = AE_L32X2_I(top_ptr, 0); + sample2 = AE_L32X2_I(bot_ptr, 0); + sample = AE_ADD32S(sample1, sample2); + AE_S32X2_I(sample, top_ptr, 0); + sample = AE_SUB32S(sample1, sample2); + AE_S32X2_I(sample, bot_ptr, 0); + top_ptr += 2; + bot_ptr += 2; } - AE_SA64POS_FP(outu, out); - /* step 2: loop to do FFT transform in smaller size */ - for (depth = 1; depth <= len; ++depth) { + /* Step 2b: Remaining FFT stages (depth >= 2) */ + for (depth = 2; depth <= len; ++depth) { m = 1 << depth; n = m >> 1; i = FFT_SIZE_MAX >> depth; + top_ptr = outx; + bot_ptr = outx + n; + /* doing FFT transforms in size m */ for (k = 0; k < size; k += m) { - /* doing one FFT transform for size m */ - for (j = 0; j < n; ++j) { - index = i * j; - top = k + j; - bottom = top + n; - tmp1.real = twiddle_real_32[index]; - tmp1.imag = twiddle_imag_32[index]; - inx = (ae_int32x2 *)&tmp1; - AE_LA32X2_IP(sample1, inu, inx); + /* + * j=0: twiddle factor W^0 = 1+0j, + * butterfly without complex multiply. + */ + sample1 = AE_L32X2_I(top_ptr, 0); + sample = AE_L32X2_I(bot_ptr, 0); + sample2 = AE_ADD32S(sample1, sample); + AE_S32X2_I(sample2, top_ptr, 0); + sample2 = AE_SUB32S(sample1, sample); + AE_S32X2_I(sample2, bot_ptr, 0); + top_ptr++; + bot_ptr++; + + /* j=1..n-1: full butterfly with twiddle multiply */ + tw_r = &twiddle_real_32[i]; + tw_i = &twiddle_imag_32[i]; + for (j = 1; j < n; ++j) { + /* load and combine twiddle factor {real, imag} into tw */ + tw = AE_MOVDA32X2(tw_r[0], tw_i[0]); + /* calculate the accumulator: twiddle * bottom */ - sample2 = outx[bottom]; - res = AE_MULF32S_HH(sample1, sample2); - AE_MULSF32S_LL(res, sample1, sample2); - res1 = AE_MULF32S_HL(sample1, sample2); - AE_MULAF32S_LH(res1, sample1, sample2); + sample2 = AE_L32X2_I(bot_ptr, 0); + res = AE_MULF32S_HH(tw, sample2); + AE_MULSF32S_LL(res, tw, sample2); + res1 = AE_MULF32S_HL(tw, sample2); + AE_MULAF32S_LH(res1, tw, sample2); sample = AE_ROUND32X2F64SSYM(res, res1); + sample1 = AE_L32X2_I(top_ptr, 0); - sample1 = outx[top]; /* calculate the top output: top = top + accumulate */ sample2 = AE_ADD32S(sample1, sample); - outtop = outx + top; - AE_SA32X2_IP(sample2, outu, outtop); + AE_S32X2_I(sample2, top_ptr, 0); + /* calculate the bottom output: bottom = top - accumulate */ sample2 = AE_SUB32S(sample1, sample); - outbottom = outx + bottom; - AE_SA32X2_IP(sample2, outu, outbottom); + AE_S32X2_I(sample2, bot_ptr, 0); + + top_ptr++; + bot_ptr++; + tw_r += i; + tw_i += i; } + /* advance pointers past current group's bottom half */ + top_ptr += n; + bot_ptr += n; } } @@ -105,16 +143,17 @@ void fft_execute_32(struct fft_plan *plan, bool ifft) /* * no need to divide N as it is already done in the input side * for Q1.31 format. Instead, we need to multiply N to compensate - * the shrink we did in the FFT transform. + * the shrink we did in the FFT transform. Also make complex + * conjugate by negating the imaginary part. */ inx = outx; - inu = AE_LA64_PP(inx); for (i = 0; i < size; ++i) { - AE_LA32X2_IP(sample, inu, inx); + AE_L32X2_IP(sample, inx, sizeof(ae_int32x2)); sample = AE_SLAA32S(sample, len); - AE_SA32X2_IP(sample, outu, outx); + sample1 = AE_NEG32S(sample); + sample = AE_SEL32_HL(sample, sample1); + AE_S32X2_IP(sample, outx, sizeof(ae_int32x2)); } - AE_SA64POS_FP(outu, outx); } } #endif diff --git a/src/math/fft/fft_common.c b/src/math/fft/fft_common.c index e1c89b09d75c..589571881443 100644 --- a/src/math/fft/fft_common.c +++ b/src/math/fft/fft_common.c @@ -1,29 +1,46 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020-2025 Intel Corporation. // // Author: Amery Song <chao.song@intel.com> // Keyon Jie <yang.jie@linux.intel.com> +#include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/buffer.h> #include <sof/audio/format.h> +#include <sof/trace/trace.h> +#include <sof/lib/uuid.h> #include <sof/common.h> #include <rtos/alloc.h> #include <sof/math/fft.h> +#include "fft_common.h" -struct fft_plan *fft_plan_new(void *inb, void *outb, uint32_t size, int bits) +LOG_MODULE_REGISTER(math_fft, CONFIG_SOF_LOG_LEVEL); +SOF_DEFINE_REG_UUID(math_fft); +DECLARE_TR_CTX(math_fft_tr, SOF_UUID(math_fft_uuid), LOG_LEVEL_INFO); + +struct fft_plan *fft_plan_common_new(struct processing_module *mod, void *inb, + void *outb, uint32_t size, int bits) { struct fft_plan *plan; int lim = 1; int len = 0; - int i; - if (!inb || !outb) + if (!inb || !outb) { + comp_cl_err(mod->dev, "NULL input/output buffers."); return NULL; + } - plan = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(struct fft_plan)); - if (!plan) + if (!is_power_of_2(size)) { + comp_cl_err(mod->dev, "The FFT size must be a power of two."); return NULL; + } + + plan = mod_zalloc(mod, sizeof(struct fft_plan)); + if (!plan) { + comp_cl_err(mod->dev, "Failed to allocate FFT plan."); + return NULL; + } switch (bits) { case 16: @@ -35,7 +52,8 @@ struct fft_plan *fft_plan_new(void *inb, void *outb, uint32_t size, int bits) plan->outb32 = outb; break; default: - rfree(plan); + comp_cl_err(mod->dev, "Invalid word length."); + mod_free(mod, plan); return NULL; } @@ -47,27 +65,50 @@ struct fft_plan *fft_plan_new(void *inb, void *outb, uint32_t size, int bits) plan->size = lim; plan->len = len; + return plan; +} - plan->bit_reverse_idx = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - plan->size * sizeof(uint16_t)); - if (!plan->bit_reverse_idx) { - rfree(plan); +void fft_plan_init_bit_reverse(uint16_t *bit_reverse_idx, int size, int len) +{ + int i; + + /* Set up the bit reverse index. The array will contain the value of + * the index with the bits order reversed. Index can be skipped. + */ + for (i = 1; i < size; ++i) + bit_reverse_idx[i] = (bit_reverse_idx[i >> 1] >> 1) | ((i & 1) << (len - 1)); +} + +struct fft_plan *mod_fft_plan_new(struct processing_module *mod, void *inb, + void *outb, uint32_t size, int bits) +{ + struct fft_plan *plan; + + if (size > FFT_SIZE_MAX || size < FFT_SIZE_MIN) { + comp_cl_err(mod->dev, "Invalid FFT size %d", size); return NULL; } - /* set up the bit reverse index */ - for (i = 1; i < plan->size; ++i) - plan->bit_reverse_idx[i] = (plan->bit_reverse_idx[i >> 1] >> 1) | - ((i & 1) << (len - 1)); + plan = fft_plan_common_new(mod, inb, outb, size, bits); + if (!plan) + return NULL; + + plan->bit_reverse_idx = mod_zalloc(mod, plan->size * sizeof(uint16_t)); + if (!plan->bit_reverse_idx) { + comp_cl_err(mod->dev, "Failed to allocate bit reverse table."); + mod_free(mod, plan); + return NULL; + } + fft_plan_init_bit_reverse(plan->bit_reverse_idx, plan->size, plan->len); return plan; } -void fft_plan_free(struct fft_plan *plan) +void mod_fft_plan_free(struct processing_module *mod, struct fft_plan *plan) { if (!plan) return; - rfree(plan->bit_reverse_idx); - rfree(plan); + mod_free(mod, plan->bit_reverse_idx); + mod_free(mod, plan); } diff --git a/src/math/fft/fft_common.h b/src/math/fft/fft_common.h new file mode 100644 index 000000000000..9ea9998073ca --- /dev/null +++ b/src/math/fft/fft_common.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +/** + * fft_plan_common_new() - Common FFT prepare function + * @param mod: Pointer to module + * @param inb: Buffer to use for complex input data + * @param outb: Buffer to use for complex output data + * @param size: Size of FFT as number of bins + * @param bits: World length of FFT. Currently only 32 is supported. + * @return Pointer to FFT plan + */ +struct fft_plan *fft_plan_common_new(struct processing_module *mod, void *inb, + void *outb, uint32_t size, int bits); + +/** + * fft_plan_init_bit_reverse - Configures a bit reversal lookup vector + * @param bit_reverse_idx: Pointer to array to store bit reverse lookup + * @param size: Size of FFT + * @param len: Power of two value equals FFT size + */ +void fft_plan_init_bit_reverse(uint16_t *bit_reverse_idx, int size, int len); diff --git a/src/math/fft/fft_multi.c b/src/math/fft/fft_multi.c new file mode 100644 index 000000000000..794eb3002c47 --- /dev/null +++ b/src/math/fft/fft_multi.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +#include <sof/audio/coefficients/fft/twiddle_3072_32.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/format.h> +#include <sof/math/icomplex32.h> +#include <sof/trace/trace.h> +#include <sof/lib/uuid.h> +#include <sof/common.h> +#include <rtos/alloc.h> +#include <sof/math/fft.h> +#include "fft_common.h" + +LOG_MODULE_REGISTER(math_fft_multi, CONFIG_SOF_LOG_LEVEL); +SOF_DEFINE_REG_UUID(math_fft_multi); +DECLARE_TR_CTX(math_fft_multi_tr, SOF_UUID(math_fft_multi_uuid), LOG_LEVEL_INFO); + +struct fft_multi_plan *mod_fft_multi_plan_new(struct processing_module *mod, void *inb, + void *outb, uint32_t size, int bits) +{ + struct fft_multi_plan *plan; + size_t tmp_size; + const int size_div3 = size / 3; + int i; + + if (!inb || !outb) { + comp_cl_err(mod->dev, "Null buffers"); + return NULL; + } + + if (size < FFT_SIZE_MIN) { + comp_cl_err(mod->dev, "Invalid FFT size %d", size); + return NULL; + } + + plan = mod_zalloc(mod, sizeof(struct fft_multi_plan)); + if (!plan) + return NULL; + + if (is_power_of_2(size)) { + plan->num_ffts = 1; + } else if (size_div3 * 3 == size) { + plan->num_ffts = 3; + } else { + comp_cl_err(mod->dev, "Not supported FFT size %d", size); + goto err; + } + + /* Allocate common bit reverse table for all FFT plans */ + plan->total_size = size; + plan->fft_size = size / plan->num_ffts; + if (plan->fft_size > FFT_SIZE_MAX) { + comp_cl_err(mod->dev, "Requested size %d FFT is too large", size); + goto err; + } + + plan->bit_reverse_idx = mod_zalloc(mod, plan->fft_size * sizeof(uint16_t)); + if (!plan->bit_reverse_idx) { + comp_cl_err(mod->dev, "Failed to allocate FFT plan"); + goto err; + } + + switch (bits) { + case 32: + plan->inb32 = inb; + plan->outb32 = outb; + + if (plan->num_ffts > 1) { + /* Allocate input/output buffers for FFTs */ + tmp_size = 2 * plan->num_ffts * plan->fft_size * sizeof(struct icomplex32); + plan->tmp_i32[0] = mod_balloc(mod, tmp_size); + if (!plan->tmp_i32[0]) { + comp_cl_err(mod->dev, "Failed to allocate FFT buffers"); + goto err; + } + + /* Set up buffers */ + plan->tmp_o32[0] = plan->tmp_i32[0] + plan->fft_size; + for (i = 1; i < plan->num_ffts; i++) { + plan->tmp_i32[i] = plan->tmp_o32[i - 1] + plan->fft_size; + plan->tmp_o32[i] = plan->tmp_i32[i] + plan->fft_size; + } + } else { + plan->tmp_i32[0] = inb; + plan->tmp_o32[0] = outb; + } + + for (i = 0; i < plan->num_ffts; i++) { + plan->fft_plan[i] = fft_plan_common_new(mod, + plan->tmp_i32[i], + plan->tmp_o32[i], + plan->fft_size, 32); + if (!plan->fft_plan[i]) + goto err; + + plan->fft_plan[i]->bit_reverse_idx = plan->bit_reverse_idx; + } + break; + default: + comp_cl_err(mod->dev, "Not supported word length %d", bits); + goto err; + } + + /* Set up common bit index reverse table */ + fft_plan_init_bit_reverse(plan->bit_reverse_idx, plan->fft_plan[0]->size, + plan->fft_plan[0]->len); + return plan; + +err: + /* mod_fft_multi_plan_free() handles partial state safely: + * - fft_plan[i] entries left NULL by mod_zalloc are skipped by mod_free, + * - tmp_i32[0] is freed only when num_ffts > 1, so it does not free + * the caller-provided inb in the single-FFT case. + */ + mod_fft_multi_plan_free(mod, plan); + return NULL; +} + +void mod_fft_multi_plan_free(struct processing_module *mod, struct fft_multi_plan *plan) +{ + int i; + + if (!plan) + return; + + for (i = 0; i < plan->num_ffts; i++) + mod_free(mod, plan->fft_plan[i]); + + /* If single FFT, the internal buffers were not allocated. */ + if (plan->num_ffts > 1) + mod_free(mod, plan->tmp_i32[0]); + + mod_free(mod, plan->bit_reverse_idx); + mod_free(mod, plan); +} diff --git a/src/math/fft/fft_multi_generic.c b/src/math/fft/fft_multi_generic.c new file mode 100644 index 000000000000..52ec1e8172c0 --- /dev/null +++ b/src/math/fft/fft_multi_generic.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025-2026 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +#include <sof/audio/format.h> +#include <sof/math/icomplex32.h> +#include <sof/common.h> +#include <sof/math/fft.h> +#include <string.h> + +#ifdef DEBUG_DUMP_TO_FILE +#include <stdio.h> +#endif + +/* Twiddle factor tables defined in fft_multi.c via twiddle_3072_32.h */ +#define FFT_MULTI_TWIDDLE_SIZE 2048 +extern const int32_t multi_twiddle_real_32[]; +extern const int32_t multi_twiddle_imag_32[]; + +/* Constants for size 3 DFT */ +#define DFT3_COEFR -1073741824 /* int32(-0.5 * 2^31) */ +#define DFT3_COEFI 1859775393 /* int32(sqrt(3) / 2 * 2^31) */ +#define DFT3_SCALE 715827883 /* int32(1/3*2^31) */ + +#ifdef FFT_GENERIC + +void dft3_32(struct icomplex32 *x_in, struct icomplex32 *y) +{ + const struct icomplex32 c0 = {DFT3_COEFR, -DFT3_COEFI}; + const struct icomplex32 c1 = {DFT3_COEFR, DFT3_COEFI}; + struct icomplex32 x[3]; + struct icomplex32 p1, p2, sum; + int i; + + for (i = 0; i < 3; i++) { + x[i].real = Q_MULTSR_32X32((int64_t)x_in[i].real, DFT3_SCALE, 31, 31, 31); + x[i].imag = Q_MULTSR_32X32((int64_t)x_in[i].imag, DFT3_SCALE, 31, 31, 31); + } + + /* + * | 1 1 1 | + * c = | 1 c0 c1 | , x = [ x0 x1 x2 ] + * | 1 c1 c0 | + * + * y(0) = c(0,0) * x(0) + c(1,0) * x(1) + c(2,0) * x(2) + * y(1) = c(0,1) * x(0) + c(1,1) * x(1) + c(2,1) * x(2) + * y(2) = c(0,2) * x(0) + c(1,2) * x(1) + c(2,2) * x(2) + */ + + /* y(0) = 1 * x(0) + 1 * x(1) + 1 * x(2) */ + icomplex32_adds(&x[0], &x[1], &sum); + icomplex32_adds(&x[2], &sum, &y[0]); + + /* y(1) = 1 * x(0) + c0 * x(1) + c1 * x(2) */ + icomplex32_mul(&c0, &x[1], &p1); + icomplex32_mul(&c1, &x[2], &p2); + icomplex32_adds(&p1, &p2, &sum); + icomplex32_adds(&x[0], &sum, &y[1]); + + /* y(2) = 1 * x(0) + c1 * x(1) + c0 * x(2) */ + icomplex32_mul(&c1, &x[1], &p1); + icomplex32_mul(&c0, &x[2], &p2); + icomplex32_adds(&p1, &p2, &sum); + icomplex32_adds(&x[0], &sum, &y[2]); +} + +void fft_multi_execute_32(struct fft_multi_plan *plan, bool ifft) +{ + struct icomplex32 x[FFT_MULTI_COUNT_MAX]; + struct icomplex32 y[FFT_MULTI_COUNT_MAX]; + struct icomplex32 t, c; + int i, j, k, m; + + /* Handle 2^N FFT */ + if (plan->num_ffts == 1) { + memset(plan->outb32, 0, plan->fft_size * sizeof(struct icomplex32)); + fft_execute_32(plan->fft_plan[0], ifft); + return; + } + +#ifdef DEBUG_DUMP_TO_FILE + FILE *fh1 = fopen("debug_fft_multi_int1.txt", "w"); + FILE *fh2 = fopen("debug_fft_multi_int2.txt", "w"); + FILE *fh3 = fopen("debug_fft_multi_twiddle.txt", "w"); + FILE *fh4 = fopen("debug_fft_multi_dft_out.txt", "w"); +#endif + + /* convert to complex conjugate for IFFT */ + if (ifft) { + for (i = 0; i < plan->total_size; i++) + icomplex32_conj(&plan->inb32[i]); + } + + /* Copy input buffers */ + k = 0; + for (i = 0; i < plan->fft_size; i++) + for (j = 0; j < plan->num_ffts; j++) + plan->tmp_i32[j][i] = plan->inb32[k++]; + + /* Clear output buffers and call individual FFTs*/ + for (j = 0; j < plan->num_ffts; j++) { + memset(&plan->tmp_o32[j][0], 0, plan->fft_size * sizeof(struct icomplex32)); + fft_execute_32(plan->fft_plan[j], 0); + } + +#ifdef DEBUG_DUMP_TO_FILE + for (j = 0; j < plan->num_ffts; j++) + for (i = 0; i < plan->fft_size; i++) + fprintf(fh1, "%d %d\n", plan->tmp_o32[j][i].real, plan->tmp_o32[j][i].imag); +#endif + + /* Multiply with twiddle factors */ + m = FFT_MULTI_TWIDDLE_SIZE / 2 / plan->fft_size; + for (j = 1; j < plan->num_ffts; j++) { + for (i = 0; i < plan->fft_size; i++) { + c = plan->tmp_o32[j][i]; + k = j * i * m; + t.real = multi_twiddle_real_32[k]; + t.imag = multi_twiddle_imag_32[k]; + // fprintf(fh3, "%d %d\n", t.real, t.imag); + icomplex32_mul(&t, &c, &plan->tmp_o32[j][i]); + } + } + +#ifdef DEBUG_DUMP_TO_FILE + for (j = 0; j < plan->num_ffts; j++) + for (i = 0; i < plan->fft_size; i++) + fprintf(fh2, "%d %d\n", plan->tmp_o32[j][i].real, plan->tmp_o32[j][i].imag); +#endif + + /* DFT of size 3 */ + j = plan->fft_size; + k = 2 * plan->fft_size; + for (i = 0; i < plan->fft_size; i++) { + x[0] = plan->tmp_o32[0][i]; + x[1] = plan->tmp_o32[1][i]; + x[2] = plan->tmp_o32[2][i]; + dft3_32(x, y); + plan->outb32[i] = y[0]; + plan->outb32[i + j] = y[1]; + plan->outb32[i + k] = y[2]; + } + +#ifdef DEBUG_DUMP_TO_FILE + for (i = 0; i < plan->total_size; i++) + fprintf(fh4, "%d %d\n", plan->outb32[i].real, plan->outb32[i].imag); +#endif + + /* shift back for IFFT */ + + /* TODO: Check if time shift method for IFFT is more efficient or more accurate + * tmp = 1 / N * fft(X); + * x = tmp([1 N:-1:2]) + */ + if (ifft) { + /* + * no need to divide N as it is already done in the input side + * for Q1.31 format. Instead, we need to multiply N to compensate + * the shrink we did in the FFT transform. + */ + for (i = 0; i < plan->total_size; i++) { + /* Need to negate imag part to match reference */ + plan->outb32[i].imag = -plan->outb32[i].imag; + icomplex32_shift(&plan->outb32[i], plan->fft_plan[0]->len, + &plan->outb32[i]); + plan->outb32[i].real = sat_int32((int64_t)plan->outb32[i].real * 3); + plan->outb32[i].imag = sat_int32((int64_t)plan->outb32[i].imag * 3); + } + } + +#ifdef DEBUG_DUMP_TO_FILE + fclose(fh1); + fclose(fh2); + fclose(fh3); + fclose(fh4); +#endif +} + +#endif /* FFT_GENERIC */ diff --git a/src/math/fft/fft_multi_hifi3.c b/src/math/fft/fft_multi_hifi3.c new file mode 100644 index 000000000000..8f0c25e65f8c --- /dev/null +++ b/src/math/fft/fft_multi_hifi3.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025-2026 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +/** + * @file fft_multi_hifi3.c + * @brief HiFi3 optimized multi-radix FFT functions. + * + * This file provides HiFi3 optimized implementations of dft3_32() and + * fft_multi_execute_32() using Xtensa HiFi3 intrinsics. These replace + * the generic versions when HiFi3 or HiFi4 hardware is available. + * + * Key optimizations over the generic versions: + * - Packed {real, imag} processing using ae_int32x2 registers + * - 64-bit MAC accumulation for fused complex multiply-add + * - Saturating 32-bit arithmetic via AE_ADD32S/AE_SLAA32S + * - Vectorized conjugate, shift, and scale in the IFFT path + */ + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/format.h> +#include <sof/math/icomplex32.h> +#include <sof/common.h> +#include <sof/math/fft.h> +#include <string.h> + +/* Twiddle factor tables defined in fft_multi.c via twiddle_3072_32.h */ +#define FFT_MULTI_TWIDDLE_SIZE 2048 +extern const int32_t multi_twiddle_real_32[]; +extern const int32_t multi_twiddle_imag_32[]; + +#ifdef FFT_HIFI3 + +#include <xtensa/tie/xt_hifi3.h> + +/** @brief Q1.31 constant -0.5 */ +#define DFT3_COEFR -1073741824 +/** @brief Q1.31 constant sqrt(3)/2 */ +#define DFT3_COEFI 1859775393 +/** @brief Q1.31 constant 1/3 */ +#define DFT3_SCALE 715827883 + +/** + * dft3_32() - Compute 3-point DFT of Q1.31 complex data (HiFi3). + * @param x_in Pointer to 3 input complex samples in Q1.31. + * @param y Pointer to 3 output complex samples in Q1.31. + * + * Computes the DFT matrix-vector product: + * + * | 1 1 1 | + * Y = | 1 c0 c1 | * X / 3 + * | 1 c1 c0 | + * + * where c0 = exp(-j*2*pi/3) and c1 = exp(+j*2*pi/3). + * Input is prescaled by 1/3 to prevent overflow. + * + * The two complex multiplies for each output bin are fused + * into a single 64-bit accumulator pair, avoiding intermediate + * rounding and saving instructions. + */ +void dft3_32(struct icomplex32 *x_in, struct icomplex32 *y) +{ + ae_int32x2 *p_in = (ae_int32x2 *)x_in; + ae_int32x2 *p_out = (ae_int32x2 *)y; + ae_int32x2 x0, x1, x2; + ae_int32x2 c0, c1; + ae_int32x2 scale; + ae_int32x2 sum, result; + ae_int64 re, im; + + /* + * Set up DFT3 twiddle factors as packed {H=real, L=imag}. + * c0 = {-0.5, -sqrt(3)/2} + * c1 = {-0.5, +sqrt(3)/2} + */ + scale = AE_MOVDA32(DFT3_COEFR); + c0 = AE_SEL32_LH(scale, AE_MOVDA32(-DFT3_COEFI)); + c1 = AE_SEL32_LH(scale, AE_MOVDA32(DFT3_COEFI)); + + /* Scale factor 1/3, broadcast to both H and L */ + scale = AE_MOVDA32(DFT3_SCALE); + + /* Load input samples as packed {real, imag} */ + x0 = AE_L32X2_I(p_in, 0); + x1 = AE_L32X2_I(p_in, 1 * sizeof(ae_int32x2)); + x2 = AE_L32X2_I(p_in, 2 * sizeof(ae_int32x2)); + + /* Scale all inputs by 1/3 to prevent overflow */ + x0 = AE_MULFP32X2RS(x0, scale); + x1 = AE_MULFP32X2RS(x1, scale); + x2 = AE_MULFP32X2RS(x2, scale); + + /* y[0] = x[0] + x[1] + x[2] */ + sum = AE_ADD32S(x0, x1); + AE_S32X2_I(AE_ADD32S(sum, x2), p_out, 0); + + /* + * y[1] = x[0] + c0 * x[1] + c1 * x[2] + * + * Fuse two complex multiplies and their sum into a single + * 64-bit accumulator pair to avoid intermediate rounding. + * + * Real part: c0.re*x1.re - c0.im*x1.im + c1.re*x2.re - c1.im*x2.im + * Imag part: c0.re*x1.im + c0.im*x1.re + c1.re*x2.im + c1.im*x2.re + */ + re = AE_MULF32S_HH(c0, x1); /* c0.re * x1.re */ + AE_MULSF32S_LL(re, c0, x1); /* -= c0.im * x1.im */ + AE_MULAF32S_HH(re, c1, x2); /* += c1.re * x2.re */ + AE_MULSF32S_LL(re, c1, x2); /* -= c1.im * x2.im */ + + im = AE_MULF32S_HL(c0, x1); /* c0.re * x1.im */ + AE_MULAF32S_LH(im, c0, x1); /* += c0.im * x1.re */ + AE_MULAF32S_HL(im, c1, x2); /* += c1.re * x2.im */ + AE_MULAF32S_LH(im, c1, x2); /* += c1.im * x2.re */ + + result = AE_ROUND32X2F64SSYM(re, im); + AE_S32X2_I(AE_ADD32S(x0, result), p_out, sizeof(ae_int32x2)); + + /* + * y[2] = x[0] + c1 * x[1] + c0 * x[2] + * + * Same structure as y[1] but with swapped coefficients. + */ + re = AE_MULF32S_HH(c1, x1); /* c1.re * x1.re */ + AE_MULSF32S_LL(re, c1, x1); /* -= c1.im * x1.im */ + AE_MULAF32S_HH(re, c0, x2); /* += c0.re * x2.re */ + AE_MULSF32S_LL(re, c0, x2); /* -= c0.im * x2.im */ + + im = AE_MULF32S_HL(c1, x1); /* c1.re * x1.im */ + AE_MULAF32S_LH(im, c1, x1); /* += c1.im * x1.re */ + AE_MULAF32S_HL(im, c0, x2); /* += c0.re * x2.im */ + AE_MULAF32S_LH(im, c0, x2); /* += c0.im * x2.re */ + + result = AE_ROUND32X2F64SSYM(re, im); + AE_S32X2_I(AE_ADD32S(x0, result), p_out, 2 * sizeof(ae_int32x2)); +} + +/** + * fft_multi_execute_32() - Execute multi-radix FFT/IFFT (HiFi3). + * @param plan Pointer to multi-FFT plan. + * @param ifft False for FFT, true for IFFT. + * + * Performs a composite FFT of size N = num_ffts * fft_size (e.g. 3 * 512 = 1536). + * For power-of-two sizes the call is forwarded to fft_execute_32(). + * + * HiFi3 optimizations vs. the generic path: + * - IFFT conjugate uses packed AE_SEL32_HL / AE_NEG32S + * - Twiddle multiply uses fused 64-bit MAC (no intermediate rounding) + * - IFFT shift-back combines negate, shift, and *3 scale in HiFi3 ops + */ +void fft_multi_execute_32(struct fft_multi_plan *plan, bool ifft) +{ + struct icomplex32 x[FFT_MULTI_COUNT_MAX]; + struct icomplex32 y[FFT_MULTI_COUNT_MAX]; + ae_int32x2 *p_src; + ae_int32x2 *p_dst; + ae_int32x2 sample, sample_neg, tw, data; + ae_int64 re, im; + int i, j, k, m; + + /* Handle 2^N FFT */ + if (plan->num_ffts == 1) { + memset(plan->outb32, 0, plan->fft_size * sizeof(struct icomplex32)); + fft_execute_32(plan->fft_plan[0], ifft); + return; + } + + /* Convert to complex conjugate for IFFT */ + if (ifft) { + p_src = (ae_int32x2 *)plan->inb32; + for (i = 0; i < plan->total_size; i++) { + AE_L32X2_IP(sample, p_src, 0); + sample_neg = AE_NEG32S(sample); + sample = AE_SEL32_HL(sample, sample_neg); + AE_S32X2_IP(sample, p_src, sizeof(ae_int32x2)); + } + } + + /* Copy input buffers (interleaved -> per-FFT) */ + k = 0; + for (i = 0; i < plan->fft_size; i++) + for (j = 0; j < plan->num_ffts; j++) + plan->tmp_i32[j][i] = plan->inb32[k++]; + + /* Clear output buffers and call individual FFTs */ + for (j = 0; j < plan->num_ffts; j++) { + memset(&plan->tmp_o32[j][0], 0, plan->fft_size * sizeof(struct icomplex32)); + fft_execute_32(plan->fft_plan[j], 0); + } + + /* Multiply with twiddle factors using HiFi3 complex multiply */ + m = FFT_MULTI_TWIDDLE_SIZE / 2 / plan->fft_size; + for (j = 1; j < plan->num_ffts; j++) { + p_dst = (ae_int32x2 *)plan->tmp_o32[j]; + for (i = 0; i < plan->fft_size; i++) { + k = j * i * m; + /* + * Build twiddle as packed {H=real, L=imag}. + * Use AE_SEL32_LH to pack two scalar loads. + */ + tw = AE_SEL32_LH(AE_MOVDA32(multi_twiddle_real_32[k]), + AE_MOVDA32(multi_twiddle_imag_32[k])); + + data = AE_L32X2_I(p_dst, 0); + + /* Complex multiply: tw * data */ + re = AE_MULF32S_HH(tw, data); + AE_MULSF32S_LL(re, tw, data); + im = AE_MULF32S_HL(tw, data); + AE_MULAF32S_LH(im, tw, data); + + AE_S32X2_IP(AE_ROUND32X2F64SSYM(re, im), + p_dst, sizeof(ae_int32x2)); + } + } + + /* DFT of size 3 */ + j = plan->fft_size; + k = 2 * plan->fft_size; + for (i = 0; i < plan->fft_size; i++) { + x[0] = plan->tmp_o32[0][i]; + x[1] = plan->tmp_o32[1][i]; + x[2] = plan->tmp_o32[2][i]; + dft3_32(x, y); + plan->outb32[i] = y[0]; + plan->outb32[i + j] = y[1]; + plan->outb32[i + k] = y[2]; + } + + /* Shift back for IFFT */ + if (ifft) { + int len = plan->fft_plan[0]->len; + + p_dst = (ae_int32x2 *)plan->outb32; + for (i = 0; i < plan->total_size; i++) { + AE_L32X2_IP(sample, p_dst, 0); + + /* Negate imag part to match reference */ + sample_neg = AE_NEG32S(sample); + sample = AE_SEL32_HL(sample, sample_neg); + + /* Shift left by FFT length to compensate shrink */ + sample = AE_SLAA32S(sample, len); + + /* Integer multiply by 3 (num_ffts) with saturation */ + data = AE_ADD32S(sample, sample); + sample = AE_ADD32S(data, sample); + + AE_S32X2_IP(sample, p_dst, sizeof(ae_int32x2)); + } + } +} + +#endif /* FFT_HIFI3 */ diff --git a/src/math/fft/tune/README.md b/src/math/fft/tune/README.md index d0ff5781890e..e753716a8952 100644 --- a/src/math/fft/tune/README.md +++ b/src/math/fft/tune/README.md @@ -7,3 +7,9 @@ octave -q --eval "sof_export_twiddle(32, 'twiddle_32.h', 1024);" octave -q --eval "sof_export_twiddle(16, 'twiddle_16.h', 1024);" cp twiddle_32.h ../../../include/sof/audio/coefficients/fft/ cp twiddle_16.h ../../../include/sof/audio/coefficients/fft/ + +To generate the twiddle factors for the non-power-of-two FFT implementation for max +size 3072 run these shell commands: + +octave -q --eval "sof_export_twiddle(32, 'twiddle_3072_32.h', 2048, 3072, 'FFT_MULTI_TWIDDLE_SIZE', 'multi_twiddle');" +cp twiddle_3072_32.h ../../../include/sof/audio/coefficients/fft/ diff --git a/src/math/fft/tune/sof_export_twiddle.m b/src/math/fft/tune/sof_export_twiddle.m index 48bf069e391f..9e6b1489c8b5 100644 --- a/src/math/fft/tune/sof_export_twiddle.m +++ b/src/math/fft/tune/sof_export_twiddle.m @@ -1,15 +1,18 @@ -% sof_export_twiddle(bits, fn, fft_size_max) +% sof_export_twiddle(bits, fn, fft_size_max, denom, str_size_max, str_var) % % Input % bits - Number of bits for data, 16 or 32 % fn - File name, defaults to twiddle.h % fft_size_max - Number of twiddle factors, defaults to 1024 if omitted +% denom - divide index * 2 * pi by denom instead of fft_size_max, same if omitted +% str_size_max - macro name for values array size, FFT_SIZE_MAX if omitted +% str_var - variable name prefix, twiddle if omitted % SPDX-License-Identifier: BSD-3-Clause % % Copyright (c) 2022, Intel Corporation. All rights reserved. -function sof_export_twiddle(bits, fn, fft_size_max) +function sof_export_twiddle(bits, fn, fft_size_max, denom, str_size_max, str_var) if nargin < 2 fn = 'twiddle.h'; @@ -19,6 +22,18 @@ function sof_export_twiddle(bits, fn, fft_size_max) fft_size_max = 1024; end +if nargin < 4 + denom = fft_size_max; +end + +if nargin < 5 + str_size_max = 'FFT_SIZE_MAX'; +end + +if nargin < 6 + str_var = 'twiddle'; +end + switch bits case 16, qx = 1; @@ -34,8 +49,8 @@ function sof_export_twiddle(bits, fn, fft_size_max) hcaps = upper(hname); i = 0:(fft_size_max - 1); -twiddle_real = cos(i * 2 * pi / fft_size_max); -twiddle_imag = -sin(i * 2 * pi / fft_size_max); +twiddle_real = cos(i * 2 * pi / denom); +twiddle_imag = -sin(i * 2 * pi / denom); year = datestr(now(), 'yyyy'); fh = fopen(fn, 'w'); @@ -48,12 +63,14 @@ function sof_export_twiddle(bits, fn, fft_size_max) fprintf(fh, '#ifndef __INCLUDE_%s_H__\n', hcaps); fprintf(fh, '#define __INCLUDE_%s_H__\n\n', hcaps); fprintf(fh, '#include <stdint.h>\n\n'); -fprintf(fh, '#define FFT_SIZE_MAX %d\n\n', fft_size_max); +fprintf(fh, '#define %s\t%d\n\n', str_size_max, fft_size_max); fprintf(fh, '/* in Q1.%d, generated from cos(i * 2 * pi / FFT_SIZE_MAX) */\n', qy); -c_export_int(fh, 'twiddle_real', 'FFT_SIZE_MAX', twiddle_real, qx, qy); +str_real = sprintf('%s_real', str_var); +c_export_int(fh, str_real, str_size_max, twiddle_real, qx, qy); fprintf(fh, '/* in Q1.%d, generated from sin(i * 2 * pi / FFT_SIZE_MAX) */\n', qy); -c_export_int(fh, 'twiddle_imag', 'FFT_SIZE_MAX', twiddle_imag, qx, qy); +str_imag = sprintf('%s_imag', str_var); +c_export_int(fh, str_imag, str_size_max, twiddle_imag, qx, qy); fprintf(fh, '#endif\n'); fclose(fh); diff --git a/src/math/fir.toml b/src/math/fir.toml new file mode 100644 index 000000000000..86f2d4163b34 --- /dev/null +++ b/src/math/fir.toml @@ -0,0 +1,6 @@ + [[module.entry]] + name = "FIR" + uuid = UUIDREG_STR_FIR + load_type = "3" + + index = __COUNTER__ diff --git a/src/math/fir_generic.c b/src/math/fir_generic.c index 24fbdc665988..802242d4dbec 100644 --- a/src/math/fir_generic.c +++ b/src/math/fir_generic.c @@ -118,6 +118,7 @@ int32_t fir_32x16(struct fir_state_32x16 *fir, int32_t x) /* Q2.46 -> Q2.31, saturate to Q1.31 */ return sat_int32(y >> shift); } +EXPORT_SYMBOL(fir_32x16); void fir_32x16_2x(struct fir_state_32x16 *fir, int32_t x0, int32_t x1, int32_t *y0, int32_t *y1) { @@ -184,5 +185,6 @@ void fir_32x16_2x(struct fir_state_32x16 *fir, int32_t x0, int32_t x1, int32_t * *y0 = sat_int32(a0 >> shift); *y1 = sat_int32(a1 >> shift); } +EXPORT_SYMBOL(fir_32x16_2x); #endif diff --git a/src/math/fir_hifi2ep.c b/src/math/fir_hifi2ep.c index 7f3a2d42a829..1dd03d7c1485 100644 --- a/src/math/fir_hifi2ep.c +++ b/src/math/fir_hifi2ep.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2017 Intel Corporation. All rights reserved. +// Copyright(c) 2017-2025 Intel Corporation. // // Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> @@ -89,7 +89,7 @@ EXPORT_SYMBOL(fir_get_lrshifts); * 8x 48 bit registers in register file P */ -void fir_32x16_hifiep(struct fir_state_32x16 *fir, int32_t x, int32_t *y, int lshift, int rshift) +void fir_32x16(struct fir_state_32x16 *fir, int32_t x, int32_t *y, int lshift, int rshift) { /* This function uses * 1x 56 bit registers Q, @@ -156,14 +156,15 @@ void fir_32x16_hifiep(struct fir_state_32x16 *fir, int32_t x, int32_t *y, int ls a = AE_SRAAQ56(AE_SLLASQ56S(a, lshift), rshift); AE_SQ32F_I(AE_ROUNDSQ32SYM(a), (ae_q32s *)y, 0); } +EXPORT_SYMBOL(fir_32x16_hifiep); /* HiFi EP has the follow number of reqisters that should not be exceeded * 4x 56 bit registers in register file Q * 8x 48 bit registers in register file P */ -void fir_32x16_2x_hifiep(struct fir_state_32x16 *fir, int32_t x0, int32_t x1, - int32_t *y0, int32_t *y1, int lshift, int rshift) +void fir_32x16_2x(struct fir_state_32x16 *fir, int32_t x0, int32_t x1, + int32_t *y0, int32_t *y1, int lshift, int rshift) { /* This function uses * 2x 56 bit registers Q, @@ -249,5 +250,6 @@ void fir_32x16_2x_hifiep(struct fir_state_32x16 *fir, int32_t x0, int32_t x1, AE_SQ32F_I(AE_ROUNDSQ32SYM(b), (ae_q32s *)y1, 0); AE_SQ32F_I(AE_ROUNDSQ32SYM(a), (ae_q32s *)y0, 0); } +EXPORT_SYMBOL(fir_32x16_2x_hifiep); #endif diff --git a/src/math/fir_hifi3.c b/src/math/fir_hifi3.c index e71fc47fc900..dd3e0edf8bde 100644 --- a/src/math/fir_hifi3.c +++ b/src/math/fir_hifi3.c @@ -1,13 +1,13 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2017 Intel Corporation. All rights reserved. +// Copyright(c) 2017-2025 Intel Corporation. // // Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> #include <sof/math/fir_config.h> #include <sof/common.h> -#if SOF_USE_MIN_HIFI(3, FILTER) +#if SOF_USE_HIFI(3, FILTER) || SOF_USE_HIFI(4, FILTER) #include <sof/audio/buffer.h> #include <sof/math/fir_hifi3.h> @@ -90,8 +90,7 @@ EXPORT_SYMBOL(fir_get_lrshifts); * 8x 48 bit registers in register file P */ -void fir_32x16_hifi3(struct fir_state_32x16 *fir, ae_int32 x, ae_int32 *y, - int shift) +void fir_32x16(struct fir_state_32x16 *fir, ae_int32 x, ae_int32 *y, int shift) { /* This function uses * 1x 56 bit registers Q, @@ -162,14 +161,15 @@ void fir_32x16_hifi3(struct fir_state_32x16 *fir, ae_int32 x, ae_int32 *y, a = AE_SLAA64S(a, shift); AE_S32_L_I(AE_ROUND32F48SSYM(a), (ae_int32 *)y, 0); } +EXPORT_SYMBOL(fir_32x16); /* HiFi EP has the follow number of reqisters that should not be exceeded * 4x 56 bit registers in register file Q * 8x 48 bit registers in register file P */ -void fir_32x16_2x_hifi3(struct fir_state_32x16 *fir, ae_int32 x0, ae_int32 x1, - ae_int32 *y0, ae_int32 *y1, int shift) +void fir_32x16_2x(struct fir_state_32x16 *fir, ae_int32 x0, ae_int32 x1, + ae_int32 *y0, ae_int32 *y1, int shift) { /* This function uses * 2x 56 bit registers Q, @@ -251,6 +251,6 @@ void fir_32x16_2x_hifi3(struct fir_state_32x16 *fir, ae_int32 x0, ae_int32 x1, AE_S32_L_I(AE_ROUND32F48SSYM(b), (ae_int32 *)y1, 0); AE_S32_L_I(AE_ROUND32F48SSYM(a), (ae_int32 *)y0, 0); } -EXPORT_SYMBOL(fir_32x16_2x_hifi3); +EXPORT_SYMBOL(fir_32x16_2x); #endif diff --git a/src/math/fir_hifi5.c b/src/math/fir_hifi5.c new file mode 100644 index 000000000000..d4b699ceabb2 --- /dev/null +++ b/src/math/fir_hifi5.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2017-2025 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +#include <sof/math/fir_config.h> +#include <sof/common.h> + +#if SOF_USE_MIN_HIFI(5, FILTER) + +#include <sof/audio/buffer.h> +#include <sof/math/fir_hifi3.h> +#include <user/fir.h> +#include <xtensa/config/defs.h> +#include <xtensa/tie/xt_hifi5.h> +#include <rtos/symbol.h> +#include <errno.h> +#include <stddef.h> +#include <stdint.h> + +/* + * EQ FIR algorithm code + */ + +void fir_reset(struct fir_state_32x16 *fir) +{ + fir->taps = 0; + fir->length = 0; + fir->out_shift = 0; + fir->coef = NULL; + /* There may need to know the beginning of dynamic allocation after + * reset so omitting setting also fir->delay to NULL. + */ +} +EXPORT_SYMBOL(fir_reset); + +int fir_delay_size(struct sof_fir_coef_data *config) +{ + /* Check FIR tap count for implementation specific constraints */ + if (config->length > SOF_FIR_MAX_LENGTH || config->length < 4) + return -EINVAL; + + /* The optimization requires the tap count to be multiple of four */ + if (config->length & 0x3) + return -EINVAL; + + /* The dual sample version needs one more delay entry. To preserve + * align for 64 bits need to add two. + */ + return (config->length + 2) * sizeof(int32_t); +} +EXPORT_SYMBOL(fir_delay_size); + +int fir_init_coef(struct fir_state_32x16 *fir, + struct sof_fir_coef_data *config) +{ + /* The length is taps plus two since the filter computes two + * samples per call. Length plus one would be minimum but the add + * must be even. The even length is needed for 64 bit loads from delay + * lines with 32 bit samples. + */ + fir->taps = (int)config->length; + fir->length = fir->taps + 2; + fir->out_shift = (int)config->out_shift; + fir->coef = (ae_f16x4 *)&config->coef[0]; + return 0; +} +EXPORT_SYMBOL(fir_init_coef); + +void fir_init_delay(struct fir_state_32x16 *fir, int32_t **data) +{ + fir->delay = (ae_int32 *)*data; + fir->delay_end = fir->delay + fir->length; + fir->rwp = (ae_int32 *)(fir->delay + fir->length - 1); + *data += fir->length; /* Point to next delay line start */ +} +EXPORT_SYMBOL(fir_init_delay); + +void fir_get_lrshifts(struct fir_state_32x16 *fir, int *lshift, + int *rshift) +{ + *lshift = (fir->out_shift < 0) ? -fir->out_shift : 0; + *rshift = (fir->out_shift > 0) ? fir->out_shift : 0; +} +EXPORT_SYMBOL(fir_get_lrshifts); + +void fir_32x16(struct fir_state_32x16 *fir, ae_int32 x, ae_int32 *y, int shift) +{ + /* This function uses + * 1x 56 bit registers Q, + * 4x 48 bit registers P + * 3x integers + * 2x address pointers, + */ + ae_f64 a; + ae_valign u; + ae_f32x2 data2; + ae_f16x4 coefs; + ae_f32x2 d0; + ae_f32x2 d1; + int i; + ae_int32 *dp = fir->rwp; + ae_int16x4 *coefp = (ae_int16x4 *)fir->coef; + const int taps_div_4 = fir->taps >> 2; + const int inc = sizeof(int32_t); + + /* Bypass samples if taps count is zero. */ + if (!taps_div_4) { + *y = x; + return; + } + + /* Write sample to delay */ + AE_S32_L_XC(x, fir->rwp, -sizeof(int32_t)); + + /* Prime the coefficients stream */ + u = AE_LA64_PP(coefp); + + /* Note: If the next function is converted to handle two samples + * per call the data load can be done with single instruction + * AE_LP24X2F_C(data2, dp, sizeof(ae_p24x2f)); + */ + a = AE_ZEROQ56(); + for (i = 0; i < taps_div_4; i++) { + /* Load four coefficients. Coef_3 contains tap h[n], + * coef_2 contains h[n+1], coef_1 contains h[n+2], and + * coef_0 contains h[n+3]; + */ + AE_LA16X4_IP(coefs, u, coefp); + + /* Load two data samples and pack to d0 to data2_h and + * d1 to data2_l. + */ + AE_L32_XC(d0, dp, inc); + AE_L32_XC(d1, dp, inc); + data2 = AE_SEL32_LL(d0, d1); + + /* Accumulate + * a += data2_h * coefs_3 + data2_l * coefs_2. The Q1.31 + * data and Q1.15 coefficients are used as 24 bits as + * Q1.23 values. + */ + AE_MULAAFD32X16_H3_L2(a, data2, coefs); + + /* Repeat the same for next two taps and increase coefp. + * a += data2_h * coefs_1 + data2_l * coefs_0. + */ + AE_L32_XC(d0, dp, inc); + AE_L32_XC(d1, dp, inc); + data2 = AE_SEL32_LL(d0, d1); + AE_MULAAFD32X16_H1_L0(a, data2, coefs); + } + + /* Do scaling shifts and store sample. */ + a = AE_SLAA64S(a, shift); + AE_S32_L_I(AE_ROUND32F48SSYM(a), (ae_int32 *)y, 0); +} +EXPORT_SYMBOL(fir_32x16); + +void fir_32x16_2x(struct fir_state_32x16 *fir, ae_int32 x0, ae_int32 x1, + ae_int32 *y0, ae_int32 *y1, int shift) +{ + /* This function uses + * 7x 64 bit AE registers + * 3x integers + * 2x address pointers, + */ + ae_valign u; + ae_f64 a = AE_ZERO64(); + ae_f64 b = AE_ZERO64(); + ae_f32x2 d0; + ae_f32x2 d1; + ae_f32x2 d2; + ae_f16x4 coefs; + ae_f32x2 *dp; + ae_f16x4 *coefp = fir->coef; + const int taps_div_4 = fir->taps >> 2; + const int inc = 2 * sizeof(int32_t); + int i; + + /* Bypass samples if taps count is zero. */ + if (!taps_div_4) { + *y0 = x0; + *y1 = x1; + return; + } + + /* Write samples to delay */ + AE_S32_L_XC(x0, fir->rwp, -sizeof(int32_t)); + dp = (ae_f32x2 *)fir->rwp; + AE_S32_L_XC(x1, fir->rwp, -sizeof(int32_t)); + + /* Prime the coefficients stream */ + u = AE_LA64_PP(coefp); + + /* Load two samples, two newest samples and proceed + * to elder input samples in delay line. + */ + AE_L32X2_XC(d0, dp, inc); + for (i = 0; i < taps_div_4; i++) { + /* Load four coefficients. Coef_3 contains tap h[n], + * coef_2 contains h[n+1], coef_1 contains h[n+2], and + * coef_0 contains h[n+3]; + */ + AE_LA16X4_IP(coefs, u, coefp); + + /* Load two data samples more. + * d0.H is x[n] the newest sample + * d0.L is x[n-1] + * d1.H is x[n-2] + * d1.L is x[n-3] + * d2.H is x[n-4] + */ + AE_L32X2_XC(d1, dp, inc); + AE_L32X2_XC(d2, dp, inc); + + /* Calculate four FIR taps for current (x1 -> a) and previous input (x0 -> b) + * b = b + d0.H * c.3 + d0.L * c.2 + d1.H * c.1 + d1.L * c.0 + * a = a + d0.L * c.3 + d1.H * c.2 + d1.L * c.1 + d2.H * c.0 + */ + AE_MULA2Q32X16_FIR_H(b, a, d0, d1, d2, coefs); + + /* Prepare for next four taps, d2 overlaps to next loop iteration as d0 */ + d0 = d2; + } + + /* Shift left by one Q1.31 x Q1.15 -> Q2.46 format for Q2.47 round and + * store output samples. + */ + b = AE_SLAA64S(b, shift + 1); + a = AE_SLAA64S(a, shift + 1); + d0 = AE_ROUND32X2F48SASYM(b, a); + AE_S32_H_I(d0, (ae_int32 *)y1, 0); + AE_S32_L_I(d0, (ae_int32 *)y0, 0); +} +EXPORT_SYMBOL(fir_32x16_2x); + +#endif diff --git a/src/math/fir_llext/CMakeLists.txt b/src/math/fir_llext/CMakeLists.txt new file mode 100644 index 000000000000..688a07fa1ffb --- /dev/null +++ b/src/math/fir_llext/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +sof_llext_build("aux1_fir" + SOURCES fir_common.c + ../fir_generic.c + ../fir_hifi2ep.c + ../fir_hifi3.c + ../fir_hifi5.c + LIB openmodules +) diff --git a/src/math/fir_llext/fir_common.c b/src/math/fir_llext/fir_common.c new file mode 100644 index 000000000000..897ac857e07d --- /dev/null +++ b/src/math/fir_llext/fir_common.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Intel Corporation. + +/* modular: llext dynamic link */ + +#include <sof/compiler_attributes.h> +#include <sof/lib/uuid.h> +#include <module/module/api_ver.h> +#include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> + +#include <stddef.h> + +static const struct sof_man_module_manifest mod_manifest __section(".module") __used = + SOF_LLEXT_AUX_MANIFEST("FIR", NULL, SOF_REG_UUID(fir)); + +SOF_LLEXT_BUILDINFO; diff --git a/src/math/fir_llext/llext.toml.h b/src/math/fir_llext/llext.toml.h new file mode 100644 index 000000000000..fa2eab98627b --- /dev/null +++ b/src/math/fir_llext/llext.toml.h @@ -0,0 +1,5 @@ +#include <tools/rimage/config/platform.toml> +#include "../fir.toml" + +[module] +count = __COUNTER__ diff --git a/src/math/gcc-builtins.c b/src/math/gcc-builtins.c new file mode 100644 index 000000000000..56eef2087b43 --- /dev/null +++ b/src/math/gcc-builtins.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c); 2025 Intel Corporation. All rights reserved. + +#include <stdint.h> +#include <rtos/symbol.h> + +/* + * Below we export compiler builtin functions to be used by LLEXT modules. + * + * These builtins are defined in the following places: + * + * https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html + * https://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html + * https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/baselib---signbitf.html + * + * Note: the list below are found in xtensa libgcc, other architecture may + * export more or less and we should then partition with some ifdefs. + */ +#if !CONFIG_64BIT + +long __ashldi3(long a, int b); +EXPORT_SYMBOL(__ashldi3); + +long __ashrdi3(long a, int b); +EXPORT_SYMBOL(__ashrdi3); + +int __divsi3(int a, int b); +EXPORT_SYMBOL(__divsi3); + +long __divdi3(long a, long b); +EXPORT_SYMBOL(__divdi3); + +long __lshrdi3(long a, int b); +EXPORT_SYMBOL(__lshrdi3); + +int __modsi3(int a, int b); +EXPORT_SYMBOL(__modsi3); + +long __moddi3(long a, long b); +EXPORT_SYMBOL(__moddi3); + +int __mulsi3(int a, int b); +EXPORT_SYMBOL(__mulsi3); + +long __muldi3(long a, long b); +EXPORT_SYMBOL(__muldi3); + +long __negdi2(long a); +EXPORT_SYMBOL(__negdi2); + +unsigned int __udivsi3(unsigned int a, unsigned int b); +EXPORT_SYMBOL(__udivsi3); + +unsigned long __udivdi3(unsigned long a, unsigned long b); +EXPORT_SYMBOL(__udivdi3); + +unsigned long __udivmoddi4(unsigned long a, unsigned long b, unsigned long *c); +EXPORT_SYMBOL(__udivmoddi4); + +unsigned int __umodsi3(unsigned int a, unsigned int b); +EXPORT_SYMBOL(__umodsi3); + +unsigned long __umoddi3(unsigned long a, unsigned long b); +EXPORT_SYMBOL(__umoddi3); + +int __cmpdi2(long a, long b); +EXPORT_SYMBOL(__cmpdi2); + +int __ucmpdi2(unsigned long a, unsigned long b); +EXPORT_SYMBOL(__ucmpdi2); + +int __absvsi2(int a); +EXPORT_SYMBOL(__absvsi2); + +long __absvdi2(long a); +EXPORT_SYMBOL(__absvdi2); + +int __addvsi3(int a, int b); +EXPORT_SYMBOL(__addvsi3); + +long __addvdi3(long a, long b); +EXPORT_SYMBOL(__addvdi3); + +int __mulvsi3(int a, int b); +EXPORT_SYMBOL(__mulvsi3); + +long __mulvdi3(long a, long b); +EXPORT_SYMBOL(__mulvdi3); + +int __negvsi2(int a); +EXPORT_SYMBOL(__negvsi2); + +long __negvdi2(long a); +EXPORT_SYMBOL(__negvdi2); + +int __subvsi3(int a, int b); +EXPORT_SYMBOL(__subvsi3); + +long __subvdi3(long a, long b); +EXPORT_SYMBOL(__subvdi3); + +int __clzsi2(unsigned int a); +EXPORT_SYMBOL(__clzsi2); + +int __clzdi2(unsigned long a); +EXPORT_SYMBOL(__clzdi2); + +int __ctzsi2(unsigned int a); +EXPORT_SYMBOL(__ctzsi2); + +int __ctzdi2(unsigned long a); +EXPORT_SYMBOL(__ctzdi2); + +int __ffsdi2(unsigned long a); +EXPORT_SYMBOL(__ffsdi2); + +int __paritysi2(unsigned int a); +EXPORT_SYMBOL(__paritysi2); + +int __paritydi2(unsigned long a); +EXPORT_SYMBOL(__paritydi2); + +int __popcountsi2(unsigned int a); +EXPORT_SYMBOL(__popcountsi2); + +int __popcountdi2(unsigned long a); +EXPORT_SYMBOL(__popcountdi2); + +float __addsf3(float a, float b); +EXPORT_SYMBOL(__addsf3); + +double __adddf3(double a, double b); +EXPORT_SYMBOL(__adddf3); + +float __subsf3(float a, float b); +EXPORT_SYMBOL(__subsf3); + +double __subdf3(double a, double b); +EXPORT_SYMBOL(__subdf3); + +float __mulsf3(float a, float b); +EXPORT_SYMBOL(__mulsf3); + +double __muldf3(double a, double b); +EXPORT_SYMBOL(__muldf3); + +float __divsf3(float a, float b); +EXPORT_SYMBOL(__divsf3); + +double __divdf3(double a, double b); +EXPORT_SYMBOL(__divdf3); + +float __negsf2(float a); +EXPORT_SYMBOL(__negsf2); + +double __negdf2(double a); +EXPORT_SYMBOL(__negdf2); + +double __extendsfdf2(float a); +EXPORT_SYMBOL(__extendsfdf2); + +float __truncdfsf2(double a); +EXPORT_SYMBOL(__truncdfsf2); + +int __fixsfsi(float a); +EXPORT_SYMBOL(__fixsfsi); + +int __fixdfsi(double a); +EXPORT_SYMBOL(__fixdfsi); + +long __fixsfdi(float a); +EXPORT_SYMBOL(__fixsfdi); + +long __fixdfdi(double a); +EXPORT_SYMBOL(__fixdfdi); + +unsigned int __fixunssfsi(float a); +EXPORT_SYMBOL(__fixunssfsi); + +unsigned int __fixunsdfsi(double a); +EXPORT_SYMBOL(__fixunsdfsi); + +unsigned long __fixunssfdi(float a); +EXPORT_SYMBOL(__fixunssfdi); + +unsigned long __fixunsdfdi(double a); +EXPORT_SYMBOL(__fixunsdfdi); + +float __floatsisf(int i); +EXPORT_SYMBOL(__floatsisf); + +double __floatsidf(int i); +EXPORT_SYMBOL(__floatsidf); + +float __floatdisf(long i); +EXPORT_SYMBOL(__floatdisf); + +double __floatdidf(long i); +EXPORT_SYMBOL(__floatdidf); + +float __floatunsisf(unsigned int i); +EXPORT_SYMBOL(__floatunsisf); + +double __floatunsidf(unsigned int i); +EXPORT_SYMBOL(__floatunsidf); + +float __floatundisf(unsigned long i); +EXPORT_SYMBOL(__floatundisf); + +double __floatundidf(unsigned long i); +EXPORT_SYMBOL(__floatundidf); + +int __unordsf2(float a, float b); +EXPORT_SYMBOL(__unordsf2); + +int __unorddf2(double a, double b); +EXPORT_SYMBOL(__unorddf2); + +int __eqsf2(float a, float b); +EXPORT_SYMBOL(__eqsf2); + +int __eqdf2(double a, double b); +EXPORT_SYMBOL(__eqdf2); + +int __nesf2(float a, float b); +EXPORT_SYMBOL(__nesf2); + +int __nedf2(double a, double b); +EXPORT_SYMBOL(__nedf2); + +int __gesf2(float a, float b); +EXPORT_SYMBOL(__gesf2); + +int __gedf2(double a, double b); +EXPORT_SYMBOL(__gedf2); + +int __ltsf2(float a, float b); +EXPORT_SYMBOL(__ltsf2); + +int __ltdf2(double a, double b); +EXPORT_SYMBOL(__ltdf2); + +int __lesf2(float a, float b); +EXPORT_SYMBOL(__lesf2); + +int __ledf2(double a, double b); +EXPORT_SYMBOL(__ledf2); + +int __gtsf2(float a, float b); +EXPORT_SYMBOL(__gtsf2); + +int __gtdf2(double a, double b); +EXPORT_SYMBOL(__gtdf2); + +float __powisf2(float a, int b); +EXPORT_SYMBOL(__powisf2); + +double __powidf2(double a, int b); +EXPORT_SYMBOL(__powidf2); + +#endif diff --git a/src/math/iir.toml b/src/math/iir.toml new file mode 100644 index 000000000000..145488fcccc9 --- /dev/null +++ b/src/math/iir.toml @@ -0,0 +1,6 @@ + [[module.entry]] + name = "IIR" + uuid = "B0CDCD9E-EF8B-404F-8480-0F287FC9D44D" + load_type = "3" + + index = __COUNTER__ diff --git a/src/math/iir_df1.c b/src/math/iir_df1.c index 861c5cd2cf19..5e4d13b8cc70 100644 --- a/src/math/iir_df1.c +++ b/src/math/iir_df1.c @@ -16,9 +16,13 @@ int iir_delay_size_df1(struct sof_eq_iir_header *config) { - int n = config->num_sections; /* One section uses two unit delays */ + uint32_t n = config->num_sections; /* One section uses four unit delays */ - if (n > SOF_EQ_IIR_BIQUADS_MAX || n < 1) + if (!n || n > SOF_EQ_IIR_BIQUADS_MAX) + return -EINVAL; + + if (!config->num_sections_in_series || + config->num_sections_in_series > n) return -EINVAL; return 4 * n * sizeof(int32_t); diff --git a/src/math/iir_df1_generic.c b/src/math/iir_df1_generic.c index 6e6482259569..4b069eafb3d7 100644 --- a/src/math/iir_df1_generic.c +++ b/src/math/iir_df1_generic.c @@ -109,4 +109,58 @@ int32_t iir_df1(struct iir_state_df1 *iir, int32_t x) } EXPORT_SYMBOL(iir_df1); +int32_t iir_df1_4th(struct iir_state_df1 *iir, int32_t x) +{ + int32_t in; + int32_t tmp; + int64_t acc; + int i; + int d = 0; /* Index to state */ + int c = 0; /* Index to coefficient a2 */ + int32_t *coefp = iir->coef; + int32_t *delay = iir->delay; + + /* Coefficients order in coef[] is {a2, a1, b2, b1, b0, shift, gain} */ + /* Delay order in state[] is {y(n - 2), y(n - 1), x(n - 2), x(n - 1)} */ + in = x; + for (i = 0; i < SOF_IIR_DF1_4TH_NUM_BIQUADS; i++) { + /* Compute output: Delay is Q3.61 + * Q2.30 x Q1.31 -> Q3.61 + * Shift Q3.61 to Q3.31 with rounding, saturate to Q1.31 + */ + acc = ((int64_t)coefp[c]) * delay[d]; /* a2 * y(n - 2) */ + acc += ((int64_t)coefp[c + 1]) * delay[d + 1]; /* a1 * y(n - 1) */ + acc += ((int64_t)coefp[c + 2]) * delay[d + 2]; /* b2 * x(n - 2) */ + acc += ((int64_t)coefp[c + 3]) * delay[d + 3]; /* b1 * x(n - 1) */ + acc += ((int64_t)coefp[c + 4]) * in; /* b0 * x */ + tmp = (int32_t)sat_int32(Q_SHIFT_RND(acc, 61, 31)); + + /* update the delay value */ + delay[d] = delay[d + 1]; + delay[d + 1] = tmp; + delay[d + 2] = delay[d + 3]; + delay[d + 3] = in; + + /* Apply gain Q2.14 x Q1.31 -> Q3.45 */ + acc = ((int64_t)coefp[c + 6]) * tmp; /* Gain */ + + /* Apply biquad output shift right parameter + * simultaneously with Q3.45 to Q3.31 conversion. Then + * saturate to 32 bits Q1.31 and prepare for next + * biquad. + */ + acc = Q_SHIFT_RND(acc, 45 + coefp[c + 5], 31); + in = sat_int32(acc); + + /* Proceed to next biquad coefficients and delay + * lines. + */ + c += SOF_EQ_IIR_NBIQUAD; + d += IIR_DF1_NUM_STATE; + } + /* Output of previous section is in variable in */ + return in; +} +EXPORT_SYMBOL(iir_df1_4th); + #endif diff --git a/src/math/iir_df1_hifi3.c b/src/math/iir_df1_hifi3.c index 7c1237f55f79..eddcc3f980ea 100644 --- a/src/math/iir_df1_hifi3.c +++ b/src/math/iir_df1_hifi3.c @@ -126,4 +126,72 @@ int32_t iir_df1(struct iir_state_df1 *iir, int32_t x) } EXPORT_SYMBOL(iir_df1); +int32_t iir_df1_4th(struct iir_state_df1 *iir, int32_t x) +{ + ae_int64 acc; + ae_valign coef_align; + ae_int32x2 coef_a2a1; + ae_int32x2 coef_b2b1; + ae_int32x2 coef_b0; + ae_int32x2 gain; + ae_int32x2 shift; + ae_int32x2 delay_y2y1; + ae_int32x2 delay_x2x1; + ae_int32 in; + ae_int32 tmp; + ae_int32x2 *coefp; + ae_int32x2 *delayp; + int32_t *delay_update; + int i; + + /* Coefficients order in coef[] is {a2, a1, b2, b1, b0, shift, gain} */ + coefp = (ae_int32x2 *)&iir->coef[0]; + delayp = (ae_int32x2 *)&iir->delay[0]; + in = x; + for (i = 0; i < SOF_IIR_DF1_4TH_NUM_BIQUADS; i++) { + /* Compute output: Delay is kept Q17.47 while multiply + * instruction gives Q2.30 x Q1.31 -> Q18.46. Need to + * shift delay line values right by one for same align + * as MAC. Store to delay line need to be shifted left + * by one similarly. + */ + coef_align = AE_LA64_PP(coefp); + AE_LA32X2_IP(coef_a2a1, coef_align, coefp); + AE_LA32X2_IP(coef_b2b1, coef_align, coefp); + AE_L32_IP(coef_b0, (ae_int32 *)coefp, 4); + AE_L32_IP(shift, (ae_int32 *)coefp, 4); + AE_L32_IP(gain, (ae_int32 *)coefp, 4); + + AE_L32X2_IP(delay_y2y1, delayp, 8); + AE_L32X2_IP(delay_x2x1, delayp, 8); + + acc = AE_MULF32R_HH(coef_a2a1, delay_y2y1); /* a2 * y(n - 2) */ + AE_MULAF32R_LL(acc, coef_a2a1, delay_y2y1); /* a1 * y(n - 1) */ + AE_MULAF32R_HH(acc, coef_b2b1, delay_x2x1); /* b2 * x(n - 2) */ + AE_MULAF32R_LL(acc, coef_b2b1, delay_x2x1); /* b1 * x(n - 1) */ + AE_MULAF32R_HH(acc, coef_b0, in); /* b0 * x */ + acc = AE_SLAI64S(acc, 1); /* Convert to Q17.47 */ + tmp = AE_ROUND32F48SSYM(acc); /* Round to Q1.31 */ + + /* update the state value */ + delay_update = (int32_t *)delayp - 4; + delay_update[0] = delay_update[1]; + delay_update[1] = tmp; + delay_update[2] = delay_update[3]; + delay_update[3] = in; + + /* Apply gain Q18.14 x Q1.31 -> Q34.30 */ + acc = AE_MULF32R_HH(gain, tmp); /* Gain */ + acc = AE_SLAI64S(acc, 17); /* Convert to Q17.47 */ + + /* Apply biquad output shift right parameter and then + * round and saturate to 32 bits Q1.31. + */ + acc = AE_SRAA64(acc, shift); + in = AE_ROUND32F48SSYM(acc); + } + return in; +} +EXPORT_SYMBOL(iir_df1_4th); + #endif diff --git a/src/math/iir_df1_hifi4.c b/src/math/iir_df1_hifi4.c index 07a4a495369d..945fd67af5bc 100644 --- a/src/math/iir_df1_hifi4.c +++ b/src/math/iir_df1_hifi4.c @@ -119,4 +119,65 @@ int32_t iir_df1(struct iir_state_df1 *iir, int32_t x) } EXPORT_SYMBOL(iir_df1); +int32_t iir_df1_4th(struct iir_state_df1 *iir, int32_t x) +{ + ae_valign coef_align; + ae_valign data_r_align; + ae_valign data_w_align = AE_ZALIGN64(); + ae_f64 acc; + ae_int32x2 delay_y2y1; + ae_int32x2 delay_x2x1; + ae_int32x2 coef_a2a1; + ae_int32x2 coef_b2b1; + ae_int32x2 coef_b0; + ae_int32x2 gain; + ae_int32x2 shift; + ae_int32 in; + ae_int32x2 *coefp = (ae_int32x2 *)iir->coef; + ae_int32x2 *delay_r = (ae_int32x2 *)iir->delay; + ae_int32x2 *delay_w = delay_r; + int i; + + /* Coefficients order in coef[] is {a2, a1, b2, b1, b0, shift, gain} */ + /* Delay order in state[] is {y(n - 2), y(n - 1), x(n - 2), x(n - 1)} */ + data_r_align = AE_LA64_PP(delay_r); + in = x; + for (i = 0; i < SOF_IIR_DF1_4TH_NUM_BIQUADS; i++) { + /* Load data */ + AE_LA32X2_IP(delay_y2y1, data_r_align, delay_r); + AE_LA32X2_IP(delay_x2x1, data_r_align, delay_r); + + /* Load coefficients */ + coef_align = AE_LA64_PP(coefp); + AE_LA32X2_IP(coef_a2a1, coef_align, coefp); + AE_LA32X2_IP(coef_b2b1, coef_align, coefp); + AE_L32_IP(coef_b0, (ae_int32 *)coefp, 4); + AE_L32_IP(shift, (ae_int32 *)coefp, 4); + AE_L32_IP(gain, (ae_int32 *)coefp, 4); + + acc = AE_MULF32RA_HH(coef_b0, in); /* acc = b0 * in */ + AE_MULAAFD32RA_HH_LL(acc, coef_a2a1, delay_y2y1); /* + a2 * y2 + a1 * y1 */ + AE_MULAAFD32RA_HH_LL(acc, coef_b2b1, delay_x2x1); /* + b2 * x2 + b1 * x1 */ + AE_PKSR32(delay_y2y1, acc, 1); /* y2 = y1, y1 = acc(q1.31) */ + delay_x2x1 = AE_SEL32_LL(delay_x2x1, in); /* x2 = x1, x1 = in */ + + /* Store data */ + AE_SA32X2_IP(delay_y2y1, data_w_align, delay_w); + AE_SA32X2_IP(delay_x2x1, data_w_align, delay_w); + + /* Apply gain */ + acc = AE_MULF32R_LL(gain, delay_y2y1); /* acc = gain * y1 */ + acc = AE_SLAI64S(acc, 17); /* Convert to Q17.47 */ + + /* Apply biquad output shift right parameter and then + * round and saturate to 32 bits Q1.31. + */ + acc = AE_SRAA64(acc, shift); + in = AE_ROUND32F48SSYM(acc); + } + AE_SA64POS_FP(data_w_align, delay_w); + return in; +} +EXPORT_SYMBOL(iir_df1_4th); + #endif diff --git a/src/math/iir_df1_hifi5.c b/src/math/iir_df1_hifi5.c index 262cb5120bff..ca331d28c7fa 100644 --- a/src/math/iir_df1_hifi5.c +++ b/src/math/iir_df1_hifi5.c @@ -116,4 +116,63 @@ int32_t iir_df1(struct iir_state_df1 *iir, int32_t x) } EXPORT_SYMBOL(iir_df1); +int32_t iir_df1_4th(struct iir_state_df1 *iir, int32_t x) +{ + ae_valignx2 coef_align; + ae_valignx2 data_r_align; + ae_valignx2 data_w_align = AE_ZALIGN128(); + ae_f64 acc; + ae_int32x2 delay_y2y1; + ae_int32x2 delay_x2x1; + ae_int32x2 coef_a2a1; + ae_int32x2 coef_b2b1; + ae_int32x2 coef_b0; + ae_int32x2 gain; + ae_int32x2 shift; + ae_int32 in; + ae_int32x4 *coefp = (ae_int32x4 *)iir->coef; + ae_int32x4 *delay_r = (ae_int32x4 *)iir->delay; + ae_int32x4 *delay_w = delay_r; + int i; + + /* Coefficients order in coef[] is {a2, a1, b2, b1, b0, shift, gain} */ + /* Delay order in state[] is {y(n - 2), y(n - 1), x(n - 2), x(n - 1)} */ + data_r_align = AE_LA128_PP(delay_r); + in = x; + for (i = 0; i < SOF_IIR_DF1_4TH_NUM_BIQUADS; i++) { + /* Load data */ + AE_LA32X2X2_IP(delay_y2y1, delay_x2x1, data_r_align, delay_r); + + /* Load coefficients */ + coef_align = AE_LA128_PP(coefp); + AE_LA32X2X2_IP(coef_a2a1, coef_b2b1, coef_align, coefp); + AE_L32_IP(coef_b0, (ae_int32 *)coefp, 4); + AE_L32_IP(shift, (ae_int32 *)coefp, 4); + AE_L32_IP(gain, (ae_int32 *)coefp, 4); + + acc = AE_MULF32RA_HH(coef_b0, in); /* acc = b0 * in */ + AE_MULAAFD32RA_HH_LL(acc, coef_a2a1, delay_y2y1); /* + a2 * y2 + a1 * y1 */ + AE_MULAAFD32RA_HH_LL(acc, coef_b2b1, delay_x2x1); /* + b2 * x2 + b1 * x1 */ + AE_PKSR32(delay_y2y1, acc, 1); /* y2 = y1, y1 = acc(q1.31) */ + delay_x2x1 = AE_SEL32_LL(delay_x2x1, in); /* x2 = x1, x1 = in */ + + /* Store data */ + AE_SA32X2X2_IP(delay_y2y1, delay_x2x1, data_w_align, delay_w); + + /* Apply gain */ + acc = AE_MULF32R_LL(gain, delay_y2y1); /* acc = gain * y1 */ + acc = AE_SLAI64S(acc, 17); /* Convert to Q17.47 */ + + /* Apply biquad output shift right parameter and then + * round and saturate to 32 bits Q1.31. + */ + acc = AE_SRAA64(acc, shift); + in = AE_ROUND32F48SSYM(acc); + } + + AE_SA128POS_FP(data_w_align, delay_w); + return in; +} +EXPORT_SYMBOL(iir_df1_4th); + #endif diff --git a/src/math/iir_df2t.c b/src/math/iir_df2t.c index b2adb69be03f..ed2b50a21a4e 100644 --- a/src/math/iir_df2t.c +++ b/src/math/iir_df2t.c @@ -16,9 +16,13 @@ int iir_delay_size_df2t(struct sof_eq_iir_header *config) { - int n = config->num_sections; /* One section uses two unit delays */ + uint32_t n = config->num_sections; /* One section uses two unit delays */ - if (n > SOF_EQ_IIR_BIQUADS_MAX || n < 1) + if (!n || n > SOF_EQ_IIR_BIQUADS_MAX) + return -EINVAL; + + if (!config->num_sections_in_series || + config->num_sections_in_series > n) return -EINVAL; return 2 * n * sizeof(int64_t); diff --git a/src/math/iir_llext/CMakeLists.txt b/src/math/iir_llext/CMakeLists.txt new file mode 100644 index 000000000000..f6f2a7c328fa --- /dev/null +++ b/src/math/iir_llext/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright (c) 2024 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_MATH_IIR_DF1) + set(df1 ../iir_df1.c ../iir_df1_generic.c ../iir_df1_hifi3.c + ../iir_df1_hifi4.c ../iir_df1_hifi5.c) +else() + set(df1 "") +endif() + +if(CONFIG_MATH_IIR_DF2T) + set(df2t ../iir_df2t.c ../iir_df2t_generic.c ../iir_df2t_hifi3.c) +else() + set(df2t "") +endif() + +if(CONFIG_MATH_IIR_DF1 OR CONFIG_MATH_IIR_DF2T) + sof_llext_build("aux1_iir" + SOURCES iir.c ${df1} ${df2t} + LIB openmodules + ) +endif() diff --git a/src/math/iir_llext/iir.c b/src/math/iir_llext/iir.c new file mode 100644 index 000000000000..7891bd8fc5b1 --- /dev/null +++ b/src/math/iir_llext/iir.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +/* modular: llext dynamic link */ + +#include <sof/compiler_attributes.h> +#include <sof/lib/uuid.h> +#include <module/module/api_ver.h> +#include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> + +static const struct sof_man_module_manifest mod_manifest[] __section(".module") __used = { + SOF_LLEXT_AUX_MANIFEST("IIR", NULL, SOF_REG_UUID(iir)), +}; + +SOF_LLEXT_BUILDINFO; diff --git a/src/math/iir_llext/llext.toml.h b/src/math/iir_llext/llext.toml.h new file mode 100644 index 000000000000..89669daea077 --- /dev/null +++ b/src/math/iir_llext/llext.toml.h @@ -0,0 +1,5 @@ +#include <tools/rimage/config/platform.toml> +#include "../iir.toml" + +[module] +count = __COUNTER__ diff --git a/src/math/mu_law.c b/src/math/mu_law.c new file mode 100644 index 000000000000..32d50dad9b75 --- /dev/null +++ b/src/math/mu_law.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +#include <sof/audio/format.h> +#include <sof/math/mu_law.h> +#include <stdint.h> + +#define SOFM_MULAW_BIAS 33 +#define SOFM_MULAW_MAX 8191 +#define SOFM_MULAW_TOGGLE_BITS 0x7f +#define SOFM_MULAW_SIGN_BIT 0x80 +#define SOFM_MULAW_MANTISSA_MASK 0x0f +#define SOFM_MULAW_MANTISSA_BITS 4 +#define SOFM_MULAW_SHIFT_MASK 0x07 +#define SOFM_MULAW_DEC_ONES_MASK 0x21 /* 0b100001 for "1abcd1", see below */ + +/* + * mu-law encode table (sign bit is b12) + * + * Input values 12:0 Output values 6:0 + * + * 0 0 0 0 0 0 0 1 a b c d x 0 0 0 a b c d + * 0 0 0 0 0 0 1 a b c d x x 0 0 1 a b c d + * 0 0 0 0 0 1 a b c d x x x 0 1 0 a b c d + * 0 0 0 0 1 a b c d x x x x 0 1 1 a b c d + * 0 0 0 1 a b c d x x x x x 1 0 0 a b c d + * 0 0 1 a b c d x x x x x x 1 0 1 a b c d + * 0 1 a b c d x x x x x x x 1 1 0 a b c d + * 1 a b c d x x x x x x x x 1 1 1 a b c d + * + * mu-law decode table (sign bit is b7) + * + * Input values 6:0 Output values 12:0 + * + * 0 0 0 a b c d 0 0 0 0 0 0 0 1 a b c d 1 + * 0 0 1 a b c d 0 0 0 0 0 0 1 a b c d 1 0 + * 0 1 0 a b c d 0 0 0 0 0 1 a b c d 1 0 0 + * 0 1 1 a b c d 0 0 0 0 1 a b c d 1 0 0 0 + * 1 0 0 a b c d 0 0 0 1 a b c d 1 0 0 0 0 + * 1 0 1 a b c d 0 0 1 a b c d 1 0 0 0 0 0 + * 1 1 0 a b c d 0 1 a b c d 1 0 0 0 0 0 0 + * 1 1 1 a b c d 1 a b c d 1 0 0 0 0 0 0 0 + */ + +/* Shift values lookup table for above table for 7 + * highest sample value bits. + */ +static uint8_t mulaw_encode_shifts[128] = { + 0, 1, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, +}; + +/** + * sofm_mu_law_encode() - Encode sample with mu-law coding + * @param sample: A s16 sample value + * + * The mu-law codec is defined in ITU-T G.711 standard and has been used + * in telecommunications in USA and Japan. The mu-law coding compresses + * 14 bit samples to 8 bit data stream. In SOF the high 14 bits of s16 + * format are used for compatibility with normal audios. + * + * @return: Compressed 8 bit code value + */ + +uint8_t sofm_mu_law_encode(int16_t sample) +{ + int sign = SOFM_MULAW_SIGN_BIT; + int shift = 0; + int low_bits; + uint8_t byte; + + /* Convert to 14 bits with shift */ + sample >>= 2; + + /* Negative samples are 1's complement with zero sign bit */ + if (sample < 0) { + sign = 0; + sample = -sample - 1; + } + + sample += SOFM_MULAW_BIAS; + if (sample > SOFM_MULAW_MAX) + sample = SOFM_MULAW_MAX; + + shift = mulaw_encode_shifts[sample >> 6]; + low_bits = (sample >> (shift + 1)) & SOFM_MULAW_MANTISSA_MASK; + + byte = (shift << SOFM_MULAW_MANTISSA_BITS) | low_bits | sign; + byte ^= SOFM_MULAW_TOGGLE_BITS; + return byte; +} + +/** + * sofm_mu_law_decode() - Decode mu-law encoded code word + * @param byte: Encoded code word + * + * The mu-law decoder expands a 8 bit code word into a 14 bit sample value. + * In the SOF the high 14 bits are aligned to the most significant bits + * to be compatible with normal s16 Q1.15 samples. + * + * @return: Sampple value in s16 format + */ +int16_t sofm_mu_law_decode(int8_t byte) +{ + int low_bits; + int shift; + int sign; + int16_t value; + + sign = byte & SOFM_MULAW_SIGN_BIT; + byte ^= SOFM_MULAW_TOGGLE_BITS; + low_bits = byte & SOFM_MULAW_MANTISSA_MASK; + shift = (byte >> SOFM_MULAW_MANTISSA_BITS) & SOFM_MULAW_SHIFT_MASK; + value = (low_bits << (shift + 1)) | (SOFM_MULAW_DEC_ONES_MASK << shift); + value -= SOFM_MULAW_BIAS; + if (!sign) + value = -value; + + /* Shift 14 bit Q1.13 to 16 bit Q1.15 */ + return value << 2; +} diff --git a/src/math/numbers.c b/src/math/numbers.c index e16be49e37e1..df4f822c749a 100644 --- a/src/math/numbers.c +++ b/src/math/numbers.c @@ -15,6 +15,9 @@ #include <rtos/symbol.h> #include <stdint.h> +/* see numbers.h */ +#ifdef USE_SOF_GCD + /* This function returns the greatest common divisor of two numbers * If both parameters are 0, gcd(0, 0) returns 0 * If first parameters is 0 or second parameter is 0, gcd(0, b) returns b @@ -74,6 +77,7 @@ int gcd(int a, int b) return a << k; } EXPORT_SYMBOL(gcd); +#endif /* USE_SOF_GCD */ #if CONFIG_NUMBERS_VECTOR_FIND @@ -176,11 +180,3 @@ uint32_t crc32(uint32_t base, const void *data, uint32_t bytes) return ~crc; } - -#if !CONFIG_64BIT -uint64_t __udivdi3(uint64_t a, uint64_t b); -EXPORT_SYMBOL(__udivdi3); - -int64_t __divdi3(int64_t a, int64_t b); -EXPORT_SYMBOL(__divdi3); -#endif diff --git a/src/math/power.c b/src/math/power.c index ba8071373721..ff9e5f911d5f 100644 --- a/src/math/power.c +++ b/src/math/power.c @@ -10,6 +10,7 @@ #include <sof/audio/format.h> #include <sof/trace/trace.h> #include <sof/math/power.h> + #include <sof/lib/uuid.h> #include <ipc/trace.h> #include <user/trace.h> @@ -56,7 +57,7 @@ int32_t power_int32(int32_t b, int32_t e) multiplier = (int32_t)((1LL << 50) / (int64_t)b); } else { multiplier = INT32_MAX; - tr_err(&math_power_tr, "power_int32(): Divide by zero error."); + tr_err(&math_power_tr, "Divide by zero error."); } } else { multiplier = b; diff --git a/src/math/sqrt_int16.c b/src/math/sqrt_int16.c index 0d62e8145187..81772fc90c3c 100644 --- a/src/math/sqrt_int16.c +++ b/src/math/sqrt_int16.c @@ -6,6 +6,7 @@ // // +#include <rtos/symbol.h> #include <sof/math/sqrt.h> #define SQRT_WRAP_SCHAR_BITS 0xFF @@ -28,7 +29,7 @@ * Arguments : uint16_t u * Return Type : int32_t */ -uint16_t sqrt_int16(uint16_t u) +uint16_t sofm_sqrt_int16(uint16_t u) { static const int32_t iv1[193] = { 46341, 46702, 47059, 47415, 47767, 48117, 48465, 48809, 49152, 49492, 49830, 50166, @@ -145,3 +146,4 @@ uint16_t sqrt_int16(uint16_t u) return y; } +EXPORT_SYMBOL(sofm_sqrt_int16); diff --git a/src/math/sqrt_int32.c b/src/math/sqrt_int32.c new file mode 100644 index 000000000000..6d412b33f33a --- /dev/null +++ b/src/math/sqrt_int32.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> +// + +#include <sof/math/sqrt.h> +#include <rtos/symbol.h> +#include <stdint.h> + +/* Lookup table for square root for initial value in iteration, + * created with Octave commands: + * + * arg=((1:64) * 2^25) / 2^30; lut = int32(sqrt(arg) * 2^30); + * fmt=['static const int32_t sqrt_int32_lut[] = {' repmat(' %d,',1, numel(lut)-1) ' %d};\n']; + * fprintf(fmt, lut) + */ +static const int32_t sqrt_int32_lut[] = { + 189812531, 268435456, 328764948, 379625062, 424433723, 464943848, 502196753, + 536870912, 569437594, 600239927, 629536947, 657529896, 684378814, 710213460, + 735140772, 759250125, 782617115, 805306368, 827373642, 848867446, 869830292, + 890299688, 910308921, 929887697, 949062656, 967857801, 986294844, 1004393507, + 1022171763, 1039646051, 1056831447, 1073741824, 1090389977, 1106787739, 1122946079, + 1138875187, 1154584553, 1170083026, 1185378878, 1200479854, 1215393219, 1230125796, + 1244684005, 1259073893, 1273301169, 1287371222, 1301289153, 1315059792, 1328687719, + 1342177280, 1355532607, 1368757628, 1381856086, 1394831545, 1407687407, 1420426919, + 1433053185, 1445569171, 1457977717, 1470281545, 1482483261, 1494585366, 1506590260, + 1518500250 +}; + +/* sofm_sqrt_int32() - Calculate 32-bit fractional square root function. */ +int32_t sofm_sqrt_int32(int32_t n) +{ + uint64_t n_shifted; + uint32_t x; + int shift; + + if (n < 1) + return 0; + + /* Scale input argument with 2^n, where n is even. + * Scale calculated sqrt() with 2^(-n/2). + */ + shift = (__builtin_clz(n) - 1) & ~1; /* Make even by clearing LSB */ + n = n << shift; + shift >>= 1; /* Divide by 2 for sqrt shift compensation */ + + /* For Q2.30 divide */ + n_shifted = (uint64_t)n << 30; + + /* Get initial guess from LUT, idx = 0 .. 63 */ + x = sqrt_int32_lut[n >> 25]; + + /* Iterate x(n+1) = 1/2 * (x(n) + N / x(n)) + * N is argument for square root + * x(n) is initial guess. Do two iterations. + */ + x = (uint32_t)(((n_shifted / x + x) + 1) >> 1); + x = (uint32_t)(((n_shifted / x + x) + 1) >> 1); + + return (int32_t)(x >> shift); +} +EXPORT_SYMBOL(sofm_sqrt_int32); diff --git a/src/math/trig.c b/src/math/trig.c index ee5014cf91d2..1c1e221a5887 100644 --- a/src/math/trig.c +++ b/src/math/trig.c @@ -7,23 +7,19 @@ // Keyon Jie <yang.jie@linux.intel.com> // Shriram Shastry <malladi.sastry@linux.intel.com> +#include <rtos/symbol.h> #include <sof/audio/format.h> #include <sof/math/trig.h> #include <sof/math/cordic.h> #include <stdint.h> -/* Use a local definition to avoid adding a dependency on <math.h> */ -#define _M_PI 3.14159265358979323846 /* pi */ +#define CORDIC_SINE_COS_LUT_Q29 652032874 /* deg = 69.586061, int32(1.214505869895220 * 2^29) */ + +#define CORDIC_SINCOS_PIOVERTWO_Q28 421657428 /* int32(pi / 2 * 2^28) */ +#define CORDIC_SINCOS_PI_Q28 843314857 /* int32(pi * 2^28) */ +#define CORDIC_SINCOS_TWOPI_Q28 1686629713 /* int32(2 * pi * 2^28) */ +#define CORDIC_SINCOS_ONEANDHALFPI_Q28 1264972285 /* int32(1.5 * pi * 2^28) */ -/* 652032874 , deg = 69.586061*/ -const int32_t cordic_sine_cos_lut_q29fl = Q_CONVERT_FLOAT(1.214505869895220, 29); -/* 1686629713, deg = 90.000000 */ -const int32_t cordic_sine_cos_piovertwo_q30fl = Q_CONVERT_FLOAT(_M_PI / 2, 30); -/* 421657428 , deg = 90.000000 */ -const int32_t cord_sincos_piovertwo_q28fl = Q_CONVERT_FLOAT(_M_PI / 2, 28); -/* 843314857, deg = 90.000000 */ -const int32_t cord_sincos_piovertwo_q29fl = Q_CONVERT_FLOAT(_M_PI / 2, 29); -/* arc trignometry constant*/ /** * CORDIC-based approximation of sine and cosine * \+----------+----------------------------------------+--------------------+-------------------+ @@ -35,20 +31,25 @@ const int32_t cord_sincos_piovertwo_q29fl = Q_CONVERT_FLOAT(_M_PI / 2, 29); * \|1686629713| Q_CONVERT_FLOAT(1.5707963267341256, 30)| 89.9999999965181| 1.57079632673413 | * \+----------+----------------------------------------+--------------------+-------------------+ */ -/* 379625062, deg = 81.0284683480568475 or round(1.4142135605216026*2^28) */ -const int32_t cord_arcsincos_q28fl = Q_CONVERT_FLOAT(1.4142135605216026 / 2, 28); -/* 1073741824, deg = 57.2957795130823229 or round(1*2^30)*/ -const int32_t cord_arcsincos_q30fl = Q_CONVERT_FLOAT(1.0000000000000000, 30); + +#define CORDIC_ARCSINCOS_SQRT2_DIV4_Q30 379625062 /* int32(sqrt(2) / 4 * 2^30) */ +#define CORDIC_ARCSINCOS_ONE_Q30 1073741824 /* int32(1 * 2^30) */ + /** * CORDIC-based approximation of sine, cosine and complex exponential */ void cordic_approx(int32_t th_rad_fxp, int32_t a_idx, int32_t *sign, int32_t *b_yn, int32_t *xn, int32_t *th_cdc_fxp) { + int32_t direction; + int32_t abs_th; int32_t b_idx; - int32_t xtmp; - int32_t ytmp; - *sign = 1; + int32_t xn_local = CORDIC_SINE_COS_LUT_Q29; + int32_t yn_local = 0; + int32_t xtmp = CORDIC_SINE_COS_LUT_Q29; + int32_t ytmp = 0; + int shift; + /* Addition or subtraction by a multiple of pi/2 is done in the data type * of the input. When the fraction length is 29, then the quantization error * introduced by the addition or subtraction of pi/2 is done with 29 bits of @@ -57,56 +58,46 @@ void cordic_approx(int32_t th_rad_fxp, int32_t a_idx, int32_t *sign, int32_t *b_ * without overflow.Increase of fractionLength makes the addition or * subtraction of a multiple of pi/2 more precise */ - if (th_rad_fxp > cord_sincos_piovertwo_q28fl) { - if ((th_rad_fxp - cord_sincos_piovertwo_q29fl) <= cord_sincos_piovertwo_q28fl) { - th_rad_fxp -= cord_sincos_piovertwo_q29fl; - *sign = -1; - } else { - th_rad_fxp -= cordic_sine_cos_piovertwo_q30fl; - } - } else if (th_rad_fxp < -cord_sincos_piovertwo_q28fl) { - if ((th_rad_fxp + cord_sincos_piovertwo_q29fl) >= -cord_sincos_piovertwo_q28fl) { - th_rad_fxp += cord_sincos_piovertwo_q29fl; - *sign = -1; + abs_th = (th_rad_fxp >= 0) ? th_rad_fxp : -th_rad_fxp; + direction = (th_rad_fxp >= 0) ? 1 : -1; + *sign = 1; + if (abs_th > CORDIC_SINCOS_PIOVERTWO_Q28) { + if (abs_th <= CORDIC_SINCOS_ONEANDHALFPI_Q28) { + th_rad_fxp -= direction * CORDIC_SINCOS_PI_Q28; + *sign = -1; } else { - th_rad_fxp += cordic_sine_cos_piovertwo_q30fl; + th_rad_fxp -= direction * CORDIC_SINCOS_TWOPI_Q28; } } th_rad_fxp <<= 2; - *b_yn = 0; - *xn = cordic_sine_cos_lut_q29fl; - xtmp = cordic_sine_cos_lut_q29fl; - ytmp = 0; /* Calculate the correct coefficient values from rotation angle. * Find difference between the coefficients from the lookup table * and those from the calculation */ for (b_idx = 0; b_idx < a_idx; b_idx++) { - if (th_rad_fxp < 0) { - th_rad_fxp += cordic_lookup[b_idx]; - *xn += ytmp; - *b_yn -= xtmp; - } else { - th_rad_fxp -= cordic_lookup[b_idx]; - *xn -= ytmp; - *b_yn += xtmp; - } - xtmp = *xn >> (b_idx + 1); - ytmp = *b_yn >> (b_idx + 1); + direction = (th_rad_fxp >= 0) ? 1 : -1; + shift = b_idx + 1; + th_rad_fxp -= direction * cordic_lookup[b_idx]; + xn_local -= direction * ytmp; + yn_local += direction * xtmp; + xtmp = xn_local >> shift; + ytmp = yn_local >> shift; } - /* Q2.30 format -sine, cosine*/ + + /* Write back results once */ + *xn = xn_local; + *b_yn = yn_local; *th_cdc_fxp = th_rad_fxp; } +EXPORT_SYMBOL(cordic_approx); /** * CORDIC-based approximation for inverse cosine - * Arguments : int32_t cosvalue - * int16_t numiters - * Return Type : int32_t + * cosvalue is Q2.30, return value is angle in Q3.29 format */ -int32_t is_scalar_cordic_acos(int32_t cosvalue, int16_t numiters) +int32_t is_scalar_cordic_acos(int32_t cosvalue, int numiters) { int32_t xdshift; int32_t ydshift; @@ -116,25 +107,22 @@ int32_t is_scalar_cordic_acos(int32_t cosvalue, int16_t numiters) int32_t y = 0; int32_t z = 0; int32_t sign; - int32_t b_i; - int i; + int b_i; int j; - int k; /* Initialize the variables for the cordic iteration * angles less than pi/4, we initialize (x,y) along the x-axis. * angles greater than or equal to pi/4, we initialize (x,y) * along the y-axis. This improves the accuracy of the algorithm * near the edge of the domain of convergence + * + * Note: not pi/4 but sqrt(2)/4 is used as the threshold */ - if ((cosvalue >> 1) < cord_arcsincos_q28fl) { - x = 0; - y = cord_arcsincos_q30fl; + if (cosvalue < CORDIC_ARCSINCOS_SQRT2_DIV4_Q30) { + y = CORDIC_ARCSINCOS_ONE_Q30; z = PI_DIV2_Q3_29; } else { - x = cord_arcsincos_q30fl; - y = 0; - z = 0; + x = CORDIC_ARCSINCOS_ONE_Q30; } /* DCORDIC(Double CORDIC) algorithm */ @@ -142,20 +130,14 @@ int32_t is_scalar_cordic_acos(int32_t cosvalue, int16_t numiters) /* CORDIC method,where the iteration step value changes EVERY time, i.e. on */ /* each iteration, in the double iteration method, the iteration step value */ /* is repeated twice and changes only through one iteration */ - i = numiters - 1; - for (b_i = 0; b_i < i; b_i++) { + for (b_i = 0; b_i < numiters; b_i++) { j = (b_i + 1) << 1; if (j >= 31) j = 31; - if (b_i < 31) - k = b_i; - else - k = 31; - - xshift = x >> k; + xshift = x >> b_i; + yshift = y >> b_i; xdshift = x >> j; - yshift = y >> k; ydshift = y >> j; /* Do nothing if x currently equals the target value. Allowed for * double rotations algorithms, as it is equivalent to rotating by @@ -182,11 +164,9 @@ int32_t is_scalar_cordic_acos(int32_t cosvalue, int16_t numiters) /** * CORDIC-based approximation for inverse sine - * Arguments : int32_t sinvalue - * int16_t numiters - * Return Type : int32_t + * sinvalue is Q2.30, return value is angle in Q2.30 format */ -int32_t is_scalar_cordic_asin(int32_t sinvalue, int16_t numiters) +int32_t is_scalar_cordic_asin(int32_t sinvalue, int numiters) { int32_t xdshift; int32_t ydshift; @@ -196,25 +176,22 @@ int32_t is_scalar_cordic_asin(int32_t sinvalue, int16_t numiters) int32_t y = 0; int32_t z = 0; int32_t sign; - int32_t b_i; - int i; + int b_i; int j; - int k; /* Initialize the variables for the cordic iteration * angles less than pi/4, we initialize (x,y) along the x-axis. * angles greater than or equal to pi/4, we initialize (x,y) * along the y-axis. This improves the accuracy of the algorithm * near the edge of the domain of convergence + * + * Note: Instead of pi/4, sqrt(2)/4 is used as the threshold */ - if ((sinvalue >> 1) > cord_arcsincos_q28fl) { - x = 0; - y = cord_arcsincos_q30fl; + if (sinvalue > CORDIC_ARCSINCOS_SQRT2_DIV4_Q30) { + y = CORDIC_ARCSINCOS_ONE_Q30; z = PI_DIV2_Q3_29; } else { - x = cord_arcsincos_q30fl; - y = 0; - z = 0; + x = CORDIC_ARCSINCOS_ONE_Q30; } /* DCORDIC(Double CORDIC) algorithm */ @@ -222,21 +199,15 @@ int32_t is_scalar_cordic_asin(int32_t sinvalue, int16_t numiters) /* CORDIC method,where the iteration step value changes EVERY time, i.e. on */ /* each iteration, in the double iteration method, the iteration step value */ /* is repeated twice and changes only through one iteration */ - i = numiters - 1; - for (b_i = 0; b_i < i; b_i++) { + for (b_i = 0; b_i < numiters; b_i++) { j = (b_i + 1) << 1; if (j >= 31) j = 31; - if (b_i < 31) - k = b_i; - else - k = 31; - - xshift = x >> k; - xdshift = x >> j; - yshift = y >> k; + xshift = x >> b_i; + yshift = y >> b_i; ydshift = y >> j; + xdshift = x >> j; /* Do nothing if x currently equals the target value. Allowed for * double rotations algorithms, as it is equivalent to rotating by * the same angle in opposite directions sequentially. Accounts for @@ -261,13 +232,9 @@ int32_t is_scalar_cordic_asin(int32_t sinvalue, int16_t numiters) } /** - * approximated complex result - * Arguments : int32_t sign - * int32_t b_yn - * int32_t xn - * enum type - * struct cordic_cmpx - * Return Type : none + * cmpx_cexp() - CORDIC-based approximation of complex exponential e^(j*THETA) + * + * The sine and cosine values are in Q2.30 format from cordic_approx()function. */ void cmpx_cexp(int32_t sign, int32_t b_yn, int32_t xn, cordic_cfg type, struct cordic_cmpx *cexp) { diff --git a/src/math/window.c b/src/math/window.c index 4795112ffc0f..39739ef24be3 100644 --- a/src/math/window.c +++ b/src/math/window.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2022 Intel Corporation. All rights reserved. +// Copyright(c) 2022-2025 Intel Corporation. // // Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> @@ -16,6 +16,7 @@ #define WIN_ONE_Q31 INT32_MAX #define WIN_05_Q31 Q_CONVERT_FLOAT(0.5, 31) +#define WIN_PI_Q28 Q_CONVERT_FLOAT(3.1415926536, 28) #define WIN_TWO_PI_Q28 Q_CONVERT_FLOAT(6.2831853072, 28) #define WIN_085_Q31 Q_CONVERT_FLOAT(0.85, 31) @@ -29,12 +30,10 @@ /* Common approximations to match e.g. Octave */ #define WIN_HAMMING_A0_Q30 Q_CONVERT_FLOAT(0.54, 30) #define WIN_HAMMING_A1_Q30 Q_CONVERT_FLOAT(0.46, 30) +#define WIN_HAMMING_A0_Q31 Q_CONVERT_FLOAT(0.54, 31) +#define WIN_HAMMING_A1_Q31 Q_CONVERT_FLOAT(0.46, 31) -/** - * \brief Return rectangular window, simply values of one - * \param[in,out] win Output vector with coefficients - * \param[in] length Length of coefficients vector - */ +/* Rectangular window */ void win_rectangular_16b(int16_t *win, int length) { int i; @@ -43,14 +42,15 @@ void win_rectangular_16b(int16_t *win, int length) win[i] = WIN_ONE_Q15; } -/** - * \brief Calculate Blackman window function, reference - * https://en.wikipedia.org/wiki/Window_function#Blackman_window +void win_rectangular_32b(int32_t *win, int length) +{ + int i; - * \param[in,out] win Output vector with coefficients - * \param[in] length Length of coefficients vector - * \param[in] a0 Parameter for window shape, use e.g. 0.42 as Q1.15 - */ + for (i = 0; i < length; i++) + win[i] = WIN_ONE_Q31; +} + +/* Blackman window */ void win_blackman_16b(int16_t win[], int length, int16_t a0) { const int32_t a1 = Q_CONVERT_FLOAT(0.5, 31); @@ -77,6 +77,64 @@ void win_blackman_16b(int16_t win[], int length, int16_t a0) } } +void win_blackman_32b(int32_t win[], int length, int32_t a0) +{ + const int32_t a1 = Q_CONVERT_FLOAT(0.5, 31); + int64_t val; + int32_t inv_length; + int32_t a; + int16_t alpha; + int32_t a2; + int32_t c1; + int32_t c2; + int n; + + alpha = WIN_ONE_Q31 - 2 * a0; /* Q1.31 */ + a2 = alpha << 15; /* Divided by 2 in Q1.31 */ + a = WIN_TWO_PI_Q28 / (length - 1); /* Q4.28 */ + inv_length = WIN_ONE_Q31 / length; + + for (n = 0; n < length; n++) { + c1 = cos_fixed_32b(a * n); + c2 = cos_fixed_32b(2 * n * Q_MULTSR_32X32((int64_t)a, inv_length, 28, 31, 28)); + val = a0 - Q_MULTSR_32X32((int64_t)a1, c1, 31, 31, 31) + + Q_MULTSR_32X32((int64_t)a2, c2, 31, 31, 31); + win[n] = sat_int32(val); + } +} + +/* Hann window */ +void win_hann_16b(int16_t win[], int length) +{ + int32_t val; + int32_t a; + int n; + + a = WIN_PI_Q28 / (length - 1); /* Q4.28 */ + for (n = 0; n < length; n++) { + /* Calculate sin(a * n)^2 */ + val = sin_fixed_32b(a * n); /* Q4.28 -> Q1.31 */ + val = Q_MULTSR_32X32((int64_t)val, val, 31, 31, 15); /* Q1.15 */ + win[n] = sat_int16(val); + } +} + +void win_hann_32b(int32_t win[], int length) +{ + int64_t val; + int32_t a; + int n; + + a = WIN_PI_Q28 / (length - 1); /* Q4.28 */ + for (n = 0; n < length; n++) { + /* Calculate sin(a * n)^2 */ + val = sin_fixed_32b(a * n); /* Q4.28 -> Q1.31 */ + val = Q_MULTSR_32X32((int64_t)val, val, 31, 31, 31); /* Q1.31 */ + win[n] = sat_int32(val); + } +} + +/* Hamming window */ void win_hamming_16b(int16_t win[], int length) { int32_t val; @@ -95,6 +153,23 @@ void win_hamming_16b(int16_t win[], int length) } } +void win_hamming_32b(int32_t win[], int length) +{ + int64_t val; + int32_t a; + int n; + + a = WIN_TWO_PI_Q28 / (length - 1); /* Q4.28 */ + for (n = 0; n < length; n++) { + /* Calculate 0.54 - 0.46 * cos(a * n) */ + val = cos_fixed_32b(a * n); /* Q4.28 -> Q1.31 */ + val = Q_MULTSR_32X32((int64_t)val, WIN_HAMMING_A1_Q31, 31, 31, 31); /* Q1.31 */ + val = WIN_HAMMING_A0_Q31 - val; + win[n] = sat_int32(val); + } +} + +/* Povey window */ void win_povey_16b(int16_t win[], int length) { int32_t cos_an; diff --git a/src/module/README.md b/src/module/README.md new file mode 100644 index 000000000000..3d79c948bdd8 --- /dev/null +++ b/src/module/README.md @@ -0,0 +1,111 @@ +# Audio Processing Modules (`src/module`) + +The `src/module` directory and the `src/include/module` headers define the Sound Open Firmware (SOF) modern Audio Processing Module API. This architecture abstracts the underlying OS and pipeline scheduler implementations from the actual audio signal processing logic, allowing modules to be written once and deployed either as statically linked core components or as dynamically loadable Zephyr EXT (LLEXT) modules. + +## Architecture Overview + +The SOF module architecture is built around three core concepts: + +1. **`struct module_interface`**: A standardized set of operations (`init`, `prepare`, `process`, `reset`, `free`, `set_configuration`) that every audio processing module implements. +2. **`struct processing_module`**: The runtime instantiated state of a module. It holds metadata, configuration objects, memory allocations (`module_resources`), and references to interconnected streams. +3. **Module Adapter (`src/audio/module_adapter`)**: The system glue layer. It masquerades as a legacy pipeline `comp_dev` to the SOF schedulers, but acts as a sandbox container for the `processing_module`. It intercepts IPC commands, manages the module's state machine, manages inputs/outputs, and safely calls the `module_interface` operations. + +```mermaid +graph TD + subgraph SOF Core Pipeline Scheduler + P[Pipeline Scheduler <br> LL/DP Domains] + end + + subgraph Module Adapter System Layer + MA[Module Adapter `comp_dev`] + IPC[IPC Command Dispatch] + MEM[Memory Resource Manager] + end + + subgraph Standardized Module Framework API + INF[`module_interface` Ops] + SRC[Source API <br> `source_get_data`] + SNK[Sink API <br> `sink_get_buffer`] + end + + subgraph Custom Audio Modules + VOL[Volume] + EQ[EQ FIR/IIR] + CUSTOM[Loadable 3rd Party <br> Zephyr LLEXT] + end + + P <-->|Execute| MA + IPC -->|Config/Triggers| MA + + MA -->|Invoke| INF + MA -->|Manage| MEM + + INF --> VOL + INF --> EQ + INF --> CUSTOM + + VOL -->|Read| SRC + VOL -->|Write| SNK + EQ -->|Read| SRC + EQ -->|Write| SNK +``` + +## Module State Machine + +Every processing module is strictly governed by a uniform runtime state machine managed by the `module_adapter`. Modules must adhere to the transitions defined by `enum module_state`: + +1. `MODULE_DISABLED`: The module is loaded but uninitialized, or has been freed. No memory is allocated. +2. `MODULE_INITIALIZED`: After a successful `.init()` call. The module parses its IPC configuration and allocates necessary local resources (delay lines, coefficient tables). +3. `MODULE_IDLE`: After a successful `.prepare()` call. Audio stream formats are fully negotiated and agreed upon (Stream params, channels, rate). +4. `MODULE_PROCESSING`: When the pipeline triggers a `START` command. The `.process()` callback is actively handling buffers. + +```mermaid +stateDiagram-v2 + [*] --> MODULE_DISABLED: Module Created + + MODULE_DISABLED --> MODULE_INITIALIZED: .init() / IPC NEW + MODULE_INITIALIZED --> MODULE_DISABLED: .free() / IPC FREE + + MODULE_INITIALIZED --> MODULE_IDLE: .prepare() / Pipeline Setup + MODULE_IDLE --> MODULE_INITIALIZED: .reset() / Pipeline Reset + + MODULE_IDLE --> MODULE_PROCESSING: .trigger(START) / IPC START + MODULE_PROCESSING --> MODULE_IDLE: .trigger(STOP/PAUSE) / IPC STOP +``` + +## Data Flows and Buffer Management + +Modules do not directly manipulate underlying DMA, ALSA, or Zephyr `comp_buffer` pointers. Instead, they interact via the decoupled **Source and Sink APIs**. This allows the adapter to seamlessly feed data from varying topological sources without changing module code. + +The flow operates primarily in a "get -> manipulate -> commit/release" pattern: + +```mermaid +sequenceDiagram + participant Adapter as Module Adapter + participant Mod as Processing Module (.process) + participant Src as Source API (Input) + participant Snk as Sink API (Output) + + Adapter->>Mod: Process Trigger (sources[], sinks[]) + + Mod->>Src: source_get_data(req_size) + Src-->>Mod: Provides read_ptr, available_bytes + + Mod->>Snk: sink_get_buffer(req_size) + Snk-->>Mod: Provides write_ptr, free_bytes + + note over Mod: Execute DSP Algorithm <br> (Read from read_ptr -> Write to write_ptr) + + Mod->>Src: source_release_data(consumed_bytes) + Mod->>Snk: sink_commit_buffer(produced_bytes) + + Mod-->>Adapter: Return Status +``` + +### Source API (`src/module/audio/source_api.c`) +- modules request data by calling `source_get_data_s16` or `s32`. This establishes an active read lock. +- Once done, the module must call `source_release_data()` releasing only the frames actually consumed. + +### Sink API (`src/module/audio/sink_api.c`) +- modules request destination buffers by calling `sink_get_buffer_s16` or `s32`. +- After processing into the provided memory array, the module marks the memory as valid by calling `sink_commit_buffer()` for the exact number of frames successfully written. diff --git a/src/module/audio/sink_api.c b/src/module/audio/sink_api.c index 5ec904d61b2f..969b37f5a987 100644 --- a/src/module/audio/sink_api.c +++ b/src/module/audio/sink_api.c @@ -36,6 +36,38 @@ int sink_get_buffer(struct sof_sink *sink, size_t req_size, } EXPORT_SYMBOL(sink_get_buffer); +int sink_get_buffer_s16(struct sof_sink *sink, size_t req_size, + int16_t **data_ptr, int16_t **buffer_start, int *buffer_samples) +{ + size_t buffer_size; + int ret; + + ret = sink_get_buffer(sink, req_size, (void **)data_ptr, (void **)buffer_start, + &buffer_size); + if (ret) + return ret; + + *buffer_samples = buffer_size >> 1; + return 0; +} +EXPORT_SYMBOL(sink_get_buffer_s16); + +int sink_get_buffer_s32(struct sof_sink *sink, size_t req_size, + int32_t **data_ptr, int32_t **buffer_start, int *buffer_samples) +{ + size_t buffer_size; + int ret; + + ret = sink_get_buffer(sink, req_size, (void **)data_ptr, (void **)buffer_start, + &buffer_size); + if (ret) + return ret; + + *buffer_samples = buffer_size >> 2; + return 0; +} +EXPORT_SYMBOL(sink_get_buffer_s32); + int sink_commit_buffer(struct sof_sink *sink, size_t commit_size) { int ret; @@ -77,6 +109,11 @@ EXPORT_SYMBOL(sink_get_frame_bytes); size_t sink_get_free_frames(struct sof_sink *sink) { + /* The frame size is a valid divisor: a host channel count of zero is + * rejected at module init (module_adapter_ipc4.c) before it reaches + * the stream, and the sample size is fixed by a valid frame format, so + * this is not re-checked on the hot path. + */ return sink_get_free_size(sink) / sink_get_frame_bytes(sink); } EXPORT_SYMBOL(sink_get_free_frames); diff --git a/src/module/audio/source_api.c b/src/module/audio/source_api.c index b74a6716b344..6ee2c54ed8d3 100644 --- a/src/module/audio/source_api.c +++ b/src/module/audio/source_api.c @@ -35,6 +35,38 @@ int source_get_data(struct sof_source *source, size_t req_size, } EXPORT_SYMBOL(source_get_data); +int source_get_data_s16(struct sof_source *source, size_t req_size, int16_t const **data_ptr, + int16_t const **buffer_start, int *buffer_samples) +{ + size_t buffer_size; + int ret; + + ret = source_get_data(source, req_size, (void const **)data_ptr, + (void const **)buffer_start, &buffer_size); + if (ret) + return ret; + + *buffer_samples = buffer_size >> 1; + return 0; +} +EXPORT_SYMBOL(source_get_data_s16); + +int source_get_data_s32(struct sof_source *source, size_t req_size, int32_t const **data_ptr, + int32_t const **buffer_start, int *buffer_samples) +{ + size_t buffer_size; + int ret; + + ret = source_get_data(source, req_size, (void const **)data_ptr, + (void const **)buffer_start, &buffer_size); + if (ret) + return ret; + + *buffer_samples = buffer_size >> 2; + return 0; +} +EXPORT_SYMBOL(source_get_data_s32); + int source_release_data(struct sof_source *source, size_t free_size) { int ret; diff --git a/src/platform/CMakeLists.txt b/src/platform/CMakeLists.txt index 8006b8b3caf8..e43c21e1ac0d 100644 --- a/src/platform/CMakeLists.txt +++ b/src/platform/CMakeLists.txt @@ -11,6 +11,8 @@ elseif(CONFIG_IMX8 OR CONFIG_IMX8X) add_subdirectory(imx8) elseif(CONFIG_IMX8M) add_subdirectory(imx8m) +elseif(CONFIG_IMX8M_CM7) + add_subdirectory(imx8m_cm7) elseif(CONFIG_IMX8ULP) add_subdirectory(imx8ulp) elseif(CONFIG_AMD) @@ -21,4 +23,10 @@ elseif(CONFIG_MT8188) add_subdirectory(mt8188) elseif(CONFIG_MT8195) add_subdirectory(mt8195) +elseif(CONFIG_MT8196) + add_subdirectory(mt8196) +elseif(CONFIG_MT8365) + add_subdirectory(mt8365) +elseif(PLATFORM STREQUAL "qemu_xtensa") + add_subdirectory(qemu_xtensa) endif() diff --git a/src/platform/Kconfig b/src/platform/Kconfig index 46f53b10e808..b2576dd2fb21 100644 --- a/src/platform/Kconfig +++ b/src/platform/Kconfig @@ -37,6 +37,20 @@ config PANTHERLAKE help Select if your target platform is Pantherlake-compatible +config WILDCATLAKE + bool "Build for Wildcatlake" + select ACE + select ACE_VERSION_3_0 + help + Select if your target platform is Wildcatlake-compatible + +config NOVALAKE + bool "Build for Novalake" + select ACE + select ACE_VERSION_4_0 + help + Select if your target platform is Novalake-compatible + config LIBRARY bool "Build Library" help @@ -131,6 +145,14 @@ config IMX8M help Select if your target platform is imx8m-compatible +config IMX8M_CM7 + bool "Build for NXP i.MX8MP CM7 core" + select BUILD_OUTPUT_BIN + select HOST_PTABLE + select IMX + help + Select if your target platform is imx8mp-compatible with cm7 core. + config IMX8ULP bool "Build for NXP i.MX8ULP" select XT_HAVE_RESET_VECTOR_ROM @@ -225,10 +247,23 @@ config ACP_7_0 select XT_WAITI_DELAY select XTENSA_EXCLUSIVE select AMD - select SCHEDULE_DMA_MULTI_CHANNEL + select AMD_BINARY_BUILD help Select if your target platform is acp_7_0-compatible +config ACP_7_X + bool "Build for ACP_7_X" + select XT_INTERRUPT_LEVEL_5 + select XT_INTERRUPT_LEVEL_3 + select XT_INTERRUPT_LEVEL_1 + select XT_INTERRUPT_LEVEL_4 + select XT_WAITI_DELAY + select XTENSA_EXCLUSIVE + select AMD + select AMD_BINARY_BUILD + help + Select if your target platform is acp_7_x-compatible + config MT8186 bool "Build for MTK MT8186 (XTOS)" select XT_INTERRUPT_LEVEL_1 @@ -275,30 +310,73 @@ config MT8195 Select if your target platform is mt8195-compatible Builds legacy/xtos firmware +config MT8365 + bool "Build for MTK MT8365" + select XT_INTERRUPT_LEVEL_1 + select XT_INTERRUPT_LEVEL_2 + select XT_INTERRUPT_LEVEL_3 + select DUMMY_DMA + select HOST_PTABLE + select MEDIATEK + select XTENSA_EXCLUSIVE + select SCHEDULE_DMA_MULTI_CHANNEL + help + Select if your target platform is mt8365-compatible + config MTK bool "Build for Mediatek (Zephyr)" - select SCHEDULE_DMA_MULTI_CHANNEL + select SCHEDULE_DMA_MULTI_CHANNEL if !ZEPHYR_NATIVE_DRIVERS select HOST_PTABLE help Select if your target is a Mediatek DSP. Builds Zephyr firmware. +config MT8196 + bool "Build for MTK MT8196" + select XT_INTERRUPT_LEVEL_1 + select XT_INTERRUPT_LEVEL_2 + select XT_INTERRUPT_LEVEL_3 + select XT_INTERRUPT_LEVEL_4 + select DUMMY_DMA + select HOST_PTABLE + select XT_WAITI_DELAY + select MEDIATEK + select XTENSA_EXCLUSIVE + select SCHEDULE_DMA_MULTI_CHANNEL + help + This configuration enables support for the MediaTek MT8196 platform. + It includes necessary interrupt levels, DMA support, and other + platform-specific features required for the proper functioning of + the MT8196 SoC. Enabling this option will ensure that the build + system includes all relevant drivers and configurations for MT8196. + + Select this option if your target platform is MT8196-compatible. + endchoice -config MAX_CORE_COUNT +# +# For non-Zephyr builds like testbench, cmocka and SOF ALSA plugin, +# set core count separately. +# +if !ZEPHYR_SOF_MODULE + +config MP_MAX_NUM_CPUS int - default 5 if LUNARLAKE - default 5 if PANTHERLAKE - default 4 if TIGERLAKE - default 3 if METEORLAKE default 1 help Maximum number of cores per configuration +endif # !ZEPHYR_SOF_MODULE + +config MAX_CORE_COUNT + int + default MP_MAX_NUM_CPUS + help + Maximum number of cores per configuration + config CORE_COUNT int "Number of cores" - default MP_MAX_NUM_CPUS if KERNEL_BIN_NAME = "zephyr" - default MAX_CORE_COUNT - range 1 MAX_CORE_COUNT + default MP_MAX_NUM_CPUS + range 1 MP_MAX_NUM_CPUS help Number of used cores Lowering available core count could result in lower power consumption @@ -311,20 +389,17 @@ config MULTICORE config INTEL bool - default n help This has to be selected for every Intel platform. It enables Intel platforms-specific features. config HOST bool - default n help This has to be selected for building linux test targets. config IMX bool - default n select COMPILER_WORKAROUND_CACHE_ATTR if XTENSA help This has to be selected for every i.MX NXP platform. @@ -332,21 +407,18 @@ config IMX config MEDIATEK bool - default n help This has to be selected for every MediaTek platform. It enables MediaTek platforms-specific features. config AMD bool - default n help This has to be selected for every AMD platform. It enables AMD platforms-specific features. config CAVS bool - default n select INTEL select SOF_ZEPHYR_NO_SOF_CLOCK @@ -358,7 +430,6 @@ config CAVS_VERSION_2_5 config ACE bool - default n select INTEL config ACE_VERSION_1_5 @@ -379,6 +450,12 @@ config ACE_VERSION_3_0 help Select for ACE version 3.0 +config ACE_VERSION_4_0 + depends on ACE + bool + help + Select for ACE version 4.0 + config HP_MEMORY_BANKS int "HP memory banks count" depends on CAVS @@ -407,7 +484,6 @@ config LP_SRAM config L1_DRAM bool "L1 DRAM memory support" - default n help Indicates that platform does support L1 DATA RAM. @@ -430,7 +506,6 @@ config L1_DRAM_MEMORY_BANK_SIZE config CAVS_USE_LPRO_IN_WAITI bool "Use low power ring oscillator in WFI" - default n depends on CAVS help Select if we want to use LPRO clock in waiti. @@ -439,7 +514,6 @@ config CAVS_USE_LPRO_IN_WAITI config KCPS_DYNAMIC_CLOCK_CONTROL bool "Use KCPS budget to determine DSP clock" - default n depends on IPC_MAJOR_4 help Select if we want to use compute budget @@ -447,7 +521,6 @@ config KCPS_DYNAMIC_CLOCK_CONTROL config L3_HEAP bool "Use L3 memory heap" - default n depends on ACE help Select this if L3 memory is supported on the platform and @@ -476,15 +549,20 @@ config RIMAGE_SIGNING_SCHEMA default "imx8" if IMX8 default "imx8x" if IMX8X default "imx8m" if IMX8M + default "imx8m_cm7" if IMX8M_CM7 default "imx8ulp" if IMX8ULP + default "imx95" if IMX95 default "rn" if RENOIR default "rmb" if REMBRANDT default "vangogh" if VANGOGH default "acp_6_3" if ACP_6_3 default "acp_7_0" if ACP_7_0 + default "acp_7_x" if ACP_7_X default "mt8186" if MT8186 default "mt8188" if MT8188 default "mt8195" if MT8195 + default "mt8196" if MT8196 + default "mt8365" if MT8365 default "" help Signing schema name used by rimage to decide how to build final binary @@ -509,7 +587,6 @@ config HAVE_AGENT config AMS bool "Enable Async Messaging Service" - default n depends on IPC_MAJOR_4 help Enables Async Messaging Service. @@ -517,7 +594,6 @@ config AMS config AGENT_PANIC_ON_DELAY bool "Enable system agent time verification panic" - default n depends on HAVE_AGENT help Enables system agent time verification panic. @@ -526,7 +602,6 @@ config AGENT_PANIC_ON_DELAY config XTENSA_EXCLUSIVE bool - default n help This has to be selected for xtensa exclusive instructions. There is a definition for EXCLUSIVE option in xtensa-config.h @@ -534,7 +609,7 @@ config XTENSA_EXCLUSIVE config FORCE_DMA_COPY_WHOLE_BLOCK bool default y if MT8195 - default n + default y if MT8365 depends on HOST_PTABLE help The host component forces DMA to copy the block size to avoid @@ -561,7 +636,6 @@ if XTENSA config INCOHERENT bool "Enable cached data access via the Coherent API" default y if CAVS || ACE - default n help The architecture is cache incoherent. i.e FW has to manually manage cache coherency amongst objects that are used on multiple cores. @@ -572,7 +646,6 @@ endif config LL_WATCHDOG bool "Enable watchdog support in ll scheduler" - default n depends on ACE help Select if you want to protect ll scheduler with a watchdog timer. diff --git a/src/platform/ace30/include/platform/lib/memory.h b/src/platform/ace30/include/platform/lib/memory.h index dab9d94c062a..70888798e22a 100644 --- a/src/platform/ace30/include/platform/lib/memory.h +++ b/src/platform/ace30/include/platform/lib/memory.h @@ -11,9 +11,7 @@ #define __PLATFORM_LIB_MEMORY_H__ /* prioritize definitions in Zephyr SoC layer */ -#ifdef __ZEPHYR__ #include <adsp_memory.h> -#endif #include <ace/lib/memory.h> #include <mem_window.h> @@ -56,7 +54,7 @@ /** * size of HPSRAM system heap */ -#define HEAPMEM_SIZE 0xD0000 +#define HEAPMEM_SIZE CONFIG_SOF_ZEPHYR_HEAP_SIZE #if CONFIG_COLD_STORE_EXECUTE_DRAM && \ (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE || !defined(LL_EXTENSION_BUILD)) diff --git a/src/platform/amd/CMakeLists.txt b/src/platform/amd/CMakeLists.txt index 5b971f6e4b9e..9ae93911168d 100644 --- a/src/platform/amd/CMakeLists.txt +++ b/src/platform/amd/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause -add_subdirectory(common) +if(CONFIG_RENOIR OR CONFIG_VANGOGH OR CONFIG_REMBRANDT OR CONFIG_ACP_6_3 OR CONFIG_ACP_7_0) + add_subdirectory(common) +endif() if(CONFIG_RENOIR) add_subdirectory(renoir) elseif(CONFIG_REMBRANDT) @@ -10,4 +12,6 @@ elseif(CONFIG_ACP_6_3) add_subdirectory(acp_6_3) elseif(CONFIG_ACP_7_0) add_subdirectory(acp_7_0) +elseif(CONFIG_ACP_7_X) + add_subdirectory(acp_7_x) endif() diff --git a/src/platform/amd/acp_6_3/include/platform/lib/memory.h b/src/platform/amd/acp_6_3/include/platform/lib/memory.h index 2597b0858715..2b4fc43e6322 100644 --- a/src/platform/amd/acp_6_3/include/platform/lib/memory.h +++ b/src/platform/amd/acp_6_3/include/platform/lib/memory.h @@ -165,11 +165,6 @@ struct sof; #define SHARED_DATA void platform_init_memmap(struct sof *sof); -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - static inline void *platform_rfree_prepare(void *ptr) { return ptr; diff --git a/src/platform/amd/acp_6_3/lib/clk.c b/src/platform/amd/acp_6_3/lib/clk.c index 5a735d4241fa..f060aafc22c6 100644 --- a/src/platform/amd/acp_6_3/lib/clk.c +++ b/src/platform/amd/acp_6_3/lib/clk.c @@ -191,7 +191,7 @@ void acp_change_clock_notify(uint32_t clock_freq) acp_6_3_get_boot_ref_clock(&boot_ref_clk); - tr_info(&acp_clk_tr, "acp_change_clock_notify clock_freq : %d clock_type : %d", + tr_info(&acp_clk_tr, "clock_freq : %d clock_type : %d", clock_freq, clock_type); fraction_val = (float)(clock_freq / (float)1000000.0f); @@ -212,7 +212,7 @@ void acp_change_clock_notify(uint32_t clock_freq) bypass_cntl.bitfields.CLK1_BYPASS_DIV = 0xF; } else { did = (float)(boot_ref_clk / (float)fraction_val); - tr_info(&acp_clk_tr, "acp_change_clock_notify CLK Divider : %d boot_ref_clk : %d\n", + tr_info(&acp_clk_tr, "CLK Divider : %d boot_ref_clk : %d\n", (uint32_t)(did * 100), (uint32_t)boot_ref_clk); if (did > 62.0f) { @@ -251,7 +251,7 @@ void acp_change_clock_notify(uint32_t clock_freq) do { dfs_status.u32all = acp_reg_read_via_smn(CLK5_CLK1_DFS_STATUS, sizeof(int)); - tr_info(&acp_clk_tr, "acp_change_clock_notify ACLK1 CLK1_DIVIDER : %d dfsstatus %d ", + tr_info(&acp_clk_tr, "ACLK1 CLK1_DIVIDER : %d dfsstatus %d ", dfs_cntl.u32all, dfs_status.u32all); } while (dfs_status.bitfields.CLK1_DFS_DIV_REQ_IDLE == 0); updated_clk = acp_reg_read_via_smn(CLK5_CLK1_CURRENT_CNT, sizeof(int)); @@ -268,7 +268,7 @@ void acp_change_clock_notify(uint32_t clock_freq) dfs_cntl.u32all = acp_reg_read_via_smn(CLK5_CLK1_DFS_CNTL, sizeof(int)); - tr_info(&acp_clk_tr, "acp_change_clock_notify ACLK2 CLK1_DIVIDER:%d dfsstatus %d ", + tr_info(&acp_clk_tr, "ACLK2 CLK1_DIVIDER:%d dfsstatus %d ", dfs_cntl.u32all, dfs_status.u32all); } while (dfs_status.bitfields.CLK1_DFS_DIV_REQ_IDLE == 0); } @@ -281,7 +281,7 @@ void acp_change_clock_notify(uint32_t clock_freq) do { dfs_status.u32all = acp_reg_read_via_smn(CLK5_CLK0_DFS_STATUS, sizeof(int)); - tr_info(&acp_clk_tr, "acp_change_clock_notify SCLK CLK1_DIVIDER: %d", + tr_info(&acp_clk_tr, "SCLK CLK1_DIVIDER: %d", dfs_cntl.u32all); } while (dfs_status.bitfields.CLK1_DFS_DIV_REQ_IDLE == 0); diff --git a/src/platform/amd/acp_6_3/platform.c b/src/platform/amd/acp_6_3/platform.c index 753073a4dcb0..e0b1f2b8fe9f 100644 --- a/src/platform/amd/acp_6_3/platform.c +++ b/src/platform/amd/acp_6_3/platform.c @@ -173,7 +173,7 @@ int platform_init(struct sof *sof) /* Initialize DMA for Trace*/ trace_point(TRACE_BOOT_PLATFORM_DMA_TRACE); sof->dmat->config.elem_array.elems = - rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(struct dma_sg_elem) * 1); sof->dmat->config.elem_array.count = 1; sof->dmat->config.elem_array.elems->dest = 0x03800000; diff --git a/src/platform/amd/acp_7_0/include/arch/xtensa/config/tie-asm.h b/src/platform/amd/acp_7_0/include/arch/xtensa/config/tie-asm.h index 86df964b4628..5e31df65fca0 100644 --- a/src/platform/amd/acp_7_0/include/arch/xtensa/config/tie-asm.h +++ b/src/platform/amd/acp_7_0/include/arch/xtensa/config/tie-asm.h @@ -182,7 +182,7 @@ .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) xchal_sa_align \ptr, 0, 0, 16, 16 ae_s64.i aed0, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_s64.i aed1, \ptr, .Lxchal_ofs_+0 ae_s64.i aed2, \ptr, .Lxchal_ofs_+8 ae_s64.i aed3, \ptr, .Lxchal_ofs_+16 @@ -191,7 +191,7 @@ ae_s64.i aed6, \ptr, .Lxchal_ofs_+40 ae_s64.i aed7, \ptr, .Lxchal_ofs_+48 ae_s64.i aed8, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_s64.i aed9, \ptr, .Lxchal_ofs_+0 ae_s64.i aed10, \ptr, .Lxchal_ofs_+8 ae_s64.i aed11, \ptr, .Lxchal_ofs_+16 @@ -200,7 +200,7 @@ ae_s64.i aed14, \ptr, .Lxchal_ofs_+40 ae_s64.i aed15, \ptr, .Lxchal_ofs_+48 ae_s64.i aed16, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_s64.i aed17, \ptr, .Lxchal_ofs_+0 ae_s64.i aed18, \ptr, .Lxchal_ofs_+8 ae_s64.i aed19, \ptr, .Lxchal_ofs_+16 @@ -209,7 +209,7 @@ ae_s64.i aed22, \ptr, .Lxchal_ofs_+40 ae_s64.i aed23, \ptr, .Lxchal_ofs_+48 ae_s64.i aed24, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_s64.i aed25, \ptr, .Lxchal_ofs_+0 ae_s64.i aed26, \ptr, .Lxchal_ofs_+8 ae_s64.i aed27, \ptr, .Lxchal_ofs_+16 @@ -225,12 +225,12 @@ s8i \at1, \ptr, .Lxchal_ofs_+58 ae_movae \at1, aep3 s8i \at1, \ptr, .Lxchal_ofs_+59 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_salign128.i u0, \ptr, .Lxchal_ofs_+0 ae_salign128.i u1, \ptr, .Lxchal_ofs_+16 ae_salign128.i u2, \ptr, .Lxchal_ofs_+32 ae_salign128.i u3, \ptr, .Lxchal_ofs_+48 - addi.a \ptr, \ptr, -320 + addi \ptr, \ptr, -320 ae_movdrzbvc aed0 // ureg AE_ZBIASV8C ae_s64.i aed0, \ptr, .Lxchal_ofs_+0 + 0 ae_movvfcrfsr aed0 // ureg FCR_FSR @@ -302,7 +302,7 @@ l32i \at1, \ptr, .Lxchal_ofs_+52 wur.ae_cend2 \at1 // ureg 251 ae_l64.i aed0, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_l64.i aed1, \ptr, .Lxchal_ofs_+0 ae_l64.i aed2, \ptr, .Lxchal_ofs_+8 ae_l64.i aed3, \ptr, .Lxchal_ofs_+16 @@ -311,7 +311,7 @@ ae_l64.i aed6, \ptr, .Lxchal_ofs_+40 ae_l64.i aed7, \ptr, .Lxchal_ofs_+48 ae_l64.i aed8, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_l64.i aed9, \ptr, .Lxchal_ofs_+0 ae_l64.i aed10, \ptr, .Lxchal_ofs_+8 ae_l64.i aed11, \ptr, .Lxchal_ofs_+16 @@ -320,7 +320,7 @@ ae_l64.i aed14, \ptr, .Lxchal_ofs_+40 ae_l64.i aed15, \ptr, .Lxchal_ofs_+48 ae_l64.i aed16, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_l64.i aed17, \ptr, .Lxchal_ofs_+0 ae_l64.i aed18, \ptr, .Lxchal_ofs_+8 ae_l64.i aed19, \ptr, .Lxchal_ofs_+16 @@ -329,7 +329,7 @@ ae_l64.i aed22, \ptr, .Lxchal_ofs_+40 ae_l64.i aed23, \ptr, .Lxchal_ofs_+48 ae_l64.i aed24, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_l64.i aed25, \ptr, .Lxchal_ofs_+0 ae_l64.i aed26, \ptr, .Lxchal_ofs_+8 ae_l64.i aed27, \ptr, .Lxchal_ofs_+16 @@ -337,7 +337,7 @@ ae_l64.i aed29, \ptr, .Lxchal_ofs_+32 ae_l64.i aed30, \ptr, .Lxchal_ofs_+40 ae_l64.i aed31, \ptr, .Lxchal_ofs_+48 - addi.a \ptr, \ptr, 56 + addi \ptr, \ptr, 56 l8ui \at1, \ptr, .Lxchal_ofs_+0 ae_movea aep0, \at1 l8ui \at1, \ptr, .Lxchal_ofs_+1 @@ -346,7 +346,7 @@ ae_movea aep2, \at1 l8ui \at1, \ptr, .Lxchal_ofs_+3 ae_movea aep3, \at1 - addi.a \ptr, \ptr, 8 + addi \ptr, \ptr, 8 ae_lalign128.i u0, \ptr, .Lxchal_ofs_+0 ae_lalign128.i u1, \ptr, .Lxchal_ofs_+16 ae_lalign128.i u2, \ptr, .Lxchal_ofs_+32 diff --git a/src/platform/amd/acp_7_0/include/arch/xtensa/config/tie.h b/src/platform/amd/acp_7_0/include/arch/xtensa/config/tie.h index 4c451a6af2c1..cd55d1d3028c 100644 --- a/src/platform/amd/acp_7_0/include/arch/xtensa/config/tie.h +++ b/src/platform/amd/acp_7_0/include/arch/xtensa/config/tie.h @@ -32,6 +32,10 @@ #ifndef XTENSA_CORE_TIE_H #define XTENSA_CORE_TIE_H +#ifndef UINT32_C +#define UINT32_C(x) x +#endif + /* parasoft-begin-suppress ALL "This file not MISRA checked." */ #define XCHAL_CP_NUM UINT32_C(1) /* number of coprocessors */ diff --git a/src/platform/amd/acp_7_0/include/arch/xtensa/idma.h b/src/platform/amd/acp_7_0/include/arch/xtensa/idma.h new file mode 100644 index 000000000000..5ba0e82d3c10 --- /dev/null +++ b/src/platform/amd/acp_7_0/include/arch/xtensa/idma.h @@ -0,0 +1,3775 @@ +/* + * Copyright (c) 2018-2023 Cadence Design Systems. ALL RIGHTS RESERVED. + * + * 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. + */ + +#ifndef IDMA_H__ +#define IDMA_H__ + +#include <xtensa/hal.h> +#include <xtensa/xtensa-types.h> +#include <xtensa/config/core-isa.h> +#if XCHAL_HAVE_EXTERN_REGS +#include <xtensa/tie/xt_externalregisters.h> +#endif + + +#ifndef XCHAL_IDMA_ADDR_WIDTH +# define XCHAL_IDMA_ADDR_WIDTH 32 +#endif + +/* If HAL doesn't define # of channels macro, need to set to 1 */ +#ifndef XCHAL_IDMA_NUM_CHANNELS +# define XCHAL_IDMA_NUM_CHANNELS 1 +#endif + +/* User enabled multichannel mode - use LIBIDMA_USE_MULTICHANNEL */ +#if (defined IDMA_USE_MULTICHANNEL) +# define LIBIDMA_USE_MULTICHANNEL 1 +#else +# define LIBIDMA_USE_MULTICHANNEL 0 +#endif + +/* Use multichannels only if user-enabled */ +#if (LIBIDMA_USE_MULTICHANNEL > 0) +# define LIBIDMA_USE_MULTICHANNEL_API 1 +#else +# define LIBIDMA_USE_MULTICHANNEL_API 0 +#endif + +/* Enable large (64-byte) descriptor API if the hardware supports it. */ +#if (XCHAL_IDMA_DESC_SIZE == 64) +# define IDMA_USE_64B_DESC 1 +# define IDMA_HAVE_LARGE_DESC 1 +# define IDMA_HAVE_3D 1 +#else +# define IDMA_USE_64B_DESC 0 +# define IDMA_HAVE_LARGE_DESC 0 +# define IDMA_HAVE_3D 0 +#endif + +/* Enable wide address API if the hardware supports it. */ +#if (XCHAL_IDMA_ADDR_WIDTH > 32) && (XCHAL_IDMA_ADDR_WIDTH <= 64) +# define IDMA_USE_WIDE_API 1 +# define IDMA_HAVE_WIDE_API 1 +#else +# define IDMA_USE_WIDE_API 0 +# define IDMA_HAVE_WIDE_API 0 +#endif + +#if (IDMA_USE_64B_DESC == 0) && (IDMA_USE_WIDE_API > 0) +/* #error "IDMA_USE_WIDE_API requires a config that supports 64-byte descriptors" */ +#endif + +/* This is INTERNAL. Need to be here as headers use it */ +#define PSO_SAVE_SIZE_PER_CHANNEL 6 +#define IDMA_PSO_SAVE_SIZE PSO_SAVE_SIZE_PER_CHANNEL*XCHAL_IDMA_NUM_CHANNELS + + +// For the old 2-channel implementation, ch0 and ch1 are at different +// base addresses. For the newer implementation, all the channels can +// be accessed at either of the two base addresses. We choose to use +// the first (device1) base address. +#if (XCHAL_IDMA_NUM_CHANNELS == 2) && (IDMA_USE_64B_DESC == 0) +#if XCHAL_HAVE_XEA2 || XCHAL_HAVE_XEA3 +#if defined(IDMA_USERMODE) +# define IDMAREG_BASE_CH0 UINT32_C(0x00910000) +# define IDMAREG_BASE_CH1 UINT32_C(0x00930400) +#else +# define IDMAREG_BASE_CH0 UINT32_C(0x00110000) +# define IDMAREG_BASE_CH1 UINT32_C(0x00130400) +#endif +# define IDMAREG_BASE(n) (((n) == 0U) ? (IDMAREG_BASE_CH0) : (IDMAREG_BASE_CH1)) +#else +# define IDMAREG_BASE_CH0 IDMA_CHAN_ADDR(0) +# define IDMAREG_BASE_CH1 IDMA_CHAN_ADDR(1) +# define IDMAREG_BASE(n) IDMA_CHAN_ADDR(n) +#endif +#else +#if defined(IDMA_USERMODE) +# define IDMAREG_BASE_SDEV1 UINT32_C(0x00910000) +#else +# define IDMAREG_BASE_SDEV1 UINT32_C(0x00110000) +#endif +# define IDMAREG_BASE(n) (IDMAREG_BASE_SDEV1 + ((UINT32_C(0x400)) * (n))) +#endif + +/* iDMA registers offsets */ +#define IDMA_REG_SETTINGS 0x00 +#define IDMA_REG_TIMEOUT 0x04 +#define IDMA_REG_DESC_START 0x08 +#define IDMA_REG_NUM_DESC 0x0C +#define IDMA_REG_DESC_INC 0x10 +#define IDMA_REG_CONTROL 0x14 +#define IDMA_REG_USERPRIV 0x18 +#define IDMA_REG_STATUS 0x40 +#define IDMA_REG_CURR_DESC 0x44 +#define IDMA_REG_DESC_TYPE 0x48 +#define IDMA_REG_SRC_ADDR 0x4C +#define IDMA_REG_DST_ADDR 0x50 + +// PSO status, after core save/restore +// Value at IDMA_PSO_STATUS_OFFSET from at XtosSaveState.idmaregs +// will indicate if idma HW was idle prior to save, so save was +// skipped, or there was forced iDMA HW disable, or save was done. +#define IDMA_PSO_STATUS_OFFSET 5 +#define IDMA_PSO_STATUS_SAVED 0x1 +#define IDMA_PSO_STATUS_DISABLED 0x2 +#define IDMA_PSO_STATUS_IDLE 0x3 + +#if !defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__) + +#include <stdint.h> +#include <stddef.h> +#include <time.h> + +/* Typedef for internal use (required by idma_os.h) */ +typedef struct idma_buf_struct idma_buf_t; + +/* libidma internal buffer ptr, used in Fixed-Buffer mode */ +extern idma_buf_t * g_idma_buf_ptr[XCHAL_IDMA_NUM_CHANNELS]; + +#if defined(IDMA_USERMODE) +#undef IDMA_USE_INTR /* parasoft-suppress MISRA2012-RULE-20_5-4 "Not defined by library" */ +#define IDMA_USE_INTR 0 +#define IDMA_USE_XTOS 1 +#define IDMA_APP_USE_XTOS 1 +#endif + +/** + * Use inline XTOS interface if application defines IDMA_APP_USE_XTOS or + * library build defines IDMA_USE_XTOS. Else use libidma OS interface. + * Both are defined in idma_os.h. + */ +#include "idma_os.h" /* parasoft-suppress MISRA2012-RULE-20_1-4 "This has to follow idma_buf_t" */ + + +/** + * Use interrupts in APIs defined in the header. Default is to use interrupts. + * Overhead of enabling/disabling interrupts to guard shared structs + */ +#if !defined(IDMA_USE_INTR) +#define IDMA_USE_INTR 1 +#endif + +/******************************************************/ +/**** Initialization flags, types, defines ****/ +/******************************************************/ + +/** + * iDMAlib and iDMA HW operation flags, for idma_init() 1st arg. + */ +#define IDMA_OCD_HALT_ON 0x001 /* Enable iDMA halt on OCD interrupt. */ + +/** +* Type of descriptor to add. NOTE: value reflects multiple of 16B. +*/ +typedef enum { + IDMA_1D_DESC = 1, + IDMA_2D_DESC = 2, + IDMA_64B_DESC = 4 +} idma_type_t; + +/** + * Maximum allowed PIF request block size. + */ +typedef enum { + MAX_BLOCK_2 = 0, + MAX_BLOCK_4 = 1, + MAX_BLOCK_8 = 2, + MAX_BLOCK_16 = 3 +} idma_max_block_t; + +/** + * TICK_CYCLES_N: iDMA HW internal timer ticks every N cycles. + */ +typedef enum { +TICK_CYCLES_1 = 0, /* internal timer ticks every 1 cycle */ +TICK_CYCLES_2 = 1, /* internal timer ticks every 2 cycles */ +TICK_CYCLES_4 = 2, +TICK_CYCLES_8 = 3, +TICK_CYCLES_16 = 4, +TICK_CYCLES_32 = 5, +TICK_CYCLES_64 = 6, +TICK_CYCLES_128 = 7 +} idma_ticks_cyc_t; + +/** + * "Descriptor Control Flags" for any type of descriptor + * This sets the idma descriptor control field - see HW description. + */ +#define DESC_IDMA_NOPRIV_SRC 0x00200 /* Non-privileged source memory access */ +#define DESC_IDMA_NOPRIV_DST 0x00800 /* Non-privileged dest. memory access */ +#define DESC_IDMA_PRIOR_H 0x08000 /* QoS high */ +#define DESC_IDMA_PRIOR_L 0x00000 /* QoS low */ +#define DESC_IDMA_TRIG_WAIT 0x20000000 /* wait for external trigger to start */ +#define DESC_IDMA_TRIG_OUT 0x40000000 /* send trigger out on desc. completion */ +#define DESC_NOTIFY_W_INT 0x80000000 /* trigger interrupt on completion */ +//* "Descriptor Control Flags" for new 64-Byte descriptors only. +#define DESC64_IDMA_OVERLAP 0x00000008 /* Overlap Bit (bit 3) */ +#define DESC64_IDMA_LONG_ADDR 0x00000400 /* LA – Long Address (bit 10) */ + +// "Descriptor Control Flags" AXI attribute bits for 64-byte descriptors. +// These go into bits 27:24 of the descriptor control word. +#define DESC64_IDMA_AXI_ATTRIBUTE(val) (((val) & 0xF) << 24) + +/** + * iDMA API return values + * For most of the iDMAlib API calls + */ +typedef enum { + IDMA_ERR_NO_BUF = -40, /* No valid ring buffer */ + IDMA_ERR_BAD_DESC = -20, /* Descriptor not correct */ + IDMA_ERR_BAD_CHAN, /* Invalid channel number */ + IDMA_ERR_NOT_INIT, /* iDMAlib and HW not initialized */ + IDMA_ERR_TASK_NOT_INIT, /* Cannot scheduled uninitialized task */ + IDMA_ERR_BAD_TASK, /* Task not correct */ + IDMA_ERR_BUSY, /* iDMA busy when not expected */ + IDMA_ERR_IN_SPEC_MODE, /* iDMAlib in unexpected mode */ + IDMA_ERR_NOT_SPEC_MODE, /* iDMAlib in unexpected mode */ + IDMA_ERR_TASK_EMPTY, /* No descs in the task/buffer */ + IDMA_ERR_TASK_OUTSTAND_NEG, /* Number of outstanding descs is a negative value */ + IDMA_ERR_TASK_IN_ERROR, /* Task in error */ + IDMA_ERR_BUFFER_IN_ERROR, /* Buffer in error */ + IDMA_ERR_NO_NEXT_TASK, /* Next task to process is missing */ + IDMA_ERR_BUF_OVFL, /* Attempt to schedule too many descriptors */ + IDMA_ERR_HW_ERROR, /* HW error detected */ + IDMA_ERR_BAD_INIT, /* Bad idma_init args */ + IDMA_ERR_UNSUP, /* Not supported in current configuration/mode */ + IDMA_OK = 0, /* No error */ + IDMA_CANT_SLEEP = 1, /* Cannot sleep (no pending descriptors) */ +} idma_status_t; + +/** + * iDMA task status API return values + * NOTE: Valid only after task is scheduled + * + * N (>=0) - Number of outstanding scheduled descriptors. + * 0 (IDMA_TASK_DONE) - Whole task has completed the execution. + * IDMA_TASK_ERROR - iDMA HW error happened due to a descriptor executed + * from this task. Error details are available (idma_hw_error_t). + * IDMA_TASK_ABORTED - Task forcefully aborted. + */ +typedef enum { + IDMA_TASK_ABORTED = -3, + IDMA_TASK_ERROR = -2, + IDMA_TASK_NOINIT = -1, + IDMA_TASK_DONE = 0, + IDMA_TASK_EMPTY = 0 +} task_status_t; + +/** + * iDMA HW error details API return values + * This corresponds to the Error Codes field + * of the HW Status register. + */ +#if XCHAL_HAVE_XEA2 +#define IDMA_ERR_FETCH_ADDR UINT32_C(0x2000) +#define IDMA_ERR_FETCH_DATA UINT32_C(0x1000) +#define IDMA_ERR_READ_ADDR UINT32_C(0x0800) +#define IDMA_ERR_READ_DATA UINT32_C(0x0400) +#define IDMA_ERR_WRITE_ADDR UINT32_C(0x0200) +#define IDMA_ERR_WRITE_DATA UINT32_C(0x0100) +#define IDMA_ERR_REG_TIMEOUT UINT32_C(0x0080) +#define IDMA_ERR_TRIG_OVFL UINT32_C(0x0040) +#define IDMA_ERR_DESC_OVFL UINT32_C(0x0020) +#define IDMA_ERR_DESC_UNKNW UINT32_C(0x0010) +#define IDMA_ERR_DESC_UNSUP_DIR UINT32_C(0x0008) +#define IDMA_ERR_DESC_BAD_PARAMS UINT32_C(0x0004) +#define IDMA_ERR_DESC_NULL_ADDR UINT32_C(0x0002) +#define IDMA_ERR_DESC_PRIVILEGE UINT32_C(0x0001) +#define IDMA_NO_ERR UINT32_C(0x0000) +#else +#define IDMA_ERR_FETCH_ADDR UINT32_C(0x80000) +#define IDMA_ERR_FETCH_DATA UINT32_C(0x40000) +#define IDMA_ERR_READ_ADDR UINT32_C(0x20000) +#define IDMA_ERR_READ_DATA UINT32_C(0x10000) +#define IDMA_ERR_WRITE_ADDR UINT32_C(0x08000) +#define IDMA_ERR_WRITE_DATA UINT32_C(0x04000) +#define IDMA_ERR_REG_TIMEOUT UINT32_C(0x02000) +#define IDMA_ERR_TRIG_OVFL UINT32_C(0x01000) +#define IDMA_ERR_DESC_OVFL UINT32_C(0x00800) +#define IDMA_ERR_DESC_UNKNW UINT32_C(0x00400) +#define IDMA_ERR_DESC_UNSUP_DIR UINT32_C(0x00200) +#define IDMA_ERR_DESC_BAD_PARAMS UINT32_C(0x00100) +#define IDMA_ERR_DESC_NULL_ADDR UINT32_C(0x00080) +#define IDMA_ERR_DESC_PRIVILEGE UINT32_C(0x00040) +#define IDMA_ERR_DESC_MMUMPU UINT32_C(0x00020) +#define IDMA_ERR_BIT_VECT UINT32_C(0x00010) +#define IDMA_ERR_VECT_OTHER UINT32_C(0x00008) +#define IDMA_ERR_VECT_DATA UINT32_C(0x00004) +#define IDMA_ERR_SRC_MMUMPU UINT32_C(0x00002) +#define IDMA_ERR_DST_MMUMPU UINT32_C(0x00001) +#define IDMA_NO_ERR UINT32_C(0x00000) +#endif + +typedef uint32_t idma_hw_error_t; + +/* Status reg fields */ +#define IDMA_STATE_IDLE UINT32_C(0x0) //idma done with all descriptors and disabled +#define IDMA_STATE_STANDBY UINT32_C(0x1) //transient stat +#define IDMA_STATE_BUSY UINT32_C(0x2) //idma busy copying +#define IDMA_STATE_DONE UINT32_C(0x3) //idma done with all descriptors but enabled +#define IDMA_STATE_HALT UINT32_C(0x4) //idma disabled during copy operation +#define IDMA_STATE_ERROR UINT32_C(0x5) //idma in error +#define IDMA_STATE_MASK UINT32_C(0x7) + +typedef uint32_t idma_state_t; + +# ifdef IDMA_DEBUG +# define INTERNAL_FUNC static +# else +# define INTERNAL_FUNC static inline +# endif + +/* No inlining for debug libs */ +#ifdef IDMA_LIB_BUILD +# define IDMA_API static inline +#else +# define IDMA_API INTERNAL_FUNC +#endif + +#define ALWAYS_INLINE __attribute__((always_inline)) static inline + +#ifndef IDMA_EXTERN +# define IDMA_EXTERN +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * iDMA error details structure - available from different API calls + */ +typedef struct idma_error_details_struct { + idma_hw_error_t err_type; /* ErrorCodes field of the Status reg */ + uint32_t currDesc; /* Descriptor causing error */ + uint32_t srcAddr; /* PIF source address causing error */ + uint32_t dstAddr; /* PIF dest. address causing error */ +} idma_error_details_t; + +/* callback typedef */ +typedef void (*idma_callback_fn)( void* arg); +/* error callback typedef */ +typedef void (*idma_err_callback_fn)( const idma_error_details_t* error); +/* log handler typedef */ +typedef void (*idma_log_h)( const char* xlog); + +/* Typedef for external API use */ +typedef struct idma_buffer_struct { + char buffer[4]; +} idma_buffer_t; + +/* allocate space for n descriptors of type idma_type_t. */ +#define IDMA_BUFFER_SIZE(n,type) \ + ( ((n)* (((type) == IDMA_1D_DESC) ? IDMA_1D_DESC_SIZE : (((type) == IDMA_2D_DESC) ? IDMA_2D_DESC_SIZE : IDMA_64_DESC_SIZE))) + \ + sizeof(struct idma_buf_struct)) + +/* Define a buffer of containing n descriptors of type n */ +#define IDMA_BUFFER_DEFINE(name, n, type) \ + IDMA_DRAM idma_buffer_t name[IDMA_BUFFER_SIZE((n), (type))/sizeof(idma_buffer_t)] + +/* Use these macros when allocating copy buffers to avoid sharing cache lines */ +#define IDMA_DCACHE_ALIGN (XCHAL_DCACHE_LINESIZE << XCHAL_DCACHE_LINES_PER_TAG_LOG2) + +/* Align to dcache line */ +#define ALIGNDCACHE __attribute__ ((aligned(IDMA_DCACHE_ALIGN))) + +/* Buffer size will be rounded to the cache alignment so it occupies the whole cache line */ +#define IDMA_SIZE(N) (((N) + IDMA_DCACHE_ALIGN-1) & -IDMA_DCACHE_ALIGN) + +/* These macros are empty if no interrupts. Otherwise, they map to OS provided + * functions that are defined in idma-xtos.h or idma-os.h. The XTOS versions + * will get inlined for performance. + */ +#if defined XCHAL_HAVE_INTERRUPTS && (IDMA_USE_INTR > 0) +# define DECLARE_PS() uint32_t ps +# define IDMA_ENABLE_INTS() idma_enable_interrupts(ps) +# define IDMA_DISABLE_INTS() ps = idma_disable_interrupts() +#else //no interrupts +# define DECLARE_PS() do {} while (0) +# define IDMA_ENABLE_INTS() do {} while (0) +# define IDMA_DISABLE_INTS() do {} while (0) +#endif + +/*************************************************/ +/** Forward declarations for internal stuff **/ +/*************************************************/ +typedef struct idma_desc_struct idma_desc_t; +typedef struct idma_2d_desc_struct idma_2d_desc_t; +typedef struct idma_desc64_struct idma_desc64_t; + +/************************************************/ +/**** MISC HELPER FUNCTIONS ****/ +/************************************************/ + +ALWAYS_INLINE void * +cvt_uint32_to_voidp(uint32_t val) +{ + return (void *) val; // parasoft-suppress MISRA2012-RULE-11_6-2 "Type conversion necessary." +} + +ALWAYS_INLINE uint32_t +cvt_voidp_to_uint32(void * val) // parasoft-suppress MISRA2012-RULE-8_13_a-4 "Cannot use const because of type conversion." +{ + return (uint32_t) val; // parasoft-suppress MISRA2012-RULE-11_6-2 "Type conversion necessary." +} + +ALWAYS_INLINE void * +cvt_uint32p_to_voidp(uint32_t * val) // parasoft-suppress MISRA2012-RULE-8_13_a-4 "Cannot use const because of type conversion." +{ + return (void *) val; +} + +ALWAYS_INLINE uint32_t * +cvt_voidp_to_uint32p(void * val) // parasoft-suppress MISRA2012-RULE-8_13_a-4 "Cannot use const because of type conversion." +{ + return (uint32_t *) val; // parasoft-suppress MISRA2012-RULE-11_5-4 "Type conversion necessary." +} + +ALWAYS_INLINE void * +cvt_int32_to_voidp(int32_t val) +{ + return (void *) val; // parasoft-suppress MISRA2012-RULE-11_6-2 "Type conversion necessary." +} + +ALWAYS_INLINE int32_t +cvt_voidp_to_int32(void * val) // parasoft-suppress MISRA2012-RULE-8_13_a-4 "Cannot use const because of type conversion." +{ + return (int32_t) val; // parasoft-suppress MISRA2012-RULE-11_6-2 "Type conversion necessary." +} + +ALWAYS_INLINE idma_desc64_t * +cvt_desc_to_desc64(idma_desc_t * val) // parasoft-suppress MISRA2012-RULE-8_13_a-4 "Cannot use const because of type conversion." +{ + return (idma_desc64_t *) val; // parasoft-suppress MISRA2012-RULE-11_3-2 MISRA2012-RULE-11_2-2 "Type conversion necessary." +} + +/************************************************/ +/**** API ****/ +/************************************************/ + +/* NOTE NOTE NOTE: + * Have to define LIBIDMA_USE_MULTICHANNEL if want to use the multichannel API. + * The new API basically adds the channel argument to the most of the old functions. + * See below, #else part, for the old API. Also, each function descriptions mentions + * if an argument is not present in the old API. + */ +#if (LIBIDMA_USE_MULTICHANNEL_API > 0) + +/** + * @name Wait for all descriptors to finish, by polling only the HW + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @retval None + */ +IDMA_API void +idma_hw_wait_all(int32_t ch); + +/** + * @name Schedule a number of descriptors, by accessing HW only. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param count Number of descriptors to schedule. + * @retval None + */ +IDMA_API void +idma_hw_schedule(int32_t ch, uint32_t count); + +/** + * @name Return number of outstanding descriptor, as indicated by HW + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @retval number of outstanding descriptor + */ +IDMA_API uint32_t +idma_hw_num_outstanding(int32_t ch); + +/** + * @name iDMAlib and iDMA HW initialization + * @brief Does iDMA HW soft reset, sets iDMAlib parameters and sets + * iDMA HW registers (Settings/Timeout) with given parameters. + * @param ch Selected. iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param flags iDMAlib initialization flags, above. + * @param block_sz idma_max_block_t above. + * @param pif_req Maximum outstanding PIF requests (1-64). + * @param ticks_per_cyc Ticks per cycle. See iDMA hardware details. + * @param timeout_ticks Timeout ticks. See iDMA hardware details. + * @param err_cb_func Register global error handler. Called on idma HW + * error detection for which intr is always enabled. + * @retval IDMA_OK Successful + * @retval !IDMA_OK Error type + */ +IDMA_API idma_status_t +idma_init( int32_t ch, + uint32_t flags, + idma_max_block_t block_sz, + uint32_t pif_req, + idma_ticks_cyc_t ticks_per_cyc, + uint32_t timeout_ticks, + idma_err_callback_fn err_cb_func); + +/** + * @name Enable fast-wake mode for all channels. + * @brief Enables fast wakeup from WAITI for all channels. All channels + * must be not busy and not in error state. + * @retval IDMA_OK Successful + * @retval IDMA_ERR_BUSY At least one channel was busy or in error + * @retval IDMA_ERR_UNSUP Not supported in this configuration + */ +idma_status_t +idma_fast_wake_enable(void); + +/** + * @name Disable fast-wake mode for all channels. + * @brief Disables fast wakeup from WAITI for all channels. All channels + * must be not busy and not in error state. + * @retval IDMA_OK Successful + * @retval IDMA_ERR_BUSY At least one channel was busy or in error + * @retval IDMA_ERR_UNSUP Not supported in this configuration + */ +idma_status_t +idma_fast_wake_disable(void); + +/** + * @name Check the state of idma HW. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + */ +IDMA_API idma_state_t +idma_get_state(int32_t ch); + +/** + * @name Add log messages handler. + * @brief Log messages from iDMAlib are sent to this handler. + * NOTE: In debug library only ! + * @param xlog Function to call on iDMAlib log call + */ +void +idma_log_handler(idma_log_h xlog); + +/** + * @name Sleep/block until current iDMA activity completes. + * @brief Wait in low-power mode until iDMA activity completes. Return immediately + * if iDMA is in error or there are no outstanding descriptors. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @retval IDMA_OK Normal return. + * @retval IDMA_CANT_SLEEP Cannot sleep (no pending descriptors). + * @retval (all other values) Error code. + */ +IDMA_API idma_status_t +idma_sleep(int32_t ch); + +/** + * @name Get the error details. + * @brief When task or fixed buffer status indicate error, use this + * function to obtain the error details. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param task Pointer to iDMA task + * @retval Pointer to the structure containing error details. + * NOTE: Pointer is valid only if idma task/buffer is in error. + */ +IDMA_API idma_error_details_t* idma_error_details(int32_t ch); +IDMA_API idma_error_details_t* idma_buffer_error_details(int32_t ch); + +/** + * @name Disable iDMA HW when not in use. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @brief Needs idma_init to resume. + */ +IDMA_API idma_status_t +idma_stop(int32_t ch); + +/** + * @name Pause iDMA HW. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @brief Can simply resume after + */ +IDMA_API void +idma_pause(int32_t ch); + +/** + * @name Resume iDMA HW. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @brief Can simply pause before + */ +IDMA_API void +idma_resume(int32_t ch); + +/** + * @name Add 1D desc to the next location in the buffer/task + * @brief Descriptors are added in order. Used in both Task and + * and the fixed-buffer mode. + * NOTE: Number of added descriptors needs to match the + * size of the task (an argument to idma_init_task()). + * @param dst... iDMA 1D transfer parameters + * @param flags Descriptor options (Control field). + * See "Descriptor Control Flags". + * @retval IDMA_OK Successful. + * @retval !IDMA_OK Error type. + */ +IDMA_API idma_status_t +idma_add_desc( idma_buffer_t *bufh, + void *dst, + void *src, + size_t size, + uint32_t flags); + +/** + * @name Add 2D desc to the next location in the buffer/task + * @brief Descriptors are added in order. Used in both Task and + * and the fixed-buffer mode. + * NOTE: Number of added descriptors needs to match the + * size of the task (an argument to idma_init_task()). + * @param dst... iDMA 1D transfer parameters + * @param flags Descriptor options (Control field). + * See "Descriptor Control Flags". + * @retval IDMA_OK Successful. + * @retval !IDMA_OK Error type. + */ +IDMA_API idma_status_t +idma_add_2d_desc( idma_buffer_t *bufh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch); + +/************************************************/ +/**** Task-mode API ****/ +/************************************************/ + +/** + * @name Initialize a task (a separate buffer/array of descriptors). + * @brief Needs to be called before adding descriptors to a task. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param task Pointer to the memory used for iDMA task. + * @param type 1D or 2D. + * @param num Number of descriptors to be added. NOTE: must match + * the actual number of added descs using _add_ calls. + * Also, IDMA_BUFFER_DEFINE must allocate sufficent memory. + * @param cb_func Function to call on each descriptor completion. + * (if enabled by descriptor). + * @param cb_data Callback data. + * @retval IDMA_OK Successful. + * @retval !IDMA_OK Error type + */ +IDMA_API idma_status_t +idma_init_task (int32_t ch, + idma_buffer_t *taskh, + idma_type_t type, + int32_t ndescs, + idma_callback_fn cb_func, + void *cb_data); + +/** + * @name Get the task execution status. + * @brief Reads the number of outstanding descriptors from the + * scheduled task. When no iDMA interrupts, must be used + * together with idma_process_tasks() as something must + * trigger iDMAlib internal task completion processing. + * @param task Pointer to iDMA task + * @retval < 0 Error (task_status_t) + * @retval >= 0 Number of outstanding descriptors in the task. + */ +IDMA_API int32_t +idma_task_status(idma_buffer_t *taskh); + +/** + * @name Create and schedule 1D copy request. + * @brief Convenience functions that combine buffer initialization, + * adding one descriptor to it and scheduling the task. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param task Pointer to iDMA buffer + * @param cb_func Function to call on each descriptor completion + * (if enabled by descriptor) + * @param cb_data Callback data. + * @retval IDMA_OK Successful. + * @retval !IDMA_OK Error type + */ +IDMA_API idma_status_t +idma_copy_task(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t size, + uint32_t flags, + void *cb_data, + idma_callback_fn cb_func); + +/** + * @name Create and schedule 2D copy request. + * @brief Convenience functions that combine buffer initialization, + * adding one descriptor to it and scheduling the task. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param task Pointer to iDMA buffer + * @param cb_func Function to call on each descriptor completion + * (if enabled by descriptor) + * @param cb_data Callback data. + * @retval IDMA_OK Successful. + * @retval !IDMA_OK Error type + */ +IDMA_API idma_status_t +idma_copy_2d_task(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + void *cb_data, + idma_callback_fn cb_func); + +/** + * @name Schedule a task for execution. + * @brief Schedule a task(separate buffer/array ofdescriptor) + * for execution in the task mode. If IDMA is busy, + * last desc from the last scheduled buffer is linked + * with the 1st desc from this task using a JUMP command. + * If IDMA is not busy iDMA HW starts execution from this task. + * NOTE: TASK MODE ONLY. + * @param buf Pointer to iDMA task to be scheduled. + * @retval IDMA_OK Successful. + * @retval !IDMA_OK Error type. + */ +idma_status_t +idma_schedule_task(idma_buffer_t *taskh); + +/** + * @name Trigger iDMAlib internal processing of completed tasks. + * @brief Needed when no interrupts are available/setup. + * NOTE: Function will also invoke completion callback, + * if set with idma_init_task() function. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @retval IDMA_OK Successful. + * @retval !IDMA_OK Error type (when iDMA is in error). + */ +IDMA_API idma_status_t +idma_process_tasks(int32_t ch); + +/** + * @name Abort all tasks. + * @brief Reset iDMA HW and set status of all "outstanding" tasks to + * aborted state. Note: "Outstanding" tasks can also include + * tasks that actually completed (their descriptors are all executed). + * To ensure all the completed tasks are not seen as "outstanding", + * enable iDMA Done interrupt for at least the last descriptor in + * a task, or call idma_process_tasks() before calling this function. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @retval IDMA_OK Successful. + * @retval !IDMA_OK Error type + */ +IDMA_API idma_status_t +idma_abort_tasks(int32_t ch); + +/************************************************/ +/**** Fixed-Buffer Mode API ****/ +/************************************************/ + +/** + * @name Initialize buffer (array of descs). Also enables the fixed-buffer + * mode which prevents using the buffer as a separate task. + * @brief Needs to be called after a buffer is created (e.g. using the + * IDMA_DEFINE_BUFFER) and before adding descriptors to it. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param buffer Pointer to the memory used for iDMA buffer + * @param type 1D or 2D + * @param ndescs Number of descriptors. In the TASK mode, the number + * of descs added to the task need to much this number. + * @param cb_func Function to call on each descriptor completion. + * (if enabled by each descriptor settings) + * @param cb_data Callback data + * @retval IDMA_OK Successful. + * @retval !IDMA_OK Error type + */ +IDMA_API idma_status_t +idma_init_loop (int32_t ch, + idma_buffer_t *bufh, + idma_type_t type, + int32_t ndescs, + void *cb_data, + idma_callback_fn cb_func); + +/** + * @name Schedule consecutive descriptors for execution. + * @brief Schedule a number of next in line descriptors, with wrap-around + * NOTE: INCOMPATIBLE with idma_copy_desc/idma_copy_2d_desc + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param count Number of descriptors to schedule. + * NOTE: Cannot be larger than the number of descriptors + * in the buffer initialized using idma_init_loop(). + * @retval < 0 Error code, from idma_status_t. + * @retval >= 0 Unique index of the scheduled descriptor in the range from 0 + * to 0x7fffffff. Starts with value of 1 at iDMAlib initialization + * time. It's expected the number of outstanding descriptors in + * the system is always less then 0x7fffffff. + * E.g. if the circular buffer contains 8 descs and retval=17, + * the 2nd descriptor in the buffer is the last scheduled one and + * by, the iDMAlib has scheduled 17 descriptors. + * NOTE: This unique index is to be used in idma_desc_done() only. + */ +IDMA_API int32_t +idma_schedule_desc(int32_t ch, + uint32_t count); + +/** + * @name Schedule consecutive descriptors for execution w/o ability to change descs. + * @brief Schedule a number of next in line descriptors, with wrap-around. + * The function is to be used when all the descriptors are already added + * so they are just scheduled or possibly updated. This is because the + * the function doesn't keep the track of the place where the next descriptor + * is to be added. + * NOTE: INCOMPATIBLE with idma_copy_desc/idma_copy_2d_desc and idma_update_desc_* + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param count Number of descriptors to schedule. + * @retval < 0 Error code, from idma_status_t. + * @retval >= 0 See idma_schedule_desc() + */ +IDMA_API int32_t +idma_schedule_desc_fast(int32_t ch, + uint32_t count); + +/** + * @name Add and schedule a 1D descriptor. + * @brief Descriptor added in order and scheduled in order. + * NOTE: INCOMPATIBLE with idma_add_desc/idma_add_2d_desc/idma_schedule_desc + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param dst iDMA transfer destination + * @param src iDMA transfer source + * @param size iDMA transfer size + * @param flags Descriptor options (Control field). See "Descriptor Control Flags". + * @retval < 0 Error code, from idma_status_t. + * @retval >= 0 See idma_schedule_desc() + */ +IDMA_API int32_t +idma_copy_desc(int32_t ch, + void *dst, + void *src, + size_t size, + uint32_t flags); + +/** + * @name Add and schedule a 2D descriptor. + * @brief Descriptor added in order and scheduled in order. + * NOTE: INCOMPATIBLE with idma_add_desc/idma_add_2d_desc/idma_schedule_desc + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param dst iDMA transfer destination + * @param src iDMA transfer source + * @param size iDMA transfer size + * @param flags Descriptor options (Control field). + * See "Descriptor Control Flags". + * @param nrows Number of rows to transfer + * @param src_pitch iDMA transfer source pitch + * @param dst_pitch iDMA transfer destination pitch + * @retval < 0 Error code, from idma_status_t. + * @retval >= 0 See idma_schedule_desc() + */ +IDMA_API int32_t +idma_copy_2d_desc(int32_t ch, + void *dst, + void *src, + size_t size, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch); + +/** + * @name Check if a descriptor is done, using unique desc ID. + * @brief Unique ID is made available when descriptor was scheduled. + * The function does the internal processing so it can be + * called in an empty loop if want to wait for desc to complete. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param index Unique ID of the descriptor. + * @retval 1 Desc is done. + * @retval 0 Desc is NOT done. + * @retval -1 Error. + */ +IDMA_API int32_t +idma_desc_done(int32_t ch, + int32_t index); + + +/** + * @name Update destination field of the "next" descriptor + * @brief Update next to be schedule descriptor (means the next + * call to idma_desc_schedule() will schedule the desc. + * updated in this call. + * ONLY IN FIXED-BUFFER MODE. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param dst New destination address + * @retval IDMA_OK Successful + * @retval !IDMA_OK Error type + */ +IDMA_API idma_status_t +idma_update_desc_dst(int32_t ch, + void *dst); + +/** + * @name Update source field of the "next" descriptor. + * @brief Update next to be schedule descriptor (means the next + * call to idma_desc_schedule() will schedule the desc. + * updated in this call. + * ONLY IN FIXED-BUFFER MODE. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param src New source address + * @retval IDMA_OK Successful + * @retval !IDMA_OK Error type + */ +IDMA_API idma_status_t +idma_update_desc_src(int32_t ch, + void *src); + +/** + * @name Update size field of the "next" descriptor. + * @brief Update next to be schedule descriptor (means the next + * call to idma_desc_schedule() will schedule the desc. + * updated in this call. + * ONLY IN FIXED-BUFFER MODE. + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @param size New copy request size + * @retval IDMA_OK Successful + * @retval !IDMA_OK Error type + */ +IDMA_API idma_status_t +idma_update_desc_size(int32_t ch, + uint32_t size); + +/** + * @name Get buffer status w/ internal processing of completed descs. + * @brief Check the number of outstanding descriptors. Will also + * trigger internal processing making this call needed when no + * interrupts are available/setup. + * ONLY IN FIXED-BUFFER MODE. + * @brief Returns error or the number of outstanding descs + * @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @retval >=0 num. of outstanding descriptors + * @retval <0 Error type + */ +IDMA_API int32_t +idma_buffer_status(int32_t ch); + +/** + * @name Check if the IDMA HW is in error. If yes the function also + * sets the error details, sets the buffer status to indicate + * error and returns the error code. +* @param ch Selected iDMA HW channel. + * NOTE: Argument present only if LIBIDMA_USE_MULTICHANNEL_API defined. + * @retval IDMA_NO_ERR No Error. + * @retval !IDMA_NO_ERR Error type + */ +IDMA_API idma_hw_error_t +idma_buffer_check_errors(int32_t ch); + +/** + * These two functions operate exactly like idma_schedule_desc() and + * idma_schedule_desc_fast(), and in addition they also return the + * current clock value (which normally is the CCOUNT register value) + * in the location pointed to by the "ptime" argument. + */ +IDMA_API int32_t +idma_schedule_desc_clock(int32_t ch, + uint32_t count, + uint32_t *ptime); + +IDMA_API int32_t +idma_schedule_desc_fast_clock(int32_t ch, + uint32_t count, + uint32_t *ptime); + +#else // OLD API - no channels + +IDMA_API void idma_hw_wait_all(void); +IDMA_API void idma_hw_schedule(uint32_t count); +IDMA_API uint32_t idma_hw_num_outstanding(void); + +void idma_log_handler(idma_log_h xlog); + +idma_status_t idma_fast_wake_enable(void); +idma_status_t idma_fast_wake_disable(void); +IDMA_API idma_status_t idma_init(uint32_t flags, idma_max_block_t block_sz, uint32_t pif_req, idma_ticks_cyc_t ticks_per_cyc, uint32_t timeout_ticks, idma_err_callback_fn err_cb_func); +IDMA_API idma_status_t idma_add_desc(idma_buffer_t *bufh, void *dst, void *src, size_t size, uint32_t flags); +IDMA_API idma_status_t idma_add_2d_desc(idma_buffer_t *bufh, void *dst, void *src, size_t row_sz, uint32_t flags, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch); +IDMA_API idma_status_t idma_init_loop (idma_buffer_t *bufh, idma_type_t type, int32_t ndescs, void *cb_data, idma_callback_fn cb_func); +IDMA_API idma_status_t idma_init_task(idma_buffer_t *taskh, idma_type_t type, int32_t ndescs, idma_callback_fn cb_func, void *cb_data); +IDMA_API idma_status_t idma_copy_task(idma_buffer_t *taskh, void *dst, void *src, size_t size, uint32_t flags, void *cb_data, idma_callback_fn cb_func); +IDMA_API idma_status_t idma_copy_2d_task(idma_buffer_t *taskh, void *dst, void *src, size_t row_sz, uint32_t flags, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch, void *cb_data, idma_callback_fn cb_func); +IDMA_API idma_status_t idma_process_tasks(void); +IDMA_API idma_status_t idma_abort_tasks(void); +IDMA_API idma_status_t idma_stop(void); +IDMA_API idma_status_t idma_update_desc_dst(void *dst); +IDMA_API idma_status_t idma_update_desc_src(void *src); +IDMA_API idma_status_t idma_update_desc_size(uint32_t size); +idma_status_t idma_schedule_task( idma_buffer_t *taskh); + +IDMA_API idma_state_t idma_get_state(void); + +IDMA_API void idma_pause(void); +IDMA_API void idma_resume(void); + +IDMA_API int32_t idma_schedule_desc(uint32_t count); +IDMA_API int32_t idma_schedule_desc_fast(uint32_t count); +IDMA_API int32_t idma_copy_desc(void *dst, void *src, size_t size, uint32_t flags); +IDMA_API int32_t idma_copy_2d_desc(void *dst, void *src, size_t size, uint32_t flags, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch); +IDMA_API int32_t idma_desc_done(int32_t index); +IDMA_API int32_t idma_buffer_status(void); +IDMA_API int32_t idma_task_status(idma_buffer_t *taskh); +IDMA_API idma_status_t idma_sleep(void); + +IDMA_API idma_hw_error_t idma_buffer_check_errors(void); + +IDMA_API idma_error_details_t* idma_error_details(void); +IDMA_API idma_error_details_t* idma_buffer_error_details(void); + +IDMA_API int32_t idma_schedule_desc_clock(uint32_t count, uint32_t *ptime); +IDMA_API int32_t idma_schedule_desc_fast_clock(uint32_t count, uint32_t *ptime); + +#endif // not LIBIDMA_USE_MULTICHANNEL_API + +/* For compatibility with macros that were used before */ +#define IDMA_HW_NUM_OUTSTANDING idma_hw_num_outstanding +#define IDMA_HW_SCHEDULE idma_hw_schedule +#define IDMA_HW_WAIT_ALL idma_hw_wait_all + +#if (IDMA_USE_64B_DESC > 0) + +/** + * @name Add 1D descriptor in 64B format to the next location in the buffer/task + * NOTE: This functions uses 32-bit src/dst addresses; it'll fetch + * one word behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_add_desc64( idma_buffer_t *bufh, + void *dst, + void *src, + size_t size, + uint32_t flags); + +/** + * @name Add 2D descriptor in 64B format to the next location in the buffer/task + * NOTE: This functions uses 32-bit src/dst addresses; it'll fetch + * one word behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_add_2d_desc64( idma_buffer_t *bufh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch); + +#if (XCHAL_IDMA_HAVE_2DPRED > 0) +/** + * @name Add predicated 2D descriptor in 64B format to the next location in the buffer/task + * NOTE: This functions uses 32-bit src/dst addresses; it'll fetch + * one word behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_add_2d_pred_desc64( idma_buffer_t *bufh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + void* pred_mask, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch); +#endif + +/** + * @name Add 3D descriptor in 64B format to the next location in the buffer/task + * NOTE: This functions uses 32-bit src/dst addresses; it'll fetch + * one word behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_add_3d_desc64( idma_buffer_t *bufh, + void *dst, + void *src, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_row_pitch, + uint32_t dst_row_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch); + +/** + * @name Create & schedule 1D copy request in 64B format + * @brief See idma_copy_task for details + * NOTE: This functions uses 32-bit src/dst addresses; it'll fetch + * one word behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_copy_task64(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t size, + uint32_t flags, + void *cb_data, + idma_callback_fn cb_func); + +/** + * @name Create & schedule 2D copy request in 64B format + * @brief See idma_copy_2d_task for details. + * NOTE: This functions uses 32-bit src/dst addresses; it'll fetch + * one word behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_copy_2d_task64(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + void *cb_data, + idma_callback_fn cb_func); + +#if (XCHAL_IDMA_HAVE_2DPRED > 0) +/** + * @name Create & schedule predicated 2D copy request in 64B format + * @brief See idma_copy_2d_task for details. + * NOTE: This functions uses 32-bit src/dst addresses; it'll fetch + * one word behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_copy_2d_pred_task64(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + void* pred_mask, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + void *cb_data, + idma_callback_fn cb_func); +#endif + +/** + * @name Add and schedule a 1D descriptor in 64B format. + * @brief See idma_copy_desc for details. + * NOTE: This functions uses 32-bit src/dst addresses; it'll fetch + * one word behind the src/dst pointers. + */ +IDMA_API int32_t +idma_copy_desc64(int32_t ch, + void *dst, + void *src, + size_t size, + uint32_t flags); + +/** + * @name Add and schedule a 2D descriptor in 64B format. + * @brief See idma_copy_2d_desc for details. + * NOTE: This functions uses 32-bit src/dst addresses; it'll fetch + * one word behind the src/dst pointers. + */ +IDMA_API int32_t +idma_copy_2d_desc64(int32_t ch, + void *dst, + void *src, + size_t size, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch); + +#if (XCHAL_IDMA_HAVE_2DPRED > 0) +/** + * @name Add and schedule a predicated 2D descriptor in 64B format. + * @brief See idma_copy_2d_desc for details. + * NOTE: This functions uses 32-bit src/dst addresses; it'll fetch + * one word behind the src/dst pointers. + */ +IDMA_API int32_t +idma_copy_2d_pred_desc64(int32_t ch, + void *dst, + void *src, + size_t size, + uint32_t flags, + void* pred_mask, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch); +#endif + +/** + * @name Add and schedule a 3D descriptor in 64B format. + * @brief See idma_copy_2d_desc for details. + * NOTE: This functions uses 32-bit src/dst addresses; it'll fetch + * one word behind the src/dst pointers. + */ +IDMA_API int32_t +idma_copy_3d_desc64(int32_t ch, + void *dst, + void *src, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_row_pitch, + uint32_t dst_row_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch); + +#if (IDMA_USE_WIDE_API > 0) + +/** + * @name Add 1D descriptor in 64B format to the next location in the buffer/task. + * @brief See idma_add_2d_desc for details on arguments. + * NOTE: This functions uses 64-bit src/dst addresses; it'll fetch + * two words behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_add_desc64_wide( idma_buffer_t *bufh, + void *dst, + void *src, + size_t size, + uint32_t flags); + +/** + * @name Add 2D descriptor in 64B format to the next location in the buffer/task + * @brief See idma_add_2d_desc for details on arguments. + * NOTE: This functions uses 64-bit src/dst addresses; it'll fetch + * two words behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_add_2d_desc64_wide( idma_buffer_t *bufh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch); + +#if (XCHAL_IDMA_HAVE_2DPRED > 0) +/** + * @name Add predicated 2D descriptor in 64B format to the next location in the buffer/task. + * @brief See idma_add_2d_desc for details on arguments. + * NOTE: This functions uses 64-bit src/dst addresses; it'll fetch + * two words behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_add_2d_pred_desc64_wide( idma_buffer_t *bufh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + void* pred_mask, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch); +#endif + +/** + * @name Add 3D descriptor in 64B format to the next location in the buffer/task. + * @brief See idma_add_3d_desc64 for details on arguments. + * NOTE: This functions uses 64-bit src/dst addresses; it'll fetch + * two words behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_add_3d_desc64_wide( idma_buffer_t *bufh, + void *dst, + void *src, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_row_pitch, + uint32_t dst_row_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch); + +/** + * @name Create & schedule 1D copy request in 64B format. + * @brief See idma_copy_task for details + * NOTE: This functions uses 64-bit src/dst addresses; it'll fetch + * two words behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_copy_task64_wide(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t size, + uint32_t flags, + void *cb_data, + idma_callback_fn cb_func); + +/** + * @name Create & schedule 2D copy request in 64B format. + * @brief See idma_copy_task for details + * NOTE: This functions uses 64-bit src/dst addresses; it'll fetch + * two words behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_copy_2d_task64_wide(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + void *cb_data, + idma_callback_fn cb_func); + +#if (XCHAL_IDMA_HAVE_2DPRED > 0) +/** + * @name Create & schedule predicated 2D copy request in 64B format. + * @brief See idma_copy_task for details + * NOTE: This functions uses 64-bit src/dst addresses; it'll fetch + * two words behind the src/dst pointers. + */ +IDMA_API idma_status_t +idma_copy_2d_pred_task64_wide(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + void* pred_mask, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + void *cb_data, + idma_callback_fn cb_func); +#endif + +/** + * @name Add and schedule a 1D descriptor in 64B format. + * @brief See idma_copy_desc for details. + * NOTE: This functions uses 64-bit src/dst addresses; it'll fetch + * two words behind the src/dst pointers. + */ +IDMA_API int32_t +idma_copy_desc64_wide(int32_t ch, + void *dst, + void *src, + size_t size, + uint32_t flags); + +/** + * @name Add and schedule a 2D descriptor in 64B format. + * @brief See idma_copy_2d_desc for details. + * NOTE: This functions uses 64-bit src/dst addresses; it'll fetch + * two word behind the src/dst pointers. + */ +IDMA_API int32_t +idma_copy_2d_desc64_wide(int32_t ch, + void *dst, + void *src, + size_t size, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch); + +#if (XCHAL_IDMA_HAVE_2DPRED > 0) +/** + * @name Add and schedule a predicated 2D descriptor in 64B format. + * @brief See idma_copy_desc for details. + * NOTE: This functions uses 64-bit src/dst addresses; it'll fetch + * two words behind the src/dst pointers. + */ +IDMA_API int32_t +idma_copy_2d_pred_desc64_wide(int32_t ch, + void *dst, + void *src, + size_t size, + uint32_t flags, + void* pred_mask, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch); +#endif + +/** + * @name Add and schedule a 3D descriptor in 64B format. + * @brief See idma_copy_desc for details. + * NOTE: This functions uses 64-bit src/dst addresses; it'll fetch + * two words behind the src/dst pointers. + */ +IDMA_API int32_t +idma_copy_3d_desc64_wide(int32_t ch, + void *dst, + void *src, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_row_pitch, + uint32_t dst_row_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch); + +#endif +#endif + + + + + +/*************************************************/ +/**** Internal Stuff ****/ +/**** DO NOT ACCESS OR RELY ON THE CODE BELOW ****/ +/*************************************************/ + +#ifdef IDMA_USE_WIDE_ADDRESS_COMPILE + +# define SRC_WIDE_ADDR_SHIFT UINT32_C(16) +# define DST_WIDE_ADDR_SHIFT UINT32_C(20) +# define IDMA_WIDE_ADDR_MASK UINT32_C(0x0000000F) + +idma_status_t +idma_copy_task_wide_i(int32_t ch, + idma_buffer_t * taskh, + void * dst, + void * src, + size_t size, + uint32_t flags, + void * cb_data, + idma_callback_fn cb_func); + +idma_status_t +idma_copy_2d_task_wide_i(int32_t ch, + idma_buffer_t * taskh, + void * dst, + void * src, + size_t row_sz, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + void * cb_data, + idma_callback_fn cb_func); + +#endif // IDMA_USE_WIDE_ADDRESS_COMPILE + +#define IDMA_CHANNEL_0 0 +#define IDMA_CHANNEL_1 1 +#define IDMA_CHANNEL_2 2 +#define IDMA_CHANNEL_3 3 +#define IDMA_CHANNEL_4 4 +#define IDMA_CHANNEL_5 5 +#define IDMA_CHANNEL_6 6 +#define IDMA_CHANNEL_7 7 + + +#if (LIBIDMA_USE_MULTICHANNEL_API > 0) +# define IDMA_CH_PTR ch +# define IDMA_CHAN_FUNC_ARG int32_t ch, +# define IDMA_CHAN_FUNC_ARG_SINGLE int32_t ch +#else +# define IDMA_CH_PTR IDMA_CHANNEL_0 +# define IDMA_CHAN_FUNC_ARG +# define IDMA_CHAN_FUNC_ARG_SINGLE void +#endif + +#if XCHAL_HAVE_XEA2 || XCHAL_HAVE_XEA3 +# define IDMA_REG_ADDR(c,r) (IDMAREG_BASE((uint32_t)(c)) + (uint32_t)(r)) +# define IDMA_RER XT_RER +# define IDMA_WER XT_WER +#else +# define IDMA_RER(r) xthal_mmio_ld32((r)) +# define IDMA_WER(v,r) xthal_mmio_st32((r),(v)) +#endif + +#if XCHAL_HAVE_XEA5 +# define IDMA_DONE_INT(ch) ((uint32_t)XCHAL_IDMA_CH0_DONE_INTERRUPT + ((ch) * UINT32_C(2))) +# define IDMA_ERR_INT(ch) ((uint32_t)XCHAL_IDMA_CH0_ERR_INTERRUPT + ((ch) * UINT32_C(2))) +#else +# define IDMA_DONE_INT(ch) ((uint32_t)XCHAL_IDMA_CH0_DONE_INTERRUPT + (ch)) +# define IDMA_ERR_INT(ch) ((uint32_t)XCHAL_IDMA_CH0_ERR_INTERRUPT + (ch)) +#endif + + +#if defined (IDMA_USERMODE) +#define IDMA_1D_DESC_CODE UINT32_C(0xA03) +#define IDMA_2D_DESC_CODE UINT32_C(0xA07) +#define IDMA_JMP_DESC_CODE UINT32_C(0xA00) +#define IDMA_64B_DESC_CODE UINT32_C(0xA01) +#define IDMA_ZVC_DESC_CODE UINT32_C(0xA05) +#else +#define IDMA_1D_DESC_CODE UINT32_C(3) +#define IDMA_2D_DESC_CODE UINT32_C(7) +#define IDMA_JMP_DESC_CODE UINT32_C(0) +#define IDMA_64B_DESC_CODE UINT32_C(1) +#define IDMA_ZVC_DESC_CODE UINT32_C(5) +#endif + +// Applicable to 64-byte and zvc descriptors only +#define IDMA_64B_SUBTYPE_MASK UINT32_C(0x00000007) +#define IDMA_64B_SUBTYPE_SHIFT 4 +#define IDMA_64B_1D_TYPE UINT32_C(0) +#define IDMA_64B_2D_TYPE UINT32_C(1) +#define IDMA_64B_2D_COMPRESS_TYPE UINT32_C(2) +#define IDMA_64B_3D_TYPE UINT32_C(4) +#define IDMA_64B_2D_FBC_TYPE UINT32_C(6) +#define IDMA_ZVC_1D_TYPE UINT32_C(5) +#define IDMA_ZVC_2D_TYPE UINT32_C(7) +#define IDMA_64B_LONG_ADDR_CTRL_BIT_MASK UINT32_C(0x00000400) +#define SET_CONTROL_SUBTYPE(a) (((a) & IDMA_64B_SUBTYPE_MASK) << IDMA_64B_SUBTYPE_SHIFT) + +// Inline selection for "wrapper" functions +#define WRAPPER_FUNC static __attribute__((always_inline)) + +#define IDMA_1D_DESC_SIZE 16 +#define IDMA_2D_DESC_SIZE 32 +#define IDMA_64_DESC_SIZE 64 + +// Data placement in local memory. First, let the user select which dataram to +// use. If the user has defined neither IDMA_USE_DRAM0 or IDMA_USE_DRAM1, then +// - if both datarams are present, choose the one at the lower address +// - if only one is present, it must be dataram0 + +#if defined (IDMA_USE_DRAM_BSS) +# define IDMA_SECTION "bss" +#else +# define IDMA_SECTION "data" +#endif + +#if defined (IDMA_USE_DRAM1) +# define IDMA_DRAM __attribute__ ((section(".dram1."IDMA_SECTION))) +#elif defined (IDMA_USE_DRAM0) +# define IDMA_DRAM __attribute__ ((section(".dram0."IDMA_SECTION))) +#else +# if (XCHAL_NUM_DATARAM > 1) +# if XCHAL_DATARAM1_VADDR > XCHAL_DATARAM0_VADDR +# define IDMA_DRAM __attribute__ ((section(".dram0."IDMA_SECTION))) +# else +# define IDMA_DRAM __attribute__ ((section(".dram1."IDMA_SECTION))) +# endif +# else +# define IDMA_DRAM __attribute__ ((section(".dram0."IDMA_SECTION))) +# endif +#endif + +#ifdef IDMA_DEBUG +# define IDMA_CONTROL_STRUCT_SIZE_ 52 +#else +# define IDMA_CONTROL_STRUCT_SIZE_ 48 +#endif + +# ifdef IDMA_DEBUG +# define IDMA_ASSERT(expr) +void idma_print(int32_t ch, const char* fmt, ...); +# define XLOG(ch, ...) do { idma_print((ch), __VA_ARGS__);} while (0) // parasoft-suppress MISRA2012-RULE-20_7 "used only in non-FuSa code" +# else +# define IDMA_ASSERT(expr) +# define XLOG(ch, ...) (void)(ch); do {} while (0) +# endif + + +/* 1D descriptor structure */ +struct idma_desc_struct { + uint32_t control; + uint32_t src; + uint32_t dst; + uint32_t size; +}; + +/* 2D descriptor structure */ +struct idma_2d_desc_struct { + uint32_t control; + uint32_t src; + uint32_t dst; + uint32_t size; + uint32_t src_pitch; + uint32_t dst_pitch; + uint32_t nrows; + uint32_t word8; +}; + +/* 64B descriptor structure */ +struct idma_desc64_struct { + uint32_t control; + uint32_t src; + uint32_t dst; + uint32_t size; + uint32_t src_pitch; + uint32_t dst_pitch; + uint32_t nrows; + uint32_t word8; + int32_t src_tile_pitch; + int32_t dst_tile_pitch; + uint32_t ntiles; + uint32_t pred_mask; + uint32_t word13; + uint32_t word14; + uint32_t ext_src; + uint32_t ext_dst; +}; + +/* Real buffer struct - NOT TO BE USED BY APPLICATION */ + +struct idma_buf_struct { + idma_desc_t * next_desc; // points past the last scheduled desc. Used by functions + // needing to update the desc that is just to be scheduled. + idma_desc_t * next_add_desc; // points past the last added desc. Used by functions that + // populate a new task, or populate a buffer where later + // schedule call will schedule them all at once. + + int32_t num_descs; // total num of descs, assigned on init. In fixed buffer mode + // it sets the size of the circular buffer by setting JUMP + // command between the last desc and the 1st one. In TASK mode + // it is used to tell the lib how many descs to schedule. + idma_desc_t * last_desc; // points past the last desc. Assigned to sped-up wrap-arround + // calculation, not to use num_descs and multiplication. + + int32_t type; // descs type, assigned on init. + + idma_buf_t * next_task; // TASK: points to next task, assigned on schedule + int32_t cur_desc_i; // FIXED-BUFFER: tracks next desc to execute. + int32_t status; // TASK: # of remaining descs after schedule. + // BOTH modes: error type, if in error. + idma_callback_fn cb_func; // Callback on completion + void * cb_data; // Completion callback argument + int32_t ch; + void * thread_id; // (OS-specific) ID of owning thread + int16_t sleeping; // Nonzero when thread is sleeping (blocked) + int16_t pending; // Nonzero when buffer is queued + int32_t pending_desc_cnt; + + idma_desc_t desc __attribute__ ((aligned(16))); +}; + + +/* Inline functions for iDMA register read/write */ +ALWAYS_INLINE uint32_t +READ_IDMA_REG(int32_t ch, int32_t reg) +{ + return IDMA_RER(IDMA_REG_ADDR(ch,reg)); +} + +ALWAYS_INLINE void +WRITE_IDMA_REG(int32_t ch, int32_t reg, uint32_t val) +{ + IDMA_WER(val, IDMA_REG_ADDR(ch,reg)); +} + +ALWAYS_INLINE void +set_desc_addr_fields(idma_desc_t * desc, + void * dst, + void * src) +{ +#ifdef IDMA_USE_WIDE_ADDRESS_COMPILE + uint32_t * src36 = cvt_voidp_to_uint32p(src); + uint32_t * dst36 = cvt_voidp_to_uint32p(dst); + uint32_t wide_addr_mask = IDMA_WIDE_ADDR_MASK; + + desc->src = src36[0]; + desc->dst = dst36[0]; + desc->control = + (desc->control & ~(wide_addr_mask << SRC_WIDE_ADDR_SHIFT)) | ((src36[1] & wide_addr_mask) << SRC_WIDE_ADDR_SHIFT); + desc->control = + (desc->control & ~(wide_addr_mask << DST_WIDE_ADDR_SHIFT)) | ((dst36[1] & wide_addr_mask) << DST_WIDE_ADDR_SHIFT); +#else + desc->src = cvt_voidp_to_uint32(src); + desc->dst = cvt_voidp_to_uint32(dst); +#endif +} + +ALWAYS_INLINE void +set_1d_fields( int32_t ch, + idma_desc_t* desc, + void *dst, + void *src, + size_t size) +{ + set_desc_addr_fields(desc, dst, src); + desc->size = size; +#ifdef IDMA_USE_WIDE_ADDRESS_COMPILE +# ifdef IDMA_DEBUG + { + uint32_t src64 = (desc->control >> SRC_WIDE_ADDR_SHIFT) & IDMA_WIDE_ADDR_MASK; + uint32_t dst64 = (desc->control >> DST_WIDE_ADDR_SHIFT) & IDMA_WIDE_ADDR_MASK; + XLOG(ch, "Add 1D desc wide @ %p, %d-bytes(%x-%p -> %x-%p), control:0x%x\n", + desc, desc->size, src64, desc->src, dst64, desc->dst, desc->control); + } +# endif +#else + XLOG(ch, "Add 1D desc @ %p, %d-bytes(%p -> %p), control:0x%x\n", desc, desc->size, desc->src, desc->dst, desc->control); +#endif + (void)(ch); +} + +ALWAYS_INLINE void +set_2d_fields(int32_t ch, + idma_desc_t* desc, + void *dst, + void *src, + size_t size, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch) +{ + idma_2d_desc_t* desc2d = (idma_2d_desc_t*) desc; // parasoft-suppress MISRA2012-RULE-11_3 "conversion checked" + set_desc_addr_fields(desc, dst, src); + desc2d->size = size; + desc2d->nrows = nrows; + desc2d->src_pitch = src_pitch; + desc2d->dst_pitch = dst_pitch; +#ifdef IDMA_USE_WIDE_ADDRESS_COMPILE +# ifdef IDMA_DEBUG + { + uint32_t src64 = (desc->control >> SRC_WIDE_ADDR_SHIFT) & IDMA_WIDE_ADDR_MASK; + uint32_t dst64 = (desc->control >> DST_WIDE_ADDR_SHIFT) & IDMA_WIDE_ADDR_MASK; + XLOG(ch, "Add 2D desc wide @ %p, %d-bytes (%x-%p -> %x-%p)\n", + desc2d, desc2d->size, src64, desc->src, dst64, desc->dst); + XLOG(ch, " (#rows:%d, src_pitch:%d, dst_pitch:%d, control:0x%x)\n", + desc2d->nrows, desc2d->src_pitch, desc2d->dst_pitch, desc2d->control); + + } +# endif +#else + XLOG(ch, "Add 2D desc @ %p, %d-bytes (%p -> %p)\n", desc2d, desc2d->size, desc2d->src, desc2d->dst); + XLOG(ch, " (#rows:%d, src_pitch:%d, dst_pitch:%d, control:0x%x)\n", + desc2d->nrows, desc2d->src_pitch, desc2d->dst_pitch, desc2d->control); +#endif + (void)(ch); +} + +#if (IDMA_USE_64B_DESC > 0) + +INTERNAL_FUNC void +set_desc64_short_addr(idma_desc64_t* desc, void *dst, void *src) // parasoft-suppress MISRA2012-RULE-8_13_a-4 "Cannot use const, backward compatibility and dst is modified" +{ + desc->src = (cvt_voidp_to_uint32p(src))[0]; + desc->dst = (cvt_voidp_to_uint32p(dst))[0]; +} + + +INTERNAL_FUNC void +set_desc64_2d_pitch(idma_desc64_t* desc, uint32_t src_pitch, uint32_t dst_pitch) +{ + desc->src_pitch = src_pitch; + desc->dst_pitch = dst_pitch; +} + +INTERNAL_FUNC void +set_desc64_3d_pitch(idma_desc64_t* desc, uint32_t src_pitch, uint32_t dst_pitch, uint32_t src_tile_pitch, uint32_t dst_tile_pitch) +{ + set_desc64_2d_pitch(desc, src_pitch, dst_pitch); + desc->src_tile_pitch = (int32_t) src_tile_pitch; + desc->dst_tile_pitch = (int32_t) dst_tile_pitch; +} + +INTERNAL_FUNC void +set_1d_desc64_fields(int32_t ch, + idma_desc_t* desch, + void *dst, + void *src, + size_t size) +{ + idma_desc64_t* desc = cvt_desc_to_desc64(desch); + + set_desc64_short_addr(desc, dst, src); + desc->size = size; + XLOG(ch, "Add 1D desc64 @ %p, %d-bytes(%lx -> %lx), control:0x%x\n", desc, desc->size, desc->src, desc->dst, desc->control); +} + +INTERNAL_FUNC void +set_2d_desc64_fields(int32_t ch, + idma_desc_t* desch, + void *dst, + void *src, + size_t size, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch) +{ + idma_desc64_t* desc = cvt_desc_to_desc64(desch); + + set_desc64_short_addr(desc, dst, src); + set_desc64_2d_pitch(desc, src_pitch, dst_pitch); + desc->size = size; + desc->nrows = nrows; + + XLOG(ch, "Add 2D desc @ %p, %d-bytes (%x -> %x)\n", desc, desc->size, desc->src, desc->dst); + XLOG(ch, " (#rows:%d, src_pitch:%d, dst_pitch:%d, control:0x%x)\n", desc->nrows, desc->src_pitch, desc->dst_pitch, desc->control); +} + +INTERNAL_FUNC void +set_3d_desc64_fields(int32_t ch, + idma_desc_t* desch, + void *dst, + void *src, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_pitch, + uint32_t dst_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch) +{ + idma_desc64_t* desc = cvt_desc_to_desc64(desch); + + set_desc64_short_addr(desc, dst, src); + set_desc64_3d_pitch(desc, src_pitch, dst_pitch, src_tile_pitch, dst_tile_pitch); + + desc->size = row_sz; + desc->nrows = nrows; + desc->ntiles = ntiles; + + XLOG(ch, "Add 3D desc @ %p, %d-bytes (%x -> %x)\n", desc, desc->size, desc->src, desc->dst); + XLOG(ch, " (#row_sz/rows/tiles:%d/%d/%d, row_pitch:%d/%d, tile_pitch:%d/%d, control:0x%x)\n", + desc->size,desc->nrows, desc->ntiles, desc->src_pitch, desc->dst_pitch, src_tile_pitch, dst_tile_pitch, desc->control); +} + +INTERNAL_FUNC void +set_desc64_ctrl(idma_desc_t* desch, uint32_t flags, uint32_t code) +{ + idma_desc64_t* desc = cvt_desc_to_desc64(desch); + desc->control = (flags | code); +} + +#if (IDMA_USE_WIDE_API > 0) + +INTERNAL_FUNC void +set_desc64_long_addr(idma_desc64_t* desc, void *dst, void *src) +{ + set_desc64_short_addr(desc, dst, src); + desc->ext_src = (cvt_voidp_to_uint32p(src))[1]; + desc->ext_dst = (cvt_voidp_to_uint32p(dst))[1]; +} + +INTERNAL_FUNC void +set_1d_desc64_fields_wide(int32_t ch, + idma_desc_t* desch, + void *dst, + void *src, + size_t size) +{ + idma_desc64_t* desc = cvt_desc_to_desc64(desch); + + set_desc64_long_addr(desc, dst, src); + desc->size = size; + XLOG(ch, "Add 1D desc64 wide @ %p, %d-bytes(%x-%x -> %x-%x), control:0x%x\n", desc, desc->size, desc->ext_src, desc->src, desc->ext_dst, desc->dst, desc->control); +} + +INTERNAL_FUNC void +set_2d_desc64_fields_wide(int32_t ch, + idma_desc_t* desch, + void *dst, + void *src, + size_t size, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch) +{ + idma_desc64_t* desc = cvt_desc_to_desc64(desch); + + set_desc64_long_addr(desc, dst, src); + set_desc64_2d_pitch(desc, src_pitch, dst_pitch); + desc->size = size; + desc->nrows = nrows; + + XLOG(ch, "Add 2D desc wide @ %p, %d-bytes (%x-%x -> %x-%x)\n", desc, desc->size, desc->ext_src, desc->src, desc->ext_dst, desc->dst); + XLOG(ch, " (#rows:%d, src_pitch:%d, dst_pitch:%d, control:0x%x)\n", desc->nrows, desc->src_pitch, desc->dst_pitch, desc->control); +} + +INTERNAL_FUNC void +set_3d_desc64_fields_wide(int32_t ch, + idma_desc_t* desch, + void *dst, + void *src, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_pitch, + uint32_t dst_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch) +{ + idma_desc64_t* desc = cvt_desc_to_desc64(desch); + + set_desc64_long_addr(desc, dst, src); + set_desc64_3d_pitch(desc, src_pitch, dst_pitch, src_tile_pitch, dst_tile_pitch); + desc->size = row_sz; + desc->nrows = nrows; + desc->ntiles = ntiles; + + XLOG(ch, "Add 3D desc wide @ %p, %d-bytes (%x-%x -> %x-%x)\n", desc, desc->size, desc->ext_src, desc->src, desc->ext_dst, desc->dst); + XLOG(ch, " (#row_sz/rows/tiles:%d/%d/%d, row_pitch:%d/%d, tile_pitch:%d/%d, control:0x%x)\n", + desc->size,desc->nrows, desc->ntiles, desc->src_pitch, desc->dst_pitch, src_tile_pitch, dst_tile_pitch, desc->control); +} + +#endif +#endif + +INTERNAL_FUNC void +set_desc_ctrl(idma_desc_t* desc, uint32_t flags, uint32_t code) +{ + desc->control = (flags | code); +} + +INTERNAL_FUNC void +update_next_add_ptr(idma_buf_t* buf) +{ + idma_desc_t* next = &buf->next_add_desc[buf->type]; + + if (next >= buf->last_desc) { + next = &buf->desc; + } + buf->next_add_desc = next; +} + +#if defined(IDMA_USE_XTOS) || defined(IDMA_APP_USE_XTOS) +INTERNAL_FUNC void +update_next_desc(int32_t ch, uint32_t count) +{ + idma_buf_t* buf; + idma_desc_t* next; + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + next = &buf->next_desc[count*(uint32_t)buf->type]; // parasoft-suppress MISRA2012-DIR-4_1_b "Skip check for performance" + + if (next >= buf->last_desc) { + next = &buf->desc + (next - buf->last_desc); // parasoft-suppress MISRA2012-RULE-18_4-4 "Pointer arithmetic cleaner than casting" + } + buf->next_desc = next; + } +} +#endif + +INTERNAL_FUNC void +hw_schedule(int32_t ch, uint32_t count) +{ + extern uint32_t g_idma_ctrl; + +#if XCHAL_HAVE_XEA2 || XCHAL_HAVE_XEA3 + XT_MEMW(); +#endif + WRITE_IDMA_REG(ch, IDMA_REG_CONTROL, 0x1U | g_idma_ctrl); + WRITE_IDMA_REG(ch, IDMA_REG_DESC_INC, count); +} + +INTERNAL_FUNC uint32_t +hw_num_outstanding(int32_t ch) +{ + return READ_IDMA_REG(ch, IDMA_REG_NUM_DESC); +} + +INTERNAL_FUNC int32_t +schedule_desc_fast(int32_t ch, uint32_t count) +{ + idma_buf_t* buf = idma_chan_buf_get(ch); + if (buf != NULL) { + buf->cur_desc_i += (int32_t)count; + buf->cur_desc_i &= INT32_C(0x7fffffff); + + XLOG(ch, "Schedule %d desc from index:%d\n", count, buf->cur_desc_i); + hw_schedule(ch, count); + return buf->cur_desc_i; + } + + return (int32_t) IDMA_ERR_BAD_CHAN; +} + +#if defined(IDMA_USE_XTOS) || defined(IDMA_APP_USE_XTOS) +INTERNAL_FUNC int32_t +schedule_desc(int32_t ch, uint32_t count) +{ + update_next_desc(ch, count); + return schedule_desc_fast(ch, count); +} +#else +int32_t schedule_thread_buffer(int32_t ch, uint32_t count); + +INTERNAL_FUNC int32_t +schedule_desc(int32_t ch, uint32_t count) +{ + return schedule_thread_buffer(ch, count); +} +#endif + +WRAPPER_FUNC idma_buf_t * +convert_buffer_to_buf(idma_buffer_t * buffer) // parasoft-suppress MISRA2012-RULE-8_13_a-4 "Pointer is converted, cannot use const here" +{ + return (idma_buf_t *) buffer; // parasoft-suppress MISRA2012-RULE-11_3-2 "Conversion to internal data type OK" +} + + +idma_status_t idma_sleep_i(int32_t ch); +int32_t idma_buffer_status_i(int32_t ch); +idma_state_t idma_get_state_i(int32_t ch); +idma_status_t idma_init_i(int32_t ch, uint32_t flags, idma_max_block_t block_sz, uint32_t pif_req, idma_ticks_cyc_t ticks_per_cyc, uint32_t timeout_ticks, idma_err_callback_fn err_cb_func); +void idma_stop_i(int32_t ch); +void idma_pause_i(int32_t ch); +void idma_enable_i(int32_t ch); +void idma_resume_i(int32_t ch); +idma_status_t idma_process_tasks_i(int32_t ch); +idma_status_t idma_abort_tasks_i(int32_t ch); +idma_status_t idma_init_task_i (int32_t ch, idma_buffer_t *taskh, idma_type_t type, int32_t ndescs, idma_callback_fn cb_func, void *cb_data); +idma_status_t idma_copy_task_i(int32_t ch, idma_buffer_t *taskh, void *dst, void *src, size_t size, uint32_t flags, void *cb_data, idma_callback_fn cb_func); +idma_status_t idma_copy_task64_i(int32_t ch, idma_buffer_t *taskh, void *dst, void *src, size_t size, uint32_t flags, void *cb_data, idma_callback_fn cb_func); +idma_status_t idma_copy_task64_wide_i(int32_t ch, idma_buffer_t *taskh, void *dst, void *src, size_t size, uint32_t flags, void *cb_data, idma_callback_fn cb_func); +idma_status_t idma_copy_2d_task64_i(int32_t ch, idma_buffer_t *taskh, void *dst, void *src, size_t row_sz, uint32_t flags, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch, void *cb_data, idma_callback_fn cb_func); +idma_status_t idma_copy_2d_task64_wide_i(int32_t ch, idma_buffer_t *taskh, void *dst, void *src, size_t row_sz, uint32_t flags, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch, void *cb_data, idma_callback_fn cb_func); +idma_status_t idma_copy_2d_pred_task64_i(int32_t ch, idma_buffer_t *taskh, void *dst, void *src, size_t row_sz, uint32_t flags, void* pred_mask, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch, void *cb_data, idma_callback_fn cb_func); +idma_status_t idma_copy_2d_pred_task64_wide_i(int32_t ch, idma_buffer_t *taskh, void *dst, void *src, size_t row_sz, uint32_t flags, void* pred_mask, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch, void *cb_data, idma_callback_fn cb_func); +idma_status_t idma_copy_3d_task64_i( int32_t ch, idma_buffer_t *taskh, void *dst, void *src, uint32_t flags, size_t row_sz, uint32_t nrows, uint32_t ntiles, uint32_t src_pitch, uint32_t dst_pitch, uint32_t src_tile_pitch, uint32_t dst_tile_pitch, void *cb_data, idma_callback_fn cb_func); +idma_status_t idma_copy_3d_task64_wide_i( int32_t ch, idma_buffer_t *taskh, void *dst, void *src, uint32_t flags, size_t row_sz, uint32_t nrows, uint32_t ntiles, uint32_t src_pitch, uint32_t dst_pitch, uint32_t src_tile_pitch, uint32_t dst_tile_pitch, void *cb_data, idma_callback_fn cb_func); +idma_status_t idma_copy_2d_task_i(int32_t ch, idma_buffer_t *taskh, void *dst, void *src, size_t row_sz, uint32_t flags, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch, void *cb_data, idma_callback_fn cb_func); +idma_status_t idma_init_loop_i (int32_t ch, idma_buffer_t* bufh, idma_type_t type, int32_t ndescs, void* cb_data, idma_callback_fn cb_func); +idma_hw_error_t idma_buffer_check_errors_i(int32_t ch); +idma_error_details_t* idma_error_details_i(int32_t ch); + + +/************************************************/ +/**** API Implementation ****/ +/************************************************/ + +IDMA_API void +idma_hw_wait_all(IDMA_CHAN_FUNC_ARG_SINGLE) +{ + uint32_t state; + do { + state = READ_IDMA_REG(IDMA_CH_PTR, IDMA_REG_STATUS) & IDMA_STATE_MASK; + if ((state == (uint32_t)IDMA_STATE_DONE) || (state == (uint32_t)IDMA_STATE_IDLE) || (state == (uint32_t)IDMA_STATE_ERROR)) { + break; + } + } while (1); +} + +IDMA_API void +idma_hw_schedule(IDMA_CHAN_FUNC_ARG + uint32_t count) +{ +#if defined(IDMA_USE_XTOS) || defined(IDMA_APP_USE_XTOS) + hw_schedule(IDMA_CH_PTR, count); +#else +# if (LIBIDMA_USE_MULTICHANNEL_API > 0) + (void) idma_schedule_desc(ch, count); +# else + (void) idma_schedule_desc(count); +# endif +#endif +} + +IDMA_API uint32_t +idma_hw_num_outstanding(IDMA_CHAN_FUNC_ARG_SINGLE) +{ + return hw_num_outstanding(IDMA_CH_PTR); +} + +IDMA_API idma_state_t +idma_get_state(IDMA_CHAN_FUNC_ARG_SINGLE) +{ + return idma_get_state_i(IDMA_CH_PTR); +} + +IDMA_API idma_status_t +idma_init( IDMA_CHAN_FUNC_ARG + uint32_t flags, + idma_max_block_t block_sz, + uint32_t pif_req, + idma_ticks_cyc_t ticks_per_cyc, + uint32_t timeout_ticks, + idma_err_callback_fn err_cb_func) +{ + return idma_init_i(IDMA_CH_PTR, flags, block_sz, pif_req, ticks_per_cyc, timeout_ticks, err_cb_func); +} + +IDMA_API idma_status_t +idma_stop(IDMA_CHAN_FUNC_ARG_SINGLE) +{ + idma_stop_i(IDMA_CH_PTR); + return IDMA_OK; +} + +IDMA_API void +idma_pause(IDMA_CHAN_FUNC_ARG_SINGLE) +{ + idma_pause_i(IDMA_CH_PTR); +} + +IDMA_API void +idma_resume(IDMA_CHAN_FUNC_ARG_SINGLE) +{ + idma_resume_i(IDMA_CH_PTR); +} + +IDMA_API idma_status_t +idma_sleep(IDMA_CHAN_FUNC_ARG_SINGLE) +{ +#if defined(IDMA_USERMODE) + return IDMA_CANT_SLEEP; +#else + return idma_sleep_i(IDMA_CH_PTR); +#endif +} + +IDMA_API idma_status_t +idma_init_loop (IDMA_CHAN_FUNC_ARG + idma_buffer_t *bufh, + idma_type_t type, + int32_t ndescs, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_init_loop_i(IDMA_CH_PTR, bufh, type, ndescs, cb_data, cb_func); +} + +IDMA_API int32_t +idma_buffer_status(IDMA_CHAN_FUNC_ARG_SINGLE) { + return idma_buffer_status_i(IDMA_CH_PTR); +} + +IDMA_API idma_status_t +idma_add_desc( idma_buffer_t *bufh, + void *dst, + void *src, + size_t size, + uint32_t flags) +{ + idma_buf_t *buf; + DECLARE_PS(); + IDMA_DISABLE_INTS(); + buf = convert_buffer_to_buf(bufh); + + set_desc_ctrl(buf->next_add_desc, flags, IDMA_1D_DESC_CODE); + set_1d_fields(buf->ch, buf->next_add_desc, dst, src, size); + + update_next_add_ptr(buf); + IDMA_ENABLE_INTS(); + return IDMA_OK; +} + + +static inline idma_status_t +idma_add_2d_desc( idma_buffer_t *bufh, void *dst, void *src, size_t row_sz, uint32_t flags, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch) +{ + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = convert_buffer_to_buf(bufh); + + set_desc_ctrl(buf->next_add_desc, flags, IDMA_2D_DESC_CODE); + set_2d_fields(buf->ch, buf->next_add_desc, dst, src, row_sz, nrows, src_pitch, dst_pitch); + + update_next_add_ptr(buf); + + IDMA_ENABLE_INTS(); + return IDMA_OK; +} + +IDMA_API int32_t +idma_copy_desc(IDMA_CHAN_FUNC_ARG + void *dst, + void *src, + size_t size, + uint32_t flags) +{ + int32_t ret; + idma_buf_t* buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(IDMA_CH_PTR); + + set_desc_ctrl(buf->next_desc, flags, IDMA_1D_DESC_CODE); + set_1d_fields(IDMA_CH_PTR, buf->next_desc, dst, src, size); + + ret = schedule_desc(IDMA_CH_PTR, 1U); + IDMA_ENABLE_INTS(); + + return ret; +} + +IDMA_API int32_t +idma_copy_2d_desc(IDMA_CHAN_FUNC_ARG void *dst, void *src, size_t size, uint32_t flags, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch) +{ + idma_buf_t* buf; + DECLARE_PS(); + int32_t ret = 0; + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(IDMA_CH_PTR); + + set_desc_ctrl(buf->next_desc, flags, IDMA_2D_DESC_CODE); + set_2d_fields (IDMA_CH_PTR, buf->next_desc, dst, src, size, nrows, src_pitch, dst_pitch); + + ret = schedule_desc(IDMA_CH_PTR, 1U); + IDMA_ENABLE_INTS(); + return ret; +} + +IDMA_API int32_t +idma_schedule_desc(IDMA_CHAN_FUNC_ARG + uint32_t count) +{ + int32_t ret; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + ret = schedule_desc(IDMA_CH_PTR, count); + IDMA_ENABLE_INTS(); + return ret; +} + +IDMA_API int32_t +idma_schedule_desc_fast(IDMA_CHAN_FUNC_ARG + uint32_t count) +{ + int32_t ret; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); +#if defined(IDMA_USE_XTOS) || defined(IDMA_APP_USE_XTOS) + ret = schedule_desc_fast(IDMA_CH_PTR, count); +#else + ret = schedule_desc(IDMA_CH_PTR, count); +#endif + IDMA_ENABLE_INTS(); + return ret; +} + +IDMA_API int32_t +idma_desc_done(IDMA_CHAN_FUNC_ARG + int32_t index) +{ + idma_buf_t* buf; + int32_t diff ; + DECLARE_PS(); + int32_t ret = 0; + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(IDMA_CH_PTR); + + if (buf == NULL) { + ret = -1; + } + else if (buf != g_idma_buf_ptr[IDMA_CH_PTR]) { // parasoft-suppress MISRA2012-RULE-14_3_zc--1 "Not a constant expression in all configs" +#if defined(IDMA_USE_XTOS) || defined(IDMA_APP_USE_XTOS) + ret = -1; +#else + /* There are 3 cases to handle when the buffer is not the active buffer: + * - buffer is queued but not yet started, + * - buffer has completed successfully, or + * - buffer has encountered an error. + */ + ret = (buf->pending > 0) ? 0 : (buf->status == 0) ? 1 : -1; +#endif + } + else { + /* Descriptor is done if it's index is less then or equal the difference between + the last scheduled descriptor, and the number of outstanding descriptors. + We take the diff between the last scheduled descriptor and the index. + This diff is (cur_desc_i - index) or 0x7fffffff - (index - cur_desc_i) + depending on which value is larger. + */ + diff = (buf->cur_desc_i - index) & INT32_C(0x7fffffff); + if ((int32_t)hw_num_outstanding(IDMA_CH_PTR) <= diff) { + ret = 1; + } + + XLOG(IDMA_CH_PTR, "Descriptor @%u: %s (remaining: %d, current:%d) \n", + index, ((ret != 0) ? "DONE" : "PENDING"), hw_num_outstanding(IDMA_CH_PTR), buf->cur_desc_i); + } + + IDMA_ENABLE_INTS(); + return ret; +} + +ALWAYS_INLINE idma_status_t +idma_update_desc_dst(IDMA_CHAN_FUNC_ARG + void *dst) +{ + idma_desc_t *desc; + idma_buf_t *buf; +#ifdef IDMA_USE_WIDE_ADDRESS_COMPILE + uint32_t * dstw = cvt_voidp_to_uint32p(dst); +#endif + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(IDMA_CH_PTR); + desc = buf->next_desc; +#ifdef IDMA_USE_WIDE_ADDRESS_COMPILE + desc->dst = dstw[0]; + { + uint32_t wide_addr_mask = IDMA_WIDE_ADDR_MASK; + desc->control = + (desc->control & ~(wide_addr_mask << DST_WIDE_ADDR_SHIFT)) | ((dstw[1] & wide_addr_mask) << DST_WIDE_ADDR_SHIFT); + } + XLOG(IDMA_CH_PTR, "Change dst field for descriptor @ %p to: %p-%p\n", + desc, cvt_uint32_to_voidp(dstw[1]), cvt_uint32_to_voidp(dstw[0])); +#else + desc->dst = cvt_voidp_to_uint32(dst); + XLOG(IDMA_CH_PTR, "Change dst field for descriptor @ %p to: %p\n", + desc, desc->dst); +#endif + IDMA_ENABLE_INTS(); + return IDMA_OK; +} + +ALWAYS_INLINE idma_status_t +idma_update_desc_src(IDMA_CHAN_FUNC_ARG + void *src) +{ + idma_desc_t *desc; + idma_buf_t *buf; +#ifdef IDMA_USE_WIDE_ADDRESS_COMPILE + uint32_t * srcw = cvt_voidp_to_uint32p(src); +#endif + + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(IDMA_CH_PTR); + desc = buf->next_desc; +#ifdef IDMA_USE_WIDE_ADDRESS_COMPILE + desc->src = srcw[0]; + { + uint32_t wide_addr_mask = IDMA_WIDE_ADDR_MASK; + desc->control = + (desc->control & ~(wide_addr_mask << SRC_WIDE_ADDR_SHIFT)) | ((srcw[1] & wide_addr_mask) << SRC_WIDE_ADDR_SHIFT); + } + XLOG(IDMA_CH_PTR, "Change src field for descriptor @ %p to: %p-%p\n", + desc, cvt_uint32_to_voidp(srcw[1]), cvt_uint32_to_voidp(srcw[0])); +#else + desc->src = cvt_voidp_to_uint32(src); + XLOG(IDMA_CH_PTR, "Change src field for descriptor @ %p to: %p\n", + desc, desc->src); +#endif + IDMA_ENABLE_INTS(); + return IDMA_OK; +} + +IDMA_API idma_status_t +idma_update_desc_size(IDMA_CHAN_FUNC_ARG + uint32_t size) +{ + idma_desc_t *desc; + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(IDMA_CH_PTR); + desc = buf->next_desc; + desc->size = size; + + XLOG(IDMA_CH_PTR, "Change size field for descriptor @ %p to: %d\n", desc, desc->size); + IDMA_ENABLE_INTS(); + return IDMA_OK; +} + +#if (IDMA_USE_64B_DESC > 0) + +IDMA_API idma_status_t +idma_update_desc64_dst(int32_t ch, void *dst) // parasoft-suppress MISRA2012-RULE-8_13_a-4 "Cannot use const, dst modified" +{ + idma_desc64_t *desc; + idma_buf_t *buf; + idma_status_t ret; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + desc = cvt_desc_to_desc64(buf->next_desc); + desc->dst = (cvt_voidp_to_uint32p(dst))[0]; + XLOG(ch, "Change dst field for descriptor @ %p to: %p\n", desc, desc->dst); + ret = IDMA_OK; + } + else { + ret = IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +IDMA_API idma_status_t +idma_update_desc64_src(int32_t ch, void *src) // parasoft-suppress MISRA2012-RULE-8_13_a-4 "Cannot use const (backward compatibility)" +{ + idma_desc64_t *desc; + idma_buf_t *buf; + idma_status_t ret; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + desc = cvt_desc_to_desc64(buf->next_desc); + desc->src = (cvt_voidp_to_uint32p(src))[0]; + + XLOG(ch, "Change src field for descriptor @ %p to: %p\n", desc, desc->src); + ret = IDMA_OK; + } + else { + ret = IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +IDMA_API idma_status_t +idma_update_desc64_size(int32_t ch, uint32_t size) +{ + idma_desc64_t *desc; + idma_buf_t *buf; + idma_status_t ret; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + desc = cvt_desc_to_desc64(buf->next_desc); + desc->size = size; + + XLOG(ch, "Change size field for descriptor @ %p to: %d\n", desc, desc->size); + ret = IDMA_OK; + } + else { + ret = IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +#if (IDMA_USE_WIDE_API > 0) + +IDMA_API idma_status_t +idma_update_desc64_dst_wide(int32_t ch, void *dst) // parasoft-suppress MISRA2012-RULE-8_13_a-4 "Cannot use const (backward compatibility)" +{ + idma_desc64_t *desc; + idma_buf_t *buf; + idma_status_t ret; + + DECLARE_PS(); + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + desc = cvt_desc_to_desc64(buf->next_desc); + desc->dst = (cvt_voidp_to_uint32p(dst))[0]; + desc->ext_dst = (cvt_voidp_to_uint32p(dst))[1]; + XLOG(ch, "Change dst field for descriptor @ %p to: %p\n", desc, desc->dst); + ret = IDMA_OK; + } + else { + ret = IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +IDMA_API idma_status_t +idma_update_desc64_src_wide(int32_t ch, void *src) // parasoft-suppress MISRA2012-RULE-8_13_a-4 "Cannot use const (backward compatibility)" +{ + idma_desc64_t *desc; + idma_buf_t *buf; + idma_status_t ret; + + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + desc = cvt_desc_to_desc64(buf->next_desc); + desc->src = (cvt_voidp_to_uint32p(src))[0]; + desc->ext_src = (cvt_voidp_to_uint32p(src))[1]; + XLOG(ch, "Change src field for descriptor @ %p to: %p\n", desc, desc->src); + ret = IDMA_OK; + } + else { + ret = IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +#endif +#endif + +IDMA_API idma_status_t +idma_init_task (IDMA_CHAN_FUNC_ARG + idma_buffer_t *taskh, + idma_type_t type, + int32_t ndescs, + idma_callback_fn cb_func, + void *cb_data) +{ + return idma_init_task_i(IDMA_CH_PTR, taskh, type, ndescs, cb_func, cb_data); +} + +ALWAYS_INLINE idma_status_t +idma_copy_task(IDMA_CHAN_FUNC_ARG + idma_buffer_t *taskh, + void *dst, + void *src, + size_t size, + uint32_t flags, + void *cb_data, + idma_callback_fn cb_func) +{ +#ifdef IDMA_USE_WIDE_ADDRESS_COMPILE + return idma_copy_task_wide_i(IDMA_CH_PTR, taskh, dst, src, size, flags, cb_data, cb_func); +#else + return idma_copy_task_i(IDMA_CH_PTR, taskh, dst, src, size, flags, cb_data, cb_func); +#endif +} + +ALWAYS_INLINE idma_status_t +idma_copy_2d_task(IDMA_CHAN_FUNC_ARG + idma_buffer_t *taskh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + void *cb_data, + idma_callback_fn cb_func) +{ +#ifdef IDMA_USE_WIDE_ADDRESS_COMPILE + return idma_copy_2d_task_wide_i(IDMA_CH_PTR, taskh, dst, src, row_sz, flags, nrows, src_pitch, dst_pitch, cb_data, cb_func); +#else + return idma_copy_2d_task_i(IDMA_CH_PTR, taskh, dst, src, row_sz, flags, nrows, src_pitch, dst_pitch, cb_data, cb_func); +#endif +} + +#if (IDMA_USE_64B_DESC > 0) + +#if (XCHAL_IDMA_HAVE_2DPRED > 0) +IDMA_API idma_status_t +idma_copy_2d_pred_task64(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + void* pred_mask, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_2d_pred_task64_i(ch, taskh, dst, src, row_sz, flags, pred_mask, nrows, src_pitch, dst_pitch, cb_data, cb_func); +} +#endif + +IDMA_API idma_status_t +idma_copy_task64(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t size, + uint32_t flags, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_task64_i(ch, taskh, dst, src, size, flags, cb_data, cb_func); +} + +IDMA_API idma_status_t +idma_copy_2d_task64(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_2d_task64_i(ch, taskh, dst, src, row_sz, flags, nrows, src_pitch, dst_pitch, cb_data, cb_func); +} + +IDMA_API idma_status_t +idma_copy_3d_task64(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_pitch, + uint32_t dst_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_3d_task64_i(ch, taskh, dst, src, flags, row_sz, nrows, ntiles, src_pitch, dst_pitch, src_tile_pitch, dst_tile_pitch, cb_data, cb_func); +} + +IDMA_API idma_status_t +idma_add_desc64( idma_buffer_t *bufh, + void *dst, + void *src, + size_t size, + uint32_t flags) +{ + idma_buf_t *buf; + DECLARE_PS(); + IDMA_DISABLE_INTS(); + buf = convert_buffer_to_buf(bufh); + + set_desc64_ctrl(buf->next_add_desc, flags, IDMA_64B_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_64B_1D_TYPE)); + set_1d_desc64_fields(buf->ch, buf->next_add_desc, dst, src, size); + update_next_add_ptr(buf); + + IDMA_ENABLE_INTS(); + return IDMA_OK; +} + +static inline idma_status_t +idma_add_2d_desc64( idma_buffer_t *bufh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch) +{ + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = convert_buffer_to_buf(bufh); + + set_desc64_ctrl(buf->next_add_desc, flags, IDMA_64B_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_64B_2D_TYPE)); + set_2d_desc64_fields(buf->ch, buf->next_add_desc, dst, src, row_sz, nrows, src_pitch, dst_pitch); + + update_next_add_ptr(buf); + + IDMA_ENABLE_INTS(); + return IDMA_OK; +} + +#if (XCHAL_IDMA_HAVE_2DPRED > 0) +static inline idma_status_t +idma_add_2d_pred_desc64( idma_buffer_t *bufh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + void* pred_mask, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch) +{ + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = convert_buffer_to_buf(bufh); + + set_desc64_ctrl(buf->next_add_desc, flags, IDMA_64B_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_64B_2D_COMPRESS_TYPE)); + set_2d_desc64_fields(buf->ch, buf->next_add_desc, dst, src, row_sz, nrows, src_pitch, dst_pitch); + (cvt_desc_to_desc64(buf->next_add_desc))->pred_mask = cvt_voidp_to_uint32(pred_mask); + + update_next_add_ptr(buf); + + IDMA_ENABLE_INTS(); + return IDMA_OK; +} +#endif + +IDMA_API idma_status_t +idma_add_3d_desc64( idma_buffer_t *bufh, + void *dst, + void *src, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_row_pitch, + uint32_t dst_row_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch) +{ + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = convert_buffer_to_buf(bufh); + set_desc64_ctrl(buf->next_add_desc, flags, IDMA_64B_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_64B_3D_TYPE)); + set_3d_desc64_fields(buf->ch, buf->next_add_desc, dst, src, row_sz, nrows, ntiles, src_row_pitch, dst_row_pitch, src_tile_pitch, dst_tile_pitch); + + update_next_add_ptr(buf); + + IDMA_ENABLE_INTS(); + return IDMA_OK; +} + +IDMA_API int32_t +idma_copy_desc64(int32_t ch, void *dst, void *src, size_t size, uint32_t flags) +{ + int32_t ret; + idma_buf_t* buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc64_ctrl(buf->next_desc, flags, IDMA_64B_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_64B_1D_TYPE)); + set_1d_desc64_fields(ch, buf->next_desc, dst, src, size); + ret = schedule_desc(ch, 1U); + } + else { + ret = (int32_t) IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +IDMA_API int32_t +idma_copy_2d_desc64(int32_t ch, + void *dst, + void *src, + size_t size, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch) +{ + idma_buf_t* buf; + DECLARE_PS(); + int32_t ret; + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc64_ctrl(buf->next_desc, flags, IDMA_64B_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_64B_2D_TYPE)); + set_2d_desc64_fields(ch, buf->next_desc, dst, src, size, nrows, src_pitch, dst_pitch); + + ret = schedule_desc(ch, 1U); + } + else { + ret = (int32_t) IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +#if (XCHAL_IDMA_HAVE_2DPRED > 0) +IDMA_API int32_t +idma_copy_2d_pred_desc64(int32_t ch, void *dst, void *src, size_t size, uint32_t flags, void* pred_mask, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch) +{ + idma_buf_t* buf; + DECLARE_PS(); + int32_t ret; + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc64_ctrl(buf->next_desc, flags, IDMA_64B_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_64B_2D_COMPRESS_TYPE)); + set_2d_desc64_fields(ch, buf->next_desc, dst, src, size, nrows, src_pitch, dst_pitch); + (cvt_desc_to_desc64(buf->next_desc))->pred_mask = cvt_voidp_to_uint32(pred_mask); + + ret = schedule_desc(ch, 1U); + } + else { + ret = (int32_t) IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} +#endif + + +IDMA_API int32_t +idma_copy_3d_desc64(int32_t ch, + void *dst, + void *src, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_row_pitch, + uint32_t dst_row_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch) +{ + idma_buf_t* buf; + DECLARE_PS(); + int32_t ret; + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc64_ctrl(buf->next_desc, flags, IDMA_64B_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_64B_3D_TYPE)); + set_3d_desc64_fields(ch, buf->next_desc, dst, src, row_sz, nrows, ntiles, src_row_pitch, dst_row_pitch, src_tile_pitch, dst_tile_pitch); + + ret = schedule_desc(ch, 1U); + } + else { + ret = (int32_t) IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +#if (IDMA_USE_WIDE_API > 0) + +IDMA_API idma_status_t +idma_copy_task64_wide(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t size, + uint32_t flags, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_task64_wide_i(ch, taskh, dst, src, size, flags, cb_data, cb_func); +} + +IDMA_API idma_status_t +idma_copy_2d_task64_wide(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_2d_task64_wide_i(ch, taskh, dst, src, row_sz, flags, nrows, src_pitch, dst_pitch, cb_data, cb_func); +} + +IDMA_API idma_status_t +idma_copy_3d_task64_wide(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_pitch, + uint32_t dst_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_3d_task64_wide_i(ch, taskh, dst, src, flags, row_sz, nrows, ntiles, src_pitch, dst_pitch, src_tile_pitch, dst_tile_pitch, cb_data, cb_func); +} + +IDMA_API idma_status_t +idma_add_desc64_wide( idma_buffer_t *bufh, + void *dst, + void *src, + size_t size, + uint32_t flags) +{ + idma_buf_t *buf; + DECLARE_PS(); + IDMA_DISABLE_INTS(); + buf = convert_buffer_to_buf(bufh); + + set_desc64_ctrl(buf->next_add_desc, flags, IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | SET_CONTROL_SUBTYPE(IDMA_64B_1D_TYPE)); + set_1d_desc64_fields_wide(buf->ch, buf->next_add_desc, dst, src, size); + update_next_add_ptr(buf); + + IDMA_ENABLE_INTS(); + return IDMA_OK; +} + +IDMA_API int32_t +idma_copy_desc64_wide(int32_t ch, void *dst, void *src, size_t size, uint32_t flags) +{ + int32_t ret; + idma_buf_t* buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc64_ctrl(buf->next_desc, flags, IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | SET_CONTROL_SUBTYPE(IDMA_64B_1D_TYPE)); + set_1d_desc64_fields_wide(ch, buf->next_desc, dst, src, size); + ret = schedule_desc(ch, 1U); + } + else { + ret = (int32_t) IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +#if (XCHAL_IDMA_HAVE_2DPRED > 0) +IDMA_API idma_status_t +idma_copy_2d_pred_task64_wide(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t row_sz, + uint32_t flags, + void* pred_mask, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_2d_pred_task64_wide_i(ch, taskh, dst, src, row_sz, flags, pred_mask, nrows, src_pitch, dst_pitch, cb_data, cb_func); +} + + +static inline idma_status_t +idma_add_2d_pred_desc64_wide( idma_buffer_t *bufh, void *dst, void *src, size_t row_sz, uint32_t flags, void* pred_mask, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch) +{ + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = convert_buffer_to_buf(bufh); + + set_desc64_ctrl(buf->next_add_desc, flags, IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | SET_CONTROL_SUBTYPE(IDMA_64B_2D_COMPRESS_TYPE)); + set_2d_desc64_fields_wide(buf->ch, buf->next_add_desc, dst, src, row_sz, nrows, src_pitch, dst_pitch); + (cvt_desc_to_desc64(buf->next_add_desc))->pred_mask = cvt_voidp_to_uint32(pred_mask); + + update_next_add_ptr(buf); + + IDMA_ENABLE_INTS(); + return IDMA_OK; +} +#endif + +static inline idma_status_t +idma_add_2d_desc64_wide( idma_buffer_t *bufh, void *dst, void *src, size_t row_sz, uint32_t flags, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch) +{ + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + buf = convert_buffer_to_buf(bufh); + + set_desc64_ctrl(buf->next_add_desc, flags, IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | SET_CONTROL_SUBTYPE(IDMA_64B_2D_TYPE)); + set_2d_desc64_fields_wide(buf->ch, buf->next_add_desc, dst, src, row_sz, nrows, src_pitch, dst_pitch); + update_next_add_ptr(buf); + + IDMA_ENABLE_INTS(); + return IDMA_OK; +} + +IDMA_API idma_status_t +idma_add_3d_desc64_wide( idma_buffer_t *bufh, + void *dst, + void *src, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_row_pitch, + uint32_t dst_row_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch) +{ + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = convert_buffer_to_buf(bufh); + set_desc64_ctrl(buf->next_add_desc, flags, IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | SET_CONTROL_SUBTYPE(IDMA_64B_3D_TYPE)); + set_3d_desc64_fields_wide(buf->ch, buf->next_add_desc, dst, src, row_sz, nrows, ntiles, src_row_pitch, dst_row_pitch, src_tile_pitch, dst_tile_pitch); + update_next_add_ptr(buf); + + IDMA_ENABLE_INTS(); + return IDMA_OK; +} + +IDMA_API int32_t +idma_copy_2d_desc64_wide(int32_t ch, void *dst, void *src, size_t size, uint32_t flags, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch) +{ + idma_buf_t* buf; + DECLARE_PS(); + int32_t ret = 0; + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc64_ctrl(buf->next_desc, flags, IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | SET_CONTROL_SUBTYPE(IDMA_64B_2D_TYPE)); + set_2d_desc64_fields_wide(ch, buf->next_desc, dst, src, size, nrows, src_pitch, dst_pitch); + ret = schedule_desc(ch, 1U); + } + else { + ret = (int32_t) IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +#if (XCHAL_IDMA_HAVE_2DPRED > 0) +IDMA_API int32_t +idma_copy_2d_pred_desc64_wide(int32_t ch, void *dst, void *src, size_t size, uint32_t flags, void* pred_mask, uint32_t nrows, uint32_t src_pitch, uint32_t dst_pitch) +{ + idma_buf_t* buf; + DECLARE_PS(); + int32_t ret = 0; + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc64_ctrl(buf->next_desc, flags, IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | SET_CONTROL_SUBTYPE(IDMA_64B_2D_COMPRESS_TYPE)); + set_2d_desc64_fields_wide(ch, buf->next_desc, dst, src, size, nrows, src_pitch, dst_pitch); + (cvt_desc_to_desc64(buf->next_desc))->pred_mask = cvt_voidp_to_uint32(pred_mask); + ret = schedule_desc(ch, 1U); + } + else { + ret = (int32_t) IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} +#endif + +IDMA_API int32_t +idma_copy_3d_desc64_wide(int32_t ch, + void *dst, + void *src, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t ntiles, + uint32_t src_row_pitch, + uint32_t dst_row_pitch, + uint32_t src_tile_pitch, + uint32_t dst_tile_pitch) +{ + idma_buf_t* buf; + DECLARE_PS(); + int32_t ret = 0; + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc64_ctrl(buf->next_desc, flags, IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | SET_CONTROL_SUBTYPE(IDMA_64B_3D_TYPE)); + set_3d_desc64_fields_wide(ch, buf->next_desc, dst, src, row_sz, nrows, ntiles, src_row_pitch, dst_row_pitch, src_tile_pitch, dst_tile_pitch); + ret = schedule_desc(ch, 1U); + } + else { + ret = (int32_t) IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} +#endif +#endif //64B + + +IDMA_API idma_status_t +idma_process_tasks(IDMA_CHAN_FUNC_ARG_SINGLE) +{ + return idma_process_tasks_i(IDMA_CH_PTR); +} + +IDMA_API idma_error_details_t* +idma_error_details(IDMA_CHAN_FUNC_ARG_SINGLE) +{ + return idma_error_details_i(IDMA_CH_PTR); +} + +IDMA_API idma_error_details_t* +idma_buffer_error_details(IDMA_CHAN_FUNC_ARG_SINGLE) +{ + return idma_error_details_i(IDMA_CH_PTR); +} + +IDMA_API idma_hw_error_t +idma_buffer_check_errors(IDMA_CHAN_FUNC_ARG_SINGLE) +{ + return idma_buffer_check_errors_i(IDMA_CH_PTR); +} + +IDMA_API idma_status_t +idma_abort_tasks(IDMA_CHAN_FUNC_ARG_SINGLE) +{ + return idma_abort_tasks_i(IDMA_CH_PTR); +} + + +IDMA_API int32_t +idma_task_status(idma_buffer_t *taskh) +{ + idma_buf_t* task; + task = convert_buffer_to_buf(taskh); + + XLOG(task->ch, "Task %p status '%s' (%d)\n", task, + (task->status == (int32_t)IDMA_TASK_ERROR) ? "Error" : + (task->status == (int32_t)IDMA_TASK_DONE) ? "Done" : + (task->status > (int32_t)IDMA_TASK_DONE) ? "Pending" : "UNKNOWN" , task->status); + + return (task->status); +} + + +IDMA_API int32_t +idma_schedule_desc_clock(IDMA_CHAN_FUNC_ARG + uint32_t count, + uint32_t *ptime) +{ + int32_t ret; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + ret = schedule_desc(IDMA_CH_PTR, count); + *ptime = (uint32_t) clock(); // parasoft-suppress MISRA2012-RULE-21_10-2 "This function is used for profiling only." + IDMA_ENABLE_INTS(); + return ret; +} + +IDMA_API int32_t +idma_schedule_desc_fast_clock(IDMA_CHAN_FUNC_ARG + uint32_t count, + uint32_t *ptime) +{ + int32_t ret; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + ret = schedule_desc_fast(IDMA_CH_PTR, count); + *ptime = (uint32_t) clock(); // parasoft-suppress MISRA2012-RULE-21_10-2 "This function is used for profiling only." + IDMA_ENABLE_INTS(); + return ret; +} + + +#if (XCHAL_IDMA_HAVE_FBC > 0) + +typedef enum { + IDMA_FBC_SF_1_1 = 0, + IDMA_FBC_SF_1_2 = 1, + IDMA_FBC_SF_3_8 = 2, +} idma_fbc_sf_t; + +typedef enum { + IDMA_FBC_CTW_32B = 0, + IDMA_FBC_CTW_64B = 1, + IDMA_FBC_CTW_128B = 2, + IDMA_FBC_CTW_256B = 3, + IDMA_FBC_CTW_512B = 4, +} idma_fbc_ctw_t; + +typedef enum { + IDMA_FBC_CTH_2 = 0, + IDMA_FBC_CTH_4 = 1, + IDMA_FBC_CTH_8 = 2, + IDMA_FBC_CTH_16 = 3, + IDMA_FBC_CTH_32 = 4, +} idma_fbc_cth_t; + + +idma_status_t +idma_copy_fbc_task64_i(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + void *baseaddr, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + idma_fbc_sf_t sf, + idma_fbc_ctw_t ctw, + idma_fbc_cth_t cth, + uint16_t custom, + void *cb_data, + idma_callback_fn cb_func); + +idma_status_t +idma_copy_fbc_task64_wide_i(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + void *baseaddr, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + idma_fbc_sf_t sf, + idma_fbc_ctw_t ctw, + idma_fbc_cth_t cth, + uint16_t custom, + void *cb_data, + idma_callback_fn cb_func); + + +INTERNAL_FUNC void +set_fbc_desc64_fields(idma_desc_t *desch, + uint32_t baseaddr_lo, + uint32_t baseaddr_hi, + idma_fbc_sf_t sf, + idma_fbc_ctw_t ctw, + idma_fbc_cth_t cth, + uint16_t custom) +{ + idma_desc64_t *desc = cvt_desc_to_desc64(desch); + + desc->word13 = baseaddr_lo; + desc->word14 = ((uint32_t)(custom >> 4) << 20) | + ((uint32_t)sf << 18) | + ((uint32_t)ctw << 15) | + ((uint32_t)cth << 12) | + ((custom & 0xF) << 8) | + (baseaddr_hi & 0xFF); +} + + +IDMA_API idma_status_t +idma_add_fbc_desc64( idma_buffer_t *bufh, + void *dst, + void *src, + void *baseaddr, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + idma_fbc_sf_t sf, + idma_fbc_ctw_t ctw, + idma_fbc_cth_t cth, + uint16_t custom) +{ + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = convert_buffer_to_buf(bufh); + + set_desc64_ctrl(buf->next_add_desc, + flags, + IDMA_64B_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_64B_2D_FBC_TYPE)); + + set_2d_desc64_fields(buf->ch, + buf->next_add_desc, + dst, + src, + row_sz, + nrows, + src_pitch, + dst_pitch); + + set_fbc_desc64_fields(buf->next_add_desc, + cvt_voidp_to_uint32(baseaddr), + 0U, + sf, + ctw, + cth, + custom); + + update_next_add_ptr(buf); + IDMA_ENABLE_INTS(); + + return IDMA_OK; +} + +IDMA_API int32_t +idma_copy_fbc_desc64(int32_t ch, + void *dst, + void *src, + void *baseaddr, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + idma_fbc_sf_t sf, + idma_fbc_ctw_t ctw, + idma_fbc_cth_t cth, + uint16_t custom) +{ + idma_buf_t *buf; + int32_t ret; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc64_ctrl(buf->next_desc, + flags, + IDMA_64B_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_64B_2D_FBC_TYPE)); + + set_2d_desc64_fields(ch, + buf->next_desc, + dst, + src, + row_sz, + nrows, + src_pitch, + dst_pitch); + + set_fbc_desc64_fields(buf->next_desc, + cvt_voidp_to_uint32(baseaddr), + 0U, + sf, + ctw, + cth, + custom); + + ret = schedule_desc(ch, 1U); + } + else { + ret = (int32_t) IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +IDMA_API idma_status_t +idma_copy_fbc_task64(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + void *baseaddr, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + idma_fbc_sf_t sf, + idma_fbc_ctw_t ctw, + idma_fbc_cth_t cth, + uint16_t custom, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_fbc_task64_i(ch, taskh, dst, src, baseaddr, flags, + row_sz, nrows, src_pitch, dst_pitch, sf, ctw, cth, + custom, cb_data, cb_func); +} + +#if (IDMA_USE_WIDE_API > 0) + +IDMA_API idma_status_t +idma_add_fbc_desc64_wide(idma_buffer_t *bufh, + void *dst, + void *src, + void *baseaddr, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + idma_fbc_sf_t sf, + idma_fbc_ctw_t ctw, + idma_fbc_cth_t cth, + uint16_t custom) +{ + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = convert_buffer_to_buf(bufh); + + set_desc64_ctrl(buf->next_add_desc, + flags, + IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | + SET_CONTROL_SUBTYPE(IDMA_64B_2D_FBC_TYPE)); + + set_2d_desc64_fields_wide(buf->ch, + buf->next_add_desc, + dst, + src, + row_sz, + nrows, + src_pitch, + dst_pitch); + + set_fbc_desc64_fields(buf->next_add_desc, + (cvt_voidp_to_uint32p(baseaddr))[0], + (cvt_voidp_to_uint32p(baseaddr))[1], + sf, + ctw, + cth, + custom); + + update_next_add_ptr(buf); + IDMA_ENABLE_INTS(); + + return IDMA_OK; +} + +IDMA_API int32_t +idma_copy_fbc_desc64_wide(int32_t ch, + void *dst, + void *src, + void *baseaddr, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + idma_fbc_sf_t sf, + idma_fbc_ctw_t ctw, + idma_fbc_cth_t cth, + uint16_t custom) +{ + idma_buf_t* buf; + int32_t ret; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc64_ctrl(buf->next_desc, + flags, + IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | + SET_CONTROL_SUBTYPE(IDMA_64B_2D_FBC_TYPE)); + + set_2d_desc64_fields_wide(ch, + buf->next_desc, + dst, + src, + row_sz, + nrows, + src_pitch, + dst_pitch); + + set_fbc_desc64_fields(buf->next_desc, + (cvt_voidp_to_uint32p(baseaddr))[0], + (cvt_voidp_to_uint32p(baseaddr))[1], + sf, + ctw, + cth, + custom); + + ret = schedule_desc(ch, 1U); + } + else { + ret = (int32_t) IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +IDMA_API idma_status_t +idma_copy_fbc_task64_wide(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + void *baseaddr, + uint32_t flags, + size_t row_sz, + uint32_t nrows, + uint32_t src_pitch, + uint32_t dst_pitch, + idma_fbc_sf_t sf, + idma_fbc_ctw_t ctw, + idma_fbc_cth_t cth, + uint16_t custom, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_fbc_task64_wide_i(ch, taskh, dst, src, baseaddr, flags, + row_sz, nrows, src_pitch, dst_pitch, + sf, ctw, cth, custom, cb_data, cb_func); +} + +#endif // IDMA_USE_WIDE_API + +#endif // XCHAL_IDMA_HAVE_FBC + + +#if (XCHAL_IDMA_HAVE_ZVC > 0) + +idma_status_t +idma_copy_zvc_task_i(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t size, + void *table_addr, + uint32_t flags, + void *cb_data, + idma_callback_fn cb_func); + +idma_status_t +idma_copy_zvc_task64_wide_i(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t size, + void *table_addr, + uint32_t flags, + void *cb_data, + idma_callback_fn cb_func); + +INTERNAL_FUNC void +set_zvc_desc_fields(idma_desc_t *desch, + void *table_addr) +{ + idma_2d_desc_t *desc2d = (idma_2d_desc_t *) desch; + + desc2d->word8 = cvt_voidp_to_uint32(table_addr); +} + +IDMA_API idma_status_t +idma_add_zvc_desc(idma_buffer_t *bufh, + void *dst, + void *src, + size_t size, + void *table_addr, + uint32_t flags) +{ + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + buf = convert_buffer_to_buf(bufh); + + set_desc_ctrl(buf->next_add_desc, + flags, + IDMA_ZVC_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_ZVC_1D_TYPE)); + set_2d_fields(buf->ch, buf->next_add_desc, dst, src, size, 0, 0, 0); + set_zvc_desc_fields(buf->next_add_desc, table_addr); + + update_next_add_ptr(buf); + IDMA_ENABLE_INTS(); + + return IDMA_OK; +} + +IDMA_API int32_t +idma_copy_zvc_desc(int32_t ch, + void *dst, + void *src, + size_t size, + void *table_addr, + uint32_t flags) +{ + idma_buf_t* buf; + int32_t ret; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc_ctrl(buf->next_desc, + flags, + IDMA_ZVC_DESC_CODE | SET_CONTROL_SUBTYPE(IDMA_ZVC_1D_TYPE)); + set_2d_fields(ch, buf->next_desc, dst, src, size, 0, 0, 0); + set_zvc_desc_fields(buf->next_desc, table_addr); + + ret = schedule_desc(ch, 1U); + } + else { + ret = IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +ALWAYS_INLINE idma_status_t +idma_copy_zvc_task(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t size, + void *table_addr, + uint32_t flags, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_zvc_task_i(ch, taskh, dst, src, size, table_addr, + flags, cb_data, cb_func); +} + + +#if (IDMA_USE_WIDE_API > 0) + +IDMA_API idma_status_t +idma_add_zvc_desc64_wide(idma_buffer_t *bufh, + void *dst, + void *src, + size_t size, + void *table_addr, + uint32_t flags) +{ + idma_buf_t *buf; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + buf = convert_buffer_to_buf(bufh); + + set_desc64_ctrl(buf->next_add_desc, + flags, + IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | + SET_CONTROL_SUBTYPE(IDMA_ZVC_1D_TYPE)); + set_2d_desc64_fields_wide(buf->ch, buf->next_add_desc, dst, src, size, 0, 0, 0); + set_zvc_desc_fields(buf->next_add_desc, table_addr); + + update_next_add_ptr(buf); + IDMA_ENABLE_INTS(); + + return IDMA_OK; +} + +IDMA_API int32_t +idma_copy_zvc_desc64_wide(int32_t ch, + void *dst, + void *src, + size_t size, + void *table_addr, + uint32_t flags) +{ + idma_buf_t* buf; + int32_t ret; + DECLARE_PS(); + + IDMA_DISABLE_INTS(); + + buf = idma_chan_buf_get(ch); + if (buf != NULL) { + set_desc_ctrl(buf->next_desc, + flags, + IDMA_64B_DESC_CODE | IDMA_64B_LONG_ADDR_CTRL_BIT_MASK | + SET_CONTROL_SUBTYPE(IDMA_ZVC_1D_TYPE)); + set_2d_desc64_fields_wide(ch, buf->next_desc, dst, src, size, 0, 0, 0); + set_zvc_desc_fields(buf->next_desc, table_addr); + + ret = schedule_desc(ch, 1U); + } + else { + ret = IDMA_ERR_NO_BUF; + } + + IDMA_ENABLE_INTS(); + return ret; +} + +ALWAYS_INLINE idma_status_t +idma_copy_zvc_task64_wide(int32_t ch, + idma_buffer_t *taskh, + void *dst, + void *src, + size_t size, + void *table_addr, + uint32_t flags, + void *cb_data, + idma_callback_fn cb_func) +{ + return idma_copy_zvc_task64_wide_i(ch, taskh, dst, src, size, table_addr, + flags, cb_data, cb_func); +} + +#endif // IDMA_USE_WIDE_API + +#endif // XCHAL_IDMA_HAVE_ZVC + + +#ifdef __cplusplus +} +#endif + +#endif + +#endif /* __IDMA_H__ */ diff --git a/src/platform/amd/acp_7_0/include/arch/xtensa/tie/xt_externalregisters.h b/src/platform/amd/acp_7_0/include/arch/xtensa/tie/xt_externalregisters.h new file mode 100644 index 000000000000..0fbb7e17e800 --- /dev/null +++ b/src/platform/amd/acp_7_0/include/arch/xtensa/tie/xt_externalregisters.h @@ -0,0 +1,77 @@ +// Customer ID=18056; Build=0xa6a6b; Copyright (c) 2017-2019 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. + +/* Definitions for the xt_externalregisters TIE package */ + +/* Do not modify. This is automatically generated.*/ + +/* parasoft-begin-suppress ALL "This file not MISRA checked." */ + +#ifndef _XTENSA_xt_externalregisters_HEADER +#define _XTENSA_xt_externalregisters_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + +#ifndef _ASMLANGUAGE +#ifndef _NOCLANGUAGE +#ifndef __ASSEMBLER__ + +#include <xtensa/tie/xt_core.h> + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern unsigned _TIE_xt_externalregisters_RER(unsigned ars /*in*/); +extern unsigned _TIE_xt_externalregisters_RSR_ERACCESS(void); +extern void _TIE_xt_externalregisters_WER(unsigned art /*in*/, unsigned ars /*in*/); +extern void _TIE_xt_externalregisters_WSR_ERACCESS(unsigned art /*in*/); +extern void _TIE_xt_externalregisters_XSR_ERACCESS(unsigned art /*inout*/); + +#endif /*__ASSEMBLER__*/ +#endif /*_NOCLANGUAGE*/ +#endif /*_ASMLANGUAGE*/ + +#define XT_RER _TIE_xt_externalregisters_RER +#define XT_RSR_ERACCESS _TIE_xt_externalregisters_RSR_ERACCESS +#define XT_WER _TIE_xt_externalregisters_WER +#define XT_WSR_ERACCESS _TIE_xt_externalregisters_WSR_ERACCESS +#define XT_XSR_ERACCESS _TIE_xt_externalregisters_XSR_ERACCESS + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ + +#endif /* !_XTENSA_xt_externalregisters_HEADER */ + +/* parasoft-end-suppress ALL "This file not MISRA checked." */ diff --git a/src/platform/amd/acp_7_0/include/arch/xtensa/xtensa-types.h b/src/platform/amd/acp_7_0/include/arch/xtensa/xtensa-types.h new file mode 100644 index 000000000000..4a0d2cd90404 --- /dev/null +++ b/src/platform/amd/acp_7_0/include/arch/xtensa/xtensa-types.h @@ -0,0 +1,65 @@ +/* + * xtensa-types.h -- General type definitions and macros. + */ + +/* + * Copyright (c) 2002-2018 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. + */ + +#ifndef XTENSA_TYPES_H +#define XTENSA_TYPES_H + +/* parasoft-begin-suppress MISRA2012-RULE-20_7 "Cannot parenthesize macro args here" */ +#if defined (_ASMLANGUAGE) || defined (__ASSEMBLER__) + +/* Redefine stdint.h macros for assembler. */ +/* parasoft-begin-suppress MISRA2012-RULE-21_1_c "It is necessary to redefine these to enable assembly code to compile." */ +#define INT8_C(x) x +#define UINT8_C(x) x +#define INT16_C(x) x +#define UINT16_C(x) x +#define INT32_C(x) x +#define UINT32_C(x) x +#define INT64_C(x) x +#define UINT64_C(x) x +/* parasoft-end-suppress MISRA2012-RULE-21_1_c "It is necessary to redefine these to enable assembly code to compile." */ + +#else + +#include <stdint.h> + +/* Adapt inline spec for older and newer versions of C standard. */ +#if (__STDC_VERSION__ >= 199901L) || defined (__cplusplus) +#define XT_INLINE __attribute__((always_inline)) static inline +#else +#define XT_INLINE __attribute__((always_inline)) static __inline__ +#endif + +/* This macro is used to mark unused function parameters and suppress warnings + from compiler / MISRA checker. + */ +#define UNUSED(x) ((void)(x)) + +#endif +/* parasoft-end-suppress MISRA2012-RULE-20_7 "Cannot parenthesize macro args here" */ + +#endif // XTENSA_TYPES_H diff --git a/src/platform/amd/acp_7_0/include/platform/chip_offset_byte.h b/src/platform/amd/acp_7_0/include/platform/chip_offset_byte.h deleted file mode 100644 index cce6411e24f8..000000000000 --- a/src/platform/amd/acp_7_0/include/platform/chip_offset_byte.h +++ /dev/null @@ -1,222 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2024 AMD.All rights reserved. - * - * Author: SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> - */ - -#ifndef _ACP_7_0_OFFSET_HEADER -#define _ACP_7_0_OFFSET_HEADER - -#define PU_REGISTER_BASE (0x9FD00000 - 0x01240000) -#define PU_SCRATCH_REG_BASE (0x9FF00000 - 0x01250000) - -/* Registers from ACP_DMA block */ -#define ACP_DMA_CNTL_0 0x1240000 -#define ACP_DMA_DSCR_STRT_IDX_0 0x1240028 -#define ACP_DMA_DSCR_CNT_0 0x1240050 -#define ACP_DMA_PRIO_0 0x1240078 -#define ACP_DMA_DESC_BASE_ADDR 0x1240118 -#define ACP_DMA_DESC_MAX_NUM_DSCR 0x124011C -#define ACP_DMA_CH_STS 0x1240120 -#define ACP_DSP0_NONCACHE_OFFSET0 0x1240400 -#define ACP_DSP0_NONCACHE_SIZE0 0x1240404 -#define ACP_DSP0_NONCACHE_OFFSET1 0x1240408 -#define ACP_DSP0_NONCACHE_SIZE1 0x124040C -#define ACP_XNNE_IDLE_STATE 0x1240550 - -/* Registers from ACP_MISC block */ -#define ACP_INTR_URGENCY_TIMER 0x124101C -#define ACP_SYSHUB_DMA_URGENCY_TIMER 0x1240838 -#define ACP_OCD_HALT_ON_RST 0x124100C -#define ACP_CLKMUX_SEL 0x124102C -#define ACP_I2S_196MHZ_CLK_SEL 0x124103C -#define ACP_DSP0_INTR_CNTL 0x1241800 -#define ACP_DSP0_INTR_STAT 0x1241804 -#define ACP_DSP_SW_INTR_CNTL 0x1241808 -#define ACP_DSP_SW_INTR_STAT 0x124180C -#define ACP_SW_INTR_TRIG 0x1241810 -#define DSP_INTERRUPT_ROUTING_CTRL_0 0x1241814 -#define DSP_INTERRUPT_ROUTING_CTRL_1 0x1241818 -#define ACP_DSP_FW_STATUS 0x1241850 -#define ACP_FUTURE_REG_ACLK_0 0x1241854 -#define ACP_AXI2DAGB_SEM_0 0x1241874 -#define ACP_DSP0_INTR_CNTL1 0x1241920 -#define ACP_DSP0_INTR_STAT1 0x1241924 -#define ACP_SRBM_CLIENT_BASE_ADDR 0x12419EC -#define ACP_SRBM_CLIENT_RDDATA 0x12419F0 -#define ACP_SRBM_CYCLE_STS 0x12419F4 -#define ACP_SRBM_CLIENT_CONFIG 0x12419F8 - -/* Registers from ACP_P1_MISC block */ -#define ACP_EXTERNAL_INTR_ENB 0x1241A00 - -/* Registers from ACP_AUDIO_BUFFERS block */ -#define ACP_AUDIO_RX_RINGBUFADDR 0x1242000 -#define ACP_AUDIO_RX_RINGBUFSIZE 0x1242004 -#define ACP_AUDIO_RX_LINKPOSITIONCNTR 0x1242008 -#define ACP_AUDIO_RX_FIFOADDR 0x124200C -#define ACP_AUDIO_RX_FIFOSIZE 0x1242010 -#define ACP_AUDIO_RX_DMA_SIZE 0x1242014 -#define ACP_AUDIO_RX_LINEARPOSITIONCNTR_HIGH 0x1242018 -#define ACP_AUDIO_RX_LINEARPOSITIONCNTR_LOW 0x124201C -#define ACP_AUDIO_RX_INTR_WATERMARK_SIZE 0x1242020 -#define ACP_AUDIO_TX_RINGBUFADDR 0x1242024 -#define ACP_AUDIO_TX_RINGBUFSIZE 0x1242028 -#define ACP_AUDIO_TX_LINKPOSITIONCNTR 0x124202C -#define ACP_AUDIO_TX_FIFOADDR 0x1242030 -#define ACP_AUDIO_TX_FIFOSIZE 0x1242034 -#define ACP_AUDIO_TX_DMA_SIZE 0x1242038 -#define ACP_AUDIO_TX_LINEARPOSITIONCNTR_HIGH 0x124203C -#define ACP_AUDIO_TX_LINEARPOSITIONCNTR_LOW 0x1242040 -#define ACP_AUDIO_TX_INTR_WATERMARK_SIZE 0x1242044 - -#define ACP_BT_RX_RINGBUFADDR 0x1242048 -#define ACP_BT_RX_RINGBUFSIZE 0x124204C -#define ACP_BT_RX_FIFOADDR 0x1242054 -#define ACP_BT_RX_FIFOSIZE 0x1242058 -#define ACP_BT_RX_DMA_SIZE 0x124205C -#define ACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x1242060 -#define ACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x1242064 -#define ACP_BT_RX_INTR_WATERMARK_SIZE 0x1242068 -#define ACP_BT_TX_RINGBUFADDR 0x124206C -#define ACP_BT_TX_RINGBUFSIZE 0x1242070 -#define ACP_BT_TX_FIFOADDR 0x1242078 -#define ACP_BT_TX_FIFOSIZE 0x124207C -#define ACP_BT_TX_DMA_SIZE 0x1242080 -#define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x1242084 -#define ACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x1242088 -#define ACP_BT_TX_INTR_WATERMARK_SIZE 0x124208C - -#define ACP_HS_RX_RINGBUFADDR 0x1242090 -#define ACP_HS_RX_RINGBUFSIZE 0x1242094 -#define ACP_HS_RX_FIFOADDR 0x124209C -#define ACP_HS_RX_FIFOSIZE 0x12420A0 -#define ACP_HS_RX_DMA_SIZE 0x12420A4 -#define ACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x12420A8 -#define ACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x12420AC -#define ACP_HS_RX_INTR_WATERMARK_SIZE 0x12420B0 -#define ACP_HS_TX_RINGBUFADDR 0x12420B4 -#define ACP_HS_TX_RINGBUFSIZE 0x12420B8 -#define ACP_HS_TX_FIFOADDR 0x12420C0 -#define ACP_HS_TX_FIFOSIZE 0x12420C4 -#define ACP_HS_TX_DMA_SIZE 0x12420C8 -#define ACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x12420CC -#define ACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x12420D0 -#define ACP_HS_TX_INTR_WATERMARK_SIZE 0x12420D4 - -/* Registers from ACP_I2S_TDM block */ -#define ACP_I2STDM_IER 0x1242400 -#define ACP_I2STDM_IRER 0x1242404 -#define ACP_I2STDM_RXFRMT 0x1242408 -#define ACP_I2STDM_ITER 0x124240C -#define ACP_I2STDM_TXFRMT 0x1242410 -#define ACP_I2STDM0_MSTRCLKGEN 0x1242414 -#define ACP_I2STDM2_MSTRCLKGEN 0x124241C - -/* Registers from ACP_BT_TDM block */ -#define ACP_BTTDM_IER 0x1242800 -#define ACP_BTTDM_IRER 0x1242804 -#define ACP_BTTDM_ITER 0x124280C -#define ACP_HSTDM_IER 0x1242814 -#define ACP_HSTDM_IRER 0x1242818 -#define ACP_HSTDM_RXFRMT 0x124281C -#define ACP_HSTDM_ITER 0x1242820 -#define ACP_HSTDM_TXFRMT 0x1242824 - -/* Registers from ACP_WOV block */ -#define ACP_WOV_PDM_ENABLE 0x1242C04 -#define ACP_WOV_PDM_DMA_ENABLE 0x1242C08 -#define ACP_WOV_RX_RINGBUFADDR 0x1242C0C -#define ACP_WOV_RX_RINGBUFSIZE 0x1242C10 -#define ACP_WOV_RX_INTR_WATERMARK_SIZE 0x1242C20 -#define ACP_WOV_PDM_FIFO_FLUSH 0x1242C24 -#define ACP_WOV_PDM_NO_OF_CHANNELS 0x1242C28 -#define ACP_WOV_PDM_DECIMATION_FACTOR 0x1242C2C -#define ACP_WOV_MISC_CTRL 0x1242C5C -#define ACP_WOV_CLK_CTRL 0x1242C60 - -/* Registers from ACP_P1_AUDIO_BUFFERS block */ -#define ACP_P1_I2S_RX_RINGBUFADDR 0x1243A00 -#define ACP_P1_I2S_RX_RINGBUFSIZE 0x1243A04 -#define ACP_P1_I2S_RX_FIFOADDR 0x1243A0C -#define ACP_P1_I2S_RX_FIFOSIZE 0x1243A10 -#define ACP_P1_I2S_RX_DMA_SIZE 0x1243A14 -#define ACP_P1_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x1243A18 -#define ACP_P1_I2S_RX_LINEARPOSITIONCNTR_LOW 0x1243A1C -#define ACP_P1_I2S_RX_INTR_WATERMARK_SIZE 0x1243A20 -#define ACP_P1_I2S_TX_RINGBUFADDR 0x1243A24 -#define ACP_P1_I2S_TX_RINGBUFSIZE 0x1243A28 -#define ACP_P1_I2S_TX_FIFOADDR 0x1243A30 -#define ACP_P1_I2S_TX_FIFOSIZE 0x1243A34 -#define ACP_P1_I2S_TX_DMA_SIZE 0x1243A38 -#define ACP_P1_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x1243A3C -#define ACP_P1_I2S_TX_LINEARPOSITIONCNTR_LOW 0x1243A40 -#define ACP_P1_I2S_TX_INTR_WATERMARK_SIZE 0x1243A44 -#define ACP_P1_BT_RX_RINGBUFADDR 0x1243A48 -#define ACP_P1_BT_RX_RINGBUFSIZE 0x1243A4C -#define ACP_P1_BT_RX_FIFOADDR 0x1243A54 -#define ACP_P1_BT_RX_FIFOSIZE 0x1243A58 -#define ACP_P1_BT_RX_DMA_SIZE 0x1243A5C -#define ACP_P1_BT_RX_LINEARPOSITIONCNTR_HIGH 0x1243A60 -#define ACP_P1_BT_RX_LINEARPOSITIONCNTR_LOW 0x1243A64 -#define ACP_P1_BT_RX_INTR_WATERMARK_SIZE 0x1243A68 -#define ACP_P1_BT_TX_RINGBUFADDR 0x1243A6C -#define ACP_P1_BT_TX_RINGBUFSIZE 0x1243A70 -#define ACP_P1_BT_TX_FIFOADDR 0x1243A78 -#define ACP_P1_BT_TX_FIFOSIZE 0x1243A7C -#define ACP_P1_BT_TX_DMA_SIZE 0x1243A80 -#define ACP_P1_BT_TX_LINEARPOSITIONCNTR_HIGH 0x1243A84 -#define ACP_P1_BT_TX_LINEARPOSITIONCNTR_LOW 0x1243A88 -#define ACP_P1_BT_TX_INTR_WATERMARK_SIZE 0x1243A8C -#define ACP_P1_HS_RX_RINGBUFADDR 0x1243A90 -#define ACP_P1_HS_RX_RINGBUFSIZE 0x1243A94 -#define ACP_P1_HS_RX_FIFOADDR 0x1243A9C -#define ACP_P1_HS_RX_FIFOSIZE 0x1243AA0 -#define ACP_P1_HS_RX_DMA_SIZE 0x1243AA4 -#define ACP_P1_HS_RX_LINEARPOSITIONCNTR_HIGH 0x1243AA8 -#define ACP_P1_HS_RX_LINEARPOSITIONCNTR_LOW 0x1243AAC -#define ACP_P1_HS_RX_INTR_WATERMARK_SIZE 0x1243AB0 -#define ACP_P1_HS_TX_RINGBUFADDR 0x1243AB4 -#define ACP_P1_HS_TX_RINGBUFSIZE 0x1243AB8 -#define ACP_P1_HS_TX_FIFOADDR 0x1243AC0 -#define ACP_P1_HS_TX_FIFOSIZE 0x1243AC4 -#define ACP_P1_HS_TX_DMA_SIZE 0x1243AC8 -#define ACP_P1_HS_TX_LINEARPOSITIONCNTR_HIGH 0x1243ACC -#define ACP_P1_HS_TX_LINEARPOSITIONCNTR_LOW 0x1243AD0 -#define ACP_P1_HS_TX_INTR_WATERMARK_SIZE 0x1243AD4 - -#define MP1_SMN_C2PMSG_69 0x58A14 -#define MP1_SMN_C2PMSG_85 0x58A54 -#define MP1_SMN_C2PMSG_93 0x58A74 - -#define CLK7_ROOTREFCLK_MUX_1 0x6C0C8 -#define CLK7_CLK_PLL_REFCLK_RATE_STARTUP 0x6C0D0 -#define CLK7_CLK_PLL_REQ 0x6C0DC -#define CLK7_CLK1_DFS_CNTL 0x6C1B0 -#define CLK7_CLK1_CURRENT_CNT 0x6C378 -#define CLK7_CLK0_DFS_CNTL 0x6C1A4 -#define CLK7_CLK0_CURRENT_CNT 0x6C374 -#define CLK7_CLK0_BYPASS_CNTL 0x6C210 -#define CLK7_CLK1_BYPASS_CNTL 0x6C234 -#define CLK7_CLK0_DFS_STATUS 0x6C1AC -#define CLK7_CLK1_DFS_STATUS 0x6C1B8 -#define CLK7_SPLL_FIELD_2 0x6C114 -#define CLK7_CLK2_CURRENT_CNT 0x6C37C -#define CLK7_CLK2_BYPASS_CNTL 0x6C258 -#define CLK7_CLK2_DFS_STATUS 0x6C1C4 -#define CLK7_CLK_PLL_PWR_REQ 0x6C2F0 -#define CLK7_CLK_DFSBYPASS_CONTROL 0x6C2F8 -#define CLK7_CLK_FSM_STATUS 0x6C304 -#define CLK7_SPLL_FUSE_1 0x6C0F8 -#define CLK7_SPLL_FUSE_2 0x6C0FC -#define CLK7_SPLL_FIELD_7 0x6C128 -#define CLK7_SPLL_FIELD_9 0x6C130 -#define CLK7_SPLL_FIELD_6nm 0x6C138 -#define CLK7_SPLL_FIELD_4 0x6C11C -#define CLK7_SPLL_FIELD_5nm_BUS_CTRL 0x6C140 -#define CLK7_SPLL_FIELD_5nm_BUS_WDATA 0x6C144 -#define CLK7_SPLL_FIELD_5nm_BUS_STATUS 0x6C148 -#define CLK7_CLK_PLL_RESET_STOP_TIMER 0x6C180 - -#endif diff --git a/src/platform/amd/acp_7_0/include/platform/chip_registers.h b/src/platform/amd/acp_7_0/include/platform/chip_registers.h deleted file mode 100644 index 99ff883e6dd5..000000000000 --- a/src/platform/amd/acp_7_0/include/platform/chip_registers.h +++ /dev/null @@ -1,1061 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2024 AMD.All rights reserved. - * - * Author: SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> - */ -#if !defined(_ACP_7_0_REG_HEADER) -#define _ACP_7_0_REG_HEADER - -typedef union acp_dma_cntl_0 { - struct { - unsigned int dmachrst:1; - unsigned int dmachrun:1; - unsigned int dmachiocen:1; - unsigned int :29; - } bits; - unsigned int u32all; -} acp_dma_cntl_0_t; - -typedef union acp_dma_ch_sts { - struct { - unsigned int dmachrunsts:8; - unsigned int :24; - } bits; - unsigned int u32all; -} acp_dma_ch_sts_t; - -typedef union acp_external_intr_enb { - struct { - unsigned int acpextintrenb:1; - unsigned int :31; - } bits; - unsigned int u32all; -} acp_external_intr_enb_t; - -typedef union acp_dsp0_intr_cntl { - struct { - unsigned int dmaiocmask:8; - unsigned int :8; - unsigned int wov_dma_intr_mask:1; - unsigned int :6; - unsigned int audio_buffer_int_mask:6; - unsigned int :3; - } bits; - unsigned int u32all; -} acp_dsp0_intr_cntl_t; - -typedef union acp_dsp0_intr_stat { - struct { - unsigned int dmaiocstat:8; - unsigned int :8; - unsigned int wov_dma_stat:1; - unsigned int :6; - unsigned int audio_buffer_int_stat:6; - unsigned int :3; - } bits; - unsigned int u32all; -} acp_dsp0_intr_stat_t; - -typedef union acp_dsp0_intr_cntl1 { - struct { - unsigned int acp_fusion_dsp_ext_timer1_timeoutmask :1; - unsigned int fusion_dsp_watchdog_timeoutmask :1; - unsigned int soundwire_mask :1; - unsigned int audio_buffer_int_mask :6; - unsigned int :23; - } bits; - unsigned int u32all; -} acp_dsp0_intr_cntl1_t; - -typedef union acp_dsp0_intr_stat1 { - struct { - unsigned int acp_fusion_dsp_timer1_timeoutstat :1; - unsigned int fusion_dsp_watchdog_timeoutstat :1; - unsigned int soundwire_stat :1; - unsigned int audio_buffer_int_stat :6; - unsigned int :23; - } bits; - unsigned int u32all; -} acp_dsp0_intr_stat1_t; - -typedef union acp_dsp_sw_intr_cntl { - struct { - unsigned int :2; - unsigned int dsp0_to_host_intr_mask:1; - unsigned int :29; - } bits; - unsigned int u32all; -} acp_dsp_sw_intr_cntl_t; - -typedef union acp_dsp_sw_intr_stat { - struct { - unsigned int host_to_dsp0_intr1_stat:1; - unsigned int host_to_dsp0_intr2_stat:1; - unsigned int dsp0_to_host_intr_stat:1; - unsigned int host_to_dsp0_intr3_stat:1; - unsigned int :28; - } bits; - unsigned int u32all; -} acp_dsp_sw_intr_stat_t; - -typedef union acp_sw_intr_trig { - struct { - unsigned int trig_host_to_dsp0_intr1:1; - unsigned int :1; - unsigned int trig_dsp0_to_host_intr:1; - unsigned int :29; - } bits; - unsigned int u32all; -} acp_sw_intr_trig_t; - -typedef union dsp_interrupt_routing_ctrl_0 { - struct { - unsigned int dma_intr_level:3; - unsigned int :18; - unsigned int watchdog_intr_level:3; - unsigned int az_sw_i2s_intr_level:3; - unsigned int sha_intr_level:3; - unsigned int :2; - } bits; - unsigned int u32all; -} dsp_interrupt_routing_ctrl_0_t; - -typedef union dsp_interrupt_routing_ctrl_1 { - struct { - unsigned int host_to_dsp_intr1_level:3; - unsigned int host_to_dsp_intr2_level:3; - unsigned int src_intr_level:3; - unsigned int mailbox_intr_level:3; - unsigned int error_intr_level:3; - unsigned int wov_intr_level:3; - unsigned int fusion_timer1_intr_level:3; - unsigned int fusion_watchdog_intr_level:3; - unsigned int p1_sw_i2s_intr_level:3; - unsigned int :5; - } bits; - unsigned int u32all; -} dsp_interrupt_routing_ctrl_1_t; - -typedef union acp_i2s_rx_ringbufaddr { - struct { - unsigned int i2s_rx_ringbufaddr:27; - unsigned int :5; - } bits; - unsigned int u32all; -} acp_i2s_rx_ringbufaddr_t; - -typedef union acp_i2s_rx_ringbufsize { - struct { - unsigned int i2s_rx_ringbufsize:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_i2s_rx_ringbufsize_t; - -typedef union acp_i2s_rx_linkpositioncntr { - struct { - unsigned int i2s_rx_linkpositioncntr:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_i2s_rx_linkpositioncntr_t; - -typedef union acp_i2s_rx_fifoaddr { - struct { - unsigned int i2s_rx_fifoaddr:27; - unsigned int :5; - } bits; - unsigned int u32all; -} acp_i2s_rx_fifoaddr_t; - -typedef union acp_i2s_rx_fifosize { - struct { - unsigned int i2s_rx_fifosize:13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_i2s_rx_fifosize_t; - -typedef union acp_i2s_rx_dma_size { - struct { - unsigned int i2s_rx_dma_size:13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_i2s_rx_dma_size_t; - -typedef union acp_i2s_rx_linearpositioncntr_high { - struct { - unsigned int i2s_rx_linearpositioncntr_high:32; - } bits; - unsigned int u32all; -} acp_i2s_rx_linearpositioncntr_high_t; - -typedef union acp_i2s_rx_linearpositioncntr_low { - struct { - unsigned int i2s_rx_linearpositioncntr_low:32; - } bits; - unsigned int u32all; -} acp_i2s_rx_linearpositioncntr_low_t; - -typedef union acp_i2s_rx_watermark_size { - struct { - unsigned int i2s_rx_intr_watermark_size:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_i2s_rx_intr_watermark_size_t; - -typedef union acp_i2s_tx_ringbufaddr { - struct { - unsigned int i2s_tx_ringbufaddr:27; - unsigned int :5; - } bits; - unsigned int u32all; -} acp_i2s_tx_ringbufaddr_t; - -typedef union acp_i2s_tx_ringbufsize { - struct { - unsigned int i2s_tx_ringbufsize:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_i2s_tx_ringbufsize_t; - -typedef union acp_i2s_tx_linkpositioncntr { - struct { - unsigned int i2s_tx_linkpositioncntr:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_i2s_tx_linkpositioncntr_t; - -typedef union acp_i2s_tx_fifoaddr { - struct { - unsigned int i2s_tx_fifoaddr:27; - unsigned int :5; - } bits; - unsigned int u32all; -} acp_i2s_tx_fifoaddr_t; - -typedef union acp_i2s_tx_fifosize { - struct { - unsigned int i2s_tx_fifosize:13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_i2s_tx_fifosize_t; - -typedef union acp_i2s_tx_dma_size { - struct { - unsigned int i2s_tx_dma_size:13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_i2s_tx_dma_size_t; - -typedef union acp_i2s_tx_linearpositioncntr_high { - struct { - unsigned int i2s_tx_linearpositioncntr_high:32; - } bits; - unsigned int u32all; -} acp_i2s_tx_linearpositioncntr_hight_t; - -typedef union acp_i2s_tx_linearpositioncntr_low { - struct { - unsigned int i2s_tx_linearpositioncntr_low:32; - } bits; - unsigned int u32all; -} acp_i2s_tx_linearpositioncntr_low_t; - -typedef union acp_i2s_tx_intr_watermark_size { - struct { - unsigned int i2s_tx_intr_watermark_size:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_i2s_tx_intr_watermark_size_t; - -typedef union acp_bt_rx_ringbufaddr { - struct { - unsigned int bt_rx_ringbufaddr:27; - unsigned int :5; - } bits; - unsigned int u32all; -} acp_bt_rx_ringbufaddr_t; - -typedef union acp_bt_rx_ringbufsize { - struct { - unsigned int bt_rx_ringbufsize:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_bt_rx_ringbufsize_t; - -typedef union acp_bt_rx_linkpositioncntr { - struct { - unsigned int bt_rx_linkpositioncntr:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_bt_rx_linkpositioncntr_t; - -typedef union acp_bt_rx_fifoaddr { - struct { - unsigned int bt_rx_fifoaddr:27; - unsigned int :5; - } bits; - unsigned int u32all; -} acp_bt_rx_fifoaddr_t; - -typedef union acp_bt_rx_fifosize { - struct { - unsigned int bt_rx_fifosize:13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_bt_rx_fifosize_t; - -typedef union acp_bt_rx_dma_size { - struct { - unsigned int bt_rx_dma_size:13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_bt_rx_dma_size_t; - -typedef union acp_bt_rx_linearpositioncntr_high { - struct { - unsigned int bt_rx_linearpositioncntr_high:32; - } bits; - unsigned int u32all; -} acp_bt_rx_linearpositioncntr_high_t; - -typedef union acp_bt_rx_linearpositioncntr_low { - struct { - unsigned int bt_rx_linearpositioncntr_low:32; - } bits; - unsigned int u32all; -} acp_bt_rx_linearpositioncntr_low_t; - -typedef union acp_bt_rx_intr_watermark_size { - struct { - unsigned int bt_rx_intr_watermark_size:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_bt_rx_intr_watermark_size_t; - -typedef union acp_bt_tx_ringbufaddr { - struct { - unsigned int bt_tx_ringbufaddr:27; - unsigned int :5; - } bits; - unsigned int u32all; -} acp_bt_tx_ringbufaddr_t; - -typedef union acp_bt_tx_ringbufsize { - struct { - unsigned int bt_tx_ringbufsize:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_bt_tx_ringbufsize_t; - -typedef union acp_bt_tx_linkpositiontcntr { - struct { - unsigned int bt_tx_linkpositioncntr:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_bt_tx_linkpositiontcntr_t; - -typedef union acp_bt_tx_fifoaddr { - struct { - unsigned int bt_tx_fifoaddr:27; - unsigned int :5; - } bits; - unsigned int u32all; -} acp_bt_tx_fifoaddr_t; - -typedef union acp_bt_tx_fifosize { - struct { - unsigned int bt_tx_fifosize:13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_bt_tx_fifosize_t; - -typedef union acp_bt_tx_dmasize { - struct { - unsigned int bt_tx_dma_size:13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_bt_tx_dmasize_t; - -typedef union acp_bt_tx_linearpositioncntr_high { - struct { - unsigned int bt_tx_linearpositioncntr_high:32; - } bits; - unsigned int u32all; -} acp_bt_tx_linearpositioncntr_high_t; - -typedef union acp_bt_tx_linearpositioncntr_low { - struct { - unsigned int bt_tx_linearpositioncntr_low:32; - } bits; - unsigned int u32all; -} acp_bt_tx_linearpositioncntr_low_t; - -typedef union acp_bt_tx_intr_watermark_size { - struct { - unsigned int bt_tx_intr_watermark_size:26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_bt_tx_intr_watermark_size_t; - -typedef union acp_i2stdm_ier { - struct { - unsigned int i2stdm_ien:1; - unsigned int :31; - } bits; - unsigned int u32all; -} acp_i2stdm_ier_t; - -typedef union acp_i2stdm_irer { - struct { - unsigned int i2stdm_rx_en:1; - unsigned int i2stdm_rx_protocol_mode:1; - unsigned int i2stdm_rx_data_path_mode:1; - unsigned int i2stdm_rx_samplen:3; - unsigned int i2stdm_rx_status:1; - unsigned int :25; - } bits; - unsigned int u32all; -} acp_i2stdm_irer_t; - -typedef union acp_i2stdm_iter { - struct { - unsigned int i2stdm_txen:1; - unsigned int i2stdm_tx_protocol_mode:1; - unsigned int i2stdm_tx_data_path_mode:1; - unsigned int i2stdm_tx_samp_len:3; - unsigned int i2stdm_tx_status:1; - unsigned int :25; - } bits; - unsigned int u32all; -} acp_i2stdm_iter_t; - -typedef union acp_bttdm_ier { - struct { - unsigned int bttdm_ien:1; - unsigned int :31; - } bits; - unsigned int u32all; -} acp_bttdm_ier_t; - -typedef union acp_bttdm_irer { - struct { - unsigned int bttdm_rx_en:1; - unsigned int bttdm_rx_protocol_mode:1; - unsigned int bttdm_rx_data_path_mode:1; - unsigned int bttdm_rx_samplen:3; - unsigned int bttdm_rx_status:1; - unsigned int :25; - } bits; - unsigned int u32all; -} acp_bttdm_irer_t; - -typedef union acp_bttdm_iter { - struct { - unsigned int bttdm_txen :1; - unsigned int bttdm_tx_protocol_mode :1; - unsigned int bttdm_tx_data_path_mode :1; - unsigned int bttdm_tx_samp_len :3; - unsigned int bttdm_tx_status :1; - unsigned int :25; - } bits; - unsigned int u32all; -} acp_bttdm_iter_t; - -typedef union acp_wov_pdm_dma_enable { - struct { - unsigned int pdm_dma_en :1; - unsigned int pdm_dma_en_status :1; - unsigned int :30; - } bits; -unsigned int u32all; -} acp_wov_pdm_dma_enable_t; - -typedef union acp_wov_rx_ringbufaddr { - struct { - unsigned int rx_ringbufaddr :27; - unsigned int :5; - } bits; - unsigned int u32all; -} acp_wov_rx_ringbufaddr_t; - -typedef union acp_wov_rx_ringbufsize { - struct { - unsigned int rx_ringbufsize :26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_wov_rx_ringbufsize_t; - -typedef union acp_wov_rx_intr_watermark_size { - struct { - unsigned int rx_intr_watermark_size :26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_wov_rx_intr_watermark_size_t; - -typedef union acp_wov_pdm_no_of_channels { - struct { - unsigned int pdm_no_of_channels :2; - unsigned int :30; - } bits; - unsigned int u32all; -} acp_wov_pdm_no_of_channels_t; - -typedef union acp_wov_pdm_decimation_factor { - struct { - unsigned int pdm_decimation_factor :2; - unsigned int :30; - } bits; - unsigned int u32all; -} acp_wov_pdm_decimation_factor_t; - -typedef union acp_wov_misc_ctrl { - struct { - unsigned int :3; - unsigned int pcm_data_shift_ctrl :2; - unsigned int :27; - } bits; - unsigned int u32all; -} acp_wov_misc_ctrl_t; - -typedef union acp_wov_clk_ctrl { - struct { - unsigned int brm_clk_ctrl :4; - unsigned int pdm_vad_clkdiv :2; - unsigned int :26; - } bits; - unsigned int u32all; -} acp_wov_clk_ctrl_t; - -typedef union acp_srbm_cycle_sts { - struct { - unsigned int srbm_clients_sts :1; - unsigned int :7; - } bits; - unsigned int u32all; -} acp_srbm_cycle_sts_t; - -typedef union acp_hs_rx_ringbufaddr { - struct { - unsigned int hs_rx_ringbufaddr :32; - } bits; - unsigned int u32all; -} acp_hs_rx_ringbufaddr_t; - -typedef union acp_hs_rx_ringbufsize { - struct { - unsigned int hs_rx_ringbufsize :26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_hs_rx_ringbufsize_t; - -typedef union acp_hs_rx_linkpositioncntr { - struct { - unsigned int hs_rx_linkpositioncntr :26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_hs_rx_linkpositioncntr_t; - -typedef union acp_hs_rx_fifoaddr { - struct { - unsigned int hs_rx_fifoaddr :27; - unsigned int :5; - } bits; - unsigned int u32all; -} acp_hs_rx_fifoaddr_t; - -typedef union acp_hs_rx_fifosize { - struct { - unsigned int hs_rx_fifosize :13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_hs_rx_fifosize_t; - -typedef union acp_hs_rx_dma_size { - struct { - unsigned int hs_rx_dma_size :13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_hs_rx_dma_size_t; - -typedef union acp_hs_rx_linearpositioncntr_high { - struct { - unsigned int hs_rx_linearpositioncntr_high :32; - } bits; - unsigned int u32all; -} acp_hs_rx_linearpositioncntr_high_t; - -typedef union acp_hs_rx_linearpositioncntr_low { - struct { - unsigned int hs_rx_linearpositioncntr_low :32; - } bits; - unsigned int u32all; -} acp_hs_rx_linearpositioncntr_low_t; - -typedef union acp_hs_rx_intr_watermark_size { - struct { - unsigned int hs_rx_intr_watermark_size :26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_hs_rx_intr_watermark_size_t; - -typedef union acp_hs_tx_ringbufaddr { - struct { - unsigned int hs_tx_ringbufaddr :32; - } bits; - unsigned int u32all; -} acp_hs_tx_ringbufaddr_t; - -typedef union acp_hs_tx_ringbufsize { - struct { - unsigned int hs_tx_ringbufsize :26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_hs_tx_ringbufsize_t; - -typedef union acp_hs_tx_linkpositioncntr { - struct { - unsigned int hs_tx_linkpositioncntr :26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_hs_tx_linkpositioncntr_t; - -typedef union acp_hs_tx_fifoaddr { - struct { - unsigned int hs_tx_fifoaddr :27; - unsigned int :5; - } bits; - unsigned int u32all; -} acp_hs_tx_fifoaddr_t; - -typedef union acp_hs_tx_fifosize { - struct { - unsigned int hs_tx_fifosize :13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_hs_tx_fifosize_t; - -typedef union acp_hs_tx_dma_size { - struct { - unsigned int hs_tx_dma_size :13; - unsigned int :19; - } bits; - unsigned int u32all; -} acp_hs_tx_dma_size_t; - -typedef union acp_hs_tx_linearpositioncntr_high { - struct { - unsigned int hs_tx_linearpositioncntr_high :32; - } bits; - unsigned int u32all; -} acp_hs_tx_linearpositioncntr_high_t; - -typedef union acp_hs_tx_linearpositioncntr_low { - struct { - unsigned int hs_tx_linearpositioncntr_low :32; - } bits; - unsigned int u32all; -} acp_hs_tx_linearpositioncntr_low_t; - -typedef union acp_hs_tx_intr_watermark_size { - struct { - unsigned int hs_tx_intr_watermark_size :26; - unsigned int :6; - } bits; - unsigned int u32all; -} acp_hs_tx_intr_watermark_size_t; - -typedef union acp_i2stdm_rxfrmt { - struct { - unsigned int i2stdm_frame_len :9; - unsigned int :6; - unsigned int i2stdm_num_slots :3; - unsigned int i2stdm_slot_len :5; - unsigned int :9; - } bits; - unsigned int u32all; -} acp_i2stdm_rxfrmt_t; - -typedef union acp_i2stdm_txfrmt { - struct { - unsigned int i2stdm_frame_len :9; - unsigned int :6; - unsigned int i2stdm_num_slots :3; - unsigned int i2stdm_slot_len :5; - unsigned int :9; - } bits; - unsigned int u32all; -} acp_i2stdm_txfrmt_t; - -typedef union acp_hstdm_ier { - struct { - unsigned int hstdm_ien :1; - unsigned int :31; - } bits; - unsigned int u32all; -} acp_hstdm_ier_t; - -typedef union acp_hstdm_irer { - struct { - unsigned int hstdm_rx_en :1; - unsigned int hstdm_rx_protocol_mode :1; - unsigned int hstdm_rx_data_path_mode :1; - unsigned int hstdm_rx_samplen :3; - unsigned int hstdm_rx_status :1; - unsigned int :25; - } bits; - unsigned int u32all; -} acp_hstdm_irer_t; - -typedef union acp_hstdm_rxfrmt { - struct { - unsigned int hstdm_frame_len :9; - unsigned int :6; - unsigned int hstdm_num_slots :3; - unsigned int hstdm_slot_len :5; - unsigned int :9; - } bits; - unsigned int u32all; -} acp_hstdm_rxfrmt_t; - -typedef union acp_hstdm_iter { - struct { - unsigned int hstdm_txen :1; - unsigned int hstdm_tx_protocol_mode :1; - unsigned int hstdm_tx_data_path_mode :1; - unsigned int hstdm_tx_samp_len :3; - unsigned int hstdm_tx_status :1; - unsigned int :25; - } bits; - unsigned int u32all; -} acp_hstdm_iter_t; - -typedef union acp_hstdm_txfrmt { - struct { - unsigned int hstdm_frame_len :9; - unsigned int :6; - unsigned int hstdm_num_slots :3; - unsigned int hstdm_slot_len :5; - unsigned int :9; - } bits; - unsigned int u32all; -} acp_hstdm_txfrmt_t; - -typedef union acp_clkmux_sel { - struct { - unsigned int acp_clkmux_sel : 3; - unsigned int : 13; - unsigned int acp_clkmux_div_value : 16; - } bits; - unsigned int u32all; -} acp_clkmux_sel_t; - -typedef union acp_i2stdm_mstrclkgen { - struct { - unsigned int i2stdm_master_mode : 1; - unsigned int i2stdm_format_mode : 1; - unsigned int i2stdm_lrclk_div_val : 11; - unsigned int i2stdm_bclk_div_val : 11; - unsigned int : 8; - } bits; - unsigned int u32all; -} acp_i2stdm_mstrclkgen_t; - -typedef union clk7_clk1_dfs_cntl_u { - struct { - unsigned int CLK1_DIVIDER : 7; - unsigned int : 25; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_clk1_dfs_cntl_u_t; - -typedef union clk7_clk1_dfs_status_u { - struct { - unsigned int : 16; - unsigned int CLK1_DFS_DIV_REQ_IDLE : 1; - unsigned int : 2; - unsigned int RO_CLK1_DFS_STATE_IDLE : 1; - unsigned int CLK1_CURRENT_DFS_DID : 7; - unsigned int : 5; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_clk1_dfs_status_u_t; - -typedef union clk7_clk1_bypass_cntl_u { - struct { - unsigned int CLK1_BYPASS_SEL : 3; - unsigned int : 13; - unsigned int CLK1_BYPASS_DIV : 4; - unsigned int : 12; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_clk1_bypass_cntl_u_t; - -typedef union clk7_clk_fsm_status_u { - struct { - unsigned int AUTOLAUCH_FSM_FULL_SPEED_IDLE : 1; - unsigned int : 3; - unsigned int AUTOLAUCH_FSM_BYPASS_IDLE : 1; - unsigned int : 3; - unsigned int RO_FSM_PLL_STATUS_STARTED : 1; - unsigned int : 3; - unsigned int RO_FSM_PLL_STATUS_STOPPED : 1; - unsigned int : 3; - unsigned int RO_EARLY_FSM_DONE : 1; - unsigned int : 3; - unsigned int RO_DFS_GAP_ACTIVE : 1; - unsigned int : 3; - unsigned int RO_DID_FSM_IDLE : 1; - unsigned int : 7; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_clk_fsm_status_t; - -typedef union clk7_clk_pll_req_u { - struct { - unsigned int fbmult_int : 9; - unsigned int : 3; - unsigned int pllspinediv : 4; - unsigned int fbmult_frac : 16; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_clk_pll_req_u_t; - -typedef union clk7_clk_pll_refclk_startup { - struct { - unsigned int main_pll_ref_clk_rate_startup : 8; - unsigned int main_pll_cfg_4_startup : 8; - unsigned int main_pll_ref_clk_div_startup : 2; - unsigned int main_pll_cfg_3_startup : 10; - unsigned int : 1; - unsigned int main_pll_refclk_src_mux0_startup : 1; - unsigned int main_pll_refclk_src_mux1_startup : 1; - unsigned int : 1; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_clk_pll_refclk_startup_t; - -typedef union clk7_spll_field_2 { - struct{ - unsigned int : 3; - unsigned int spll_fbdiv_mask_en : 1; - unsigned int spll_fracn_en : 1; - unsigned int spll_freq_jump_en : 1; - unsigned int : 25; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_spll_field_2_t; - -typedef union clk7_clk_dfsbypass_cntl { - struct { - unsigned int enter_dfs_bypass_0 : 1; - unsigned int enter_dfs_bypass_1 : 1; - unsigned int : 14; - unsigned int exit_dfs_bypass_0 : 1; - unsigned int exit_dfs_bypass_1 : 1; - unsigned int : 14; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_clk_dfsbypass_cntl_t; - -typedef union clk7_clk_pll_pwr_req { - struct { - unsigned int PLL_AUTO_START_REQ : 1; - unsigned int : 3; - unsigned int PLL_AUTO_STOP_REQ : 1; - unsigned int : 3; - unsigned int PLL_AUTO_STOP_NOCLK_REQ : 1; - unsigned int : 3; - unsigned int PLL_AUTO_STOP_REFBYPCLK_REQ : 1; - unsigned int : 3; - unsigned int PLL_FORCE_RESET_HIGH : 1; - unsigned int : 15; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_clk_pll_pwr_req_t; - -typedef union clk7_spll_fuse_1 { - struct { - unsigned int : 8; - unsigned int spll_gp_coarse_exp : 4; - unsigned int spll_gp_coarse_mant : 4; - unsigned int : 4; - unsigned int spll_gi_coarse_exp : 4; - unsigned int : 1; - unsigned int spll_gi_coarse_mant : 2; - unsigned int : 5; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_spll_fuse_1_t; - -typedef union clk7_spll_fuse_2 { - struct { - unsigned int spll_tdc_resolution : 8; - unsigned int spll_freq_offset_exp : 4; - unsigned int spll_freq_offset_mant : 5; - unsigned int : 15; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_spll_fuse_2_t; - -typedef union clk7_spll_field_9 { - struct { - unsigned int : 16; - unsigned int spll_dpll_cfg_3 : 10; - unsigned int spll_fll_mode : 1; - unsigned int : 5; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_spll_field_9_t; - -typedef union clk7_spll_field_6nm { - struct { - unsigned int spll_dpll_cfg_4 : 8; - unsigned int spll_reg_tim_exp : 3; - unsigned int spll_reg_tim_mant : 1; - unsigned int spll_ref_tim_exp : 3; - unsigned int spll_ref_tim_mant : 1; - unsigned int spll_vco_pre_div : 2; - unsigned int : 14; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_spll_field_6nm_t; - -typedef union clk7_spll_field_7 { - struct { - unsigned int : 7; - unsigned int spll_pllout_sel : 1; - unsigned int spll_pllout_req : 1; - unsigned int spll_pllout_state : 2; - unsigned int spll_postdiv_ovrd : 4; - unsigned int spll_postdiv_pllout_ovrd : 4; - unsigned int spll_postdiv_sync_enable : 1; - unsigned int : 1; - unsigned int spll_pwr_state : 2; - unsigned int : 1; - unsigned int spll_refclk_rate : 8; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_spll_field_7_t; - -typedef union clk7_spll_field_4 { - struct { - unsigned int spll_fcw0_frac_ovrd : 16; - unsigned int pll_out_sel : 1; - unsigned int : 3; - unsigned int pll_pwr_dn_state : 2; - unsigned int : 2; - unsigned int spll_refclk_div : 2; - unsigned int : 6; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_spll_field_4_t; - -typedef union clk7_spll_field_5nm_bus_ctrl { - struct { - unsigned int bus_spll_async_mode :1; - unsigned int bus_spll_apb_mode :1; - unsigned int bus_spll_addr :8; - unsigned int bus_spll_byte_en :4; - unsigned int bus_spll_rdtr :1; - unsigned int bus_spll_resetb :1; - unsigned int bus_spll_sel :1; - unsigned int bus_spll_wrtr :1; - unsigned int :14; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_spll_field_5nm_bus_ctrl_t; - -typedef union clk7_spll_field_5nm_bus_wdata { - struct { - unsigned int bus_spll_wr_data; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_spll_field_5nm_bus_wdata_t; - -typedef union clk7_rootrefclk_mux_1 { - struct { - unsigned int ROOTREFCLK_MUX_1 : 1; - unsigned int reserved : 31; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_rootrefclk_mux_1_t; - -typedef union clk7_spll_field_5nm_bus_status { - struct { - unsigned int spll_bus_error :1; - unsigned int spll_bus_rd_valid :1; - unsigned int spll_bus_wr_ack :1; - unsigned int :29; - } bitfields, bits; - uint32_t u32all; - int32_t i32all; - float f32all; -} clk7_spll_field_5nm_bus_status_t; - -#endif diff --git a/src/platform/amd/acp_7_0/include/platform/lib/memory.h b/src/platform/amd/acp_7_0/include/platform/lib/memory.h index e19c61457b8c..60a72e9f38c1 100644 --- a/src/platform/amd/acp_7_0/include/platform/lib/memory.h +++ b/src/platform/amd/acp_7_0/include/platform/lib/memory.h @@ -1,8 +1,10 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2024 AMD.All rights reserved. + * Copyright(c) 2024, 2026 AMD.All rights reserved. * * Author: SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> + * Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> + * Sivasubramanian <sravisar@amd.com> */ #ifdef __SOF_LIB_MEMORY_H__ @@ -10,7 +12,9 @@ #define __PLATFORM_LIB_MEMORY_H__ #include <rtos/cache.h> -#include <platform/chip_offset_byte.h> + +#define PU_REGISTER_BASE (0x9FD00000 - 0x01240000) +#define PU_SCRATCH_REG_BASE (0x9FF00000 - 0x01250000) /* data cache line alignment */ #define PLATFORM_DCACHE_ALIGN 128 @@ -26,7 +30,7 @@ #define DRAM1_BASE 0xE0010000 #define DRAM1_SIZE 0x10000 #define SRAM1_BASE 0x6000C000 -#define SRAM1_SIZE 0x27A000 +#define SRAM1_SIZE 0x274000 #define DMA0_BASE PU_REGISTER_BASE #define DMA0_SIZE 0x4 @@ -35,12 +39,22 @@ #define DAI_BASE (PU_REGISTER_BASE + ACP_I2S_RX_RINGBUFADDR) #define DAI_BASE_REM (PU_REGISTER_BASE + ACP_P1_I2S_RX_RINGBUFADDR) #define DAI_SIZE 0x4 + +#define SW1_AUDIO_TX_FIFO_OFFST (ACP_P1_AUDIO_TX_FIFOADDR - ACP_P1_AUDIO_RX_RINGBUFADDR) +#define SW1_AUDIO_RX_FIFO_OFFST (ACP_P1_AUDIO_RX_FIFOADDR - ACP_P1_AUDIO_RX_RINGBUFADDR) + #define BT_TX_FIFO_OFFST (ACP_P1_BT_TX_FIFOADDR - ACP_P1_I2S_RX_RINGBUFADDR) #define BT_RX_FIFO_OFFST (ACP_P1_BT_RX_FIFOADDR - ACP_P1_I2S_RX_RINGBUFADDR) +#define SW1_HS_TX_FIFO_OFFST (ACP_P1_HS_TX_FIFOADDR - ACP_P1_HS_RX_RINGBUFADDR) +#define SW1_HS_RX_FIFO_OFFST (ACP_P1_HS_RX_FIFOADDR - ACP_P1_HS_RX_RINGBUFADDR) + #define HS_TX_FIFO_OFFST (ACP_P1_HS_TX_FIFOADDR - ACP_P1_I2S_RX_RINGBUFADDR) #define HS_RX_FIFO_OFFST (ACP_P1_HS_TX_FIFOADDR - ACP_P1_I2S_RX_RINGBUFADDR) +#define SW0_AUDIO_TX_FIFO_OFFST (ACP_AUDIO_TX_FIFOADDR - ACP_AUDIO_RX_RINGBUFADDR) +#define SW0_AUDIO_RX_FIFO_OFFST (ACP_AUDIO_RX_FIFOADDR - ACP_AUDIO_RX_RINGBUFADDR) + #define BT0_TX_FIFO_OFFST (ACP_BT_TX_FIFOADDR - ACP_AUDIO_RX_RINGBUFADDR) #define BT0_RX_FIFO_OFFST (ACP_BT_RX_FIFOADDR - ACP_AUDIO_RX_RINGBUFADDR) @@ -162,17 +176,12 @@ struct sof; #define SHARED_DATA void platform_init_memmap(struct sof *sof); -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - static inline void *platform_rfree_prepare(void *ptr) { return ptr; } #endif - +#define host_to_local(addr) addr #endif /* __PLATFORM_LIB_MEMORY_H__ */ #else diff --git a/src/platform/amd/acp_7_0/include/platform/platform.h b/src/platform/amd/acp_7_0/include/platform/platform.h index 3e927ace6687..5c2e7db0549e 100644 --- a/src/platform/amd/acp_7_0/include/platform/platform.h +++ b/src/platform/amd/acp_7_0/include/platform/platform.h @@ -1,8 +1,10 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2024 AMD.All rights reserved. + * Copyright(c) 2024, 2026 AMD.All rights reserved. * - * Author: SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> + * Author: SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> + * Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> + * Sivasubramanian <sravisar@amd.com> */ #ifdef __SOF_PLATFORM_H__ @@ -17,9 +19,9 @@ #include <stddef.h> #include <stdint.h> #include <platform/fw_scratch_mem.h> -#include <platform/chip_registers.h> +#include <platform/platform_misc.h> -struct ll_schedule_domain; +#define INTERRUPT_ENABLE 1 struct timer; #define PLATFORM_DEFAULT_CLOCK CLK_CPU(0) diff --git a/src/platform/amd/acp_7_0/include/platform/platform_misc.h b/src/platform/amd/acp_7_0/include/platform/platform_misc.h new file mode 100644 index 000000000000..83eb206ee2e9 --- /dev/null +++ b/src/platform/amd/acp_7_0/include/platform/platform_misc.h @@ -0,0 +1,448 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 AMD. All rights reserved. + * + * + */ + +//Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> +// Sivasubramanian <sravisar@amd.com> + +#define ACP_SW_INTR_TRIG 0x1241810 +#define ACP_DSP0_INTR_CNTL 0x1241800 +#define ACP_DSP0_INTR_STAT 0x1241804 +#define ACP_DSP_SW_INTR_CNTL 0x1241808 +#define ACP_DSP_SW_INTR_STAT 0x124180C +#define ACP_AXI2DAGB_SEM_0 0x1241874 +#define ACP_SRBM_CLIENT_BASE_ADDR 0x12419EC +#define ACP_SRBM_CLIENT_RDDATA 0x12419F0 +#define ACP_SRBM_CYCLE_STS 0x12419F4 +#define ACP_SRBM_CLIENT_CONFIG 0x12419F8 +#define MP1_SMN_C2PMSG_69 0x58A14 +#define MP1_SMN_C2PMSG_85 0x58A54 +#define MP1_SMN_C2PMSG_93 0x58A74 +#define CLK7_ROOTREFCLK_MUX_1 0x6C0C8 +#define CLK7_CLK_PLL_REFCLK_RATE_STARTUP 0x6C0D0 +#define CLK7_CLK_PLL_REQ 0x6C0DC +#define CLK7_CLK1_DFS_CNTL 0x6C1B0 +#define CLK7_CLK1_CURRENT_CNT 0x6C378 +#define CLK7_CLK0_DFS_CNTL 0x6C1A4 +#define CLK7_CLK0_CURRENT_CNT 0x6C374 +#define CLK7_CLK0_BYPASS_CNTL 0x6C210 +#define CLK7_CLK1_BYPASS_CNTL 0x6C234 +#define CLK7_CLK0_DFS_STATUS 0x6C1AC +#define CLK7_CLK1_DFS_STATUS 0x6C1B8 +#define CLK7_SPLL_FIELD_2 0x6C114 +#define CLK7_CLK2_CURRENT_CNT 0x6C37C +#define CLK7_CLK2_BYPASS_CNTL 0x6C258 +#define CLK7_CLK2_DFS_STATUS 0x6C1C4 +#define CLK7_CLK_PLL_PWR_REQ 0x6C2F0 +#define CLK7_CLK_DFSBYPASS_CONTROL 0x6C2F8 +#define CLK7_CLK_FSM_STATUS 0x6C304 +#define CLK7_SPLL_FUSE_1 0x6C0F8 +#define CLK7_SPLL_FUSE_2 0x6C0FC +#define CLK7_SPLL_FIELD_7 0x6C128 +#define CLK7_SPLL_FIELD_9 0x6C130 +#define CLK7_SPLL_FIELD_6nm 0x6C138 +#define CLK7_SPLL_FIELD_4 0x6C11C +#define CLK7_SPLL_FIELD_5nm_BUS_CTRL 0x6C140 +#define CLK7_SPLL_FIELD_5nm_BUS_WDATA 0x6C144 +#define CLK7_SPLL_FIELD_5nm_BUS_STATUS 0x6C148 +#define CLK7_CLK_PLL_RESET_STOP_TIMER 0x6C180 + +typedef union acp_srbm_cycle_sts { + struct { + unsigned int srbm_clients_sts :1; + unsigned int :7; + } bits; + unsigned int u32all; +} acp_srbm_cycle_sts_t; + +typedef union acp_clkmux_sel { + struct { + unsigned int acp_clkmux_sel : 3; + unsigned int : 13; + unsigned int acp_clkmux_div_value : 16; + } bits; + unsigned int u32all; +} acp_clkmux_sel_t; + +typedef union clk7_clk1_dfs_cntl_u { + struct { + unsigned int CLK1_DIVIDER : 7; + unsigned int : 25; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk1_dfs_cntl_u_t; + +typedef union clk7_clk1_dfs_status_u { + struct { + unsigned int : 16; + unsigned int CLK1_DFS_DIV_REQ_IDLE : 1; + unsigned int : 2; + unsigned int RO_CLK1_DFS_STATE_IDLE : 1; + unsigned int CLK1_CURRENT_DFS_DID : 7; + unsigned int : 5; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk1_dfs_status_u_t; + +typedef union clk7_clk1_bypass_cntl_u { + struct { + unsigned int CLK1_BYPASS_SEL : 3; + unsigned int : 13; + unsigned int CLK1_BYPASS_DIV : 4; + unsigned int : 12; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk1_bypass_cntl_u_t; + +typedef union clk7_clk_fsm_status_u { + struct { + unsigned int AUTOLAUCH_FSM_FULL_SPEED_IDLE : 1; + unsigned int : 3; + unsigned int AUTOLAUCH_FSM_BYPASS_IDLE : 1; + unsigned int : 3; + unsigned int RO_FSM_PLL_STATUS_STARTED : 1; + unsigned int : 3; + unsigned int RO_FSM_PLL_STATUS_STOPPED : 1; + unsigned int : 3; + unsigned int RO_EARLY_FSM_DONE : 1; + unsigned int : 3; + unsigned int RO_DFS_GAP_ACTIVE : 1; + unsigned int : 3; + unsigned int RO_DID_FSM_IDLE : 1; + unsigned int : 7; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk_fsm_status_t; + +typedef union clk7_clk_pll_req_u { + struct { + unsigned int fbmult_int : 9; + unsigned int : 3; + unsigned int pllspinediv : 4; + unsigned int fbmult_frac : 16; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk_pll_req_u_t; + +typedef union clk7_clk_pll_refclk_startup { + struct { + unsigned int main_pll_ref_clk_rate_startup : 8; + unsigned int main_pll_cfg_4_startup : 8; + unsigned int main_pll_ref_clk_div_startup : 2; + unsigned int main_pll_cfg_3_startup : 10; + unsigned int : 1; + unsigned int main_pll_refclk_src_mux0_startup : 1; + unsigned int main_pll_refclk_src_mux1_startup : 1; + unsigned int : 1; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk_pll_refclk_startup_t; + +typedef union clk7_spll_field_2 { + struct{ + unsigned int : 3; + unsigned int spll_fbdiv_mask_en : 1; + unsigned int spll_fracn_en : 1; + unsigned int spll_freq_jump_en : 1; + unsigned int : 25; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_2_t; + +typedef union clk7_clk_dfsbypass_cntl { + struct { + unsigned int enter_dfs_bypass_0 : 1; + unsigned int enter_dfs_bypass_1 : 1; + unsigned int : 14; + unsigned int exit_dfs_bypass_0 : 1; + unsigned int exit_dfs_bypass_1 : 1; + unsigned int : 14; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk_dfsbypass_cntl_t; + +typedef union clk7_clk_pll_pwr_req { + struct { + unsigned int PLL_AUTO_START_REQ : 1; + unsigned int : 3; + unsigned int PLL_AUTO_STOP_REQ : 1; + unsigned int : 3; + unsigned int PLL_AUTO_STOP_NOCLK_REQ : 1; + unsigned int : 3; + unsigned int PLL_AUTO_STOP_REFBYPCLK_REQ : 1; + unsigned int : 3; + unsigned int PLL_FORCE_RESET_HIGH : 1; + unsigned int : 15; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk_pll_pwr_req_t; + +typedef union clk7_spll_fuse_1 { + struct { + unsigned int : 8; + unsigned int spll_gp_coarse_exp : 4; + unsigned int spll_gp_coarse_mant : 4; + unsigned int : 4; + unsigned int spll_gi_coarse_exp : 4; + unsigned int : 1; + unsigned int spll_gi_coarse_mant : 2; + unsigned int : 5; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_fuse_1_t; + +typedef union clk7_spll_fuse_2 { + struct { + unsigned int spll_tdc_resolution : 8; + unsigned int spll_freq_offset_exp : 4; + unsigned int spll_freq_offset_mant : 5; + unsigned int : 15; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_fuse_2_t; + +typedef union clk7_spll_field_9 { + struct { + unsigned int : 16; + unsigned int spll_dpll_cfg_3 : 10; + unsigned int spll_fll_mode : 1; + unsigned int : 5; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_9_t; + +typedef union clk7_spll_field_6nm { + struct { + unsigned int spll_dpll_cfg_4 : 8; + unsigned int spll_reg_tim_exp : 3; + unsigned int spll_reg_tim_mant : 1; + unsigned int spll_ref_tim_exp : 3; + unsigned int spll_ref_tim_mant : 1; + unsigned int spll_vco_pre_div : 2; + unsigned int : 14; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_6nm_t; + +typedef union clk7_spll_field_7 { + struct { + unsigned int : 7; + unsigned int spll_pllout_sel : 1; + unsigned int spll_pllout_req : 1; + unsigned int spll_pllout_state : 2; + unsigned int spll_postdiv_ovrd : 4; + unsigned int spll_postdiv_pllout_ovrd : 4; + unsigned int spll_postdiv_sync_enable : 1; + unsigned int : 1; + unsigned int spll_pwr_state : 2; + unsigned int : 1; + unsigned int spll_refclk_rate : 8; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_7_t; + +typedef union clk7_spll_field_4 { + struct { + unsigned int spll_fcw0_frac_ovrd : 16; + unsigned int pll_out_sel : 1; + unsigned int : 3; + unsigned int pll_pwr_dn_state : 2; + unsigned int : 2; + unsigned int spll_refclk_div : 2; + unsigned int : 6; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_4_t; + +typedef union clk7_spll_field_5nm_bus_ctrl { + struct { + unsigned int bus_spll_async_mode :1; + unsigned int bus_spll_apb_mode :1; + unsigned int bus_spll_addr :8; + unsigned int bus_spll_byte_en :4; + unsigned int bus_spll_rdtr :1; + unsigned int bus_spll_resetb :1; + unsigned int bus_spll_sel :1; + unsigned int bus_spll_wrtr :1; + unsigned int :14; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_5nm_bus_ctrl_t; + +typedef union clk7_spll_field_5nm_bus_wdata { + struct { + unsigned int bus_spll_wr_data; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_5nm_bus_wdata_t; + +typedef union clk7_rootrefclk_mux_1 { + struct { + unsigned int ROOTREFCLK_MUX_1 : 1; + unsigned int reserved : 31; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_rootrefclk_mux_1_t; + +typedef union clk7_spll_field_5nm_bus_status { + struct { + unsigned int spll_bus_error :1; + unsigned int spll_bus_rd_valid :1; + unsigned int spll_bus_wr_ack :1; + unsigned int :29; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_5nm_bus_status_t; + +typedef union acp_dsp0_sdw_intr_cntl { + struct { + unsigned int soundwire_mask :17; + unsigned int :15; + } bits; + unsigned int u32all; +} acp_dsp0_sdw_intr_cntl_t; + +typedef union acp_dsp_sw_intr_stat { + struct { + unsigned int host_to_dsp0_intr1_stat:1; + unsigned int host_to_dsp0_intr2_stat:1; + unsigned int dsp0_to_host_intr_stat:1; + unsigned int host_to_dsp0_intr3_stat:1; + unsigned int :28; + } bits; + unsigned int u32all; +} acp_dsp_sw_intr_stat_t; + +typedef union acp_sw_intr_trig { + struct { + unsigned int trig_host_to_dsp0_intr1:1; + unsigned int :1; + unsigned int trig_dsp0_to_host_intr:1; + unsigned int :29; + } bits; + unsigned int u32all; +} acp_sw_intr_trig_t; + +typedef void (*dma_callback_t)(const struct device *dev, void *user_data, + uint32_t channel, int status); + +#define ACP_DMA_CHAN_COUNT 12 +struct acp_dma_ptr_data { + /* base address of dma buffer */ + uint32_t base; + /* size of dma buffer */ + uint32_t size; + /* write pointer of dma buffer */ + uint32_t wr_ptr; + /* read pointer of dma buffer */ + uint32_t rd_ptr; + /* read size of dma buffer */ + uint32_t rd_size; + /* write size of dma buffer */ + uint32_t wr_size; + /* system memory size defined for the stream */ + uint32_t sys_buff_size; + /* virtual system memory offset for system memory buffer */ + uint32_t phy_off; + /* probe_channel id */ + uint32_t probe_channel; +}; + +enum acp_dma_state { + ACP_DMA_READY, + ACP_DMA_PREPARED, + ACP_DMA_SUSPENDED, + ACP_DMA_ACTIVE, +}; + +struct acp_dma_chan_data { + uint32_t direction; + enum acp_dma_state state; + struct acp_dma_ptr_data ptr_data; /* pointer data */ + dma_callback_t dma_tfrcallback; + void *priv_data;//unused +}; + +struct dma_context1 { + /** magic code to identify the context */ + int32_t magic; + /** number of dma channels */ + int dma_channels; + /** atomic holding bit flags for each channel to mark as used/unused */ + atomic_t *atomic; +}; + +struct sdw_pin_data { + uint32_t pin_num; + uint32_t pin_dir; + uint32_t dma_channel; + uint32_t index; + uint32_t instance; +}; + +struct tdm_context { + uint64_t prev_pos; + uint32_t buff_size; + uint32_t tdm_instance; + uint32_t pin_dir; + uint32_t dma_channel; + uint32_t index; + uint32_t frame_fmt; +}; + +struct dmic_context { + uint32_t dmic_instance; + uint32_t pin_dir; + uint32_t dma_channel; + uint32_t index; +}; + +struct acp_dma_dev_data { + struct dma_context1 dma_ctx; + struct acp_dma_chan_data chan_data[ACP_DMA_CHAN_COUNT]; + + ATOMIC_DEFINE(atomic, ACP_DMA_CHAN_COUNT); + struct dma_config *dma_config; + void *dai_index_ptr; +}; diff --git a/src/platform/amd/acp_7_0/lib/clk.c b/src/platform/amd/acp_7_0/lib/clk.c index 89fa787db1c3..da2b069682d0 100644 --- a/src/platform/amd/acp_7_0/lib/clk.c +++ b/src/platform/amd/acp_7_0/lib/clk.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2024 AMD.All rights reserved. +// Copyright(c) 2024, 2026 AMD.All rights reserved. // // Author: SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> +// Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> +// Sivasubramanian <sravisar@amd.com> // #include <sof/common.h> @@ -36,8 +38,8 @@ #include <stddef.h> #include <stdint.h> #include <platform/fw_scratch_mem.h> -#include <platform/chip_registers.h> +LOG_MODULE_REGISTER(acp_clk, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(acp_clk); DECLARE_TR_CTX(acp_clk_tr, SOF_UUID(acp_clk_uuid), LOG_LEVEL_INFO); @@ -183,7 +185,7 @@ void acp_change_clock_notify(uint32_t clock_freq) acp_7_0_get_boot_ref_clock(&boot_ref_clk); - tr_info(&acp_clk_tr, "acp_change_clock_notify clock_freq : %d clock_type : %d", + tr_info(&acp_clk_tr, "clock_freq : %d clock_type : %d", clock_freq, clock_type); fraction_val = (float)(clock_freq / 1000000.0f); @@ -204,7 +206,7 @@ void acp_change_clock_notify(uint32_t clock_freq) bypass_cntl.bitfields.CLK1_BYPASS_DIV = 0xF; } else { did = boot_ref_clk / fraction_val; - tr_info(&acp_clk_tr, "acp_change_clock_notify CLK Divider : %d boot_ref_clk : %d\n", + tr_info(&acp_clk_tr, "CLK Divider : %d boot_ref_clk : %d\n", (uint32_t)(did * 100), (uint32_t)boot_ref_clk); if (did > 62.0f) { @@ -241,7 +243,7 @@ void acp_change_clock_notify(uint32_t clock_freq) do { dfs_status.u32all = acp_reg_read_via_smn(CLK7_CLK1_DFS_STATUS, sizeof(int)); - tr_info(&acp_clk_tr, "acp_change_clock_notify ACLK1 CLK1_DIVIDER : %d dfsstatus %d ", + tr_info(&acp_clk_tr, "ACLK1 CLK1_DIVIDER : %d dfsstatus %d ", dfs_cntl.u32all, dfs_status.u32all); } while (dfs_status.bitfields.CLK1_DFS_DIV_REQ_IDLE == 0); updated_clk = acp_reg_read_via_smn(CLK7_CLK1_CURRENT_CNT, sizeof(int)); @@ -258,7 +260,7 @@ void acp_change_clock_notify(uint32_t clock_freq) dfs_cntl.u32all = acp_reg_read_via_smn(CLK7_CLK1_DFS_CNTL, sizeof(int)); - tr_info(&acp_clk_tr, "acp_change_clock_notify ACLK2 CLK1_DIVIDER:%d dfsstatus %d ", + tr_info(&acp_clk_tr, "ACLK2 CLK1_DIVIDER:%d dfsstatus %d ", dfs_cntl.u32all, dfs_status.u32all); } while (dfs_status.bitfields.CLK1_DFS_DIV_REQ_IDLE == 0); } @@ -272,7 +274,7 @@ void acp_change_clock_notify(uint32_t clock_freq) do { dfs_status.u32all = acp_reg_read_via_smn(CLK7_CLK0_DFS_STATUS, sizeof(int)); - tr_info(&acp_clk_tr, "acp_change_clock_notify SCLK CLK1_DIVIDER: %d", + tr_info(&acp_clk_tr, "SCLK CLK1_DIVIDER: %d", dfs_cntl.u32all); } while (dfs_status.bitfields.CLK1_DFS_DIV_REQ_IDLE == 0); diff --git a/src/platform/amd/acp_7_0/lib/dai.c b/src/platform/amd/acp_7_0/lib/dai.c index a2ddf2df5386..87c3f8f62a53 100644 --- a/src/platform/amd/acp_7_0/lib/dai.c +++ b/src/platform/amd/acp_7_0/lib/dai.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // -//Copyright(c) 2024 AMD. All rights reserved. +//Copyright(c) 2024, 2026 AMD. All rights reserved. // //Author: SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> +// Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> +// Sivasubramanian <sravisar@amd.com> #include <sof/common.h> #include <sof/drivers/acp_dai_dma.h> @@ -70,6 +72,141 @@ static struct dai hsdai[] = { } }; +static struct dai swaudiodai[] = { + { + .index = DI_SDW0_ACP_SW_AUDIO_TX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_PLAYBACK] = { + .offset = DAI_BASE_REM + SW0_AUDIO_TX_FIFO_OFFST, + .handshake = SDW0_ACP_SW_AUDIO_TX_EN_CH, + } + }, + .drv = &acp_swaudiodai_driver, + }, + { + .index = DI_SDW0_ACP_SW_AUDIO_RX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_CAPTURE] = { + .offset = DAI_BASE_REM + SW0_AUDIO_RX_FIFO_OFFST, + .handshake = SDW0_ACP_SW_AUDIO_RX_EN_CH, + }, + }, + .drv = &acp_swaudiodai_driver, + }, + { + .index = DI_SDW0_ACP_SW_BT_TX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_PLAYBACK] = { + .offset = DAI_BASE_REM + BT0_TX_FIFO_OFFST, + .handshake = SDW0_ACP_SW_BT_TX_EN_CH, + } + }, + .drv = &acp_swaudiodai_driver, + }, + { + .index = DI_SDW0_ACP_SW_BT_RX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_CAPTURE] = { + .offset = DAI_BASE_REM + BT0_RX_FIFO_OFFST, + .handshake = SDW0_ACP_SW_BT_RX_EN_CH, + }, + }, + .drv = &acp_swaudiodai_driver, + }, + { + .index = DI_SDW0_ACP_SW_HS_TX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_PLAYBACK] = { + .offset = DAI_BASE_REM + HS0_TX_FIFO_OFFST, + .handshake = SDW0_ACP_SW_HS_TX_EN_CH, + } + }, + .drv = &acp_swaudiodai_driver, + }, + { + .index = DI_SDW0_ACP_SW_HS_RX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_CAPTURE] = { + .offset = DAI_BASE_REM + HS0_RX_FIFO_OFFST, + .handshake = SDW0_ACP_SW_HS_RX_EN_CH, + }, + }, + .drv = &acp_swaudiodai_driver, + }, + { + .index = DI_SDW1_ACP_P1_SW_BT_TX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_PLAYBACK] = { + .offset = DAI_BASE_REM + BT_TX_FIFO_OFFST, + .handshake = SDW1_ACP_P1_SW_BT_TX_EN_CH, + } + }, + .drv = &acp_swaudiodai_driver, + }, + { + .index = DI_SDW1_ACP_P1_SW_BT_RX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_CAPTURE] = { + .offset = DAI_BASE_REM + BT_RX_FIFO_OFFST, + .handshake = SDW1_ACP_P1_SW_BT_RX_EN_CH, + }, + }, + .drv = &acp_swaudiodai_driver, + }, + { + .index = DI_SDW1_ACP_P1_SW_AUDIO_TX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_PLAYBACK] = { + .offset = DAI_BASE_REM + SW1_AUDIO_TX_FIFO_OFFST, + .handshake = SDW1_ACP_P1_SW_AUDIO_TX_EN_CH, + } + }, + .drv = &acp_swaudiodai_driver, + }, + { + .index = DI_SDW1_ACP_P1_SW_AUDIO_RX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_CAPTURE] = { + .offset = DAI_BASE_REM + SW1_AUDIO_RX_FIFO_OFFST, + .handshake = SDW1_ACP_P1_SW_AUDIO_RX_EN_CH, + }, + }, + .drv = &acp_swaudiodai_driver, + }, + { + .index = DI_SDW1_ACP_P1_SW_HS_TX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_PLAYBACK] = { + .offset = DAI_BASE_REM + SW1_HS_TX_FIFO_OFFST, + .handshake = SDW1_ACP_P1_SW_HS_TX_EN_CH, + }, + }, + .drv = &acp_swaudiodai_driver, + }, + { + .index = DI_SDW1_ACP_P1_SW_HS_RX, + .plat_data = { + .base = DAI_BASE_REM, + .fifo[SOF_IPC_STREAM_CAPTURE] = { + .offset = DAI_BASE_REM + SW1_HS_RX_FIFO_OFFST, + .handshake = SDW1_ACP_P1_SW_HS_RX_EN_CH, + }, + }, + .drv = &acp_swaudiodai_driver, + }, +}; + #ifdef ACP_SP_ENABLE static struct dai spdai[] = { { @@ -163,6 +300,11 @@ const struct dai_type_info dti[] = { .num_dais = ARRAY_SIZE(btdai) }, #endif + { + .type = SOF_DAI_AMD_SDW, + .dai_array = swaudiodai, + .num_dais = ARRAY_SIZE(swaudiodai) + }, }; const struct dai_info lib_dai = { @@ -179,6 +321,8 @@ int dai_init(struct sof *sof) k_spinlock_init(&acp_dmic_dai[i].lock); for (i = 0; i < ARRAY_SIZE(hsdai); i++) k_spinlock_init(&hsdai[i].lock); + for (i = 0; i < ARRAY_SIZE(swaudiodai); i++) + k_spinlock_init(&swaudiodai[i].lock); #ifdef ACP_SP_ENABLE for (i = 0; i < ARRAY_SIZE(spdai); i++) k_spinlock_init(&spdai[i].lock); diff --git a/src/platform/amd/acp_7_0/lib/dma.c b/src/platform/amd/acp_7_0/lib/dma.c index 9d840c3f5a6c..bbc6b4a6cd8a 100644 --- a/src/platform/amd/acp_7_0/lib/dma.c +++ b/src/platform/amd/acp_7_0/lib/dma.c @@ -22,6 +22,7 @@ extern struct dma_ops acp_dai_bt_dma_ops; extern struct dma_ops acp_dai_sp_dma_ops; #endif extern struct dma_ops acp_dai_hs_dma_ops; +extern struct dma_ops acp_dai_sw_audio_dma_ops; SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { { @@ -51,6 +52,20 @@ SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { }, .ops = &acp_dai_hs_dma_ops, }, +{ + .plat_data = { + .id = DMA_ID_DAI_SW_AUDIO, + .dir = DMA_DIR_DEV_TO_MEM | DMA_DIR_MEM_TO_DEV, + .devs = DMA_DEV_SW, + .caps = DMA_CAP_SW, + .base = DMA0_BASE, + .chan_size = DMA0_SIZE, + .channels = 12, + .irq = IRQ_NUM_EXT_LEVEL5, + .irq_name = "irqsteer1", + }, + .ops = &acp_dai_sw_audio_dma_ops, +}, { .plat_data = { .id = DMA_ID_DAI_DMIC, diff --git a/src/platform/amd/acp_7_0/platform.c b/src/platform/amd/acp_7_0/platform.c index 2ea94c659d92..72162bfd68f4 100644 --- a/src/platform/amd/acp_7_0/platform.c +++ b/src/platform/amd/acp_7_0/platform.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // -//Copyright(c) 2024 AMD. All rights reserved. +//Copyright(c) 2024, 2026 AMD. All rights reserved. // //Author: SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> +// Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> +// Sivasubramanian <sravisar@amd.com> #include <sof/compiler_info.h> #include <sof/debug/debug.h> @@ -33,7 +35,12 @@ #include <sof_versions.h> #include <errno.h> #include <stdint.h> -#include <platform/chip_offset_byte.h> +#include <zephyr/logging/log.h> + +LOG_MODULE_REGISTER(platform_file, CONFIG_SOF_LOG_LEVEL); + +#define INTERRUPT_DISABLE 0 +extern void acp_dsp_to_host_intr_trig(void); struct sof; static const struct sof_ipc_fw_ready ready @@ -48,11 +55,14 @@ static const struct sof_ipc_fw_ready ready .micro = SOF_MICRO, .minor = SOF_MINOR, .major = SOF_MAJOR, -#ifdef DEBUG_BUILD - /* only added in debug for reproducibility in releases */ - .build = SOF_BUILD, +#if BLD_COUNTERS + .build = SOF_BUILD, /* See version-build-counter.cmake */ .date = __DATE__, .time = __TIME__, +#else + .build = -1, + .date = "dtermin.\0", + .time = "fwready.\0", #endif .tag = SOF_TAG, .abi_version = SOF_ABI_VERSION, @@ -126,62 +136,34 @@ const struct ext_man_windows xsram_window }, }; -static SHARED_DATA struct timer timer = { - .id = TIMER0, - .irq = IRQ_NUM_TIMER0, -}; - int platform_init(struct sof *sof) { int ret; - sof->platform_timer = &timer; - sof->cpu_timers = &timer; /* to view system memory */ - interrupt_init(sof); platform_interrupt_init(); platform_clock_init(sof); scheduler_init_edf(); /* init low latency domains and schedulers */ /* CONFIG_SYSTICK_PERIOD set as PLATFORM_DEFAULT_CLOCK */ - sof->platform_timer_domain = - timer_domain_init(sof->platform_timer, PLATFORM_DEFAULT_CLOCK); - scheduler_init_ll(sof->platform_timer_domain); - platform_timer_start(sof->platform_timer); + sof->platform_timer_domain = zephyr_domain_init(PLATFORM_DEFAULT_CLOCK); + zephyr_ll_scheduler_init(sof->platform_timer_domain); + /*CONFIG_SYSTICK_PERIOD hardcoded as 200000*/ sa_init(sof, 200000); clock_set_freq(CLK_CPU(cpu_get_id()), CLK_MAX_CPU_HZ); /* init DMA */ - ret = acp_dma_init(sof); + ret = dmac_init(sof); if (ret < 0) return -ENODEV; - /* Init DMA platform domain */ - sof->platform_dma_domain = - dma_multi_chan_domain_init(&sof->dma_info->dma_array[0], - sizeof(sof->dma_info->dma_array), - PLATFORM_DEFAULT_CLOCK, true); - sof->platform_dma_domain->full_sync = true; - scheduler_init_ll(sof->platform_dma_domain); + /* initialize the host IPC mechanisms */ ipc_init(sof); /* initialize the DAI mechanisms */ ret = dai_init(sof); if (ret < 0) return -ENODEV; -#if CONFIG_TRACE - /* Initialize DMA for Trace*/ - trace_point(TRACE_BOOT_PLATFORM_DMA_TRACE); - sof->dmat->config.elem_array.elems = - rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(struct dma_sg_elem) * 1); - sof->dmat->config.elem_array.count = 1; - sof->dmat->config.elem_array.elems->dest = 0x03800000; - sof->dmat->config.elem_array.elems->size = 65536; - sof->dmat->config.scatter = 0; - dma_trace_init_complete(sof->dmat); -#endif - /* show heap status */ - heap_trace_all(1); + return 0; } @@ -209,8 +191,3 @@ int platform_context_save(struct sof *sof) { return 0; } - -void platform_wait_for_interrupt(int level) -{ - arch_wait_for_interrupt(level); -} diff --git a/src/platform/amd/acp_7_x/CMakeLists.txt b/src/platform/amd/acp_7_x/CMakeLists.txt new file mode 100644 index 000000000000..3108ac12f8db --- /dev/null +++ b/src/platform/amd/acp_7_x/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_subdirectory(lib) +add_local_sources(sof platform.c) diff --git a/src/platform/amd/acp_7_x/include/arch/xtensa/config/core-isa.h b/src/platform/amd/acp_7_x/include/arch/xtensa/config/core-isa.h new file mode 100644 index 000000000000..fbf0c967fd6c --- /dev/null +++ b/src/platform/amd/acp_7_x/include/arch/xtensa/config/core-isa.h @@ -0,0 +1,757 @@ +/* + * xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa + * processor CORE configuration + * + * See <xtensa/config/core.h>, which includes this file, for more details. + */ + +/* Xtensa processor core configuration information. + + Customer ID=20511; Build=0xb6494; Copyright (c) 1999-2024 Tensilica 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. */ + +#ifndef XTENSA_CORE_CONFIGURATION_H_ +#define XTENSA_CORE_CONFIGURATION_H_ + + +/**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + * configured, and a value of 0 otherwise. These macros are always defined. + */ + + +/*---------------------------------------------------------------------- + ISA + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED 1 /* windowed registers option */ +#define XCHAL_NUM_AREGS 64 /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2 6 /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE 16 /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG 1 /* debug option */ +#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS 1 /* zero-overhead loops */ +#define XCHAL_LOOP_BUFFER_SIZE 256 /* zero-ov. loop instr buffer size */ +#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX 1 /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT 1 /* SEXT instruction */ +#define XCHAL_HAVE_DEPBITS 0 /* DEPBITS instruction */ +#define XCHAL_HAVE_CLAMPS 1 /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32 1 /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH 1 /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_DIV32 1 /* QUOS/QUOU/REMS/REMU instructions */ +#define XCHAL_HAVE_L32R 1 /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS 0 /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_EXCLUSIVE 0 /* L32EX/S32EX instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12 1 /* (obsolete option) */ +#define XCHAL_HAVE_ABS 1 /* ABS instruction */ +#define XCHAL_HAVE_RELEASE_SYNC 1 /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I 0 /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION 0 /* speculation */ +#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS 1 /* */ +#define XCHAL_NUM_MISC_REGS 2 /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID 1 /* processor ID register */ +#define XCHAL_HAVE_EXTERN_REGS 1 /* WER/RER instructions */ +#define XCHAL_HAVE_MX 0 /* MX core (Tensilica internal) */ +#define XCHAL_HAVE_MP_INTERRUPTS 0 /* interrupt distributor port */ +#define XCHAL_HAVE_MP_RUNSTALL 0 /* core RunStall control port */ +#define XCHAL_HAVE_PSO 0 /* Power Shut-Off */ +#define XCHAL_HAVE_PSO_CDM 0 /* core/debug/mem pwr domains */ +#define XCHAL_HAVE_PSO_FULL_RETENTION 0 /* all regs preserved on PSO */ +#define XCHAL_HAVE_THREADPTR 1 /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS 1 /* boolean registers */ +#define XCHAL_HAVE_CP 1 /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG 2 /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16 0 /* MAC16 package */ +#define XCHAL_HAVE_LX 1 /* LX core */ +#define XCHAL_HAVE_NX 0 /* NX core (starting RH) */ +#define XCHAL_HAVE_RNX 0 /* RNX core (starting RJ) */ + +#define XCHAL_HAVE_SUPERGATHER 0 /* SuperGather */ + +#define XCHAL_HAVE_FUSION 0 /* Fusion */ +#define XCHAL_HAVE_FUSION_FP 0 /* Fusion FP option */ +#define XCHAL_HAVE_FUSION_LOW_POWER 0 /* Fusion Low Power option */ +#define XCHAL_HAVE_FUSION_AES 0 /* Fusion BLE/Wifi AES-128 CCM option */ +#define XCHAL_HAVE_FUSION_CONVENC 0 /* Fusion Conv Encode option */ +#define XCHAL_HAVE_FUSION_LFSR_CRC 0 /* Fusion LFSR-CRC option */ +#define XCHAL_HAVE_FUSION_BITOPS 0 /* Fusion Bit Operations Support option */ +#define XCHAL_HAVE_FUSION_AVS 0 /* Fusion AVS option */ +#define XCHAL_HAVE_FUSION_16BIT_BASEBAND 0 /* Fusion 16-bit Baseband option */ +#define XCHAL_HAVE_FUSION_VITERBI 0 /* Fusion Viterbi option */ +#define XCHAL_HAVE_FUSION_SOFTDEMAP 0 /* Fusion Soft Bit Demap option */ +#define XCHAL_HAVE_HIFIPRO 0 /* HiFiPro Audio Engine pkg */ +#define XCHAL_HAVE_HIFI5 1 /* HiFi5 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI5_NN_MAC 1 /* HiFi5 Audio Engine NN-MAC option */ +#define XCHAL_HAVE_HIFI5_VFPU 1 /* HiFi5 Audio Engine Single-Precision VFPU option */ +#define XCHAL_HAVE_HIFI5_HP_VFPU 1 /* HiFi5 Audio Engine Half-Precision VFPU option */ +#define XCHAL_HAVE_HIFI4 0 /* HiFi4 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI4_VFPU 1 /* HiFi4 Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI3 1 /* HiFi3 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI3_VFPU 1 /* HiFi3 Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI3Z 0 /* HiFi3Z Audio Engine pkg */ +#define XCHAL_HAVE_HIFI3Z_VFPU 0 /* HiFi3Z Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI1 0 /* HiFi1 */ +#define XCHAL_HAVE_HIFI1_VFPU 0 /* HiFi1 VFPU option */ +#define XCHAL_HAVE_HIFI1_LOW_LATENCY_MAC_FMA 0 /* HiFi1 Low-latency MAC/FMA option */ +#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI2EP 0 /* HiFi2EP */ +#define XCHAL_HAVE_HIFI_MINI 0 + + + +#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */ +#define XCHAL_HAVE_USER_DPFPU 0 /* user DP floating-point pkg */ +#define XCHAL_HAVE_USER_SPFPU 1 /* user SP floating-point pkg */ +#define XCHAL_HAVE_FP 1 /* single prec floating point */ +#define XCHAL_HAVE_FP_DIV 1 /* FP with DIV instructions */ +#define XCHAL_HAVE_FP_RECIP 1 /* FP with RECIP instructions */ +#define XCHAL_HAVE_FP_SQRT 1 /* FP with SQRT instructions */ +#define XCHAL_HAVE_FP_RSQRT 1 /* FP with RSQRT instructions */ +#define XCHAL_HAVE_DFP 0 /* double precision FP pkg */ +#define XCHAL_HAVE_DFP_DIV 0 /* DFP with DIV instructions */ +#define XCHAL_HAVE_DFP_RECIP 0 /* DFP with RECIP instructions*/ +#define XCHAL_HAVE_DFP_SQRT 0 /* DFP with SQRT instructions */ +#define XCHAL_HAVE_DFP_RSQRT 0 /* DFP with RSQRT instructions*/ +#define XCHAL_HAVE_DFP_ACCEL 0 /* double precision FP acceleration pkg */ +#define XCHAL_HAVE_DFP_accel XCHAL_HAVE_DFP_ACCEL /* for backward compatibility */ + +#define XCHAL_HAVE_DFPU_SINGLE_ONLY 0 /* DFPU Coprocessor, single precision only */ +#define XCHAL_HAVE_DFPU_SINGLE_DOUBLE 0 /* DFPU Coprocessor, single and double precision */ +#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */ +#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */ + +#define XCHAL_HAVE_FUSIONG 0 /* FusionG */ +#define XCHAL_HAVE_FUSIONG3 0 /* FusionG3 */ +#define XCHAL_HAVE_FUSIONG6 0 /* FusionG6 */ +#define XCHAL_HAVE_FUSIONG_SP_VFPU 0 /* sp_vfpu option on FusionG */ +#define XCHAL_HAVE_FUSIONG_DP_VFPU 0 /* dp_vfpu option on FusionG */ +#define XCHAL_FUSIONG_SIMD32 0 /* simd32 for FusionG */ + +#define XCHAL_HAVE_FUSIONJ 0 /* FusionJ */ +#define XCHAL_HAVE_FUSIONJ6 0 /* FusionJ6 */ +#define XCHAL_HAVE_FUSIONJ_SP_VFPU 0 /* sp_vfpu option on FusionJ */ +#define XCHAL_HAVE_FUSIONJ_DP_VFPU 0 /* dp_vfpu option on FusionJ */ +#define XCHAL_FUSIONJ_SIMD32 0 /* simd32 for FusionJ */ + +#define XCHAL_HAVE_PDX 0 /* PDX-LX */ +#define XCHAL_PDX_SIMD32 0 /* simd32 for PDX */ +#define XCHAL_HAVE_PDX4 0 /* PDX4-LX */ +#define XCHAL_HAVE_PDX8 0 /* PDX8-LX */ +#define XCHAL_HAVE_PDX16 0 /* PDX16-LX */ +#define XCHAL_HAVE_PDXNX 0 /* PDX-NX */ + +#define XCHAL_HAVE_CONNXD2 0 /* ConnX D2 pkg */ +#define XCHAL_HAVE_CONNXD2_DUALLSFLIX 0 /* ConnX D2 & Dual LoadStore Flix */ +#define XCHAL_HAVE_BALL 0 +#define XCHAL_HAVE_BALLAP 0 +#define XCHAL_HAVE_BBE16 0 /* ConnX BBE16 pkg */ +#define XCHAL_HAVE_BBE16_RSQRT 0 /* BBE16 & vector recip sqrt */ +#define XCHAL_HAVE_BBE16_VECDIV 0 /* BBE16 & vector divide */ +#define XCHAL_HAVE_BBE16_DESPREAD 0 /* BBE16 & despread */ +#define XCHAL_HAVE_CONNX_B10 0 /* ConnX B10 pkg*/ +#define XCHAL_HAVE_CONNX_B20 0 /* ConnX B20 pkg*/ +#define XCHAL_HAVE_CONNX_B_DP_VFPU 0 /* Double-precision Vector Floating-point option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_DPX_VFPU 0 /* Double-precision Vector Floating-point option on FP Machine*/ +#define XCHAL_HAVE_CONNX_B_SP_VFPU 0 /* Single-precision Vector Floating-point option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_SPX_VFPU 0 /* Single-precision Extended Vector Floating-point option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_HP_VFPU 0 /* Half-precision Vector Floating-point option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_HPX_VFPU 0 /* Half-precision Extended Vector Floating-point option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_32B_MAC 0 /* 32-bit vector MAC (real and complex), FIR & FFT option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_VITERBI 0 /* Viterbi option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_TURBO 0 /* Turbo option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_LDPC 0 /* LDPC option on ConnX B10 & B20 */ +#define XCHAL_HAVE_BBENEP 0 /* ConnX BBENEP pkgs */ +#define XCHAL_HAVE_BBENEP_SP_VFPU 0 /* sp_vfpu option on BBE-EP */ +#define XCHAL_HAVE_BSP3 0 /* ConnX BSP3 pkg */ +#define XCHAL_HAVE_BSP3_TRANSPOSE 0 /* BSP3 & transpose32x32 */ +#define XCHAL_HAVE_SSP16 0 /* ConnX SSP16 pkg */ +#define XCHAL_HAVE_SSP16_VITERBI 0 /* SSP16 & viterbi */ +#define XCHAL_HAVE_TURBO16 0 /* ConnX Turbo16 pkg */ +#define XCHAL_HAVE_BBP16 0 /* ConnX BBP16 pkg */ +#define XCHAL_HAVE_FLIX3 0 /* basic 3-way FLIX option */ +#define XCHAL_HAVE_GRIVPEP 0 /* General Release of IVPEP */ +#define XCHAL_HAVE_GRIVPEP_HISTOGRAM 0 /* Histogram option on GRIVPEP */ + +#define XCHAL_HAVE_VISION 0 /* Vision P5/P6 */ +#define XCHAL_VISION_SIMD16 0 /* simd16 for Vision P5/P6 */ +#define XCHAL_VISION_TYPE 0 /* Vision P5, P6, Q6, Q7 or Q8 */ +#define XCHAL_VISION_QUAD_MAC_TYPE 0 /* quad_mac option on Vision P6 */ +#define XCHAL_HAVE_VISION_HISTOGRAM 0 /* histogram option on Vision P5/P6 */ +#define XCHAL_HAVE_VISION_DP_VFPU 0 /* dp_vfpu option on Vision Q7/Q8 */ +#define XCHAL_HAVE_VISION_SP_VFPU 0 /* sp_vfpu option on Vision P5/P6/Q6/Q7 */ +#define XCHAL_HAVE_VISION_SP_VFPU_2XFMAC 0 /* sp_vfpu_2xfma option on Vision Q7 */ +#define XCHAL_HAVE_VISION_HP_VFPU 0 /* hp_vfpu option on Vision P6/Q6 */ +#define XCHAL_HAVE_VISION_HP_VFPU_2XFMAC 0 /* hp_vfpu_2xfma option on Vision Q7 */ + +#define XCHAL_HAVE_VISIONC 0 /* Vision C */ + +#define XCHAL_HAVE_XNNE 1 /* XNNE */ +#define XCHAL_XNNE_VERSION 2 /* XNNE version */ +#define XCHAL_XNNE_PADDR 0x20000000 /* Base address */ +#define XCHAL_XNNE_NUM_SBLKS 1 /* SBLK count */ +#define XCHAL_XNNE_MBLKS_PER_SBLK 4 /* MBLKs per SBLK */ +#define XCHAL_XNNE_IBUF_SIZE 0 /* IBuf size */ +#define XCHAL_XNNE_OBUF_SIZE 0 /* OBuf size */ +#define XCHAL_XNNE_CBUF_SIZE 0 /* CBuf size */ +#define XCHAL_XNNE_UBUF_SIZE 131072 /* UBuf size */ +#define XCHAL_XNNE_AXIM_DATA_WIDTH 128 /* Data Width */ + + +/*---------------------------------------------------------------------- + MISC + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_LOADSTORE_UNITS 2 /* load/store units */ +#define XCHAL_NUM_WRITEBUFFER_ENTRIES 16 /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH 16 /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH 16 /* data width in bytes */ +#define XCHAL_DATA_PIPE_DELAY 2 /* d-side pipeline delay + (1 = 5-stage, 2 = 7-stage) */ +#define XCHAL_CLOCK_GATING_GLOBAL 1 /* global clock gating */ +#define XCHAL_CLOCK_GATING_FUNCUNIT 1 /* funct. unit clock gating */ +/* In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/ +#define XCHAL_UNALIGNED_LOAD_HW 0 /* unaligned loads work in hw */ +#define XCHAL_UNALIGNED_STORE_HW 0 /* unaligned stores work in hw*/ + +#define XCHAL_UNIFIED_LOADSTORE 0 + +#define XCHAL_SW_VERSION 1409000 /* sw version of this header */ +#define XCHAL_SW_VERSION_MAJOR 14000 /* major ver# of sw */ +#define XCHAL_SW_VERSION_MINOR 9 /* minor ver# of sw */ +#define XCHAL_SW_VERSION_MICRO 0 /* micro ver# of sw */ +#define XCHAL_SW_MINOR_VERSION 1409000 /* with zeroed micro */ +#define XCHAL_SW_MICRO_VERSION 1409000 + +#define XCHAL_CORE_ID "ACP73x_HiFi5_NNE_PROD" /* alphanum core name + (CoreID) set in the Xtensa + Processor Generator */ + +#define XCHAL_BUILD_UNIQUE_ID 0x000B6494 /* 22-bit sw build ID */ + +/* + * These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0 0xC0039286 /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1 0x2A4B6494 /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME "LX7.1.9" /* full version name */ +#define XCHAL_HW_VERSION_MAJOR 2810 /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR 9 /* minor ver# of targeted hw */ +#define XCHAL_HW_VERSION_MICRO 0 /* subdot ver# of targeted hw */ +#define XCHAL_HW_VERSION 281090 /* major*100+(major<2810 ? minor : minor*10+micro) */ +#define XCHAL_HW_REL_LX7 1 +#define XCHAL_HW_REL_LX7_1 1 +#define XCHAL_HW_REL_LX7_1_9 1 +#define XCHAL_HW_CONFIGID_RELIABLE 1 +/* If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR 2810 /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR 9 /* minor v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MICRO 0 /* micro v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION 281090 /* earliest targeted hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR 2810 /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR 9 /* minor v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MICRO 0 /* micro v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION 281090 /* latest targeted hw */ + +/* Config is enabled for functional safety: */ +#define XCHAL_HAVE_FUNC_SAFETY 0 + +/* Config is enabled for secure operation: */ +#define XCHAL_HAVE_SECURE 0 + +#define XCHAL_HAVE_APB 0 + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE 128 /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE 128 /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH 7 /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH 7 /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE 131072 /* I-cache size in bytes or 0 */ +#define XCHAL_ICACHE_SIZE_LOG2 17 +#define XCHAL_DCACHE_SIZE 131072 /* D-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE_LOG2 17 + +#define XCHAL_DCACHE_IS_WRITEBACK 1 /* writeback feature */ +#define XCHAL_DCACHE_IS_COHERENT 0 /* MP coherence feature */ + +#define XCHAL_HAVE_PREFETCH 1 /* PREFCTL register */ +#define XCHAL_HAVE_PREFETCH_L1 1 /* prefetch to L1 cache */ +#define XCHAL_PREFETCH_CASTOUT_LINES 2 /* dcache pref. castout bufsz */ +#define XCHAL_PREFETCH_ENTRIES 16 /* cache prefetch entries */ +#define XCHAL_PREFETCH_BLOCK_ENTRIES 0 /* prefetch block streams */ +#define XCHAL_HAVE_CACHE_BLOCKOPS 0 /* block prefetch for caches */ +#define XCHAL_HAVE_CME_DOWNGRADES 0 +#define XCHAL_HAVE_ICACHE_TEST 1 /* Icache test instructions */ +#define XCHAL_HAVE_DCACHE_TEST 1 /* Dcache test instructions */ +#define XCHAL_HAVE_ICACHE_DYN_WAYS 1 /* Icache dynamic way support */ +#define XCHAL_HAVE_DCACHE_DYN_WAYS 1 /* Dcache dynamic way support */ +#define XCHAL_HAVE_ICACHE_DYN_ENABLE 1 /* Icache enabled via MEMCTL */ +#define XCHAL_HAVE_DCACHE_DYN_ENABLE 1 /* Dcache enabled via MEMCTL */ + +#define XCHAL_L1SCACHE_SIZE 0 +#define XCHAL_L1SCACHE_SIZE_LOG2 0 +#define XCHAL_L1SCACHE_WAYS 1 +#define XCHAL_L1SCACHE_WAYS_LOG2 0 +#define XCHAL_L1SCACHE_ACCESS_SIZE 0 +#define XCHAL_L1SCACHE_BANKS 1 + +#define XCHAL_L1VCACHE_SIZE 0 + +#define XCHAL_HAVE_L2 0 /* NX L2 cache controller */ +#define XCHAL_HAVE_L2_CACHE 0 +#define XCHAL_NUM_CORES_IN_CLUSTER 0 + +/* PRID_ID macros are for internal use only ... subject to removal */ +#define PRID_ID_SHIFT 0 +#define PRID_ID_BITS 4 +#define PRID_ID_MASK 0x0000000F + +/* This one is a form of caching, though not architecturally visible: */ +#define XCHAL_HAVE_BRANCH_PREDICTION 0 /* branch [target] prediction */ + + + + +/**************************************************************************** + Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF 1 /* any outbound bus present */ + +#define XCHAL_HAVE_AXI 1 /* AXI bus */ +#define XCHAL_HAVE_AXI_ECC 1 /* ECC on AXI bus */ +#define XCHAL_HAVE_ACELITE 0 /* ACELite bus */ + +#define XCHAL_HAVE_PIF_WR_RESP 1 /* pif write response */ +#define XCHAL_HAVE_PIF_REQ_ATTR 1 /* pif attribute */ + +/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */ + +/* Number of cache sets in log2(lines per way): */ +#define XCHAL_ICACHE_SETWIDTH 8 +#define XCHAL_DCACHE_SETWIDTH 8 + +/* Cache set associativity (number of ways): */ +#define XCHAL_ICACHE_WAYS 4 +#define XCHAL_ICACHE_WAYS_LOG2 2 +#define XCHAL_DCACHE_WAYS 4 +#define XCHAL_DCACHE_WAYS_LOG2 2 + +/* Cache features: */ +#define XCHAL_ICACHE_LINE_LOCKABLE 1 +#define XCHAL_DCACHE_LINE_LOCKABLE 1 +#define XCHAL_ICACHE_ECC_PARITY 0 +#define XCHAL_DCACHE_ECC_PARITY 0 +#define XCHAL_ICACHE_ECC_WIDTH 4 +#define XCHAL_DCACHE_ECC_WIDTH 1 + +/* Cache access size in bytes (affects operation of SICW instruction): */ +#define XCHAL_ICACHE_ACCESS_SIZE 16 +#define XCHAL_DCACHE_ACCESS_SIZE 16 + +#define XCHAL_DCACHE_BANKS 2 /* number of banks */ + +/* The number of Cache lines associated with a single cache tag */ +#define XCHAL_DCACHE_LINES_PER_TAG_LOG2 0 + +/* Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits): */ + +/* Extended memory attributes supported. */ +#define XCHAL_HAVE_EXT_CA 0 + + +/*---------------------------------------------------------------------- + INTERNAL I/D RAM/ROMs and XLMI + ----------------------------------------------------------------------*/ +#define XCHAL_NUM_INSTROM 0 /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM 1 /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM 0 /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM 1 /* number of core data RAMs */ +#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI 0 /* number of core XLMI ports */ +#define XCHAL_HAVE_IRAMCFG 0 /* IRAMxCFG register present */ +#define XCHAL_HAVE_DRAMCFG 0 /* DRAMxCFG register present */ + +/* Instruction RAM 0: */ +#define XCHAL_INSTRAM0_VADDR 0x7F000000 /* virtual address */ +#define XCHAL_INSTRAM0_PADDR 0x7F000000 /* physical address */ +#define XCHAL_INSTRAM0_SIZE 524288 /* size in bytes */ +#define XCHAL_INSTRAM0_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_HAVE_INSTRAM0 1 +#define XCHAL_INSTRAM0_HAVE_IDMA 0 /* idma supported by this local memory */ + +/* Data RAM 0: */ +#define XCHAL_DATARAM0_VADDR 0xE0000000 /* virtual address */ +#define XCHAL_DATARAM0_PADDR 0xE0000000 /* physical address */ +#define XCHAL_DATARAM0_SIZE 524288 /* size in bytes */ +#define XCHAL_DATARAM0_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_DATARAM0_BANKS 2 /* number of banks */ +#define XCHAL_HAVE_DATARAM0 1 +#define XCHAL_DATARAM0_HAVE_IDMA 1 /* idma supported by this local memory */ + +#define XCHAL_HAVE_IMEM_LOADSTORE 1 /* can load/store to IROM/IRAM*/ + + +/*---------------------------------------------------------------------- + IDMA + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_IDMA 0 +#define XCHAL_IDMA_NUM_CHANNELS 1 /* number of channels */ +#define XCHAL_IDMA_ADDR_WIDTH 32 /* address width in bits */ +#define XCHAL_IDMA_DATA_WIDTH 128 /* data width in bits */ +#define XCHAL_IDMA_DESC_SIZE 32 /* max descriptor size */ +#define XCHAL_IDMA_MAX_OUTSTANDING_REQ 64 /* max outstanding requests */ +#define XCHAL_IDMA_HAVE_REORDERBUF 0 /* has reorder buffer */ +#define XCHAL_IDMA_HAVE_TRANSPOSE 0 /* has transpose function */ +#define XCHAL_HAVE_IDMA_TRANSPOSE 0 /* Deprecated */ +#define XCHAL_IDMA_NUM_AXI2AXI_CHAN 0 /* how many channels support AXI-to-AXI transfers */ +#define XCHAL_IDMA_ID_PER_CHANNEL 0 + +#define XCHAL_IDMA_CH0_DONE_INTERRUPT 9 +#define XCHAL_IDMA_CH0_ERR_INTERRUPT 10 + + +/*---------------------------------------------------------------------- + INTERRUPTS and TIMERS + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */ +#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS 2 /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS 13 /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2 4 /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS 7 /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS 6 /* number of interrupt levels + (not including level zero) */ + + +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */ +#define XCHAL_EXCM_LEVEL 5 /* level masked by PS.EXCM */ + /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/* Masks of interrupts at each interrupt level: */ +#define XCHAL_INTLEVEL1_MASK 0x00001F43 +#define XCHAL_INTLEVEL2_MASK 0x00000004 +#define XCHAL_INTLEVEL3_MASK 0x00000008 +#define XCHAL_INTLEVEL4_MASK 0x00000010 +#define XCHAL_INTLEVEL5_MASK 0x00000020 +#define XCHAL_INTLEVEL6_MASK 0x00000000 +#define XCHAL_INTLEVEL7_MASK 0x00000080 + +/* Masks of interrupts at each range 1..n of interrupt levels: */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x00001F43 +#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x00001F47 +#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x00001F4F +#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x00001F5F +#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x00001F7F +#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x00001F7F +#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x00001FFF + +/* Level of each interrupt: */ +#define XCHAL_INT0_LEVEL 1 +#define XCHAL_INT1_LEVEL 1 +#define XCHAL_INT2_LEVEL 2 +#define XCHAL_INT3_LEVEL 3 +#define XCHAL_INT4_LEVEL 4 +#define XCHAL_INT5_LEVEL 5 +#define XCHAL_INT6_LEVEL 1 +#define XCHAL_INT7_LEVEL 7 +#define XCHAL_INT8_LEVEL 1 +#define XCHAL_INT9_LEVEL 1 +#define XCHAL_INT10_LEVEL 1 +#define XCHAL_INT11_LEVEL 1 +#define XCHAL_INT12_LEVEL 1 +#define XCHAL_DEBUGLEVEL 6 /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */ +#define XCHAL_NMILEVEL 7 /* NMI "level" (for use with + EXCSAVE/EPS/EPC_n, RFI n) */ + +/* Type of each interrupt: */ +#define XCHAL_INT0_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT1_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT2_TYPE XTHAL_INTTYPE_WRITE_ERROR +#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT7_TYPE XTHAL_INTTYPE_NMI +#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT9_TYPE XTHAL_INTTYPE_IDMA_DONE +#define XCHAL_INT10_TYPE XTHAL_INTTYPE_IDMA_ERR +#define XCHAL_INT11_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_LEVEL + +/* Masks of interrupts for each type of interrupt: */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFFE000 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x00001938 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00000000 +#define XCHAL_INTTYPE_MASK_NMI 0x00000080 +#define XCHAL_INTTYPE_MASK_SOFTWARE 0x00000002 +#define XCHAL_INTTYPE_MASK_TIMER 0x00000041 +#define XCHAL_INTTYPE_MASK_ETIE 0x00000000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000004 +#define XCHAL_INTTYPE_MASK_DBG_REQUEST 0x00000000 +#define XCHAL_INTTYPE_MASK_BREAKIN 0x00000000 +#define XCHAL_INTTYPE_MASK_TRAX 0x00000000 +#define XCHAL_INTTYPE_MASK_PROFILING 0x00000000 +#define XCHAL_INTTYPE_MASK_IDMA_DONE 0x00000200 +#define XCHAL_INTTYPE_MASK_IDMA_ERR 0x00000400 +#define XCHAL_INTTYPE_MASK_GS_ERR 0x00000000 +#define XCHAL_INTTYPE_MASK_L2_ERR 0x00000000 +#define XCHAL_INTTYPE_MASK_L2_STATUS 0x00000000 +#define XCHAL_INTTYPE_MASK_COR_ECC_ERR 0x00000000 +#define XCHAL_INTTYPE_MASK_WWDT 0x00000000 +#define XCHAL_INTTYPE_MASK_FXLK 0x00000000 + +/* Interrupt numbers assigned to specific interrupt sources: */ +#define XCHAL_TIMER0_INTERRUPT 0 /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT 6 /* CCOMPARE1 */ +#define XCHAL_TIMER2_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_NMI_INTERRUPT 7 /* non-maskable interrupt */ +#define XCHAL_WRITE_ERROR_INTERRUPT 2 +#define XCHAL_IDMA_DONE_INTERRUPT 9 +#define XCHAL_IDMA_ERR_INTERRUPT 10 + +/* Interrupt numbers for levels at which only one interrupt is configured: */ +#define XCHAL_INTLEVEL2_NUM 2 +#define XCHAL_INTLEVEL3_NUM 3 +#define XCHAL_INTLEVEL4_NUM 4 +#define XCHAL_INTLEVEL5_NUM 5 +#define XCHAL_INTLEVEL7_NUM 7 +/* (There are many interrupts each at level(s) 1.) */ + + +/* + * External interrupt mapping. + * These macros describe how Xtensa processor interrupt numbers + * (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + * map to external BInterrupt<n> pins, for those interrupts + * configured as external (level-triggered, edge-triggered, or NMI). + * See the Xtensa processor databook for more details. + */ + +/* Core interrupt numbers mapped to each EXTERNAL BInterrupt pin number: */ +#define XCHAL_EXTINT0_NUM 3 /* (intlevel 3) */ +#define XCHAL_EXTINT1_NUM 4 /* (intlevel 4) */ +#define XCHAL_EXTINT2_NUM 5 /* (intlevel 5) */ +#define XCHAL_EXTINT3_NUM 7 /* (intlevel 7) */ +#define XCHAL_EXTINT4_NUM 8 /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM 11 /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM 12 /* (intlevel 1) */ +/* EXTERNAL BInterrupt pin numbers mapped to each core interrupt number: */ +#define XCHAL_INT3_EXTNUM 0 /* (intlevel 3) */ +#define XCHAL_INT4_EXTNUM 1 /* (intlevel 4) */ +#define XCHAL_INT5_EXTNUM 2 /* (intlevel 5) */ +#define XCHAL_INT7_EXTNUM 3 /* (intlevel 7) */ +#define XCHAL_INT8_EXTNUM 4 /* (intlevel 1) */ +#define XCHAL_INT11_EXTNUM 5 /* (intlevel 1) */ +#define XCHAL_INT12_EXTNUM 6 /* (intlevel 1) */ + +#define XCHAL_HAVE_ISB 0 /* No ISB */ +#define XCHAL_ISB_VADDR 0 /* N/A */ +#define XCHAL_HAVE_ITB 0 /* No ITB */ +#define XCHAL_ITB_VADDR 0 /* N/A */ + +#define XCHAL_HAVE_KSL 0 /* Kernel Stack Limit */ +#define XCHAL_HAVE_ISL 0 /* Interrupt Stack Limit */ +#define XCHAL_HAVE_PSL 0 /* Pageable Stack Limit */ + + +/*---------------------------------------------------------------------- + EXCEPTIONS and VECTORS + ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture + number: 1 == XEA1 (until T1050) + 2 == XEA2 (LX) + 3 == XEA3 (NX) + 0 == XEA5 (RNX) */ +#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEA3 0 /* Exception Architecture 3 */ +#define XCHAL_HAVE_XEA5 0 /* Exception Architecture 5 */ +#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */ +#define XCHAL_HAVE_IMPRECISE_EXCEPTIONS 0 /* imprecise exception option */ +#define XCHAL_EXCCAUSE_NUM 64 /* Number of exceptions */ +#define XCHAL_HAVE_HALT 0 /* halt architecture option */ +#define XCHAL_HAVE_BOOTLOADER 0 /* boot loader (for TX) */ +#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */ +#define XCHAL_HAVE_VECTOR_SELECT 0 /* relocatable vectors */ +#define XCHAL_HAVE_VECBASE 0 /* relocatable vectors */ + +#define XCHAL_RESET_VECOFS 0x00000000 +#define XCHAL_RESET_VECTOR_VADDR 0x7F000000 +#define XCHAL_RESET_VECTOR_PADDR 0x7F000000 +#define XCHAL_USER_VECOFS 0x00000000 +#define XCHAL_USER_VECTOR_VADDR 0x7F000740 +#define XCHAL_USER_VECTOR_PADDR 0x7F000740 +#define XCHAL_KERNEL_VECOFS 0x00000000 +#define XCHAL_KERNEL_VECTOR_VADDR 0x7F000700 +#define XCHAL_KERNEL_VECTOR_PADDR 0x7F000700 +#define XCHAL_DOUBLEEXC_VECOFS 0x00000000 +#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x7F0007C0 +#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x7F0007C0 +#define XCHAL_WINDOW_OF4_VECOFS 0x00000000 +#define XCHAL_WINDOW_UF4_VECOFS 0x00000040 +#define XCHAL_WINDOW_OF8_VECOFS 0x00000080 +#define XCHAL_WINDOW_UF8_VECOFS 0x000000C0 +#define XCHAL_WINDOW_OF12_VECOFS 0x00000100 +#define XCHAL_WINDOW_UF12_VECOFS 0x00000140 +#define XCHAL_WINDOW_VECTORS_VADDR 0x7F000400 +#define XCHAL_WINDOW_VECTORS_PADDR 0x7F000400 +#define XCHAL_INTLEVEL2_VECOFS 0x00000000 +#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x7F000580 +#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x7F000580 +#define XCHAL_INTLEVEL3_VECOFS 0x00000000 +#define XCHAL_INTLEVEL3_VECTOR_VADDR 0x7F0005C0 +#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x7F0005C0 +#define XCHAL_INTLEVEL4_VECOFS 0x00000000 +#define XCHAL_INTLEVEL4_VECTOR_VADDR 0x7F000600 +#define XCHAL_INTLEVEL4_VECTOR_PADDR 0x7F000600 +#define XCHAL_INTLEVEL5_VECOFS 0x00000000 +#define XCHAL_INTLEVEL5_VECTOR_VADDR 0x7F000640 +#define XCHAL_INTLEVEL5_VECTOR_PADDR 0x7F000640 +#define XCHAL_INTLEVEL6_VECOFS 0x00000000 +#define XCHAL_INTLEVEL6_VECTOR_VADDR 0x7F000680 +#define XCHAL_INTLEVEL6_VECTOR_PADDR 0x7F000680 +#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL6_VECOFS +#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL6_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL6_VECTOR_PADDR +#define XCHAL_NMI_VECOFS 0x00000000 +#define XCHAL_NMI_VECTOR_VADDR 0x7F0006C0 +#define XCHAL_NMI_VECTOR_PADDR 0x7F0006C0 +#define XCHAL_INTLEVEL7_VECOFS XCHAL_NMI_VECOFS +#define XCHAL_INTLEVEL7_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR +#define XCHAL_INTLEVEL7_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR + + +/*---------------------------------------------------------------------- + DEBUG MODULE + ----------------------------------------------------------------------*/ + +/* Misc */ +#define XCHAL_HAVE_DEBUG_ERI 1 /* ERI to debug module */ +#define XCHAL_HAVE_DEBUG_APB 1 /* APB to debug module */ +#define XCHAL_HAVE_DEBUG_JTAG 1 /* JTAG to debug module */ + +/* On-Chip Debug (OCD) */ +#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY 0 /* faster OCD option (to LX4) */ +#define XCHAL_HAVE_OCD_LS32DDR 1 /* L32DDR/S32DDR (faster OCD) */ + +/* TRAX (in core) */ +#define XCHAL_HAVE_TRAX 1 /* TRAX in debug module */ +#define XCHAL_TRAX_MEM_SIZE 4096 /* TRAX memory size in bytes */ +#define XCHAL_TRAX_MEM_SHAREABLE 0 /* start/end regs; ready sig. */ +#define XCHAL_TRAX_ATB_WIDTH 0 /* ATB width (bits), 0=no ATB */ +#define XCHAL_TRAX_TIME_WIDTH 0 /* timestamp bitwidth, 0=none */ + +/* Perf counters */ +#define XCHAL_NUM_PERF_COUNTERS 0 /* performance counters */ + + +/*---------------------------------------------------------------------- + MMU + ----------------------------------------------------------------------*/ + +/* See core-matmap.h header file for more details. */ + +#define XCHAL_HAVE_TLBS 0 /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY 0 /* one way maps I+D 4GB vaddr */ +#define XCHAL_HAVE_IDENTITY_MAP 1 /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR 0 /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU 0 /* full MMU (with page table + [autorefill] and protection) + usable for an MMU-based OS */ + +/* If none of the above last 5 are set, it's a custom TLB configuration. */ + +#define XCHAL_MMU_ASID_BITS 0 /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS 1 /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS 0 /* num of bits in RING field */ + +/*---------------------------------------------------------------------- + MPU + ----------------------------------------------------------------------*/ +#define XCHAL_HAVE_MPU 1 +#define XCHAL_MPU_ENTRIES 32 +#define XCHAL_MPU_LOCK 0 + +#define XCHAL_MPU_ALIGN_REQ 1 /* MPU requires alignment of entries to background map */ +#define XCHAL_MPU_BACKGROUND_ENTRIES 2 /* number of entries in bg map*/ +#define XCHAL_MPU_BG_CACHEADRDIS 0xFF /* default CACHEADRDIS for bg */ + +#define XCHAL_MPU_ALIGN_BITS 12 +#define XCHAL_MPU_ALIGN 4096 + +/*----------------------------------------------------------------------- + CSR Parity +------------------------------------------------------------------------*/ +#define XCHAL_HAVE_CSR_PARITY 0 + + +/*---------------------------------------------------------------------- + FLEX-LOCK +------------------------------------------------------------------------*/ + +#define XCHAL_HAVE_FXLK 0 + +/*---------------------------------------------------------------------- + WWDT (Windowed Watchdog Timer) +------------------------------------------------------------------------*/ +#define XCHAL_HAVE_WWDT 0 +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* XTENSA_CORE_CONFIGURATION_H_ */ + diff --git a/src/platform/amd/acp_7_x/include/arch/xtensa/config/core-matmap.h b/src/platform/amd/acp_7_x/include/arch/xtensa/config/core-matmap.h new file mode 100644 index 000000000000..23dca086d8b8 --- /dev/null +++ b/src/platform/amd/acp_7_x/include/arch/xtensa/config/core-matmap.h @@ -0,0 +1,106 @@ +/* + * xtensa/config/core-matmap.h -- Memory access and translation mapping + * parameters (CHAL) of the Xtensa processor core configuration. + * + * If you are using Xtensa Tools, see <xtensa/config/core.h> (which includes + * this file) for more details. + * + * In the Xtensa processor products released to date, all parameters + * defined in this file are derivable (at least in theory) from + * information contained in the core-isa.h header file. + * In particular, the following core configuration parameters are relevant: + * XCHAL_HAVE_CACHEATTR + * XCHAL_HAVE_MIMIC_CACHEATTR + * XCHAL_HAVE_XLT_CACHEATTR + * XCHAL_HAVE_PTP_MMU + * XCHAL_ITLB_ARF_ENTRIES_LOG2 + * XCHAL_DTLB_ARF_ENTRIES_LOG2 + * XCHAL_DCACHE_IS_WRITEBACK + * XCHAL_ICACHE_SIZE (presence of I-cache) + * XCHAL_DCACHE_SIZE (presence of D-cache) + * XCHAL_HW_VERSION_MAJOR + * XCHAL_HW_VERSION_MINOR + */ + +/* Customer ID=20511; Build=0xb6494; Copyright (c) 1999-2024 Tensilica 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. */ + + +#ifndef XTENSA_CONFIG_CORE_MATMAP_H +#define XTENSA_CONFIG_CORE_MATMAP_H + + +/*---------------------------------------------------------------------- + CACHE (MEMORY ACCESS) ATTRIBUTES + ----------------------------------------------------------------------*/ +/*---------------------------------------------------------------------- + MPU + ----------------------------------------------------------------------*/ + +/* Mappings for legacy constants where appropriate */ + +#define XCHAL_CA_WRITEBACK (XTHAL_MEM_WRITEBACK | XTHAL_AR_RWXrwx) + +#define XCHAL_CA_WRITEBACK_NOALLOC (XTHAL_MEM_WRITEBACK_NOALLOC| XTHAL_AR_RWXrwx ) + +#define XCHAL_CA_WRITETHRU (XTHAL_MEM_WRITETHRU | XTHAL_AR_RWXrwx) + +#define XCHAL_CA_ILLEGAL (XTHAL_AR_NONE | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASS (XTHAL_AR_RWXrwx | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASSBUF (XTHAL_AR_RWXrwx | XTHAL_MEM_DEVICE |\ + XTHAL_MEM_BUFFERABLE) +#define XCHAL_CA_BYPASS_RX (XTHAL_AR_RX | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASS_RW (XTHAL_AR_RW | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASS_R (XTHAL_AR_R | XTHAL_MEM_DEVICE) +#define XCHAL_HAVE_CA_WRITEBACK_NOALLOC 1 + +#define XCHAL_CA_R (XTHAL_AR_R) +#define XCHAL_CA_RX (XTHAL_AR_RX) +#define XCHAL_CA_RW (XTHAL_AR_RW) +#define XCHAL_CA_RWX (XTHAL_AR_RWX) + + +/* + * Contents of MPU background map. + * NOTE: caller must define the XCHAL_MPU_BGMAP() macro (not defined here + * but specified below) before expanding the XCHAL_MPU_BACKGROUND_MAP(s) macro. + * + * XCHAL_MPU_BGMAP(s, vaddr_start, vaddr_last, rights, memtype, x...) + * + * s = passed from XCHAL_MPU_BACKGROUND_MAP(s), eg. to select how to expand + * vaddr_start = first byte of region (always 0 for first entry) + * vaddr_end = last byte of region (always 0xFFFFFFFF for last entry) + * rights = access rights + * memtype = memory type + * x = reserved for future use (0 until then) + */ +/* parasoft-begin-suppress MISRA2012-RULE-20_7 "Macro use model requires s to not be in ()" */ +#define XCHAL_MPU_BACKGROUND_MAP(s) \ + XCHAL_MPU_BGMAP(s, 0x00000000, 0x7fffffff, 7, 6, 0) \ + XCHAL_MPU_BGMAP(s, 0x80000000, 0xffffffff, 7, 6, 0) \ +/* parasoft-end-suppress MISRA2012-RULE-20_7 "Macro use model requires s to not be in ()" */ + + /* end */ + + + +#endif /*XTENSA_CONFIG_CORE_MATMAP_H*/ + diff --git a/src/platform/amd/acp_7_x/include/arch/xtensa/config/defs.h b/src/platform/amd/acp_7_x/include/arch/xtensa/config/defs.h new file mode 100644 index 000000000000..cbcb6b5c39de --- /dev/null +++ b/src/platform/amd/acp_7_x/include/arch/xtensa/config/defs.h @@ -0,0 +1,38 @@ +/* Definitions for Xtensa instructions, types, and protos. */ + +/* Customer ID=20511; Build=0xb6494; Copyright (c) 2003-2004 Tensilica 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. */ + +/* NOTE: This file exists only for backward compatibility with T1050 + and earlier Xtensa releases. It includes only a subset of the + available header files. */ + +#ifndef _XTENSA_BASE_HEADER +#define _XTENSA_BASE_HEADER + +#ifdef __XTENSA__ + +#include <xtensa/tie/xt_core.h> +#include <xtensa/tie/xt_misc.h> +#include <xtensa/tie/xt_booleans.h> + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_BASE_HEADER */ diff --git a/src/platform/amd/acp_7_x/include/arch/xtensa/config/specreg.h b/src/platform/amd/acp_7_x/include/arch/xtensa/config/specreg.h new file mode 100644 index 000000000000..81a0a6780016 --- /dev/null +++ b/src/platform/amd/acp_7_x/include/arch/xtensa/config/specreg.h @@ -0,0 +1,109 @@ +/* + * Xtensa Special Register symbolic names + */ + +/* $Id: //depot/rel/Homewood/ib.9/Xtensa/SWConfig/hal/specreg.h.tpp#1 $ */ + +/* Customer ID=20511; Build=0xb6494; Copyright (c) 1998-2002 Tensilica 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. */ + +#ifndef XTENSA_SPECREG_H +#define XTENSA_SPECREG_H + +/* Include these special register bitfield definitions, for historical reasons: */ +#include <xtensa/corebits.h> + + +/* Special registers: */ +#define LBEG 0 +#define LEND 1 +#define LCOUNT 2 +#define SAR 3 +#define BR 4 +#define PREFCTL 40 +#define WINDOWBASE 72 +#define WINDOWSTART 73 +#define MPUENB 90 +#define ERACCESS 95 +#define IBREAKENABLE 96 +#define MEMCTL 97 +#define CACHEADRDIS 98 +#define DDR 104 +#define IBREAKA_0 128 +#define IBREAKA_1 129 +#define DBREAKA_0 144 +#define DBREAKA_1 145 +#define DBREAKC_0 160 +#define DBREAKC_1 161 +#define EPC_1 177 +#define EPC_2 178 +#define EPC_3 179 +#define EPC_4 180 +#define EPC_5 181 +#define EPC_6 182 +#define EPC_7 183 +#define DEPC 192 +#define EPS_2 194 +#define EPS_3 195 +#define EPS_4 196 +#define EPS_5 197 +#define EPS_6 198 +#define EPS_7 199 +#define EXCSAVE_1 209 +#define EXCSAVE_2 210 +#define EXCSAVE_3 211 +#define EXCSAVE_4 212 +#define EXCSAVE_5 213 +#define EXCSAVE_6 214 +#define EXCSAVE_7 215 +#define CPENABLE 224 +#define INTERRUPT 226 +#define INTENABLE 228 +#define PS 230 +#define EXCCAUSE 232 +#define DEBUGCAUSE 233 +#define CCOUNT 234 +#define PRID 235 +#define ICOUNT 236 +#define ICOUNTLEVEL 237 +#define EXCVADDR 238 +#define CCOMPARE_0 240 +#define CCOMPARE_1 241 +#define MISC_REG_0 244 +#define MISC_REG_1 245 + + +/* Special cases (bases of special register series): */ +#define IBREAKA 128 +#define DBREAKA 144 +#define DBREAKC 160 +#define EPC 176 +#define EPS 192 +#define EXCSAVE 208 +#define CCOMPARE 240 + +/* Special names for read-only and write-only interrupt registers: */ +#define INTREAD 226 +#define INTSET 226 +#define INTCLEAR 227 + +#endif /* XTENSA_SPECREG_H */ + diff --git a/src/platform/amd/acp_7_x/include/arch/xtensa/config/system.h b/src/platform/amd/acp_7_x/include/arch/xtensa/config/system.h new file mode 100644 index 000000000000..5a03eebf7b85 --- /dev/null +++ b/src/platform/amd/acp_7_x/include/arch/xtensa/config/system.h @@ -0,0 +1,262 @@ +/* + * xtensa/config/system.h -- HAL definitions that are dependent on SYSTEM configuration + * + * NOTE: The location and contents of this file are highly subject to change. + * + * Source for configuration-independent binaries (which link in a + * configuration-specific HAL library) must NEVER include this file. + * The HAL itself has historically included this file in some instances, + * but this is not appropriate either, because the HAL is meant to be + * core-specific but system independent. + */ + +/* Customer ID=20511; Build=0xb6494; Copyright (c) 2000-2010 Tensilica 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. */ + + +#ifndef XTENSA_CONFIG_SYSTEM_H +#define XTENSA_CONFIG_SYSTEM_H + + +/*---------------------------------------------------------------------- + CONFIGURED SOFTWARE OPTIONS + ----------------------------------------------------------------------*/ + +#define XSHAL_USE_ABSOLUTE_LITERALS 0 /* (sw-only option, whether software uses absolute literals) */ +#define XSHAL_HAVE_TEXT_SECTION_LITERALS 1 /* Set if there is some memory that allows both code and literals. */ + +#define XSHAL_ABI XTHAL_ABI_WINDOWED /* (sw-only option, selected ABI) */ +/* The above maps to one of the following constants: */ +#define XTHAL_ABI_WINDOWED 0 +#define XTHAL_ABI_CALL0 1 + +#define XSHAL_CLIB XTHAL_CLIB_XCLIB /* (sw-only option, selected C library) */ +/* The above maps to one of the following constants: */ +#define XTHAL_CLIB_NEWLIB 0 +#define XTHAL_CLIB_UCLIBC 1 +#define XTHAL_CLIB_XCLIB 2 + +#define XSHAL_USE_FLOATING_POINT 1 + +#define XSHAL_FLOATING_POINT_ABI 1 + +/* SW workarounds enabled for HW errata: */ + +/*---------------------------------------------------------------------- + DEVICE ADDRESSES + ----------------------------------------------------------------------*/ + +/* + * Strange place to find these, but the configuration GUI + * allows moving these around to account for various core + * configurations. Specific boards (and their BSP software) + * will have specific meanings for these components. + */ + +/* I/O Block areas: */ +#define XSHAL_IOBLOCK_CACHED_VADDR 0x70000000 +#define XSHAL_IOBLOCK_CACHED_PADDR 0x70000000 +#define XSHAL_IOBLOCK_CACHED_SIZE 0x0E000000 + +#define XSHAL_IOBLOCK_BYPASS_VADDR 0x90000000 +#define XSHAL_IOBLOCK_BYPASS_PADDR 0x90000000 +#define XSHAL_IOBLOCK_BYPASS_SIZE 0x0E000000 + +/* System ROM: */ +#define XSHAL_ROM_VADDR 0x50000000 +#define XSHAL_ROM_PADDR 0x50000000 +#define XSHAL_ROM_SIZE 0x00020000 +/* Largest available area (free of vectors): */ +#define XSHAL_ROM_AVAIL_VADDR 0x50000000 +#define XSHAL_ROM_AVAIL_VSIZE 0x00020000 + +/* System RAM: */ +#define XSHAL_RAM_VADDR 0x60000000 +#define XSHAL_RAM_PADDR 0x60000000 +#define XSHAL_RAM_VSIZE 0x1F000000 +#define XSHAL_RAM_PSIZE 0x1F000000 +#define XSHAL_RAM_SIZE XSHAL_RAM_PSIZE +/* Largest available area (free of vectors): */ +#define XSHAL_RAM_AVAIL_VADDR 0x60000000 +#define XSHAL_RAM_AVAIL_VSIZE 0x1F000000 + +/* + * Shadow system RAM (same device as system RAM, at different address). + * (Emulation boards need this for the SONIC Ethernet driver + * when data caches are configured for writeback mode.) + * NOTE: on full MMU configs, this points to the BYPASS virtual address + * of system RAM, ie. is the same as XSHAL_RAM_* except that virtual + * addresses are viewed through the BYPASS static map rather than + * the CACHED static map. + */ +#define XSHAL_RAM_BYPASS_VADDR 0x20000000 +#define XSHAL_RAM_BYPASS_PADDR 0x20000000 +#define XSHAL_RAM_BYPASS_PSIZE 0x1F000000 + +/* Alternate system RAM (different device than system RAM): */ + +/* Some available location in which to place devices in a simulation (eg. XTMP): */ +#define XSHAL_SIMIO_CACHED_VADDR 0xC0000000 +#define XSHAL_SIMIO_BYPASS_VADDR 0xC0000000 +#define XSHAL_SIMIO_PADDR 0xC0000000 +#define XSHAL_SIMIO_SIZE 0x20000000 + + +/*---------------------------------------------------------------------- + * For use by reference testbench exit and diagnostic routines. + */ +#define XSHAL_MAGIC_EXIT 0xc61b3000 +#define XSHAL_STL_INFO_LOCATION 0xbffffffc + +/*---------------------------------------------------------------------- + * DEVICE-ADDRESS DEPENDENT... + * + * Values written to CACHEATTR special register (or its equivalent) + * to enable and disable caches in various modes. + *----------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------- + BACKWARD COMPATIBILITY ... + ----------------------------------------------------------------------*/ + +/* + * NOTE: the following two macros are DEPRECATED. Use the latter + * board-specific macros instead, which are specially tuned for the + * particular target environments' memory maps. + */ +#define XSHAL_CACHEATTR_BYPASS XSHAL_XT2000_CACHEATTR_BYPASS /* disable caches in bypass mode */ +#define XSHAL_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_DEFAULT /* default setting to enable caches (no writeback!) */ + +/*---------------------------------------------------------------------- + GENERIC + ----------------------------------------------------------------------*/ + +/* For the following, a 512MB region is used if it contains a system (PIF) RAM, + * system (PIF) ROM, local memory, or XLMI. */ + +/* These set any unused 512MB region to cache-BYPASS attribute: */ +#define XSHAL_ALLVALID_CACHEATTR_WRITEBACK 0x42224422 /* enable caches in write-back mode */ +#define XSHAL_ALLVALID_CACHEATTR_WRITEALLOC 0x12221122 /* enable caches in write-allocate mode */ +#define XSHAL_ALLVALID_CACHEATTR_WRITETHRU 0x12221122 /* enable caches in write-through mode */ +#define XSHAL_ALLVALID_CACHEATTR_BYPASS 0x22222222 /* disable caches in bypass mode */ +#define XSHAL_ALLVALID_CACHEATTR_DEFAULT XSHAL_ALLVALID_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +/* These set any unused 512MB region to ILLEGAL attribute: */ +#define XSHAL_STRICT_CACHEATTR_WRITEBACK 0x4FFF44FF /* enable caches in write-back mode */ +#define XSHAL_STRICT_CACHEATTR_WRITEALLOC 0x1FFF11FF /* enable caches in write-allocate mode */ +#define XSHAL_STRICT_CACHEATTR_WRITETHRU 0x1FFF11FF /* enable caches in write-through mode */ +#define XSHAL_STRICT_CACHEATTR_BYPASS 0x2FFF22FF /* disable caches in bypass mode */ +#define XSHAL_STRICT_CACHEATTR_DEFAULT XSHAL_STRICT_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +/* These set the first 512MB, if unused, to ILLEGAL attribute to help catch + * NULL-pointer dereference bugs; all other unused 512MB regions are set + * to cache-BYPASS attribute: */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITEBACK 0x4222442F /* enable caches in write-back mode */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITEALLOC 0x1222112F /* enable caches in write-allocate mode */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITETHRU 0x1222112F /* enable caches in write-through mode */ +#define XSHAL_TRAPNULL_CACHEATTR_BYPASS 0x2222222F /* disable caches in bypass mode */ +#define XSHAL_TRAPNULL_CACHEATTR_DEFAULT XSHAL_TRAPNULL_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +/*---------------------------------------------------------------------- + ISS (Instruction Set Simulator) SPECIFIC ... + ----------------------------------------------------------------------*/ + +/* For now, ISS defaults to the TRAPNULL settings: */ +#define XSHAL_ISS_CACHEATTR_WRITEBACK XSHAL_TRAPNULL_CACHEATTR_WRITEBACK +#define XSHAL_ISS_CACHEATTR_WRITEALLOC XSHAL_TRAPNULL_CACHEATTR_WRITEALLOC +#define XSHAL_ISS_CACHEATTR_WRITETHRU XSHAL_TRAPNULL_CACHEATTR_WRITETHRU +#define XSHAL_ISS_CACHEATTR_BYPASS XSHAL_TRAPNULL_CACHEATTR_BYPASS +#define XSHAL_ISS_CACHEATTR_DEFAULT XSHAL_TRAPNULL_CACHEATTR_WRITEBACK + +#define XSHAL_ISS_PIPE_REGIONS 0 +#define XSHAL_ISS_SDRAM_REGIONS 0 + + +/*---------------------------------------------------------------------- + XT2000 BOARD SPECIFIC ... + ----------------------------------------------------------------------*/ + +/* For the following, a 512MB region is used if it contains any system RAM, + * system ROM, local memory, XLMI, or other XT2000 board device or memory. + * Regions containing devices are forced to cache-BYPASS mode regardless + * of whether the macro is _WRITEBACK vs. _BYPASS etc. */ + +/* These set any 512MB region unused on the XT2000 to ILLEGAL attribute: */ +#define XSHAL_XT2000_CACHEATTR_WRITEBACK 0x4FF2442F /* enable caches in write-back mode */ +#define XSHAL_XT2000_CACHEATTR_WRITEALLOC 0x1FF2112F /* enable caches in write-allocate mode */ +#define XSHAL_XT2000_CACHEATTR_WRITETHRU 0x1FF2112F /* enable caches in write-through mode */ +#define XSHAL_XT2000_CACHEATTR_BYPASS 0x2FF2222F /* disable caches in bypass mode */ +#define XSHAL_XT2000_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +#define XSHAL_XT2000_PIPE_REGIONS 0x00000000 /* BusInt pipeline regions */ +#define XSHAL_XT2000_SDRAM_REGIONS 0x00000044 /* BusInt SDRAM regions */ + + +/*---------------------------------------------------------------------- + VECTOR INFO AND SIZES + ----------------------------------------------------------------------*/ + +#define XSHAL_VECTORS_PACKED 0 /* UNUSED */ +#define XSHAL_STATIC_VECTOR_SELECT 0 +#define XSHAL_RESET_VECTOR_VADDR 0x7F000000 +#define XSHAL_RESET_VECTOR_PADDR 0x7F000000 + +/* + * Sizes allocated to vectors by the system (memory map) configuration. + * These sizes are constrained by core configuration (eg. one vector's + * code cannot overflow into another vector) but are dependent on the + * system or board (or LSP) memory map configuration. + * + * Whether or not each vector happens to be in a system ROM is also + * a system configuration matter, sometimes useful, included here also: + */ +#define XSHAL_RESET_VECTOR_SIZE 0x00000300 +#define XSHAL_RESET_VECTOR_ISROM 0 +#define XSHAL_USER_VECTOR_SIZE 0x00000038 +#define XSHAL_USER_VECTOR_ISROM 0 +#define XSHAL_PROGRAMEXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_USEREXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_KERNEL_VECTOR_SIZE 0x00000038 +#define XSHAL_KERNEL_VECTOR_ISROM 0 +#define XSHAL_STACKEDEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_KERNELEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_DOUBLEEXC_VECTOR_SIZE 0x00000040 +#define XSHAL_DOUBLEEXC_VECTOR_ISROM 0 +#define XSHAL_WINDOW_VECTORS_SIZE 0x00000178 +#define XSHAL_WINDOW_VECTORS_ISROM 0 +#define XSHAL_INTLEVEL2_VECTOR_SIZE 0x00000038 +#define XSHAL_INTLEVEL2_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL3_VECTOR_SIZE 0x00000038 +#define XSHAL_INTLEVEL3_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL4_VECTOR_SIZE 0x00000038 +#define XSHAL_INTLEVEL4_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL5_VECTOR_SIZE 0x00000038 +#define XSHAL_INTLEVEL5_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL6_VECTOR_SIZE 0x00000038 +#define XSHAL_INTLEVEL6_VECTOR_ISROM 0 +#define XSHAL_DEBUG_VECTOR_SIZE XSHAL_INTLEVEL6_VECTOR_SIZE +#define XSHAL_DEBUG_VECTOR_ISROM XSHAL_INTLEVEL6_VECTOR_ISROM +#define XSHAL_NMI_VECTOR_SIZE 0x00000038 +#define XSHAL_NMI_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL7_VECTOR_SIZE XSHAL_NMI_VECTOR_SIZE + +#endif /*XTENSA_CONFIG_SYSTEM_H*/ + diff --git a/src/platform/amd/acp_7_x/include/arch/xtensa/config/tie-asm.h b/src/platform/amd/acp_7_x/include/arch/xtensa/config/tie-asm.h new file mode 100644 index 000000000000..18935b08cc73 --- /dev/null +++ b/src/platform/amd/acp_7_x/include/arch/xtensa/config/tie-asm.h @@ -0,0 +1,382 @@ +/* + * tie-asm.h -- compile-time HAL assembler definitions dependent on CORE & TIE + * + * NOTE: This header file is not meant to be included directly. + */ + +/* This header file contains assembly-language definitions (assembly + macros, etc.) for this specific Xtensa processor's TIE extensions + and options. It is customized to this Xtensa processor configuration. + + Customer ID=20511; Build=0xb6494; Copyright (c) 1999-2024 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. */ + +#ifndef _XTENSA_CORE_TIE_ASM_H +#define _XTENSA_CORE_TIE_ASM_H + +#include <xtensa/coreasm.h> + +/* Selection parameter values for save-area save/restore macros: */ +/* Option vs. TIE: */ +#define XTHAL_SAS_TIE 0x0001 /* custom extension or coprocessor */ +#define XTHAL_SAS_OPT 0x0002 /* optional (and not a coprocessor) */ +#define XTHAL_SAS_ANYOT 0x0003 /* both of the above */ +/* Whether used automatically by compiler: */ +#define XTHAL_SAS_NOCC 0x0004 /* not used by compiler w/o special opts/code */ +#define XTHAL_SAS_CC 0x0008 /* used by compiler without special opts/code */ +#define XTHAL_SAS_ANYCC 0x000C /* both of the above */ +/* ABI handling across function calls: */ +#define XTHAL_SAS_CALR 0x0010 /* caller-saved */ +#define XTHAL_SAS_CALE 0x0020 /* callee-saved */ +#define XTHAL_SAS_GLOB 0x0040 /* global across function calls (in thread) */ +#define XTHAL_SAS_ANYABI 0x0070 /* all of the above three */ +/* Misc */ +#define XTHAL_SAS_ALL 0xFFFF /* include all default NCP contents */ +#define XTHAL_SAS3(optie,ccuse,abi) ( ((optie) & XTHAL_SAS_ANYOT) \ + | ((ccuse) & XTHAL_SAS_ANYCC) \ + | ((abi) & XTHAL_SAS_ANYABI) ) + + + /* + * Macro to store all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 4 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_NCP_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters: + * continue If macro invoked as part of a larger store sequence, set to 1 + * if this is not the first in the sequence. Defaults to 0. + * ofs Offset from start of larger sequence (from value of first ptr + * in sequence) at which to store. Defaults to next available space + * (or 0 if <continue> is 0). + * select Select what category(ies) of registers to store, as a bitmask + * (see XTHAL_SAS_xxx constants). Defaults to all registers. + * alloc Select what category(ies) of registers to allocate; if any + * category is selected here that is not in <select>, space for + * the corresponding registers is skipped without doing any store. + */ + .macro xchal_ncp_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL alloc=0 + xchal_sa_start \continue, \ofs + // Optional global registers used by default by the compiler: + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\select) + xchal_sa_align \ptr, 0, 1016, 4, 4 + rur.threadptr \at1 // threadptr option + s32i \at1, \ptr, .Lxchal_ofs_+0 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .elseif ((XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1016, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + // Optional caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 1016, 4, 4 + rsr.br \at1 // boolean option + s32i \at1, \ptr, .Lxchal_ofs_+0 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .elseif ((XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1016, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + // Custom caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 1016, 4, 4 + rur.xnne_rerr \at1 // ureg 0 + s32i \at1, \ptr, .Lxchal_ofs_+0 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .elseif ((XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1016, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .endm // xchal_ncp_store + + /* + * Macro to load all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 4 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_NCP_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters: + * continue If macro invoked as part of a larger load sequence, set to 1 + * if this is not the first in the sequence. Defaults to 0. + * ofs Offset from start of larger sequence (from value of first ptr + * in sequence) at which to load. Defaults to next available space + * (or 0 if <continue> is 0). + * select Select what category(ies) of registers to load, as a bitmask + * (see XTHAL_SAS_xxx constants). Defaults to all registers. + * alloc Select what category(ies) of registers to allocate; if any + * category is selected here that is not in <select>, space for + * the corresponding registers is skipped without doing any load. + */ + .macro xchal_ncp_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL alloc=0 + xchal_sa_start \continue, \ofs + // Optional global registers used by default by the compiler: + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\select) + xchal_sa_align \ptr, 0, 1016, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_+0 + wur.threadptr \at1 // threadptr option + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .elseif ((XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1016, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + // Optional caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 1016, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_+0 + wsr.br \at1 // boolean option + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .elseif ((XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1016, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + // Custom caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 1016, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_+0 + wur.xnne_rerr \at1 // ureg 0 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .elseif ((XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1016, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .endm // xchal_ncp_load + + +#define XCHAL_NCP_NUM_ATMPS 1 + + /* + * Macro to store the state of TIE coprocessor AudioEngineLX. + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 16 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_CP1_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters are the same as for xchal_ncp_store. + */ +#define xchal_cp_AudioEngineLX_store xchal_cp1_store + .macro xchal_cp1_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL alloc=0 + xchal_sa_start \continue, \ofs + // Custom caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 0, 16, 16 + ae_s64.i aed0, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_s64.i aed1, \ptr, .Lxchal_ofs_+0 + ae_s64.i aed2, \ptr, .Lxchal_ofs_+8 + ae_s64.i aed3, \ptr, .Lxchal_ofs_+16 + ae_s64.i aed4, \ptr, .Lxchal_ofs_+24 + ae_s64.i aed5, \ptr, .Lxchal_ofs_+32 + ae_s64.i aed6, \ptr, .Lxchal_ofs_+40 + ae_s64.i aed7, \ptr, .Lxchal_ofs_+48 + ae_s64.i aed8, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_s64.i aed9, \ptr, .Lxchal_ofs_+0 + ae_s64.i aed10, \ptr, .Lxchal_ofs_+8 + ae_s64.i aed11, \ptr, .Lxchal_ofs_+16 + ae_s64.i aed12, \ptr, .Lxchal_ofs_+24 + ae_s64.i aed13, \ptr, .Lxchal_ofs_+32 + ae_s64.i aed14, \ptr, .Lxchal_ofs_+40 + ae_s64.i aed15, \ptr, .Lxchal_ofs_+48 + ae_s64.i aed16, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_s64.i aed17, \ptr, .Lxchal_ofs_+0 + ae_s64.i aed18, \ptr, .Lxchal_ofs_+8 + ae_s64.i aed19, \ptr, .Lxchal_ofs_+16 + ae_s64.i aed20, \ptr, .Lxchal_ofs_+24 + ae_s64.i aed21, \ptr, .Lxchal_ofs_+32 + ae_s64.i aed22, \ptr, .Lxchal_ofs_+40 + ae_s64.i aed23, \ptr, .Lxchal_ofs_+48 + ae_s64.i aed24, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_s64.i aed25, \ptr, .Lxchal_ofs_+0 + ae_s64.i aed26, \ptr, .Lxchal_ofs_+8 + ae_s64.i aed27, \ptr, .Lxchal_ofs_+16 + ae_s64.i aed28, \ptr, .Lxchal_ofs_+24 + ae_s64.i aed29, \ptr, .Lxchal_ofs_+32 + ae_s64.i aed30, \ptr, .Lxchal_ofs_+40 + ae_s64.i aed31, \ptr, .Lxchal_ofs_+48 + ae_movae \at1, aep0 + s8i \at1, \ptr, .Lxchal_ofs_+56 + ae_movae \at1, aep1 + s8i \at1, \ptr, .Lxchal_ofs_+57 + ae_movae \at1, aep2 + s8i \at1, \ptr, .Lxchal_ofs_+58 + ae_movae \at1, aep3 + s8i \at1, \ptr, .Lxchal_ofs_+59 + addi \ptr, \ptr, 64 + ae_salign128.i u0, \ptr, .Lxchal_ofs_+0 + ae_salign128.i u1, \ptr, .Lxchal_ofs_+16 + ae_salign128.i u2, \ptr, .Lxchal_ofs_+32 + ae_salign128.i u3, \ptr, .Lxchal_ofs_+48 + addi \ptr, \ptr, -320 + ae_movdrzbvc aed0 // ureg AE_ZBIASV8C + ae_s64.i aed0, \ptr, .Lxchal_ofs_+0 + 0 + ae_movvfcrfsr aed0 // ureg FCR_FSR + ae_s64.i aed0, \ptr, .Lxchal_ofs_+8 + 0 + rur.ae_ovf_sar \at1 // ureg 240 + s32i \at1, \ptr, .Lxchal_ofs_+16 + rur.ae_bithead \at1 // ureg 241 + s32i \at1, \ptr, .Lxchal_ofs_+20 + rur.ae_ts_fts_bu_bp \at1 // ureg 242 + s32i \at1, \ptr, .Lxchal_ofs_+24 + rur.ae_cw_sd_no \at1 // ureg 243 + s32i \at1, \ptr, .Lxchal_ofs_+28 + rur.ae_cbegin0 \at1 // ureg 246 + s32i \at1, \ptr, .Lxchal_ofs_+32 + rur.ae_cend0 \at1 // ureg 247 + s32i \at1, \ptr, .Lxchal_ofs_+36 + rur.ae_cbegin1 \at1 // ureg 248 + s32i \at1, \ptr, .Lxchal_ofs_+40 + rur.ae_cend1 \at1 // ureg 249 + s32i \at1, \ptr, .Lxchal_ofs_+44 + rur.ae_cbegin2 \at1 // ureg 250 + s32i \at1, \ptr, .Lxchal_ofs_+48 + rur.ae_cend2 \at1 // ureg 251 + s32i \at1, \ptr, .Lxchal_ofs_+52 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 384 + .elseif ((XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 0, 16, 16 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 384 + .endif + .endm // xchal_cp1_store + + /* + * Macro to load the state of TIE coprocessor AudioEngineLX. + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 16 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_CP1_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters are the same as for xchal_ncp_load. + */ +#define xchal_cp_AudioEngineLX_load xchal_cp1_load + .macro xchal_cp1_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL alloc=0 + xchal_sa_start \continue, \ofs + // Custom caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 0, 16, 16 + ae_l64.i aed0, \ptr, .Lxchal_ofs_+0 + 0 // ureg AE_ZBIASV8C + ae_movzbvcdr aed0 + ae_l64.i aed0, \ptr, .Lxchal_ofs_+8 + 0 // ureg FCR_FSR + ae_movfcrfsrv aed0 + l32i \at1, \ptr, .Lxchal_ofs_+16 + wur.ae_ovf_sar \at1 // ureg 240 + l32i \at1, \ptr, .Lxchal_ofs_+20 + wur.ae_bithead \at1 // ureg 241 + l32i \at1, \ptr, .Lxchal_ofs_+24 + wur.ae_ts_fts_bu_bp \at1 // ureg 242 + l32i \at1, \ptr, .Lxchal_ofs_+28 + wur.ae_cw_sd_no \at1 // ureg 243 + l32i \at1, \ptr, .Lxchal_ofs_+32 + wur.ae_cbegin0 \at1 // ureg 246 + l32i \at1, \ptr, .Lxchal_ofs_+36 + wur.ae_cend0 \at1 // ureg 247 + l32i \at1, \ptr, .Lxchal_ofs_+40 + wur.ae_cbegin1 \at1 // ureg 248 + l32i \at1, \ptr, .Lxchal_ofs_+44 + wur.ae_cend1 \at1 // ureg 249 + l32i \at1, \ptr, .Lxchal_ofs_+48 + wur.ae_cbegin2 \at1 // ureg 250 + l32i \at1, \ptr, .Lxchal_ofs_+52 + wur.ae_cend2 \at1 // ureg 251 + ae_l64.i aed0, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_l64.i aed1, \ptr, .Lxchal_ofs_+0 + ae_l64.i aed2, \ptr, .Lxchal_ofs_+8 + ae_l64.i aed3, \ptr, .Lxchal_ofs_+16 + ae_l64.i aed4, \ptr, .Lxchal_ofs_+24 + ae_l64.i aed5, \ptr, .Lxchal_ofs_+32 + ae_l64.i aed6, \ptr, .Lxchal_ofs_+40 + ae_l64.i aed7, \ptr, .Lxchal_ofs_+48 + ae_l64.i aed8, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_l64.i aed9, \ptr, .Lxchal_ofs_+0 + ae_l64.i aed10, \ptr, .Lxchal_ofs_+8 + ae_l64.i aed11, \ptr, .Lxchal_ofs_+16 + ae_l64.i aed12, \ptr, .Lxchal_ofs_+24 + ae_l64.i aed13, \ptr, .Lxchal_ofs_+32 + ae_l64.i aed14, \ptr, .Lxchal_ofs_+40 + ae_l64.i aed15, \ptr, .Lxchal_ofs_+48 + ae_l64.i aed16, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_l64.i aed17, \ptr, .Lxchal_ofs_+0 + ae_l64.i aed18, \ptr, .Lxchal_ofs_+8 + ae_l64.i aed19, \ptr, .Lxchal_ofs_+16 + ae_l64.i aed20, \ptr, .Lxchal_ofs_+24 + ae_l64.i aed21, \ptr, .Lxchal_ofs_+32 + ae_l64.i aed22, \ptr, .Lxchal_ofs_+40 + ae_l64.i aed23, \ptr, .Lxchal_ofs_+48 + ae_l64.i aed24, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_l64.i aed25, \ptr, .Lxchal_ofs_+0 + ae_l64.i aed26, \ptr, .Lxchal_ofs_+8 + ae_l64.i aed27, \ptr, .Lxchal_ofs_+16 + ae_l64.i aed28, \ptr, .Lxchal_ofs_+24 + ae_l64.i aed29, \ptr, .Lxchal_ofs_+32 + ae_l64.i aed30, \ptr, .Lxchal_ofs_+40 + ae_l64.i aed31, \ptr, .Lxchal_ofs_+48 + addi \ptr, \ptr, 56 + l8ui \at1, \ptr, .Lxchal_ofs_+0 + ae_movea aep0, \at1 + l8ui \at1, \ptr, .Lxchal_ofs_+1 + ae_movea aep1, \at1 + l8ui \at1, \ptr, .Lxchal_ofs_+2 + ae_movea aep2, \at1 + l8ui \at1, \ptr, .Lxchal_ofs_+3 + ae_movea aep3, \at1 + addi \ptr, \ptr, 8 + ae_lalign128.i u0, \ptr, .Lxchal_ofs_+0 + ae_lalign128.i u1, \ptr, .Lxchal_ofs_+16 + ae_lalign128.i u2, \ptr, .Lxchal_ofs_+32 + ae_lalign128.i u3, \ptr, .Lxchal_ofs_+48 + .set .Lxchal_pofs_, .Lxchal_pofs_ + 320 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 64 + .elseif ((XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 0, 16, 16 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 384 + .endif + .endm // xchal_cp1_load + +#define XCHAL_CP1_NUM_ATMPS 1 +#define XCHAL_SA_NUM_ATMPS 1 + + /* Empty macros for unconfigured coprocessors: */ + .macro xchal_cp0_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp0_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp2_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp2_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp3_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp3_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp4_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp4_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp5_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp5_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp6_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp6_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp7_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp7_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + +#endif /*_XTENSA_CORE_TIE_ASM_H*/ + diff --git a/src/platform/amd/acp_7_x/include/arch/xtensa/config/tie.h b/src/platform/amd/acp_7_x/include/arch/xtensa/config/tie.h new file mode 100644 index 000000000000..3faa4ccfa7a1 --- /dev/null +++ b/src/platform/amd/acp_7_x/include/arch/xtensa/config/tie.h @@ -0,0 +1,211 @@ +/* + * tie.h -- compile-time HAL definitions dependent on CORE & TIE configuration + * + * NOTE: This header file is not meant to be included directly. + */ + +/* This header file describes this specific Xtensa processor's TIE extensions + that extend basic Xtensa core functionality. It is customized to this + Xtensa processor configuration. + + Customer ID=20511; Build=0xb6494; Copyright (c) 1999-2024 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. */ + +#ifndef XTENSA_CORE_TIE_H +#define XTENSA_CORE_TIE_H + +/* parasoft-begin-suppress ALL "This file not MISRA checked." */ + +#define XCHAL_CP_NUM 1 /* number of coprocessors */ +#define XCHAL_CP_MAX 2 /* max CP ID + 1 (0 if none) */ +#define XCHAL_CP_MASK 0x02 /* bitmask of all CPs by ID */ +#define XCHAL_CP_PORT_MASK 0x00 /* bitmask of only port CPs */ + +/* Basic parameters of each coprocessor: */ +#define XCHAL_CP1_NAME "AudioEngineLX" +#define XCHAL_CP1_IDENT AudioEngineLX +#define XCHAL_CP1_SA_SIZE 384 /* size of state save area */ +#define XCHAL_CP1_SA_ALIGN 16 /* min alignment of save area */ +#define XCHAL_CP_ID_AUDIOENGINELX 1 /* coprocessor ID (0..7) */ + +/* Filler info for unassigned coprocessors, to simplify arrays etc: */ +#define XCHAL_CP0_SA_SIZE 0 +#define XCHAL_CP0_SA_ALIGN 1 +#define XCHAL_CP2_SA_SIZE 0 +#define XCHAL_CP2_SA_ALIGN 1 +#define XCHAL_CP3_SA_SIZE 0 +#define XCHAL_CP3_SA_ALIGN 1 +#define XCHAL_CP4_SA_SIZE 0 +#define XCHAL_CP4_SA_ALIGN 1 +#define XCHAL_CP5_SA_SIZE 0 +#define XCHAL_CP5_SA_ALIGN 1 +#define XCHAL_CP6_SA_SIZE 0 +#define XCHAL_CP6_SA_ALIGN 1 +#define XCHAL_CP7_SA_SIZE 0 +#define XCHAL_CP7_SA_ALIGN 1 + +/* Save area for non-coprocessor optional and custom (TIE) state: */ +#define XCHAL_NCP_SA_SIZE 12 +#define XCHAL_NCP_SA_ALIGN 4 + +/* Total save area for optional and custom state (NCP + CPn): */ +#define XCHAL_TOTAL_SA_SIZE 400 /* with 16-byte align padding */ +#define XCHAL_TOTAL_SA_ALIGN 16 /* actual minimum alignment */ + +/* + * Detailed contents of save areas. + * NOTE: caller must define the XCHAL_SA_REG macro (not defined here) + * before expanding the XCHAL_xxx_SA_LIST() macros. + * + * XCHAL_SA_REG(s,ccused,abikind,kind,opt,name,galign,align,asize, + * dbnum,base,regnum,bitsz,gapsz,reset,x...) + * + * s = passed from XCHAL_*_LIST(s), eg. to select how to expand + * ccused = set if used by compiler without special options or code + * abikind = 0 (caller-saved), 1 (callee-saved), or 2 (thread-global) + * kind = 0 (special reg), 1 (TIE user reg), or 2 (TIE regfile reg) + * opt = 0 (custom TIE extension or coprocessor), or 1 (optional reg) + * name = lowercase reg name (no quotes) + * galign = group byte alignment (power of 2) (galign >= align) + * align = register byte alignment (power of 2) + * asize = allocated size in bytes (asize*8 == bitsz + gapsz + padsz) + * (not including any pad bytes required to galign this or next reg) + * dbnum = unique target number f/debug (see <xtensa-libdb-macros.h>) + * base = reg shortname w/o index (or sr=special, ur=TIE user reg) + * regnum = reg index in regfile, or special/TIE-user reg number + * bitsz = number of significant bits (regfile width, or ur/sr mask bits) + * gapsz = intervening bits, if bitsz bits not stored contiguously + * (padsz = pad bits at end [TIE regfile] or at msbits [ur,sr] of asize) + * reset = register reset value (or 0 if undefined at reset) + * x = reserved for future use (0 until then) + * + * To filter out certain registers, e.g. to expand only the non-global + * registers used by the compiler, you can do something like this: + * + * #define XCHAL_SA_REG(s,ccused,p...) SELCC##ccused(p) + * #define SELCC0(p...) + * #define SELCC1(abikind,p...) SELAK##abikind(p) + * #define SELAK0(p...) REG(p) + * #define SELAK1(p...) REG(p) + * #define SELAK2(p...) + * #define REG(kind,tie,name,galn,aln,asz,csz,dbnum,base,rnum,bsz,rst,x...) \ + * ...what you want to expand... + */ + +#define XCHAL_NCP_SA_NUM 3 +#define XCHAL_NCP_SA_LIST(s) \ + XCHAL_SA_REG(s,1,2,1,1, threadptr, 4, 4, 4,0x03E7, ur,231, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,0,1, br, 4, 4, 4,0x0204, sr,4 , 16,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, xnne_rerr, 4, 4, 4,0x0300, ur,0 , 1,0,0,0) + +#define XCHAL_CP0_SA_NUM 0 +#define XCHAL_CP0_SA_LIST(s) /* empty */ + +#define XCHAL_CP1_SA_NUM 52 +#define XCHAL_CP1_SA_LIST(s) \ + XCHAL_SA_REG(s,0,0,1,0, ae_zbiasv8c,16, 8, 8,0x1029, ur,-1 , 16,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, fcr_fsr, 8, 8, 8,0x102A, ur,-1 , 7,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_ovf_sar, 4, 4, 4,0x03F0, ur,240, 15,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_bithead, 4, 4, 4,0x03F1, ur,241, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0,ae_ts_fts_bu_bp, 4, 4, 4,0x03F2, ur,242, 16,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cw_sd_no, 4, 4, 4,0x03F3, ur,243, 29,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cbegin0, 4, 4, 4,0x03F6, ur,246, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cend0, 4, 4, 4,0x03F7, ur,247, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cbegin1, 4, 4, 4,0x03F8, ur,248, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cend1, 4, 4, 4,0x03F9, ur,249, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cbegin2, 4, 4, 4,0x03FA, ur,250, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cend2, 4, 4, 4,0x03FB, ur,251, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed0, 8, 8, 8,0x1000, aed,0 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed1, 8, 8, 8,0x1001, aed,1 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed2, 8, 8, 8,0x1002, aed,2 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed3, 8, 8, 8,0x1003, aed,3 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed4, 8, 8, 8,0x1004, aed,4 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed5, 8, 8, 8,0x1005, aed,5 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed6, 8, 8, 8,0x1006, aed,6 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed7, 8, 8, 8,0x1007, aed,7 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed8, 8, 8, 8,0x1008, aed,8 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed9, 8, 8, 8,0x1009, aed,9 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed10, 8, 8, 8,0x100A, aed,10 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed11, 8, 8, 8,0x100B, aed,11 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed12, 8, 8, 8,0x100C, aed,12 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed13, 8, 8, 8,0x100D, aed,13 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed14, 8, 8, 8,0x100E, aed,14 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed15, 8, 8, 8,0x100F, aed,15 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed16, 8, 8, 8,0x1010, aed,16 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed17, 8, 8, 8,0x1011, aed,17 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed18, 8, 8, 8,0x1012, aed,18 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed19, 8, 8, 8,0x1013, aed,19 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed20, 8, 8, 8,0x1014, aed,20 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed21, 8, 8, 8,0x1015, aed,21 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed22, 8, 8, 8,0x1016, aed,22 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed23, 8, 8, 8,0x1017, aed,23 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed24, 8, 8, 8,0x1018, aed,24 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed25, 8, 8, 8,0x1019, aed,25 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed26, 8, 8, 8,0x101A, aed,26 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed27, 8, 8, 8,0x101B, aed,27 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed28, 8, 8, 8,0x101C, aed,28 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed29, 8, 8, 8,0x101D, aed,29 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed30, 8, 8, 8,0x101E, aed,30 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed31, 8, 8, 8,0x101F, aed,31 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aep0, 1, 1, 1,0x1024, aep,0 , 8,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aep1, 1, 1, 1,0x1025, aep,1 , 8,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aep2, 1, 1, 1,0x1026, aep,2 , 8,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aep3, 1, 1, 1,0x1027, aep,3 , 8,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, u0,16,16,16,0x1020, u,0 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, u1,16,16,16,0x1021, u,1 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, u2,16,16,16,0x1022, u,2 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, u3,16,16,16,0x1023, u,3 ,128,0,0,0) + +#define XCHAL_CP2_SA_NUM 0 +#define XCHAL_CP2_SA_LIST(s) /* empty */ + +#define XCHAL_CP3_SA_NUM 0 +#define XCHAL_CP3_SA_LIST(s) /* empty */ + +#define XCHAL_CP4_SA_NUM 0 +#define XCHAL_CP4_SA_LIST(s) /* empty */ + +#define XCHAL_CP5_SA_NUM 0 +#define XCHAL_CP5_SA_LIST(s) /* empty */ + +#define XCHAL_CP6_SA_NUM 0 +#define XCHAL_CP6_SA_LIST(s) /* empty */ + +#define XCHAL_CP7_SA_NUM 0 +#define XCHAL_CP7_SA_LIST(s) /* empty */ + +/* Byte length of instruction from its first nibble (op0 field), per FLIX. */ +/* (not available, must use XCHAL_BYTE0_FORMAT_LENGTHS for this processor) */ +/* Byte length of instruction from its first byte, per FLIX. */ +#define XCHAL_BYTE0_FORMAT_LENGTHS \ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,16, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,3,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,16, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,8,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,16, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,3,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,16, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,8,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,16, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,3,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,16, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,8,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,16, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,3,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,16, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,8 + +/* parasoft-end-suppress ALL "This file not MISRA checked." */ + +#endif /* XTENSA_CORE_TIE_H */ + diff --git a/src/platform/amd/acp_7_x/include/arch/xtensa/tie/xt_datacache.h b/src/platform/amd/acp_7_x/include/arch/xtensa/tie/xt_datacache.h new file mode 100755 index 000000000000..a84835c4b5f7 --- /dev/null +++ b/src/platform/amd/acp_7_x/include/arch/xtensa/tie/xt_datacache.h @@ -0,0 +1,103 @@ +// Customer ID=20511; Build=0xb6494; Copyright (c) 2017-2019 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. + +/* Definitions for the xt_datacache TIE package */ + +/* Do not modify. This is automatically generated.*/ + +/* parasoft-begin-suppress ALL "This file not MISRA checked." */ + +#ifndef _XTENSA_xt_datacache_HEADER +#define _XTENSA_xt_datacache_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + +#ifndef _ASMLANGUAGE +#ifndef _NOCLANGUAGE +#ifndef __ASSEMBLER__ + +#include <xtensa/tie/xt_core.h> + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern void _TIE_xt_datacache_DHI(const int * s, immediate i); +extern void _TIE_xt_datacache_DHU(const int * s, immediate i); +extern void _TIE_xt_datacache_DHWB(const int * s, immediate i); +extern void _TIE_xt_datacache_DHWBI(const int * s, immediate i); +extern void _TIE_xt_datacache_DII(const int * s, immediate i); +extern void _TIE_xt_datacache_DIU(const int * s, immediate i); +extern void _TIE_xt_datacache_DIWB(const int * s, immediate i); +extern void _TIE_xt_datacache_DIWBI(const int * s, immediate i); +extern void _TIE_xt_datacache_DIWBUI_P(const int * s /*inout*/); +extern void _TIE_xt_datacache_DPFL(const int * s, immediate i); +extern void _TIE_xt_datacache_DPFR(const int * s, immediate i); +extern void _TIE_xt_datacache_DPFRO(const int * s, immediate i); +extern void _TIE_xt_datacache_DPFW(const int * s, immediate i); +extern void _TIE_xt_datacache_DPFWO(const int * s, immediate i); +extern int _TIE_xt_datacache_LDCT(const int * s); +extern int _TIE_xt_datacache_LDCW(const int * s); +extern void _TIE_xt_datacache_SDCT(int t, int * s); +extern void _TIE_xt_datacache_SDCW(int t, int * s); + +#endif /*__ASSEMBLER__*/ +#endif /*_NOCLANGUAGE*/ +#endif /*_ASMLANGUAGE*/ + +#define XT_DHI _TIE_xt_datacache_DHI +#define XT_DHU _TIE_xt_datacache_DHU +#define XT_DHWB _TIE_xt_datacache_DHWB +#define XT_DHWBI _TIE_xt_datacache_DHWBI +#define XT_DII _TIE_xt_datacache_DII +#define XT_DIU _TIE_xt_datacache_DIU +#define XT_DIWB _TIE_xt_datacache_DIWB +#define XT_DIWBI _TIE_xt_datacache_DIWBI +#define XT_DIWBUI_P _TIE_xt_datacache_DIWBUI_P +#define XT_DPFL _TIE_xt_datacache_DPFL +#define XT_DPFR _TIE_xt_datacache_DPFR +#define XT_DPFRO _TIE_xt_datacache_DPFRO +#define XT_DPFW _TIE_xt_datacache_DPFW +#define XT_DPFWO _TIE_xt_datacache_DPFWO +#define XT_LDCT _TIE_xt_datacache_LDCT +#define XT_LDCW _TIE_xt_datacache_LDCW +#define XT_SDCT _TIE_xt_datacache_SDCT +#define XT_SDCW _TIE_xt_datacache_SDCW + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ + +#endif /* !_XTENSA_xt_datacache_HEADER */ + +/* parasoft-end-suppress ALL "This file not MISRA checked." */ diff --git a/src/platform/amd/acp_7_x/include/platform/fw_scratch_mem.h b/src/platform/amd/acp_7_x/include/platform/fw_scratch_mem.h new file mode 100644 index 000000000000..8c7eec522e65 --- /dev/null +++ b/src/platform/amd/acp_7_x/include/platform/fw_scratch_mem.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 AMD. All rights reserved. + * + * Author: Sneha Voona <sneha.voona@amd.com> + * DineshKumar Kalva <DineshKumar.Kalva@amd.com> + */ +#ifndef __EXT_SCRATCH_MEM_H__ +#define __EXT_SCRATCH_MEM_H__ + +#include <sof/lib/mailbox.h> + +/* MAX number of DMA descriptors */ +#define MAX_NUM_DMA_DESC_DSCR 64 +#define SCRATCH_REG_OFFSET 0x1250000 +#define ACP_SRAM 0x03800000 + +typedef struct acp_atu_grp_pte { + uint32_t low_part; + uint32_t high_part; +} __attribute__((packed, aligned(4))) acp_atu_grp_pte_t; + +typedef union acp_cfg_dma_trns_cnt { + struct{ + uint32_t trns_cnt : 19; + uint32_t reserved : 12; + uint32_t ioc : 1; + } bits; + unsigned int u32all; +} __attribute__((packed, aligned(4))) acp_cfg_dma_trns_cnt_t; + +typedef struct acp_config_dma_descriptor { + uint32_t src_addr; + uint32_t dest_addr; + acp_cfg_dma_trns_cnt_t trns_cnt; + uint32_t reserved; +} __attribute__((packed, aligned(4))) acp_cfg_dma_descriptor_t; + +typedef struct acp_config_dma_misc { + uint32_t channelstatus; + uint32_t channel; + uint32_t flag; +} __attribute__((packed, aligned(4))) acp_cfg_dma_misc_t; + +typedef struct acp_scratch_memory_config { + /* ACP out box buffer */ + uint8_t acp_outbox_buffer[MAILBOX_DSPBOX_SIZE]; + + /* ACP in box buffer */ + uint8_t acp_inbox_buffer[MAILBOX_HOSTBOX_SIZE]; + + /* ACP debug box buffer */ + uint8_t acp_debug_buffer[MAILBOX_DEBUG_SIZE]; + + /* ACP exception box buffer */ + uint8_t acp_except_buffer[MAILBOX_EXCEPTION_SIZE]; + + /* ACP stream buffer */ + uint8_t acp_stream_buffer[MAILBOX_STREAM_SIZE]; + + /* ACP trace buffer */ + uint8_t acp_trace_buffer[MAILBOX_TRACE_SIZE]; + + /* Host msg write flag */ + uint32_t acp_host_msg_write; + + /* Host ack flag */ + uint32_t acp_host_ack_write; + + /* Dsp msg write flag */ + uint32_t acp_dsp_msg_write; + + /* Dsp ack flag */ + uint32_t acp_dsp_ack_write; + + /* ACP pte1 table */ + acp_atu_grp_pte_t acp_atugrp1_pte[16]; + + /* ACP pte2 table */ + acp_atu_grp_pte_t acp_atugrp2_pte[16]; + + /* ACP pte3 table */ + acp_atu_grp_pte_t acp_atugrp3_pte[16]; + + /* ACP pte4 table */ + acp_atu_grp_pte_t acp_atugrp4_pte[16]; + + /* ACP pte5 table */ + acp_atu_grp_pte_t acp_atugrp5_pte[16]; + + /* ACP pte6 table */ + acp_atu_grp_pte_t acp_atugrp6_pte[16]; + + /* ACP pte7 table */ + acp_atu_grp_pte_t acp_atugrp7_pte[16]; + + /* ACP pte8 table */ + acp_atu_grp_pte_t acp_atugrp8_pte[16]; + + /* ACP DMA Descriptor */ + acp_cfg_dma_descriptor_t acp_cfg_dma_descriptor[MAX_NUM_DMA_DESC_DSCR]; + + /* Stream physical offset */ + uint32_t phy_offset[8]; + + /* Stream system memory size */ + uint32_t syst_buff_size[8]; + + /* Fifo buffers are not part of scratch memory on ACP_7_X */ + /* Added fifo members to align with Driver structure */ + /* ACP transmit fifo buffer */ + uint8_t acp_transmit_fifo_buffer[256] __attribute__((aligned(128))); + + /* ACP receive fifo buffer */ + uint8_t acp_receive_fifo_buffer[256] __attribute__((aligned(128))); + uint32_t reserve[]; +} __attribute__((packed, aligned(4))) acp_scratch_mem_config_t; + +#endif /* __EXT_SCRATCH_MEM_H__ */ diff --git a/src/platform/amd/acp_7_x/include/platform/lib/memory.h b/src/platform/amd/acp_7_x/include/platform/lib/memory.h new file mode 100644 index 000000000000..df1007e50674 --- /dev/null +++ b/src/platform/amd/acp_7_x/include/platform/lib/memory.h @@ -0,0 +1,247 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 AMD. All rights reserved. + * + * Author: Sneha Voona <sneha.voona@amd.com> + * DineshKumar Kalva <DineshKumar.Kalva@amd.com> + */ + +#ifdef __SOF_LIB_MEMORY_H__ + +#ifndef __PLATFORM_LIB_MEMORY_H__ +#define __PLATFORM_LIB_MEMORY_H__ + +#include <rtos/cache.h> + +/* data cache line alignment */ +#define PLATFORM_DCACHE_ALIGN 128 + +#define PU_REGISTER_BASE (0x9FD00000 - 0x01240000) + +/* physical DSP addresses */ +#define IRAM_BASE 0x7F000000 +#define IRAM_SIZE 0x20000 + +#define DRAM0_BASE 0xE0000000 +#define DRAM0_SIZE 0x10000 +#define SRAM0_BASE 0x9FF00000 + +#define DRAM1_BASE 0xE0010000 +#define DRAM1_SIZE 0x10000 +#define SRAM1_BASE 0x6000C000 +#define SRAM1_SIZE 0x274000 + +#define DMA0_BASE PU_REGISTER_BASE +#define DMA0_SIZE 0x4 + +/* DAI DMA register base address */ +#define DAI_BASE_I2S_TDM (PU_REGISTER_BASE + ACP_I2S_TDM_RX_RINGBUFADDR) +#define DAI_BASE_SW (PU_REGISTER_BASE + ACP_SW0_RX_DMA0_RINGBUFADDR) +#define DAI_BASE_PDM (PU_REGISTER_BASE + ACP_WOV_RX_RINGBUFADDR) +#define DAI_BASE_PDM1 (DAI_BASE_PDM + ACP_PDM_2_RX_RINGBUFADDR_96K) +#define DAI_SIZE 0x4 + +#define I2S_TDM_TX_FIFO_OFFST (ACP_I2S_TDM_TX_FIFOADDR - ACP_I2S_TDM_RX_RINGBUFADDR) +#define I2S_TDM_RX_FIFO_OFFST (ACP_I2S_TDM_RX_FIFOADDR - ACP_I2S_TDM_RX_RINGBUFADDR) + +/* SW0 FIFO */ +#define SW0_AUDIO0_TX_FIFO_OFFST (ACP_SW0_TX_DMA0_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO0_RX_FIFO_OFFST (ACP_SW0_RX_DMA0_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO1_TX_FIFO_OFFST (ACP_SW0_TX_DMA1_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO1_RX_FIFO_OFFST (ACP_SW0_RX_DMA1_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO2_TX_FIFO_OFFST (ACP_SW0_TX_DMA2_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO2_RX_FIFO_OFFST (ACP_SW0_RX_DMA2_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO3_TX_FIFO_OFFST (ACP_SW0_TX_DMA3_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO3_RX_FIFO_OFFST (ACP_SW0_RX_DMA3_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO4_TX_FIFO_OFFST (ACP_SW0_TX_DMA4_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO4_RX_FIFO_OFFST (ACP_SW0_RX_DMA4_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO5_TX_FIFO_OFFST (ACP_SW0_TX_DMA5_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO5_RX_FIFO_OFFST (ACP_SW0_RX_DMA5_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO6_TX_FIFO_OFFST (ACP_SW0_TX_DMA6_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO6_RX_FIFO_OFFST (ACP_SW0_RX_DMA6_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO7_TX_FIFO_OFFST (ACP_SW0_TX_DMA7_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW0_AUDIO7_RX_FIFO_OFFST (ACP_SW0_RX_DMA7_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) + +/* SW1 FIFO */ +#define SW1_AUDIO0_TX_FIFO_OFFST (ACP_SW1_TX_DMA0_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO0_RX_FIFO_OFFST (ACP_SW1_RX_DMA0_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO1_TX_FIFO_OFFST (ACP_SW1_TX_DMA1_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO1_RX_FIFO_OFFST (ACP_SW1_RX_DMA1_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO2_TX_FIFO_OFFST (ACP_SW1_TX_DMA2_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO2_RX_FIFO_OFFST (ACP_SW1_RX_DMA2_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO3_TX_FIFO_OFFST (ACP_SW1_TX_DMA3_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO3_RX_FIFO_OFFST (ACP_SW1_RX_DMA3_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO4_TX_FIFO_OFFST (ACP_SW1_TX_DMA4_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO4_RX_FIFO_OFFST (ACP_SW1_RX_DMA4_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO5_TX_FIFO_OFFST (ACP_SW1_TX_DMA5_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO5_RX_FIFO_OFFST (ACP_SW1_RX_DMA5_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO6_TX_FIFO_OFFST (ACP_SW1_TX_DMA6_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO6_RX_FIFO_OFFST (ACP_SW1_RX_DMA6_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO7_TX_FIFO_OFFST (ACP_SW1_TX_DMA7_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW1_AUDIO7_RX_FIFO_OFFST (ACP_SW1_RX_DMA7_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) + +/* SW2 FIFO */ +#define SW2_AUDIO0_TX_FIFO_OFFST (ACP_SW2_TX_DMA0_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO0_RX_FIFO_OFFST (ACP_SW2_RX_DMA0_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO1_TX_FIFO_OFFST (ACP_SW2_TX_DMA1_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO1_RX_FIFO_OFFST (ACP_SW2_RX_DMA1_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO2_TX_FIFO_OFFST (ACP_SW2_TX_DMA2_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO2_RX_FIFO_OFFST (ACP_SW2_RX_DMA2_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO3_TX_FIFO_OFFST (ACP_SW2_TX_DMA3_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO3_RX_FIFO_OFFST (ACP_SW2_RX_DMA3_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO4_TX_FIFO_OFFST (ACP_SW2_TX_DMA4_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO4_RX_FIFO_OFFST (ACP_SW2_RX_DMA4_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO5_TX_FIFO_OFFST (ACP_SW2_TX_DMA5_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO5_RX_FIFO_OFFST (ACP_SW2_RX_DMA5_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO6_TX_FIFO_OFFST (ACP_SW2_TX_DMA6_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO6_RX_FIFO_OFFST (ACP_SW2_RX_DMA6_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO7_TX_FIFO_OFFST (ACP_SW2_TX_DMA7_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW2_AUDIO7_RX_FIFO_OFFST (ACP_SW2_RX_DMA7_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) + +/* SW3 FIFO */ +#define SW3_AUDIO0_TX_FIFO_OFFST (ACP_SW3_TX_DMA0_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO0_RX_FIFO_OFFST (ACP_SW3_RX_DMA0_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO1_TX_FIFO_OFFST (ACP_SW3_TX_DMA1_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO1_RX_FIFO_OFFST (ACP_SW3_RX_DMA1_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO2_TX_FIFO_OFFST (ACP_SW3_TX_DMA2_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO2_RX_FIFO_OFFST (ACP_SW3_RX_DMA2_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO3_TX_FIFO_OFFST (ACP_SW3_TX_DMA3_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO3_RX_FIFO_OFFST (ACP_SW3_RX_DMA3_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO4_TX_FIFO_OFFST (ACP_SW3_TX_DMA4_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO4_RX_FIFO_OFFST (ACP_SW3_RX_DMA4_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO5_TX_FIFO_OFFST (ACP_SW3_TX_DMA5_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO5_RX_FIFO_OFFST (ACP_SW3_RX_DMA5_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO6_TX_FIFO_OFFST (ACP_SW3_TX_DMA6_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO6_RX_FIFO_OFFST (ACP_SW3_RX_DMA6_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO7_TX_FIFO_OFFST (ACP_SW3_TX_DMA7_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) +#define SW3_AUDIO7_RX_FIFO_OFFST (ACP_SW3_RX_DMA7_FIFOADDR - ACP_SW0_RX_DMA0_RINGBUFADDR) + +#define UUID_ENTRY_ELF_BASE 0x1FFFA000 +#define UUID_ENTRY_ELF_SIZE 0x6000 + +/* Log buffer base need to be updated properly, these are used in linker scripts */ +#define LOG_ENTRY_ELF_BASE 0x20000000 +#define LOG_ENTRY_ELF_SIZE 0x2000000 + +#define EXT_MANIFEST_ELF_BASE (LOG_ENTRY_ELF_BASE + LOG_ENTRY_ELF_SIZE) +#define EXT_MANIFEST_ELF_SIZE 0x2000000 + +/* Stack configuration */ +#define SOF_STACK_SIZE (0x1000) +#define SOF_STACK_TOTAL_SIZE SOF_STACK_SIZE +#define SOF_STACK_END (DRAM1_BASE + DRAM1_SIZE - SOF_STACK_SIZE) +#define SOF_STACK_BASE (SOF_STACK_END + SOF_STACK_SIZE) + +/* Mailbox configuration */ +#define SRAM_OUTBOX_BASE SRAM0_BASE +#define SRAM_OUTBOX_SIZE 0x400 +#define SRAM_OUTBOX_OFFSET 0 + +#define SRAM_INBOX_BASE (SRAM_OUTBOX_BASE + SRAM_OUTBOX_SIZE) +#define SRAM_INBOX_SIZE 0x400 +#define SRAM_INBOX_OFFSET SRAM_OUTBOX_SIZE + +#define SRAM_DEBUG_BASE (SRAM_INBOX_BASE + SRAM_INBOX_SIZE) +#define SRAM_DEBUG_SIZE 0x400 +#define SRAM_DEBUG_OFFSET (SRAM_INBOX_OFFSET + SRAM_INBOX_SIZE) + +#define SRAM_EXCEPT_BASE (SRAM_DEBUG_BASE + SRAM_DEBUG_SIZE) +#define SRAM_EXCEPT_SIZE 0x400 +#define SRAM_EXCEPT_OFFSET (SRAM_DEBUG_OFFSET + SRAM_DEBUG_SIZE) + +#define SRAM_STREAM_BASE (SRAM_EXCEPT_BASE + SRAM_EXCEPT_SIZE) +#define SRAM_STREAM_SIZE 0x400 +#define SRAM_STREAM_OFFSET (SRAM_EXCEPT_OFFSET + SRAM_EXCEPT_SIZE) + +#define SRAM_TRACE_BASE (SRAM_STREAM_BASE + SRAM_STREAM_SIZE) +#define SRAM_TRACE_SIZE 0x400 +#define SRAM_TRACE_OFFSET (SRAM_STREAM_OFFSET + SRAM_STREAM_SIZE) +#define SOF_MAILBOX_SIZE (SRAM_INBOX_SIZE + SRAM_OUTBOX_SIZE \ + + SRAM_DEBUG_SIZE + SRAM_EXCEPT_SIZE \ + + SRAM_STREAM_SIZE + SRAM_TRACE_SIZE) + +/* Heap section sizes for module pool */ +#define HEAP_RT_COUNT8 0 +#define HEAP_RT_COUNT16 192 +#define HEAP_RT_COUNT32 192 +#define HEAP_RT_COUNT64 128 +#define HEAP_RT_COUNT128 240 +#define HEAP_RT_COUNT256 128 +#define HEAP_RT_COUNT512 16 +#define HEAP_RT_COUNT1024 73 +#define HEAP_RT_COUNT2048 48 + +/* Heap section sizes for system runtime heap */ +#define HEAP_SYS_RT_COUNT64 720 +#define HEAP_SYS_RT_COUNT512 240 +#define HEAP_SYS_RT_COUNT1024 91 + +#define SIZE_OF_MEMORY_FOR_DATA_SECTION 0x60000 + +/* Heap configuration */ +#define HEAP_SYSTEM_BASE (SRAM1_BASE + SIZE_OF_MEMORY_FOR_DATA_SECTION) +#define HEAP_SYSTEM_SIZE 0x40000 +#define HEAP_SYSTEM_0_BASE HEAP_SYSTEM_BASE +#define HEAP_SYS_RUNTIME_BASE (HEAP_SYSTEM_BASE + HEAP_SYSTEM_SIZE) +#define HEAP_SYS_RUNTIME_SIZE (HEAP_SYS_RT_COUNT64 * 64 + HEAP_SYS_RT_COUNT512 * 512 + \ + HEAP_SYS_RT_COUNT1024 * 1024) + +#define HEAP_RUNTIME_BASE (HEAP_SYS_RUNTIME_BASE + HEAP_SYS_RUNTIME_SIZE) +#define HEAP_RUNTIME_SIZE \ + (HEAP_RT_COUNT8 * 8 + HEAP_RT_COUNT16 * 16 + \ + HEAP_RT_COUNT32 * 32 + HEAP_RT_COUNT64 * 64 + \ + HEAP_RT_COUNT128 * 128 + HEAP_RT_COUNT256 * 256 + \ + HEAP_RT_COUNT512 * 512 + HEAP_RT_COUNT1024 * 1024 + \ + HEAP_RT_COUNT2048 * 2048) + +#define HEAP_BUFFER_BASE (HEAP_RUNTIME_BASE + HEAP_RUNTIME_SIZE) +#define HEAP_BUFFER_SIZE (0x60000) +#define HEAP_BUFFER_BLOCK_SIZE 0x180 +#define HEAP_BUFFER_COUNT (HEAP_BUFFER_SIZE / HEAP_BUFFER_BLOCK_SIZE) + +#define PLATFORM_HEAP_SYSTEM 1 +#define PLATFORM_HEAP_SYSTEM_RUNTIME 1 +#define PLATFORM_HEAP_RUNTIME 1 +#define PLATFORM_HEAP_BUFFER 1 + +/* Vector and literal sizes - not in core-isa.h */ +#define SOF_MEM_VECT_LIT_SIZE 0x7 +#define SOF_MEM_VECT_TEXT_SIZE 0x37 +#define SOF_MEM_VECT_SIZE (SOF_MEM_VECT_TEXT_SIZE + SOF_MEM_VECT_LIT_SIZE) + +#define SOF_MEM_RESET_TEXT_SIZE 0x400 +#define SOF_MEM_RESET_LIT_SIZE 0x8 +#define SOF_MEM_VECBASE_LIT_SIZE 0x178 +#define SOF_MEM_WIN_TEXT_SIZE 0x178 + +#define SOF_MEM_RO_SIZE 0x8 + +#define uncache_to_cache(address) address +#define cache_to_uncache(address) address +#define is_uncached(address) 0 + +#define HEAP_BUF_ALIGNMENT PLATFORM_DCACHE_ALIGN + +/* brief EDF task's default stack size in bytes */ +#define PLATFORM_TASK_DEFAULT_STACK_SIZE 3072 + +#if !defined(__ASSEMBLER__) && !defined(LINKER) +struct sof; + +#define SHARED_DATA +void platform_init_memmap(struct sof *sof); + +static inline void *platform_rfree_prepare(void *ptr) +{ + return ptr; +} +#endif +#define host_to_local(addr) (addr) +#define local_to_host(addr) (addr) + +#endif /* __PLATFORM_LIB_MEMORY_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/memory.h" +#endif /* __SOF_LIB_MEMORY_H__ */ diff --git a/src/platform/amd/acp_7_x/include/platform/platform.h b/src/platform/amd/acp_7_x/include/platform/platform.h new file mode 100644 index 000000000000..2a6b0147446d --- /dev/null +++ b/src/platform/amd/acp_7_x/include/platform/platform.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 AMD. All rights reserved. + * + * Author: Sneha Voona <sneha.voona@amd.com> + * DineshKumar Kalva <DineshKumar.Kalva@amd.com> + */ + +#ifdef __SOF_PLATFORM_H__ + +#ifndef __PLATFORM_PLATFORM_H__ +#define __PLATFORM_PLATFORM_H__ + +#if !defined(__ASSEMBLER__) && !defined(LINKER) + +#include <rtos/interrupt.h> +#include <rtos/clk.h> +#include <sof/lib/mailbox.h> +#include <stddef.h> +#include <stdint.h> +#include <platform/fw_scratch_mem.h> +#include <platform/platform_misc.h> + +struct ll_schedule_domain; +struct timer; +#define INTERRUPT_ENABLE 1 +#define PLATFORM_DEFAULT_CLOCK CLK_CPU(0) + +/* IPC Interrupt */ +#define PLATFORM_IPC_INTERRUPT IRQ_EXT_IPC_LEVEL_3 +#define PLATFORM_IPC_INTERRUPT_NAME NULL + +/* Host page size */ +#define HOST_PAGE_SIZE 65536 + +/* pipeline IRQ */ +#define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE0 +#define PLATFORM_SCHEDULE_IRQ_NAME NULL + +/* Platform stream capabilities */ +#define PLATFORM_MAX_CHANNELS 8 +#define PLATFORM_MAX_STREAMS 5 + +/* local buffer size of DMA tracing */ +#define DMA_TRACE_LOCAL_SIZE 8192 + +/* trace bytes flushed during panic */ +#define DMA_FLUSH_TRACE_SIZE (MAILBOX_TRACE_SIZE >> 2) + +/* the interval of DMA trace copying */ +#define DMA_TRACE_PERIOD 500 /* 1000 / 50000 */ + +/* + * the interval of reschedule DMA trace copying in special case like half + * fullness of local DMA trace buffer + */ +#define DMA_TRACE_RESCHEDULE_TIME 100 + +/* DSP default delay in cycles */ +#define PLATFORM_DEFAULT_DELAY 12 + +/* default dma trace channel */ +#define DMA_TRACE_CHANNEL 7 + +/* debug offset */ +#define ACP_SOF_FW_STATUS 0 + +/* Platform defined panic code */ +static inline void platform_panic(uint32_t p) +{ + acp_sw_intr_trig_t sw_intr_trig; + volatile acp_scratch_mem_config_t *pscratch_mem_cfg = + (volatile acp_scratch_mem_config_t *)(PU_SCRATCH_REG_BASE + SCRATCH_REG_OFFSET); + + pscratch_mem_cfg->acp_dsp_msg_write = p; + mailbox_sw_reg_write(ACP_SOF_FW_STATUS, p); + /* Read the Software Interrupt controller register and update */ + sw_intr_trig = (acp_sw_intr_trig_t)io_reg_read(PU_REGISTER_BASE + ACP_SW_INTR_TRIG); + /* Configures the trigger bit in ACP_DSP_SW_INTR_TRIG register */ + sw_intr_trig.bits.trig_dsp0_to_host_intr = INTERRUPT_ENABLE; + /* Write the Software Interrupt trigger register */ + io_reg_write((PU_REGISTER_BASE + ACP_SW_INTR_TRIG), sw_intr_trig.u32all); +} + +/* + * brief Platform specific CPU entering idle. + * May be power-optimized using platform specific capabilities. + * @param level Interrupt level. + */ +void platform_wait_for_interrupt(int level); + +extern intptr_t _module_init_start; +extern intptr_t _module_init_end; +#endif + +#endif /* __PLATFORM_PLATFORM_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/platform.h" +#endif /* __SOF_PLATFORM_H__ */ diff --git a/src/platform/amd/acp_7_x/include/platform/platform_misc.h b/src/platform/amd/acp_7_x/include/platform/platform_misc.h new file mode 100644 index 000000000000..949f3622374f --- /dev/null +++ b/src/platform/amd/acp_7_x/include/platform/platform_misc.h @@ -0,0 +1,577 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 AMD. All rights reserved. + * + * Author: Sneha Voona <sneha.voona@amd.com> + */ + +#include <zephyr/drivers/dma.h> + +#define PU_REGISTER_BASE (0x9FD00000 - 0x01240000) +#define PU_SCRATCH_REG_BASE (0x9FF00000 - 0x01250000) +#define ACP_FUTURE_REG_ACLK_0 0x12418E0 /* don't use - reserved for driver gsync */ +#define ACP_FUTURE_REG_ACLK_1 0x12418E4 +#define ACP_FUTURE_REG_ACLK_2 0x12418E8 +#define ACP_FUTURE_REG_ACLK_3 0x12418EC +#define ACP_FUTURE_REG_ACLK_4 0x12418F0 +#define ACP_SW_INTR_TRIG 0x1241890 +#define ACP_DSP0_INTR_CNTL 0x1241800 +#define ACP_DSP0_INTR_STAT 0x1241818 +#define ACP_DSP_SW_INTR_CNTL 0x1241860 +#define ACP_DSP_SW_INTR_STAT 0x1241864 +#define ACP_AXI2DAGB_SEM_0 0x12418F4 +#define ACP_SRBM_CLIENT_BASE_ADDR 0x1241BF0 +#define ACP_SRBM_CLIENT_RDDATA 0x1241BF4 +#define ACP_SRBM_CYCLE_STS 0x1241BF8 +#define ACP_SRBM_CLIENT_CONFIG 0x1241BFC + +/* Registers from SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6 block ACP_7X */ +#define ACP_7X_SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_REFCLK_BRDS 0x6D204 +#define ACP_7X_SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_NON_AI_CTRL0_BRDS 0x6D214 +#define ACP_7X_SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL6_1_BRDS 0x6D21C +#define ACP_7X_SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL7_BRDS 0x6D220 +#define ACP_7X_SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL9_BRDS 0x6D20C + +/* Registers from CLK6 block */ +#define mmCLK6_PLL0_DFS0_CNTL 0x6D014 +#define mmCLK6_PLL0_DFS0_STATUS 0x6D018 +#define mmCLK6_PLL0_DFS1_CNTL 0x6D01C +#define mmCLK6_PLL0_DFS1_STATUS 0x6D020 +#define mmCLK6_CLK0_BYPASS_CNTL 0x6D06C +#define mmCLK6_CLK1_BYPASS_CNTL 0x6D08C +#define mmCLK6_CLK_TICK_CNT_CONFIG_REG 0x6D188 +#define mmCLK6_CLK0_CURRENT_CNT 0x6D190 +#define mmCLK6_CLK1_CURRENT_CNT 0x6D194 + +/* CLK6 register aliases without mm prefix for clock management code */ +#define CLK6_PLL0_DFS0_CNTL mmCLK6_PLL0_DFS0_CNTL +#define CLK6_PLL0_DFS1_CNTL mmCLK6_PLL0_DFS1_CNTL +#define CLK6_PLL0_DFS1_STATUS mmCLK6_PLL0_DFS1_STATUS +#define CLK0_CURRENT_CNT mmCLK6_CLK0_CURRENT_CNT +#define CLK1_CURRENT_CNT mmCLK6_CLK1_CURRENT_CNT +#define CLK_TICK_CNT_CONFIG_REG mmCLK6_CLK_TICK_CNT_CONFIG_REG + +/* SYSTEMPLL2P0 register aliases without ACP_7X prefix */ +#define SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_NON_AI_CTRL0_BRDS ACP_7X_SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_NON_AI_CTRL0_BRDS +#define SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_REFCLK_BRDS ACP_7X_SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_REFCLK_BRDS +#define SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL6_1_BRDS ACP_7X_SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL6_1_BRDS +#define SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL7_BRDS ACP_7X_SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL7_BRDS +#define SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL9_BRDS ACP_7X_SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL9_BRDS + +#define mmMP1_C2PMSG_37 0x3B10994 +#define mmMP1_C2PMSG_38 0x3B10998 +#define mmMP1_C2PMSG_39 0x3B1099C +#define ACPSMC_MSG_PllPowerState 0x3 /* Toggle PLL power state ON/OFF */ +#define ACP_AUDIOPLL_POWER_OFF_REQ 0x0 /* ACP Power Down Request Value */ +#define ACP_AUDIOPLL_POWER_ON_REQ 0x1 /* ACP Power Up Request Value */ +#define ACP_AUDIOPLL_POWER_OFF_REQ_WITH_WOV_EN 0x2 /* ACP Power Down Request Value */ +#define ACP_AUDIOPLL_POWER_ON_REQ_WITH_WOV_EN 0x3 /* ACP Power Up Request Value */ +#define ACP_AUDIO_CLK_SEL 0x1241038 +#define ACP_PDM_CORE_CLK_SEL 0x124103C + +typedef union acp_srbm_cycle_sts { + struct { + unsigned int srbm_clients_sts :1; + unsigned int:7; + } bits; + unsigned int u32all; +} acp_srbm_cycle_sts_t; + +typedef union acp_clkmux_sel { + struct { + unsigned int acp_clkmux_sel:3; + unsigned int:13; + unsigned int acp_clkmux_div_value:16; + } bits; + unsigned int u32all; +} acp_clkmux_sel_t; + +typedef union clk7_clk1_dfs_cntl_u { + struct { + unsigned int CLK1_DIVIDER:7; + unsigned int:25; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk1_dfs_cntl_u_t; +typedef union clk7_clk1_dfs_status_u { + struct { + unsigned int : 16; + unsigned int CLK1_DFS_DIV_REQ_IDLE :1; + unsigned int : 2; + unsigned int RO_CLK1_DFS_STATE_IDLE :1; + unsigned int CLK1_CURRENT_DFS_DID :7; + unsigned int : 5; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk1_dfs_status_u_t; + +typedef union clk7_clk1_bypass_cntl_u { + struct { + unsigned int CLK1_BYPASS_SEL:3; + unsigned int:13; + unsigned int CLK1_BYPASS_DIV:4; + unsigned int:12; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk1_bypass_cntl_u_t; + +typedef union clk7_clk_fsm_status_u { + struct { + unsigned int AUTOLAUCH_FSM_FULL_SPEED_IDLE:1; + unsigned int:3; + unsigned int AUTOLAUCH_FSM_BYPASS_IDLE:1; + unsigned int:3; + unsigned int RO_FSM_PLL_STATUS_STARTED:1; + unsigned int:3; + unsigned int RO_FSM_PLL_STATUS_STOPPED:1; + unsigned int:3; + unsigned int RO_EARLY_FSM_DONE:1; + unsigned int:3; + unsigned int RO_DFS_GAP_ACTIVE:1; + unsigned int:3; + unsigned int RO_DID_FSM_IDLE:1; + unsigned int:7; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk_fsm_status_t; + +typedef union clk7_clk_pll_req_u { + struct { + unsigned int fbmult_int:9; + unsigned int:3; + unsigned int pllspinediv:4; + unsigned int fbmult_frac:16; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk_pll_req_u_t; + +typedef union clk7_clk_pll_refclk_startup { + struct { + unsigned int main_pll_ref_clk_rate_startup:8; + unsigned int main_pll_cfg_4_startup :8; + unsigned int main_pll_ref_clk_div_startup:2; + unsigned int main_pll_cfg_3_startup :10; + unsigned int:1; + unsigned int main_pll_refclk_src_mux0_startup:1; + unsigned int main_pll_refclk_src_mux1_startup:1; + unsigned int:1; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk_pll_refclk_startup_t; +typedef union clk7_spll_field_2 { + struct{ + unsigned int:3; + unsigned int spll_fbdiv_mask_en :1; + unsigned int spll_fracn_en :1; + unsigned int spll_freq_jump_en :1; + unsigned int:25; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_2_t; + +typedef union clk7_clk_dfsbypass_cntl { + struct { + unsigned int enter_dfs_bypass_0 :1; + unsigned int enter_dfs_bypass_1 :1; + unsigned int:14; + unsigned int exit_dfs_bypass_0 :1; + unsigned int exit_dfs_bypass_1 :1; + unsigned int:14; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk_dfsbypass_cntl_t; + +typedef union clk7_clk_pll_pwr_req { + struct { + unsigned int PLL_AUTO_START_REQ :1; + unsigned int:3; + unsigned int PLL_AUTO_STOP_REQ :1; + unsigned int:3; + unsigned int PLL_AUTO_STOP_NOCLK_REQ :1; + unsigned int:3; + unsigned int PLL_AUTO_STOP_REFBYPCLK_REQ:1; + unsigned int:3; + unsigned int PLL_FORCE_RESET_HIGH :1; + unsigned int:15; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_clk_pll_pwr_req_t; + +typedef union clk7_spll_fuse_1 { + struct { + unsigned int:8; + unsigned int spll_gp_coarse_exp :4; + unsigned int spll_gp_coarse_mant :4; + unsigned int:4; + unsigned int spll_gi_coarse_exp :4; + unsigned int:1; + unsigned int spll_gi_coarse_mant :2; + unsigned int:5; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_fuse_1_t; + +typedef union clk7_spll_fuse_2 { + struct { + unsigned int spll_tdc_resolution :8; + unsigned int spll_freq_offset_exp :4; + unsigned int spll_freq_offset_mant :5; + unsigned int:15; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_fuse_2_t; + +typedef union clk7_spll_field_9 { + struct { + unsigned int:16; + unsigned int spll_dpll_cfg_3 :10; + unsigned int spll_fll_mode :1; + unsigned int:5; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_9_t; + +typedef union clk7_spll_field_6nm { + struct { + unsigned int spll_dpll_cfg_4 :8; + unsigned int spll_reg_tim_exp :3; + unsigned int spll_reg_tim_mant :1; + unsigned int spll_ref_tim_exp :3; + unsigned int spll_ref_tim_mant :1; + unsigned int spll_vco_pre_div :2; + unsigned int:14; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_6nm_t; + +typedef union clk7_spll_field_7 { + struct { + unsigned int:7; + unsigned int spll_pllout_sel :1; + unsigned int spll_pllout_req :1; + unsigned int spll_pllout_state :2; + unsigned int spll_postdiv_ovrd :4; + unsigned int spll_postdiv_pllout_ovrd :4; + unsigned int spll_postdiv_sync_enable :1; + unsigned int:1; + unsigned int spll_pwr_state :2; + unsigned int:1; + unsigned int spll_refclk_rate :8; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_7_t; + +typedef union clk7_spll_field_4 { + struct { + unsigned int spll_fcw0_frac_ovrd :16; + unsigned int pll_out_sel :1; + unsigned int:3; + unsigned int pll_pwr_dn_state :2; + unsigned int:2; + unsigned int spll_refclk_div :2; + unsigned int:6; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_4_t; + +typedef union clk7_spll_field_5nm_bus_ctrl { + struct { + unsigned int bus_spll_async_mode :1; + unsigned int bus_spll_apb_mode :1; + unsigned int bus_spll_addr :8; + unsigned int bus_spll_byte_en :4; + unsigned int bus_spll_rdtr :1; + unsigned int bus_spll_resetb :1; + unsigned int bus_spll_sel :1; + unsigned int bus_spll_wrtr :1; + unsigned int:14; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_5nm_bus_ctrl_t; + +typedef union clk7_spll_field_5nm_bus_wdata { + struct { + unsigned int bus_spll_wr_data; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_5nm_bus_wdata_t; + +typedef union clk7_rootrefclk_mux_1 { + struct { + unsigned int ROOTREFCLK_MUX_1 :1; + unsigned int reserved :31; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_rootrefclk_mux_1_t; + +typedef union clk7_spll_field_5nm_bus_status { + struct { + unsigned int spll_bus_error :1; + unsigned int spll_bus_rd_valid :1; + unsigned int spll_bus_wr_ack :1; + unsigned int:29; + } bitfields, bits; + uint32_t u32all; + int32_t i32all; + float f32all; +} clk7_spll_field_5nm_bus_status_t; + +typedef union clk_tick_cnt_config_reg { + struct { + uint32_t TIMER_THRESHOLD:24; + uint32_t TIMER_ENABLE:1; + uint32_t HISTORY_ENABLE:1; + uint32_t HISTORY_SP_RESET:1; + uint32_t HISTORY_CLK_SEL:5; + } bitfields, bits; + uint32_t u32All; + int32_t i32All; + float f32All; +} clk_tick_cnt_config_reg_t; +typedef union SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_NON_AI_CTRL0_BRDS_u { + struct { + uint32_t vco_pre_div:2; + uint32_t dac_ibiastrim:4; + uint32_t:26; + } bitfields, bits; + uint32_t u32All; + int32_t i32All; + float f32All; +} SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_NON_AI_CTRL0_BRDS_u_t; + +typedef union SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_REFCLK_BRDS_u { + struct { + uint32_t refclk_rate:8; + uint32_t refclk_div: 6; + uint32_t:1; + uint32_t cml_sel:1; + uint32_t:16; + + } bitfields, bits; + uint32_t u32All; + int32_t i32All; + float f32All; +} SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_REFCLK_BRDS_u_t; + +typedef union SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL6_1_BRDS_u { + struct { + uint32_t fcw_int:9; + uint32_t:23; + } bitfields, bits; + uint32_t u32All; + int32_t i32All; + float f32All; +} SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL6_1_BRDS_u_t; + +typedef union SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL7_BRDS_u { + struct { + uint32_t fcw_frac:16; + uint32_t:16; + } bitfields, bits; + uint32_t u32All; + int32_t i32All; + float f32All; +} SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL7_BRDS_u_t; + +typedef union SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL9_BRDS_u { + struct { + uint32_t fcw0_frac_lsb:8; + uint32_t fcw1_frac_lsb:8; + uint32_t:16; + } bitfields, bits; + uint32_t u32All; + int32_t i32All; + float f32All; +} SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL9_BRDS_u_t; + +typedef union clk6_pll_dfs_cntl_u { + struct { + uint32_t PLL0_DFS0_DIVIDER:7; + uint32_t PLL0_DFS0_DDCA:2; + uint32_t:3; + uint32_t PLL0_DFS0_ADCA:4; + uint32_t PLL0_DFS0_AllowZeroDID :1; + uint32_t PLL0_DFS0_EnableCLKOffInBypass:1; + uint32_t PLL0_DFS0_EnableVCO48OffInBypass :1; + uint32_t:1; + uint32_t PLL0_DFS0_DiDtWait:3; + uint32_t:1; + uint32_t PLL0_DFS0_DiDtFloor : 2; + uint32_t:2; + uint32_t PLL0_DFS0_SlamDid:1; + uint32_t PLL0_DFS0_FastRamp :1; + uint32_t:2; + } bitfields, bits; + uint32_t u32All; + int32_t i32All; + float f32All; +} clk6_pll_dfs_cntl_u_t; + +typedef union clk_dfs_status_u { + struct { + uint32_t PLL0_DFS0_CURRENT_DFS_DID:7; + uint32_t:1; + uint32_t PLL0_DFS0_AUTOLAUCH_FSM_FULL_SPEED_IDLE:1; + uint32_t PLL0_DFS0_AUTOLAUCH_FSM_BYPASS_IDLE: 1; + uint32_t:6; + uint32_t PLL0_DFS0_DFS_STATE_IDLE:1; + uint32_t PLL0_DFS0_DID_FSM_IDLE:1; + uint32_t PLL0_DFS0_DFS_DIV_REQ_IDLE: 1; + uint32_t:13; + } bitfields, bits; + uint32_t u32All; + int32_t i32All; + float f32All; +} clk_dfs_status_u_t; + +typedef union clk6_clk_bypass_cntl_u { + struct { + uint32_t CLK_BYPASS_SEL:3; + uint32_t CLK_BYPASS_DIV:4; + uint32_t CLK_PMUX_SGMode:8; + uint32_t CLK_BYPASS_SEL_STARTUP:3; + uint32_t:1; + uint32_t CLK_BYPASS_DIV_STARTUP:4; + uint32_t:8; + } bitfields, bits; + uint32_t u32All; + int32_t i32All; + float f32All; +} clk6_bypass_cntl_u_t; + +typedef union acp_dsp_sw_intr_stat { + struct { + unsigned int host_to_dsp0_intr1_stat:1; + unsigned int host_to_dsp0_intr2_stat:1; + unsigned int dsp0_to_host_intr_stat:1; + unsigned int host_to_dsp0_intr3_stat:1; + unsigned int:28; + } bits; + unsigned int u32all; +} acp_dsp_sw_intr_stat_t; + +typedef union acp_sw_intr_trig { + struct { + unsigned int trig_host_to_dsp0_intr1:1; + unsigned int:1; + unsigned int trig_dsp0_to_host_intr:1; + unsigned int:29; + } bits; + unsigned int u32all; +} acp_sw_intr_trig_t; + +typedef void (*dma_callback_t)(const struct device *dev, void *user_data, + uint32_t channel, int status); + +#define ACP_DMA_CHAN_COUNT 64 +struct acp_dma_ptr_data { + /* base address of dma buffer */ + uint32_t base; + /* size of dma buffer */ + uint32_t size; + /* write pointer of dma buffer */ + uint32_t wr_ptr; + /* read pointer of dma buffer */ + uint32_t rd_ptr; + /* read size of dma buffer */ + uint32_t rd_size; + /* write size of dma buffer */ + uint32_t wr_size; + /* system memory size defined for the stream */ + uint32_t sys_buff_size; + /* virtual system memory offset for system memory buffer */ + uint32_t phy_off; + /* probe_channel id */ + uint32_t probe_channel; +}; + +enum acp_dma_state { + ACP_DMA_READY, + ACP_DMA_PREPARED, + ACP_DMA_SUSPENDED, + ACP_DMA_ACTIVE, +}; + +struct acp_dma_chan_data { + uint32_t direction; + enum acp_dma_state state; + struct acp_dma_ptr_data ptr_data; /* pointer data */ + dma_callback_t dma_tfrcallback; + void *priv_data; /* unused */ +}; + + +#define SDW_INSTANCES 4 +struct sdw_pin_data { + uint32_t pin_num; + uint32_t pin_dir; + uint32_t dma_channel; + uint32_t dma_channel1; + uint32_t index[SDW_INSTANCES]; + uint32_t instance; + uint32_t instance1; +}; + +struct tdm_context { + uint64_t prev_pos; + uint32_t buff_size; + uint32_t tdm_instance; + uint32_t pin_dir; + uint32_t dma_channel; + uint32_t index; + uint32_t frame_fmt; +}; + +struct dmic_context { + uint64_t prev_pos; + uint32_t dmic_instance; + uint32_t pin_dir; + uint32_t dma_channel; + uint32_t index; +}; + +struct acp_dma_dev_data { + struct dma_context dma_ctx; + struct acp_dma_chan_data chan_data[ACP_DMA_CHAN_COUNT]; + + ATOMIC_DEFINE(atomic, ACP_DMA_CHAN_COUNT); + struct dma_config *dma_config; + void *dai_index_ptr; +}; + diff --git a/src/platform/amd/acp_7_x/lib/CMakeLists.txt b/src/platform/amd/acp_7_x/lib/CMakeLists.txt new file mode 100644 index 000000000000..147d9d9bea93 --- /dev/null +++ b/src/platform/amd/acp_7_x/lib/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources(sof + clk.c +) diff --git a/src/platform/amd/acp_7_x/lib/clk.c b/src/platform/amd/acp_7_x/lib/clk.c new file mode 100644 index 000000000000..00aa89be48b2 --- /dev/null +++ b/src/platform/amd/acp_7_x/lib/clk.c @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2026 AMD. All rights reserved. + * + * Author: Sneha Voona <sneha.voona@amd.com> + * Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> + */ + +#include <sof/common.h> +#include <rtos/clk.h> +#include <sof/lib/cpu.h> +#include <sof/lib/memory.h> +#include <sof/lib/notifier.h> +#include <rtos/sof.h> +#include <rtos/atomic.h> +#include <sof/audio/component.h> +#include <rtos/bit.h> +#include <sof/drivers/acp_dai_dma.h> +#include <rtos/interrupt.h> +#include <rtos/timer.h> +#include <rtos/alloc.h> +#include <rtos/clk.h> +#include <sof/lib/cpu.h> +#include <sof/lib/dma.h> +#include <sof/lib/io.h> +#include <sof/lib/pm_runtime.h> +#include <sof/lib/notifier.h> +#include <sof/platform.h> +#include <sof/schedule/schedule.h> +#include <rtos/spinlock.h> +#include <sof/math/numbers.h> +#include <sof/trace/trace.h> +#include <ipc/topology.h> +#include <user/trace.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <platform/fw_scratch_mem.h> + +SOF_DEFINE_REG_UUID(acp_clk); +LOG_MODULE_REGISTER(acp_clk, CONFIG_SOF_LOG_LEVEL); +DECLARE_TR_CTX(acp_clk_tr, SOF_UUID(acp_clk_uuid), LOG_LEVEL_INFO); + +/* Frequency tables */ +const struct freq_table platform_cpu_freq[] = { + {600000000, 600000 }, +}; + +STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, + invalid_number_of_cpu_frequencies); + +/* Type definitions */ +typedef enum { + PLL_MODE_100MHZ_NORMAL, + PLL_MODE_48MHZ_NORMAL, + PLL_MODE_32KHZ_LPPM, + PLL_MODE_48MHZ_LPPM, + PLL_MODE_100MHZ_LPPM +} PLL_MODE; + +/* Enumeration for the Clock Types */ +typedef enum _acp_clock_type_ { + acp_aclk_clock, + acp_sclk_clock, + acp_clock_type_max, + acp_clock_type_force = 0xFF +} acp_clock_type_t; + +/* Static variables */ +static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; + +/* Function prototypes */ +void audio_pll_power_off(void); +void audio_pll_power_on(void); +void clk_dfs_bypassexit(void); +void audio_pll_mode_switch(uint32_t mode, uint32_t fcw_int, uint32_t fcw_frac, + uint32_t fcw_denom, uint32_t pllspinediv); +void clk7_init_vco(void); +void acp_7_x_reg_wait(void); +void acp_7_x_get_boot_ref_clock(float *boot_ref_clk); +uint32_t acp_clk_update_dfs_did(uint32_t did, uint32_t clk_type); +void acp_cpl_aclk_dfs_did_update(bool poll, uint32_t timeout_cnt, uint8_t did); +void acp_cpl_audioclk_dfs_did_update(bool poll, uint32_t timeout_cnt, uint8_t did); +void acp_cpl_aclk_poll_dfs_div_req_idle(uint32_t timeout_cnt); +void acp_cpl_audioclk_poll_dfs_div_req_idle(uint32_t timeout_cnt); +void change_clock_notify(uint32_t clock_freq); +int acp_get_current_clk(acp_clock_type_t clk_type, + float *clk_value); + +/* Static function prototypes */ +static int acp_reg_read_via_smn(uint32_t reg_offset, uint32_t size); +static void acp_reg_write_via_smn(uint32_t reg_offset, uint32_t reg_value, uint32_t size); + +static int acp_reg_read_via_smn(uint32_t reg_offset, + uint32_t size) +{ + uint32_t reg_value; + uint32_t delay_cnt = 10000; + uint32_t smn_client_base_addr = (reg_offset >> 10); + uint32_t region_start_addr = (smn_client_base_addr << 10); + uint32_t apertureid = ((reg_offset >> 20) & 0xFFF); + acp_srbm_cycle_sts_t acp_srbm_cycle_sts; + + io_reg_write((PU_REGISTER_BASE + ACP_SRBM_CLIENT_CONFIG), apertureid); + io_reg_write((PU_REGISTER_BASE + ACP_SRBM_CLIENT_BASE_ADDR), smn_client_base_addr); + reg_value = (uint32_t)io_reg_read(PU_REGISTER_BASE + + (ACP_MASTER_REG_ACCESS_ADDRESS + reg_offset - region_start_addr + ACP_FIRST_REG_OFFSET)); + if (reg_value) { + reg_value = 0; + } + acp_srbm_cycle_sts = (acp_srbm_cycle_sts_t)io_reg_read(PU_REGISTER_BASE + + ACP_SRBM_CYCLE_STS); + while (delay_cnt > 0) { + if (!acp_srbm_cycle_sts.bits.srbm_clients_sts) { + return (uint32_t)io_reg_read(PU_REGISTER_BASE + ACP_SRBM_CLIENT_RDDATA); + } + acp_srbm_cycle_sts = (acp_srbm_cycle_sts_t)io_reg_read(PU_REGISTER_BASE + + ACP_SRBM_CYCLE_STS); + delay_cnt--; + } + return -1; +} + +static void acp_reg_write_via_smn(uint32_t reg_offset, + uint32_t value, uint32_t size) +{ + uint32_t delay_cnt = 10000; + uint32_t smn_client_base_addr = (reg_offset >> 10); + uint32_t region_start_addr = (smn_client_base_addr << 10); + uint32_t apertureid = ((reg_offset >> 20) & 0xFFF); + acp_srbm_cycle_sts_t acp_srbm_cycle_sts; + + io_reg_write((PU_REGISTER_BASE + ACP_SRBM_CLIENT_CONFIG), apertureid); + io_reg_write((PU_REGISTER_BASE + ACP_SRBM_CLIENT_BASE_ADDR), smn_client_base_addr); + io_reg_write((PU_REGISTER_BASE + (ACP_MASTER_REG_ACCESS_ADDRESS + + reg_offset - region_start_addr + + ACP_FIRST_REG_OFFSET)), value); + acp_srbm_cycle_sts = + (acp_srbm_cycle_sts_t)io_reg_read(PU_REGISTER_BASE + ACP_SRBM_CYCLE_STS); + while (delay_cnt > 0) { + acp_srbm_cycle_sts = (acp_srbm_cycle_sts_t)io_reg_read(PU_REGISTER_BASE + + ACP_SRBM_CYCLE_STS); + if (!acp_srbm_cycle_sts.bits.srbm_clients_sts) { + return; + } + delay_cnt--; + } +} + +void platform_clock_init(struct sof *sof) +{ + int i; + + sof->clocks = platform_clocks_info; + for (i = 0; i < CONFIG_CORE_COUNT; i++) { + sof->clocks[i] = (struct clock_info) { + .freqs_num = NUM_CPU_FREQ, + .freqs = platform_cpu_freq, + .default_freq_idx = CPU_DEFAULT_IDX, + .current_freq_idx = CPU_DEFAULT_IDX, + .notification_id = NOTIFIER_ID_CPU_FREQ, + .notification_mask = NOTIFIER_TARGET_CORE_MASK(i), + .set_freq = NULL, + }; + } + /* acp_reg_write_via_smn(CLK6_PLL0_DFS0_CNTL, 0x19, sizeof(int)); */ +} +void acp_cpl_audioclk_poll_dfs_div_req_idle(uint32_t timeout_cnt) +{ + uint32_t timeout = 0; + clk_dfs_status_u_t clk_dfs_status; + + do { + clk_dfs_status.u32All = acp_reg_read_via_smn( + mmCLK6_PLL0_DFS0_STATUS, sizeof(uint32_t)); + timeout++; + } while ((clk_dfs_status.bitfields.PLL0_DFS0_DFS_DIV_REQ_IDLE == 0) & + (timeout < timeout_cnt)); + +} + +uint32_t mp1_mailbox_send(uint32_t _reg_id, uint32_t _value) +{ + uint32_t ready = 0; + uint32_t wait_cnt = 0; + + while (wait_cnt < 0x1000) { + ready = acp_reg_read_via_smn(mmMP1_C2PMSG_38, sizeof(ready)); + if (ready != 0) { + break; + } + wait_cnt++; + } + if (ready == 0) { + return 0; + } + /* Clear the response register */ + acp_reg_write_via_smn(mmMP1_C2PMSG_38, 0, sizeof(uint32_t)); + /* Write the argument (value) to the argument register */ + acp_reg_write_via_smn(mmMP1_C2PMSG_39, _value, sizeof(uint32_t)); + /* Write the message ID to the message register */ + acp_reg_write_via_smn(mmMP1_C2PMSG_37, _reg_id, sizeof(uint32_t)); + /* Poll until response is non-zero */ + uint32_t resp = 0; + /* TODO: Enable this code after bringup is complete. This is commented to avoid hang */ + int count = 0; + + do { + resp = acp_reg_read_via_smn(mmMP1_C2PMSG_38, sizeof(uint32_t)); + count++; + if (count >= 100) { + break; + } + } while (resp == 0); + /* Optionally, read back the argument register if needed (not used here) */ + + return resp; +} + +void acp_clk_d0_sequence(uint32_t clock_freq) +{ + /* Send message to PMFW to power on Audio PLL */ + mp1_mailbox_send(ACPSMC_MSG_PllPowerState, ACP_AUDIOPLL_POWER_ON_REQ); + + change_clock_notify(clock_freq); + + /* Audio PLL DFS Output for AUDIOCLK */ + acp_reg_write_via_smn(mmCLK6_CLK0_BYPASS_CNTL, 0, sizeof(uint32_t)); + /* Audio PLL DFS Output for ACLK */ + acp_reg_write_via_smn(mmCLK6_CLK1_BYPASS_CNTL, 0, sizeof(uint32_t)); + +} + +void acp_clk_d3_sequence(void) +{ + clk6_bypass_cntl_u_t bypass_cntl; + + bypass_cntl.u32All = 0; + bypass_cntl.bitfields.CLK_BYPASS_SEL = 4; + + /* SET AUDIOCLK TO LPPLL 196.608MHz */ + acp_reg_write_via_smn(mmCLK6_CLK0_BYPASS_CNTL, bypass_cntl.u32All, sizeof(uint32_t)); + + bypass_cntl.u32All = 0; + bypass_cntl.bitfields.CLK_BYPASS_SEL = 2; + + /* SET ACLK TO LPPLL 393MHz */ + acp_reg_write_via_smn(mmCLK6_CLK1_BYPASS_CNTL, bypass_cntl.u32All, sizeof(uint32_t)); + /* mp1_mailbox_send(ACPSMC_MSG_PllPowerState, ACP_AUDIOPLL_POWER_OFF_REQ); */ + + /* Send message to PMFW to power off Audio PLL */ + mp1_mailbox_send(ACPSMC_MSG_PllPowerState, ACP_AUDIOPLL_POWER_OFF_REQ_WITH_WOV_EN); +} + +void change_clock_notify(uint32_t clock_freq) +{ + uint32_t final_did = 4; /* Default DID value */ + float did = 0.0f; + float fraction_val = 0.0f; + uint32_t int_did_val = 0; + float boot_ref_clk = 0.0f; + acp_clock_type_t clock_type = acp_aclk_clock; + + acp_7_x_get_boot_ref_clock(&boot_ref_clk); + + tr_info(&acp_clk_tr, "acp_change_clock_notify clock_freq : %d clock_type : %d", clock_freq, clock_type); + + fraction_val = (float)(clock_freq / (float)1000000.0f); /*converting Hz to Mhz*/ + clock_freq = (clock_freq / 1000000); /*converting Hz to Mhz*/ + + did = (float)(boot_ref_clk/(float)fraction_val); + if (did > 62.0f) { + final_did = 0x7F; + } else { + /* Fractional part of the divider value. Based on fractional + * value increment the did value. + */ + /* Refer DID value sheet for reference. */ + /* Extracting the fractional value from float divider value */ + fraction_val = did - (uint8_t)(did); + + /* Extracting only integer part of the divider */ + did = did - fraction_val; + if (did <= 16.00f) { + did = (did * 4.0f); + } else if ((did > 16.0f) && (did <= 32.0f)) { + did = ((did - 16.0f) * 2.0f + 64.0f); + } else if ((did > 32.0f) && (did <= 62.0f)) { + did = ((did - 32.0f) + 96.0f); + } + + /* Following logic is to ensure the fractional divider value is + * only limited to 2 decimal places, in order to ensure correct + * calculation of DID value + */ + int_did_val = (uint32_t)(fraction_val * 100.0f); + fraction_val = (float)(int_did_val / 100.0f); + + if (fraction_val == 0.0f) { + final_did = (uint8_t)(did); + } else if (fraction_val <= 0.25f) { + final_did = (uint8_t)(did)+1; + } else if ((fraction_val > 0.25f) && (fraction_val <= 0.5f)) { + final_did = (uint8_t)(did)+2; + } else if ((fraction_val > 0.5f) && (fraction_val <= 0.75f)) { + final_did = (uint8_t)(did)+3; + } else if ((fraction_val > 0.75f)) { + final_did = (uint8_t)(did)+4; + } + } + + acp_clk_update_dfs_did((uint32_t)final_did, clock_type); + +} +void acp_change_clock_notify(uint32_t clock_freq) +{ + if (clock_freq) { + /* d0 sequence */ + acp_clk_d0_sequence(clock_freq); + } else { + /* d3 sequence */ + acp_clk_d3_sequence(); + } + +} + +uint32_t acp_clk_update_dfs_did(uint32_t did, uint32_t clk_type) +{ + uint32_t updated_clk = 0; + + if (clk_type == acp_aclk_clock) { + acp_cpl_aclk_dfs_did_update(true, 10, did); + } else if (clk_type == acp_sclk_clock) { + acp_cpl_audioclk_dfs_did_update(true, 10, did); + } + + acp_get_current_clk(acp_aclk_clock, (float *)&updated_clk); + return updated_clk; + +} +void acp_cpl_aclk_dfs_did_update(bool poll, uint32_t timeout_cnt, uint8_t did) +{ /* CLK instance #6, clock slice #1 */ + clk6_pll_dfs_cntl_u_t clk6_pll0_dfs1_cntl; + + clk6_pll0_dfs1_cntl.u32All = acp_reg_read_via_smn(CLK6_PLL0_DFS1_CNTL, sizeof(int)); + clk6_pll0_dfs1_cntl.bitfields.PLL0_DFS0_DIVIDER = did; + acp_reg_write_via_smn(CLK6_PLL0_DFS1_CNTL, clk6_pll0_dfs1_cntl.u32All, sizeof(int)); + if (poll) { + acp_cpl_aclk_poll_dfs_div_req_idle(10); + } +} +void acp_cpl_audioclk_dfs_did_update(bool poll, uint32_t timeout_cnt, uint8_t did) +{ /* CLK instance #6, clock slice #0 */ + clk6_pll_dfs_cntl_u_t clk6_pll0_dfs0_cntl; + + clk6_pll0_dfs0_cntl.u32All = acp_reg_read_via_smn(CLK6_PLL0_DFS0_CNTL, sizeof(uint32_t)); + clk6_pll0_dfs0_cntl.bitfields.PLL0_DFS0_DIVIDER = did; + acp_reg_write_via_smn(CLK6_PLL0_DFS0_CNTL, clk6_pll0_dfs0_cntl.u32All, sizeof(uint32_t)); + /* polling DID change done */ + if (poll) { + acp_cpl_audioclk_poll_dfs_div_req_idle(timeout_cnt); + } +} + +void acp_cpl_aclk_poll_dfs_div_req_idle(uint32_t timeout_cnt) +{ + uint32_t timeout = 0; + clk_dfs_status_u_t clk6_pll0_dfs1_status; + + do { + clk6_pll0_dfs1_status.u32All = acp_reg_read_via_smn( + CLK6_PLL0_DFS1_STATUS, sizeof(uint32_t)); + timeout++; + } while ((clk6_pll0_dfs1_status.bitfields.PLL0_DFS0_DFS_DIV_REQ_IDLE == 0) && + (timeout < timeout_cnt)); +} + +void acp_7_x_get_boot_ref_clock(float *_boot_ref_clk) +{ + volatile SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_NON_AI_CTRL0_BRDS_u_t non_ai_ctrl0; + volatile SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_REFCLK_BRDS_u_t clk_pll_refclk; + volatile SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL6_1_BRDS_u_t ai_freq_ctrl6_1_brds; + volatile SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL7_BRDS_u_t ai_freq_ctrl7_brds; + volatile SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL9_BRDS_u_t ai_freq_ctrl9_brds; + + non_ai_ctrl0.u32All = acp_reg_read_via_smn( + SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_NON_AI_CTRL0_BRDS, sizeof(uint32_t)); + clk_pll_refclk.u32All = acp_reg_read_via_smn( + SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_REFCLK_BRDS, sizeof(uint32_t)); + ai_freq_ctrl6_1_brds.u32All = acp_reg_read_via_smn( + SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL6_1_BRDS, sizeof(uint32_t)); + ai_freq_ctrl7_brds.u32All = acp_reg_read_via_smn( + SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL7_BRDS, sizeof(uint32_t)); + ai_freq_ctrl9_brds.u32All = acp_reg_read_via_smn( + SYSTEMPLL2P0_N3_BUS_CSR_SNAP_6_AI_FREQ_CTRL9_BRDS, sizeof(uint32_t)); + + *_boot_ref_clk = 0.0f; + /* 16777216 = 2^24 */ + *_boot_ref_clk = + (((float)(ai_freq_ctrl6_1_brds.bitfields.fcw_int) + + ((float)(ai_freq_ctrl7_brds.bitfields.fcw_frac << 8 | + ai_freq_ctrl9_brds.bitfields.fcw0_frac_lsb) / + (16777216.0f))) * + (clk_pll_refclk.bitfields.refclk_rate / 2) * + (1 << non_ai_ctrl0.bitfields.vco_pre_div)); +} + +int acp_get_current_clk(acp_clock_type_t clk_type, float *clk_value) +{ + uint32_t temp_clk_value = 0; + clk_tick_cnt_config_reg_t clk_tick_config; + + clk_tick_config.u32All = acp_reg_read_via_smn(CLK_TICK_CNT_CONFIG_REG, sizeof(uint32_t)); + + /* Get current output clock based on CLK TYPE */ + if (acp_sclk_clock == clk_type) { + temp_clk_value = acp_reg_read_via_smn(CLK0_CURRENT_CNT, sizeof(uint32_t)); + } else if (acp_aclk_clock == clk_type) { + temp_clk_value = acp_reg_read_via_smn(CLK1_CURRENT_CNT, sizeof(uint32_t)); + } else { + return -EINVAL; /* Invalid parameter */ + } + + *clk_value = temp_clk_value / (clk_tick_config.bitfields.TIMER_THRESHOLD / 48.0f); + return 0; /* Success */ +} diff --git a/src/platform/amd/acp_7_x/platform.c b/src/platform/amd/acp_7_x/platform.c new file mode 100644 index 000000000000..f6778dd0bf98 --- /dev/null +++ b/src/platform/amd/acp_7_x/platform.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2026 AMD. All rights reserved. + * + * Author: Sneha Voona <sneha.voona@amd.com> + * DineshKumar Kalva <DineshKumar.Kalva@amd.com> + * Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> + */ + +#include <sof/compiler_info.h> +#include <sof/debug/debug.h> +#include <rtos/interrupt.h> +#include <sof/drivers/acp_dai_dma.h> +#include <sof/ipc/driver.h> +#include <rtos/timer.h> +#include <sof/fw-ready-metadata.h> +#include <sof/lib/agent.h> +#include <rtos/clk.h> +#include <sof/lib/cpu.h> +#include <sof/lib/dai.h> +#include <sof/lib/dma.h> +#include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <sof/lib/mm_heap.h> +#include <sof/platform.h> +#include <sof/schedule/edf_schedule.h> +#include <sof/schedule/ll_schedule.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <rtos/sof.h> +#include <sof/trace/dma-trace.h> +#include <ipc/dai.h> +#include <ipc/header.h> +#include <ipc/info.h> +#include <kernel/abi.h> +#include <kernel/ext_manifest.h> +#include <sof_versions.h> +#include <errno.h> +#include <stdint.h> +#include <zephyr/logging/log.h> + +LOG_MODULE_REGISTER(platform_file, CONFIG_SOF_LOG_LEVEL); + +#define INTERRUPT_DISABLE 0 +extern void acp_dsp_to_host_intr_trig(void); +struct sof; +static const struct sof_ipc_fw_ready ready + __attribute__((section(".fw_ready"))) = { + .hdr = { + .cmd = SOF_IPC_FW_READY, + .size = sizeof(struct sof_ipc_fw_ready), + }, + /* dspbox is for DSP initiated IPC, hostbox is for host initiated IPC */ + .version = { + .hdr.size = sizeof(struct sof_ipc_fw_version), + .micro = SOF_MICRO, + .minor = SOF_MINOR, + .major = SOF_MAJOR, +#if BLD_COUNTERS + .build = SOF_BUILD, /* See version-build-counter.cmake */ + .date = __DATE__, + .time = __TIME__, +#else + .build = -1, + .date = "dtermin.\0", + .time = "fwready.\0", +#endif + .tag = SOF_TAG, + .abi_version = SOF_ABI_VERSION, + }, + .flags = DEBUG_SET_FW_READY_FLAGS, +}; + +#define NUM_ACP_WINDOWS 6 + +const struct ext_man_windows xsram_window +#ifdef CONFIG_AMD_BINARY_BUILD + __aligned(EXT_MAN_ALIGN) __unused = { +#else + __aligned(EXT_MAN_ALIGN) __section(".fw_metadata") __unused = { +#endif + .hdr = { + .type = EXT_MAN_ELEM_WINDOW, + .elem_size = ALIGN_UP_COMPILE(sizeof(struct ext_man_windows), EXT_MAN_ALIGN), + }, + .window = { + .ext_hdr = { + .hdr.cmd = SOF_IPC_FW_READY, + .hdr.size = sizeof(struct sof_ipc_window), + .type = SOF_IPC_EXT_WINDOW, + }, + .num_windows = NUM_ACP_WINDOWS, + .window = { + { + .type = SOF_IPC_REGION_UPBOX, + .id = 0, + .flags = 0, + .size = MAILBOX_DSPBOX_SIZE, + .offset = MAILBOX_DSPBOX_OFFSET, + }, + { + .type = SOF_IPC_REGION_DOWNBOX, + .id = 0, + .flags = 0, + .size = MAILBOX_HOSTBOX_SIZE, + .offset = MAILBOX_HOSTBOX_OFFSET, + }, + { + .type = SOF_IPC_REGION_DEBUG, + .id = 0, + .flags = 0, + .size = MAILBOX_DEBUG_SIZE, + .offset = MAILBOX_DEBUG_OFFSET, + }, + { + .type = SOF_IPC_REGION_TRACE, + .id = 0, + .flags = 0, + .size = MAILBOX_TRACE_SIZE, + .offset = MAILBOX_TRACE_OFFSET, + }, + { + .type = SOF_IPC_REGION_STREAM, + .id = 0, + .flags = 0, + .size = MAILBOX_STREAM_SIZE, + .offset = MAILBOX_STREAM_OFFSET, + }, + { + .type = SOF_IPC_REGION_EXCEPTION, + .id = 0, + .flags = 0, + .size = MAILBOX_EXCEPTION_SIZE, + .offset = MAILBOX_EXCEPTION_OFFSET, + }, + }, + }, +}; + +int platform_init(struct sof *sof) +{ + int ret; + + platform_clock_init(sof); + scheduler_init_edf(); + /* init low latency domains and schedulers */ + /* CONFIG_SYSTICK_PERIOD set as PLATFORM_DEFAULT_CLOCK */ + sof->platform_timer_domain = zephyr_domain_init(PLATFORM_DEFAULT_CLOCK); + zephyr_ll_scheduler_init(sof->platform_timer_domain); + + /*CONFIG_SYSTICK_PERIOD hardcoded as 200000*/ + sa_init(sof, 200000); + clock_set_freq(CLK_CPU(cpu_get_id()), CLK_MAX_CPU_HZ); + /* init DMA */ + ret = dmac_init(sof); + if (ret < 0) { + return -ENODEV; + } + + /* initialize the host IPC mechanisms */ + ipc_init(sof); + /* initialize the DAI mechanisms */ + ret = dai_init(sof); + if (ret < 0) { + return -ENODEV; + } + + /* show heap status */ + heap_trace_all(1); + return 0; +} + +int platform_boot_complete(uint32_t boot_message) +{ + acp_sw_intr_trig_t swintrtrig; + volatile acp_scratch_mem_config_t *pscratch_mem_cfg = + (volatile acp_scratch_mem_config_t *)(PU_SCRATCH_REG_BASE + SCRATCH_REG_OFFSET); + mailbox_dspbox_write(0, &ready, sizeof(ready)); +#ifdef CONFIG_AMD_BINARY_BUILD + mailbox_dspbox_write(sizeof(ready), &xsram_window.window, sizeof(xsram_window.window)); +#endif + pscratch_mem_cfg->acp_dsp_msg_write = 1; + acp_dsp_to_host_intr_trig(); + /* Configures the trigger bit in ACP_DSP_SW_INTR_TRIG register */ + swintrtrig = (acp_sw_intr_trig_t)io_reg_read(PU_REGISTER_BASE + ACP_SW_INTR_TRIG); + swintrtrig.bits.trig_dsp0_to_host_intr = INTERRUPT_DISABLE; + io_reg_write((PU_REGISTER_BASE + ACP_SW_INTR_TRIG), swintrtrig.u32all); + clock_set_freq(CLK_CPU(cpu_get_id()), CLK_DEFAULT_CPU_HZ); + return 0; +} + +int platform_context_save(struct sof *sof) +{ + return 0; +} +#ifdef __XCC__ +/* This is a stub for the Xtensa libc (not their newlib version), + * which inexplicably wants to pull in an unlink() implementation when + * linked against the C++ standard library. Obviously nothing in SOF + * uses the C library filesystem layer, this is just spurious. + */ +int __attribute__((weak)) _unlink_r(struct _reent *ptr, const char *file) +{ + return -1; +} +#endif diff --git a/src/platform/amd/common/include/platform/ipc.h b/src/platform/amd/common/include/platform/ipc.h index 26c392776662..a715adde1254 100644 --- a/src/platform/amd/common/include/platform/ipc.h +++ b/src/platform/amd/common/include/platform/ipc.h @@ -1,9 +1,10 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2023 AMD. All rights reserved. + * Copyright(c) 2023, 2026 AMD. All rights reserved. * *Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> * SaiSurya, Ch <saisurya.chakkaveeravenkatanaga@amd.com> + * Sivasubramanian <sravisar@amd.com> */ #ifndef _COMMON_IPC_HEADER #define _COMMON_IPC_HEADER @@ -11,6 +12,7 @@ #include <stdint.h> #include <platform/platform.h> +#define IRQ_NUM_EXT_LEVEL3 3 uint32_t sof_ipc_host_status(void); uint32_t sof_ipc_host_ack_flag(void); void sof_ipc_host_ack_clear(void); diff --git a/src/platform/amd/common/include/platform/lib/dai.h b/src/platform/amd/common/include/platform/lib/dai.h index c2ed312ac4f0..250e8f945552 100644 --- a/src/platform/amd/common/include/platform/lib/dai.h +++ b/src/platform/amd/common/include/platform/lib/dai.h @@ -18,7 +18,10 @@ #define SDW0_ACP_SW_AUDIO_TX_EN_CH 5 #define SDW0_ACP_SW_BT_RX_EN_CH 6 #define SDW0_ACP_SW_BT_TX_EN_CH 7 -#define SDW0_ACP_SW_BT_CH_OFFSET 4 +#define SDW1_ACP_P1_SW_AUDIO_RX_EN_CH 8 +#define SDW1_ACP_P1_SW_AUDIO_TX_EN_CH 9 +#define SDW1_ACP_P1_SW_HS_RX_EN_CH 10 +#define SDW1_ACP_P1_SW_HS_TX_EN_CH 11 #define DI_SDW0_ACP_SW_AUDIO_TX 0 #define DI_SDW0_ACP_SW_BT_TX 1 @@ -26,8 +29,12 @@ #define DI_SDW0_ACP_SW_AUDIO_RX 3 #define DI_SDW0_ACP_SW_BT_RX 4 #define DI_SDW0_ACP_SW_HS_RX 5 +#define DI_SDW1_ACP_P1_SW_AUDIO_TX 64 #define DI_SDW1_ACP_P1_SW_BT_TX 65 +#define DI_SDW1_ACP_P1_SW_HS_TX 66 +#define DI_SDW1_ACP_P1_SW_AUDIO_RX 67 #define DI_SDW1_ACP_P1_SW_BT_RX 68 +#define DI_SDW1_ACP_P1_SW_HS_RX 69 #endif /* __PLATFORM_LIB_DAI_H__ */ diff --git a/src/platform/amd/common/include/platform/lib/dma.h b/src/platform/amd/common/include/platform/lib/dma.h index b8d6064d8862..f8d053876353 100644 --- a/src/platform/amd/common/include/platform/lib/dma.h +++ b/src/platform/amd/common/include/platform/lib/dma.h @@ -13,7 +13,7 @@ #define PLATFORM_NUM_DMACS 4 /* max number of supported DMA channels */ -#define PLATFORM_MAX_DMA_CHAN 8 +#define PLATFORM_MAX_DMA_CHAN 12 #define DMA_ID_DMA0 0 #define DMA_ID_HOST 1 diff --git a/src/platform/amd/rembrandt/include/arch/xtensa/config/tie-asm.h b/src/platform/amd/rembrandt/include/arch/xtensa/config/tie-asm.h index 9ec7b495afd9..9ac7ec55993d 100644 --- a/src/platform/amd/rembrandt/include/arch/xtensa/config/tie-asm.h +++ b/src/platform/amd/rembrandt/include/arch/xtensa/config/tie-asm.h @@ -166,7 +166,7 @@ .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) xchal_sa_align \ptr, 0, 0, 16, 16 ae_s64.i aed0, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_s64.i aed1, \ptr, .Lxchal_ofs_+0 ae_s64.i aed2, \ptr, .Lxchal_ofs_+8 ae_s64.i aed3, \ptr, .Lxchal_ofs_+16 @@ -175,7 +175,7 @@ ae_s64.i aed6, \ptr, .Lxchal_ofs_+40 ae_s64.i aed7, \ptr, .Lxchal_ofs_+48 ae_s64.i aed8, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_s64.i aed9, \ptr, .Lxchal_ofs_+0 ae_s64.i aed10, \ptr, .Lxchal_ofs_+8 ae_s64.i aed11, \ptr, .Lxchal_ofs_+16 @@ -184,7 +184,7 @@ ae_s64.i aed14, \ptr, .Lxchal_ofs_+40 ae_s64.i aed15, \ptr, .Lxchal_ofs_+48 ae_s64.i aed16, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_s64.i aed17, \ptr, .Lxchal_ofs_+0 ae_s64.i aed18, \ptr, .Lxchal_ofs_+8 ae_s64.i aed19, \ptr, .Lxchal_ofs_+16 @@ -193,7 +193,7 @@ ae_s64.i aed22, \ptr, .Lxchal_ofs_+40 ae_s64.i aed23, \ptr, .Lxchal_ofs_+48 ae_s64.i aed24, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_s64.i aed25, \ptr, .Lxchal_ofs_+0 ae_s64.i aed26, \ptr, .Lxchal_ofs_+8 ae_s64.i aed27, \ptr, .Lxchal_ofs_+16 @@ -209,12 +209,12 @@ s8i \at1, \ptr, .Lxchal_ofs_+58 ae_movae \at1, aep3 s8i \at1, \ptr, .Lxchal_ofs_+59 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_salign128.i u0, \ptr, .Lxchal_ofs_+0 ae_salign128.i u1, \ptr, .Lxchal_ofs_+16 ae_salign128.i u2, \ptr, .Lxchal_ofs_+32 ae_salign128.i u3, \ptr, .Lxchal_ofs_+48 - addi.a \ptr, \ptr, -320 + addi \ptr, \ptr, -320 ae_movdrzbvc aed0 // ureg AE_ZBIASV8C ae_s64.i aed0, \ptr, .Lxchal_ofs_+0 + 0 ae_movvfcrfsr aed0 // ureg FCR_FSR @@ -286,7 +286,7 @@ l32i \at1, \ptr, .Lxchal_ofs_+52 wur.ae_cend2 \at1 // ureg 251 ae_l64.i aed0, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_l64.i aed1, \ptr, .Lxchal_ofs_+0 ae_l64.i aed2, \ptr, .Lxchal_ofs_+8 ae_l64.i aed3, \ptr, .Lxchal_ofs_+16 @@ -295,7 +295,7 @@ ae_l64.i aed6, \ptr, .Lxchal_ofs_+40 ae_l64.i aed7, \ptr, .Lxchal_ofs_+48 ae_l64.i aed8, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_l64.i aed9, \ptr, .Lxchal_ofs_+0 ae_l64.i aed10, \ptr, .Lxchal_ofs_+8 ae_l64.i aed11, \ptr, .Lxchal_ofs_+16 @@ -304,7 +304,7 @@ ae_l64.i aed14, \ptr, .Lxchal_ofs_+40 ae_l64.i aed15, \ptr, .Lxchal_ofs_+48 ae_l64.i aed16, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_l64.i aed17, \ptr, .Lxchal_ofs_+0 ae_l64.i aed18, \ptr, .Lxchal_ofs_+8 ae_l64.i aed19, \ptr, .Lxchal_ofs_+16 @@ -313,7 +313,7 @@ ae_l64.i aed22, \ptr, .Lxchal_ofs_+40 ae_l64.i aed23, \ptr, .Lxchal_ofs_+48 ae_l64.i aed24, \ptr, .Lxchal_ofs_+56 - addi.a \ptr, \ptr, 64 + addi \ptr, \ptr, 64 ae_l64.i aed25, \ptr, .Lxchal_ofs_+0 ae_l64.i aed26, \ptr, .Lxchal_ofs_+8 ae_l64.i aed27, \ptr, .Lxchal_ofs_+16 @@ -321,7 +321,7 @@ ae_l64.i aed29, \ptr, .Lxchal_ofs_+32 ae_l64.i aed30, \ptr, .Lxchal_ofs_+40 ae_l64.i aed31, \ptr, .Lxchal_ofs_+48 - addi.a \ptr, \ptr, 56 + addi \ptr, \ptr, 56 l8ui \at1, \ptr, .Lxchal_ofs_+0 ae_movea aep0, \at1 l8ui \at1, \ptr, .Lxchal_ofs_+1 @@ -330,7 +330,7 @@ ae_movea aep2, \at1 l8ui \at1, \ptr, .Lxchal_ofs_+3 ae_movea aep3, \at1 - addi.a \ptr, \ptr, 8 + addi \ptr, \ptr, 8 ae_lalign128.i u0, \ptr, .Lxchal_ofs_+0 ae_lalign128.i u1, \ptr, .Lxchal_ofs_+16 ae_lalign128.i u2, \ptr, .Lxchal_ofs_+32 diff --git a/src/platform/amd/rembrandt/include/platform/lib/memory.h b/src/platform/amd/rembrandt/include/platform/lib/memory.h index 92ac53b4c2ed..bd618b6d9bdb 100644 --- a/src/platform/amd/rembrandt/include/platform/lib/memory.h +++ b/src/platform/amd/rembrandt/include/platform/lib/memory.h @@ -156,11 +156,6 @@ struct sof; #define SHARED_DATA void platform_init_memmap(struct sof *sof); -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - static inline void *platform_rfree_prepare(void *ptr) { return ptr; diff --git a/src/platform/amd/rembrandt/lib/CMakeLists.txt b/src/platform/amd/rembrandt/lib/CMakeLists.txt index 271a099cc6a9..163fe4463158 100644 --- a/src/platform/amd/rembrandt/lib/CMakeLists.txt +++ b/src/platform/amd/rembrandt/lib/CMakeLists.txt @@ -4,5 +4,4 @@ add_local_sources(sof clk.c dai.c dma.c - memory.c ) diff --git a/src/platform/amd/rembrandt/lib/dma.c b/src/platform/amd/rembrandt/lib/dma.c index d739e77bad1b..66ddea8effe8 100644 --- a/src/platform/amd/rembrandt/lib/dma.c +++ b/src/platform/amd/rembrandt/lib/dma.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // -//Copyright(c) 2022 AMD. All rights reserved. +//Copyright(c) 2022, 2026 AMD. All rights reserved. // //Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> // Bala Kishore <balakishore.pati@amd.com> +// Sivasubramanian <sravisar@amd.com> #include <sof/common.h> #include <platform/fw_scratch_mem.h> @@ -41,8 +42,8 @@ SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { .plat_data = { .id = DMA_ID_DAI_DMIC, .dir = DMA_DIR_DEV_TO_MEM, - .devs = DMA_DEV_DMIC, - .caps = DMA_CAP_DMIC, + .devs = SOF_DMA_DEV_DMIC, + .caps = SOF_DMA_CAP_DMIC, .base = DMA0_BASE, .chan_size = DMA0_SIZE, .channels = 8, @@ -54,8 +55,8 @@ SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { .plat_data = { .id = DMA_ID_DAI_HS, .dir = DMA_DIR_DEV_TO_MEM | DMA_DIR_MEM_TO_DEV, - .devs = DMA_DEV_SP, - .caps = DMA_CAP_SP, + .devs = SOF_DMA_DEV_SP, + .caps = SOF_DMA_CAP_SP, .base = DMA0_BASE, .chan_size = DMA0_SIZE, .channels = 8, diff --git a/src/platform/amd/rembrandt/lib/memory.c b/src/platform/amd/rembrandt/lib/memory.c deleted file mode 100644 index 4d289a95c112..000000000000 --- a/src/platform/amd/rembrandt/lib/memory.c +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright 2022 AMD -// -// Author:Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com> - -#include <sof/common.h> -#include <sof/lib/mm_heap.h> -#include <sof/lib/memory.h> -#include <sof/platform.h> -#include <rtos/sof.h> -#include <ipc/topology.h> -#ifndef __ZEPHYR__ -/* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; - -/* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { - BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), - BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), - BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), -}; - -/* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; - -/* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { - BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), - BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), - BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), - BLOCK_DEF(128, HEAP_RT_COUNT128, mod_block128), - BLOCK_DEF(256, HEAP_RT_COUNT256, mod_block256), - BLOCK_DEF(512, HEAP_RT_COUNT512, mod_block512), - BLOCK_DEF(1024, HEAP_RT_COUNT1024, mod_block1024), - BLOCK_DEF(2048, HEAP_RT_COUNT2048, mod_block2048), -}; - -/* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; - -/* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { - BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), -}; - -static SHARED_DATA struct mm memmap = { - .system[0] = { - .heap = HEAP_SYSTEM_BASE, - .size = HEAP_SYSTEM_SIZE, - .info = {.free = HEAP_SYSTEM_SIZE,}, - .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, - }, - .system_runtime[0] = { - .blocks = ARRAY_SIZE(sys_rt_heap_map), - .map = sys_rt_heap_map, - .heap = HEAP_SYS_RUNTIME_BASE, - .size = HEAP_SYS_RUNTIME_SIZE, - .info = {.free = HEAP_SYS_RUNTIME_SIZE,}, - .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, - }, - .runtime[0] = { - .blocks = ARRAY_SIZE(rt_heap_map), - .map = rt_heap_map, - .heap = HEAP_RUNTIME_BASE, - .size = HEAP_RUNTIME_SIZE, - .info = {.free = HEAP_RUNTIME_SIZE,}, - .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, - }, - .buffer[0] = { - .blocks = ARRAY_SIZE(buf_heap_map), - .map = buf_heap_map, - .heap = HEAP_BUFFER_BASE, - .size = HEAP_BUFFER_SIZE, - .info = {.free = HEAP_BUFFER_SIZE,}, - .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA | SOF_MEM_CAPS_CACHE | SOF_MEM_CAPS_HP, - }, - .total = {.free = HEAP_SYSTEM_SIZE + HEAP_SYS_RUNTIME_SIZE + - HEAP_RUNTIME_SIZE + HEAP_BUFFER_SIZE,}, -}; - -void platform_init_memmap(struct sof *sof) -{ - /* memmap has been initialized statically as a part of .data */ - sof->memory_map = &memmap; -} -#endif diff --git a/src/platform/amd/rembrandt/platform.c b/src/platform/amd/rembrandt/platform.c index 23ced7356a95..1c26e8e8fcfa 100644 --- a/src/platform/amd/rembrandt/platform.c +++ b/src/platform/amd/rembrandt/platform.c @@ -123,23 +123,13 @@ const struct ext_man_windows xsram_window }, }; -#ifndef __ZEPHYR__ -static SHARED_DATA struct timer timer = { - .id = TIMER0, - .irq = IRQ_NUM_TIMER0, -}; -#endif - int platform_init(struct sof *sof) { int ret; -#ifndef __ZEPHYR__ - sof->platform_timer = &timer; - sof->cpu_timers = &timer; -#else + /* initialize cascade interrupts before any usage */ interrupt_init(sof); -#endif + /* to view system memory */ platform_interrupt_init(); platform_clock_init(sof); @@ -149,9 +139,7 @@ int platform_init(struct sof *sof) sof->platform_timer_domain = timer_domain_init(sof->platform_timer, PLATFORM_DEFAULT_CLOCK); scheduler_init_ll(sof->platform_timer_domain); -#ifndef __ZEPHYR__ - platform_timer_start(sof->platform_timer); -#endif + /*CONFIG_SYSTICK_PERIOD hardcoded as 200000*/ sa_init(sof, 200000); clock_set_freq(CLK_CPU(cpu_get_id()), CLK_MAX_CPU_HZ); @@ -173,7 +161,7 @@ int platform_init(struct sof *sof) #if CONFIG_TRACE /* Initialize DMA for Trace*/ trace_point(TRACE_BOOT_PLATFORM_DMA_TRACE); - sof->dmat->config.elem_array.elems = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + sof->dmat->config.elem_array.elems = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(struct dma_sg_elem) * 1); sof->dmat->config.elem_array.count = 1; sof->dmat->config.elem_array.elems->dest = 0x03800000; @@ -202,14 +190,8 @@ int platform_boot_complete(uint32_t boot_message) clock_set_freq(CLK_CPU(cpu_get_id()), CLK_DEFAULT_CPU_HZ); return 0; } + int platform_context_save(struct sof *sof) { return 0; } - -#ifndef __ZEPHYR__ -void platform_wait_for_interrupt(int level) -{ - arch_wait_for_interrupt(level); -} -#endif diff --git a/src/platform/amd/renoir/include/platform/lib/memory.h b/src/platform/amd/renoir/include/platform/lib/memory.h index 4caeb0e30d06..0d1df900e6fd 100644 --- a/src/platform/amd/renoir/include/platform/lib/memory.h +++ b/src/platform/amd/renoir/include/platform/lib/memory.h @@ -151,11 +151,6 @@ struct sof; #define SHARED_DATA void platform_init_memmap(struct sof *sof); -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - static inline void *platform_rfree_prepare(void *ptr) { return ptr; diff --git a/src/platform/amd/renoir/lib/clk.c b/src/platform/amd/renoir/lib/clk.c index dddc974f631a..4880daafac71 100644 --- a/src/platform/amd/renoir/lib/clk.c +++ b/src/platform/amd/renoir/lib/clk.c @@ -122,7 +122,7 @@ void platform_clock_init(struct sof *sof) { int i; - sof->clocks = platform_shared_get(platform_clocks_info, sizeof(platform_clocks_info)); + sof->clocks = platform_clocks_info; for (i = 0; i < PLATFORM_CORE_COUNT; i++) { sof->clocks[i] = (struct clock_info) { diff --git a/src/platform/amd/renoir/lib/memory.c b/src/platform/amd/renoir/lib/memory.c index 9f16b1977f05..a5b33cbb24d6 100644 --- a/src/platform/amd/renoir/lib/memory.c +++ b/src/platform/amd/renoir/lib/memory.c @@ -91,5 +91,5 @@ static SHARED_DATA struct mm memmap = { void platform_init_memmap(struct sof *sof) { /* memmap has been initialized statically as a part of .data */ - sof->memory_map = platform_shared_get(&memmap, sizeof(memmap)); + sof->memory_map = &memmap; } diff --git a/src/platform/amd/renoir/platform.c b/src/platform/amd/renoir/platform.c index eecb8d61af56..419f1251bd84 100644 --- a/src/platform/amd/renoir/platform.c +++ b/src/platform/amd/renoir/platform.c @@ -133,7 +133,7 @@ int platform_init(struct sof *sof) { int ret; - sof->platform_timer = platform_shared_get(&timer_shared, sizeof(timer_shared)); + sof->platform_timer = &timer_shared; sof->cpu_timers = sof->platform_timer; /* to view system memory */ @@ -167,7 +167,7 @@ int platform_init(struct sof *sof) #if CONFIG_TRACE /* Initialize DMA for Trace*/ trace_point(TRACE_BOOT_PLATFORM_DMA_TRACE); - sof->dmat->config.elem_array.elems = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + sof->dmat->config.elem_array.elems = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(struct dma_sg_elem) * 1); sof->dmat->config.elem_array.count = 1; sof->dmat->config.elem_array.elems->dest = 0x03800000; diff --git a/src/platform/amd/vangogh/include/platform/lib/memory.h b/src/platform/amd/vangogh/include/platform/lib/memory.h index 6e0b768cc57a..49a12236833c 100644 --- a/src/platform/amd/vangogh/include/platform/lib/memory.h +++ b/src/platform/amd/vangogh/include/platform/lib/memory.h @@ -150,11 +150,6 @@ struct sof; #define SHARED_DATA void platform_init_memmap(struct sof *sof); -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - static inline void *platform_rfree_prepare(void *ptr) { return ptr; diff --git a/src/platform/amd/vangogh/platform.c b/src/platform/amd/vangogh/platform.c index ad06fbb4b3cd..300239a023be 100644 --- a/src/platform/amd/vangogh/platform.c +++ b/src/platform/amd/vangogh/platform.c @@ -166,7 +166,7 @@ int platform_init(struct sof *sof) #if CONFIG_TRACE /* Initialize DMA for Trace*/ trace_point(TRACE_BOOT_PLATFORM_DMA_TRACE); - sof->dmat->config.elem_array.elems = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + sof->dmat->config.elem_array.elems = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(struct dma_sg_elem) * 1); sof->dmat->config.elem_array.count = 1; sof->dmat->config.elem_array.elems->dest = 0x03800000; diff --git a/src/platform/imx8/include/platform/lib/memory.h b/src/platform/imx8/include/platform/lib/memory.h index 1c3d88fe4d4d..674d1af2611f 100644 --- a/src/platform/imx8/include/platform/lib/memory.h +++ b/src/platform/imx8/include/platform/lib/memory.h @@ -187,11 +187,6 @@ struct sof; void platform_init_memmap(struct sof *sof); -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - #define uncache_to_cache(address) address #define cache_to_uncache(address) address #define cache_to_uncache_init(address) address diff --git a/src/platform/imx8/lib/clk.c b/src/platform/imx8/lib/clk.c index 5c21a47964e1..152cac1752d7 100644 --- a/src/platform/imx8/lib/clk.c +++ b/src/platform/imx8/lib/clk.c @@ -11,9 +11,7 @@ #include <sof/lib/notifier.h> #include <rtos/sof.h> -#ifdef __ZEPHYR__ #include <zephyr/sys/util.h> -#endif const struct freq_table platform_cpu_freq[] = { #ifdef CONFIG_IMX8 @@ -32,7 +30,7 @@ void platform_clock_init(struct sof *sof) { int i; - sof->clocks = platform_shared_get(platform_clocks_info, sizeof(platform_clocks_info)); + sof->clocks = platform_clocks_info; for (i = 0; i < CONFIG_CORE_COUNT; i++) { sof->clocks[i] = (struct clock_info) { diff --git a/src/platform/imx8/lib/memory.c b/src/platform/imx8/lib/memory.c index 78cb05c86cbb..d4527d756ac1 100644 --- a/src/platform/imx8/lib/memory.c +++ b/src/platform/imx8/lib/memory.c @@ -95,5 +95,5 @@ static SHARED_DATA struct mm memmap = { void platform_init_memmap(struct sof *sof) { /* memmap has been initialized statically as a part of .data */ - sof->memory_map = platform_shared_get(&memmap, sizeof(memmap)); + sof->memory_map = &memmap; } diff --git a/src/platform/imx8m/include/platform/lib/memory.h b/src/platform/imx8m/include/platform/lib/memory.h index 6b2c00f89bad..490e65a0052d 100644 --- a/src/platform/imx8m/include/platform/lib/memory.h +++ b/src/platform/imx8m/include/platform/lib/memory.h @@ -211,11 +211,6 @@ void platform_init_memmap(struct sof *sof); #define cache_to_uncache_init(address) address #define is_uncached(address) 0 -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - /** * \brief Function for keeping shared data synchronized. * It's used after usage of data shared by different cores. diff --git a/src/platform/imx8m/lib/clk.c b/src/platform/imx8m/lib/clk.c index dda25341fa48..78aacfd05e28 100644 --- a/src/platform/imx8m/lib/clk.c +++ b/src/platform/imx8m/lib/clk.c @@ -10,9 +10,7 @@ #include <sof/lib/notifier.h> #include <rtos/sof.h> -#ifdef __ZEPHYR__ #include <zephyr/sys/util.h> -#endif const struct freq_table platform_cpu_freq[] = { { 800000000, 800000 }, @@ -27,7 +25,7 @@ void platform_clock_init(struct sof *sof) { int i; - sof->clocks = platform_shared_get(platform_clocks_info, sizeof(platform_clocks_info)); + sof->clocks = platform_clocks_info; for (i = 0; i < CONFIG_CORE_COUNT; i++) { sof->clocks[i] = (struct clock_info) { diff --git a/src/platform/imx8m/lib/dma.c b/src/platform/imx8m/lib/dma.c index ddcfc663bfac..f9cb5a74682a 100644 --- a/src/platform/imx8m/lib/dma.c +++ b/src/platform/imx8m/lib/dma.c @@ -42,7 +42,7 @@ static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { }; static const struct dma_info lib_dma = { - .dma_array = cache_to_uncache_init((struct dma *)dma), + .dma_array = cache_to_uncache_init((void *)dma), .num_dmas = ARRAY_SIZE(dma) }; diff --git a/src/platform/imx8m/lib/memory.c b/src/platform/imx8m/lib/memory.c index 85596ca2b525..9f26cd3ebe80 100644 --- a/src/platform/imx8m/lib/memory.c +++ b/src/platform/imx8m/lib/memory.c @@ -97,5 +97,5 @@ static SHARED_DATA struct mm memmap = { void platform_init_memmap(struct sof *sof) { /* memmap has been initialized statically as a part of .data */ - sof->memory_map = platform_shared_get(&memmap, sizeof(memmap)); + sof->memory_map = &memmap; } diff --git a/src/platform/imx8m/platform.c b/src/platform/imx8m/platform.c index e1f956590d92..46e60a7e8608 100644 --- a/src/platform/imx8m/platform.c +++ b/src/platform/imx8m/platform.c @@ -127,13 +127,6 @@ const struct ext_man_windows xsram_window }, }; -#ifndef __ZEPHYR__ -static SHARED_DATA struct timer timer_shared = { - .id = TIMER0, /* internal timer */ - .irq = IRQ_NUM_TIMER0, -}; -#endif - int platform_boot_complete(uint32_t boot_message) { mailbox_dspbox_write(0, &ready, sizeof(ready)); @@ -154,11 +147,6 @@ int platform_init(struct sof *sof) { int ret; -#ifndef __ZEPHYR__ - sof->platform_timer = platform_shared_get(&timer_shared, sizeof(timer_shared)); - sof->cpu_timers = sof->platform_timer; -#endif - platform_interrupt_init(); platform_clock_init(sof); scheduler_init_edf(); @@ -168,10 +156,6 @@ int platform_init(struct sof *sof) timer_domain_init(sof->platform_timer, PLATFORM_DEFAULT_CLOCK); scheduler_init_ll(sof->platform_timer_domain); -#ifndef __ZEPHYR__ - platform_timer_start(sof->platform_timer); -#endif - sa_init(sof, CONFIG_SYSTICK_PERIOD); clock_set_freq(CLK_CPU(cpu_get_id()), CLK_MAX_CPU_HZ); @@ -204,10 +188,3 @@ int platform_context_save(struct sof *sof) { return 0; } - -#ifndef __ZEPHYR__ -void platform_wait_for_interrupt(int level) -{ - arch_wait_for_interrupt(level); -} -#endif diff --git a/src/platform/imx8m_cm7/include/platform/lib/clk.h b/src/platform/imx8m_cm7/include/platform/lib/clk.h new file mode 100644 index 000000000000..379aade87252 --- /dev/null +++ b/src/platform/imx8m_cm7/include/platform/lib/clk.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 NXP + */ + +#ifdef __SOF_LIB_CLK_H__ + +#ifndef __PLATFORM_LIB_CLK_H__ +#define __PLATFORM_LIB_CLK_H__ + +#define CLK_MAX_CPU_HZ 800000000 +#define CPU_DEFAULT_IDX 0 +#define NUM_CPU_FREQ 1 +#define NUM_CLOCKS 1 + +struct sof; + +void platform_clock_init(struct sof *sof); + +#endif /* __PLATFORM_LIB_CLK_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/clk.h" + +#endif /* __SOF_LIB_CLK_H__ */ diff --git a/src/platform/imx8m_cm7/include/platform/lib/dma.h b/src/platform/imx8m_cm7/include/platform/lib/dma.h new file mode 100644 index 000000000000..ad55e7f7fb89 --- /dev/null +++ b/src/platform/imx8m_cm7/include/platform/lib/dma.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 NXP + */ + +#ifdef __SOF_LIB_DMA_H__ + +#ifndef __PLATFORM_LIB_DMA_H__ +#define __PLATFORM_LIB_DMA_H__ + +/* TODO: remove me whenever possible */ + +#endif /* __PLATFORM_LIB_DMA_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/dma.h" + +#endif /* __SOF_LIB_DMA_H__ */ diff --git a/src/platform/imx8m_cm7/include/platform/lib/mailbox.h b/src/platform/imx8m_cm7/include/platform/lib/mailbox.h new file mode 100644 index 000000000000..6099d36806f9 --- /dev/null +++ b/src/platform/imx8m_cm7/include/platform/lib/mailbox.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 NXP + */ + +#ifdef __SOF_LIB_MAILBOX_H__ + +#ifndef __PLATFORM_LIB_MAILBOX_H__ +#define __PLATFORM_LIB_MAILBOX_H__ + +/* The i.MX8MP CM7 mailbox region is organized like this: + * + * +---------------+-------------------------+ + * | Region name | Base address | Size | + * +---------------+---------------+---------+ + * | Outbox region | 0x82000000 | 0x1000 | + * +---------------+---------------+---------+ + * | Inbox region | 0x82001000 | 0x1000 | + * +---------------+---------------+---------+ + * | Stream region | 0x82002000 | 0x1000 | + * +---------------+---------------+---------+ + * + * IMPORTANT: all regions should be 32-byte aligned. + * This is required because cache maintenance might + * be performed on them. + */ + +/* outbox */ +#define MAILBOX_DSPBOX_SIZE 0x1000 +#define MAILBOX_DSPBOX_BASE 0x82000000 +#define MAILBOX_DSPBOX_OFFSET 0 + +/* inbox */ +#define MAILBOX_HOSTBOX_SIZE 0x1000 +#define MAILBOX_HOSTBOX_BASE 0x82001000 +#define MAILBOX_HOSTBOX_OFFSET (MAILBOX_DSPBOX_OFFSET + MAILBOX_DSPBOX_SIZE) + +/* stream */ +#define MAILBOX_STREAM_SIZE 0x1000 +#define MAILBOX_STREAM_BASE 0x82002000 +#define MAILBOX_STREAM_OFFSET (MAILBOX_HOSTBOX_OFFSET + MAILBOX_HOSTBOX_SIZE) + +#endif /* __PLATFORM_LIB_MAILBOX_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/mailbox.h" + +#endif /* __SOF_LIB_MAILBOX_H__ */ diff --git a/src/platform/imx8m_cm7/include/platform/lib/memory.h b/src/platform/imx8m_cm7/include/platform/lib/memory.h new file mode 100644 index 000000000000..af0b0b823e24 --- /dev/null +++ b/src/platform/imx8m_cm7/include/platform/lib/memory.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 NXP + */ + +#ifdef __SOF_LIB_MEMORY_H__ + +#ifndef __PLATFORM_LIB_MEMORY_H__ +#define __PLATFORM_LIB_MEMORY_H__ + +#include <rtos/cache.h> + +#define PLATFORM_DCACHE_ALIGN DCACHE_LINE_SIZE + +#define SHARED_DATA + +#define uncache_to_cache(address) address +#define cache_to_uncache(address) address +#define cache_to_uncache_init(address) address +#define is_uncached(address) 0 + +/* no address translation required */ +#define host_to_local(addr) (addr) +#define local_to_host(addr) (addr) + +#define HEAPMEM_SIZE 0x00010000 + +/* WAKEUP domain MU1 side B */ +#define MU_BASE 0x30AB0000UL + +#endif /* __PLATFORM_LIB_MEMORY_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/memory.h" + +#endif /* __SOF_LIB_MEMORY_H__*/ diff --git a/src/platform/imx8m_cm7/include/platform/platform.h b/src/platform/imx8m_cm7/include/platform/platform.h new file mode 100644 index 000000000000..7d65624accda --- /dev/null +++ b/src/platform/imx8m_cm7/include/platform/platform.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 NXP + */ + +#ifdef __SOF_PLATFORM_H__ + +#ifndef __PLATFORM_PLATFORM_H__ +#define __PLATFORM_PLATFORM_H__ + +/* refers to M7 core clock - one core, one clock */ +#define PLATFORM_DEFAULT_CLOCK 0 + +#define HOST_PAGE_SIZE 4096 + +#define PLATFORM_PAGE_TABLE_SIZE 256 + +/* TODO: generous (SOF is usually used with 2 channels at most on i.MX + * platforms) and (potentially) not true. Can be adjusted later on if + * need be. + */ +#define PLATFORM_MAX_CHANNELS 4 +/* TODO: same as PLATFORM_MAX_CHANNELS */ +#define PLATFORM_MAX_STREAMS 5 + +/* WAKEUP domain MU7 side B */ +#define PLATFORM_IPC_INTERRUPT 97 + +#endif /* __PLATFORM_PLATFORM_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/platform.h" + +#endif /* __SOF_PLATFORM_H__ */ diff --git a/src/platform/imx8m_cm7/include/platform/trace/trace.h b/src/platform/imx8m_cm7/include/platform/trace/trace.h new file mode 100644 index 000000000000..3209ad9dc0ae --- /dev/null +++ b/src/platform/imx8m_cm7/include/platform/trace/trace.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 NXP + */ + +#ifdef __SOF_TRACE_TRACE_H__ + +#ifndef __PLATFORM_TRACE_TRACE_H__ +#define __PLATFORM_TRACE_TRACE_H__ + +/* TODO: remove me whenever possible */ + +#endif /* __PLATFORM_TRACE_TRACE_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/trace/trace.h" + +#endif /* __SOF_TRACE_TRACE_H__ */ diff --git a/src/platform/imx8m_cm7/lib/clk.c b/src/platform/imx8m_cm7/lib/clk.c new file mode 100644 index 000000000000..9c2bcd70f63f --- /dev/null +++ b/src/platform/imx8m_cm7/lib/clk.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright 2026 NXP + */ + +#include <rtos/clk.h> +#include <sof/lib/notifier.h> + +static const struct freq_table platform_cpu_freq[] = { + { + .freq = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, + .ticks_per_msec = CONFIG_SYS_CLOCK_TICKS_PER_SEC / 1000, + }, +}; + +static struct clock_info platform_clocks_info[NUM_CLOCKS]; + +void platform_clock_init(struct sof *sof) +{ + int i; + + sof->clocks = platform_clocks_info; + + for (i = 0; i < CONFIG_CORE_COUNT; i++) { + sof->clocks[i] = (struct clock_info) { + .freqs_num = NUM_CPU_FREQ, + .freqs = platform_cpu_freq, + .default_freq_idx = CPU_DEFAULT_IDX, + .current_freq_idx = CPU_DEFAULT_IDX, + .notification_id = NOTIFIER_ID_CPU_FREQ, + .notification_mask = NOTIFIER_TARGET_CORE_MASK(i), + .set_freq = NULL, + }; + } +} diff --git a/src/platform/imx8m_cm7/linker/data-sections.ld b/src/platform/imx8m_cm7/linker/data-sections.ld new file mode 100644 index 000000000000..3df5d5526577 --- /dev/null +++ b/src/platform/imx8m_cm7/linker/data-sections.ld @@ -0,0 +1,5 @@ +SECTION_PROLOGUE(.fw_metadata,,) +{ + KEEP (*(*.fw_metadata)) + . = ALIGN(16); +} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) diff --git a/src/platform/imx8m_cm7/platform.c b/src/platform/imx8m_cm7/platform.c new file mode 100644 index 000000000000..2da512f3063d --- /dev/null +++ b/src/platform/imx8m_cm7/platform.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright 2026 NXP + */ + +#include <rtos/sof.h> +#include <rtos/clk.h> +#include <sof/platform.h> +#include <sof/schedule/edf_schedule.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <sof/schedule/ll_schedule.h> +#include <sof/lib/dma.h> +#include <sof/lib/dai.h> +#include <sof/debug/debug.h> +#include <sof_versions.h> +#include <kernel/abi.h> +#include <kernel/ext_manifest.h> +#include <sof/drivers/mu.h> + +static const struct sof_ipc_fw_ready ready = { + .hdr = { + .cmd = SOF_IPC_FW_READY, + .size = sizeof(struct sof_ipc_fw_ready), + }, + .version = { + .hdr.size = sizeof(struct sof_ipc_fw_version), + .micro = SOF_MICRO, + .minor = SOF_MINOR, + .major = SOF_MAJOR, +#ifdef DEBUG_BUILD + .build = SOF_BUILD, + .date = __DATE__, + .time = __TIME__, +#endif + .tag = SOF_TAG, + .abi_version = SOF_ABI_VERSION, + .src_hash = SOF_SRC_HASH, + }, + .flags = DEBUG_SET_FW_READY_FLAGS, +}; + +const struct ext_man_windows windows + __aligned(EXT_MAN_ALIGN) __section(".fw_metadata") __unused = { + .hdr = { + .type = EXT_MAN_ELEM_WINDOW, + .elem_size = ALIGN_UP_COMPILE(sizeof(struct ext_man_windows), EXT_MAN_ALIGN), + }, + .window = { + .ext_hdr = { + .hdr.cmd = SOF_IPC_FW_READY, + .hdr.size = sizeof(struct sof_ipc_window), + .type = SOF_IPC_EXT_WINDOW, + }, + .num_windows = 3, + .window = { + { + .type = SOF_IPC_REGION_DOWNBOX, + .size = MAILBOX_HOSTBOX_SIZE, + .offset = MAILBOX_HOSTBOX_OFFSET, + }, + { + .type = SOF_IPC_REGION_UPBOX, + .size = MAILBOX_DSPBOX_SIZE, + .offset = MAILBOX_DSPBOX_OFFSET, + }, + { + .type = SOF_IPC_REGION_STREAM, + .size = MAILBOX_STREAM_SIZE, + .offset = MAILBOX_STREAM_OFFSET, + }, + }, + }, +}; + +int platform_boot_complete(uint32_t boot_message) +{ + mailbox_dspbox_write(0, &ready, sizeof(ready)); + + imx_mu_xcr_rmw(IMX_MU_VERSION, IMX_MU_GCR, + IMX_MU_xCR_GIRn(IMX_MU_VERSION, 1), 0); + + return 0; +} + +int platform_context_save(struct sof *sof) +{ + /* nothing to be done here */ + return 0; +} + +int platform_init(struct sof *sof) +{ + int ret; + + platform_clock_init(sof); + + scheduler_init_edf(); + + sof->platform_timer_domain = zephyr_domain_init(PLATFORM_DEFAULT_CLOCK); + zephyr_ll_scheduler_init(sof->platform_timer_domain); + + ret = dmac_init(sof); + if (ret < 0) + return ret; + + ipc_init(sof); + + dai_init(sof); + + return 0; +} diff --git a/src/platform/imx8ulp/include/platform/lib/memory.h b/src/platform/imx8ulp/include/platform/lib/memory.h index 00aa9b8b2a41..ee74e6989e86 100644 --- a/src/platform/imx8ulp/include/platform/lib/memory.h +++ b/src/platform/imx8ulp/include/platform/lib/memory.h @@ -195,11 +195,6 @@ void platform_init_memmap(struct sof *sof); #define cache_to_uncache_init(address) address #define is_uncached(address) 0 -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - /** * \brief Function for keeping shared data synchronized. * It's used after usage of data shared by different cores. diff --git a/src/platform/imx8ulp/lib/clk.c b/src/platform/imx8ulp/lib/clk.c index 29b8be6b7c6a..93a0a83ed54d 100644 --- a/src/platform/imx8ulp/lib/clk.c +++ b/src/platform/imx8ulp/lib/clk.c @@ -10,9 +10,7 @@ #include <sof/lib/notifier.h> #include <rtos/sof.h> -#ifdef __ZEPHYR__ #include <zephyr/sys/util.h> -#endif const struct freq_table platform_cpu_freq[] = { { 528000000, 528000 }, @@ -27,7 +25,7 @@ void platform_clock_init(struct sof *sof) { int i; - sof->clocks = platform_shared_get(platform_clocks_info, sizeof(platform_clocks_info)); + sof->clocks = platform_clocks_info; for (i = 0; i < CONFIG_CORE_COUNT; i++) { sof->clocks[i] = (struct clock_info) { diff --git a/src/platform/imx8ulp/lib/memory.c b/src/platform/imx8ulp/lib/memory.c index ac80bf55aae6..cafd4b5d3d0c 100644 --- a/src/platform/imx8ulp/lib/memory.c +++ b/src/platform/imx8ulp/lib/memory.c @@ -96,5 +96,5 @@ static SHARED_DATA struct mm memmap = { void platform_init_memmap(struct sof *sof) { /* memmap has been initialized statically as a part of .data */ - sof->memory_map = platform_shared_get(&memmap, sizeof(memmap)); + sof->memory_map = &memmap; } diff --git a/src/platform/imx8ulp/platform.c b/src/platform/imx8ulp/platform.c index a00889694f1a..88e6dfb8d56d 100644 --- a/src/platform/imx8ulp/platform.c +++ b/src/platform/imx8ulp/platform.c @@ -126,13 +126,6 @@ const struct ext_man_windows xsram_window } }; -#ifndef __ZEPHYR__ -static SHARED_DATA struct timer timer_shared = { - .id = TIMER0, /* internal timer */ - .irq = IRQ_NUM_TIMER0, -}; -#endif - int platform_boot_complete(uint32_t boot_message) { mailbox_dspbox_write(0, &ready, sizeof(ready)); @@ -153,11 +146,6 @@ int platform_init(struct sof *sof) { int ret; -#ifndef __ZEPHYR__ - sof->platform_timer = platform_shared_get(&timer_shared, sizeof(timer_shared)); - sof->cpu_timers = sof->platform_timer; -#endif - platform_interrupt_init(); platform_clock_init(sof); scheduler_init_edf(); @@ -167,9 +155,6 @@ int platform_init(struct sof *sof) timer_domain_init(sof->platform_timer, PLATFORM_DEFAULT_CLOCK); scheduler_init_ll(sof->platform_timer_domain); -#ifndef __ZEPHYR__ - platform_timer_start(sof->platform_timer); -#endif sa_init(sof, CONFIG_SYSTICK_PERIOD); clock_set_freq(CLK_CPU(cpu_get_id()), CLK_MAX_CPU_HZ); @@ -202,10 +187,3 @@ int platform_context_save(struct sof *sof) { return 0; } - -#ifndef __ZEPHYR__ -void platform_wait_for_interrupt(int level) -{ - arch_wait_for_interrupt(level); -} -#endif diff --git a/src/platform/imx93_a55/include/platform/lib/memory.h b/src/platform/imx93_a55/include/platform/lib/memory.h index 77ca3ec6103b..b9c84ff42a7f 100644 --- a/src/platform/imx93_a55/include/platform/lib/memory.h +++ b/src/platform/imx93_a55/include/platform/lib/memory.h @@ -58,11 +58,6 @@ /* WM8962 is connected to SAI3 */ #define SAI3_BASE 0x42660000 -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - #endif /* __PLATFORM_LIB_MEMORY_H__ */ #else diff --git a/src/platform/imx95/include/platform/lib/memory.h b/src/platform/imx95/include/platform/lib/memory.h index bf3ff05a5c69..552c20e32530 100644 --- a/src/platform/imx95/include/platform/lib/memory.h +++ b/src/platform/imx95/include/platform/lib/memory.h @@ -28,11 +28,6 @@ /* WAKEUP domain MU7 side B */ #define MU_BASE 0x42440000UL -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - #endif /* __PLATFORM_LIB_MEMORY_H__ */ #else diff --git a/src/platform/intel/ace/include/ace/lib/memory.h b/src/platform/intel/ace/include/ace/lib/memory.h index f021b18b00c9..f5740a7d659d 100644 --- a/src/platform/intel/ace/include/ace/lib/memory.h +++ b/src/platform/intel/ace/include/ace/lib/memory.h @@ -31,22 +31,7 @@ #define uncache_to_cache(address) sys_cache_cached_ptr_get(address) #define cache_to_uncache(address) sys_cache_uncached_ptr_get(address) -#define is_uncached(address) sys_cache_is_ptr_cached(address) - -/** - * \brief Returns pointer to the memory shared by multiple cores. - * \param[in,out] ptr Initial pointer to the allocated memory. - * \param[in] bytes Size of the allocated memory - * \return Appropriate pointer to the shared memory. - * - * This function is called only once right after allocation of shared memory. - * Platforms with uncached memory region should return aliased address. - * On platforms without such region simple invalidate is enough. - */ -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} +#define is_uncached(address) (!sys_cache_is_ptr_cached(address)) #endif /* __ACE_LIB_MEMORY_H__ */ diff --git a/src/platform/intel/ace/include/ace/version.h b/src/platform/intel/ace/include/ace/version.h index 1a1aa52381d7..c2df425307e6 100644 --- a/src/platform/intel/ace/include/ace/version.h +++ b/src/platform/intel/ace/include/ace/version.h @@ -11,6 +11,7 @@ #define ACE_VERSION_1_5 0x10500 /* MTL */ #define ACE_VERSION_2_0 0x20000 /* LNL */ #define ACE_VERSION_3_0 0x30000 /* PTL */ +#define ACE_VERSION_4_0 0x40000 /* NVL */ /* ACE version defined by CONFIG_ACE_VER_*/ #if defined(CONFIG_ACE_VERSION_1_5) @@ -19,6 +20,8 @@ #define ACE_VERSION ACE_VERSION_2_0 #elif defined(CONFIG_ACE_VERSION_3_0) #define ACE_VERSION ACE_VERSION_3_0 +#elif defined(CONFIG_ACE_VERSION_4_0) +#define ACE_VERSION ACE_VERSION_4_0 #endif #define HW_CFG_VERSION ACE_VERSION diff --git a/src/platform/intel/ace/lib/watchdog.c b/src/platform/intel/ace/lib/watchdog.c index dcae80da801d..a9efb2ae0b7e 100644 --- a/src/platform/intel/ace/lib/watchdog.c +++ b/src/platform/intel/ace/lib/watchdog.c @@ -5,6 +5,7 @@ * Author: Adrian Warecki <adrian.warecki@intel.com> */ +#include <sof/lib/memory.h> #include <sof/lib/uuid.h> #include <rtos/idc.h> #include <sof/schedule/ll_schedule_domain.h> @@ -72,7 +73,7 @@ static void watchdog_timeout(const struct device *dev, int core) watchdog_secondary_core_action_on_timeout(); } -void watchdog_init(void) +__cold void watchdog_init(void) { int i, ret; const struct wdt_timeout_cfg watchdog_config = { @@ -80,6 +81,8 @@ void watchdog_init(void) .callback = watchdog_timeout, }; + assert_can_be_cold(); + secondary_timeout_ipc.tx_data = NULL; secondary_timeout_ipc.tx_size = 0; list_init(&secondary_timeout_ipc.list); diff --git a/src/platform/intel/ace/platform.c b/src/platform/intel/ace/platform.c index 9e88861d9a97..f19003117e08 100644 --- a/src/platform/intel/ace/platform.c +++ b/src/platform/intel/ace/platform.c @@ -18,6 +18,7 @@ #include <sof/lib/cpu-clk-manager.h> #include <sof/schedule/edf_schedule.h> #include <sof/schedule/dp_schedule.h> +#include <sof/schedule/twb_schedule.h> #include <sof/schedule/ll_schedule.h> #include <sof/schedule/ll_schedule_domain.h> #include <sof/trace/trace.h> @@ -26,7 +27,9 @@ #include <kernel/abi.h> #include <rtos/clk.h> #include <sof/lib/cpu.h> - +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include "sof/audio/mic_privacy_manager.h" +#endif #include <sof_versions.h> #include <stdint.h> @@ -58,12 +61,15 @@ static const struct sof_ipc_fw_ready ready .flags = DEBUG_SET_FW_READY_FLAGS, }; -int platform_boot_complete(uint32_t boot_message) +__cold int platform_boot_complete(uint32_t boot_message) { struct ipc_cmd_hdr header; + assert_can_be_cold(); + /* get any IPC specific boot message and optional data */ ipc_boot_complete_msg(&header, 0); + header.pri |= boot_message; struct ipc_msg msg = { .header = header.pri, @@ -84,10 +90,12 @@ static struct pm_notifier pm_state_notifier = { #endif /* Runs on the primary core only */ -int platform_init(struct sof *sof) +__cold int platform_init(struct sof *sof) { int ret; + assert_can_be_cold(); + trace_point(TRACE_BOOT_PLATFORM_CLOCK); platform_clock_init(sof); @@ -115,6 +123,12 @@ int platform_init(struct sof *sof) return ret; #endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ +#if CONFIG_ZEPHYR_TWB_SCHEDULER + ret = scheduler_twb_init(); + if (ret < 0) + return ret; +#endif + /* init the system agent */ trace_point(TRACE_BOOT_PLATFORM_AGENT); sa_init(sof, CONFIG_SYSTICK_PERIOD); @@ -137,6 +151,13 @@ int platform_init(struct sof *sof) watchdog_init(); +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + /* Init mic privacy manager */ + ret = mic_privacy_manager_init(); + if (ret < 0) + return ret; +#endif + /* show heap status */ heap_trace_all(1); diff --git a/src/platform/intel/cavs/include/cavs/lib/memory.h b/src/platform/intel/cavs/include/cavs/lib/memory.h index b53c76d64b6d..0473131da6c8 100644 --- a/src/platform/intel/cavs/include/cavs/lib/memory.h +++ b/src/platform/intel/cavs/include/cavs/lib/memory.h @@ -75,26 +75,6 @@ static inline void *cache_to_uncache(void __sparse_cache *address) #define cache_to_uncache_init(address) address #endif -/** - * \brief Returns pointer to the memory shared by multiple cores. - * \param[in,out] ptr Initial pointer to the allocated memory. - * \param[in] bytes Size of the allocated memory - * \return Appropriate pointer to the shared memory. - * - * This function is called only once right after allocation of shared memory. - * Platforms with uncached memory region should return aliased address. - * On platforms without such region simple invalidate is enough. - */ -static inline void *platform_shared_get(void *ptr, int bytes) -{ -#if CONFIG_CORE_COUNT > 1 && !defined __ZEPHYR__ - dcache_invalidate_region((__sparse_force void __sparse_cache *)ptr, bytes); - return cache_to_uncache(ptr); -#else - return ptr; -#endif -} - /** * \brief Transforms pointer if necessary before freeing the memory. * \param[in,out] ptr Pointer to the allocated memory. diff --git a/src/platform/intel/cavs/platform.c b/src/platform/intel/cavs/platform.c index 366424bae1dd..8a1a7c59c3b5 100644 --- a/src/platform/intel/cavs/platform.c +++ b/src/platform/intel/cavs/platform.c @@ -107,9 +107,7 @@ int platform_boot_complete(uint32_t boot_message) return 0; } -static struct pm_notifier pm_state_notifier = { - .state_exit = cpu_notify_state_exit, -}; +static struct pm_notifier pm_state_notifier; /* Runs on the primary core only */ int platform_init(struct sof *sof) @@ -138,6 +136,7 @@ int platform_init(struct sof *sof) return ret; /* register power states exit notifiers */ + pm_state_notifier.state_exit = cpu_notify_state_exit; pm_notifier_register(&pm_state_notifier); /* initialize the host IPC mechanisms */ diff --git a/src/platform/library/include/platform/lib/memory.h b/src/platform/library/include/platform/lib/memory.h index fafb3df303f7..11f0114c1dde 100644 --- a/src/platform/library/include/platform/lib/memory.h +++ b/src/platform/library/include/platform/lib/memory.h @@ -37,11 +37,6 @@ uint8_t *get_library_mailbox(void); #define SHARED_DATA -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - void platform_init_memmap(struct sof *sof); static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/library/lib/alloc.c b/src/platform/library/lib/alloc.c index 48bfd50431ce..953267ab5265 100644 --- a/src/platform/library/lib/alloc.c +++ b/src/platform/library/lib/alloc.c @@ -16,12 +16,17 @@ /* testbench mem alloc definition */ -void *rmalloc(enum mem_zone zone, uint32_t flags, uint32_t caps, size_t bytes) +void *rmalloc_align(uint32_t flags, size_t bytes, uint32_t alignment) { return malloc(bytes); } -void *rzalloc(enum mem_zone zone, uint32_t flags, uint32_t caps, size_t bytes) +void *rmalloc(uint32_t flags, size_t bytes) +{ + return malloc(bytes); +} + +void *rzalloc(uint32_t flags, size_t bytes) { return calloc(bytes, 1); } @@ -31,16 +36,21 @@ void rfree(void *ptr) free(ptr); } -void *rballoc_align(uint32_t flags, uint32_t caps, size_t bytes, +void *rballoc_align(uint32_t flags, size_t bytes, uint32_t alignment) { return malloc(bytes); } -void *rbrealloc_align(void *ptr, uint32_t flags, uint32_t caps, size_t bytes, - size_t old_bytes, uint32_t alignment) +void *sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, + size_t alignment) +{ + return malloc(bytes); +} + +void sof_heap_free(struct k_heap *heap, void *addr) { - return realloc(ptr, bytes); + free(addr); } void heap_trace(struct mm_heap *heap, int size) @@ -54,3 +64,13 @@ void heap_trace_all(int force) { heap_trace(NULL, 0); } + +struct k_heap *sof_sys_heap_get(void) +{ + return NULL; +} + +struct k_heap *sof_sys_user_heap_get(void) +{ + return NULL; +} diff --git a/src/platform/library/lib/clk.c b/src/platform/library/lib/clk.c index 9098ec88fc48..aa7c86cd2f91 100644 --- a/src/platform/library/lib/clk.c +++ b/src/platform/library/lib/clk.c @@ -2,7 +2,6 @@ #include <rtos/clk.h> -#ifndef __ZEPHYR__ uint64_t clock_ms_to_ticks(int clock, uint64_t ms) { return 0; @@ -17,4 +16,3 @@ uint64_t clock_ns_to_ticks(int clock, uint64_t ns) { return 0; } -#endif /* __ZEPHYR__ */ diff --git a/src/platform/library/platform.c b/src/platform/library/platform.c index 8d54b1898d19..756c34c996f4 100644 --- a/src/platform/library/platform.c +++ b/src/platform/library/platform.c @@ -13,9 +13,7 @@ #include <sof/lib/mailbox.h> #include <sof/lib/dai.h> -#ifndef __ZEPHYR__ static SHARED_DATA struct timer timer = {}; -#endif /* __ZEPHYR__ */ static uint8_t mailbox[MAILBOX_DSPBOX_SIZE + MAILBOX_HOSTBOX_SIZE + @@ -38,10 +36,8 @@ int dmac_init(struct sof *sof) int platform_init(struct sof *sof) { -#ifndef __ZEPHYR__ sof->platform_timer = &timer; sof->cpu_timers = &timer; -#endif platform_clock_init(sof); @@ -70,17 +66,3 @@ int platform_context_save(struct sof *sof) { return 0; } - -#ifdef __ZEPHYR__ -/* Stubs for unsupported architectures */ - -/* Platform */ -int platform_boot_complete(uint32_t boot_message) -{ - return 0; -} - -/* Logging */ -LOG_MODULE_REGISTER(sof); - -#endif diff --git a/src/platform/library/schedule/schedule.c b/src/platform/library/schedule/schedule.c index b1dfcbb19445..f110711afe35 100644 --- a/src/platform/library/schedule/schedule.c +++ b/src/platform/library/schedule/schedule.c @@ -25,9 +25,29 @@ int schedule_task_init(struct task *task, uint16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags) { + struct schedulers *schedulers = *arch_schedulers_get(); + struct schedule_data *sch = NULL; + struct list_item *slist; + if (type >= SOF_SCHEDULE_COUNT) return -EINVAL; + if (!schedulers) + return -ENODEV; + + task->sch = NULL; + list_for_item(slist, &schedulers->list) { + sch = container_of(slist, struct schedule_data, list); + if (type == sch->type) { + task->sch = sch; + break; + } + } + + if (!task->sch) { + return -ENODEV; + } + task->uid = uid; task->type = type; task->priority = priority; diff --git a/src/platform/lunarlake/include/platform/lib/memory.h b/src/platform/lunarlake/include/platform/lib/memory.h index b5bda0ede464..276c61d17d58 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 0xF0000 +#define HEAPMEM_SIZE CONFIG_SOF_ZEPHYR_HEAP_SIZE #if CONFIG_COLD_STORE_EXECUTE_DRAM && \ (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE || !defined(LL_EXTENSION_BUILD)) diff --git a/src/platform/meteorlake/include/platform/lib/memory.h b/src/platform/meteorlake/include/platform/lib/memory.h index 76b60f98fabb..cd279b603c64 100644 --- a/src/platform/meteorlake/include/platform/lib/memory.h +++ b/src/platform/meteorlake/include/platform/lib/memory.h @@ -56,7 +56,7 @@ /** * size of HPSRAM system heap */ -#define HEAPMEM_SIZE 0xF0000 +#define HEAPMEM_SIZE CONFIG_SOF_ZEPHYR_HEAP_SIZE #if CONFIG_COLD_STORE_EXECUTE_DRAM && \ (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE || !defined(LL_EXTENSION_BUILD)) diff --git a/src/platform/mt8186/include/platform/lib/memory.h b/src/platform/mt8186/include/platform/lib/memory.h index 65148c9c348d..305e4c917846 100644 --- a/src/platform/mt8186/include/platform/lib/memory.h +++ b/src/platform/mt8186/include/platform/lib/memory.h @@ -192,11 +192,6 @@ struct sof; void platform_init_memmap(struct sof *sof); -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - #define uncache_to_cache(address) address #define cache_to_uncache(address) address #define cache_to_uncache_init(address) address diff --git a/src/platform/mt8186/lib/clk.c b/src/platform/mt8186/lib/clk.c index 555ab83c2a4f..6a5b2910c506 100644 --- a/src/platform/mt8186/lib/clk.c +++ b/src/platform/mt8186/lib/clk.c @@ -36,7 +36,7 @@ static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; static void clk_dsppll_enable(uint32_t value) { - tr_dbg(&clkdrv_tr, "clk_dsppll_enable: %d\n", value); + tr_dbg(&clkdrv_tr, "%d\n", value); switch (value) { case ADSP_CLK_PLL_300M: @@ -60,7 +60,7 @@ static void clk_dsppll_enable(uint32_t value) static void clk_dsppll_disable(void) { - tr_dbg(&clkdrv_tr, "clk_dsppll_disable\n"); + tr_dbg(&clkdrv_tr, "entry"); io_reg_update_bits(MTK_ADSPPLL_CON0, MTK_PLL_BASE_EN, 0); wait_delay_us(1); @@ -135,7 +135,7 @@ void platform_clock_init(struct sof *sof) { int i; - sof->clocks = platform_shared_get(platform_clocks_info, sizeof(platform_clocks_info)); + sof->clocks = platform_clocks_info; for (i = 0; i < CONFIG_CORE_COUNT; i++) { sof->clocks[i] = (struct clock_info){ diff --git a/src/platform/mt8186/lib/memory.c b/src/platform/mt8186/lib/memory.c index 2a01e0333bab..1ffc41859713 100644 --- a/src/platform/mt8186/lib/memory.c +++ b/src/platform/mt8186/lib/memory.c @@ -98,5 +98,5 @@ static SHARED_DATA struct mm memmap = { void platform_init_memmap(struct sof *sof) { /* memmap has been initialized statically as a part of .data */ - sof->memory_map = platform_shared_get(&memmap, sizeof(memmap)); + sof->memory_map = &memmap; } diff --git a/src/platform/mt8186/platform.c b/src/platform/mt8186/platform.c index f171e6cb7d0b..e08766eba70d 100644 --- a/src/platform/mt8186/platform.c +++ b/src/platform/mt8186/platform.c @@ -163,7 +163,7 @@ int platform_init(struct sof *sof) { int ret; - sof->platform_timer = platform_shared_get(&timer_shared, sizeof(timer_shared)); + sof->platform_timer = &timer_shared; sof->cpu_timers = sof->platform_timer; platform_interrupt_init(); diff --git a/src/platform/mt8188/include/platform/lib/memory.h b/src/platform/mt8188/include/platform/lib/memory.h index 65148c9c348d..305e4c917846 100644 --- a/src/platform/mt8188/include/platform/lib/memory.h +++ b/src/platform/mt8188/include/platform/lib/memory.h @@ -192,11 +192,6 @@ struct sof; void platform_init_memmap(struct sof *sof); -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - #define uncache_to_cache(address) address #define cache_to_uncache(address) address #define cache_to_uncache_init(address) address diff --git a/src/platform/mt8188/lib/clk.c b/src/platform/mt8188/lib/clk.c index d11b9fe2317b..bd97dad069a4 100644 --- a/src/platform/mt8188/lib/clk.c +++ b/src/platform/mt8188/lib/clk.c @@ -36,7 +36,7 @@ static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; static void clk_dsppll_enable(uint32_t value) { - tr_dbg(&clkdrv_tr, "clk_dsppll_enable %d\n", value); + tr_dbg(&clkdrv_tr, "%d\n", value); switch (value) { case ADSP_CLK_PLL_400M: @@ -60,7 +60,7 @@ static void clk_dsppll_enable(uint32_t value) static void clk_dsppll_disable(void) { - tr_dbg(&clkdrv_tr, "clk_dsppll_disable\n"); + tr_dbg(&clkdrv_tr, "entry"); io_reg_update_bits(MTK_ADSPPLL_CON0, MTK_PLL_EN, 0); wait_delay_us(1); @@ -123,7 +123,7 @@ void platform_clock_init(struct sof *sof) { int i; - sof->clocks = platform_shared_get(platform_clocks_info, sizeof(platform_clocks_info)); + sof->clocks = platform_clocks_info; for (i = 0; i < CONFIG_CORE_COUNT; i++) { sof->clocks[i] = (struct clock_info){ diff --git a/src/platform/mt8188/lib/memory.c b/src/platform/mt8188/lib/memory.c index 73d3af0f4d43..5ef0828ffc6c 100644 --- a/src/platform/mt8188/lib/memory.c +++ b/src/platform/mt8188/lib/memory.c @@ -98,5 +98,5 @@ static SHARED_DATA struct mm memmap = { void platform_init_memmap(struct sof *sof) { /* memmap has been initialized statically as a part of .data */ - sof->memory_map = platform_shared_get(&memmap, sizeof(memmap)); + sof->memory_map = &memmap; } diff --git a/src/platform/mt8188/platform.c b/src/platform/mt8188/platform.c index fc2e83dbed25..d3433a3b46c8 100644 --- a/src/platform/mt8188/platform.c +++ b/src/platform/mt8188/platform.c @@ -161,7 +161,7 @@ int platform_init(struct sof *sof) { int ret; - sof->platform_timer = platform_shared_get(&timer_shared, sizeof(timer_shared)); + sof->platform_timer = &timer_shared; sof->cpu_timers = sof->platform_timer; platform_interrupt_init(); diff --git a/src/platform/mt8195/include/platform/lib/memory.h b/src/platform/mt8195/include/platform/lib/memory.h index 42ee7f7990ab..7a93d36d1b2a 100644 --- a/src/platform/mt8195/include/platform/lib/memory.h +++ b/src/platform/mt8195/include/platform/lib/memory.h @@ -183,11 +183,6 @@ struct sof; void platform_init_memmap(struct sof *sof); -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - #define uncache_to_cache(address) address #define cache_to_uncache(address) address #define cache_to_uncache_init(address) address diff --git a/src/platform/mt8195/lib/clk.c b/src/platform/mt8195/lib/clk.c index 3f69c5e2d8f1..894396ab4855 100644 --- a/src/platform/mt8195/lib/clk.c +++ b/src/platform/mt8195/lib/clk.c @@ -77,7 +77,7 @@ static inline int dsp_clk_value_convert(int value) static void clk_dsppll_enable(void) { - tr_dbg(&clkdrv_tr, "clk_dsppll_enable\n"); + tr_dbg(&clkdrv_tr, "entry"); io_reg_update_bits(AUDIODSP_CK_CG, 0x1 << RG_AUDIODSP_SW_CG, 0x0); clk_setl(DSPPLL_CON4, PLL_PWR_ON); @@ -91,7 +91,7 @@ static void clk_dsppll_enable(void) static void clk_dsppll_disable(void) { - tr_dbg(&clkdrv_tr, "clk_dsppll_disable\n"); + tr_dbg(&clkdrv_tr, "entry"); clk_clrl(DSPPLL_CON0, PLL_EN); wait_delay_us(1); @@ -144,7 +144,7 @@ static int clock_platform_set_cpu_freq(int clock, int freq_idx) if (adsp_clock == adsp_clk_req) return 0; - tr_info(&clkdrv_tr, "clock_platform_set_cpu_freq %d\n", adsp_clk_req); + tr_info(&clkdrv_tr, "%d\n", adsp_clk_req); /* convert res manager value to driver map */ clk_mux = dsp_clk_value_convert(freq_idx); @@ -177,7 +177,7 @@ void platform_clock_init(struct sof *sof) { int i; - sof->clocks = platform_shared_get(platform_clocks_info, sizeof(platform_clocks_info)); + sof->clocks = platform_clocks_info; for (i = 0; i < CONFIG_CORE_COUNT; i++) { sof->clocks[i] = (struct clock_info){ diff --git a/src/platform/mt8195/lib/memory.c b/src/platform/mt8195/lib/memory.c index b2d545ff6f1d..c452a0520cc7 100644 --- a/src/platform/mt8195/lib/memory.c +++ b/src/platform/mt8195/lib/memory.c @@ -97,5 +97,5 @@ static SHARED_DATA struct mm memmap = { void platform_init_memmap(struct sof *sof) { /* memmap has been initialized statically as a part of .data */ - sof->memory_map = platform_shared_get(&memmap, sizeof(memmap)); + sof->memory_map = &memmap; } diff --git a/src/platform/mt8195/platform.c b/src/platform/mt8195/platform.c index 7e713290437d..6a08580ad043 100644 --- a/src/platform/mt8195/platform.c +++ b/src/platform/mt8195/platform.c @@ -182,7 +182,7 @@ int platform_init(struct sof *sof) { int ret; - sof->platform_timer = platform_shared_get(&timer_shared, sizeof(timer_shared)); + sof->platform_timer = &timer_shared; sof->cpu_timers = sof->platform_timer; platform_interrupt_init(); diff --git a/src/platform/mt8196/CMakeLists.txt b/src/platform/mt8196/CMakeLists.txt new file mode 100644 index 000000000000..f7a68fd4ea31 --- /dev/null +++ b/src/platform/mt8196/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_subdirectory(lib) + +add_local_sources(sof platform.c afe-platform.c) +target_include_directories(sof_options INTERFACE ${PROJECT_SOURCE_DIR}/src/platform/mt8196/include/arch) +target_include_directories(sof_options INTERFACE ${PROJECT_SOURCE_DIR}/src/platform/mt8196/include/platform) diff --git a/src/platform/mt8196/afe-platform.c b/src/platform/mt8196/afe-platform.c new file mode 100755 index 000000000000..3d9452772ba7 --- /dev/null +++ b/src/platform/mt8196/afe-platform.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Darren Ye <darren.ye@mediatek.com> + */ + +#include <sof/common.h> +#include <errno.h> +#include <sof/drivers/afe-drv.h> +#include <mt8196-afe-reg.h> +#include <mt8196-afe-common.h> + +/* + * AFE: Audio Front-End + * + * frontend (memif): + * memory interface + * UL (uplink for capture) + * DL (downlink for playback) + * backend: + * TDM In + * TDM Out + * DMIC + * GASRC + * I2S Out + * I2S In + * etc. + * interconn: + * inter-connection, + * connect frontends and backends as DSP path + */ + +static const struct mtk_base_memif_data memif_data[MT8196_MEMIF_NUM] = { + [MT8196_MEMIF_DL1] = { + .name = "DL1", + .id = MT8196_MEMIF_DL1, + .reg_ofs_base = AFE_DL1_BASE, + .reg_ofs_cur = AFE_DL1_CUR, + .reg_ofs_end = AFE_DL1_END, + .reg_ofs_base_msb = AFE_DL1_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL1_CUR_MSB, + .reg_ofs_end_msb = AFE_DL1_END_MSB, + .fs_reg = AFE_DL1_CON0, + .fs_shift = DL1_SEL_FS_SFT, + .fs_maskbit = DL1_SEL_FS_MASK, + .mono_reg = AFE_DL1_CON0, + .mono_shift = DL1_MONO_SFT, + .int_odd_flag_reg = -1, + .int_odd_flag_shift = 0, + .enable_reg = AFE_DL1_CON0, + .enable_shift = DL1_ON_SFT, + .hd_reg = AFE_DL1_CON0, + .hd_shift = DL1_HD_MODE_SFT, + .hd_align_reg = AFE_DL1_CON0, + .hd_align_mshift = DL1_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .ch_num_reg = -1, + .msb_reg = -1, + .msb_shift = -1, + .pbuf_reg = AFE_DL1_CON0, + .pbuf_mask = DL1_PBUF_SIZE_MASK, + .pbuf_shift = DL1_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL1_CON0, + .minlen_mask = DL1_MINLEN_MASK, + .minlen_shift = DL1_MINLEN_SFT, + }, + [MT8196_MEMIF_DL_24CH] = { + .name = "DL_24CH", + .id = MT8196_MEMIF_DL_24CH, + .reg_ofs_base = AFE_DL_24CH_BASE, + .reg_ofs_cur = AFE_DL_24CH_CUR, + .reg_ofs_end = AFE_DL_24CH_END, + .reg_ofs_base_msb = AFE_DL_24CH_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL_24CH_CUR_MSB, + .reg_ofs_end_msb = AFE_DL_24CH_END_MSB, + .fs_reg = AFE_DL_24CH_CON0, + .fs_shift = DL_24CH_SEL_FS_SFT, + .fs_maskbit = DL_24CH_SEL_FS_MASK, + .mono_reg = -1, + .mono_shift = -1, + .int_odd_flag_reg = -1, + .int_odd_flag_shift = 0, + .enable_reg = AFE_DL_24CH_CON0, + .enable_shift = DL_24CH_ON_SFT, + .hd_reg = AFE_DL_24CH_CON0, + .hd_shift = DL_24CH_HD_MODE_SFT, + .hd_align_reg = AFE_DL_24CH_CON0, + .hd_align_mshift = DL_24CH_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + .pbuf_reg = AFE_DL_24CH_CON0, + .pbuf_mask = DL_24CH_PBUF_SIZE_MASK, + .pbuf_shift = DL_24CH_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL_24CH_CON0, + .minlen_mask = DL_24CH_MINLEN_MASK, + .minlen_shift = DL_24CH_MINLEN_SFT, + .ch_num_reg = AFE_DL_24CH_CON0, + .ch_num_maskbit = DL_24CH_NUM_MASK, + .ch_num_shift = DL_24CH_NUM_SFT, + }, + [MT8196_MEMIF_UL0] = { + .name = "UL0", + .id = MT8196_MEMIF_UL0, + .reg_ofs_base = AFE_VUL0_BASE, + .reg_ofs_cur = AFE_VUL0_CUR, + .reg_ofs_end = AFE_VUL0_END, + .reg_ofs_base_msb = AFE_VUL0_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL0_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL0_END_MSB, + .fs_reg = AFE_VUL0_CON0, + .fs_shift = VUL0_SEL_FS_SFT, + .fs_maskbit = VUL0_SEL_FS_MASK, + .mono_reg = AFE_VUL0_CON0, + .mono_shift = VUL0_MONO_SFT, + .int_odd_flag_reg = -1, + .int_odd_flag_shift = 0, + .enable_reg = AFE_VUL0_CON0, + .enable_shift = VUL0_ON_SFT, + .hd_reg = AFE_VUL0_CON0, + .hd_shift = VUL0_HD_MODE_SFT, + .hd_align_reg = AFE_VUL0_CON0, + .hd_align_mshift = VUL0_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8196_MEMIF_UL1] = { + .name = "UL1", + .id = MT8196_MEMIF_UL1, + .reg_ofs_base = AFE_VUL1_BASE, + .reg_ofs_cur = AFE_VUL1_CUR, + .reg_ofs_end = AFE_VUL1_END, + .reg_ofs_base_msb = AFE_VUL1_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL1_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL1_END_MSB, + .fs_reg = AFE_VUL1_CON0, + .fs_shift = VUL1_SEL_FS_SFT, + .fs_maskbit = VUL1_SEL_FS_MASK, + .mono_reg = AFE_VUL1_CON0, + .mono_shift = VUL1_MONO_SFT, + .enable_reg = AFE_VUL1_CON0, + .enable_shift = VUL1_ON_SFT, + .hd_reg = AFE_VUL1_CON0, + .hd_shift = VUL1_HD_MODE_SFT, + .hd_align_reg = AFE_VUL1_CON0, + .hd_align_mshift = VUL1_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8196_MEMIF_UL2] = { + .name = "UL2", + .id = MT8196_MEMIF_UL2, + .reg_ofs_base = AFE_VUL2_BASE, + .reg_ofs_cur = AFE_VUL2_CUR, + .reg_ofs_end = AFE_VUL2_END, + .reg_ofs_base_msb = AFE_VUL2_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL2_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL2_END_MSB, + .fs_reg = AFE_VUL2_CON0, + .fs_shift = VUL2_SEL_FS_SFT, + .fs_maskbit = VUL2_SEL_FS_MASK, + .mono_reg = AFE_VUL2_CON0, + .mono_shift = VUL2_MONO_SFT, + .int_odd_flag_reg = -1, + .int_odd_flag_shift = 0, + .enable_reg = AFE_VUL2_CON0, + .enable_shift = VUL2_ON_SFT, + .hd_reg = AFE_VUL2_CON0, + .hd_shift = VUL2_HD_MODE_SFT, + .hd_align_reg = AFE_VUL2_CON0, + .hd_align_mshift = VUL2_HALIGN_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, +}; + +struct mt8196_afe_rate { + unsigned int rate; + unsigned int reg_value; +}; + +static const struct mt8196_afe_rate mt8196_afe_rates[] = { + { + .rate = 8000, + .reg_value = 0, + }, + { + .rate = 12000, + .reg_value = 2, + }, + { + .rate = 16000, + .reg_value = 4, + }, + { + .rate = 24000, + .reg_value = 6, + }, + { + .rate = 32000, + .reg_value = 8, + }, + { + .rate = 48000, + .reg_value = 0x0a, + }, + { + .rate = 96000, + .reg_value = 14, + }, + { + .rate = 192000, + .reg_value = 18, + }, + { + .rate = 384000, + .reg_value = 22, + }, + { + .rate = 11025, + .reg_value = 1, + }, + { + .rate = 22050, + .reg_value = 5, + }, + { + .rate = 44100, + .reg_value = 9, + }, + { + .rate = 88200, + .reg_value = 13, + }, + { + .rate = 176400, + .reg_value = 17, + }, + { + .rate = 352800, + .reg_value = 21, + }, +}; + +static unsigned int mt8196_afe_fs_timing(unsigned int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mt8196_afe_rates); i++) + if (mt8196_afe_rates[i].rate == rate) + return mt8196_afe_rates[i].reg_value; + + return -EINVAL; +} + +static unsigned int mt8196_afe_fs(unsigned int rate, int aud_blk) +{ + return mt8196_afe_fs_timing(rate); +} + +struct mtk_base_afe_platform mtk_afe_platform = { + .base_addr = AFE_BASE_ADDR, + .memif_datas = memif_data, + .memif_size = MT8196_MEMIF_NUM, + .memif_dl_num = MT8196_MEMIF_DL_NUM, + .memif_32bit_supported = 0, + .irq_datas = NULL, + .irqs_size = 0, + .dais_size = MT8196_DAI_NUM, + .afe_fs = mt8196_afe_fs, + .irq_fs = mt8196_afe_fs_timing, +}; diff --git a/src/platform/mt8196/include/arch/xtensa/config/core-isa.h b/src/platform/mt8196/include/arch/xtensa/config/core-isa.h new file mode 100644 index 000000000000..b0d7ed6a7c67 --- /dev/null +++ b/src/platform/mt8196/include/arch/xtensa/config/core-isa.h @@ -0,0 +1,831 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa + * processor CORE configuration + * + * See <xtensa/config/core.h>, which includes this file, for more details. + */ + +/* Xtensa processor core configuration information. + * + * Customer ID=7578; Build=0xa69ab; Copyright (c) 1999-2023 Tensilica 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. + */ + +#ifndef XTENSA_CORE_CONFIGURATION_H_ +#define XTENSA_CORE_CONFIGURATION_H_ + +/**************************************************************************** + * Parameters Useful for Any Code, USER or PRIVILEGED + **************************************************************************** + */ + +/* + * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + * configured, and a value of 0 otherwise. These macros are always defined. + */ + +/*---------------------------------------------------------------------- + * ISA + *---------------------------------------------------------------------- + */ + +#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED 1 /* windowed registers option */ +#define XCHAL_NUM_AREGS 64 /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2 6 /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE 16 /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG 1 /* debug option */ +#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS 1 /* zero-overhead loops */ +#define XCHAL_LOOP_BUFFER_SIZE 256 /* zero-ov. loop instr buffer size */ +#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX 1 /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT 1 /* SEXT instruction */ +#define XCHAL_HAVE_DEPBITS 0 /* DEPBITS instruction */ +#define XCHAL_HAVE_CLAMPS 1 /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32 1 /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_DIV32 1 /* QUOS/QUOU/REMS/REMU instructions */ +#define XCHAL_HAVE_L32R 1 /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS 0 /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_EXCLUSIVE 1 /* L32EX/S32EX instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12 1 /* (obsolete option) */ +#define XCHAL_HAVE_ABS 1 /* ABS instruction */ +#define XCHAL_HAVE_RELEASE_SYNC 1 /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I 0 /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION 0 /* speculation */ +#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS 1 /* */ +#define XCHAL_NUM_MISC_REGS 4 /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID 1 /* processor ID register */ +#define XCHAL_HAVE_EXTERN_REGS 1 /* WER/RER instructions */ +#define XCHAL_HAVE_MX 0 /* MX core (Tensilica internal) */ +#define XCHAL_HAVE_MP_INTERRUPTS 0 /* interrupt distributor port */ +#define XCHAL_HAVE_MP_RUNSTALL 0 /* core RunStall control port */ +#define XCHAL_HAVE_PSO 0 /* Power Shut-Off */ +#define XCHAL_HAVE_PSO_CDM 0 /* core/debug/mem pwr domains */ +#define XCHAL_HAVE_PSO_FULL_RETENTION 0 /* all regs preserved on PSO */ +#define XCHAL_HAVE_THREADPTR 1 /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS 1 /* boolean registers */ +#define XCHAL_HAVE_CP 1 /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG 2 /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16 0 /* MAC16 package */ +#define XCHAL_HAVE_LX 1 /* LX core */ +#define XCHAL_HAVE_NX 0 /* NX core (starting RH) */ +#define XCHAL_HAVE_RNX 0 /* RNX core (starting RJ) */ + +#define XCHAL_HAVE_SUPERGATHER 0 /* SuperGather */ + +#define XCHAL_HAVE_FUSION 0 /* Fusion */ +#define XCHAL_HAVE_FUSION_FP 0 /* Fusion FP option */ +#define XCHAL_HAVE_FUSION_LOW_POWER 0 /* Fusion Low Power option */ +#define XCHAL_HAVE_FUSION_AES 0 /* Fusion BLE/Wifi AES-128 CCM option */ +#define XCHAL_HAVE_FUSION_CONVENC 0 /* Fusion Conv Encode option */ +#define XCHAL_HAVE_FUSION_LFSR_CRC 0 /* Fusion LFSR-CRC option */ +#define XCHAL_HAVE_FUSION_BITOPS 0 /* Fusion Bit Operations Support option */ +#define XCHAL_HAVE_FUSION_AVS 0 /* Fusion AVS option */ +#define XCHAL_HAVE_FUSION_16BIT_BASEBAND 0 /* Fusion 16-bit Baseband option */ +#define XCHAL_HAVE_FUSION_VITERBI 0 /* Fusion Viterbi option */ +#define XCHAL_HAVE_FUSION_SOFTDEMAP 0 /* Fusion Soft Bit Demap option */ +#define XCHAL_HAVE_HIFIPRO 0 /* HiFiPro Audio Engine pkg */ +#define XCHAL_HAVE_HIFI5 1 /* HiFi5 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI5_NN_MAC 1 /* HiFi5 Audio Engine NN-MAC option */ + +/* HiFi5 Audio Engine Single--Precision VFPU option */ +#define XCHAL_HAVE_HIFI5_VFPU 1 +#define XCHAL_HAVE_HIFI5_HP_VFPU 1 /* HiFi5 Audio Engine Half-Precision VFPU option */ +#define XCHAL_HAVE_HIFI4 0 /* HiFi4 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI4_VFPU 1 /* HiFi4 Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI3 1 /* HiFi3 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI3_VFPU 1 /* HiFi3 Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI3Z 0 /* HiFi3Z Audio Engine pkg */ +#define XCHAL_HAVE_HIFI3Z_VFPU 0 /* HiFi3Z Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI1 0 /* HiFi1 */ +#define XCHAL_HAVE_HIFI1_VFPU 0 /* HiFi1 VFPU option */ +/* HiFi1 Low-latency MAC/FMA option */ +#define XCHAL_HAVE_HIFI1_LOW_LATENCY_MAC_FMA 0 +#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI2EP 0 /* HiFi2EP */ +#define XCHAL_HAVE_HIFI_MINI 0 + +#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */ +#define XCHAL_HAVE_USER_DPFPU 0 /* user DP floating-point pkg */ +#define XCHAL_HAVE_USER_SPFPU 1 /* user SP floating-point pkg */ +#define XCHAL_HAVE_FP 1 /* single prec floating point */ +#define XCHAL_HAVE_FP_DIV 1 /* FP with DIV instructions */ +#define XCHAL_HAVE_FP_RECIP 1 /* FP with RECIP instructions */ +#define XCHAL_HAVE_FP_SQRT 1 /* FP with SQRT instructions */ +#define XCHAL_HAVE_FP_RSQRT 1 /* FP with RSQRT instructions */ +#define XCHAL_HAVE_DFP 0 /* double precision FP pkg */ +#define XCHAL_HAVE_DFP_DIV 0 /* DFP with DIV instructions */ +#define XCHAL_HAVE_DFP_RECIP 0 /* DFP with RECIP instructions*/ +#define XCHAL_HAVE_DFP_SQRT 0 /* DFP with SQRT instructions */ +#define XCHAL_HAVE_DFP_RSQRT 0 /* DFP with RSQRT instructions*/ +#define XCHAL_HAVE_DFP_ACCEL 0 /* double precision FP acceleration pkg */ +#define XCHAL_HAVE_DFP_accel XCHAL_HAVE_DFP_ACCEL /* for backward compatibility */ + +#define XCHAL_HAVE_DFPU_SINGLE_ONLY 0 /* DFPU Coprocessor, single precision only */ +#define XCHAL_HAVE_DFPU_SINGLE_DOUBLE 0 /* DFPU Coprocessor, single and double precision */ +#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */ +#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */ + +#define XCHAL_HAVE_FUSIONG 0 /* FusionG */ +#define XCHAL_HAVE_FUSIONG3 0 /* FusionG3 */ +#define XCHAL_HAVE_FUSIONG6 0 /* FusionG6 */ +#define XCHAL_HAVE_FUSIONG_SP_VFPU 0 /* sp_vfpu option on FusionG */ +#define XCHAL_HAVE_FUSIONG_DP_VFPU 0 /* dp_vfpu option on FusionG */ +#define XCHAL_FUSIONG_SIMD32 0 /* simd32 for FusionG */ + +#define XCHAL_HAVE_FUSIONJ 0 /* FusionJ */ +#define XCHAL_HAVE_FUSIONJ6 0 /* FusionJ6 */ +#define XCHAL_HAVE_FUSIONJ_SP_VFPU 0 /* sp_vfpu option on FusionJ */ +#define XCHAL_HAVE_FUSIONJ_DP_VFPU 0 /* dp_vfpu option on FusionJ */ +#define XCHAL_FUSIONJ_SIMD32 0 /* simd32 for FusionJ */ + +#define XCHAL_HAVE_PDX 0 /* PDX-LX */ +#define XCHAL_PDX_SIMD32 0 /* simd32 for PDX */ +#define XCHAL_HAVE_PDX4 0 /* PDX4-LX */ +#define XCHAL_HAVE_PDX8 0 /* PDX8-LX */ +#define XCHAL_HAVE_PDX16 0 /* PDX16-LX */ +#define XCHAL_HAVE_PDXNX 0 /* PDX-NX */ + +#define XCHAL_HAVE_CONNXD2 0 /* ConnX D2 pkg */ +#define XCHAL_HAVE_CONNXD2_DUALLSFLIX 0 /* ConnX D2 & Dual LoadStore Flix */ +#define XCHAL_HAVE_BALL 0 +#define XCHAL_HAVE_BALLAP 0 +#define XCHAL_HAVE_BBE16 0 /* ConnX BBE16 pkg */ +#define XCHAL_HAVE_BBE16_RSQRT 0 /* BBE16 & vector recip sqrt */ +#define XCHAL_HAVE_BBE16_VECDIV 0 /* BBE16 & vector divide */ +#define XCHAL_HAVE_BBE16_DESPREAD 0 /* BBE16 & despread */ +#define XCHAL_HAVE_CONNX_B10 0 /* ConnX B10 pkg*/ +#define XCHAL_HAVE_CONNX_B20 0 /* ConnX B20 pkg*/ + +/* Double-precision Vector Floating-point option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_DP_VFPU 0 +/* Double-precision Vector Floating-point option on FP Machine*/ +#define XCHAL_HAVE_CONNX_B_DPX_VFPU 0 +/* Single-precision Vector Floating-point option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_SP_VFPU 0 +/* Single-precision Extended Vector Floating-point option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_SPX_VFPU 0 +/* Half-precision Vector Floating-point option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_HP_VFPU 0 +/* Half-precision Extended Vector Floating-point option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_HPX_VFPU 0 +/* 32-bit vector MAC (real and complex), FIR & FFT option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_32B_MAC 0 +#define XCHAL_HAVE_CONNX_B_VITERBI 0 /* Viterbi option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_TURBO 0 /* Turbo option on ConnX B10 & B20 */ +#define XCHAL_HAVE_CONNX_B_LDPC 0 /* LDPC option on ConnX B10 & B20 */ +#define XCHAL_HAVE_BBENEP 0 /* ConnX BBENEP pkgs */ +#define XCHAL_HAVE_BBENEP_SP_VFPU 0 /* sp_vfpu option on BBE-EP */ +#define XCHAL_HAVE_BSP3 0 /* ConnX BSP3 pkg */ +#define XCHAL_HAVE_BSP3_TRANSPOSE 0 /* BSP3 & transpose32x32 */ +#define XCHAL_HAVE_SSP16 0 /* ConnX SSP16 pkg */ +#define XCHAL_HAVE_SSP16_VITERBI 0 /* SSP16 & viterbi */ +#define XCHAL_HAVE_TURBO16 0 /* ConnX Turbo16 pkg */ +#define XCHAL_HAVE_BBP16 0 /* ConnX BBP16 pkg */ +#define XCHAL_HAVE_FLIX3 0 /* basic 3-way FLIX option */ +#define XCHAL_HAVE_GRIVPEP 0 /* General Release of IVPEP */ +#define XCHAL_HAVE_GRIVPEP_HISTOGRAM 0 /* Histogram option on GRIVPEP */ + +#define XCHAL_HAVE_VISION 0 /* Vision P5/P6 */ +#define XCHAL_VISION_SIMD16 0 /* simd16 for Vision P5/P6 */ +#define XCHAL_VISION_TYPE 0 /* Vision P5, P6, Q6, Q7 or Q8 */ +#define XCHAL_VISION_QUAD_MAC_TYPE 0 /* quad_mac option on Vision P6 */ +#define XCHAL_HAVE_VISION_HISTOGRAM 0 /* histogram option on Vision P5/P6 */ +#define XCHAL_HAVE_VISION_DP_VFPU 0 /* dp_vfpu option on Vision Q7/Q8 */ +#define XCHAL_HAVE_VISION_SP_VFPU 0 /* sp_vfpu option on Vision P5/P6/Q6/Q7 */ +#define XCHAL_HAVE_VISION_SP_VFPU_2XFMAC 0 /* sp_vfpu_2xfma option on Vision Q7 */ +#define XCHAL_HAVE_VISION_HP_VFPU 0 /* hp_vfpu option on Vision P6/Q6 */ +#define XCHAL_HAVE_VISION_HP_VFPU_2XFMAC 0 /* hp_vfpu_2xfma option on Vision Q7 */ + +#define XCHAL_HAVE_VISIONC 0 /* Vision C */ + +#define XCHAL_HAVE_XNNE 0 /* XNNE */ + +/*---------------------------------------------------------------------- + * MISC + *---------------------------------------------------------------------- + */ + +#define XCHAL_NUM_LOADSTORE_UNITS 2 /* load/store units */ +#define XCHAL_NUM_WRITEBUFFER_ENTRIES 32 /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH 16 /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH 16 /* data width in bytes */ + +/* d-side pipeline delay (1 = 5-stage, 2 = 7-stage) */ +#define XCHAL_DATA_PIPE_DELAY 2 +#define XCHAL_CLOCK_GATING_GLOBAL 1 /* global clock gating */ +#define XCHAL_CLOCK_GATING_FUNCUNIT 1 /* funct. unit clock gating */ +/* In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/ +#define XCHAL_UNALIGNED_LOAD_HW 0 /* unaligned loads work in hw */ +#define XCHAL_UNALIGNED_STORE_HW 0 /* unaligned stores work in hw*/ + +#define XCHAL_UNIFIED_LOADSTORE 0 + +#define XCHAL_SW_VERSION 1411000 /* sw version of this header */ +#define XCHAL_SW_VERSION_MAJOR 14000 /* major ver# of sw */ +#define XCHAL_SW_VERSION_MINOR 11 /* minor ver# of sw */ +#define XCHAL_SW_VERSION_MICRO 0 /* micro ver# of sw */ +#define XCHAL_SW_MINOR_VERSION 1411000 /* with zeroed micro */ +#define XCHAL_SW_MICRO_VERSION 1411000 + +/* alphanum core name (CoreID) set in the Xtensa Processor Generator */ +#define XCHAL_CORE_ID "HiFi5_MPU_lock_2023_11" + +#define XCHAL_BUILD_UNIQUE_ID 0x000A69AB /* 22-bit sw build ID */ + +/* + * These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0 0xC003B286 /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1 0x2A09D04B /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME "LX7.1.8" /* full version name */ +#define XCHAL_HW_VERSION_MAJOR 2810 /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR 8 /* minor ver# of targeted hw */ +#define XCHAL_HW_VERSION_MICRO 0 /* subdot ver# of targeted hw */ +/* major*100+(major<2810 ? minor : minor*10+micro) */ +#define XCHAL_HW_VERSION 281080 +#define XCHAL_HW_REL_LX7 1 +#define XCHAL_HW_REL_LX7_1 1 +#define XCHAL_HW_REL_LX7_1_8 1 +#define XCHAL_HW_CONFIGID_RELIABLE 1 +/* If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR 2810 /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR 8 /* minor v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MICRO 0 /* micro v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION 281080 /* earliest targeted hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR 2810 /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR 8 /* minor v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MICRO 0 /* micro v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION 281080 /* latest targeted hw */ + +/* Config is enabled for functional safety: */ +#define XCHAL_HAVE_FUNC_SAFETY 0 + +/* Config is enabled for secure operation: */ +#define XCHAL_HAVE_SECURE 0 + +#define XCHAL_HAVE_APB 0 + +/*---------------------------------------------------------------------- + * CACHE + *---------------------------------------------------------------------- + */ + +#define XCHAL_ICACHE_LINESIZE 128 /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE 128 /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH 7 /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH 7 /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE 65536 /* I-cache size in bytes or 0 */ +#define XCHAL_ICACHE_SIZE_LOG2 16 +#define XCHAL_DCACHE_SIZE 131072 /* D-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE_LOG2 17 + +#define XCHAL_DCACHE_IS_WRITEBACK 1 /* writeback feature */ +#define XCHAL_DCACHE_IS_COHERENT 0 /* MP coherence feature */ + +#define XCHAL_HAVE_PREFETCH 1 /* PREFCTL register */ +#define XCHAL_HAVE_PREFETCH_L1 1 /* prefetch to L1 cache */ +#define XCHAL_PREFETCH_CASTOUT_LINES 2 /* dcache pref. castout bufsz */ +#define XCHAL_PREFETCH_ENTRIES 16 /* cache prefetch entries */ +#define XCHAL_PREFETCH_BLOCK_ENTRIES 0 /* prefetch block streams */ +#define XCHAL_HAVE_CACHE_BLOCKOPS 0 /* block prefetch for caches */ +#define XCHAL_HAVE_CME_DOWNGRADES 0 +#define XCHAL_HAVE_ICACHE_TEST 1 /* Icache test instructions */ +#define XCHAL_HAVE_DCACHE_TEST 1 /* Dcache test instructions */ +#define XCHAL_HAVE_ICACHE_DYN_WAYS 1 /* Icache dynamic way support */ +#define XCHAL_HAVE_DCACHE_DYN_WAYS 1 /* Dcache dynamic way support */ +#define XCHAL_HAVE_ICACHE_DYN_ENABLE 1 /* Icache enabled via MEMCTL */ +#define XCHAL_HAVE_DCACHE_DYN_ENABLE 1 /* Dcache enabled via MEMCTL */ + +#define XCHAL_L1SCACHE_SIZE 0 +#define XCHAL_L1SCACHE_SIZE_LOG2 0 +#define XCHAL_L1SCACHE_WAYS 1 +#define XCHAL_L1SCACHE_WAYS_LOG2 0 +#define XCHAL_L1SCACHE_ACCESS_SIZE 0 +#define XCHAL_L1SCACHE_BANKS 1 + +#define XCHAL_L1VCACHE_SIZE 0 + +#define XCHAL_HAVE_L2 0 /* NX L2 cache controller */ +#define XCHAL_HAVE_L2_CACHE 0 +#define XCHAL_NUM_CORES_IN_CLUSTER 0 + +/* PRID_ID macros are for internal use only ... subject to removal */ +#define PRID_ID_SHIFT 0 +#define PRID_ID_BITS 4 +#define PRID_ID_MASK 0x0000000F + +/* This one is a form of caching, though not architecturally visible: */ +#define XCHAL_HAVE_BRANCH_PREDICTION 0 /* branch [target] prediction */ + +/**************************************************************************** + * Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- + * CACHE + *---------------------------------------------------------------------- + */ + +#define XCHAL_HAVE_PIF 1 /* any outbound bus present */ + +#define XCHAL_HAVE_AXI 1 /* AXI bus */ +#define XCHAL_HAVE_AXI_ECC 1 /* ECC on AXI bus */ +#define XCHAL_HAVE_ACELITE 0 /* ACELite bus */ + +#define XCHAL_HAVE_PIF_WR_RESP 1 /* pif write response */ +#define XCHAL_HAVE_PIF_REQ_ATTR 1 /* pif attribute */ + +/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */ + +/* Number of cache sets in log2(lines per way): */ +#define XCHAL_ICACHE_SETWIDTH 7 +#define XCHAL_DCACHE_SETWIDTH 8 + +/* Cache set associativity (number of ways): */ +#define XCHAL_ICACHE_WAYS 4 +#define XCHAL_ICACHE_WAYS_LOG2 2 +#define XCHAL_DCACHE_WAYS 4 +#define XCHAL_DCACHE_WAYS_LOG2 2 + +/* Cache features: */ +#define XCHAL_ICACHE_LINE_LOCKABLE 1 +#define XCHAL_DCACHE_LINE_LOCKABLE 1 +#define XCHAL_ICACHE_ECC_PARITY 0 +#define XCHAL_DCACHE_ECC_PARITY 0 +#define XCHAL_ICACHE_ECC_WIDTH 4 +#define XCHAL_DCACHE_ECC_WIDTH 1 + +/* Cache access size in bytes (affects operation of SICW instruction): */ +#define XCHAL_ICACHE_ACCESS_SIZE 16 +#define XCHAL_DCACHE_ACCESS_SIZE 16 + +#define XCHAL_DCACHE_BANKS 2 /* number of banks */ + +/* The number of Cache lines associated with a single cache tag */ +#define XCHAL_DCACHE_LINES_PER_TAG_LOG2 0 + +/* Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits): */ + +/* Extended memory attributes supported. */ +#define XCHAL_HAVE_EXT_CA 0 + +/*---------------------------------------------------------------------- + * INTERNAL I/D RAM/ROMs and XLMI + *---------------------------------------------------------------------- + */ +#define XCHAL_NUM_INSTROM 0 /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM 1 /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM 0 /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM 2 /* number of core data RAMs */ +#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI 0 /* number of core XLMI ports */ +#define XCHAL_HAVE_IRAMCFG 0 /* IRAMxCFG register present */ +#define XCHAL_HAVE_DRAMCFG 0 /* DRAMxCFG register present */ + +/* Instruction RAM 0: */ +#define XCHAL_INSTRAM0_VADDR 0x3FFF0000 /* virtual address */ +#define XCHAL_INSTRAM0_PADDR 0x3FFF0000 /* physical address */ +#define XCHAL_INSTRAM0_SIZE 262144 /* size in bytes */ +#define XCHAL_INSTRAM0_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_HAVE_INSTRAM0 1 +#define XCHAL_INSTRAM0_HAVE_IDMA 0 /* idma supported by this local memory */ + +/* Data RAM 0: */ +#define XCHAL_DATARAM0_VADDR 0x3FFE8000 /* virtual address */ +#define XCHAL_DATARAM0_PADDR 0x3FFE8000 /* physical address */ +#define XCHAL_DATARAM0_SIZE 65536 /* size in bytes */ +#define XCHAL_DATARAM0_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_DATARAM0_BANKS 2 /* number of banks */ +#define XCHAL_HAVE_DATARAM0 1 +#define XCHAL_DATARAM0_HAVE_IDMA 0 /* idma supported by this local memory */ + +/* Data RAM 1: */ +#define XCHAL_DATARAM1_VADDR 0x3FFE9000 /* virtual address */ +#define XCHAL_DATARAM1_PADDR 0x3FFE9000 /* physical address */ +#define XCHAL_DATARAM1_SIZE 131072 /* size in bytes */ +#define XCHAL_DATARAM1_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_DATARAM1_BANKS 2 /* number of banks */ +#define XCHAL_HAVE_DATARAM1 1 +#define XCHAL_DATARAM1_HAVE_IDMA 0 /* idma supported by this local memory */ + +#define XCHAL_HAVE_IMEM_LOADSTORE 1 /* can load/store to IROM/IRAM*/ + +/*---------------------------------------------------------------------- + * IDMA + *---------------------------------------------------------------------- + */ + +#define XCHAL_HAVE_IDMA 0 + +/*---------------------------------------------------------------------- + * INTERRUPTS and TIMERS + *---------------------------------------------------------------------- + */ + +#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */ +#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS 3 /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS 32 /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2 5 /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS 26 /* num of external interrupts */ +/* number of interrupt levels (not including level zero) */ +#define XCHAL_NUM_INTLEVELS 5 +#define XCHAL_INTERRUPT_RANGE 32 /* range of interrupt numbers */ + +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */ +#define XCHAL_EXCM_LEVEL 3 /* level masked by PS.EXCM */ + /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/* Masks of interrupts at each interrupt level: */ +#define XCHAL_INTLEVEL1_MASK 0x040000FF +#define XCHAL_INTLEVEL2_MASK 0xA800FF00 +#define XCHAL_INTLEVEL3_MASK 0x518F0000 +#define XCHAL_INTLEVEL4_MASK 0x00700000 +#define XCHAL_INTLEVEL5_MASK 0x00000000 +#define XCHAL_INTLEVEL6_MASK 0x02000000 +#define XCHAL_INTLEVEL7_MASK 0x00000000 + +/* Masks of interrupts at each range 1..n of interrupt levels: */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x040000FF +#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0xAC00FFFF +#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0xFD8FFFFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0xFDFFFFFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0xFDFFFFFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0xFFFFFFFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0xFFFFFFFF + +/* Level of each interrupt: */ +#define XCHAL_INT0_LEVEL 1 +#define XCHAL_INT1_LEVEL 1 +#define XCHAL_INT2_LEVEL 1 +#define XCHAL_INT3_LEVEL 1 +#define XCHAL_INT4_LEVEL 1 +#define XCHAL_INT5_LEVEL 1 +#define XCHAL_INT6_LEVEL 1 +#define XCHAL_INT7_LEVEL 1 +#define XCHAL_INT8_LEVEL 2 +#define XCHAL_INT9_LEVEL 2 +#define XCHAL_INT10_LEVEL 2 +#define XCHAL_INT11_LEVEL 2 +#define XCHAL_INT12_LEVEL 2 +#define XCHAL_INT13_LEVEL 2 +#define XCHAL_INT14_LEVEL 2 +#define XCHAL_INT15_LEVEL 2 +#define XCHAL_INT16_LEVEL 3 +#define XCHAL_INT17_LEVEL 3 +#define XCHAL_INT18_LEVEL 3 +#define XCHAL_INT19_LEVEL 3 +#define XCHAL_INT20_LEVEL 4 +#define XCHAL_INT21_LEVEL 4 +#define XCHAL_INT22_LEVEL 4 +#define XCHAL_INT23_LEVEL 3 +#define XCHAL_INT24_LEVEL 3 +#define XCHAL_INT25_LEVEL 6 +#define XCHAL_INT26_LEVEL 1 +#define XCHAL_INT27_LEVEL 2 +#define XCHAL_INT28_LEVEL 3 +#define XCHAL_INT29_LEVEL 2 +#define XCHAL_INT30_LEVEL 3 +#define XCHAL_INT31_LEVEL 2 +#define XCHAL_DEBUGLEVEL 5 /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */ +/* NMI "level" (for use with EXCSAVE/EPS/EPC_n, RFI n) */ +#define XCHAL_NMILEVEL 6 + +/* Type of each interrupt: */ +#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT7_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT10_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT11_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT13_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT14_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT15_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT16_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT17_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT18_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT19_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT20_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT21_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT22_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT23_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT24_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT25_TYPE XTHAL_INTTYPE_NMI +#define XCHAL_INT26_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT27_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT28_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT29_TYPE XTHAL_INTTYPE_PROFILING +#define XCHAL_INT30_TYPE XTHAL_INTTYPE_WRITE_ERROR +#define XCHAL_INT31_TYPE XTHAL_INTTYPE_SOFTWARE + +/* Masks of interrupts for each type of interrupt: */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0x00000000 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x007FFFFF +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x01800000 +#define XCHAL_INTTYPE_MASK_NMI 0x02000000 +#define XCHAL_INTTYPE_MASK_SOFTWARE 0x80000000 +#define XCHAL_INTTYPE_MASK_TIMER 0x1C000000 +#define XCHAL_INTTYPE_MASK_ETIE 0x00000000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x40000000 +#define XCHAL_INTTYPE_MASK_DBG_REQUEST 0x00000000 +#define XCHAL_INTTYPE_MASK_BREAKIN 0x00000000 +#define XCHAL_INTTYPE_MASK_TRAX 0x00000000 +#define XCHAL_INTTYPE_MASK_PROFILING 0x20000000 +#define XCHAL_INTTYPE_MASK_IDMA_DONE 0x00000000 +#define XCHAL_INTTYPE_MASK_IDMA_ERR 0x00000000 +#define XCHAL_INTTYPE_MASK_GS_ERR 0x00000000 +#define XCHAL_INTTYPE_MASK_L2_ERR 0x00000000 +#define XCHAL_INTTYPE_MASK_L2_STATUS 0x00000000 +#define XCHAL_INTTYPE_MASK_COR_ECC_ERR 0x00000000 +#define XCHAL_INTTYPE_MASK_WWDT 0x00000000 +#define XCHAL_INTTYPE_MASK_FXLK 0x00000000 + +/* Interrupt numbers assigned to specific interrupt sources: */ +#define XCHAL_TIMER0_INTERRUPT 26 /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT 27 /* CCOMPARE1 */ +#define XCHAL_TIMER2_INTERRUPT 28 /* CCOMPARE2 */ +#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_NMI_INTERRUPT 25 /* non-maskable interrupt */ +#define XCHAL_WRITE_ERROR_INTERRUPT 30 +#define XCHAL_PROFILING_INTERRUPT 29 + +/* Interrupt numbers for levels at which only one interrupt is configured: */ +#define XCHAL_INTLEVEL6_NUM 25 +/* (There are many interrupts each at level(s) 1, 2, 3, 4.) */ + +/* + * External interrupt mapping. + * These macros describe how Xtensa processor interrupt numbers + * (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + * map to external BInterrupt<n> pins, for those interrupts + * configured as external (level-triggered, edge-triggered, or NMI). + * See the Xtensa processor databook for more details. + */ + +/* Core interrupt numbers mapped to each EXTERNAL BInterrupt pin number: */ +#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */ +#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */ +#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM 6 /* (intlevel 1) */ +#define XCHAL_EXTINT7_NUM 7 /* (intlevel 1) */ +#define XCHAL_EXTINT8_NUM 8 /* (intlevel 2) */ +#define XCHAL_EXTINT9_NUM 9 /* (intlevel 2) */ +#define XCHAL_EXTINT10_NUM 10 /* (intlevel 2) */ +#define XCHAL_EXTINT11_NUM 11 /* (intlevel 2) */ +#define XCHAL_EXTINT12_NUM 12 /* (intlevel 2) */ +#define XCHAL_EXTINT13_NUM 13 /* (intlevel 2) */ +#define XCHAL_EXTINT14_NUM 14 /* (intlevel 2) */ +#define XCHAL_EXTINT15_NUM 15 /* (intlevel 2) */ +#define XCHAL_EXTINT16_NUM 16 /* (intlevel 3) */ +#define XCHAL_EXTINT17_NUM 17 /* (intlevel 3) */ +#define XCHAL_EXTINT18_NUM 18 /* (intlevel 3) */ +#define XCHAL_EXTINT19_NUM 19 /* (intlevel 3) */ +#define XCHAL_EXTINT20_NUM 20 /* (intlevel 4) */ +#define XCHAL_EXTINT21_NUM 21 /* (intlevel 4) */ +#define XCHAL_EXTINT22_NUM 22 /* (intlevel 4) */ +#define XCHAL_EXTINT23_NUM 23 /* (intlevel 3) */ +#define XCHAL_EXTINT24_NUM 24 /* (intlevel 3) */ +#define XCHAL_EXTINT25_NUM 25 /* (intlevel 6) */ +/* EXTERNAL BInterrupt pin numbers mapped to each core interrupt number: */ +#define XCHAL_INT0_EXTNUM 0 /* (intlevel 1) */ +#define XCHAL_INT1_EXTNUM 1 /* (intlevel 1) */ +#define XCHAL_INT2_EXTNUM 2 /* (intlevel 1) */ +#define XCHAL_INT3_EXTNUM 3 /* (intlevel 1) */ +#define XCHAL_INT4_EXTNUM 4 /* (intlevel 1) */ +#define XCHAL_INT5_EXTNUM 5 /* (intlevel 1) */ +#define XCHAL_INT6_EXTNUM 6 /* (intlevel 1) */ +#define XCHAL_INT7_EXTNUM 7 /* (intlevel 1) */ +#define XCHAL_INT8_EXTNUM 8 /* (intlevel 2) */ +#define XCHAL_INT9_EXTNUM 9 /* (intlevel 2) */ +#define XCHAL_INT10_EXTNUM 10 /* (intlevel 2) */ +#define XCHAL_INT11_EXTNUM 11 /* (intlevel 2) */ +#define XCHAL_INT12_EXTNUM 12 /* (intlevel 2) */ +#define XCHAL_INT13_EXTNUM 13 /* (intlevel 2) */ +#define XCHAL_INT14_EXTNUM 14 /* (intlevel 2) */ +#define XCHAL_INT15_EXTNUM 15 /* (intlevel 2) */ +#define XCHAL_INT16_EXTNUM 16 /* (intlevel 3) */ +#define XCHAL_INT17_EXTNUM 17 /* (intlevel 3) */ +#define XCHAL_INT18_EXTNUM 18 /* (intlevel 3) */ +#define XCHAL_INT19_EXTNUM 19 /* (intlevel 3) */ +#define XCHAL_INT20_EXTNUM 20 /* (intlevel 4) */ +#define XCHAL_INT21_EXTNUM 21 /* (intlevel 4) */ +#define XCHAL_INT22_EXTNUM 22 /* (intlevel 4) */ +#define XCHAL_INT23_EXTNUM 23 /* (intlevel 3) */ +#define XCHAL_INT24_EXTNUM 24 /* (intlevel 3) */ +#define XCHAL_INT25_EXTNUM 25 /* (intlevel 6) */ + +#define XCHAL_HAVE_ISB 0 /* No ISB */ +#define XCHAL_ISB_VADDR 0 /* N/A */ +#define XCHAL_HAVE_ITB 0 /* No ITB */ +#define XCHAL_ITB_VADDR 0 /* N/A */ + +#define XCHAL_HAVE_KSL 0 /* Kernel Stack Limit */ +#define XCHAL_HAVE_ISL 0 /* Interrupt Stack Limit */ +#define XCHAL_HAVE_PSL 0 /* Pageable Stack Limit */ + +/*---------------------------------------------------------------------- + * EXCEPTIONS and VECTORS + *---------------------------------------------------------------------- + */ + +/* Xtensa Exception Architecture + * number: 1 == XEA1 (until T1050) + * 2 == XEA2 (LX) + * 3 == XEA3 (NX) + * 0 == XEA5 (RNX) + */ +#define XCHAL_XEA_VERSION 2 +#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEA3 0 /* Exception Architecture 3 */ +#define XCHAL_HAVE_XEA5 0 /* Exception Architecture 5 */ +#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */ +#define XCHAL_HAVE_IMPRECISE_EXCEPTIONS 0 /* imprecise exception option */ +#define XCHAL_EXCCAUSE_NUM 64 /* Number of exceptions */ +#define XCHAL_HAVE_HALT 0 /* halt architecture option */ +#define XCHAL_HAVE_BOOTLOADER 0 /* boot loader (for TX) */ +#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */ +#define XCHAL_HAVE_VECTOR_SELECT 1 /* relocatable vectors */ +#define XCHAL_HAVE_VECBASE 1 /* relocatable vectors */ +#define XCHAL_VECBASE_RESET_VADDR 0x4e100400 /* VECBASE reset value */ +#define XCHAL_VECBASE_RESET_PADDR 0x4e100400 +#define XCHAL_RESET_VECBASE_OVERLAP 0 /* UNUSED */ + +#define XCHAL_RESET_VECTOR0_VADDR 0x4e100000 +#define XCHAL_RESET_VECTOR0_PADDR 0x4e100000 +#define XCHAL_RESET_VECTOR1_VADDR 0x4e100680 +#define XCHAL_RESET_VECTOR1_PADDR 0x4e100680 +#define XCHAL_RESET_VECTOR_VADDR XCHAL_RESET_VECTOR1_VADDR +#define XCHAL_RESET_VECTOR_PADDR XCHAL_RESET_VECTOR1_PADDR +#define XCHAL_USER_VECOFS 0x0000023C +#define XCHAL_USER_VECTOR_VADDR 0x4e10063C +#define XCHAL_USER_VECTOR_PADDR 0x4e10063C +#define XCHAL_KERNEL_VECOFS 0x0000021C +#define XCHAL_KERNEL_VECTOR_VADDR 0x4e10061C +#define XCHAL_KERNEL_VECTOR_PADDR 0x4e10061C +#define XCHAL_DOUBLEEXC_VECOFS 0x0000025C +#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x4e10065C +#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x4e10065C +#define XCHAL_WINDOW_OF4_VECOFS 0x00000000 +#define XCHAL_WINDOW_UF4_VECOFS 0x00000040 +#define XCHAL_WINDOW_OF8_VECOFS 0x00000080 +#define XCHAL_WINDOW_UF8_VECOFS 0x000000C0 +#define XCHAL_WINDOW_OF12_VECOFS 0x00000100 +#define XCHAL_WINDOW_UF12_VECOFS 0x00000140 +#define XCHAL_WINDOW_VECTORS_VADDR 0x4e100400 +#define XCHAL_WINDOW_VECTORS_PADDR 0x4e100400 +#define XCHAL_INTLEVEL2_VECOFS 0x0000017C +#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x4e10057C +#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x4e10057C +#define XCHAL_INTLEVEL3_VECOFS 0x0000019C +#define XCHAL_INTLEVEL3_VECTOR_VADDR 0x4e10059C +#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x4e10059C +#define XCHAL_INTLEVEL4_VECOFS 0x000001BC +#define XCHAL_INTLEVEL4_VECTOR_VADDR 0x4e1005BC +#define XCHAL_INTLEVEL4_VECTOR_PADDR 0x4e1005BC +#define XCHAL_INTLEVEL5_VECOFS 0x000001DC +#define XCHAL_INTLEVEL5_VECTOR_VADDR 0x4e1005DC +#define XCHAL_INTLEVEL5_VECTOR_PADDR 0x4e1005DC +#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL5_VECOFS +#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL5_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL5_VECTOR_PADDR +#define XCHAL_NMI_VECOFS 0x000001FC +#define XCHAL_NMI_VECTOR_VADDR 0x4e1005FC +#define XCHAL_NMI_VECTOR_PADDR 0x4e1005FC +#define XCHAL_INTLEVEL6_VECOFS XCHAL_NMI_VECOFS +#define XCHAL_INTLEVEL6_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR +#define XCHAL_INTLEVEL6_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR + +/*---------------------------------------------------------------------- + * DEBUG MODULE + *---------------------------------------------------------------------- + */ + +/* Misc */ +#define XCHAL_HAVE_DEBUG_ERI 1 /* ERI to debug module */ +#define XCHAL_HAVE_DEBUG_APB 1 /* APB to debug module */ +#define XCHAL_HAVE_DEBUG_JTAG 1 /* JTAG to debug module */ + +/* On-Chip Debug (OCD) */ +#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY 0 /* faster OCD option (to LX4) */ +#define XCHAL_HAVE_OCD_LS32DDR 1 /* L32DDR/S32DDR (faster OCD) */ + +/* TRAX (in core) */ +#define XCHAL_HAVE_TRAX 1 /* TRAX in debug module */ +#define XCHAL_TRAX_MEM_SIZE 4096 /* TRAX memory size in bytes */ +#define XCHAL_TRAX_MEM_SHAREABLE 1 /* start/end regs; ready sig. */ +#define XCHAL_TRAX_ATB_WIDTH 32 /* ATB width (bits), 0=no ATB */ +#define XCHAL_TRAX_TIME_WIDTH 64 /* timestamp bitwidth, 0=none */ + +/* Perf counters */ +#define XCHAL_NUM_PERF_COUNTERS 8 /* performance counters */ + +/*---------------------------------------------------------------------- + * MMU + *---------------------------------------------------------------------- + */ + +/* See core-matmap.h header file for more details. */ +#define XCHAL_HAVE_TLBS 0 /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY 0 /* one way maps I+D 4GB vaddr */ +#define XCHAL_HAVE_IDENTITY_MAP 1 /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR 0 /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */ +/* full MMU (with page table [autorefill] and protection) usable for an MMU-based OS */ +#define XCHAL_HAVE_PTP_MMU 0 + +/* If none of the above last 5 are set, it's a custom TLB configuration. */ + +#define XCHAL_MMU_ASID_BITS 0 /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS 1 /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS 0 /* num of bits in RING field */ + +/*---------------------------------------------------------------------- + * MPU + *---------------------------------------------------------------------- + */ +#define XCHAL_HAVE_MPU 1 +#define XCHAL_MPU_ENTRIES 32 +#define XCHAL_MPU_LOCK 1 + +/* MPU requires alignment of entries to background map */ +#define XCHAL_MPU_ALIGN_REQ 1 +#define XCHAL_MPU_BACKGROUND_ENTRIES 2 /* number of entries in bg map*/ +#define XCHAL_MPU_BG_CACHEADRDIS 0xFF /* default CACHEADRDIS for bg */ + +#define XCHAL_MPU_ALIGN_BITS 7 +#define XCHAL_MPU_ALIGN 128 + +/*----------------------------------------------------------------------- + * CSR Parity + *------------------------------------------------------------------------ + */ +#define XCHAL_HAVE_CSR_PARITY 0 + + +/*---------------------------------------------------------------------- + * FLEX-LOCK + *------------------------------------------------------------------------ + */ + +#define XCHAL_HAVE_FXLK 0 + +/*---------------------------------------------------------------------- + * WWDT (Windowed Watchdog Timer) + *------------------------------------------------------------------------ + */ +#define XCHAL_HAVE_WWDT 0 +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + +#endif /* XTENSA_CORE_CONFIGURATION_H_ */ + diff --git a/src/platform/mt8196/include/arch/xtensa/config/core-matmap.h b/src/platform/mt8196/include/arch/xtensa/config/core-matmap.h new file mode 100644 index 000000000000..a35a16752f8b --- /dev/null +++ b/src/platform/mt8196/include/arch/xtensa/config/core-matmap.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * xtensa/config/core-matmap.h -- Memory access and translation mapping + * parameters (CHAL) of the Xtensa processor core configuration. + * + * If you are using Xtensa Tools, see <xtensa/config/core.h> (which includes + * this file) for more details. + * + * In the Xtensa processor products released to date, all parameters + * defined in this file are derivable (at least in theory) from + * information contained in the core-isa.h header file. + * In particular, the following core configuration parameters are relevant: + * XCHAL_HAVE_CACHEATTR + * XCHAL_HAVE_MIMIC_CACHEATTR + * XCHAL_HAVE_XLT_CACHEATTR + * XCHAL_HAVE_PTP_MMU + * XCHAL_ITLB_ARF_ENTRIES_LOG2 + * XCHAL_DTLB_ARF_ENTRIES_LOG2 + * XCHAL_DCACHE_IS_WRITEBACK + * XCHAL_ICACHE_SIZE (presence of I-cache) + * XCHAL_DCACHE_SIZE (presence of D-cache) + * XCHAL_HW_VERSION_MAJOR + * XCHAL_HW_VERSION_MINOR + */ + +/* Customer ID=7578; Build=0xa69ab; Copyright (c) 1999-2023 Tensilica 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. + */ + +#ifndef XTENSA_CONFIG_CORE_MATMAP_H +#define XTENSA_CONFIG_CORE_MATMAP_H + +/*---------------------------------------------------------------------- + * CACHE (MEMORY ACCESS) ATTRIBUTES + *---------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------- + * MPU + *---------------------------------------------------------------------- + */ + +/* Mappings for legacy constants where appropriate */ + +#define XCHAL_CA_WRITEBACK (XTHAL_MEM_WRITEBACK | XTHAL_AR_RWXrwx) + +#define XCHAL_CA_WRITEBACK_NOALLOC (XTHAL_MEM_WRITEBACK_NOALLOC | XTHAL_AR_RWXrwx) + +#define XCHAL_CA_WRITETHRU (XTHAL_MEM_WRITETHRU | XTHAL_AR_RWXrwx) + +#define XCHAL_CA_ILLEGAL (XTHAL_AR_NONE | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASS (XTHAL_AR_RWXrwx | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASSBUF (XTHAL_AR_RWXrwx | XTHAL_MEM_DEVICE |\ +XTHAL_MEM_BUFFERABLE) +#define XCHAL_CA_BYPASS_RX (XTHAL_AR_RX | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASS_RW (XTHAL_AR_RW | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASS_R (XTHAL_AR_R | XTHAL_MEM_DEVICE) +#define XCHAL_HAVE_CA_WRITEBACK_NOALLOC 1 + +/* + * Contents of MPU background map. + * NOTE: caller must define the XCHAL_MPU_BGMAP() macro (not defined here + * but specified below) before expanding the XCHAL_MPU_BACKGROUND_MAP(s) macro. + * + * XCHAL_MPU_BGMAP(s, vaddr_start, vaddr_last, rights, memtype, x...) + * + * s = passed from XCHAL_MPU_BACKGROUND_MAP(s), eg. to select how to expand + * vaddr_start = first byte of region (always 0 for first entry) + * vaddr_end = last byte of region (always 0xFFFFFFFF for last entry) + * rights = access rights + * memtype = memory type + * x = reserved for future use (0 until then) + */ +/* parasoft-begin-suppress MISRA2012-RULE-20_7 "Macro use model requires s to not be in ()" */ +#define XCHAL_MPU_BACKGROUND_MAP(s) (\ +XCHAL_MPU_BGMAP(s, 0x00000000, 0x7fffffff, 7, 6, 0) \ +XCHAL_MPU_BGMAP(s, 0x80000000, 0xffffffff, 7, 6, 0) \) +/* parasoft-end-suppress MISRA2012-RULE-20_7 "Macro use model requires s to not be in ()" */ + +/* end */ + +#endif /*XTENSA_CONFIG_CORE_MATMAP_H*/ + diff --git a/src/platform/mt8196/include/arch/xtensa/config/defs.h b/src/platform/mt8196/include/arch/xtensa/config/defs.h new file mode 100644 index 000000000000..18ee59f671b3 --- /dev/null +++ b/src/platform/mt8196/include/arch/xtensa/config/defs.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Definitions for Xtensa instructions, types, and protos. */ + +/* Customer ID = 7578; Build = 0xa69ab; Copyright (c) 2003-2004 Tensilica 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. + */ + +/* NOTE: This file exists only for backward compatibility with T1050 + * and earlier Xtensa releases. It includes only a subset of the + * available header files. + */ + +#ifndef _XTENSA_BASE_HEADER +#define _XTENSA_BASE_HEADER + +#ifdef __XTENSA__ + +#include <xtensa/tie/xt_core.h> +#include <xtensa/tie/xt_misc.h> +#include <xtensa/tie/xt_booleans.h> + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_BASE_HEADER */ diff --git a/src/platform/mt8196/include/arch/xtensa/config/key.h b/src/platform/mt8196/include/arch/xtensa/config/key.h new file mode 100644 index 000000000000..61a1fa79ed1c --- /dev/null +++ b/src/platform/mt8196/include/arch/xtensa/config/key.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Customer ID = 7578; Build = 0xa69ab; Copyright (c) 2020-2021 by Cadence Design Systems. Inc. + * ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Cadence Design Systems Inc. + */ + +#ifndef TENSILICA_CONFIG_KEY +#define TENSILICA_CONFIG_KEY 1 + +#include <xtensa/xtensa-types.h> + +#endif + diff --git a/src/platform/mt8196/include/arch/xtensa/config/secure.h b/src/platform/mt8196/include/arch/xtensa/config/secure.h new file mode 100644 index 000000000000..8d46c3eb0257 --- /dev/null +++ b/src/platform/mt8196/include/arch/xtensa/config/secure.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Secure Mode defines. */ + +/* Customer ID = 7578; Build = 0xa69ab; Copyright (c) 2020 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. + */ + +#ifndef XTENSA_SECURE_H +#define XTENSA_SECURE_H + +/* SRAM */ +#define XCHAL_HAVE_SECURE_SRAM 0 + +/* INSTRAM0 */ +#define XCHAL_HAVE_SECURE_INSTRAM0 0 + +/* DATARAM1 */ +#define XCHAL_HAVE_SECURE_DATARAM1 0 + +/* DATARAM0 */ +#define XCHAL_HAVE_SECURE_DATARAM0 0 + +/* Array of all secure regions' start/size */ +#define XCHAL_SECURE_MEM_LIST \ +{ \ +} + +#endif /* XTENSA_SECURE_H */ + diff --git a/src/platform/mt8196/include/arch/xtensa/config/specreg.h b/src/platform/mt8196/include/arch/xtensa/config/specreg.h new file mode 100644 index 000000000000..e2ef5d4dd469 --- /dev/null +++ b/src/platform/mt8196/include/arch/xtensa/config/specreg.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Xtensa Special Register symbolic names + */ + +/* Id: + * //depot/rel/Homewood/ib.11/Xtensa/SWConfig/hal/specreg.h.tpp#1 + */ + +/* Customer ID = 7578; Build = 0xa69ab; Copyright (c) 1998-2002 Tensilica 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. + */ + +#ifndef XTENSA_SPECREG_H +#define XTENSA_SPECREG_H + +/* Include these special register bitfield definitions, for historical reasons: */ +#include <xtensa/corebits.h> + +/* Special registers: */ +#define LBEG 0 +#define LEND 1 +#define LCOUNT 2 +#define SAR 3 +#define BR 4 +#define PREFCTL 40 +#define WINDOWBASE 72 +#define WINDOWSTART 73 +#define MPUENB 90 +#define ERACCESS 95 +#define IBREAKENABLE 96 +#define MEMCTL 97 +#define CACHEADRDIS 98 +#define DDR 104 +#define IBREAKA_0 128 +#define IBREAKA_1 129 +#define DBREAKA_0 144 +#define DBREAKA_1 145 +#define DBREAKC_0 160 +#define DBREAKC_1 161 +#define EPC_1 177 +#define EPC_2 178 +#define EPC_3 179 +#define EPC_4 180 +#define EPC_5 181 +#define EPC_6 182 +#define DEPC 192 +#define EPS_2 194 +#define EPS_3 195 +#define EPS_4 196 +#define EPS_5 197 +#define EPS_6 198 +#define EXCSAVE_1 209 +#define EXCSAVE_2 210 +#define EXCSAVE_3 211 +#define EXCSAVE_4 212 +#define EXCSAVE_5 213 +#define EXCSAVE_6 214 +#define CPENABLE 224 +#define INTERRUPT 226 +#define INTCLEAR 227 +#define INTENABLE 228 +#define PS 230 +#define VECBASE 231 +#define EXCCAUSE 232 +#define DEBUGCAUSE 233 +#define CCOUNT 234 +#define PRID 235 +#define ICOUNT 236 +#define ICOUNTLEVEL 237 +#define EXCVADDR 238 +#define CCOMPARE_0 240 +#define CCOMPARE_1 241 +#define CCOMPARE_2 242 +#define MISC_REG_0 244 +#define MISC_REG_1 245 +#define MISC_REG_2 246 +#define MISC_REG_3 247 + +/* Special cases (bases of special register series): */ +#define IBREAKA 128 +#define DBREAKA 144 +#define DBREAKC 160 +#define EPC 176 +#define EPS 192 +#define EXCSAVE 208 +#define CCOMPARE 240 + +/* Special names for read-only and write-only interrupt registers: */ +#define INTREAD 226 +#define INTSET 226 + +#endif /* XTENSA_SPECREG_H */ + diff --git a/src/platform/mt8196/include/arch/xtensa/config/system.h b/src/platform/mt8196/include/arch/xtensa/config/system.h new file mode 100644 index 000000000000..77b6a105f71f --- /dev/null +++ b/src/platform/mt8196/include/arch/xtensa/config/system.h @@ -0,0 +1,293 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * xtensa/config/system.h -- HAL definitions that are dependent on SYSTEM configuration + * + * NOTE: The location and contents of this file are highly subject to change. + * + * Source for configuration-independent binaries (which link in a + * configuration-specific HAL library) must NEVER include this file. + * The HAL itself has historically included this file in some instances, + * but this is not appropriate either, because the HAL is meant to be + * core-specific but system independent. + */ + +/* Customer ID = 7578; Build = 0xa69ab; Copyright (c) 2000-2010 Tensilica 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. + */ + +#ifndef XTENSA_CONFIG_SYSTEM_H +#define XTENSA_CONFIG_SYSTEM_H + +/*---------------------------------------------------------------------- + * CONFIGURED SOFTWARE OPTIONS + *---------------------------------------------------------------------- + */ + +/* (sw-only option, whether software uses absolute literals) */ +#define XSHAL_USE_ABSOLUTE_LITERALS 0 +/* Set if there is some memory that allows both code and literals. */ +#define XSHAL_HAVE_TEXT_SECTION_LITERALS 1 + +/* (sw-only option, selected ABI) */ +#define XSHAL_ABI XTHAL_ABI_WINDOWED +/* The above maps to one of the following constants: */ +#define XTHAL_ABI_WINDOWED 0 +#define XTHAL_ABI_CALL0 1 + +/* (sw-only option, selected C library) */ +#define XSHAL_CLIB XTHAL_CLIB_XCLIB +/* The above maps to one of the following constants: */ +#define XTHAL_CLIB_NEWLIB 0 +#define XTHAL_CLIB_UCLIBC 1 +#define XTHAL_CLIB_XCLIB 2 + +#define XSHAL_USE_FLOATING_POINT 1 + +#define XSHAL_FLOATING_POINT_ABI 1 + +/* SW workarounds enabled for HW errata: */ + +/*---------------------------------------------------------------------- + * DEVICE ADDRESSES + *---------------------------------------------------------------------- + */ + +/* + * Strange place to find these, but the configuration GUI + * allows moving these around to account for various core + * configurations. Specific boards (and their BSP software) + * will have specific meanings for these components. + */ + +/* I/O Block areas: */ +#define XSHAL_IOBLOCK_CACHED_VADDR 0x70000000 +#define XSHAL_IOBLOCK_CACHED_PADDR 0x70000000 +#define XSHAL_IOBLOCK_CACHED_SIZE 0x0E000000 + +#define XSHAL_IOBLOCK_BYPASS_VADDR 0x90000000 +#define XSHAL_IOBLOCK_BYPASS_PADDR 0x90000000 +#define XSHAL_IOBLOCK_BYPASS_SIZE 0x0E000000 + +/* System ROM: */ + +/* System RAM: */ +#define XSHAL_RAM_VADDR 0x40000000 +#define XSHAL_RAM_PADDR 0x40000000 +#define XSHAL_RAM_VSIZE 0x80000000 +#define XSHAL_RAM_PSIZE 0x80000000 +#define XSHAL_RAM_SIZE XSHAL_RAM_PSIZE +/* Largest available area (free of vectors): */ +#define XSHAL_RAM_AVAIL_VADDR 0x50000000 +#define XSHAL_RAM_AVAIL_VSIZE 0x80000000 + +/* + * Shadow system RAM (same device as system RAM, at different address). + * (Emulation boards need this for the SONIC Ethernet driver + * when data caches are configured for writeback mode.) + * NOTE: on full MMU configs, this points to the BYPASS virtual address + * of system RAM, ie. is the same as XSHAL_RAM_* except that virtual + * addresses are viewed through the BYPASS static map rather than + * the CACHED static map. + */ +#define XSHAL_RAM_BYPASS_VADDR 0x20000000 +#define XSHAL_RAM_BYPASS_PADDR 0x20000000 +#define XSHAL_RAM_BYPASS_PSIZE 0x20000000 + +/* Alternate system RAM (different device than system RAM): */ + +/* Some available location in which to place devices in a simulation (eg. XTMP): */ +#define XSHAL_SIMIO_CACHED_VADDR 0x20000000 +#define XSHAL_SIMIO_BYPASS_VADDR 0x20000000 +#define XSHAL_SIMIO_PADDR 0x20000000 +#define XSHAL_SIMIO_SIZE 0x20000000 + +/*---------------------------------------------------------------------- + * For use by reference testbench exit and diagnostic routines. + *---------------------------------------------------------------------- + */ +#define XSHAL_MAGIC_EXIT 0xdeeeb400 +#define XSHAL_STL_INFO_LOCATION 0xfffffffc + +/*---------------------------------------------------------------------- + * DEVICE-ADDRESS DEPENDENT... + * + * Values written to CACHEATTR special register (or its equivalent) + * to enable and disable caches in various modes. + *---------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------- + * BACKWARD COMPATIBILITY ... + *---------------------------------------------------------------------- + */ + +/* + * NOTE: the following two macros are DEPRECATED. Use the latter + * board-specific macros instead, which are specially tuned for the + * particular target environments' memory maps. + */ +/* disable caches in bypass mode */ +#define XSHAL_CACHEATTR_BYPASS XSHAL_XT2000_CACHEATTR_BYPASS +/* default setting to enable caches (no writeback!) */ +#define XSHAL_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_DEFAULT + +/*---------------------------------------------------------------------- + * GENERIC + *---------------------------------------------------------------------- + */ + +/* For the following, a 512MB region is used if it contains a system (PIF) RAM, + * system (PIF) ROM, local memory, or XLMI. + */ + +/* These set any unused 512MB region to cache-BYPASS attribute: */ +/* enable caches in write-back mode */ +#define XSHAL_ALLVALID_CACHEATTR_WRITEBACK 0x24444422 +/* enable caches in write-allocate mode */ +#define XSHAL_ALLVALID_CACHEATTR_WRITEALLOC 0x21111122 +/* enable caches in write-through mode */ +#define XSHAL_ALLVALID_CACHEATTR_WRITETHRU 0x21111122 +/* disable caches in bypass mode */ +#define XSHAL_ALLVALID_CACHEATTR_BYPASS 0x22222222 +/* default setting to enable caches */ +#define XSHAL_ALLVALID_CACHEATTR_DEFAULT XSHAL_ALLVALID_CACHEATTR_WRITEBACK + +/* These set any unused 512MB region to ILLEGAL attribute: */ +/* enable caches in write-back mode */ +#define XSHAL_STRICT_CACHEATTR_WRITEBACK 0xF44444FF +/* enable caches in write-allocate mode */ +#define XSHAL_STRICT_CACHEATTR_WRITEALLOC 0xF11111FF +/* enable caches in write-through mode */ +#define XSHAL_STRICT_CACHEATTR_WRITETHRU 0xF11111FF +/* disable caches in bypass mode */ +#define XSHAL_STRICT_CACHEATTR_BYPASS 0xF22222FF +/* default setting to enable caches */ +#define XSHAL_STRICT_CACHEATTR_DEFAULT XSHAL_STRICT_CACHEATTR_WRITEBACK + +/* These set the first 512MB, if unused, to ILLEGAL attribute to help catch + * NULL-pointer dereference bugs; all other unused 512MB regions are set + * to cache-BYPASS attribute: + */ +/* enable caches in write-back mode */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITEBACK 0x2444442F +/* enable caches in write-allocate mode */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITEALLOC 0x2111112F +/* enable caches in write-through mode */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITETHRU 0x2111112F +/* disable caches in bypass mode */ +#define XSHAL_TRAPNULL_CACHEATTR_BYPASS 0x2222222F +/* default setting to enable caches */ +#define XSHAL_TRAPNULL_CACHEATTR_DEFAULT XSHAL_TRAPNULL_CACHEATTR_WRITEBACK + +/*---------------------------------------------------------------------- + *ISS (Instruction Set Simulator) SPECIFIC ... + *---------------------------------------------------------------------- + */ + +/* For now, ISS defaults to the TRAPNULL settings: */ +#define XSHAL_ISS_CACHEATTR_WRITEBACK XSHAL_TRAPNULL_CACHEATTR_WRITEBACK +#define XSHAL_ISS_CACHEATTR_WRITEALLOC XSHAL_TRAPNULL_CACHEATTR_WRITEALLOC +#define XSHAL_ISS_CACHEATTR_WRITETHRU XSHAL_TRAPNULL_CACHEATTR_WRITETHRU +#define XSHAL_ISS_CACHEATTR_BYPASS XSHAL_TRAPNULL_CACHEATTR_BYPASS +#define XSHAL_ISS_CACHEATTR_DEFAULT XSHAL_TRAPNULL_CACHEATTR_WRITEBACK + +#define XSHAL_ISS_PIPE_REGIONS 0 +#define XSHAL_ISS_SDRAM_REGIONS 0 + +/*---------------------------------------------------------------------- + * XT2000 BOARD SPECIFIC ... + *---------------------------------------------------------------------- + */ + +/* For the following, a 512MB region is used if it contains any system RAM, + * system ROM, local memory, XLMI, or other XT2000 board device or memory. + * Regions containing devices are forced to cache-BYPASS mode regardless + * of whether the macro is _WRITEBACK vs. _BYPASS etc. + */ + +/* These set any 512MB region unused on the XT2000 to ILLEGAL attribute: */ +/* enable caches in write-back mode */ +#define XSHAL_XT2000_CACHEATTR_WRITEBACK 0xF442442F +/* enable caches in write-allocate mode */ +#define XSHAL_XT2000_CACHEATTR_WRITEALLOC 0xF112112F +/* enable caches in write-through mode */ +#define XSHAL_XT2000_CACHEATTR_WRITETHRU 0xF112112F +/* disable caches in bypass mode */ +#define XSHAL_XT2000_CACHEATTR_BYPASS 0xF222222F +/* default setting to enable caches */ +#define XSHAL_XT2000_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_WRITEBACK + +#define XSHAL_XT2000_PIPE_REGIONS 0x00000000 /* BusInt pipeline regions */ +#define XSHAL_XT2000_SDRAM_REGIONS 0x00000024 /* BusInt SDRAM regions */ + +/*---------------------------------------------------------------------- + * VECTOR INFO AND SIZES + *---------------------------------------------------------------------- + */ + +#define XSHAL_VECTORS_PACKED 0 /* UNUSED */ +#define XSHAL_STATIC_VECTOR_SELECT 1 +#define XSHAL_RESET_VECTOR_VADDR 0x4e100680 +#define XSHAL_RESET_VECTOR_PADDR 0x4e100680 + +/* + * Sizes allocated to vectors by the system (memory map) configuration. + * These sizes are constrained by core configuration (eg. one vector's + * code cannot overflow into another vector) but are dependent on the + * system or board (or LSP) memory map configuration. + * + * Whether or not each vector happens to be in a system ROM is also + * a system configuration matter, sometimes useful, included here also: + */ +#define XSHAL_RESET_VECTOR_SIZE 0x000002E0 +#define XSHAL_RESET_VECTOR_ISROM 0 +#define XSHAL_USER_VECTOR_SIZE 0x0000001C +#define XSHAL_USER_VECTOR_ISROM 0 +/* for backward compatibility */ +#define XSHAL_PROGRAMEXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE +/* for backward compatibility */ +#define XSHAL_USEREXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE +#define XSHAL_KERNEL_VECTOR_SIZE 0x0000001C +#define XSHAL_KERNEL_VECTOR_ISROM 0 +/* for backward compatibility */ +#define XSHAL_STACKEDEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE +/* for backward compatibility */ +#define XSHAL_KERNELEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE +#define XSHAL_DOUBLEEXC_VECTOR_SIZE 0x0000001C +#define XSHAL_DOUBLEEXC_VECTOR_ISROM 0 +#define XSHAL_WINDOW_VECTORS_SIZE 0x00000178 +#define XSHAL_WINDOW_VECTORS_ISROM 0 +#define XSHAL_INTLEVEL2_VECTOR_SIZE 0x0000001C +#define XSHAL_INTLEVEL2_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL3_VECTOR_SIZE 0x0000001C +#define XSHAL_INTLEVEL3_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL4_VECTOR_SIZE 0x0000001C +#define XSHAL_INTLEVEL4_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL5_VECTOR_SIZE 0x0000001C +#define XSHAL_INTLEVEL5_VECTOR_ISROM 0 +#define XSHAL_DEBUG_VECTOR_SIZE XSHAL_INTLEVEL5_VECTOR_SIZE +#define XSHAL_DEBUG_VECTOR_ISROM XSHAL_INTLEVEL5_VECTOR_ISROM +#define XSHAL_NMI_VECTOR_SIZE 0x0000001C +#define XSHAL_NMI_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL6_VECTOR_SIZE XSHAL_NMI_VECTOR_SIZE + +#endif /*XTENSA_CONFIG_SYSTEM_H*/ + diff --git a/src/platform/mt8196/include/arch/xtensa/config/tie-asm.h b/src/platform/mt8196/include/arch/xtensa/config/tie-asm.h new file mode 100644 index 000000000000..ebef0818d327 --- /dev/null +++ b/src/platform/mt8196/include/arch/xtensa/config/tie-asm.h @@ -0,0 +1,362 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * tie-asm.h -- compile-time HAL assembler definitions dependent on CORE & TIE + * + * NOTE: This header file is not meant to be included directly. + */ + +/* This header file contains assembly-language definitions (assembly + * macros, etc.) for this specific Xtensa processor's TIE extensions + * and options. It is customized to this Xtensa processor configuration. + * + * Customer ID = 7578; Build = 0xa69ab; Copyright (c) 1999-2023 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. + */ + +#ifndef _XTENSA_CORE_TIE_ASM_H +#define _XTENSA_CORE_TIE_ASM_H + +#include <xtensa/coreasm.h> + +/* Selection parameter values for save-area save/restore macros: */ +/* Option vs. TIE: */ +#define XTHAL_SAS_TIE 0x0001 /* custom extension or coprocessor */ +#define XTHAL_SAS_OPT 0x0002 /* optional (and not a coprocessor) */ +#define XTHAL_SAS_ANYOT 0x0003 /* both of the above */ +/* Whether used automatically by compiler: */ +#define XTHAL_SAS_NOCC 0x0004 /* not used by compiler w/o special opts/code */ +#define XTHAL_SAS_CC 0x0008 /* used by compiler without special opts/code */ +#define XTHAL_SAS_ANYCC 0x000C /* both of the above */ +/* ABI handling across function calls: */ +#define XTHAL_SAS_CALR 0x0010 /* caller-saved */ +#define XTHAL_SAS_CALE 0x0020 /* callee-saved */ +#define XTHAL_SAS_GLOB 0x0040 /* global across function calls (in thread) */ +#define XTHAL_SAS_ANYABI 0x0070 /* all of the above three */ +/* Misc */ +#define XTHAL_SAS_ALL 0xFFFF /* include all default NCP contents */ +#define XTHAL_SAS3(optie, ccuse, abi) (((optie) & XTHAL_SAS_ANYOT) \ +| ((ccuse) & XTHAL_SAS_ANYCC) \ +| ((abi) & XTHAL_SAS_ANYABI)) + +/* + * Macro to store all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 4 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_NCP_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters: + * continue If macro invoked as part of a larger store sequence, set to 1 + * if this is not the first in the sequence. Defaults to 0. + * ofs Offset from start of larger sequence (from value of first ptr + * in sequence) at which to store. Defaults to next available space + * (or 0 if <continue> is 0). + * select Select what category(ies) of registers to store, as a bitmask + * (see XTHAL_SAS_xxx constants). Defaults to all registers. + * alloc Select what category(ies) of registers to allocate; if any + * category is selected here that is not in <select>, space for + * the corresponding registers is skipped without doing any store. + */ +.macro xchal_ncp_store ptr at1 at2 at3 at4 continue = 0 ofs = -1 select = XTHAL_SAS_ALL alloc = 0 +xchal_sa_start \continue, \ofs +// Optional global registers used by default by the compiler: +.ifeq(XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\select) +xchal_sa_align \ptr, 0, 1016, 4, 4 +rur.threadptr \at1 // threadptr option +s32i \at1, \ptr, .Lxchal_ofs_ + 0 +.set .Lxchal_ofs_, .Lxchal_ofs_ + 4 +.elseif((XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\alloc)) == 0 +xchal_sa_align \ptr, 0, 1016, 4, 4 +.set .Lxchal_ofs_, .Lxchal_ofs_ + 4 +.endif +// Optional caller-saved registers not used by default by the compiler: +.ifeq(XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) +xchal_sa_align \ptr, 0, 1016, 4, 4 +rsr.br \at1 // boolean option +s32i \at1, \ptr, .Lxchal_ofs_ + 0 +.set .Lxchal_ofs_, .Lxchal_ofs_ + 4 +.elseif((XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 +xchal_sa_align \ptr, 0, 1016, 4, 4 +.set .Lxchal_ofs_, .Lxchal_ofs_ + 4 +.endif +.endm // xchal_ncp_store + +/* + * Macro to load all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 4 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_NCP_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters: + * continue If macro invoked as part of a larger load sequence, set to 1 + * if this is not the first in the sequence. Defaults to 0. + * ofs Offset from start of larger sequence (from value of first ptr + * in sequence) at which to load. Defaults to next available space + * (or 0 if <continue> is 0). + * select Select what category(ies) of registers to load, as a bitmask + * (see XTHAL_SAS_xxx constants). Defaults to all registers. + * alloc Select what category(ies) of registers to allocate; if any + * category is selected here that is not in <select>, space for + * the corresponding registers is skipped without doing any load. + */ +.macro xchal_ncp_load ptr at1 at2 at3 at4 continue = 0 ofs = -1 select = XTHAL_SAS_ALL alloc = 0 +xchal_sa_start \continue, \ofs +// Optional global registers used by default by the compiler: +.ifeq(XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\select) +xchal_sa_align \ptr, 0, 1016, 4, 4 +l32i \at1, \ptr, .Lxchal_ofs_ + 0 +wur.threadptr \at1 // threadptr option +.set .Lxchal_ofs_, .Lxchal_ofs_ + 4 +.elseif((XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\alloc)) == 0 +xchal_sa_align \ptr, 0, 1016, 4, 4 +.set .Lxchal_ofs_, .Lxchal_ofs_ + 4 +.endif +// Optional caller-saved registers not used by default by the compiler: +.ifeq(XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) +xchal_sa_align \ptr, 0, 1016, 4, 4 +l32i \at1, \ptr, .Lxchal_ofs_ + 0 +wsr.br \at1 // boolean option +.set .Lxchal_ofs_, .Lxchal_ofs_ + 4 +.elseif((XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 +xchal_sa_align \ptr, 0, 1016, 4, 4 +.set .Lxchal_ofs_, .Lxchal_ofs_ + 4 +.endif +.endm // xchal_ncp_load + +#define XCHAL_NCP_NUM_ATMPS 1 + +/* + * Macro to store the state of TIE coprocessor AudioEngineLX. + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 16 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_CP1_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters are the same as for xchal_ncp_store. + */ +#define xchal_cp_AudioEngineLX_store xchal_cp1_store +.macro xchal_cp1_store ptr at1 at2 at3 at4 continue = 0 ofs = -1 select = XTHAL_SAS_ALL alloc = 0 +xchal_sa_start \continue, \ofs +// Custom caller-saved registers not used by default by the compiler: +.ifeq(XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) +xchal_sa_align \ptr, 0, 0, 16, 16 +ae_s64.i aed0, \ptr, .Lxchal_ofs_ + 56 +addi.a \ptr, \ptr, 64 +ae_s64.i aed1, \ptr, .Lxchal_ofs_ + 0 +ae_s64.i aed2, \ptr, .Lxchal_ofs_ + 8 +ae_s64.i aed3, \ptr, .Lxchal_ofs_ + 16 +ae_s64.i aed4, \ptr, .Lxchal_ofs_ + 24 +ae_s64.i aed5, \ptr, .Lxchal_ofs_ + 32 +ae_s64.i aed6, \ptr, .Lxchal_ofs_ + 40 +ae_s64.i aed7, \ptr, .Lxchal_ofs_ + 48 +ae_s64.i aed8, \ptr, .Lxchal_ofs_ + 56 +addi.a \ptr, \ptr, 64 +ae_s64.i aed9, \ptr, .Lxchal_ofs_ + 0 +ae_s64.i aed10, \ptr, .Lxchal_ofs_ + 8 +ae_s64.i aed11, \ptr, .Lxchal_ofs_ + 16 +ae_s64.i aed12, \ptr, .Lxchal_ofs_ + 24 +ae_s64.i aed13, \ptr, .Lxchal_ofs_ + 32 +ae_s64.i aed14, \ptr, .Lxchal_ofs_ + 40 +ae_s64.i aed15, \ptr, .Lxchal_ofs_ + 48 +ae_s64.i aed16, \ptr, .Lxchal_ofs_ + 56 +addi.a \ptr, \ptr, 64 +ae_s64.i aed17, \ptr, .Lxchal_ofs_ + 0 +ae_s64.i aed18, \ptr, .Lxchal_ofs_ + 8 +ae_s64.i aed19, \ptr, .Lxchal_ofs_ + 16 +ae_s64.i aed20, \ptr, .Lxchal_ofs_ + 24 +ae_s64.i aed21, \ptr, .Lxchal_ofs_ + 32 +ae_s64.i aed22, \ptr, .Lxchal_ofs_ + 40 +ae_s64.i aed23, \ptr, .Lxchal_ofs_ + 48 +ae_s64.i aed24, \ptr, .Lxchal_ofs_ + 56 +addi.a \ptr, \ptr, 64 +ae_s64.i aed25, \ptr, .Lxchal_ofs_ + 0 +ae_s64.i aed26, \ptr, .Lxchal_ofs_ + 8 +ae_s64.i aed27, \ptr, .Lxchal_ofs_ + 16 +ae_s64.i aed28, \ptr, .Lxchal_ofs_ + 24 +ae_s64.i aed29, \ptr, .Lxchal_ofs_ + 32 +ae_s64.i aed30, \ptr, .Lxchal_ofs_ + 40 +ae_s64.i aed31, \ptr, .Lxchal_ofs_ + 48 +ae_movae \at1, aep0 +s8i \at1, \ptr, .Lxchal_ofs_ + 56 +ae_movae \at1, aep1 +s8i \at1, \ptr, .Lxchal_ofs_ + 57 +ae_movae \at1, aep2 +s8i \at1, \ptr, .Lxchal_ofs_ + 58 +ae_movae \at1, aep3 +s8i \at1, \ptr, .Lxchal_ofs_ + 59 +addi.a \ptr, \ptr, 64 +ae_salign128.i u0, \ptr, .Lxchal_ofs_ + 0 +ae_salign128.i u1, \ptr, .Lxchal_ofs_ + 16 +ae_salign128.i u2, \ptr, .Lxchal_ofs_ + 32 +ae_salign128.i u3, \ptr, .Lxchal_ofs_ + 48 +addi.a \ptr, \ptr, -320 +ae_movdrzbvc aed0 // ureg AE_ZBIASV8C +ae_s64.i aed0, \ptr, .Lxchal_ofs_ + 0 + 0 +ae_movvfcrfsr aed0 // ureg FCR_FSR +ae_s64.i aed0, \ptr, .Lxchal_ofs_ + 8 + 0 +rur.ae_ovf_sar \at1 // ureg 240 +s32i \at1, \ptr, .Lxchal_ofs_ + 16 +rur.ae_bithead \at1 // ureg 241 +s32i \at1, \ptr, .Lxchal_ofs_ + 20 +rur.ae_ts_fts_bu_bp \at1 // ureg 242 +s32i \at1, \ptr, .Lxchal_ofs_ + 24 +rur.ae_cw_sd_no \at1 // ureg 243 +s32i \at1, \ptr, .Lxchal_ofs_ + 28 +rur.ae_cbegin0 \at1 // ureg 246 +s32i \at1, \ptr, .Lxchal_ofs_ + 32 +rur.ae_cend0 \at1 // ureg 247 +s32i \at1, \ptr, .Lxchal_ofs_ + 36 +rur.ae_cbegin1 \at1 // ureg 248 +s32i \at1, \ptr, .Lxchal_ofs_ + 40 +rur.ae_cend1 \at1 // ureg 249 +s32i \at1, \ptr, .Lxchal_ofs_ + 44 +rur.ae_cbegin2 \at1 // ureg 250 +s32i \at1, \ptr, .Lxchal_ofs_ + 48 +rur.ae_cend2 \at1 // ureg 251 +s32i \at1, \ptr, .Lxchal_ofs_ + 52 +.set .Lxchal_ofs_, .Lxchal_ofs_ + 384 +.elseif((XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 +xchal_sa_align \ptr, 0, 0, 16, 16 +.set .Lxchal_ofs_, .Lxchal_ofs_ + 384 +.endif +.endm // xchal_cp1_store + +/* + * Macro to load the state of TIE coprocessor AudioEngineLX. + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 16 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_CP1_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters are the same as for xchal_ncp_load. + */ +#define xchal_cp_AudioEngineLX_load xchal_cp1_load +.macro xchal_cp1_load ptr at1 at2 at3 at4 continue = 0 ofs = -1 select = XTHAL_SAS_ALL alloc = 0 +xchal_sa_start \continue, \ofs +// Custom caller-saved registers not used by default by the compiler: +.ifeq(XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) +xchal_sa_align \ptr, 0, 0, 16, 16 +ae_l64.i aed0, \ptr, .Lxchal_ofs_ + 0 + 0 // ureg AE_ZBIASV8C +ae_movzbvcdr aed0 +ae_l64.i aed0, \ptr, .Lxchal_ofs_ + 8 + 0 // ureg FCR_FSR +ae_movfcrfsrv aed0 +l32i \at1, \ptr, .Lxchal_ofs_ + 16 +wur.ae_ovf_sar \at1 // ureg 240 +l32i \at1, \ptr, .Lxchal_ofs_ + 20 +wur.ae_bithead \at1 // ureg 241 +l32i \at1, \ptr, .Lxchal_ofs_ + 24 +wur.ae_ts_fts_bu_bp \at1 // ureg 242 +l32i \at1, \ptr, .Lxchal_ofs_ + 28 +wur.ae_cw_sd_no \at1 // ureg 243 +l32i \at1, \ptr, .Lxchal_ofs_ + 32 +wur.ae_cbegin0 \at1 // ureg 246 +l32i \at1, \ptr, .Lxchal_ofs_ + 36 +wur.ae_cend0 \at1 // ureg 247 +l32i \at1, \ptr, .Lxchal_ofs_ + 40 +wur.ae_cbegin1 \at1 // ureg 248 +l32i \at1, \ptr, .Lxchal_ofs_ + 44 +wur.ae_cend1 \at1 // ureg 249 +l32i \at1, \ptr, .Lxchal_ofs_ + 48 +wur.ae_cbegin2 \at1 // ureg 250 +l32i \at1, \ptr, .Lxchal_ofs_ + 52 +wur.ae_cend2 \at1 // ureg 251 +ae_l64.i aed0, \ptr, .Lxchal_ofs_ + 56 +addi.a \ptr, \ptr, 64 +ae_l64.i aed1, \ptr, .Lxchal_ofs_ + 0 +ae_l64.i aed2, \ptr, .Lxchal_ofs_ + 8 +ae_l64.i aed3, \ptr, .Lxchal_ofs_ + 16 +ae_l64.i aed4, \ptr, .Lxchal_ofs_ + 24 +ae_l64.i aed5, \ptr, .Lxchal_ofs_ + 32 +ae_l64.i aed6, \ptr, .Lxchal_ofs_ + 40 +ae_l64.i aed7, \ptr, .Lxchal_ofs_ + 48 +ae_l64.i aed8, \ptr, .Lxchal_ofs_ + 56 +addi.a \ptr, \ptr, 64 +ae_l64.i aed9, \ptr, .Lxchal_ofs_ + 0 +ae_l64.i aed10, \ptr, .Lxchal_ofs_ + 8 +ae_l64.i aed11, \ptr, .Lxchal_ofs_ + 16 +ae_l64.i aed12, \ptr, .Lxchal_ofs_ + 24 +ae_l64.i aed13, \ptr, .Lxchal_ofs_ + 32 +ae_l64.i aed14, \ptr, .Lxchal_ofs_ + 40 +ae_l64.i aed15, \ptr, .Lxchal_ofs_ + 48 +ae_l64.i aed16, \ptr, .Lxchal_ofs_ + 56 +addi.a \ptr, \ptr, 64 +ae_l64.i aed17, \ptr, .Lxchal_ofs_ + 0 +ae_l64.i aed18, \ptr, .Lxchal_ofs_ + 8 +ae_l64.i aed19, \ptr, .Lxchal_ofs_ + 16 +ae_l64.i aed20, \ptr, .Lxchal_ofs_ + 24 +ae_l64.i aed21, \ptr, .Lxchal_ofs_ + 32 +ae_l64.i aed22, \ptr, .Lxchal_ofs_ + 40 +ae_l64.i aed23, \ptr, .Lxchal_ofs_ + 48 +ae_l64.i aed24, \ptr, .Lxchal_ofs_ + 56 +addi.a \ptr, \ptr, 64 +ae_l64.i aed25, \ptr, .Lxchal_ofs_ + 0 +ae_l64.i aed26, \ptr, .Lxchal_ofs_ + 8 +ae_l64.i aed27, \ptr, .Lxchal_ofs_ + 16 +ae_l64.i aed28, \ptr, .Lxchal_ofs_ + 24 +ae_l64.i aed29, \ptr, .Lxchal_ofs_ + 32 +ae_l64.i aed30, \ptr, .Lxchal_ofs_ + 40 +ae_l64.i aed31, \ptr, .Lxchal_ofs_ + 48 +addi.a \ptr, \ptr, 56 +l8ui \at1, \ptr, .Lxchal_ofs_ + 0 +ae_movea aep0, \at1 +l8ui \at1, \ptr, .Lxchal_ofs_ + 1 +ae_movea aep1, \at1 +l8ui \at1, \ptr, .Lxchal_ofs_ + 2 +ae_movea aep2, \at1 +l8ui \at1, \ptr, .Lxchal_ofs_ + 3 +ae_movea aep3, \at1 +addi.a \ptr, \ptr, 8 +ae_lalign128.i u0, \ptr, .Lxchal_ofs_ + 0 +ae_lalign128.i u1, \ptr, .Lxchal_ofs_ + 16 +ae_lalign128.i u2, \ptr, .Lxchal_ofs_ + 32 +ae_lalign128.i u3, \ptr, .Lxchal_ofs_ + 48 +.set .Lxchal_pofs_, .Lxchal_pofs_ + 320 +.set .Lxchal_ofs_, .Lxchal_ofs_ + 64 +.elseif((XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 +xchal_sa_align \ptr, 0, 0, 16, 16 +.set .Lxchal_ofs_, .Lxchal_ofs_ + 384 +.endif +.endm // xchal_cp1_load + +#define XCHAL_CP1_NUM_ATMPS 1 +#define XCHAL_SA_NUM_ATMPS 1 + +/* Empty macros for unconfigured coprocessors: */ +.macro xchal_cp0_store p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp0_load p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp2_store p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp2_load p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp3_store p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp3_load p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp4_store p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp4_load p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp5_store p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp5_load p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp6_store p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp6_load p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp7_store p a b c d continue = 0 ofs = -1 select = -1 ; .endm +.macro xchal_cp7_load p a b c d continue = 0 ofs = -1 select = -1 ; .endm + +#endif /*_XTENSA_CORE_TIE_ASM_H*/ + diff --git a/src/platform/mt8196/include/arch/xtensa/config/tie.h b/src/platform/mt8196/include/arch/xtensa/config/tie.h new file mode 100644 index 000000000000..517d79faab47 --- /dev/null +++ b/src/platform/mt8196/include/arch/xtensa/config/tie.h @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * tie.h -- compile-time HAL definitions dependent on CORE & TIE configuration + * + * NOTE: This header file is not meant to be included directly. + */ + +/* This header file describes this specific Xtensa processor's TIE extensions + * that extend basic Xtensa core functionality. It is customized to this + * Xtensa processor configuration. + * + * Customer ID = 7578; Build = 0xa69ab; Copyright (c) 1999-2023 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. + */ + +#ifndef XTENSA_CORE_TIE_H +#define XTENSA_CORE_TIE_H + +/* parasoft-begin-suppress ALL "This file not MISRA checked." */ + +#define XCHAL_CP_NUM UINT32_C(1) /* number of coprocessors */ +#define XCHAL_CP_MAX UINT32_C(2) /* max CP ID + 1 (0 if none) */ +#define XCHAL_CP_MASK UINT32_C(0x02) /* bitmask of all CPs by ID */ +#define XCHAL_CP_PORT_MASK UINT32_C(0x00) /* bitmask of only port CPs */ + +/* Basic parameters of each coprocessor: */ +#define XCHAL_CP1_NAME "audio_engine_lx" +#define XCHAL_CP1_IDENT audio_engine_lx +#define XCHAL_CP1_SA_SIZE UINT32_C(384) /* size of state save area */ +#define XCHAL_CP1_SA_ALIGN UINT32_C(16) /* min alignment of save area */ +#define XCHAL_CP_ID_AUDIOENGINELX 1 /* coprocessor ID (0..7) */ + +/* Filler info for unassigned coprocessors, to simplify arrays etc: */ +#define XCHAL_CP0_SA_SIZE UINT32_C(0) +#define XCHAL_CP0_SA_ALIGN UINT32_C(1) +#define XCHAL_CP2_SA_SIZE UINT32_C(0) +#define XCHAL_CP2_SA_ALIGN UINT32_C(1) +#define XCHAL_CP3_SA_SIZE UINT32_C(0) +#define XCHAL_CP3_SA_ALIGN UINT32_C(1) +#define XCHAL_CP4_SA_SIZE UINT32_C(0) +#define XCHAL_CP4_SA_ALIGN UINT32_C(1) +#define XCHAL_CP5_SA_SIZE UINT32_C(0) +#define XCHAL_CP5_SA_ALIGN UINT32_C(1) +#define XCHAL_CP6_SA_SIZE UINT32_C(0) +#define XCHAL_CP6_SA_ALIGN UINT32_C(1) +#define XCHAL_CP7_SA_SIZE UINT32_C(0) +#define XCHAL_CP7_SA_ALIGN UINT32_C(1) + +/* Save area for non-coprocessor optional and custom (TIE) state: */ +#define XCHAL_NCP_SA_SIZE UINT32_C(8) +#define XCHAL_NCP_SA_ALIGN UINT32_C(4) + +/* Total save area for optional and custom state (NCP + CPn): */ +#define XCHAL_TOTAL_SA_SIZE UINT32_C(400) /* with 16-byte align padding */ +#define XCHAL_TOTAL_SA_ALIGN UINT32_C(16) /* actual minimum alignment */ + +/* + * Detailed contents of save areas. + * NOTE: caller must define the XCHAL_SA_REG macro (not defined here) + * before expanding the XCHAL_xxx_SA_LIST() macros. + * + * XCHAL_SA_REG(s, ccused, abikind, kind, opt, name, galign, align, asize, + * dbnum, base, regnum, bitsz, gapsz, reset, x...) + * + * s = passed from XCHAL_*_LIST(s), eg. to select how to expand + * ccused = set if used by compiler without special options or code + * abikind = 0 (caller-saved), 1 (callee-saved), or 2 (thread-global) + * kind = 0 (special reg), 1 (TIE user reg), or 2 (TIE regfile reg) + * opt = 0 (custom TIE extension or coprocessor), or 1 (optional reg) + * name = lowercase reg name (no quotes) + * galign = group byte alignment (power of 2) (galign >= align) + * align = register byte alignment (power of 2) + * asize = allocated size in bytes (asize*8 == bitsz + gapsz + padsz) + * (not including any pad bytes required to galign this or next reg) + * dbnum = unique target number f/debug (see <xtensa-libdb-macros.h>) + * base = reg shortname w/o index (or sr = special, ur = TIE user reg) + * regnum = reg index in regfile, or special/TIE-user reg number + * bitsz = number of significant bits (regfile width, or ur/sr mask bits) + * gapsz = intervening bits, if bitsz bits not stored contiguously + * (padsz = pad bits at end [TIE regfile] or at msbits [ur, sr] of asize) + * reset = register reset value (or 0 if undefined at reset) + * x = reserved for future use (0 until then) + * + * To filter out certain registers, e.g. to expand only the non-global + * registers used by the compiler, you can do something like this: + * + * #define XCHAL_SA_REG(s, ccused, p...) SELCC##ccused(p) + * #define SELCC0(p...) + * #define SELCC1(abikind, p...) SELAK##abikind(p) + * #define SELAK0(p...) REG(p) + * #define SELAK1(p...) REG(p) + * #define SELAK2(p...) + * #define REG(kind, tie, name, galn, aln, asz, csz, dbnum, base, rnum, bsz, rst, x...) \ + * ...what you want to expand... + */ + +#define XCHAL_NCP_SA_NUM 2 +#define XCHAL_NCP_SA_LIST(s) (\ +XCHAL_SA_REG(s, 1, 2, 1, 1, threadptr, 4, 4, 4, 0x03E7, ur, 231, 32, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 0, 1, br, 4, 4, 4, 0x0204, sr, 4, 16, 0, 0, 0)) + +#define XCHAL_CP0_SA_NUM 0 +#define XCHAL_CP0_SA_LIST(s) /* empty */ + +#define XCHAL_CP1_SA_NUM 52 +#define XCHAL_CP1_SA_LIST(s) (\ +XCHAL_SA_REG(s, 0, 0, 1, 0, ae_zbiasv8c, 16, 8, 8, 0x1029, ur, -1, 16, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 1, 0, fcr_fsr, 8, 8, 8, 0x102A, ur, -1, 7, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 1, 0, ae_ovf_sar, 4, 4, 4, 0x03F0, ur, 240, 15, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 1, 0, ae_bithead, 4, 4, 4, 0x03F1, ur, 241, 32, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 1, 0, ae_ts_fts_bu_bp, 4, 4, 4, 0x03F2, ur, 242, 16, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 1, 0, ae_cw_sd_no, 4, 4, 4, 0x03F3, ur, 243, 29, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 1, 0, ae_cbegin0, 4, 4, 4, 0x03F6, ur, 246, 32, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 1, 0, ae_cend0, 4, 4, 4, 0x03F7, ur, 247, 32, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 1, 0, ae_cbegin1, 4, 4, 4, 0x03F8, ur, 248, 32, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 1, 0, ae_cend1, 4, 4, 4, 0x03F9, ur, 249, 32, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 1, 0, ae_cbegin2, 4, 4, 4, 0x03FA, ur, 250, 32, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 1, 0, ae_cend2, 4, 4, 4, 0x03FB, ur, 251, 32, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed0, 8, 8, 8, 0x1000, aed, 0, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed1, 8, 8, 8, 0x1001, aed, 1, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed2, 8, 8, 8, 0x1002, aed, 2, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed3, 8, 8, 8, 0x1003, aed, 3, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed4, 8, 8, 8, 0x1004, aed, 4, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed5, 8, 8, 8, 0x1005, aed, 5, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed6, 8, 8, 8, 0x1006, aed, 6, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed7, 8, 8, 8, 0x1007, aed, 7, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed8, 8, 8, 8, 0x1008, aed, 8, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed9, 8, 8, 8, 0x1009, aed, 9, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed10, 8, 8, 8, 0x100A, aed, 10, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed11, 8, 8, 8, 0x100B, aed, 11, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed12, 8, 8, 8, 0x100C, aed, 12, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed13, 8, 8, 8, 0x100D, aed, 13, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed14, 8, 8, 8, 0x100E, aed, 14, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed15, 8, 8, 8, 0x100F, aed, 15, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed16, 8, 8, 8, 0x1010, aed, 16, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed17, 8, 8, 8, 0x1011, aed, 17, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed18, 8, 8, 8, 0x1012, aed, 18, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed19, 8, 8, 8, 0x1013, aed, 19, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed20, 8, 8, 8, 0x1014, aed, 20, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed21, 8, 8, 8, 0x1015, aed, 21, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed22, 8, 8, 8, 0x1016, aed, 22, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed23, 8, 8, 8, 0x1017, aed, 23, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed24, 8, 8, 8, 0x1018, aed, 24, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed25, 8, 8, 8, 0x1019, aed, 25, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed26, 8, 8, 8, 0x101A, aed, 26, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed27, 8, 8, 8, 0x101B, aed, 27, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed28, 8, 8, 8, 0x101C, aed, 28, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed29, 8, 8, 8, 0x101D, aed, 29, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed30, 8, 8, 8, 0x101E, aed, 30, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aed31, 8, 8, 8, 0x101F, aed, 31, 64, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aep0, 1, 1, 1, 0x1024, aep, 0, 8, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aep1, 1, 1, 1, 0x1025, aep, 1, 8, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aep2, 1, 1, 1, 0x1026, aep, 2, 8, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, aep3, 1, 1, 1, 0x1027, aep, 3, 8, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, u0, 16, 16, 16, 0x1020, u, 0, 128, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, u1, 16, 16, 16, 0x1021, u, 1, 128, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, u2, 16, 16, 16, 0x1022, u, 2, 128, 0, 0, 0) \ +XCHAL_SA_REG(s, 0, 0, 2, 0, u3, 16, 16, 16, 0x1023, u, 3, 128, 0, 0, 0)) + +#define XCHAL_CP2_SA_NUM 0 +#define XCHAL_CP2_SA_LIST(s) /* empty */ + +#define XCHAL_CP3_SA_NUM 0 +#define XCHAL_CP3_SA_LIST(s) /* empty */ + +#define XCHAL_CP4_SA_NUM 0 +#define XCHAL_CP4_SA_LIST(s) /* empty */ + +#define XCHAL_CP5_SA_NUM 0 +#define XCHAL_CP5_SA_LIST(s) /* empty */ + +#define XCHAL_CP6_SA_NUM 0 +#define XCHAL_CP6_SA_LIST(s) /* empty */ + +#define XCHAL_CP7_SA_NUM 0 +#define XCHAL_CP7_SA_LIST(s) /* empty */ + +/* Byte length of instruction from its first nibble (op0 field), per FLIX. */ +#define XCHAL_OP0_FORMAT_LENGTHS (3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16) +/* Byte length of instruction from its first byte, per FLIX. */ +#define XCHAL_BYTE0_FORMAT_LENGTHS (\ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \ +3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 16, \) + +/* parasoft-end-suppress ALL "This file not MISRA checked." */ + +#endif /* XTENSA_CORE_TIE_H */ + diff --git a/src/platform/mt8196/include/platform/drivers/idc.h b/src/platform/mt8196/include/platform/drivers/idc.h new file mode 100644 index 000000000000..8ad311b1471b --- /dev/null +++ b/src/platform/mt8196/include/platform/drivers/idc.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#if defined(__XTOS_RTOS_IDC_H__) || defined(__ZEPHYR_RTOS_IDC_H__) + +#ifndef __PLATFORM_DRIVERS_IDC_H__ +#define __PLATFORM_DRIVERS_IDC_H__ + +#include <stdint.h> + +struct idc_msg; + +static inline int idc_send_msg(struct idc_msg *msg, uint32_t mode) +{ + return 0; +} + +static inline int idc_init(void) +{ + return 0; +} + +#endif /* __PLATFORM_DRIVERS_IDC_H__ */ + +#else + +#error "This file shouldn't be included from outside of Zephyr/XTOS's rtos/idc.h" + +#endif diff --git a/src/platform/mt8196/include/platform/drivers/intc.h b/src/platform/mt8196/include/platform/drivers/intc.h new file mode 100644 index 000000000000..be741ae6e484 --- /dev/null +++ b/src/platform/mt8196/include/platform/drivers/intc.h @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ +#ifndef MTK_INTC_H +#define MTK_INTC_H + +#include <rtos/bit.h> +#include <stdint.h> +#include <platform/drivers/mt_reg_base.h> + +enum IRQn_Type { + CCU_IRQn = 0, + SCP_IRQn = 1, + SPM_IRQn = 2, + PCIE_IRQn = 3, + INFRA_HANG_IRQn = 4, + PERI_TIMEOUT_IRQn = 5, + MBOX_C0_IRQn = 6, + MBOX_C1_IRQn = 7, + TIMER0_IRQn = 8, + TIMER1_IRQn = 9, + IPC_C0_IRQn = 10, + IPC_C1_IRQn = 11, + IPC1_RSV_IRQn = 12, + C2C_SW_C0_IRQn = 13, + C2C_SW_C1_IRQn = 14, + UART_IRQn = 15, + UART_BT_IRQn = 16, + LATENCY_MON_IRQn = 17, + BUS_TRACKER_IRQn = 18, + USB0_IRQn = 19, + USB1_IRQn = 20, + SCPVOW_IRQn = 21, + CCIF3_C0_IRQn = 22, + CCIF3_C1_IRQn = 23, + PWR_CTRL_IRQn = 24, + DMA_C0_IRQn = 25, + DMA_C1_IRQn = 26, // no use as gdma only has one set + AXI_DMA0_IRQn = 27, + AXI_DMA1_IRQn = 28, + AUDIO_C0_IRQn = 29, + AUDIO_C1_IRQn = 30, + HIFI5_WDT_C0_IRQn = 31, + HIFI5_WDT_C1_IRQn = 32, + APU_MBOX_C0_IRQn = 33, + APU_MBOX_C1_IRQn = 34, + TIMER2_IRQn = 35, + PWR_ON_C0_IRQ = 36, + PWR_ON_C1_IRQ = 37, + WAKEUP_SRC_C0_IRQn = 38, + WAKEUP_SRC_C1_IRQn = 39, + WDT_IRQn = 40, + CONNSYS1_IRQn = 41, // BTCVSD + CONNSYS3_IRQn = 42, // BLEISO + CONNSYS4_IRQn = 43, // ISOCH, bt2dsp_isoch_irq_mask + CONNSYS2_IRQn = 44, // A2DP + IPIC_IRQn = 45, + AXI_DMA2_IRQn = 46, + AXI_DMA3_IRQn = 47, + APSRC_DDREN_IRQn = 48, + LAT_MON_EMI_IRQn = 49, + LAT_MON_INFRA_IRQn = 50, + DEVAPC_VIO_IRQn = 51, + AO_INFRA_HANG_IRQn = 52, + BUS_TRA_EMI_IRQn = 53, + BUS_TRA_INFRA_IRQn = 54, + L2SRAM_VIO_IRQn = 55, + L2SRAM_SETERR_IRQn = 56, + PCIERC_GRP2_IRQn = 57, + PCIERC_GRP3_IRQn = 58, + IRQ_MAX_CHANNEL = 59, + NO_IRQ = 0xFFFFFFFFU, // -1 +}; + +#define INTC_GRP_LEN 2 +#define INTC_GRP_GAP 3 // size of group = 2 words = 8 bytes +#define WORD_LEN 32 +#define INTC_WORD(irq) ((irq) >> 5) +#define INTC_BIT(irq) (1 << ((irq) & 0x1F)) +#define INTC_WORD_OFS(word) ((word) << 2) +#ifndef INTC_GROUP_OFS +#define INTC_GROUP_OFS(grp) ((grp) << INTC_GRP_GAP) +#endif + +// #define INTC_IRQ_RAW_STA(word) (INTC_IRQ_RAW_STA0 + INTC_WORD_OFS(word)) +#define INTC_IRQ_STA(word) (INTC_IRQ_STA0 + INTC_WORD_OFS(word)) +#define INTC_IRQ_EN(word) (INTC_IRQ_EN0 + INTC_WORD_OFS(word)) +#define INTC_IRQ_WAKE_EN(word) (INTC_IRQ_WAKE_EN0 + INTC_WORD_OFS(word)) +#define INTC_IRQ_STAGE1_EN(word) (INTC_IRQ_STAGE1_EN0 + INTC_WORD_OFS(word)) +#define INTC_IRQ_POL(word) (INTC_IRQ_POL0 + INTC_WORD_OFS(word)) +#define INTC_IRQ_GRP(grp, word) (INTC_IRQ_GRP0_0 + INTC_GROUP_OFS(grp)\ + + INTC_WORD_OFS(word)) +#define INTC_IRQ_GRP_STA(grp, word) (INTC_IRQ_GRP0_STA0 + INTC_GROUP_OFS(grp)\ + + INTC_WORD_OFS(word)) + +/* intc group level */ +#define INTC_GRP0_LEVEL XCHAL_INT0_LEVEL +#define INTC_GRP1_LEVEL XCHAL_INT1_LEVEL +#define INTC_GRP2_LEVEL XCHAL_INT2_LEVEL +#define INTC_GRP3_LEVEL XCHAL_INT3_LEVEL +#define INTC_GRP4_LEVEL XCHAL_INT4_LEVEL +#define INTC_GRP5_LEVEL XCHAL_INT5_LEVEL +#define INTC_GRP6_LEVEL XCHAL_INT7_LEVEL +#define INTC_GRP7_LEVEL XCHAL_INT8_LEVEL +#define INTC_GRP8_LEVEL XCHAL_INT9_LEVEL +#define INTC_GRP9_LEVEL XCHAL_INT10_LEVEL +#define INTC_GRP10_LEVEL XCHAL_INT11_LEVEL +#define INTC_GRP11_LEVEL XCHAL_INT16_LEVEL +#define INTC_GRP12_LEVEL XCHAL_INT17_LEVEL +#define INTC_GRP13_LEVEL XCHAL_INT18_LEVEL +#define INTC_GRP14_LEVEL XCHAL_INT20_LEVEL +#define INTC_GRP15_LEVEL XCHAL_INT21_LEVEL + + +enum INTC_GROUP { + INTC_GRP0 = 0, + INTC_GRP1, + INTC_GRP2, + INTC_GRP3, + INTC_GRP4, + INTC_GRP5, + INTC_GRP6, + INTC_GRP7, + INTC_GRP8, + INTC_GRP9, + INTC_GRP10, + INTC_GRP11, + INTC_GRP12, + INTC_GRP13, + INTC_GRP14, + INTC_GRP15, + INTC_GRP_NUM, + NO_GRP, +}; + +enum INTC_POL { + INTC_POL_HIGH = 0x0, + INTC_POL_LOW = 0x1, + INTC_POL_NUM, +}; + +struct intc_irq_desc_t { + uint8_t id; + uint8_t group; + uint8_t pol; +}; + +struct intc_desc_t { + uint32_t int_en[INTC_GRP_LEN]; + uint32_t grp_irqs[INTC_GRP_NUM][INTC_GRP_LEN]; + struct intc_irq_desc_t irqs[IRQ_MAX_CHANNEL]; +}; + +struct intc_irq_config { + uint32_t int_en[INTC_GRP_LEN]; +}; + +struct intc_grp_config { + uint32_t grp_irq[INTC_GRP_NUM][INTC_GRP_LEN]; +}; + +struct intc_coreoff_wake_en_config { + uint32_t wake_en[INTC_GRP_LEN]; +}; + +struct intc_sleep_wake_en_config { + uint32_t wake_en[INTC_GRP_LEN]; +}; + +extern const unsigned char grp_pri[INTC_GRP_NUM]; +extern const uint8_t irq2grp_map[IRQ_MAX_CHANNEL]; +extern const uint8_t grp2hifi_irq_map[INTC_GRP_NUM]; +void intc_init(void); + +#ifdef CFG_TICKLESS_SUPPORT +extern struct intc_sleep_wake_en_config sleep_wakeup_src_en; +#endif +#ifdef CFG_CORE_OFF_SUPPORT +extern struct intc_coreoff_wake_en_config coreoff_wakeup_src_en; +#endif + +#endif /* INTC_H */ + diff --git a/src/platform/mt8196/include/platform/drivers/interrupt.h b/src/platform/mt8196/include/platform/drivers/interrupt.h new file mode 100644 index 000000000000..71048100df8c --- /dev/null +++ b/src/platform/mt8196/include/platform/drivers/interrupt.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#ifdef __SOF_DRIVERS_INTERRUPT_H__ + +#ifndef __PLATFORM_DRIVERS_INTERRUPT_H__ +#define __PLATFORM_DRIVERS_INTERRUPT_H__ + +#include <stdint.h> +#include <platform/drivers/mt_reg_base.h> +#include <platform/drivers/intc.h> + +#define PLATFORM_IRQ_HW_NUM XCHAL_NUM_INTERRUPTS +#define PLATFORM_IRQ_FIRST_CHILD PLATFORM_IRQ_HW_NUM +#define PLATFORM_IRQ_CHILDREN 32 + +/* MTK_ADSP_IRQ_MASK */ +#define MTK_DSP_OUT_IRQ_MASK 0x3FF + +#define HIFI_IRQ_MAX_CHANNEL 26 + +#define DEFALUT_WAKEUP_SRC_MASK_BIT 0x001A5E13 +#define DEFAULT_WAKEUP_SRC_EN0_BIT 0xA046B550 +#define DEFAULT_WAKEUP_SRC_EN1_BIT 0x00002148 + +#define MTK_DSP_IRQ_MBOX_C0 2 +#define MTK_DSP_IRQ_OSTIMER32_C0 1 +#define IPC0_IRQn IPC_C0_IRQn +#define C2C_SW_IRQn C2C_SW_C0_IRQn +#define CCIF3_IRQn CCIF3_C0_IRQn +#define DMA_IRQn DMA_C0_IRQn +#define AUDIO_IRQn AUDIO_C0_IRQn +#define HIFI5_WDT_IRQn HIFI5_WDT_C0_IRQn +#define APU_MBOX_IRQn APU_MBOX_C0_IRQn +#define PWR_ON_CORE_IRQn PWR_ON_C0_IRQ +#define WAKEUP_SRC_IRQn WAKEUP_SRC_C0_IRQn +#define AXI_DMA_CH0_IRQn AXI_DMA0_IRQn +#define AXI_DMA_CH1_IRQn AXI_DMA2_IRQn + +/* following interrupts are HiFi internal interrupts */ +#define MTK_DSP_IRQ_NMI 25 +#define MTK_DSP_IRQ_PROFILING 29 +#define MTK_DSP_IRQ_WERR 30 +#define MTK_DSP_IRQ_SW 31 +#define MTK_MAX_IRQ_NUM 59 + +/* grouped mailbox IRQ */ +#define MTK_DSP_IRQ_MBOX0 59 +#define MTK_DSP_IRQ_MBOX1 60 +#define MTK_DSP_IRQ_MBOX2 61 +#define MTK_DSP_IRQ_MBOX3 62 +#define MTK_DSP_IRQ_MBOX4 63 + +#define MTK_DSP_MBOX_MASK 0xF + +int mtk_irq_group_id(uint32_t irq); +void intc_irq_unmask(enum IRQn_Type irq); +void intc_irq_mask(enum IRQn_Type irq); +int intc_irq_enable(enum IRQn_Type irq); +int intc_irq_disable(enum IRQn_Type irq); + +#endif /* __PLATFORM_DRIVERS_INTERRUPT_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/drivers/interrupt.h" + +#endif /* __SOF_DRIVERS_INTERRUPT_H__ */ diff --git a/src/platform/mt8196/include/platform/drivers/mt_reg_base.h b/src/platform/mt8196/include/platform/drivers/mt_reg_base.h new file mode 100644 index 000000000000..bb990270512e --- /dev/null +++ b/src/platform/mt8196/include/platform/drivers/mt_reg_base.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + * + */ + +#ifndef MT_REG_BASE_H +#define MT_REG_BASE_H + +#define MTK_DSP_CFGREG_BASE 0x1A000000 /* DSP Register base */ +#define MTK_DSP_CFGREG_SIZE 0x1000 +#define MTK_ADSP_CFGREG_SW_RSTN (MTK_DSP_CFGREG_BASE + 0x0000) +#define MTK_ADSP_HIFI_IO_CONFIG (MTK_DSP_CFGREG_BASE + 0x000c) +#define MTK_ADSP_IRQ_STATUS (MTK_DSP_CFGREG_BASE + 0x0010) +#define MTK_ADSP_SW_INT_SET (MTK_DSP_CFGREG_BASE + 0x0018) +#define MTK_ADSP_SW_INT_CLR (MTK_DSP_CFGREG_BASE + 0x001c) +#define MTK_ADSP_SW_INT_32A (MTK_DSP_CFGREG_BASE + 0x0020) +#define MTK_ADSP_IRQ_MASK (MTK_DSP_CFGREG_BASE + 0x0030) +#define MTK_ADSP_GENERAL_IRQ_SET (MTK_DSP_CFGREG_BASE + 0x0034) +#define MTK_ADSP_GENERAL_IRQ_CLR (MTK_DSP_CFGREG_BASE + 0x0038) +#define MTK_ADSP_DVFSRC_STATE (MTK_DSP_CFGREG_BASE + 0x003c) +#define MTK_ADSP_DVFSRC_REQ (MTK_DSP_CFGREG_BASE + 0x0040) +#define MTK_ADSP_DDREN_REQ_0 (MTK_DSP_CFGREG_BASE + 0x0044) +#define MTK_ADSP_SPM_ACK (MTK_DSP_CFGREG_BASE + 0x004c) +#define MTK_ADSP_IRQ_EN (MTK_DSP_CFGREG_BASE + 0x0050) +#define MTK_ADSP_IRQ_POL_FIX (MTK_DSP_CFGREG_BASE + 0x0054) +#define MTK_ADSP_SPM_WAKEUPSRC_CORE0 (MTK_DSP_CFGREG_BASE + 0x005c) +#define MTK_ADSP_SEMAPHORE (MTK_DSP_CFGREG_BASE + 0x0064) +#define MTK_ADSP_DBG_SEL (MTK_DSP_CFGREG_BASE + 0x0074) +#define MTK_ADSP_DBG_INFO (MTK_DSP_CFGREG_BASE + 0x0078) +#define MTK_ADSP_WDT_CON_C0 (MTK_DSP_CFGREG_BASE + 0x007c) +#define MTK_ADSP_WDT_INIT_VALUE_C0 (MTK_DSP_CFGREG_BASE + 0x0080) +#define MTK_ADSP_WDT_CNT_C0 (MTK_DSP_CFGREG_BASE + 0x0084) +#define MTK_ADSP_WAKEUPSRC_MASK_C0 (MTK_DSP_CFGREG_BASE + 0x00a0) +#define MTK_ADSP_WAKEUPSRC_IRQ_C0 (MTK_DSP_CFGREG_BASE + 0x00a4) +#define MTK_ADSP2SPM_MBOX (MTK_DSP_CFGREG_BASE + 0x00bc) +#define MTK_SPM2ADSP_MBOX (MTK_DSP_CFGREG_BASE + 0x00c0) + +/* intc */ +#define MTK_ADSP_INTC_BASE (MTK_DSP_CFGREG_BASE + 0x14000) + +#define INTC_IRQ_RAW_STA0 (MTK_ADSP_INTC_BASE + 0x000) +#define INTC_IRQ_STA0 (MTK_ADSP_INTC_BASE + 0x008) +#define INTC_IRQ_STA1 (MTK_ADSP_INTC_BASE + 0x00c) +#define INTC_IRQ_EN0 (MTK_ADSP_INTC_BASE + 0x010) +#define INTC_IRQ_POL0 (MTK_ADSP_INTC_BASE + 0x018) +#define INTC_IRQ_WAKE_EN0 (MTK_ADSP_INTC_BASE + 0x020) +#define INTC_IRQ_STAGE1_EN0 (MTK_ADSP_INTC_BASE + 0x030) +#define INTC_IRQ_GRP0_0 (MTK_ADSP_INTC_BASE + 0x040) +#define INTC_IRQ_GRP0_STA0 (MTK_ADSP_INTC_BASE + 0x0C0) +#define INTC_GRP_IRQ_OUT_STA (MTK_ADSP_INTC_BASE + 0x140) + +#define MTK_GPR_RW_REG0 (MTK_DSP_CFGREG_BASE + 0x0440) +#define MTK_GPR_RW_REG1 (MTK_DSP_CFGREG_BASE + 0x0444) +#define MTK_GPR_RW_REG2 (MTK_DSP_CFGREG_BASE + 0x0448) +#define MTK_GPR_RW_REG3 (MTK_DSP_CFGREG_BASE + 0x044c) +#define MTK_GPR_RW_REG4 (MTK_DSP_CFGREG_BASE + 0x0450) +#define MTK_GPR_RW_REG5 (MTK_DSP_CFGREG_BASE + 0x0454) +#define MTK_GPR_RW_REG6 (MTK_DSP_CFGREG_BASE + 0x0458) +#define MTK_GPR_RW_REG7 (MTK_DSP_CFGREG_BASE + 0x045c) +#define MTK_GPR_RW_REG8 (MTK_DSP_CFGREG_BASE + 0x0460) +#define MTK_GPR_RW_REG9 (MTK_DSP_CFGREG_BASE + 0x0464) +#define MTK_GPR_RW_REG10 (MTK_DSP_CFGREG_BASE + 0x0468) +#define MTK_GPR_RW_REG11 (MTK_DSP_CFGREG_BASE + 0x046c) +#define MTK_GPR_RW_REG12 (MTK_DSP_CFGREG_BASE + 0x0470) +#define MTK_GPR_RW_REG13 (MTK_DSP_CFGREG_BASE + 0x0474) +#define MTK_GPR_RW_REG14 (MTK_DSP_CFGREG_BASE + 0x0478) +#define MTK_GPR_RW_REG15 (MTK_DSP_CFGREG_BASE + 0x047c) +#define MTK_GPR_RW_REG16 (MTK_DSP_CFGREG_BASE + 0x0480) +#define MTK_GPR_RW_REG17 (MTK_DSP_CFGREG_BASE + 0x0484) +#define MTK_GPR_RW_REG18 (MTK_DSP_CFGREG_BASE + 0x0488) +#define MTK_GPR_RW_REG19 (MTK_DSP_CFGREG_BASE + 0x048c) +#define MTK_GPR_RW_REG20 (MTK_DSP_CFGREG_BASE + 0x0490) +#define MTK_GPR_RW_REG21 (MTK_DSP_CFGREG_BASE + 0x0494) +#define MTK_GPR_RW_REG22 (MTK_DSP_CFGREG_BASE + 0x0498) +#define MTK_GPR_RW_REG23 (MTK_DSP_CFGREG_BASE + 0x049c) +#define MTK_GPR_RW_REG24 (MTK_DSP_CFGREG_BASE + 0x04a0) +#define MTK_GPR_RW_REG25 (MTK_DSP_CFGREG_BASE + 0x04a4) +#define MTK_GPR_RW_REG26 (MTK_DSP_CFGREG_BASE + 0x04a8) +#define MTK_GPR_RW_REG27 (MTK_DSP_CFGREG_BASE + 0x04ac) +/* use for tickless status */ +#define MTK_GPR_RW_REG28 (MTK_DSP_CFGREG_BASE + 0x04b0) +#define MTK_GPR_RW_REG29 (MTK_DSP_CFGREG_BASE + 0x04b4) + +#define MTK_ADSP_IRQ_OUT_MASK (MTK_DSP_CFGREG_BASE + 0x0500) + +#define MTK_DSP_CKCTRL_BASE (MTK_DSP_CFGREG_BASE + 0x1000) +#define MTK_DSP_CKCTRL_SIZE 0x1000 + +#define MTK_DSP_OS_TIMER_BASE (MTK_DSP_CFGREG_BASE + 0xB000) +#define MTK_DSP_OS_TIMER_SIZE 0x1000 + +#define MTK_DSP_UART0_BASE (MTK_DSP_CFGREG_BASE + 0xD000) +#define MTK_DSP_UART0_SIZE 0x1000 +#define MTK_DSP_BT_UART_BASE (MTK_DSP_CFGREG_BASE + 0xE000) +#define MTK_DSP_BT_UART_SIZE 0x1000 + +#define MTK_DSP_BUS_BASE (MTK_DSP_CFGREG_BASE + 0xF000) +#define MTK_DSP_BUS_SIZE 0x1000 + +#define MTK_DSP_SECURE_BASE (MTK_DSP_CFGREG_BASE + 0x345000) +#define MTK_MBOX_IRQ_IN (MTK_DSP_SECURE_BASE + 0x70) + +/* MBOX registers */ +#define MTK_ADSP_MBOX_BASE (MTK_DSP_CFGREG_BASE + 0x350000) +#define MTK_ADSP_MBOX_REG_BASE(x) (MTK_ADSP_MBOX_BASE + (0x10000 * (x))) +#define MTK_ADSP_MBOX_REG_SIZE (0x50000) +#define MTK_ADSP_MBOX_IN_CMD(x) (MTK_ADSP_MBOX_REG_BASE(x) + 0x100) +#define MTK_ADSP_MBOX_IN_CMD_CLR(x) (MTK_ADSP_MBOX_REG_BASE(x) + 0x108) +#define MTK_ADSP_MBOX_OUT_CMD(x) (MTK_ADSP_MBOX_REG_BASE(x) + 0x104) +#define MTK_ADSP_MBOX_OUT_CMD_CLR(x) (MTK_ADSP_MBOX_REG_BASE(x) + 0x10c) + +#endif /* MT_REG_BASE_H */ diff --git a/src/platform/mt8196/include/platform/drivers/timer.h b/src/platform/mt8196/include/platform/drivers/timer.h new file mode 100644 index 000000000000..8aeacca52981 --- /dev/null +++ b/src/platform/mt8196/include/platform/drivers/timer.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#ifndef __PLATFORM_DRIVERS_TIMER_H__ +#define __PLATFORM_DRIVERS_TIMER_H__ + +#include <rtos/bit.h> +#include <platform/drivers/mt_reg_base.h> + +/*-------timer:ostimer0-------*/ +enum ostimer { + OSTIMER0 = 0, + OSTIMER1, + OSTIMER2, + OSTIMER3, + NR_TMRS +}; + +#define MTK_TIMER_CON(n) (MTK_DSP_OS_TIMER_BASE + 0x0 + 0x10 * (n)) +#define MTK_TIMER_RST_VAL(n) (MTK_DSP_OS_TIMER_BASE + 0x4 + 0x10 * (n)) +#define MTK_TIMER_CUR_VAL(n) (MTK_DSP_OS_TIMER_BASE + 0x8 + 0x10 * (n)) +#define MTK_TIMER_IRQ_ACK(n) (MTK_DSP_OS_TIMER_BASE + 0xC + 0x10 * (n)) + +#define MTK_TIMER_ENABLE_BIT BIT(0) +#define MTK_TIMER_IRQ_ENABLE BIT(0) +#define MTK_TIMER_IRQ_STA BIT(4) +#define MTK_TIMER_IRQ_CLEAR BIT(5) + +#define MTK_TIMER_CLKSRC_BIT (BIT(4) | BIT(5)) +#define MTK_TIMER_CLK_SRC_CLK_26M 0 +#define MTK_TIMER_CLK_SRC_BCLK BIT(5) +#define MTK_TIMER_CLK_SRC_PCLK (BIT(4) | BIT(5)) + +/*-------platform_timer: 64 bit systimer-------*/ +#define MTK_OSTIMER_CON (MTK_DSP_OS_TIMER_BASE + 0x80) +#define MTK_OSTIMER_CUR_L (MTK_DSP_OS_TIMER_BASE + 0x8C) +#define MTK_OSTIMER_CUR_H (MTK_DSP_OS_TIMER_BASE + 0x90) +#define MTK_OSTIMER_TVAL (MTK_DSP_OS_TIMER_BASE + 0x94) +#define MTK_OSTIMER_IRQ_ACK (MTK_DSP_OS_TIMER_BASE + 0x98) + +#define MTK_OSTIMER_EN_BIT BIT(0) + +#endif /* __PLATFORM_DRIVERS_TIMER_H__ */ diff --git a/src/platform/mt8196/include/platform/lib/clk.h b/src/platform/mt8196/include/platform/lib/clk.h new file mode 100644 index 000000000000..f4f311948fb4 --- /dev/null +++ b/src/platform/mt8196/include/platform/lib/clk.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#ifdef __SOF_LIB_CLK_H__ + +#ifndef __PLATFORM_LIB_CLK_H__ +#define __PLATFORM_LIB_CLK_H__ + +#include <stdint.h> + +struct sof; + +#define CPU_DEFAULT_IDX 0 + +#define CLK_CPU(x) (x) +#define CLK_DEFAULT_CPU_HZ 26000000 +#define CLK_MAX_CPU_HZ 800000000 +#define NUM_CLOCKS 1 +#define NUM_CPU_FREQ 2 + +void platform_clock_init(struct sof *sof); + +#endif /* __PLATFORM_LIB_CLK_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/clk.h" + +#endif /* __SOF_LIB_CLK_H__ */ diff --git a/src/platform/mt8196/include/platform/lib/cpu.h b/src/platform/mt8196/include/platform/lib/cpu.h new file mode 100644 index 000000000000..f99974213c2f --- /dev/null +++ b/src/platform/mt8196/include/platform/lib/cpu.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#ifdef __SOF_LIB_CPU_H__ + +#ifndef __PLATFORM_LIB_CPU_H__ +#define __PLATFORM_LIB_CPU_H__ + +/** \brief Id of primary DSP core */ +#define PLATFORM_PRIMARY_CORE_ID 0 + +#endif /* __PLATFORM_LIB_CPU_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/cpu.h" + +#endif /* __SOF_LIB_CPU_H__ */ diff --git a/src/platform/mt8196/include/platform/lib/dai.h b/src/platform/mt8196/include/platform/lib/dai.h new file mode 100644 index 000000000000..e56a35d5ccc1 --- /dev/null +++ b/src/platform/mt8196/include/platform/lib/dai.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#ifdef __SOF_LIB_DAI_H__ + +#ifndef __PLATFORM_LIB_DAI_H__ +#define __PLATFORM_LIB_DAI_H__ + +#endif /* __PLATFORM_LIB_DAI_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/dai.h" + +#endif /* __SOF_LIB_DAI_H__ */ diff --git a/src/platform/mt8196/include/platform/lib/dma.h b/src/platform/mt8196/include/platform/lib/dma.h new file mode 100644 index 000000000000..419f160cbfd9 --- /dev/null +++ b/src/platform/mt8196/include/platform/lib/dma.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#ifdef __SOF_LIB_DMA_H__ + +#ifndef __PLATFORM_LIB_DMA_H__ +#define __PLATFORM_LIB_DMA_H__ + +#define PLATFORM_NUM_DMACS 2 + +/* max number of supported DMA channels */ +#define PLATFORM_MAX_DMA_CHAN 32 + +#define DMA_ID_AFE_MEMIF 0 +#define DMA_ID_HOST 1 + +#define dma_chan_irq(dma, chan) dma_irq(dma) +#define dma_chan_irq_name(dma, chan) dma_irq_name(dma) + +#endif /* __PLATFORM_LIB_DMA_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/dma.h" + +#endif /* __SOF_LIB_DMA_H__ */ diff --git a/src/platform/mt8196/include/platform/lib/mailbox.h b/src/platform/mt8196/include/platform/lib/mailbox.h new file mode 100644 index 000000000000..04896aaa3ee5 --- /dev/null +++ b/src/platform/mt8196/include/platform/lib/mailbox.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#ifdef __SOF_LIB_MAILBOX_H__ + +#ifndef __PLATFORM_LIB_MAILBOX_H__ +#define __PLATFORM_LIB_MAILBOX_H__ + +#include <sof/lib/io.h> +#include <sof/lib/memory.h> +#include <stddef.h> +#include <stdint.h> + +/* + * The Window Region on MT8186 SRAM is organised like this :- + * +--------------------------------------------------------------------------+ + * | Offset | Region | Size | + * +---------------------+----------------+-----------------------------------+ + * | SRAM_OUTBOX_BASE | Outbox | SRAM_MAILBOX_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SRAM_INBOX_BASE | Inbox | SRAM_INBOX_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SRAM_DEBUG_BASE | Debug data | SRAM_DEBUG_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SRAM_EXCEPT_BASE | Except | SRAM_EXCEPT_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SRAM_STREAM_BASE | Stream | SRAM_STREAM_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SRAM_TRACE_BASE | Trace Buffer | SRAM_TRACE_SIZE | + * +---------------------+----------------+-----------------------------------+ + */ + +#define MAILBOX_DSPBOX_SIZE SRAM_OUTBOX_SIZE +#define MAILBOX_DSPBOX_BASE SRAM_OUTBOX_BASE +#define MAILBOX_DSPBOX_OFFSET SRAM_OUTBOX_OFFSET + +#define MAILBOX_HOSTBOX_SIZE SRAM_INBOX_SIZE +#define MAILBOX_HOSTBOX_BASE SRAM_INBOX_BASE +#define MAILBOX_HOSTBOX_OFFSET SRAM_INBOX_OFFSET + +#define MAILBOX_DEBUG_SIZE SRAM_DEBUG_SIZE +#define MAILBOX_DEBUG_BASE SRAM_DEBUG_BASE +#define MAILBOX_DEBUG_OFFSET SRAM_DEBUG_OFFSET + +#define MAILBOX_EXCEPTION_SIZE SRAM_EXCEPT_SIZE +#define MAILBOX_EXCEPTION_BASE SRAM_EXCEPT_BASE +#define MAILBOX_EXCEPTION_OFFSET SRAM_EXCEPT_OFFSET + +#define MAILBOX_STREAM_SIZE SRAM_STREAM_SIZE +#define MAILBOX_STREAM_BASE SRAM_STREAM_BASE +#define MAILBOX_STREAM_OFFSET SRAM_STREAM_OFFSET + +#define MAILBOX_TRACE_SIZE SRAM_TRACE_SIZE +#define MAILBOX_TRACE_BASE SRAM_TRACE_BASE +#define MAILBOX_TRACE_OFFSET SRAM_TRACE_OFFSET + +#define ADSP_IPI_OP_REQ 0x1 +#define ADSP_IPI_OP_RSP 0x2 +void trigger_irq_to_host_req(void); +void trigger_irq_to_host_rsp(void); + +static inline void mailbox_sw_reg_write(size_t offset, uint32_t src) +{ + io_reg_write(MAILBOX_DEBUG_BASE + offset, src); +} + +#endif /* __PLATFORM_LIB_MAILBOX_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/mailbox.h" + +#endif /* __SOF_LIB_MAILBOX_H__ */ diff --git a/src/platform/mt8196/include/platform/lib/memory.h b/src/platform/mt8196/include/platform/lib/memory.h new file mode 100644 index 000000000000..b849fe09cb4f --- /dev/null +++ b/src/platform/mt8196/include/platform/lib/memory.h @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#ifdef __SOF_LIB_MEMORY_H__ + +#ifndef __PLATFORM_LIB_MEMORY_H__ +#define __PLATFORM_LIB_MEMORY_H__ + +#include <rtos/cache.h> + +/* data cache line alignment */ +#define PLATFORM_DCACHE_ALIGN sizeof(void *) + +/* physical DSP addresses */ +#define SRAM_BASE 0x4e100000 +#define SRAM_SIZE 0x80000 + +/* reset vector + rodata + module_init + text + data + bss */ +#define SOF_DATA_SIZE 0x80000 +#define VECTOR_SIZE 0x700 +#define SRAM_START (SRAM_BASE + VECTOR_SIZE) + +#define DRAM_BASE 0x90000000 +#define DRAM0_SIZE 0x500000 +#define MAILBOX_BASE (DRAM_BASE + DRAM0_SIZE) +#define DSP_SYS_SIZE 0xA00000 + +#define UUID_ENTRY_ELF_BASE (SRAM_BASE + SOF_DATA_SIZE) +#define UUID_ENTRY_ELF_SIZE 0x6000 + +#define LOG_ENTRY_ELF_BASE (UUID_ENTRY_ELF_BASE + UUID_ENTRY_ELF_SIZE) +#define LOG_ENTRY_ELF_SIZE 0x20000 +#define EXT_MANIFEST_ELF_BASE (LOG_ENTRY_ELF_BASE + LOG_ENTRY_ELF_SIZE) +#define EXT_MANIFEST_ELF_SIZE (SRAM_BASE + SRAM_SIZE - EXT_MANIFEST_ELF_BASE) + +/* + * The Memory Layout on MT8189 are organised like this :- + * + * +--------------------------------------------------------------------------+ + * | Offset | Region | Size | + * +---------------------+----------------+-----------------------------------+ + * | SRAM_START | RO Data | SOF_DATA_SIZE | + * | | text | | + * | | Data | | + * | | BSS | | + * +---------------------+----------------+-----------------------------------+ + * | fw_ready | + * +---------------------+----------------+-----------------------------------+ + * | static_uuid | + * +---------------------+----------------+-----------------------------------+ + * | static_log | + * +---------------------+----------------+-----------------------------------+ + * | fw_metadata | + * +---------------------+----------------+-----------------------------------+ + * + * +---------------------+----------------+-----------------------------------+ + * | SOF_DRAM_BASE | | SOF_DRAM_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | HEAP_SYSTEM_BASE | System Heap | HEAP_SYSTEM_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | HEAP_RUNTIME_BASE | Runtime Heap | HEAP_RUNTIME_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | HEAP_BUFFER_BASE | Module Buffers | HEAP_BUFFER_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SOF_STACK_END | Stack | SOF_STACK_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SOF_STACK_BASE | | | + * +---------------------+----------------+-----------------------------------+ + * | MAILBOX_BASE | | SOF_MAILBOX_SIZE | + * +---------------------+----------------+-----------------------------------+ + */ + +#define SRAM_OUTBOX_BASE MAILBOX_BASE +#define SRAM_OUTBOX_SIZE 0x1000 +#define SRAM_OUTBOX_OFFSET 0 + +#define SRAM_INBOX_BASE (SRAM_OUTBOX_BASE + SRAM_OUTBOX_SIZE) +#define SRAM_INBOX_SIZE 0x1000 +#define SRAM_INBOX_OFFSET SRAM_OUTBOX_SIZE + +#define SRAM_DEBUG_BASE (SRAM_INBOX_BASE + SRAM_INBOX_SIZE) +#define SRAM_DEBUG_SIZE 0x800 +#define SRAM_DEBUG_OFFSET (SRAM_INBOX_OFFSET + SRAM_INBOX_SIZE) + +#define SRAM_EXCEPT_BASE (SRAM_DEBUG_BASE + SRAM_DEBUG_SIZE) +#define SRAM_EXCEPT_SIZE 0x800 +#define SRAM_EXCEPT_OFFSET (SRAM_DEBUG_OFFSET + SRAM_DEBUG_SIZE) + +#define SRAM_STREAM_BASE (SRAM_EXCEPT_BASE + SRAM_EXCEPT_SIZE) +#define SRAM_STREAM_SIZE 0x1000 +#define SRAM_STREAM_OFFSET (SRAM_EXCEPT_OFFSET + SRAM_EXCEPT_SIZE) + +#define SRAM_TRACE_BASE (SRAM_STREAM_BASE + SRAM_STREAM_SIZE) +#define SRAM_TRACE_SIZE 0x1000 +#define SRAM_TRACE_OFFSET (SRAM_STREAM_OFFSET + SRAM_STREAM_SIZE) + +/*4K + 4K +2K + 2K + 4K + 4K = 20KB*/ +#define SOF_MAILBOX_SIZE \ + (SRAM_INBOX_SIZE + SRAM_OUTBOX_SIZE + SRAM_DEBUG_SIZE + \ + SRAM_EXCEPT_SIZE + SRAM_STREAM_SIZE + SRAM_TRACE_SIZE) + +/* SOF image on DRAM */ +#define SOF_DRAM_BASE DRAM_BASE +#define SOF_DRAM_SIZE 0x100000 + +/* Heap section sizes for module pool */ +#define HEAP_RT_COUNT8 0 +#define HEAP_RT_COUNT16 48 +#define HEAP_RT_COUNT32 48 +#define HEAP_RT_COUNT64 32 +#define HEAP_RT_COUNT128 32 +#define HEAP_RT_COUNT256 32 +#define HEAP_RT_COUNT512 32 +#define HEAP_RT_COUNT1024 4 +#define HEAP_RT_COUNT2048 2 +#define HEAP_RT_COUNT4096 2 + +/* Heap section sizes for system runtime heap */ +#define HEAP_SYS_RT_COUNT64 128 +#define HEAP_SYS_RT_COUNT512 16 +#define HEAP_SYS_RT_COUNT1024 8 + +/* Heap configuration */ + +#define HEAP_SYSTEM_BASE (SOF_DRAM_BASE + SOF_DRAM_SIZE) +#define HEAP_SYSTEM_SIZE 0x6000 + +#define HEAP_SYS_RUNTIME_BASE (HEAP_SYSTEM_BASE + HEAP_SYSTEM_SIZE) +/*24KB*/ +#define HEAP_SYS_RUNTIME_SIZE \ + (HEAP_SYS_RT_COUNT64 * 64 + HEAP_SYS_RT_COUNT512 * 512 + \ + HEAP_SYS_RT_COUNT1024 * 1024) + +#define HEAP_RUNTIME_BASE (HEAP_SYS_RUNTIME_BASE + HEAP_SYS_RUNTIME_SIZE) +/*48*(16 +32) + 32*(64 128+256) + 4*(512+1024) + 1*2048 = 24832 = 24.25KB*/ +#define HEAP_RUNTIME_SIZE \ + (HEAP_RT_COUNT8 * 8 + HEAP_RT_COUNT16 * 16 + \ + HEAP_RT_COUNT32 * 32 + HEAP_RT_COUNT64 * 64 + \ + HEAP_RT_COUNT128 * 128 + HEAP_RT_COUNT256 * 256 + \ + HEAP_RT_COUNT512 * 512 + HEAP_RT_COUNT1024 * 1024 + \ + HEAP_RT_COUNT2048 * 2048 + HEAP_RT_COUNT4096 * 4096) + +#define HEAP_BUFFER_BASE (HEAP_RUNTIME_BASE + HEAP_RUNTIME_SIZE) +#define HEAP_BUFFER_SIZE \ + (DRAM0_SIZE - SOF_DRAM_SIZE - HEAP_RUNTIME_SIZE - SOF_STACK_TOTAL_SIZE - \ + HEAP_SYS_RUNTIME_SIZE - HEAP_SYSTEM_SIZE) + +#define HEAP_BUFFER_BLOCK_SIZE 0x100 +#define HEAP_BUFFER_COUNT (HEAP_BUFFER_SIZE / HEAP_BUFFER_BLOCK_SIZE) + +#define PLATFORM_HEAP_SYSTEM 1 /* one per core */ +#define PLATFORM_HEAP_SYSTEM_RUNTIME 1 /* one per core */ +#define PLATFORM_HEAP_RUNTIME 1 +#define PLATFORM_HEAP_BUFFER 1 + +/* Stack configuration */ +#define SOF_STACK_SIZE (CONFIG_SOF_STACK_SIZE) +#define SOF_STACK_TOTAL_SIZE SOF_STACK_SIZE /*4KB*/ +#define SOF_STACK_BASE (DRAM_BASE + DRAM0_SIZE) +#define SOF_STACK_END (SOF_STACK_BASE - SOF_STACK_TOTAL_SIZE) + +/* Vector and literal sizes - not in core-isa.h */ +#define SOF_MEM_VECT_LIT_SIZE 0x4 +#define SOF_MEM_VECT_TEXT_SIZE 0x1c +#define SOF_MEM_VECT_SIZE (SOF_MEM_VECT_TEXT_SIZE + SOF_MEM_VECT_LIT_SIZE) + +#define SOF_MEM_RESET_TEXT_SIZE 0x2e0 +#define SOF_MEM_RESET_LIT_SIZE 0x120 +#define SOF_MEM_VECBASE_LIT_SIZE 0x178 + +#define SOF_MEM_RO_SIZE 0x8 + +#define HEAP_BUF_ALIGNMENT DCACHE_LINE_SIZE + +/** \brief EDF task's default stack size in bytes. */ +#define PLATFORM_TASK_DEFAULT_STACK_SIZE 3072 + +#if !defined(__ASSEMBLER__) && !defined(LINKER) + +struct sof; + +/** + * \brief Data shared between different cores. + * Does nothing, since mt8186 doesn't support SMP. + */ +#define SHARED_DATA + +void platform_init_memmap(struct sof *sof); + +#define uncache_to_cache(address) address +#define cache_to_uncache(address) address +#define cache_to_uncache_init(address) address +#define is_uncached(address) 0 + +/** + * \brief Function for keeping shared data synchronized. + * It's used after usage of data shared by different cores. + * Such data is either statically marked with SHARED_DATA + * or dynamically allocated with SOF_MEM_FLAG_SHARED flag. + * Does nothing, since mt8186 doesn't support SMP. + */ + +static inline void *platform_rfree_prepare(void *ptr) +{ + return ptr; +} + +#endif + +#define host_to_local(addr) (addr) +#define local_to_host(addr) (addr) + +#endif /* __PLATFORM_LIB_MEMORY_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/memory.h" + +#endif /* __SOF_LIB_MEMORY_H__ */ diff --git a/src/platform/mt8196/include/platform/lib/pm_runtime.h b/src/platform/mt8196/include/platform/lib/pm_runtime.h new file mode 100644 index 000000000000..7d6213823fd6 --- /dev/null +++ b/src/platform/mt8196/include/platform/lib/pm_runtime.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#ifdef __SOF_LIB_PM_RUNTIME_H__ + +#ifndef __PLATFORM_LIB_PM_RUNTIME_H__ +#define __PLATFORM_LIB_PM_RUNTIME_H__ + +#include <stdint.h> + +struct pm_runtime_data; + +/** + * \brief Initializes platform specific runtime power management. + * \param[in,out] prd Runtime power management data. + */ +static inline void platform_pm_runtime_init(struct pm_runtime_data *prd) +{ +} + +/** + * \brief Retrieves platform specific power management resource. + * + * \param[in] context Type of power management context. + * \param[in] index The index of the device. + * \param[in] flags The flags, set of RPM_... + */ +static inline void platform_pm_runtime_get(uint32_t context, uint32_t index, uint32_t flags) +{ +} + +/** + * \brief Releases platform specific power management resource. + * + * \param[in] context Type of power management context. + * \param[in] index The index of the device. + * \param[in] flags The flags, set of RPM_... + */ +static inline void platform_pm_runtime_put(uint32_t context, uint32_t index, uint32_t flags) +{ +} + +static inline void platform_pm_runtime_enable(uint32_t context, uint32_t index) +{ +} + +static inline void platform_pm_runtime_disable(uint32_t context, uint32_t index) +{ +} + +static inline bool platform_pm_runtime_is_active(uint32_t context, uint32_t index) +{ + return false; +} + +#endif /* __PLATFORM_LIB_PM_RUNTIME_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/pm_runtime.h" + +#endif /* __SOF_LIB_PM_RUNTIME_H__ */ diff --git a/src/platform/mt8196/include/platform/mt8196-afe-common.h b/src/platform/mt8196/include/platform/mt8196-afe-common.h new file mode 100755 index 000000000000..e75195b50bd4 --- /dev/null +++ b/src/platform/mt8196/include/platform/mt8196-afe-common.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Darren Ye <darren.ye@mediatek.com> + */ + +#ifndef _MT_8196_AFE_COMMON_H_ +#define _MT_8196_AFE_COMMON_H_ + +enum { + MT8196_MEMIF_START, + MT8196_MEMIF_DL_START = MT8196_MEMIF_START, + MT8196_MEMIF_DL1 = MT8196_MEMIF_DL_START, + MT8196_MEMIF_DL_24CH, + MT8196_MEMIF_DL_END, + MT8196_MEMIF_UL_START = MT8196_MEMIF_DL_END, + MT8196_MEMIF_UL0 = MT8196_MEMIF_UL_START, + MT8196_MEMIF_UL1, + MT8196_MEMIF_UL2, + MT8196_MEMIF_UL_END, + MT8196_MEMIF_END = MT8196_MEMIF_UL_END, + MT8196_MEMIF_DL_NUM = (MT8196_MEMIF_DL_END - MT8196_MEMIF_DL_START), + MT8196_MEMIF_UL_NUM = (MT8196_MEMIF_UL_END - MT8196_MEMIF_UL_START), + MT8196_MEMIF_NUM = (MT8196_MEMIF_END - MT8196_MEMIF_START), +}; + +/* update irq ID (= enum) from AFE_IRQ_MCU_STATUS */ +enum { + MT8196_IRQ_0, + MT8196_IRQ_1, + MT8196_IRQ_2, + MT8196_IRQ_3, + MT8196_IRQ_4, + MT8196_IRQ_5, + MT8196_IRQ_6, + MT8196_IRQ_7, + MT8196_IRQ_8, + MT8196_IRQ_9, + MT8196_IRQ_10, + MT8196_IRQ_11, + MT8196_IRQ_12, + MT8196_IRQ_13, + MT8196_IRQ_14, + MT8196_IRQ_15, + MT8196_IRQ_16, + MT8196_IRQ_17, + MT8196_IRQ_18, + MT8196_IRQ_19, + MT8196_IRQ_20, + MT8196_IRQ_21, + MT8196_IRQ_22, + MT8196_IRQ_23, + MT8196_IRQ_24, + MT8196_IRQ_25, + MT8196_IRQ_26, + MT8196_IRQ_31, /* used only for TDM */ + MT8196_IRQ_NUM, +}; + +enum { + MT8196_DAI_I2S_OUT4, /* speaker */ + MT8196_DAI_I2S_OUT6, /* headset out */ + MT8196_DAI_AP_DMIC, /* DMIC */ + MT8196_DAI_I2S_IN6, /* headset mic */ + MT8196_DAI_AP_DMIC_CH34, + MT8196_DAI_NUM, +}; + +#endif diff --git a/src/platform/mt8196/include/platform/mt8196-afe-reg.h b/src/platform/mt8196/include/platform/mt8196-afe-reg.h new file mode 100755 index 000000000000..10c4237dd6b5 --- /dev/null +++ b/src/platform/mt8196/include/platform/mt8196-afe-reg.h @@ -0,0 +1,2979 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Darren Ye <darren.ye@mediatek.com> + */ + +#ifndef _MT8196_AFE_REG_H_ +#define _MT8196_AFE_REG_H_ + +#define AFE_BASE_ADDR 0x1A110000 + +/***************************************************************************** + * R E G I S T E R D E F I N I T I O N + *****************************************************************************/ +/* AFE_DL1_BASE_MSB */ +#define DL1_BASE_ADDR_MSB_SFT 0 +#define DL1_BASE_ADDR_MSB_MASK 0x1ff +#define DL1_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_DL1_BASE */ +#define DL1_BASE_ADDR_SFT 4 +#define DL1_BASE_ADDR_MASK 0xfffffff +#define DL1_BASE_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_DL1_CUR_MSB */ +#define DL1_CUR_PTR_MSB_SFT 0 +#define DL1_CUR_PTR_MSB_MASK 0x1ff +#define DL1_CUR_PTR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_DL1_CUR */ +#define DL1_CUR_PTR_SFT 0 +#define DL1_CUR_PTR_MASK 0xffffffff +#define DL1_CUR_PTR_MASK_SFT (0xffffffff << 0) + +/* AFE_DL1_END_MSB */ +#define DL1_END_ADDR_MSB_SFT 0 +#define DL1_END_ADDR_MSB_MASK 0x1ff +#define DL1_END_ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_DL1_END */ +#define DL1_END_ADDR_SFT 4 +#define DL1_END_ADDR_MASK 0xfffffff +#define DL1_END_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_DL1_RCH_MON */ +#define DL1_RCH_DATA_SFT 0 +#define DL1_RCH_DATA_MASK 0xffffffff +#define DL1_RCH_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL1_LCH_MON */ +#define DL1_LCH_DATA_SFT 0 +#define DL1_LCH_DATA_MASK 0xffffffff +#define DL1_LCH_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL1_CON0 */ +#define DL1_ON_SFT 28 +#define DL1_ON_MASK 0x1 +#define DL1_ON_MASK_SFT (0x1 << 28) +#define DL1_ONE_HEART_SEL_SFT 22 +#define DL1_ONE_HEART_SEL_MASK 0x3 +#define DL1_ONE_HEART_SEL_MASK_SFT (0x3 << 22) +#define DL1_MINLEN_SFT 20 +#define DL1_MINLEN_MASK 0x3 +#define DL1_MINLEN_MASK_SFT (0x3 << 20) +#define DL1_MAXLEN_SFT 16 +#define DL1_MAXLEN_MASK 0x3 +#define DL1_MAXLEN_MASK_SFT (0x3 << 16) +#define DL1_SEL_DOMAIN_SFT 13 +#define DL1_SEL_DOMAIN_MASK 0x7 +#define DL1_SEL_DOMAIN_MASK_SFT (0x7 << 13) +#define DL1_SEL_FS_SFT 8 +#define DL1_SEL_FS_MASK 0x1f +#define DL1_SEL_FS_MASK_SFT (0x1f << 8) +#define DL1_SW_CLEAR_BUF_EMPTY_SFT 7 +#define DL1_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL1_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7) +#define DL1_PBUF_SIZE_SFT 5 +#define DL1_PBUF_SIZE_MASK 0x3 +#define DL1_PBUF_SIZE_MASK_SFT (0x3 << 5) +#define DL1_MONO_SFT 4 +#define DL1_MONO_MASK 0x1 +#define DL1_MONO_MASK_SFT (0x1 << 4) +#define DL1_NORMAL_MODE_SFT 3 +#define DL1_NORMAL_MODE_MASK 0x1 +#define DL1_NORMAL_MODE_MASK_SFT (0x1 << 3) +#define DL1_HALIGN_SFT 2 +#define DL1_HALIGN_MASK 0x1 +#define DL1_HALIGN_MASK_SFT (0x1 << 2) +#define DL1_HD_MODE_SFT 0 +#define DL1_HD_MODE_MASK 0x3 +#define DL1_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL_24CH_BASE_MSB */ +#define DL_24CH_BASE__ADDR_MSB_SFT 0 +#define DL_24CH_BASE__ADDR_MSB_MASK 0x1ff +#define DL_24CH_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_DL_24CH_BASE */ +#define DL_24CH_BASE_ADDR_SFT 4 +#define DL_24CH_BASE_ADDR_MASK 0xfffffff +#define DL_24CH_BASE_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_DL_24CH_CUR_MSB */ +#define DL_24CH_CUR_PTR_MSB_SFT 0 +#define DL_24CH_CUR_PTR_MSB_MASK 0x1ff +#define DL_24CH_CUR_PTR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_DL_24CH_CUR */ +#define DL_24CH_CUR_PTR_SFT 0 +#define DL_24CH_CUR_PTR_MASK 0xffffffff +#define DL_24CH_CUR_PTR_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_END_MSB */ +#define DL_24CH_END_ADDR_MSB_SFT 0 +#define DL_24CH_END_ADDR_MSB_MASK 0x1ff +#define DL_24CH_END_ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_DL_24CH_END */ +#define DL_24CH_END_ADDR_SFT 4 +#define DL_24CH_END_ADDR_MASK 0xfffffff +#define DL_24CH_END_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_DL_24CH_CON0 */ +#define DL_24CH_ON_SFT 31 +#define DL_24CH_ON_MASK 0x1 +#define DL_24CH_ON_MASK_SFT (0x1 << 31) +#define DL_24CH_NUM_SFT 24 +#define DL_24CH_NUM_MASK 0x3f +#define DL_24CH_NUM_MASK_SFT (0x3f << 24) +#define DL_24CH_ONE_HEART_SEL_SFT 22 +#define DL_24CH_ONE_HEART_SEL_MASK 0x3 +#define DL_24CH_ONE_HEART_SEL_MASK_SFT (0x3 << 22) +#define DL_24CH_MINLEN_SFT 20 +#define DL_24CH_MINLEN_MASK 0x3 +#define DL_24CH_MINLEN_MASK_SFT (0x3 << 20) +#define DL_24CH_MAXLEN_SFT 16 +#define DL_24CH_MAXLEN_MASK 0x3 +#define DL_24CH_MAXLEN_MASK_SFT (0x3 << 16) +#define DL_24CH_SEL_DOMAIN_SFT 13 +#define DL_24CH_SEL_DOMAIN_MASK 0x7 +#define DL_24CH_SEL_DOMAIN_MASK_SFT (0x7 << 13) +#define DL_24CH_SEL_FS_SFT 8 +#define DL_24CH_SEL_FS_MASK 0x1f +#define DL_24CH_SEL_FS_MASK_SFT (0x1f << 8) +#define DL_24CH_BUF_EMPTY_CLR_SFT 7 +#define DL_24CH_BUF_EMPTY_CLR_MASK 0x1 +#define DL_24CH_BUF_EMPTY_CLR_MASK_SFT (0x1 << 7) +#define DL_24CH_PBUF_SIZE_SFT 5 +#define DL_24CH_PBUF_SIZE_MASK 0x3 +#define DL_24CH_PBUF_SIZE_MASK_SFT (0x3 << 5) +#define DL_24CH_HANG_CLR_SFT 4 +#define DL_24CH_HANG_CLR_MASK 0x1 +#define DL_24CH_HANG_CLR_MASK_SFT (0x1 << 4) +#define DL_24CH_NORMAL_MODE_SFT 3 +#define DL_24CH_NORMAL_MODE_MASK 0x1 +#define DL_24CH_NORMAL_MODE_MASK_SFT (0x1 << 3) +#define DL_24CH_HALIGN_SFT 2 +#define DL_24CH_HALIGN_MASK 0x1 +#define DL_24CH_HALIGN_MASK_SFT (0x1 << 2) +#define DL_24CH_HD_MODE_SFT 0 +#define DL_24CH_HD_MODE_MASK 0x3 +#define DL_24CH_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL24_BASE_MSB */ +#define DL24_BASE__ADDR_MSB_SFT 0 +#define DL24_BASE__ADDR_MSB_MASK 0x1ff +#define DL24_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_DL24_BASE */ +#define DL24_BASE_ADDR_SFT 4 +#define DL24_BASE_ADDR_MASK 0xfffffff +#define DL24_BASE_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_DL24_CUR_MSB */ +#define DL24_CUR_PTR_MSB_SFT 0 +#define DL24_CUR_PTR_MSB_MASK 0x1ff +#define DL24_CUR_PTR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_DL24_CUR */ +#define DL24_CUR_PTR_SFT 0 +#define DL24_CUR_PTR_MASK 0xffffffff +#define DL24_CUR_PTR_MASK_SFT (0xffffffff << 0) + +/* AFE_DL24_END_MSB */ +#define DL24_END_ADDR_MSB_SFT 0 +#define DL24_END_ADDR_MSB_MASK 0x1ff +#define DL24_END_ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_DL24_END */ +#define DL24_END_ADDR_SFT 4 +#define DL24_END_ADDR_MASK 0xfffffff +#define DL24_END_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_DL24_RCH_MON */ +#define DL24_RCH_DATA_SFT 0 +#define DL24_RCH_DATA_MASK 0xffffffff +#define DL24_RCH_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL24_LCH_MON */ +#define DL24_LCH_DATA_SFT 0 +#define DL24_LCH_DATA_MASK 0xffffffff +#define DL24_LCH_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL24_CON0 */ +#define DL24_ON_SFT 28 +#define DL24_ON_MASK 0x1 +#define DL24_ON_MASK_SFT (0x1 << 28) +#define DL24_ONE_HEART_SEL_SFT 22 +#define DL24_ONE_HEART_SEL_MASK 0x3 +#define DL24_ONE_HEART_SEL_MASK_SFT (0x3 << 22) +#define DL24_MINLEN_SFT 20 +#define DL24_MINLEN_MASK 0x3 +#define DL24_MINLEN_MASK_SFT (0x3 << 20) +#define DL24_MAXLEN_SFT 16 +#define DL24_MAXLEN_MASK 0x3 +#define DL24_MAXLEN_MASK_SFT (0x3 << 16) +#define DL24_SEL_DOMAIN_SFT 13 +#define DL24_SEL_DOMAIN_MASK 0x7 +#define DL24_SEL_DOMAIN_MASK_SFT (0x7 << 13) +#define DL24_SEL_FS_SFT 8 +#define DL24_SEL_FS_MASK 0x1f +#define DL24_SEL_FS_MASK_SFT (0x1f << 8) +#define DL24_SW_CLEAR_BUF_EMPTY_SFT 7 +#define DL24_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL24_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7) +#define DL24_PBUF_SIZE_SFT 5 +#define DL24_PBUF_SIZE_MASK 0x3 +#define DL24_PBUF_SIZE_MASK_SFT (0x3 << 5) +#define DL24_MONO_SFT 4 +#define DL24_MONO_MASK 0x1 +#define DL24_MONO_MASK_SFT (0x1 << 4) +#define DL24_NORMAL_MODE_SFT 3 +#define DL24_NORMAL_MODE_MASK 0x1 +#define DL24_NORMAL_MODE_MASK_SFT (0x1 << 3) +#define DL24_HALIGN_SFT 2 +#define DL24_HALIGN_MASK 0x1 +#define DL24_HALIGN_MASK_SFT (0x1 << 2) +#define DL24_HD_MODE_SFT 0 +#define DL24_HD_MODE_MASK 0x3 +#define DL24_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL0_BASE_MSB */ +#define VUL0_BASE_ADDR_MSB_SFT 0 +#define VUL0_BASE_ADDR_MSB_MASK 0x1ff +#define VUL0_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_VUL0_BASE */ +#define VUL0_BASE_ADDR_SFT 4 +#define VUL0_BASE_ADDR_MASK 0xfffffff +#define VUL0_BASE_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_VUL0_CUR_MSB */ +#define VUL0_CUR_PTR_MSB_SFT 0 +#define VUL0_CUR_PTR_MSB_MASK 0x1ff +#define VUL0_CUR_PTR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_VUL0_CUR */ +#define VUL0_CUR_PTR_SFT 0 +#define VUL0_CUR_PTR_MASK 0xffffffff +#define VUL0_CUR_PTR_MASK_SFT (0xffffffff << 0) + +/* AFE_VUL0_END_MSB */ +#define VUL0_END_ADDR_MSB_SFT 0 +#define VUL0_END_ADDR_MSB_MASK 0x1ff +#define VUL0_END_ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_VUL0_END */ +#define VUL0_END_ADDR_SFT 4 +#define VUL0_END_ADDR_MASK 0xfffffff +#define VUL0_END_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_VUL0_RCH_MON */ +#define VUL0_RCH_DATA_SFT 0 +#define VUL0_RCH_DATA_MASK 0xffffffff +#define VUL0_RCH_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_VUL0_LCH_MON */ +#define VUL0_LCH_DATA_SFT 0 +#define VUL0_LCH_DATA_MASK 0xffffffff +#define VUL0_LCH_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_VUL0_CON0 */ +#define VUL0_ON_SFT 28 +#define VUL0_ON_MASK 0x1 +#define VUL0_ON_MASK_SFT (0x1 << 28) +#define VUL0_MINLEN_SFT 20 +#define VUL0_MINLEN_MASK 0x3 +#define VUL0_MINLEN_MASK_SFT (0x3 << 20) +#define VUL0_MAXLEN_SFT 16 +#define VUL0_MAXLEN_MASK 0x3 +#define VUL0_MAXLEN_MASK_SFT (0x3 << 16) +#define VUL0_SEL_DOMAIN_SFT 13 +#define VUL0_SEL_DOMAIN_MASK 0x7 +#define VUL0_SEL_DOMAIN_MASK_SFT (0x7 << 13) +#define VUL0_SEL_FS_SFT 8 +#define VUL0_SEL_FS_MASK 0x1f +#define VUL0_SEL_FS_MASK_SFT (0x1f << 8) +#define VUL0_SW_CLEAR_BUF_FULL_SFT 7 +#define VUL0_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL0_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7) +#define VUL0_WR_SIGN_SFT 6 +#define VUL0_WR_SIGN_MASK 0x1 +#define VUL0_WR_SIGN_MASK_SFT (0x1 << 6) +#define VUL0_R_MONO_SFT 5 +#define VUL0_R_MONO_MASK 0x1 +#define VUL0_R_MONO_MASK_SFT (0x1 << 5) +#define VUL0_MONO_SFT 4 +#define VUL0_MONO_MASK 0x1 +#define VUL0_MONO_MASK_SFT (0x1 << 4) +#define VUL0_NORMAL_MODE_SFT 3 +#define VUL0_NORMAL_MODE_MASK 0x1 +#define VUL0_NORMAL_MODE_MASK_SFT (0x1 << 3) +#define VUL0_HALIGN_SFT 2 +#define VUL0_HALIGN_MASK 0x1 +#define VUL0_HALIGN_MASK_SFT (0x1 << 2) +#define VUL0_HD_MODE_SFT 0 +#define VUL0_HD_MODE_MASK 0x3 +#define VUL0_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL1_BASE_MSB */ +#define VUL1_BASE_ADDR_MSB_SFT 0 +#define VUL1_BASE_ADDR_MSB_MASK 0x1ff +#define VUL1_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_VUL1_BASE */ +#define VUL1_BASE_ADDR_SFT 4 +#define VUL1_BASE_ADDR_MASK 0xfffffff +#define VUL1_BASE_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_VUL1_CUR_MSB */ +#define VUL1_CUR_PTR_MSB_SFT 0 +#define VUL1_CUR_PTR_MSB_MASK 0x1ff +#define VUL1_CUR_PTR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_VUL1_CUR */ +#define VUL1_CUR_PTR_SFT 0 +#define VUL1_CUR_PTR_MASK 0xffffffff +#define VUL1_CUR_PTR_MASK_SFT (0xffffffff << 0) + +/* AFE_VUL1_END_MSB */ +#define VUL1_END_ADDR_MSB_SFT 0 +#define VUL1_END_ADDR_MSB_MASK 0x1ff +#define VUL1_END_ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_VUL1_END */ +#define VUL1_END_ADDR_SFT 4 +#define VUL1_END_ADDR_MASK 0xfffffff +#define VUL1_END_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_VUL1_RCH_MON */ +#define VUL1_RCH_DATA_SFT 0 +#define VUL1_RCH_DATA_MASK 0xffffffff +#define VUL1_RCH_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_VUL1_LCH_MON */ +#define VUL1_LCH_DATA_SFT 0 +#define VUL1_LCH_DATA_MASK 0xffffffff +#define VUL1_LCH_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_VUL1_CON0 */ +#define VUL1_ON_SFT 28 +#define VUL1_ON_MASK 0x1 +#define VUL1_ON_MASK_SFT (0x1 << 28) +#define VUL1_MINLEN_SFT 20 +#define VUL1_MINLEN_MASK 0x3 +#define VUL1_MINLEN_MASK_SFT (0x3 << 20) +#define VUL1_MAXLEN_SFT 16 +#define VUL1_MAXLEN_MASK 0x3 +#define VUL1_MAXLEN_MASK_SFT (0x3 << 16) +#define VUL1_SEL_DOMAIN_SFT 13 +#define VUL1_SEL_DOMAIN_MASK 0x7 +#define VUL1_SEL_DOMAIN_MASK_SFT (0x7 << 13) +#define VUL1_SEL_FS_SFT 8 +#define VUL1_SEL_FS_MASK 0x1f +#define VUL1_SEL_FS_MASK_SFT (0x1f << 8) +#define VUL1_SW_CLEAR_BUF_FULL_SFT 7 +#define VUL1_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL1_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7) +#define VUL1_WR_SIGN_SFT 6 +#define VUL1_WR_SIGN_MASK 0x1 +#define VUL1_WR_SIGN_MASK_SFT (0x1 << 6) +#define VUL1_R_MONO_SFT 5 +#define VUL1_R_MONO_MASK 0x1 +#define VUL1_R_MONO_MASK_SFT (0x1 << 5) +#define VUL1_MONO_SFT 4 +#define VUL1_MONO_MASK 0x1 +#define VUL1_MONO_MASK_SFT (0x1 << 4) +#define VUL1_NORMAL_MODE_SFT 3 +#define VUL1_NORMAL_MODE_MASK 0x1 +#define VUL1_NORMAL_MODE_MASK_SFT (0x1 << 3) +#define VUL1_HALIGN_SFT 2 +#define VUL1_HALIGN_MASK 0x1 +#define VUL1_HALIGN_MASK_SFT (0x1 << 2) +#define VUL1_HD_MODE_SFT 0 +#define VUL1_HD_MODE_MASK 0x3 +#define VUL1_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL2_BASE_MSB */ +#define VUL2_BASE_ADDR_MSB_SFT 0 +#define VUL2_BASE_ADDR_MSB_MASK 0x1ff +#define VUL2_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_VUL2_BASE */ +#define VUL2_BASE_ADDR_SFT 4 +#define VUL2_BASE_ADDR_MASK 0xfffffff +#define VUL2_BASE_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_VUL2_CUR_MSB */ +#define VUL2_CUR_PTR_MSB_SFT 0 +#define VUL2_CUR_PTR_MSB_MASK 0x1ff +#define VUL2_CUR_PTR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_VUL2_CUR */ +#define VUL2_CUR_PTR_SFT 0 +#define VUL2_CUR_PTR_MASK 0xffffffff +#define VUL2_CUR_PTR_MASK_SFT (0xffffffff << 0) + +/* AFE_VUL2_END_MSB */ +#define VUL2_END_ADDR_MSB_SFT 0 +#define VUL2_END_ADDR_MSB_MASK 0x1ff +#define VUL2_END_ADDR_MSB_MASK_SFT (0x1ff << 0) + +/* AFE_VUL2_END */ +#define VUL2_END_ADDR_SFT 4 +#define VUL2_END_ADDR_MASK 0xfffffff +#define VUL2_END_ADDR_MASK_SFT (0xfffffff << 4) + +/* AFE_VUL2_RCH_MON */ +#define VUL2_RCH_DATA_SFT 0 +#define VUL2_RCH_DATA_MASK 0xffffffff +#define VUL2_RCH_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_VUL2_LCH_MON */ +#define VUL2_LCH_DATA_SFT 0 +#define VUL2_LCH_DATA_MASK 0xffffffff +#define VUL2_LCH_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_VUL2_CON0 */ +#define VUL2_ON_SFT 28 +#define VUL2_ON_MASK 0x1 +#define VUL2_ON_MASK_SFT (0x1 << 28) +#define VUL2_MINLEN_SFT 20 +#define VUL2_MINLEN_MASK 0x3 +#define VUL2_MINLEN_MASK_SFT (0x3 << 20) +#define VUL2_MAXLEN_SFT 16 +#define VUL2_MAXLEN_MASK 0x3 +#define VUL2_MAXLEN_MASK_SFT (0x3 << 16) +#define VUL2_SEL_DOMAIN_SFT 13 +#define VUL2_SEL_DOMAIN_MASK 0x7 +#define VUL2_SEL_DOMAIN_MASK_SFT (0x7 << 13) +#define VUL2_SEL_FS_SFT 8 +#define VUL2_SEL_FS_MASK 0x1f +#define VUL2_SEL_FS_MASK_SFT (0x1f << 8) +#define VUL2_SW_CLEAR_BUF_FULL_SFT 7 +#define VUL2_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL2_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7) +#define VUL2_WR_SIGN_SFT 6 +#define VUL2_WR_SIGN_MASK 0x1 +#define VUL2_WR_SIGN_MASK_SFT (0x1 << 6) +#define VUL2_R_MONO_SFT 5 +#define VUL2_R_MONO_MASK 0x1 +#define VUL2_R_MONO_MASK_SFT (0x1 << 5) +#define VUL2_MONO_SFT 4 +#define VUL2_MONO_MASK 0x1 +#define VUL2_MONO_MASK_SFT (0x1 << 4) +#define VUL2_NORMAL_MODE_SFT 3 +#define VUL2_NORMAL_MODE_MASK 0x1 +#define VUL2_NORMAL_MODE_MASK_SFT (0x1 << 3) +#define VUL2_HALIGN_SFT 2 +#define VUL2_HALIGN_MASK 0x1 +#define VUL2_HALIGN_MASK_SFT (0x1 << 2) +#define VUL2_HD_MODE_SFT 0 +#define VUL2_HD_MODE_MASK 0x3 +#define VUL2_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL_24CH_CH0_MON */ +#define DL_24CH_CH0_DATA_SFT 0 +#define DL_24CH_CH0_DATA_MASK 0xffffffff +#define DL_24CH_CH0_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH1_MON */ +#define DL_24CH_CH1_DATA_SFT 0 +#define DL_24CH_CH1_DATA_MASK 0xffffffff +#define DL_24CH_CH1_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH2_MON */ +#define DL_24CH_CH2_DATA_SFT 0 +#define DL_24CH_CH2_DATA_MASK 0xffffffff +#define DL_24CH_CH2_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH3_MON */ +#define DL_24CH_CH3_DATA_SFT 0 +#define DL_24CH_CH3_DATA_MASK 0xffffffff +#define DL_24CH_CH3_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH4_MON */ +#define DL_24CH_CH4_DATA_SFT 0 +#define DL_24CH_CH4_DATA_MASK 0xffffffff +#define DL_24CH_CH4_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH5_MON */ +#define DL_24CH_CH5_DATA_SFT 0 +#define DL_24CH_CH5_DATA_MASK 0xffffffff +#define DL_24CH_CH5_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH6_MON */ +#define DL_24CH_CH6_DATA_SFT 0 +#define DL_24CH_CH6_DATA_MASK 0xffffffff +#define DL_24CH_CH6_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH7_MON */ +#define DL_24CH_CH7_DATA_SFT 0 +#define DL_24CH_CH7_DATA_MASK 0xffffffff +#define DL_24CH_CH7_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH8_MON */ +#define DL_24CH_CH8_DATA_SFT 0 +#define DL_24CH_CH8_DATA_MASK 0xffffffff +#define DL_24CH_CH8_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH9_MON */ +#define DL_24CH_CH9_DATA_SFT 0 +#define DL_24CH_CH9_DATA_MASK 0xffffffff +#define DL_24CH_CH9_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH10_MON */ +#define DL_24CH_CH10_DATA_SFT 0 +#define DL_24CH_CH10_DATA_MASK 0xffffffff +#define DL_24CH_CH10_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH11_MON */ +#define DL_24CH_CH11_DATA_SFT 0 +#define DL_24CH_CH11_DATA_MASK 0xffffffff +#define DL_24CH_CH11_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH12_MON */ +#define DL_24CH_CH12_DATA_SFT 0 +#define DL_24CH_CH12_DATA_MASK 0xffffffff +#define DL_24CH_CH12_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH13_MON */ +#define DL_24CH_CH13_DATA_SFT 0 +#define DL_24CH_CH13_DATA_MASK 0xffffffff +#define DL_24CH_CH13_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH14_MON */ +#define DL_24CH_CH14_DATA_SFT 0 +#define DL_24CH_CH14_DATA_MASK 0xffffffff +#define DL_24CH_CH14_DATA_MASK_SFT (0xffffffff << 0) + +/* AFE_DL_24CH_CH15_MON */ +#define DL_24CH_CH15_DATA_SFT 0 +#define DL_24CH_CH15_DATA_MASK 0xffffffff +#define DL_24CH_CH15_DATA_MASK_SFT (0xffffffff << 0) + +#define AUDIO_TOP_CON0 0x0 +#define AUDIO_TOP_CON1 0x4 +#define AUDIO_TOP_CON2 0x8 +#define AUDIO_TOP_CON3 0xc +#define AUDIO_TOP_CON4 0x10 +#define AUDIO_ENGEN_CON0 0x14 +#define AUDIO_ENGEN_CON0_USER1 0x18 +#define AUDIO_ENGEN_CON0_USER2 0x1c +#define AFE_SINEGEN_CON0 0x20 +#define AFE_SINEGEN_CON1 0x24 +#define AFE_SINEGEN_CON2 0x28 +#define AFE_SINEGEN_CON3 0x2c +#define AFE_APLL1_TUNER_CFG 0x30 +#define AFE_APLL1_TUNER_MON0 0x34 +#define AFE_APLL2_TUNER_CFG 0x38 +#define AFE_APLL2_TUNER_MON0 0x3c +#define AUDIO_TOP_RG0 0x4c +#define AUDIO_TOP_RG1 0x50 +#define AUDIO_TOP_RG2 0x54 +#define AUDIO_TOP_RG3 0x58 +#define AUDIO_TOP_RG4 0x5c +#define AFE_SPM_CONTROL_REQ 0x60 +#define AFE_SPM_CONTROL_ACK 0x64 +#define AUD_TOP_CFG_VCORE_RG 0x68 +#define AUDIO_TOP_IP_VERSION 0x6c +#define AUDIO_ENGEN_CON0_MON 0x7c +#define AUD_TOP_CFG_VLP_RG 0x98 +#define AUD_TOP_MON_RG 0x9c +#define AUDIO_USE_DEFAULT_DELSEL0 0xa0 +#define AUDIO_USE_DEFAULT_DELSEL1 0xa4 +#define AUDIO_USE_DEFAULT_DELSEL2 0xa8 +#define AFE_CONNSYS_I2S_IPM_VER_MON 0xb0 +#define AFE_CONNSYS_I2S_MON_SEL 0xb4 +#define AFE_CONNSYS_I2S_MON 0xb8 +#define AFE_CONNSYS_I2S_CON 0xbc +#define AFE_PCM0_INTF_CON0 0xc0 +#define AFE_PCM0_INTF_CON1 0xc4 +#define AFE_PCM_INTF_MON 0xc8 +#define AFE_PCM1_INTF_CON0 0xd0 +#define AFE_PCM1_INTF_CON1 0xd4 +#define AFE_PCM_TOP_IP_VERSION 0xe8 +#define AFE_IRQ_MCU_EN 0x100 +#define AFE_IRQ_MCU_DSP_EN 0x104 +#define AFE_IRQ_MCU_DSP2_EN 0x108 +#define AFE_IRQ_MCU_SCP_EN 0x10c +#define AFE_CUSTOM_IRQ_MCU_EN 0x110 +#define AFE_CUSTOM_IRQ_MCU_DSP_EN 0x114 +#define AFE_CUSTOM_IRQ_MCU_DSP2_EN 0x118 +#define AFE_CUSTOM_IRQ_MCU_SCP_EN 0x11c +#define AFE_IRQ_MCU_STATUS 0x120 +#define AFE_CUSTOM_IRQ_MCU_STATUS 0x124 +#define AFE_IRQ0_MCU_CFG0 0x140 +#define AFE_IRQ0_MCU_CFG1 0x144 +#define AFE_IRQ1_MCU_CFG0 0x148 +#define AFE_IRQ1_MCU_CFG1 0x14c +#define AFE_IRQ2_MCU_CFG0 0x150 +#define AFE_IRQ2_MCU_CFG1 0x154 +#define AFE_IRQ3_MCU_CFG0 0x158 +#define AFE_IRQ3_MCU_CFG1 0x15c +#define AFE_IRQ4_MCU_CFG0 0x160 +#define AFE_IRQ4_MCU_CFG1 0x164 +#define AFE_IRQ5_MCU_CFG0 0x168 +#define AFE_IRQ5_MCU_CFG1 0x16c +#define AFE_IRQ6_MCU_CFG0 0x170 +#define AFE_IRQ6_MCU_CFG1 0x174 +#define AFE_IRQ7_MCU_CFG0 0x178 +#define AFE_IRQ7_MCU_CFG1 0x17c +#define AFE_IRQ8_MCU_CFG0 0x180 +#define AFE_IRQ8_MCU_CFG1 0x184 +#define AFE_IRQ9_MCU_CFG0 0x188 +#define AFE_IRQ9_MCU_CFG1 0x18c +#define AFE_IRQ10_MCU_CFG0 0x190 +#define AFE_IRQ10_MCU_CFG1 0x194 +#define AFE_IRQ11_MCU_CFG0 0x198 +#define AFE_IRQ11_MCU_CFG1 0x19c +#define AFE_IRQ12_MCU_CFG0 0x1a0 +#define AFE_IRQ12_MCU_CFG1 0x1a4 +#define AFE_IRQ13_MCU_CFG0 0x1a8 +#define AFE_IRQ13_MCU_CFG1 0x1ac +#define AFE_IRQ14_MCU_CFG0 0x1b0 +#define AFE_IRQ14_MCU_CFG1 0x1b4 +#define AFE_IRQ15_MCU_CFG0 0x1b8 +#define AFE_IRQ15_MCU_CFG1 0x1bc +#define AFE_IRQ16_MCU_CFG0 0x1c0 +#define AFE_IRQ16_MCU_CFG1 0x1c4 +#define AFE_IRQ17_MCU_CFG0 0x1c8 +#define AFE_IRQ17_MCU_CFG1 0x1cc +#define AFE_IRQ18_MCU_CFG0 0x1d0 +#define AFE_IRQ18_MCU_CFG1 0x1d4 +#define AFE_IRQ19_MCU_CFG0 0x1d8 +#define AFE_IRQ19_MCU_CFG1 0x1dc +#define AFE_IRQ20_MCU_CFG0 0x1e0 +#define AFE_IRQ20_MCU_CFG1 0x1e4 +#define AFE_IRQ21_MCU_CFG0 0x1e8 +#define AFE_IRQ21_MCU_CFG1 0x1ec +#define AFE_IRQ22_MCU_CFG0 0x1f0 +#define AFE_IRQ22_MCU_CFG1 0x1f4 +#define AFE_IRQ23_MCU_CFG0 0x1f8 +#define AFE_IRQ23_MCU_CFG1 0x1fc +#define AFE_IRQ24_MCU_CFG0 0x200 +#define AFE_IRQ24_MCU_CFG1 0x204 +#define AFE_IRQ25_MCU_CFG0 0x208 +#define AFE_IRQ25_MCU_CFG1 0x20c +#define AFE_IRQ26_MCU_CFG0 0x210 +#define AFE_IRQ26_MCU_CFG1 0x214 +#define AFE_CUSTOM_IRQ0_MCU_CFG0 0x268 +#define AFE_IRQ_MCU_MON0 0x300 +#define AFE_IRQ_MCU_MON1 0x304 +#define AFE_IRQ_MCU_MON2 0x308 +#define AFE_IRQ0_CNT_MON 0x310 +#define AFE_IRQ1_CNT_MON 0x314 +#define AFE_IRQ2_CNT_MON 0x318 +#define AFE_IRQ3_CNT_MON 0x31c +#define AFE_IRQ4_CNT_MON 0x320 +#define AFE_IRQ5_CNT_MON 0x324 +#define AFE_IRQ6_CNT_MON 0x328 +#define AFE_IRQ7_CNT_MON 0x32c +#define AFE_IRQ8_CNT_MON 0x330 +#define AFE_IRQ9_CNT_MON 0x334 +#define AFE_IRQ10_CNT_MON 0x338 +#define AFE_IRQ11_CNT_MON 0x33c +#define AFE_IRQ12_CNT_MON 0x340 +#define AFE_IRQ13_CNT_MON 0x344 +#define AFE_IRQ14_CNT_MON 0x348 +#define AFE_IRQ15_CNT_MON 0x34c +#define AFE_IRQ16_CNT_MON 0x350 +#define AFE_IRQ17_CNT_MON 0x354 +#define AFE_IRQ18_CNT_MON 0x358 +#define AFE_IRQ19_CNT_MON 0x35c +#define AFE_IRQ20_CNT_MON 0x360 +#define AFE_IRQ21_CNT_MON 0x364 +#define AFE_IRQ22_CNT_MON 0x368 +#define AFE_IRQ23_CNT_MON 0x36c +#define AFE_IRQ24_CNT_MON 0x370 +#define AFE_IRQ25_CNT_MON 0x374 +#define AFE_IRQ26_CNT_MON 0x378 +#define AFE_CUSTOM_IRQ0_CNT_MON 0x390 +#define AFE_CUSTOM_IRQ0_MCU_CFG1 0x3dc +#define AFE_GAIN0_CON0 0x400 +#define AFE_GAIN0_CON1_R 0x404 +#define AFE_GAIN0_CON1_L 0x408 +#define AFE_GAIN0_CON2 0x40c +#define AFE_GAIN0_CON3 0x410 +#define AFE_GAIN0_CUR_R 0x414 +#define AFE_GAIN0_CUR_L 0x418 +#define AFE_GAIN1_CON0 0x41c +#define AFE_GAIN1_CON1_R 0x420 +#define AFE_GAIN1_CON1_L 0x424 +#define AFE_GAIN1_CON2 0x428 +#define AFE_GAIN1_CON3 0x42c +#define AFE_GAIN1_CUR_R 0x430 +#define AFE_GAIN1_CUR_L 0x434 +#define AFE_GAIN2_CON0 0x438 +#define AFE_GAIN2_CON1_R 0x43c +#define AFE_GAIN2_CON1_L 0x440 +#define AFE_GAIN2_CON2 0x444 +#define AFE_GAIN2_CON3 0x448 +#define AFE_GAIN2_CUR_R 0x44c +#define AFE_GAIN2_CUR_L 0x450 +#define AFE_GAIN3_CON0 0x454 +#define AFE_GAIN3_CON1_R 0x458 +#define AFE_GAIN3_CON1_L 0x45c +#define AFE_GAIN3_CON2 0x460 +#define AFE_GAIN3_CON3 0x464 +#define AFE_GAIN3_CUR_R 0x468 +#define AFE_GAIN3_CUR_L 0x46c +#define AFE_STF_CON0 0xb80 +#define AFE_STF_CON1 0xb84 +#define AFE_STF_COEFF 0xb88 +#define AFE_STF_GAIN 0xb8c +#define AFE_STF_MON 0xb90 +#define AFE_STF_IP_VERSION 0xb94 +#define AFE_CM0_CON0 0xba0 +#define AFE_CM0_MON 0xba4 +#define AFE_CM0_IP_VERSION 0xba8 +#define AFE_CM1_CON0 0xbb0 +#define AFE_CM1_MON 0xbb4 +#define AFE_CM1_IP_VERSION 0xbb8 +#define AFE_CM2_CON0 0xbc0 +#define AFE_CM2_MON 0xbc4 +#define AFE_CM2_IP_VERSION 0xbc8 +#define AFE_ADDA_UL0_SRC_CON0 0xbd0 +#define AFE_ADDA_UL0_SRC_CON1 0xbd4 +#define AFE_ADDA_UL0_SRC_CON2 0xbd8 +#define AFE_ADDA_UL0_SRC_DEBUG 0xbdc +#define AFE_ADDA_UL0_SRC_DEBUG_MON0 0xbe0 +#define AFE_ADDA_UL0_SRC_MON0 0xbe4 +#define AFE_ADDA_UL0_SRC_MON1 0xbe8 +#define AFE_ADDA_UL0_IIR_COEF_02_01 0xbec +#define AFE_ADDA_UL0_IIR_COEF_04_03 0xbf0 +#define AFE_ADDA_UL0_IIR_COEF_06_05 0xbf4 +#define AFE_ADDA_UL0_IIR_COEF_08_07 0xbf8 +#define AFE_ADDA_UL0_IIR_COEF_10_09 0xbfc +#define AFE_ADDA_UL0_ULCF_CFG_02_01 0xc00 +#define AFE_ADDA_UL0_ULCF_CFG_04_03 0xc04 +#define AFE_ADDA_UL0_ULCF_CFG_06_05 0xc08 +#define AFE_ADDA_UL0_ULCF_CFG_08_07 0xc0c +#define AFE_ADDA_UL0_ULCF_CFG_10_09 0xc10 +#define AFE_ADDA_UL0_ULCF_CFG_12_11 0xc14 +#define AFE_ADDA_UL0_ULCF_CFG_14_13 0xc18 +#define AFE_ADDA_UL0_ULCF_CFG_16_15 0xc1c +#define AFE_ADDA_UL0_ULCF_CFG_18_17 0xc20 +#define AFE_ADDA_UL0_ULCF_CFG_20_19 0xc24 +#define AFE_ADDA_UL0_ULCF_CFG_22_21 0xc28 +#define AFE_ADDA_UL0_ULCF_CFG_24_23 0xc2c +#define AFE_ADDA_UL0_ULCF_CFG_26_25 0xc30 +#define AFE_ADDA_UL0_ULCF_CFG_28_27 0xc34 +#define AFE_ADDA_UL0_ULCF_CFG_30_29 0xc38 +#define AFE_ADDA_UL0_ULCF_CFG_32_31 0xc3c +#define AFE_ADDA_UL0_IP_VERSION 0xc4c +#define AFE_ADDA_UL1_SRC_CON0 0xc50 +#define AFE_ADDA_UL1_SRC_CON1 0xc54 +#define AFE_ADDA_UL1_SRC_CON2 0xc58 +#define AFE_ADDA_UL1_SRC_DEBUG 0xc5c +#define AFE_ADDA_UL1_SRC_DEBUG_MON0 0xc60 +#define AFE_ADDA_UL1_SRC_MON0 0xc64 +#define AFE_ADDA_UL1_SRC_MON1 0xc68 +#define AFE_ADDA_UL1_IIR_COEF_02_01 0xc6c +#define AFE_ADDA_UL1_IIR_COEF_04_03 0xc70 +#define AFE_ADDA_UL1_IIR_COEF_06_05 0xc74 +#define AFE_ADDA_UL1_IIR_COEF_08_07 0xc78 +#define AFE_ADDA_UL1_IIR_COEF_10_09 0xc7c +#define AFE_ADDA_UL1_ULCF_CFG_02_01 0xc80 +#define AFE_ADDA_UL1_ULCF_CFG_04_03 0xc84 +#define AFE_ADDA_UL1_ULCF_CFG_06_05 0xc88 +#define AFE_ADDA_UL1_ULCF_CFG_08_07 0xc8c +#define AFE_ADDA_UL1_ULCF_CFG_10_09 0xc90 +#define AFE_ADDA_UL1_ULCF_CFG_12_11 0xc94 +#define AFE_ADDA_UL1_ULCF_CFG_14_13 0xc98 +#define AFE_ADDA_UL1_ULCF_CFG_16_15 0xc9c +#define AFE_ADDA_UL1_ULCF_CFG_18_17 0xca0 +#define AFE_ADDA_UL1_ULCF_CFG_20_19 0xca4 +#define AFE_ADDA_UL1_ULCF_CFG_22_21 0xca8 +#define AFE_ADDA_UL1_ULCF_CFG_24_23 0xcac +#define AFE_ADDA_UL1_ULCF_CFG_26_25 0xcb0 +#define AFE_ADDA_UL1_ULCF_CFG_28_27 0xcb4 +#define AFE_ADDA_UL1_ULCF_CFG_30_29 0xcb8 +#define AFE_ADDA_UL1_ULCF_CFG_32_31 0xcbc +#define AFE_ADDA_UL1_IP_VERSION 0xccc +#define AFE_ADDA_UL2_SRC_CON0 0xcd0 +#define AFE_ADDA_UL2_SRC_CON1 0xcd4 +#define AFE_ADDA_UL2_SRC_CON2 0xcd8 +#define AFE_ADDA_UL2_SRC_DEBUG 0xcdc +#define AFE_ADDA_UL2_SRC_DEBUG_MON0 0xce0 +#define AFE_ADDA_UL2_SRC_MON0 0xce4 +#define AFE_ADDA_UL2_SRC_MON1 0xce8 +#define AFE_ADDA_UL2_IIR_COEF_02_01 0xcec +#define AFE_ADDA_UL2_IIR_COEF_04_03 0xcf0 +#define AFE_ADDA_UL2_IIR_COEF_06_05 0xcf4 +#define AFE_ADDA_UL2_IIR_COEF_08_07 0xcf8 +#define AFE_ADDA_UL2_IIR_COEF_10_09 0xcfc +#define AFE_ADDA_UL2_ULCF_CFG_02_01 0xd00 +#define AFE_ADDA_UL2_ULCF_CFG_04_03 0xd04 +#define AFE_ADDA_UL2_ULCF_CFG_06_05 0xd08 +#define AFE_ADDA_UL2_ULCF_CFG_08_07 0xd0c +#define AFE_ADDA_UL2_ULCF_CFG_10_09 0xd10 +#define AFE_ADDA_UL2_ULCF_CFG_12_11 0xd14 +#define AFE_ADDA_UL2_ULCF_CFG_14_13 0xd18 +#define AFE_ADDA_UL2_ULCF_CFG_16_15 0xd1c +#define AFE_ADDA_UL2_ULCF_CFG_18_17 0xd20 +#define AFE_ADDA_UL2_ULCF_CFG_20_19 0xd24 +#define AFE_ADDA_UL2_ULCF_CFG_22_21 0xd28 +#define AFE_ADDA_UL2_ULCF_CFG_24_23 0xd2c +#define AFE_ADDA_UL2_ULCF_CFG_26_25 0xd30 +#define AFE_ADDA_UL2_ULCF_CFG_28_27 0xd34 +#define AFE_ADDA_UL2_ULCF_CFG_30_29 0xd38 +#define AFE_ADDA_UL2_ULCF_CFG_32_31 0xd3c +#define AFE_ADDA_UL2_IP_VERSION 0xd4c +#define AFE_ADDA_PROXIMITY_CON0 0xed0 +#define AFE_ADDA_ULSRC_PHASE_CON0 0xf00 +#define AFE_ADDA_ULSRC_PHASE_CON1 0xf04 +#define AFE_ADDA_ULSRC_PHASE_CON2 0xf08 +#define AFE_ADDA_ULSRC_PHASE_CON3 0xf0c +#define AFE_MTKAIF_IPM_VER_MON 0x1180 +#define AFE_MTKAIF_MON_SEL 0x1184 +#define AFE_MTKAIF_MON 0x1188 +#define AFE_MTKAIF0_CFG0 0x1190 +#define AFE_MTKAIF0_TX_CFG0 0x1194 +#define AFE_MTKAIF0_RX_CFG0 0x1198 +#define AFE_MTKAIF0_RX_CFG1 0x119c +#define AFE_MTKAIF0_RX_CFG2 0x11a0 +#define AFE_MTKAIF1_CFG0 0x11f0 +#define AFE_MTKAIF1_TX_CFG0 0x11f4 +#define AFE_MTKAIF1_RX_CFG0 0x11f8 +#define AFE_MTKAIF1_RX_CFG1 0x11fc +#define AFE_MTKAIF1_RX_CFG2 0x1200 +#define AFE_AUD_PAD_TOP_CFG0 0x1204 +#define AFE_AUD_PAD_TOP_MON 0x1208 +#define AFE_ADDA_MTKAIFV4_TX_CFG0 0x1280 +#define AFE_ADDA6_MTKAIFV4_TX_CFG0 0x1284 +#define AFE_ADDA_MTKAIFV4_RX_CFG0 0x1288 +#define AFE_ADDA_MTKAIFV4_RX_CFG1 0x128c +#define AFE_ADDA6_MTKAIFV4_RX_CFG0 0x1290 +#define AFE_ADDA6_MTKAIFV4_RX_CFG1 0x1294 +#define AFE_ADDA_MTKAIFV4_TX_SYNCWORD_CFG 0x1298 +#define AFE_ADDA_MTKAIFV4_RX_SYNCWORD_CFG 0x129c +#define AFE_ADDA_MTKAIFV4_MON0 0x12a0 +#define AFE_ADDA_MTKAIFV4_MON1 0x12a4 +#define AFE_ADDA6_MTKAIFV4_MON0 0x12a8 +#define ETDM_IN0_CON0 0x1300 +#define ETDM_IN0_CON1 0x1304 +#define ETDM_IN0_CON2 0x1308 +#define ETDM_IN0_CON3 0x130c +#define ETDM_IN0_CON4 0x1310 +#define ETDM_IN0_CON5 0x1314 +#define ETDM_IN0_CON6 0x1318 +#define ETDM_IN0_CON7 0x131c +#define ETDM_IN0_CON8 0x1320 +#define ETDM_IN0_CON9 0x1324 +#define ETDM_IN0_MON 0x1328 +#define ETDM_IN1_CON0 0x1330 +#define ETDM_IN1_CON1 0x1334 +#define ETDM_IN1_CON2 0x1338 +#define ETDM_IN1_CON3 0x133c +#define ETDM_IN1_CON4 0x1340 +#define ETDM_IN1_CON5 0x1344 +#define ETDM_IN1_CON6 0x1348 +#define ETDM_IN1_CON7 0x134c +#define ETDM_IN1_CON8 0x1350 +#define ETDM_IN1_CON9 0x1354 +#define ETDM_IN1_MON 0x1358 +#define ETDM_IN2_CON0 0x1360 +#define ETDM_IN2_CON1 0x1364 +#define ETDM_IN2_CON2 0x1368 +#define ETDM_IN2_CON3 0x136c +#define ETDM_IN2_CON4 0x1370 +#define ETDM_IN2_CON5 0x1374 +#define ETDM_IN2_CON6 0x1378 +#define ETDM_IN2_CON7 0x137c +#define ETDM_IN2_CON8 0x1380 +#define ETDM_IN2_CON9 0x1384 +#define ETDM_IN2_MON 0x1388 +#define ETDM_IN3_CON0 0x1390 +#define ETDM_IN3_CON1 0x1394 +#define ETDM_IN3_CON2 0x1398 +#define ETDM_IN3_CON3 0x139c +#define ETDM_IN3_CON4 0x13a0 +#define ETDM_IN3_CON5 0x13a4 +#define ETDM_IN3_CON6 0x13a8 +#define ETDM_IN3_CON7 0x13ac +#define ETDM_IN3_CON8 0x13b0 +#define ETDM_IN3_CON9 0x13b4 +#define ETDM_IN3_MON 0x13b8 +#define ETDM_IN4_CON0 0x13c0 +#define ETDM_IN4_CON1 0x13c4 +#define ETDM_IN4_CON2 0x13c8 +#define ETDM_IN4_CON3 0x13cc +#define ETDM_IN4_CON4 0x13d0 +#define ETDM_IN4_CON5 0x13d4 +#define ETDM_IN4_CON6 0x13d8 +#define ETDM_IN4_CON7 0x13dc +#define ETDM_IN4_CON8 0x13e0 +#define ETDM_IN4_CON9 0x13e4 +#define ETDM_IN4_MON 0x13e8 +#define ETDM_IN5_CON0 0x13f0 +#define ETDM_IN5_CON1 0x13f4 +#define ETDM_IN5_CON2 0x13f8 +#define ETDM_IN5_CON3 0x13fc +#define ETDM_IN5_CON4 0x1400 +#define ETDM_IN5_CON5 0x1404 +#define ETDM_IN5_CON6 0x1408 +#define ETDM_IN5_CON7 0x140c +#define ETDM_IN5_CON8 0x1410 +#define ETDM_IN5_CON9 0x1414 +#define ETDM_IN5_MON 0x1418 +#define ETDM_IN6_CON0 0x1420 +#define ETDM_IN6_CON1 0x1424 +#define ETDM_IN6_CON2 0x1428 +#define ETDM_IN6_CON3 0x142c +#define ETDM_IN6_CON4 0x1430 +#define ETDM_IN6_CON5 0x1434 +#define ETDM_IN6_CON6 0x1438 +#define ETDM_IN6_CON7 0x143c +#define ETDM_IN6_CON8 0x1440 +#define ETDM_IN6_CON9 0x1444 +#define ETDM_IN6_MON 0x1448 +#define ETDM_OUT0_CON0 0x1480 +#define ETDM_OUT0_CON1 0x1484 +#define ETDM_OUT0_CON2 0x1488 +#define ETDM_OUT0_CON3 0x148c +#define ETDM_OUT0_CON4 0x1490 +#define ETDM_OUT0_CON5 0x1494 +#define ETDM_OUT0_CON6 0x1498 +#define ETDM_OUT0_CON7 0x149c +#define ETDM_OUT0_CON8 0x14a0 +#define ETDM_OUT0_CON9 0x14a4 +#define ETDM_OUT0_MON 0x14a8 +#define ETDM_OUT1_CON0 0x14c0 +#define ETDM_OUT1_CON1 0x14c4 +#define ETDM_OUT1_CON2 0x14c8 +#define ETDM_OUT1_CON3 0x14cc +#define ETDM_OUT1_CON4 0x14d0 +#define ETDM_OUT1_CON5 0x14d4 +#define ETDM_OUT1_CON6 0x14d8 +#define ETDM_OUT1_CON7 0x14dc +#define ETDM_OUT1_CON8 0x14e0 +#define ETDM_OUT1_CON9 0x14e4 +#define ETDM_OUT1_MON 0x14e8 +#define ETDM_OUT2_CON0 0x1500 +#define ETDM_OUT2_CON1 0x1504 +#define ETDM_OUT2_CON2 0x1508 +#define ETDM_OUT2_CON3 0x150c +#define ETDM_OUT2_CON4 0x1510 +#define ETDM_OUT2_CON5 0x1514 +#define ETDM_OUT2_CON6 0x1518 +#define ETDM_OUT2_CON7 0x151c +#define ETDM_OUT2_CON8 0x1520 +#define ETDM_OUT2_CON9 0x1524 +#define ETDM_OUT2_MON 0x1528 +#define ETDM_OUT3_CON0 0x1540 +#define ETDM_OUT3_CON1 0x1544 +#define ETDM_OUT3_CON2 0x1548 +#define ETDM_OUT3_CON3 0x154c +#define ETDM_OUT3_CON4 0x1550 +#define ETDM_OUT3_CON5 0x1554 +#define ETDM_OUT3_CON6 0x1558 +#define ETDM_OUT3_CON7 0x155c +#define ETDM_OUT3_CON8 0x1560 +#define ETDM_OUT3_CON9 0x1564 +#define ETDM_OUT3_MON 0x1568 +#define ETDM_OUT4_CON0 0x1580 +#define ETDM_OUT4_CON1 0x1584 +#define ETDM_OUT4_CON2 0x1588 +#define ETDM_OUT4_CON3 0x158c +#define ETDM_OUT4_CON4 0x1590 +#define ETDM_OUT4_CON5 0x1594 +#define ETDM_OUT4_CON6 0x1598 +#define ETDM_OUT4_CON7 0x159c +#define ETDM_OUT4_CON8 0x15a0 +#define ETDM_OUT4_CON9 0x15a4 +#define ETDM_OUT4_MON 0x15a8 +#define ETDM_OUT5_CON0 0x15c0 +#define ETDM_OUT5_CON1 0x15c4 +#define ETDM_OUT5_CON2 0x15c8 +#define ETDM_OUT5_CON3 0x15cc +#define ETDM_OUT5_CON4 0x15d0 +#define ETDM_OUT5_CON5 0x15d4 +#define ETDM_OUT5_CON6 0x15d8 +#define ETDM_OUT5_CON7 0x15dc +#define ETDM_OUT5_CON8 0x15e0 +#define ETDM_OUT5_CON9 0x15e4 +#define ETDM_OUT5_MON 0x15e8 +#define ETDM_OUT6_CON0 0x1600 +#define ETDM_OUT6_CON1 0x1604 +#define ETDM_OUT6_CON2 0x1608 +#define ETDM_OUT6_CON3 0x160c +#define ETDM_OUT6_CON4 0x1610 +#define ETDM_OUT6_CON5 0x1614 +#define ETDM_OUT6_CON6 0x1618 +#define ETDM_OUT6_CON7 0x161c +#define ETDM_OUT6_CON8 0x1620 +#define ETDM_OUT6_CON9 0x1624 +#define ETDM_OUT6_MON 0x1628 +#define ETDM_0_3_COWORK_CON0 0x1680 +#define ETDM_0_3_COWORK_CON1 0x1684 +#define ETDM_0_3_COWORK_CON2 0x1688 +#define ETDM_0_3_COWORK_CON3 0x168c +#define ETDM_4_7_COWORK_CON0 0x1690 +#define ETDM_4_7_COWORK_CON1 0x1694 +#define ETDM_4_7_COWORK_CON2 0x1698 +#define ETDM_4_7_COWORK_CON3 0x169c +#define AFE_DPTX_CON 0x2040 +#define AFE_DPTX_MON 0x2044 +#define AFE_TDM_CON1 0x2048 +#define AFE_TDM_CON2 0x204c +#define AFE_TDM_CON3 0x2050 +#define AFE_TDM_OUT_MON 0x2054 +#define AFE_HDMI_CONN0 0x2078 +#define AFE_TDM_TOP_IP_VERSION 0x207c +#define AFE_CONN004_0 0x2100 +#define AFE_CONN004_1 0x2104 +#define AFE_CONN004_2 0x2108 +#define AFE_CONN004_4 0x2110 +#define AFE_CONN004_5 0x2114 +#define AFE_CONN004_6 0x2118 +#define AFE_CONN004_7 0x211c +#define AFE_CONN005_0 0x2120 +#define AFE_CONN005_1 0x2124 +#define AFE_CONN005_2 0x2128 +#define AFE_CONN005_4 0x2130 +#define AFE_CONN005_5 0x2134 +#define AFE_CONN005_6 0x2138 +#define AFE_CONN005_7 0x213c +#define AFE_CONN006_0 0x2140 +#define AFE_CONN006_1 0x2144 +#define AFE_CONN006_2 0x2148 +#define AFE_CONN006_4 0x2150 +#define AFE_CONN006_5 0x2154 +#define AFE_CONN006_6 0x2158 +#define AFE_CONN006_7 0x215c +#define AFE_CONN007_0 0x2160 +#define AFE_CONN007_1 0x2164 +#define AFE_CONN007_2 0x2168 +#define AFE_CONN007_4 0x2170 +#define AFE_CONN007_5 0x2174 +#define AFE_CONN007_6 0x2178 +#define AFE_CONN007_7 0x217c +#define AFE_CONN008_0 0x2180 +#define AFE_CONN008_1 0x2184 +#define AFE_CONN008_2 0x2188 +#define AFE_CONN008_4 0x2190 +#define AFE_CONN008_5 0x2194 +#define AFE_CONN008_6 0x2198 +#define AFE_CONN008_7 0x219c +#define AFE_CONN009_0 0x21a0 +#define AFE_CONN009_1 0x21a4 +#define AFE_CONN009_2 0x21a8 +#define AFE_CONN009_4 0x21b0 +#define AFE_CONN009_5 0x21b4 +#define AFE_CONN009_6 0x21b8 +#define AFE_CONN009_7 0x21bc +#define AFE_CONN010_0 0x21c0 +#define AFE_CONN010_1 0x21c4 +#define AFE_CONN010_2 0x21c8 +#define AFE_CONN010_4 0x21d0 +#define AFE_CONN010_5 0x21d4 +#define AFE_CONN010_6 0x21d8 +#define AFE_CONN010_7 0x21dc +#define AFE_CONN011_0 0x21e0 +#define AFE_CONN011_1 0x21e4 +#define AFE_CONN011_2 0x21e8 +#define AFE_CONN011_4 0x21f0 +#define AFE_CONN011_5 0x21f4 +#define AFE_CONN011_6 0x21f8 +#define AFE_CONN011_7 0x21fc +#define AFE_CONN012_0 0x2200 +#define AFE_CONN012_1 0x2204 +#define AFE_CONN012_2 0x2208 +#define AFE_CONN012_4 0x2210 +#define AFE_CONN012_5 0x2214 +#define AFE_CONN012_6 0x2218 +#define AFE_CONN012_7 0x221c +#define AFE_CONN014_0 0x2240 +#define AFE_CONN014_1 0x2244 +#define AFE_CONN014_2 0x2248 +#define AFE_CONN014_4 0x2250 +#define AFE_CONN014_5 0x2254 +#define AFE_CONN014_6 0x2258 +#define AFE_CONN014_7 0x225c +#define AFE_CONN015_0 0x2260 +#define AFE_CONN015_1 0x2264 +#define AFE_CONN015_2 0x2268 +#define AFE_CONN015_4 0x2270 +#define AFE_CONN015_5 0x2274 +#define AFE_CONN015_6 0x2278 +#define AFE_CONN015_7 0x227c +#define AFE_CONN016_0 0x2280 +#define AFE_CONN016_1 0x2284 +#define AFE_CONN016_2 0x2288 +#define AFE_CONN016_4 0x2290 +#define AFE_CONN016_5 0x2294 +#define AFE_CONN016_6 0x2298 +#define AFE_CONN016_7 0x229c +#define AFE_CONN017_0 0x22a0 +#define AFE_CONN017_1 0x22a4 +#define AFE_CONN017_2 0x22a8 +#define AFE_CONN017_4 0x22b0 +#define AFE_CONN017_5 0x22b4 +#define AFE_CONN017_6 0x22b8 +#define AFE_CONN017_7 0x22bc +#define AFE_CONN018_0 0x22c0 +#define AFE_CONN018_1 0x22c4 +#define AFE_CONN018_2 0x22c8 +#define AFE_CONN018_4 0x22d0 +#define AFE_CONN018_5 0x22d4 +#define AFE_CONN018_6 0x22d8 +#define AFE_CONN018_7 0x22dc +#define AFE_CONN019_0 0x22e0 +#define AFE_CONN019_1 0x22e4 +#define AFE_CONN019_2 0x22e8 +#define AFE_CONN019_4 0x22f0 +#define AFE_CONN019_5 0x22f4 +#define AFE_CONN019_6 0x22f8 +#define AFE_CONN019_7 0x22fc +#define AFE_CONN020_0 0x2300 +#define AFE_CONN020_1 0x2304 +#define AFE_CONN020_2 0x2308 +#define AFE_CONN020_4 0x2310 +#define AFE_CONN020_5 0x2314 +#define AFE_CONN020_6 0x2318 +#define AFE_CONN020_7 0x231c +#define AFE_CONN021_0 0x2320 +#define AFE_CONN021_1 0x2324 +#define AFE_CONN021_2 0x2328 +#define AFE_CONN021_4 0x2330 +#define AFE_CONN021_5 0x2334 +#define AFE_CONN021_6 0x2338 +#define AFE_CONN021_7 0x233c +#define AFE_CONN022_0 0x2340 +#define AFE_CONN022_1 0x2344 +#define AFE_CONN022_2 0x2348 +#define AFE_CONN022_4 0x2350 +#define AFE_CONN022_5 0x2354 +#define AFE_CONN022_6 0x2358 +#define AFE_CONN022_7 0x235c +#define AFE_CONN023_0 0x2360 +#define AFE_CONN023_1 0x2364 +#define AFE_CONN023_2 0x2368 +#define AFE_CONN023_4 0x2370 +#define AFE_CONN023_5 0x2374 +#define AFE_CONN023_6 0x2378 +#define AFE_CONN023_7 0x237c +#define AFE_CONN024_0 0x2380 +#define AFE_CONN024_1 0x2384 +#define AFE_CONN024_2 0x2388 +#define AFE_CONN024_4 0x2390 +#define AFE_CONN024_5 0x2394 +#define AFE_CONN024_6 0x2398 +#define AFE_CONN024_7 0x239c +#define AFE_CONN025_0 0x23a0 +#define AFE_CONN025_1 0x23a4 +#define AFE_CONN025_2 0x23a8 +#define AFE_CONN025_4 0x23b0 +#define AFE_CONN025_5 0x23b4 +#define AFE_CONN025_6 0x23b8 +#define AFE_CONN025_7 0x23bc +#define AFE_CONN026_0 0x23c0 +#define AFE_CONN026_1 0x23c4 +#define AFE_CONN026_2 0x23c8 +#define AFE_CONN026_4 0x23d0 +#define AFE_CONN026_5 0x23d4 +#define AFE_CONN026_6 0x23d8 +#define AFE_CONN026_7 0x23dc +#define AFE_CONN027_0 0x23e0 +#define AFE_CONN027_1 0x23e4 +#define AFE_CONN027_2 0x23e8 +#define AFE_CONN027_4 0x23f0 +#define AFE_CONN027_5 0x23f4 +#define AFE_CONN027_6 0x23f8 +#define AFE_CONN027_7 0x23fc +#define AFE_CONN028_0 0x2400 +#define AFE_CONN028_1 0x2404 +#define AFE_CONN028_2 0x2408 +#define AFE_CONN028_4 0x2410 +#define AFE_CONN028_5 0x2414 +#define AFE_CONN028_6 0x2418 +#define AFE_CONN028_7 0x241c +#define AFE_CONN029_0 0x2420 +#define AFE_CONN029_1 0x2424 +#define AFE_CONN029_2 0x2428 +#define AFE_CONN029_4 0x2430 +#define AFE_CONN029_5 0x2434 +#define AFE_CONN029_6 0x2438 +#define AFE_CONN029_7 0x243c +#define AFE_CONN030_0 0x2440 +#define AFE_CONN030_1 0x2444 +#define AFE_CONN030_2 0x2448 +#define AFE_CONN030_4 0x2450 +#define AFE_CONN030_5 0x2454 +#define AFE_CONN030_6 0x2458 +#define AFE_CONN030_7 0x245c +#define AFE_CONN031_0 0x2460 +#define AFE_CONN031_1 0x2464 +#define AFE_CONN031_2 0x2468 +#define AFE_CONN031_4 0x2470 +#define AFE_CONN031_5 0x2474 +#define AFE_CONN031_6 0x2478 +#define AFE_CONN031_7 0x247c +#define AFE_CONN032_0 0x2480 +#define AFE_CONN032_1 0x2484 +#define AFE_CONN032_2 0x2488 +#define AFE_CONN032_4 0x2490 +#define AFE_CONN032_5 0x2494 +#define AFE_CONN032_6 0x2498 +#define AFE_CONN032_7 0x249c +#define AFE_CONN033_0 0x24a0 +#define AFE_CONN033_1 0x24a4 +#define AFE_CONN033_2 0x24a8 +#define AFE_CONN033_4 0x24b0 +#define AFE_CONN033_5 0x24b4 +#define AFE_CONN033_6 0x24b8 +#define AFE_CONN033_7 0x24bc +#define AFE_CONN034_0 0x24c0 +#define AFE_CONN034_1 0x24c4 +#define AFE_CONN034_2 0x24c8 +#define AFE_CONN034_4 0x24d0 +#define AFE_CONN034_5 0x24d4 +#define AFE_CONN034_6 0x24d8 +#define AFE_CONN034_7 0x24dc +#define AFE_CONN035_0 0x24e0 +#define AFE_CONN035_1 0x24e4 +#define AFE_CONN035_2 0x24e8 +#define AFE_CONN035_4 0x24f0 +#define AFE_CONN035_5 0x24f4 +#define AFE_CONN035_6 0x24f8 +#define AFE_CONN035_7 0x24fc +#define AFE_CONN036_0 0x2500 +#define AFE_CONN036_1 0x2504 +#define AFE_CONN036_2 0x2508 +#define AFE_CONN036_4 0x2510 +#define AFE_CONN036_5 0x2514 +#define AFE_CONN036_6 0x2518 +#define AFE_CONN036_7 0x251c +#define AFE_CONN037_0 0x2520 +#define AFE_CONN037_1 0x2524 +#define AFE_CONN037_2 0x2528 +#define AFE_CONN037_4 0x2530 +#define AFE_CONN037_5 0x2534 +#define AFE_CONN037_6 0x2538 +#define AFE_CONN037_7 0x253c +#define AFE_CONN038_0 0x2540 +#define AFE_CONN038_1 0x2544 +#define AFE_CONN038_2 0x2548 +#define AFE_CONN038_4 0x2550 +#define AFE_CONN038_5 0x2554 +#define AFE_CONN038_6 0x2558 +#define AFE_CONN038_7 0x255c +#define AFE_CONN039_0 0x2560 +#define AFE_CONN039_1 0x2564 +#define AFE_CONN039_2 0x2568 +#define AFE_CONN039_4 0x2570 +#define AFE_CONN039_5 0x2574 +#define AFE_CONN039_6 0x2578 +#define AFE_CONN039_7 0x257c +#define AFE_CONN040_0 0x2580 +#define AFE_CONN040_1 0x2584 +#define AFE_CONN040_2 0x2588 +#define AFE_CONN040_4 0x2590 +#define AFE_CONN040_5 0x2594 +#define AFE_CONN040_6 0x2598 +#define AFE_CONN040_7 0x259c +#define AFE_CONN041_0 0x25a0 +#define AFE_CONN041_1 0x25a4 +#define AFE_CONN041_2 0x25a8 +#define AFE_CONN041_4 0x25b0 +#define AFE_CONN041_5 0x25b4 +#define AFE_CONN041_6 0x25b8 +#define AFE_CONN041_7 0x25bc +#define AFE_CONN042_0 0x25c0 +#define AFE_CONN042_1 0x25c4 +#define AFE_CONN042_2 0x25c8 +#define AFE_CONN042_4 0x25d0 +#define AFE_CONN042_5 0x25d4 +#define AFE_CONN042_6 0x25d8 +#define AFE_CONN042_7 0x25dc +#define AFE_CONN043_0 0x25e0 +#define AFE_CONN043_1 0x25e4 +#define AFE_CONN043_2 0x25e8 +#define AFE_CONN043_4 0x25f0 +#define AFE_CONN043_5 0x25f4 +#define AFE_CONN043_6 0x25f8 +#define AFE_CONN043_7 0x25fc +#define AFE_CONN044_0 0x2600 +#define AFE_CONN044_1 0x2604 +#define AFE_CONN044_2 0x2608 +#define AFE_CONN044_4 0x2610 +#define AFE_CONN044_5 0x2614 +#define AFE_CONN044_6 0x2618 +#define AFE_CONN044_7 0x261c +#define AFE_CONN045_0 0x2620 +#define AFE_CONN045_1 0x2624 +#define AFE_CONN045_2 0x2628 +#define AFE_CONN045_4 0x2630 +#define AFE_CONN045_5 0x2634 +#define AFE_CONN045_6 0x2638 +#define AFE_CONN045_7 0x263c +#define AFE_CONN046_0 0x2640 +#define AFE_CONN046_1 0x2644 +#define AFE_CONN046_2 0x2648 +#define AFE_CONN046_4 0x2650 +#define AFE_CONN046_5 0x2654 +#define AFE_CONN046_6 0x2658 +#define AFE_CONN046_7 0x265c +#define AFE_CONN047_0 0x2660 +#define AFE_CONN047_1 0x2664 +#define AFE_CONN047_2 0x2668 +#define AFE_CONN047_4 0x2670 +#define AFE_CONN047_5 0x2674 +#define AFE_CONN047_6 0x2678 +#define AFE_CONN047_7 0x267c +#define AFE_CONN048_0 0x2680 +#define AFE_CONN048_1 0x2684 +#define AFE_CONN048_2 0x2688 +#define AFE_CONN048_4 0x2690 +#define AFE_CONN048_5 0x2694 +#define AFE_CONN048_6 0x2698 +#define AFE_CONN048_7 0x269c +#define AFE_CONN049_0 0x26a0 +#define AFE_CONN049_1 0x26a4 +#define AFE_CONN049_2 0x26a8 +#define AFE_CONN049_4 0x26b0 +#define AFE_CONN049_5 0x26b4 +#define AFE_CONN049_6 0x26b8 +#define AFE_CONN049_7 0x26bc +#define AFE_CONN050_0 0x26c0 +#define AFE_CONN050_1 0x26c4 +#define AFE_CONN050_2 0x26c8 +#define AFE_CONN050_4 0x26d0 +#define AFE_CONN050_5 0x26d4 +#define AFE_CONN050_6 0x26d8 +#define AFE_CONN050_7 0x26dc +#define AFE_CONN051_0 0x26e0 +#define AFE_CONN051_1 0x26e4 +#define AFE_CONN051_2 0x26e8 +#define AFE_CONN051_4 0x26f0 +#define AFE_CONN051_5 0x26f4 +#define AFE_CONN051_6 0x26f8 +#define AFE_CONN051_7 0x26fc +#define AFE_CONN052_0 0x2700 +#define AFE_CONN052_1 0x2704 +#define AFE_CONN052_2 0x2708 +#define AFE_CONN052_4 0x2710 +#define AFE_CONN052_5 0x2714 +#define AFE_CONN052_6 0x2718 +#define AFE_CONN052_7 0x271c +#define AFE_CONN053_0 0x2720 +#define AFE_CONN053_1 0x2724 +#define AFE_CONN053_2 0x2728 +#define AFE_CONN053_4 0x2730 +#define AFE_CONN053_5 0x2734 +#define AFE_CONN053_6 0x2738 +#define AFE_CONN053_7 0x273c +#define AFE_CONN054_0 0x2740 +#define AFE_CONN054_1 0x2744 +#define AFE_CONN054_2 0x2748 +#define AFE_CONN054_4 0x2750 +#define AFE_CONN054_5 0x2754 +#define AFE_CONN054_6 0x2758 +#define AFE_CONN054_7 0x275c +#define AFE_CONN055_0 0x2760 +#define AFE_CONN055_1 0x2764 +#define AFE_CONN055_2 0x2768 +#define AFE_CONN055_4 0x2770 +#define AFE_CONN055_5 0x2774 +#define AFE_CONN055_6 0x2778 +#define AFE_CONN055_7 0x277c +#define AFE_CONN056_0 0x2780 +#define AFE_CONN056_1 0x2784 +#define AFE_CONN056_2 0x2788 +#define AFE_CONN056_4 0x2790 +#define AFE_CONN056_5 0x2794 +#define AFE_CONN056_6 0x2798 +#define AFE_CONN056_7 0x279c +#define AFE_CONN057_0 0x27a0 +#define AFE_CONN057_1 0x27a4 +#define AFE_CONN057_2 0x27a8 +#define AFE_CONN057_4 0x27b0 +#define AFE_CONN057_5 0x27b4 +#define AFE_CONN057_6 0x27b8 +#define AFE_CONN057_7 0x27bc +#define AFE_CONN058_0 0x27c0 +#define AFE_CONN058_1 0x27c4 +#define AFE_CONN058_2 0x27c8 +#define AFE_CONN058_4 0x27d0 +#define AFE_CONN058_5 0x27d4 +#define AFE_CONN058_6 0x27d8 +#define AFE_CONN058_7 0x27dc +#define AFE_CONN059_0 0x27e0 +#define AFE_CONN059_1 0x27e4 +#define AFE_CONN059_2 0x27e8 +#define AFE_CONN059_4 0x27f0 +#define AFE_CONN059_5 0x27f4 +#define AFE_CONN059_6 0x27f8 +#define AFE_CONN059_7 0x27fc +#define AFE_CONN060_0 0x2800 +#define AFE_CONN060_1 0x2804 +#define AFE_CONN060_2 0x2808 +#define AFE_CONN060_4 0x2810 +#define AFE_CONN060_5 0x2814 +#define AFE_CONN060_6 0x2818 +#define AFE_CONN060_7 0x281c +#define AFE_CONN061_0 0x2820 +#define AFE_CONN061_1 0x2824 +#define AFE_CONN061_2 0x2828 +#define AFE_CONN061_4 0x2830 +#define AFE_CONN061_5 0x2834 +#define AFE_CONN061_6 0x2838 +#define AFE_CONN061_7 0x283c +#define AFE_CONN062_0 0x2840 +#define AFE_CONN062_1 0x2844 +#define AFE_CONN062_2 0x2848 +#define AFE_CONN062_4 0x2850 +#define AFE_CONN062_5 0x2854 +#define AFE_CONN062_6 0x2858 +#define AFE_CONN062_7 0x285c +#define AFE_CONN063_0 0x2860 +#define AFE_CONN063_1 0x2864 +#define AFE_CONN063_2 0x2868 +#define AFE_CONN063_4 0x2870 +#define AFE_CONN063_5 0x2874 +#define AFE_CONN063_6 0x2878 +#define AFE_CONN063_7 0x287c +#define AFE_CONN064_0 0x2880 +#define AFE_CONN064_1 0x2884 +#define AFE_CONN064_2 0x2888 +#define AFE_CONN064_4 0x2890 +#define AFE_CONN064_5 0x2894 +#define AFE_CONN064_6 0x2898 +#define AFE_CONN064_7 0x289c +#define AFE_CONN065_0 0x28a0 +#define AFE_CONN065_1 0x28a4 +#define AFE_CONN065_2 0x28a8 +#define AFE_CONN065_4 0x28b0 +#define AFE_CONN065_5 0x28b4 +#define AFE_CONN065_6 0x28b8 +#define AFE_CONN065_7 0x28bc +#define AFE_CONN066_0 0x28c0 +#define AFE_CONN066_1 0x28c4 +#define AFE_CONN066_2 0x28c8 +#define AFE_CONN066_4 0x28d0 +#define AFE_CONN066_5 0x28d4 +#define AFE_CONN066_6 0x28d8 +#define AFE_CONN066_7 0x28dc +#define AFE_CONN067_0 0x28e0 +#define AFE_CONN067_1 0x28e4 +#define AFE_CONN067_2 0x28e8 +#define AFE_CONN067_4 0x28f0 +#define AFE_CONN067_5 0x28f4 +#define AFE_CONN067_6 0x28f8 +#define AFE_CONN067_7 0x28fc +#define AFE_CONN068_0 0x2900 +#define AFE_CONN068_1 0x2904 +#define AFE_CONN068_2 0x2908 +#define AFE_CONN068_4 0x2910 +#define AFE_CONN068_5 0x2914 +#define AFE_CONN068_6 0x2918 +#define AFE_CONN068_7 0x291c +#define AFE_CONN069_0 0x2920 +#define AFE_CONN069_1 0x2924 +#define AFE_CONN069_2 0x2928 +#define AFE_CONN069_4 0x2930 +#define AFE_CONN069_5 0x2934 +#define AFE_CONN069_6 0x2938 +#define AFE_CONN069_7 0x293c +#define AFE_CONN070_0 0x2940 +#define AFE_CONN070_1 0x2944 +#define AFE_CONN070_2 0x2948 +#define AFE_CONN070_4 0x2950 +#define AFE_CONN070_5 0x2954 +#define AFE_CONN070_6 0x2958 +#define AFE_CONN070_7 0x295c +#define AFE_CONN071_0 0x2960 +#define AFE_CONN071_1 0x2964 +#define AFE_CONN071_2 0x2968 +#define AFE_CONN071_4 0x2970 +#define AFE_CONN071_5 0x2974 +#define AFE_CONN071_6 0x2978 +#define AFE_CONN071_7 0x297c +#define AFE_CONN072_0 0x2980 +#define AFE_CONN072_1 0x2984 +#define AFE_CONN072_2 0x2988 +#define AFE_CONN072_4 0x2990 +#define AFE_CONN072_5 0x2994 +#define AFE_CONN072_6 0x2998 +#define AFE_CONN072_7 0x299c +#define AFE_CONN073_0 0x29a0 +#define AFE_CONN073_1 0x29a4 +#define AFE_CONN073_2 0x29a8 +#define AFE_CONN073_4 0x29b0 +#define AFE_CONN073_5 0x29b4 +#define AFE_CONN073_6 0x29b8 +#define AFE_CONN073_7 0x29bc +#define AFE_CONN074_0 0x29c0 +#define AFE_CONN074_1 0x29c4 +#define AFE_CONN074_2 0x29c8 +#define AFE_CONN074_4 0x29d0 +#define AFE_CONN074_5 0x29d4 +#define AFE_CONN074_6 0x29d8 +#define AFE_CONN074_7 0x29dc +#define AFE_CONN075_0 0x29e0 +#define AFE_CONN075_1 0x29e4 +#define AFE_CONN075_2 0x29e8 +#define AFE_CONN075_4 0x29f0 +#define AFE_CONN075_5 0x29f4 +#define AFE_CONN075_6 0x29f8 +#define AFE_CONN075_7 0x29fc +#define AFE_CONN076_0 0x2a00 +#define AFE_CONN076_1 0x2a04 +#define AFE_CONN076_2 0x2a08 +#define AFE_CONN076_4 0x2a10 +#define AFE_CONN076_5 0x2a14 +#define AFE_CONN076_6 0x2a18 +#define AFE_CONN076_7 0x2a1c +#define AFE_CONN077_0 0x2a20 +#define AFE_CONN077_1 0x2a24 +#define AFE_CONN077_2 0x2a28 +#define AFE_CONN077_4 0x2a30 +#define AFE_CONN077_5 0x2a34 +#define AFE_CONN077_6 0x2a38 +#define AFE_CONN077_7 0x2a3c +#define AFE_CONN078_0 0x2a40 +#define AFE_CONN078_1 0x2a44 +#define AFE_CONN078_2 0x2a48 +#define AFE_CONN078_4 0x2a50 +#define AFE_CONN078_5 0x2a54 +#define AFE_CONN078_6 0x2a58 +#define AFE_CONN078_7 0x2a5c +#define AFE_CONN079_0 0x2a60 +#define AFE_CONN079_1 0x2a64 +#define AFE_CONN079_2 0x2a68 +#define AFE_CONN079_4 0x2a70 +#define AFE_CONN079_5 0x2a74 +#define AFE_CONN079_6 0x2a78 +#define AFE_CONN079_7 0x2a7c +#define AFE_CONN080_0 0x2a80 +#define AFE_CONN080_1 0x2a84 +#define AFE_CONN080_2 0x2a88 +#define AFE_CONN080_4 0x2a90 +#define AFE_CONN080_5 0x2a94 +#define AFE_CONN080_6 0x2a98 +#define AFE_CONN080_7 0x2a9c +#define AFE_CONN081_0 0x2aa0 +#define AFE_CONN081_1 0x2aa4 +#define AFE_CONN081_2 0x2aa8 +#define AFE_CONN081_4 0x2ab0 +#define AFE_CONN081_5 0x2ab4 +#define AFE_CONN081_6 0x2ab8 +#define AFE_CONN081_7 0x2abc +#define AFE_CONN082_0 0x2ac0 +#define AFE_CONN082_1 0x2ac4 +#define AFE_CONN082_2 0x2ac8 +#define AFE_CONN082_4 0x2ad0 +#define AFE_CONN082_5 0x2ad4 +#define AFE_CONN082_6 0x2ad8 +#define AFE_CONN082_7 0x2adc +#define AFE_CONN083_0 0x2ae0 +#define AFE_CONN083_1 0x2ae4 +#define AFE_CONN083_2 0x2ae8 +#define AFE_CONN083_4 0x2af0 +#define AFE_CONN083_5 0x2af4 +#define AFE_CONN083_6 0x2af8 +#define AFE_CONN083_7 0x2afc +#define AFE_CONN084_0 0x2b00 +#define AFE_CONN084_1 0x2b04 +#define AFE_CONN084_2 0x2b08 +#define AFE_CONN084_4 0x2b10 +#define AFE_CONN084_5 0x2b14 +#define AFE_CONN084_6 0x2b18 +#define AFE_CONN084_7 0x2b1c +#define AFE_CONN085_0 0x2b20 +#define AFE_CONN085_1 0x2b24 +#define AFE_CONN085_2 0x2b28 +#define AFE_CONN085_4 0x2b30 +#define AFE_CONN085_5 0x2b34 +#define AFE_CONN085_6 0x2b38 +#define AFE_CONN085_7 0x2b3c +#define AFE_CONN086_0 0x2b40 +#define AFE_CONN086_1 0x2b44 +#define AFE_CONN086_2 0x2b48 +#define AFE_CONN086_4 0x2b50 +#define AFE_CONN086_5 0x2b54 +#define AFE_CONN086_6 0x2b58 +#define AFE_CONN086_7 0x2b5c +#define AFE_CONN087_0 0x2b60 +#define AFE_CONN087_1 0x2b64 +#define AFE_CONN087_2 0x2b68 +#define AFE_CONN087_4 0x2b70 +#define AFE_CONN087_5 0x2b74 +#define AFE_CONN087_6 0x2b78 +#define AFE_CONN087_7 0x2b7c +#define AFE_CONN088_0 0x2b80 +#define AFE_CONN088_1 0x2b84 +#define AFE_CONN088_2 0x2b88 +#define AFE_CONN088_4 0x2b90 +#define AFE_CONN088_5 0x2b94 +#define AFE_CONN088_6 0x2b98 +#define AFE_CONN088_7 0x2b9c +#define AFE_CONN089_0 0x2ba0 +#define AFE_CONN089_1 0x2ba4 +#define AFE_CONN089_2 0x2ba8 +#define AFE_CONN089_4 0x2bb0 +#define AFE_CONN089_5 0x2bb4 +#define AFE_CONN089_6 0x2bb8 +#define AFE_CONN089_7 0x2bbc +#define AFE_CONN090_0 0x2bc0 +#define AFE_CONN090_1 0x2bc4 +#define AFE_CONN090_2 0x2bc8 +#define AFE_CONN090_4 0x2bd0 +#define AFE_CONN090_5 0x2bd4 +#define AFE_CONN090_6 0x2bd8 +#define AFE_CONN090_7 0x2bdc +#define AFE_CONN091_0 0x2be0 +#define AFE_CONN091_1 0x2be4 +#define AFE_CONN091_2 0x2be8 +#define AFE_CONN091_4 0x2bf0 +#define AFE_CONN091_5 0x2bf4 +#define AFE_CONN091_6 0x2bf8 +#define AFE_CONN091_7 0x2bfc +#define AFE_CONN092_0 0x2c00 +#define AFE_CONN092_1 0x2c04 +#define AFE_CONN092_2 0x2c08 +#define AFE_CONN092_4 0x2c10 +#define AFE_CONN092_5 0x2c14 +#define AFE_CONN092_6 0x2c18 +#define AFE_CONN092_7 0x2c1c +#define AFE_CONN093_0 0x2c20 +#define AFE_CONN093_1 0x2c24 +#define AFE_CONN093_2 0x2c28 +#define AFE_CONN093_4 0x2c30 +#define AFE_CONN093_5 0x2c34 +#define AFE_CONN093_6 0x2c38 +#define AFE_CONN093_7 0x2c3c +#define AFE_CONN094_0 0x2c40 +#define AFE_CONN094_1 0x2c44 +#define AFE_CONN094_2 0x2c48 +#define AFE_CONN094_4 0x2c50 +#define AFE_CONN094_5 0x2c54 +#define AFE_CONN094_6 0x2c58 +#define AFE_CONN094_7 0x2c5c +#define AFE_CONN095_0 0x2c60 +#define AFE_CONN095_1 0x2c64 +#define AFE_CONN095_2 0x2c68 +#define AFE_CONN095_4 0x2c70 +#define AFE_CONN095_5 0x2c74 +#define AFE_CONN095_6 0x2c78 +#define AFE_CONN095_7 0x2c7c +#define AFE_CONN096_0 0x2c80 +#define AFE_CONN096_1 0x2c84 +#define AFE_CONN096_2 0x2c88 +#define AFE_CONN096_4 0x2c90 +#define AFE_CONN096_5 0x2c94 +#define AFE_CONN096_6 0x2c98 +#define AFE_CONN096_7 0x2c9c +#define AFE_CONN097_0 0x2ca0 +#define AFE_CONN097_1 0x2ca4 +#define AFE_CONN097_2 0x2ca8 +#define AFE_CONN097_4 0x2cb0 +#define AFE_CONN097_5 0x2cb4 +#define AFE_CONN097_6 0x2cb8 +#define AFE_CONN097_7 0x2cbc +#define AFE_CONN098_0 0x2cc0 +#define AFE_CONN098_1 0x2cc4 +#define AFE_CONN098_2 0x2cc8 +#define AFE_CONN098_4 0x2cd0 +#define AFE_CONN098_5 0x2cd4 +#define AFE_CONN098_6 0x2cd8 +#define AFE_CONN098_7 0x2cdc +#define AFE_CONN099_0 0x2ce0 +#define AFE_CONN099_1 0x2ce4 +#define AFE_CONN099_2 0x2ce8 +#define AFE_CONN099_4 0x2cf0 +#define AFE_CONN099_5 0x2cf4 +#define AFE_CONN099_6 0x2cf8 +#define AFE_CONN099_7 0x2cfc +#define AFE_CONN100_0 0x2d00 +#define AFE_CONN100_1 0x2d04 +#define AFE_CONN100_2 0x2d08 +#define AFE_CONN100_4 0x2d10 +#define AFE_CONN100_5 0x2d14 +#define AFE_CONN100_6 0x2d18 +#define AFE_CONN100_7 0x2d1c +#define AFE_CONN102_0 0x2d40 +#define AFE_CONN102_1 0x2d44 +#define AFE_CONN102_2 0x2d48 +#define AFE_CONN102_4 0x2d50 +#define AFE_CONN102_5 0x2d54 +#define AFE_CONN102_6 0x2d58 +#define AFE_CONN102_7 0x2d5c +#define AFE_CONN103_0 0x2d60 +#define AFE_CONN103_1 0x2d64 +#define AFE_CONN103_2 0x2d68 +#define AFE_CONN103_4 0x2d70 +#define AFE_CONN103_5 0x2d74 +#define AFE_CONN103_6 0x2d78 +#define AFE_CONN103_7 0x2d7c +#define AFE_CONN104_0 0x2d80 +#define AFE_CONN104_1 0x2d84 +#define AFE_CONN104_2 0x2d88 +#define AFE_CONN104_4 0x2d90 +#define AFE_CONN104_5 0x2d94 +#define AFE_CONN104_6 0x2d98 +#define AFE_CONN104_7 0x2d9c +#define AFE_CONN105_0 0x2da0 +#define AFE_CONN105_1 0x2da4 +#define AFE_CONN105_2 0x2da8 +#define AFE_CONN105_4 0x2db0 +#define AFE_CONN105_5 0x2db4 +#define AFE_CONN105_6 0x2db8 +#define AFE_CONN105_7 0x2dbc +#define AFE_CONN106_0 0x2dc0 +#define AFE_CONN106_1 0x2dc4 +#define AFE_CONN106_2 0x2dc8 +#define AFE_CONN106_4 0x2dd0 +#define AFE_CONN106_5 0x2dd4 +#define AFE_CONN106_6 0x2dd8 +#define AFE_CONN106_7 0x2ddc +#define AFE_CONN108_0 0x2e00 +#define AFE_CONN108_1 0x2e04 +#define AFE_CONN108_2 0x2e08 +#define AFE_CONN108_4 0x2e10 +#define AFE_CONN108_5 0x2e14 +#define AFE_CONN108_6 0x2e18 +#define AFE_CONN108_7 0x2e1c +#define AFE_CONN109_0 0x2e20 +#define AFE_CONN109_1 0x2e24 +#define AFE_CONN109_2 0x2e28 +#define AFE_CONN109_4 0x2e30 +#define AFE_CONN109_5 0x2e34 +#define AFE_CONN109_6 0x2e38 +#define AFE_CONN109_7 0x2e3c +#define AFE_CONN110_0 0x2e40 +#define AFE_CONN110_1 0x2e44 +#define AFE_CONN110_2 0x2e48 +#define AFE_CONN110_4 0x2e50 +#define AFE_CONN110_5 0x2e54 +#define AFE_CONN110_6 0x2e58 +#define AFE_CONN110_7 0x2e5c +#define AFE_CONN111_0 0x2e60 +#define AFE_CONN111_1 0x2e64 +#define AFE_CONN111_2 0x2e68 +#define AFE_CONN111_4 0x2e70 +#define AFE_CONN111_5 0x2e74 +#define AFE_CONN111_6 0x2e78 +#define AFE_CONN111_7 0x2e7c +#define AFE_CONN112_0 0x2e80 +#define AFE_CONN112_1 0x2e84 +#define AFE_CONN112_2 0x2e88 +#define AFE_CONN112_4 0x2e90 +#define AFE_CONN112_5 0x2e94 +#define AFE_CONN112_6 0x2e98 +#define AFE_CONN112_7 0x2e9c +#define AFE_CONN113_0 0x2ea0 +#define AFE_CONN113_1 0x2ea4 +#define AFE_CONN113_2 0x2ea8 +#define AFE_CONN113_4 0x2eb0 +#define AFE_CONN113_5 0x2eb4 +#define AFE_CONN113_6 0x2eb8 +#define AFE_CONN113_7 0x2ebc +#define AFE_CONN114_0 0x2ec0 +#define AFE_CONN114_1 0x2ec4 +#define AFE_CONN114_2 0x2ec8 +#define AFE_CONN114_4 0x2ed0 +#define AFE_CONN114_5 0x2ed4 +#define AFE_CONN114_6 0x2ed8 +#define AFE_CONN114_7 0x2edc +#define AFE_CONN115_0 0x2ee0 +#define AFE_CONN115_1 0x2ee4 +#define AFE_CONN115_2 0x2ee8 +#define AFE_CONN115_4 0x2ef0 +#define AFE_CONN115_5 0x2ef4 +#define AFE_CONN115_6 0x2ef8 +#define AFE_CONN115_7 0x2efc +#define AFE_CONN116_0 0x2f00 +#define AFE_CONN116_1 0x2f04 +#define AFE_CONN116_2 0x2f08 +#define AFE_CONN116_4 0x2f10 +#define AFE_CONN116_5 0x2f14 +#define AFE_CONN116_6 0x2f18 +#define AFE_CONN116_7 0x2f1c +#define AFE_CONN117_0 0x2f20 +#define AFE_CONN117_1 0x2f24 +#define AFE_CONN117_2 0x2f28 +#define AFE_CONN117_4 0x2f30 +#define AFE_CONN117_5 0x2f34 +#define AFE_CONN117_6 0x2f38 +#define AFE_CONN117_7 0x2f3c +#define AFE_CONN118_0 0x2f40 +#define AFE_CONN118_1 0x2f44 +#define AFE_CONN118_2 0x2f48 +#define AFE_CONN118_4 0x2f50 +#define AFE_CONN118_5 0x2f54 +#define AFE_CONN118_6 0x2f58 +#define AFE_CONN118_7 0x2f5c +#define AFE_CONN119_0 0x2f60 +#define AFE_CONN119_1 0x2f64 +#define AFE_CONN119_2 0x2f68 +#define AFE_CONN119_4 0x2f70 +#define AFE_CONN119_5 0x2f74 +#define AFE_CONN119_6 0x2f78 +#define AFE_CONN119_7 0x2f7c +#define AFE_CONN120_0 0x2f80 +#define AFE_CONN120_1 0x2f84 +#define AFE_CONN120_2 0x2f88 +#define AFE_CONN120_4 0x2f90 +#define AFE_CONN120_5 0x2f94 +#define AFE_CONN120_6 0x2f98 +#define AFE_CONN120_7 0x2f9c +#define AFE_CONN121_0 0x2fa0 +#define AFE_CONN121_1 0x2fa4 +#define AFE_CONN121_2 0x2fa8 +#define AFE_CONN121_4 0x2fb0 +#define AFE_CONN121_5 0x2fb4 +#define AFE_CONN121_6 0x2fb8 +#define AFE_CONN121_7 0x2fbc +#define AFE_CONN122_0 0x2fc0 +#define AFE_CONN122_1 0x2fc4 +#define AFE_CONN122_2 0x2fc8 +#define AFE_CONN122_4 0x2fd0 +#define AFE_CONN122_5 0x2fd4 +#define AFE_CONN122_6 0x2fd8 +#define AFE_CONN122_7 0x2fdc +#define AFE_CONN123_0 0x2fe0 +#define AFE_CONN123_1 0x2fe4 +#define AFE_CONN123_2 0x2fe8 +#define AFE_CONN123_4 0x2ff0 +#define AFE_CONN123_5 0x2ff4 +#define AFE_CONN123_6 0x2ff8 +#define AFE_CONN123_7 0x2ffc +#define AFE_CONN124_0 0x3000 +#define AFE_CONN124_1 0x3004 +#define AFE_CONN124_2 0x3008 +#define AFE_CONN124_4 0x3010 +#define AFE_CONN124_5 0x3014 +#define AFE_CONN124_6 0x3018 +#define AFE_CONN124_7 0x301c +#define AFE_CONN125_0 0x3020 +#define AFE_CONN125_1 0x3024 +#define AFE_CONN125_2 0x3028 +#define AFE_CONN125_4 0x3030 +#define AFE_CONN125_5 0x3034 +#define AFE_CONN125_6 0x3038 +#define AFE_CONN125_7 0x303c +#define AFE_CONN126_0 0x3040 +#define AFE_CONN126_1 0x3044 +#define AFE_CONN126_2 0x3048 +#define AFE_CONN126_4 0x3050 +#define AFE_CONN126_5 0x3054 +#define AFE_CONN126_6 0x3058 +#define AFE_CONN126_7 0x305c +#define AFE_CONN127_0 0x3060 +#define AFE_CONN127_1 0x3064 +#define AFE_CONN127_2 0x3068 +#define AFE_CONN127_4 0x3070 +#define AFE_CONN127_5 0x3074 +#define AFE_CONN127_6 0x3078 +#define AFE_CONN127_7 0x307c +#define AFE_CONN128_0 0x3080 +#define AFE_CONN128_1 0x3084 +#define AFE_CONN128_2 0x3088 +#define AFE_CONN128_4 0x3090 +#define AFE_CONN128_5 0x3094 +#define AFE_CONN128_6 0x3098 +#define AFE_CONN128_7 0x309c +#define AFE_CONN129_0 0x30a0 +#define AFE_CONN129_1 0x30a4 +#define AFE_CONN129_2 0x30a8 +#define AFE_CONN129_4 0x30b0 +#define AFE_CONN129_5 0x30b4 +#define AFE_CONN129_6 0x30b8 +#define AFE_CONN129_7 0x30bc +#define AFE_CONN130_0 0x30c0 +#define AFE_CONN130_1 0x30c4 +#define AFE_CONN130_2 0x30c8 +#define AFE_CONN130_4 0x30d0 +#define AFE_CONN130_5 0x30d4 +#define AFE_CONN130_6 0x30d8 +#define AFE_CONN130_7 0x30dc +#define AFE_CONN131_0 0x30e0 +#define AFE_CONN131_1 0x30e4 +#define AFE_CONN131_2 0x30e8 +#define AFE_CONN131_4 0x30f0 +#define AFE_CONN131_5 0x30f4 +#define AFE_CONN131_6 0x30f8 +#define AFE_CONN131_7 0x30fc +#define AFE_CONN132_0 0x3100 +#define AFE_CONN132_1 0x3104 +#define AFE_CONN132_2 0x3108 +#define AFE_CONN132_4 0x3110 +#define AFE_CONN132_5 0x3114 +#define AFE_CONN132_6 0x3118 +#define AFE_CONN132_7 0x311c +#define AFE_CONN133_0 0x3120 +#define AFE_CONN133_1 0x3124 +#define AFE_CONN133_2 0x3128 +#define AFE_CONN133_4 0x3130 +#define AFE_CONN133_5 0x3134 +#define AFE_CONN133_6 0x3138 +#define AFE_CONN133_7 0x313c +#define AFE_CONN134_0 0x3140 +#define AFE_CONN134_1 0x3144 +#define AFE_CONN134_2 0x3148 +#define AFE_CONN134_4 0x3150 +#define AFE_CONN134_5 0x3154 +#define AFE_CONN134_6 0x3158 +#define AFE_CONN134_7 0x315c +#define AFE_CONN135_0 0x3160 +#define AFE_CONN135_1 0x3164 +#define AFE_CONN135_2 0x3168 +#define AFE_CONN135_4 0x3170 +#define AFE_CONN135_5 0x3174 +#define AFE_CONN135_6 0x3178 +#define AFE_CONN135_7 0x317c +#define AFE_CONN136_0 0x3180 +#define AFE_CONN136_1 0x3184 +#define AFE_CONN136_2 0x3188 +#define AFE_CONN136_4 0x3190 +#define AFE_CONN136_5 0x3194 +#define AFE_CONN136_6 0x3198 +#define AFE_CONN136_7 0x319c +#define AFE_CONN137_0 0x31a0 +#define AFE_CONN137_1 0x31a4 +#define AFE_CONN137_2 0x31a8 +#define AFE_CONN137_4 0x31b0 +#define AFE_CONN137_5 0x31b4 +#define AFE_CONN137_6 0x31b8 +#define AFE_CONN137_7 0x31bc +#define AFE_CONN138_0 0x31c0 +#define AFE_CONN138_1 0x31c4 +#define AFE_CONN138_2 0x31c8 +#define AFE_CONN138_4 0x31d0 +#define AFE_CONN138_5 0x31d4 +#define AFE_CONN138_6 0x31d8 +#define AFE_CONN138_7 0x31dc +#define AFE_CONN139_0 0x31e0 +#define AFE_CONN139_1 0x31e4 +#define AFE_CONN139_2 0x31e8 +#define AFE_CONN139_4 0x31f0 +#define AFE_CONN139_5 0x31f4 +#define AFE_CONN139_6 0x31f8 +#define AFE_CONN139_7 0x31fc +#define AFE_CONN148_0 0x3300 +#define AFE_CONN148_1 0x3304 +#define AFE_CONN148_2 0x3308 +#define AFE_CONN148_4 0x3310 +#define AFE_CONN148_5 0x3314 +#define AFE_CONN148_6 0x3318 +#define AFE_CONN148_7 0x331c +#define AFE_CONN149_0 0x3320 +#define AFE_CONN149_1 0x3324 +#define AFE_CONN149_2 0x3328 +#define AFE_CONN149_4 0x3330 +#define AFE_CONN149_5 0x3334 +#define AFE_CONN149_6 0x3338 +#define AFE_CONN149_7 0x333c +#define AFE_CONN180_0 0x3700 +#define AFE_CONN180_1 0x3704 +#define AFE_CONN180_2 0x3708 +#define AFE_CONN180_4 0x3710 +#define AFE_CONN180_5 0x3714 +#define AFE_CONN180_6 0x3718 +#define AFE_CONN180_7 0x371c +#define AFE_CONN181_0 0x3720 +#define AFE_CONN181_1 0x3724 +#define AFE_CONN181_2 0x3728 +#define AFE_CONN181_4 0x3730 +#define AFE_CONN181_5 0x3734 +#define AFE_CONN181_6 0x3738 +#define AFE_CONN181_7 0x373c +#define AFE_CONN182_0 0x3740 +#define AFE_CONN182_1 0x3744 +#define AFE_CONN182_2 0x3748 +#define AFE_CONN182_4 0x3750 +#define AFE_CONN182_5 0x3754 +#define AFE_CONN182_6 0x3758 +#define AFE_CONN182_7 0x375c +#define AFE_CONN183_0 0x3760 +#define AFE_CONN183_1 0x3764 +#define AFE_CONN183_2 0x3768 +#define AFE_CONN183_4 0x3770 +#define AFE_CONN183_5 0x3774 +#define AFE_CONN183_6 0x3778 +#define AFE_CONN183_7 0x377c +#define AFE_CONN184_0 0x3780 +#define AFE_CONN184_1 0x3784 +#define AFE_CONN184_2 0x3788 +#define AFE_CONN184_4 0x3790 +#define AFE_CONN184_5 0x3794 +#define AFE_CONN184_6 0x3798 +#define AFE_CONN184_7 0x379c +#define AFE_CONN185_0 0x37a0 +#define AFE_CONN185_1 0x37a4 +#define AFE_CONN185_2 0x37a8 +#define AFE_CONN185_4 0x37b0 +#define AFE_CONN185_5 0x37b4 +#define AFE_CONN185_6 0x37b8 +#define AFE_CONN185_7 0x37bc +#define AFE_CONN186_0 0x37c0 +#define AFE_CONN186_1 0x37c4 +#define AFE_CONN186_2 0x37c8 +#define AFE_CONN186_4 0x37d0 +#define AFE_CONN186_5 0x37d4 +#define AFE_CONN186_6 0x37d8 +#define AFE_CONN186_7 0x37dc +#define AFE_CONN187_0 0x37e0 +#define AFE_CONN187_1 0x37e4 +#define AFE_CONN187_2 0x37e8 +#define AFE_CONN187_4 0x37f0 +#define AFE_CONN187_5 0x37f4 +#define AFE_CONN187_6 0x37f8 +#define AFE_CONN187_7 0x37fc +#define AFE_CONN188_0 0x3800 +#define AFE_CONN188_1 0x3804 +#define AFE_CONN188_2 0x3808 +#define AFE_CONN188_4 0x3810 +#define AFE_CONN188_5 0x3814 +#define AFE_CONN188_6 0x3818 +#define AFE_CONN188_7 0x381c +#define AFE_CONN189_0 0x3820 +#define AFE_CONN189_1 0x3824 +#define AFE_CONN189_2 0x3828 +#define AFE_CONN189_4 0x3830 +#define AFE_CONN189_5 0x3834 +#define AFE_CONN189_6 0x3838 +#define AFE_CONN189_7 0x383c +#define AFE_CONN190_0 0x3840 +#define AFE_CONN190_1 0x3844 +#define AFE_CONN190_2 0x3848 +#define AFE_CONN190_4 0x3850 +#define AFE_CONN190_5 0x3854 +#define AFE_CONN190_6 0x3858 +#define AFE_CONN190_7 0x385c +#define AFE_CONN191_0 0x3860 +#define AFE_CONN191_1 0x3864 +#define AFE_CONN191_2 0x3868 +#define AFE_CONN191_4 0x3870 +#define AFE_CONN191_5 0x3874 +#define AFE_CONN191_6 0x3878 +#define AFE_CONN191_7 0x387c +#define AFE_CONN192_0 0x3880 +#define AFE_CONN192_1 0x3884 +#define AFE_CONN192_2 0x3888 +#define AFE_CONN192_4 0x3890 +#define AFE_CONN192_5 0x3894 +#define AFE_CONN192_6 0x3898 +#define AFE_CONN192_7 0x389c +#define AFE_CONN193_0 0x38a0 +#define AFE_CONN193_1 0x38a4 +#define AFE_CONN193_2 0x38a8 +#define AFE_CONN193_4 0x38b0 +#define AFE_CONN193_5 0x38b4 +#define AFE_CONN193_6 0x38b8 +#define AFE_CONN193_7 0x38bc +#define AFE_CONN194_0 0x38c0 +#define AFE_CONN194_1 0x38c4 +#define AFE_CONN194_2 0x38c8 +#define AFE_CONN194_4 0x38d0 +#define AFE_CONN194_5 0x38d4 +#define AFE_CONN194_6 0x38d8 +#define AFE_CONN194_7 0x38dc +#define AFE_CONN195_0 0x38e0 +#define AFE_CONN195_1 0x38e4 +#define AFE_CONN195_2 0x38e8 +#define AFE_CONN195_4 0x38f0 +#define AFE_CONN195_5 0x38f4 +#define AFE_CONN195_6 0x38f8 +#define AFE_CONN195_7 0x38fc +#define AFE_CONN196_0 0x3900 +#define AFE_CONN196_1 0x3904 +#define AFE_CONN196_2 0x3908 +#define AFE_CONN196_4 0x3910 +#define AFE_CONN196_5 0x3914 +#define AFE_CONN196_6 0x3918 +#define AFE_CONN196_7 0x391c +#define AFE_CONN197_0 0x3920 +#define AFE_CONN197_1 0x3924 +#define AFE_CONN197_2 0x3928 +#define AFE_CONN197_4 0x3930 +#define AFE_CONN197_5 0x3934 +#define AFE_CONN197_6 0x3938 +#define AFE_CONN197_7 0x393c +#define AFE_CONN198_0 0x3940 +#define AFE_CONN198_1 0x3944 +#define AFE_CONN198_2 0x3948 +#define AFE_CONN198_4 0x3950 +#define AFE_CONN198_5 0x3954 +#define AFE_CONN198_6 0x3958 +#define AFE_CONN198_7 0x395c +#define AFE_CONN199_0 0x3960 +#define AFE_CONN199_1 0x3964 +#define AFE_CONN199_2 0x3968 +#define AFE_CONN199_4 0x3970 +#define AFE_CONN199_5 0x3974 +#define AFE_CONN199_6 0x3978 +#define AFE_CONN199_7 0x397c +#define AFE_CONN200_0 0x3980 +#define AFE_CONN200_1 0x3984 +#define AFE_CONN200_2 0x3988 +#define AFE_CONN200_4 0x3990 +#define AFE_CONN200_5 0x3994 +#define AFE_CONN200_6 0x3998 +#define AFE_CONN200_7 0x399c +#define AFE_CONN201_0 0x39a0 +#define AFE_CONN201_1 0x39a4 +#define AFE_CONN201_2 0x39a8 +#define AFE_CONN201_4 0x39b0 +#define AFE_CONN201_5 0x39b4 +#define AFE_CONN201_6 0x39b8 +#define AFE_CONN201_7 0x39bc +#define AFE_CONN202_0 0x39c0 +#define AFE_CONN202_1 0x39c4 +#define AFE_CONN202_2 0x39c8 +#define AFE_CONN202_4 0x39d0 +#define AFE_CONN202_5 0x39d4 +#define AFE_CONN202_6 0x39d8 +#define AFE_CONN202_7 0x39dc +#define AFE_CONN203_0 0x39e0 +#define AFE_CONN203_1 0x39e4 +#define AFE_CONN203_2 0x39e8 +#define AFE_CONN203_4 0x39f0 +#define AFE_CONN203_5 0x39f4 +#define AFE_CONN203_6 0x39f8 +#define AFE_CONN203_7 0x39fc +#define AFE_CONN204_0 0x3a00 +#define AFE_CONN204_1 0x3a04 +#define AFE_CONN204_2 0x3a08 +#define AFE_CONN204_4 0x3a10 +#define AFE_CONN204_5 0x3a14 +#define AFE_CONN204_6 0x3a18 +#define AFE_CONN204_7 0x3a1c +#define AFE_CONN205_0 0x3a20 +#define AFE_CONN205_1 0x3a24 +#define AFE_CONN205_2 0x3a28 +#define AFE_CONN205_4 0x3a30 +#define AFE_CONN205_5 0x3a34 +#define AFE_CONN205_6 0x3a38 +#define AFE_CONN205_7 0x3a3c +#define AFE_CONN206_0 0x3a40 +#define AFE_CONN206_1 0x3a44 +#define AFE_CONN206_2 0x3a48 +#define AFE_CONN206_4 0x3a50 +#define AFE_CONN206_5 0x3a54 +#define AFE_CONN206_6 0x3a58 +#define AFE_CONN206_7 0x3a5c +#define AFE_CONN207_0 0x3a60 +#define AFE_CONN207_1 0x3a64 +#define AFE_CONN207_2 0x3a68 +#define AFE_CONN207_4 0x3a70 +#define AFE_CONN207_5 0x3a74 +#define AFE_CONN207_6 0x3a78 +#define AFE_CONN207_7 0x3a7c +#define AFE_CONN208_0 0x3a80 +#define AFE_CONN208_1 0x3a84 +#define AFE_CONN208_2 0x3a88 +#define AFE_CONN208_4 0x3a90 +#define AFE_CONN208_5 0x3a94 +#define AFE_CONN208_6 0x3a98 +#define AFE_CONN208_7 0x3a9c +#define AFE_CONN209_0 0x3aa0 +#define AFE_CONN209_1 0x3aa4 +#define AFE_CONN209_2 0x3aa8 +#define AFE_CONN209_4 0x3ab0 +#define AFE_CONN209_5 0x3ab4 +#define AFE_CONN209_6 0x3ab8 +#define AFE_CONN209_7 0x3abc +#define AFE_CONN210_0 0x3ac0 +#define AFE_CONN210_1 0x3ac4 +#define AFE_CONN210_2 0x3ac8 +#define AFE_CONN210_4 0x3ad0 +#define AFE_CONN210_5 0x3ad4 +#define AFE_CONN210_6 0x3ad8 +#define AFE_CONN210_7 0x3adc +#define AFE_CONN211_0 0x3ae0 +#define AFE_CONN211_1 0x3ae4 +#define AFE_CONN211_2 0x3ae8 +#define AFE_CONN211_4 0x3af0 +#define AFE_CONN211_5 0x3af4 +#define AFE_CONN211_6 0x3af8 +#define AFE_CONN211_7 0x3afc +#define AFE_CONN_MON_CFG 0x4080 +#define AFE_CONN_MON0 0x4084 +#define AFE_CONN_MON1 0x4088 +#define AFE_CONN_MON2 0x408c +#define AFE_CONN_MON3 0x4090 +#define AFE_CONN_MON4 0x4094 +#define AFE_CONN_MON5 0x4098 +#define AFE_CONN_RS_0 0x40a0 +#define AFE_CONN_RS_1 0x40a4 +#define AFE_CONN_RS_2 0x40a8 +#define AFE_CONN_RS_3 0x40ac +#define AFE_CONN_RS_4 0x40b0 +#define AFE_CONN_RS_5 0x40b4 +#define AFE_CONN_RS_6 0x40b8 +#define AFE_CONN_DI_0 0x40c0 +#define AFE_CONN_DI_1 0x40c4 +#define AFE_CONN_DI_2 0x40c8 +#define AFE_CONN_DI_3 0x40cc +#define AFE_CONN_DI_4 0x40d0 +#define AFE_CONN_DI_5 0x40d4 +#define AFE_CONN_DI_6 0x40d8 +#define AFE_CONN_16BIT_0 0x40e0 +#define AFE_CONN_16BIT_1 0x40e4 +#define AFE_CONN_16BIT_2 0x40e8 +#define AFE_CONN_16BIT_3 0x40ec +#define AFE_CONN_16BIT_4 0x40f0 +#define AFE_CONN_16BIT_5 0x40f4 +#define AFE_CONN_16BIT_6 0x40f8 +#define AFE_CONN_24BIT_0 0x4100 +#define AFE_CONN_24BIT_1 0x4104 +#define AFE_CONN_24BIT_2 0x4108 +#define AFE_CONN_24BIT_3 0x410c +#define AFE_CONN_24BIT_4 0x4110 +#define AFE_CONN_24BIT_5 0x4114 +#define AFE_CONN_24BIT_6 0x4118 +#define AFE_CBIP_CFG0 0x4380 +#define AFE_CBIP_SLV_DECODER_MON0 0x4384 +#define AFE_CBIP_SLV_DECODER_MON1 0x4388 +#define AFE_CBIP_SLV_MUX_MON_CFG 0x438c +#define AFE_CBIP_SLV_MUX_MON0 0x4390 +#define AFE_CBIP_SLV_MUX_MON1 0x4394 +#define AFE_MEMIF_CON0 0x4400 +#define AFE_MEMIF_ONE_HEART 0x4420 +#define AFE_DL0_BASE_MSB 0x4440 +#define AFE_DL0_BASE 0x4444 +#define AFE_DL0_CUR_MSB 0x4448 +#define AFE_DL0_CUR 0x444c +#define AFE_DL0_END_MSB 0x4450 +#define AFE_DL0_END 0x4454 +#define AFE_DL0_RCH_MON 0x4458 +#define AFE_DL0_LCH_MON 0x445c +#define AFE_DL0_CON0 0x4460 +#define AFE_DL0_MON0 0x4464 +#define AFE_DL1_BASE_MSB 0x4470 +#define AFE_DL1_BASE 0x4474 +#define AFE_DL1_CUR_MSB 0x4478 +#define AFE_DL1_CUR 0x447c +#define AFE_DL1_END_MSB 0x4480 +#define AFE_DL1_END 0x4484 +#define AFE_DL1_RCH_MON 0x4488 +#define AFE_DL1_LCH_MON 0x448c +#define AFE_DL1_CON0 0x4490 +#define AFE_DL1_MON0 0x4494 +#define AFE_DL2_BASE_MSB 0x44a0 +#define AFE_DL2_BASE 0x44a4 +#define AFE_DL2_CUR_MSB 0x44a8 +#define AFE_DL2_CUR 0x44ac +#define AFE_DL2_END_MSB 0x44b0 +#define AFE_DL2_END 0x44b4 +#define AFE_DL2_RCH_MON 0x44b8 +#define AFE_DL2_LCH_MON 0x44bc +#define AFE_DL2_CON0 0x44c0 +#define AFE_DL2_MON0 0x44c4 +#define AFE_DL3_BASE_MSB 0x44d0 +#define AFE_DL3_BASE 0x44d4 +#define AFE_DL3_CUR_MSB 0x44d8 +#define AFE_DL3_CUR 0x44dc +#define AFE_DL3_END_MSB 0x44e0 +#define AFE_DL3_END 0x44e4 +#define AFE_DL3_RCH_MON 0x44e8 +#define AFE_DL3_LCH_MON 0x44ec +#define AFE_DL3_CON0 0x44f0 +#define AFE_DL3_MON0 0x44f4 +#define AFE_DL4_BASE_MSB 0x4500 +#define AFE_DL4_BASE 0x4504 +#define AFE_DL4_CUR_MSB 0x4508 +#define AFE_DL4_CUR 0x450c +#define AFE_DL4_END_MSB 0x4510 +#define AFE_DL4_END 0x4514 +#define AFE_DL4_RCH_MON 0x4518 +#define AFE_DL4_LCH_MON 0x451c +#define AFE_DL4_CON0 0x4520 +#define AFE_DL4_MON0 0x4524 +#define AFE_DL5_BASE_MSB 0x4530 +#define AFE_DL5_BASE 0x4534 +#define AFE_DL5_CUR_MSB 0x4538 +#define AFE_DL5_CUR 0x453c +#define AFE_DL5_END_MSB 0x4540 +#define AFE_DL5_END 0x4544 +#define AFE_DL5_RCH_MON 0x4548 +#define AFE_DL5_LCH_MON 0x454c +#define AFE_DL5_CON0 0x4550 +#define AFE_DL5_MON0 0x4554 +#define AFE_DL6_BASE_MSB 0x4560 +#define AFE_DL6_BASE 0x4564 +#define AFE_DL6_CUR_MSB 0x4568 +#define AFE_DL6_CUR 0x456c +#define AFE_DL6_END_MSB 0x4570 +#define AFE_DL6_END 0x4574 +#define AFE_DL6_RCH_MON 0x4578 +#define AFE_DL6_LCH_MON 0x457c +#define AFE_DL6_CON0 0x4580 +#define AFE_DL6_MON0 0x4584 +#define AFE_DL7_BASE_MSB 0x4590 +#define AFE_DL7_BASE 0x4594 +#define AFE_DL7_CUR_MSB 0x4598 +#define AFE_DL7_CUR 0x459c +#define AFE_DL7_END_MSB 0x45a0 +#define AFE_DL7_END 0x45a4 +#define AFE_DL7_RCH_MON 0x45a8 +#define AFE_DL7_LCH_MON 0x45ac +#define AFE_DL7_CON0 0x45b0 +#define AFE_DL7_MON0 0x45b4 +#define AFE_DL8_BASE_MSB 0x45c0 +#define AFE_DL8_BASE 0x45c4 +#define AFE_DL8_CUR_MSB 0x45c8 +#define AFE_DL8_CUR 0x45cc +#define AFE_DL8_END_MSB 0x45d0 +#define AFE_DL8_END 0x45d4 +#define AFE_DL8_RCH_MON 0x45d8 +#define AFE_DL8_LCH_MON 0x45dc +#define AFE_DL8_CON0 0x45e0 +#define AFE_DL8_MON0 0x45e4 +#define AFE_DL_4CH_BASE_MSB 0x45f0 +#define AFE_DL_4CH_BASE 0x45f4 +#define AFE_DL_4CH_CUR_MSB 0x45f8 +#define AFE_DL_4CH_CUR 0x45fc +#define AFE_DL_4CH_END_MSB 0x4600 +#define AFE_DL_4CH_END 0x4604 +#define AFE_DL_4CH_CON0 0x4610 +#define AFE_DL_4CH_MON0 0x4618 +#define AFE_DL_24CH_BASE_MSB 0x4620 +#define AFE_DL_24CH_BASE 0x4624 +#define AFE_DL_24CH_CUR_MSB 0x4628 +#define AFE_DL_24CH_CUR 0x462c +#define AFE_DL_24CH_END_MSB 0x4630 +#define AFE_DL_24CH_END 0x4634 +#define AFE_DL_24CH_CON0 0x4640 +#define AFE_DL_24CH_MON0 0x4648 +#define AFE_DL23_BASE_MSB 0x4680 +#define AFE_DL23_BASE 0x4684 +#define AFE_DL23_CUR_MSB 0x4688 +#define AFE_DL23_CUR 0x468c +#define AFE_DL23_END_MSB 0x4690 +#define AFE_DL23_END 0x4694 +#define AFE_DL23_RCH_MON 0x4698 +#define AFE_DL23_LCH_MON 0x469c +#define AFE_DL23_CON0 0x46a0 +#define AFE_DL23_MON0 0x46a4 +#define AFE_DL24_BASE_MSB 0x46b0 +#define AFE_DL24_BASE 0x46b4 +#define AFE_DL24_CUR_MSB 0x46b8 +#define AFE_DL24_CUR 0x46bc +#define AFE_DL24_END_MSB 0x46c0 +#define AFE_DL24_END 0x46c4 +#define AFE_DL24_RCH_MON 0x46c8 +#define AFE_DL24_LCH_MON 0x46cc +#define AFE_DL24_CON0 0x46d0 +#define AFE_DL24_MON0 0x46d4 +#define AFE_DL25_BASE_MSB 0x46e0 +#define AFE_DL25_BASE 0x46e4 +#define AFE_DL25_CUR_MSB 0x46e8 +#define AFE_DL25_CUR 0x46ec +#define AFE_DL25_END_MSB 0x46f0 +#define AFE_DL25_END 0x46f4 +#define AFE_DL25_RCH_MON 0x46f8 +#define AFE_DL25_LCH_MON 0x46fc +#define AFE_DL25_CON0 0x4700 +#define AFE_DL25_MON0 0x4704 +#define AFE_DL26_BASE_MSB 0x4710 +#define AFE_DL26_BASE 0x4714 +#define AFE_DL26_CUR_MSB 0x4718 +#define AFE_DL26_CUR 0x471c +#define AFE_DL26_END_MSB 0x4720 +#define AFE_DL26_END 0x4724 +#define AFE_DL26_RCH_MON 0x4728 +#define AFE_DL26_LCH_MON 0x472c +#define AFE_DL26_CON0 0x4730 +#define AFE_DL26_MON0 0x4734 +#define AFE_VUL0_BASE_MSB 0x4d60 +#define AFE_VUL0_BASE 0x4d64 +#define AFE_VUL0_CUR_MSB 0x4d68 +#define AFE_VUL0_CUR 0x4d6c +#define AFE_VUL0_END_MSB 0x4d70 +#define AFE_VUL0_END 0x4d74 +#define AFE_VUL0_RCH_MON 0x4d78 +#define AFE_VUL0_LCH_MON 0x4d7c +#define AFE_VUL0_CON0 0x4d80 +#define AFE_VUL0_MON0 0x4d84 +#define AFE_VUL1_BASE_MSB 0x4d90 +#define AFE_VUL1_BASE 0x4d94 +#define AFE_VUL1_CUR_MSB 0x4d98 +#define AFE_VUL1_CUR 0x4d9c +#define AFE_VUL1_END_MSB 0x4da0 +#define AFE_VUL1_END 0x4da4 +#define AFE_VUL1_RCH_MON 0x4da8 +#define AFE_VUL1_LCH_MON 0x4dac +#define AFE_VUL1_CON0 0x4db0 +#define AFE_VUL1_MON0 0x4db4 +#define AFE_VUL2_BASE_MSB 0x4dc0 +#define AFE_VUL2_BASE 0x4dc4 +#define AFE_VUL2_CUR_MSB 0x4dc8 +#define AFE_VUL2_CUR 0x4dcc +#define AFE_VUL2_END_MSB 0x4dd0 +#define AFE_VUL2_END 0x4dd4 +#define AFE_VUL2_RCH_MON 0x4dd8 +#define AFE_VUL2_LCH_MON 0x4ddc +#define AFE_VUL2_CON0 0x4de0 +#define AFE_VUL2_MON0 0x4de4 +#define AFE_VUL3_BASE_MSB 0x4df0 +#define AFE_VUL3_BASE 0x4df4 +#define AFE_VUL3_CUR_MSB 0x4df8 +#define AFE_VUL3_CUR 0x4dfc +#define AFE_VUL3_END_MSB 0x4e00 +#define AFE_VUL3_END 0x4e04 +#define AFE_VUL3_RCH_MON 0x4e08 +#define AFE_VUL3_LCH_MON 0x4e0c +#define AFE_VUL3_CON0 0x4e10 +#define AFE_VUL3_MON0 0x4e14 +#define AFE_VUL4_BASE_MSB 0x4e20 +#define AFE_VUL4_BASE 0x4e24 +#define AFE_VUL4_CUR_MSB 0x4e28 +#define AFE_VUL4_CUR 0x4e2c +#define AFE_VUL4_END_MSB 0x4e30 +#define AFE_VUL4_END 0x4e34 +#define AFE_VUL4_RCH_MON 0x4e38 +#define AFE_VUL4_LCH_MON 0x4e3c +#define AFE_VUL4_CON0 0x4e40 +#define AFE_VUL4_MON0 0x4e44 +#define AFE_VUL5_BASE_MSB 0x4e50 +#define AFE_VUL5_BASE 0x4e54 +#define AFE_VUL5_CUR_MSB 0x4e58 +#define AFE_VUL5_CUR 0x4e5c +#define AFE_VUL5_END_MSB 0x4e60 +#define AFE_VUL5_END 0x4e64 +#define AFE_VUL5_RCH_MON 0x4e68 +#define AFE_VUL5_LCH_MON 0x4e6c +#define AFE_VUL5_CON0 0x4e70 +#define AFE_VUL5_MON0 0x4e74 +#define AFE_VUL6_BASE_MSB 0x4e80 +#define AFE_VUL6_BASE 0x4e84 +#define AFE_VUL6_CUR_MSB 0x4e88 +#define AFE_VUL6_CUR 0x4e8c +#define AFE_VUL6_END_MSB 0x4e90 +#define AFE_VUL6_END 0x4e94 +#define AFE_VUL6_RCH_MON 0x4e98 +#define AFE_VUL6_LCH_MON 0x4e9c +#define AFE_VUL6_CON0 0x4ea0 +#define AFE_VUL6_MON0 0x4ea4 +#define AFE_VUL7_BASE_MSB 0x4eb0 +#define AFE_VUL7_BASE 0x4eb4 +#define AFE_VUL7_CUR_MSB 0x4eb8 +#define AFE_VUL7_CUR 0x4ebc +#define AFE_VUL7_END_MSB 0x4ec0 +#define AFE_VUL7_END 0x4ec4 +#define AFE_VUL7_RCH_MON 0x4ec8 +#define AFE_VUL7_LCH_MON 0x4ecc +#define AFE_VUL7_CON0 0x4ed0 +#define AFE_VUL7_MON0 0x4ed4 +#define AFE_VUL8_BASE_MSB 0x4ee0 +#define AFE_VUL8_BASE 0x4ee4 +#define AFE_VUL8_CUR_MSB 0x4ee8 +#define AFE_VUL8_CUR 0x4eec +#define AFE_VUL8_END_MSB 0x4ef0 +#define AFE_VUL8_END 0x4ef4 +#define AFE_VUL8_RCH_MON 0x4ef8 +#define AFE_VUL8_LCH_MON 0x4efc +#define AFE_VUL8_CON0 0x4f00 +#define AFE_VUL8_MON0 0x4f04 +#define AFE_VUL9_BASE_MSB 0x4f10 +#define AFE_VUL9_BASE 0x4f14 +#define AFE_VUL9_CUR_MSB 0x4f18 +#define AFE_VUL9_CUR 0x4f1c +#define AFE_VUL9_END_MSB 0x4f20 +#define AFE_VUL9_END 0x4f24 +#define AFE_VUL9_RCH_MON 0x4f28 +#define AFE_VUL9_LCH_MON 0x4f2c +#define AFE_VUL9_CON0 0x4f30 +#define AFE_VUL9_MON0 0x4f34 +#define AFE_VUL10_BASE_MSB 0x4f40 +#define AFE_VUL10_BASE 0x4f44 +#define AFE_VUL10_CUR_MSB 0x4f48 +#define AFE_VUL10_CUR 0x4f4c +#define AFE_VUL10_END_MSB 0x4f50 +#define AFE_VUL10_END 0x4f54 +#define AFE_VUL10_RCH_MON 0x4f58 +#define AFE_VUL10_LCH_MON 0x4f5c +#define AFE_VUL10_CON0 0x4f60 +#define AFE_VUL10_MON0 0x4f64 +#define AFE_VUL24_BASE_MSB 0x4fa0 +#define AFE_VUL24_BASE 0x4fa4 +#define AFE_VUL24_CUR_MSB 0x4fa8 +#define AFE_VUL24_CUR 0x4fac +#define AFE_VUL24_END_MSB 0x4fb0 +#define AFE_VUL24_END 0x4fb4 +#define AFE_VUL24_CON0 0x4fb8 +#define AFE_VUL24_MON0 0x4fbc +#define AFE_VUL25_BASE_MSB 0x4fc0 +#define AFE_VUL25_BASE 0x4fc4 +#define AFE_VUL25_CUR_MSB 0x4fc8 +#define AFE_VUL25_CUR 0x4fcc +#define AFE_VUL25_END_MSB 0x4fd0 +#define AFE_VUL25_END 0x4fd4 +#define AFE_VUL25_CON0 0x4fd8 +#define AFE_VUL25_MON0 0x4fdc +#define AFE_VUL26_BASE_MSB 0x4fe0 +#define AFE_VUL26_BASE 0x4fe4 +#define AFE_VUL26_CUR_MSB 0x4fe8 +#define AFE_VUL26_CUR 0x4fec +#define AFE_VUL26_END_MSB 0x4ff0 +#define AFE_VUL26_END 0x4ff4 +#define AFE_VUL26_CON0 0x4ff8 +#define AFE_VUL26_MON0 0x4ffc +#define AFE_VUL_CM0_BASE_MSB 0x51c0 +#define AFE_VUL_CM0_BASE 0x51c4 +#define AFE_VUL_CM0_CUR_MSB 0x51c8 +#define AFE_VUL_CM0_CUR 0x51cc +#define AFE_VUL_CM0_END_MSB 0x51d0 +#define AFE_VUL_CM0_END 0x51d4 +#define AFE_VUL_CM0_CON0 0x51d8 +#define AFE_VUL_CM1_BASE_MSB 0x51e0 +#define AFE_VUL_CM1_BASE 0x51e4 +#define AFE_VUL_CM1_CUR_MSB 0x51e8 +#define AFE_VUL_CM1_CUR 0x51ec +#define AFE_VUL_CM1_END_MSB 0x51f0 +#define AFE_VUL_CM1_END 0x51f4 +#define AFE_VUL_CM1_CON0 0x51f8 +#define AFE_VUL_CM2_BASE_MSB 0x5200 +#define AFE_VUL_CM2_BASE 0x5204 +#define AFE_VUL_CM2_CUR_MSB 0x5208 +#define AFE_VUL_CM2_CUR 0x520c +#define AFE_VUL_CM2_END_MSB 0x5210 +#define AFE_VUL_CM2_END 0x5214 +#define AFE_VUL_CM2_CON0 0x5218 +#define AFE_ETDM_IN0_BASE_MSB 0x5220 +#define AFE_ETDM_IN0_BASE 0x5224 +#define AFE_ETDM_IN0_CUR_MSB 0x5228 +#define AFE_ETDM_IN0_CUR 0x522c +#define AFE_ETDM_IN0_END_MSB 0x5230 +#define AFE_ETDM_IN0_END 0x5234 +#define AFE_ETDM_IN0_CON0 0x5238 +#define AFE_ETDM_IN1_BASE_MSB 0x5240 +#define AFE_ETDM_IN1_BASE 0x5244 +#define AFE_ETDM_IN1_CUR_MSB 0x5248 +#define AFE_ETDM_IN1_CUR 0x524c +#define AFE_ETDM_IN1_END_MSB 0x5250 +#define AFE_ETDM_IN1_END 0x5254 +#define AFE_ETDM_IN1_CON0 0x5258 +#define AFE_ETDM_IN2_BASE_MSB 0x5260 +#define AFE_ETDM_IN2_BASE 0x5264 +#define AFE_ETDM_IN2_CUR_MSB 0x5268 +#define AFE_ETDM_IN2_CUR 0x526c +#define AFE_ETDM_IN2_END_MSB 0x5270 +#define AFE_ETDM_IN2_END 0x5274 +#define AFE_ETDM_IN2_CON0 0x5278 +#define AFE_ETDM_IN3_BASE_MSB 0x5280 +#define AFE_ETDM_IN3_BASE 0x5284 +#define AFE_ETDM_IN3_CUR_MSB 0x5288 +#define AFE_ETDM_IN3_CUR 0x528c +#define AFE_ETDM_IN3_END_MSB 0x5290 +#define AFE_ETDM_IN3_END 0x5294 +#define AFE_ETDM_IN3_CON0 0x5298 +#define AFE_ETDM_IN4_BASE_MSB 0x52a0 +#define AFE_ETDM_IN4_BASE 0x52a4 +#define AFE_ETDM_IN4_CUR_MSB 0x52a8 +#define AFE_ETDM_IN4_CUR 0x52ac +#define AFE_ETDM_IN4_END_MSB 0x52b0 +#define AFE_ETDM_IN4_END 0x52b4 +#define AFE_ETDM_IN4_CON0 0x52b8 +#define AFE_ETDM_IN5_BASE_MSB 0x52c0 +#define AFE_ETDM_IN5_BASE 0x52c4 +#define AFE_ETDM_IN5_CUR_MSB 0x52c8 +#define AFE_ETDM_IN5_CUR 0x52cc +#define AFE_ETDM_IN5_END_MSB 0x52d0 +#define AFE_ETDM_IN5_END 0x52d4 +#define AFE_ETDM_IN5_CON0 0x52d8 +#define AFE_ETDM_IN6_BASE_MSB 0x52e0 +#define AFE_ETDM_IN6_BASE 0x52e4 +#define AFE_ETDM_IN6_CUR_MSB 0x52e8 +#define AFE_ETDM_IN6_CUR 0x52ec +#define AFE_ETDM_IN6_END_MSB 0x52f0 +#define AFE_ETDM_IN6_END 0x52f4 +#define AFE_ETDM_IN6_CON0 0x52f8 +#define AFE_HDMI_OUT_BASE_MSB 0x5360 +#define AFE_HDMI_OUT_BASE 0x5364 +#define AFE_HDMI_OUT_CUR_MSB 0x5368 +#define AFE_HDMI_OUT_CUR 0x536c +#define AFE_HDMI_OUT_END_MSB 0x5370 +#define AFE_HDMI_OUT_END 0x5374 +#define AFE_HDMI_OUT_CON0 0x5378 +#define AFE_VUL24_RCH_MON 0x53e0 +#define AFE_VUL24_LCH_MON 0x53e4 +#define AFE_VUL25_RCH_MON 0x53e8 +#define AFE_VUL25_LCH_MON 0x53ec +#define AFE_VUL26_RCH_MON 0x53f0 +#define AFE_VUL26_LCH_MON 0x53f4 +#define AFE_VUL_CM0_RCH_MON 0x5458 +#define AFE_VUL_CM0_LCH_MON 0x545c +#define AFE_VUL_CM1_RCH_MON 0x5460 +#define AFE_VUL_CM1_LCH_MON 0x5464 +#define AFE_VUL_CM2_RCH_MON 0x5468 +#define AFE_VUL_CM2_LCH_MON 0x546c +#define AFE_DL_4CH_CH0_MON 0x54f4 +#define AFE_DL_4CH_CH1_MON 0x54f8 +#define AFE_DL_4CH_CH2_MON 0x54fc +#define AFE_DL_4CH_CH3_MON 0x5500 +#define AFE_DL_24CH_CH0_MON 0x5504 +#define AFE_DL_24CH_CH1_MON 0x5508 +#define AFE_DL_24CH_CH2_MON 0x550c +#define AFE_DL_24CH_CH3_MON 0x5510 +#define AFE_DL_24CH_CH4_MON 0x5514 +#define AFE_DL_24CH_CH5_MON 0x5518 +#define AFE_DL_24CH_CH6_MON 0x551c +#define AFE_DL_24CH_CH7_MON 0x5520 +#define AFE_DL_24CH_CH8_MON 0x5524 +#define AFE_DL_24CH_CH9_MON 0x5528 +#define AFE_DL_24CH_CH10_MON 0x552c +#define AFE_DL_24CH_CH11_MON 0x5530 +#define AFE_DL_24CH_CH12_MON 0x5534 +#define AFE_DL_24CH_CH13_MON 0x5538 +#define AFE_DL_24CH_CH14_MON 0x553c +#define AFE_DL_24CH_CH15_MON 0x5540 +#define AFE_SRAM_BOUND 0x5620 +#define AFE_SECURE_CON0 0x5624 +#define AFE_SECURE_CON1 0x5628 +#define AFE_SE_SECURE_CON0 0x5630 +#define AFE_SE_SECURE_CON1 0x5634 +#define AFE_SE_SECURE_CON2 0x5638 +#define AFE_SE_SECURE_CON3 0x563c +#define AFE_SE_PROT_SIDEBAND0 0x5640 +#define AFE_SE_PROT_SIDEBAND1 0x5644 +#define AFE_SE_PROT_SIDEBAND2 0x5648 +#define AFE_SE_PROT_SIDEBAND3 0x564c +#define AFE_SE_DOMAIN_SIDEBAND0 0x5650 +#define AFE_SE_DOMAIN_SIDEBAND1 0x5654 +#define AFE_SE_DOMAIN_SIDEBAND2 0x5658 +#define AFE_SE_DOMAIN_SIDEBAND3 0x565c +#define AFE_SE_DOMAIN_SIDEBAND4 0x5660 +#define AFE_SE_DOMAIN_SIDEBAND5 0x5664 +#define AFE_SE_DOMAIN_SIDEBAND6 0x5668 +#define AFE_SE_DOMAIN_SIDEBAND7 0x566c +#define AFE_SE_DOMAIN_SIDEBAND8 0x5670 +#define AFE_SE_DOMAIN_SIDEBAND9 0x5674 +#define AFE_PROT_SIDEBAND0_MON 0x5678 +#define AFE_PROT_SIDEBAND1_MON 0x567c +#define AFE_PROT_SIDEBAND2_MON 0x5680 +#define AFE_PROT_SIDEBAND3_MON 0x5684 +#define AFE_DOMAIN_SIDEBAND0_MON 0x5688 +#define AFE_DOMAIN_SIDEBAND1_MON 0x568c +#define AFE_DOMAIN_SIDEBAND2_MON 0x5690 +#define AFE_DOMAIN_SIDEBAND3_MON 0x5694 +#define AFE_DOMAIN_SIDEBAND4_MON 0x5698 +#define AFE_DOMAIN_SIDEBAND5_MON 0x569c +#define AFE_DOMAIN_SIDEBAND6_MON 0x56a0 +#define AFE_DOMAIN_SIDEBAND7_MON 0x56a4 +#define AFE_DOMAIN_SIDEBAND8_MON 0x56a8 +#define AFE_DOMAIN_SIDEBAND9_MON 0x56ac +#define AFE_SECURE_CONN0 0x56b0 +#define AFE_SECURE_CONN_ETDM0 0x56b4 +#define AFE_SECURE_CONN_ETDM1 0x56b8 +#define AFE_SECURE_CONN_ETDM2 0x56bc +#define AFE_SECURE_SRAM_CON0 0x56c0 +#define AFE_SECURE_SRAM_CON1 0x56c4 +#define AFE_SE_CONN_INPUT_MASK0 0x56d0 +#define AFE_SE_CONN_INPUT_MASK1 0x56d4 +#define AFE_SE_CONN_INPUT_MASK2 0x56d8 +#define AFE_SE_CONN_INPUT_MASK3 0x56dc +#define AFE_SE_CONN_INPUT_MASK4 0x56e0 +#define AFE_SE_CONN_INPUT_MASK5 0x56e4 +#define AFE_SE_CONN_INPUT_MASK6 0x56e8 +#define AFE_SE_CONN_INPUT_MASK7 0x56ec +#define AFE_NON_SE_CONN_INPUT_MASK0 0x56f0 +#define AFE_NON_SE_CONN_INPUT_MASK1 0x56f4 +#define AFE_NON_SE_CONN_INPUT_MASK2 0x56f8 +#define AFE_NON_SE_CONN_INPUT_MASK3 0x56fc +#define AFE_NON_SE_CONN_INPUT_MASK4 0x5700 +#define AFE_NON_SE_CONN_INPUT_MASK5 0x5704 +#define AFE_NON_SE_CONN_INPUT_MASK6 0x5708 +#define AFE_NON_SE_CONN_INPUT_MASK7 0x570c +#define AFE_SE_CONN_OUTPUT_SEL0 0x5710 +#define AFE_SE_CONN_OUTPUT_SEL1 0x5714 +#define AFE_SE_CONN_OUTPUT_SEL2 0x5718 +#define AFE_SE_CONN_OUTPUT_SEL3 0x571c +#define AFE_SE_CONN_OUTPUT_SEL4 0x5720 +#define AFE_SE_CONN_OUTPUT_SEL5 0x5724 +#define AFE_SE_CONN_OUTPUT_SEL6 0x5728 +#define AFE_SE_CONN_OUTPUT_SEL7 0x572c +#define AFE_PCM0_INTF_CON1_MASK_MON 0x5730 +#define AFE_PCM0_INTF_CON0_MASK_MON 0x5734 +#define AFE_CONNSYS_I2S_CON_MASK_MON 0x5738 +#define AFE_TDM_CON2_MASK_MON 0x5744 +#define AFE_MTKAIF0_CFG0_MASK_MON 0x574c +#define AFE_MTKAIF1_CFG0_MASK_MON 0x5750 +#define AFE_ADDA_UL0_SRC_CON0_MASK_MON 0x5754 +#define AFE_ADDA_UL1_SRC_CON0_MASK_MON 0x5758 +#define AFE_ADDA_UL2_SRC_CON0_MASK_MON 0x575c +#define AFE_ASRC_NEW_CON0 0x7800 +#define AFE_ASRC_NEW_CON1 0x7804 +#define AFE_ASRC_NEW_CON2 0x7808 +#define AFE_ASRC_NEW_CON3 0x780c +#define AFE_ASRC_NEW_CON4 0x7810 +#define AFE_ASRC_NEW_CON5 0x7814 +#define AFE_ASRC_NEW_CON6 0x7818 +#define AFE_ASRC_NEW_CON7 0x781c +#define AFE_ASRC_NEW_CON8 0x7820 +#define AFE_ASRC_NEW_CON9 0x7824 +#define AFE_ASRC_NEW_CON10 0x7828 +#define AFE_ASRC_NEW_CON11 0x782c +#define AFE_ASRC_NEW_CON12 0x7830 +#define AFE_ASRC_NEW_CON13 0x7834 +#define AFE_ASRC_NEW_CON14 0x7838 +#define AFE_ASRC_NEW_IP_VERSION 0x783c +#define AFE_GASRC0_NEW_CON0 0x7840 +#define AFE_GASRC0_NEW_CON1 0x7844 +#define AFE_GASRC0_NEW_CON2 0x7848 +#define AFE_GASRC0_NEW_CON3 0x784c +#define AFE_GASRC0_NEW_CON4 0x7850 +#define AFE_GASRC0_NEW_CON5 0x7854 +#define AFE_GASRC0_NEW_CON6 0x7858 +#define AFE_GASRC0_NEW_CON7 0x785c +#define AFE_GASRC0_NEW_CON8 0x7860 +#define AFE_GASRC0_NEW_CON9 0x7864 +#define AFE_GASRC0_NEW_CON10 0x7868 +#define AFE_GASRC0_NEW_CON11 0x786c +#define AFE_GASRC0_NEW_CON12 0x7870 +#define AFE_GASRC0_NEW_CON13 0x7874 +#define AFE_GASRC0_NEW_CON14 0x7878 +#define AFE_GASRC0_NEW_IP_VERSION 0x787c +#define AFE_GASRC1_NEW_CON0 0x7880 +#define AFE_GASRC1_NEW_CON1 0x7884 +#define AFE_GASRC1_NEW_CON2 0x7888 +#define AFE_GASRC1_NEW_CON3 0x788c +#define AFE_GASRC1_NEW_CON4 0x7890 +#define AFE_GASRC1_NEW_CON5 0x7894 +#define AFE_GASRC1_NEW_CON6 0x7898 +#define AFE_GASRC1_NEW_CON7 0x789c +#define AFE_GASRC1_NEW_CON8 0x78a0 +#define AFE_GASRC1_NEW_CON9 0x78a4 +#define AFE_GASRC1_NEW_CON10 0x78a8 +#define AFE_GASRC1_NEW_CON11 0x78ac +#define AFE_GASRC1_NEW_CON12 0x78b0 +#define AFE_GASRC1_NEW_CON13 0x78b4 +#define AFE_GASRC1_NEW_CON14 0x78b8 +#define AFE_GASRC1_NEW_IP_VERSION 0x78bc +#define AFE_GASRC2_NEW_CON0 0x78c0 +#define AFE_GASRC2_NEW_CON1 0x78c4 +#define AFE_GASRC2_NEW_CON2 0x78c8 +#define AFE_GASRC2_NEW_CON3 0x78cc +#define AFE_GASRC2_NEW_CON4 0x78d0 +#define AFE_GASRC2_NEW_CON5 0x78d4 +#define AFE_GASRC2_NEW_CON6 0x78d8 +#define AFE_GASRC2_NEW_CON7 0x78dc +#define AFE_GASRC2_NEW_CON8 0x78e0 +#define AFE_GASRC2_NEW_CON9 0x78e4 +#define AFE_GASRC2_NEW_CON10 0x78e8 +#define AFE_GASRC2_NEW_CON11 0x78ec +#define AFE_GASRC2_NEW_CON12 0x78f0 +#define AFE_GASRC2_NEW_CON13 0x78f4 +#define AFE_GASRC2_NEW_CON14 0x78f8 +#define AFE_GASRC2_NEW_IP_VERSION 0x78fc +#define AFE_GASRC3_NEW_CON0 0x7900 +#define AFE_GASRC3_NEW_CON1 0x7904 +#define AFE_GASRC3_NEW_CON2 0x7908 +#define AFE_GASRC3_NEW_CON3 0x790c +#define AFE_GASRC3_NEW_CON4 0x7910 +#define AFE_GASRC3_NEW_CON5 0x7914 +#define AFE_GASRC3_NEW_CON6 0x7918 +#define AFE_GASRC3_NEW_CON7 0x791c +#define AFE_GASRC3_NEW_CON8 0x7920 +#define AFE_GASRC3_NEW_CON9 0x7924 +#define AFE_GASRC3_NEW_CON10 0x7928 +#define AFE_GASRC3_NEW_CON11 0x792c +#define AFE_GASRC3_NEW_CON12 0x7930 +#define AFE_GASRC3_NEW_CON13 0x7934 +#define AFE_GASRC3_NEW_CON14 0x7938 +#define AFE_GASRC3_NEW_IP_VERSION 0x793c +#define AFE_GASRC4_NEW_CON0 0x7940 +#define AFE_GASRC4_NEW_CON1 0x7944 +#define AFE_GASRC4_NEW_CON2 0x7948 +#define AFE_GASRC4_NEW_CON3 0x794c +#define AFE_GASRC4_NEW_CON4 0x7950 +#define AFE_GASRC4_NEW_CON5 0x7954 +#define AFE_GASRC4_NEW_CON6 0x7958 +#define AFE_GASRC4_NEW_CON7 0x795c +#define AFE_GASRC4_NEW_CON8 0x7960 +#define AFE_GASRC4_NEW_CON9 0x7964 +#define AFE_GASRC4_NEW_CON10 0x7968 +#define AFE_GASRC4_NEW_CON11 0x796c +#define AFE_GASRC4_NEW_CON12 0x7970 +#define AFE_GASRC4_NEW_CON13 0x7974 +#define AFE_GASRC4_NEW_CON14 0x7978 +#define AFE_GASRC4_NEW_IP_VERSION 0x797c +#define AFE_GASRC5_NEW_CON0 0x7980 +#define AFE_GASRC5_NEW_CON1 0x7984 +#define AFE_GASRC5_NEW_CON2 0x7988 +#define AFE_GASRC5_NEW_CON3 0x798c +#define AFE_GASRC5_NEW_CON4 0x7990 +#define AFE_GASRC5_NEW_CON5 0x7994 +#define AFE_GASRC5_NEW_CON6 0x7998 +#define AFE_GASRC5_NEW_CON7 0x799c +#define AFE_GASRC5_NEW_CON8 0x79a0 +#define AFE_GASRC5_NEW_CON9 0x79a4 +#define AFE_GASRC5_NEW_CON10 0x79a8 +#define AFE_GASRC5_NEW_CON11 0x79ac +#define AFE_GASRC5_NEW_CON12 0x79b0 +#define AFE_GASRC5_NEW_CON13 0x79b4 +#define AFE_GASRC5_NEW_CON14 0x79b8 +#define AFE_GASRC5_NEW_IP_VERSION 0x79bc +#define AFE_GASRC6_NEW_CON0 0x79c0 +#define AFE_GASRC6_NEW_CON1 0x79c4 +#define AFE_GASRC6_NEW_CON2 0x79c8 +#define AFE_GASRC6_NEW_CON3 0x79cc +#define AFE_GASRC6_NEW_CON4 0x79d0 +#define AFE_GASRC6_NEW_CON5 0x79d4 +#define AFE_GASRC6_NEW_CON6 0x79d8 +#define AFE_GASRC6_NEW_CON7 0x79dc +#define AFE_GASRC6_NEW_CON8 0x79e0 +#define AFE_GASRC6_NEW_CON9 0x79e4 +#define AFE_GASRC6_NEW_CON10 0x79e8 +#define AFE_GASRC6_NEW_CON11 0x79ec +#define AFE_GASRC6_NEW_CON12 0x79f0 +#define AFE_GASRC6_NEW_CON13 0x79f4 +#define AFE_GASRC6_NEW_CON14 0x79f8 +#define AFE_GASRC6_NEW_IP_VERSION 0x79fc +#define AFE_GASRC7_NEW_CON0 0x7a00 +#define AFE_GASRC7_NEW_CON1 0x7a04 +#define AFE_GASRC7_NEW_CON2 0x7a08 +#define AFE_GASRC7_NEW_CON3 0x7a0c +#define AFE_GASRC7_NEW_CON4 0x7a10 +#define AFE_GASRC7_NEW_CON5 0x7a14 +#define AFE_GASRC7_NEW_CON6 0x7a18 +#define AFE_GASRC7_NEW_CON7 0x7a1c +#define AFE_GASRC7_NEW_CON8 0x7a20 +#define AFE_GASRC7_NEW_CON9 0x7a24 +#define AFE_GASRC7_NEW_CON10 0x7a28 +#define AFE_GASRC7_NEW_CON11 0x7a2c +#define AFE_GASRC7_NEW_CON12 0x7a30 +#define AFE_GASRC7_NEW_CON13 0x7a34 +#define AFE_GASRC7_NEW_CON14 0x7a38 +#define AFE_GASRC7_NEW_IP_VERSION 0x7a3c +#define AFE_GASRC8_NEW_CON0 0x7a40 +#define AFE_GASRC8_NEW_CON1 0x7a44 +#define AFE_GASRC8_NEW_CON2 0x7a48 +#define AFE_GASRC8_NEW_CON3 0x7a4c +#define AFE_GASRC8_NEW_CON4 0x7a50 +#define AFE_GASRC8_NEW_CON5 0x7a54 +#define AFE_GASRC8_NEW_CON6 0x7a58 +#define AFE_GASRC8_NEW_CON7 0x7a5c +#define AFE_GASRC8_NEW_CON8 0x7a60 +#define AFE_GASRC8_NEW_CON9 0x7a64 +#define AFE_GASRC8_NEW_CON10 0x7a68 +#define AFE_GASRC8_NEW_CON11 0x7a6c +#define AFE_GASRC8_NEW_CON12 0x7a70 +#define AFE_GASRC8_NEW_CON13 0x7a74 +#define AFE_GASRC8_NEW_CON14 0x7a78 +#define AFE_GASRC8_NEW_IP_VERSION 0x7a7c +#define AFE_GASRC9_NEW_CON0 0x7a80 +#define AFE_GASRC9_NEW_CON1 0x7a84 +#define AFE_GASRC9_NEW_CON2 0x7a88 +#define AFE_GASRC9_NEW_CON3 0x7a8c +#define AFE_GASRC9_NEW_CON4 0x7a90 +#define AFE_GASRC9_NEW_CON5 0x7a94 +#define AFE_GASRC9_NEW_CON6 0x7a98 +#define AFE_GASRC9_NEW_CON7 0x7a9c +#define AFE_GASRC9_NEW_CON8 0x7aa0 +#define AFE_GASRC9_NEW_CON9 0x7aa4 +#define AFE_GASRC9_NEW_CON10 0x7aa8 +#define AFE_GASRC9_NEW_CON11 0x7aac +#define AFE_GASRC9_NEW_CON12 0x7ab0 +#define AFE_GASRC9_NEW_CON13 0x7ab4 +#define AFE_GASRC9_NEW_CON14 0x7ab8 +#define AFE_GASRC9_NEW_IP_VERSION 0x7abc +#define AFE_GASRC10_NEW_CON0 0x7ac0 +#define AFE_GASRC10_NEW_CON1 0x7ac4 +#define AFE_GASRC10_NEW_CON2 0x7ac8 +#define AFE_GASRC10_NEW_CON3 0x7acc +#define AFE_GASRC10_NEW_CON4 0x7ad0 +#define AFE_GASRC10_NEW_CON5 0x7ad4 +#define AFE_GASRC10_NEW_CON6 0x7ad8 +#define AFE_GASRC10_NEW_CON7 0x7adc +#define AFE_GASRC10_NEW_CON8 0x7ae0 +#define AFE_GASRC10_NEW_CON9 0x7ae4 +#define AFE_GASRC10_NEW_CON10 0x7ae8 +#define AFE_GASRC10_NEW_CON11 0x7aec +#define AFE_GASRC10_NEW_CON12 0x7af0 +#define AFE_GASRC10_NEW_CON13 0x7af4 +#define AFE_GASRC10_NEW_CON14 0x7af8 +#define AFE_GASRC10_NEW_IP_VERSION 0x7afc +#define AFE_GASRC11_NEW_CON0 0x7b00 +#define AFE_GASRC11_NEW_CON1 0x7b04 +#define AFE_GASRC11_NEW_CON2 0x7b08 +#define AFE_GASRC11_NEW_CON3 0x7b0c +#define AFE_GASRC11_NEW_CON4 0x7b10 +#define AFE_GASRC11_NEW_CON5 0x7b14 +#define AFE_GASRC11_NEW_CON6 0x7b18 +#define AFE_GASRC11_NEW_CON7 0x7b1c +#define AFE_GASRC11_NEW_CON8 0x7b20 +#define AFE_GASRC11_NEW_CON9 0x7b24 +#define AFE_GASRC11_NEW_CON10 0x7b28 +#define AFE_GASRC11_NEW_CON11 0x7b2c +#define AFE_GASRC11_NEW_CON12 0x7b30 +#define AFE_GASRC11_NEW_CON13 0x7b34 +#define AFE_GASRC11_NEW_CON14 0x7b38 +#define AFE_GASRC11_NEW_IP_VERSION 0x7b3c +#define AFE_GASRC12_NEW_CON0 0x7b40 +#define AFE_GASRC12_NEW_CON1 0x7b44 +#define AFE_GASRC12_NEW_CON2 0x7b48 +#define AFE_GASRC12_NEW_CON3 0x7b4c +#define AFE_GASRC12_NEW_CON4 0x7b50 +#define AFE_GASRC12_NEW_CON5 0x7b54 +#define AFE_GASRC12_NEW_CON6 0x7b58 +#define AFE_GASRC12_NEW_CON7 0x7b5c +#define AFE_GASRC12_NEW_CON8 0x7b60 +#define AFE_GASRC12_NEW_CON9 0x7b64 +#define AFE_GASRC12_NEW_CON10 0x7b68 +#define AFE_GASRC12_NEW_CON11 0x7b6c +#define AFE_GASRC12_NEW_CON12 0x7b70 +#define AFE_GASRC12_NEW_CON13 0x7b74 +#define AFE_GASRC12_NEW_CON14 0x7b78 +#define AFE_GASRC12_NEW_IP_VERSION 0x7b7c +#define AFE_GASRC13_NEW_CON0 0x7b80 +#define AFE_GASRC13_NEW_CON1 0x7b84 +#define AFE_GASRC13_NEW_CON2 0x7b88 +#define AFE_GASRC13_NEW_CON3 0x7b8c +#define AFE_GASRC13_NEW_CON4 0x7b90 +#define AFE_GASRC13_NEW_CON5 0x7b94 +#define AFE_GASRC13_NEW_CON6 0x7b98 +#define AFE_GASRC13_NEW_CON7 0x7b9c +#define AFE_GASRC13_NEW_CON8 0x7ba0 +#define AFE_GASRC13_NEW_CON9 0x7ba4 +#define AFE_GASRC13_NEW_CON10 0x7ba8 +#define AFE_GASRC13_NEW_CON11 0x7bac +#define AFE_GASRC13_NEW_CON12 0x7bb0 +#define AFE_GASRC13_NEW_CON13 0x7bb4 +#define AFE_GASRC13_NEW_CON14 0x7bb8 +#define AFE_GASRC13_NEW_IP_VERSION 0x7bbc +#define AFE_GASRC14_NEW_CON0 0x7bc0 +#define AFE_GASRC14_NEW_CON1 0x7bc4 +#define AFE_GASRC14_NEW_CON2 0x7bc8 +#define AFE_GASRC14_NEW_CON3 0x7bcc +#define AFE_GASRC14_NEW_CON4 0x7bd0 +#define AFE_GASRC14_NEW_CON5 0x7bd4 +#define AFE_GASRC14_NEW_CON6 0x7bd8 +#define AFE_GASRC14_NEW_CON7 0x7bdc +#define AFE_GASRC14_NEW_CON8 0x7be0 +#define AFE_GASRC14_NEW_CON9 0x7be4 +#define AFE_GASRC14_NEW_CON10 0x7be8 +#define AFE_GASRC14_NEW_CON11 0x7bec +#define AFE_GASRC14_NEW_CON12 0x7bf0 +#define AFE_GASRC14_NEW_CON13 0x7bf4 +#define AFE_GASRC14_NEW_CON14 0x7bf8 +#define AFE_GASRC14_NEW_IP_VERSION 0x7bfc +#define AFE_GASRC15_NEW_CON0 0x7c00 +#define AFE_GASRC15_NEW_CON1 0x7c04 +#define AFE_GASRC15_NEW_CON2 0x7c08 +#define AFE_GASRC15_NEW_CON3 0x7c0c +#define AFE_GASRC15_NEW_CON4 0x7c10 +#define AFE_GASRC15_NEW_CON5 0x7c14 +#define AFE_GASRC15_NEW_CON6 0x7c18 +#define AFE_GASRC15_NEW_CON7 0x7c1c +#define AFE_GASRC15_NEW_CON8 0x7c20 +#define AFE_GASRC15_NEW_CON9 0x7c24 +#define AFE_GASRC15_NEW_CON10 0x7c28 +#define AFE_GASRC15_NEW_CON11 0x7c2c +#define AFE_GASRC15_NEW_CON12 0x7c30 +#define AFE_GASRC15_NEW_CON13 0x7c34 +#define AFE_GASRC15_NEW_CON14 0x7c38 +#define AFE_GASRC15_NEW_IP_VERSION 0x7c3c + +#define AFE_MAX_REGISTER AFE_GASRC15_NEW_IP_VERSION + +#define AFE_IRQ_STATUS_BITS 0x87FFFFFF +#define AFE_IRQ_CNT_SHIFT 0 +#define AFE_IRQ_CNT_MASK 0xffffff +#endif diff --git a/src/platform/mt8196/include/platform/platform.h b/src/platform/mt8196/include/platform/platform.h new file mode 100644 index 000000000000..60becc79ded7 --- /dev/null +++ b/src/platform/mt8196/include/platform/platform.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#ifdef __SOF_PLATFORM_H__ + +#ifndef __PLATFORM_PLATFORM_H__ +#define __PLATFORM_PLATFORM_H__ + +#if !defined(__ASSEMBLER__) && !defined(LINKER) + +#include <sof/lib/mailbox.h> +#include <stddef.h> +#include <stdint.h> + +struct ll_schedule_domain; +struct timer; + +#define PLATFORM_DEFAULT_CLOCK CLK_CPU(0) +#define LPSRAM_SIZE 16384 + +/* IPC Interrupt */ +#define PLATFORM_IPC_INTERRUPT MTK_DSP_IRQ_MAILBOX +#define PLATFORM_IPC_INTERRUPT_NAME NULL + +/* Host page size */ +#define HOST_PAGE_SIZE 4096 +#define PLATFORM_PAGE_TABLE_SIZE 256 + +/* pipeline IRQ */ +#define PLATFORM_SCHEDULE_IRQ MTK_DSP_IRQ_SW +#define PLATFORM_SCHEDULE_IRQ_NAME NULL + +/* Platform stream capabilities */ +#define PLATFORM_MAX_CHANNELS 4 +#define PLATFORM_MAX_STREAMS 5 + +/* local buffer size of DMA tracing */ +#define DMA_TRACE_LOCAL_SIZE HOST_PAGE_SIZE + +/* trace bytes flushed during panic */ +#define DMA_FLUSH_TRACE_SIZE (MAILBOX_TRACE_SIZE >> 2) + +/* the interval of DMA trace copying */ +#define DMA_TRACE_PERIOD 500000 + +/* + * the interval of reschedule DMA trace copying in special case like half + * fullness of local DMA trace buffer + */ +#define DMA_TRACE_RESCHEDULE_TIME 100 + +/* DSP default delay in cycles */ +#define PLATFORM_DEFAULT_DELAY 12 + +#define SRAM_REG_FW_STATUS 0x4 + +/* Platform defined panic code */ +static inline void platform_panic(uint32_t p) +{ + /* Store the error code in the debug box so the + * application processor can pick it up. Takes up 4 bytes + * from the debug box. + */ + mailbox_sw_reg_write(SRAM_REG_FW_STATUS, p); + + /* Notify application processor */ + trigger_irq_to_host_req(); +} + +/** + * \brief Platform specific CPU entering idle. + * May be power-optimized using platform specific capabilities. + * @param level Interrupt level. + */ +void platform_wait_for_interrupt(int level); + +extern intptr_t _module_init_start; +extern intptr_t _module_init_end; +#endif + +#endif /* __PLATFORM_PLATFORM_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/platform.h" + +#endif /* __SOF_PLATFORM_H__ */ diff --git a/src/platform/mt8196/include/platform/trace/trace.h b/src/platform/mt8196/include/platform/trace/trace.h new file mode 100644 index 000000000000..ede2259cf192 --- /dev/null +++ b/src/platform/mt8196/include/platform/trace/trace.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#ifdef __SOF_TRACE_TRACE_H__ + +#ifndef __PLATFORM_TRACE_TRACE_H__ +#define __PLATFORM_TRACE_TRACE_H__ + +#include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <sof/lib/io.h> +#include <platform/drivers/mt_reg_base.h> + +#define platform_trace_point(__x) + +#endif /* __PLATFORM_TRACE_TRACE_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/trace/trace.h" + +#endif /* __SOF_TRACE_TRACE_H__ */ diff --git a/src/platform/mt8196/lib/CMakeLists.txt b/src/platform/mt8196/lib/CMakeLists.txt new file mode 100644 index 000000000000..ef71f8eea6cd --- /dev/null +++ b/src/platform/mt8196/lib/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources(sof + clk.c + dma.c + memory.c + dai.c +) diff --git a/src/platform/mt8196/lib/clk.c b/src/platform/mt8196/lib/clk.c new file mode 100644 index 000000000000..ebf109a0c9fc --- /dev/null +++ b/src/platform/mt8196/lib/clk.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#include <platform/drivers/mt_reg_base.h> +#include <rtos/clk.h> +#include <rtos/wait.h> +#include <sof/common.h> +#include <sof/lib/cpu.h> +#include <sof/lib/io.h> +#include <sof/lib/memory.h> +#include <sof/lib/notifier.h> +#include <sof/lib/uuid.h> +#include <rtos/sof.h> +#include <sof/trace/trace.h> + +SOF_DEFINE_REG_UUID(clkdrv_mt8196); + +DECLARE_TR_CTX(clkdrv_tr, SOF_UUID(clkdrv_mt8196_uuid), LOG_LEVEL_INFO); + +/* default voltage is 0.75V */ +const struct freq_table platform_cpu_freq[] = { + { 26000000, 26000}, + { 800000000, 26000}, +}; + +STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, + invalid_number_of_cpu_frequencies); + +static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; + +void platform_clock_init(struct sof *sof) +{ + int i; + + tr_dbg(&clkdrv_tr, "clock init\n"); + sof->clocks = platform_clocks_info; + + /* When the system is in an active state, the DSP clock operates at 800MHz (0.75V). + * In a low power scenario, the DSP enters WFI state, and the clock reduces to 26MHz. + * The clock selection is controlled by the host, and we do not allow SOF to change + * the ADSP frequency. + */ + for (i = 0; i < CONFIG_CORE_COUNT; i++) { + sof->clocks[i] = (struct clock_info){ + .freqs_num = NUM_CPU_FREQ, + .freqs = platform_cpu_freq, + .default_freq_idx = CPU_DEFAULT_IDX, + .current_freq_idx = CPU_DEFAULT_IDX, + .notification_id = NOTIFIER_ID_CPU_FREQ, + .notification_mask = NOTIFIER_TARGET_CORE_MASK(i), + .set_freq = NULL, + }; + } +} diff --git a/src/platform/mt8196/lib/dai.c b/src/platform/mt8196/lib/dai.c new file mode 100755 index 000000000000..6f5300e6aa48 --- /dev/null +++ b/src/platform/mt8196/lib/dai.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Darren Ye <darren.ye@mediatek.com> + */ + +#include <sof/common.h> +#include <sof/lib/dai.h> +#include <sof/lib/memory.h> +#include <sof/lib/uuid.h> +#include <rtos/sof.h> +#include <rtos/spinlock.h> +#include <ipc/dai.h> +#include <ipc/stream.h> +#include <sof/drivers/afe-dai.h> +#include <mt8196-afe-common.h> + +static int afe_dai_handshake[MT8196_DAI_NUM] = { + AFE_HANDSHAKE(MT8196_DAI_I2S_OUT4, MT8196_IRQ_12, MT8196_MEMIF_DL_24CH), + AFE_HANDSHAKE(MT8196_DAI_I2S_OUT6, MT8196_IRQ_1, MT8196_MEMIF_DL1), + AFE_HANDSHAKE(MT8196_DAI_AP_DMIC, MT8196_IRQ_13, MT8196_MEMIF_UL0), + AFE_HANDSHAKE(MT8196_DAI_I2S_IN6, MT8196_IRQ_0, MT8196_MEMIF_UL1), + AFE_HANDSHAKE(MT8196_DAI_AP_DMIC_CH34, MT8196_IRQ_15, MT8196_MEMIF_UL2), +}; + +static SHARED_DATA struct dai afe_dai[MT8196_DAI_NUM]; + +const struct dai_type_info dti[] = { + { + .type = SOF_DAI_MEDIATEK_AFE, + .dai_array = afe_dai, + .num_dais = ARRAY_SIZE(afe_dai), + }, +}; + +const struct dai_info lib_dai = { + .dai_type_array = dti, + .num_dai_types = ARRAY_SIZE(dti), +}; + +int dai_init(struct sof *sof) +{ + int i; + + /* initialize spin locks early to enable ref counting */ + for (i = 0; i < ARRAY_SIZE(afe_dai); i++) { + k_spinlock_init(&afe_dai[i].lock); + afe_dai[i].index = AFE_HS_GET_DAI(afe_dai_handshake[i]); + afe_dai[i].drv = &afe_dai_driver; + /* TODO, fifo[0] change to target playback or capture */ + afe_dai[i].plat_data.fifo[0].handshake = afe_dai_handshake[i]; + } + + sof->dai_info = &lib_dai; + + return 0; +} diff --git a/src/platform/mt8196/lib/dma.c b/src/platform/mt8196/lib/dma.c new file mode 100644 index 000000000000..0cc4e1043a26 --- /dev/null +++ b/src/platform/mt8196/lib/dma.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + * Darren Ye <darren.ye@mediatek.com> + */ + +#include <rtos/interrupt.h> +#include <rtos/spinlock.h> +#include <sof/common.h> +#include <sof/drivers/afe-memif.h> +#include <sof/lib/dma.h> +#include <sof/lib/memory.h> +#include <rtos/sof.h> +#include <mt8196-afe-reg.h> +#include <mt8196-afe-common.h> + +extern const struct dma_ops dummy_dma_ops; + +static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +{ + .plat_data = { + .id = DMA_ID_HOST, + .dir = DMA_DIR_HMEM_TO_LMEM | DMA_DIR_LMEM_TO_HMEM, + .devs = DMA_DEV_HOST, + .channels = 16, + }, + .ops = &dummy_dma_ops, +}, +{ + .plat_data = { + .id = DMA_ID_AFE_MEMIF, + .dir = DMA_DIR_MEM_TO_DEV | DMA_DIR_DEV_TO_MEM, + .devs = DMA_DEV_AFE_MEMIF, + .base = AFE_BASE_ADDR, + .channels = MT8196_MEMIF_NUM, + }, + .ops = &memif_ops, +}, + +}; + +static const struct dma_info lib_dma = { + .dma_array = cache_to_uncache_init((struct dma *)dma), + .num_dmas = ARRAY_SIZE(dma) +}; + +int dmac_init(struct sof *sof) +{ + int i; + + /* early lock initialization for ref counting */ + for (i = 0; i < ARRAY_SIZE(dma); i++) + k_spinlock_init(&dma[i].lock); + + sof->dma_info = &lib_dma; + + return 0; +} diff --git a/src/platform/mt8196/lib/memory.c b/src/platform/mt8196/lib/memory.c new file mode 100644 index 000000000000..7445f1713830 --- /dev/null +++ b/src/platform/mt8196/lib/memory.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + */ + +#include <ipc/topology.h> +#include <sof/common.h> +#include <sof/lib/mm_heap.h> +#include <sof/lib/memory.h> +#include <rtos/sof.h> + +/* Heap blocks for system runtime */ +static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; + +/* Heap memory for system runtime */ +static SHARED_DATA struct block_map sys_rt_heap_map[] = { + BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), + BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), + BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), +}; + +/* Heap blocks for modules */ +static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static SHARED_DATA struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; + +/* Heap memory map for modules */ +static SHARED_DATA struct block_map rt_heap_map[] = { + BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), + BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), + BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), + BLOCK_DEF(128, HEAP_RT_COUNT128, mod_block128), + BLOCK_DEF(256, HEAP_RT_COUNT256, mod_block256), + BLOCK_DEF(512, HEAP_RT_COUNT512, mod_block512), + BLOCK_DEF(1024, HEAP_RT_COUNT1024, mod_block1024), + BLOCK_DEF(2048, HEAP_RT_COUNT2048, mod_block2048), + BLOCK_DEF(4096, HEAP_RT_COUNT4096, mod_block4096), +}; + +/* Heap blocks for buffers */ +static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; + +/* Heap memory map for buffers */ +static SHARED_DATA struct block_map buf_heap_map[] = { + BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), +}; + +static SHARED_DATA struct mm memmap = { + .system[0] = { + .heap = HEAP_SYSTEM_BASE, + .size = HEAP_SYSTEM_SIZE, + .info = {.free = HEAP_SYSTEM_SIZE,}, + .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_CACHE | + SOF_MEM_CAPS_DMA, + }, + .system_runtime[0] = { + .blocks = ARRAY_SIZE(sys_rt_heap_map), + .map = sys_rt_heap_map, + .heap = HEAP_SYS_RUNTIME_BASE, + .size = HEAP_SYS_RUNTIME_SIZE, + .info = {.free = HEAP_SYS_RUNTIME_SIZE,}, + .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_CACHE | + SOF_MEM_CAPS_DMA, + }, + .runtime[0] = { + .blocks = ARRAY_SIZE(rt_heap_map), + .map = rt_heap_map, + .heap = HEAP_RUNTIME_BASE, + .size = HEAP_RUNTIME_SIZE, + .info = {.free = HEAP_RUNTIME_SIZE,}, + .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_CACHE | + SOF_MEM_CAPS_DMA, + }, + .buffer[0] = { + .blocks = ARRAY_SIZE(buf_heap_map), + .map = buf_heap_map, + .heap = HEAP_BUFFER_BASE, + .size = HEAP_BUFFER_SIZE, + .info = {.free = HEAP_BUFFER_SIZE,}, + .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_CACHE | + SOF_MEM_CAPS_DMA, + }, + .total = {.free = HEAP_SYSTEM_SIZE + HEAP_SYS_RUNTIME_SIZE + + HEAP_RUNTIME_SIZE + HEAP_BUFFER_SIZE,}, +}; + +void platform_init_memmap(struct sof *sof) +{ + /* memmap has been initialized statically as a part of .data */ + sof->memory_map = &memmap; +} diff --git a/src/platform/mt8196/mt8196.x.in b/src/platform/mt8196/mt8196.x.in new file mode 100644 index 000000000000..939779d8f120 --- /dev/null +++ b/src/platform/mt8196/mt8196.x.in @@ -0,0 +1,554 @@ +/* + * Linker Script for mt8196 MediaTek + * + * This script is run through the GNU C preprocessor to align the memory + * offsets with headers. + * + * Use spaces for formatting as cpp ignore tab sizes. + */ + + +#include <sof/lib/memory.h> +#include <xtensa/config/core-isa.h> + +#if CONFIG_MEDIATEK_DRAM_IMAGE +#define IMAGE_LOC sof_dram +#else +#define IMAGE_LOC sof_sram +#endif + +OUTPUT_ARCH(xtensa) + +MEMORY +{ + vector_reset_text : + org = XCHAL_RESET_VECTOR0_PADDR, + len = SOF_MEM_RESET_TEXT_SIZE + vector_reset_lit : + org = XCHAL_RESET_VECTOR0_PADDR + SOF_MEM_RESET_TEXT_SIZE, + len = SOF_MEM_RESET_LIT_SIZE + vector_base_text : + org = XCHAL_VECBASE_RESET_PADDR, + len = SOF_MEM_VECBASE_LIT_SIZE + vector_int2_lit : + org = XCHAL_INTLEVEL2_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_int2_text : + org = XCHAL_INTLEVEL2_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + vector_int3_lit : + org = XCHAL_INTLEVEL3_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_int3_text : + org = XCHAL_INTLEVEL3_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + vector_int4_lit : + org = XCHAL_INTLEVEL4_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_int4_text : + org = XCHAL_INTLEVEL4_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + vector_int5_lit : + org = XCHAL_INTLEVEL5_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_int5_text : + org = XCHAL_INTLEVEL5_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + vector_kernel_lit : + org = XCHAL_KERNEL_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_kernel_text : + org = XCHAL_KERNEL_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + vector_user_lit : + org = XCHAL_USER_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_user_text : + org = XCHAL_USER_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + vector_double_lit : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_double_text : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + sof_sram : + org = SRAM_START, + len = SRAM_SIZE + sof_dram : + org = SOF_DRAM_BASE, + len = SOF_DRAM_SIZE + system_heap : + org = HEAP_SYSTEM_BASE, + len = HEAP_SYSTEM_SIZE + system_runtime_heap : + org = HEAP_SYS_RUNTIME_BASE, + len = HEAP_SYS_RUNTIME_SIZE + runtime_heap : + org = HEAP_RUNTIME_BASE, + len = HEAP_RUNTIME_SIZE + buffer_heap : + org = HEAP_BUFFER_BASE, + len = HEAP_BUFFER_SIZE + sof_stack : + org = SOF_STACK_END, + len = SOF_STACK_BASE - SOF_STACK_END + static_uuid_entries_seg (!ari) : + org = UUID_ENTRY_ELF_BASE, + len = UUID_ENTRY_ELF_SIZE + static_log_entries_seg (!ari) : + org = LOG_ENTRY_ELF_BASE, + len = LOG_ENTRY_ELF_SIZE + fw_metadata_seg (!ari) : + org = EXT_MANIFEST_ELF_BASE, + len = EXT_MANIFEST_ELF_SIZE +} + +PHDRS +{ + vector_reset_text_phdr PT_LOAD; + vector_reset_lit_phdr PT_LOAD; + vector_base_text_phdr PT_LOAD; + vector_base_lit_phdr PT_LOAD; + vector_int2_text_phdr PT_LOAD; + vector_int2_lit_phdr PT_LOAD; + vector_int3_text_phdr PT_LOAD; + vector_int3_lit_phdr PT_LOAD; + vector_int4_text_phdr PT_LOAD; + vector_int4_lit_phdr PT_LOAD; + vector_int5_text_phdr PT_LOAD; + vector_int5_lit_phdr PT_LOAD; + vector_kernel_text_phdr PT_LOAD; + vector_kernel_lit_phdr PT_LOAD; + vector_user_text_phdr PT_LOAD; + vector_user_lit_phdr PT_LOAD; + vector_double_text_phdr PT_LOAD; + vector_double_lit_phdr PT_LOAD; + sof_sram_phdr PT_LOAD; + system_heap_phdr PT_LOAD; + system_runtime_heap_phdr PT_LOAD; + runtime_heap_phdr PT_LOAD; + buffer_heap_phdr PT_LOAD; + sof_stack_phdr PT_LOAD; + static_uuid_entries_phdr PT_NOTE; + static_log_entries_phdr PT_NOTE; + metadata_entries_phdr PT_NOTE; +} + +/* Default entry point: */ +ENTRY(_ResetVector) +_rom_store_table = 0; + +/* ABI0 does not use Window base */ +PROVIDE(_memmap_vecbase_reset = XCHAL_VECBASE_RESET_PADDR); + +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000404; +_memmap_cacheattr_wt_base = 0x00000404; +_memmap_cacheattr_bp_base = 0x00000404; +_memmap_cacheattr_unused_mask = 0xFFFFF0FF; +_memmap_cacheattr_wb_trapnull = 0x44444444; +_memmap_cacheattr_wba_trapnull = 0x44444444; +_memmap_cacheattr_wbna_trapnull = 0x44444444; +_memmap_cacheattr_wt_trapnull = 0x44444444; +_memmap_cacheattr_bp_trapnull = 0x44444444; +_memmap_cacheattr_wb_strict = 0x00000404; +_memmap_cacheattr_wt_strict = 0x00000404; +_memmap_cacheattr_bp_strict = 0x00000404; +_memmap_cacheattr_wb_allvalid = 0x44444444; +_memmap_cacheattr_wt_allvalid = 0x44444444; +_memmap_cacheattr_bp_allvalid = 0x44444444; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +_EXT_MAN_ALIGN_ = 16; +EXTERN(ext_man_fw_ver) + +SECTIONS +{ + .ResetVector.text : ALIGN(4) + { + _ResetVector_text_start = ABSOLUTE(.); + KEEP (*(.ResetVector.text)) + _ResetVector_text_end = ABSOLUTE(.); + } >vector_reset_text :vector_reset_text_phdr + + .ResetVector.literal : ALIGN(4) + { + _ResetVector_literal_start = ABSOLUTE(.); + *(.ResetVector.literal) + _ResetVector_literal_end = ABSOLUTE(.); + } >vector_reset_lit :vector_reset_lit_phdr + + .WindowVectors.text : ALIGN(4) + { + _WindowVectors_text_start = ABSOLUTE(.); + KEEP (*(.WindowVectors.text)) + _WindowVectors_text_end = ABSOLUTE(.); + } >vector_base_text :vector_base_text_phdr + + .Level2InterruptVector.literal : ALIGN(4) + { + _Level2InterruptVector_literal_start = ABSOLUTE(.); + *(.Level2InterruptVector.literal) + _Level2InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int2_lit :vector_int2_lit_phdr + + .Level2InterruptVector.text : ALIGN(4) + { + _Level2InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level2InterruptVector.text)) + _Level2InterruptVector_text_end = ABSOLUTE(.); + } >vector_int2_text :vector_int2_text_phdr + + .Level3InterruptVector.literal : ALIGN(4) + { + _Level3InterruptVector_literal_start = ABSOLUTE(.); + *(.Level3InterruptVector.literal) + _Level3InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int3_lit :vector_int3_lit_phdr + + .Level3InterruptVector.text : ALIGN(4) + { + _Level3InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level3InterruptVector.text)) + _Level3InterruptVector_text_end = ABSOLUTE(.); + } >vector_int3_text :vector_int3_text_phdr + + .Level4InterruptVector.literal : ALIGN(4) + { + _Level4InterruptVector_literal_start = ABSOLUTE(.); + *(.Level4InterruptVector.literal) + _Level4InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int4_lit :vector_int4_lit_phdr + + .Level4InterruptVector.text : ALIGN(4) + { + _Level4InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level4InterruptVector.text)) + _Level4InterruptVector_text_end = ABSOLUTE(.); + } >vector_int4_text :vector_int4_text_phdr + + .DebugExceptionVector.literal : ALIGN(4) + { + _DebugExceptionVector_literal_start = ABSOLUTE(.); + *(.DebugExceptionVector.literal) + _DebugExceptionVector_literal_end = ABSOLUTE(.); + } >vector_int5_lit :vector_int5_lit_phdr + + .DebugExceptionVector.text : ALIGN(4) + { + _DebugExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.DebugExceptionVector.text)) + _DebugExceptionVector_text_end = ABSOLUTE(.); + } >vector_int5_text :vector_int5_text_phdr + + .NMIExceptionVector.literal : ALIGN(4) + { + _NMIExceptionVector_literal_start = ABSOLUTE(.); + *(.NMIExceptionVector.literal) + _NMIExceptionVector_literal_end = ABSOLUTE(.); + } >vector_int5_lit :vector_int5_lit_phdr + + .NMIExceptionVector.text : ALIGN(4) + { + _NMIExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.NMIExceptionVector.text)) + _NMIExceptionVector_text_end = ABSOLUTE(.); + } >vector_int5_text :vector_int5_text_phdr + + .KernelExceptionVector.literal : ALIGN(4) + { + _KernelExceptionVector_literal_start = ABSOLUTE(.); + *(.KernelExceptionVector.literal) + _KernelExceptionVector_literal_end = ABSOLUTE(.); + } >vector_kernel_lit :vector_kernel_lit_phdr + + .KernelExceptionVector.text : ALIGN(4) + { + _KernelExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.KernelExceptionVector.text)) + _KernelExceptionVector_text_end = ABSOLUTE(.); + } >vector_kernel_text :vector_kernel_text_phdr + + .UserExceptionVector.literal : ALIGN(4) + { + _UserExceptionVector_literal_start = ABSOLUTE(.); + *(.UserExceptionVector.literal) + _UserExceptionVector_literal_end = ABSOLUTE(.); + } >vector_user_lit :vector_user_lit_phdr + + .UserExceptionVector.text : ALIGN(4) + { + _UserExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.UserExceptionVector.text)) + _UserExceptionVector_text_end = ABSOLUTE(.); + } >vector_user_text :vector_user_text_phdr + + .DoubleExceptionVector.literal : ALIGN(4) + { + _DoubleExceptionVector_literal_start = ABSOLUTE(.); + *(.DoubleExceptionVector.literal) + _DoubleExceptionVector_literal_end = ABSOLUTE(.); + } >vector_double_lit :vector_double_lit_phdr + + .DoubleExceptionVector.text : ALIGN(4) + { + _DoubleExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.DoubleExceptionVector.text)) + _DoubleExceptionVector_text_end = ABSOLUTE(.); + } >vector_double_text :vector_double_text_phdr + + .fw_ready : ALIGN(4) + { + KEEP (*(.fw_ready)) + KEEP (*(.fw_ready_metadata)) + } >IMAGE_LOC :sof_sram_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + KEEP (*(.xt_except_table)) + KEEP (*(.gcc_except_table)) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + KEEP (*(.eh_frame)) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >IMAGE_LOC :sof_sram_phdr + + .module_init : ALIGN(4) + { + _module_init_start = ABSOLUTE(.); + *(*.initcall) + _module_init_end = ABSOLUTE(.); + } >IMAGE_LOC :sof_sram_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.entry.text) + *(.init.literal) + KEEP(*(.init)) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + KEEP(*(.fini)) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >IMAGE_LOC :sof_sram_phdr + + .reset.rodata : ALIGN(4) + { + _reset_rodata_start = ABSOLUTE(.); + *(.reset.rodata) + _reset_rodata_end = ABSOLUTE(.); + } >IMAGE_LOC :sof_sram_phdr + + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + KEEP(*(.gnu.linkonce.d.*personality*)) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + KEEP(*(.jcr)) + _trace_ctx_start = ABSOLUTE(.); + *(.trace_ctx) + _trace_ctx_end = ABSOLUTE(.); + _data_end = ABSOLUTE(.); + } >IMAGE_LOC :sof_sram_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >IMAGE_LOC :sof_sram_phdr + + .bss (NOLOAD) : ALIGN(8) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + } >IMAGE_LOC :sof_sram_phdr + + /* stack */ + _end = SOF_STACK_END; + PROVIDE(end = SOF_STACK_END); + _stack_sentry = SOF_STACK_END; + __stack = SOF_STACK_BASE; + + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_ranges 0 : { *(.debug_ranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .xt.insn 0 : + { + KEEP (*(.xt.insn)) + KEEP (*(.gnu.linkonce.x.*)) + } + .xt.prop 0 : + { + KEEP (*(.xt.prop)) + KEEP (*(.xt.prop.*)) + KEEP (*(.gnu.linkonce.prop.*)) + } + .xt.lit 0 : + { + KEEP (*(.xt.lit)) + KEEP (*(.xt.lit.*)) + KEEP (*(.gnu.linkonce.p.*)) + } + .xt.profile_range 0 : + { + KEEP (*(.xt.profile_range)) + KEEP (*(.gnu.linkonce.profile_range.*)) + } + .xt.profile_ranges 0 : + { + KEEP (*(.xt.profile_ranges)) + KEEP (*(.gnu.linkonce.xt.profile_ranges.*)) + } + .xt.profile_files 0 : + { + KEEP (*(.xt.profile_files)) + KEEP (*(.gnu.linkonce.xt.profile_files.*)) + } + + .xtensa.info 0 : + { + *(.xtensa.info) + } + + .comment 0 : + { + KEEP(*(.comment)) + } + + .note.GNU-stack 0 : + { + *(.note.GNU-stack) + } + + .system_heap (NOLOAD) : ALIGN(8) + { + . = ALIGN (32); + _system_heap_start = ABSOLUTE(.); + . = . + HEAP_SYSTEM_SIZE; + _system_heap_end = ABSOLUTE(.); + } >system_heap :system_heap_phdr + + .system_runtime_heap (NOLOAD) : ALIGN(8) + { + . = ALIGN (HEAP_BUF_ALIGNMENT); + _system_runtime_heap_start = ABSOLUTE(.); + . = . + HEAP_SYS_RUNTIME_SIZE; + _system_runtime_heap_end = ABSOLUTE(.); + } >system_runtime_heap :system_runtime_heap_phdr + + .runtime_heap (NOLOAD) : ALIGN(8) + { + . = ALIGN (32); + _runtime_heap_start = ABSOLUTE(.); + . = . + HEAP_RUNTIME_SIZE; + _runtime_heap_end = ABSOLUTE(.); + } >runtime_heap :runtime_heap_phdr + + .buffer_heap (NOLOAD) : ALIGN(8) + { + . = ALIGN (HEAP_BUF_ALIGNMENT); + _buffer_heap_start = ABSOLUTE(.); + . = . + HEAP_BUFFER_SIZE; + _buffer_heap_end = ABSOLUTE(.); + } >buffer_heap :buffer_heap_phdr + + .sof_stack (NOLOAD) : ALIGN(8) + { + . = ALIGN (4096); + _sof_stack_start = ABSOLUTE(.); + . = . + SOF_STACK_TOTAL_SIZE; + _sof_stack_end = ABSOLUTE(.); + } >sof_stack :sof_stack_phdr + + .static_uuid_entries (COPY) : ALIGN(1024) + { + *(*.static_uuids) + } > static_uuid_entries_seg :static_uuid_entries_phdr + + .static_log_entries (COPY) : ALIGN(1024) + { + *(*.static_log*) + } > static_log_entries_seg :static_log_entries_phdr + + .fw_metadata (COPY) : ALIGN(1024) + { + KEEP (*(.fw_metadata)) + . = ALIGN(_EXT_MAN_ALIGN_); + } >fw_metadata_seg :metadata_entries_phdr +} diff --git a/src/platform/mt8196/platform.c b/src/platform/mt8196/platform.c new file mode 100644 index 000000000000..c093e7b003ef --- /dev/null +++ b/src/platform/mt8196/platform.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Hailong Fan <hailong.fan@mediatek.com> + * Darren Ye <darren.ye@mediatek.com> + */ + +#include <errno.h> +#include <ipc/header.h> +#include <ipc/info.h> +#include <kernel/abi.h> +#include <kernel/ext_manifest.h> +#include <platform/drivers/timer.h> +#include <rtos/clk.h> +#include <rtos/timer.h> +#include <rtos/interrupt.h> +#include <sof/compiler_info.h> +#include <sof/debug/debug.h> +#include <sof/drivers/edma.h> +#include <sof/ipc/msg.h> +#include <sof/fw-ready-metadata.h> +#include <sof/lib/agent.h> +#include <sof/lib/cpu.h> +#include <sof/lib/dai.h> +#include <sof/lib/dma.h> +#include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <sof/lib/mm_heap.h> +#include <sof/platform.h> +#include <sof/schedule/edf_schedule.h> +#include <sof/schedule/ll_schedule.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <rtos/sof.h> +#include <sof/trace/dma-trace.h> +#include <sof_versions.h> +#include <stdint.h> +#include <xtensa/hal.h> + +struct sof; + +static const struct sof_ipc_fw_ready ready + __section(".fw_ready") = { + .hdr = { + .cmd = SOF_IPC_FW_READY, + .size = sizeof(struct sof_ipc_fw_ready), + }, + /* dspbox is for DSP initiated IPC, hostbox is for host initiated IPC */ + .version = { + .hdr.size = sizeof(struct sof_ipc_fw_version), + .micro = SOF_MICRO, + .minor = SOF_MINOR, + .major = SOF_MAJOR, + .tag = SOF_TAG, + .abi_version = SOF_ABI_VERSION, + .src_hash = SOF_SRC_HASH, + }, + .flags = DEBUG_SET_FW_READY_FLAGS, +}; + +#define NUM_MTK_WINDOWS 6 + +const struct ext_man_windows xsram_window + __aligned(EXT_MAN_ALIGN) __section(".fw_metadata") __unused = { + .hdr = { + .type = EXT_MAN_ELEM_WINDOW, + .elem_size = ALIGN_UP_COMPILE(sizeof(struct ext_man_windows), EXT_MAN_ALIGN), + }, + .window = { + .ext_hdr = { + .hdr.cmd = SOF_IPC_FW_READY, + .hdr.size = sizeof(struct sof_ipc_window), + .type = SOF_IPC_EXT_WINDOW, + }, + .num_windows = NUM_MTK_WINDOWS, + .window = { + { + .type = SOF_IPC_REGION_UPBOX, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_DSPBOX_SIZE, + .offset = MAILBOX_DSPBOX_OFFSET, + }, + { + .type = SOF_IPC_REGION_DOWNBOX, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_HOSTBOX_SIZE, + .offset = MAILBOX_HOSTBOX_OFFSET, + }, + { + .type = SOF_IPC_REGION_DEBUG, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_DEBUG_SIZE, + .offset = MAILBOX_DEBUG_OFFSET, + }, + { + .type = SOF_IPC_REGION_TRACE, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_TRACE_SIZE, + .offset = MAILBOX_TRACE_OFFSET, + }, + { + .type = SOF_IPC_REGION_STREAM, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_STREAM_SIZE, + .offset = MAILBOX_STREAM_OFFSET, + }, + { + .type = SOF_IPC_REGION_EXCEPTION, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_EXCEPTION_SIZE, + .offset = MAILBOX_EXCEPTION_OFFSET, + }, + }, + } +}; + +static SHARED_DATA struct timer timer_shared = { + .id = OSTIMER0, + .irq = MTK_DSP_IRQ_OSTIMER32_C0, +}; + +/* Override the default MPU setup. This table matches the memory map + * of the 'sample_controller' core and will need to be modified for + * other cores. + * NOTE: This table sets up all of external memory as shared uncached. + * For best results, edit the LSP memory map to create a separate + * section in shared memory, place all sections that need to be uncached + * into that section, and only map that section uncached. See README + * for more details. + */ +const struct xthal_MPU_entry __xt_mpu_init_table[] __section(".ResetVector.text") = { + XTHAL_MPU_ENTRY(0x00000000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_DEVICE), // infra + XTHAL_MPU_ENTRY(0x10000000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_DEVICE), // infra + XTHAL_MPU_ENTRY(0x1a000000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_DEVICE), // cfg + XTHAL_MPU_ENTRY(0x1a110000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_DEVICE), // audio + XTHAL_MPU_ENTRY(0x4e100000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_WRITEBACK), // sram + XTHAL_MPU_ENTRY(0x4e180000, 1, XTHAL_AR_NONE, XTHAL_MEM_DEVICE), // unused + XTHAL_MPU_ENTRY(0x90000000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_WRITEBACK), // dram + XTHAL_MPU_ENTRY(0x90500000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_NON_CACHEABLE), // dram + XTHAL_MPU_ENTRY(0x90900000, 1, XTHAL_AR_NONE, XTHAL_MEM_DEVICE), // unused +}; + +const unsigned int __xt_mpu_init_table_size __section(".ResetVector.text") = + ARRAY_SIZE(__xt_mpu_init_table); + +int platform_boot_complete(uint32_t boot_message) +{ + mailbox_dspbox_write(0, &ready, sizeof(ready)); + /* now interrupt host to tell it we are done booting */ + trigger_irq_to_host_req(); + + return 0; +} + +int platform_init(struct sof *sof) +{ + int ret; + + sof->platform_timer = &timer_shared; + sof->cpu_timers = sof->platform_timer; + platform_interrupt_init(); + platform_clock_init(sof); + + scheduler_init_edf(); + + /* init low latency domains and schedulers */ + sof->platform_timer_domain = timer_domain_init(sof->platform_timer, PLATFORM_DEFAULT_CLOCK); + scheduler_init_ll(sof->platform_timer_domain); + platform_timer_start(sof->platform_timer); + sa_init(sof, CONFIG_SYSTICK_PERIOD); + + /* init DMA */ + ret = dmac_init(sof); + if (ret < 0) + return -ENODEV; + + /* Init platform domain */ + sof->platform_dma_domain = dma_multi_chan_domain_init(&sof->dma_info->dma_array[0], 1, + PLATFORM_DEFAULT_CLOCK, false); + + scheduler_init_ll(sof->platform_dma_domain); + + /* initialize the host IPC mechanisms */ + ipc_init(sof); + + ret = dai_init(sof); + if (ret < 0) + return ret; + +#if CONFIG_TRACE + /* Initialize DMA for Trace*/ + trace_point(TRACE_BOOT_PLATFORM_DMA_TRACE); + dma_trace_init_complete(sof->dmat); +#endif + + /* show heap status */ + heap_trace_all(1); + + return 0; +} + +int platform_context_save(struct sof *sof) +{ + return 0; +} + +void platform_wait_for_interrupt(int level) +{ + arch_wait_for_interrupt(level); +} + diff --git a/src/platform/mt8365/CMakeLists.txt b/src/platform/mt8365/CMakeLists.txt new file mode 100644 index 000000000000..4091be2eeaff --- /dev/null +++ b/src/platform/mt8365/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_subdirectory(lib) + +add_local_sources(sof platform.c afe-platform.c) +target_include_directories(sof_options INTERFACE ${PROJECT_SOURCE_DIR}/src/platform/mt8365/include/arch) +target_include_directories(sof_options INTERFACE ${PROJECT_SOURCE_DIR}/src/platform/mt8365/include/platform) diff --git a/src/platform/mt8365/afe-platform.c b/src/platform/mt8365/afe-platform.c new file mode 100644 index 000000000000..1255972479ce --- /dev/null +++ b/src/platform/mt8365/afe-platform.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#include <sof/common.h> +#include <errno.h> +#include <sof/drivers/afe-drv.h> +#include <mt8365-afe-regs.h> +#include <mt8365-afe-common.h> + +/* + * AFE: Audio Front-End + * + * frontend (memif): + * memory interface + * AWB, VULx, TDM_IN (uplink for capture) + * DLx, TDM_OUT (downlink for playback) + * backend: + * TDM In + * TMD out + * DMIC + * GASRC + * etc. + * interconn: + * inter-connection, + * connect frontends and backends as DSP path + */ + +static const struct mtk_base_memif_data memif_data[MT8365_MEMIF_NUM] = { + [MT8365_MEMIF_DL1] = { + .name = "DL1", + .id = MT8365_MEMIF_DL1, + .reg_ofs_base = AFE_DL1_BASE, + .reg_ofs_cur = AFE_DL1_CUR, + .reg_ofs_end = AFE_DL1_END, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 0, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON1, + .mono_shift = 21, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 1, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 16, + .agent_disable_reg = -1, + .agent_disable_shift = 0, + .ch_num_reg = -1, + .ch_num_shift = 0, + .ch_num_maskbit = 0, + .msb_reg = -1, + .msb_shift = 0, + .msb2_reg = -1, + .msb2_shift = 0, + }, + [MT8365_MEMIF_DL2] = { + .name = "DL2", + .id = MT8365_MEMIF_DL2, + .reg_ofs_base = AFE_DL2_BASE, + .reg_ofs_cur = AFE_DL2_CUR, + .reg_ofs_end = AFE_DL2_END, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 4, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON1, + .mono_shift = 22, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 2, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 18, + .agent_disable_reg = -1, + .agent_disable_shift = 0, + .ch_num_reg = -1, + .ch_num_shift = 0, + .ch_num_maskbit = 0, + .msb_reg = -1, + .msb_shift = 0, + .msb2_reg = -1, + .msb2_shift = 0, + }, + [MT8365_MEMIF_TDM_OUT] = { + .name = "TDM_OUT", + .id = MT8365_MEMIF_DL2, + .reg_ofs_base = AFE_HDMI_OUT_BASE, + .reg_ofs_cur = AFE_HDMI_OUT_CUR, + .reg_ofs_end = AFE_HDMI_OUT_END, + .fs_reg = -1, + .fs_shift = 0, + .fs_maskbit = 0, + .mono_reg = -1, + .mono_shift = 0, + .enable_reg = AFE_HDMI_OUT_CON0, + .enable_shift = 0, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 28, + .agent_disable_reg = -1, + .agent_disable_shift = 0, + .ch_num_reg = -1, + .ch_num_shift = 0, + .ch_num_maskbit = 0, + .msb_reg = -1, + .msb_shift = 0, + .msb2_reg = -1, + .msb2_shift = 0, + }, + [MT8365_MEMIF_AWB] = { + .name = "AWB", + .id = MT8365_MEMIF_AWB, + .reg_ofs_base = AFE_AWB_BASE, + .reg_ofs_cur = AFE_AWB_CUR, + .reg_ofs_end = AFE_AWB_END, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 12, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON1, + .mono_shift = 24, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 6, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 20, + .agent_disable_reg = -1, + .agent_disable_shift = 0, + .ch_num_reg = -1, + .ch_num_shift = 0, + .ch_num_maskbit = 0, + .msb_reg = AFE_MEMIF_MSB, + .msb_shift = 17, + .msb2_reg = -1, + .msb2_shift = 0, + }, + [MT8365_MEMIF_VUL] = { + .name = "VUL", + .id = MT8365_MEMIF_VUL, + .reg_ofs_base = AFE_VUL_BASE, + .reg_ofs_cur = AFE_VUL_CUR, + .reg_ofs_end = AFE_VUL_END, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 16, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON1, + .mono_shift = 27, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 3, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 22, + .agent_disable_reg = -1, + .agent_disable_shift = 0, + .ch_num_reg = -1, + .ch_num_shift = 0, + .ch_num_maskbit = 0, + .msb_reg = AFE_MEMIF_MSB, + .msb_shift = 20, + .msb2_reg = -1, + .msb2_shift = 0, + }, + [MT8365_MEMIF_VUL2] = { + .name = "VUL2", + .id = MT8365_MEMIF_VUL2, + .reg_ofs_base = AFE_VUL_D2_BASE, + .reg_ofs_cur = AFE_VUL_D2_CUR, + .reg_ofs_end = AFE_VUL_D2_END, + .fs_reg = AFE_DAC_CON0, + .fs_shift = 20, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON0, + .mono_shift = 10, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 9, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 14, + .agent_disable_reg = -1, + .agent_disable_shift = 0, + .ch_num_reg = -1, + .ch_num_shift = 0, + .ch_num_maskbit = 0, + .msb_reg = AFE_MEMIF_MSB, + .msb_shift = 21, + .msb2_reg = -1, + .msb2_shift = 0, + }, + [MT8365_MEMIF_VUL3] = { + .name = "VUL3", + .id = MT8365_MEMIF_VUL3, + .reg_ofs_base = AFE_VUL3_BASE, + .reg_ofs_cur = AFE_VUL3_CUR, + .reg_ofs_end = AFE_VUL3_END, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 8, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON0, + .mono_shift = 13, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 12, + .hd_reg = AFE_MEMIF_PBUF2_SIZE, + .hd_shift = 10, + .agent_disable_reg = -1, + .agent_disable_shift = 0, + .ch_num_reg = -1, + .ch_num_shift = 0, + .ch_num_maskbit = 0, + .msb_reg = AFE_MEMIF_MSB, + .msb_shift = 27, + .msb2_reg = -1, + .msb2_shift = 0, + }, + [MT8365_MEMIF_TDM_IN] = { + .name = "TDM_IN", + .id = MT8365_MEMIF_TDM_IN, + .reg_ofs_base = AFE_HDMI_IN_2CH_BASE, + .reg_ofs_cur = AFE_HDMI_IN_2CH_CUR, + .reg_ofs_end = AFE_HDMI_IN_2CH_END, + .fs_reg = -1, + .fs_shift = 0, + .fs_maskbit = 0, + .mono_reg = AFE_HDMI_IN_2CH_CON0, + .mono_shift = 1, + .enable_reg = AFE_HDMI_IN_2CH_CON0, + .enable_shift = 0, + .hd_reg = AFE_MEMIF_PBUF2_SIZE, + .hd_shift = 8, + .agent_disable_reg = -1, + .agent_disable_shift = 0, + .ch_num_reg = -1, + .ch_num_shift = 0, + .ch_num_maskbit = 0, + .msb_reg = AFE_MEMIF_MSB, + .msb_shift = 28, + .msb2_reg = -1, + .msb2_shift = 0, + }, +}; + +struct mt8365_afe_rate { + unsigned int rate; + unsigned int reg_value; +}; + +static const struct mt8365_afe_rate mt8365_afe_rates[] = { + { + .rate = 8000, + .reg_value = 0, + }, + { + .rate = 11025, + .reg_value = 1, + }, + { + .rate = 12000, + .reg_value = 2, + }, + { + .rate = 16000, + .reg_value = 4, + }, + { + .rate = 22050, + .reg_value = 5, + }, + { + .rate = 24000, + .reg_value = 6, + }, + { + .rate = 32000, + .reg_value = 8, + }, + { + .rate = 44100, + .reg_value = 9, + }, + { + .rate = 48000, + .reg_value = 10, + }, + { + .rate = 88200, + .reg_value = 11, + }, + { + .rate = 96000, + .reg_value = 12, + }, + { + .rate = 176400, + .reg_value = 13, + }, + { + .rate = 192000, + .reg_value = 14, + }, +}; + +static unsigned int mt8365_afe_fs_timing(unsigned int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mt8365_afe_rates); i++) + if (mt8365_afe_rates[i].rate == rate) + return mt8365_afe_rates[i].reg_value; + + return -EINVAL; +} + +static unsigned int mt8365_afe_fs(unsigned int rate, int aud_blk) +{ + return mt8365_afe_fs_timing(rate); +} + +static unsigned int mt8365_afe2adsp_addr(unsigned int addr) +{ + /*TODO : Need apply the address remap */ + return addr; +} + +static unsigned int mt8365_adsp2afe_addr(unsigned int addr) +{ + /* TODO : Need apply the address remap */ + return addr; +} + +struct mtk_base_afe_platform mtk_afe_platform = { + .base_addr = AFE_REG_BASE, + .memif_datas = memif_data, + .memif_size = MT8365_MEMIF_NUM, + .memif_dl_num = MT8365_MEMIF_DL_NUM, + .memif_32bit_supported = 0, + .irq_datas = NULL, + .irqs_size = 0, + .dais_size = MT8365_DAI_NUM, + .afe2adsp_addr = mt8365_afe2adsp_addr, + .adsp2afe_addr = mt8365_adsp2afe_addr, + .afe_fs = mt8365_afe_fs, + .irq_fs = mt8365_afe_fs_timing, +}; diff --git a/src/platform/mt8365/include/arch/xtensa/config/core-isa.h b/src/platform/mt8365/include/arch/xtensa/config/core-isa.h new file mode 100644 index 000000000000..b8efd6318c50 --- /dev/null +++ b/src/platform/mt8365/include/arch/xtensa/config/core-isa.h @@ -0,0 +1,649 @@ +/* + * xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa + * processor CORE configuration + * + * See <xtensa/config/core.h>, which includes this file, for more details. + */ + +/* Xtensa processor core configuration information. + + Customer ID=13943; Build=0x75f5e; Copyright (c) 1999-2018 Tensilica 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. */ + +#ifndef _XTENSA_CORE_CONFIGURATION_H +#define _XTENSA_CORE_CONFIGURATION_H + + +/**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + * configured, and a value of 0 otherwise. These macros are always defined. + */ + + +/*---------------------------------------------------------------------- + ISA + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED 1 /* windowed registers option */ +#define XCHAL_NUM_AREGS 64 /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2 6 /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE 11 /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG 1 /* debug option */ +#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS 1 /* zero-overhead loops */ +#define XCHAL_LOOP_BUFFER_SIZE 256 /* zero-ov. loop instr buffer size */ +#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX 1 /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT 1 /* SEXT instruction */ +#define XCHAL_HAVE_DEPBITS 0 /* DEPBITS instruction */ +#define XCHAL_HAVE_CLAMPS 1 /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32 1 /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_DIV32 1 /* QUOS/QUOU/REMS/REMU instructions */ +#define XCHAL_HAVE_L32R 1 /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS 0 /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_EXCLUSIVE 1 /* L32EX/S32EX instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12 1 /* (obsolete option) */ +#define XCHAL_HAVE_ABS 1 /* ABS instruction */ +/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */ +/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */ +#define XCHAL_HAVE_RELEASE_SYNC 1 /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I 0 /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION 0 /* speculation */ +#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS 1 /* */ +#define XCHAL_NUM_MISC_REGS 4 /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID 1 /* processor ID register */ +#define XCHAL_HAVE_EXTERN_REGS 1 /* WER/RER instructions */ +#define XCHAL_HAVE_MX 0 /* MX core (Tensilica internal) */ +#define XCHAL_HAVE_MP_INTERRUPTS 0 /* interrupt distributor port */ +#define XCHAL_HAVE_MP_RUNSTALL 0 /* core RunStall control port */ +#define XCHAL_HAVE_PSO 0 /* Power Shut-Off */ +#define XCHAL_HAVE_PSO_CDM 0 /* core/debug/mem pwr domains */ +#define XCHAL_HAVE_PSO_FULL_RETENTION 0 /* all regs preserved on PSO */ +#define XCHAL_HAVE_THREADPTR 1 /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS 1 /* boolean registers */ +#define XCHAL_HAVE_CP 1 /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG 2 /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16 0 /* MAC16 package */ + +#define XCHAL_HAVE_FUSION 0 /* Fusion*/ +#define XCHAL_HAVE_FUSION_FP 0 /* Fusion FP option */ +#define XCHAL_HAVE_FUSION_LOW_POWER 0 /* Fusion Low Power option */ +#define XCHAL_HAVE_FUSION_AES 0 /* Fusion BLE/Wifi AES-128 CCM option */ +#define XCHAL_HAVE_FUSION_CONVENC 0 /* Fusion Conv Encode option */ +#define XCHAL_HAVE_FUSION_LFSR_CRC 0 /* Fusion LFSR-CRC option */ +#define XCHAL_HAVE_FUSION_BITOPS 0 /* Fusion Bit Operations Support option */ +#define XCHAL_HAVE_FUSION_AVS 0 /* Fusion AVS option */ +#define XCHAL_HAVE_FUSION_16BIT_BASEBAND 0 /* Fusion 16-bit Baseband option */ +#define XCHAL_HAVE_FUSION_VITERBI 0 /* Fusion Viterbi option */ +#define XCHAL_HAVE_FUSION_SOFTDEMAP 0 /* Fusion Soft Bit Demap option */ +#define XCHAL_HAVE_HIFIPRO 0 /* HiFiPro Audio Engine pkg */ +#define XCHAL_HAVE_HIFI5 0 /* HiFi5 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI5_VFPU 0 /* HiFi5 Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI4 1 /* HiFi4 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI4_VFPU 1 /* HiFi4 Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI3 1 /* HiFi3 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI3_VFPU 0 /* HiFi3 Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI3Z 0 /* HiFi3Z Audio Engine pkg */ +#define XCHAL_HAVE_HIFI3Z_VFPU 0 /* HiFi3Z Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI2EP 0 /* HiFi2EP */ +#define XCHAL_HAVE_HIFI_MINI 0 + + + +#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */ +#define XCHAL_HAVE_USER_DPFPU 0 /* user DP floating-point pkg */ +#define XCHAL_HAVE_USER_SPFPU 1 /* user SP floating-point pkg */ +#define XCHAL_HAVE_FP 1 /* single prec floating point */ +#define XCHAL_HAVE_FP_DIV 1 /* FP with DIV instructions */ +#define XCHAL_HAVE_FP_RECIP 1 /* FP with RECIP instructions */ +#define XCHAL_HAVE_FP_SQRT 1 /* FP with SQRT instructions */ +#define XCHAL_HAVE_FP_RSQRT 1 /* FP with RSQRT instructions */ +#define XCHAL_HAVE_DFP 0 /* double precision FP pkg */ +#define XCHAL_HAVE_DFP_DIV 0 /* DFP with DIV instructions */ +#define XCHAL_HAVE_DFP_RECIP 0 /* DFP with RECIP instructions*/ +#define XCHAL_HAVE_DFP_SQRT 0 /* DFP with SQRT instructions */ +#define XCHAL_HAVE_DFP_RSQRT 0 /* DFP with RSQRT instructions*/ +#define XCHAL_HAVE_DFP_ACCEL 0 /* double precision FP acceleration pkg */ +#define XCHAL_HAVE_DFP_accel XCHAL_HAVE_DFP_ACCEL /* for backward compatibility */ + +#define XCHAL_HAVE_DFPU_SINGLE_ONLY 0 /* DFPU Coprocessor, single precision only */ +#define XCHAL_HAVE_DFPU_SINGLE_DOUBLE 0 /* DFPU Coprocessor, single and double precision */ +#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */ +#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */ + +#define XCHAL_HAVE_FUSIONG 0 /* FusionG */ +#define XCHAL_HAVE_FUSIONG3 0 /* FusionG3 */ +#define XCHAL_HAVE_FUSIONG6 0 /* FusionG6 */ +#define XCHAL_HAVE_FUSIONG_SP_VFPU 0 /* sp_vfpu option on FusionG */ +#define XCHAL_HAVE_FUSIONG_DP_VFPU 0 /* dp_vfpu option on FusionG */ +#define XCHAL_FUSIONG_SIMD32 0 /* simd32 for FusionG */ + +#define XCHAL_HAVE_PDX 0 /* PDX */ +#define XCHAL_PDX_SIMD32 0 /* simd32 for PDX */ +#define XCHAL_HAVE_PDX4 0 /* PDX4 */ +#define XCHAL_HAVE_PDX8 0 /* PDX8 */ +#define XCHAL_HAVE_PDX16 0 /* PDX16 */ + +#define XCHAL_HAVE_CONNXD2 0 /* ConnX D2 pkg */ +#define XCHAL_HAVE_CONNXD2_DUALLSFLIX 0 /* ConnX D2 & Dual LoadStore Flix */ +#define XCHAL_HAVE_BBE16 0 /* ConnX BBE16 pkg */ +#define XCHAL_HAVE_BBE16_RSQRT 0 /* BBE16 & vector recip sqrt */ +#define XCHAL_HAVE_BBE16_VECDIV 0 /* BBE16 & vector divide */ +#define XCHAL_HAVE_BBE16_DESPREAD 0 /* BBE16 & despread */ +#define XCHAL_HAVE_BBENEP 0 /* ConnX BBENEP pkgs */ +#define XCHAL_HAVE_BBENEP_SP_VFPU 0 /* sp_vfpu option on BBE-EP */ +#define XCHAL_HAVE_BSP3 0 /* ConnX BSP3 pkg */ +#define XCHAL_HAVE_BSP3_TRANSPOSE 0 /* BSP3 & transpose32x32 */ +#define XCHAL_HAVE_SSP16 0 /* ConnX SSP16 pkg */ +#define XCHAL_HAVE_SSP16_VITERBI 0 /* SSP16 & viterbi */ +#define XCHAL_HAVE_TURBO16 0 /* ConnX Turbo16 pkg */ +#define XCHAL_HAVE_BBP16 0 /* ConnX BBP16 pkg */ +#define XCHAL_HAVE_FLIX3 0 /* basic 3-way FLIX option */ +#define XCHAL_HAVE_GRIVPEP 0 /* General Release of IVPEP */ +#define XCHAL_HAVE_GRIVPEP_HISTOGRAM 0 /* Histogram option on GRIVPEP */ + +#define XCHAL_HAVE_VISION 0 /* Vision P5/P6 */ +#define XCHAL_VISION_SIMD16 0 /* simd16 for Vision P5/P6 */ +#define XCHAL_VISION_TYPE 0 /* Vision P5, P6, or P3 */ +#define XCHAL_VISION_QUAD_MAC_TYPE 0 /* quad_mac option on Vision P6 */ +#define XCHAL_HAVE_VISION_HISTOGRAM 0 /* histogram option on Vision P5/P6 */ +#define XCHAL_HAVE_VISION_SP_VFPU 0 /* sp_vfpu option on Vision P5/P6 */ +#define XCHAL_HAVE_VISION_HP_VFPU 0 /* hp_vfpu option on Vision P6 */ + +#define XCHAL_HAVE_VISIONC 0 /* Vision C */ + +/*---------------------------------------------------------------------- + MISC + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_LOADSTORE_UNITS 2 /* load/store units */ +#define XCHAL_NUM_WRITEBUFFER_ENTRIES 32 /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH 16 /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH 8 /* data width in bytes */ +#define XCHAL_DATA_PIPE_DELAY 2 /* d-side pipeline delay + (1 = 5-stage, 2 = 7-stage) */ +#define XCHAL_CLOCK_GATING_GLOBAL 1 /* global clock gating */ +#define XCHAL_CLOCK_GATING_FUNCUNIT 1 /* funct. unit clock gating */ +/* In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/ +#define XCHAL_UNALIGNED_LOAD_HW 0 /* unaligned loads work in hw */ +#define XCHAL_UNALIGNED_STORE_HW 0 /* unaligned stores work in hw*/ + +#define XCHAL_SW_VERSION 1200009 /* sw version of this header */ + +#define XCHAL_CORE_ID "hifi4_Aquila_E2_PROD" /* alphanum core name + (CoreID) set in the Xtensa + Processor Generator */ + +#define XCHAL_BUILD_UNIQUE_ID 0x00075F5E /* 22-bit sw build ID */ + +/* + * These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0 0xC0F3FBFE /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1 0x22475F5E /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME "LX7.0.9" /* full version name */ +#define XCHAL_HW_VERSION_MAJOR 2700 /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR 9 /* minor ver# of targeted hw */ +#define XCHAL_HW_VERSION 270009 /* major*100+minor */ +#define XCHAL_HW_REL_LX7 1 +#define XCHAL_HW_REL_LX7_0 1 +#define XCHAL_HW_REL_LX7_0_9 1 +#define XCHAL_HW_CONFIGID_RELIABLE 1 +/* If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR 2700 /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR 9 /* minor v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION 270009 /* earliest targeted hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR 2700 /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR 9 /* minor v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION 270009 /* latest targeted hw */ + + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE 128 /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE 128 /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH 7 /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH 7 /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE 32768 /* I-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE 32768 /* D-cache size in bytes or 0 */ + +#define XCHAL_DCACHE_IS_WRITEBACK 1 /* writeback feature */ +#define XCHAL_DCACHE_IS_COHERENT 0 /* MP coherence feature */ + +#define XCHAL_HAVE_PREFETCH 1 /* PREFCTL register */ +#define XCHAL_HAVE_PREFETCH_L1 0 /* prefetch to L1 dcache */ +#define XCHAL_PREFETCH_CASTOUT_LINES 1 /* dcache pref. castout bufsz */ +#define XCHAL_PREFETCH_ENTRIES 16 /* cache prefetch entries */ +#define XCHAL_PREFETCH_BLOCK_ENTRIES 0 /* prefetch block streams */ +#define XCHAL_HAVE_CACHE_BLOCKOPS 0 /* block prefetch for caches */ +#define XCHAL_HAVE_ICACHE_TEST 1 /* Icache test instructions */ +#define XCHAL_HAVE_DCACHE_TEST 1 /* Dcache test instructions */ +#define XCHAL_HAVE_ICACHE_DYN_WAYS 1 /* Icache dynamic way support */ +#define XCHAL_HAVE_DCACHE_DYN_WAYS 1 /* Dcache dynamic way support */ + + + + +/**************************************************************************** + Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF 1 /* any outbound bus present */ + +#define XCHAL_HAVE_AXI 1 /* AXI bus */ +#define XCHAL_HAVE_AXI_ECC 1 /* ECC on AXI bus */ +#define XCHAL_HAVE_ACELITE 0 /* ACELite bus */ + +#define XCHAL_HAVE_PIF_WR_RESP 1 /* pif write response */ +#define XCHAL_HAVE_PIF_REQ_ATTR 1 /* pif attribute */ + +/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */ + +/* Number of cache sets in log2(lines per way): */ +#define XCHAL_ICACHE_SETWIDTH 6 +#define XCHAL_DCACHE_SETWIDTH 6 + +/* Cache set associativity (number of ways): */ +#define XCHAL_ICACHE_WAYS 4 +#define XCHAL_DCACHE_WAYS 4 + +/* Cache features: */ +#define XCHAL_ICACHE_LINE_LOCKABLE 1 +#define XCHAL_DCACHE_LINE_LOCKABLE 1 +#define XCHAL_ICACHE_ECC_PARITY 0 +#define XCHAL_DCACHE_ECC_PARITY 0 + +/* Cache access size in bytes (affects operation of SICW instruction): */ +#define XCHAL_ICACHE_ACCESS_SIZE 16 +#define XCHAL_DCACHE_ACCESS_SIZE 8 + +#define XCHAL_DCACHE_BANKS 2 /* number of banks */ + +/* Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits): */ + + +/*---------------------------------------------------------------------- + INTERNAL I/D RAM/ROMs and XLMI + ----------------------------------------------------------------------*/ +#define XCHAL_NUM_INSTROM 0 /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM 2 /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM 0 /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM 2 /* number of core data RAMs */ +#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI 0 /* number of core XLMI ports */ + +/* Instruction RAM 0: */ +#define XCHAL_INSTRAM0_VADDR 0x40000000 /* virtual address */ +#define XCHAL_INSTRAM0_PADDR 0x40000000 /* physical address */ +#define XCHAL_INSTRAM0_SIZE 65536 /* size in bytes */ +#define XCHAL_INSTRAM0_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_HAVE_INSTRAM0 1 +#define XCHAL_INSTRAM0_HAVE_IDMA 0 /* idma supported by this local memory */ + +/* Instruction RAM 1: */ +#define XCHAL_INSTRAM1_VADDR 0x40010000 /* virtual address */ +#define XCHAL_INSTRAM1_PADDR 0x40010000 /* physical address */ +#define XCHAL_INSTRAM1_SIZE 65536 /* size in bytes */ +#define XCHAL_INSTRAM1_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_HAVE_INSTRAM1 1 +#define XCHAL_INSTRAM1_HAVE_IDMA 0 /* idma supported by this local memory */ + +/* Data RAM 0: */ +#define XCHAL_DATARAM0_VADDR 0x1E000000 /* virtual address */ +#define XCHAL_DATARAM0_PADDR 0x1E000000 /* physical address */ +#define XCHAL_DATARAM0_SIZE 262144 /* size in bytes */ +#define XCHAL_DATARAM0_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_DATARAM0_BANKS 2 /* number of banks */ +#define XCHAL_HAVE_DATARAM0 1 +#define XCHAL_DATARAM0_HAVE_IDMA 0 /* idma supported by this local memory */ + +/* Data RAM 1: */ +#define XCHAL_DATARAM1_VADDR 0x1E040000 /* virtual address */ +#define XCHAL_DATARAM1_PADDR 0x1E040000 /* physical address */ +#define XCHAL_DATARAM1_SIZE 262144 /* size in bytes */ +#define XCHAL_DATARAM1_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_DATARAM1_BANKS 2 /* number of banks */ +#define XCHAL_HAVE_DATARAM1 1 +#define XCHAL_DATARAM1_HAVE_IDMA 0 /* idma supported by this local memory */ + +#define XCHAL_HAVE_IDMA 0 +#define XCHAL_HAVE_IDMA_TRANSPOSE 0 + +#define XCHAL_HAVE_IMEM_LOADSTORE 1 /* can load/store to IROM/IRAM*/ + + +/*---------------------------------------------------------------------- + INTERRUPTS and TIMERS + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */ +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */ +#define XCHAL_HAVE_NMI 0 /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS 3 /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS 25 /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2 5 /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS 18 /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS 4 /* number of interrupt levels + (not including level zero) */ +#define XCHAL_EXCM_LEVEL 2 /* level masked by PS.EXCM */ + /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/* Masks of interrupts at each interrupt level: */ +#define XCHAL_INTLEVEL1_MASK 0x00B900FF +#define XCHAL_INTLEVEL2_MASK 0x0142FF00 +#define XCHAL_INTLEVEL3_MASK 0x00040000 +#define XCHAL_INTLEVEL4_MASK 0x00000000 +#define XCHAL_INTLEVEL5_MASK 0x00000000 +#define XCHAL_INTLEVEL6_MASK 0x00000000 +#define XCHAL_INTLEVEL7_MASK 0x00000000 + +/* Masks of interrupts at each range 1..n of interrupt levels: */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x00B900FF +#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x01FBFFFF +#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x01FFFFFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x01FFFFFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x01FFFFFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x01FFFFFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x01FFFFFF + +/* Level of each interrupt: */ +#define XCHAL_INT0_LEVEL 1 +#define XCHAL_INT1_LEVEL 1 +#define XCHAL_INT2_LEVEL 1 +#define XCHAL_INT3_LEVEL 1 +#define XCHAL_INT4_LEVEL 1 +#define XCHAL_INT5_LEVEL 1 +#define XCHAL_INT6_LEVEL 1 +#define XCHAL_INT7_LEVEL 1 +#define XCHAL_INT8_LEVEL 2 +#define XCHAL_INT9_LEVEL 2 +#define XCHAL_INT10_LEVEL 2 +#define XCHAL_INT11_LEVEL 2 +#define XCHAL_INT12_LEVEL 2 +#define XCHAL_INT13_LEVEL 2 +#define XCHAL_INT14_LEVEL 2 +#define XCHAL_INT15_LEVEL 2 +#define XCHAL_INT16_LEVEL 1 +#define XCHAL_INT17_LEVEL 2 +#define XCHAL_INT18_LEVEL 3 +#define XCHAL_INT19_LEVEL 1 +#define XCHAL_INT20_LEVEL 1 +#define XCHAL_INT21_LEVEL 1 +#define XCHAL_INT22_LEVEL 2 +#define XCHAL_INT23_LEVEL 1 +#define XCHAL_INT24_LEVEL 2 +#define XCHAL_DEBUGLEVEL 4 /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */ + +/* Type of each interrupt: */ +#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT7_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT10_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT11_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT13_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT14_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT15_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT16_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT17_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT18_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT19_TYPE XTHAL_INTTYPE_WRITE_ERROR +#define XCHAL_INT20_TYPE XTHAL_INTTYPE_PROFILING +#define XCHAL_INT21_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT22_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT23_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT24_TYPE XTHAL_INTTYPE_EXTERN_LEVEL + +/* Masks of interrupts for each type of interrupt: */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFE000000 +#define XCHAL_INTTYPE_MASK_SOFTWARE 0x00600000 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x0000C0C0 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x01803F3F +#define XCHAL_INTTYPE_MASK_TIMER 0x00070000 +#define XCHAL_INTTYPE_MASK_NMI 0x00000000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00080000 +#define XCHAL_INTTYPE_MASK_PROFILING 0x00100000 +#define XCHAL_INTTYPE_MASK_IDMA_DONE 0x00000000 +#define XCHAL_INTTYPE_MASK_IDMA_ERR 0x00000000 +#define XCHAL_INTTYPE_MASK_GS_ERR 0x00000000 + +/* Interrupt numbers assigned to specific interrupt sources: */ +#define XCHAL_TIMER0_INTERRUPT 16 /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT 17 /* CCOMPARE1 */ +#define XCHAL_TIMER2_INTERRUPT 18 /* CCOMPARE2 */ +#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_WRITE_ERROR_INTERRUPT 19 +#define XCHAL_PROFILING_INTERRUPT 20 + +/* Interrupt numbers for levels at which only one interrupt is configured: */ +#define XCHAL_INTLEVEL3_NUM 18 +/* (There are many interrupts each at level(s) 1, 2.) */ + + +/* + * External interrupt mapping. + * These macros describe how Xtensa processor interrupt numbers + * (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + * map to external BInterrupt<n> pins, for those interrupts + * configured as external (level-triggered, edge-triggered, or NMI). + * See the Xtensa processor databook for more details. + */ + +/* Core interrupt numbers mapped to each EXTERNAL BInterrupt pin number: */ +#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */ +#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */ +#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM 6 /* (intlevel 1) */ +#define XCHAL_EXTINT7_NUM 7 /* (intlevel 1) */ +#define XCHAL_EXTINT8_NUM 8 /* (intlevel 2) */ +#define XCHAL_EXTINT9_NUM 9 /* (intlevel 2) */ +#define XCHAL_EXTINT10_NUM 10 /* (intlevel 2) */ +#define XCHAL_EXTINT11_NUM 11 /* (intlevel 2) */ +#define XCHAL_EXTINT12_NUM 12 /* (intlevel 2) */ +#define XCHAL_EXTINT13_NUM 13 /* (intlevel 2) */ +#define XCHAL_EXTINT14_NUM 14 /* (intlevel 2) */ +#define XCHAL_EXTINT15_NUM 15 /* (intlevel 2) */ +#define XCHAL_EXTINT16_NUM 23 /* (intlevel 1) */ +#define XCHAL_EXTINT17_NUM 24 /* (intlevel 2) */ +/* EXTERNAL BInterrupt pin numbers mapped to each core interrupt number: */ +#define XCHAL_INT0_EXTNUM 0 /* (intlevel 1) */ +#define XCHAL_INT1_EXTNUM 1 /* (intlevel 1) */ +#define XCHAL_INT2_EXTNUM 2 /* (intlevel 1) */ +#define XCHAL_INT3_EXTNUM 3 /* (intlevel 1) */ +#define XCHAL_INT4_EXTNUM 4 /* (intlevel 1) */ +#define XCHAL_INT5_EXTNUM 5 /* (intlevel 1) */ +#define XCHAL_INT6_EXTNUM 6 /* (intlevel 1) */ +#define XCHAL_INT7_EXTNUM 7 /* (intlevel 1) */ +#define XCHAL_INT8_EXTNUM 8 /* (intlevel 2) */ +#define XCHAL_INT9_EXTNUM 9 /* (intlevel 2) */ +#define XCHAL_INT10_EXTNUM 10 /* (intlevel 2) */ +#define XCHAL_INT11_EXTNUM 11 /* (intlevel 2) */ +#define XCHAL_INT12_EXTNUM 12 /* (intlevel 2) */ +#define XCHAL_INT13_EXTNUM 13 /* (intlevel 2) */ +#define XCHAL_INT14_EXTNUM 14 /* (intlevel 2) */ +#define XCHAL_INT15_EXTNUM 15 /* (intlevel 2) */ +#define XCHAL_INT23_EXTNUM 16 /* (intlevel 1) */ +#define XCHAL_INT24_EXTNUM 17 /* (intlevel 2) */ + + +/*---------------------------------------------------------------------- + EXCEPTIONS and VECTORS + ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture + number: 1 == XEA1 (old) + 2 == XEA2 (new) + 0 == XEAX (extern) or TX */ +#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */ +#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */ +#define XCHAL_HAVE_HALT 0 /* halt architecture option */ +#define XCHAL_HAVE_BOOTLOADER 0 /* boot loader (for TX) */ +#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */ +#define XCHAL_HAVE_VECTOR_SELECT 1 /* relocatable vectors */ +#define XCHAL_HAVE_VECBASE 1 /* relocatable vectors */ +#define XCHAL_VECBASE_RESET_VADDR 0x40020400 /* VECBASE reset value */ +#define XCHAL_VECBASE_RESET_PADDR 0x40020400 +#define XCHAL_RESET_VECBASE_OVERLAP 0 + +#define XCHAL_RESET_VECTOR0_VADDR 0x40020000 +#define XCHAL_RESET_VECTOR0_PADDR 0x40020000 +#define XCHAL_RESET_VECTOR1_VADDR 0x40000640 +#define XCHAL_RESET_VECTOR1_PADDR 0x40000640 +#define XCHAL_RESET_VECTOR_VADDR 0x40000640 +#define XCHAL_RESET_VECTOR_PADDR 0x40000640 +#define XCHAL_USER_VECOFS 0x000001FC +#define XCHAL_USER_VECTOR_VADDR 0x400205FC +#define XCHAL_USER_VECTOR_PADDR 0x400205FC +#define XCHAL_KERNEL_VECOFS 0x000001DC +#define XCHAL_KERNEL_VECTOR_VADDR 0x400205DC +#define XCHAL_KERNEL_VECTOR_PADDR 0x400205DC +#define XCHAL_DOUBLEEXC_VECOFS 0x0000021C +#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x4002061C +#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x4002061C +#define XCHAL_WINDOW_OF4_VECOFS 0x00000000 +#define XCHAL_WINDOW_UF4_VECOFS 0x00000040 +#define XCHAL_WINDOW_OF8_VECOFS 0x00000080 +#define XCHAL_WINDOW_UF8_VECOFS 0x000000C0 +#define XCHAL_WINDOW_OF12_VECOFS 0x00000100 +#define XCHAL_WINDOW_UF12_VECOFS 0x00000140 +#define XCHAL_WINDOW_VECTORS_VADDR 0x40020400 +#define XCHAL_WINDOW_VECTORS_PADDR 0x40020400 +#define XCHAL_INTLEVEL2_VECOFS 0x0000017C +#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x4002057C +#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x4002057C +#define XCHAL_INTLEVEL3_VECOFS 0x0000019C +#define XCHAL_INTLEVEL3_VECTOR_VADDR 0x4002059C +#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x4002059C +#define XCHAL_INTLEVEL4_VECOFS 0x000001BC +#define XCHAL_INTLEVEL4_VECTOR_VADDR 0x400205BC +#define XCHAL_INTLEVEL4_VECTOR_PADDR 0x400205BC +#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL4_VECOFS +#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL4_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL4_VECTOR_PADDR + + +/*---------------------------------------------------------------------- + DEBUG MODULE + ----------------------------------------------------------------------*/ + +/* Misc */ +#define XCHAL_HAVE_DEBUG_ERI 1 /* ERI to debug module */ +#define XCHAL_HAVE_DEBUG_APB 1 /* APB to debug module */ +#define XCHAL_HAVE_DEBUG_JTAG 1 /* JTAG to debug module */ + +/* On-Chip Debug (OCD) */ +#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY 0 /* faster OCD option (to LX4) */ +#define XCHAL_HAVE_OCD_LS32DDR 1 /* L32DDR/S32DDR (faster OCD) */ + +/* TRAX (in core) */ +#define XCHAL_HAVE_TRAX 1 /* TRAX in debug module */ +#define XCHAL_TRAX_MEM_SIZE 262144 /* TRAX memory size in bytes */ +#define XCHAL_TRAX_MEM_SHAREABLE 1 /* start/end regs; ready sig. */ +#define XCHAL_TRAX_ATB_WIDTH 32 /* ATB width (bits), 0=no ATB */ +#define XCHAL_TRAX_TIME_WIDTH 0 /* timestamp bitwidth, 0=none */ + +/* Perf counters */ +#define XCHAL_NUM_PERF_COUNTERS 8 /* performance counters */ + + +/*---------------------------------------------------------------------- + MMU + ----------------------------------------------------------------------*/ + +/* See core-matmap.h header file for more details. */ + +#define XCHAL_HAVE_TLBS 0 /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY 0 /* one way maps I+D 4GB vaddr */ +#define XCHAL_HAVE_IDENTITY_MAP 1 /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR 0 /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU 0 /* full MMU (with page table + [autorefill] and protection) + usable for an MMU-based OS */ + +/* If none of the above last 5 are set, it's a custom TLB configuration. */ + +#define XCHAL_MMU_ASID_BITS 0 /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS 1 /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS 0 /* num of bits in RING field */ + +/*---------------------------------------------------------------------- + MPU + ----------------------------------------------------------------------*/ +#define XCHAL_HAVE_MPU 1 +#define XCHAL_MPU_ENTRIES 32 + +#define XCHAL_MPU_ALIGN_REQ 1 /* MPU requires alignment of entries to background map */ +#define XCHAL_MPU_BACKGROUND_ENTRIES 2 /* number of entries in bg map*/ +#define XCHAL_MPU_BG_CACHEADRDIS 0xFF /* default CACHEADRDIS for bg */ + +#define XCHAL_MPU_ALIGN_BITS 12 +#define XCHAL_MPU_ALIGN 4096 + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* _XTENSA_CORE_CONFIGURATION_H */ + diff --git a/src/platform/mt8365/include/arch/xtensa/config/core-matmap.h b/src/platform/mt8365/include/arch/xtensa/config/core-matmap.h new file mode 100644 index 000000000000..1235cf0f758b --- /dev/null +++ b/src/platform/mt8365/include/arch/xtensa/config/core-matmap.h @@ -0,0 +1,103 @@ +/* + * xtensa/config/core-matmap.h -- Memory access and translation mapping + * parameters (CHAL) of the Xtensa processor core configuration. + * + * If you are using Xtensa Tools, see <xtensa/config/core.h> (which includes + * this file) for more details. + * + * In the Xtensa processor products released to date, all parameters + * defined in this file are derivable (at least in theory) from + * information contained in the core-isa.h header file. + * In particular, the following core configuration parameters are relevant: + * XCHAL_HAVE_CACHEATTR + * XCHAL_HAVE_MIMIC_CACHEATTR + * XCHAL_HAVE_XLT_CACHEATTR + * XCHAL_HAVE_PTP_MMU + * XCHAL_ITLB_ARF_ENTRIES_LOG2 + * XCHAL_DTLB_ARF_ENTRIES_LOG2 + * XCHAL_DCACHE_IS_WRITEBACK + * XCHAL_ICACHE_SIZE (presence of I-cache) + * XCHAL_DCACHE_SIZE (presence of D-cache) + * XCHAL_HW_VERSION_MAJOR + * XCHAL_HW_VERSION_MINOR + */ + +/* Customer ID=13943; Build=0x75f5e; Copyright (c) 1999-2018 Tensilica 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. */ + + +#ifndef XTENSA_CONFIG_CORE_MATMAP_H +#define XTENSA_CONFIG_CORE_MATMAP_H + + +/*---------------------------------------------------------------------- + CACHE (MEMORY ACCESS) ATTRIBUTES + ----------------------------------------------------------------------*/ +/*---------------------------------------------------------------------- + MPU + ----------------------------------------------------------------------*/ + +/* Mappings for legacy constants where appropriate */ + +#define XCHAL_CA_WRITEBACK (XTHAL_MEM_WRITEBACK | XTHAL_AR_RWXrwx) + +#define XCHAL_CA_WRITEBACK_NOALLOC (XTHAL_MEM_WRITEBACK_NOALLOC| XTHAL_AR_RWXrwx ) + +#define XCHAL_CA_WRITETHRU (XTHAL_MEM_WRITETHRU | XTHAL_AR_RWXrwx) + +#define XCHAL_CA_ILLEGAL (XTHAL_AR_NONE | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASS (XTHAL_AR_RWXrwx | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASSBUF (XTHAL_AR_RWXrwx | XTHAL_MEM_DEVICE |\ + XTHAL_MEM_BUFFERABLE) +#define XCHAL_CA_BYPASS_RX (XTHAL_AR_RX | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASS_RW (XTHAL_AR_RW | XTHAL_MEM_DEVICE) +#define XCHAL_CA_BYPASS_R (XTHAL_AR_R | XTHAL_MEM_DEVICE) +#define XCHAL_HAVE_CA_WRITEBACK_NOALLOC 1 + +#define XCHAL_CA_R (XTHAL_AR_R) +#define XCHAL_CA_RX (XTHAL_AR_RX) +#define XCHAL_CA_RW (XTHAL_AR_RW) +#define XCHAL_CA_RWX (XTHAL_AR_RWX) + + +/* + * Contents of MPU background map. + * NOTE: caller must define the XCHAL_MPU_BGMAP() macro (not defined here + * but specified below) before expanding the XCHAL_MPU_BACKGROUND_MAP(s) macro. + * + * XCHAL_MPU_BGMAP(s, vaddr_start, vaddr_last, rights, memtype, x...) + * + * s = passed from XCHAL_MPU_BACKGROUND_MAP(s), eg. to select how to expand + * vaddr_start = first byte of region (always 0 for first entry) + * vaddr_end = last byte of region (always 0xFFFFFFFF for last entry) + * rights = access rights + * memtype = memory type + * x = reserved for future use (0 until then) + */ +#define XCHAL_MPU_BACKGROUND_MAP(s) \ + XCHAL_MPU_BGMAP(s, 0x00000000, 0x7fffffff, 7, 6, 0) \ + XCHAL_MPU_BGMAP(s, 0x80000000, 0xffffffff, 7, 6, 0) \ + /* end */ + + + +#endif /*XTENSA_CONFIG_CORE_MATMAP_H*/ + diff --git a/src/platform/mt8365/include/arch/xtensa/config/defs.h b/src/platform/mt8365/include/arch/xtensa/config/defs.h new file mode 100644 index 000000000000..2a05ec08e4bb --- /dev/null +++ b/src/platform/mt8365/include/arch/xtensa/config/defs.h @@ -0,0 +1,38 @@ +/* Definitions for Xtensa instructions, types, and protos. */ + +/* Customer ID=13943; Build=0x75f5e; Copyright (c) 2003-2004 Tensilica 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. */ + +/* NOTE: This file exists only for backward compatibility with T1050 + and earlier Xtensa releases. It includes only a subset of the + available header files. */ + +#ifndef _XTENSA_BASE_HEADER +#define _XTENSA_BASE_HEADER + +#ifdef __XTENSA__ + +#include <xtensa/tie/xt_core.h> +#include <xtensa/tie/xt_misc.h> +#include <xtensa/tie/xt_booleans.h> + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_BASE_HEADER */ diff --git a/src/platform/mt8365/include/arch/xtensa/config/specreg.h b/src/platform/mt8365/include/arch/xtensa/config/specreg.h new file mode 100644 index 000000000000..9345cc424d5a --- /dev/null +++ b/src/platform/mt8365/include/arch/xtensa/config/specreg.h @@ -0,0 +1,103 @@ +/* + * Xtensa Special Register symbolic names + */ + +/* $Id: //depot/rel/Foxhill/dot.9/Xtensa/SWConfig/hal/specreg.h.tpp#1 $ */ + +/* Customer ID=13943; Build=0x75f5e; Copyright (c) 1998-2002 Tensilica 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. */ + +#ifndef XTENSA_SPECREG_H +#define XTENSA_SPECREG_H + +/* Include these special register bitfield definitions, for historical reasons: */ +#include <xtensa/corebits.h> + + +/* Special registers: */ +#define LBEG 0 +#define LEND 1 +#define LCOUNT 2 +#define SAR 3 +#define BR 4 +#define PREFCTL 40 +#define WINDOWBASE 72 +#define WINDOWSTART 73 +#define MPUENB 90 +#define ERACCESS 95 +#define IBREAKENABLE 96 +#define MEMCTL 97 +#define CACHEADRDIS 98 +#define DDR 104 +#define IBREAKA_0 128 +#define IBREAKA_1 129 +#define DBREAKA_0 144 +#define DBREAKA_1 145 +#define DBREAKC_0 160 +#define DBREAKC_1 161 +#define EPC_1 177 +#define EPC_2 178 +#define EPC_3 179 +#define EPC_4 180 +#define DEPC 192 +#define EPS_2 194 +#define EPS_3 195 +#define EPS_4 196 +#define EXCSAVE_1 209 +#define EXCSAVE_2 210 +#define EXCSAVE_3 211 +#define EXCSAVE_4 212 +#define CPENABLE 224 +#define INTERRUPT 226 +#define INTENABLE 228 +#define PS 230 +#define VECBASE 231 +#define EXCCAUSE 232 +#define DEBUGCAUSE 233 +#define CCOUNT 234 +#define PRID 235 +#define ICOUNT 236 +#define ICOUNTLEVEL 237 +#define EXCVADDR 238 +#define CCOMPARE_0 240 +#define CCOMPARE_1 241 +#define CCOMPARE_2 242 +#define MISC_REG_0 244 +#define MISC_REG_1 245 +#define MISC_REG_2 246 +#define MISC_REG_3 247 + +/* Special cases (bases of special register series): */ +#define IBREAKA 128 +#define DBREAKA 144 +#define DBREAKC 160 +#define EPC 176 +#define EPS 192 +#define EXCSAVE 208 +#define CCOMPARE 240 + +/* Special names for read-only and write-only interrupt registers: */ +#define INTREAD 226 +#define INTSET 226 +#define INTCLEAR 227 + +#endif /* XTENSA_SPECREG_H */ + diff --git a/src/platform/mt8365/include/arch/xtensa/config/system.h b/src/platform/mt8365/include/arch/xtensa/config/system.h new file mode 100644 index 000000000000..2368853e0097 --- /dev/null +++ b/src/platform/mt8365/include/arch/xtensa/config/system.h @@ -0,0 +1,267 @@ +/* + * xtensa/config/system.h -- HAL definitions that are dependent on SYSTEM configuration + * + * NOTE: The location and contents of this file are highly subject to change. + * + * Source for configuration-independent binaries (which link in a + * configuration-specific HAL library) must NEVER include this file. + * The HAL itself has historically included this file in some instances, + * but this is not appropriate either, because the HAL is meant to be + * core-specific but system independent. + */ + +/* Customer ID=13943; Build=0x75f5e; Copyright (c) 2000-2010 Tensilica 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. */ + + +#ifndef XTENSA_CONFIG_SYSTEM_H +#define XTENSA_CONFIG_SYSTEM_H + +/*#include <xtensa/hal.h>*/ + + + +/*---------------------------------------------------------------------- + CONFIGURED SOFTWARE OPTIONS + ----------------------------------------------------------------------*/ + +#define XSHAL_USE_ABSOLUTE_LITERALS 0 /* (sw-only option, whether software uses absolute literals) */ +#define XSHAL_HAVE_TEXT_SECTION_LITERALS 1 /* Set if there is some memory that allows both code and literals. */ + +#define XSHAL_ABI XTHAL_ABI_WINDOWED /* (sw-only option, selected ABI) */ +/* The above maps to one of the following constants: */ +#define XTHAL_ABI_WINDOWED 0 +#define XTHAL_ABI_CALL0 1 +/* Alternatives: */ +/*#define XSHAL_WINDOWED_ABI 1*/ /* set if windowed ABI selected */ +/*#define XSHAL_CALL0_ABI 0*/ /* set if call0 ABI selected */ + +#define XSHAL_CLIB XTHAL_CLIB_XCLIB /* (sw-only option, selected C library) */ +/* The above maps to one of the following constants: */ +#define XTHAL_CLIB_NEWLIB 0 +#define XTHAL_CLIB_UCLIBC 1 +#define XTHAL_CLIB_XCLIB 2 +/* Alternatives: */ +/*#define XSHAL_NEWLIB 0*/ /* set if newlib C library selected */ +/*#define XSHAL_UCLIBC 0*/ /* set if uCLibC C library selected */ +/*#define XSHAL_XCLIB 1*/ /* set if Xtensa C library selected */ + +#define XSHAL_USE_FLOATING_POINT 1 + +#define XSHAL_FLOATING_POINT_ABI 1 + +/* SW workarounds enabled for HW errata: */ + +/* SW options for functional safety: */ +#define XSHAL_FUNC_SAFETY_ENABLED 0 + +/*---------------------------------------------------------------------- + DEVICE ADDRESSES + ----------------------------------------------------------------------*/ + +/* + * Strange place to find these, but the configuration GUI + * allows moving these around to account for various core + * configurations. Specific boards (and their BSP software) + * will have specific meanings for these components. + */ + +/* I/O Block areas: */ +#define XSHAL_IOBLOCK_CACHED_VADDR 0x70000000 +#define XSHAL_IOBLOCK_CACHED_PADDR 0x70000000 +#define XSHAL_IOBLOCK_CACHED_SIZE 0x0E000000 + +#define XSHAL_IOBLOCK_BYPASS_VADDR 0x50000000 +#define XSHAL_IOBLOCK_BYPASS_PADDR 0x50000000 +#define XSHAL_IOBLOCK_BYPASS_SIZE 0x0E000000 + +/* System ROM: */ +/*#define XSHAL_ROM_[VP]ADDR ...not configured...*/ +/*#define XSHAL_ROM_SIZE ...not configured...*/ +/*#define XSHAL_ROM_AVAIL_V{ADDR,SIZE} ...not configured...*/ + +/* System RAM: */ +#define XSHAL_RAM_VADDR 0x40020000 +#define XSHAL_RAM_PADDR 0x40020000 +#define XSHAL_RAM_VSIZE 0x80000000 +#define XSHAL_RAM_PSIZE 0x80000000 +#define XSHAL_RAM_SIZE XSHAL_RAM_PSIZE +/* Largest available area (free of vectors): */ +#define XSHAL_RAM_AVAIL_VADDR 0x4002061C +#define XSHAL_RAM_AVAIL_VSIZE 0x7FFFF9E4 + +/* + * Shadow system RAM (same device as system RAM, at different address). + * (Emulation boards need this for the SONIC Ethernet driver + * when data caches are configured for writeback mode.) + * NOTE: on full MMU configs, this points to the BYPASS virtual address + * of system RAM, ie. is the same as XSHAL_RAM_* except that virtual + * addresses are viewed through the BYPASS static map rather than + * the CACHED static map. + */ +#define XSHAL_RAM_BYPASS_VADDR 0x20000000 +#define XSHAL_RAM_BYPASS_PADDR 0x20000000 +#define XSHAL_RAM_BYPASS_PSIZE 0x20000000 + +/* Alternate system RAM (different device than system RAM): */ +/*#define XSHAL_ALTRAM_[VP]ADDR ...not configured...*/ +/*#define XSHAL_ALTRAM_SIZE ...not configured...*/ + +/* Some available location in which to place devices in a simulation (eg. XTMP): */ +#define XSHAL_SIMIO_CACHED_VADDR 0x20000000 +#define XSHAL_SIMIO_BYPASS_VADDR 0x20000000 +#define XSHAL_SIMIO_PADDR 0x20000000 +#define XSHAL_SIMIO_SIZE 0x20000000 + + +/*---------------------------------------------------------------------- + * For use by reference testbench exit and diagnostic routines. + */ +#define XSHAL_MAGIC_EXIT 0xcce5000 + +/*---------------------------------------------------------------------- + * DEVICE-ADDRESS DEPENDENT... + * + * Values written to CACHEATTR special register (or its equivalent) + * to enable and disable caches in various modes. + *----------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------- + BACKWARD COMPATIBILITY ... + ----------------------------------------------------------------------*/ + +/* + * NOTE: the following two macros are DEPRECATED. Use the latter + * board-specific macros instead, which are specially tuned for the + * particular target environments' memory maps. + */ +#define XSHAL_CACHEATTR_BYPASS XSHAL_XT2000_CACHEATTR_BYPASS /* disable caches in bypass mode */ +#define XSHAL_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_DEFAULT /* default setting to enable caches (no writeback!) */ + +/*---------------------------------------------------------------------- + GENERIC + ----------------------------------------------------------------------*/ + +/* For the following, a 512MB region is used if it contains a system (PIF) RAM, + * system (PIF) ROM, local memory, or XLMI. */ + +/* These set any unused 512MB region to cache-BYPASS attribute: */ +#define XSHAL_ALLVALID_CACHEATTR_WRITEBACK 0x24444424 /* enable caches in write-back mode */ +#define XSHAL_ALLVALID_CACHEATTR_WRITEALLOC 0x21111121 /* enable caches in write-allocate mode */ +#define XSHAL_ALLVALID_CACHEATTR_WRITETHRU 0x21111121 /* enable caches in write-through mode */ +#define XSHAL_ALLVALID_CACHEATTR_BYPASS 0x22222222 /* disable caches in bypass mode */ +#define XSHAL_ALLVALID_CACHEATTR_DEFAULT XSHAL_ALLVALID_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +/* These set any unused 512MB region to ILLEGAL attribute: */ +#define XSHAL_STRICT_CACHEATTR_WRITEBACK 0xF44444F4 /* enable caches in write-back mode */ +#define XSHAL_STRICT_CACHEATTR_WRITEALLOC 0xF11111F1 /* enable caches in write-allocate mode */ +#define XSHAL_STRICT_CACHEATTR_WRITETHRU 0xF11111F1 /* enable caches in write-through mode */ +#define XSHAL_STRICT_CACHEATTR_BYPASS 0xF22222F2 /* disable caches in bypass mode */ +#define XSHAL_STRICT_CACHEATTR_DEFAULT XSHAL_STRICT_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +/* These set the first 512MB, if unused, to ILLEGAL attribute to help catch + * NULL-pointer dereference bugs; all other unused 512MB regions are set + * to cache-BYPASS attribute: */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITEBACK 0x24444424 /* enable caches in write-back mode */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITEALLOC 0x21111121 /* enable caches in write-allocate mode */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITETHRU 0x21111121 /* enable caches in write-through mode */ +#define XSHAL_TRAPNULL_CACHEATTR_BYPASS 0x22222222 /* disable caches in bypass mode */ +#define XSHAL_TRAPNULL_CACHEATTR_DEFAULT XSHAL_TRAPNULL_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +/*---------------------------------------------------------------------- + ISS (Instruction Set Simulator) SPECIFIC ... + ----------------------------------------------------------------------*/ + +/* For now, ISS defaults to the TRAPNULL settings: */ +#define XSHAL_ISS_CACHEATTR_WRITEBACK XSHAL_TRAPNULL_CACHEATTR_WRITEBACK +#define XSHAL_ISS_CACHEATTR_WRITEALLOC XSHAL_TRAPNULL_CACHEATTR_WRITEALLOC +#define XSHAL_ISS_CACHEATTR_WRITETHRU XSHAL_TRAPNULL_CACHEATTR_WRITETHRU +#define XSHAL_ISS_CACHEATTR_BYPASS XSHAL_TRAPNULL_CACHEATTR_BYPASS +#define XSHAL_ISS_CACHEATTR_DEFAULT XSHAL_TRAPNULL_CACHEATTR_WRITEBACK + +#define XSHAL_ISS_PIPE_REGIONS 0 +#define XSHAL_ISS_SDRAM_REGIONS 0 + + +/*---------------------------------------------------------------------- + XT2000 BOARD SPECIFIC ... + ----------------------------------------------------------------------*/ + +/* For the following, a 512MB region is used if it contains any system RAM, + * system ROM, local memory, XLMI, or other XT2000 board device or memory. + * Regions containing devices are forced to cache-BYPASS mode regardless + * of whether the macro is _WRITEBACK vs. _BYPASS etc. */ + +/* These set any 512MB region unused on the XT2000 to ILLEGAL attribute: */ +#define XSHAL_XT2000_CACHEATTR_WRITEBACK 0xF4444224 /* enable caches in write-back mode */ +#define XSHAL_XT2000_CACHEATTR_WRITEALLOC 0xF1111221 /* enable caches in write-allocate mode */ +#define XSHAL_XT2000_CACHEATTR_WRITETHRU 0xF1111221 /* enable caches in write-through mode */ +#define XSHAL_XT2000_CACHEATTR_BYPASS 0xF2222222 /* disable caches in bypass mode */ +#define XSHAL_XT2000_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +#define XSHAL_XT2000_PIPE_REGIONS 0x00000000 /* BusInt pipeline regions */ +#define XSHAL_XT2000_SDRAM_REGIONS 0x00000014 /* BusInt SDRAM regions */ + + +/*---------------------------------------------------------------------- + VECTOR INFO AND SIZES + ----------------------------------------------------------------------*/ + +#define XSHAL_VECTORS_PACKED 0 +#define XSHAL_STATIC_VECTOR_SELECT 1 +#define XSHAL_RESET_VECTOR_VADDR 0x40000640 +#define XSHAL_RESET_VECTOR_PADDR 0x40000640 + +/* + * Sizes allocated to vectors by the system (memory map) configuration. + * These sizes are constrained by core configuration (eg. one vector's + * code cannot overflow into another vector) but are dependent on the + * system or board (or LSP) memory map configuration. + * + * Whether or not each vector happens to be in a system ROM is also + * a system configuration matter, sometimes useful, included here also: + */ +#define XSHAL_RESET_VECTOR_SIZE 0x000002E0 +#define XSHAL_RESET_VECTOR_ISROM 0 +#define XSHAL_USER_VECTOR_SIZE 0x0000001C +#define XSHAL_USER_VECTOR_ISROM 0 +#define XSHAL_PROGRAMEXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_USEREXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_KERNEL_VECTOR_SIZE 0x0000001C +#define XSHAL_KERNEL_VECTOR_ISROM 0 +#define XSHAL_STACKEDEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_KERNELEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_DOUBLEEXC_VECTOR_SIZE 0x0000001C +#define XSHAL_DOUBLEEXC_VECTOR_ISROM 0 +#define XSHAL_WINDOW_VECTORS_SIZE 0x00000178 +#define XSHAL_WINDOW_VECTORS_ISROM 0 +#define XSHAL_INTLEVEL2_VECTOR_SIZE 0x0000001C +#define XSHAL_INTLEVEL2_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL3_VECTOR_SIZE 0x0000001C +#define XSHAL_INTLEVEL3_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL4_VECTOR_SIZE 0x0000001C +#define XSHAL_INTLEVEL4_VECTOR_ISROM 0 +#define XSHAL_DEBUG_VECTOR_SIZE XSHAL_INTLEVEL4_VECTOR_SIZE +#define XSHAL_DEBUG_VECTOR_ISROM XSHAL_INTLEVEL4_VECTOR_ISROM + + +#endif /*XTENSA_CONFIG_SYSTEM_H*/ + diff --git a/src/platform/mt8365/include/arch/xtensa/config/tie-asm.h b/src/platform/mt8365/include/arch/xtensa/config/tie-asm.h new file mode 100644 index 000000000000..2d9c889ecc5b --- /dev/null +++ b/src/platform/mt8365/include/arch/xtensa/config/tie-asm.h @@ -0,0 +1,336 @@ +/* + * tie-asm.h -- compile-time HAL assembler definitions dependent on CORE & TIE + * + * NOTE: This header file is not meant to be included directly. + */ + +/* This header file contains assembly-language definitions (assembly + macros, etc.) for this specific Xtensa processor's TIE extensions + and options. It is customized to this Xtensa processor configuration. + + Customer ID=13943; Build=0x75f5e; Copyright (c) 1999-2018 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. */ + +#ifndef _XTENSA_CORE_TIE_ASM_H +#define _XTENSA_CORE_TIE_ASM_H + +/* Selection parameter values for save-area save/restore macros: */ +/* Option vs. TIE: */ +#define XTHAL_SAS_TIE 0x0001 /* custom extension or coprocessor */ +#define XTHAL_SAS_OPT 0x0002 /* optional (and not a coprocessor) */ +#define XTHAL_SAS_ANYOT 0x0003 /* both of the above */ +/* Whether used automatically by compiler: */ +#define XTHAL_SAS_NOCC 0x0004 /* not used by compiler w/o special opts/code */ +#define XTHAL_SAS_CC 0x0008 /* used by compiler without special opts/code */ +#define XTHAL_SAS_ANYCC 0x000C /* both of the above */ +/* ABI handling across function calls: */ +#define XTHAL_SAS_CALR 0x0010 /* caller-saved */ +#define XTHAL_SAS_CALE 0x0020 /* callee-saved */ +#define XTHAL_SAS_GLOB 0x0040 /* global across function calls (in thread) */ +#define XTHAL_SAS_ANYABI 0x0070 /* all of the above three */ +/* Misc */ +#define XTHAL_SAS_ALL 0xFFFF /* include all default NCP contents */ +#define XTHAL_SAS3(optie,ccuse,abi) ( ((optie) & XTHAL_SAS_ANYOT) \ + | ((ccuse) & XTHAL_SAS_ANYCC) \ + | ((abi) & XTHAL_SAS_ANYABI) ) + + + /* + * Macro to store all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 4 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_NCP_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters: + * continue If macro invoked as part of a larger store sequence, set to 1 + * if this is not the first in the sequence. Defaults to 0. + * ofs Offset from start of larger sequence (from value of first ptr + * in sequence) at which to store. Defaults to next available space + * (or 0 if <continue> is 0). + * select Select what category(ies) of registers to store, as a bitmask + * (see XTHAL_SAS_xxx constants). Defaults to all registers. + * alloc Select what category(ies) of registers to allocate; if any + * category is selected here that is not in <select>, space for + * the corresponding registers is skipped without doing any store. + */ + .macro xchal_ncp_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL alloc=0 + xchal_sa_start \continue, \ofs + // Optional global registers used by default by the compiler: + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\select) + xchal_sa_align \ptr, 0, 1016, 4, 4 + rur.THREADPTR \at1 // threadptr option + s32i \at1, \ptr, .Lxchal_ofs_+0 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .elseif ((XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1016, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + // Optional caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 1016, 4, 4 + rsr.BR \at1 // boolean option + s32i \at1, \ptr, .Lxchal_ofs_+0 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .elseif ((XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1016, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + // Custom caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 1012, 4, 4 + rur.accreg_0 \at1 // ureg 3 + s32i \at1, \ptr, .Lxchal_ofs_+0 + rur.accreg_1 \at1 // ureg 4 + s32i \at1, \ptr, .Lxchal_ofs_+4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 8 + .elseif ((XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1012, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 8 + .endif + .endm // xchal_ncp_store + + /* + * Macro to load all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 4 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_NCP_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters: + * continue If macro invoked as part of a larger load sequence, set to 1 + * if this is not the first in the sequence. Defaults to 0. + * ofs Offset from start of larger sequence (from value of first ptr + * in sequence) at which to load. Defaults to next available space + * (or 0 if <continue> is 0). + * select Select what category(ies) of registers to load, as a bitmask + * (see XTHAL_SAS_xxx constants). Defaults to all registers. + * alloc Select what category(ies) of registers to allocate; if any + * category is selected here that is not in <select>, space for + * the corresponding registers is skipped without doing any load. + */ + .macro xchal_ncp_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL alloc=0 + xchal_sa_start \continue, \ofs + // Optional global registers used by default by the compiler: + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\select) + xchal_sa_align \ptr, 0, 1016, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_+0 + wur.THREADPTR \at1 // threadptr option + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .elseif ((XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1016, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + // Optional caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 1016, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_+0 + wsr.BR \at1 // boolean option + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .elseif ((XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1016, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + // Custom caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 1012, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_+0 + wur.accreg_0 \at1 // ureg 3 + l32i \at1, \ptr, .Lxchal_ofs_+4 + wur.accreg_1 \at1 // ureg 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 8 + .elseif ((XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 1012, 4, 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 8 + .endif + .endm // xchal_ncp_load + + +#define XCHAL_NCP_NUM_ATMPS 1 + + /* + * Macro to store the state of TIE coprocessor AudioEngineLX. + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 8 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_CP1_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters are the same as for xchal_ncp_store. + */ +#define xchal_cp_AudioEngineLX_store xchal_cp1_store + .macro xchal_cp1_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL alloc=0 + xchal_sa_start \continue, \ofs + // Custom caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 0, 8, 8 + ae_s64.i aed0, \ptr, .Lxchal_ofs_+40 + ae_s64.i aed1, \ptr, .Lxchal_ofs_+48 + ae_s64.i aed2, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_s64.i aed3, \ptr, .Lxchal_ofs_+0 + ae_s64.i aed4, \ptr, .Lxchal_ofs_+8 + ae_s64.i aed5, \ptr, .Lxchal_ofs_+16 + ae_s64.i aed6, \ptr, .Lxchal_ofs_+24 + ae_s64.i aed7, \ptr, .Lxchal_ofs_+32 + ae_s64.i aed8, \ptr, .Lxchal_ofs_+40 + ae_s64.i aed9, \ptr, .Lxchal_ofs_+48 + ae_s64.i aed10, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_s64.i aed11, \ptr, .Lxchal_ofs_+0 + ae_s64.i aed12, \ptr, .Lxchal_ofs_+8 + ae_s64.i aed13, \ptr, .Lxchal_ofs_+16 + ae_s64.i aed14, \ptr, .Lxchal_ofs_+24 + ae_s64.i aed15, \ptr, .Lxchal_ofs_+32 + ae_movae \at1, aep0 + s8i \at1, \ptr, .Lxchal_ofs_+40 + ae_movae \at1, aep1 + s8i \at1, \ptr, .Lxchal_ofs_+41 + ae_movae \at1, aep2 + s8i \at1, \ptr, .Lxchal_ofs_+42 + ae_movae \at1, aep3 + s8i \at1, \ptr, .Lxchal_ofs_+43 + ae_salign64.i u0, \ptr, .Lxchal_ofs_+48 + ae_salign64.i u1, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_salign64.i u2, \ptr, .Lxchal_ofs_+0 + ae_salign64.i u3, \ptr, .Lxchal_ofs_+8 + addi \ptr, \ptr, -192 + ae_movvfcrfsr aed0 // ureg FCR_FSR + ae_s64.i aed0, \ptr, .Lxchal_ofs_+0 + 0 + rur.AE_OVF_SAR \at1 // ureg 240 + s32i \at1, \ptr, .Lxchal_ofs_+8 + rur.AE_BITHEAD \at1 // ureg 241 + s32i \at1, \ptr, .Lxchal_ofs_+12 + rur.AE_TS_FTS_BU_BP \at1 // ureg 242 + s32i \at1, \ptr, .Lxchal_ofs_+16 + rur.AE_CW_SD_NO \at1 // ureg 243 + s32i \at1, \ptr, .Lxchal_ofs_+20 + rur.AE_CBEGIN0 \at1 // ureg 246 + s32i \at1, \ptr, .Lxchal_ofs_+24 + rur.AE_CEND0 \at1 // ureg 247 + s32i \at1, \ptr, .Lxchal_ofs_+28 + rur.AE_CBEGIN1 \at1 // ureg 248 + s32i \at1, \ptr, .Lxchal_ofs_+32 + rur.AE_CEND1 \at1 // ureg 249 + s32i \at1, \ptr, .Lxchal_ofs_+36 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 208 + .elseif ((XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 0, 8, 8 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 208 + .endif + .endm // xchal_cp1_store + + /* + * Macro to load the state of TIE coprocessor AudioEngineLX. + * Required parameters: + * ptr Save area pointer address register (clobbered) + * (register must contain a 8 byte aligned address). + * at1..at4 Four temporary address registers (first XCHAL_CP1_NUM_ATMPS + * registers are clobbered, the remaining are unused). + * Optional parameters are the same as for xchal_ncp_load. + */ +#define xchal_cp_AudioEngineLX_load xchal_cp1_load + .macro xchal_cp1_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL alloc=0 + xchal_sa_start \continue, \ofs + // Custom caller-saved registers not used by default by the compiler: + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\select) + xchal_sa_align \ptr, 0, 0, 8, 8 + ae_l64.i aed0, \ptr, .Lxchal_ofs_+0 + 0 // ureg FCR_FSR + ae_movfcrfsrv aed0 + l32i \at1, \ptr, .Lxchal_ofs_+8 + wur.AE_OVF_SAR \at1 // ureg 240 + l32i \at1, \ptr, .Lxchal_ofs_+12 + wur.AE_BITHEAD \at1 // ureg 241 + l32i \at1, \ptr, .Lxchal_ofs_+16 + wur.AE_TS_FTS_BU_BP \at1 // ureg 242 + l32i \at1, \ptr, .Lxchal_ofs_+20 + wur.AE_CW_SD_NO \at1 // ureg 243 + l32i \at1, \ptr, .Lxchal_ofs_+24 + wur.AE_CBEGIN0 \at1 // ureg 246 + l32i \at1, \ptr, .Lxchal_ofs_+28 + wur.AE_CEND0 \at1 // ureg 247 + l32i \at1, \ptr, .Lxchal_ofs_+32 + wur.AE_CBEGIN1 \at1 // ureg 248 + l32i \at1, \ptr, .Lxchal_ofs_+36 + wur.AE_CEND1 \at1 // ureg 249 + ae_l64.i aed0, \ptr, .Lxchal_ofs_+40 + ae_l64.i aed1, \ptr, .Lxchal_ofs_+48 + ae_l64.i aed2, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_l64.i aed3, \ptr, .Lxchal_ofs_+0 + ae_l64.i aed4, \ptr, .Lxchal_ofs_+8 + ae_l64.i aed5, \ptr, .Lxchal_ofs_+16 + ae_l64.i aed6, \ptr, .Lxchal_ofs_+24 + ae_l64.i aed7, \ptr, .Lxchal_ofs_+32 + ae_l64.i aed8, \ptr, .Lxchal_ofs_+40 + ae_l64.i aed9, \ptr, .Lxchal_ofs_+48 + ae_l64.i aed10, \ptr, .Lxchal_ofs_+56 + addi \ptr, \ptr, 64 + ae_l64.i aed11, \ptr, .Lxchal_ofs_+0 + ae_l64.i aed12, \ptr, .Lxchal_ofs_+8 + ae_l64.i aed13, \ptr, .Lxchal_ofs_+16 + ae_l64.i aed14, \ptr, .Lxchal_ofs_+24 + ae_l64.i aed15, \ptr, .Lxchal_ofs_+32 + addi \ptr, \ptr, 40 + l8ui \at1, \ptr, .Lxchal_ofs_+0 + ae_movea aep0, \at1 + l8ui \at1, \ptr, .Lxchal_ofs_+1 + ae_movea aep1, \at1 + l8ui \at1, \ptr, .Lxchal_ofs_+2 + ae_movea aep2, \at1 + l8ui \at1, \ptr, .Lxchal_ofs_+3 + ae_movea aep3, \at1 + addi \ptr, \ptr, 8 + ae_lalign64.i u0, \ptr, .Lxchal_ofs_+0 + ae_lalign64.i u1, \ptr, .Lxchal_ofs_+8 + ae_lalign64.i u2, \ptr, .Lxchal_ofs_+16 + ae_lalign64.i u3, \ptr, .Lxchal_ofs_+24 + .set .Lxchal_pofs_, .Lxchal_pofs_ + 176 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 32 + .elseif ((XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~(\alloc)) == 0 + xchal_sa_align \ptr, 0, 0, 8, 8 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 208 + .endif + .endm // xchal_cp1_load + +#define XCHAL_CP1_NUM_ATMPS 1 +#define XCHAL_SA_NUM_ATMPS 1 + + /* Empty macros for unconfigured coprocessors: */ + .macro xchal_cp0_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp0_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp2_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp2_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp3_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp3_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp4_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp4_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp5_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp5_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp6_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp6_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp7_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp7_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + +#endif /*_XTENSA_CORE_TIE_ASM_H*/ + diff --git a/src/platform/mt8365/include/arch/xtensa/config/tie.h b/src/platform/mt8365/include/arch/xtensa/config/tie.h new file mode 100644 index 000000000000..196c1fd575b8 --- /dev/null +++ b/src/platform/mt8365/include/arch/xtensa/config/tie.h @@ -0,0 +1,189 @@ +/* + * tie.h -- compile-time HAL definitions dependent on CORE & TIE configuration + * + * NOTE: This header file is not meant to be included directly. + */ + +/* This header file describes this specific Xtensa processor's TIE extensions + that extend basic Xtensa core functionality. It is customized to this + Xtensa processor configuration. + + Customer ID=13943; Build=0x75f5e; Copyright (c) 1999-2018 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. */ + +#ifndef _XTENSA_CORE_TIE_H +#define _XTENSA_CORE_TIE_H + +#define XCHAL_CP_NUM 1 /* number of coprocessors */ +#define XCHAL_CP_MAX 2 /* max CP ID + 1 (0 if none) */ +#define XCHAL_CP_MASK 0x02 /* bitmask of all CPs by ID */ +#define XCHAL_CP_PORT_MASK 0x00 /* bitmask of only port CPs */ + +/* Basic parameters of each coprocessor: */ +#define XCHAL_CP1_NAME "AudioEngineLX" +#define XCHAL_CP1_IDENT AudioEngineLX +#define XCHAL_CP1_SA_SIZE 208 /* size of state save area */ +#define XCHAL_CP1_SA_ALIGN 8 /* min alignment of save area */ +#define XCHAL_CP_ID_AUDIOENGINELX 1 /* coprocessor ID (0..7) */ + +/* Filler info for unassigned coprocessors, to simplify arrays etc: */ +#define XCHAL_CP0_SA_SIZE 0 +#define XCHAL_CP0_SA_ALIGN 1 +#define XCHAL_CP2_SA_SIZE 0 +#define XCHAL_CP2_SA_ALIGN 1 +#define XCHAL_CP3_SA_SIZE 0 +#define XCHAL_CP3_SA_ALIGN 1 +#define XCHAL_CP4_SA_SIZE 0 +#define XCHAL_CP4_SA_ALIGN 1 +#define XCHAL_CP5_SA_SIZE 0 +#define XCHAL_CP5_SA_ALIGN 1 +#define XCHAL_CP6_SA_SIZE 0 +#define XCHAL_CP6_SA_ALIGN 1 +#define XCHAL_CP7_SA_SIZE 0 +#define XCHAL_CP7_SA_ALIGN 1 + +/* Save area for non-coprocessor optional and custom (TIE) state: */ +#define XCHAL_NCP_SA_SIZE 16 +#define XCHAL_NCP_SA_ALIGN 4 + +/* Total save area for optional and custom state (NCP + CPn): */ +#define XCHAL_TOTAL_SA_SIZE 224 /* with 16-byte align padding */ +#define XCHAL_TOTAL_SA_ALIGN 8 /* actual minimum alignment */ + +/* + * Detailed contents of save areas. + * NOTE: caller must define the XCHAL_SA_REG macro (not defined here) + * before expanding the XCHAL_xxx_SA_LIST() macros. + * + * XCHAL_SA_REG(s,ccused,abikind,kind,opt,name,galign,align,asize, + * dbnum,base,regnum,bitsz,gapsz,reset,x...) + * + * s = passed from XCHAL_*_LIST(s), eg. to select how to expand + * ccused = set if used by compiler without special options or code + * abikind = 0 (caller-saved), 1 (callee-saved), or 2 (thread-global) + * kind = 0 (special reg), 1 (TIE user reg), or 2 (TIE regfile reg) + * opt = 0 (custom TIE extension or coprocessor), or 1 (optional reg) + * name = lowercase reg name (no quotes) + * galign = group byte alignment (power of 2) (galign >= align) + * align = register byte alignment (power of 2) + * asize = allocated size in bytes (asize*8 == bitsz + gapsz + padsz) + * (not including any pad bytes required to galign this or next reg) + * dbnum = unique target number f/debug (see <xtensa-libdb-macros.h>) + * base = reg shortname w/o index (or sr=special, ur=TIE user reg) + * regnum = reg index in regfile, or special/TIE-user reg number + * bitsz = number of significant bits (regfile width, or ur/sr mask bits) + * gapsz = intervening bits, if bitsz bits not stored contiguously + * (padsz = pad bits at end [TIE regfile] or at msbits [ur,sr] of asize) + * reset = register reset value (or 0 if undefined at reset) + * x = reserved for future use (0 until then) + * + * To filter out certain registers, e.g. to expand only the non-global + * registers used by the compiler, you can do something like this: + * + * #define XCHAL_SA_REG(s,ccused,p...) SELCC##ccused(p) + * #define SELCC0(p...) + * #define SELCC1(abikind,p...) SELAK##abikind(p) + * #define SELAK0(p...) REG(p) + * #define SELAK1(p...) REG(p) + * #define SELAK2(p...) + * #define REG(kind,tie,name,galn,aln,asz,csz,dbnum,base,rnum,bsz,rst,x...) \ + * ...what you want to expand... + */ + +#define XCHAL_NCP_SA_NUM 4 +#define XCHAL_NCP_SA_LIST(s) \ + XCHAL_SA_REG(s,1,2,1,1, threadptr, 4, 4, 4,0x03E7, ur,231, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,0,1, br, 4, 4, 4,0x0204, sr,4 , 16,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, accreg_0, 4, 4, 4,0x0303, ur,3 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, accreg_1, 4, 4, 4,0x0304, ur,4 , 32,0,0,0) + +#define XCHAL_CP0_SA_NUM 0 +#define XCHAL_CP0_SA_LIST(s) /* empty */ + +#define XCHAL_CP1_SA_NUM 33 +#define XCHAL_CP1_SA_LIST(s) \ + XCHAL_SA_REG(s,0,0,1,0, fcr_fsr, 8, 8, 8,0x1019, ur,-1 , 7,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_ovf_sar, 4, 4, 4,0x03F0, ur,240, 15,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_bithead, 4, 4, 4,0x03F1, ur,241, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0,ae_ts_fts_bu_bp, 4, 4, 4,0x03F2, ur,242, 16,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cw_sd_no, 4, 4, 4,0x03F3, ur,243, 29,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cbegin0, 4, 4, 4,0x03F6, ur,246, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cend0, 4, 4, 4,0x03F7, ur,247, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cbegin1, 4, 4, 4,0x03F8, ur,248, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ae_cend1, 4, 4, 4,0x03F9, ur,249, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed0, 8, 8, 8,0x1000, aed,0 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed1, 8, 8, 8,0x1001, aed,1 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed2, 8, 8, 8,0x1002, aed,2 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed3, 8, 8, 8,0x1003, aed,3 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed4, 8, 8, 8,0x1004, aed,4 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed5, 8, 8, 8,0x1005, aed,5 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed6, 8, 8, 8,0x1006, aed,6 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed7, 8, 8, 8,0x1007, aed,7 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed8, 8, 8, 8,0x1008, aed,8 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed9, 8, 8, 8,0x1009, aed,9 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed10, 8, 8, 8,0x100A, aed,10 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed11, 8, 8, 8,0x100B, aed,11 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed12, 8, 8, 8,0x100C, aed,12 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed13, 8, 8, 8,0x100D, aed,13 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed14, 8, 8, 8,0x100E, aed,14 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aed15, 8, 8, 8,0x100F, aed,15 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aep0, 1, 1, 1,0x1014, aep,0 , 8,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aep1, 1, 1, 1,0x1015, aep,1 , 8,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aep2, 1, 1, 1,0x1016, aep,2 , 8,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, aep3, 1, 1, 1,0x1017, aep,3 , 8,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, u0, 8, 8, 8,0x1010, u,0 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, u1, 8, 8, 8,0x1011, u,1 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, u2, 8, 8, 8,0x1012, u,2 , 64,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, u3, 8, 8, 8,0x1013, u,3 , 64,0,0,0) + +#define XCHAL_CP2_SA_NUM 0 +#define XCHAL_CP2_SA_LIST(s) /* empty */ + +#define XCHAL_CP3_SA_NUM 0 +#define XCHAL_CP3_SA_LIST(s) /* empty */ + +#define XCHAL_CP4_SA_NUM 0 +#define XCHAL_CP4_SA_LIST(s) /* empty */ + +#define XCHAL_CP5_SA_NUM 0 +#define XCHAL_CP5_SA_LIST(s) /* empty */ + +#define XCHAL_CP6_SA_NUM 0 +#define XCHAL_CP6_SA_LIST(s) /* empty */ + +#define XCHAL_CP7_SA_NUM 0 +#define XCHAL_CP7_SA_LIST(s) /* empty */ + +/* Byte length of instruction from its first nibble (op0 field), per FLIX. */ +/* (not available, must use XCHAL_BYTE0_FORMAT_LENGTHS for this processor) */ +/* Byte length of instruction from its first byte, per FLIX. */ +#define XCHAL_BYTE0_FORMAT_LENGTHS \ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11,\ + 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,6,11 + +#endif /*_XTENSA_CORE_TIE_H*/ + diff --git a/src/platform/mt8365/include/platform/drivers/idc.h b/src/platform/mt8365/include/platform/drivers/idc.h new file mode 100644 index 000000000000..b638b9ec987e --- /dev/null +++ b/src/platform/mt8365/include/platform/drivers/idc.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#if defined(__XTOS_RTOS_IDC_H__) || defined(__ZEPHYR_RTOS_IDC_H__) + +#ifndef __PLATFORM_DRIVERS_IDC_H__ +#define __PLATFORM_DRIVERS_IDC_H__ + +#include <stdint.h> + +struct idc_msg; + +static inline int idc_send_msg(struct idc_msg *msg, uint32_t mode) +{ + return 0; +} + +static inline int idc_init(void) +{ + return 0; +} + +#endif /* __PLATFORM_DRIVERS_IDC_H__ */ + +#else + +#error "This file shouldn't be included from outside of Zephyr/XTOS's rtos/idc.h" + +#endif diff --git a/src/platform/mt8365/include/platform/drivers/interrupt.h b/src/platform/mt8365/include/platform/drivers/interrupt.h new file mode 100644 index 000000000000..c40b68ab1f42 --- /dev/null +++ b/src/platform/mt8365/include/platform/drivers/interrupt.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifdef __SOF_DRIVERS_INTERRUPT_H__ + +#ifndef __PLATFORM_DRIVERS_INTERRUPT_H__ +#define __PLATFORM_DRIVERS_INTERRUPT_H__ + +#include <stdint.h> +#include <platform/drivers/mt_reg_base.h> + +#define PLATFORM_IRQ_HW_NUM XCHAL_NUM_INTERRUPTS +#define PLATFORM_IRQ_FIRST_CHILD PLATFORM_IRQ_HW_NUM +#define PLATFORM_IRQ_CHILDREN (LX_MCU_IRQ_B - LX_CQDMA_IRQ0_B + 1) + +#define IRQ_EXT_MASK 0x3F0 + +/* interrupt table */ +#define MTK_DSP_EXT_IRQ0 0 +#define L1_INT_IRQ_B 1 // (INT_LEVEL(1) | IRQ_INVALID) +#define L1_DSP_TIMER_IRQ0_B 2 // (INT_LEVEL(2) | INTERRUPT_ID(0)) +#define L1_DSP_TIMER_IRQ1_B 3 // (INT_LEVEL(3) | INTERRUPT_ID(1)) +#define L1_DSP_TIMER_IRQ2_B 4 // (INT_LEVEL(4) | INTERRUPT_ID(2)) +#define L1_DSP_TIMER_IRQ3_B 5 // (INT_LEVEL(5) | INTERRUPT_ID(3)) +#define MTK_DSP_EXT_IRQ6 6 +#define MTK_DSP_EXT_IRQ7 7 +#define MTK_DSP_EXT_IRQ8 8 +#define MTK_DSP_EXT_IRQ9 9 +#define MTK_DSP_EXT_IRQ10 10 +#define MTK_DSP_EXT_IRQ11 11 +#define MTK_DSP_EXT_IRQ12 12 +#define MTK_DSP_EXT_IRQ13 13 +#define MTK_DSP_EXT_IRQ14 14 +#define MTK_DSP_EXT_IRQ15 15 +/* HiFi internal interrupts */ +#define MTK_DSP_IRQ_TIMER0 16 +#define MTK_DSP_IRQ_TIMER1 17 +#define MTK_DSP_IRQ_TIMER2 18 +#define MTK_DSP_IRQ_WRITE_ERROR 19 +#define MTK_DSP_IRQ_PROFILING 20 +#define MTK_DSP_IRQ_SOFTWARE0 21 +#define MTK_DSP_IRQ_SOFTWARE1 22 +/* HiFi external interrupts */ +#define MTK_DSP_EXT_INT23 23 +#define MTK_DSP_EXT_INT24 24 + +/* group 1 cascaded IRQ trigger L1_INT_IRQ_B */ +#define IRQ_EXT_GROUP1_BASE L1_INT_IRQ_B +#define LX_CQDMA_IRQ0_B 25 // (INT_LEVEL(1) | INTERRUPT_ID(4)) +#define LX_CQDMA_IRQ1_B 26 // (INT_LEVEL(1) | INTERRUPT_ID(5)) +#define LX_CQDMA_IRQ2_B 27 // (INT_LEVEL(1) | INTERRUPT_ID(6)) +#define LX_UART_IRQ_B 28 // (INT_LEVEL(1) | INTERRUPT_ID(7)) +#define LX_AFE_IRQ_B 29 // (INT_LEVEL(1) | INTERRUPT_ID(8)) +#define LX_MCU_IRQ_B 30 // (INT_LEVEL(1) | INTERRUPT_ID(9)) + +int mtk_irq_group_id(uint32_t irq); + +/* L1_DSP_TIMER_IRQ0_B corresponds to bit# 0 of RG_DSP_IRQ_EN */ +#define IRQ_EXT_BIT_OFFSET (-2) + +/* base_irq = 25; (LX_CQDMA_IRQ0_B - base_irq) corresponds to bit# 4 of RG_DSP_IRQ_EN */ +#define IRQ_EXT_GROUP1_BIT_OFFSET (4) + +#define RG_DSP_IRQ_EN DSP_RG_INT_EN_CTL0 +#define RG_DSP_IRQ_STATUS DSP_RG_INT_STATUS0 + +#endif /* __PLATFORM_DRIVERS_INTERRUPT_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/drivers/interrupt.h" + +#endif /* __SOF_DRIVERS_INTERRUPT_H__ */ diff --git a/src/platform/mt8365/include/platform/drivers/mt_reg_base.h b/src/platform/mt8365/include/platform/drivers/mt_reg_base.h new file mode 100644 index 000000000000..289ab7d256d6 --- /dev/null +++ b/src/platform/mt8365/include/platform/drivers/mt_reg_base.h @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifndef MT_REG_BASE_H +#define MT_REG_BASE_H + +#define DSP_REG_BASE (0x1D062000) /* DSPCFG base */ +#define DSP_TIMER_BASE (0x1D060000) +#define DSP_UART0_BASE (0x1D061000) +#define DSP_WDT_BASE (0x1D062400) +#define DSP_IRQ_BASE (0x1D063000) +#define DSP_D_TCM (CFG_HIFI4_DTCM_ADDRESS) +#define DSP_I_TCM (CFG_HIFI4_ITCM_ADDRESS) +#define DSP_DRAM_BASE (CFG_HIFI4_DRAM_ADDRESS) + +#define DSP_AUDIO_SRAM_BASE (0x11221000) +#define DSP_AUDIO_SRAM_SIZE (0xA000) +#define DSP_REG_REMAP_BASE (0x1D060000) +#define DSP_REG_REMAP_SIZE (0x8000) +#define DSP_SYS_REG_BASE (0x10000000) +#define DSP_SYS_REG_SIZE (0x1221000) +#define DSP_VER_REG_BASE (0x08000000) +#define DSP_VER_REG_SIZE (0x1000) + + +#define DSP_JTAGMUX (DSP_REG_BASE + 0x0000) +#define DSP_ALTRESETVEC (DSP_REG_BASE + 0x0004) +#define DSP_PDEBUGDATA (DSP_REG_BASE + 0x0008) +#define DSP_PDEBUGBUS0 (DSP_REG_BASE + 0x000c) +#define DSP_PDEBUGBUS1 (DSP_REG_BASE + 0x0010) +#define DSP_PDEBUGINST (DSP_REG_BASE + 0x0014) +#define DSP_PDEBUGLS0STAT (DSP_REG_BASE + 0x0018) +#define DSP_PDEBUGLS1STAT (DSP_REG_BASE + 0x001c) +#define DSP_PDEBUGPC (DSP_REG_BASE + 0x0020) +#define DSP_RESET_SW (DSP_REG_BASE + 0x0024) +#define DSP_PFAULTBUS (DSP_REG_BASE + 0x0028) +#define DSP_PFAULTINFO (DSP_REG_BASE + 0x002c) +#define DSP_GPR00 (DSP_REG_BASE + 0x0030) +#define DSP_GPR01 (DSP_REG_BASE + 0x0034) +#define DSP_GPR02 (DSP_REG_BASE + 0x0038) +#define DSP_GPR03 (DSP_REG_BASE + 0x003c) +#define DSP_GPR04 (DSP_REG_BASE + 0x0040) +#define DSP_GPR05 (DSP_REG_BASE + 0x0044) +#define DSP_GPR06 (DSP_REG_BASE + 0x0048) +#define DSP_GPR07 (DSP_REG_BASE + 0x004c) +#define DSP_GPR08 (DSP_REG_BASE + 0x0050) +#define DSP_GPR09 (DSP_REG_BASE + 0x0054) +#define DSP_GPR0A (DSP_REG_BASE + 0x0058) +#define DSP_GPR0B (DSP_REG_BASE + 0x005c) +#define DSP_GPR0C (DSP_REG_BASE + 0x0060) +#define DSP_GPR0D (DSP_REG_BASE + 0x0064) +#define DSP_GPR0E (DSP_REG_BASE + 0x0068) +#define DSP_GPR0F (DSP_REG_BASE + 0x006c) +#define DSP_GPR10 (DSP_REG_BASE + 0x0070) +#define DSP_GPR11 (DSP_REG_BASE + 0x0074) +#define DSP_GPR12 (DSP_REG_BASE + 0x0078) +#define DSP_GPR13 (DSP_REG_BASE + 0x007c) +#define DSP_GPR14 (DSP_REG_BASE + 0x0080) +#define DSP_GPR15 (DSP_REG_BASE + 0x0084) +#define DSP_GPR16 (DSP_REG_BASE + 0x0088) +#define DSP_GPR17 (DSP_REG_BASE + 0x008c) +#define DSP_GPR18 (DSP_REG_BASE + 0x0090) +#define DSP_GPR19 (DSP_REG_BASE + 0x0094) +#define DSP_GPR1A (DSP_REG_BASE + 0x0098) +#define DSP_GPR1B (DSP_REG_BASE + 0x009c) +#define DSP_GPR1C (DSP_REG_BASE + 0x00a0) +#define DSP_GPR1D (DSP_REG_BASE + 0x00a4) +#define DSP_GPR1E (DSP_REG_BASE + 0x00a8) +#define DSP_GPR1F (DSP_REG_BASE + 0x00ac) +#define DSP_TCM_OFFSET (DSP_REG_BASE + 0x00b0) /* not used */ +#define DSP_DDR_OFFSET (DSP_REG_BASE + 0x00b4) /* not used */ +#define DSP_INTFDSP (DSP_REG_BASE + 0x00d0) +#define DSP_INTFDSP_CLR (DSP_REG_BASE + 0x00d4) +#define DSP_SRAM_PD_SW1 (DSP_REG_BASE + 0x00d8) +#define DSP_SRAM_PD_SW2 (DSP_REG_BASE + 0x00dc) +#define DSP_OCD (DSP_REG_BASE + 0x00e0) +#define DSP_RG_DSP_IRQ_POL (DSP_REG_BASE + 0x00f0) /* not used */ +#define DSP_DSP_IRQ_EN (DSP_REG_BASE + 0x00f4) /* not used */ +#define DSP_DSP_IRQ_LEVEL (DSP_REG_BASE + 0x00f8) /* not used */ +#define DSP_DSP_IRQ_STATUS (DSP_REG_BASE + 0x00fc) /* not used */ +#define DSP_RG_INT2CIRQ (DSP_REG_BASE + 0x0114) +#define DSP_RG_INT_POL_CTL0 (DSP_REG_BASE + 0x0120) +#define DSP_RG_INT_EN_CTL0 (DSP_REG_BASE + 0x0130) +#define DSP_RG_INT_LV_CTL0 (DSP_REG_BASE + 0x0140) +#define DSP_RG_INT_STATUS0 (DSP_REG_BASE + 0x0150) +#define DSP_PDEBUGSTATUS0 (DSP_REG_BASE + 0x0200) +#define DSP_PDEBUGSTATUS1 (DSP_REG_BASE + 0x0204) +#define DSP_PDEBUGSTATUS2 (DSP_REG_BASE + 0x0208) +#define DSP_PDEBUGSTATUS3 (DSP_REG_BASE + 0x020c) +#define DSP_PDEBUGSTATUS4 (DSP_REG_BASE + 0x0210) +#define DSP_PDEBUGSTATUS5 (DSP_REG_BASE + 0x0214) +#define DSP_PDEBUGSTATUS6 (DSP_REG_BASE + 0x0218) +#define DSP_PDEBUGSTATUS7 (DSP_REG_BASE + 0x021c) +#define DSP_DSP2PSRAM_PRIORITY (DSP_REG_BASE + 0x0220) /* not used */ +#define DSP_AUDIO_DSP2SPM_INT (DSP_REG_BASE + 0x0224) +#define DSP_AUDIO_DSP2SPM_INT_ACK (DSP_REG_BASE + 0x0228) +#define DSP_AUDIO_DSP_DEBUG_SEL (DSP_REG_BASE + 0x022C) +#define DSP_AUDIO_DSP_EMI_BASE_ADDR (DSP_REG_BASE + 0x02E0) /* not used */ +#define DSP_AUDIO_DSP_SHARED_IRAM (DSP_REG_BASE + 0x02E4) +#define DSP_AUDIO_DSP_CKCTRL_P2P_CK_CON (DSP_REG_BASE + 0x02F0) +#define DSP_RG_SEMAPHORE00 (DSP_REG_BASE + 0x0300) +#define DSP_RG_SEMAPHORE01 (DSP_REG_BASE + 0x0304) +#define DSP_RG_SEMAPHORE02 (DSP_REG_BASE + 0x0308) +#define DSP_RG_SEMAPHORE03 (DSP_REG_BASE + 0x030C) +#define DSP_RG_SEMAPHORE04 (DSP_REG_BASE + 0x0310) +#define DSP_RG_SEMAPHORE05 (DSP_REG_BASE + 0x0314) +#define DSP_RG_SEMAPHORE06 (DSP_REG_BASE + 0x0318) +#define DSP_RG_SEMAPHORE07 (DSP_REG_BASE + 0x031C) +#define DSP_RESERVED_0 (DSP_REG_BASE + 0x03F0) +#define DSP_RESERVED_1 (DSP_REG_BASE + 0x03F4) /* use for tickless status */ + +/* Redefinition for using Special registers */ +#define TICKLESS_STATUS_REG (DSP_RESERVED_1) + +/* WDT CONFIGS */ +#define ADSP_WDT_MODE (DSP_REG_BASE + 0x400 + 0x00) +#define ADSP_WDT_LENGTH (DSP_REG_BASE + 0x400 + 0x04) +#define ADSP_WDT_RESTART (DSP_REG_BASE + 0x400 + 0x08) +#define ADSP_WDT_STA (DSP_REG_BASE + 0x400 + 0x0C) +#define ADSP_WDT_SWRST (DSP_REG_BASE + 0x400 + 0x14) + +#define ADSP_WDT_SWRST_KEY 0x1209 +#define ADSP_WDT_RESTART_RELOAD 0x1971 +#define ADSP_WDT_LENGTH_KEY 0x8 + +#define WDT_LENGTH_TIMEOUT(n) ((n) << 5) + +/* DSP IPI IRQ */ +#define CPU2DSP_IRQ BIT(0) +#define DSP2CPU_IRQ BIT(1) +#define DSP2SPM_IRQ_B BIT(2) + +#endif /* MT_REG_BASE_H */ + diff --git a/src/platform/mt8365/include/platform/drivers/timer.h b/src/platform/mt8365/include/platform/drivers/timer.h new file mode 100644 index 000000000000..8d389d5da4e0 --- /dev/null +++ b/src/platform/mt8365/include/platform/drivers/timer.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifndef __PLATFORM_DRIVERS_TIMER_H__ +#define __PLATFORM_DRIVERS_TIMER_H__ + +#include <rtos/bit.h> +#include <platform/drivers/mt_reg_base.h> + + +/*-------timer:ostimer0-------*/ +enum ostimer { + OSTIMER0 = 0, + OSTIMER1, + OSTIMER2, + OSTIMER3, + NR_TMRS +}; + +#define TIMER_CON(n) (DSP_TIMER_BASE + 0x40 + 0x8 * (n)) +#define TIMER_CNT_VAL(n) (DSP_TIMER_BASE + 0x44 + 0x8 * (n)) + +#define TIMER_ENABLE_BIT (0x1 << 0) +#define TIMER_IRQ_ENABLE (0x1 << 1) +#define TIMER_IRQ_STA (0x1 << 4) +#define TIMER_IRQ_CLEAR (0x1 << 4) + +/** + * system timer register map + */ +#define CNTCR (DSP_TIMER_BASE + 0x00) +#define CNTSR (DSP_TIMER_BASE + 0x04) +#define CNTCV_L (DSP_TIMER_BASE + 0x08) +#define CNTCV_H (DSP_TIMER_BASE + 0x0c) +#define CNTWACR (DSP_TIMER_BASE + 0x10) +#define CNTRACR (DSP_TIMER_BASE + 0x14) +#define CNTACR_LOCK (DSP_TIMER_BASE + 0x18) +#define CNTFID0 (DSP_TIMER_BASE + 0x20) +#define CNTFID1 (DSP_TIMER_BASE + 0x24) +#define CNTFID2 (DSP_TIMER_BASE + 0x28) +#define CNTFIDE (DSP_TIMER_BASE + 0x2c) + +#define CNT_EN_BIT BIT(0) +#define CLKSRC_BIT (BIT(8) | BIT(9)) +#define CLKSRC_13M_BIT BIT(8) +#define COMP_BIT (BIT(10) | BIT(11) | BIT(12)) +#define COMP_20_25_EN_BIT (BIT(11) | BIT(12)) + +#define CNT_EN (0x1 << 0) +#define CNTTVAL_EN (0x1 << 0) +#define CNTIRQ_EN (0x1 << 1) +#define CNTIRQ_STACLR (0x1 << 4) +#define CNTMODE_REPEAT (0x1 << 8) + + +#define DELAY_TIMER_1US_TICK (13U) // (13MHz) +#define DELAY_TIMER_1MS_TICK (13000U) // (13MHz) +#define TIME_TO_TICK_US(us) ((us)*DELAY_TIMER_1US_TICK) +#define TIME_TO_TICK_MS(ms) ((ms)*DELAY_TIMER_1MS_TICK) + +#define SYSTICK_TIMER_IRQ L1_DSP_TIMER_IRQ0_B + + +#endif /* __PLATFORM_DRIVERS_TIMER_H__ */ diff --git a/src/platform/mt8365/include/platform/lib/clk.h b/src/platform/mt8365/include/platform/lib/clk.h new file mode 100644 index 000000000000..beaa2f762bbe --- /dev/null +++ b/src/platform/mt8365/include/platform/lib/clk.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifdef __SOF_LIB_CLK_H__ + +#ifndef __PLATFORM_LIB_CLK_H__ +#define __PLATFORM_LIB_CLK_H__ + +#include <stdint.h> + +struct sof; + +#define CPU_DEFAULT_IDX 4 + +#define CLK_CPU(x) (x) +#define CLK_DEFAULT_CPU_HZ 600000000 +#define CLK_MAX_CPU_HZ 600000000 +#define CLK_SUSPEND_CPU_HZ 26000000 +#define NUM_CLOCKS 1 +#define NUM_CPU_FREQ 5 + +void platform_clock_init(struct sof *sof); + +#define REG_APMIXDSYS_BASE 0x1000C000 +#define REG_TOPCKGEN_BASE 0x10000000 + +#define DSPPLL_CON0 (REG_APMIXDSYS_BASE + 0x390) +#define DSPPLL_CON1 (REG_APMIXDSYS_BASE + 0x394) +#define DSPPLL_CON2 (REG_APMIXDSYS_BASE + 0x398) +#define DSPPLL_CON3 (REG_APMIXDSYS_BASE + 0x39C) + +#define ULPLL_CON0 (REG_APMIXDSYS_BASE + 0x3B0) +#define ULPLL_CON1 (REG_APMIXDSYS_BASE + 0x3B4) + +#define PLL_BASE_EN BIT(0) +#define PLL_PWR_ON BIT(0) +#define PLL_ISO_EN BIT(1) + +#define DSPPLL_312MHZ 0 +#define DSPPLL_400MHZ 1 +#define DSPPLL_600MHZ 2 + +#define CLK_MODE (REG_TOPCKGEN_BASE + 0x0) +#define CLK_CFG_UPDATE1 (REG_TOPCKGEN_BASE + 0x8) +#define CLK_CFG_8 (REG_TOPCKGEN_BASE + 0xC0) +#define CLK_CFG_8_SET (REG_TOPCKGEN_BASE + 0xC4) +#define CLK_CFG_8_CLR (REG_TOPCKGEN_BASE + 0xC8) + +#define CLK_SCP_CFG_1 (REG_TOPCKGEN_BASE + 0x204) + +#define CLK_DSP_SEL_26M 0 +#define CLK_DSP_SEL_26M_D_2 1 +#define CLK_DSP_SEL_DSPPLL 2 +#define CLK_DSP_SEL_DSPPLL_D_2 3 +#define CLK_DSP_SEL_DSPPLL_D_4 4 +#define CLK_DSP_SEL_DSPPLL_D_8 5 + +#define CLK_TOPCKGEN_SEL_PLLGP_26M 1 +#define CLK_TOPCKGEN_SEL_ULPLL_26M 2 +#define CLK_TOPCKGEN_SEL_GPIO_26M 4 + +enum mux_id_t { + MUX_CLK_DSP_SEL = 0, + MUX_CLK_TOPCKGEN_26M_SEL, + HIFI4DSP_MUX_NUM, +}; + +enum mux_26m_t { + DCXO_26 = 0, + ULPLL_26M, +}; + +enum DSP_HW_DSP_CLK { + DSP_CLK_13M = 0, + DSP_CLK_26M, + DSP_CLK_PLL_312M, + DSP_CLK_PLL_400M, + DSP_CLK_PLL_600M, +}; +#endif /* __PLATFORM_LIB_CLK_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/clk.h" + +#endif /* __SOF_LIB_CLK_H__ */ diff --git a/src/platform/mt8365/include/platform/lib/cpu.h b/src/platform/mt8365/include/platform/lib/cpu.h new file mode 100644 index 000000000000..1c72bd51b176 --- /dev/null +++ b/src/platform/mt8365/include/platform/lib/cpu.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifdef __SOF_LIB_CPU_H__ + +#ifndef __PLATFORM_LIB_CPU_H__ +#define __PLATFORM_LIB_CPU_H__ + +/** \brief Id of primary DSP core */ +#define PLATFORM_PRIMARY_CORE_ID 0 + +#endif /* __PLATFORM_LIB_CPU_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/cpu.h" + +#endif /* __SOF_LIB_CPU_H__ */ diff --git a/src/platform/mt8365/include/platform/lib/dai.h b/src/platform/mt8365/include/platform/lib/dai.h new file mode 100644 index 000000000000..98fe70955f2f --- /dev/null +++ b/src/platform/mt8365/include/platform/lib/dai.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifdef __SOF_LIB_DAI_H__ + +#ifndef __PLATFORM_LIB_DAI_H__ +#define __PLATFORM_LIB_DAI_H__ + +#endif /* __PLATFORM_LIB_DAI_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/dai.h" + +#endif /* __SOF_LIB_DAI_H__ */ diff --git a/src/platform/mt8365/include/platform/lib/dma.h b/src/platform/mt8365/include/platform/lib/dma.h new file mode 100644 index 000000000000..479591ab5daa --- /dev/null +++ b/src/platform/mt8365/include/platform/lib/dma.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifdef __SOF_LIB_DMA_H__ + +#ifndef __PLATFORM_LIB_DMA_H__ +#define __PLATFORM_LIB_DMA_H__ + +#define PLATFORM_NUM_DMACS 2 + +/* max number of supported DMA channels */ +#define PLATFORM_MAX_DMA_CHAN 32 + +#define DMA_ID_AFE_MEMIF 0 +#define DMA_ID_HOST 1 + +#define dma_chan_irq(dma, chan) dma_irq(dma) +#define dma_chan_irq_name(dma, chan) dma_irq_name(dma) + +#endif /* __PLATFORM_LIB_DMA_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/dma.h" + +#endif /* __SOF_LIB_DMA_H__ */ diff --git a/src/platform/mt8365/include/platform/lib/mailbox.h b/src/platform/mt8365/include/platform/lib/mailbox.h new file mode 100644 index 000000000000..27f48a72238c --- /dev/null +++ b/src/platform/mt8365/include/platform/lib/mailbox.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifdef __SOF_LIB_MAILBOX_H__ + +#ifndef __PLATFORM_LIB_MAILBOX_H__ +#define __PLATFORM_LIB_MAILBOX_H__ + +#include <sof/lib/memory.h> +#include <stddef.h> +#include <stdint.h> + +/* + * The Window Region on MT8365 SRAM is organised like this :- + * +--------------------------------------------------------------------------+ + * | Offset | Region | Size | + * +---------------------+----------------+-----------------------------------+ + * | SRAM_TRACE_BASE | Trace Buffer | SRAM_TRACE_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SRAM_DEBUG_BASE | Debug data | SRAM_DEBUG_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SRAM_INBOX_BASE | Inbox | SRAM_INBOX_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SRAM_OUTBOX_BASE | Outbox | SRAM_MAILBOX_SIZE | + * +---------------------+----------------+-----------------------------------+ + */ + +#define MAILBOX_DSPBOX_SIZE SRAM_OUTBOX_SIZE +#define MAILBOX_DSPBOX_BASE SRAM_OUTBOX_BASE +#define MAILBOX_DSPBOX_OFFSET SRAM_OUTBOX_OFFSET + +#define MAILBOX_HOSTBOX_SIZE SRAM_INBOX_SIZE +#define MAILBOX_HOSTBOX_BASE SRAM_INBOX_BASE +#define MAILBOX_HOSTBOX_OFFSET SRAM_INBOX_OFFSET + +#define MAILBOX_DEBUG_SIZE SRAM_DEBUG_SIZE +#define MAILBOX_DEBUG_BASE SRAM_DEBUG_BASE +#define MAILBOX_DEBUG_OFFSET SRAM_DEBUG_OFFSET + +#define MAILBOX_TRACE_SIZE SRAM_TRACE_SIZE +#define MAILBOX_TRACE_BASE SRAM_TRACE_BASE +#define MAILBOX_TRACE_OFFSET SRAM_TRACE_OFFSET + +#define MAILBOX_EXCEPTION_SIZE SRAM_EXCEPT_SIZE +#define MAILBOX_EXCEPTION_BASE SRAM_EXCEPT_BASE +#define MAILBOX_EXCEPTION_OFFSET SRAM_EXCEPT_OFFSET + +#define MAILBOX_STREAM_SIZE SRAM_STREAM_SIZE +#define MAILBOX_STREAM_BASE SRAM_STREAM_BASE +#define MAILBOX_STREAM_OFFSET SRAM_STREAM_OFFSET + +static inline void mailbox_sw_reg_write(size_t offset, uint32_t src) +{ + volatile uint32_t *ptr; + + ptr = (volatile uint32_t *)(MAILBOX_DEBUG_BASE + offset); + *ptr = src; +} + +static inline uint32_t mailbox_sw_reg_read(size_t offset) +{ + volatile uint32_t *ptr; + + ptr = (volatile uint32_t *)(MAILBOX_DEBUG_BASE + offset); + + return *ptr; +} + + #define ADSP_IPI_OP_REQ 0x1 + #define ADSP_IPI_OP_RSP 0x2 +void trigger_irq_to_host_req(void); +void trigger_irq_to_host_rsp(void); + +#endif /* __PLATFORM_LIB_MAILBOX_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/mailbox.h" + +#endif /* __SOF_LIB_MAILBOX_H__ */ diff --git a/src/platform/mt8365/include/platform/lib/memory.h b/src/platform/mt8365/include/platform/lib/memory.h new file mode 100644 index 000000000000..75965466ae95 --- /dev/null +++ b/src/platform/mt8365/include/platform/lib/memory.h @@ -0,0 +1,238 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifdef __SOF_LIB_MEMORY_H__ + +#ifndef __PLATFORM_LIB_MEMORY_H__ +#define __PLATFORM_LIB_MEMORY_H__ + +#include <rtos/cache.h> +#include <xtensa/config/core-isa.h> + +#define BOOT_WITH_DRAM /*Use DRAM as SRAM1 for heap related*/ +/* data cache line alignment */ +#define PLATFORM_DCACHE_ALIGN sizeof(void *) + +/* + * +-----------------------------------+-----------------------------+ + * | | AUDIO_DSP_SHARED_DRAM | + * +------------+----------------------+---------+---------+---------+ + * | DSP | Sys | Size | 00b | 01b *** | 11b | + * +------------+------------+---------+---------+---------+---------+ + * | 0x40000000 | 0x1e100000 | 0x8000 | iram0_0 | iram0_0 | iram0_0 | + * | 0x40008000 | 0x1e108000 | 0x8000 | iram0_1 | iram0_1 | --- | + * | 0x40010000 | 0x1e110000 | 0x8000 | iram1 | --- | --- | + * +------------+------------+---------+---------+---------+---------+ + * | 0x1e000000 | 0x1e000000 | 0x40000 | dram0 | dram0 | dram0 | + * | 0x1e040000 | 0x1e040000 | 0x20000 | dram1 | dram1 | dram1 | + * | 0x1e060000 | 0x1e060000 | 0x8000 | --- | iram1 | iram1 | + * | 0x1e068000 | 0x1e068000 | 0x8000 | --- | --- | iram0_1 | + * +------------+------------+---------+---------+---------+---------+ + */ + +/* BOOT_WITH_DRAM ONLY */ +/* physical DSP addresses */ +#define DRAM_BASE 0x60000000 +#define DRAM_AUDIO_SHARED_SIZE 0x280000 +#define DRAM_SIZE 0x1000000 /*DRAM Size : 16M , need to sync with Host side*/ + +#define SRAM_TOTAL_SIZE 0x40000 /*256KB DSP SRAM*/ +#define VECTOR_SIZE 0x628 + +#define SRAM0_BASE DRAM_BASE +#define SRAM0_SIZE (DRAM_SIZE >> 1) +#define SRAM1_BASE (DRAM_BASE + SRAM0_SIZE) +#define SRAM1_SIZE \ + (DRAM_SIZE - SRAM0_SIZE - DRAM_AUDIO_SHARED_SIZE - UUID_ENTRY_ELF_SIZE - \ + LOG_ENTRY_ELF_SIZE - EXT_MANIFEST_ELF_SIZE) + +#define DMA_SIZE 0x100000 + +#define UUID_ENTRY_ELF_SIZE 0x6000 +#define LOG_ENTRY_ELF_SIZE 0x200000 +#define EXT_MANIFEST_ELF_SIZE 0x100000 + +#define UUID_ENTRY_ELF_BASE (SRAM1_BASE + SRAM1_SIZE) +#define LOG_ENTRY_ELF_BASE (UUID_ENTRY_ELF_BASE + UUID_ENTRY_ELF_SIZE) +#define EXT_MANIFEST_ELF_BASE (LOG_ENTRY_ELF_BASE + LOG_ENTRY_ELF_SIZE) + +/* + * The Memory Layout on MT8365 are organised like this :- + * + * +--------------------------------------------------------------------------+ + * | Offset | Region | Size | + * +---------------------+----------------+-----------------------------------+ + * | XCHAL_RESET_VECTOR0 | DSP Vectors | VECTOR_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SRAM0_BASE | fw_ready | SRAM0_SIZE | + * | | RO Data | | + * | | module_init | | + * | | Text | | + * | | Data | | + * | | BSS | | + * +---------------------+----------------+-----------------------------------+ + * | SRAM1_BASE | MAILBOX | SOF_MAILBOX_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | HEAP_SYSTEM_BASE | System Heap | HEAP_SYSTEM_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | HEAP_RUNTIME_BASE | Runtime Heap | HEAP_RUNTIME_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | HEAP_BUFFER_BASE | Module Buffers | HEAP_BUFFER_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SOF_STACK_END | Stack | SOF_STACK_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SOF_STACK_BASE | | | + * +---------------------+----------------+-----------------------------------+ + */ + +/* Mailbox configuration */ +#define SRAM_OUTBOX_BASE SRAM1_BASE +#define SRAM_OUTBOX_SIZE 0x1000 +#define SRAM_OUTBOX_OFFSET 0 + +#define SRAM_INBOX_BASE (SRAM_OUTBOX_BASE + SRAM_OUTBOX_SIZE) +#define SRAM_INBOX_SIZE 0x1000 +#define SRAM_INBOX_OFFSET SRAM_OUTBOX_SIZE + +#define SRAM_DEBUG_BASE (SRAM_INBOX_BASE + SRAM_INBOX_SIZE) +#define SRAM_DEBUG_SIZE 0x800 +#define SRAM_DEBUG_OFFSET (SRAM_INBOX_OFFSET + SRAM_INBOX_SIZE) + +#define SRAM_EXCEPT_BASE (SRAM_DEBUG_BASE + SRAM_DEBUG_SIZE) +#define SRAM_EXCEPT_SIZE 0x800 +#define SRAM_EXCEPT_OFFSET (SRAM_DEBUG_OFFSET + SRAM_DEBUG_SIZE) + +#define SRAM_STREAM_BASE (SRAM_EXCEPT_BASE + SRAM_EXCEPT_SIZE) +#define SRAM_STREAM_SIZE 0x1000 +#define SRAM_STREAM_OFFSET (SRAM_EXCEPT_OFFSET + SRAM_EXCEPT_SIZE) + +#define SRAM_TRACE_BASE (SRAM_STREAM_BASE + SRAM_STREAM_SIZE) +#define SRAM_TRACE_SIZE 0x1000 +#define SRAM_TRACE_OFFSET (SRAM_STREAM_OFFSET + SRAM_STREAM_SIZE) + +/*4K + 4K +2K + 2K + 4K + 4K = 20KB*/ +#define SOF_MAILBOX_SIZE \ + (SRAM_INBOX_SIZE + SRAM_OUTBOX_SIZE + SRAM_DEBUG_SIZE + SRAM_EXCEPT_SIZE + \ + SRAM_STREAM_SIZE + SRAM_TRACE_SIZE) + +/* Heap section sizes for module pool */ +#define HEAP_RT_COUNT8 0 +#define HEAP_RT_COUNT16 48 +#define HEAP_RT_COUNT32 48 +#define HEAP_RT_COUNT64 32 +#define HEAP_RT_COUNT128 32 +#define HEAP_RT_COUNT256 32 +#define HEAP_RT_COUNT512 32 +#define HEAP_RT_COUNT1024 4 +#define HEAP_RT_COUNT2048 2 +#define HEAP_RT_COUNT4096 2 + +/* Heap section sizes for system runtime heap */ +#define HEAP_SYS_RT_COUNT64 128 +#define HEAP_SYS_RT_COUNT512 16 +#define HEAP_SYS_RT_COUNT1024 8 + +/* Heap configuration */ + +#define HEAP_SYSTEM_BASE (SRAM1_BASE + SOF_MAILBOX_SIZE) +#define HEAP_SYSTEM_SIZE 0x6000 + +#define HEAP_SYSTEM_0_BASE HEAP_SYSTEM_BASE + +#define HEAP_SYS_RUNTIME_BASE (HEAP_SYSTEM_BASE + HEAP_SYSTEM_SIZE) +/*24KB*/ +#define HEAP_SYS_RUNTIME_SIZE \ + (HEAP_SYS_RT_COUNT64 * 64 + HEAP_SYS_RT_COUNT512 * 512 + HEAP_SYS_RT_COUNT1024 * 1024) + +#define HEAP_RUNTIME_BASE (HEAP_SYS_RUNTIME_BASE + HEAP_SYS_RUNTIME_SIZE) +/*48*(16 +32) + 32*(64 128+256) + 4*(512+1024) + 1*2048 = 24832 = 24.25KB*/ +#define HEAP_RUNTIME_SIZE \ + (HEAP_RT_COUNT8 * 8 + HEAP_RT_COUNT16 * 16 + HEAP_RT_COUNT32 * 32 + HEAP_RT_COUNT64 * 64 + \ + HEAP_RT_COUNT128 * 128 + HEAP_RT_COUNT256 * 256 + HEAP_RT_COUNT512 * 512 + \ + HEAP_RT_COUNT1024 * 1024 + HEAP_RT_COUNT2048 * 2048 + HEAP_RT_COUNT4096 * 4096) + +#define HEAP_BUFFER_BASE (HEAP_RUNTIME_BASE + HEAP_RUNTIME_SIZE) +#define HEAP_BUFFER_SIZE \ + (SRAM1_SIZE - SOF_MAILBOX_SIZE - HEAP_RUNTIME_SIZE - SOF_STACK_TOTAL_SIZE - \ + HEAP_SYS_RUNTIME_SIZE - HEAP_SYSTEM_SIZE) + +#define HEAP_BUFFER_BLOCK_SIZE 0x100 +#define HEAP_BUFFER_COUNT (HEAP_BUFFER_SIZE / HEAP_BUFFER_BLOCK_SIZE) + +#define PLATFORM_HEAP_SYSTEM 1 /* one per core */ +#define PLATFORM_HEAP_SYSTEM_RUNTIME 1 /* one per core */ +#define PLATFORM_HEAP_RUNTIME 1 +#define PLATFORM_HEAP_BUFFER 1 + +/* Stack configuration */ +#define SOF_STACK_SIZE 0x8000 +#define SOF_STACK_TOTAL_SIZE SOF_STACK_SIZE /*4KB*/ +#define SOF_STACK_BASE (SRAM1_BASE + SRAM1_SIZE) +#define SOF_STACK_END (SOF_STACK_BASE - SOF_STACK_TOTAL_SIZE) + +/* Vector and literal sizes - not in core-isa.h */ +#define SOF_MEM_VECT_LIT_SIZE 0x4 +#define SOF_MEM_VECT_TEXT_SIZE 0x1c +#define SOF_MEM_VECT_SIZE (SOF_MEM_VECT_TEXT_SIZE + SOF_MEM_VECT_LIT_SIZE) + +#define SOF_MEM_RESET_TEXT_SIZE 0x2e0 +#define SOF_MEM_RESET_LIT_SIZE 0x120 +#define SOF_MEM_VECBASE_LIT_SIZE 0x178 + +#define SOF_MEM_RO_SIZE 0x8 + +#define HEAP_BUF_ALIGNMENT DCACHE_LINE_SIZE + +/** \brief EDF task's default stack size in bytes. */ +#ifdef CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING +#define PLATFORM_TASK_DEFAULT_STACK_SIZE (12 * 1024) +#else +#define PLATFORM_TASK_DEFAULT_STACK_SIZE 3072 +#endif + +#if !defined(__ASSEMBLER__) && !defined(LINKER) + +struct sof; + +/** + * \brief Data shared between different cores. + * Does nothing, since mt8195 doesn't support SMP. + */ +#define SHARED_DATA + +void platform_init_memmap(struct sof *sof); + +#define uncache_to_cache(address) address +#define cache_to_uncache(address) address +#define cache_to_uncache_init(address) address +#define is_uncached(address) 0 + +/** + * \brief Function for keeping shared data synchronized. + * It's used after usage of data shared by different cores. + * Such data is either statically marked with SHARED_DATA + * or dynamically allocated with SOF_MEM_FLAG_SHARED flag. + * Does nothing, since mt8195 doesn't support SMP. + */ + +static inline void *platform_rfree_prepare(void *ptr) +{ + return ptr; +} + +#endif + +#define host_to_local(addr) (addr) +#define local_to_host(addr) (addr) + +#endif /* __PLATFORM_LIB_MEMORY_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/memory.h" + +#endif /* __SOF_LIB_MEMORY_H__ */ diff --git a/src/platform/mt8365/include/platform/lib/pm_runtime.h b/src/platform/mt8365/include/platform/lib/pm_runtime.h new file mode 100644 index 000000000000..e93410938f30 --- /dev/null +++ b/src/platform/mt8365/include/platform/lib/pm_runtime.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifdef __SOF_LIB_PM_RUNTIME_H__ + +#ifndef __PLATFORM_LIB_PM_RUNTIME_H__ +#define __PLATFORM_LIB_PM_RUNTIME_H__ + +#include <stdint.h> + +struct pm_runtime_data; + +/** + * \brief Initializes platform specific runtime power management. + * \param[in,out] prd Runtime power management data. + */ +static inline void platform_pm_runtime_init(struct pm_runtime_data *prd) +{ +} + +/** + * \brief Retrieves platform specific power management resource. + * + * \param[in] context Type of power management context. + * \param[in] index Index of the device. + * \param[in] flags Flags, set of RPM_... + */ +static inline void platform_pm_runtime_get(uint32_t context, uint32_t index, uint32_t flags) +{ +} + +/** + * \brief Releases platform specific power management resource. + * + * \param[in] context Type of power management context. + * \param[in] index Index of the device. + * \param[in] flags Flags, set of RPM_... + */ +static inline void platform_pm_runtime_put(uint32_t context, uint32_t index, uint32_t flags) +{ +} + +static inline void platform_pm_runtime_enable(uint32_t context, uint32_t index) +{ +} + +static inline void platform_pm_runtime_disable(uint32_t context, uint32_t index) +{ +} + +static inline bool platform_pm_runtime_is_active(uint32_t context, uint32_t index) +{ + return false; +} + +#endif /* __PLATFORM_LIB_PM_RUNTIME_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/pm_runtime.h" + +#endif /* __SOF_LIB_PM_RUNTIME_H__ */ diff --git a/src/platform/mt8365/include/platform/mt8365-afe-common.h b/src/platform/mt8365/include/platform/mt8365-afe-common.h new file mode 100644 index 000000000000..f597f6980da2 --- /dev/null +++ b/src/platform/mt8365/include/platform/mt8365-afe-common.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifndef _MT_8365_AFE_COMMON_H_ +#define _MT_8365_AFE_COMMON_H_ + +/* AFE: the abbreviation for Audio Front End */ + +enum { + MT8365_MEMIF_START, + MT8365_MEMIF_DL_START = MT8365_MEMIF_START, + MT8365_MEMIF_DL1 = MT8365_MEMIF_DL_START, + MT8365_MEMIF_DL2, + MT8365_MEMIF_TDM_OUT, + MT8365_MEMIF_DL_END, + MT8365_MEMIF_UL_START = MT8365_MEMIF_DL_END, + MT8365_MEMIF_AWB = MT8365_MEMIF_UL_START, + MT8365_MEMIF_VUL, + MT8365_MEMIF_VUL2, + MT8365_MEMIF_VUL3, + MT8365_MEMIF_TDM_IN, + MT8365_MEMIF_UL_END, + MT8365_MEMIF_END = MT8365_MEMIF_UL_END, + MT8365_MEMIF_DL_NUM = (MT8365_MEMIF_DL_END - MT8365_MEMIF_DL_START), + MT8365_MEMIF_UL_NUM = (MT8365_MEMIF_UL_END - MT8365_MEMIF_UL_START), + MT8365_MEMIF_NUM = (MT8365_MEMIF_END - MT8365_MEMIF_START), +}; + +enum { + MT8365_AFE_IRQ_1, + MT8365_AFE_IRQ_2, + MT8365_AFE_IRQ_3, + MT8365_AFE_IRQ_4, + MT8365_AFE_IRQ_5, + MT8365_AFE_IRQ_6, + MT8365_AFE_IRQ_7, + MT8365_AFE_IRQ_8, + MT8365_AFE_IRQ_9, + MT8365_AFE_IRQ_10, + MT8365_AFE_IRQ_NUM, +}; + +enum { + MT8365_AFE_IO_INT_ADDA_OUT, + MT8365_AFE_IO_2ND_I2S, + MT8365_AFE_IO_INT_ADDA_IN, + MT8365_AFE_IO_DMIC, + MT8365_DAI_NUM, +}; + +#endif /* _MT_8365_AFE_COMMON_H_ */ diff --git a/src/platform/mt8365/include/platform/mt8365-afe-regs.h b/src/platform/mt8365/include/platform/mt8365-afe-regs.h new file mode 100644 index 000000000000..8bd7163434dc --- /dev/null +++ b/src/platform/mt8365/include/platform/mt8365-afe-regs.h @@ -0,0 +1,1207 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifndef _MT8365_AFE_REGS_H_ +#define _MT8365_AFE_REGS_H_ + +#define AFE_REG_BASE 0x11220000 +#define AFE_REG_SIZE 0x1000 +#define AFE_SRAM_BASE 0x11221000 +#define AFE_SRAM_SIZE 0xA000 + +/***************************************************************************** + * R E G I S T E R D E F I N I T I O N + *****************************************************************************/ +#define AUDIO_TOP_CON0 (0x0000) +#define AUDIO_TOP_CON1 (0x0004) +#define AUDIO_TOP_CON2 (0x0008) +#define AUDIO_TOP_CON3 (0x000c) + +#define AFE_DAC_CON0 (0x0010) +#define AFE_DAC_CON1 (0x0014) +#define AFE_I2S_CON (0x0018) +#define AFE_CONN0 (0x0020) +#define AFE_CONN1 (0x0024) +#define AFE_CONN2 (0x0028) +#define AFE_CONN3 (0x002c) +#define AFE_CONN4 (0x0030) +#define AFE_I2S_CON1 (0x0034) +#define AFE_I2S_CON2 (0x0038) +#define AFE_MRGIF_CON (0x003c) +#define AFE_DL1_BASE (0x0040) +#define AFE_DL1_CUR (0x0044) +#define AFE_DL1_END (0x0048) +#define AFE_I2S_CON3 (0x004c) +#define AFE_DL2_BASE (0x0050) +#define AFE_DL2_CUR (0x0054) +#define AFE_DL2_END (0x0058) +#define AFE_CONN5 (0x005c) +#define AFE_AWB_BASE (0x0070) +#define AFE_AWB_END (0x0078) +#define AFE_AWB_CUR (0x007c) +#define AFE_VUL_BASE (0x0080) +#define AFE_VUL_END (0x0088) +#define AFE_VUL_CUR (0x008c) +#define AFE_CONN6 (0x00bc) +#define AFE_MEMIF_MSB (0x00cc) +#define AFE_MEMIF_MON0 (0x00d0) +#define AFE_MEMIF_MON1 (0x00d4) +#define AFE_MEMIF_MON2 (0x00d8) +#define AFE_MEMIF_MON3 (0x00dc) +#define AFE_MEMIF_MON4 (0x00e0) +#define AFE_MEMIF_MON5 (0x00e4) +#define AFE_MEMIF_MON6 (0x00e8) +#define AFE_MEMIF_MON7 (0x00ec) +#define AFE_MEMIF_MON8 (0x00f0) +#define AFE_MEMIF_MON9 (0x00f4) +#define AFE_MEMIF_MON10 (0x00f8) +#define AFE_MEMIF_MON11 (0x00fc) +#define AFE_ADDA_DL_SRC2_CON0 (0x0108) +#define AFE_ADDA_DL_SRC2_CON1 (0x010c) +#define AFE_ADDA_UL_SRC_CON0 (0x0114) +#define AFE_ADDA_UL_SRC_CON1 (0x0118) +#define AFE_ADDA_TOP_CON0 (0x0120) +#define AFE_ADDA_UL_DL_CON0 (0x0124) +#define AFE_ADDA_SRC_DEBUG (0x012c) +#define AFE_ADDA_SRC_DEBUG_MON0 (0x0130) +#define AFE_ADDA_SRC_DEBUG_MON1 (0x0134) +#define AFE_ADDA_UL_SRC_MON0 (0x0148) +#define AFE_ADDA_UL_SRC_MON1 (0x014c) +#define AFE_SRAM_BOUND (0x0170) +#define AFE_SECURE_CON (0x0174) +#define AFE_SECURE_CONN0 (0x0178) +#define AFE_SIDETONE_DEBUG (0x01d0) +#define AFE_SIDETONE_MON (0x01d4) +#define AFE_SIDETONE_CON0 (0x01e0) +#define AFE_SIDETONE_COEFF (0x01e4) +#define AFE_SIDETONE_CON1 (0x01e8) +#define AFE_SIDETONE_GAIN (0x01ec) +#define AFE_SGEN_CON0 (0x01f0) +#define AFE_SINEGEN_CON_TDM (0x01f8) +#define AFE_SINEGEN_CON_TDM_IN (0x01fc) +#define AFE_TOP_CON0 (0x0200) +#define AFE_BUS_CFG (0x0240) +#define AFE_BUS_MON0 (0x0244) +#define AFE_ADDA_PREDIS_CON0 (0x0260) +#define AFE_ADDA_PREDIS_CON1 (0x0264) +#define AFE_CONN_MON0 (0x0280) +#define AFE_CONN_MON1 (0x0284) +#define AFE_CONN_MON2 (0x0288) +#define AFE_CONN_MON3 (0x028c) +#define AFE_ADDA_IIR_COEF_02_01 (0x0290) +#define AFE_ADDA_IIR_COEF_04_03 (0x0294) +#define AFE_ADDA_IIR_COEF_06_05 (0x0298) +#define AFE_ADDA_IIR_COEF_08_07 (0x029c) +#define AFE_ADDA_IIR_COEF_10_09 (0x02a0) +#define AFE_VUL_D2_BASE (0x0350) +#define AFE_VUL_D2_END (0x0358) +#define AFE_VUL_D2_CUR (0x035c) +#define AFE_HDMI_OUT_CON0 (0x0370) +#define AFE_HDMI_OUT_BASE (0x0374) +#define AFE_HDMI_OUT_CUR (0x0378) +#define AFE_HDMI_OUT_END (0x037c) +#define AFE_SPDIF_OUT_CON0 (0x0380) +#define AFE_SPDIF_OUT_BASE (0x0384) +#define AFE_SPDIF_OUT_CUR (0x0388) +#define AFE_SPDIF_OUT_END (0x038c) +#define AFE_HDMI_CONN0 (0x0390) +#define AFE_HDMI_CONN1 (0x0398) +#define AFE_CONN_TDMIN_CON (0x039c) +#define AFE_IRQ_MCU_CON (0x03a0) +#define AFE_IRQ_MCU_STATUS (0x03a4) +#define AFE_IRQ_MCU_CLR (0x03a8) +#define AFE_IRQ_MCU_CNT1 (0x03ac) +#define AFE_IRQ_MCU_CNT2 (0x03b0) +#define AFE_IRQ_MCU_EN (0x03b4) +#define AFE_IRQ_MCU_MON2 (0x03b8) +#define AFE_IRQ_MCU_CNT5 (0x03bc) +#define AFE_IRQ1_MCU_CNT_MON (0x03c0) +#define AFE_IRQ2_MCU_CNT_MON (0x03c4) +#define AFE_IRQ1_MCU_EN_CNT_MON (0x03c8) +#define AFE_IRQ5_MCU_CNT_MON (0x03cc) +#define AFE_MEMIF_MINLEN (0x03d0) +#define AFE_MEMIF_MAXLEN (0x03d4) +#define AFE_MEMIF_PBUF_SIZE (0x03d8) +#define AFE_IRQ_MCU_CNT7 (0x03dc) +#define AFE_IRQ7_MCU_CNT_MON (0x03e0) +#define AFE_MEMIF_PBUF2_SIZE (0x03ec) +#define AFE_APLL_TUNER_CFG (0x03f0) +#define AFE_APLL_TUNER_CFG1 (0x03f4) +#define AFE_IRQ_MCU_CON2 (0x03f8) +#define IRQ13_MCU_CNT (0x0408) +#define IRQ13_MCU_CNT_MON (0x040c) +#define AFE_GAIN1_CON0 (0x0410) +#define AFE_GAIN1_CON1 (0x0414) +#define AFE_GAIN1_CON2 (0x0418) +#define AFE_GAIN1_CON3 (0x041c) +#define AFE_GAIN2_CON0 (0x0428) +#define AFE_GAIN2_CON1 (0x042c) +#define AFE_GAIN2_CON2 (0x0430) +#define AFE_GAIN2_CON3 (0x0434) +#define AFE_GAIN2_CUR (0x043c) +#define AFE_CONN11 (0x0448) +#define AFE_CONN12 (0x044c) +#define AFE_CONN13 (0x0450) +#define AFE_CONN14 (0x0454) +#define AFE_CONN15 (0x0458) +#define AFE_CONN16 (0x045c) +#define AFE_CONN7 (0x0460) +#define AFE_CONN8 (0x0464) +#define AFE_CONN9 (0x0468) +#define AFE_CONN10 (0x046c) +#define AFE_CONN21 (0x0470) +#define AFE_CONN22 (0x0474) +#define AFE_CONN23 (0x0478) +#define AFE_CONN24 (0x047c) +#define AFE_IEC_CFG (0x0480) +#define AFE_IEC_NSNUM (0x0484) +#define AFE_IEC_BURST_INFO (0x0488) +#define AFE_IEC_BURST_LEN (0x048c) +#define AFE_IEC_NSADR (0x0490) +#define AFE_CONN_RS (0x0494) +#define AFE_CONN_DI (0x0498) +#define AFE_IEC_CHL_STAT0 (0x04a0) +#define AFE_IEC_CHL_STAT1 (0x04a4) +#define AFE_IEC_CHR_STAT0 (0x04a8) +#define AFE_IEC_CHR_STAT1 (0x04ac) +#define AFE_CONN25 (0x04b0) +#define AFE_CONN26 (0x04b4) +#define FPGA_CFG2 (0x04b8) +#define FPGA_CFG3 (0x04bc) +#define FPGA_CFG0 (0x04c0) +#define FPGA_CFG1 (0x04c4) +#define AFE_SRAM_DELSEL_CON0 (0x04f0) +#define AFE_SRAM_DELSEL_CON1 (0x04f4) +#define AFE_SRAM_DELSEL_CON2 (0x04f8) +#define FPGA_CFG4 (0x04fc) +#define AFE_TDM_GASRC4_ASRC_2CH_CON0 (0x0500) +#define AFE_TDM_GASRC4_ASRC_2CH_CON1 (0x0504) +#define AFE_TDM_GASRC4_ASRC_2CH_CON2 (0x0508) +#define AFE_TDM_GASRC4_ASRC_2CH_CON3 (0x050c) +#define AFE_TDM_GASRC4_ASRC_2CH_CON4 (0x0510) +#define AFE_TDM_GASRC4_ASRC_2CH_CON5 (0x0514) +#define AFE_TDM_GASRC4_ASRC_2CH_CON6 (0x0518) +#define AFE_TDM_GASRC4_ASRC_2CH_CON7 (0x051c) +#define AFE_TDM_GASRC4_ASRC_2CH_CON8 (0x0520) +#define AFE_TDM_GASRC4_ASRC_2CH_CON9 (0x0524) +#define AFE_TDM_GASRC4_ASRC_2CH_CON10 (0x0528) +#define AFE_TDM_GASRC4_ASRC_2CH_CON12 (0x0530) +#define AFE_TDM_GASRC4_ASRC_2CH_CON13 (0x0534) +#define PCM_INTF_CON2 (0x0538) +#define PCM2_INTF_CON (0x053c) +#define AFE_APB_MON (0x0540) +#define AFE_CONN34 (0x0544) +#define AFE_TDM_CON1 (0x0548) +#define AFE_TDM_CON2 (0x054c) +#define PCM_INTF_CON1 (0x0550) +#define AFE_SECURE_MASK_CONN47_1 (0x0554) +#define AFE_SECURE_MASK_CONN48_1 (0x0558) +#define AFE_SECURE_MASK_CONN49_1 (0x055c) +#define AFE_SECURE_MASK_CONN50_1 (0x0560) +#define AFE_SECURE_MASK_CONN51_1 (0x0564) +#define AFE_SECURE_MASK_CONN52_1 (0x0568) +#define AFE_SECURE_MASK_CONN53_1 (0x056c) +#define AFE_SE_SECURE_CON (0x0570) +#define AFE_TDM_IN_CON1 (0x0588) +#define AFE_TDM_IN_CON2 (0x058c) +#define AFE_TDM_IN_MON1 (0x0590) +#define AFE_TDM_IN_MON2 (0x0594) +#define AFE_TDM_IN_MON3 (0x0598) +#define AFE_DMIC0_UL_SRC_CON0 (0x05b4) +#define AFE_DMIC0_UL_SRC_CON1 (0x05b8) +#define AFE_DMIC0_SRC_DEBUG (0x05bc) +#define AFE_DMIC0_SRC_DEBUG_MON0 (0x05c0) +#define AFE_DMIC0_UL_SRC_MON0 (0x05c8) +#define AFE_DMIC0_UL_SRC_MON1 (0x05cc) +#define AFE_DMIC0_IIR_COEF_02_01 (0x05d0) +#define AFE_DMIC0_IIR_COEF_04_03 (0x05d4) +#define AFE_DMIC0_IIR_COEF_06_05 (0x05d8) +#define AFE_DMIC0_IIR_COEF_08_07 (0x05dc) +#define AFE_DMIC0_IIR_COEF_10_09 (0x05e0) +#define AFE_DMIC1_UL_SRC_CON0 (0x0620) +#define AFE_DMIC1_UL_SRC_CON1 (0x0624) +#define AFE_DMIC1_SRC_DEBUG (0x0628) +#define AFE_DMIC1_SRC_DEBUG_MON0 (0x062c) +#define AFE_DMIC1_UL_SRC_MON0 (0x0634) +#define AFE_DMIC1_UL_SRC_MON1 (0x0638) +#define AFE_DMIC1_IIR_COEF_02_01 (0x063c) +#define AFE_DMIC1_IIR_COEF_04_03 (0x0640) +#define AFE_DMIC1_IIR_COEF_06_05 (0x0644) +#define AFE_DMIC1_IIR_COEF_08_07 (0x0648) +#define AFE_DMIC1_IIR_COEF_10_09 (0x064c) +#define AFE_SECURE_MASK_CONN39_1 (0x068c) +#define AFE_SECURE_MASK_CONN40_1 (0x0690) +#define AFE_SECURE_MASK_CONN41_1 (0x0694) +#define AFE_SECURE_MASK_CONN42_1 (0x0698) +#define AFE_SECURE_MASK_CONN43_1 (0x069c) +#define AFE_SECURE_MASK_CONN44_1 (0x06a0) +#define AFE_SECURE_MASK_CONN45_1 (0x06a4) +#define AFE_SECURE_MASK_CONN46_1 (0x06a8) +#define AFE_TDM_GASRC1_ASRC_2CH_CON0 (0x06c0) +#define AFE_TDM_GASRC1_ASRC_2CH_CON1 (0x06c4) +#define AFE_TDM_GASRC1_ASRC_2CH_CON2 (0x06c8) +#define AFE_TDM_GASRC1_ASRC_2CH_CON3 (0x06cc) +#define AFE_TDM_GASRC1_ASRC_2CH_CON4 (0x06d0) +#define AFE_TDM_GASRC1_ASRC_2CH_CON5 (0x06d4) +#define AFE_TDM_GASRC1_ASRC_2CH_CON6 (0x06d8) +#define AFE_TDM_GASRC1_ASRC_2CH_CON7 (0x06dc) +#define AFE_TDM_GASRC1_ASRC_2CH_CON8 (0x06e0) +#define AFE_TDM_GASRC1_ASRC_2CH_CON9 (0x06e4) +#define AFE_TDM_GASRC1_ASRC_2CH_CON10 (0x06e8) +#define AFE_TDM_GASRC1_ASRC_2CH_CON12 (0x06f0) +#define AFE_TDM_GASRC1_ASRC_2CH_CON13 (0x06f4) +#define AFE_TDM_ASRC_CON0 (0x06f8) +#define AFE_TDM_GASRC2_ASRC_2CH_CON0 (0x0700) +#define AFE_TDM_GASRC2_ASRC_2CH_CON1 (0x0704) +#define AFE_TDM_GASRC2_ASRC_2CH_CON2 (0x0708) +#define AFE_TDM_GASRC2_ASRC_2CH_CON3 (0x070c) +#define AFE_TDM_GASRC2_ASRC_2CH_CON4 (0x0710) +#define AFE_TDM_GASRC2_ASRC_2CH_CON5 (0x0714) +#define AFE_TDM_GASRC2_ASRC_2CH_CON6 (0x0718) +#define AFE_TDM_GASRC2_ASRC_2CH_CON7 (0x071c) +#define AFE_TDM_GASRC2_ASRC_2CH_CON8 (0x0720) +#define AFE_TDM_GASRC2_ASRC_2CH_CON9 (0x0724) +#define AFE_TDM_GASRC2_ASRC_2CH_CON10 (0x0728) +#define AFE_TDM_GASRC2_ASRC_2CH_CON12 (0x0730) +#define AFE_TDM_GASRC2_ASRC_2CH_CON13 (0x0734) +#define AFE_TDM_GASRC3_ASRC_2CH_CON0 (0x0740) +#define AFE_TDM_GASRC3_ASRC_2CH_CON1 (0x0744) +#define AFE_TDM_GASRC3_ASRC_2CH_CON2 (0x0748) +#define AFE_TDM_GASRC3_ASRC_2CH_CON3 (0x074c) +#define AFE_TDM_GASRC3_ASRC_2CH_CON4 (0x0750) +#define AFE_TDM_GASRC3_ASRC_2CH_CON5 (0x0754) +#define AFE_TDM_GASRC3_ASRC_2CH_CON6 (0x0758) +#define AFE_TDM_GASRC3_ASRC_2CH_CON7 (0x075c) +#define AFE_TDM_GASRC3_ASRC_2CH_CON8 (0x0760) +#define AFE_TDM_GASRC3_ASRC_2CH_CON9 (0x0764) +#define AFE_TDM_GASRC3_ASRC_2CH_CON10 (0x0768) +#define AFE_TDM_GASRC3_ASRC_2CH_CON12 (0x0770) +#define AFE_TDM_GASRC3_ASRC_2CH_CON13 (0x0774) +#define AFE_DMIC2_UL_SRC_CON0 (0x0780) +#define AFE_DMIC2_UL_SRC_CON1 (0x0784) +#define AFE_DMIC2_SRC_DEBUG (0x0788) +#define AFE_DMIC2_SRC_DEBUG_MON0 (0x078c) +#define AFE_DMIC2_UL_SRC_MON0 (0x0794) +#define AFE_DMIC2_UL_SRC_MON1 (0x0798) +#define AFE_DMIC2_IIR_COEF_02_01 (0x079c) +#define AFE_DMIC2_IIR_COEF_04_03 (0x07a0) +#define AFE_DMIC2_IIR_COEF_06_05 (0x07a4) +#define AFE_DMIC2_IIR_COEF_08_07 (0x07a8) +#define AFE_DMIC2_IIR_COEF_10_09 (0x07ac) +#define AFE_DMIC3_UL_SRC_CON0 (0x07ec) +#define AFE_DMIC3_UL_SRC_CON1 (0x07f0) +#define AFE_DMIC3_SRC_DEBUG (0x07f4) +#define AFE_DMIC3_SRC_DEBUG_MON0 (0x07f8) +#define AFE_DMIC3_UL_SRC_MON0 (0x0800) +#define AFE_DMIC3_UL_SRC_MON1 (0x0804) +#define AFE_DMIC3_IIR_COEF_02_01 (0x0808) +#define AFE_DMIC3_IIR_COEF_04_03 (0x080c) +#define AFE_DMIC3_IIR_COEF_06_05 (0x0810) +#define AFE_DMIC3_IIR_COEF_08_07 (0x0814) +#define AFE_DMIC3_IIR_COEF_10_09 (0x0818) +#define AFE_SECURE_MASK_CONN25_1 (0x0858) +#define AFE_SECURE_MASK_CONN26_1 (0x085c) +#define AFE_SECURE_MASK_CONN27_1 (0x0860) +#define AFE_SECURE_MASK_CONN28_1 (0x0864) +#define AFE_SECURE_MASK_CONN29_1 (0x0868) +#define AFE_SECURE_MASK_CONN30_1 (0x086c) +#define AFE_SECURE_MASK_CONN31_1 (0x0870) +#define AFE_SECURE_MASK_CONN32_1 (0x0874) +#define AFE_SECURE_MASK_CONN33_1 (0x0878) +#define AFE_SECURE_MASK_CONN34_1 (0x087c) +#define AFE_SECURE_MASK_CONN35_1 (0x0880) +#define AFE_SECURE_MASK_CONN36_1 (0x0884) +#define AFE_SECURE_MASK_CONN37_1 (0x0888) +#define AFE_SECURE_MASK_CONN38_1 (0x088c) +#define AFE_IRQ_MCU_SCP_EN (0x0890) +#define AFE_IRQ_MCU_DSP_EN (0x0894) +#define AFE_IRQ3_MCU_CNT_MON (0x0898) +#define AFE_IRQ4_MCU_CNT_MON (0x089c) +#define AFE_IRQ8_MCU_CNT_MON (0x08a0) +#define AFE_IRQ_MCU_CNT3 (0x08a4) +#define AFE_IRQ_MCU_CNT4 (0x08a8) +#define AFE_IRQ_MCU_CNT8 (0x08ac) +#define AFE_IRQ_MCU_CNT11 (0x08b0) +#define AFE_IRQ_MCU_CNT12 (0x08b4) +#define AFE_IRQ11_MCU_CNT_MON (0x08b8) +#define AFE_IRQ12_MCU_CNT_MON (0x08bc) +#define AFE_VUL3_BASE (0x08c0) +#define AFE_VUL3_CUR (0x08c4) +#define AFE_VUL3_END (0x08c8) +#define AFE_VUL3_BASE_MSB (0x08d0) +#define AFE_VUL3_END_MSB (0x08d4) +#define AFE_IRQ10_MCU_CNT_MON (0x08d8) +#define AFE_IRQ_MCU_CNT10 (0x08dc) +#define AFE_IRQ_ACC1_CNT (0x08e0) +#define AFE_IRQ_ACC2_CNT (0x08e4) +#define AFE_IRQ_ACC1_CNT_MON1 (0x08e8) +#define AFE_IRQ_ACC2_CNT_MON (0x08ec) +#define AFE_TSF_CON (0x08f0) +#define AFE_TSF_MON (0x08f4) +#define AFE_IRQ_ACC1_CNT_MON2 (0x08f8) +#define AFE_SPDIFIN_CFG0 (0x0900) +#define AFE_SPDIFIN_CFG1 (0x0904) +#define AFE_SPDIFIN_CHSTS1 (0x0908) +#define AFE_SPDIFIN_CHSTS2 (0x090c) +#define AFE_SPDIFIN_CHSTS3 (0x0910) +#define AFE_SPDIFIN_CHSTS4 (0x0914) +#define AFE_SPDIFIN_CHSTS5 (0x0918) +#define AFE_SPDIFIN_CHSTS6 (0x091c) +#define AFE_SPDIFIN_DEBUG1 (0x0920) +#define AFE_SPDIFIN_DEBUG2 (0x0924) +#define AFE_SPDIFIN_DEBUG3 (0x0928) +#define AFE_SPDIFIN_DEBUG4 (0x092c) +#define AFE_SPDIFIN_EC (0x0930) +#define AFE_SPDIFIN_CKLOCK_CFG (0x0934) +#define AFE_SPDIFIN_BR (0x093c) +#define AFE_SPDIFIN_BR_DBG1 (0x0940) +#define AFE_SPDIFIN_INT_EXT (0x0948) +#define AFE_SPDIFIN_INT_EXT2 (0x094c) +#define SPDIFIN_FREQ_INFO (0x0950) +#define SPDIFIN_FREQ_INFO_2 (0x0954) +#define SPDIFIN_FREQ_INFO_3 (0x0958) +#define SPDIFIN_FREQ_STATUS (0x095c) +#define SPDIFIN_USERCODE1 (0x0960) +#define SPDIFIN_USERCODE2 (0x0964) +#define SPDIFIN_USERCODE3 (0x0968) +#define SPDIFIN_USERCODE4 (0x096c) +#define SPDIFIN_USERCODE5 (0x0970) +#define SPDIFIN_USERCODE6 (0x0974) +#define SPDIFIN_USERCODE7 (0x0978) +#define SPDIFIN_USERCODE8 (0x097c) +#define SPDIFIN_USERCODE9 (0x0980) +#define SPDIFIN_USERCODE10 (0x0984) +#define SPDIFIN_USERCODE11 (0x0988) +#define SPDIFIN_USERCODE12 (0x098c) +#define SPDIFIN_MEMIF_CON0 (0x0990) +#define SPDIFIN_BASE_ADR (0x0994) +#define SPDIFIN_END_ADR (0x0998) +#define SPDIFIN_APLL_TUNER_CFG (0x09a0) +#define SPDIFIN_APLL_TUNER_CFG1 (0x09a4) +#define SPDIFIN_APLL2_TUNER_CFG (0x09a8) +#define SPDIFIN_APLL2_TUNER_CFG1 (0x09ac) +#define SPDIFIN_TYPE_DET (0x09b0) +#define MPHONE_MULTI_CON0 (0x09b4) +#define SPDIFIN_CUR_ADR (0x09b8) +#define AFE_SINEGEN_CON_SPDIFIN (0x09bc) +#define AFE_HDMI_IN_2CH_CON0 (0x09c0) +#define AFE_HDMI_IN_2CH_BASE (0x09c4) +#define AFE_HDMI_IN_2CH_END (0x09c8) +#define AFE_HDMI_IN_2CH_CUR (0x09cc) +#define AFE_MEMIF_BUF_MON0 (0x09d0) +#define AFE_MEMIF_BUF_MON1 (0x09d4) +#define AFE_MEMIF_BUF_MON2 (0x09d8) +#define AFE_MEMIF_BUF_MON3 (0x09dc) +#define AFE_MEMIF_BUF_MON6 (0x09e8) +#define AFE_MEMIF_BUF_MON7 (0x09ec) +#define AFE_MEMIF_BUF_MON8 (0x09f0) +#define AFE_MEMIF_BUF_MON10 (0x09f8) +#define AFE_MEMIF_BUF_MON11 (0x09fc) +#define SYSTOP_STC_CONFIG (0x0a00) +#define AUDIO_STC_STATUS (0x0a04) +#define SYSTOP_W_STC_H (0x0a08) +#define SYSTOP_W_STC_L (0x0a0c) +#define SYSTOP_R_STC_H (0x0a10) +#define SYSTOP_R_STC_L (0x0a14) +#define AUDIO_W_STC_H (0x0a18) +#define AUDIO_W_STC_L (0x0a1c) +#define AUDIO_R_STC_H (0x0a20) +#define AUDIO_R_STC_L (0x0a24) +#define SYSTOP_W_STC2_H (0x0a28) +#define SYSTOP_W_STC2_L (0x0a2c) +#define SYSTOP_R_STC2_H (0x0a30) +#define SYSTOP_R_STC2_L (0x0a34) +#define AUDIO_W_STC2_H (0x0a38) +#define AUDIO_W_STC2_L (0x0a3c) +#define AUDIO_R_STC2_H (0x0a40) +#define AUDIO_R_STC2_L (0x0a44) + +#define AFE_CONN17 (0x0a48) +#define AFE_CONN18 (0x0a4c) +#define AFE_CONN19 (0x0a50) +#define AFE_CONN20 (0x0a54) +#define AFE_CONN27 (0x0a58) +#define AFE_CONN28 (0x0a5c) +#define AFE_CONN29 (0x0a60) +#define AFE_CONN30 (0x0a64) +#define AFE_CONN31 (0x0a68) +#define AFE_CONN32 (0x0a6c) +#define AFE_CONN33 (0x0a70) +#define AFE_CONN35 (0x0a74) +#define AFE_CONN36 (0x0a78) +#define AFE_CONN37 (0x0a7c) +#define AFE_CONN38 (0x0a80) +#define AFE_CONN39 (0x0a84) +#define AFE_CONN40 (0x0a88) +#define AFE_CONN41 (0x0a8c) +#define AFE_CONN42 (0x0a90) +#define AFE_CONN44 (0x0a94) +#define AFE_CONN45 (0x0a98) +#define AFE_CONN46 (0x0a9c) +#define AFE_CONN47 (0x0aa0) +#define AFE_CONN_24BIT (0x0aa4) +#define AFE_CONN0_1 (0x0aa8) +#define AFE_CONN1_1 (0x0aac) +#define AFE_CONN2_1 (0x0ab0) +#define AFE_CONN3_1 (0x0ab4) +#define AFE_CONN4_1 (0x0ab8) +#define AFE_CONN5_1 (0x0abc) +#define AFE_CONN6_1 (0x0ac0) +#define AFE_CONN7_1 (0x0ac4) +#define AFE_CONN8_1 (0x0ac8) +#define AFE_CONN9_1 (0x0acc) +#define AFE_CONN10_1 (0x0ad0) +#define AFE_CONN11_1 (0x0ad4) +#define AFE_CONN12_1 (0x0ad8) +#define AFE_CONN13_1 (0x0adc) +#define AFE_CONN14_1 (0x0ae0) +#define AFE_CONN15_1 (0x0ae4) +#define AFE_CONN16_1 (0x0ae8) +#define AFE_CONN17_1 (0x0aec) +#define AFE_CONN18_1 (0x0af0) +#define AFE_CONN19_1 (0x0af4) +#define AFE_CONN43 (0x0af8) +#define AFE_CONN43_1 (0x0afc) +#define AFE_CONN21_1 (0x0b00) +#define AFE_CONN22_1 (0x0b04) +#define AFE_CONN23_1 (0x0b08) +#define AFE_CONN24_1 (0x0b0c) +#define AFE_CONN25_1 (0x0b10) +#define AFE_CONN26_1 (0x0b14) +#define AFE_CONN27_1 (0x0b18) +#define AFE_CONN28_1 (0x0b1c) +#define AFE_CONN29_1 (0x0b20) +#define AFE_CONN30_1 (0x0b24) +#define AFE_CONN31_1 (0x0b28) +#define AFE_CONN32_1 (0x0b2c) +#define AFE_CONN33_1 (0x0b30) +#define AFE_CONN34_1 (0x0b34) +#define AFE_CONN35_1 (0x0b38) +#define AFE_CONN36_1 (0x0b3c) +#define AFE_CONN37_1 (0x0b40) +#define AFE_CONN38_1 (0x0b44) +#define AFE_CONN39_1 (0x0b48) +#define AFE_CONN40_1 (0x0b4c) +#define AFE_CONN41_1 (0x0b50) +#define AFE_CONN42_1 (0x0b54) +#define AFE_CONN44_1 (0x0b58) +#define AFE_CONN45_1 (0x0b5c) +#define AFE_CONN46_1 (0x0b60) +#define AFE_CONN47_1 (0x0b64) +#define AFE_CONN_RS_1 (0x0b68) +#define AFE_CONN_DI_1 (0x0b6c) +#define AFE_CONN_24BIT_1 (0x0b70) +#define AFE_GAIN1_CUR (0x0b78) +#define AFE_CONN20_1 (0x0b7c) +#define AFE_DL1_BASE_MSB (0x0b80) +#define AFE_DL1_END_MSB (0x0b84) +#define AFE_DL2_BASE_MSB (0x0b88) +#define AFE_DL2_END_MSB (0x0b8c) +#define AFE_AWB_BASE_MSB (0x0b90) +#define AFE_AWB_END_MSB (0x0b94) +#define AFE_VUL_BASE_MSB (0x0ba0) +#define AFE_VUL_END_MSB (0x0ba4) +#define AFE_VUL_D2_BASE_MSB (0x0ba8) +#define AFE_VUL_D2_END_MSB (0x0bac) +#define AFE_HDMI_OUT_BASE_MSB (0x0bb8) +#define AFE_HDMI_OUT_END_MSB (0x0bbc) +#define AFE_HDMI_IN_2CH_BASE_MSB (0x0bc0) +#define AFE_HDMI_IN_2CH_END_MSB (0x0bc4) +#define AFE_SPDIF_OUT_BASE_MSB (0x0bc8) +#define AFE_SPDIF_OUT_END_MSB (0x0bcc) +#define SPDIFIN_BASE_MSB (0x0bd0) +#define SPDIFIN_END_MSB (0x0bd4) +#define AFE_DL1_CUR_MSB (0x0bd8) +#define AFE_DL2_CUR_MSB (0x0bdc) +#define AFE_AWB_CUR_MSB (0x0be8) +#define AFE_VUL_CUR_MSB (0x0bf8) +#define AFE_VUL_D2_CUR_MSB (0x0c04) +#define AFE_HDMI_OUT_CUR_MSB (0x0c0c) +#define AFE_HDMI_IN_2CH_CUR_MSB (0x0c10) +#define AFE_SPDIF_OUT_CUR_MSB (0x0c14) +#define SPDIFIN_CUR_MSB (0x0c18) +#define AFE_CONN_REG (0x0c20) +#define AFE_SECURE_MASK_CONN14_1 (0x0c24) +#define AFE_SECURE_MASK_CONN15_1 (0x0c28) +#define AFE_SECURE_MASK_CONN16_1 (0x0c2c) +#define AFE_SECURE_MASK_CONN17_1 (0x0c30) +#define AFE_SECURE_MASK_CONN18_1 (0x0c34) +#define AFE_SECURE_MASK_CONN19_1 (0x0c38) +#define AFE_SECURE_MASK_CONN20_1 (0x0c3c) +#define AFE_SECURE_MASK_CONN21_1 (0x0c40) +#define AFE_SECURE_MASK_CONN22_1 (0x0c44) +#define AFE_SECURE_MASK_CONN23_1 (0x0c48) +#define AFE_SECURE_MASK_CONN24_1 (0x0c4c) +#define AFE_ADDA_DL_SDM_DCCOMP_CON (0x0c50) +#define AFE_ADDA_DL_SDM_TEST (0x0c54) +#define AFE_ADDA_DL_DC_COMP_CFG0 (0x0c58) +#define AFE_ADDA_DL_DC_COMP_CFG1 (0x0c5c) +#define AFE_ADDA_DL_SDM_FIFO_MON (0x0c60) +#define AFE_ADDA_DL_SRC_LCH_MON (0x0c64) +#define AFE_ADDA_DL_SRC_RCH_MON (0x0c68) +#define AFE_ADDA_DL_SDM_OUT_MON (0x0c6c) +#define AFE_ADDA_DL_SDM_DITHER_CON (0x0c70) + +#define AFE_VUL3_CUR_MSB (0x0c78) +#define AFE_ASRC_2CH_CON0 (0x0c80) +#define AFE_ASRC_2CH_CON1 (0x0c84) +#define AFE_ASRC_2CH_CON2 (0x0c88) +#define AFE_ASRC_2CH_CON3 (0x0c8c) +#define AFE_ASRC_2CH_CON4 (0x0c90) +#define AFE_ASRC_2CH_CON5 (0x0c94) +#define AFE_ASRC_2CH_CON6 (0x0c98) +#define AFE_ASRC_2CH_CON7 (0x0c9c) +#define AFE_ASRC_2CH_CON8 (0x0ca0) +#define AFE_ASRC_2CH_CON9 (0x0ca4) +#define AFE_ASRC_2CH_CON10 (0x0ca8) +#define AFE_ASRC_2CH_CON12 (0x0cb0) +#define AFE_ASRC_2CH_CON13 (0x0cb4) + +#define AFE_PCM_TX_ASRC_2CH_CON0 (0x0cc0) +#define AFE_PCM_TX_ASRC_2CH_CON1 (0x0cc4) +#define AFE_PCM_TX_ASRC_2CH_CON2 (0x0cc8) +#define AFE_PCM_TX_ASRC_2CH_CON3 (0x0ccc) +#define AFE_PCM_TX_ASRC_2CH_CON4 (0x0cd0) +#define AFE_PCM_TX_ASRC_2CH_CON5 (0x0cd4) +#define AFE_PCM_TX_ASRC_2CH_CON6 (0x0cd8) +#define AFE_PCM_TX_ASRC_2CH_CON7 (0x0cdc) +#define AFE_PCM_TX_ASRC_2CH_CON8 (0x0ce0) +#define AFE_PCM_TX_ASRC_2CH_CON9 (0x0ce4) +#define AFE_PCM_TX_ASRC_2CH_CON10 (0x0ce8) +#define AFE_PCM_TX_ASRC_2CH_CON12 (0x0cf0) +#define AFE_PCM_TX_ASRC_2CH_CON13 (0x0cf4) +#define AFE_PCM_RX_ASRC_2CH_CON0 (0x0d00) +#define AFE_PCM_RX_ASRC_2CH_CON1 (0x0d04) +#define AFE_PCM_RX_ASRC_2CH_CON2 (0x0d08) +#define AFE_PCM_RX_ASRC_2CH_CON3 (0x0d0c) +#define AFE_PCM_RX_ASRC_2CH_CON4 (0x0d10) +#define AFE_PCM_RX_ASRC_2CH_CON5 (0x0d14) +#define AFE_PCM_RX_ASRC_2CH_CON6 (0x0d18) +#define AFE_PCM_RX_ASRC_2CH_CON7 (0x0d1c) +#define AFE_PCM_RX_ASRC_2CH_CON8 (0x0d20) +#define AFE_PCM_RX_ASRC_2CH_CON9 (0x0d24) +#define AFE_PCM_RX_ASRC_2CH_CON10 (0x0d28) +#define AFE_PCM_RX_ASRC_2CH_CON12 (0x0d30) +#define AFE_PCM_RX_ASRC_2CH_CON13 (0x0d34) + +#define AFE_ADDA_PREDIS_CON2 (0x0d40) +#define AFE_ADDA_PREDIS_CON3 (0x0d44) +#define AFE_SECURE_MASK_CONN4_1 (0x0d48) +#define AFE_SECURE_MASK_CONN5_1 (0x0d4c) +#define AFE_SECURE_MASK_CONN6_1 (0x0d50) +#define AFE_SECURE_MASK_CONN7_1 (0x0d54) +#define AFE_SECURE_MASK_CONN8_1 (0x0d58) +#define AFE_SECURE_MASK_CONN9_1 (0x0d5c) +#define AFE_SECURE_MASK_CONN10_1 (0x0d60) +#define AFE_SECURE_MASK_CONN11_1 (0x0d64) +#define AFE_SECURE_MASK_CONN12_1 (0x0d68) +#define AFE_SECURE_MASK_CONN13_1 (0x0d6c) +#define AFE_MEMIF_MON12 (0x0d70) +#define AFE_MEMIF_MON13 (0x0d74) +#define AFE_MEMIF_MON14 (0x0d78) +#define AFE_MEMIF_MON15 (0x0d7c) +#define AFE_SECURE_MASK_CONN42 (0x0dbc) +#define AFE_SECURE_MASK_CONN43 (0x0dc0) +#define AFE_SECURE_MASK_CONN44 (0x0dc4) +#define AFE_SECURE_MASK_CONN45 (0x0dc8) +#define AFE_SECURE_MASK_CONN46 (0x0dcc) +#define AFE_HD_ENGEN_ENABLE (0x0dd0) +#define AFE_SECURE_MASK_CONN47 (0x0dd4) +#define AFE_SECURE_MASK_CONN48 (0x0dd8) +#define AFE_SECURE_MASK_CONN49 (0x0ddc) +#define AFE_SECURE_MASK_CONN50 (0x0de0) +#define AFE_SECURE_MASK_CONN51 (0x0de4) +#define AFE_SECURE_MASK_CONN52 (0x0de8) +#define AFE_SECURE_MASK_CONN53 (0x0dec) +#define AFE_SECURE_MASK_CONN0_1 (0x0df0) +#define AFE_SECURE_MASK_CONN1_1 (0x0df4) +#define AFE_SECURE_MASK_CONN2_1 (0x0df8) +#define AFE_SECURE_MASK_CONN3_1 (0x0dfc) + +#define AFE_ADDA_MTKAIF_CFG0 (0x0e00) +#define AFE_ADDA_MTKAIF_SYNCWORD_CFG (0x0e14) +#define AFE_ADDA_MTKAIF_RX_CFG0 (0x0e20) +#define AFE_ADDA_MTKAIF_RX_CFG1 (0x0e24) +#define AFE_ADDA_MTKAIF_RX_CFG2 (0x0e28) +#define AFE_ADDA_MTKAIF_MON0 (0x0e34) +#define AFE_ADDA_MTKAIF_MON1 (0x0e38) +#define AFE_AUD_PAD_TOP (0x0e40) + +#define AFE_CM1_CON4 (0x0e48) +#define AFE_CM2_CON4 (0x0e4c) +#define AFE_CM1_CON0 (0x0e50) +#define AFE_CM1_CON1 (0x0e54) +#define AFE_CM1_CON2 (0x0e58) +#define AFE_CM1_CON3 (0x0e5c) +#define AFE_CM2_CON0 (0x0e60) +#define AFE_CM2_CON1 (0x0e64) +#define AFE_CM2_CON2 (0x0e68) +#define AFE_CM2_CON3 (0x0e6c) +#define AFE_CM2_CONN0 (0x0e70) +#define AFE_CM2_CONN1 (0x0e74) +#define AFE_CM2_CONN2 (0x0e78) + +#define AFE_GENERAL1_ASRC_2CH_CON0 (0x0e80) +#define AFE_GENERAL1_ASRC_2CH_CON1 (0x0e84) +#define AFE_GENERAL1_ASRC_2CH_CON2 (0x0e88) +#define AFE_GENERAL1_ASRC_2CH_CON3 (0x0e8c) +#define AFE_GENERAL1_ASRC_2CH_CON4 (0x0e90) +#define AFE_GENERAL1_ASRC_2CH_CON5 (0x0e94) +#define AFE_GENERAL1_ASRC_2CH_CON6 (0x0e98) +#define AFE_GENERAL1_ASRC_2CH_CON7 (0x0e9c) +#define AFE_GENERAL1_ASRC_2CH_CON8 (0x0ea0) +#define AFE_GENERAL1_ASRC_2CH_CON9 (0x0ea4) +#define AFE_GENERAL1_ASRC_2CH_CON10 (0x0ea8) +#define AFE_GENERAL1_ASRC_2CH_CON12 (0x0eb0) +#define AFE_GENERAL1_ASRC_2CH_CON13 (0x0eb4) +#define GENERAL_ASRC_MODE (0x0eb8) +#define GENERAL_ASRC_EN_ON (0x0ebc) + +#define AFE_CONN48 (0x0ec0) +#define AFE_CONN49 (0x0ec4) +#define AFE_CONN50 (0x0ec8) +#define AFE_CONN51 (0x0ecc) +#define AFE_CONN52 (0x0ed0) +#define AFE_CONN53 (0x0ed4) +#define AFE_CONN48_1 (0x0ee0) +#define AFE_CONN49_1 (0x0ee4) +#define AFE_CONN50_1 (0x0ee8) +#define AFE_CONN51_1 (0x0eec) +#define AFE_CONN52_1 (0x0ef0) +#define AFE_CONN53_1 (0x0ef4) + +#define AFE_GENERAL2_ASRC_2CH_CON0 (0x0f00) +#define AFE_GENERAL2_ASRC_2CH_CON1 (0x0f04) +#define AFE_GENERAL2_ASRC_2CH_CON2 (0x0f08) +#define AFE_GENERAL2_ASRC_2CH_CON3 (0x0f0c) +#define AFE_GENERAL2_ASRC_2CH_CON4 (0x0f10) +#define AFE_GENERAL2_ASRC_2CH_CON5 (0x0f14) +#define AFE_GENERAL2_ASRC_2CH_CON6 (0x0f18) +#define AFE_GENERAL2_ASRC_2CH_CON7 (0x0f1c) +#define AFE_GENERAL2_ASRC_2CH_CON8 (0x0f20) +#define AFE_GENERAL2_ASRC_2CH_CON9 (0x0f24) +#define AFE_GENERAL2_ASRC_2CH_CON10 (0x0f28) +#define AFE_GENERAL2_ASRC_2CH_CON12 (0x0f30) +#define AFE_GENERAL2_ASRC_2CH_CON13 (0x0f34) + +#define AFE_SECURE_MASK_CONN28 (0x0f48) +#define AFE_SECURE_MASK_CONN29 (0x0f4c) +#define AFE_SECURE_MASK_CONN30 (0x0f50) +#define AFE_SECURE_MASK_CONN31 (0x0f54) +#define AFE_SECURE_MASK_CONN32 (0x0f58) +#define AFE_SECURE_MASK_CONN33 (0x0f5c) +#define AFE_SECURE_MASK_CONN34 (0x0f60) +#define AFE_SECURE_MASK_CONN35 (0x0f64) +#define AFE_SECURE_MASK_CONN36 (0x0f68) +#define AFE_SECURE_MASK_CONN37 (0x0f6c) +#define AFE_SECURE_MASK_CONN38 (0x0f70) +#define AFE_SECURE_MASK_CONN39 (0x0f74) +#define AFE_SECURE_MASK_CONN40 (0x0f78) +#define AFE_SECURE_MASK_CONN41 (0x0f7c) +#define AFE_SIDEBAND0 (0x0f80) +#define AFE_SIDEBAND1 (0x0f84) +#define AFE_SECURE_SIDEBAND0 (0x0f88) +#define AFE_SECURE_SIDEBAND1 (0x0f8c) +#define AFE_SECURE_MASK_CONN0 (0x0f90) +#define AFE_SECURE_MASK_CONN1 (0x0f94) +#define AFE_SECURE_MASK_CONN2 (0x0f98) +#define AFE_SECURE_MASK_CONN3 (0x0f9c) +#define AFE_SECURE_MASK_CONN4 (0x0fa0) +#define AFE_SECURE_MASK_CONN5 (0x0fa4) +#define AFE_SECURE_MASK_CONN6 (0x0fa8) +#define AFE_SECURE_MASK_CONN7 (0x0fac) +#define AFE_SECURE_MASK_CONN8 (0x0fb0) +#define AFE_SECURE_MASK_CONN9 (0x0fb4) +#define AFE_SECURE_MASK_CONN10 (0x0fb8) +#define AFE_SECURE_MASK_CONN11 (0x0fbc) +#define AFE_SECURE_MASK_CONN12 (0x0fc0) +#define AFE_SECURE_MASK_CONN13 (0x0fc4) +#define AFE_SECURE_MASK_CONN14 (0x0fc8) +#define AFE_SECURE_MASK_CONN15 (0x0fcc) +#define AFE_SECURE_MASK_CONN16 (0x0fd0) +#define AFE_SECURE_MASK_CONN17 (0x0fd4) +#define AFE_SECURE_MASK_CONN18 (0x0fd8) +#define AFE_SECURE_MASK_CONN19 (0x0fdc) +#define AFE_SECURE_MASK_CONN20 (0x0fe0) +#define AFE_SECURE_MASK_CONN21 (0x0fe4) +#define AFE_SECURE_MASK_CONN22 (0x0fe8) +#define AFE_SECURE_MASK_CONN23 (0x0fec) +#define AFE_SECURE_MASK_CONN24 (0x0ff0) +#define AFE_SECURE_MASK_CONN25 (0x0ff4) +#define AFE_SECURE_MASK_CONN26 (0x0ff8) +#define AFE_SECURE_MASK_CONN27 (0x0ffc) + +#define MAX_REGISTER AFE_SECURE_MASK_CONN27 + +#define AFE_IRQ_STATUS_BITS 0x3ff + +/* AUDIO_TOP_CON0 (0x0000) */ +#define AUD_TCON0_PDN_TML BIT(27) +#define AUD_TCON0_PDN_DAC_PREDIS BIT(26) +#define AUD_TCON0_PDN_DAC BIT(25) +#define AUD_TCON0_PDN_ADC BIT(24) +#define AUD_TCON0_PDN_TDM_IN BIT(23) +#define AUD_TCON0_PDN_TDM_OUT BIT(22) +#define AUD_TCON0_PDN_SPDIF BIT(21) +#define AUD_TCON0_PDN_APLL_TUNER BIT(19) +#define AUD_TCON0_PDN_APLL2_TUNER BIT(18) +#define AUD_TCON0_PDN_INTDIR BIT(15) +#define AUD_TCON0_PDN_24M BIT(9) +#define AUD_TCON0_PDN_22M BIT(8) +#define AUD_TCON0_PDN_I2S_IN BIT(6) +#define AUD_TCON0_PDN_AFE BIT(2) + +/* AUDIO_TOP_CON1 (0x0004) */ +#define AUD_TCON1_PDN_TDM_ASRC BIT(15) +#define AUD_TCON1_PDN_GENERAL2_ASRC BIT(14) +#define AUD_TCON1_PDN_GENERAL1_ASRC BIT(13) +#define AUD_TCON1_PDN_CONNSYS_I2S_ASRC BIT(12) +#define AUD_TCON1_PDN_DMIC3_ADC BIT(11) +#define AUD_TCON1_PDN_DMIC2_ADC BIT(10) +#define AUD_TCON1_PDN_DMIC1_ADC BIT(9) +#define AUD_TCON1_PDN_DMIC0_ADC BIT(8) +#define AUD_TCON1_PDN_I2S4_BCLK BIT(7) +#define AUD_TCON1_PDN_I2S3_BCLK BIT(6) +#define AUD_TCON1_PDN_I2S2_BCLK BIT(5) +#define AUD_TCON1_PDN_I2S1_BCLK BIT(4) + +/* AUDIO_TOP_CON3 (0x000C) */ +#define AUD_TCON3_HDMI_BCK_INV BIT(3) + +/* AFE_I2S_CON (0x0018) */ +#define AFE_I2S_CON_PHASE_SHIFT_FIX BIT(31) +#define AFE_I2S_CON_FROM_IO_MUX BIT(28) +#define AFE_I2S_CON_LOW_JITTER_CLK BIT(12) +#define AFE_I2S_CON_RATE(x) (((x) & 0xf) << 8) +#define AFE_I2S_CON_FORMAT_I2S BIT(3) +#define AFE_I2S_CON_SRC_SLAVE BIT(2) + +/* AFE_ASRC_2CH_CON0 */ +#define ONE_HEART_MASK (0x1 << 31) +#define CHSET_STR_CLR (0x1<<4) +#define ASM_ON_MASK (0x1<<0) +#define ASM_ON (0x1<<0) + +/* CON2 */ +#define O16BIT_MASK (0x1<<19) +#define CLR_IIR_HISTORY_MASK (0x1<<17) +#define CLR_IIR_HISTORY (0x1<<17) +#define IS_MONO_MASK (0x1<<16) +#define IIR_EN_MASK (0x1<<11) +#define IIR_EN (0x1<<11) +#define IIR_DIS (0x0<<11) +#define IIR_STAGE_MASK (0x7<<8) +#define IIR_STAGE_8 (0x7<<8) + +/* CON5 */ +#define CALI_CYCLE_MASK (0xFFFF << 16) +#define CALI_64_CYCLE (0x3F << 16) +#define CALI_96_CYCLE (0x5F << 16) +#define CALI_441_CYCLE (0x1B8 << 16) + +#define CALI_AUTORST_MASK (0x1 << 15) +#define CALI_AUTORST_ENABLE (0x1 << 15) +#define CALI_AUTORST_DISABLE (0x0 << 15) + +#define AUTO_TUNE_FREQ5_MASK (0x1 << 12) +#define AUTO_TUNE_FREQ5_ENABLE (0x1 << 12) +#define AUTO_TUNE_FREQ5_DISABLE (0x0 << 12) + +#define COMP_FREQ_RES_MASK (0x1 << 11) +#define COMP_FREQ_RES_ENABLE (0x1 << 11) + +#define CALI_SEL_MASK (0x3 << 8) +#define CALI_SEL_00 (0x0 << 8) +#define CALI_SEL_01 (0x1 << 8) + +#define CALI_BP_DGL_MASK (0x1 << 7) +#define CALI_BP_DGL_BYPASS (0x1 << 7) + +#define AUTO_TUNE_FREQ4_MASK (0x1 << 3) +#define AUTO_TUNE_FREQ4_ENABLE (0x1 << 3) +#define AUTO_TUNE_FREQ4_DISABLE (0x0 << 3) + +#define CALI_AUTO_RESTART_MASK (0x1 << 2) +#define CALI_AUTO_RESTART_ENABLE (0x1 << 2) + +#define CALI_USE_FREQ_OUT_MASK (0x1 << 1) +#define CALI_USE_FREQ (0x1 << 1) +#define CALI_USE_PERIOD (0x0 << 1) + +#define CALI_ON_MASK (0x1 << 0) +#define CALI_ON (0x1 << 0) +#define CALI_OFF (0x0 << 0) + + +#define AFE_I2S_CON_WLEN_32BIT BIT(1) +#define AFE_I2S_CON_EN BIT(0) + +#define AFE_CONN3_I03_O03_S BIT(3) +#define AFE_CONN4_I04_O04_S BIT(4) +#define AFE_CONN4_I03_O04_S BIT(3) + +/* AFE_I2S_CON1 (0x0034) */ +#define AFE_I2S_CON1_I2S2_TO_PAD (1 << 18) +#define AFE_I2S_CON1_TDMOUT_TO_PAD (0 << 18) +#define AFE_I2S_CON1_TDMOUT_MUX_MASK GENMASK(18, 18) +#define AFE_I2S_CON1_LOW_JITTER_CLK BIT(12) +#define AFE_I2S_CON1_RATE(x) (((x) & 0xf) << 8) +#define AFE_I2S_CON1_FORMAT_I2S BIT(3) +#define AFE_I2S_CON1_WLEN_32BIT BIT(1) +#define AFE_I2S_CON1_EN BIT(0) + +/* AFE_I2S_CON2 (0x0038) */ +#define AFE_I2S_CON2_LOW_JITTER_CLK BIT(12) +#define AFE_I2S_CON2_RATE(x) (((x) & 0xf) << 8) +#define AFE_I2S_CON2_FORMAT_I2S BIT(3) +#define AFE_I2S_CON2_WLEN_32BIT BIT(1) +#define AFE_I2S_CON2_EN BIT(0) + +/* AFE_I2S_CON3 (0x004C) */ +#define AFE_I2S_CON3_LOW_JITTER_CLK BIT(12) +#define AFE_I2S_CON3_RATE(x) (((x) & 0xf) << 8) +#define AFE_I2S_CON3_FORMAT_I2S BIT(3) +#define AFE_I2S_CON3_WLEN_32BIT BIT(1) +#define AFE_I2S_CON3_EN BIT(0) + +/* AFE_ADDA_DL_SRC2_CON0 (0x0108) */ +#define AFE_ADDA_DL_8X_UPSAMPLE (BIT(25) | BIT(24)) +#define AFE_ADDA_DL_MUTE_OFF (BIT(12) | BIT(11)) +#define AFE_ADDA_DL_VOICE_DATA BIT(5) +#define AFE_ADDA_DL_DEGRADE_GAIN BIT(1) + +/* AFE_ADDA_UL_DL_CON0 */ +#define AFE_ADDA_UL_DL_ADDA_AFE_ON_MASK BIT(0) +#define AFE_ADDA_UL_DL_ADDA_AFE_ON (1 << 0) +#define AFE_ADDA_UL_DL_ADDA_AFE_OFF (0 << 0) +#define AFE_ADDA_UL_DL_DMIC_CLKDIV_ON_MASK BIT(1) +#define AFE_ADDA_UL_DL_DMIC_CLKDIV_ON (1 << 1) +#define AFE_ADDA_UL_DL_DMIC_CLKDIV_OFF (0 << 1) + +/* AFE_SINEGEN_CON0 (0x01f0) */ +#define AFE_SINEGEN_CON0_EN BIT(26) +#define AFE_SINEGEN_CON0_IN_OUT_SEL BIT(27) +#define AFE_SINEGEN_CON0_MODE_MASK GENMASK(31, 28) +#define AFE_SINEGEN_CON0_AMP_DIV_CH2_MASK GENMASK(19, 17) +#define AFE_SINEGEN_CON0_AMP_DIV_CH1_MASK GENMASK(7, 5) +#define AFE_SINEGEN_CON0_AMP_DIV_CH2(x) (((x) & 0x7) << 17) +#define AFE_SINEGEN_CON0_AMP_DIV_CH1(x) (((x) & 0x7) << 5) +#define AFE_SINEGEN_CON0_FREQ_DIV_CH2_MASK GENMASK(16, 12) +#define AFE_SINEGEN_CON0_FREQ_DIV_CH1_MASK GENMASK(4, 0) +#define AFE_SINEGEN_CON0_FREQ_DIV_CH2(x) (((x) & 0x1f) << 12) +#define AFE_SINEGEN_CON0_FREQ_DIV_CH1(x) (((x) & 0x1f) << 0) +#define AFE_SINEGEN_CON0_TIMING_CH2_MASK GENMASK(23, 20) +#define AFE_SINEGEN_CON0_TIMING_CH1_MASK GENMASK(11, 8) +#define AFE_SINEGEN_CON0_TIMING_CH2(x) (((x) & 0xf) << 20) +#define AFE_SINEGEN_CON0_TIMING_CH1(x) (((x) & 0xf) << 8) +#define AFE_SINEGEN_CON0_TIMING_8K (0) +#define AFE_SINEGEN_CON0_TIMING_11D025K (1) +#define AFE_SINEGEN_CON0_TIMING_12K (2) +#define AFE_SINEGEN_CON0_TIMING_16K (4) +#define AFE_SINEGEN_CON0_TIMING_22D05K (5) +#define AFE_SINEGEN_CON0_TIMING_24K (6) +#define AFE_SINEGEN_CON0_TIMING_32K (8) +#define AFE_SINEGEN_CON0_TIMING_44D1K (9) +#define AFE_SINEGEN_CON0_TIMING_48K (10) +#define AFE_SINEGEN_CON0_TIMING_88D2K (11) +#define AFE_SINEGEN_CON0_TIMING_96K (12) +#define AFE_SINEGEN_CON0_TIMING_176D4K (13) +#define AFE_SINEGEN_CON0_TIMING_192K (14) + +/* AFE_HDMI_OUT_CON0 (0x0370) */ +#define AFE_HDMI_OUT_CON0_CH_MASK GENMASK(7, 4) + +/* AFE_HDMI_CONN0 (0x0390) */ +#define AFE_HDMI_CONN0_O35_I35 (0x7 << 21) +#define AFE_HDMI_CONN0_O34_I34 (0x6 << 18) +#define AFE_HDMI_CONN0_O33_I33 (0x5 << 15) +#define AFE_HDMI_CONN0_O32_I32 (0x4 << 12) +#define AFE_HDMI_CONN0_O31_I30 (0x2 << 9) +#define AFE_HDMI_CONN0_O31_I31 (0x3 << 9) +#define AFE_HDMI_CONN0_O30_I31 (0x3 << 6) +#define AFE_HDMI_CONN0_O30_I30 (0x2 << 6) +#define AFE_HDMI_CONN0_O29_I29 (0x1 << 3) +#define AFE_HDMI_CONN0_O28_I28 (0x0 << 0) + +/* AFE_CONN_TDMIN_CON (0x039c) */ +#define AFE_CONN_TDMIN_O41_I41 (0x1 << 3) +#define AFE_CONN_TDMIN_O41_I40 (0x0 << 3) +#define AFE_CONN_TDMIN_O40_I41 (0x1 << 0) +#define AFE_CONN_TDMIN_O40_I40 (0x0 << 0) +#define AFE_CONN_TDMIN_CON0_MASK GENMASK(5, 0) + +/* AFE_APLL_TUNER_CFG (0x03f0) */ +#define AFE_APLL_TUNER_CFG_MASK GENMASK(15, 1) +#define AFE_APLL_TUNER_CFG_EN_MASK GENMASK(0, 0) + +/* AFE_APLL_TUNER_CFG1 (0x03f4) */ +#define AFE_APLL_TUNER_CFG1_MASK GENMASK(15, 1) +#define AFE_APLL_TUNER_CFG1_EN_MASK GENMASK(0, 0) + +/* AFE_TDM_CON1 (0x0548) */ +#define AFE_TDM_CON1_LRCK_WIDTH(x) (((x) - 1) << 24) +#define AFE_TDM_CON1_32_BCK_CYCLES (0x2 << 12) +#define AFE_TDM_CON1_16_BCK_CYCLES (0x0 << 12) +#define AFE_TDM_CON1_8CH_PER_SDATA (0x2 << 10) +#define AFE_TDM_CON1_4CH_PER_SDATA (0x1 << 10) +#define AFE_TDM_CON1_2CH_PER_SDATA (0x0 << 10) +#define AFE_TDM_CON1_WLEN_32BIT BIT(9) +#define AFE_TDM_CON1_WLEN_16BIT BIT(8) +#define AFE_TDM_CON1_MSB_ALIGNED BIT(4) +#define AFE_TDM_CON1_1_BCK_DELAY BIT(3) +#define AFE_TDM_CON1_LRCK_INV BIT(2) +#define AFE_TDM_CON1_EN BIT(0) + +/* AFE_TDM_CON2 (0x054c) */ +#define AFE_TDM_CON2_SOUT_MASK GENMASK(14, 0) + +/* PCM_INTF_CON1 (0x0550) */ +#define PCM_INTF_CON1_EXT_MODEM (1 << 17) +#define PCM_INTF_CON1_16BIT (0 << 16) +#define PCM_INTF_CON1_24BIT (1 << 16) +#define PCM_INTF_CON1_32BCK (0 << 14) +#define PCM_INTF_CON1_64BCK (1 << 14) +#define PCM_INTF_CON1_MASTER_MODE (0 << 5) +#define PCM_INTF_CON1_SLAVE_MODE (1 << 5) +#define PCM_INTF_CON1_FS_8K (0 << 3) +#define PCM_INTF_CON1_FS_16K (1 << 3) +#define PCM_INTF_CON1_FS_32K (2 << 3) +#define PCM_INTF_CON1_FS_48K (3 << 3) +#define PCM_INTF_CON1_SYNC_LEN(x) (((x) - 1) << 9) +#define PCM_INTF_CON1_FORMAT(x) ((x) << 1) +#define PCM_INTF_CON1_SYNC_OUT_INV BIT(23) +#define PCM_INTF_CON1_BCLK_OUT_INV BIT(22) +#define PCM_INTF_CON1_SYNC_IN_INV BIT(21) +#define PCM_INTF_CON1_BCLK_IN_INV BIT(20) +#define PCM_INTF_CON1_BYPASS_ASRC BIT(6) +#define PCM_INTF_CON1_EN BIT(0) +#define PCM_INTF_CON1_CONFIG_MASK (0xf3fffe) + +/* AFE_TDM_IN_CON1 (0x0588) */ +#define AFE_TDM_IN_CON1_LRCK_WIDTH(x) (((x) - 1) << 24) +#define AFE_TDM_IN_CON1_FAST_LRCK_CYCLE_32BCK (0x2 << 16) +#define AFE_TDM_IN_CON1_FAST_LRCK_CYCLE_16BCK (0x0 << 16) +#define AFE_TDM_IN_CON1_8CH_PER_SDATA (0x2 << 12) +#define AFE_TDM_IN_CON1_4CH_PER_SDATA (0x1 << 12) +#define AFE_TDM_IN_CON1_2CH_PER_SDATA (0x0 << 12) +#define AFE_TDM_IN_CON1_WLEN_32BIT (0x3 << 8) +#define AFE_TDM_IN_CON1_WLEN_24BIT (0x2 << 8) +#define AFE_TDM_IN_CON1_WLEN_16BIT (0x1 << 8) +#define AFE_TDM_IN_CON1_I2S BIT(3) +#define AFE_TDM_IN_CON1_LRCK_INV BIT(2) +#define AFE_TDM_IN_CON1_BCK_INV BIT(1) +#define AFE_TDM_IN_CON1_EN BIT(0) + +/* AFE_TDM_IN_CON2 (0x058c) */ +#define AFE_TDM_IN_CON2_DISABLE_CH01 BIT(0) +#define AFE_TDM_IN_CON2_DISABLE_CH23 BIT(1) +#define AFE_TDM_IN_CON2_DISABLE_CH45 BIT(2) +#define AFE_TDM_IN_CON2_DISABLE_CH67 BIT(3) + +/* AFE_DMIC0_UL_SRC_CON0 (0x05b4) + * AFE_DMIC0_UL_SRC_CON0 (0x0620) + * AFE_DMIC0_UL_SRC_CON0 (0x0780) + * AFE_DMIC0_UL_SRC_CON0 (0x07ec) + */ +#define DMIC_TOP_CON_DMIC_TWO_WIRE_MODE BIT(23) +#define DMIC_TOP_CON_DMIC_CK_PHASE_SEL_CH2(x) ((x) << 24) +#define DMIC_TOP_CON_DMIC_CK_PHASE_SEL_CH1(x) ((x) << 27) +#define DMIC_TOP_CON_DMIC_CH2_ON_MASK BIT(22) +#define DMIC_TOP_CON_DMIC_CH2_ON (1 << 22) +#define DMIC_TOP_CON_DMIC_CH2_OFF (0 << 22) +#define DMIC_TOP_CON_DMIC_CH1_ON_MASK BIT(21) +#define DMIC_TOP_CON_DMIC_CH1_ON (1 << 21) +#define DMIC_TOP_CON_DMIC_CH1_OFF (0 << 21) +#define DMIC_TOP_CON_DMIC_VOICE_MODE_8K (0 << 17) +#define DMIC_TOP_CON_DMIC_VOICE_MODE_16K (1 << 17) +#define DMIC_TOP_CON_DMIC_VOICE_MODE_32K (2 << 17) +#define DMIC_TOP_CON_DMIC_VOICE_MODE_48K (3 << 17) +#define DMIC_TOP_CON_DMIC_NO_LOW_POWER_MODE (0 << 14) +#define DMIC_TOP_CON_DMIC_LOW_POWER_MODE(x) ((x) << 14) +#define DMIC_TOP_CON_DMIC_IIR_ON BIT(10) +#define DMIC_TOP_CON_DMIC_INPUT_MODE(x) ((x) << 5) +#define DMIC_TOP_CON_DMIC_IIR_MODE(x) ((x) << 7) +#define DMIC_TOP_CON_DMIC_SDM3_LEVEL_MODE BIT(1) +#define DMIC_TOP_CON_DMIC_SRC_ON_MASK BIT(0) +#define DMIC_TOP_CON_DMIC_SRC_ON (1 << 0) +#define DMIC_TOP_CON_DMIC_SRC_OFF (0 << 0) +#define DMIC_TOP_CON_DMIC_SDM3_DE_SELECT (0 << 1) +#define DMIC_TOP_CON_CONFIG_MASK (0x3f8ed7a6) + +/* AFE_TDM_ASRC_CON0 (0x06f8)*/ +#define TDM_ASRC_OUT_MODE(x) ((x) << 4) +#define TDM_ASRC_OUT_MODE_MASK GENMASK(7, 4) +#define TDM_ASRC_OUT_SEL BIT(2) +#define TDM_ASRC_OUT_SEL_TO_CM1 (0 << 2) +#define TDM_ASRC_OUT_SEL_TO_CM2 (1 << 2) +#define TDM_ASRC_IN_SEL_FROM_TDMIN (0 << 1) +#define TDM_ASRC_IN_SEL_FROM_TDMOUT (1 << 1) +#define TDM_ASRC_IN_SEL_MASK BIT(1) +#define TDM_ASRC_EN_ON BIT(0) + +/* AFE_CONN_24BIT (0x0AA4) */ +#define AFE_CONN_24BIT_O10 BIT(10) +#define AFE_CONN_24BIT_O09 BIT(9) +#define AFE_CONN_24BIT_O06 BIT(6) +#define AFE_CONN_24BIT_O05 BIT(5) +#define AFE_CONN_24BIT_O04 BIT(4) +#define AFE_CONN_24BIT_O03 BIT(3) +#define AFE_CONN_24BIT_O02 BIT(2) +#define AFE_CONN_24BIT_O01 BIT(1) +#define AFE_CONN_24BIT_O00 BIT(0) + +/* AFE_HD_ENGEN_ENABLE */ +#define AFE_22M_PLL_EN BIT(0) +#define AFE_22M_PLL_ON (1 << 0) +#define AFE_22M_PLL_OFF (0 << 0) +#define AFE_24M_PLL_EN BIT(1) +#define AFE_24M_PLL_ON (1 << 1) +#define AFE_24M_PLL_OFF (0 << 1) + +/* AFE_GAIN1_CON0 (0x0410) */ +#define AFE_GAIN1_CON0_EN_MASK GENMASK(0, 0) +#define AFE_GAIN1_CON0_MODE_MASK GENMASK(7, 4) +#define AFE_GAIN1_CON0_SAMPLE_PER_STEP_MASK GENMASK(15, 8) + +/* AFE_GAIN1_CON1 (0x0414) */ +#define AFE_GAIN1_CON1_MASK GENMASK(19, 0) + +/* AFE_GAIN1_CUR (0x0B78) */ +#define AFE_GAIN1_CUR_MASK GENMASK(19, 0) + +/* AFE_CM1_CON0 (0x0e50) */ +/* AFE_CM2_CON0 (0x0e60) */ +#define CM_AFE_CM_CH_NUM(x) (((x) - 1) << 0) +#define CM_AFE_CM_CH_NUM_MASK GENMASK(3, 0) +#define CM_AFE_CM_ON BIT(4) +#define CM_AFE_CM_OFF (0 << 4) +#define CM_AFE_CM_START_DATA(x) ((x) << 8) +#define CM_AFE_CM_START_DATA_MASK GENMASK(11, 8) + +#define CM_AFE_CM1_VUL_SEL_CM1_OUTPUT (0 << 12) +#define CM_AFE_CM1_VUL_SEL_O17_O18 (1 << 12) +#define CM_AFE_CM1_VUL_SEL BIT(12) +#define CM_AFE_CM1_IN_MODE(x) ((x) << 16) +#define CM_AFE_CM1_IN_MODE_MASK GENMASK(19, 16) +#define CM_AFE_CM2_TDM_SEL_CM2_OUTPUT (1 << 12) +#define CM_AFE_CM2_TDM_SEL_TDM (0 << 12) +#define CM_AFE_CM2_TDM_SEL BIT(12) +#define CM_AFE_CM2_CLK_SEL_24M (0 << 13) +#define CM_AFE_CM2_CLK_SEL_22M (1 << 13) +#define CM_AFE_CM2_CLK_SEL BIT(13) +#define CM_AFE_CM2_GASRC1_OUT_SEL BIT(17) +#define CM_AFE_CM2_GASRC2_OUT_SEL BIT(16) +#define GASRC1_OUT_TO_TDM_OUT_EN (0 << 17) +#define GASRC1_OUT_TO_ENGEN_OUT_EN (1 << 17) +#define GASRC2_OUT_TO_TDM_OUT_EN (0 << 16) +#define GASRC2_OUT_TO_ENGEN_OUT_EN (1 << 16) + +/* AFE_CM2_CONN* */ +#define CM2_AFE_CM2_CONN_CFG1(x) ((x) << 0) +#define CM2_AFE_CM2_CONN_CFG1_MASK GENMASK(4, 0) +#define CM2_AFE_CM2_CONN_CFG2(x) ((x) << 5) +#define CM2_AFE_CM2_CONN_CFG2_MASK GENMASK(9, 5) +#define CM2_AFE_CM2_CONN_CFG3(x) ((x) << 10) +#define CM2_AFE_CM2_CONN_CFG3_MASK GENMASK(14, 10) +#define CM2_AFE_CM2_CONN_CFG4(x) ((x) << 15) +#define CM2_AFE_CM2_CONN_CFG4_MASK GENMASK(19, 15) +#define CM2_AFE_CM2_CONN_CFG5(x) ((x) << 20) +#define CM2_AFE_CM2_CONN_CFG5_MASK GENMASK(24, 20) +#define CM2_AFE_CM2_CONN_CFG6(x) ((x) << 25) +#define CM2_AFE_CM2_CONN_CFG6_MASK GENMASK(29, 25) +#define CM2_AFE_CM2_CONN_CFG7(x) ((x) << 0) +#define CM2_AFE_CM2_CONN_CFG7_MASK GENMASK(4, 0) +#define CM2_AFE_CM2_CONN_CFG8(x) ((x) << 5) +#define CM2_AFE_CM2_CONN_CFG8_MASK GENMASK(9, 5) +#define CM2_AFE_CM2_CONN_CFG9(x) ((x) << 10) +#define CM2_AFE_CM2_CONN_CFG9_MASK GENMASK(14, 10) +#define CM2_AFE_CM2_CONN_CFG10(x) ((x) << 15) +#define CM2_AFE_CM2_CONN_CFG10_MASK GENMASK(19, 15) +#define CM2_AFE_CM2_CONN_CFG11(x) ((x) << 20) +#define CM2_AFE_CM2_CONN_CFG11_MASK GENMASK(24, 20) +#define CM2_AFE_CM2_CONN_CFG12(x) ((x) << 25) +#define CM2_AFE_CM2_CONN_CFG12_MASK GENMASK(29, 25) +#define CM2_AFE_CM2_CONN_CFG13(x) ((x) << 0) +#define CM2_AFE_CM2_CONN_CFG13_MASK GENMASK(4, 0) +#define CM2_AFE_CM2_CONN_CFG14(x) ((x) << 5) +#define CM2_AFE_CM2_CONN_CFG14_MASK GENMASK(9, 5) +#define CM2_AFE_CM2_CONN_CFG15(x) ((x) << 10) +#define CM2_AFE_CM2_CONN_CFG15_MASK GENMASK(14, 10) +#define CM2_AFE_CM2_CONN_CFG16(x) ((x) << 15) +#define CM2_AFE_CM2_CONN_CFG16_MASK GENMASK(19, 15) + +/* AFE_CM1_CON* */ +#define CM_AFE_CM_UPDATE_CNT1(x) (((x) & (0xffff)) << 0) +#define CM_AFE_CM_UPDATE_CNT2(x) (((x) & (0xffff)) << 16) +#define CM_AFE_CM_UPDATE_CNT1_MASK GENMASK(15, 0) +#define CM_AFE_CM_UPDATE_CNT2_MASK GENMASK(31, 16) +#define CM_AFE_CM_UPDATE_CNT_MASK GENMASK(31, 0) + +/* AFE_CM2_CON0 (0x0e60)*/ +#define GASRC_ASRC1_OUT_EN_SEL BIT(17) +#define GASRC_ASRC2_OUT_EN_SEL BIT(16) + + +/* AFE_GENERAL1_ASRC_2CH_CON0 (0x0e80) + * AFE_GENERAL2_ASRC_2CH_CON0 (0x0f00) + */ +#define GASRC_CON0_CHSET0_CLR_IIR_HISTORY BIT(17) +#define GASRC_NEW_CON0_CHSET0_OFS_SEL_MASK GENMASK(15, 14) +#define GASRC_NEW_CON0_CHSET0_OFS_SEL_TX (0 << 14) +#define GASRC_NEW_CON0_CHSET0_OFS_SEL_RX (1 << 14) +#define GASRC_NEW_CON0_CHSET0_IFS_SEL_MASK GENMASK(13, 12) +#define GASRC_NEW_CON0_CHSET0_IFS_SEL_TX (3 << 12) +#define GASRC_NEW_CON0_CHSET0_IFS_SEL_RX (2 << 12) +#define GASRC_CON0_CHSET_IIR_EN BIT(11) +#define GASRC_CON0_CHSET_IIR_STAGE(x) ((x) << 8) +#define GASRC_CON0_CHSET_IIR_STAGE_MASK GENMASK(10, 8) +#define GASRC_CON0_CHSET_STR_CLR BIT(4) +#define GASRC_CON0_COEFF_SRAM_CTRL BIT(1) +#define GASRC_CON0_ASM_ON BIT(0) + +/* GENERAL_ASRC_MODE (0x0eb8) */ +#define GASRC_MODE_GASRC1_IN_MODE(x) (((x) & 0xf) << 0) +#define GASRC_MODE_GASRC2_IN_MODE(x) (((x) & 0xf) << 8) +#define GASRC_MODE_GASRC1_IN_MODE_MASK GENMASK(3, 0) +#define GASRC_MODE_GASRC2_IN_MODE_MASK GENMASK(11, 8) +#define GASRC_MODE_GASRC1_OUT_MODE(x) (((x) & 0xf) << 4) +#define GASRC_MODE_GASRC2_OUT_MODE(x) (((x) & 0xf) << 12) +#define GASRC_MODE_GASRC1_OUT_MODE_MASK GENMASK(7, 4) +#define GASRC_MODE_GASRC2_OUT_MODE_MASK GENMASK(15, 12) + +/* GENERAL_ASRC_EN_ON (0x0ebc) */ +#define GASRC_EN_ON_MASK(x) (0x1 << (x)) +#define GASRC_EN_ON(x) (0x1 << (x)) +#define GASRC_EN_OFF(x) (0x0 << (x)) + +/* AFE_GENERAL1_ASRC_2CH_CON5 (0x0e94) + * AFE_GENERAL2_ASRC_2CH_CON5 (0x0f14) + */ +#define GASRC_CON5_CALI_CYCLE_MASK GENMASK(31, 16) +#define GASRC_CON5_CALI_64_CYCLE (0x3F << 16) +#define GASRC_CON5_CALI_96_CYCLE (0x5F << 16) +#define GASRC_CON5_CALI_441_CYCLE (0x1B8 << 16) +#define GASRC_CON5_CALI_AUTORST_ENABLE BIT(15) +#define GASRC_CON5_AUTO_TUNE_FREQ5_ENABLE BIT(12) +#define GASRC_CON5_AUTO_TUNE_FREQ5_DISABLE (0x0 << 12) +#define GASRC_CON5_COMP_FREQ_RES_ENABLE BIT(11) +#define GASRC_CON5_CALI_BP_DGL_BYPASS BIT(7) +#define GASRC_CON5_AUTO_TUNE_FREQ4_ENABLE BIT(3) +#define GASRC_CON5_AUTO_TUNE_FREQ4_DISABLE (0x0 << 3) +#define GASRC_CON5_CALI_AUTO_RESTART_ENABLE BIT(2) +#define GASRC_CON5_CALI_USE_FREQ BIT(1) +#define GASRC_CON5_CALI_USE_PERIOD (0x0 << 1) +#define GASRC_CON5_CALI_ON BIT(0) +#define GASRC_CON5_CALI_OFF (0x0 << 0) +#define GASRC_CON5_CALI_SEL_MASK GENMASK(9, 8) +#define GASRC_CON5_CALI_SEL_00 (0x0 << 8) +#define GASRC_CON5_CALI_SEL_01 (0x1 << 8) + +/* AFE_TDM_GASRC*_ASRC_2CH_CON0 */ +#define TDM_ASRC_CON0_ONE_HEART BIT(31) + +#endif /* _MT8365_AFE_REGS_H_ */ diff --git a/src/platform/mt8365/include/platform/platform.h b/src/platform/mt8365/include/platform/platform.h new file mode 100644 index 000000000000..c447312c16a5 --- /dev/null +++ b/src/platform/mt8365/include/platform/platform.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifdef __SOF_PLATFORM_H__ + +#ifndef __PLATFORM_PLATFORM_H__ +#define __PLATFORM_PLATFORM_H__ + +#if !defined(__ASSEMBLER__) && !defined(LINKER) + +#include <sof/lib/mailbox.h> +#include <stddef.h> +#include <stdint.h> + +struct ll_schedule_domain; +struct timer; + +#define PLATFORM_DEFAULT_CLOCK CLK_CPU(0) +#define LPSRAM_SIZE 16384 + +/* Host page size */ +#define HOST_PAGE_SIZE 4096 +#define PLATFORM_PAGE_TABLE_SIZE 256 + +/* pipeline IRQ */ +#define PLATFORM_SCHEDULE_IRQ MTK_DSP_IRQ_SOFTWARE0 +#define PLATFORM_SCHEDULE_IRQ_NAME NULL + +/* Platform stream capabilities */ +#define PLATFORM_MAX_CHANNELS 4 +#define PLATFORM_MAX_STREAMS 5 + +/* local buffer size of DMA tracing */ +#define DMA_TRACE_LOCAL_SIZE HOST_PAGE_SIZE + +/* trace bytes flushed during panic */ +#define DMA_FLUSH_TRACE_SIZE (MAILBOX_TRACE_SIZE >> 2) + +/* the interval of DMA trace copying */ +#define DMA_TRACE_PERIOD 500000 + +/* + * the interval of reschedule DMA trace copying in special case like half + * fullness of local DMA trace buffer + */ +#define DMA_TRACE_RESCHEDULE_TIME 100 + +/* DSP default delay in cycles */ +#define PLATFORM_DEFAULT_DELAY 12 + +#define SRAM_REG_FW_STATUS 0x4 +#define SRAM_REG_OP_CPU2DSP 0x8 +#define SRAM_REG_OP_DSP2CPU 0xC + +/* Platform defined panic code */ +static inline void platform_panic(uint32_t p) +{ + /* Store the error code in the debug box so the + * application processor can pick it up. Takes up 4 bytes + * from the debug box. + */ + mailbox_sw_reg_write(SRAM_REG_FW_STATUS, p); + + /* Notify application processor */ + trigger_irq_to_host_req(); +} + +/** + * \brief Platform specific CPU entering idle. + * May be power-optimized using platform specific capabilities. + * @param level Interrupt level. + */ +void platform_wait_for_interrupt(int level); + +extern intptr_t _module_init_start; +extern intptr_t _module_init_end; +#endif + +#endif /* __PLATFORM_PLATFORM_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/platform.h" + +#endif /* __SOF_PLATFORM_H__ */ diff --git a/src/platform/mt8365/include/platform/trace/trace.h b/src/platform/mt8365/include/platform/trace/trace.h new file mode 100644 index 000000000000..63122335e650 --- /dev/null +++ b/src/platform/mt8365/include/platform/trace/trace.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#ifdef __SOF_TRACE_TRACE_H__ + +#ifndef __PLATFORM_TRACE_TRACE_H__ +#define __PLATFORM_TRACE_TRACE_H__ + +#include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <sof/lib/io.h> +#include <platform/drivers/mt_reg_base.h> + +#define platform_trace_point(__x) + +#endif /* __PLATFORM_TRACE_TRACE_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/trace/trace.h" + +#endif /* __SOF_TRACE_TRACE_H__ */ diff --git a/src/platform/mt8365/lib/CMakeLists.txt b/src/platform/mt8365/lib/CMakeLists.txt new file mode 100644 index 000000000000..ef71f8eea6cd --- /dev/null +++ b/src/platform/mt8365/lib/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources(sof + clk.c + dma.c + memory.c + dai.c +) diff --git a/src/platform/mt8365/lib/clk.c b/src/platform/mt8365/lib/clk.c new file mode 100644 index 000000000000..57bc821049fb --- /dev/null +++ b/src/platform/mt8365/lib/clk.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#include <sof/common.h> +#include <rtos/clk.h> +#include <sof/lib/cpu.h> +#include <sof/lib/memory.h> +#include <sof/lib/notifier.h> +#include <sof/lib/uuid.h> +#include <rtos/wait.h> +#include <rtos/sof.h> +#include <sof/trace/trace.h> + +SOF_DEFINE_REG_UUID(clkdrv_mt8365); + +DECLARE_TR_CTX(clkdrv_tr, SOF_UUID(clkdrv_mt8365_uuid), LOG_LEVEL_INFO); + +static int dsppll_enable; /* default no adsp clock*/ +static int adsp_clock; + +const struct freq_table platform_cpu_freq[] = { + { 13000000, 13000}, + { 26000000, 13000}, + { 312000000, 13000}, + { 400000000, 13000}, + { 600000000, 13000}, +}; + +const uint32_t cpu_freq_enc[] = { + 13000000, + 26000000, + 0x83180000, + 0x820F6276, + 0x821713B1, +}; + +STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, + invalid_number_of_cpu_frequencies); + +static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; + +static inline void clk_setl(uint32_t addr, uint32_t val) +{ + io_reg_write(addr, io_reg_read(addr) | (val)); +} + +static inline void clk_clrl(uint32_t addr, uint32_t val) +{ + io_reg_write(addr, io_reg_read(addr) & ~(val)); +} + +static inline int dsp_clk_value_convert(int value) +{ + int ret; + + switch (value) { + case DSP_CLK_13M: + ret = CLK_DSP_SEL_26M_D_2; + break; + case DSP_CLK_26M: + ret = CLK_DSP_SEL_26M; + break; + case DSP_CLK_PLL_312M: + case DSP_CLK_PLL_400M: + case DSP_CLK_PLL_600M: + ret = CLK_DSP_SEL_DSPPLL; + break; + default: + ret = CLK_DSP_SEL_26M; + break; + } + + return ret; +} + +static void clk_dsppll_enable(void) +{ + tr_dbg(&clkdrv_tr, "entry"); + + clk_setl(DSPPLL_CON3, PLL_PWR_ON); + wait_delay_us(1); + clk_clrl(DSPPLL_CON3, PLL_ISO_EN); + wait_delay_us(1); + clk_setl(DSPPLL_CON0, PLL_BASE_EN); + wait_delay_us(20); + dsppll_enable = 1; + +} + +static void clk_dsppll_disable(void) +{ + tr_dbg(&clkdrv_tr, "entry"); + + clk_clrl(DSPPLL_CON0, PLL_BASE_EN); + wait_delay_us(1); + clk_setl(DSPPLL_CON3, PLL_ISO_EN); + wait_delay_us(1); + clk_clrl(DSPPLL_CON3, PLL_PWR_ON); + dsppll_enable = 0; +} + +static int dsppll_get_enable(void) +{ + tr_dbg(&clkdrv_tr, "dsppll_enable=%d.\n", dsppll_enable); + + return dsppll_enable; +} + +static int set_mux_sel(enum mux_id_t mux_id, uint32_t value) +{ + switch (mux_id) { + case MUX_CLK_DSP_SEL: + io_reg_update_bits(CLK_CFG_8_CLR, (0x7 << 24), (0x7 << 24)); + io_reg_update_bits(CLK_CFG_8_SET, (0x7 << 24), (value << 24)); + io_reg_write(CLK_CFG_UPDATE1, 0x8); + + tr_dbg(&clkdrv_tr, "adspclk_mux=%x, CLK_CFG_8=0x%08x\n", + value, io_reg_read(CLK_CFG_8)); + break; + default: + tr_dbg(&clkdrv_tr, "error: unknown mux_id (%d)\n", mux_id); + break; + } + + return 0; +} + +static int clock_platform_set_dsp_freq(int clock, int freq_idx) +{ + uint32_t enc = cpu_freq_enc[freq_idx]; + int clk_mux; + int adsp_clk_req = platform_cpu_freq[freq_idx].freq; + + if (adsp_clock == adsp_clk_req) + return 0; + + tr_info(&clkdrv_tr, "clock_platform_set_cpu_freq %d\n", adsp_clk_req); + + /* convert res manager value to driver map */ + clk_mux = dsp_clk_value_convert(freq_idx); + + if (enc > 26000000) { + /* adsp pll */ + if (!dsppll_get_enable()) { + clk_dsppll_enable(); + set_mux_sel(MUX_CLK_DSP_SEL, clk_mux); + } + /* set adsp pll clock */ + io_reg_update_bits(DSPPLL_CON1, 0xffffffff, enc); + } else { + /* clk26m */ + if (dsppll_get_enable()) { + set_mux_sel(MUX_CLK_DSP_SEL, clk_mux); + clk_dsppll_disable(); + } + } + + adsp_clock = adsp_clk_req; + + return 0; +} + +void platform_clock_init(struct sof *sof) +{ + int i; + + sof->clocks = platform_clocks_info; + + for (i = 0; i < CONFIG_CORE_COUNT; i++) { + sof->clocks[i] = (struct clock_info){ + .freqs_num = NUM_CPU_FREQ, + .freqs = platform_cpu_freq, + .default_freq_idx = CPU_DEFAULT_IDX, + .current_freq_idx = CPU_DEFAULT_IDX, + .notification_id = NOTIFIER_ID_CPU_FREQ, + .notification_mask = NOTIFIER_TARGET_CORE_MASK(i), + .set_freq = clock_platform_set_dsp_freq, + }; + } + + adsp_clock = 0; + dsppll_enable = 0; + clock_set_freq(CLK_CPU(cpu_get_id()), CLK_MAX_CPU_HZ); +} diff --git a/src/platform/mt8365/lib/dai.c b/src/platform/mt8365/lib/dai.c new file mode 100644 index 000000000000..6700e3257ac2 --- /dev/null +++ b/src/platform/mt8365/lib/dai.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#include <sof/common.h> +#include <sof/lib/dai.h> +#include <sof/lib/memory.h> +#include <rtos/sof.h> +#include <rtos/spinlock.h> +#include <ipc/dai.h> +#include <ipc/stream.h> + +#include <sof/drivers/afe-dai.h> +#include <mt8365-afe-common.h> + +/* MEMIF specified IRQs set in the Linux driver: + * + * [MT8365_AFE_MEMIF_DL1] = MT8365_AFE_IRQ1, + * [MT8365_AFE_MEMIF_DL2] = MT8365_AFE_IRQ2, + * [MT8365_AFE_MEMIF_TDM_OUT] = MT8365_AFE_IRQ5, + * // [MT8365_AFE_MEMIF_SPDIF_OUT] = MT8365_AFE_IRQ6, + * [MT8365_AFE_MEMIF_AWB] = MT8365_AFE_IRQ3, + * [MT8365_AFE_MEMIF_VUL] = MT8365_AFE_IRQ4, + * [MT8365_AFE_MEMIF_VUL2] = MT8365_AFE_IRQ7, + * [MT8365_AFE_MEMIF_VUL3] = MT8365_AFE_IRQ8, + * // [MT8365_AFE_MEMIF_SPDIF_IN] = MT8365_AFE_IRQ9, + * [MT8365_AFE_MEMIF_TDM_IN] = MT8365_AFE_IRQ10, + */ + +static int afe_dai_handshake[MT8365_DAI_NUM] = { + AFE_HANDSHAKE(MT8365_AFE_IO_INT_ADDA_OUT, MT8365_AFE_IRQ_1, MT8365_MEMIF_DL1), + AFE_HANDSHAKE(MT8365_AFE_IO_2ND_I2S, MT8365_AFE_IRQ_2, MT8365_MEMIF_DL2), + AFE_HANDSHAKE(MT8365_AFE_IO_INT_ADDA_IN, MT8365_AFE_IRQ_3, MT8365_MEMIF_AWB), + AFE_HANDSHAKE(MT8365_AFE_IO_DMIC, MT8365_AFE_IRQ_4, MT8365_MEMIF_VUL), +}; + +static SHARED_DATA struct dai afe_dai[MT8365_DAI_NUM]; + +const struct dai_type_info dti[] = { + { + .type = SOF_DAI_MEDIATEK_AFE, + .dai_array = afe_dai, + .num_dais = ARRAY_SIZE(afe_dai), + }, +}; + +const struct dai_info lib_dai = { + .dai_type_array = dti, + .num_dai_types = ARRAY_SIZE(dti), +}; + +int dai_init(struct sof *sof) +{ + int i; + + /* initialize spin locks early to enable ref counting */ + for (i = 0; i < ARRAY_SIZE(afe_dai); i++) { + k_spinlock_init(&afe_dai[i].lock); + afe_dai[i].index = AFE_HS_GET_DAI(afe_dai_handshake[i]); + afe_dai[i].drv = &afe_dai_driver; + /* TODO, fifo[0] change to target playback or capture */ + afe_dai[i].plat_data.fifo[0].handshake = afe_dai_handshake[i]; + } + + sof->dai_info = &lib_dai; + + return 0; +} diff --git a/src/platform/mt8365/lib/dma.c b/src/platform/mt8365/lib/dma.c new file mode 100644 index 000000000000..9e6209790731 --- /dev/null +++ b/src/platform/mt8365/lib/dma.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#include <sof/common.h> +#include <sof/drivers/afe-memif.h> +#include <rtos/interrupt.h> +#include <sof/lib/dma.h> +#include <sof/lib/memory.h> +#include <rtos/sof.h> +#include <rtos/spinlock.h> + +#include <mt8365-afe-regs.h> +#include <mt8365-afe-common.h> + +extern const struct dma_ops dummy_dma_ops; + +static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +{ + .plat_data = { + .id = DMA_ID_HOST, + .dir = DMA_DIR_HMEM_TO_LMEM | DMA_DIR_LMEM_TO_HMEM, + .devs = DMA_DEV_HOST, + .channels = 16, + }, + .ops = &dummy_dma_ops, +}, +{ + .plat_data = { + .id = DMA_ID_AFE_MEMIF, + .dir = DMA_DIR_MEM_TO_DEV | DMA_DIR_DEV_TO_MEM, + .devs = DMA_DEV_AFE_MEMIF, + .base = AFE_REG_BASE, + .channels = MT8365_MEMIF_NUM, + }, + .ops = &memif_ops, +}, +}; + +static const struct dma_info lib_dma = { + .dma_array = cache_to_uncache_init((struct dma *)dma), + .num_dmas = ARRAY_SIZE(dma) +}; + +int dmac_init(struct sof *sof) +{ + int i; + + /* early lock initialization for ref counting */ + for (i = 0; i < ARRAY_SIZE(dma); i++) + k_spinlock_init(&dma[i].lock); + + sof->dma_info = &lib_dma; + + return 0; +} diff --git a/src/platform/mt8365/lib/memory.c b/src/platform/mt8365/lib/memory.c new file mode 100644 index 000000000000..7ed1417dc1f2 --- /dev/null +++ b/src/platform/mt8365/lib/memory.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#include <sof/common.h> +#include <sof/lib/mm_heap.h> +#include <sof/lib/memory.h> +#include <rtos/sof.h> +#include <ipc/topology.h> + +/* Heap blocks for system runtime */ +static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; + +/* Heap memory for system runtime */ +static SHARED_DATA struct block_map sys_rt_heap_map[] = { + BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), + BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), + BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), +}; + +/* Heap blocks for modules */ +static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static SHARED_DATA struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; + +/* Heap memory map for modules */ +static SHARED_DATA struct block_map rt_heap_map[] = { + BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), + BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), + BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), + BLOCK_DEF(128, HEAP_RT_COUNT128, mod_block128), + BLOCK_DEF(256, HEAP_RT_COUNT256, mod_block256), + BLOCK_DEF(512, HEAP_RT_COUNT512, mod_block512), + BLOCK_DEF(1024, HEAP_RT_COUNT1024, mod_block1024), + BLOCK_DEF(2048, HEAP_RT_COUNT2048, mod_block2048), + BLOCK_DEF(4096, HEAP_RT_COUNT4096, mod_block4096), +}; + +/* Heap blocks for buffers */ +static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; + +/* Heap memory map for buffers */ +static SHARED_DATA struct block_map buf_heap_map[] = { + BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), +}; + +static SHARED_DATA struct mm memmap = { + .system[0] = { + .heap = HEAP_SYSTEM_BASE, + .size = HEAP_SYSTEM_SIZE, + .info = {.free = HEAP_SYSTEM_SIZE,}, + .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_CACHE | + SOF_MEM_CAPS_DMA, + }, + .system_runtime[0] = { + .blocks = ARRAY_SIZE(sys_rt_heap_map), + .map = sys_rt_heap_map, + .heap = HEAP_SYS_RUNTIME_BASE, + .size = HEAP_SYS_RUNTIME_SIZE, + .info = {.free = HEAP_SYS_RUNTIME_SIZE,}, + .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_CACHE | + SOF_MEM_CAPS_DMA, + }, + .runtime[0] = { + .blocks = ARRAY_SIZE(rt_heap_map), + .map = rt_heap_map, + .heap = HEAP_RUNTIME_BASE, + .size = HEAP_RUNTIME_SIZE, + .info = {.free = HEAP_RUNTIME_SIZE,}, + .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_CACHE | + SOF_MEM_CAPS_DMA, + }, + .buffer[0] = { + .blocks = ARRAY_SIZE(buf_heap_map), + .map = buf_heap_map, + .heap = HEAP_BUFFER_BASE, + .size = HEAP_BUFFER_SIZE, + .info = {.free = HEAP_BUFFER_SIZE,}, + .caps = SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_CACHE | + SOF_MEM_CAPS_DMA, + }, + .total = {.free = HEAP_SYSTEM_SIZE + HEAP_SYS_RUNTIME_SIZE + + HEAP_RUNTIME_SIZE + HEAP_BUFFER_SIZE,}, +}; + +void platform_init_memmap(struct sof *sof) +{ + /* memmap has been initialized statically as a part of .data */ + sof->memory_map = &memmap; +} diff --git a/src/platform/mt8365/mt8365.x.in b/src/platform/mt8365/mt8365.x.in new file mode 100644 index 000000000000..fdf588d33e4f --- /dev/null +++ b/src/platform/mt8365/mt8365.x.in @@ -0,0 +1,492 @@ +/* + * Linker Script for mt8365 MediaTek + * + * This script is run through the GNU C preprocessor to align the memory + * offsets with headers. + * + * Use spaces for formatting as cpp ignore tab sizes. + */ + +#include <sof/lib/memory.h> +#include <xtensa/config/core-isa.h> + +OUTPUT_ARCH(xtensa) + +MEMORY +{ + vector_reset_text : + org = XCHAL_RESET_VECTOR0_PADDR, + len = SOF_MEM_RESET_TEXT_SIZE + vector_reset_lit : + org = XCHAL_RESET_VECTOR0_PADDR + SOF_MEM_RESET_TEXT_SIZE, + len = SOF_MEM_RESET_LIT_SIZE + vector_base_text : + org = XCHAL_VECBASE_RESET_PADDR, + len = SOF_MEM_VECBASE_LIT_SIZE + vector_int2_lit : + org = XCHAL_INTLEVEL2_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_int2_text : + org = XCHAL_INTLEVEL2_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + vector_int3_lit : + org = XCHAL_INTLEVEL3_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_int3_text : + org = XCHAL_INTLEVEL3_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + vector_int4_lit : + org = XCHAL_INTLEVEL4_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_int4_text : + org = XCHAL_INTLEVEL4_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + vector_kernel_lit : + org = XCHAL_KERNEL_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_kernel_text : + org = XCHAL_KERNEL_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + vector_user_lit : + org = XCHAL_USER_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_user_text : + org = XCHAL_USER_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + vector_double_lit : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR - SOF_MEM_VECT_LIT_SIZE, + len = SOF_MEM_VECT_LIT_SIZE + vector_double_text : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR, + len = SOF_MEM_VECT_TEXT_SIZE + sof_sram : + org = SRAM0_BASE, + len = SRAM0_SIZE + system_heap : + org = HEAP_SYSTEM_BASE, + len = HEAP_SYSTEM_SIZE + system_runtime_heap : + org = HEAP_SYS_RUNTIME_BASE, + len = HEAP_SYS_RUNTIME_SIZE + runtime_heap : + org = HEAP_RUNTIME_BASE, + len = HEAP_RUNTIME_SIZE + buffer_heap : + org = HEAP_BUFFER_BASE, + len = HEAP_BUFFER_SIZE + sof_stack : + org = SOF_STACK_END, + len = SOF_STACK_BASE - SOF_STACK_END + static_uuid_entries_seg (!ari) : + org = UUID_ENTRY_ELF_BASE, + len = UUID_ENTRY_ELF_SIZE + static_log_entries_seg (!ari) : + org = LOG_ENTRY_ELF_BASE, + len = LOG_ENTRY_ELF_SIZE + fw_metadata_seg (!ari) : + org = EXT_MANIFEST_ELF_BASE, + len = EXT_MANIFEST_ELF_SIZE +} + +PHDRS +{ + vector_reset_text_phdr PT_LOAD; + vector_reset_lit_phdr PT_LOAD; + vector_base_text_phdr PT_LOAD; + vector_base_lit_phdr PT_LOAD; + vector_int2_text_phdr PT_LOAD; + vector_int2_lit_phdr PT_LOAD; + vector_int3_text_phdr PT_LOAD; + vector_int3_lit_phdr PT_LOAD; + vector_int4_text_phdr PT_LOAD; + vector_int4_lit_phdr PT_LOAD; + vector_kernel_text_phdr PT_LOAD; + vector_kernel_lit_phdr PT_LOAD; + vector_user_text_phdr PT_LOAD; + vector_user_lit_phdr PT_LOAD; + vector_double_text_phdr PT_LOAD; + vector_double_lit_phdr PT_LOAD; + sof_sram_phdr PT_LOAD; + system_heap_phdr PT_LOAD; + system_runtime_heap_phdr PT_LOAD; + runtime_heap_phdr PT_LOAD; + buffer_heap_phdr PT_LOAD; + sof_stack_phdr PT_LOAD; + static_uuid_entries_phdr PT_NOTE; + static_log_entries_phdr PT_NOTE; + metadata_entries_phdr PT_NOTE; +} + +/* Default entry point: */ +ENTRY(_ResetVector) +_rom_store_table = 0; + +/* ABI0 does not use Window base */ +PROVIDE(_memmap_vecbase_reset = XCHAL_VECBASE_RESET_PADDR); + +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000100; +_memmap_cacheattr_wt_base = 0x00000300; +_memmap_cacheattr_bp_base = 0x00000400; +_memmap_cacheattr_unused_mask = 0xFFFFF0FF; +_memmap_cacheattr_wb_trapnull = 0x44444140; +_memmap_cacheattr_wba_trapnull = 0x44444140; +_memmap_cacheattr_wbna_trapnull = 0x44444240; +_memmap_cacheattr_wt_trapnull = 0x44444340; +_memmap_cacheattr_bp_trapnull = 0x44444440; +_memmap_cacheattr_wb_strict = 0x00000100; +_memmap_cacheattr_wt_strict = 0x00000300; +_memmap_cacheattr_bp_strict = 0x00000400; +_memmap_cacheattr_wb_allvalid = 0x44444144; +_memmap_cacheattr_wt_allvalid = 0x44444344; +_memmap_cacheattr_bp_allvalid = 0x44444444; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +_EXT_MAN_ALIGN_ = 16; +EXTERN(ext_man_fw_ver) + +SECTIONS +{ + .ResetVector.text : ALIGN(4) + { + _ResetVector_text_start = ABSOLUTE(.); + KEEP (*(.ResetVector.text)) + _ResetVector_text_end = ABSOLUTE(.); + } >vector_reset_text :vector_reset_text_phdr + + .ResetVector.literal : ALIGN(4) + { + _ResetVector_literal_start = ABSOLUTE(.); + *(.ResetVector.literal) + _ResetVector_literal_end = ABSOLUTE(.); + } >vector_reset_lit :vector_reset_lit_phdr + + .WindowVectors.text : ALIGN(4) + { + _WindowVectors_text_start = ABSOLUTE(.); + KEEP (*(.WindowVectors.text)) + _WindowVectors_text_end = ABSOLUTE(.); + } >vector_base_text :vector_base_text_phdr + + .Level2InterruptVector.literal : ALIGN(4) + { + _Level2InterruptVector_literal_start = ABSOLUTE(.); + *(.Level2InterruptVector.literal) + _Level2InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int2_lit :vector_int2_lit_phdr + + .Level2InterruptVector.text : ALIGN(4) + { + _Level2InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level2InterruptVector.text)) + _Level2InterruptVector_text_end = ABSOLUTE(.); + } >vector_int2_text :vector_int2_text_phdr + + .Level3InterruptVector.literal : ALIGN(4) + { + _Level3InterruptVector_literal_start = ABSOLUTE(.); + *(.Level3InterruptVector.literal) + _Level3InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int3_lit :vector_int3_lit_phdr + + .Level3InterruptVector.text : ALIGN(4) + { + _Level3InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level3InterruptVector.text)) + _Level3InterruptVector_text_end = ABSOLUTE(.); + } >vector_int3_text :vector_int3_text_phdr + + .DebugExceptionVector.literal : ALIGN(4) + { + _DebugExceptionVector_literal_start = ABSOLUTE(.); + *(.DebugExceptionVector.literal) + _DebugExceptionVector_literal_end = ABSOLUTE(.); + } >vector_int4_lit :vector_int4_lit_phdr + + .DebugExceptionVector.text : ALIGN(4) + { + _DebugExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.DebugExceptionVector.text)) + _DebugExceptionVector_text_end = ABSOLUTE(.); + } >vector_int4_text :vector_int4_text_phdr + + .KernelExceptionVector.literal : ALIGN(4) + { + _KernelExceptionVector_literal_start = ABSOLUTE(.); + *(.KernelExceptionVector.literal) + _KernelExceptionVector_literal_end = ABSOLUTE(.); + } >vector_kernel_lit :vector_kernel_lit_phdr + + .KernelExceptionVector.text : ALIGN(4) + { + _KernelExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.KernelExceptionVector.text)) + _KernelExceptionVector_text_end = ABSOLUTE(.); + } >vector_kernel_text :vector_kernel_text_phdr + + .UserExceptionVector.literal : ALIGN(4) + { + _UserExceptionVector_literal_start = ABSOLUTE(.); + *(.UserExceptionVector.literal) + _UserExceptionVector_literal_end = ABSOLUTE(.); + } >vector_user_lit :vector_user_lit_phdr + + .UserExceptionVector.text : ALIGN(4) + { + _UserExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.UserExceptionVector.text)) + _UserExceptionVector_text_end = ABSOLUTE(.); + } >vector_user_text :vector_user_text_phdr + + .DoubleExceptionVector.literal : ALIGN(4) + { + _DoubleExceptionVector_literal_start = ABSOLUTE(.); + *(.DoubleExceptionVector.literal) + _DoubleExceptionVector_literal_end = ABSOLUTE(.); + } >vector_double_lit :vector_double_lit_phdr + + .DoubleExceptionVector.text : ALIGN(4) + { + _DoubleExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.DoubleExceptionVector.text)) + _DoubleExceptionVector_text_end = ABSOLUTE(.); + } >vector_double_text :vector_double_text_phdr + + .fw_ready : ALIGN(4) + { + KEEP (*(.fw_ready)) + KEEP (*(.fw_ready_metadata)) + } >sof_sram :sof_sram_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + KEEP (*(.xt_except_table)) + KEEP (*(.gcc_except_table)) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + KEEP (*(.eh_frame)) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >sof_sram :sof_sram_phdr + + .module_init : ALIGN(4) + { + _module_init_start = ABSOLUTE(.); + *(*.initcall) + _module_init_end = ABSOLUTE(.); + } >sof_sram :sof_sram_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.entry.text) + *(.init.literal) + KEEP(*(.init)) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + KEEP(*(.fini)) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >sof_sram :sof_sram_phdr + + .reset.rodata : ALIGN(4) + { + _reset_rodata_start = ABSOLUTE(.); + *(.reset.rodata) + _reset_rodata_end = ABSOLUTE(.); + } >sof_sram :sof_sram_phdr + + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + KEEP(*(.gnu.linkonce.d.*personality*)) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + KEEP(*(.jcr)) + _trace_ctx_start = ABSOLUTE(.); + *(.trace_ctx) + _trace_ctx_end = ABSOLUTE(.); + _data_end = ABSOLUTE(.); + } >sof_sram :sof_sram_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >sof_sram :sof_sram_phdr + + .bss (NOLOAD) : ALIGN(8) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + } >sof_sram :sof_sram_phdr + + /* stack */ + _end = SOF_STACK_END; + PROVIDE(end = SOF_STACK_END); + _stack_sentry = SOF_STACK_END; + __stack = SOF_STACK_BASE; + + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .xt.insn 0 : + { + KEEP (*(.xt.insn)) + KEEP (*(.gnu.linkonce.x.*)) + } + .xt.prop 0 : + { + KEEP (*(.xt.prop)) + KEEP (*(.xt.prop.*)) + KEEP (*(.gnu.linkonce.prop.*)) + } + .xt.lit 0 : + { + KEEP (*(.xt.lit)) + KEEP (*(.xt.lit.*)) + KEEP (*(.gnu.linkonce.p.*)) + } + .xt.profile_range 0 : + { + KEEP (*(.xt.profile_range)) + KEEP (*(.gnu.linkonce.profile_range.*)) + } + .xt.profile_ranges 0 : + { + KEEP (*(.xt.profile_ranges)) + KEEP (*(.gnu.linkonce.xt.profile_ranges.*)) + } + .xt.profile_files 0 : + { + KEEP (*(.xt.profile_files)) + KEEP (*(.gnu.linkonce.xt.profile_files.*)) + } + + .system_heap (NOLOAD) : ALIGN(8) + { + . = ALIGN (32); + _system_heap_start = ABSOLUTE(.); + . = . + HEAP_SYSTEM_SIZE; + _system_heap_end = ABSOLUTE(.); + } >system_heap :system_heap_phdr + + .system_runtime_heap (NOLOAD) : ALIGN(8) + { + . = ALIGN (HEAP_BUF_ALIGNMENT); + _system_runtime_heap_start = ABSOLUTE(.); + . = . + HEAP_SYS_RUNTIME_SIZE; + _system_runtime_heap_end = ABSOLUTE(.); + } >system_runtime_heap :system_runtime_heap_phdr + + .runtime_heap (NOLOAD) : ALIGN(8) + { + . = ALIGN (32); + _runtime_heap_start = ABSOLUTE(.); + . = . + HEAP_RUNTIME_SIZE; + _runtime_heap_end = ABSOLUTE(.); + } >runtime_heap :runtime_heap_phdr + + .buffer_heap (NOLOAD) : ALIGN(8) + { + . = ALIGN (HEAP_BUF_ALIGNMENT); + _buffer_heap_start = ABSOLUTE(.); + . = . + HEAP_BUFFER_SIZE; + _buffer_heap_end = ABSOLUTE(.); + } >buffer_heap :buffer_heap_phdr + + .sof_stack (NOLOAD) : ALIGN(8) + { + . = ALIGN (4096); + _sof_stack_start = ABSOLUTE(.); + . = . + SOF_STACK_TOTAL_SIZE; + _sof_stack_end = ABSOLUTE(.); + } >sof_stack :sof_stack_phdr + + .static_uuid_entries (COPY) : ALIGN(1024) + { + *(*.static_uuids) + } > static_uuid_entries_seg :static_uuid_entries_phdr + + .static_log_entries (COPY) : ALIGN(1024) + { + *(*.static_log*) + } > static_log_entries_seg :static_log_entries_phdr + + .fw_metadata (COPY) : ALIGN(1024) + { + KEEP (*(.fw_metadata)) + . = ALIGN(_EXT_MAN_ALIGN_); + } >fw_metadata_seg :metadata_entries_phdr +} diff --git a/src/platform/mt8365/platform.c b/src/platform/mt8365/platform.c new file mode 100644 index 000000000000..5ae6378c5eb5 --- /dev/null +++ b/src/platform/mt8365/platform.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 MediaTek. All rights reserved. + * + * Author: Andrew Perepech <andrew.perepech@mediatek.com> + */ + +#include <errno.h> +#include <ipc/dai.h> +#include <ipc/header.h> +#include <ipc/info.h> +#include <kernel/abi.h> +#include <kernel/ext_manifest.h> +#include <platform/drivers/timer.h> +#include <rtos/clk.h> +#include <rtos/timer.h> +#include <rtos/interrupt.h> +#include <sof/compiler_info.h> +#include <sof/debug/debug.h> +#include <sof/drivers/edma.h> +#include <sof/ipc/msg.h> +#include <sof/fw-ready-metadata.h> +#include <sof/lib/agent.h> +#include <sof/lib/cpu.h> +#include <sof/lib/dai.h> +#include <sof/lib/dma.h> +#include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <sof/lib/mm_heap.h> +#include <sof/platform.h> +#include <sof/schedule/edf_schedule.h> +#include <sof/schedule/ll_schedule.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <rtos/sof.h> +#include <sof/trace/dma-trace.h> +#include <sof_versions.h> +#include <stdint.h> +#include <xtensa/hal.h> + +struct sof; + +static const struct sof_ipc_fw_ready ready + __section(".fw_ready") = { + .hdr = { + .cmd = SOF_IPC_FW_READY, + .size = sizeof(struct sof_ipc_fw_ready), + }, + /* dspbox is for DSP initiated IPC, hostbox is for host initiated IPC */ + .version = { + .hdr.size = sizeof(struct sof_ipc_fw_version), + .micro = SOF_MICRO, + .minor = SOF_MINOR, + .major = SOF_MAJOR, + .tag = SOF_TAG, + .abi_version = SOF_ABI_VERSION, + .src_hash = SOF_SRC_HASH, + }, + .flags = DEBUG_SET_FW_READY_FLAGS, +}; + +#define NUM_MTK_WINDOWS 6 + +const struct ext_man_windows xsram_window + __aligned(EXT_MAN_ALIGN) __section(".fw_metadata") __unused = { + .hdr = { + .type = EXT_MAN_ELEM_WINDOW, + .elem_size = ALIGN_UP_COMPILE(sizeof(struct ext_man_windows), EXT_MAN_ALIGN), + }, + .window = { + .ext_hdr = { + .hdr.cmd = SOF_IPC_FW_READY, + .hdr.size = sizeof(struct sof_ipc_window), + .type = SOF_IPC_EXT_WINDOW, + }, + .num_windows = NUM_MTK_WINDOWS, + .window = { + { + .type = SOF_IPC_REGION_UPBOX, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_DSPBOX_SIZE, + .offset = MAILBOX_DSPBOX_OFFSET, + }, + { + .type = SOF_IPC_REGION_DOWNBOX, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_HOSTBOX_SIZE, + .offset = MAILBOX_HOSTBOX_OFFSET, + }, + { + .type = SOF_IPC_REGION_DEBUG, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_DEBUG_SIZE, + .offset = MAILBOX_DEBUG_OFFSET, + }, + { + .type = SOF_IPC_REGION_TRACE, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_TRACE_SIZE, + .offset = MAILBOX_TRACE_OFFSET, + }, + { + .type = SOF_IPC_REGION_STREAM, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_STREAM_SIZE, + .offset = MAILBOX_STREAM_OFFSET, + }, + { + .type = SOF_IPC_REGION_EXCEPTION, + .id = 0, /* map to host window 0 */ + .flags = 0, + .size = MAILBOX_EXCEPTION_SIZE, + .offset = MAILBOX_EXCEPTION_OFFSET, + }, + }, + } +}; + +static SHARED_DATA struct timer timer_shared = { + .id = OSTIMER0, + .irq = SYSTICK_TIMER_IRQ, +}; + +/* Override the default MPU setup. This table matches the memory map + * of the 'sample_controller' core and will need to be modified for + * other cores. + * NOTE: This table sets up all of external memory as shared uncached. + * For best results, edit the LSP memory map to create a separate + * section in shared memory, place all sections that need to be uncached + * into that section, and only map that section uncached. See README + * for more details. + */ +const struct xthal_MPU_entry __xt_mpu_init_table[] __section(".ResetVector.text") = { + XTHAL_MPU_ENTRY(0x00000000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_DEVICE), // infra + XTHAL_MPU_ENTRY(0x40020000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_WRITEBACK), // vectors + XTHAL_MPU_ENTRY(0x40060000, 1, XTHAL_AR_NONE, XTHAL_MEM_DEVICE), // unused + XTHAL_MPU_ENTRY(0x60000000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_WRITEBACK), // DSP FW + XTHAL_MPU_ENTRY(0x60800000, 1, XTHAL_AR_RWXrwx, XTHAL_MEM_NON_CACHEABLE), // shared + XTHAL_MPU_ENTRY(0x61000000, 1, XTHAL_AR_NONE, XTHAL_MEM_DEVICE), // unused +}; + +const unsigned int __xt_mpu_init_table_size __section(".ResetVector.text") = + ARRAY_SIZE(__xt_mpu_init_table); + +int platform_boot_complete(uint32_t boot_message) +{ + mailbox_dspbox_write(0, &ready, sizeof(ready)); + + /* now interrupt host to tell it we are done booting */ + trigger_irq_to_host_req(); + + return 0; +} + +int platform_init(struct sof *sof) +{ + int ret; + + mailbox_sw_reg_write(SRAM_REG_FW_STATUS, 0); + mailbox_sw_reg_write(SRAM_REG_OP_CPU2DSP, 0); + mailbox_sw_reg_write(SRAM_REG_OP_DSP2CPU, 0); + + sof->platform_timer = &timer_shared; + sof->cpu_timers = sof->platform_timer; + + platform_interrupt_init(); + platform_clock_init(sof); + + scheduler_init_edf(); + + /* init low latency domains and schedulers */ + sof->platform_timer_domain = timer_domain_init(sof->platform_timer, PLATFORM_DEFAULT_CLOCK); + scheduler_init_ll(sof->platform_timer_domain); + + platform_timer_start(sof->platform_timer); + sa_init(sof, CONFIG_SYSTICK_PERIOD); + + /* init DMA */ + ret = dmac_init(sof); + if (ret < 0) + return -ENODEV; + + /* Init platform domain */ + sof->platform_dma_domain = dma_multi_chan_domain_init(&sof->dma_info->dma_array[0], 1, + PLATFORM_DEFAULT_CLOCK, false); + scheduler_init_ll(sof->platform_dma_domain); + + /* initialize the host IPC mechanims */ + ipc_init(sof); + + ret = dai_init(sof); + if (ret < 0) + return ret; + +#if CONFIG_TRACE + /* Initialize DMA for Trace*/ + trace_point(TRACE_BOOT_PLATFORM_DMA_TRACE); + dma_trace_init_complete(sof->dmat); +#endif + + /* show heap status */ + heap_trace_all(1); + + return 0; +} + +int platform_context_save(struct sof *sof) +{ + clock_set_freq(CLK_CPU(cpu_get_id()), CLK_DEFAULT_CPU_HZ); + return 0; +} + +void platform_wait_for_interrupt(int level) +{ + arch_wait_for_interrupt(level); +} + diff --git a/src/platform/mtk/dai.c b/src/platform/mtk/dai.c index 0cc22445ca2f..2e1d85a89dfc 100644 --- a/src/platform/mtk/dai.c +++ b/src/platform/mtk/dai.c @@ -1,9 +1,14 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright(c) 2024 Google LLC. All rights reserved. // Author: Andy Ross <andyross@google.com> +#ifndef CONFIG_ZEPHYR_NATIVE_DRIVERS #include <sof/lib/dai-legacy.h> +#endif #include <ipc/dai.h> #include <sof/drivers/afe-drv.h> +#include <stdbool.h> +#include <errno.h> +#include <zephyr/devicetree.h> /* The legacy driver stores register addresses as an offset from an * arbitrary base address (which is not actually a unified block of @@ -12,16 +17,28 @@ */ #if defined(CONFIG_SOC_MT8186) #define MTK_AFE_BASE 0x11210000 +#define SRAM_CPU_START 0x10800000 #elif defined(CONFIG_SOC_SERIES_MT818X) #define MTK_AFE_BASE 0x10b10000 +#define SRAM_CPU_START 0x10d00000 #elif defined(CONFIG_SOC_MT8195) #define MTK_AFE_BASE 0x10890000 +#define SRAM_CPU_START 0x10840000 #elif defined(CONFIG_SOC_MT8196) #define MTK_AFE_BASE 0x1a110000 +#define SRAM_CPU_START 0x1a210000 +#elif defined(CONFIG_SOC_MT8365) +#define MTK_AFE_BASE 0x11220000 +#define SRAM_CPU_START 0x1e000000 #else #error Unrecognized device #endif +#define SRAM_ADSP_START DT_REG_ADDR(DT_NODELABEL(sram0)) +#define SRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sram0)) +#define SRAM_ADSP_END (SRAM_ADSP_START + SRAM_SIZE) +#define SRAM_CPU_END (SRAM_CPU_START + SRAM_SIZE) + /* Bitfield register: address, left shift amount, and number of bits */ struct afe_bitfld { uint32_t reg; @@ -70,7 +87,7 @@ struct afe_cfg { */ static void cfg_convert(const struct afe_cfg *src, struct mtk_base_memif_data *dst) { -#define REGCVT(R) (((R) > 0) ? ((R) - MTK_AFE_BASE) : -1) +#define REGCVT(R) (((R) > 0) ? ((R) - MTK_AFE_BASE) : 0) #define COPYBIT(S, Dr, Ds) do { \ dst->Dr = REGCVT(src->S.reg); \ @@ -124,7 +141,7 @@ static void cfg_convert(const struct afe_cfg *src, struct mtk_base_memif_data *d .base = DT_PROP(n, base), \ .end = DT_PROP(n, end), \ .cur = DT_PROP(n, cur), \ - .fs = DT_PROP(n, fs), \ + COND_PROP(n, fs) \ .hd = DT_PROP(n, hd), \ .enable = DT_PROP(n, enable), \ COND_PROP(n, mono) \ @@ -146,6 +163,7 @@ static struct mtk_base_memif_data afe_memifs[] = { DT_FOREACH_STATUS_OKAY(mediatek_afe, EMPTY_STRUCT) }; +#ifndef CONFIG_ZEPHYR_NATIVE_DRIVERS static struct dai mtk_dais[] = { DT_FOREACH_STATUS_OKAY(mediatek_afe, EMPTY_STRUCT) }; @@ -198,11 +216,84 @@ static const struct dai_info mtk_dai_info = { .dai_type_array = mtk_dai_types, .num_dai_types = ARRAY_SIZE(mtk_dai_types), }; +#endif /* !CONFIG_ZEPHYR_NATIVE_DRIVERS */ + +#if defined(CONFIG_SOC_SERIES_MT818X) || defined(CONFIG_SOC_MT8195) +static unsigned int mtk_afe2adsp_addr(unsigned int addr) +{ + /* CPU -> ADSP address remap */ + if ((addr >= SRAM_CPU_START) && (addr < SRAM_CPU_END)) { + addr = SRAM_ADSP_START + (addr - SRAM_CPU_START); + } + + return addr; +} + +static unsigned int mtk_adsp2afe_addr(unsigned int addr) +{ + /* ADSP -> CPU address remap */ + if ((addr >= SRAM_ADSP_START) && (addr < SRAM_ADSP_END)) { + addr = SRAM_CPU_START + (addr - SRAM_ADSP_START); + } + + return addr; +} +#endif /* Static table of fs register values. TODO: binary search */ static unsigned int mtk_afe_fs_timing(unsigned int rate) { static const struct { int hz, reg; } rate2reg[] = { +#if defined(CONFIG_SOC_MT8188) || defined(CONFIG_SOC_MT8195) + { 7350, 16 }, + { 8000, 0 }, + { 11025, 17 }, + { 12000, 1 }, + { 14700, 18 }, + { 16000, 2 }, + { 22050, 19 }, + { 24000, 3 }, + { 29400, 20 }, + { 32000, 4 }, + { 44100, 21 }, + { 48000, 5 }, + { 88200, 22 }, + { 96000, 6 }, + { 176400, 23 }, + { 192000, 7 }, + { 352800, 24 }, + { 384000, 8 }, +#elif defined(CONFIG_SOC_MT8186) + { 8000, 0 }, + { 11025, 1 }, + { 12000, 2 }, + { 16000, 4 }, + { 22050, 5 }, + { 24000, 6 }, + { 32000, 8 }, + { 44100, 9 }, + { 48000, 10 }, + { 88200, 11 }, + { 96000, 12 }, + { 176400, 13 }, + { 192000, 14 }, + { 352800, 7 }, + { 384000, 3 }, +#elif defined(CONFIG_SOC_MT8365) + { 8000, 0 }, + { 11025, 1 }, + { 12000, 2 }, + { 16000, 4 }, + { 22050, 5 }, + { 24000, 6 }, + { 32000, 8 }, + { 44100, 9 }, + { 48000, 10 }, + { 88200, 11 }, + { 96000, 12 }, + { 176400, 13 }, + { 192000, 14 }, +#else { 8000, 0 }, { 11025, 1 }, { 12000, 2 }, @@ -218,6 +309,7 @@ static unsigned int mtk_afe_fs_timing(unsigned int rate) { 192000, 18 }, { 352800, 21 }, { 384000, 22 }, +#endif }; for (int i = 0; i < ARRAY_SIZE(rate2reg); i++) @@ -239,9 +331,13 @@ struct mtk_base_afe_platform mtk_afe_platform = { .memif_32bit_supported = 0, .irq_datas = NULL, .irqs_size = 0, - .dais_size = ARRAY_SIZE(mtk_dais), + .dais_size = ARRAY_SIZE(afes), .afe_fs = mtk_afe_fs, .irq_fs = mtk_afe_fs_timing, +#if defined(CONFIG_SOC_SERIES_MT818X) || defined(CONFIG_SOC_MT8195) + .afe2adsp_addr = mtk_afe2adsp_addr, + .adsp2afe_addr = mtk_adsp2afe_addr, +#endif }; int mtk_dai_init(struct sof *sof) @@ -253,6 +349,7 @@ int mtk_dai_init(struct sof *sof) afe_memifs[i].id = i; cfg_convert(&afes[i], &afe_memifs[i]); +#ifndef CONFIG_ZEPHYR_NATIVE_DRIVERS /* Also initialize the dais array */ extern const struct dai_driver afe_dai_driver; @@ -273,6 +370,7 @@ int mtk_dai_init(struct sof *sof) int hs = (i << 16) | di; mtk_dais[di].plat_data.fifo[0].handshake = hs; +#endif } /* DTS stores the direction as a boolean property, but the @@ -288,7 +386,9 @@ int mtk_dai_init(struct sof *sof) for (/**/; i < ARRAY_SIZE(afes); i++) __ASSERT_NO_MSG(!afes[i].downlink); +#ifndef CONFIG_ZEPHYR_NATIVE_DRIVERS sof->dai_info = &mtk_dai_info; sof->dma_info = &mtk_dma_info; +#endif return 0; } diff --git a/src/platform/mtk/include/platform/lib/memory.h b/src/platform/mtk/include/platform/lib/memory.h index a84809bf2d48..1e3acbee6912 100644 --- a/src/platform/mtk/include/platform/lib/memory.h +++ b/src/platform/mtk/include/platform/lib/memory.h @@ -16,11 +16,6 @@ BUILD_ASSERT(PLATFORM_DCACHE_ALIGN == XCHAL_DCACHE_LINESIZE); #define uncache_to_cache(addr) (addr) #define cache_to_uncache(addr) (addr) -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - #define host_to_local(addr) (addr) #define PLATFORM_HEAP_SYSTEM 1 @@ -42,7 +37,7 @@ static inline void *platform_shared_get(void *ptr, int bytes) * validation that the kernel driver interprets the manifest * correctly. Right now we're using the historical addresses. */ -#ifdef CONFIG_SOC_MT8195 +#if defined(CONFIG_SOC_MT8195) || defined(CONFIG_SOC_MT8365) #define MTK_IPC_BASE (DT_REG_ADDR(DT_NODELABEL(dram0)) + 0x800000) #else #define MTK_IPC_BASE (DT_REG_ADDR(DT_NODELABEL(dram0)) + 0x500000) diff --git a/src/platform/mtk/platform.c b/src/platform/mtk/platform.c index 53b48f12b6e9..22497cf19641 100644 --- a/src/platform/mtk/platform.c +++ b/src/platform/mtk/platform.c @@ -24,12 +24,25 @@ void mtk_dai_init(struct sof *sof); +#ifndef CONFIG_SOC_MT8365 #define MBOX0 DEVICE_DT_GET(DT_INST(0, mediatek_mbox)) #define MBOX1 DEVICE_DT_GET(DT_INST(1, mediatek_mbox)) +#else +#define IPI DEVICE_DT_GET(DT_INST(0, mediatek_ipi)) + +#define MAILBOX_DEBUG_BASE MTK_IPC_WIN_BASE(DEBUG) + +#define SRAM_REG_OP_CPU2DSP 0x8 +#define SRAM_REG_OP_DSP2CPU 0xC + +#define ADSP_IPI_OP_REQ 0x1 +#define ADSP_IPI_OP_RSP 0x2 +#endif /* Use the same UUID as in "ipc-zephyr.c", which is actually an Intel driver */ SOF_DEFINE_REG_UUID(zipc_task); +#ifndef CONFIG_SOC_MT8365 static void mbox_cmd_fn(const struct device *mbox, void *arg) { /* We're in ISR context. This unblocks the IPC task thread, @@ -38,6 +51,7 @@ static void mbox_cmd_fn(const struct device *mbox, void *arg) */ ipc_schedule_process(ipc_get()); } +#endif enum task_state ipc_platform_do_cmd(struct ipc *ipc) { @@ -54,13 +68,23 @@ enum task_state ipc_platform_do_cmd(struct ipc *ipc) void ipc_platform_complete_cmd(struct ipc *ipc) { +#ifndef CONFIG_SOC_MT8365 mtk_adsp_mbox_signal(MBOX0, 1); +#else + *(uint32_t *)(MAILBOX_DEBUG_BASE + SRAM_REG_OP_DSP2CPU) = ADSP_IPI_OP_RSP; + mtk_adsp_ipi_signal(IPI, 1); +#endif } static void mtk_ipc_send(const void *msg, size_t sz) { mailbox_dspbox_write(0, msg, sz); +#ifndef CONFIG_SOC_MT8365 mtk_adsp_mbox_signal(MBOX1, 0); +#else + *(uint32_t *)(MAILBOX_DEBUG_BASE + SRAM_REG_OP_DSP2CPU) = ADSP_IPI_OP_REQ; + mtk_adsp_ipi_signal(IPI, 1); +#endif } int ipc_platform_send_msg(const struct ipc_msg *msg) @@ -75,11 +99,36 @@ int ipc_platform_send_msg(const struct ipc_msg *msg) return 0; } +#ifndef CONFIG_SOC_MT8365 static void mbox_reply_fn(const struct device *mbox, void *arg) { ipc_get()->is_notification_pending = false; } +#else + +static void ipi_handler_fn(const struct device *ipi, void *arg) +{ + uint32_t op; + + op = *(uint32_t *)(MAILBOX_DEBUG_BASE + SRAM_REG_OP_CPU2DSP); + + switch (op) { + case ADSP_IPI_OP_REQ: + /* new message from host */ + ipc_schedule_process(ipc_get()); + break; + case ADSP_IPI_OP_RSP: + /* reply message(done) from host */ + ipc_get()->is_notification_pending = false; + break; + default: + /* do nothing */ + break; + } +} +#endif + /* "Host Page Table" support. The platform is responsible for * providing a buffer into which the IPC layer reads a DMA "page * table" from the host. This isn't really a page table, it's a @@ -108,14 +157,23 @@ struct ipc_data_host_buffer *ipc_platform_get_host_buffer(struct ipc *ipc) int platform_ipc_init(struct ipc *ipc) { mtk_host_buffer.page_table = hostbuf_ptable; +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + mtk_host_buffer.dmac = sof_dma_get(SOF_DMA_DIR_HMEM_TO_LMEM, 0, + SOF_DMA_DEV_HOST, SOF_DMA_ACCESS_SHARED); +#else mtk_host_buffer.dmac = dma_get(DMA_DIR_HMEM_TO_LMEM, 0, DMA_DEV_HOST, DMA_ACCESS_SHARED); +#endif schedule_task_init_edf(&ipc->ipc_task, SOF_UUID(zipc_task_uuid), &ipc_task_ops, ipc, 0, 0); +#ifndef CONFIG_SOC_MT8365 mtk_adsp_mbox_set_handler(MBOX0, 0, mbox_cmd_fn, NULL); mtk_adsp_mbox_set_handler(MBOX1, 1, mbox_reply_fn, NULL); +#else + mtk_adsp_ipi_set_handler(IPI, 0, ipi_handler_fn, NULL); +#endif return 0; } @@ -157,18 +215,63 @@ void clocks_init(struct sof *sof) sof->clocks = clks; } +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS +/* + * Allocate SOF-level channel descriptor arrays (struct dma_chan_data[]) for + * each sof_dma entry. Native Zephyr DMA drivers manage their own internal + * channel state but do not allocate the SOF-layer chan[] array that + * dai-zephyr.c and host-zephyr.c rely on (e.g. dd->chan = &dd->dma->chan[i]). + * Legacy DMA drivers (dummy-dma, afe-memif) did this in their own probe(); + * in the native path we do it here after dmac_init() registers the DMA info. + */ +static int mtk_dma_chan_alloc(struct sof *sof) +{ + int i, j; + + for (i = 0; i < sof->dma_info->num_dmas; i++) { + struct sof_dma *d = &sof->dma_info->dma_array[i]; + + if (!d->plat_data.channels || d->chan) + continue; + + d->chan = rzalloc(SOF_MEM_FLAG_KERNEL, + d->plat_data.channels * sizeof(struct dma_chan_data)); + if (!d->chan) + return -ENOMEM; + + for (j = 0; j < d->plat_data.channels; j++) { + d->chan[j].dma = d; + d->chan[j].index = j; + } + } + + return 0; +} +#endif + int platform_init(struct sof *sof) { + int ret; + clocks_init(sof); + scheduler_init_edf(); sof->platform_timer_domain = zephyr_domain_init(PLATFORM_DEFAULT_CLOCK); + scheduler_init_ll(sof->platform_timer_domain); mtk_dai_init(sof); +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + /* In native mode, DMA is registered in sof/zephyr/lib/dma.c */ + dmac_init(sof); + ret = mtk_dma_chan_alloc(sof); + if (ret < 0) + return ret; +#endif ipc_init(sof); - scheduler_init_edf(); - scheduler_init_ll(sof->platform_timer_domain); +#if CONFIG_SCHEDULE_DMA_MULTI_CHANNEL sof->platform_dma_domain = dma_multi_chan_domain_init(&sof->dma_info->dma_array[0], sof->dma_info->num_dmas, PLATFORM_DEFAULT_CLOCK, false); +#endif sa_init(sof, CONFIG_SYSTICK_PERIOD); return 0; } diff --git a/src/platform/novalake/include/platform/lib/clk.h b/src/platform/novalake/include/platform/lib/clk.h new file mode 100644 index 000000000000..e4017efcf329 --- /dev/null +++ b/src/platform/novalake/include/platform/lib/clk.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022-2024 Intel Corporation. + * + * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> + * Keyon Jie <yang.jie@linux.intel.com> + * Rander Wang <rander.wang@intel.com> + */ + +#ifdef __SOF_LIB_CLK_H__ + +#ifndef __PLATFORM_LIB_CLK_H__ +#define __PLATFORM_LIB_CLK_H__ + +#include <ace/lib/clk.h> + +#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_LOWEST_FREQ_IDX CPU_WOVCRO_FREQ_IDX + +#define CPU_DEFAULT_IDX CPU_HPRO_FREQ_IDX + +#define NUM_CPU_FREQ 3 + +#endif /* __PLATFORM_LIB_CLK_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/clk.h" + +#endif /* __SOF_LIB_CLK_H__ */ diff --git a/src/platform/novalake/include/platform/lib/mailbox.h b/src/platform/novalake/include/platform/lib/mailbox.h new file mode 100644 index 000000000000..7d253fd9327e --- /dev/null +++ b/src/platform/novalake/include/platform/lib/mailbox.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022-2024 Intel Corporation. + */ + +#ifdef __SOF_LIB_MAILBOX_H__ + +#ifndef __PLATFORM_LIB_MAILBOX_H__ +#define __PLATFORM_LIB_MAILBOX_H__ + +#include <ace/lib/mailbox.h> + +#endif /* __PLATFORM_LIB_MAILBOX_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/mailbox.h" + +#endif /* __SOF_LIB_MAILBOX_H__ */ diff --git a/src/platform/novalake/include/platform/lib/memory.h b/src/platform/novalake/include/platform/lib/memory.h new file mode 100644 index 000000000000..666c4fc9eb89 --- /dev/null +++ b/src/platform/novalake/include/platform/lib/memory.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022-2024 Intel Corporation. + * + * Author: Marcin Rajwa <marcin.rajwa@linux.intel.com> + */ + +#ifdef __SOF_LIB_MEMORY_H__ + +#ifndef __PLATFORM_LIB_MEMORY_H__ +#define __PLATFORM_LIB_MEMORY_H__ + +/* prioritize definitions in Zephyr SoC layer */ +#include <adsp_memory.h> + +#include <ace/lib/memory.h> +#include <mem_window.h> +#include <sof/lib/cpu.h> + +/* HP SRAM windows */ +#define WIN_BASE(n) DT_REG_ADDR(DT_PHANDLE(MEM_WINDOW_NODE(n), memory)) + +/* window 0 */ +#define SRAM_SW_REG_BASE ((uint32_t)(WIN_BASE(0) + WIN0_OFFSET)) +#define SRAM_SW_REG_SIZE 0x1000 + +#define SRAM_OUTBOX_BASE (SRAM_SW_REG_BASE + SRAM_SW_REG_SIZE) +#define SRAM_OUTBOX_SIZE 0x1000 + +/* window 1 */ +#define SRAM_INBOX_BASE ((uint32_t)(WIN_BASE(1) + WIN1_OFFSET)) +#define SRAM_INBOX_SIZE ((uint32_t)WIN_SIZE(1)) + +/* window 2 */ +#define SRAM_DEBUG_BASE ((uint32_t)(WIN_BASE(2) + WIN2_OFFSET)) +#define SRAM_DEBUG_SIZE 0x800 + +#define SRAM_EXCEPT_BASE (SRAM_DEBUG_BASE + SRAM_DEBUG_SIZE) +#define SRAM_EXCEPT_SIZE 0x800 + +#define SRAM_STREAM_BASE (SRAM_EXCEPT_BASE + SRAM_EXCEPT_SIZE) +#define SRAM_STREAM_SIZE 0x1000 + +/* Stack configuration */ +#define SOF_STACK_SIZE (CONFIG_SOF_STACK_SIZE) + +#define PLATFORM_HEAP_SYSTEM CONFIG_CORE_COUNT /* one per core */ +#define PLATFORM_HEAP_SYSTEM_RUNTIME CONFIG_CORE_COUNT /* one per core */ +#define PLATFORM_HEAP_RUNTIME 1 +#define PLATFORM_HEAP_RUNTIME_SHARED 1 +#define PLATFORM_HEAP_SYSTEM_SHARED 1 +#define PLATFORM_HEAP_BUFFER 2 + +/** + * size of HPSRAM system heap + */ +#define HEAPMEM_SIZE CONFIG_SOF_ZEPHYR_HEAP_SIZE + +#if CONFIG_COLD_STORE_EXECUTE_DRAM && \ + (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE || !defined(LL_EXTENSION_BUILD)) +#define __cold __section(".cold") +#define __cold_rodata __section(".coldrodata") +#endif + +#endif /* __PLATFORM_LIB_MEMORY_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/lib/memory.h" + +#endif /* __SOF_LIB_MEMORY_H__ */ diff --git a/src/platform/novalake/include/platform/platform.h b/src/platform/novalake/include/platform/platform.h new file mode 100644 index 000000000000..62ba6a24fe97 --- /dev/null +++ b/src/platform/novalake/include/platform/platform.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022-2024 Intel Corporation. + * + * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> + * Keyon Jie <yang.jie@linux.intel.com> + * Rander Wang <rander.wang@intel.com> + * Xiuli Pan <xiuli.pan@linux.intel.com> + */ + +#ifdef __SOF_PLATFORM_H__ + +#ifndef __PLATFORM_PLATFORM_H__ +#define __PLATFORM_PLATFORM_H__ + +#include <rtos/clk.h> + +/*! \def PLATFORM_DEFAULT_CLOCK + * \brief clock source for audio pipeline + * + * There are two types of clock: cpu clock which is a internal clock in + * xtensa core, and ssp clock which is provided by external HW IP. + * The choice depends on HW features on different platform + */ +#define PLATFORM_DEFAULT_CLOCK CLK_SSP + +/* Host page size */ +#define HOST_PAGE_SIZE 4096 + +/* Platform stream capabilities */ +#define PLATFORM_MAX_CHANNELS 8 +#define PLATFORM_MAX_STREAMS 16 + +/* local buffer size of DMA tracing */ +#define DMA_TRACE_LOCAL_SIZE (HOST_PAGE_SIZE * 2) + +#endif /* __PLATFORM_PLATFORM_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/platform.h" + +#endif /* __SOF_PLATFORM_H__ */ diff --git a/src/platform/novalake/include/platform/trace/trace.h b/src/platform/novalake/include/platform/trace/trace.h new file mode 100644 index 000000000000..2e1e6022854f --- /dev/null +++ b/src/platform/novalake/include/platform/trace/trace.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022-2024 Intel Corporation. + */ + +#ifdef __SOF_TRACE_TRACE_H__ + +#ifndef __PLATFORM_TRACE_TRACE_H__ +#define __PLATFORM_TRACE_TRACE_H__ + +#include <sof/lib/cpu.h> +#include <sof/lib/mailbox.h> +#include <sof/lib/memory.h> +#include <stdint.h> + +/* Platform defined trace code */ +static inline void platform_trace_point(uint32_t x) +{ } + +#endif /* __PLATFORM_TRACE_TRACE_H__ */ + +#else + +#error "This file shouldn't be included from outside of sof/trace/trace.h" + +#endif /* __SOF_TRACE_TRACE_H__ */ diff --git a/src/platform/novalake/lib/clk.c b/src/platform/novalake/lib/clk.c new file mode 100644 index 000000000000..29a69aaab1d3 --- /dev/null +++ b/src/platform/novalake/lib/clk.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022-2024 Intel Corporation. +// +// Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> +// Janusz Jankowski <janusz.jankowski@linux.intel.com> + +#include <sof/common.h> +#include <rtos/clk.h> + +static const struct freq_table platform_cpu_freq[] = { + { 38400000, 38400 }, + { 120000000, 120000 }, + { CLK_MAX_CPU_HZ, CLK_MAX_CPU_HZ / 1000 } +}; + +STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, invalid_number_of_cpu_frequencies); + +const struct freq_table *cpu_freq = platform_cpu_freq; diff --git a/src/platform/posix/dma.c b/src/platform/posix/dma.c index fa1f030d87cd..63ab0c31e069 100644 --- a/src/platform/posix/dma.c +++ b/src/platform/posix/dma.c @@ -176,7 +176,7 @@ DEVICE_DEFINE(pzdma2, "pzdma2", pzdma_init, NULL, &pzdma2_data, &pzdma2_cfg, DEVICE_DEFINE(pzdma3, "pzdma3", pzdma_init, NULL, &pzdma3_data, &pzdma3_cfg, POST_KERNEL, 0, &pzdma_api); -struct dma posix_sof_dma[4]; +struct sof_dma posix_sof_dma[4]; const struct dma_info posix_sof_dma_info = { .dma_array = posix_sof_dma, @@ -194,7 +194,7 @@ void posix_dma_init(struct sof *sof) }; for (int i = 0; i < ARRAY_SIZE(posix_sof_dma); i++) { - posix_sof_dma[i] = (struct dma) {}; + posix_sof_dma[i] = (struct sof_dma) {}; posix_sof_dma[i].plat_data.dir = 0xffffffff; posix_sof_dma[i].plat_data.caps = 0xffffffff; posix_sof_dma[i].plat_data.devs = 0xffffffff; diff --git a/src/platform/posix/fuzz.c b/src/platform/posix/fuzz.c index 555a22d40578..e60d8e549035 100644 --- a/src/platform/posix/fuzz.c +++ b/src/platform/posix/fuzz.c @@ -10,37 +10,68 @@ #include <zephyr/sys/time_units.h> #include <nsi_cpu_if.h> #include <nsi_main_semipublic.h> +#include <platform/fuzz.h> const uint8_t *posix_fuzz_buf; size_t posix_fuzz_sz; +/* Number of simulator quanta the budget is split into for the + * drain-or-abort loop. More quanta = earlier exit on quick testcases. + */ +#define POSIX_FUZZ_DRAIN_QUANTA 8 + /** * Entry point for fuzzing. Works by placing the data * into two known symbols, triggering an app-visible interrupt, and - * then letting the simulator run for a fixed amount of time (intended to be - * "long enough" to handle the event and reach a quiescent state - * again) + * then letting the simulator run for up to a fixed amount of time + * split into small quanta, exiting as soon as the OS has drained the + * staged fuzz input. If the budget is exhausted before drain we drop + * pending state to keep testcases isolated. */ NATIVE_SIMULATOR_IF int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { static bool runner_initialized; + uint64_t total_us; + uint64_t quantum_us; + int i; if (!runner_initialized) { nsi_init(0, NULL); runner_initialized = true; } + total_us = k_ticks_to_us_ceil64(CONFIG_ZEPHYR_POSIX_FUZZ_TICKS); + quantum_us = (total_us + POSIX_FUZZ_DRAIN_QUANTA - 1) / POSIX_FUZZ_DRAIN_QUANTA; + if (quantum_us == 0) + quantum_us = 1; + + /* Fresh testcase: drop any leftovers from a previous case before + * staging the new buffer, so state from the prior input cannot + * influence this one. + */ + posix_fuzz_case_begin(); + /* Provide the fuzz data to the embedded OS as an interrupt, with - * "DMA-like" data placed into native_fuzz_buf/sz + * "DMA-like" data placed into posix_fuzz_buf/sz. */ - posix_fuzz_buf = (void *)data; + posix_fuzz_buf = data; posix_fuzz_sz = sz; hw_irq_ctrl_set_irq(CONFIG_ZEPHYR_POSIX_FUZZ_IRQ); - /* Give the OS time to process whatever happened in that - * interrupt and reach an idle state. + /* Bounded drain loop: run simulator in small quanta and exit + * as soon as both the raw input buffer and the staged IPC + * queue are empty. + */ + for (i = 0; i < POSIX_FUZZ_DRAIN_QUANTA; i++) { + nsi_exec_for(quantum_us); + if (!posix_fuzz_case_pending()) + return 0; + } + + /* Budget exhausted without full drain: hard reset so the next + * testcase starts clean. */ - nsi_exec_for(k_ticks_to_us_ceil64(CONFIG_ZEPHYR_POSIX_FUZZ_TICKS)); + posix_fuzz_case_abort(); return 0; } diff --git a/src/platform/posix/include/platform/fuzz.h b/src/platform/posix/include/platform/fuzz.h new file mode 100644 index 000000000000..91f28b3285d2 --- /dev/null +++ b/src/platform/posix/include/platform/fuzz.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2026 Intel Corporation. All rights reserved. */ + +#ifndef PLATFORM_POSIX_FUZZ_H +#define PLATFORM_POSIX_FUZZ_H + +#include <stdbool.h> + +/** + * @brief Reset IPC staging state at the start of a new fuzz testcase. + * + * Must be called before staging new fuzz input so that any leftover + * state from a previous testcase that failed to drain within the tick + * budget cannot influence the new one. + */ +void posix_fuzz_case_begin(void); + +/** + * @brief Query whether any staged IPC fuzz input is still pending. + * + * @return true if the raw input buffer or the IPC staging queue is + * non-empty, false when fully drained. + */ +bool posix_fuzz_case_pending(void); + +/** + * @brief Hard-reset all staged IPC fuzz state. + * + * Called when the simulator tick budget is exhausted before the input + * has been fully drained, ensuring the next testcase starts clean. + */ +void posix_fuzz_case_abort(void); + +#endif /* PLATFORM_POSIX_FUZZ_H */ diff --git a/src/platform/posix/include/platform/lib/memory.h b/src/platform/posix/include/platform/lib/memory.h index e15e5f370aec..f2f6e567223b 100644 --- a/src/platform/posix/include/platform/lib/memory.h +++ b/src/platform/posix/include/platform/lib/memory.h @@ -6,25 +6,38 @@ #define PLATFORM_HOST_PLATFORM_MEMORY_H #include <stdint.h> +#include <ipc/header.h> #define PLATFORM_DCACHE_ALIGN 64 #define uncache_to_cache(addr) (addr) #define cache_to_uncache(addr) (addr) +/* + * Mailbox base macros must yield byte-pointer arithmetic so that the + * generic mailbox API in `sof/src/include/sof/lib/mailbox.h` + * (`MAILBOX_HOSTBOX_BASE + offset`, etc., where `offset` is a byte + * offset) addresses the intended byte. The backing storage is + * declared as `uint32_t[]` only for natural-alignment; addressing is + * done through a `uint8_t *` cast so byte offsets do not get scaled + * by `sizeof(uint32_t)`. Every other SOF platform defines these + * bases as plain byte addresses (integer literals or + * `SRAM_INBOX_BASE`), so the cast keeps POSIX consistent with that + * ABI. + */ extern uint32_t posix_hostbox[]; -#define MAILBOX_HOSTBOX_SIZE 1024 -#define MAILBOX_HOSTBOX_BASE (&posix_hostbox[0]) +#define MAILBOX_HOSTBOX_SIZE SOF_IPC_MSG_MAX_SIZE +#define MAILBOX_HOSTBOX_BASE ((uint8_t *)&posix_hostbox[0]) extern uint32_t posix_dspbox[]; #define MAILBOX_DSPBOX_SIZE 4096 -#define MAILBOX_DSPBOX_BASE (&posix_dspbox[0]) +#define MAILBOX_DSPBOX_BASE ((uint8_t *)&posix_dspbox[0]) extern uint32_t posix_stream[]; #define MAILBOX_STREAM_SIZE 4096 -#define MAILBOX_STREAM_BASE (&posix_stream[0]) +#define MAILBOX_STREAM_BASE ((uint8_t *)&posix_stream[0]) extern uint32_t posix_trace[]; -#define MAILBOX_TRACE_BASE (&posix_trace[0]) +#define MAILBOX_TRACE_BASE ((uint8_t *)&posix_trace[0]) #define MAILBOX_TRACE_SIZE 4096 #define PLATFORM_HEAP_SYSTEM 1 @@ -34,11 +47,6 @@ extern uint32_t posix_trace[]; #define host_to_local(addr) (addr) -static inline void *platform_shared_get(void *ptr, int bytes) -{ - return ptr; -} - #define SHARED_DATA /**/ #endif /* PLATFORM_HOST_PLATFORM_MEMORY_H */ diff --git a/src/platform/posix/ipc.c b/src/platform/posix/ipc.c index b8c54b9a38d9..c8012a697847 100644 --- a/src/platform/posix/ipc.c +++ b/src/platform/posix/ipc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright(c) 2022 Google LLC. All rights reserved. // Author: Andy Ross <andyross@google.com> +#include <platform/fuzz.h> #include <sof/lib/uuid.h> #include <sof/ipc/msg.h> #include <sof/lib/mailbox.h> @@ -8,6 +9,8 @@ #include <sof/ipc/schedule.h> #include <sof/schedule/edf_schedule.h> #include <sof/audio/component_ext.h> +#include <stdbool.h> +#include <stddef.h> // 6c8f0d53-ff77-4ca1-b825-c0c4e1b0d322 SOF_DEFINE_REG_UUID(ipc_task_posix); @@ -22,8 +25,9 @@ static void posix_ipc_isr(void *arg) ipc_schedule_process(global_ipc); } -// External symbols set up by the fuzzing layer -extern uint8_t *posix_fuzz_buf, posix_fuzz_sz; +// External symbols set up by the fuzzing layer in fuzz.c. +extern const uint8_t *posix_fuzz_buf; +extern size_t posix_fuzz_sz; // Lots of space. Should really synchronize with the -max_len // parameter to libFuzzer (defaults to 4096), but that requires @@ -32,42 +36,77 @@ extern uint8_t *posix_fuzz_buf, posix_fuzz_sz; static uint8_t fuzz_in[65536]; static size_t fuzz_in_sz; -// The protocol here is super simple: the first byte is a message size -// in units of 16 bits (the buffer maximum defaults to 384 bytes, and -// I didn't want to waste space early in the buffer lest I confuse the -// fuzzing heuristics). We then copy that much of the input buffer -// (subject to clamping obviously) into the incoming IPC message -// buffer and invoke the ISR. Any remainder will be delivered -// synchronously as another message after receipt of "complete_cmd()" -// from the SOF engine, etc... Eventually we'll receive another fuzz -// input after some amount of simulated time has passed (c.f. -// CONFIG_ZEPHYR_POSIX_FUZZ_TICKS) +/* + * Testcase-isolation helpers used by the libFuzzer entry point in + * fuzz.c. They keep ownership of the cross-call state in one module + * so a new testcase never observes leftovers from a previous one that + * failed to drain inside the simulator tick budget. + */ +void posix_fuzz_case_begin(void) +{ + fuzz_in_sz = 0; +} + +bool posix_fuzz_case_pending(void) +{ + return posix_fuzz_sz != 0 || fuzz_in_sz != 0; +} + +void posix_fuzz_case_abort(void) +{ + posix_fuzz_sz = 0; + fuzz_in_sz = 0; +} + +// The framing protocol is super simple: the first two bytes are a +// little-endian message size in bytes (capped below at +// SOF_IPC_MSG_MAX_SIZE - 4 so it always fits in the IPC message +// buffer). We then copy that much of the input buffer (subject to +// clamping obviously) into the incoming IPC message buffer and invoke +// the ISR. Any remainder will be delivered synchronously as another +// message after receipt of "complete_cmd()" from the SOF engine, +// etc... Eventually we'll receive another fuzz input after some +// amount of simulated time has passed (c.f. +// CONFIG_ZEPHYR_POSIX_FUZZ_TICKS). +// +// The historical encoding used a single byte multiplied by 2, which +// capped each message at 510 bytes. That was fine for IPC3 +// (SOF_IPC_MSG_MAX_SIZE = 384) but limited IPC4 (max 4096) to ~12% +// of its envelope, hiding all large_config / vendor_config / +// pipeline-state-data paths from coverage feedback. Widening to two +// bytes lets the fuzzer reach the full IPC4 message range; existing +// corpora are reinterpreted but libFuzzer recovers within minutes. +#define POSIX_FUZZ_HDR_LEN 2 + static void fuzz_isr(const void *arg) { size_t rem, i, n = MIN(posix_fuzz_sz, sizeof(fuzz_in) - fuzz_in_sz); - bool comp_new = false; - int comp_idx = 0; for (i = 0; i < n; i++) fuzz_in[fuzz_in_sz++] = posix_fuzz_buf[i]; - if (fuzz_in_sz == 0) + if (fuzz_in_sz < POSIX_FUZZ_HDR_LEN) return; if (!global_ipc->comp_data) return; - size_t maxsz = SOF_IPC_MSG_MAX_SIZE - 4, msgsz = fuzz_in[0] * 2; + size_t maxsz = SOF_IPC_MSG_MAX_SIZE - 4; + size_t msgsz = (size_t)fuzz_in[0] | ((size_t)fuzz_in[1] << 8); - n = MIN(msgsz, MIN(fuzz_in_sz - 1, maxsz)); - rem = fuzz_in_sz - (n + 1); + msgsz = MIN(msgsz, maxsz); + n = MIN(msgsz, fuzz_in_sz - POSIX_FUZZ_HDR_LEN); + rem = fuzz_in_sz - (n + POSIX_FUZZ_HDR_LEN); memset(global_ipc->comp_data, 0, maxsz); - memcpy(global_ipc->comp_data, &fuzz_in[1], n); - memmove(&fuzz_in[0], &fuzz_in[n + 1], rem); + memcpy(global_ipc->comp_data, &fuzz_in[POSIX_FUZZ_HDR_LEN], n); + memmove(&fuzz_in[0], &fuzz_in[n + POSIX_FUZZ_HDR_LEN], rem); fuzz_in_sz = rem; #ifdef CONFIG_IPC_MAJOR_3 + bool comp_new = false; + int comp_idx = 0; + // One special case: a first byte of 0xff (which is in the // otherwise-ignored size value at the front of the command -- // we rewrite those) is interpreted as a "component new" @@ -86,8 +125,6 @@ static void fuzz_isr(const void *arg) // on only rarely, fill it in manually. *(uint32_t *)global_ipc->comp_data = msgsz; - struct sof_ipc_comp *cc = global_ipc->comp_data; - // "Adjust" the command to represent a "comp new" command per // above. Basically we want to copy in the UUID value for one // of the runtime-enumerated drivers based on data already @@ -146,11 +183,38 @@ static void fuzz_isr(const void *arg) // ipc_platform_compact_read_msg(), writing 8 bytes unconditionally on // the header object it receives, which is then returned here, and // then passed to ipc_cmd(). +// +// The harness also mirrors the framed message into MAILBOX_HOSTBOX so +// that handlers reading payload directly from the hostbox region +// (large_config_set/get, set_dx, set_pipeline_state, vendor_config and +// friends in ipc4/handler-user.c and ipc4/handler-kernel.c) observe +// the fuzz bytes rather than stale or zero-filled memory. +// +// The two IPC majors split header and payload differently: +// +// * IPC3 carries the header in-band at the start of the message, and +// mailbox_validate() walks the full message starting from offset 0 +// of the hostbox. The full message is mirrored as-is. +// +// * IPC4 splits the 8-byte compact header (consumed via +// ipc_compact_read_msg()) from the payload, which on real hardware +// lives in HOSTBOX. The harness therefore mirrors only the +// post-header bytes, so the first dword of MAILBOX_HOSTBOX matches +// the first dword of the IPC4 payload (e.g. pipelines_count for +// SET_PIPELINE_STATE) instead of header bits. +// +// posix_hostbox is sized to SOF_IPC_MSG_MAX_SIZE (see +// platform/lib/memory.h), so the copy is always in bounds for both +// IPC3 and IPC4 message envelopes. enum task_state ipc_platform_do_cmd(struct ipc *ipc) { struct ipc_cmd_hdr *hdr; #ifdef CONFIG_IPC_MAJOR_4 + memset(posix_hostbox, 0, SOF_IPC_MSG_MAX_SIZE); + memcpy(posix_hostbox, + (const uint8_t *)global_ipc->comp_data + sizeof(struct ipc_cmd_hdr), + SOF_IPC_MSG_MAX_SIZE - sizeof(struct ipc_cmd_hdr)); hdr = ipc_compact_read_msg(); #else memcpy(posix_hostbox, global_ipc->comp_data, SOF_IPC_MSG_MAX_SIZE); diff --git a/src/platform/qemu_xtensa/CMakeLists.txt b/src/platform/qemu_xtensa/CMakeLists.txt new file mode 100644 index 000000000000..8688947cf0c6 --- /dev/null +++ b/src/platform/qemu_xtensa/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources(sof platform.c) diff --git a/src/platform/qemu_xtensa/include/platform/lib/clk.h b/src/platform/qemu_xtensa/include/platform/lib/clk.h new file mode 100644 index 000000000000..c9f05cdf405b --- /dev/null +++ b/src/platform/qemu_xtensa/include/platform/lib/clk.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + */ + +#ifndef __PLATFORM_LIB_CLK_H__ +#define __PLATFORM_LIB_CLK_H__ + +/* Dummy clk header for qemu_xtensa */ +#define CLK_MAX_CPU_HZ 10000000 +#define CPU_LOWEST_FREQ_IDX 0 + +#endif /* __PLATFORM_LIB_CLK_H__ */ diff --git a/src/platform/qemu_xtensa/include/platform/lib/dai.h b/src/platform/qemu_xtensa/include/platform/lib/dai.h new file mode 100644 index 000000000000..418c383789a8 --- /dev/null +++ b/src/platform/qemu_xtensa/include/platform/lib/dai.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + */ + +#ifndef __PLATFORM_LIB_DAI_H__ +#define __PLATFORM_LIB_DAI_H__ + +/* Dummy dai header for qemu_xtensa */ + +#endif /* __PLATFORM_LIB_DAI_H__ */ diff --git a/src/platform/qemu_xtensa/include/platform/lib/dma.h b/src/platform/qemu_xtensa/include/platform/lib/dma.h new file mode 100644 index 000000000000..4c4068b99392 --- /dev/null +++ b/src/platform/qemu_xtensa/include/platform/lib/dma.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + */ + +#ifndef __PLATFORM_LIB_DMA_H__ +#define __PLATFORM_LIB_DMA_H__ + +/* Dummy dma header for qemu_xtensa */ +struct dma; + +struct sof_dma { + const struct device *z_dev; +}; + +#endif /* __PLATFORM_LIB_DMA_H__ */ diff --git a/src/platform/qemu_xtensa/include/platform/lib/mailbox.h b/src/platform/qemu_xtensa/include/platform/lib/mailbox.h new file mode 100644 index 000000000000..47c97744fe6d --- /dev/null +++ b/src/platform/qemu_xtensa/include/platform/lib/mailbox.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + */ + +#ifndef __PLATFORM_LIB_MAILBOX_H__ +#define __PLATFORM_LIB_MAILBOX_H__ + +/* Dummy mailbox header for qemu_xtensa */ +#define MAILBOX_HOSTBOX_BASE 0x10000000 +#define MAILBOX_HOSTBOX_SIZE 0x1000 +#define MAILBOX_DSPBOX_BASE 0x10005000 +#define MAILBOX_DSPBOX_SIZE 0x1000 +#define MAILBOX_STREAM_BASE 0x10001000 +#define MAILBOX_STREAM_SIZE 0x1000 +#define MAILBOX_TRACE_BASE 0x10002000 +#define MAILBOX_TRACE_SIZE 0x1000 +#define MAILBOX_EXCEPTION_BASE 0x10003000 +#define MAILBOX_EXCEPTION_SIZE 0x1000 +#define MAILBOX_DEBUG_BASE 0x10004000 +#define MAILBOX_DEBUG_SIZE 0x1000 +#define MAILBOX_SW_REG_BASE 0x10005000 +#define MAILBOX_SW_REG_SIZE 0x1000 + +#include <stddef.h> +#include <stdint.h> + +static inline void mailbox_sw_regs_write(size_t offset, const void *src, size_t bytes) {} +static inline void mailbox_sw_reg_write(size_t offset, uint32_t val) {} +static inline void mailbox_sw_reg_write64(size_t offset, uint64_t val) {} +static inline uint32_t mailbox_sw_reg_read(size_t offset) { return 0; } +static inline uint64_t mailbox_sw_reg_read64(size_t offset) { return 0; } + +#endif /* __PLATFORM_LIB_MAILBOX_H__ */ diff --git a/src/platform/qemu_xtensa/include/platform/lib/memory.h b/src/platform/qemu_xtensa/include/platform/lib/memory.h new file mode 100644 index 000000000000..7c8f9da9c1c1 --- /dev/null +++ b/src/platform/qemu_xtensa/include/platform/lib/memory.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + */ + +#ifndef __PLATFORM_LIB_MEMORY_H__ +#define __PLATFORM_LIB_MEMORY_H__ + +/* Dummy memory header for qemu_xtensa */ + +#define PLATFORM_DCACHE_ALIGN sizeof(void *) +#define HOST_PAGE_SIZE 4096 +#define SHARED_DATA + +#endif /* __PLATFORM_LIB_MEMORY_H__ */ diff --git a/src/platform/qemu_xtensa/include/platform/platform.h b/src/platform/qemu_xtensa/include/platform/platform.h new file mode 100644 index 000000000000..5f89152251b4 --- /dev/null +++ b/src/platform/qemu_xtensa/include/platform/platform.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + */ + +#ifndef __PLATFORM_PLATFORM_H__ +#define __PLATFORM_PLATFORM_H__ + +/* Dummy platform header for qemu_xtensa */ +#define PLATFORM_CORE_COUNT 1 +#define PLATFORM_MAX_CHANNELS 8 +#define PLATFORM_MAX_STREAMS 8 + +#define HW_CFG_VERSION 0x010000 +#define DMA_TRACE_LOCAL_SIZE HOST_PAGE_SIZE + +struct ipc_msg; +static inline void ipc_platform_send_msg_direct(const struct ipc_msg *msg) {} + +#endif /* __PLATFORM_PLATFORM_H__ */ diff --git a/src/platform/qemu_xtensa/include/platform/trace/trace.h b/src/platform/qemu_xtensa/include/platform/trace/trace.h new file mode 100644 index 000000000000..65499099cd52 --- /dev/null +++ b/src/platform/qemu_xtensa/include/platform/trace/trace.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + */ + +#ifndef __PLATFORM_TRACE_TRACE_H__ +#define __PLATFORM_TRACE_TRACE_H__ + +/* Dummy trace header for qemu_xtensa */ +#define PLATFORM_TRACE_DICT_FRONT 0 + +#endif /* __PLATFORM_TRACE_TRACE_H__ */ diff --git a/src/platform/qemu_xtensa/platform.c b/src/platform/qemu_xtensa/platform.c new file mode 100644 index 000000000000..f39ba5c1a639 --- /dev/null +++ b/src/platform/qemu_xtensa/platform.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. +// +#include <sof/lib/mailbox.h> +#include <sof/ipc/common.h> +#include <rtos/sof.h> + +void ipc_platform_complete_cmd(struct ipc *ipc) +{ +} + +int platform_boot_complete(uint32_t boot_message) +{ + return 0; +} + +int platform_init(struct sof *sof) +{ + return 0; +} diff --git a/src/probe/CMakeLists.txt b/src/probe/CMakeLists.txt index e12e3554b94f..4cbc818513dd 100644 --- a/src/probe/CMakeLists.txt +++ b/src/probe/CMakeLists.txt @@ -1,3 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof probe.c) +if(CONFIG_PROBE STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(llext ${PROJECT_BINARY_DIR}/probe_llext) + add_dependencies(app probe) +elseif(CONFIG_PROBE) + add_local_sources(sof probe.c) +endif() diff --git a/src/probe/probe.c b/src/probe/probe.c index 190633c34ec8..19f62bf81a14 100644 --- a/src/probe/probe.c +++ b/src/probe/probe.c @@ -13,7 +13,6 @@ #include <rtos/alloc.h> #include <rtos/init.h> #include <sof/lib/dma.h> -#include <sof/lib/notifier.h> #include <sof/lib/uuid.h> #include <sof/ipc/topology.h> #include <sof/ipc/driver.h> @@ -80,11 +79,11 @@ struct probe_dma_ext { * Probe main struct */ struct probe_pdata { + struct task dmap_work; /**< probe task */ struct probe_dma_ext ext_dma; /**< extraction DMA */ struct probe_dma_ext inject_dma[CONFIG_PROBE_DMA_MAX]; /**< injection DMA */ struct probe_point probe_points[CONFIG_PROBE_POINTS_MAX]; /**< probe points */ struct probe_data_packet header; /**< data packet header */ - struct task dmap_work; /**< probe task */ }; /** @@ -98,11 +97,11 @@ static int probe_dma_buffer_init(struct probe_dma_buf *buffer, uint32_t size, uint32_t align) { /* allocate new buffer */ - buffer->addr = (uintptr_t)rballoc_align(0, SOF_MEM_CAPS_DMA, + buffer->addr = (uintptr_t)rballoc_align(0 | SOF_MEM_FLAG_DMA, size, align); if (!buffer->addr) { - tr_err(&pr_tr, "probe_dma_buffer_init(): alloc failed"); + tr_err(&pr_tr, "alloc failed"); return -ENOMEM; } @@ -145,7 +144,7 @@ static int probe_dma_init(struct probe_dma_ext *dma, uint32_t direction) dma->dc.dmac = dma_get(direction, 0, SOF_DMA_DEV_HOST, SOF_DMA_ACCESS_SHARED); if (!dma->dc.dmac) { - tr_err(&pr_tr, "probe_dma_init(): dma->dc.dmac = NULL"); + tr_err(&pr_tr, "dma->dc.dmac = NULL"); return -ENODEV; } dma->dc.dmac->priv_data = &dma->dc.dmac->chan->index; @@ -176,7 +175,7 @@ static int probe_dma_init(struct probe_dma_ext *dma, uint32_t direction) dma->config.dest_width = sizeof(uint32_t); dma->config.cyclic = 0; - err = dma_sg_alloc(&dma->config.elem_array, SOF_MEM_ZONE_RUNTIME, + err = dma_sg_alloc(NULL, &dma->config.elem_array, SOF_MEM_FLAG_USER, dma->config.direction, elem_num, elem_size, elem_addr, 0); if (err < 0) return err; @@ -201,7 +200,7 @@ static int probe_dma_init(struct probe_dma_ext *dma, uint32_t direction) dma->dc.dmac = sof_dma_get(direction, 0, SOF_DMA_DEV_HOST, SOF_DMA_ACCESS_SHARED); if (!dma->dc.dmac) { - tr_err(&pr_tr, "probe_dma_init(): dma->dc.dmac = NULL"); + tr_err(&pr_tr, "dma->dc.dmac = NULL"); return -ENODEV; } @@ -213,7 +212,7 @@ static int probe_dma_init(struct probe_dma_ext *dma, uint32_t direction) channel = dma_request_channel(dma->dc.dmac->z_dev, &channel); if (channel < 0) { - tr_err(&pr_tr, "probe_dma_init(): dma_request_channel() failed"); + tr_err(&pr_tr, "dma_request_channel() failed"); return -EINVAL; } dma->dc.chan = &dma->dc.dmac->chan[channel]; @@ -255,14 +254,14 @@ static int probe_dma_init(struct probe_dma_ext *dma, uint32_t direction) static int probe_dma_deinit(struct probe_dma_ext *dma) { int err = 0; - dma_sg_free(&dma->config.elem_array); + dma_sg_free(NULL, &dma->config.elem_array); #if CONFIG_ZEPHYR_NATIVE_DRIVERS err = dma_stop(dma->dc.dmac->z_dev, dma->dc.chan->index); #else err = dma_stop_legacy(dma->dc.chan); #endif if (err < 0) { - tr_err(&pr_tr, "probe_dma_deinit(): dma_stop() failed"); + tr_err(&pr_tr, "dma_stop() failed"); return err; } #if CONFIG_ZEPHYR_NATIVE_DRIVERS @@ -303,7 +302,7 @@ static enum task_state probe_task(void *data) ©_align); #endif if (err < 0) { - tr_err(&pr_tr, "probe_task(): dma_get_attribute failed."); + tr_err(&pr_tr, "dma_get_attribute failed."); return SOF_TASK_STATE_COMPLETED; } @@ -325,7 +324,7 @@ static enum task_state probe_task(void *data) return SOF_TASK_STATE_RESCHEDULE; if (err < 0) { - tr_err(&pr_tr, "probe_task(): dma_copy_to_host() failed."); + tr_err(&pr_tr, "dma_copy_to_host() failed."); return err; } @@ -338,29 +337,64 @@ static enum task_state probe_task(void *data) return SOF_TASK_STATE_RESCHEDULE; } +#if CONFIG_LOG_BACKEND_SOF_PROBE_OUTPUT_AUTO_ENABLE +static void probe_auto_enable_logs(uint32_t stream_tag) +{ + struct probe_point log_point = { +#if CONFIG_IPC_MAJOR_4 + .buffer_id = { + .full_id = 0, + }, +#else + .buffer_id = 0, +#endif + .purpose = PROBE_PURPOSE_EXTRACTION, + .stream_tag = stream_tag, + }; + int ret; + + ret = probe_point_add(1, &log_point); + + if (ret) + tr_err(&pr_tr, "failed"); +} +#endif + int probe_init(const struct probe_dma *probe_dma) { struct probe_pdata *_probe = probe_get(); uint32_t i; int err; - tr_dbg(&pr_tr, "probe_init()"); + tr_dbg(&pr_tr, "entry"); if (_probe) { - tr_err(&pr_tr, "probe_init(): Probes already initialized."); + tr_err(&pr_tr, "Probes already initialized."); return -EINVAL; } /* alloc probes main struct */ - sof_get()->probe = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_RAM, + sof_get()->probe = rzalloc(SOF_MEM_FLAG_USER, sizeof(*_probe)); + if (!sof_get()->probe) { + tr_err(&pr_tr, "Alloc failed."); + return -ENOMEM; + } _probe = probe_get(); if (!_probe) { - tr_err(&pr_tr, "probe_init(): Alloc failed."); + tr_err(&pr_tr, "Alloc failed."); return -ENOMEM; } + /* initialize injection DMAs as invalid */ + for (i = 0; i < CONFIG_PROBE_DMA_MAX; i++) + _probe->inject_dma[i].stream_tag = PROBE_DMA_INVALID; + + /* initialize probe points as invalid */ + for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++) + _probe->probe_points[i].stream_tag = PROBE_POINT_INVALID; + /* setup extraction dma if requested */ if (probe_dma) { tr_dbg(&pr_tr, "\tstream_tag = %u, dma_buffer_size = %u", @@ -371,7 +405,7 @@ int probe_init(const struct probe_dma *probe_dma) err = probe_dma_init(&_probe->ext_dma, SOF_DMA_DIR_LMEM_TO_HMEM); if (err < 0) { - tr_err(&pr_tr, "probe_init(): probe_dma_init() failed"); + tr_err(&pr_tr, "probe_dma_init() failed"); _probe->ext_dma.stream_tag = PROBE_DMA_INVALID; return err; } @@ -381,7 +415,7 @@ int probe_init(const struct probe_dma *probe_dma) err = dma_start_legacy(_probe->ext_dma.dc.chan); #endif if (err < 0) { - tr_err(&pr_tr, "probe_init(): failed to start extraction dma"); + tr_err(&pr_tr, "failed to start extraction dma"); return -EBUSY; } @@ -390,20 +424,16 @@ int probe_init(const struct probe_dma *probe_dma) SOF_UUID(probe_task_uuid), SOF_SCHEDULE_LL_TIMER, SOF_TASK_PRI_LOW, probe_task, _probe, 0, 0); + +#if CONFIG_LOG_BACKEND_SOF_PROBE_OUTPUT_AUTO_ENABLE + probe_auto_enable_logs(probe_dma->stream_tag); +#endif } else { tr_dbg(&pr_tr, "\tno extraction DMA setup"); _probe->ext_dma.stream_tag = PROBE_DMA_INVALID; } - /* initialize injection DMAs as invalid */ - for (i = 0; i < CONFIG_PROBE_DMA_MAX; i++) - _probe->inject_dma[i].stream_tag = PROBE_DMA_INVALID; - - /* initialize probe points as invalid */ - for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++) - _probe->probe_points[i].stream_tag = PROBE_POINT_INVALID; - return 0; } @@ -413,10 +443,10 @@ int probe_deinit(void) uint32_t i; int err; - tr_dbg(&pr_tr, "probe_deinit()"); + tr_dbg(&pr_tr, "entry"); if (!_probe) { - tr_err(&pr_tr, "probe_deinit(): Not initialized."); + tr_err(&pr_tr, "Not initialized."); return -EINVAL; } @@ -424,7 +454,7 @@ int probe_deinit(void) /* check for attached injection probe DMAs */ for (i = 0; i < CONFIG_PROBE_DMA_MAX; i++) { if (_probe->inject_dma[i].stream_tag != PROBE_DMA_INVALID) { - tr_err(&pr_tr, "probe_deinit(): Cannot deinitialize with injection DMAs attached."); + tr_err(&pr_tr, "Cannot deinitialize with injection DMAs attached."); return -EINVAL; } } @@ -432,13 +462,13 @@ int probe_deinit(void) /* check for connected probe points */ for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++) { if (_probe->probe_points[i].stream_tag != PROBE_POINT_INVALID) { - tr_err(&pr_tr, "probe_deinit(): Cannot deinitialize with probe points connected."); + tr_err(&pr_tr, "Cannot deinitialize with probe points connected."); return -EINVAL; } } if (_probe->ext_dma.stream_tag != PROBE_DMA_INVALID) { - tr_dbg(&pr_tr, "probe_deinit() Freeing task and extraction DMA."); + tr_dbg(&pr_tr, "Freeing task and extraction DMA."); schedule_task_free(&_probe->dmap_work); err = probe_dma_deinit(&_probe->ext_dma); if (err < 0) @@ -460,10 +490,10 @@ int probe_dma_add(uint32_t count, const struct probe_dma *probe_dma) uint32_t first_free; int err; - tr_dbg(&pr_tr, "probe_dma_add() count = %u", count); + tr_dbg(&pr_tr, "count = %u", count); if (!_probe) { - tr_err(&pr_tr, "probe_dma_add(): Not initialized."); + tr_err(&pr_tr, "Not initialized."); return -EINVAL; } @@ -489,14 +519,14 @@ int probe_dma_add(uint32_t count, const struct probe_dma *probe_dma) } if (stream_tag == probe_dma[i].stream_tag) { - tr_err(&pr_tr, "probe_dma_add(): Probe DMA %u already attached.", + tr_err(&pr_tr, "Probe DMA %u already attached.", stream_tag); return -EINVAL; } } if (first_free == CONFIG_PROBE_DMA_MAX) { - tr_err(&pr_tr, "probe_dma_add(): Exceeded maximum number of DMAs attached = " + tr_err(&pr_tr, "Exceeded maximum number of DMAs attached = " STRINGIFY(CONFIG_PROBE_DMA_MAX)); return -EINVAL; } @@ -509,7 +539,7 @@ int probe_dma_add(uint32_t count, const struct probe_dma *probe_dma) err = probe_dma_init(&_probe->inject_dma[first_free], SOF_DMA_DIR_HMEM_TO_LMEM); if (err < 0) { - tr_err(&pr_tr, "probe_dma_add(): probe_dma_init() failed"); + tr_err(&pr_tr, "probe_dma_init() failed"); _probe->inject_dma[first_free].stream_tag = PROBE_DMA_INVALID; return err; @@ -544,10 +574,10 @@ int probe_dma_remove(uint32_t count, const uint32_t *stream_tag) uint32_t j; int err; - tr_dbg(&pr_tr, "probe_dma_remove() count = %u", count); + tr_dbg(&pr_tr, "count = %u", count); if (!_probe) { - tr_err(&pr_tr, "probe_dma_remove(): Not initialized."); + tr_err(&pr_tr, "Not initialized."); return -EINVAL; } @@ -602,7 +632,7 @@ static int copy_to_pbuffer(struct probe_dma_buf *pbuf, void *data, /* copy data to probe buffer */ if (memcpy_s((void *)pbuf->w_ptr, pbuf->end_addr - pbuf->w_ptr, data, head)) { - tr_err(&pr_tr, "copy_to_pbuffer(): memcpy_s() failed"); + tr_err(&pr_tr, "memcpy_s() failed"); return -EINVAL; } dcache_writeback_region((__sparse_force void __sparse_cache *)pbuf->w_ptr, head); @@ -612,7 +642,7 @@ static int copy_to_pbuffer(struct probe_dma_buf *pbuf, void *data, pbuf->w_ptr = pbuf->addr; if (memcpy_s((void *)pbuf->w_ptr, (char *)pbuf->end_addr - (char *)pbuf->w_ptr, (char *)data + head, tail)) { - tr_err(&pr_tr, "copy_to_pbuffer(): memcpy_s() failed"); + tr_err(&pr_tr, "memcpy_s() failed"); return -EINVAL; } dcache_writeback_region((__sparse_force void __sparse_cache *)pbuf->w_ptr, tail); @@ -659,7 +689,7 @@ static int copy_from_pbuffer(struct probe_dma_buf *pbuf, void *data, /* data from DMA so invalidate it */ dcache_invalidate_region((__sparse_force void __sparse_cache *)pbuf->r_ptr, head); if (memcpy_s(data, bytes, (void *)pbuf->r_ptr, head)) { - tr_err(&pr_tr, "copy_from_pbuffer(): memcpy_s() failed"); + tr_err(&pr_tr, "memcpy_s() failed"); return -EINVAL; } @@ -669,7 +699,7 @@ static int copy_from_pbuffer(struct probe_dma_buf *pbuf, void *data, pbuf->r_ptr = pbuf->addr; dcache_invalidate_region((__sparse_force void __sparse_cache *)pbuf->r_ptr, tail); if (memcpy_s((char *)data + head, tail, (void *)pbuf->r_ptr, tail)) { - tr_err(&pr_tr, "copy_from_pbuffer(): memcpy_s() failed"); + tr_err(&pr_tr, "memcpy_s() failed"); return -EINVAL; } pbuf->r_ptr = pbuf->r_ptr + tail; @@ -758,7 +788,7 @@ static uint32_t probe_gen_format(uint32_t frame_fmt, uint32_t rate, float_fmt = 1; break; default: - tr_err(&pr_tr, "probe_gen_format(): Invalid frame format specified = 0x%08x", + tr_err(&pr_tr, "Invalid frame format specified = 0x%08x", frame_fmt); return 0; } @@ -836,27 +866,32 @@ 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) +static ssize_t probe_logging_hook(uint8_t *buffer, size_t length) { struct probe_pdata *_probe = probe_get(); uint64_t checksum; + size_t max_len; int ret; + max_len = _probe->ext_dma.dmapb.avail - sizeof(struct probe_data_packet) - sizeof(checksum); + length = MIN(max_len, length); + ret = probe_gen_header(PROBE_LOGGING_BUFFER_ID, length, 0, &checksum); if (ret < 0) - return; + return ret; ret = copy_to_pbuffer(&_probe->ext_dma.dmapb, buffer, length); if (ret < 0) - return; + return ret; ret = copy_to_pbuffer(&_probe->ext_dma.dmapb, &checksum, sizeof(checksum)); if (ret < 0) - return; + return ret; kick_probe_task(_probe); + return length; } #endif @@ -866,14 +901,12 @@ static void probe_logging_hook(uint8_t *buffer, size_t length) * Extraction probe: generate format, header and copy data to probe buffer. * Injection probe: find corresponding DMA, check avail data, copy data, * update pointers and request more data from host if needed. - * \param[in] arg pointer (not used). - * \param[in] type of notify. - * \param[in] data pointer. + * \param[in] arg pointer to buffer_id. + * \param[in] cb_data pointer to buffer callback transaction data. */ -static void probe_cb_produce(void *arg, enum notify_id type, void *data) +static void probe_cb_produce(void *arg, struct buffer_cb_transact *cb_data) { struct probe_pdata *_probe = probe_get(); - struct buffer_cb_transact *cb_data = data; struct comp_buffer *buffer = cb_data->buffer; struct probe_dma_ext *dma; uint32_t buffer_id; @@ -885,7 +918,7 @@ static void probe_cb_produce(void *arg, enum notify_id type, void *data) uint32_t format; uint64_t checksum; - buffer_id = *(int *)arg; + buffer_id = *(uint32_t *)arg; /* search for probe point connected to this buffer */ for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++) @@ -893,7 +926,7 @@ static void probe_cb_produce(void *arg, enum notify_id type, void *data) break; if (i == CONFIG_PROBE_POINTS_MAX) { - tr_err(&pr_tr, "probe_cb_produce(): probe not found for buffer id: %d", + tr_err(&pr_tr, "probe not found for buffer id: %d", buffer_id); return; } @@ -950,7 +983,7 @@ static void probe_cb_produce(void *arg, enum notify_id type, void *data) } } if (j == CONFIG_PROBE_DMA_MAX) { - tr_err(&pr_tr, "probe_cb_produce(): dma not found"); + tr_err(&pr_tr, "dma not found"); return; } dma = &_probe->inject_dma[j]; @@ -967,7 +1000,7 @@ static void probe_cb_produce(void *arg, enum notify_id type, void *data) &free_bytes); #endif if (ret < 0) { - tr_err(&pr_tr, "probe_cb_produce(): dma_get_data_size() failed, ret = %u", + tr_err(&pr_tr, "dma_get_data_size() failed, ret = %u", ret); goto err; } @@ -1027,25 +1060,23 @@ static void probe_cb_produce(void *arg, enum notify_id type, void *data) } return; err: - tr_err(&pr_tr, "probe_cb_produce(): failed to generate probe data"); + tr_err(&pr_tr, "failed to generate probe data"); } /** * \brief Callback for buffer free, it will remove probe point. - * \param[in] arg pointer (not used). - * \param[in] type of notify. - * \param[in] data pointer. + * \param[in] arg pointer to buffer_id. */ -static void probe_cb_free(void *arg, enum notify_id type, void *data) +static void probe_cb_free(void *arg) { - uint32_t buffer_id = *(int *)arg; + uint32_t buffer_id = *(uint32_t *)arg; int ret; - tr_dbg(&pr_tr, "probe_cb_free() buffer_id = %u", buffer_id); + tr_dbg(&pr_tr, "buffer_id = %u", buffer_id); ret = probe_point_remove(1, &buffer_id); if (ret < 0) - tr_err(&pr_tr, "probe_cb_free(): probe_point_remove() failed"); + tr_err(&pr_tr, "probe_point_remove() failed"); } static bool probe_purpose_needs_ext_dma(uint32_t purpose) @@ -1066,7 +1097,7 @@ static struct comp_buffer *ipc4_get_buffer(struct ipc_comp_dev *dev, probe_point switch (probe_point.fields.type) { case PROBE_TYPE_INPUT: comp_dev_for_each_producer(dev->cd, buf) { - queue_id = IPC4_SRC_QUEUE_ID(buf_get_id(buf)); + queue_id = IPC4_SINK_QUEUE_ID(buf_get_id(buf)); if (queue_id == probe_point.fields.index) return buf; @@ -1074,7 +1105,7 @@ static struct comp_buffer *ipc4_get_buffer(struct ipc_comp_dev *dev, probe_point break; case PROBE_TYPE_OUTPUT: comp_dev_for_each_consumer(dev->cd, buf) { - queue_id = IPC4_SINK_QUEUE_ID(buf_get_id(buf)); + queue_id = IPC4_SRC_QUEUE_ID(buf_get_id(buf)); if (queue_id == probe_point.fields.index) return buf; @@ -1119,10 +1150,10 @@ int probe_point_add(uint32_t count, const struct probe_point *probe) #if CONFIG_IPC_MAJOR_4 struct comp_buffer *buf = NULL; #endif - tr_dbg(&pr_tr, "probe_point_add() count = %u", count); + tr_dbg(&pr_tr, "count = %u", count); if (!_probe) { - tr_err(&pr_tr, "probe_point_add(): Not initialized."); + tr_err(&pr_tr, "Not initialized."); return -EINVAL; } @@ -1137,7 +1168,7 @@ int probe_point_add(uint32_t count, const struct probe_point *probe) probe[i].stream_tag); if (!verify_purpose(probe[i].purpose)) { - tr_err(&pr_tr, "probe_point_add() error: invalid purpose %d", + tr_err(&pr_tr, "error: invalid purpose %d", probe[i].purpose); return -EINVAL; @@ -1145,7 +1176,7 @@ int probe_point_add(uint32_t count, const struct probe_point *probe) if (_probe->ext_dma.stream_tag == PROBE_DMA_INVALID && probe_purpose_needs_ext_dma(probe[i].purpose)) { - tr_err(&pr_tr, "probe_point_add(): extraction DMA not enabled."); + tr_err(&pr_tr, "extraction DMA not enabled."); return -EINVAL; } @@ -1161,7 +1192,7 @@ int probe_point_add(uint32_t count, const struct probe_point *probe) #endif /* check if buffer exists */ if (!dev) { - tr_err(&pr_tr, "probe_point_add(): No device with ID %u found.", + tr_err(&pr_tr, "No device with ID %u found.", buf_id->full_id); return -EINVAL; @@ -1169,14 +1200,14 @@ int probe_point_add(uint32_t count, const struct probe_point *probe) #if CONFIG_IPC_MAJOR_4 buf = ipc4_get_buffer(dev, *buf_id); if (!buf) { - tr_err(&pr_tr, "probe_point_add(): buffer %u not found.", + tr_err(&pr_tr, "buffer %u not found.", buf_id->full_id); return -EINVAL; } #else if (dev->type != COMP_TYPE_BUFFER) { - tr_err(&pr_tr, "probe_point_add(): Device ID %u is not a buffer.", + tr_err(&pr_tr, "Device ID %u is not a buffer.", buf_id->full_id); return -EINVAL; @@ -1200,7 +1231,7 @@ int probe_point_add(uint32_t count, const struct probe_point *probe) if (buffer_id == buf_id->full_id) { if (_probe->probe_points[j].purpose == probe[i].purpose) { - tr_err(&pr_tr, "probe_point_add(): Probe already attached to buffer %u with purpose %u", + tr_err(&pr_tr, "Probe already attached to buffer %u with purpose %u", buffer_id, probe[i].purpose); @@ -1210,7 +1241,7 @@ int probe_point_add(uint32_t count, const struct probe_point *probe) } if (first_free == CONFIG_PROBE_POINTS_MAX) { - tr_err(&pr_tr, "probe_point_add(): Maximum number of probe points connected aleady: " + tr_err(&pr_tr, "Maximum number of probe points connected aleady: " STRINGIFY(CONFIG_PROBE_POINTS_MAX)); return -EINVAL; @@ -1231,7 +1262,7 @@ int probe_point_add(uint32_t count, const struct probe_point *probe) } if (!dma_found) { - tr_err(&pr_tr, "probe_point_add(): No DMA with stream tag %u found for injection.", + tr_err(&pr_tr, "No DMA with stream tag %u found for injection.", probe[i].stream_tag); return -EINVAL; @@ -1242,7 +1273,7 @@ int probe_point_add(uint32_t count, const struct probe_point *probe) #else if (dma_start_legacy(_probe->inject_dma[j].dc.chan) < 0) { #endif - tr_err(&pr_tr, "probe_point_add(): failed to start dma"); + tr_err(&pr_tr, "failed to start dma"); return -EBUSY; } @@ -1257,7 +1288,7 @@ int probe_point_add(uint32_t count, const struct probe_point *probe) } if (j == CONFIG_PROBE_POINTS_MAX) { - tr_dbg(&pr_tr, "probe_point_add(): start probe task"); + tr_dbg(&pr_tr, "start probe task"); schedule_task(&_probe->dmap_work, 1000, 1000); } /* ignore probe stream tag for extraction probes */ @@ -1279,16 +1310,13 @@ int probe_point_add(uint32_t count, const struct probe_point *probe) probe_point_id_t *new_buf_id = &_probe->probe_points[first_free].buffer_id; #if CONFIG_IPC_MAJOR_4 - notifier_register(&new_buf_id->full_id, buf, NOTIFIER_ID_BUFFER_PRODUCE, - &probe_cb_produce, 0); - notifier_register(&new_buf_id->full_id, buf, NOTIFIER_ID_BUFFER_FREE, - &probe_cb_free, 0); + struct comp_buffer *probe_buf = buf; #else - notifier_register(&new_buf_id->full_id, dev->cb, NOTIFIER_ID_BUFFER_PRODUCE, - &probe_cb_produce, 0); - notifier_register(&new_buf_id->full_id, dev->cb, NOTIFIER_ID_BUFFER_FREE, - &probe_cb_free, 0); + struct comp_buffer *probe_buf = (struct comp_buffer *)dev->cb; #endif + probe_buf->probe_cb_produce = probe_cb_produce; + probe_buf->probe_cb_free = probe_cb_free; + probe_buf->probe_cb_arg = &new_buf_id->full_id; } } @@ -1302,10 +1330,10 @@ int probe_dma_info(struct sof_ipc_probe_info_params *data, uint32_t max_size) uint32_t i = 0; uint32_t j = 0; - tr_dbg(&pr_tr, "probe_dma_info()"); + tr_dbg(&pr_tr, "entry"); if (!_probe) { - tr_err(&pr_tr, "probe_dma_info(): Not initialized."); + tr_err(&pr_tr, "Not initialized."); return -EINVAL; } @@ -1340,10 +1368,10 @@ int probe_point_info(struct sof_ipc_probe_info_params *data, uint32_t max_size) uint32_t i = 0; uint32_t j = 0; - tr_dbg(&pr_tr, "probe_point_info()"); + tr_dbg(&pr_tr, "entry"); if (!_probe) { - tr_err(&pr_tr, "probe_point_info(): Not initialized."); + tr_err(&pr_tr, "Not initialized."); return -EINVAL; } @@ -1382,10 +1410,10 @@ int probe_point_remove(uint32_t count, const uint32_t *buffer_id) struct comp_buffer *buf; #endif - tr_dbg(&pr_tr, "probe_point_remove() count = %u", count); + tr_dbg(&pr_tr, "count = %u", count); if (!_probe) { - tr_err(&pr_tr, "probe_point_remove(): Not initialized."); + tr_err(&pr_tr, "Not initialized."); return -EINVAL; } /* remove each requested probe point */ @@ -1397,6 +1425,10 @@ int probe_point_remove(uint32_t count, const uint32_t *buffer_id) if (_probe->probe_points[j].stream_tag != PROBE_POINT_INVALID && buf_id->full_id == buffer_id[i]) { +#if CONFIG_LOG_BACKEND_SOF_PROBE + if (enable_logs(&_probe->probe_points[j])) + probe_logging_init(NULL); +#endif #if CONFIG_IPC_MAJOR_4 dev = ipc_get_comp_by_id(ipc_get(), IPC4_COMP_ID(buf_id->fields.module_id, @@ -1404,19 +1436,20 @@ int probe_point_remove(uint32_t count, const uint32_t *buffer_id) if (dev) { buf = ipc4_get_buffer(dev, *buf_id); if (buf) { - notifier_unregister(NULL, buf, - NOTIFIER_ID_BUFFER_PRODUCE); - notifier_unregister(NULL, buf, - NOTIFIER_ID_BUFFER_FREE); + buf->probe_cb_produce = NULL; + buf->probe_cb_free = NULL; + buf->probe_cb_arg = NULL; } } #else dev = ipc_get_comp_by_id(ipc_get(), buffer_id[i]); if (dev) { - notifier_unregister(&buf_id->full_id, dev->cb, - NOTIFIER_ID_BUFFER_PRODUCE); - notifier_unregister(&buf_id->full_id, dev->cb, - NOTIFIER_ID_BUFFER_FREE); + struct comp_buffer *probe_buf = + (struct comp_buffer *)dev->cb; + + probe_buf->probe_cb_produce = NULL; + probe_buf->probe_cb_free = NULL; + probe_buf->probe_cb_arg = NULL; } #endif _probe->probe_points[j].stream_tag = @@ -1430,7 +1463,7 @@ int probe_point_remove(uint32_t count, const uint32_t *buffer_id) break; } if (j == CONFIG_PROBE_POINTS_MAX) { - tr_dbg(&pr_tr, "probe_point_remove(): cancel probe task"); + tr_dbg(&pr_tr, "cancel probe task"); schedule_task_cancel(&_probe->dmap_work); } @@ -1445,7 +1478,7 @@ static int probe_mod_init(struct processing_module *mod) const struct ipc4_probe_module_cfg *probe_cfg = mod_data->cfg.init_data; int ret; - comp_info(dev, "probe_mod_init()"); + comp_info(dev, "entry"); ret = probe_init(&probe_cfg->gtw_cfg); if (ret < 0) @@ -1458,10 +1491,13 @@ static int probe_free(struct processing_module *mod) { struct comp_dev *dev = mod->dev; - comp_info(dev, "probe_free()"); + comp_info(dev, "entry"); probe_deinit(); +#if CONFIG_LOG_BACKEND_SOF_PROBE + probe_logging_init(NULL); +#endif return 0; } @@ -1472,7 +1508,7 @@ static int probe_set_config(struct processing_module *mod, uint32_t param_id, { struct comp_dev *dev = mod->dev; - comp_info(dev, "probe_set_config()"); + comp_info(dev, "entry"); switch (param_id) { case IPC4_PROBE_MODULE_PROBE_POINTS_ADD: @@ -1538,14 +1574,14 @@ static int probe_get_available_points(struct processing_module *mod, id.fields.type = PROBE_TYPE_INPUT; comp_dev_for_each_producer(icd->cd, buf) { - id.fields.index = IPC4_SRC_QUEUE_ID(buf_get_id(buf)); + id.fields.index = IPC4_SINK_QUEUE_ID(buf_get_id(buf)); if (probe_add_point_info_params(info, id, i, max_size)) return 0; i++; } id.fields.type = PROBE_TYPE_OUTPUT; comp_dev_for_each_consumer(icd->cd, buf) { - id.fields.index = IPC4_SINK_QUEUE_ID(buf_get_id(buf)); + id.fields.index = IPC4_SRC_QUEUE_ID(buf_get_id(buf)); if (probe_add_point_info_params(info, id, i, max_size)) return 0; i++; @@ -1597,7 +1633,7 @@ static int probe_dummy_process(struct processing_module *mod, { struct comp_dev *dev = mod->dev; - comp_warn(dev, "probe_dummy_process() called"); + comp_warn(dev, "called"); return 0; } @@ -1610,9 +1646,6 @@ static const struct module_interface probe_interface = { .free = probe_free, }; -DECLARE_MODULE_ADAPTER(probe_interface, PROBE_UUID, pr_tr); -SOF_MODULE_INIT(probe, sys_comp_module_probe_interface_init); - #if CONFIG_PROBE_MODULE /* modular: llext dynamic link */ @@ -1620,16 +1653,16 @@ SOF_MODULE_INIT(probe, sys_comp_module_probe_interface_init); #include <module/module/llext.h> #include <rimage/sof/user/manifest.h> -#define UUID_PROBE 0x08, 0x08, 0xAD, 0x7C, 0x10, 0xAB, 0x23, 0xCD, 0xEF, 0x45, \ - 0x12, 0xAB, 0x34, 0xCD, 0x56, 0xEF, - -SOF_LLEXT_MOD_ENTRY(probe, &probe_interface); - static const struct sof_man_module_manifest mod_manifest __section(".module") __used = - SOF_LLEXT_MODULE_MANIFEST("PROBE", probe_llext_entry, 1, UUID_PROBE, 40); + SOF_LLEXT_MODULE_MANIFEST("PROBE", &probe_interface, 1, SOF_REG_UUID(probe4), 40); SOF_LLEXT_BUILDINFO; +#else + +DECLARE_MODULE_ADAPTER(probe_interface, PROBE_UUID, pr_tr); +SOF_MODULE_INIT(probe, sys_comp_module_probe_interface_init); + #endif /* CONFIG_COMP_PROBE_MODULE */ #endif /* CONFIG_IPC_MAJOR_4 */ diff --git a/src/probe/probe.toml b/src/probe/probe.toml index 848234b0085c..5075ad866061 100644 --- a/src/probe/probe.toml +++ b/src/probe/probe.toml @@ -4,7 +4,7 @@ [[module.entry]] name = "PROBE" - uuid = "7CAD0808-AB10-CD23-EF45-12AB34CD56EF" + uuid = UUIDREG_STR_PROBE4 affinity_mask = "0x1" instance_count = "1" domain_types = "0" diff --git a/src/samples/audio/CMakeLists.txt b/src/samples/audio/CMakeLists.txt index 328070c2bb52..1dde973de0d7 100644 --- a/src/samples/audio/CMakeLists.txt +++ b/src/samples/audio/CMakeLists.txt @@ -1,22 +1,22 @@ # SPDX-License-Identifier: BSD-3-Clause -if(CONFIG_SAMPLE_SMART_AMP) - if(CONFIG_IPC_MAJOR_3) - add_local_sources(sof - smart_amp_test_ipc3.c - ) - elseif(CONFIG_IPC_MAJOR_4) - add_local_sources(sof - smart_amp_test_ipc4.c - ) - endif() + +if(CONFIG_IPC_MAJOR_3) + set(ipc_suffix ipc3) +elseif(CONFIG_IPC_MAJOR_4) + set(ipc_suffix ipc4) +endif() + +if(CONFIG_SAMPLE_SMART_AMP STREQUAL "m" AND DEFINED CONFIG_LLEXT) + add_subdirectory(smart_amp_test_llext ${PROJECT_BINARY_DIR}/smart_amp_test_llext) + add_dependencies(app smart_amp_test) +elseif(CONFIG_SAMPLE_SMART_AMP) + add_local_sources(sof smart_amp_test_${ipc_suffix}.c) endif() if(CONFIG_SAMPLE_KEYPHRASE) - add_local_sources(sof - detect_test.c - ) + add_local_sources(sof detect_test.c) endif() if(CONFIG_KWD_NN_SAMPLE_KEYPHRASE) - add_local_sources(sof kwd_nn_detect_test.c) + add_local_sources(sof kwd_nn_detect_test.c) endif() diff --git a/src/samples/audio/detect_test.c b/src/samples/audio/detect_test.c index 35270b60f275..7979d7db3d6c 100644 --- a/src/samples/audio/detect_test.c +++ b/src/samples/audio/detect_test.c @@ -139,7 +139,7 @@ static void notify_host(const struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); - comp_info(dev, "notify_host()"); + comp_info(dev, "entry"); #if CONFIG_IPC_MAJOR_4 ipc_msg_send(cd->msg, NULL, true); @@ -177,7 +177,7 @@ static void notify_kpb(const struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); - comp_info(dev, "notify_kpb(), preamble: %u", cd->detect_preamble); + comp_info(dev, "preamble: %u", cd->detect_preamble); cd->client_data.r_ptr = NULL; cd->client_data.sink = NULL; @@ -282,7 +282,7 @@ static int test_keyword_get_threshold(struct comp_dev *dev, int sample_width) return ACTIVATION_DEFAULT_THRESHOLD_S32; #endif /* CONFIG_FORMAT_S32LE */ default: - comp_err(dev, "test_keyword_get_threshold(), unsupported sample width: %d", + comp_err(dev, "unsupported sample width: %d", sample_width); return -EINVAL; } @@ -311,7 +311,7 @@ static int test_keyword_apply_config(struct comp_dev *dev, if (!cd->config.activation_threshold) { ret = test_keyword_get_threshold(dev, sample_width); if (ret < 0) { - comp_err(dev, "test_keyword_apply_config(): unsupported sample width %u", + comp_err(dev, "unsupported sample width %u", sample_width); return ret; } @@ -332,7 +332,7 @@ static void test_keyword_set_params(struct comp_dev *dev, struct comp_data *cd = comp_get_drvdata(dev); enum sof_ipc_frame valid_fmt, frame_fmt; - comp_info(dev, "test_keyword_set_params()"); + comp_info(dev, "entry"); memset(params, 0, sizeof(*params)); params->channels = cd->base_cfg.audio_fmt.channels_count; @@ -361,11 +361,11 @@ static int test_keyword_set_config(struct comp_dev *dev, const char *data, cfg = (const struct sof_detect_test_config *)data; cfg_size = data_size; - comp_info(dev, "test_keyword_set_config(): config size = %u", + comp_info(dev, "config size = %u", cfg_size); if (cfg_size != sizeof(struct sof_detect_test_config)) { - comp_err(dev, "test_keyword_set_config(): invalid config size"); + comp_err(dev, "invalid config size"); return -EINVAL; } @@ -379,12 +379,12 @@ static int test_keyword_get_config(struct comp_dev *dev, char *data, size_t cfg_size; int ret; - comp_info(dev, "test_keyword_get_config()"); + comp_info(dev, "entry"); cfg_size = sizeof(struct sof_detect_test_config); if (cfg_size > *data_size) { - comp_err(dev, "test_keyword_get_config(): wrong config size: %d", + comp_err(dev, "wrong config size: %d", *data_size); return -EINVAL; } @@ -405,7 +405,7 @@ static int test_keyword_set_large_config(struct comp_dev *dev, uint32_t data_offset, const char *data) { - comp_dbg(dev, "test_keyword_set_large_config()"); + comp_dbg(dev, "entry"); struct comp_data *cd = comp_get_drvdata(dev); switch (param_id) { @@ -429,7 +429,7 @@ static int test_keyword_get_large_config(struct comp_dev *dev, uint32_t *data_offset, char *data) { - comp_dbg(dev, "test_keyword_get_large_config()"); + comp_dbg(dev, "entry"); switch (param_id) { case IPC4_DETECT_TEST_GET_CONFIG: @@ -492,10 +492,10 @@ static int test_keyword_set_config(struct comp_dev *dev, cfg = (struct sof_detect_test_config *)cdata->data->data; bs = cfg->size; - comp_info(dev, "test_keyword_set_config(), blob size = %zu", bs); + comp_info(dev, "blob size = %zu", bs); if (bs != sizeof(struct sof_detect_test_config)) { - comp_err(dev, "test_keyword_set_config(): invalid blob size"); + comp_err(dev, "invalid blob size"); return -EINVAL; } @@ -519,7 +519,7 @@ static int test_keyword_ctrl_set_bin_data(struct comp_dev *dev, * configuration will be used when playback/capture * starts. */ - comp_err(dev, "keyword_ctrl_set_bin_data(): driver is busy"); + comp_err(dev, "driver is busy"); return -EBUSY; } @@ -531,7 +531,7 @@ static int test_keyword_ctrl_set_bin_data(struct comp_dev *dev, ret = comp_data_blob_set_cmd(cd->model_handler, cdata); break; default: - comp_err(dev, "keyword_ctrl_set_bin_data(): unknown binary data type"); + comp_err(dev, "unknown binary data type"); break; } @@ -545,20 +545,20 @@ static int test_keyword_ctrl_set_data(struct comp_dev *dev, /* Check version from ABI header */ if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { - comp_err(dev, "test_keyword_cmd_set_data(): invalid version"); + comp_err(dev, "invalid version"); return -EINVAL; } switch (cdata->cmd) { case SOF_CTRL_CMD_ENUM: - comp_info(dev, "test_keyword_cmd_set_data(), SOF_CTRL_CMD_ENUM"); + comp_info(dev, "SOF_CTRL_CMD_ENUM"); break; case SOF_CTRL_CMD_BINARY: - comp_info(dev, "test_keyword_cmd_set_data(), SOF_CTRL_CMD_BINARY"); + comp_info(dev, "SOF_CTRL_CMD_BINARY"); ret = test_keyword_ctrl_set_bin_data(dev, cdata); break; default: - comp_err(dev, "test_keyword_cmd_set_data(): invalid cdata->cmd"); + comp_err(dev, "invalid cdata->cmd"); ret = -EINVAL; break; } @@ -573,7 +573,7 @@ static int test_keyword_get_config(struct comp_dev *dev, size_t bs; int ret = 0; - comp_info(dev, "test_keyword_get_config()"); + comp_info(dev, "entry"); /* Copy back to user space */ bs = cd->config.size; @@ -606,7 +606,7 @@ static int test_keyword_ctrl_get_bin_data(struct comp_dev *dev, ret = comp_data_blob_get_cmd(cd->model_handler, cdata, size); break; default: - comp_err(dev, "test_keyword_ctrl_get_bin_data(): unknown binary data type"); + comp_err(dev, "unknown binary data type"); break; } @@ -618,14 +618,14 @@ static int test_keyword_ctrl_get_data(struct comp_dev *dev, { int ret = 0; - comp_info(dev, "test_keyword_ctrl_get_data() size: %d", size); + comp_info(dev, "size: %d", size); switch (cdata->cmd) { case SOF_CTRL_CMD_BINARY: ret = test_keyword_ctrl_get_bin_data(dev, cdata, size); break; default: - comp_err(dev, "test_keyword_ctrl_get_data(): invalid cdata->cmd"); + comp_err(dev, "invalid cdata->cmd"); return -EINVAL; } @@ -638,7 +638,7 @@ static int test_keyword_cmd(struct comp_dev *dev, int cmd, void *data, { struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4); - comp_info(dev, "test_keyword_cmd()"); + comp_info(dev, "entry"); switch (cmd) { case COMP_CMD_SET_DATA: @@ -650,6 +650,7 @@ static int test_keyword_cmd(struct comp_dev *dev, int cmd, void *data, } } #endif /* CONFIG_IPC_MAJOR_4 */ +static int test_keyword_params(struct comp_dev *dev, struct sof_ipc_stream_params *params); static struct comp_dev *test_keyword_new(const struct comp_driver *drv, const struct comp_ipc_config *config, @@ -666,14 +667,14 @@ static struct comp_dev *test_keyword_new(const struct comp_driver *drv, struct comp_data *cd = NULL; int ret = 0; - comp_cl_info(&comp_keyword, "test_keyword_new()"); + comp_cl_info(&comp_keyword, "entry"); dev = comp_alloc(drv, sizeof(*dev)); if (!dev) return NULL; dev->ipc_config = *config; - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); if (!cd) goto fail; @@ -689,6 +690,10 @@ static struct comp_dev *test_keyword_new(const struct comp_driver *drv, /* component model data handler */ cd->model_handler = comp_data_blob_handler_new(dev); + if (!cd->model_handler) { + comp_err(dev, "comp_data_blob_handler_new failed"); + goto cd_fail; + } #if CONFIG_IPC_MAJOR_4 /* For IPC4 we only receive the base_cfg, make a copy of it */ @@ -699,12 +704,12 @@ static struct comp_dev *test_keyword_new(const struct comp_driver *drv, if (bs > 0) { if (bs < sizeof(struct sof_detect_test_config)) { - comp_err(dev, "test_keyword_new(): invalid data size"); + comp_err(dev, "invalid data size"); goto cd_fail; } if (test_keyword_apply_config(dev, cfg)) { - comp_err(dev, "test_keyword_new(): failed to apply config"); + comp_err(dev, "failed to apply config"); goto cd_fail; } } @@ -713,7 +718,7 @@ static struct comp_dev *test_keyword_new(const struct comp_driver *drv, ret = comp_init_data_blob(cd->model_handler, INITIAL_MODEL_DATA_SIZE, NULL); if (ret < 0) { - comp_err(dev, "test_keyword_new(): model data initial failed"); + comp_err(dev, "model data initial failed"); goto cd_fail; } @@ -730,16 +735,16 @@ static struct comp_dev *test_keyword_new(const struct comp_driver *drv, #endif /* CONFIG_IPC_MAJOR_4 */ if (!cd->msg) { - comp_err(dev, "test_keyword_new(): ipc notification init failed"); + comp_err(dev, "ipc notification init failed"); goto cd_fail; } #if CONFIG_KWD_NN_SAMPLE_KEYPHRASE /* global buffer to accumulate data for processing */ - cd->input = rballoc_align(0, SOF_MEM_CAPS_RAM, + cd->input = rballoc_align(SOF_MEM_FLAG_USER, sizeof(int16_t) * KWD_NN_IN_BUFF_SIZE, 64); if (!cd->input) { - comp_err(dev, "test_keyword_new(): input alloc failed"); + comp_err(dev, "input alloc failed"); goto cd_fail; } bzero(cd->input, sizeof(int16_t) * KWD_NN_IN_BUFF_SIZE); @@ -749,13 +754,23 @@ static struct comp_dev *test_keyword_new(const struct comp_driver *drv, dev->direction = SOF_IPC_STREAM_CAPTURE; dev->direction_set = true; dev->state = COMP_STATE_READY; + +#if CONFIG_IPC_MAJOR_4 + struct sof_ipc_stream_params params; + + /* retrieve params based on base config for IPC4 */ + ret = test_keyword_params(dev, ¶ms); + if (ret < 0) + goto cd_fail; +#endif + return dev; cd_fail: comp_data_blob_handler_free(cd->model_handler); rfree(cd); fail: - rfree(dev); + comp_free_device(dev); return NULL; } @@ -763,7 +778,7 @@ static void test_keyword_free(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); - comp_info(dev, "test_keyword_free()"); + comp_info(dev, "entry"); #if CONFIG_AMS int ret; @@ -771,13 +786,13 @@ static void test_keyword_free(struct comp_dev *dev) /* Unregister KD as AMS producer */ ret = ams_helper_unregister_producer(dev, cd->kpd_uuid_id); if (ret) - comp_err(dev, "test_keyword_free(): unregister ams error %d", ret); + comp_err(dev, "unregister ams error %d", ret); #endif ipc_msg_free(cd->msg); comp_data_blob_handler_free(cd->model_handler); rfree(cd); - rfree(dev); + comp_free_device(dev); } static int test_keyword_verify_params(struct comp_dev *dev, @@ -785,11 +800,11 @@ static int test_keyword_verify_params(struct comp_dev *dev, { int ret; - comp_dbg(dev, "test_keyword_verify_params()"); + comp_dbg(dev, "entry"); ret = comp_verify_params(dev, 0, params); if (ret < 0) { - comp_err(dev, "test_keyword_verify_params(): verification failed!"); + comp_err(dev, "verification failed!"); return ret; } @@ -810,36 +825,12 @@ static int test_keyword_params(struct comp_dev *dev, err = test_keyword_verify_params(dev, params); if (err < 0) { - comp_err(dev, "test_keyword_params(): pcm params verification failed."); + comp_err(dev, "pcm params verification failed."); return err; } cd->sample_valid_bytes = params->sample_valid_bytes; - /* keyword components will only ever have 1 source */ - sourceb = comp_dev_get_first_data_producer(dev); - 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"); - return -EINVAL; - } - - if (!detector_is_sample_width_supported(frame_fmt)) { - comp_err(dev, "test_keyword_params(): only 16-bit format supported"); - return -EINVAL; - } - - /* calculate the length of the preamble */ - if (cd->config.preamble_time) { - cd->keyphrase_samples = cd->config.preamble_time * - (rate / 1000); - } else { - cd->keyphrase_samples = KEYPHRASE_DEFAULT_PREAMBLE_LENGTH; - } - /* * Threshold might be already set via IPC4_DETECT_TEST_SET_CONFIG, * otherwise apply default value. @@ -847,7 +838,7 @@ static int test_keyword_params(struct comp_dev *dev, if (!cd->config.activation_threshold) { err = test_keyword_get_threshold(dev, params->sample_valid_bytes * 8); if (err < 0) { - comp_err(dev, "test_keyword_params(): unsupported sample width %u", + comp_err(dev, "unsupported sample width %u", params->sample_valid_bytes * 8); return err; } @@ -855,6 +846,32 @@ static int test_keyword_params(struct comp_dev *dev, cd->config.activation_threshold = err; } + /* keyword components will only ever have 1 source */ + sourceb = comp_dev_get_first_data_producer(dev); + if (sourceb) { + 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, "only single-channel supported"); + return -EINVAL; + } + + if (!detector_is_sample_width_supported(frame_fmt)) { + comp_err(dev, "only 16-bit format supported"); + return -EINVAL; + } + + /* calculate the length of the preamble */ + if (cd->config.preamble_time) { + cd->keyphrase_samples = cd->config.preamble_time * + (rate / 1000); + } else { + cd->keyphrase_samples = KEYPHRASE_DEFAULT_PREAMBLE_LENGTH; + } + } + #if CONFIG_AMS cd->kpd_uuid_id = AMS_INVALID_MSG_TYPE; #endif /* CONFIG_AMS */ @@ -867,7 +884,7 @@ static int test_keyword_trigger(struct comp_dev *dev, int cmd) int ret; struct comp_data *cd = comp_get_drvdata(dev); - comp_info(dev, "test_keyword_trigger()"); + comp_info(dev, "entry"); ret = comp_set_state(dev, cmd); if (ret) @@ -890,7 +907,7 @@ static int test_keyword_copy(struct comp_dev *dev) struct comp_buffer *source; uint32_t frames; - comp_dbg(dev, "test_keyword_copy()"); + comp_dbg(dev, "entry"); /* keyword components will only ever have 1 source */ source = comp_dev_get_first_data_producer(dev); @@ -914,7 +931,7 @@ static int test_keyword_reset(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); - comp_info(dev, "test_keyword_reset()"); + comp_info(dev, "entry"); cd->activation = 0; cd->detect_preamble = 0; @@ -926,6 +943,7 @@ static int test_keyword_reset(struct comp_dev *dev) static int test_keyword_prepare(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); + struct sof_ipc_stream_params params; uint16_t valid_bits = cd->sample_valid_bytes * 8; uint16_t sample_width; int ret; @@ -936,7 +954,13 @@ static int test_keyword_prepare(struct comp_dev *dev) sample_width = cd->config.sample_width; #endif /* CONFIG_IPC_MAJOR_4 */ - comp_info(dev, "test_keyword_prepare()"); + comp_info(dev, "entry"); + + ret = test_keyword_params(dev, ¶ms); + if (ret < 0) { + comp_err(dev, "params config failed."); + return ret; + } /* * FIXME: this condition is always "false" for IPC4 as audio format cannot be changed @@ -949,7 +973,7 @@ static int test_keyword_prepare(struct comp_dev *dev) ret = test_keyword_get_threshold(dev, valid_bits); if (ret < 0) { - comp_err(dev, "test_keyword_prepare(): unsupported sample width %u", + comp_err(dev, "unsupported sample width %u", valid_bits); return ret; } @@ -1089,8 +1113,7 @@ static SHARED_DATA struct comp_driver_info comp_keyword_info = { UT_STATIC void sys_comp_keyword_init(void) { - comp_register(platform_shared_get(&comp_keyword_info, - sizeof(comp_keyword_info))); + comp_register(&comp_keyword_info); } DECLARE_MODULE(sys_comp_keyword_init); diff --git a/src/samples/audio/detect_test.toml b/src/samples/audio/detect_test.toml index 8173ef5f10c1..3d764d47341f 100644 --- a/src/samples/audio/detect_test.toml +++ b/src/samples/audio/detect_test.toml @@ -1,6 +1,6 @@ [[module.entry]] name = "KDTEST" - uuid = "EBA8D51F-7827-47B5-82EE-DE6E7743AF67" + uuid = UUIDREG_STR_KEYWORD affinity_mask = "0x1" instance_count = "1" domain_types = "0" diff --git a/src/samples/audio/kwd_nn_detect_test.c b/src/samples/audio/kwd_nn_detect_test.c index ef71a441580b..5d1f054bb040 100644 --- a/src/samples/audio/kwd_nn_detect_test.c +++ b/src/samples/audio/kwd_nn_detect_test.c @@ -84,18 +84,18 @@ void kwd_nn_detect_test(struct comp_dev *dev, result = kwd_nn_detect_postprocess(confidences); time_stop = sof_cycle_get_64(); comp_dbg(dev, - "KWD: kwd_nn_detect_test_copy() inference done in %u ms", + "KWD: inference done in %u ms", (unsigned int)k_cyc_to_ms_near64(time_stop - time_start)); switch (result) { case KWD_NN_YES_KEYWORD: case KWD_NN_NO_KEYWORD: if (result == KWD_NN_NO_KEYWORD) comp_info(dev, - "kwd_nn_detect_test_copy(): keyword NO detected confidence %d", + "keyword NO detected confidence %d", confidences[3]); else comp_info(dev, - "kwd_nn_detect_test_copy(): keyword YES detected confidences %d", + "keyword YES detected confidences %d", confidences[2]); /* The algorithm shall use cd->drain_req * to specify its draining size request. diff --git a/src/samples/audio/smart_amp_test.toml b/src/samples/audio/smart_amp_test.toml index 39f2a76c47a8..1576ed449bf6 100644 --- a/src/samples/audio/smart_amp_test.toml +++ b/src/samples/audio/smart_amp_test.toml @@ -5,7 +5,7 @@ REM # smart amp test module config [[module.entry]] name = "SMATEST" - uuid = "167A961E-8AE4-11EA-89F1-000C29CE1635" + uuid = UUIDREG_STR_SMART_AMP_TEST affinity_mask = "0x1" instance_count = "1" domain_types = "0" @@ -23,7 +23,8 @@ REM # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] #ifdef CONFIG_METEORLAKE mod_cfg = [0, 0, 0, 0, 296, 5000000, 384, 384, 0, 5000, 0] -#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_PANTHERLAKE) +#elif defined(CONFIG_LUNARLAKE) || defined(CONFIG_SOC_ACE30) || \ + defined(CONFIG_SOC_ACE40) mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] #endif diff --git a/src/samples/audio/smart_amp_test_ipc3.c b/src/samples/audio/smart_amp_test_ipc3.c index 289b8a36e126..5b2abf1ae03b 100644 --- a/src/samples/audio/smart_amp_test_ipc3.c +++ b/src/samples/audio/smart_amp_test_ipc3.c @@ -61,7 +61,7 @@ static struct comp_dev *smart_amp_new(const struct comp_driver *drv, return NULL; dev->ipc_config = *config; - sad = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*sad)); + sad = rzalloc(SOF_MEM_FLAG_USER, sizeof(*sad)); if (!sad) goto fail; @@ -88,7 +88,7 @@ static struct comp_dev *smart_amp_new(const struct comp_driver *drv, comp_data_blob_handler_free(sad->model_handler); rfree(sad); fail: - rfree(dev); + comp_free_device(dev); return NULL; } @@ -110,11 +110,11 @@ static int smart_amp_set_config(struct comp_dev *dev, ASSUME_ALIGNED(&cdata->data->data, sizeof(uint32_t)); bs = cfg->size; - comp_dbg(dev, "smart_amp_set_config(), actual blob size = %zu, expected blob size = %zu", + comp_dbg(dev, "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 = %zu, expected blob size = %zu", + comp_err(dev, "invalid blob size, actual blob size = %zu, expected blob size = %zu", bs, sizeof(struct sof_smart_amp_config)); return -EINVAL; } @@ -164,7 +164,7 @@ static int smart_amp_ctrl_get_bin_data(struct comp_dev *dev, case SOF_SMART_AMP_MODEL: return comp_data_blob_get_cmd(sad->model_handler, cdata, size); default: - comp_warn(dev, "smart_amp_ctrl_get_bin_data(): unknown binary data type"); + comp_warn(dev, "unknown binary data type"); break; } @@ -174,13 +174,13 @@ static int smart_amp_ctrl_get_bin_data(struct comp_dev *dev, static int smart_amp_ctrl_get_data(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata, int size) { - comp_info(dev, "smart_amp_ctrl_get_data() size: %d", size); + comp_info(dev, "size: %d", size); switch (cdata->cmd) { case SOF_CTRL_CMD_BINARY: return smart_amp_ctrl_get_bin_data(dev, cdata, size); default: - comp_err(dev, "smart_amp_ctrl_get_data(): invalid cdata->cmd"); + comp_err(dev, "invalid cdata->cmd"); return -EINVAL; } } @@ -193,7 +193,7 @@ static int smart_amp_ctrl_set_bin_data(struct comp_dev *dev, assert(sad); if (dev->state < COMP_STATE_READY) { - comp_err(dev, "smart_amp_ctrl_set_bin_data(): driver in init!"); + comp_err(dev, "driver in init!"); return -EBUSY; } @@ -203,7 +203,7 @@ static int smart_amp_ctrl_set_bin_data(struct comp_dev *dev, case SOF_SMART_AMP_MODEL: return comp_data_blob_set_cmd(sad->model_handler, cdata); default: - comp_warn(dev, "smart_amp_ctrl_set_bin_data(): unknown binary data type"); + comp_warn(dev, "unknown binary data type"); break; } @@ -215,19 +215,19 @@ static int smart_amp_ctrl_set_data(struct comp_dev *dev, { /* Check version from ABI header */ if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { - comp_err(dev, "smart_amp_ctrl_set_data(): invalid version"); + comp_err(dev, "invalid version"); return -EINVAL; } switch (cdata->cmd) { case SOF_CTRL_CMD_ENUM: - comp_info(dev, "smart_amp_ctrl_set_data(), SOF_CTRL_CMD_ENUM"); + comp_info(dev, "SOF_CTRL_CMD_ENUM"); break; case SOF_CTRL_CMD_BINARY: - comp_info(dev, "smart_amp_ctrl_set_data(), SOF_CTRL_CMD_BINARY"); + comp_info(dev, "SOF_CTRL_CMD_BINARY"); return smart_amp_ctrl_set_bin_data(dev, cdata); default: - comp_err(dev, "smart_amp_ctrl_set_data(): invalid cdata->cmd"); + comp_err(dev, "invalid cdata->cmd"); return -EINVAL; } @@ -240,7 +240,7 @@ static int smart_amp_cmd(struct comp_dev *dev, int cmd, void *data, { struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4); - comp_info(dev, "smart_amp_cmd(): cmd: %d", cmd); + comp_info(dev, "cmd: %d", cmd); switch (cmd) { case COMP_CMD_SET_DATA: @@ -256,12 +256,12 @@ static void smart_amp_free(struct comp_dev *dev) { struct smart_amp_data *sad = comp_get_drvdata(dev); - comp_info(dev, "smart_amp_free()"); + comp_info(dev, "entry"); comp_data_blob_handler_free(sad->model_handler); rfree(sad); - rfree(dev); + comp_free_device(dev); } static int smart_amp_verify_params(struct comp_dev *dev, @@ -269,11 +269,11 @@ static int smart_amp_verify_params(struct comp_dev *dev, { int ret; - comp_info(dev, "smart_amp_verify_params()"); + comp_info(dev, "entry"); ret = comp_verify_params(dev, BUFF_PARAMS_CHANNELS, params); if (ret < 0) { - comp_err(dev, "smart_amp_verify_params() error: comp_verify_params() failed."); + comp_err(dev, "error: comp_verify_params() failed."); return ret; } @@ -285,13 +285,13 @@ static int smart_amp_params(struct comp_dev *dev, { int err; - comp_info(dev, "smart_amp_params()"); + comp_info(dev, "entry"); smart_amp_set_params(dev, params); err = smart_amp_verify_params(dev, params); if (err < 0) { - comp_err(dev, "smart_amp_params(): pcm params verification failed."); + comp_err(dev, "pcm params verification failed."); return err; } @@ -303,7 +303,7 @@ static int smart_amp_trigger(struct comp_dev *dev, int cmd) struct smart_amp_data *sad = comp_get_drvdata(dev); int ret = 0; - comp_info(dev, "smart_amp_trigger(), command = %u", cmd); + comp_info(dev, "command = %u", cmd); ret = comp_set_state(dev, cmd); @@ -340,7 +340,7 @@ static int smart_amp_process_s16(struct comp_dev *dev, int i; int j; - comp_dbg(dev, "smart_amp_process_s16()"); + comp_dbg(dev, "entry"); for (i = 0; i < frames; i++) { for (j = 0 ; j < sad->out_channels; j++) { @@ -372,7 +372,7 @@ static int smart_amp_process_s32(struct comp_dev *dev, int i; int j; - comp_dbg(dev, "smart_amp_process_s32()"); + comp_dbg(dev, "entry"); for (i = 0; i < frames; i++) { for (j = 0 ; j < sad->out_channels; j++) { @@ -419,7 +419,7 @@ static int smart_amp_copy(struct comp_dev *dev) uint32_t sink_bytes; uint32_t feedback_bytes; - comp_dbg(dev, "smart_amp_copy()"); + comp_dbg(dev, "entry"); /* available bytes and samples calculation */ avail_passthrough_frames = @@ -440,7 +440,7 @@ static int smart_amp_copy(struct comp_dev *dev) feedback_bytes = avail_frames * audio_stream_frame_bytes(&buf->stream); - comp_dbg(dev, "smart_amp_copy(): processing %d feedback frames (avail_passthrough_frames: %d)", + comp_dbg(dev, "processing %d feedback frames (avail_passthrough_frames: %d)", avail_frames, avail_passthrough_frames); /* perform buffer writeback after source_buf process */ @@ -476,7 +476,7 @@ static int smart_amp_copy(struct comp_dev *dev) static int smart_amp_reset(struct comp_dev *dev) { - comp_info(dev, "smart_amp_reset()"); + comp_info(dev, "entry"); comp_set_state(dev, COMP_TRIGGER_RESET); @@ -489,7 +489,7 @@ static int smart_amp_prepare(struct comp_dev *dev) struct comp_buffer *source_buffer; int ret; - comp_info(dev, "smart_amp_prepare()"); + comp_info(dev, "entry"); ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); if (ret < 0) @@ -509,6 +509,10 @@ static int smart_amp_prepare(struct comp_dev *dev) } sad->sink_buf = comp_dev_get_first_data_consumer(dev); + if (!sad->sink_buf) { + comp_err(dev, "no sink buffer"); + return -ENOTCONN; + } sad->out_channels = audio_stream_get_channels(&sad->sink_buf->stream); @@ -523,7 +527,7 @@ static int smart_amp_prepare(struct comp_dev *dev) sad->process = get_smart_amp_process(dev, sad->source_buf); if (!sad->process) { - comp_err(dev, "smart_amp_prepare(): get_smart_amp_process failed"); + comp_err(dev, "get_smart_amp_process failed"); ret = -EINVAL; } return ret; @@ -551,8 +555,7 @@ static SHARED_DATA struct comp_driver_info comp_smart_amp_info = { UT_STATIC void sys_comp_smart_amp_test_init(void) { - comp_register(platform_shared_get(&comp_smart_amp_info, - sizeof(comp_smart_amp_info))); + comp_register(&comp_smart_amp_info); } DECLARE_MODULE(sys_comp_smart_amp_test_init); diff --git a/src/samples/audio/smart_amp_test_ipc4.c b/src/samples/audio/smart_amp_test_ipc4.c index 41d8ff2db25a..89d5861fed71 100644 --- a/src/samples/audio/smart_amp_test_ipc4.c +++ b/src/samples/audio/smart_amp_test_ipc4.c @@ -3,8 +3,8 @@ // Copyright(c) 2020 Intel Corporation. All rights reserved. // // Author: Bartosz Kokoszko <bartoszx.kokoszko@linux.intel.com> - -#ifndef __SOF_MODULE_SERVICE_BUILD__ +#include <sof/compiler_attributes.h> +#include <sof/samples/audio/smart_amp_test.h> #include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/ipc-config.h> #include <sof/trace/trace.h> @@ -18,29 +18,11 @@ #include <ipc4/module.h> LOG_MODULE_REGISTER(smart_amp_test, CONFIG_SOF_LOG_LEVEL); -#include <zephyr/logging/log.h> SOF_DEFINE_REG_UUID(smart_amp_test); DECLARE_TR_CTX(smart_amp_test_comp_tr, SOF_UUID(smart_amp_test_uuid), LOG_LEVEL_INFO); -#else -#include <string.h> -#include <stdint.h> -#include <stddef.h> - -#include <module/base.h> -#include <module/interface.h> -#include <iadk/adsp_error_code.h> -#include <audio/source_api.h> -#include <audio/sink_api.h> -#include <ipc4/module.h> -#include <sof/math/numbers.h> -#endif -#include <sof/compiler_attributes.h> -#include <sof/samples/audio/smart_amp_test.h> -#include <module/module/api_ver.h> -#include <rimage/sof/user/manifest.h> typedef void (*smart_amp_proc)(int8_t const *src_ptr, int8_t const *src_begin, @@ -53,61 +35,67 @@ typedef void (*smart_amp_proc)(int8_t const *src_ptr, struct smart_amp_data { struct sof_smart_amp_ipc4_config ipc4_cfg; struct sof_smart_amp_config config; + struct comp_data_blob_handler *model_handler; + void *data_blob; + size_t data_blob_size; smart_amp_proc process; uint32_t out_channels; }; -#ifdef __SOF_MODULE_SERVICE_BUILD__ -static struct smart_amp_data smart_amp_priv; -#endif - /* When building as a loadable module, we need .bss to avoid rimage errors */ static int keep_bss __attribute__((used)); static int smart_amp_init(struct processing_module *mod) { struct smart_amp_data *sad; + struct comp_dev *dev = mod->dev; struct module_data *mod_data = &mod->priv; - int ret; + const size_t in_size = sizeof(struct ipc4_input_pin_format) * SMART_AMP_NUM_IN_PINS; + const size_t out_size = sizeof(struct ipc4_output_pin_format) * SMART_AMP_NUM_OUT_PINS; const struct ipc4_base_module_extended_cfg *base_cfg = mod_data->cfg.init_data; + int ret; if (!base_cfg) { - LOG_ERR("smart_amp_init(): no module configuration"); + comp_err(dev, "No module configuration"); return -EINVAL; } - LOG_DBG("smart_amp_init()"); + comp_dbg(dev, "entry"); -#ifndef __SOF_MODULE_SERVICE_BUILD__ - sad = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*sad)); + sad = mod_zalloc(mod, sizeof(*sad)); if (!sad) return -ENOMEM; -#else - sad = &smart_amp_priv; -#endif + mod_data->private = sad; + /* component model data handler */ + sad->model_handler = mod_data_blob_handler_new(mod); + if (!sad->model_handler) { + ret = -ENOMEM; + goto sad_fail; + } + if (base_cfg->base_cfg_ext.nb_input_pins != SMART_AMP_NUM_IN_PINS || base_cfg->base_cfg_ext.nb_output_pins != SMART_AMP_NUM_OUT_PINS) { + comp_err(dev, "Invalid pin configuration"); ret = -EINVAL; goto sad_fail; } /* Copy the pin formats */ - sad->ipc4_cfg.input_pins[0] = - *((struct ipc4_input_pin_format *)base_cfg->base_cfg_ext.pin_formats); - sad->ipc4_cfg.input_pins[1] = - *((struct ipc4_input_pin_format *)base_cfg->base_cfg_ext.pin_formats + 1); - sad->ipc4_cfg.output_pin = - *(struct ipc4_output_pin_format *)(base_cfg->base_cfg_ext.pin_formats - + sizeof(sad->ipc4_cfg.input_pins)); + memcpy_s(sad->ipc4_cfg.input_pins, in_size, + base_cfg->base_cfg_ext.pin_formats, in_size); + memcpy_s(&sad->ipc4_cfg.output_pin, out_size, + &base_cfg->base_cfg_ext.pin_formats[in_size], out_size); + + mod->max_sources = SMART_AMP_NUM_IN_PINS; return 0; sad_fail: -#ifndef __SOF_MODULE_SERVICE_BUILD__ - rfree(sad); -#endif + mod_data_blob_handler_free(mod, sad->model_handler); + mod_free(mod, sad); + return ret; } @@ -116,21 +104,23 @@ static int smart_amp_set_config(struct processing_module *mod, uint32_t config_i const uint8_t *fragment, size_t fragment_size, uint8_t *response, size_t response_size) { + struct comp_dev *dev = mod->dev; struct smart_amp_data *sad = module_get_private_data(mod); - LOG_DBG("smart_amp_set_config()"); + comp_dbg(dev, "entry"); switch (config_id) { case SMART_AMP_SET_MODEL: - return 0; + return comp_data_blob_set(sad->model_handler, pos, + data_offset_size, fragment, fragment_size); case SMART_AMP_SET_CONFIG: if (fragment_size != sizeof(sad->config)) { - LOG_ERR("smart_amp_set_config(): invalid config size %u, expect %u", - fragment_size, sizeof(struct sof_smart_amp_config)); + comp_err(dev, "invalid config size %u, expect %u", + fragment_size, sizeof(struct sof_smart_amp_config)); return -EINVAL; } - LOG_DBG("smart_amp_set_config(): config size = %u", fragment_size); - sad->config = *(struct sof_smart_amp_config *)fragment; + comp_dbg(dev, "config size = %u", fragment_size); + memcpy_s(&sad->config, sizeof(sad->config), fragment, fragment_size); return 0; default: return -EINVAL; @@ -142,12 +132,19 @@ static inline int smart_amp_get_config(struct processing_module *mod, uint8_t *fragment, size_t fragment_size) { struct smart_amp_data *sad = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + int ret; - LOG_DBG("smart_amp_get_config()"); + comp_dbg(dev, "entry"); switch (config_id) { case SMART_AMP_GET_CONFIG: - *(struct sof_smart_amp_config *)fragment = sad->config; + ret = memcpy_s(fragment, fragment_size, &sad->config, sizeof(sad->config)); + if (ret) { + comp_err(dev, "wrong config size %d", + fragment_size); + return ret; + } *data_offset_size = sizeof(sad->config); return 0; default: @@ -157,11 +154,12 @@ static inline int smart_amp_get_config(struct processing_module *mod, static int smart_amp_free(struct processing_module *mod) { -#ifndef __SOF_MODULE_SERVICE_BUILD__ struct smart_amp_data *sad = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; - rfree(sad); -#endif + comp_dbg(dev, "entry"); + mod_data_blob_handler_free(mod, sad->model_handler); + mod_free(mod, sad); return 0; } @@ -333,7 +331,6 @@ static smart_amp_proc get_smart_amp_process(struct sof_source **sources, int num case SOF_IPC_FRAME_S32_LE: break; default: - LOG_ERR("smart_amp_process() error: not supported frame format"); return NULL; } } @@ -345,7 +342,6 @@ static smart_amp_proc get_smart_amp_process(struct sof_source **sources, int num case SOF_IPC_FRAME_S32_LE: break; default: - LOG_ERR("smart_amp_process() error: not supported frame format"); return NULL; } } @@ -357,12 +353,11 @@ static int smart_amp_prepare(struct processing_module *mod, struct sof_sink **sinks, int num_of_sinks) { struct smart_amp_data *sad = module_get_private_data(mod); - - LOG_DBG("smart_amp_prepare()"); + struct comp_dev *dev = mod->dev; sad->process = get_smart_amp_process(sources, num_of_sources, sinks, num_of_sinks); if (!sad->process) { - LOG_ERR("smart_amp_prepare(): get_smart_amp_process failed"); + comp_err(dev, "get_smart_amp_process() failed"); return -EINVAL; } @@ -379,61 +374,23 @@ static const struct module_interface smart_amp_test_interface = { .free = smart_amp_free }; -/* - * We have to distinguish between 3 kinds of builds: - * 1. built-in: MAJOR_IADSP_API_VERSION isn't defined - * 2. system-service API: MAJOR_IADSP_API_VERSION and - * __SOF_MODULE_SERVICE_BUILD__ are defined - * 3. dynamic linking: only MAJOR_IADSP_API_VERSION is defined - */ - -#ifndef __SOF_MODULE_SERVICE_BUILD__ -/* All builds except system-service API */ - -DECLARE_MODULE_ADAPTER(smart_amp_test_interface, smart_amp_test_uuid, smart_amp_test_comp_tr); -/* DECLARE_MODULE_ADAPTER() creates - * "sys_comp_module_<smart_amp_test_interface>_init()" (and a lot more) - */ -SOF_MODULE_INIT(smart_amp_test, sys_comp_module_smart_amp_test_interface_init); - -#endif - -#if defined(MAJOR_IADSP_API_VERSION) || defined(CONFIG_SAMPLE_SMART_AMP_MODULE) -/* modular: system-services or dynamic link */ +#if CONFIG_SAMPLE_SMART_AMP_MODULE +/* modular: llext dynamic link */ +#include <module/module/api_ver.h> #include <module/module/llext.h> +#include <rimage/sof/user/manifest.h> -SOF_LLEXT_MOD_ENTRY(smart_amp_test, &smart_amp_test_interface); - -static const struct sof_man_module_manifest main_manifest __section(".module") __attribute__((used)) = { - .module = { - .name = "SMATEST", - .uuid = {0x1E, 0x96, 0x7A, 0x16, 0xE4, 0x8A, 0xEA, 0x11, - 0x89, 0xF1, 0x00, 0x0C, 0x29, 0xCE, 0x16, 0x35}, - .entry_point = (uint32_t)smart_amp_test_llext_entry, - .instance_max_count = 1, - .type = { -#ifdef __SOF_MODULE_SERVICE_BUILD__ - .load_type = SOF_MAN_MOD_TYPE_MODULE, -#else - .load_type = SOF_MAN_MOD_TYPE_LLEXT, -#endif - .domain_ll = 1, - }, - .affinity_mask = 1, - } +static const struct sof_man_module_manifest mod_manifest[] __section(".module") __used = { + SOF_LLEXT_MODULE_MANIFEST("SMATEST", &smart_amp_test_interface, 1, + SOF_REG_UUID(smart_amp_test), 1), }; -#ifdef __SOF_MODULE_SERVICE_BUILD__ -/* system services */ - -DECLARE_LOADABLE_MODULE_API_VERSION(smart_amp_test); +SOF_LLEXT_BUILDINFO; #else -/* dynamic link */ - -SOF_LLEXT_BUILDINFO; -#endif +DECLARE_MODULE_ADAPTER(smart_amp_test_interface, smart_amp_test_uuid, smart_amp_test_comp_tr); +SOF_MODULE_INIT(smart_amp_test, sys_comp_module_smart_amp_test_interface_init); #endif diff --git a/src/schedule/CMakeLists.txt b/src/schedule/CMakeLists.txt index cc9a83c5daab..622b75e46888 100644 --- a/src/schedule/CMakeLists.txt +++ b/src/schedule/CMakeLists.txt @@ -1,17 +1,61 @@ # SPDX-License-Identifier: BSD-3-Clause -if(CONFIG_SCHEDULE_DMA_MULTI_CHANNEL) - add_local_sources(sof dma_multi_chan_domain.c) +set(base_files + schedule.c +) + +if(CONFIG_SCHEDULE_DMA_MULTI_CHANNEL AND NOT(CONFIG_DMA_DOMAIN)) + list(APPEND base_files dma_multi_chan_domain.c) endif() -if(CONFIG_SCHEDULE_DMA_SINGLE_CHANNEL) - add_local_sources(sof dma_single_chan_domain.c) +if(CONFIG_SCHEDULE_DMA_SINGLE_CHANNEL AND NOT(CONFIG_DMA_DOMAIN)) + list(APPEND base_files dma_single_chan_domain.c) endif() -add_local_sources(sof - edf_schedule.c - ll_schedule.c - schedule.c - task.c - timer_domain.c +is_zephyr(zephyr) +if(zephyr) ### Zephyr ### + +zephyr_library_sources( + ${base_files} + zephyr_domain.c ) + +if (CONFIG_SOC_ACP_6_0) + # Zephyr DMA domain should only be used with zephyr_ll + if (CONFIG_DMA_DOMAIN) + zephyr_library_sources( + zephyr_ll.c + zephyr_dma_domain.c + ) + else() + zephyr_library_sources( + ll_schedule_xtos.c + ) + endif() +else() + zephyr_library_sources( + zephyr_ll.c + ) +endif() + +if (CONFIG_SOF_USERSPACE_APPLICATION) + zephyr_library_sources_ifdef(CONFIG_ZEPHYR_DP_SCHEDULER + zephyr_dp_schedule.c + zephyr_dp_schedule_application.c + ) +else() + zephyr_library_sources_ifdef(CONFIG_ZEPHYR_DP_SCHEDULER + zephyr_dp_schedule.c + zephyr_dp_schedule_thread.c + ) +endif() + +zephyr_library_sources_ifdef(CONFIG_ZEPHYR_TWB_SCHEDULER + zephyr_twb_schedule.c +) + +zephyr_library_sources_ifdef(CONFIG_SOF_USERSPACE_LL + zephyr_ll_user.c +) + +endif() diff --git a/src/schedule/Kconfig b/src/schedule/Kconfig index d7665aee3581..f1383e70103f 100644 --- a/src/schedule/Kconfig +++ b/src/schedule/Kconfig @@ -15,6 +15,7 @@ config SCHEDULE_DMA_MULTI_CHANNEL config SCHEDULE_LL_STATS_LOG bool "Log low-latency scheduler statistics" default y + depends on !SOF_USERSPACE_LL help Log statistics from low-latency scheduler. This is a low overhead mechanism to gather average and worst-case execution times of @@ -41,3 +42,32 @@ config SCHEDULE_LL_STATS_LOG_WINDOW_SIZE Size of the statistics window as a power of two. The window size setting also impacts the rate of reporting. With 1ms scheduler tick, default of 10 results in 1024msec window size. + +config SCHEDULE_LL_NO_RESCHEDULE_TASK + bool "Low-latency scheduler skips task rescheduling" + default n + help + Select this to instantiate the low-latency scheduler without task + rescheduling, given that the operation is optional. Under such cases, + scheduler_ops::reschedule_task will set to NULL instead, tasks with + the attempt to reschedule (e.g. DMA trace works) will be relinguished + directly and return no error. + +config ZEPHYR_TWB_SCHEDULER + bool "use Zephyr thread based TWB scheduler" + default n + depends on ZEPHYR_SOF_MODULE + depends on TIMESLICE_PER_THREAD + depends on THREAD_RUNTIME_STATS + depends on SCHED_THREAD_USAGE + help + Enable Tasks with Budget preemptive scheduler based on + Zephyr preemptive threads for each SOF task that has pre-allocated + MCPS budget renewed with every system tick. + +config TWB_IPC_TASK + bool "use TWB scheduler for IPC task" + default n + depends on ZEPHYR_TWB_SCHEDULER + help + Switch IPC task to TWB scheduler. diff --git a/src/schedule/Kconfig.threads_prio b/src/schedule/Kconfig.threads_prio new file mode 100644 index 000000000000..a7d51c666b63 --- /dev/null +++ b/src/schedule/Kconfig.threads_prio @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config LL_THREAD_PRIORITY + int "LL thread cooperative high priority" + default -16 + help + LL thread configured priority in the system. + Should be in cooperative range: + -NUM_COOP_PRIORITIES to -1 + +config TWB_THREAD_MEDIUM_PRIORITY + int "TWB thread preemptible medium priority" + default 1 + help + TWB thread configured priority in the system. + Should be in preemptible range: + 0 to NUM_PREEMPT_PRIORITIES-1 + +config TWB_THREAD_LOW_PRIORITY + int "TWB thread preemptible low priority" + default 12 + help + TWB thread configured priority in the system. + Should be in preemptible range: + 0 to NUM_PREEMPT_PRIORITIES-1 + +config DP_THREAD_PRIORITY + int "DP thread preemptible low priority" + default 12 + help + DP thread configured priority in the system. + Should be in preemptible range: + 0 to NUM_PREEMPT_PRIORITIES-1 + +config EDF_THREAD_PRIORITY + int "EDF thread preemptible low priority" + default 1 + help + EDF thread configured priority in the system. + Should be in preemptible range: + 0 to NUM_PREEMPT_PRIORITIES-1 diff --git a/src/schedule/README.md b/src/schedule/README.md new file mode 100644 index 000000000000..493ab092decc --- /dev/null +++ b/src/schedule/README.md @@ -0,0 +1,168 @@ +# SOF Scheduling Architecture + +This directory (`src/schedule`) contains the Sound Open Firmware (SOF) scheduling infrastructure, deeply integrated with the underlying Zephyr RTOS. SOF utilizes a multi-tiered scheduling approach to cater to different real-time constraints, ranging from hard real-time, low-latency requirements to more relaxed, compute-intensive data processing tasks. + +## Overview of Schedulers + +SOF categorizes tasks and assigns them to specialized schedulers: + +1. **LL (Low Latency) Scheduler**: For tasks that require strict, predictable, and lowest possible latency bound to hardware events (Timers, DMA interrupts). +2. **DP (Data Processing) Scheduler**: For compute-intensive components that process large chunks of data and operate on deadlines rather than strict cycles. +3. **TWB (Thread With Budget) Scheduler**: For tasks that are allotted a specific execution "budget" per scheduler tick, expressed in Zephyr time-slice ticks (e.g. derived from `ZEPHYR_TWB_BUDGET_MAX` in OS ticks), which the runtime then uses to limit and account for CPU cycles to prevent starvation. + +Below is a high-level component interaction architecture of the SOF scheduling domains on top of Zephyr. + +```mermaid +graph TD + subgraph Zephyr RTOS + Timer[Hardware Timer] + DMA[DMA Controller] + Threads[Zephyr Threads] + end + + subgraph Generic Scheduler API + API[schedule.c API] + end + + subgraph LL Scheduler Domain + LL[zephyr_ll.c] + LLDomain[zephyr_domain.c] + DMADomain[zephyr_dma_domain.c] + end + + subgraph DP Scheduler Domain + DP[zephyr_dp_schedule.c] + DPThread[zephyr_dp_schedule_thread.c] + end + + subgraph TWB Scheduler Domain + TWB[zephyr_twb_schedule.c] + end + + API --> LL + API --> DP + API --> TWB + + Timer -.->|Interrupt| LLDomain + DMA -.->|Interrupt| DMADomain + + LLDomain --> |Wakeup| LL + DMADomain --> |Wakeup| LL + LL -->|Runs tasks| Threads + + LL -->|NOTIFIER_ID_LL_POST_RUN| DP + DP -->|Recalculate Deadlines| DPThread + DPThread -->|Update Thread Deadlines| Threads + + LL -->|LL Tick Source| TWB + TWB -->|Update Time Slices| Threads +``` + +--- + +## 1. LL (Low Latency) Scheduler + +The LL scheduler (`zephyr_ll.c`) is designed for extreme low-latency processing. It bypasses complex generic Zephyr scheduling for its internal tasks to minimize overhead, executing a list of registered SOF tasks in a strict priority order. + +### Architecture + +- **Domain Threads**: The LL scheduler runs within a dedicated high-priority Zephyr thread (`ll_thread0`, etc.) pinned to each core (`zephyr_domain.c`). +- **Triggers**: It is woken up by a hardware timer (e.g., a 1ms tick) or directly by hardware DMA interrupts (`zephyr_dma_domain.c`). +- **Execution**: Once woken up, it locks the domain, iterates through all scheduled tasks in priority order, moves them to a temporary list, and calls their `.run()` functions. +- **Post-Run**: After all tasks execute, it triggers a `NOTIFIER_ID_LL_POST_RUN` event. This event cascades to wake up other dependent schedulers like DP and TWB. Event not run on LL userspace configuration. + +### Task State Diagram + +```mermaid +stateDiagram-v2 + [*] --> INIT: task_init + INIT --> QUEUED: schedule_task + QUEUED --> RUNNING: zephyr_ll_run (Timer/DMA Tick) + RUNNING --> RUNNING: return RESCHEDULE + RUNNING --> FREE: return COMPLETED + RUNNING --> CANCEL: task_cancel + + QUEUED --> CANCEL: task_cancel + CANCEL --> FREE: task_free + + FREE --> [*] +``` + +*(Note: State transitions handle Zephyr SMP locking to ensure a task is safely dequeued before state shifts)* + +--- + +## 2. DP (Data Processing) Scheduler + +The DP scheduler (`zephyr_dp_schedule.c`) manages asynchronous, compute-heavy tasks that process data when enough input is available and sufficient output space is free. It effectively relies on Zephyr's EDF (Earliest Deadline First) or standard preemptive scheduling capabilities. + +### Architecture + +- **Separate Threads**: Unlike LL which multiplexes tasks inside a single thread, **each DP task is assigned its own Zephyr thread**. +- **Wakeup Mechanism**: DP scheduling is evaluated at the end of each LL tick (`scheduler_dp_recalculate()`). +- **Readiness**: It checks if a component has sufficient data across its sinks and sources. If so, it transitions to `RUNNING` and signals the individual DP thread via a Zephyr Event object. +- **Deadlines**: Once ready, the DP thread computes its deadline absolute timestamp (`module_get_deadline()`) and calls `k_thread_absolute_deadline_set()`, submitting to the Zephyr kernel's EDF scheduler. + +### Task State Diagram + +```mermaid +stateDiagram-v2 + [*] --> INIT: task_init + INIT --> QUEUED: schedule_task + + note right of QUEUED + Wait for LL POST RUN event + to evaluate Readiness. + end note + + QUEUED --> RUNNING: resources ready (set priority/deadline) + RUNNING --> QUEUED: return RESCHEDULE (processed chunk) + RUNNING --> COMPLETED: return COMPLETED + RUNNING --> CANCEL: task_cancel + + QUEUED --> CANCEL: task_cancel + COMPLETED --> FREE: task_free + CANCEL --> FREE: task_free + + FREE --> [*] +``` + +--- + +## 3. TWB (Thread With Budget) Scheduler + +The TWB scheduler (`zephyr_twb_schedule.c`) provides execution budget limits for specific tasks to prevent them from starving the CPU. This is useful for intensive workloads that shouldn't disrupt the overall systemic low-latency chain. + +### Architecture + +- **Separate Threads**: Similar to DP, each TWB task executes in its own Zephyr thread. +- **Time Slicing**: When scheduled, the thread's execution budget is configured in OS ticks via `k_thread_time_slice_set()`. This tick-based budget is internally converted to hardware cycles for accounting against the CPU cycles actually consumed. +- **Budget Exhaustion**: If the thread consumes its budget (as measured in hardware cycles derived from the tick budget) before completing its work for the tick, a callback (`scheduler_twb_task_cb()`) is invoked by the Zephyr kernel. This callback immediately drops the thread's priority to a background level (`CONFIG_TWB_THREAD_LOW_PRIORITY`), preventing starvation of other threads. +- **Replenishment**: On the next LL tick (`scheduler_twb_ll_tick()`), the consumed hardware cycles are reset, and the thread's original priority and time slice are restored, granting it a fresh tick-based budget. + +### Task State Diagram + +```mermaid +stateDiagram-v2 + [*] --> INIT: task_init + INIT --> RUNNING: schedule_task (Thread Created) + + state RUNNING { + [*] --> HighPriority: Budget replenished + HighPriority --> LowPriority: Budget Exhausted (Callback) + LowPriority --> HighPriority: Next LL Tick + } + + RUNNING --> QUEUED: return RESCHEDULE + QUEUED --> RUNNING: Next LL Tick (Restore Priority) + + RUNNING --> CANCEL: task_cancel + QUEUED --> CANCEL: task_cancel + + RUNNING --> COMPLETED: return COMPLETED + + CANCEL --> FREE: task_free + COMPLETED --> FREE: task_free + + FREE --> [*] +``` diff --git a/src/schedule/dma_multi_chan_domain.c b/src/schedule/dma_multi_chan_domain.c index 9bf41a8515dc..7fd478d50afc 100644 --- a/src/schedule/dma_multi_chan_domain.c +++ b/src/schedule/dma_multi_chan_domain.c @@ -86,7 +86,7 @@ static int dma_multi_chan_domain_irq_register(struct dma_domain_data *data, { int ret; - tr_info(&ll_tr, "dma_multi_chan_domain_irq_register()"); + tr_info(&ll_tr, "entry"); /* always go through dma_multi_chan_domain_irq_handler, * so we have different arg registered for every channel @@ -125,7 +125,7 @@ static int dma_multi_chan_domain_register(struct ll_schedule_domain *domain, int i; int j; - tr_info(&ll_tr, "dma_multi_chan_domain_register()"); + tr_info(&ll_tr, "entry"); /* check if task should be registered */ if (!pipe_task->registrable) @@ -192,7 +192,7 @@ static int dma_multi_chan_domain_register(struct ll_schedule_domain *domain, */ static void dma_multi_chan_domain_irq_unregister(struct dma_domain_data *data) { - tr_info(&ll_tr, "dma_multi_chan_domain_irq_unregister()"); + tr_info(&ll_tr, "entry"); interrupt_disable(data->irq, data); @@ -217,7 +217,7 @@ static int dma_multi_chan_domain_unregister(struct ll_schedule_domain *domain, int i; int j; - tr_info(&ll_tr, "dma_multi_chan_domain_unregister()"); + tr_info(&ll_tr, "entry"); /* check if task should be unregistered */ if (!task || !pipe_task->registrable) @@ -365,13 +365,22 @@ struct ll_schedule_domain *dma_multi_chan_domain_init(struct dma *dma_array, int i; int j; - tr_info(&ll_tr, "dma_multi_chan_domain_init(): num_dma %d, clk %d, aggregated_irq %d", + tr_info(&ll_tr, "num_dma %d, clk %d, aggregated_irq %d", num_dma, clk, aggregated_irq); domain = domain_init(SOF_SCHEDULE_LL_DMA, clk, true, &dma_multi_chan_domain_ops); + if (!domain) { + tr_err(&ll_tr, "domain init failed"); + return NULL; + } - dma_domain = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dma_domain)); + dma_domain = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*dma_domain)); + if (!dma_domain) { + tr_err(&ll_tr, "allocation failed"); + rfree(domain); + return NULL; + } dma_domain->dma_array = dma_array; dma_domain->num_dma = num_dma; dma_domain->aggregated_irq = aggregated_irq; diff --git a/src/schedule/dma_single_chan_domain.c b/src/schedule/dma_single_chan_domain.c index 7016bc64688a..d234c473586a 100644 --- a/src/schedule/dma_single_chan_domain.c +++ b/src/schedule/dma_single_chan_domain.c @@ -101,7 +101,7 @@ static struct dma_chan_data *dma_chan_min_period(struct dma_domain *dma_domain) */ static void dma_domain_notify_change(struct dma_chan_data *channel) { - tr_info(&ll_tr, "dma_domain_notify_change()"); + tr_info(&ll_tr, "entry"); notifier_event(channel, NOTIFIER_ID_DMA_DOMAIN_CHANGE, NOTIFIER_TARGET_CORE_ALL_MASK & ~BIT(cpu_get_id()), @@ -124,7 +124,7 @@ static int dma_single_chan_domain_irq_register(struct dma_chan_data *channel, int irq = dma_chan_irq(channel->dma, channel->index); int ret; - tr_info(&ll_tr, "dma_single_chan_domain_irq_register()"); + tr_info(&ll_tr, "entry"); data->irq = interrupt_get_irq(irq, dma_irq_name(channel->dma)); if (data->irq < 0) { @@ -154,7 +154,7 @@ static int dma_single_chan_domain_irq_register(struct dma_chan_data *channel, */ static void dma_single_chan_domain_irq_unregister(struct dma_domain_data *data) { - tr_info(&ll_tr, "dma_single_chan_domain_irq_unregister()"); + tr_info(&ll_tr, "entry"); interrupt_disable(data->irq, data->arg); interrupt_unregister(data->irq, data->arg); @@ -188,7 +188,7 @@ static int dma_single_chan_domain_register(struct ll_schedule_domain *domain, bool register_needed = true; int ret = 0; - tr_info(&ll_tr, "dma_single_chan_domain_register()"); + tr_info(&ll_tr, "entry"); /* check if task should be registered */ if (!pipe_task->registrable) @@ -206,7 +206,7 @@ static int dma_single_chan_domain_register(struct ll_schedule_domain *domain, if (data->channel->period == channel->period) goto out; - tr_info(&ll_tr, "dma_single_chan_domain_register(): lower period detected, registering again"); + tr_info(&ll_tr, "lower period detected, registering again"); /* unregister from current channel */ dma_single_chan_domain_irq_unregister(data); @@ -221,11 +221,11 @@ static int dma_single_chan_domain_register(struct ll_schedule_domain *domain, if (channel->period <= UINT_MAX) tr_info(&ll_tr, - "dma_single_chan_domain_register(): registering on channel with period %u", + "registering on channel with period %u", (unsigned int)channel->period); else tr_info(&ll_tr, - "dma_single_chan_domain_register(): registering on channel with period > %u", + "registering on channel with period > %u", UINT_MAX); /* register for interrupt */ @@ -308,7 +308,7 @@ static void dma_domain_unregister_owner(struct ll_schedule_domain *domain, struct dma *dmas = dma_domain->dma_array; struct dma_chan_data *channel; - tr_info(&ll_tr, "dma_domain_unregister_owner()"); + tr_info(&ll_tr, "entry"); /* transfers still scheduled on this channel */ if (data->channel->status == COMP_STATE_ACTIVE) @@ -317,7 +317,7 @@ static void dma_domain_unregister_owner(struct ll_schedule_domain *domain, channel = dma_chan_min_period(dma_domain); if (channel && dma_chan_is_any_running(dmas, dma_domain->num_dma)) { /* another channel is running */ - tr_info(&ll_tr, "dma_domain_unregister_owner(): domain in use, change owner"); + tr_info(&ll_tr, "domain in use, change owner"); /* change owner */ dma_domain->owner = channel->core; @@ -369,7 +369,7 @@ static int dma_single_chan_domain_unregister(struct ll_schedule_domain *domain, int core = cpu_get_id(); struct dma_domain_data *data = &dma_domain->data[core]; - tr_info(&ll_tr, "dma_single_chan_domain_unregister()"); + tr_info(&ll_tr, "entry"); /* check if task should be unregistered */ if (!task || !pipe_task->registrable) @@ -505,7 +505,7 @@ static void dma_domain_changed(void *arg, enum notify_id type, void *data) int core = cpu_get_id(); struct dma_domain_data *domain_data = &dma_domain->data[core]; - tr_info(&ll_tr, "dma_domain_changed()"); + tr_info(&ll_tr, "entry"); /* unregister from current DMA channel */ dma_single_chan_domain_irq_unregister(domain_data); @@ -538,13 +538,22 @@ struct ll_schedule_domain *dma_single_chan_domain_init(struct dma *dma_array, struct ll_schedule_domain *domain; struct dma_domain *dma_domain; - tr_info(&ll_tr, "dma_single_chan_domain_init(): num_dma %d, clk %d", + tr_info(&ll_tr, "num_dma %d, clk %d", num_dma, clk); domain = domain_init(SOF_SCHEDULE_LL_DMA, clk, false, &dma_single_chan_domain_ops); + if (!domain) { + tr_err(&ll_tr, "domain init failed"); + return NULL; + } - dma_domain = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dma_domain)); + dma_domain = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*dma_domain)); + if (!dma_domain) { + tr_err(&ll_tr, "allocation failed"); + rfree(domain); + return NULL; + } dma_domain->dma_array = dma_array; dma_domain->num_dma = num_dma; dma_domain->owner = DMA_DOMAIN_OWNER_INVALID; diff --git a/src/schedule/edf_schedule.c b/src/schedule/edf_schedule.c deleted file mode 100644 index 11bf195dba7a..000000000000 --- a/src/schedule/edf_schedule.c +++ /dev/null @@ -1,335 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2017 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> -// Tomasz Lauda <tomasz.lauda@linux.intel.com> - -#include <sof/common.h> -#include <rtos/panic.h> -#include <rtos/interrupt.h> -#include <rtos/timer.h> -#include <rtos/alloc.h> -#include <rtos/clk.h> -#include <sof/lib/uuid.h> -#include <sof/list.h> -#include <sof/platform.h> -#include <sof/schedule/edf_schedule.h> -#include <sof/schedule/schedule.h> -#include <rtos/task.h> -#include <rtos/sof.h> -#include <ipc/topology.h> -#include <errno.h> -#include <stddef.h> -#include <stdint.h> - -SOF_DEFINE_REG_UUID(edf_sched); - -DECLARE_TR_CTX(edf_tr, SOF_UUID(edf_sched_uuid), LOG_LEVEL_INFO); - -struct edf_schedule_data { - struct list_item list; /* list of tasks in priority queue */ - uint32_t clock; - int irq; -}; - -static const struct scheduler_ops schedule_edf_ops; - -static int schedule_edf_task_complete(void *data, struct task *task); -static int schedule_edf_task_running(void *data, struct task *task); -static void schedule_edf(struct edf_schedule_data *edf_sch); - -static void schedule_edf_task_run(struct task *task, void *data) -{ - while (1) { - /* execute task run function and remove task from the list - * only if completed - */ - if (task_run(task) == SOF_TASK_STATE_COMPLETED) - schedule_edf_task_complete(data, task); - - /* find new task for execution */ - schedule_edf(data); - } -} - -static void edf_scheduler_run(void *data) -{ - struct edf_schedule_data *edf_sch = data; - uint64_t deadline_next = SOF_TASK_DEADLINE_IDLE; - struct task *task_next = NULL; - struct list_item *tlist; - struct task *task; - uint64_t deadline; - uint32_t flags; - - tr_dbg(&edf_tr, "edf_scheduler_run()"); - - irq_local_disable(flags); - - /* find next task to run */ - list_for_item(tlist, &edf_sch->list) { - task = container_of(tlist, struct task, list); - - if (task->state != SOF_TASK_STATE_QUEUED && - task->state != SOF_TASK_STATE_RUNNING) - continue; - - deadline = task_get_deadline(task); - - if (deadline == SOF_TASK_DEADLINE_NOW) { - /* task needs to be scheduled ASAP */ - task_next = task; - break; - } - - /* get earliest deadline */ - if (deadline <= deadline_next) { - deadline_next = deadline; - task_next = task; - } - } - - irq_local_enable(flags); - - /* schedule next pending task */ - if (task_next) - schedule_edf_task_running(data, task_next); -} - -static int schedule_edf_task(void *data, struct task *task, uint64_t start, - uint64_t period) -{ - struct edf_schedule_data *edf_sch = data; - uint32_t flags; - (void) period; /* not used */ - (void) start; /* not used */ - - irq_local_disable(flags); - - /* not enough MCPS to complete */ - if (task->state == SOF_TASK_STATE_QUEUED || - task->state == SOF_TASK_STATE_RUNNING) { - tr_err(&edf_tr, "schedule_edf_task(), task already queued or running %d", - task->state); - irq_local_enable(flags); - return -EALREADY; - } - - /* add task to the list */ - list_item_append(&task->list, &edf_sch->list); - - task->state = SOF_TASK_STATE_QUEUED; - - irq_local_enable(flags); - - schedule_edf(edf_sch); - - return 0; -} - -int schedule_task_init_edf(struct task *task, const struct sof_uuid_entry *uid, - const struct task_ops *ops, - void *data, uint16_t core, uint32_t flags) -{ - struct edf_task_pdata *edf_pdata = NULL; - int ret; - - ret = schedule_task_init(task, uid, SOF_SCHEDULE_EDF, 0, ops->run, data, - core, flags); - if (ret < 0) - return ret; - - if (edf_sch_get_pdata(task)) - return -EEXIST; - - edf_pdata = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(*edf_pdata)); - if (!edf_pdata) { - tr_err(&edf_tr, "schedule_task_init_edf(): alloc failed"); - return -ENOMEM; - } - - edf_sch_set_pdata(task, edf_pdata); - - task->ops.complete = ops->complete; - task->ops.get_deadline = ops->get_deadline; - - if (task_context_alloc(&edf_pdata->ctx) < 0) - goto error; - if (task_context_init(edf_pdata->ctx, &schedule_edf_task_run, - task, scheduler_get_data(SOF_SCHEDULE_EDF), - task->core, NULL, 0) < 0) - goto error; - - /* flush for secondary core */ - if (!cpu_is_primary(task->core)) - dcache_writeback_invalidate_region(edf_pdata, - sizeof(*edf_pdata)); - return 0; - -error: - tr_err(&edf_tr, "schedule_task_init_edf(): init context failed"); - if (edf_pdata->ctx) - task_context_free(edf_pdata->ctx); - rfree(edf_pdata); - edf_sch_set_pdata(task, NULL); - return -EINVAL; -} - -static int schedule_edf_task_running(void *data, struct task *task) -{ - struct edf_task_pdata *edf_pdata = edf_sch_get_pdata(task); - uint32_t flags; - - tr_dbg(&edf_tr, "schedule_edf_task_running()"); - - irq_local_disable(flags); - - task_context_set(edf_pdata->ctx); - task->state = SOF_TASK_STATE_RUNNING; - - irq_local_enable(flags); - - return 0; -} - -static int schedule_edf_task_complete(void *data, struct task *task) -{ - uint32_t flags; - - tr_dbg(&edf_tr, "schedule_edf_task_complete()"); - - irq_local_disable(flags); - - task_complete(task); - - task->state = SOF_TASK_STATE_COMPLETED; - list_item_del(&task->list); - - irq_local_enable(flags); - - return 0; -} - -static int schedule_edf_task_cancel(void *data, struct task *task) -{ - uint32_t flags; - - tr_dbg(&edf_tr, "schedule_edf_task_cancel()"); - - irq_local_disable(flags); - - /* cancel and delete only if queued */ - if (task->state == SOF_TASK_STATE_QUEUED) { - task->state = SOF_TASK_STATE_CANCEL; - list_item_del(&task->list); - } - - irq_local_enable(flags); - - return 0; -} - -static int schedule_edf_task_free(void *data, struct task *task) -{ - struct edf_task_pdata *edf_pdata = edf_sch_get_pdata(task); - uint32_t flags; - - irq_local_disable(flags); - - task->state = SOF_TASK_STATE_FREE; - - task_context_free(edf_pdata->ctx); - edf_pdata->ctx = NULL; - rfree(edf_pdata); - edf_sch_set_pdata(task, NULL); - - irq_local_enable(flags); - - return 0; -} - -int scheduler_init_edf(void) -{ - struct edf_schedule_data *edf_sch; - - tr_info(&edf_tr, "edf_scheduler_init()"); - - edf_sch = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, - sizeof(*edf_sch)); - list_init(&edf_sch->list); - edf_sch->clock = PLATFORM_DEFAULT_CLOCK; - - scheduler_init(SOF_SCHEDULE_EDF, &schedule_edf_ops, edf_sch); - - /* initialize main task context before enabling interrupt */ - task_main_init(); - - /* configure EDF scheduler interrupt */ - edf_sch->irq = interrupt_get_irq(PLATFORM_SCHEDULE_IRQ, - PLATFORM_SCHEDULE_IRQ_NAME); - if (edf_sch->irq < 0) - return edf_sch->irq; - - interrupt_register(edf_sch->irq, edf_scheduler_run, edf_sch); - interrupt_enable(edf_sch->irq, edf_sch); - - return 0; -} - -static void scheduler_free_edf(void *data, uint32_t flags) -{ - struct edf_schedule_data *edf_sch = data; - uint32_t irq_flags; - - irq_local_disable(irq_flags); - - /* disable and unregister EDF scheduler interrupt */ - interrupt_disable(edf_sch->irq, edf_sch); - interrupt_unregister(edf_sch->irq, edf_sch); - - if (!(flags & SOF_SCHEDULER_FREE_IRQ_ONLY)) - /* free main task context */ - task_main_free(); - - irq_local_enable(irq_flags); -} - -static int scheduler_restore_edf(void *data) -{ - struct edf_schedule_data *edf_sch = data; - uint32_t flags; - - irq_local_disable(flags); - - edf_sch->irq = interrupt_get_irq(PLATFORM_SCHEDULE_IRQ, - PLATFORM_SCHEDULE_IRQ_NAME); - - if (edf_sch->irq < 0) { - tr_err(&edf_tr, "scheduler_restore_edf(): getting irq failed."); - return edf_sch->irq; - } - - interrupt_register(edf_sch->irq, edf_scheduler_run, edf_sch); - interrupt_enable(edf_sch->irq, edf_sch); - - irq_local_enable(flags); - - return 0; -} - -static void schedule_edf(struct edf_schedule_data *edf_sch) -{ - interrupt_set(edf_sch->irq); -} - -static const struct scheduler_ops schedule_edf_ops = { - .schedule_task = schedule_edf_task, - .schedule_task_running = schedule_edf_task_running, - .reschedule_task = NULL, - .schedule_task_cancel = schedule_edf_task_cancel, - .schedule_task_free = schedule_edf_task_free, - .scheduler_free = scheduler_free_edf, - .scheduler_restore = scheduler_restore_edf, -}; diff --git a/src/schedule/ll_schedule.c b/src/schedule/ll_schedule.c deleted file mode 100644 index 8881fd7bd224..000000000000 --- a/src/schedule/ll_schedule.c +++ /dev/null @@ -1,803 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2016 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> -// Keyon Jie <yang.jie@linux.intel.com> -// Tomasz Lauda <tomasz.lauda@linux.intel.com> - -#include <rtos/atomic.h> -#include <sof/audio/pipeline.h> -#include <sof/common.h> -#include <rtos/interrupt.h> -#include <rtos/timer.h> -#include <rtos/alloc.h> -#include <rtos/clk.h> -#include <sof/lib/cpu.h> -#include <sof/lib/memory.h> -#include <sof/lib/notifier.h> -#include <sof/lib/perf_cnt.h> -#include <sof/lib/uuid.h> -#include <sof/list.h> -#include <sof/platform.h> -#include <sof/schedule/ll_schedule.h> -#include <sof/schedule/ll_schedule_domain.h> -#include <sof/schedule/schedule.h> -#include <rtos/task.h> -#include <rtos/spinlock.h> -#include <ipc/topology.h> - -#include <errno.h> -#include <limits.h> -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -LOG_MODULE_REGISTER(ll_schedule, CONFIG_SOF_LOG_LEVEL); - -SOF_DEFINE_REG_UUID(ll_sched); - -DECLARE_TR_CTX(ll_tr, SOF_UUID(ll_sched_uuid), LOG_LEVEL_INFO); - -/* - * LL Scheduler Task State Transition Diagram - * - * schedule_task() +---------+ - * +------------------| INIT | - * | +---------+ - * | - * v - * +--------+ is_pending() +---------+ is_pending() +----------+ - * | QUEUED |------------->| PENDING |<-------------|RESCHEDULE| - * +--------+ +---------+ +----------+ - * | ^ - * execute()| | - * v | - * +---------+ task_run() | - * | RUNNING |--------------------+ - * +---------+ reschedule - * | - * task_run()| - * completed v - * +---------+ - * |COMPLETED| - * +---------+ - */ - -/* one instance of data allocated per core */ -struct ll_schedule_data { - struct list_item tasks; /* list of ll tasks */ - atomic_t num_tasks; /* number of ll tasks */ -#if CONFIG_PERFORMANCE_COUNTERS__LL_TASKS - struct perf_cnt_data pcd; -#endif - struct ll_schedule_domain *domain; /* scheduling domain */ -}; - -static const struct scheduler_ops schedule_ll_ops; - -#if CONFIG_PERFORMANCE_COUNTERS__LL_TASKS -static void perf_ll_sched_trace(struct perf_cnt_data *pcd, int ignored) -{ - tr_info(&ll_tr, "perf ll_work peak plat %u cpu %u", - (uint32_t)((pcd)->plat_delta_peak), - (uint32_t)((pcd)->cpu_delta_peak)); -} - -static void perf_avg_ll_sched_trace(struct perf_cnt_data *pcd, int ignored) -{ - tr_info(&ll_tr, "perf ll_work cpu avg %u (current peak %u)", - (uint32_t)((pcd)->cpu_delta_sum), - (uint32_t)((pcd)->cpu_delta_peak)); -} - -#endif - -static bool schedule_ll_is_pending(struct ll_schedule_data *sch) -{ - struct ll_schedule_domain *domain = sch->domain; - struct list_item *tlist; - struct task *task; - uint32_t pending_count = 0; - struct comp_dev *sched_comp; - k_spinlock_key_t key; - - key = k_spin_lock(&domain->lock); - - do { - sched_comp = NULL; - - /* mark each valid task as pending */ - list_for_item(tlist, &sch->tasks) { - task = container_of(tlist, struct task, list); - - /* - * only tasks queued or waiting for reschedule are - * pending for scheduling - */ - if (task->state != SOF_TASK_STATE_QUEUED && - task->state != SOF_TASK_STATE_RESCHEDULE) - continue; - - if (domain_is_pending(domain, task, &sched_comp)) { - task->state = SOF_TASK_STATE_PENDING; - pending_count++; - } - } - } while (sched_comp); - - k_spin_unlock(&domain->lock, key); - - return pending_count > 0; -} - -static void schedule_ll_task_update_start(struct ll_schedule_data *sch, - struct task *task) -{ - struct ll_task_pdata *pdata = ll_sch_get_pdata(task); - uint64_t next; - - next = sch->domain->ticks_per_ms * pdata->period / 1000; - - task->start += next; -} - -/* caller should hold the domain lock */ -static void schedule_ll_task_done(struct ll_schedule_data *sch, - struct task *task) -{ - /* Remove from the task list, schedule_task_cancel() won't handle it again */ - list_item_del(&task->list); - - /* unregister the task */ - domain_unregister(sch->domain, task, atomic_sub(&sch->num_tasks, 1) - 1); - - tr_info(&ll_tr, "task complete %p %pU", task, task->uid); - tr_info(&ll_tr, "num_tasks %ld total_num_tasks %ld", - atomic_read(&sch->num_tasks), - atomic_read(&sch->domain->total_num_tasks)); -} - -/* perf measurement windows size 2^x */ -#define CHECKS_WINDOW_SIZE 10 - -#ifdef CONFIG_SCHEDULE_LOG_CYCLE_STATISTICS -static inline void dsp_load_check(struct task *task, uint32_t cycles0, uint32_t cycles1) -{ - uint32_t diff; - - if (cycles1 > cycles0) - diff = cycles1 - cycles0; - else - diff = UINT32_MAX - cycles0 + cycles1; - - task->cycles_sum += diff; - - if (task->cycles_max < diff) - task->cycles_max = diff; - - if (++task->cycles_cnt == 1 << CHECKS_WINDOW_SIZE) { - task->cycles_sum >>= CHECKS_WINDOW_SIZE; - tr_info(&ll_tr, "task %p %pU avg %u, max %u", task, task->uid, - task->cycles_sum, task->cycles_max); - task->cycles_sum = 0; - task->cycles_max = 0; - task->cycles_cnt = 0; - } -} -#endif - -static void schedule_ll_tasks_execute(struct ll_schedule_data *sch) -{ - struct ll_schedule_domain *domain = sch->domain; - struct list_item *wlist; - struct task *task; - k_spinlock_key_t key; - - /* check each task in the list for pending */ - wlist = sch->tasks.next; - - /* - * Cannot use list_for_item(_safe)() because the task can cancel some - * other tasks, removing them from the list. This happens, e.g. when - * a pipeline task terminates a DMIC task. - */ - while (wlist != &sch->tasks) { -#ifdef CONFIG_SCHEDULE_LOG_CYCLE_STATISTICS - uint32_t cycles0, cycles1; -#endif - task = list_item(wlist, struct task, list); - - if (task->state != SOF_TASK_STATE_PENDING) { - wlist = task->list.next; - continue; - } - - tr_dbg(&ll_tr, "task %p %pU being started...", task, task->uid); - -#ifdef CONFIG_SCHEDULE_LOG_CYCLE_STATISTICS - cycles0 = (uint32_t)sof_cycle_get_64(); -#endif - task->state = SOF_TASK_STATE_RUNNING; - - /* - * The running task might cancel other tasks, which then get - * removed from the list - */ - task->state = task_run(task); - - wlist = task->list.next; - - key = k_spin_lock(&domain->lock); - - /* do we need to reschedule this task */ - if (task->state == SOF_TASK_STATE_COMPLETED) { - schedule_ll_task_done(sch, task); - } else { - /* update task's start time */ - schedule_ll_task_update_start(sch, task); - tr_dbg(&ll_tr, "task %p uid %pU finished, next period ticks %u, domain->next_tick %u", - task, task->uid, (uint32_t)task->start, - (uint32_t)domain->next_tick); - } - - k_spin_unlock(&domain->lock, key); - -#ifdef CONFIG_SCHEDULE_LOG_CYCLE_STATISTICS - cycles1 = (uint32_t)sof_cycle_get_64(); - dsp_load_check(task, cycles0, cycles1); -#endif - } -} - -static void schedule_ll_client_reschedule(struct ll_schedule_data *sch) -{ - struct list_item *tlist; - struct task *task; - struct task *task_take = NULL; - uint64_t next_tick = sch->domain->new_target_tick; - - /* rearm only if there is work to do */ - if (atomic_read(&sch->domain->total_num_tasks)) { - /* traverse to set timer according to the earliest task */ - list_for_item(tlist, &sch->tasks) { - task = container_of(tlist, struct task, list); - - /* only check tasks asked for rescheduling */ - if (task->state != SOF_TASK_STATE_RESCHEDULE) - continue; - - /* update to use the earlier tick */ - if (task->start < next_tick) { - next_tick = task->start; - task_take = task; - } - } - - tr_dbg(&ll_tr, - "schedule_ll_clients_reschedule next_tick %u task_take %p", - (unsigned int)next_tick, task_take); - - /* update the target_tick */ - if (task_take) - sch->domain->new_target_tick = next_tick; - } - -} - -static void schedule_ll_tasks_run(void *data) -{ - struct ll_schedule_data *sch = data; - struct ll_schedule_domain *domain = sch->domain; - k_spinlock_key_t key; - uint32_t flags; - uint32_t core = cpu_get_id(); - - tr_dbg(&ll_tr, "timer interrupt on core %d, at %u, previous next_tick %u", - core, - (unsigned int)sof_cycle_get_64_atomic(), - (unsigned int)domain->next_tick); - - irq_local_disable(flags); - key = k_spin_lock(&domain->lock); - - /* disable domain on current core until tasks are finished */ - domain_disable(domain, core); - - if (!atomic_read(&domain->enabled_cores)) { - /* clear the domain/interrupts */ - domain_clear(domain); - } - - k_spin_unlock(&domain->lock, key); - - perf_cnt_init(&sch->pcd); - - /* run tasks if there are any pending */ - if (schedule_ll_is_pending(sch)) - schedule_ll_tasks_execute(sch); - - notifier_event(sch, NOTIFIER_ID_LL_POST_RUN, - NOTIFIER_TARGET_CORE_LOCAL, NULL, 0); - - perf_cnt_stamp(&sch->pcd, perf_ll_sched_trace, 0 /* ignored */); - perf_cnt_average(&sch->pcd, perf_avg_ll_sched_trace, 0 /* ignored */); - - key = k_spin_lock(&domain->lock); - - /* reset the new_target_tick for the first core */ - if (domain->new_target_tick < sof_cycle_get_64_atomic()) - domain->new_target_tick = UINT64_MAX; - - /* update the new_target_tick according to tasks on current core */ - schedule_ll_client_reschedule(sch); - - /* set the next interrupt according to the new_target_tick */ - if (domain->new_target_tick < domain->next_tick) { - domain_set(domain, domain->new_target_tick); - tr_dbg(&ll_tr, "tasks on core %d done, new_target_tick %u set", - core, (unsigned int)domain->new_target_tick); - } - - /* tasks on current core finished, re-enable domain on it */ - if (atomic_read(&sch->num_tasks)) - domain_enable(domain, core); - - k_spin_unlock(&domain->lock, key); - - irq_local_enable(flags); -} - -static int schedule_ll_domain_set(struct ll_schedule_data *sch, - struct task *task, uint64_t start, - uint64_t period, struct task *reference) -{ - struct ll_schedule_domain *domain = sch->domain; - int core = cpu_get_id(); - uint64_t task_start_us; - uint64_t task_start_ticks; - uint64_t task_start; - uint64_t offset; - k_spinlock_key_t key; - int ret; - - key = k_spin_lock(&domain->lock); - - ret = domain_register(domain, task, &schedule_ll_tasks_run, sch); - if (ret < 0) { - tr_err(&ll_tr, "schedule_ll_domain_set: cannot register domain %d", - ret); - goto done; - } - - tr_dbg(&ll_tr, "task->start %u next_tick %u", - (unsigned int)task->start, - (unsigned int)domain->next_tick); - - task_start_us = period ? period : start; - task_start_ticks = domain->ticks_per_ms * task_start_us / 1000; - task_start = task_start_ticks + sof_cycle_get_64_atomic(); - - if (reference) { - task->start = reference->start; - } else if (domain->next_tick == UINT64_MAX) { - /* first task, set domain */ - domain_set(domain, task_start); - task->start = domain->next_tick; - } else if (!period) { - /* one shot task, set domain if it is earlier */ - task->start = task_start; - if (task->start < domain->next_tick) - domain_set(domain, task_start); - } else if (task_start + task_start_ticks < domain->next_tick) { - /* - * Earlier periodic task, try to make it cadence-aligned with the existed task. - * In this case task_start_ticks is the number of ticks per period. - */ - offset = (domain->next_tick - task_start) % task_start_ticks; - task_start += offset; - domain_set(domain, task_start); - task->start = domain->next_tick; - } else { - /* later periodic task, simplify and cover it by the coming interrupt */ - task->start = domain->next_tick; - } - - /* increase task number of the core */ - atomic_add(&sch->num_tasks, 1); - - /* make sure enable domain on the core */ - domain_enable(domain, core); - - tr_info(&ll_tr, "new added task->start %u at %u", - (unsigned int)task->start, - (unsigned int)sof_cycle_get_64_atomic()); - tr_info(&ll_tr, "num_tasks %ld total_num_tasks %ld", - atomic_read(&sch->num_tasks), - atomic_read(&domain->total_num_tasks)); - -done: - k_spin_unlock(&domain->lock, key); - - return ret; -} - -static void schedule_ll_domain_clear(struct ll_schedule_data *sch, - struct task *task) -{ - struct ll_schedule_domain *domain = sch->domain; - k_spinlock_key_t key; - - key = k_spin_lock(&domain->lock); - - /* - * Decrement the number of tasks on the core. - * Disable domain on the core if needed - */ - if (atomic_sub(&sch->num_tasks, 1) == 1) - domain_disable(domain, cpu_get_id()); - - /* unregister the task */ - domain_unregister(domain, task, atomic_read(&sch->num_tasks)); - - tr_info(&ll_tr, "num_tasks %ld total_num_tasks %ld", - atomic_read(&sch->num_tasks), - atomic_read(&domain->total_num_tasks)); - - k_spin_unlock(&domain->lock, key); -} - -static void schedule_ll_task_insert(struct task *task, struct list_item *tasks) -{ - struct list_item *tlist; - struct task *curr_task; - - /* tasks are added into the list from highest to lowest priority - * and tasks with the same priority should be served on - * a first-come-first-serve basis - */ - list_for_item(tlist, tasks) { - curr_task = container_of(tlist, struct task, list); - if (task->priority < curr_task->priority) { - list_item_append(&task->list, &curr_task->list); - return; - } - } - - /* if task has not been added, means that it has the lowest - * priority and should be added at the end of the list - */ - list_item_append(&task->list, tasks); -} - -static void schedule_ll_task_insert_before(struct task *task, struct task *before) -{ - list_item_append(&task->list, &before->list); -} - -static void schedule_ll_task_insert_after(struct task *task, struct task *after) -{ - list_item_prepend(&task->list, &after->list); -} - -static int schedule_ll_task_common(struct ll_schedule_data *sch, struct task *task, - uint64_t start, uint64_t period, - struct task *reference, bool before) -{ - struct ll_task_pdata *pdata; - struct ll_task_pdata *reg_pdata; - struct list_item *tlist; - struct task *curr_task; - struct task *registrable_task = NULL; - struct pipeline_task *pipe_task; - uint32_t flags; - int ret = 0; - - irq_local_disable(flags); - - /* check if task is already scheduled */ - list_for_item(tlist, &sch->tasks) { - curr_task = container_of(tlist, struct task, list); - - /* keep original start */ - if (curr_task == task) - goto out; - } - - pdata = ll_sch_get_pdata(task); - - tr_info(&ll_tr, "task add %p %pU", task, task->uid); - if (start <= UINT_MAX && period <= UINT_MAX) - tr_info(&ll_tr, "task params pri %d flags %d start %u period %u", - task->priority, task->flags, - (unsigned int)start, (unsigned int)period); - else - tr_info(&ll_tr, "task params pri %d flags %d start or period > %u", - task->priority, task->flags, UINT_MAX); - - pdata->period = period; - - /* for full synchronous domain, calculate ratio and initialize skip_cnt for task */ - if (sch->domain->full_sync) { - pdata->ratio = 1; - pdata->skip_cnt = (uint16_t)SOF_TASK_SKIP_COUNT; - - /* get the registrable task */ - list_for_item(tlist, &sch->tasks) { - curr_task = container_of(tlist, struct task, list); - pipe_task = pipeline_task_get(curr_task); - - /* registrable task found */ - if (pipe_task->registrable) { - registrable_task = curr_task; - break; - } - } - - /* we found a registrable task */ - if (registrable_task) { - reg_pdata = ll_sch_get_pdata(registrable_task); - - /* update ratio for all tasks */ - list_for_item(tlist, &sch->tasks) { - curr_task = container_of(tlist, struct task, list); - pdata = ll_sch_get_pdata(curr_task); - - /* the assumption is that the registrable - * task has the smallest period - */ - if (pdata->period < reg_pdata->period) { - tr_err(&ll_tr, - "schedule_ll_task(): registrable task has a period longer than current task"); - ret = -EINVAL; - goto out; - } - - pdata->ratio = period / reg_pdata->period; - } - } - } - - /* insert task into the list */ - if (!reference) - schedule_ll_task_insert(task, &sch->tasks); - else if (before) - schedule_ll_task_insert_before(task, reference); - else - schedule_ll_task_insert_after(task, reference); - task->state = SOF_TASK_STATE_QUEUED; - - /* set schedule domain */ - ret = schedule_ll_domain_set(sch, task, start, period, reference); - if (ret < 0) { - list_item_del(&task->list); - goto out; - } - - -out: - irq_local_enable(flags); - - return ret; -} - -static int schedule_ll_task(void *data, struct task *task, uint64_t start, - uint64_t period) -{ - struct ll_schedule_data *sch = data; - - return schedule_ll_task_common(sch, task, start, period, NULL, false); -} - -static int schedule_ll_task_before(void *data, struct task *task, uint64_t start, - uint64_t period, struct task *before) -{ - struct ll_schedule_data *sch = data; - - return schedule_ll_task_common(sch, task, start, period, before, true); -} - -static int schedule_ll_task_after(void *data, struct task *task, uint64_t start, - uint64_t period, struct task *after) -{ - struct ll_schedule_data *sch = data; - - return schedule_ll_task_common(sch, task, start, period, after, false); -} - -int schedule_task_init_ll(struct task *task, - const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), - void *data, uint16_t core, uint32_t flags) -{ - struct ll_task_pdata *ll_pdata; - int ret; - - ret = schedule_task_init(task, uid, type, priority, run, data, core, - flags); - if (ret < 0) - return ret; - - if (ll_sch_get_pdata(task)) - return -EEXIST; - - ll_pdata = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_RAM, - sizeof(*ll_pdata)); - - if (!ll_pdata) { - tr_err(&ll_tr, "schedule_task_init_ll(): alloc failed"); - return -ENOMEM; - } - - ll_sch_set_pdata(task, ll_pdata); - - return 0; -} - -static int schedule_ll_task_free(void *data, struct task *task) -{ - struct ll_task_pdata *ll_pdata; - uint32_t flags; - - irq_local_disable(flags); - - /* release the resources */ - task->state = SOF_TASK_STATE_FREE; - ll_pdata = ll_sch_get_pdata(task); - rfree(ll_pdata); - ll_sch_set_pdata(task, NULL); - - irq_local_enable(flags); - - return 0; -} - -static int schedule_ll_task_cancel(void *data, struct task *task) -{ - struct ll_schedule_data *sch = data; - struct list_item *tlist; - struct task *curr_task; - uint32_t flags; - - irq_local_disable(flags); - - tr_info(&ll_tr, "task cancel %p %pU", task, task->uid); - - /* check to see if we are scheduled */ - list_for_item(tlist, &sch->tasks) { - curr_task = container_of(tlist, struct task, list); - - /* found it */ - if (curr_task == task) { - schedule_ll_domain_clear(sch, task); - - /* remove work from list */ - task->state = SOF_TASK_STATE_CANCEL; - list_item_del(&task->list); - - break; - } - } - - irq_local_enable(flags); - - return 0; -} - -static int reschedule_ll_task(void *data, struct task *task, uint64_t start) -{ - struct ll_schedule_data *sch = data; - struct list_item *tlist; - struct task *curr_task; - uint32_t flags; - uint64_t time; - - time = sch->domain->ticks_per_ms * start / 1000; - - time += sof_cycle_get_64_atomic(); - - irq_local_disable(flags); - - /* check to see if we are already scheduled */ - list_for_item(tlist, &sch->tasks) { - curr_task = container_of(tlist, struct task, list); - /* found it */ - if (curr_task == task) { - /* set start time */ - task->start = time; - goto out; - } - } - - tr_err(&ll_tr, "reschedule_ll_task(): task not found"); - -out: - - irq_local_enable(flags); - - return 0; -} - -static void scheduler_free_ll(void *data, uint32_t flags) -{ - struct ll_schedule_data *sch = data; - uint32_t irq_flags; - - irq_local_disable(irq_flags); - - domain_unregister(sch->domain, NULL, 0); - - if (!(flags & SOF_SCHEDULER_FREE_IRQ_ONLY)) - notifier_unregister(sch, NULL, - NOTIFIER_CLK_CHANGE_ID(sch->domain->clk)); - - irq_local_enable(irq_flags); -} - -static void ll_scheduler_recalculate_tasks(struct ll_schedule_data *sch, - struct clock_notify_data *clk_data) -{ - uint64_t current = sof_cycle_get_64_atomic(); - struct list_item *tlist; - struct task *task; - uint64_t delta_ms; - - list_for_item(tlist, &sch->tasks) { - task = container_of(tlist, struct task, list); - delta_ms = (task->start - current) / - clk_data->old_ticks_per_msec; - - task->start = delta_ms ? - current + sch->domain->ticks_per_ms * delta_ms : - current + (sch->domain->ticks_per_ms >> 3); - } -} - -static void ll_scheduler_notify(void *arg, enum notify_id type, void *data) -{ - struct ll_schedule_data *sch = arg; - struct clock_notify_data *clk_data = data; - uint32_t flags; - - irq_local_disable(flags); - - /* we need to recalculate tasks when clock frequency changes */ - if (clk_data->message == CLOCK_NOTIFY_POST) { - sch->domain->ticks_per_ms = k_ms_to_cyc_ceil64(1); - ll_scheduler_recalculate_tasks(sch, clk_data); - } - - irq_local_enable(flags); -} - -int scheduler_init_ll(struct ll_schedule_domain *domain) -{ - struct ll_schedule_data *sch; - - /* initialize scheduler private data */ - sch = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, sizeof(*sch)); - list_init(&sch->tasks); - atomic_init(&sch->num_tasks, 0); - sch->domain = domain; - - /* notification of clock changes */ - notifier_register(sch, NULL, NOTIFIER_CLK_CHANGE_ID(domain->clk), - ll_scheduler_notify, 0); - - scheduler_init(domain->type, &schedule_ll_ops, sch); - - - return 0; -} - -static const struct scheduler_ops schedule_ll_ops = { - .schedule_task = schedule_ll_task, - .schedule_task_before = schedule_ll_task_before, - .schedule_task_after = schedule_ll_task_after, - .schedule_task_free = schedule_ll_task_free, - .schedule_task_cancel = schedule_ll_task_cancel, - .reschedule_task = reschedule_ll_task, - .scheduler_free = scheduler_free_ll, - .scheduler_restore = NULL, - .schedule_task_running = NULL, -}; diff --git a/src/schedule/ll_schedule_xtos.c b/src/schedule/ll_schedule_xtos.c new file mode 100644 index 000000000000..d0460b57a563 --- /dev/null +++ b/src/schedule/ll_schedule_xtos.c @@ -0,0 +1,812 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2016 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// Keyon Jie <yang.jie@linux.intel.com> +// Tomasz Lauda <tomasz.lauda@linux.intel.com> + +#include <rtos/atomic.h> +#include <sof/audio/pipeline.h> +#include <sof/common.h> +#include <rtos/interrupt.h> +#include <rtos/timer.h> +#include <rtos/alloc.h> +#include <rtos/clk.h> +#include <sof/lib/cpu.h> +#include <sof/lib/memory.h> +#include <sof/lib/notifier.h> +#include <sof/lib/perf_cnt.h> +#include <sof/lib/uuid.h> +#include <sof/list.h> +#include <sof/platform.h> +#include <sof/schedule/ll_schedule.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <sof/schedule/schedule.h> +#include <rtos/task.h> +#include <rtos/spinlock.h> +#include <ipc/topology.h> + +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +LOG_MODULE_REGISTER(ll_schedule, CONFIG_SOF_LOG_LEVEL); + +SOF_DEFINE_REG_UUID(ll_sched); + +DECLARE_TR_CTX(ll_tr, SOF_UUID(ll_sched_uuid), LOG_LEVEL_INFO); + +/* + * LL Scheduler Task State Transition Diagram + * + * schedule_task() +---------+ + * +------------------| INIT | + * | +---------+ + * | + * v + * +--------+ is_pending() +---------+ is_pending() +----------+ + * | QUEUED |------------->| PENDING |<-------------|RESCHEDULE| + * +--------+ +---------+ +----------+ + * | ^ + * execute()| | + * v | + * +---------+ task_run() | + * | RUNNING |--------------------+ + * +---------+ reschedule + * | + * task_run()| + * completed v + * +---------+ + * |COMPLETED| + * +---------+ + */ + +/* one instance of data allocated per core */ +struct ll_schedule_data { + struct list_item tasks; /* list of ll tasks */ + atomic_t num_tasks; /* number of ll tasks */ +#if CONFIG_PERFORMANCE_COUNTERS__LL_TASKS + struct perf_cnt_data pcd; +#endif + struct ll_schedule_domain *domain; /* scheduling domain */ +}; + +static const struct scheduler_ops schedule_ll_ops; + +#if CONFIG_PERFORMANCE_COUNTERS__LL_TASKS +static void perf_ll_sched_trace(struct perf_cnt_data *pcd, int ignored) +{ + tr_info(&ll_tr, "perf ll_work peak plat %u cpu %u", + (uint32_t)((pcd)->plat_delta_peak), + (uint32_t)((pcd)->cpu_delta_peak)); +} + +static void perf_avg_ll_sched_trace(struct perf_cnt_data *pcd, int ignored) +{ + tr_info(&ll_tr, "perf ll_work cpu avg %u (current peak %u)", + (uint32_t)((pcd)->cpu_delta_sum), + (uint32_t)((pcd)->cpu_delta_peak)); +} + +#endif + +static bool schedule_ll_is_pending(struct ll_schedule_data *sch) +{ + struct ll_schedule_domain *domain = sch->domain; + struct list_item *tlist; + struct task *task; + uint32_t pending_count = 0; + struct comp_dev *sched_comp; + k_spinlock_key_t key; + + key = k_spin_lock(&domain->lock); + + do { + sched_comp = NULL; + + /* mark each valid task as pending */ + list_for_item(tlist, &sch->tasks) { + task = container_of(tlist, struct task, list); + + /* + * only tasks queued or waiting for reschedule are + * pending for scheduling + */ + if (task->state != SOF_TASK_STATE_QUEUED && + task->state != SOF_TASK_STATE_RESCHEDULE) + continue; + + if (domain_is_pending(domain, task, &sched_comp)) { + task->state = SOF_TASK_STATE_PENDING; + pending_count++; + } + } + } while (sched_comp); + + k_spin_unlock(&domain->lock, key); + + return pending_count > 0; +} + +static void schedule_ll_task_update_start(struct ll_schedule_data *sch, + struct task *task) +{ + struct ll_task_pdata *pdata = ll_sch_get_pdata(task); + uint64_t next; + + next = sch->domain->ticks_per_ms * pdata->period / 1000; + + task->start += next; +} + +/* caller should hold the domain lock */ +static void schedule_ll_task_done(struct ll_schedule_data *sch, + struct task *task) +{ + /* Remove from the task list, schedule_task_cancel() won't handle it again */ + list_item_del(&task->list); + + /* unregister the task */ + domain_unregister(sch->domain, task, atomic_sub(&sch->num_tasks, 1) - 1); + + tr_info(&ll_tr, "task complete %p %pU", task, task->uid); + tr_info(&ll_tr, "num_tasks %ld total_num_tasks %ld", + atomic_read(&sch->num_tasks), + atomic_read(&sch->domain->total_num_tasks)); +} + +/* perf measurement windows size 2^x */ +#define CHECKS_WINDOW_SIZE 10 + +#ifdef CONFIG_SCHEDULE_LOG_CYCLE_STATISTICS +static inline void dsp_load_check(struct task *task, uint32_t cycles0, uint32_t cycles1) +{ + uint32_t diff; + + if (cycles1 > cycles0) + diff = cycles1 - cycles0; + else + diff = UINT32_MAX - cycles0 + cycles1; + + task->cycles_sum += diff; + + if (task->cycles_max < diff) + task->cycles_max = diff; + + if (++task->cycles_cnt == 1 << CHECKS_WINDOW_SIZE) { + task->cycles_sum >>= CHECKS_WINDOW_SIZE; + tr_info(&ll_tr, "task %p %pU avg %u, max %u", task, task->uid, + task->cycles_sum, task->cycles_max); + task->cycles_sum = 0; + task->cycles_max = 0; + task->cycles_cnt = 0; + } +} +#endif + +static void schedule_ll_tasks_execute(struct ll_schedule_data *sch) +{ + struct ll_schedule_domain *domain = sch->domain; + struct list_item *wlist; + struct task *task; + k_spinlock_key_t key; + + /* check each task in the list for pending */ + wlist = sch->tasks.next; + + /* + * Cannot use list_for_item(_safe)() because the task can cancel some + * other tasks, removing them from the list. This happens, e.g. when + * a pipeline task terminates a DMIC task. + */ + while (wlist != &sch->tasks) { +#ifdef CONFIG_SCHEDULE_LOG_CYCLE_STATISTICS + uint32_t cycles0, cycles1; +#endif + task = list_item(wlist, struct task, list); + + if (task->state != SOF_TASK_STATE_PENDING) { + wlist = task->list.next; + continue; + } + + tr_dbg(&ll_tr, "task %p %pU being started...", task, task->uid); + +#ifdef CONFIG_SCHEDULE_LOG_CYCLE_STATISTICS + cycles0 = (uint32_t)sof_cycle_get_64(); +#endif + task->state = SOF_TASK_STATE_RUNNING; + + /* + * The running task might cancel other tasks, which then get + * removed from the list + */ + task->state = task_run(task); + + wlist = task->list.next; + + key = k_spin_lock(&domain->lock); + + /* do we need to reschedule this task */ + if (task->state == SOF_TASK_STATE_COMPLETED) { + schedule_ll_task_done(sch, task); + } else { + /* update task's start time */ + schedule_ll_task_update_start(sch, task); + tr_dbg(&ll_tr, "task %p uid %pU finished, next period ticks %u, domain->next_tick %u", + task, task->uid, (uint32_t)task->start, + (uint32_t)domain->next_tick); + } + + k_spin_unlock(&domain->lock, key); + +#ifdef CONFIG_SCHEDULE_LOG_CYCLE_STATISTICS + cycles1 = (uint32_t)sof_cycle_get_64(); + dsp_load_check(task, cycles0, cycles1); +#endif + } +} + +static void schedule_ll_client_reschedule(struct ll_schedule_data *sch) +{ + struct list_item *tlist; + struct task *task; + struct task *task_take = NULL; + uint64_t next_tick = sch->domain->new_target_tick; + + /* rearm only if there is work to do */ + if (atomic_read(&sch->domain->total_num_tasks)) { + /* traverse to set timer according to the earliest task */ + list_for_item(tlist, &sch->tasks) { + task = container_of(tlist, struct task, list); + + /* only check tasks asked for rescheduling */ + if (task->state != SOF_TASK_STATE_RESCHEDULE) + continue; + + /* update to use the earlier tick */ + if (task->start < next_tick) { + next_tick = task->start; + task_take = task; + } + } + + tr_dbg(&ll_tr, + "schedule_ll_clients_reschedule next_tick %u task_take %p", + (unsigned int)next_tick, task_take); + + /* update the target_tick */ + if (task_take) + sch->domain->new_target_tick = next_tick; + } + +} + +static void schedule_ll_tasks_run(void *data) +{ + struct ll_schedule_data *sch = data; + struct ll_schedule_domain *domain = sch->domain; + k_spinlock_key_t key; + uint32_t flags; + uint32_t core = cpu_get_id(); + + tr_dbg(&ll_tr, "timer interrupt on core %d, at %u, previous next_tick %u", + core, + (unsigned int)sof_cycle_get_64_atomic(), + (unsigned int)domain->next_tick); + + irq_local_disable(flags); + key = k_spin_lock(&domain->lock); + + /* disable domain on current core until tasks are finished */ + domain_disable(domain, core); + + if (!atomic_read(&domain->enabled_cores)) { + /* clear the domain/interrupts */ + domain_clear(domain); + } + + k_spin_unlock(&domain->lock, key); + + perf_cnt_init(&sch->pcd); + + /* run tasks if there are any pending */ + if (schedule_ll_is_pending(sch)) + schedule_ll_tasks_execute(sch); + + notifier_event(sch, NOTIFIER_ID_LL_POST_RUN, + NOTIFIER_TARGET_CORE_LOCAL, NULL, 0); + + perf_cnt_stamp(&sch->pcd, perf_ll_sched_trace, 0 /* ignored */); + perf_cnt_average(&sch->pcd, perf_avg_ll_sched_trace, 0 /* ignored */); + + key = k_spin_lock(&domain->lock); + + /* reset the new_target_tick for the first core */ + if (domain->new_target_tick < sof_cycle_get_64_atomic()) + domain->new_target_tick = UINT64_MAX; + + /* update the new_target_tick according to tasks on current core */ + schedule_ll_client_reschedule(sch); + + /* set the next interrupt according to the new_target_tick */ + if (domain->new_target_tick < domain->next_tick) { + domain_set(domain, domain->new_target_tick); + tr_dbg(&ll_tr, "tasks on core %d done, new_target_tick %u set", + core, (unsigned int)domain->new_target_tick); + } + + /* tasks on current core finished, re-enable domain on it */ + if (atomic_read(&sch->num_tasks)) + domain_enable(domain, core); + + k_spin_unlock(&domain->lock, key); + + irq_local_enable(flags); +} + +static int schedule_ll_domain_set(struct ll_schedule_data *sch, + struct task *task, uint64_t start, + uint64_t period, struct task *reference) +{ + struct ll_schedule_domain *domain = sch->domain; + int core = cpu_get_id(); + uint64_t task_start_us; + uint64_t task_start_ticks; + uint64_t task_start; + uint64_t offset; + k_spinlock_key_t key; + int ret; + + key = k_spin_lock(&domain->lock); + + ret = domain_register(domain, task, &schedule_ll_tasks_run, sch); + if (ret < 0) { + tr_err(&ll_tr, "cannot register domain %d", + ret); + goto done; + } + + tr_dbg(&ll_tr, "task->start %u next_tick %u", + (unsigned int)task->start, + (unsigned int)domain->next_tick); + + task_start_us = period ? period : start; + task_start_ticks = domain->ticks_per_ms * task_start_us / 1000; + task_start = task_start_ticks + sof_cycle_get_64_atomic(); + + if (reference) { + task->start = reference->start; + } else if (domain->next_tick == UINT64_MAX) { + /* first task, set domain */ + domain_set(domain, task_start); + task->start = domain->next_tick; + } else if (!period) { + /* one shot task, set domain if it is earlier */ + task->start = task_start; + if (task->start < domain->next_tick) + domain_set(domain, task_start); + } else if (task_start + task_start_ticks < domain->next_tick) { + /* + * Earlier periodic task, try to make it cadence-aligned with the existed task. + * In this case task_start_ticks is the number of ticks per period. + */ + offset = (domain->next_tick - task_start) % task_start_ticks; + task_start += offset; + domain_set(domain, task_start); + task->start = domain->next_tick; + } else { + /* later periodic task, simplify and cover it by the coming interrupt */ + task->start = domain->next_tick; + } + + /* increase task number of the core */ + atomic_add(&sch->num_tasks, 1); + + /* make sure enable domain on the core */ + domain_enable(domain, core); + + tr_info(&ll_tr, "new added task->start %u at %u", + (unsigned int)task->start, + (unsigned int)sof_cycle_get_64_atomic()); + tr_info(&ll_tr, "num_tasks %ld total_num_tasks %ld", + atomic_read(&sch->num_tasks), + atomic_read(&domain->total_num_tasks)); + +done: + k_spin_unlock(&domain->lock, key); + + return ret; +} + +static void schedule_ll_domain_clear(struct ll_schedule_data *sch, + struct task *task) +{ + struct ll_schedule_domain *domain = sch->domain; + k_spinlock_key_t key; + + key = k_spin_lock(&domain->lock); + + /* + * Decrement the number of tasks on the core. + * Disable domain on the core if needed + */ + if (atomic_sub(&sch->num_tasks, 1) == 1) + domain_disable(domain, cpu_get_id()); + + /* unregister the task */ + domain_unregister(domain, task, atomic_read(&sch->num_tasks)); + + tr_info(&ll_tr, "num_tasks %ld total_num_tasks %ld", + atomic_read(&sch->num_tasks), + atomic_read(&domain->total_num_tasks)); + + k_spin_unlock(&domain->lock, key); +} + +static void schedule_ll_task_insert(struct task *task, struct list_item *tasks) +{ + struct list_item *tlist; + struct task *curr_task; + + /* tasks are added into the list from highest to lowest priority + * and tasks with the same priority should be served on + * a first-come-first-serve basis + */ + list_for_item(tlist, tasks) { + curr_task = container_of(tlist, struct task, list); + if (task->priority < curr_task->priority) { + list_item_append(&task->list, &curr_task->list); + return; + } + } + + /* if task has not been added, means that it has the lowest + * priority and should be added at the end of the list + */ + list_item_append(&task->list, tasks); +} + +static void schedule_ll_task_insert_before(struct task *task, struct task *before) +{ + list_item_append(&task->list, &before->list); +} + +static void schedule_ll_task_insert_after(struct task *task, struct task *after) +{ + list_item_prepend(&task->list, &after->list); +} + +static int schedule_ll_task_common(struct ll_schedule_data *sch, struct task *task, + uint64_t start, uint64_t period, + struct task *reference, bool before) +{ + struct ll_task_pdata *pdata; + struct ll_task_pdata *reg_pdata; + struct list_item *tlist; + struct task *curr_task; + struct task *registrable_task = NULL; + struct pipeline_task *pipe_task; + uint32_t flags; + int ret = 0; + + irq_local_disable(flags); + + /* check if task is already scheduled */ + list_for_item(tlist, &sch->tasks) { + curr_task = container_of(tlist, struct task, list); + + /* keep original start */ + if (curr_task == task) + goto out; + } + + pdata = ll_sch_get_pdata(task); + + tr_info(&ll_tr, "task add %p %pU", task, task->uid); + if (start <= UINT_MAX && period <= UINT_MAX) + tr_info(&ll_tr, "task params pri %d flags %d start %u period %u", + task->priority, task->flags, + (unsigned int)start, (unsigned int)period); + else + tr_info(&ll_tr, "task params pri %d flags %d start or period > %u", + task->priority, task->flags, UINT_MAX); + + pdata->period = period; + + /* for full synchronous domain, calculate ratio and initialize skip_cnt for task */ + if (sch->domain->full_sync) { + pdata->ratio = 1; + pdata->skip_cnt = (uint16_t)SOF_TASK_SKIP_COUNT; + + /* get the registrable task */ + list_for_item(tlist, &sch->tasks) { + curr_task = container_of(tlist, struct task, list); + pipe_task = pipeline_task_get(curr_task); + + /* registrable task found */ + if (pipe_task->registrable) { + registrable_task = curr_task; + break; + } + } + + /* we found a registrable task */ + if (registrable_task) { + reg_pdata = ll_sch_get_pdata(registrable_task); + + /* update ratio for all tasks */ + list_for_item(tlist, &sch->tasks) { + curr_task = container_of(tlist, struct task, list); + pdata = ll_sch_get_pdata(curr_task); + + /* the assumption is that the registrable + * task has the smallest period + */ + if (pdata->period < reg_pdata->period) { + tr_err(&ll_tr, + "registrable task has a period longer than current task"); + ret = -EINVAL; + goto out; + } + + pdata->ratio = period / reg_pdata->period; + } + } + } + + /* insert task into the list */ + if (!reference) + schedule_ll_task_insert(task, &sch->tasks); + else if (before) + schedule_ll_task_insert_before(task, reference); + else + schedule_ll_task_insert_after(task, reference); + task->state = SOF_TASK_STATE_QUEUED; + + /* set schedule domain */ + ret = schedule_ll_domain_set(sch, task, start, period, reference); + if (ret < 0) { + list_item_del(&task->list); + goto out; + } + + +out: + irq_local_enable(flags); + + return ret; +} + +static int schedule_ll_task(void *data, struct task *task, uint64_t start, + uint64_t period) +{ + struct ll_schedule_data *sch = data; + + return schedule_ll_task_common(sch, task, start, period, NULL, false); +} + +static int schedule_ll_task_before(void *data, struct task *task, uint64_t start, + uint64_t period, struct task *before) +{ + struct ll_schedule_data *sch = data; + + return schedule_ll_task_common(sch, task, start, period, before, true); +} + +static int schedule_ll_task_after(void *data, struct task *task, uint64_t start, + uint64_t period, struct task *after) +{ + struct ll_schedule_data *sch = data; + + return schedule_ll_task_common(sch, task, start, period, after, false); +} + +int schedule_task_init_ll(struct task *task, + const struct sof_uuid_entry *uid, uint16_t type, + uint16_t priority, enum task_state (*run)(void *data), + void *data, uint16_t core, uint32_t flags) +{ + struct ll_task_pdata *ll_pdata; + int ret; + + ret = schedule_task_init(task, uid, type, priority, run, data, core, + flags); + if (ret < 0) + return ret; + + if (ll_sch_get_pdata(task)) + return -EEXIST; + + ll_pdata = rzalloc(SOF_MEM_FLAG_KERNEL, + sizeof(*ll_pdata)); + + if (!ll_pdata) { + tr_err(&ll_tr, "alloc failed"); + return -ENOMEM; + } + + ll_sch_set_pdata(task, ll_pdata); + + return 0; +} + +static int schedule_ll_task_free(void *data, struct task *task) +{ + struct ll_task_pdata *ll_pdata; + uint32_t flags; + + irq_local_disable(flags); + + /* release the resources */ + task->state = SOF_TASK_STATE_FREE; + ll_pdata = ll_sch_get_pdata(task); + rfree(ll_pdata); + ll_sch_set_pdata(task, NULL); + + irq_local_enable(flags); + + return 0; +} + +static int schedule_ll_task_cancel(void *data, struct task *task) +{ + struct ll_schedule_data *sch = data; + struct list_item *tlist; + struct task *curr_task; + uint32_t flags; + + irq_local_disable(flags); + + tr_info(&ll_tr, "task cancel %p %pU", task, task->uid); + + /* check to see if we are scheduled */ + list_for_item(tlist, &sch->tasks) { + curr_task = container_of(tlist, struct task, list); + + /* found it */ + if (curr_task == task) { + schedule_ll_domain_clear(sch, task); + + /* remove work from list */ + task->state = SOF_TASK_STATE_CANCEL; + list_item_del(&task->list); + + break; + } + } + + irq_local_enable(flags); + + return 0; +} + +#if CONFIG_SCHEDULE_LL_NO_RESCHEDULE_TASK +/* As a null function pointer */ +#define reschedule_ll_task ((void*)0) + +#else +static int reschedule_ll_task(void *data, struct task *task, uint64_t start) +{ + struct ll_schedule_data *sch = data; + struct list_item *tlist; + struct task *curr_task; + uint32_t flags; + uint64_t time; + + time = sch->domain->ticks_per_ms * start / 1000; + + time += sof_cycle_get_64_atomic(); + + irq_local_disable(flags); + + /* check to see if we are already scheduled */ + list_for_item(tlist, &sch->tasks) { + curr_task = container_of(tlist, struct task, list); + /* found it */ + if (curr_task == task) { + /* set start time */ + task->start = time; + goto out; + } + } + + tr_err(&ll_tr, "task not found"); + +out: + + irq_local_enable(flags); + + return 0; +} +#endif + +static void scheduler_free_ll(void *data, uint32_t flags) +{ + struct ll_schedule_data *sch = data; + uint32_t irq_flags; + + irq_local_disable(irq_flags); + + domain_unregister(sch->domain, NULL, 0); + + if (!(flags & SOF_SCHEDULER_FREE_IRQ_ONLY)) + notifier_unregister(sch, NULL, + NOTIFIER_CLK_CHANGE_ID(sch->domain->clk)); + + irq_local_enable(irq_flags); +} + +static void ll_scheduler_recalculate_tasks(struct ll_schedule_data *sch, + struct clock_notify_data *clk_data) +{ + uint64_t current = sof_cycle_get_64_atomic(); + struct list_item *tlist; + struct task *task; + uint64_t delta_ms; + + list_for_item(tlist, &sch->tasks) { + task = container_of(tlist, struct task, list); + delta_ms = (task->start - current) / + clk_data->old_ticks_per_msec; + + task->start = delta_ms ? + current + sch->domain->ticks_per_ms * delta_ms : + current + (sch->domain->ticks_per_ms >> 3); + } +} + +static void ll_scheduler_notify(void *arg, enum notify_id type, void *data) +{ + struct ll_schedule_data *sch = arg; + struct clock_notify_data *clk_data = data; + uint32_t flags; + + irq_local_disable(flags); + + /* we need to recalculate tasks when clock frequency changes */ + if (clk_data->message == CLOCK_NOTIFY_POST) { + sch->domain->ticks_per_ms = k_ms_to_cyc_ceil64(1); + ll_scheduler_recalculate_tasks(sch, clk_data); + } + + irq_local_enable(flags); +} + +int scheduler_init_ll(struct ll_schedule_domain *domain) +{ + struct ll_schedule_data *sch; + + /* initialize scheduler private data */ + sch = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(*sch)); + if (!sch) { + tr_err(&ll_tr, "allocation failed"); + return -ENOMEM; + } + list_init(&sch->tasks); + atomic_init(&sch->num_tasks, 0); + sch->domain = domain; + + /* notification of clock changes */ + notifier_register(sch, NULL, NOTIFIER_CLK_CHANGE_ID(domain->clk), + ll_scheduler_notify, 0); + + scheduler_init(domain->type, &schedule_ll_ops, sch); + + + return 0; +} + +static const struct scheduler_ops schedule_ll_ops = { + .schedule_task = schedule_ll_task, + .schedule_task_before = schedule_ll_task_before, + .schedule_task_after = schedule_ll_task_after, + .schedule_task_free = schedule_ll_task_free, + .schedule_task_cancel = schedule_ll_task_cancel, + .reschedule_task = reschedule_ll_task, + .scheduler_free = scheduler_free_ll, + .schedule_task_running = NULL, +}; diff --git a/src/schedule/schedule.c b/src/schedule/schedule.c index b8c6832b446b..231bba864856 100644 --- a/src/schedule/schedule.c +++ b/src/schedule/schedule.c @@ -22,16 +22,53 @@ SOF_DEFINE_REG_UUID(schedule); DECLARE_TR_CTX(sch_tr, SOF_UUID(schedule_uuid), LOG_LEVEL_INFO); +static inline bool scheduler_is_user(int type) +{ + /* + * currently only LL managed in user-space, but longterm + * goal is to move all audio application level scheduling + * to user-space and only keep Zephyr scheduler logic in + * kernel + */ + return type == SOF_SCHEDULE_LL_TIMER; +} + int schedule_task_init(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, uint16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags) { + struct schedulers *schedulers; + struct schedule_data *sch = NULL; + struct list_item *slist; + if (type >= SOF_SCHEDULE_COUNT) { - tr_err(&sch_tr, "schedule_task_init(): invalid task type"); + tr_err(&sch_tr, "invalid task type"); return -EINVAL; } + if (IS_ENABLED(CONFIG_SOF_USERSPACE_LL) && scheduler_is_user(type)) + schedulers = *arch_user_schedulers_get_for_core(core); + else + schedulers = *arch_schedulers_get(); + + if (!schedulers) + return -ENODEV; + + task->sch = NULL; + list_for_item(slist, &schedulers->list) { + sch = container_of(slist, struct schedule_data, list); + if (type == sch->type) { + task->sch = sch; + break; + } + } + + if (!task->sch) { + tr_err(&sch_tr, "unable to bind scheduler to task %p (type %d)", task, type); + return -ENODEV; + } + task->uid = uid; task->type = type; task->priority = priority; @@ -47,11 +84,21 @@ int schedule_task_init(struct task *task, static void scheduler_register(struct schedule_data *scheduler) { struct schedulers **sch = arch_schedulers_get(); + struct k_heap *heap = NULL; + + if (IS_ENABLED(CONFIG_SOF_USERSPACE_LL) && scheduler_is_user(scheduler->type)) { + sch = arch_user_schedulers_get(); + heap = sof_sys_user_heap_get(); + } if (!*sch) { /* init schedulers list */ - *sch = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, - sizeof(**sch)); + *sch = sof_heap_alloc(heap, 0, sizeof(**sch), 0); + if (!*sch) { + tr_err(&sch_tr, "allocation failed"); + return; + } + memset(*sch, 0, sizeof(**sch)); list_init(&(*sch)->list); } @@ -61,12 +108,21 @@ static void scheduler_register(struct schedule_data *scheduler) void scheduler_init(int type, const struct scheduler_ops *ops, void *data) { struct schedule_data *sch; + struct k_heap *heap = NULL; + + if (IS_ENABLED(CONFIG_SOF_USERSPACE_LL) && scheduler_is_user(type)) + heap = sof_sys_user_heap_get(); if (!ops || !ops->schedule_task || !ops->schedule_task_cancel || !ops->schedule_task_free) return; - sch = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, sizeof(*sch)); + sch = sof_heap_alloc(heap, SOF_MEM_FLAG_KERNEL, sizeof(*sch), 0); + if (!sch) { + tr_err(&sch_tr, "allocation failed"); + sof_panic(SOF_IPC_PANIC_IPC); + } + memset(sch, 0, sizeof(*sch)); list_init(&sch->list); sch->type = type; sch->ops = ops; diff --git a/src/schedule/task.c b/src/schedule/task.c deleted file mode 100644 index bf55c70fec02..000000000000 --- a/src/schedule/task.c +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2016 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - -/* - * Generic audio task. - */ - -#include <sof/audio/component_ext.h> -#include <sof/audio/pipeline.h> -#include <rtos/panic.h> -#include <sof/ipc/msg.h> -#include <rtos/alloc.h> -#include <sof/lib/agent.h> -#include <sof/lib/cpu.h> -#include <sof/lib/memory.h> -#include <sof/lib/uuid.h> -#include <rtos/wait.h> -#include <sof/platform.h> -#include <sof/schedule/edf_schedule.h> -#include <sof/schedule/schedule.h> -#include <rtos/task.h> -#include <rtos/sof.h> -#include <ipc/topology.h> -#include <errno.h> -#include <stddef.h> -#include <stdint.h> - -typedef enum task_state (*task_main)(void *); - -SOF_DEFINE_REG_UUID(main_task); - -static void sys_module_init(void) -{ - intptr_t *module_init = (intptr_t *)(&_module_init_start); - - for (; module_init < (intptr_t *)&_module_init_end; ++module_init) - ((void(*)(void))(*module_init))(); -} - -static uint64_t task_main_deadline(void *data) -{ - return SOF_TASK_DEADLINE_IDLE; -} - -enum task_state task_main_primary_core(void *data) -{ - struct ipc *ipc = ipc_get(); - - /* main audio processing loop */ - while (1) { - /* sleep until next IPC or DMA */ - wait_for_interrupt(0); - - if (!ipc->pm_prepare_D3) - ipc_send_queued_msg(); - - } - - return SOF_TASK_STATE_COMPLETED; -} - -void task_main_init(void) -{ - struct task **main_task = task_main_get(); - int cpu = cpu_get_id(); - int ret; - task_main main_main = cpu == PLATFORM_PRIMARY_CORE_ID ? - &task_main_primary_core : &task_main_secondary_core; - struct task_ops ops = { - .run = main_main, - .get_deadline = task_main_deadline, - }; - - *main_task = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, - sizeof(**main_task)); - - ret = schedule_task_init_edf(*main_task, SOF_UUID(main_task_uuid), - &ops, NULL, cpu, 0); - assert(!ret); -} - -void task_main_free(void) -{ - schedule_task_free(*task_main_get()); -} - -int task_main_start(struct sof *sof) -{ - int ret; - - /* init default audio components */ - sys_comp_init(sof); - - /* init self-registered modules */ - sys_module_init(); - - /* init pipeline position offsets */ - pipeline_posn_init(sof); - - /* let host know DSP boot is complete */ - ret = platform_boot_complete(0); - if (ret < 0) - return ret; - - /* task initialized in edf_scheduler_init */ - schedule_task(*task_main_get(), 0, UINT64_MAX); - - /* something bad happened */ - return -EIO; -} diff --git a/src/schedule/timer_domain.c b/src/schedule/timer_domain.c deleted file mode 100644 index 25c37cfc4c3a..000000000000 --- a/src/schedule/timer_domain.c +++ /dev/null @@ -1,168 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2019 Intel Corporation. All rights reserved. -// -// Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - -#include <rtos/timer.h> -#include <rtos/alloc.h> -#include <sof/lib/cpu.h> -#include <sof/lib/memory.h> -#include <sof/math/numbers.h> -#include <sof/platform.h> -#include <sof/schedule/ll_schedule.h> -#include <sof/schedule/ll_schedule_domain.h> -#include <sof/schedule/schedule.h> -#include <rtos/task.h> -#include <ipc/topology.h> -#include <limits.h> -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -#define LL_TIMER_SET_OVERHEAD_TICKS 1000 /* overhead/delay to set the tick, in ticks */ - -struct timer_domain { - struct timer *timer; - void *arg[CONFIG_CORE_COUNT]; -}; - -static void timer_report_delay(int id, uint64_t delay) -{ - uint32_t ll_delay_us = (delay * 1000) / - clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, 1); - - if (delay <= UINT_MAX) - tr_err(&ll_tr, "timer_report_delay(): timer %d delayed by %d uS %d ticks", - id, ll_delay_us, (unsigned int)delay); - else - tr_err(&ll_tr, "timer_report_delay(): timer %d delayed by %d uS, ticks > %u", - id, ll_delay_us, UINT_MAX); - - /* Fix compile error when traces are disabled */ - (void)ll_delay_us; -} - -static int timer_domain_register(struct ll_schedule_domain *domain, - struct task *task, - void (*handler)(void *arg), void *arg) -{ - struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain); - int core = cpu_get_id(); - - tr_dbg(&ll_tr, "timer_domain_register()"); - - /* tasks already registered on this core */ - if (timer_domain->arg[core]) - return 0; - - timer_domain->arg[core] = arg; - - tr_info(&ll_tr, "timer_domain_register domain->type %d domain->clk %d domain->ticks_per_ms %d", - domain->type, domain->clk, domain->ticks_per_ms); - - return timer_register(timer_domain->timer, handler, arg); -} - -static int timer_domain_unregister(struct ll_schedule_domain *domain, - struct task *task, uint32_t num_tasks) -{ - struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain); - int core = cpu_get_id(); - - if (task) - return 0; - - tr_dbg(&ll_tr, "timer_domain_unregister()"); - - /* tasks still registered on this core */ - if (!timer_domain->arg[core] || num_tasks) - return 0; - - tr_info(&ll_tr, "timer_domain_unregister domain->type %d domain->clk %d", - domain->type, domain->clk); - - timer_unregister(timer_domain->timer, timer_domain->arg[core]); - - timer_domain->arg[core] = NULL; - - return 0; -} - -static void timer_domain_enable(struct ll_schedule_domain *domain, int core) -{ - struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain); - - timer_enable(timer_domain->timer, timer_domain->arg[core], core); -} - -static void timer_domain_disable(struct ll_schedule_domain *domain, int core) -{ - struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain); - - timer_disable(timer_domain->timer, timer_domain->arg[core], core); -} - -static void timer_domain_set(struct ll_schedule_domain *domain, uint64_t start) -{ - struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain); - uint64_t ticks_set; - /* make sure to require for ticks later than tout from now */ - const uint64_t time = platform_timer_get_atomic(timer_domain->timer); - const uint64_t ticks_req = MAX(start, time + LL_TIMER_SET_OVERHEAD_TICKS); - - ticks_set = platform_timer_set(timer_domain->timer, ticks_req); - - tr_dbg(&ll_tr, "timer_domain_set(): ticks_set %u ticks_req %u current %u", - (unsigned int)ticks_set, (unsigned int)ticks_req, - (unsigned int)platform_timer_get_atomic(timer_get())); - - /* Was timer set to the value we requested? If no it means some - * delay occurred and we should report that in error log. - */ - if (ticks_req < ticks_set) - timer_report_delay(timer_domain->timer->id, - ticks_set - ticks_req); - - domain->next_tick = ticks_set; - -} - -static void timer_domain_clear(struct ll_schedule_domain *domain) -{ - struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain); - - platform_timer_clear(timer_domain->timer); -} - -static bool timer_domain_is_pending(struct ll_schedule_domain *domain, - struct task *task, struct comp_dev **comp) -{ - return task->start <= platform_timer_get_atomic(timer_get()); -} - -static const struct ll_schedule_domain_ops timer_domain_ops = { - .domain_register = timer_domain_register, - .domain_unregister = timer_domain_unregister, - .domain_enable = timer_domain_enable, - .domain_disable = timer_domain_disable, - .domain_set = timer_domain_set, - .domain_clear = timer_domain_clear, - .domain_is_pending = timer_domain_is_pending -}; - -struct ll_schedule_domain *timer_domain_init(struct timer *timer, int clk) -{ - struct ll_schedule_domain *domain; - struct timer_domain *timer_domain; - - domain = domain_init(SOF_SCHEDULE_LL_TIMER, clk, false, - &timer_domain_ops); - - timer_domain = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*timer_domain)); - timer_domain->timer = timer; - - ll_sch_domain_set_pdata(domain, timer_domain); - - return domain; -} diff --git a/src/schedule/zephyr_dma_domain.c b/src/schedule/zephyr_dma_domain.c index 05e95a0dad0e..9bb76660ab29 100644 --- a/src/schedule/zephyr_dma_domain.c +++ b/src/schedule/zephyr_dma_domain.c @@ -119,12 +119,19 @@ struct ll_schedule_domain *zephyr_dma_domain_init(struct dma *dma_array, clk, true, &zephyr_dma_domain_ops); + if (!domain) { + tr_err(&ll_tr, "domain init failed"); + return NULL; + } /* initialize domain pdata */ - zephyr_dma_domain = rzalloc(SOF_MEM_ZONE_SYS_SHARED, - 0, - SOF_MEM_CAPS_RAM, + zephyr_dma_domain = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*zephyr_dma_domain)); + if (!zephyr_dma_domain) { + tr_err(&ll_tr, "allocation failed"); + rfree(domain); + return NULL; + } zephyr_dma_domain->dma_array = dma_array; zephyr_dma_domain->num_dma = num_dma; @@ -308,8 +315,8 @@ static int register_dma_irq(struct zephyr_dma_domain *domain, * that IRQ hasn't been allocated yet so we need to do * so here. */ - crt_irq_data = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, - SOF_MEM_CAPS_RAM, sizeof(*crt_irq_data)); + crt_irq_data = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*crt_irq_data)); if (!crt_irq_data) return -ENOMEM; @@ -321,8 +328,8 @@ static int register_dma_irq(struct zephyr_dma_domain *domain, list_item_append(&crt_irq_data->list, &domain->irqs); } - chan_data = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, - SOF_MEM_CAPS_RAM, sizeof(*chan_data)); + chan_data = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*chan_data)); if (!chan_data) return -ENOMEM; @@ -381,7 +388,7 @@ static int zephyr_dma_domain_register(struct ll_schedule_domain *domain, dt = zephyr_dma_domain->domain_thread + core; pipe_task = pipeline_task_get(task); - tr_info(&ll_tr, "zephyr_dma_domain_register()"); + tr_info(&ll_tr, "entry"); /* don't even bother trying to register DMA IRQ for * non-registrable tasks. @@ -450,12 +457,14 @@ static int zephyr_dma_domain_register(struct ll_schedule_domain *domain, dt, NULL, NULL, - -CONFIG_NUM_COOP_PRIORITIES, + CONFIG_LL_THREAD_PRIORITY, 0, K_FOREVER); +#ifdef CONFIG_SCHED_CPU_MASK k_thread_cpu_mask_clear(thread); k_thread_cpu_mask_enable(thread, core); +#endif k_thread_name_set(thread, thread_name); k_thread_start(thread); @@ -554,7 +563,7 @@ static int zephyr_dma_domain_unregister(struct ll_schedule_domain *domain, core = cpu_get_id(); dt = zephyr_dma_domain->domain_thread + core; - tr_info(&ll_tr, "zephyr_dma_domain_unregister()"); + tr_info(&ll_tr, "entry"); /* unregister the DMA IRQ only for PPL tasks marked as "registrable" * diff --git a/src/schedule/zephyr_domain.c b/src/schedule/zephyr_domain.c index bcb7a93b2498..3837f0b135c6 100644 --- a/src/schedule/zephyr_domain.c +++ b/src/schedule/zephyr_domain.c @@ -6,6 +6,8 @@ #include <rtos/timer.h> #include <rtos/alloc.h> +#include <rtos/symbol.h> +#include <rtos/userspace_helper.h> #include <sof/lib/cpu.h> #include <sof/lib/memory.h> #include <sof/lib/watchdog.h> @@ -37,17 +39,28 @@ LOG_MODULE_DECLARE(ll_schedule, CONFIG_SOF_LOG_LEVEL); #define ZEPHYR_LL_STACK_SIZE 8192 +#if CONFIG_SOF_USERSPACE_LL +K_THREAD_STACK_ARRAY_DEFINE(ll_sched_stack, CONFIG_CORE_COUNT, ZEPHYR_LL_STACK_SIZE); +#else K_KERNEL_STACK_ARRAY_DEFINE(ll_sched_stack, CONFIG_CORE_COUNT, ZEPHYR_LL_STACK_SIZE); +#endif struct zephyr_domain_thread { - struct k_thread ll_thread; - struct k_sem sem; + struct k_thread *ll_thread; + struct k_sem *sem; +#ifndef CONFIG_SOF_USERSPACE_LL + struct k_thread ll_thread_obj; + struct k_sem sem_obj; +#endif void (*handler)(void *arg); void *arg; }; struct zephyr_domain { - struct k_timer timer; + struct k_timer *timer; +#ifndef CONFIG_SOF_USERSPACE_LL + struct k_timer timer_obj; +#endif struct zephyr_domain_thread domain_thread[CONFIG_CORE_COUNT]; struct ll_schedule_domain *ll_domain; #if CONFIG_CROSS_CORE_STREAM @@ -76,16 +89,18 @@ static inline void stats_report(unsigned int runs, int core, unsigned int cycles static void zephyr_domain_thread_fn(void *p1, void *p2, void *p3) { struct zephyr_domain *zephyr_domain = p1; - int core = cpu_get_id(); + int core = POINTER_TO_INT(p2); struct zephyr_domain_thread *dt = zephyr_domain->domain_thread + core; #ifdef CONFIG_SCHEDULE_LL_STATS_LOG unsigned int runs = 0, overruns = 0, cycles_sum = 0, cycles_max = 0; unsigned int cycles0, cycles1, diff, timer_fired; #endif + tr_dbg(&ll_tr, "ll core %u thread starting", core); + for (;;) { /* immediately go to sleep, waiting to be woken up by the timer */ - k_sem_take(&dt->sem, K_FOREVER); + k_sem_take(dt->sem, K_FOREVER); #ifdef CONFIG_SCHEDULE_LL_STATS_LOG cycles0 = k_cycle_get_32(); @@ -111,7 +126,8 @@ static void zephyr_domain_thread_fn(void *p1, void *p2, void *p3) } #endif - dt->handler(dt->arg); + if (dt->handler) + dt->handler(dt->arg); #ifdef CONFIG_SCHEDULE_LL_STATS_LOG cycles1 = k_cycle_get_32(); @@ -119,7 +135,7 @@ static void zephyr_domain_thread_fn(void *p1, void *p2, void *p3) /* This handles wrapping correctly too */ diff = cycles1 - cycles0; - timer_fired = k_timer_status_get(&zephyr_domain->timer); + timer_fired = k_timer_status_get(zephyr_domain->timer); if (timer_fired > 1) overruns++; @@ -162,10 +178,13 @@ static void zephyr_domain_timer_fn(struct k_timer *timer) struct zephyr_domain_thread *dt = zephyr_domain->domain_thread + core; if (dt->handler) - k_sem_give(&dt->sem); + k_sem_give(dt->sem); } } +/* The normal kernel-space implementation for register/unregister */ +#ifndef CONFIG_SOF_USERSPACE_LL + static int zephyr_domain_register(struct ll_schedule_domain *domain, struct task *task, void (*handler)(void *arg), void *arg) @@ -177,7 +196,7 @@ static int zephyr_domain_register(struct ll_schedule_domain *domain, k_tid_t thread; k_spinlock_key_t key; - tr_dbg(&ll_tr, "zephyr_domain_register()"); + tr_dbg(&ll_tr, "entry"); /* domain work only needs registered once on each core */ if (dt->handler) @@ -187,31 +206,34 @@ static int zephyr_domain_register(struct ll_schedule_domain *domain, dt->arg = arg; /* 10 is rather random, we better not accumulate 10 missed timer interrupts */ - k_sem_init(&dt->sem, 0, 10); + k_sem_init(dt->sem, 0, 10); thread_name[sizeof(thread_name) - 2] = '0' + core; - thread = k_thread_create(&dt->ll_thread, - ll_sched_stack[core], - ZEPHYR_LL_STACK_SIZE, - zephyr_domain_thread_fn, zephyr_domain, NULL, NULL, - -CONFIG_NUM_COOP_PRIORITIES, 0, K_FOREVER); + /* not allocated dynamically when LL in kernel space */ + dt->ll_thread = &dt->ll_thread_obj; + + thread = k_thread_create(dt->ll_thread, ll_sched_stack[core], ZEPHYR_LL_STACK_SIZE, + zephyr_domain_thread_fn, zephyr_domain, INT_TO_POINTER(core), + NULL, CONFIG_LL_THREAD_PRIORITY, 0, K_FOREVER); +#ifdef CONFIG_SCHED_CPU_MASK k_thread_cpu_mask_clear(thread); k_thread_cpu_mask_enable(thread, core); +#endif k_thread_name_set(thread, thread_name); k_thread_start(thread); key = k_spin_lock(&domain->lock); - if (!k_timer_user_data_get(&zephyr_domain->timer)) { + if (!k_timer_user_data_get(zephyr_domain->timer)) { k_timeout_t start = {0}; - k_timer_init(&zephyr_domain->timer, zephyr_domain_timer_fn, NULL); - k_timer_user_data_set(&zephyr_domain->timer, zephyr_domain); + k_timer_init(zephyr_domain->timer, zephyr_domain_timer_fn, NULL); + k_timer_user_data_set(zephyr_domain->timer, zephyr_domain); - k_timer_start(&zephyr_domain->timer, start, K_USEC(LL_TIMER_PERIOD_US)); + k_timer_start(zephyr_domain->timer, start, K_USEC(LL_TIMER_PERIOD_US)); /* Enable the watchdog */ watchdog_enable(core); @@ -219,7 +241,7 @@ static int zephyr_domain_register(struct ll_schedule_domain *domain, k_spin_unlock(&domain->lock, key); - tr_info(&ll_tr, "zephyr_domain_register domain->type %d domain->clk %d domain->ticks_per_ms %d period %d", + tr_info(&ll_tr, "domain->type %d domain->clk %d domain->ticks_per_ms %d period %d", domain->type, domain->clk, domain->ticks_per_ms, (uint32_t)LL_TIMER_PERIOD_US); return 0; @@ -232,7 +254,7 @@ static int zephyr_domain_unregister(struct ll_schedule_domain *domain, int core = cpu_get_id(); k_spinlock_key_t key; - tr_dbg(&ll_tr, "zephyr_domain_unregister()"); + tr_dbg(&ll_tr, "entry"); /* tasks still registered on this core */ if (num_tasks) @@ -244,26 +266,242 @@ static int zephyr_domain_unregister(struct ll_schedule_domain *domain, /* Disable the watchdog */ watchdog_disable(core); - k_timer_stop(&zephyr_domain->timer); - k_timer_user_data_set(&zephyr_domain->timer, NULL); + k_timer_stop(zephyr_domain->timer); + k_timer_user_data_set(zephyr_domain->timer, NULL); } zephyr_domain->domain_thread[core].handler = NULL; k_spin_unlock(&domain->lock, key); - tr_info(&ll_tr, "zephyr_domain_unregister domain->type %d domain->clk %d", + tr_info(&ll_tr, "domain->type %d domain->clk %d", domain->type, domain->clk); /* * If running in the context of the domain thread, k_thread_abort() will * not return */ - k_thread_abort(&zephyr_domain->domain_thread[core].ll_thread); + k_thread_abort(zephyr_domain->domain_thread[core].ll_thread); + + tr_dbg(&ll_tr, "exit"); + + return 0; +} + +#else /* CONFIG_SOF_USERSPACE_LL */ + +/* + * Privileged thread initialization for userspace LL scheduling. + * Creates the scheduling thread, sets up timer, grants access to kernel + * objects. Must be called from kernel context before any user-space + * domain_register() calls. + */ +static int zephyr_domain_thread_init(struct ll_schedule_domain *domain, + struct task *task) +{ + struct zephyr_domain *zephyr_domain = ll_sch_domain_get_pdata(domain); + struct zephyr_domain_thread *dt; + char thread_name[] = "ll_thread0"; + k_tid_t thread; + int core = task->core; + + tr_dbg(&ll_tr, "entry"); + + if (core >= CONFIG_CORE_COUNT) + return -EINVAL; + + dt = zephyr_domain->domain_thread + core; + + /* thread only needs to be created once per core */ + if (dt->ll_thread) + return 0; + + dt->handler = NULL; + dt->arg = NULL; + + dt->sem = k_object_alloc(K_OBJ_SEM); + if (!dt->sem) { + tr_err(&ll_tr, "Failed to allocate semaphore for core %d", core); + return -ENOMEM; + } + + /* 10 is rather random, we better not accumulate 10 missed timer interrupts */ + k_sem_init(dt->sem, 0, 10); + + thread_name[sizeof(thread_name) - 2] = '0' + core; + + /* Allocate thread structure dynamically */ + dt->ll_thread = k_object_alloc(K_OBJ_THREAD); + if (!dt->ll_thread) { + tr_err(&ll_tr, "Failed to allocate thread object for core %d", core); + k_object_free(dt->sem); + dt->sem = NULL; + return -ENOMEM; + } + + thread = k_thread_create(dt->ll_thread, ll_sched_stack[core], ZEPHYR_LL_STACK_SIZE, + zephyr_domain_thread_fn, zephyr_domain, + INT_TO_POINTER(core), NULL, CONFIG_LL_THREAD_PRIORITY, + K_USER, K_FOREVER); + +#ifdef CONFIG_SCHED_CPU_MASK + k_thread_cpu_mask_clear(thread); + k_thread_cpu_mask_enable(thread, core); +#endif + k_thread_name_set(thread, thread_name); + + k_mem_domain_add_thread(zephyr_ll_mem_domain(), thread); + k_thread_access_grant(thread, dt->sem, domain->lock, zephyr_domain->timer); + user_grant_dai_access_all(thread); + user_grant_dma_access_all(thread); + tr_dbg(&ll_tr, "granted LL access to thread %p (core %d)", thread, core); + + k_thread_start(thread); + + k_mutex_lock(domain->lock, K_FOREVER); + if (!k_timer_user_data_get(zephyr_domain->timer)) { + k_timeout_t start = {0}; + + k_timer_init(zephyr_domain->timer, zephyr_domain_timer_fn, NULL); + k_timer_user_data_set(zephyr_domain->timer, zephyr_domain); + + k_timer_start(zephyr_domain->timer, start, K_USEC(LL_TIMER_PERIOD_US)); + + /* Enable the watchdog */ + watchdog_enable(core); + } + + k_mutex_unlock(domain->lock); + + tr_info(&ll_tr, "domain->type %d domain->clk %d domain->ticks_per_ms %d period %d", + domain->type, domain->clk, domain->ticks_per_ms, (uint32_t)LL_TIMER_PERIOD_US); + + return 0; +} + +/* + * User-space register: bookkeeping only. The privileged thread setup has + * already been done by domain_thread_init() called from kernel context. + */ +static int zephyr_domain_register_user(struct ll_schedule_domain *domain, + struct task *task, + void (*handler)(void *arg), void *arg) +{ + struct zephyr_domain *zephyr_domain = ll_sch_domain_get_pdata(domain); + struct zephyr_domain_thread *dt; + int core; + + tr_dbg(&ll_tr, "register_user entry"); + + if (task->core >= CONFIG_CORE_COUNT) + return -EINVAL; + + core = task->core; + dt = zephyr_domain->domain_thread + core; + + if (!dt->ll_thread) { + tr_err(&ll_tr, "domain_thread_init() not called for core %d", core); + return -EINVAL; + } + + __ASSERT_NO_MSG(!dt->handler || dt->handler == handler); + if (dt->handler) + return 0; + + dt->handler = handler; + dt->arg = arg; + + tr_info(&ll_tr, "task registered on core %d", core); + + return 0; +} + +static int zephyr_domain_unregister_user(struct ll_schedule_domain *domain, + struct task *task, uint32_t num_tasks) +{ + struct zephyr_domain *zephyr_domain = ll_sch_domain_get_pdata(domain); + int core = task->core; + + tr_dbg(&ll_tr, "entry"); + + /* tasks still registered on this core */ + if (num_tasks) + return 0; + + k_mutex_lock(domain->lock, K_FOREVER); + + zephyr_domain->domain_thread[core].handler = NULL; + + k_mutex_unlock(domain->lock); + + /* + * In this user thread implementation, the timer is left + * running until privileged domain_thread_free() is called + * to clean up resources. + */ + + tr_dbg(&ll_tr, "exit"); return 0; } +/* + * Free resources acquired by zephyr_domain_thread_init(). + * Stops the timer, aborts the scheduling thread and frees the thread object. + * Must be called from kernel context. + */ +static void zephyr_domain_thread_free(struct ll_schedule_domain *domain, + uint32_t num_tasks) +{ + struct zephyr_domain *zephyr_domain = ll_sch_domain_get_pdata(domain); + int core = cpu_get_id(); + struct zephyr_domain_thread *dt = zephyr_domain->domain_thread + core; + + tr_dbg(&ll_tr, "thread_free entry, core %d, num_tasks %u", core, num_tasks); + + /* Still tasks on other cores, only clean up this core's thread */ + k_mutex_lock(domain->lock, K_FOREVER); + + if (!num_tasks && !atomic_read(&domain->total_num_tasks)) { + /* Last task globally: stop the timer and watchdog */ + watchdog_disable(core); + + k_timer_stop(zephyr_domain->timer); + k_timer_user_data_set(zephyr_domain->timer, NULL); + } + + dt->handler = NULL; + dt->arg = NULL; + + k_mutex_unlock(domain->lock); + + if (dt->ll_thread) { + k_thread_abort(dt->ll_thread); + k_object_free(dt->ll_thread); + dt->ll_thread = NULL; + } + + if (dt->sem) { + k_object_free(dt->sem); + dt->sem = NULL; + } + + tr_info(&ll_tr, "thread_free done, core %d", core); +} + +struct k_thread *zephyr_domain_thread_tid(struct ll_schedule_domain *domain) +{ + struct zephyr_domain *zephyr_domain = ll_sch_domain_get_pdata(domain); + int core = cpu_get_id(); + struct zephyr_domain_thread *dt = zephyr_domain->domain_thread + core; + + tr_dbg(&ll_tr, "entry"); + + return dt->ll_thread; +} + +#endif /* CONFIG_SOF_USERSPACE_LL */ + #if CONFIG_CROSS_CORE_STREAM static void zephyr_domain_block(struct ll_schedule_domain *domain) { @@ -289,28 +527,67 @@ static void zephyr_domain_unblock(struct ll_schedule_domain *domain) } #endif -static const struct ll_schedule_domain_ops zephyr_domain_ops = { +APP_TASK_DATA static const struct ll_schedule_domain_ops zephyr_domain_ops = { +#ifdef CONFIG_SOF_USERSPACE_LL + .domain_register = zephyr_domain_register_user, + .domain_unregister = zephyr_domain_unregister_user, + .domain_thread_init = zephyr_domain_thread_init, + .domain_thread_free = zephyr_domain_thread_free, +#else .domain_register = zephyr_domain_register, .domain_unregister = zephyr_domain_unregister, +#endif #if CONFIG_CROSS_CORE_STREAM .domain_block = zephyr_domain_block, .domain_unblock = zephyr_domain_unblock, #endif }; +/* Core 0 only */ struct ll_schedule_domain *zephyr_domain_init(int clk) { struct ll_schedule_domain *domain; struct zephyr_domain *zephyr_domain; + int core; domain = domain_init(SOF_SCHEDULE_LL_TIMER, clk, false, &zephyr_domain_ops); + if (!domain) { + tr_err(&ll_tr, "domain init failed"); + return NULL; + } - zephyr_domain = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, +#if CONFIG_SOF_USERSPACE_LL + zephyr_domain = sof_heap_alloc(zephyr_ll_user_heap(), + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*zephyr_domain), sizeof(void *)); + if (zephyr_domain) + memset(zephyr_domain, 0, sizeof(*zephyr_domain)); +#else + zephyr_domain = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*zephyr_domain)); +#endif + if (!zephyr_domain) { + tr_err(&ll_tr, "domain allocation failed"); + k_panic(); + return NULL; + } zephyr_domain->ll_domain = domain; +#if CONFIG_SOF_USERSPACE_LL + /* Allocate timer dynamically for userspace access */ + zephyr_domain->timer = k_object_alloc(K_OBJ_TIMER); + if (!zephyr_domain->timer) { + tr_err(&ll_tr, "timer allocation failed"); + k_panic(); + return NULL; + } +#else + /* not allocated dynamically when LL in kernel space */ + zephyr_domain->timer = &zephyr_domain->timer_obj; +#endif + #if CONFIG_CROSS_CORE_STREAM atomic_set(&zephyr_domain->block, 0); k_mutex_init(&zephyr_domain->block_mutex); @@ -319,5 +596,28 @@ struct ll_schedule_domain *zephyr_domain_init(int clk) ll_sch_domain_set_pdata(domain, zephyr_domain); + for (core = 0; core < CONFIG_CORE_COUNT; core++) { +#ifndef CONFIG_SOF_USERSPACE_LL + struct zephyr_domain_thread *dt = zephyr_domain->domain_thread + core; + + /* not allocated dynamically when LL in kernel space */ + dt->sem = &dt->sem_obj; +#endif + } + return domain; } + +/* Check if currently running in the LL scheduler thread context */ +bool ll_sch_is_current(void) +{ + struct zephyr_domain *zephyr_domain = ll_sch_domain_get_pdata(zephyr_ll_domain()); + + if (!zephyr_domain) + return false; + + struct zephyr_domain_thread *dt = zephyr_domain->domain_thread + cpu_get_id(); + + return k_current_get() == dt->ll_thread; +} +EXPORT_SYMBOL(ll_sch_is_current); diff --git a/src/schedule/zephyr_dp_schedule.c b/src/schedule/zephyr_dp_schedule.c index 68f3fdc37e70..1c6b94d3bb4c 100644 --- a/src/schedule/zephyr_dp_schedule.c +++ b/src/schedule/zephyr_dp_schedule.c @@ -7,7 +7,9 @@ #include <sof/audio/component.h> #include <sof/audio/module_adapter/module/generic.h> +#include <sof/llext_manager.h> #include <rtos/task.h> +#include <rtos/userspace_helper.h> #include <stdint.h> #include <sof/schedule/dp_schedule.h> #include <sof/schedule/ll_schedule.h> @@ -17,9 +19,14 @@ #include <rtos/interrupt.h> #include <zephyr/kernel.h> #include <zephyr/sys_clock.h> +#include <zephyr/sys/sem.h> +#include <zephyr/sys/mutex.h> +#include <sof/lib/memory.h> #include <sof/lib/notifier.h> #include <ipc4/base_fw.h> +#include "zephyr_dp_schedule.h" + #include <zephyr/kernel/thread.h> LOG_MODULE_REGISTER(dp_schedule, CONFIG_SOF_LOG_LEVEL); @@ -27,39 +34,34 @@ SOF_DEFINE_REG_UUID(dp_sched); DECLARE_TR_CTX(dp_tr, SOF_UUID(dp_sched_uuid), LOG_LEVEL_INFO); -/** - * \brief a priority of the DP threads in the system. - */ -#define ZEPHYR_DP_THREAD_PRIORITY (CONFIG_NUM_PREEMPT_PRIORITIES - 2) +#define DP_LOCK_INIT(i, _) Z_SEM_INITIALIZER(dp_lock[i], 1, 1) +#define DP_LOCK_INIT_LIST LISTIFY(CONFIG_MP_MAX_NUM_CPUS, DP_LOCK_INIT, (,)) -struct scheduler_dp_data { - struct list_item tasks; /* list of active dp tasks */ - struct task ll_tick_src; /* LL task - source of DP tick */ -}; - -struct task_dp_pdata { - k_tid_t thread_id; /* zephyr thread ID */ - struct k_thread thread; /* memory space for a thread */ - uint32_t deadline_clock_ticks; /* dp module deadline in Zephyr ticks */ - k_thread_stack_t __sparse_cache *p_stack; /* pointer to thread stack */ - size_t stack_size; /* size of the stack in bytes */ - struct k_sem sem; /* semaphore for task scheduling */ - struct processing_module *mod; /* the module to be scheduled */ - uint32_t ll_cycles_to_start; /* current number of LL cycles till delayed start */ -}; +/* User threads don't need access to this array. Access is performed from + * the kernel space via a syscall. Array must be placed in special section + * to be qualified as initialized by the gen_kobject_list.py script. + */ +static +STRUCT_SECTION_ITERABLE_ARRAY(k_sem, dp_lock, CONFIG_MP_MAX_NUM_CPUS) = { DP_LOCK_INIT_LIST }; -/* Single CPU-wide lock - * as each per-core instance if dp-scheduler has separate structures, it is enough to - * use irq_lock instead of cross-core spinlocks +/* Each per-core instance of DP scheduler has separate structures; hence, locks are per-core. + * + * TODO: consider using cpu_get_id() instead of supplying core as a parameter. */ -static inline unsigned int scheduler_dp_lock(void) +unsigned int scheduler_dp_lock(uint16_t core) { - return irq_lock(); + k_sem_take(&dp_lock[core], K_FOREVER); + return core; } -static inline void scheduler_dp_unlock(unsigned int key) +void scheduler_dp_unlock(unsigned int key) { - irq_unlock(key); + k_sem_give(&dp_lock[key]); +} + +void scheduler_dp_grant(k_tid_t thread_id, uint16_t core) +{ + k_thread_access_grant(thread_id, &dp_lock[core]); } /* dummy LL task - to start LL on secondary cores */ @@ -220,73 +222,51 @@ static enum task_state scheduler_dp_ll_tick_dummy(void *data) * 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) { (void)receiver_data; (void)event_type; (void)caller_data; - struct list_item *tlist; - struct task *curr_task; - struct task_dp_pdata *pdata; unsigned int lock_key; struct scheduler_dp_data *dp_sch = scheduler_get_data(SOF_SCHEDULE_DP); - 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; - struct processing_module *mod = pdata->mod; - - /* decrease number of LL ticks/cycles left till the module reaches its deadline */ - if (pdata->ll_cycles_to_start) { - pdata->ll_cycles_to_start--; - if (!pdata->ll_cycles_to_start) - /* deadline reached, clear startup delay flag. - * see dp_startup_delay comment for details - */ - mod->dp_startup_delay = false; - } - - if (curr_task->state == SOF_TASK_STATE_QUEUED) { - 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->deadline_clock_ticks); - - /* trigger the task */ - curr_task->state = SOF_TASK_STATE_RUNNING; - k_sem_give(&pdata->sem); - } - } - } + /* remember current timestamp as "NOW" */ + dp_sch->last_ll_tick_timestamp = k_cycle_get_32(); + + lock_key = scheduler_dp_lock(cpu_get_id()); + scheduler_dp_recalculate(dp_sch, event_type == NOTIFIER_ID_LL_POST_RUN); scheduler_dp_unlock(lock_key); } +#if CONFIG_SOF_USERSPACE_APPLICATION static int scheduler_dp_task_cancel(void *data, struct task *task) +{ + /* Should never be called */ + k_panic(); + return -EOPNOTSUPP; +} +#endif + +static int scheduler_dp_task_stop(void *data, struct task *task) { unsigned int lock_key; struct scheduler_dp_data *dp_sch = (struct scheduler_dp_data *)data; struct task_dp_pdata *pdata = task->priv_data; - /* this is asyn cancel - mark the task as canceled and remove it from scheduling */ - lock_key = scheduler_dp_lock(); + lock_key = scheduler_dp_lock(cpu_get_id()); task->state = SOF_TASK_STATE_CANCEL; list_item_del(&task->list); - /* if there're no more DP task, stop LL tick source */ + /* 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); - /* if the task is waiting on a semaphore - let it run and self-terminate */ - k_sem_give(&pdata->sem); + /* if the task is waiting - let it run and self-terminate */ + k_event_set(pdata->event, DP_TASK_EVENT_CANCEL); + scheduler_dp_unlock(lock_key); /* wait till the task has finished, if there was any task created */ @@ -299,8 +279,9 @@ static int scheduler_dp_task_cancel(void *data, struct task *task) static int scheduler_dp_task_free(void *data, struct task *task) { struct task_dp_pdata *pdata = task->priv_data; + int ret; - scheduler_dp_task_cancel(data, task); + scheduler_dp_task_stop(data, task); /* the thread should be terminated at this moment, * abort is safe and will ensure no use after free @@ -311,71 +292,12 @@ static int scheduler_dp_task_free(void *data, struct task *task) } /* free task stack */ - rfree((__sparse_force void *)pdata->p_stack); + ret = user_stack_free(pdata->p_stack); pdata->p_stack = NULL; - /* all other memory has been allocated as a single malloc, will be freed later by caller */ - return 0; -} - -/* Thread function called in component context, on target core */ -static void dp_thread_fn(void *p1, void *p2, void *p3) -{ - struct task *task = p1; - (void)p2; - (void)p3; - struct task_dp_pdata *task_pdata = task->priv_data; - unsigned int lock_key; - enum task_state state; - - while (1) { - /* - * the thread is started immediately after creation, it will stop on semaphore - * Semaphore will be released once the task is ready to process - */ - k_sem_take(&task_pdata->sem, K_FOREVER); - - if (task->state == SOF_TASK_STATE_RUNNING) - state = task_run(task); - else - state = task->state; /* to avoid undefined variable warning */ - - lock_key = scheduler_dp_lock(); - /* - * check if task is still running, may have been canceled by external call - * if not, set the state returned by run procedure - */ - if (task->state == SOF_TASK_STATE_RUNNING) { - task->state = state; - switch (state) { - case SOF_TASK_STATE_RESCHEDULE: - /* mark to reschedule, schedule time is already calculated */ - task->state = SOF_TASK_STATE_QUEUED; - break; - - case SOF_TASK_STATE_CANCEL: - case SOF_TASK_STATE_COMPLETED: - /* remove from scheduling */ - list_item_del(&task->list); - break; - - default: - /* illegal state, serious defect, won't happen */ - k_panic(); - } - } - - if (task->state == SOF_TASK_STATE_COMPLETED || - task->state == SOF_TASK_STATE_CANCEL) - break; /* exit the while loop, terminate the thread */ - - scheduler_dp_unlock(lock_key); - } + scheduler_dp_internal_free(task); - scheduler_dp_unlock(lock_key); - /* call task_complete */ - if (task->state == SOF_TASK_STATE_COMPLETED) - task_complete(task); + return ret; } static int scheduler_dp_task_shedule(void *data, struct task *task, uint64_t start, @@ -384,10 +306,14 @@ 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 deadline_clock_ticks; - int ret; - lock_key = scheduler_dp_lock(); + lock_key = scheduler_dp_lock(cpu_get_id()); + + if (task_is_active(task)) { + scheduler_dp_unlock(lock_key); + tr_dbg(&dp_tr, "DP task already active"); + return 0; + } if (task->state != SOF_TASK_STATE_INIT && task->state != SOF_TASK_STATE_CANCEL && @@ -396,22 +322,6 @@ static int scheduler_dp_task_shedule(void *data, struct task *task, uint64_t sta return -EINVAL; } - /* create a zephyr thread for the task */ - pdata->thread_id = k_thread_create(&pdata->thread, (__sparse_force void *)pdata->p_stack, - pdata->stack_size, dp_thread_fn, task, NULL, NULL, - ZEPHYR_DP_THREAD_PRIORITY, K_USER, K_FOREVER); - - /* pin the thread to specific core */ - ret = k_thread_cpu_pin(pdata->thread_id, task->core); - if (ret < 0) { - tr_err(&dp_tr, "zephyr_dp_task_init(): zephyr task pin to core failed"); - goto err; - } - - /* start the thread, it should immediately stop at a semaphore, so clean it */ - k_sem_reset(&pdata->sem); - k_thread_start(pdata->thread_id); - /* 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); @@ -420,37 +330,30 @@ static int scheduler_dp_task_shedule(void *data, struct task *task, uint64_t sta task->state = SOF_TASK_STATE_QUEUED; list_item_prepend(&task->list, &dp_sch->tasks); - deadline_clock_ticks = period * CONFIG_SYS_CLOCK_TICKS_PER_SEC; - /* period/deadline is in us - convert to seconds in next step - * or it always will be zero because of integer calculation - */ - deadline_clock_ticks /= 1000000; - - pdata->deadline_clock_ticks = deadline_clock_ticks; - pdata->ll_cycles_to_start = period / LL_TIMER_PERIOD_US; pdata->mod->dp_startup_delay = true; scheduler_dp_unlock(lock_key); tr_dbg(&dp_tr, "DP task scheduled with period %u [us]", (uint32_t)period); return 0; - -err: - /* cleanup - unlock and free all allocated resources */ - scheduler_dp_unlock(lock_key); - k_thread_abort(pdata->thread_id); - return ret; } static struct scheduler_ops schedule_dp_ops = { .schedule_task = scheduler_dp_task_shedule, +#if CONFIG_SOF_USERSPACE_APPLICATION .schedule_task_cancel = scheduler_dp_task_cancel, +#else + .schedule_task_cancel = scheduler_dp_task_stop, +#endif .schedule_task_free = scheduler_dp_task_free, }; -int scheduler_dp_init(void) +__cold int scheduler_dp_init(void) { int ret; - struct scheduler_dp_data *dp_sch = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_RAM, + + assert_can_be_cold(); + + struct scheduler_dp_data *dp_sch = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(struct scheduler_dp_data)); if (!dp_sch) return -ENOMEM; @@ -474,83 +377,6 @@ int scheduler_dp_init(void) return 0; } -int scheduler_dp_task_init(struct task **task, - const struct sof_uuid_entry *uid, - const struct task_ops *ops, - struct processing_module *mod, - uint16_t core, - size_t stack_size) -{ - void __sparse_cache *p_stack = NULL; - - /* memory allocation helper structure */ - struct { - struct task task; - struct task_dp_pdata pdata; - } *task_memory; - - int ret; - - /* must be called on the same core the task will be binded to */ - assert(cpu_get_id() == core); - - /* - * allocate memory - * to avoid multiple malloc operations allocate all required memory as a single structure - * and return pointer to task_memory->task - * As the structure contains zephyr kernel specific data, it must be located in - * shared, non cached memory - */ - task_memory = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, - sizeof(*task_memory)); - if (!task_memory) { - tr_err(&dp_tr, "zephyr_dp_task_init(): memory alloc failed"); - return -ENOMEM; - } - - /* allocate stack - must be aligned and cached so a separate alloc */ - stack_size = Z_KERNEL_STACK_SIZE_ADJUST(stack_size); - p_stack = (__sparse_force void __sparse_cache *) - rballoc_align(0, SOF_MEM_CAPS_RAM, stack_size, Z_KERNEL_STACK_OBJ_ALIGN); - if (!p_stack) { - tr_err(&dp_tr, "zephyr_dp_task_init(): stack alloc failed"); - ret = -ENOMEM; - goto err; - } - - /* internal SOF task init */ - ret = schedule_task_init(&task_memory->task, uid, SOF_SCHEDULE_DP, 0, ops->run, - mod, core, 0); - if (ret < 0) { - tr_err(&dp_tr, "zephyr_dp_task_init(): schedule_task_init failed"); - goto err; - } - - /* initialize other task structures */ - task_memory->task.ops.complete = ops->complete; - task_memory->task.ops.get_deadline = ops->get_deadline; - task_memory->task.state = SOF_TASK_STATE_INIT; - task_memory->task.core = core; - - /* initialize semaprhore */ - k_sem_init(&task_memory->pdata.sem, 0, 1); - - /* success, fill the structures */ - task_memory->task.priv_data = &task_memory->pdata; - task_memory->pdata.p_stack = p_stack; - task_memory->pdata.stack_size = stack_size; - task_memory->pdata.mod = mod; - *task = &task_memory->task; - - - return 0; -err: - /* cleanup - free all allocated resources */ - rfree((__sparse_force void *)p_stack); - rfree(task_memory); - return ret; -} - void scheduler_get_task_info_dp(struct scheduler_props *scheduler_props, uint32_t *data_off_size) { unsigned int lock_key; @@ -559,7 +385,7 @@ void scheduler_get_task_info_dp(struct scheduler_props *scheduler_props, uint32_ struct scheduler_dp_data *dp_sch = (struct scheduler_dp_data *)scheduler_get_data(SOF_SCHEDULE_DP); - lock_key = scheduler_dp_lock(); + lock_key = scheduler_dp_lock(cpu_get_id()); scheduler_get_task_info(scheduler_props, data_off_size, &dp_sch->tasks); scheduler_dp_unlock(lock_key); } diff --git a/src/schedule/zephyr_dp_schedule.h b/src/schedule/zephyr_dp_schedule.h new file mode 100644 index 000000000000..c4f37fc812f2 --- /dev/null +++ b/src/schedule/zephyr_dp_schedule.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Marcin Szkudlinski + */ + +#include <rtos/task.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/list.h> +#include <sof/compiler_attributes.h> + +#include <zephyr/app_memory/mem_domain.h> + +#include <stdbool.h> +#include <stdint.h> + +struct scheduler_dp_data { + struct list_item tasks; /* list of active dp tasks */ + struct task ll_tick_src; /* LL task - source of DP tick */ + uint32_t last_ll_tick_timestamp;/* a timestamp as k_cycle_get_32 of last LL tick, + * "NOW" for DP deadline calculation + */ +}; + +enum sof_dp_part_type { + SOF_DP_PART_HEAP, + SOF_DP_PART_HEAP_CACHE, + SOF_DP_PART_CFG, + SOF_DP_PART_CFG_CACHE, + SOF_DP_PART_TYPE_COUNT, +}; + +struct ipc4_flat; + +struct task_dp_pdata { + k_tid_t thread_id; /* zephyr thread ID */ + struct k_thread *thread; /* pointer to the kernels' thread object */ + struct k_thread thread_struct; /* thread object for kernel threads */ + uint32_t deadline_clock_ticks; /* dp module deadline in Zephyr ticks */ + k_thread_stack_t *p_stack; /* pointer to thread stack */ + struct processing_module *mod; /* the module to be scheduled */ + uint32_t ll_cycles_to_start; /* current number of LL cycles till delayed start */ +#if CONFIG_SOF_USERSPACE_APPLICATION + struct ipc4_flat *flat; + struct k_mem_partition mpart[SOF_DP_PART_TYPE_COUNT]; +#endif + struct k_event *event; /* pointer to event for task scheduling */ + struct k_event event_struct; /* event for task scheduling for kernel threads */ +#if IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) + struct k_work_user *ipc_work_item; /* work item for IPC handling */ +#endif +}; + +void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch, bool is_ll_post_run); +void dp_thread_fn(void *p1, void *p2, void *p3); +unsigned int scheduler_dp_lock(uint16_t core); +void scheduler_dp_unlock(unsigned int key); +void scheduler_dp_grant(k_tid_t thread_id, uint16_t core); +int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid, + const struct task_ops *ops, struct processing_module *mod, + uint16_t core, size_t stack_size, uint32_t options); +void scheduler_dp_internal_free(struct task *task); diff --git a/src/schedule/zephyr_dp_schedule_application.c b/src/schedule/zephyr_dp_schedule_application.c new file mode 100644 index 000000000000..791e16ab190d --- /dev/null +++ b/src/schedule/zephyr_dp_schedule_application.c @@ -0,0 +1,617 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + * Author: Marcin Szkudlinski + */ + +#include <rtos/task.h> + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/common.h> +#include <sof/list.h> +#include <sof/llext_manager.h> +#include <sof/objpool.h> +#include <sof/schedule/dp_schedule.h> +#include <sof/schedule/ll_schedule_domain.h> + +#include <zephyr/app_memory/mem_domain.h> +#include <zephyr/kernel.h> +#include <zephyr/logging/log.h> +#include <zephyr/sys/slist.h> + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> + +#include "zephyr_dp_schedule.h" + +LOG_MODULE_DECLARE(dp_schedule, CONFIG_SOF_LOG_LEVEL); +extern struct tr_ctx dp_tr; + +static struct objpool_head dp_mdom_head = {.list = LIST_INIT(dp_mdom_head.list)}; + +/* Synchronization semaphore for the scheduler thread to wait for DP startup */ +#define DP_SYNC_INIT(i, _) Z_SEM_INITIALIZER(dp_sync[i], 0, 1) +#define DP_SYNC_INIT_LIST LISTIFY(CONFIG_CORE_COUNT, DP_SYNC_INIT, (,)) +static STRUCT_SECTION_ITERABLE_ARRAY(k_sem, dp_sync, CONFIG_CORE_COUNT) = { DP_SYNC_INIT_LIST }; + +struct ipc4_flat { + unsigned int cmd; + int ret; + union { + struct { + struct ipc4_module_bind_unbind bu; + enum bind_type type; + } bind; + struct { + unsigned int trigger_cmd; + enum ipc4_pipeline_state state; + int n_sources; + int n_sinks; + struct sof_source *source[CONFIG_MODULE_MAX_CONNECTIONS]; + struct sof_sink *sink[CONFIG_MODULE_MAX_CONNECTIONS]; + } pipeline_state; + }; +}; + +/* Pack IPC input data */ +static int ipc_thread_flatten(unsigned int cmd, const union scheduler_dp_thread_ipc_param *param, + struct ipc4_flat *flat) +{ + flat->cmd = cmd; + + /* + * FIXME: SOF_IPC4_MOD_* and SOF_IPC4_GLB_* aren't fully orthogonal, but + * so far none of the used ones overlap + */ + switch (cmd) { + case SOF_IPC4_MOD_BIND: + case SOF_IPC4_MOD_UNBIND: + flat->bind.bu = *param->bind_data->ipc4_data; + flat->bind.type = param->bind_data->bind_type; + break; + case SOF_IPC4_GLB_SET_PIPELINE_STATE: + flat->pipeline_state.trigger_cmd = param->pipeline_state.trigger_cmd; + switch (param->pipeline_state.trigger_cmd) { + case COMP_TRIGGER_STOP: + break; + case COMP_TRIGGER_PREPARE: + if (param->pipeline_state.n_sources > CONFIG_MODULE_MAX_CONNECTIONS || + param->pipeline_state.n_sinks > CONFIG_MODULE_MAX_CONNECTIONS) + return -ENOMEM; + + flat->pipeline_state.state = param->pipeline_state.state; + flat->pipeline_state.n_sources = param->pipeline_state.n_sources; + flat->pipeline_state.n_sinks = param->pipeline_state.n_sinks; + /* Up to 2 * CONFIG_MODULE_MAX_CONNECTIONS */ + memcpy(flat->pipeline_state.source, param->pipeline_state.sources, + flat->pipeline_state.n_sources * + sizeof(flat->pipeline_state.source[0])); + memcpy(flat->pipeline_state.sink, param->pipeline_state.sinks, + flat->pipeline_state.n_sinks * + sizeof(flat->pipeline_state.sink[0])); + } + } + + return 0; +} + +/* Unpack IPC data and execute a callback */ +static void ipc_thread_unflatten_run(struct processing_module *pmod, struct ipc4_flat *flat) +{ + const struct module_interface *const ops = pmod->dev->drv->adapter_ops; + + switch (flat->cmd) { + case SOF_IPC4_MOD_BIND: + if (ops->bind) { + struct bind_info bind_data = { + .ipc4_data = &flat->bind.bu, + .bind_type = flat->bind.type, + }; + + flat->ret = ops->bind(pmod, &bind_data); + } else { + flat->ret = 0; + } + break; + case SOF_IPC4_MOD_UNBIND: + if (ops->unbind) { + struct bind_info bind_data = { + .ipc4_data = &flat->bind.bu, + .bind_type = flat->bind.type, + }; + + flat->ret = ops->unbind(pmod, &bind_data); + } else { + flat->ret = 0; + } + break; + case SOF_IPC4_MOD_DELETE_INSTANCE: + flat->ret = ops->free(pmod); + break; + case SOF_IPC4_MOD_INIT_INSTANCE: + flat->ret = ops->init(pmod); + break; + case SOF_IPC4_GLB_SET_PIPELINE_STATE: + switch (flat->pipeline_state.trigger_cmd) { + case COMP_TRIGGER_STOP: + flat->ret = ops->reset(pmod); + break; + case COMP_TRIGGER_PREPARE: + flat->ret = ops->prepare(pmod, + flat->pipeline_state.source, + flat->pipeline_state.n_sources, + flat->pipeline_state.sink, + flat->pipeline_state.n_sinks); + } + } +} + +#define DP_THREAD_IPC_TIMEOUT K_MSEC(100) + +/* Signal an IPC and wait for processing completion */ +int scheduler_dp_thread_ipc(struct processing_module *pmod, unsigned int cmd, + const union scheduler_dp_thread_ipc_param *param) +{ + struct task_dp_pdata *pdata = pmod->dev->task->priv_data; + int ret; + + if (!pmod) { + tr_err(&dp_tr, "no thread module"); + return -EINVAL; + } + + if (cmd == SOF_IPC4_MOD_INIT_INSTANCE) { + /* Wait for the DP thread to start */ + ret = k_sem_take(&dp_sync[pmod->dev->task->core], DP_THREAD_IPC_TIMEOUT); + if (ret < 0) { + tr_err(&dp_tr, "Failed waiting for DP thread to start: %d", ret); + return ret; + } + } + + unsigned int lock_key = scheduler_dp_lock(pmod->dev->task->core); + + /* IPCs are serialised */ + pdata->flat->ret = -ENOSYS; + + ret = ipc_thread_flatten(cmd, param, pdata->flat); + if (!ret) + k_event_post(pdata->event, DP_TASK_EVENT_IPC); + + scheduler_dp_unlock(lock_key); + + if (!ret) { + /* Wait for completion */ + ret = k_sem_take(&dp_sync[cpu_get_id()], DP_THREAD_IPC_TIMEOUT); + if (ret < 0) + tr_err(&dp_tr, "Failed waiting for DP thread: %d", ret); + else + ret = pdata->flat->ret; + } + + return ret; +} + +/* Go through all DP tasks and recalculate their readiness and deadlines + * NOT REENTRANT, called with scheduler_dp_lock() held + */ +void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch, bool is_ll_post_run) +{ + struct list_item *tlist; + struct task *curr_task; + struct task_dp_pdata *pdata; + + list_for_item(tlist, &dp_sch->tasks) { + curr_task = container_of(tlist, struct task, list); + pdata = curr_task->priv_data; + struct processing_module *mod = pdata->mod; + bool trigger_task = false; + + /* decrease number of LL ticks/cycles left till the module reaches its deadline */ + if (mod->dp_startup_delay && is_ll_post_run && pdata->ll_cycles_to_start) { + pdata->ll_cycles_to_start--; + if (!pdata->ll_cycles_to_start) + /* delayed start complete, clear startup delay flag. + * see dp_startup_delay comment for details + */ + mod->dp_startup_delay = false; + } + + if (curr_task->state == SOF_TASK_STATE_QUEUED && + mod->dev->state >= COMP_STATE_ACTIVE) { + /* trigger the task */ + curr_task->state = SOF_TASK_STATE_RUNNING; + trigger_task = true; + k_event_post(pdata->event, DP_TASK_EVENT_PROCESS); + } + + if (curr_task->state == SOF_TASK_STATE_RUNNING) { + /* (re) calculate deadline for all running tasks */ + /* get module deadline in us */ + uint32_t deadline = module_get_deadline(mod); + + /* if a deadline cannot be calculated, use a fixed value relative to its + * first start + */ + if (deadline >= UINT32_MAX / 2 && trigger_task) + deadline = module_get_lpt(mod); + + if (deadline < UINT32_MAX) { + /* round down to 1ms */ + deadline = deadline / 1000; + + /* calculate number of ticks */ + deadline = deadline * (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000); + + /* add to "NOW", overflows are OK */ + deadline = dp_sch->last_ll_tick_timestamp + deadline; + + /* set in Zephyr. Note that it may be in past, it does not matter, + * Zephyr still will schedule the thread with earlier deadline + * first + */ + k_thread_absolute_deadline_set(pdata->thread_id, deadline); + } + } + } +} + +/* Thread function called in component context, on target core */ +void dp_thread_fn(void *p1, void *p2, void *p3) +{ + struct task *task = p1; + struct task_dp_pdata *task_pdata = task->priv_data; + struct processing_module *pmod = task_pdata->mod; + unsigned int lock_key; + enum task_state state; + bool task_stop; + + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + /* The IPC thread is waiting for the thread to be started, it can proceed now. */ + k_sem_give(&dp_sync[task->core]); + comp_info(pmod->dev, "userspace thread started"); + + do { + uint32_t mask = k_event_wait_safe(task_pdata->event, + DP_TASK_EVENT_PROCESS | DP_TASK_EVENT_CANCEL | + DP_TASK_EVENT_IPC, false, K_FOREVER); + + if (mask & DP_TASK_EVENT_IPC) { + /* handle IPC */ + tr_dbg(&dp_tr, "got IPC wake up for %p state %d", pmod, task->state); + ipc_thread_unflatten_run(pmod, task_pdata->flat); + k_sem_give(&dp_sync[task->core]); + } + + if (mask & DP_TASK_EVENT_PROCESS) { + bool ready; + + if (task->state == SOF_TASK_STATE_RUNNING) { + ready = module_is_ready_to_process(pmod, pmod->sources, + pmod->num_of_sources, + pmod->sinks, pmod->num_of_sinks); + } else { + state = task->state; /* to avoid undefined variable warning */ + ready = false; + } + + if (ready) { + if (pmod->dp_startup_delay && !task_pdata->ll_cycles_to_start) { + /* first time run - use delayed start */ + task_pdata->ll_cycles_to_start = + module_get_lpt(pmod) / LL_TIMER_PERIOD_US; + + /* in case LPT < LL cycle - delay at least cycle */ + if (!task_pdata->ll_cycles_to_start) + task_pdata->ll_cycles_to_start = 1; + } + + state = task_run(task); + } + + lock_key = scheduler_dp_lock(task->core); + /* + * check if task is still running, may have been canceled by external call + * if not, set the state returned by run procedure + */ + if (ready && task->state == SOF_TASK_STATE_RUNNING) { + task->state = state; + switch (state) { + case SOF_TASK_STATE_RESCHEDULE: + /* mark to reschedule, schedule time is already calculated */ + task->state = SOF_TASK_STATE_QUEUED; + break; + + case SOF_TASK_STATE_CANCEL: + case SOF_TASK_STATE_COMPLETED: + /* task already removed from scheduling */ + break; + + default: + /* illegal state, serious defect, won't happen */ + k_oops(); + } + } else { + task->state = SOF_TASK_STATE_QUEUED; + } + } else { + lock_key = scheduler_dp_lock(task->core); + } + + /* if true exit the while loop, terminate the thread */ + task_stop = task->state == SOF_TASK_STATE_COMPLETED || + task->state == SOF_TASK_STATE_CANCEL; + + scheduler_dp_unlock(lock_key); + } while (!task_stop); + + /* call task_complete */ + if (task->state == SOF_TASK_STATE_COMPLETED) + task_complete(task); +} + +/* + * Safe to call with partial successful initialisation, + * k_mem_domain_remove_partition() then just returns -ENOENT + */ +static void scheduler_dp_domain_free(struct task_dp_pdata *pdata) +{ + struct processing_module *pmod = pdata->mod; + struct k_mem_domain *mdom = pmod->mdom; + + llext_manager_rm_domain(pmod->dev->ipc_config.id, mdom); + + k_mem_domain_remove_partition(mdom, pdata->mpart + SOF_DP_PART_HEAP); + k_mem_domain_remove_partition(mdom, pdata->mpart + SOF_DP_PART_HEAP_CACHE); + k_mem_domain_remove_partition(mdom, pdata->mpart + SOF_DP_PART_CFG); + k_mem_domain_remove_partition(mdom, pdata->mpart + SOF_DP_PART_CFG_CACHE); + + if (mdom->num_partitions) { + /* Violation: all partitions should be freed by now */ + unsigned int n = mdom->num_partitions; + + LOG_WRN("%u domain partition(s) not freed, force-freeing them all", n); + + for (unsigned int i = 0; i < arch_mem_domain_max_partitions_get() && n; i++) { + struct k_mem_partition *dpart = &mdom->partitions[i]; + + if (dpart->size) { + k_mem_domain_remove_partition(mdom, dpart); + n--; + } + } + } + + /* All partitions removed, the domain can be freed now */ + pmod->mdom = NULL; + k_mem_domain_deinit(mdom); + objpool_free(&dp_mdom_head, mdom); +} + +/* memory allocation helper structure */ +struct scheduler_dp_task_memory { + struct task task; + struct task_dp_pdata pdata; + struct comp_driver drv; + struct ipc4_flat flat; +}; + +void scheduler_dp_internal_free(struct task *task) +{ + struct task_dp_pdata *pdata = task->priv_data; + + k_object_free(pdata->event); + k_object_free(pdata->thread); + scheduler_dp_domain_free(pdata); + + mod_free(pdata->mod, container_of(task, struct scheduler_dp_task_memory, task)); +} + +#ifdef CONFIG_THREAD_NAME +static void scheduler_dp_thread_name_set(k_tid_t thread_id, struct processing_module *mod) +{ + char name[CONFIG_THREAD_MAX_NAME_LEN]; + + snprintf(name, sizeof(name), "DP:%#x", mod->dev->ipc_config.id); + + k_thread_name_set(thread_id, name); +} +#else +/* k_thread_name_set() is a no-op so skip constructing a thread name */ +#define scheduler_dp_thread_name_set(x, y) +#endif + +/* Called only in IPC context */ +int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid, + const struct task_ops *ops, struct processing_module *mod, + uint16_t core, size_t stack_size, uint32_t options) +{ + k_thread_stack_t *p_stack; + struct scheduler_dp_task_memory *task_memory; + + int ret; + + /* must be called on the same core the task will be bound to */ + assert(cpu_get_id() == core); + + /* + * allocate memory + * to avoid multiple malloc operations allocate all required memory as a single structure + * and return pointer to task_memory->task + * As the structure contains zephyr kernel specific data, it must be located in + * shared, non cached memory + */ + task_memory = mod_alloc_ext(mod, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*task_memory), 0); + if (!task_memory) { + tr_err(&dp_tr, "memory alloc failed"); + return -ENOMEM; + } + + memset(task_memory, 0, sizeof(*task_memory)); + + task_memory->drv = *mod->dev->drv; + mod->dev->drv = &task_memory->drv; + + /* allocate stack - must be aligned and cached so a separate alloc */ + p_stack = user_stack_allocate(stack_size, options); + if (!p_stack) { + tr_err(&dp_tr, "stack alloc failed"); + ret = -ENOMEM; + goto e_tmem; + } + + struct task *ptask = &task_memory->task; + + /* internal SOF task init */ + ret = schedule_task_init(ptask, uid, SOF_SCHEDULE_DP, 0, ops->run, mod, core, options); + if (ret < 0) { + tr_err(&dp_tr, "schedule_task_init failed"); + goto e_stack; + } + + struct task_dp_pdata *pdata = &task_memory->pdata; + + pdata->flat = &task_memory->flat; + + pdata->event = k_object_alloc(K_OBJ_EVENT); + if (!pdata->event) { + tr_err(&dp_tr, "Event object allocation failed"); + ret = -ENOMEM; + goto e_stack; + } + + pdata->thread = k_object_alloc(K_OBJ_THREAD); + if (!pdata->thread) { + tr_err(&dp_tr, "Thread object allocation failed"); + ret = -ENOMEM; + goto e_kobj; + } + memset(&pdata->thread->arch, 0, sizeof(pdata->thread->arch)); + + /* success, fill the structures */ + pdata->p_stack = p_stack; + pdata->mod = mod; + + /* initialize other task structures */ + ptask->ops.complete = ops->complete; + ptask->ops.get_deadline = ops->get_deadline; + ptask->priv_data = pdata; + list_init(&ptask->list); + *task = ptask; + + /* create a zephyr thread for the task */ + pdata->thread_id = k_thread_create(pdata->thread, p_stack, + stack_size, dp_thread_fn, ptask, NULL, NULL, + CONFIG_DP_THREAD_PRIORITY, ptask->flags, K_FOREVER); + scheduler_dp_thread_name_set(pdata->thread_id, mod); + + unsigned int pidx; + size_t size; + uintptr_t start; + bool on_pool = false; + +#ifdef CONFIG_SCHED_CPU_MASK + /* pin the thread to specific core */ + ret = k_thread_cpu_pin(pdata->thread_id, core); + if (ret < 0) { + tr_err(&dp_tr, "zephyr task pin to core failed"); + goto e_thread; + } +#endif + + k_thread_access_grant(pdata->thread_id, pdata->event, &dp_sync[core]); + scheduler_dp_grant(pdata->thread_id, core); + + struct k_mem_domain *mdom = objpool_alloc(&dp_mdom_head, sizeof(*mdom), + SOF_MEM_FLAG_COHERENT); + + if (!mdom) { + tr_err(&dp_tr, "objpool allocation failed"); + ret = -ENOMEM; + goto e_thread; + } + + on_pool = true; + + mod->mdom = mdom; + + if (!mdom->arch.ptables) { + ret = k_mem_domain_init(mdom, 0, NULL); + if (ret < 0) + goto e_thread; + } + + /* Module heap partition */ + mod_heap_info(mod, &size, &start); + pdata->mpart[SOF_DP_PART_HEAP] = (struct k_mem_partition){ + .start = (uintptr_t)sys_cache_uncached_ptr_get((void *)start), + .size = size, + .attr = K_MEM_PARTITION_P_RW_U_RW, + }; + pdata->mpart[SOF_DP_PART_HEAP_CACHE] = (struct k_mem_partition){ + .start = start, + .size = size, + .attr = K_MEM_PARTITION_P_RW_U_RW | XTENSA_MMU_CACHED_WB, + }; + /* Host mailbox partition for additional IPC parameters: read-only */ + pdata->mpart[SOF_DP_PART_CFG] = (struct k_mem_partition){ + .start = (uintptr_t)sys_cache_uncached_ptr_get((void *)MAILBOX_HOSTBOX_BASE), + .size = 4096, + .attr = K_MEM_PARTITION_P_RO_U_RO, + }; + pdata->mpart[SOF_DP_PART_CFG_CACHE] = (struct k_mem_partition){ + .start = (uintptr_t)MAILBOX_HOSTBOX_BASE, + .size = 4096, + .attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB, + }; + + for (pidx = 0; pidx < SOF_DP_PART_TYPE_COUNT; pidx++) { + ret = k_mem_domain_add_partition(mdom, pdata->mpart + pidx); + if (ret < 0) + goto e_dom; + } + + ret = llext_manager_add_domain(mod->dev->ipc_config.id, mdom); + if (ret < 0) { + tr_err(&dp_tr, "failed to add LLEXT to domain %d", ret); + goto e_dom; + } + + /* + * Keep this call last, able to fail, otherwise domain will be removed + * before its thread + */ + ret = k_mem_domain_add_thread(mdom, pdata->thread_id); + if (ret < 0) { + tr_err(&dp_tr, "failed to add thread to domain %d", ret); + goto e_dom; + } + + /* start the thread, it should immediately stop at the semaphore */ + k_event_init(pdata->event); + k_thread_start(pdata->thread_id); + + return 0; + +e_dom: + scheduler_dp_domain_free(pdata); + on_pool = false; +e_thread: + if (on_pool) + objpool_free(&dp_mdom_head, mdom); + k_thread_abort(pdata->thread_id); +e_kobj: + /* k_object_free looks for a pointer in the list, any invalid value can be passed */ + k_object_free(pdata->thread); + k_object_free(pdata->event); +e_stack: + user_stack_free(p_stack); +e_tmem: + mod_free(mod, task_memory); + return ret; +} diff --git a/src/schedule/zephyr_dp_schedule_thread.c b/src/schedule/zephyr_dp_schedule_thread.c new file mode 100644 index 000000000000..7fbb3b6a5c21 --- /dev/null +++ b/src/schedule/zephyr_dp_schedule_thread.c @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + * Author: Marcin Szkudlinski + * Adrian Warecki + */ + +#include <rtos/task.h> + +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/module_adapter/library/userspace_proxy.h> +#include <sof/audio/module_adapter/library/userspace_proxy_user.h> +#include <sof/common.h> +#include <sof/list.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <sof/schedule/dp_schedule.h> +#include <sof/trace/trace.h> + +#include <zephyr/kernel.h> + +#include <stdbool.h> +#include <stdint.h> + +#include "zephyr_dp_schedule.h" + +LOG_MODULE_DECLARE(dp_schedule, CONFIG_SOF_LOG_LEVEL); +extern struct tr_ctx dp_tr; + +/* Go through all DP tasks and recalculate their readiness and deadlines + * NOT REENTRANT, should be called with scheduler_dp_lock() + */ +void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch, bool is_ll_post_run) +{ + struct list_item *tlist; + struct task *curr_task; + struct task_dp_pdata *pdata; + + list_for_item(tlist, &dp_sch->tasks) { + curr_task = container_of(tlist, struct task, list); + pdata = curr_task->priv_data; + struct processing_module *mod = pdata->mod; + bool trigger_task = false; + + /* decrease number of LL ticks/cycles left till the module reaches its deadline */ + if (mod->dp_startup_delay && is_ll_post_run && pdata->ll_cycles_to_start) { + pdata->ll_cycles_to_start--; + if (!pdata->ll_cycles_to_start) + /* delayed start complete, clear startup delay flag. + * see dp_startup_delay comment for details + */ + mod->dp_startup_delay = false; + } + + if (curr_task->state == SOF_TASK_STATE_QUEUED) { + 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) { + /* trigger the task */ + curr_task->state = SOF_TASK_STATE_RUNNING; + if (mod->dp_startup_delay && !pdata->ll_cycles_to_start) { + /* first time run - use delayed start */ + pdata->ll_cycles_to_start = + module_get_lpt(pdata->mod) / LL_TIMER_PERIOD_US; + + /* in case LPT < LL cycle - delay at least cycle */ + if (!pdata->ll_cycles_to_start) + pdata->ll_cycles_to_start = 1; + } + trigger_task = true; + k_event_post(pdata->event, DP_TASK_EVENT_PROCESS); + } + } + if (curr_task->state == SOF_TASK_STATE_RUNNING) { + /* (re) calculate deadline for all running tasks */ + /* get module deadline in us*/ + uint32_t deadline = module_get_deadline(mod); + + /* if a deadline cannot be calculated, use a fixed value relative to its + * first start + */ + if (deadline >= UINT32_MAX / 2 && trigger_task) + deadline = module_get_lpt(mod); + + if (deadline < UINT32_MAX) { + /* round down to 1ms */ + deadline = deadline / 1000; + + /* calculate number of ticks */ + deadline = deadline * (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000); + + /* add to "NOW", overflows are OK */ + deadline = dp_sch->last_ll_tick_timestamp + deadline; + + /* set in Zephyr. Note that it may be in past, it does not matter, + * Zephyr still will schedule the thread with earlier deadline + * first + */ + k_thread_absolute_deadline_set(pdata->thread_id, deadline); + } + } + } +} + +/* Thread function called in component context, on target core */ +void dp_thread_fn(void *p1, void *p2, void *p3) +{ + struct task *task = p1; + (void)p2; + (void)p3; + struct task_dp_pdata *task_pdata = task->priv_data; + struct scheduler_dp_data *dp_sch = NULL; + unsigned int lock_key; + enum task_state state; + bool task_stop = false; + uint32_t event; + + if (!(task->flags & K_USER)) + dp_sch = scheduler_get_data(SOF_SCHEDULE_DP); + + do { + /* + * the thread is started immediately after creation, it will stop on event. + * Event will be signalled once the task is ready to process. + */ + event = k_event_wait_safe(task_pdata->event, DP_TASK_EVENT_PROCESS | + DP_TASK_EVENT_CANCEL | DP_TASK_EVENT_IPC, false, + K_FOREVER); + +#if IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) + if (event & DP_TASK_EVENT_IPC) { + assert(task_pdata->ipc_work_item); + userspace_proxy_worker_handler(task_pdata->ipc_work_item); + } +#endif + + if (event & DP_TASK_EVENT_PROCESS) { + state = task->state; /* to avoid undefined variable warning */ + if (task->state == SOF_TASK_STATE_RUNNING && event & DP_TASK_EVENT_PROCESS) + state = task_run(task); + + lock_key = scheduler_dp_lock(task->core); + /* + * check if task is still running, may have been canceled by external call + * if not, set the state returned by run procedure + */ + if (task->state == SOF_TASK_STATE_RUNNING) { + task->state = state; + switch (state) { + case SOF_TASK_STATE_RESCHEDULE: + /* mark to reschedule, schedule time is already calculated + */ + task->state = SOF_TASK_STATE_QUEUED; + break; + + case SOF_TASK_STATE_CANCEL: + case SOF_TASK_STATE_COMPLETED: + /* remove from scheduling */ + list_item_del(&task->list); + break; + + default: + /* illegal state, serious defect, won't happen */ + k_panic(); + } + } + + /* if true exit the while loop, terminate the thread */ + task_stop = task->state == SOF_TASK_STATE_COMPLETED || + task->state == SOF_TASK_STATE_CANCEL; + /* recalculate all DP tasks readiness and deadlines + * TODO: it should be for all tasks, for all cores + * currently its limited to current core only + */ + if (dp_sch) + scheduler_dp_recalculate(dp_sch, false); + + scheduler_dp_unlock(lock_key); + } + + if (event & DP_TASK_EVENT_CANCEL) + task_stop = true; + } while (!task_stop); + + /* call task_complete */ + if (task->state == SOF_TASK_STATE_COMPLETED) + task_complete(task); +} + +int scheduler_dp_task_init(struct task **task, + const struct sof_uuid_entry *uid, + const struct task_ops *ops, + struct processing_module *mod, + uint16_t core, + size_t stack_size, + uint32_t options) +{ + void __sparse_cache *p_stack = NULL; + struct k_heap *const user_heap = mod->dev->drv->user_heap; + + /* memory allocation helper structure */ + struct { + struct task task; /* keep first, used for freeing below */ + struct task_dp_pdata pdata; + } *task_memory; + + int ret; + + /* must be called on the same core the task will be binded to */ + assert(cpu_get_id() == core); + + /* + * allocate memory + * to avoid multiple malloc operations allocate all required memory as a single structure + * and return pointer to task_memory->task + * As the structure contains zephyr kernel specific data, it must be located in + * shared, non cached memory + */ + task_memory = sof_heap_alloc(user_heap, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*task_memory), 0); + if (!task_memory) { + tr_err(&dp_tr, "memory alloc failed"); + return -ENOMEM; + } + + memset(task_memory, 0, sizeof(*task_memory)); + /* allocate stack - must be aligned and cached so a separate alloc */ + p_stack = user_stack_allocate(stack_size, options); + if (!p_stack) { + tr_err(&dp_tr, "stack alloc failed"); + ret = -ENOMEM; + goto err; + } + + /* internal SOF task init */ + ret = schedule_task_init(&task_memory->task, uid, SOF_SCHEDULE_DP, 0, ops->run, + mod, core, options); + if (ret < 0) { + tr_err(&dp_tr, "schedule_task_init failed"); + goto err; + } + + struct task_dp_pdata *pdata = &task_memory->pdata; + + /* Point to event_struct event for kernel threads synchronization */ + /* It will be overwritten for K_USER threads to dynamic ones. */ + pdata->event = &pdata->event_struct; + pdata->thread = &pdata->thread_struct; + +#ifdef CONFIG_USERSPACE + if (options & K_USER) { + pdata->event = k_object_alloc(K_OBJ_EVENT); + if (!pdata->event) { + tr_err(&dp_tr, "Event object allocation failed"); + ret = -ENOMEM; + goto err; + } + + pdata->thread = k_object_alloc(K_OBJ_THREAD); + if (!pdata->thread) { + tr_err(&dp_tr, "Thread object allocation failed"); + ret = -ENOMEM; + goto err; + } + } +#endif /* CONFIG_USERSPACE */ + + /* initialize other task structures */ + task_memory->task.ops.complete = ops->complete; + task_memory->task.ops.get_deadline = ops->get_deadline; + task_memory->task.state = SOF_TASK_STATE_INIT; + task_memory->task.core = core; + task_memory->task.priv_data = pdata; + k_event_init(pdata->event); + + /* success, fill the structures */ + pdata->p_stack = p_stack; + pdata->mod = mod; + + /* create a zephyr thread for the task */ + pdata->thread_id = k_thread_create(pdata->thread, (__sparse_force void *)p_stack, + stack_size, dp_thread_fn, &task_memory->task, NULL, NULL, + CONFIG_DP_THREAD_PRIORITY, task_memory->task.flags, + K_FOREVER); + +#ifdef CONFIG_SCHED_CPU_MASK + /* pin the thread to specific core */ + ret = k_thread_cpu_pin(pdata->thread_id, core); + if (ret < 0) { + tr_err(&dp_tr, "zephyr task pin to core failed"); + goto e_thread; + } +#endif + +#ifdef CONFIG_USERSPACE + if (options & K_USER) { + k_thread_access_grant(pdata->thread_id, pdata->event); + scheduler_dp_grant(pdata->thread_id, core); + + ret = k_mem_domain_add_thread(pdata->mod->user_ctx->comp_dom, pdata->thread_id); + if (ret < 0) { + tr_err(&dp_tr, "k_mem_domain_add_thread() failed %d", ret); + goto e_thread; + } + +#if IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) + pdata->ipc_work_item = userspace_proxy_register_ipc_handler(mod, pdata->event); + assert(pdata->ipc_work_item); +#endif + } +#endif /* CONFIG_USERSPACE */ + + /* start the thread, it should immediately stop at an event */ + k_thread_start(pdata->thread_id); + + /* success, fill output parameter */ + *task = &task_memory->task; + return 0; + +e_thread: + k_thread_abort(pdata->thread_id); +err: + /* cleanup - free all allocated resources */ + if (user_stack_free((__sparse_force void *)p_stack)) + tr_err(&dp_tr, "user_stack_free failed!"); + + /* k_object_free looks for a pointer in the list, any invalid value can be passed */ + k_object_free(task_memory->pdata.event); + k_object_free(task_memory->pdata.thread); + sof_heap_free(user_heap, task_memory); + return ret; +} + +void scheduler_dp_internal_free(struct task *task) +{ + struct task_dp_pdata *pdata = task->priv_data; + +#ifdef CONFIG_USERSPACE + if (pdata->event != &pdata->event_struct) + k_object_free(pdata->event); + if (pdata->thread != &pdata->thread_struct) + k_object_free(pdata->thread); +#endif + + /* task is the first member in task_memory above */ + sof_heap_free(pdata->mod->dev->drv->user_heap, task); +} diff --git a/src/schedule/zephyr_ll.c b/src/schedule/zephyr_ll.c index e455421ef040..79b85118b5d3 100644 --- a/src/schedule/zephyr_ll.c +++ b/src/schedule/zephyr_ll.c @@ -9,6 +9,7 @@ #include <rtos/symbol.h> #include <sof/audio/component.h> #include <rtos/interrupt.h> +#include <sof/lib/memory.h> #include <sof/lib/notifier.h> #include <sof/schedule/ll_schedule_domain.h> #include <sof/schedule/schedule.h> @@ -30,6 +31,10 @@ struct zephyr_ll { unsigned int n_tasks; /* task counter */ struct ll_schedule_domain *ll_domain; /* scheduling domain */ unsigned int core; /* core ID of this instance */ +#if CONFIG_SOF_USERSPACE_LL + struct k_mutex *lock; /* mutex for userspace */ +#endif + struct k_heap *heap; }; /* per-task scheduler data */ @@ -39,19 +44,76 @@ struct zephyr_ll_pdata { struct k_sem sem; }; +#if CONFIG_SOF_USERSPACE_LL +/* + * Mutex pointer in user-accessible partition so user-space threads + * can read the pointer for syscalls. The actual lock object resides + * in kernel memory, there are just handles! + */ +static APP_SYSUSER_BSS struct k_mutex *zephyr_ll_locks[CONFIG_CORE_COUNT]; + +/* + * Shadow ownership tracking for the per-core LL mutex, used only to + * power user_ll_assert_locked(). The kernel k_mutex object is not + * readable from user-space threads, so its owner cannot be inspected + * directly; instead record the owner and recursion depth here, in a + * user-accessible partition. Updated on every lock/unlock of the LL + * mutex, by both the LL thread (zephyr_ll_lock()) and IPC handlers + * (user_ll_lock_sched()). Only ever mutated by the current lock holder + * while the lock is held, so no extra synchronization is required. + */ +#ifdef CONFIG_ASSERT +static APP_SYSUSER_BSS k_tid_t zephyr_ll_lock_owner[CONFIG_CORE_COUNT]; +static APP_SYSUSER_BSS uint32_t zephyr_ll_lock_depth[CONFIG_CORE_COUNT]; + +static inline void zephyr_ll_lock_acquired(int core) +{ + zephyr_ll_lock_owner[core] = k_current_get(); + zephyr_ll_lock_depth[core]++; +} + +static inline void zephyr_ll_lock_releasing(int core) +{ + assert(zephyr_ll_lock_owner[core] == k_current_get()); + if (--zephyr_ll_lock_depth[core] == 0) + zephyr_ll_lock_owner[core] = NULL; +} + +void user_ll_assert_locked(int core) +{ + assert(core < CONFIG_CORE_COUNT && + zephyr_ll_lock_owner[core] == k_current_get()); +} +#else +static inline void zephyr_ll_lock_acquired(int core) { (void)core; } +static inline void zephyr_ll_lock_releasing(int core) { (void)core; } +#endif /* CONFIG_ASSERT */ +#endif + static void zephyr_ll_lock(struct zephyr_ll *sch, uint32_t *flags) { +#if CONFIG_SOF_USERSPACE_LL + k_mutex_lock(sch->lock, K_FOREVER); + zephyr_ll_lock_acquired(sch->core); +#else irq_local_disable(*flags); +#endif } static void zephyr_ll_unlock(struct zephyr_ll *sch, uint32_t *flags) { +#if CONFIG_SOF_USERSPACE_LL + zephyr_ll_lock_releasing(sch->core); + k_mutex_unlock(sch->lock); +#else irq_local_enable(*flags); +#endif } static void zephyr_ll_assert_core(const struct zephyr_ll *sch) { - assert(CONFIG_CORE_COUNT == 1 || sch->core == cpu_get_id()); + assert(CONFIG_CORE_COUNT == 1 || IS_ENABLED(CONFIG_SOF_USERSPACE_LL) || + sch->core == cpu_get_id()); } /* Locking: caller should hold the domain lock */ @@ -176,6 +238,8 @@ static void zephyr_ll_run(void *data) struct list_item *list, *tmp, task_head = LIST_INIT(task_head); uint32_t flags; + tr_dbg(&ll_tr, "entry"); + zephyr_ll_lock(sch, &flags); /* @@ -206,7 +270,15 @@ static void zephyr_ll_run(void *data) list_item_del(list); list_item_append(list, &task_head); + /* in user-space LL builds, the LL lock protects LL + * tasks against IPC thread, so the lock must be held + * while running the tasks. + * in kernel LL builds, IPC thread blocks interrupts for + * critical section, so lock can be freed here. + */ +#ifndef CONFIG_SOF_USERSPACE_LL zephyr_ll_unlock(sch, &flags); +#endif /* * task's .run() should only return either @@ -216,12 +288,14 @@ static void zephyr_ll_run(void *data) if (state != SOF_TASK_STATE_COMPLETED && state != SOF_TASK_STATE_RESCHEDULE) { tr_err(&ll_tr, - "zephyr_ll_run: invalid return state %u", + "invalid return state %u", state); state = SOF_TASK_STATE_RESCHEDULE; } +#ifndef CONFIG_SOF_USERSPACE_LL zephyr_ll_lock(sch, &flags); +#endif if (pdata->freeing || state == SOF_TASK_STATE_COMPLETED) { zephyr_ll_task_done(sch, task); @@ -248,8 +322,11 @@ static void zephyr_ll_run(void *data) zephyr_ll_unlock(sch, &flags); +#ifndef CONFIG_SOF_USERSPACE_LL + /* TODO: to be replaced with direct function calls */ notifier_event(sch, NOTIFIER_ID_LL_POST_RUN, NOTIFIER_TARGET_CORE_LOCAL, NULL, 0); +#endif } static void schedule_ll_callback(void *data) @@ -342,8 +419,7 @@ static int zephyr_ll_task_schedule_common(struct zephyr_ll *sch, struct task *ta ret = domain_register(sch->ll_domain, task, &schedule_ll_callback, sch); if (ret < 0) - tr_err(&ll_tr, "zephyr_ll_task_schedule: cannot register domain %d", - ret); + tr_err(&ll_tr, "cannot register domain %d", ret); return 0; } @@ -385,11 +461,12 @@ static int zephyr_ll_task_free(void *data, struct task *task) zephyr_ll_assert_core(sch); +#ifndef CONFIG_SOF_USERSPACE_LL if (k_is_in_isr()) { - tr_err(&ll_tr, - "zephyr_ll_task_free: cannot free tasks from interrupt context!"); + tr_err(&ll_tr, "cannot free tasks from interrupt context!"); return -EDEADLK; } +#endif zephyr_ll_lock(sch, &flags); @@ -433,7 +510,7 @@ static int zephyr_ll_task_free(void *data, struct task *task) /* Protect against racing with schedule_task() */ zephyr_ll_lock(sch, &flags); task->priv_data = NULL; - rfree(pdata); + sof_heap_free(sch->heap, pdata); zephyr_ll_unlock(sch, &flags); return 0; @@ -481,9 +558,42 @@ static void zephyr_ll_scheduler_free(void *data, uint32_t flags) zephyr_ll_assert_core(sch); if (sch->n_tasks) - tr_err(&ll_tr, "zephyr_ll_scheduler_free: %u tasks are still active!", + tr_err(&ll_tr, "%u tasks are still active!", sch->n_tasks); + +#if CONFIG_SOF_USERSPACE_LL + domain_thread_free(sch->ll_domain, sch->n_tasks); +#endif +} + +#if CONFIG_SOF_USERSPACE_LL +struct k_thread *zephyr_ll_init_context(void *data, struct task *task) +{ + struct zephyr_ll *sch = data; + int ret; + + /* + * Use domain_thread_init() for privileged setup (thread creation, + * timer, access grants). domain_register() is now bookkeeping only + * and will be called later from user context when scheduling tasks. + */ + ret = domain_thread_init(sch->ll_domain, task); + if (ret < 0) { + tr_err(&ll_tr, "cannot init_context %d", ret); + return NULL; + } + + assert(!k_is_user_context()); + k_thread_access_grant(zephyr_domain_thread_tid(sch->ll_domain), sch->lock); + + tr_dbg(&ll_tr, "granting access to lock %p for thread %p", sch->lock, + zephyr_domain_thread_tid(sch->ll_domain)); + tr_dbg(&ll_tr, "granting access to domain lock %p for thread %p", &sch->ll_domain->lock, + zephyr_domain_thread_tid(sch->ll_domain)); + + return zephyr_domain_thread_tid(sch->ll_domain); } +#endif static const struct scheduler_ops zephyr_ll_ops = { .schedule_task = zephyr_ll_task_schedule, @@ -492,31 +602,90 @@ static const struct scheduler_ops zephyr_ll_ops = { .schedule_task_free = zephyr_ll_task_free, .schedule_task_cancel = zephyr_ll_task_cancel, .scheduler_free = zephyr_ll_scheduler_free, +#if CONFIG_SOF_USERSPACE_LL + .scheduler_init_context = zephyr_ll_init_context, +#endif }; +#if CONFIG_SOF_USERSPACE_LL +struct task *zephyr_ll_task_alloc(void) +{ + struct task *task = sof_heap_alloc(zephyr_ll_user_heap(), SOF_MEM_FLAG_USER, + sizeof(*task), sizeof(void *)); + + if (task) + /* At least .priv_data must be NULL for zephyr_ll_task_init() */ + memset(task, 0, sizeof(*task)); + + return task; +} + +/** + * Lock the LL scheduler to prevent it from processing tasks. + * + * Uses the LL scheduler's own k_mutex which is re-entrant, so + * schedule_task() calls within the locked section will not deadlock. + * Must be paired with user_ll_unlock_sched(). + */ +void user_ll_lock_sched(int core) +{ + assert(core >= 0 && core < CONFIG_CORE_COUNT && zephyr_ll_locks[core] != NULL); + int __maybe_unused ret = k_mutex_lock(zephyr_ll_locks[core], K_FOREVER); + assert(!ret); + zephyr_ll_lock_acquired(core); +} + +/** + * Unlock the LL scheduler after a previous user_ll_lock_sched() call. + */ +void user_ll_unlock_sched(int core) +{ + assert(core >= 0 && core < CONFIG_CORE_COUNT && zephyr_ll_locks[core] != NULL); + zephyr_ll_lock_releasing(core); + int __maybe_unused ret = k_mutex_unlock(zephyr_ll_locks[core]); + assert(!ret); +} + +#endif /* CONFIG_SOF_USERSPACE_LL */ + int zephyr_ll_task_init(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, uint16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags) { struct zephyr_ll_pdata *pdata; + struct k_heap *heap = sof_sys_heap_get(); + int alloc_flags = SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT; int ret; + tr_dbg(&ll_tr, "ll-scheduler task %p init", data); + if (task->priv_data) return -EEXIST; + /* + * schedule_task_init() must be run on target core, see + * sof/zephyr/schedule.c:arch_schedulers_get() + */ + assert(cpu_get_id() == core); + ret = schedule_task_init(task, uid, type, priority, run, data, core, flags); if (ret < 0) return ret; - pdata = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, - sizeof(*pdata)); +#if CONFIG_SOF_USERSPACE_LL + heap = zephyr_ll_user_heap(); + alloc_flags = SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT; +#endif + pdata = sof_heap_alloc(heap, alloc_flags, sizeof(*pdata), 0); if (!pdata) { - tr_err(&ll_tr, "zephyr_ll_task_init(): alloc failed"); + tr_err(&ll_tr, "alloc failed"); return -ENOMEM; } + memset(pdata, 0, sizeof(*pdata)); + k_sem_init(&pdata->sem, 0, 1); task->priv_data = pdata; @@ -527,16 +696,50 @@ EXPORT_SYMBOL(zephyr_ll_task_init); /* TODO: low-power mode clock support */ /* Runs on each core during initialisation with the same domain argument */ -int zephyr_ll_scheduler_init(struct ll_schedule_domain *domain) +__cold int zephyr_ll_scheduler_init(struct ll_schedule_domain *domain) { struct zephyr_ll *sch; + int core = cpu_get_id(); + struct k_heap *heap = sof_sys_heap_get(); + int flags = SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT; + + assert_can_be_cold(); + +#if CONFIG_SOF_USERSPACE_LL + heap = zephyr_ll_user_heap(); + flags = SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT; +#endif + tr_dbg(&ll_tr, "init on core %d", core); /* initialize per-core scheduler private data */ - sch = rmalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, sizeof(*sch)); + sch = sof_heap_alloc(heap, flags, sizeof(*sch), 0); + if (!sch) { + tr_err(&ll_tr, "allocation failed"); + return -ENOMEM; + } + + memset(sch, 0, sizeof(*sch)); + list_init(&sch->tasks); sch->ll_domain = domain; - sch->core = cpu_get_id(); + sch->core = core; sch->n_tasks = 0; + sch->heap = heap; + +#if CONFIG_SOF_USERSPACE_LL + /* Allocate mutex dynamically for userspace access */ + sch->lock = k_object_alloc(K_OBJ_MUTEX); + if (!sch->lock) { + tr_err(&ll_tr, "mutex allocation failed"); + sof_heap_free(sch->heap, sch); + return -ENOMEM; + } + assert(core < CONFIG_CORE_COUNT && zephyr_ll_locks[core] == NULL); + zephyr_ll_locks[core] = sch->lock; + k_mutex_init(sch->lock); + + tr_dbg(&ll_tr, "ll-scheduler init done, sch %p sch->lock %p", sch, sch->lock); +#endif scheduler_init(domain->type, &zephyr_ll_ops, sch); @@ -555,3 +758,11 @@ void scheduler_get_task_info_ll(struct scheduler_props *scheduler_props, scheduler_get_task_info(scheduler_props, data_off_size, &ll_sch->tasks); zephyr_ll_unlock(ll_sch, &flags); } + +/* Return a pointer to the LL scheduler timer domain */ +struct ll_schedule_domain *zephyr_ll_domain(void) +{ + struct zephyr_ll *ll_sch = scheduler_get_data(SOF_SCHEDULE_LL_TIMER); + + return ll_sch->ll_domain; +} diff --git a/src/schedule/zephyr_ll_user.c b/src/schedule/zephyr_ll_user.c new file mode 100644 index 000000000000..bad2f6c9cbb6 --- /dev/null +++ b/src/schedule/zephyr_ll_user.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include <zephyr/cache.h> +#include <zephyr/kernel.h> +#include <zephyr/logging/log.h> + +#include <rtos/userspace_helper.h> + +#include <sof/schedule/ll_schedule_domain.h> + +LOG_MODULE_DECLARE(ll_schedule, CONFIG_SOF_LOG_LEVEL); + +/** + * Memory resources for userspace LL scheduler + * + * This structure encapsulates the memory management resources required for the + * low-latency (LL) scheduler in userspace mode. It provides memory isolation + * and heap management for LL scheduler threads. Only kernel accessible. + */ +struct zephyr_ll_mem_resources { + struct k_mem_domain mem_domain; /**< Memory domain for LL thread isolation */ + struct k_heap heap; /**< Heap allocator for LL scheduler memory */ +}; + +static struct zephyr_ll_mem_resources ll_mem_resources; + +/** + * Heap allocator for LL scheduler memory (user accessible pointer) + * + * Note: this is also user-writable, so kernel must not rely on this to + * be correct and must always validate it separately. + */ +APP_SYSUSER_DATA static struct k_heap *zephyr_ll_heap; + +static struct k_heap *ll_heap_alloc(void) +{ + const size_t alloc_size = CONFIG_SOF_ZEPHYR_SYS_USER_HEAP_SIZE; + + BUILD_ASSERT(CONFIG_SOF_ZEPHYR_SYS_USER_HEAP_SIZE % CONFIG_MM_DRV_PAGE_SIZE == 0); + + void *mem = rballoc_align(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, alloc_size, + CONFIG_MM_DRV_PAGE_SIZE); + if (!mem) + return NULL; + + k_heap_init(&ll_mem_resources.heap, mem, alloc_size); + + /* + * k_heap_init() does not set these, so set the values + * manually here + */ + ll_mem_resources.heap.heap.init_mem = mem; + ll_mem_resources.heap.heap.init_bytes = alloc_size; + + return &ll_mem_resources.heap; +} + +static void ll_heap_init(void) +{ + struct k_heap *heap = ll_heap_alloc(); + struct k_mem_partition mem_partition; + int ret; + + if (!heap) { + tr_err(&ll_tr, "heap alloc fail"); + k_panic(); + } + + /* Create memory partition for sch_data array */ + mem_partition.start = (uintptr_t)sys_cache_cached_ptr_get(heap->heap.init_mem); + mem_partition.size = heap->heap.init_bytes; + mem_partition.attr = K_MEM_PARTITION_P_RW_U_RW | XTENSA_MMU_CACHED_WB; + + ret = k_mem_domain_add_partition(&ll_mem_resources.mem_domain, &mem_partition); + tr_dbg(&ll_tr, "init ll heap %p, size %u (cached), ret %d", + (void *)mem_partition.start, heap->heap.init_bytes, ret); + if (ret) + k_panic(); + +#ifdef CONFIG_CACHE_HAS_MIRRORED_MEMORY_REGIONS + mem_partition.start = (uintptr_t)sys_cache_uncached_ptr_get(heap->heap.init_mem); + mem_partition.attr = K_MEM_PARTITION_P_RW_U_RW; + ret = k_mem_domain_add_partition(&ll_mem_resources.mem_domain, &mem_partition); + tr_dbg(&ll_tr, "init ll heap %p, size %u (uncached), ret %d", + (void *)mem_partition.start, heap->heap.init_bytes, ret); + if (ret) + k_panic(); +#endif +} + +void zephyr_ll_user_resources_init(void) +{ + int ret; + + k_mem_domain_init(&ll_mem_resources.mem_domain, 0, NULL); + + ll_heap_init(); + + /* store a user-accessible pointer */ + zephyr_ll_heap = &ll_mem_resources.heap; + + /* attach common partition to LL domain */ + user_memory_attach_common_partition(zephyr_ll_mem_domain()); + + ret = user_memory_attach_system_user_partition(zephyr_ll_mem_domain()); + if (ret) + k_panic(); +} + +/** + * Check if 'heap' is a valid heap pointer. + * + * Available only in kernel mode. + * + * @return true if valid + */ +bool zephyr_ll_user_heap_verify(struct k_heap *heap) +{ + return heap == &ll_mem_resources.heap; +} + +/** + * Returns heap object to use in user-space LL code. + * + * Can be called from user-space. + * + * @return heap pointer that can be passed to sof_heap_alloc() + */ +struct k_heap *zephyr_ll_user_heap(void) +{ + return zephyr_ll_heap; +} + +/** + * Returns pointer to LL user-space memory domain. + * + * Available only in kernel mode. + * + * @return pointer to memory domain + */ +struct k_mem_domain *zephyr_ll_mem_domain(void) +{ + return &ll_mem_resources.mem_domain; +} diff --git a/src/schedule/zephyr_twb_schedule.c b/src/schedule/zephyr_twb_schedule.c new file mode 100644 index 000000000000..5e85cbf61134 --- /dev/null +++ b/src/schedule/zephyr_twb_schedule.c @@ -0,0 +1,504 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2024 Intel Corporation. All rights reserved. + * + * Author: Adrian Bonislawski <adrian.bonislawski@intel.com> + */ + +#include <rtos/task.h> +#include <stdint.h> +#include <sof/lib/memory.h> +#include <sof/lib/uuid.h> +#include <sof/schedule/schedule.h> +#include <sof/schedule/ll_schedule.h> +#include <sof/schedule/twb_schedule.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <sof/trace/trace.h> +#include <rtos/wait.h> +#include <rtos/interrupt.h> +#include <zephyr/init.h> +#include <zephyr/kernel.h> +#include <zephyr/kernel/thread.h> +#include <zephyr/sys_clock.h> + +LOG_MODULE_REGISTER(twb_schedule, CONFIG_SOF_LOG_LEVEL); +SOF_DEFINE_REG_UUID(twb_sched); + +DECLARE_TR_CTX(twb_tr, SOF_UUID(twb_sched_uuid), LOG_LEVEL_INFO); + +struct scheduler_twb_data { + struct list_item tasks; /* list of active TWB tasks */ + struct task ll_tick_src; /* LL task - source of TWB tick */ +}; + +struct task_twb_data { + k_tid_t thread_id; /* zephyr thread ID */ + k_thread_stack_t __sparse_cache *p_stack; /* pointer to thread stack */ + struct k_sem sem; /* thread semaphore */ + int32_t thread_prio; /* thread default priority */ + uint32_t cycles_granted; /* cycles budget for the task */ + uint32_t cycles_consumed; /* cycles consumed by the task */ + uint64_t cycles_ref; /* reference cycles for the task */ +}; + +/* Single CPU-wide lock + * as each per-core instance if TWB-scheduler has separate structures, it is enough to + * use irq_lock instead of cross-core spinlocks + */ +static inline unsigned int scheduler_twb_lock(void) +{ + return irq_lock(); +} + +static inline void scheduler_twb_unlock(unsigned int key) +{ + irq_unlock(key); +} + +/** + * @brief Callback function for the TWB scheduler task. + * + * This function is called when the TWB scheduler task runs out of budget. + * It lowers the priority of the thread and sets the time slice to 0. + * + * @param thread Pointer to the thread structure. + * @param data Pointer to additional data (not used). + */ +static void scheduler_twb_task_cb(struct k_thread *thread, void *data) +{ + tr_dbg(&twb_tr, "TWB task %p out of budget, lowering priority", data); + + k_thread_priority_set(thread, CONFIG_TWB_THREAD_LOW_PRIORITY); + k_thread_time_slice_set(thread, 0, &scheduler_twb_task_cb, data); +} + +/** + * @brief Executes the LL tick of the TWB scheduler. + * + * This function is responsible for executing the LL tick of the TWB scheduler. + * It iterates through the list of tasks and performs the necessary operations + * based on the task's state. + * If a task is in the QUEUED state, it is transitioned to the RUNNING state + * and its associated thread is resumed. + * If a task is in the RUNNING state, its thread's priority and time slice + * are set based on the task's budget. + * The function also retrieves the runtime statistics of the thread and + * updates the task's reference cycle count. + * If a task is in the CANCEL or COMPLETED state, it is removed from the list. + * + * @param data Pointer to the scheduler_twb_data structure. + * @return The state of the task after the LL tick execution. + * If no task requires further execution, SOF_TASK_STATE_COMPLETED is returned. + * Otherwise, SOF_TASK_STATE_RESCHEDULE is returned. + */ +static enum task_state scheduler_twb_ll_tick(void *data) +{ + struct scheduler_twb_data *twb_sch = data; + k_thread_runtime_stats_t rt_stats_thread; + struct list_item *tlist, *tmp; + struct task_twb_data *pdata; + struct task *curr_task; + unsigned int lock_key; + bool keep_ll_tick_src = false; + + lock_key = scheduler_twb_lock(); + + /* Iterate through the list of tasks */ + list_for_item_safe(tlist, tmp, &twb_sch->tasks) { + curr_task = container_of(tlist, struct task, list); + pdata = curr_task->priv_data; + + /* Reset consumed cycles */ + pdata->cycles_consumed = 0; + + switch (curr_task->state) { + case SOF_TASK_STATE_QUEUED: + curr_task->state = SOF_TASK_STATE_RUNNING; + k_sem_give(&pdata->sem); + COMPILER_FALLTHROUGH; + case SOF_TASK_STATE_RUNNING: + if (pdata->cycles_granted) { + /* Reset thread's priority and time slice based on task's budget */ + k_thread_priority_set(pdata->thread_id, pdata->thread_prio); + k_thread_time_slice_set(pdata->thread_id, pdata->cycles_granted, + &scheduler_twb_task_cb, curr_task); + + /* Retrieve runtime statistics of the thread & update ref cycle */ + k_thread_runtime_stats_get(pdata->thread_id, &rt_stats_thread); + pdata->cycles_ref = rt_stats_thread.execution_cycles; + } + keep_ll_tick_src = true; + break; + case SOF_TASK_STATE_CANCEL: + case SOF_TASK_STATE_COMPLETED: + /* Finally remove task from the list */ + list_item_del(&curr_task->list); + break; + default: + break; + } + } + + scheduler_twb_unlock(lock_key); + + if (!keep_ll_tick_src) + return SOF_TASK_STATE_COMPLETED; + + return SOF_TASK_STATE_RESCHEDULE; +} + +/** + * @brief Thread function for a TWB task. + * + * This function is responsible for executing the TWB task in a loop. + * It checks the state of the task, runs the task if it is in the running state, + * and handles different task states such as rescheduling, cancellation, and completion. + * It also updates the runtime statistics of the thread and suspends the + * thread if the task is not in the running state. + * + * @param p1 Pointer to the task structure. + * @param p2 Unused parameter. + * @param p3 Unused parameter. + */ +static void twb_thread_fn(void *p1, void *p2, void *p3) +{ + struct task *task = p1; + struct task *ll_tick_src = p2; + (void)p3; + struct task_twb_data *pdata = task->priv_data; + k_thread_runtime_stats_t rt_stats_thread; + enum task_state state; + unsigned int lock_key; + + while (1) { + if (ll_tick_src->state == SOF_TASK_STATE_INIT || ll_tick_src->state == SOF_TASK_STATE_FREE) + schedule_task(ll_tick_src, 0, 0); + + if (task->state == SOF_TASK_STATE_RUNNING) { + state = task_run(task); + } else { + state = task->state; /* to avoid undefined variable warning */ + } + + lock_key = scheduler_twb_lock(); + /* + * check if task is still running, may have been canceled by external call + * if not, set the state returned by run procedure + */ + if (task->state == SOF_TASK_STATE_RUNNING) { + if (pdata->cycles_granted) { + k_thread_runtime_stats_get(pdata->thread_id, &rt_stats_thread); + pdata->cycles_consumed += rt_stats_thread.execution_cycles - pdata->cycles_ref; + pdata->cycles_ref = rt_stats_thread.execution_cycles; + } + switch (state) { + case SOF_TASK_STATE_RESCHEDULE: + /* mark to reschedule, schedule time is already calculated */ + task->state = SOF_TASK_STATE_QUEUED; + break; + case SOF_TASK_STATE_CANCEL: + task->state = SOF_TASK_STATE_CANCEL; + break; + case SOF_TASK_STATE_COMPLETED: + break; + + default: + /* illegal state, serious defect, won't happen */ + scheduler_twb_unlock(lock_key); + k_panic(); + } + } + + scheduler_twb_unlock(lock_key); + + if (state == SOF_TASK_STATE_COMPLETED) { + task->state = SOF_TASK_STATE_COMPLETED; + task_complete(task); + } + + if (state != SOF_TASK_STATE_RUNNING) + k_sem_take(&pdata->sem, K_FOREVER); + }; + /* never be here */ +} + +/** + * Schedule a task in the TWB scheduler. + * + * This function adds a task to the TWB scheduler list, + * recalculate budget and starts the thread associated with the task. + * If there are no TWB tasks scheduled yet, it also runs the LL tick source task. + * + * @param data Pointer to the TWB scheduler data. + * @param task Pointer to the task to be scheduled. + * @param start The start time of the task. + * @param period The period of the task. + * @return 0 on success, or a negative error code on failure. + */ +static int scheduler_twb_task_shedule(void *data, struct task *task, uint64_t start, + uint64_t period) +{ + struct scheduler_twb_data *twb_sch = (struct scheduler_twb_data *)data; + struct task_twb_data *pdata = task->priv_data; + struct list_item *tlist; + struct task *task_iter; + unsigned int lock_key; + bool list_prepend = true; + bool thread_started = true; + uint32_t budget_left = 0; + + lock_key = scheduler_twb_lock(); + + if (task->state != SOF_TASK_STATE_INIT && + task->state != SOF_TASK_STATE_CANCEL && + task->state != SOF_TASK_STATE_COMPLETED) { + scheduler_twb_unlock(lock_key); + return -EINVAL; + } else if (task->state == SOF_TASK_STATE_INIT) { + thread_started = false; + } + + /* add a task to TWB scheduler list */ + task->state = SOF_TASK_STATE_RUNNING; + + /* if there's no TWB tasks scheduled yet, run ll tick source task */ + if (list_is_empty(&twb_sch->tasks)) { + if (!k_is_in_isr()) + schedule_task(&twb_sch->ll_tick_src, 0, 0); + } else { + list_for_item(tlist, &twb_sch->tasks) { + task_iter = container_of(tlist, struct task, list); + if (task == task_iter) { + list_prepend = false; + break; + } + } + } + + if (list_prepend) + list_item_prepend(&task->list, &twb_sch->tasks); + + /* If the task has a cycles budget, calculate the budget_left and set the thread priority */ + if (pdata->cycles_granted) { + if (pdata->cycles_consumed < SYS_TICKS_TO_HW_CYCLES(pdata->cycles_granted)) { + budget_left = HW_CYCLES_TO_SYS_TICKS(SYS_TICKS_TO_HW_CYCLES(pdata->cycles_granted) - pdata->cycles_consumed); + k_thread_priority_set(pdata->thread_id, pdata->thread_prio); + } else { + k_thread_priority_set(pdata->thread_id, CONFIG_TWB_THREAD_LOW_PRIORITY); + } + k_thread_time_slice_set(pdata->thread_id, budget_left, &scheduler_twb_task_cb, task); + } + + tr_dbg(&twb_tr, "TWB task %p scheduled with budget %d/%d", task, budget_left, pdata->cycles_granted); + + /* start the thread */ + if (!thread_started) + k_thread_start(pdata->thread_id); + else + k_sem_give(&pdata->sem); + + scheduler_twb_unlock(lock_key); + + return 0; +} + +static int scheduler_twb_task_cancel(void *data, struct task *task) +{ + struct task_twb_data *task_pdata = task->priv_data; + k_thread_runtime_stats_t rt_stats_thread; + unsigned int lock_key; + + lock_key = scheduler_twb_lock(); + + if (task_pdata->cycles_granted) { + /* Get the stats and update the consumed cycles */ + k_thread_runtime_stats_get(task_pdata->thread_id, &rt_stats_thread); + task_pdata->cycles_consumed += rt_stats_thread.execution_cycles - task_pdata->cycles_ref; + task_pdata->cycles_ref = rt_stats_thread.execution_cycles; + } + + /* Set the task state to CANCEL */ + task->state = SOF_TASK_STATE_CANCEL; + + scheduler_twb_unlock(lock_key); + + return 0; +} + +static int scheduler_twb_task_free(void *data, struct task *task) +{ + struct task_twb_data *pdata = task->priv_data; + + scheduler_twb_task_cancel(data, task); + + list_item_del(&task->list); + + /* abort the execution of the thread */ + k_thread_abort(pdata->thread_id); + + /* free task stack */ + rfree((__sparse_force void *)pdata->p_stack); + + /* all other memory has been allocated as a single malloc, will be freed later by caller */ + return 0; +} + +static struct scheduler_ops schedule_twb_ops = { + .schedule_task = scheduler_twb_task_shedule, + .schedule_task_cancel = scheduler_twb_task_cancel, + .schedule_task_free = scheduler_twb_task_free, +}; + +__cold int scheduler_twb_init(void) +{ + struct scheduler_twb_data *twb_sch = rzalloc(SOF_MEM_FLAG_KERNEL, + sizeof(struct scheduler_twb_data)); + int ret; + + assert_can_be_cold(); + + if (!twb_sch) + return -ENOMEM; + + list_init(&twb_sch->tasks); + + scheduler_init(SOF_SCHEDULE_TWB, &schedule_twb_ops, twb_sch); + + /* init src of TWB tick */ + ret = schedule_task_init_ll(&twb_sch->ll_tick_src, + SOF_UUID(twb_sched_uuid), + SOF_SCHEDULE_LL_TIMER, + 0, scheduler_twb_ll_tick, twb_sch, + cpu_get_id(), 0); + + return ret; +} + +int scheduler_twb_task_init(struct task **task, + const struct sof_uuid_entry *uid, + const struct task_ops *ops, + void *data, + int32_t core, + const char *name, + size_t stack_size, + int32_t thread_priority, + uint32_t cycles_granted) +{ + struct scheduler_twb_data *twb_sch; + void __sparse_cache *p_stack = NULL; + k_tid_t thread_id = NULL; + int ret; + + /* memory allocation helper structure */ + struct { + struct task task; + struct task_twb_data pdata; + struct k_thread thread; + } *task_memory; + + twb_sch = scheduler_get_data(SOF_SCHEDULE_TWB); + if (!twb_sch) { + tr_err(&twb_tr, "TWB not initialized"); + return -EINVAL; + } + + /* must be called on the same core the task will be binded to */ + assert(cpu_get_id() == core); + + if (thread_priority < 0) { + tr_err(&twb_tr, "non preemptible priority"); + return -EINVAL; + } + + /* + * allocate memory + * to avoid multiple malloc operations allocate all required memory as a single structure + * and return pointer to task_memory->task + * As the structure contains zephyr kernel specific data, it must be located in + * shared, non cached memory + */ + task_memory = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + sizeof(*task_memory)); + if (!task_memory) { + tr_err(&twb_tr, "memory alloc failed"); + return -ENOMEM; + } + + /* allocate stack - must be aligned and cached so a separate alloc */ + stack_size = Z_KERNEL_STACK_SIZE_ADJUST(stack_size); + p_stack = (__sparse_force void __sparse_cache *) + rballoc_align(SOF_MEM_FLAG_KERNEL, stack_size, Z_KERNEL_STACK_OBJ_ALIGN); + if (!p_stack) { + tr_err(&twb_tr, "stack alloc failed"); + ret = -ENOMEM; + goto err; + } + + /* create a zephyr thread for the task */ + thread_id = k_thread_create(&task_memory->thread, (__sparse_force void *)p_stack, + stack_size, twb_thread_fn, &task_memory->task, &twb_sch->ll_tick_src, NULL, + thread_priority, K_USER, K_FOREVER); + if (!thread_id) { + ret = -EFAULT; + tr_err(&twb_tr, "zephyr thread create failed"); + goto err; + } + +#ifdef CONFIG_SCHED_CPU_MASK + /* pin the thread to specific core */ + ret = k_thread_cpu_pin(thread_id, core); + if (ret < 0) { + ret = -EFAULT; + tr_err(&twb_tr, "zephyr task pin to core %d failed", core); + goto err; + } +#endif + + /* set the thread name */ + if (name) { + ret = k_thread_name_set(thread_id, name); + if (ret < 0) + tr_warn(&twb_tr, "failed to set thread name"); + } + + /* internal SOF task init */ + ret = schedule_task_init(&task_memory->task, uid, SOF_SCHEDULE_TWB, thread_priority, + ops->run, data, core, 0); + if (ret < 0) { + tr_err(&twb_tr, "schedule_task_init failed"); + goto err; + } + + /* unlimited mcps budget */ + if (cycles_granted >= ZEPHYR_TWB_BUDGET_MAX) + cycles_granted = 0; + + /* initialize other task structures */ + task_memory->task.ops.complete = ops->complete; + task_memory->task.ops.get_deadline = ops->get_deadline; + + /* success, fill the structures */ + 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.thread_prio = thread_priority; + task_memory->pdata.cycles_granted = cycles_granted; + task_memory->pdata.cycles_consumed = 0; + task_memory->pdata.cycles_ref = 0; + *task = &task_memory->task; + + k_sem_init(&task_memory->pdata.sem, 0, 10); + + tr_dbg(&twb_tr, "TWB task %p initialized: thread: %p, core: %d, prio: %d, budget: %d", + task, thread_id, core, thread_priority, cycles_granted); + + return 0; +err: + /* cleanup - free all allocated resources */ + if (thread_id) + k_thread_abort(thread_id); + + rfree((__sparse_force void *)p_stack); + rfree(task_memory); + return ret; +} diff --git a/src/spinlock.c b/src/spinlock.c deleted file mode 100644 index 52e80a29ff42..000000000000 --- a/src/spinlock.c +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2020 Intel Corporation. All rights reserved. -// -// Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - -#include <rtos/interrupt.h> -#if CONFIG_DEBUG_LOCKS -#include <sof/lib/uuid.h> -#endif -#include <rtos/spinlock.h> - -#include <stdint.h> - -#if CONFIG_DEBUG_LOCKS - -SOF_DEFINE_REG_UUID(spinlock); - -DECLARE_TR_CTX(sl_tr, SOF_UUID(spinlock_uuid), LOG_LEVEL_INFO); - -#endif - -#ifndef __ZEPHYR__ -k_spinlock_key_t _k_spin_lock_irq(struct k_spinlock *lock) -{ - k_spinlock_key_t key = interrupt_global_disable(); -#if CONFIG_DEBUG_LOCKS - lock_dbg_atomic++; -#endif - arch_spin_lock(lock); -#if CONFIG_DEBUG_LOCKS - if (lock_dbg_atomic < DBG_LOCK_USERS) - lock_dbg_user[lock_dbg_atomic - 1] = (lock)->user; -#endif - return key; -} - -void _k_spin_unlock_irq(struct k_spinlock *lock, k_spinlock_key_t key, int line) -{ - arch_spin_unlock(lock); -#if CONFIG_DEBUG_LOCKS - lock_dbg_atomic--; -#endif - interrupt_global_enable(key); -} -#endif diff --git a/src/trace/CMakeLists.txt b/src/trace/CMakeLists.txt index 75b843876df4..7fab6cf5eaaa 100644 --- a/src/trace/CMakeLists.txt +++ b/src/trace/CMakeLists.txt @@ -1,3 +1,5 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof dma-trace.c trace.c) +if(CONFIG_TRACE) + add_local_sources(sof dma-trace.c trace.c) +endif() diff --git a/src/trace/Kconfig b/src/trace/Kconfig index 5ff6b2001130..92ccb461ed18 100644 --- a/src/trace/Kconfig +++ b/src/trace/Kconfig @@ -108,6 +108,16 @@ config LOG_BACKEND_SOF_PROBE Logging is enabled by setting up a probe point with probe purpose value of PROBE_PURPOSE_LOGGING. +config LOG_BACKEND_SOF_PROBE_OUTPUT_AUTO_ENABLE + bool "Automatically enable probes logging when probe dma is started" + depends on LOG_BACKEND_SOF_PROBE + help + Automatically enable logging as soon as probes DMA + starts. This option simplifies probes logging back + end usage as there is no need to enable logs after + every boot. The probes DMA is still needed before the + log output can be enabled. + config LOG_BACKEND_SOF_PROBE_OUTPUT_DICTIONARY bool "Dictionary" select LOG_DICTIONARY_SUPPORT diff --git a/src/trace/dma-trace.c b/src/trace/dma-trace.c index a1dbda7d10bb..554204ac5c70 100644 --- a/src/trace/dma-trace.c +++ b/src/trace/dma-trace.c @@ -96,7 +96,7 @@ static enum task_state trace_work(void *data) size = dma_copy_to_host(&d->dc, config, d->posn.host_offset, buffer->r_ptr, size); if (size < 0) { - tr_err(&dt_tr, "trace_work(): dma_copy_to_host() failed"); + tr_err(&dt_tr, "dma_copy_to_host() failed"); goto out; } @@ -149,7 +149,12 @@ int dma_trace_init_early(struct sof *sof) */ assert(!dma_trace_initialized(sof->dmat)); - sof->dmat = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*sof->dmat)); + sof->dmat = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*sof->dmat)); + if (!sof->dmat) { + mtrace_printf(LOG_LEVEL_ERROR, + "alloc failed"); + return -ENOMEM; + } dma_sg_init(&sof->dmat->config.elem_array); k_spinlock_init(&sof->dmat->lock); @@ -166,11 +171,9 @@ int dma_trace_init_early(struct sof *sof) err: mtrace_printf(LOG_LEVEL_ERROR, - "dma_trace_init_early() failed: %d", ret); + "failed: %d", ret); - /* Cannot rfree(sof->dmat) from the system memory pool, see - * comments in lib/alloc.c - */ + rfree(sof->dmat); sof->dmat = NULL; return ret; @@ -181,11 +184,11 @@ int dma_trace_init_complete(struct dma_trace_data *d) { int ret = 0; - tr_info(&dt_tr, "dma_trace_init_complete()"); + tr_info(&dt_tr, "entry"); if (!d) { mtrace_printf(LOG_LEVEL_ERROR, - "dma_trace_init_complete(): failed, no dma_trace_data"); + "failed, no dma_trace_data"); return -ENOMEM; } @@ -193,7 +196,7 @@ int dma_trace_init_complete(struct dma_trace_data *d) ret = dma_copy_new(&d->dc); if (ret < 0) { mtrace_printf(LOG_LEVEL_ERROR, - "dma_trace_init_complete(): dma_copy_new() failed: %d", ret); + "dma_copy_new() failed: %d", ret); goto out; } #if CONFIG_ZEPHYR_NATIVE_DRIVERS @@ -205,7 +208,7 @@ int dma_trace_init_complete(struct dma_trace_data *d) #endif if (ret < 0) { mtrace_printf(LOG_LEVEL_ERROR, - "dma_trace_init_complete(): dma_get_attribute() failed: %d", ret); + "dma_get_attribute() failed: %d", ret); goto out; } @@ -246,11 +249,6 @@ static void dma_trace_buffer_free(struct dma_trace_data *d) static int dma_trace_buffer_init(struct dma_trace_data *d) { -#if CONFIG_DMA_GW - struct dma_sg_config *config = &d->gw_config; - uint32_t elem_size, elem_addr, elem_num; - int ret; -#endif struct dma_trace_buf *buffer = &d->dmatb; void *buf; k_spinlock_key_t key; @@ -270,7 +268,7 @@ static int dma_trace_buffer_init(struct dma_trace_data *d) if (!d || !d->dc.dmac) { mtrace_printf(LOG_LEVEL_ERROR, - "dma_trace_buffer_init() failed, no DMAC! d=%p", d); + "failed, no DMAC! d=%p", d); return -ENODEV; } #if CONFIG_ZEPHYR_NATIVE_DRIVERS @@ -284,10 +282,10 @@ static int dma_trace_buffer_init(struct dma_trace_data *d) return err; /* For DMA to work properly the buffer must be correctly aligned */ - buf = rballoc_align(0, SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, + buf = rballoc_align(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA, DMA_TRACE_LOCAL_SIZE, addr_align); if (!buf) { - mtrace_printf(LOG_LEVEL_ERROR, "dma_trace_buffer_init(): alloc failed"); + mtrace_printf(LOG_LEVEL_ERROR, "alloc failed"); return -ENOMEM; } @@ -306,30 +304,6 @@ static int dma_trace_buffer_init(struct dma_trace_data *d) k_spin_unlock(&d->lock, key); -#if CONFIG_DMA_GW - /* size of every trace record */ - elem_size = sizeof(uint64_t) * 2; - - /* Initialize address of local elem */ - elem_addr = (uint32_t)buffer->addr; - - /* the number of elem list */ - elem_num = DMA_TRACE_LOCAL_SIZE / elem_size; - - config->direction = DMA_DIR_LMEM_TO_HMEM; - config->src_width = sizeof(uint32_t); - config->dest_width = sizeof(uint32_t); - config->cyclic = 0; - - ret = dma_sg_alloc(&config->elem_array, SOF_MEM_ZONE_SYS, - config->direction, elem_num, elem_size, - elem_addr, 0); - if (ret < 0) { - dma_trace_buffer_free(d); - return ret; - } -#endif - #ifdef __ZEPHYR__ #define ZEPHYR_VER_OPT " zephyr:" STRINGIFY(BUILD_VERSION) #else @@ -358,77 +332,6 @@ static int dma_trace_buffer_init(struct dma_trace_data *d) return 0; } -#if CONFIG_DMA_GW - -static int dma_trace_start(struct dma_trace_data *d) -{ - int err = 0; - - /* DMA Controller initialization is platform-specific */ - if (!d || !d->dc.dmac) { - mtrace_printf(LOG_LEVEL_ERROR, - "dma_trace_start failed: no DMAC!"); - return -ENODEV; - } - - if (d->dc.chan) { - /* We already have DMA channel for dtrace, stop it */ - mtrace_printf(LOG_LEVEL_WARNING, - "dma_trace_start(): DMA reconfiguration (active stream_tag: %u)", - d->active_stream_tag); - - schedule_task_cancel(&d->dmat_work); - err = dma_stop_legacy(d->dc.chan); - if (err < 0) { - mtrace_printf(LOG_LEVEL_ERROR, - "dma_trace_start(): DMA channel failed to stop"); - } else if (d->active_stream_tag != d->stream_tag) { - /* Re-request a channel if different tag is provided */ - mtrace_printf(LOG_LEVEL_WARNING, - "dma_trace_start(): stream_tag change from %u to %u", - d->active_stream_tag, d->stream_tag); - - dma_channel_put_legacy(d->dc.chan); - d->dc.chan = NULL; - err = dma_copy_set_stream_tag(&d->dc, d->stream_tag); - } - } else { - err = dma_copy_set_stream_tag(&d->dc, d->stream_tag); - } - - if (err < 0) - return err; - - /* Reset host buffer information as host is re-configuring dtrace */ - d->posn.host_offset = 0; - - d->active_stream_tag = d->stream_tag; - - err = dma_set_config_legacy(d->dc.chan, &d->gw_config); - if (err < 0) { - mtrace_printf(LOG_LEVEL_ERROR, "dma_set_config() failed: %d", err); - goto error; - } - - err = dma_start_legacy(d->dc.chan); - if (err == 0) - return 0; - -error: - dma_channel_put_legacy(d->dc.chan); - d->dc.chan = NULL; - - return err; -} - -static int dma_trace_get_avail_data(struct dma_trace_data *d, - struct dma_trace_buf *buffer, - int avail) -{ - /* align data to HD-DMA burst size */ - return ALIGN_DOWN(avail, d->dma_copy_align); -} -#else static int dma_trace_get_avail_data(struct dma_trace_data *d, struct dma_trace_buf *buffer, int avail) @@ -461,8 +364,6 @@ static int dma_trace_get_avail_data(struct dma_trace_data *d, return size; } -#endif /* CONFIG_DMA_GW */ - /** Invoked remotely by SOF_IPC_TRACE_DMA_PARAMS* Depends on * dma_trace_init_complete() */ @@ -475,19 +376,9 @@ int dma_trace_enable(struct dma_trace_data *d) if (err < 0) return err; -#if CONFIG_DMA_GW - /* - * GW DMA need finish DMA config and start before - * host driver trigger start DMA - */ - err = dma_trace_start(d); - if (err < 0) - goto out; -#endif - /* validate DMA context */ if (!d->dc.dmac || !d->dc.chan) { - tr_err_atomic(&dt_tr, "dma_trace_enable(): not valid"); + tr_err_atomic(&dt_tr, "not valid"); err = -ENODEV; goto out; } @@ -516,7 +407,7 @@ void dma_trace_disable(struct dma_trace_data *d) #if (CONFIG_HOST_PTABLE) /* Free up the host SG if it is set */ if (d->host_size) { - dma_sg_free(&d->config.elem_array); + dma_sg_free(NULL, &d->config.elem_array); d->host_size = 0; } #endif @@ -653,7 +544,7 @@ static void dtrace_add_event(const char *e, uint32_t length) trace_data->dropped_entries; trace_data->dropped_entries = 0; mtrace_printf(LOG_LEVEL_WARNING, - "dtrace_add_event(): number of dropped logs = %u", + "number of dropped logs = %u", tmp_dropped_entries); } } diff --git a/src/trace/trace.c b/src/trace/trace.c index dc0eaff0e5d6..bc17c848a902 100644 --- a/src/trace/trace.c +++ b/src/trace/trace.c @@ -498,7 +498,12 @@ void trace_off(void) void trace_init(struct sof *sof) { - sof->trace = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*sof->trace)); + sof->trace = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*sof->trace)); + if (!sof->trace) { + mtrace_printf(LOG_LEVEL_ERROR, "allocation failed"); + sof_panic(SOF_IPC_PANIC_IPC); + } + sof->trace->enable = 1; sof->trace->pos = 0; #if CONFIG_TRACE_FILTERING_ADAPTIVE diff --git a/test/cmocka/m/export_headerfile_open.m b/test/cmocka/m/export_headerfile_open.m index 058da8d9bc7c..5b83e202d8a7 100644 --- a/test/cmocka/m/export_headerfile_open.m +++ b/test/cmocka/m/export_headerfile_open.m @@ -9,7 +9,7 @@ % SPDX-License-Identifier: BSD-3-Clause % -% Copyright(c) 2022 Intel Corporation. All rights reserved. +% Copyright(c) 2022-2025 Intel Corporation. function fh = export_headerfile_open(headerfn, corp) @@ -23,7 +23,7 @@ end fprintf(fh, '/* SPDX-License-Identifier: BSD-3-Clause\n'); fprintf(fh, ' *\n'); - fprintf(fh, ' * Copyright(c) %s %s. All rights reserved.\n', ... + fprintf(fh, ' * Copyright(c) %s %s.\n', ... datestr(now, 'yyyy'), corp); fprintf(fh, ' */\n\n'); end diff --git a/test/cmocka/src/CMakeLists.txt b/test/cmocka/src/CMakeLists.txt index c69f777bf575..2c244aea9d0d 100644 --- a/test/cmocka/src/CMakeLists.txt +++ b/test/cmocka/src/CMakeLists.txt @@ -2,5 +2,4 @@ add_subdirectory(audio) add_subdirectory(lib) -add_subdirectory(list) add_subdirectory(math) diff --git a/test/cmocka/src/audio/buffer/buffer_copy.c b/test/cmocka/src/audio/buffer/buffer_copy.c index be1500cb66f0..f4e958d7fe19 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, false); - struct comp_buffer *snk = buffer_new(&test_buf_desc, false); + struct comp_buffer *src = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *snk = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); 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, false); - struct comp_buffer *snk = buffer_new(&test_buf_desc, false); + struct comp_buffer *src = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *snk = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); 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, false); - struct comp_buffer *snk = buffer_new(&test_buf_desc, false); + struct comp_buffer *src = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *snk = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); 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, false); - struct comp_buffer *snk = buffer_new(&test_buf_desc, false); + struct comp_buffer *src = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *snk = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); 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, false); - struct comp_buffer *snk = buffer_new(&test_buf_desc, false); + struct comp_buffer *src = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *snk = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); 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 e2ce0c274b57..1561c94ec675 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, false); + struct comp_buffer *buf = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); 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 b0c7d11ce555..a1fc37383274 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, false); + struct comp_buffer *buf = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); 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 8c3e437d612a..3fd5504560d8 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, false); + struct comp_buffer *buf = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); 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, false); + struct comp_buffer *buf = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); 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 305a6846966c..226128b220d2 100644 --- a/test/cmocka/src/audio/eq_fir/CMakeLists.txt +++ b/test/cmocka/src/audio/eq_fir/CMakeLists.txt @@ -37,6 +37,7 @@ add_library(audio_for_eq_fir STATIC ${PROJECT_SOURCE_DIR}/src/ipc/ipc3/helper.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc-common.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc-helper.c + ${PROJECT_SOURCE_DIR}/src/lib/objpool.c ${PROJECT_SOURCE_DIR}/test/cmocka/src/notifier_mocks.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-graph.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-params.c diff --git a/test/cmocka/src/audio/eq_fir/eq_fir_process.c b/test/cmocka/src/audio/eq_fir/eq_fir_process.c index ebfd02b2411f..5e3b1dd5b156 100644 --- a/test/cmocka/src/audio/eq_fir/eq_fir_process.c +++ b/test/cmocka/src/audio/eq_fir/eq_fir_process.c @@ -11,6 +11,7 @@ #include <sof/audio/component_ext.h> #include <eq_fir/eq_fir.h> #include <sof/audio/module_adapter/module/generic.h> +#include <ipc/control.h> #include "../../util.h" #include "../../../include/cmocka_chirp_2ch.h" @@ -69,26 +70,48 @@ static int setup_group(void **state) static struct sof_ipc_comp_process *create_eq_fir_comp_ipc(struct test_data *td) { struct sof_ipc_comp_process *ipc; - struct sof_eq_fir_config *eq; size_t ipc_size = sizeof(struct sof_ipc_comp_process); - struct sof_abi_hdr *blob = (struct sof_abi_hdr *)fir_coef_2ch; - const struct sof_uuid uuid = { - .a = 0x43a90ce7, .b = 0xf3a5, .c = 0x41df, - .d = {0xac, 0x06, 0xba, 0x98, 0x65, 0x1a, 0xe6, 0xa3} - }; + const struct sof_uuid uuid = SOF_REG_UUID(eq_fir); - ipc = calloc(1, ipc_size + blob->size + SOF_UUID_SIZE); + ipc = calloc(1, ipc_size + SOF_UUID_SIZE); memcpy_s(ipc + 1, SOF_UUID_SIZE, &uuid, SOF_UUID_SIZE); - eq = (struct sof_eq_fir_config *)((char *)(ipc + 1) + SOF_UUID_SIZE); ipc->comp.hdr.size = ipc_size + SOF_UUID_SIZE; ipc->comp.type = SOF_COMP_MODULE_ADAPTER; ipc->config.hdr.size = sizeof(struct sof_ipc_comp_config); - ipc->size = blob->size; + ipc->size = 0; ipc->comp.ext_data_length = SOF_UUID_SIZE; - memcpy_s(eq, blob->size, blob->data, blob->size); return ipc; } +static int eq_fir_send_config(struct processing_module *mod) +{ + const struct module_interface *const ops = mod->dev->drv->adapter_ops; + struct sof_abi_hdr *blob = (struct sof_abi_hdr *)fir_coef_2ch; + size_t cdata_size = sizeof(struct sof_ipc_ctrl_data) + + sizeof(struct sof_abi_hdr) + blob->size; + struct sof_ipc_ctrl_data *cdata; + int ret; + + cdata = calloc(1, cdata_size); + if (!cdata) + return -ENOMEM; + + cdata->cmd = SOF_CTRL_CMD_BINARY; + cdata->num_elems = blob->size; + cdata->data[0].magic = blob->magic; + cdata->data[0].type = blob->type; + cdata->data[0].size = blob->size; + cdata->data[0].abi = blob->abi; + memcpy_s(cdata->data[0].data, blob->size, blob->data, blob->size); + + ret = ops->set_configuration(mod, 0, MODULE_CFG_FRAGMENT_SINGLE, + blob->size, (const uint8_t *)cdata, + blob->size, NULL, 0); + + free(cdata); + return ret; +} + static void prepare_sink(struct test_data *td, struct processing_module *mod) { struct test_parameters *parameters = td->params; @@ -159,6 +182,10 @@ static int setup(void **state) dev->frames = params->frames; mod = comp_mod(dev); + ret = eq_fir_send_config(mod); + if (ret) + return ret; + prepare_sink(td, mod); prepare_source(td, mod); @@ -189,6 +216,7 @@ static int teardown(void **state) test_free(mod->input_buffers); test_free(mod->output_buffers); test_free(mod->stream_params); + mod->stream_params = NULL; test_free(td->params); free_test_source(td->source); free_test_sink(td->sink); diff --git a/test/cmocka/src/audio/eq_iir/CMakeLists.txt b/test/cmocka/src/audio/eq_iir/CMakeLists.txt index a328590b7106..b5ff8770eec2 100644 --- a/test/cmocka/src/audio/eq_iir/CMakeLists.txt +++ b/test/cmocka/src/audio/eq_iir/CMakeLists.txt @@ -35,9 +35,12 @@ add_library(audio_for_eq_iir STATIC ${PROJECT_SOURCE_DIR}/src/audio/audio_stream.c ${PROJECT_SOURCE_DIR}/src/audio/component.c ${PROJECT_SOURCE_DIR}/src/audio/data_blob.c + ${PROJECT_SOURCE_DIR}/src/module/audio/source_api.c + ${PROJECT_SOURCE_DIR}/src/module/audio/sink_api.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc3/helper.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc-common.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc-helper.c + ${PROJECT_SOURCE_DIR}/src/lib/objpool.c ${PROJECT_SOURCE_DIR}/test/cmocka/src/notifier_mocks.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-graph.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-params.c diff --git a/test/cmocka/src/audio/eq_iir/eq_iir_process.c b/test/cmocka/src/audio/eq_iir/eq_iir_process.c index 54716bcfd0f1..756a4606c68b 100644 --- a/test/cmocka/src/audio/eq_iir/eq_iir_process.c +++ b/test/cmocka/src/audio/eq_iir/eq_iir_process.c @@ -13,6 +13,7 @@ #include <sof/audio/component_ext.h> #include <eq_iir/eq_iir.h> #include <sof/audio/module_adapter/module/generic.h> +#include <ipc/control.h> #include "../../util.h" #include "../../../include/cmocka_chirp_2ch.h" @@ -68,26 +69,48 @@ static int setup_group(void **state) static struct sof_ipc_comp_process *create_eq_iir_comp_ipc(struct test_data *td) { struct sof_ipc_comp_process *ipc; - struct sof_eq_iir_config *eq; size_t ipc_size = sizeof(struct sof_ipc_comp_process); - struct sof_abi_hdr *blob = (struct sof_abi_hdr *)iir_coef_2ch; - const struct sof_uuid uuid = { - .a = 0x5150c0e6, .b = 0x27f9, .c = 0x4ec8, - .d = {0x83, 0x51, 0xc7, 0x05, 0xb6, 0x42, 0xd1, 0x2f} - }; + const struct sof_uuid uuid = SOF_REG_UUID(eq_iir); - ipc = calloc(1, ipc_size + blob->size + SOF_UUID_SIZE); + ipc = calloc(1, ipc_size + SOF_UUID_SIZE); memcpy_s(ipc + 1, SOF_UUID_SIZE, &uuid, SOF_UUID_SIZE); - eq = (struct sof_eq_iir_config *)((char *)(ipc + 1) + SOF_UUID_SIZE); ipc->comp.hdr.size = ipc_size + SOF_UUID_SIZE; ipc->comp.type = SOF_COMP_MODULE_ADAPTER; ipc->config.hdr.size = sizeof(struct sof_ipc_comp_config); - ipc->size = blob->size; + ipc->size = 0; ipc->comp.ext_data_length = SOF_UUID_SIZE; - memcpy_s(eq, blob->size, blob->data, blob->size); return ipc; } +static int eq_iir_send_config(struct processing_module *mod) +{ + const struct module_interface *const ops = mod->dev->drv->adapter_ops; + struct sof_abi_hdr *blob = (struct sof_abi_hdr *)iir_coef_2ch; + size_t cdata_size = sizeof(struct sof_ipc_ctrl_data) + sizeof(struct sof_abi_hdr) + + blob->size; + struct sof_ipc_ctrl_data *cdata; + int ret; + + cdata = calloc(1, cdata_size); + if (!cdata) + return -ENOMEM; + + cdata->cmd = SOF_CTRL_CMD_BINARY; + cdata->num_elems = blob->size; + cdata->data[0].magic = blob->magic; + cdata->data[0].type = blob->type; + cdata->data[0].size = blob->size; + cdata->data[0].abi = blob->abi; + memcpy_s(cdata->data[0].data, blob->size, blob->data, blob->size); + + ret = ops->set_configuration(mod, 0, MODULE_CFG_FRAGMENT_SINGLE, + blob->size, (const uint8_t *)cdata, + blob->size, NULL, 0); + + free(cdata); + return ret; +} + static void prepare_sink(struct test_data *td, struct processing_module *mod) { struct test_parameters *parameters = td->params; @@ -158,6 +181,10 @@ static int setup(void **state) dev->frames = params->frames; mod = comp_mod(dev); + ret = eq_iir_send_config(mod); + if (ret) + return ret; + prepare_sink(td, mod); prepare_source(td, mod); @@ -188,6 +215,7 @@ static int teardown(void **state) test_free(mod->input_buffers); test_free(mod->output_buffers); test_free(mod->stream_params); + mod->stream_params = NULL; test_free(td->params); free_test_source(td->source); free_test_sink(td->sink); diff --git a/test/cmocka/src/audio/mixer/CMakeLists.txt b/test/cmocka/src/audio/mixer/CMakeLists.txt index 723cb091ff61..c0dbb8a0a4fc 100644 --- a/test/cmocka/src/audio/mixer/CMakeLists.txt +++ b/test/cmocka/src/audio/mixer/CMakeLists.txt @@ -10,6 +10,7 @@ cmocka_test(mixer ${PROJECT_SOURCE_DIR}/src/ipc/ipc3/helper.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc-common.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc-helper.c + ${PROJECT_SOURCE_DIR}/src/lib/objpool.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 @@ -25,6 +26,7 @@ cmocka_test(mixer ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-schedule.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-stream.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-xrun.c + ${PROJECT_SOURCE_DIR}/src/audio/data_blob.c ${PROJECT_SOURCE_DIR}/src/module/audio/source_api.c ${PROJECT_SOURCE_DIR}/src/module/audio/sink_api.c ${PROJECT_SOURCE_DIR}/src/math/numbers.c diff --git a/test/cmocka/src/audio/module_adapter_test.c b/test/cmocka/src/audio/module_adapter_test.c index 29140e4581e9..81ec6cadc1b7 100644 --- a/test/cmocka/src/audio/module_adapter_test.c +++ b/test/cmocka/src/audio/module_adapter_test.c @@ -77,7 +77,7 @@ void module_adapter_test_free(struct processing_module_test_data *test_data) } for (i = 0; i < test_data->num_sources; i++) { - free_test_sink(test_data->sources[i]); + free_test_source(test_data->sources[i]); test_free(test_data->input_buffers[i]); } diff --git a/test/cmocka/src/audio/mux/CMakeLists.txt b/test/cmocka/src/audio/mux/CMakeLists.txt index 67b10f77270d..a4a72613fd6b 100644 --- a/test/cmocka/src/audio/mux/CMakeLists.txt +++ b/test/cmocka/src/audio/mux/CMakeLists.txt @@ -25,6 +25,7 @@ add_library( ${PROJECT_SOURCE_DIR}/src/math/numbers.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc3/helper.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc-helper.c + ${PROJECT_SOURCE_DIR}/src/lib/objpool.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 diff --git a/test/cmocka/src/audio/mux/demux_copy.c b/test/cmocka/src/audio/mux/demux_copy.c index 40040023b6df..8e331446bbf4 100644 --- a/test/cmocka/src/audio/mux/demux_copy.c +++ b/test/cmocka/src/audio/mux/demux_copy.c @@ -96,10 +96,7 @@ static struct sof_ipc_comp_process *create_demux_comp_ipc(struct test_data *td) size_t ipc_size = sizeof(struct sof_ipc_comp_process); size_t mux_size = sizeof(struct sof_mux_config) + MUX_MAX_STREAMS * sizeof(struct mux_stream_data); - const struct sof_uuid uuid = { - .a = 0xc4b26868, .b = 0x1430, .c = 0x470e, - .d = {0xa0, 0x89, 0x15, 0xd1, 0xc7, 0x7f, 0x85, 0x1a} - }; + const struct sof_uuid uuid = SOF_REG_UUID(demux); int i, j; ipc = calloc(1, ipc_size + mux_size + SOF_UUID_SIZE); @@ -160,6 +157,7 @@ static int setup_test_case(void **state) struct processing_module *mod; struct sof_ipc_comp_process *ipc; size_t sample_size = td->format == SOF_IPC_FRAME_S16_LE ? sizeof(int16_t) : sizeof(int32_t); + struct pipeline *dummy_pipe; ipc = create_demux_comp_ipc(td); dev = comp_new((struct sof_ipc_comp *)ipc); @@ -167,6 +165,13 @@ static int setup_test_case(void **state) if (!dev) return -EINVAL; + /* Add dummy pipeline to bypass comp_check_eos() */ + dummy_pipe = test_malloc(sizeof(*dummy_pipe)); + if (!dummy_pipe) + return -ENOMEM; + dummy_pipe->expect_eos = false; + dev->pipeline = dummy_pipe; + mod = comp_mod(dev); td->dev = dev; td->mod = mod; @@ -183,11 +188,16 @@ static int teardown_test_case(void **state) struct test_data *td = *((struct test_data **)state); int i; + rfree(td->mod->input_buffers); + rfree(td->mod->output_buffers); + free_test_source(td->source); for (i = 0; i < MUX_MAX_STREAMS; ++i) free_test_sink(td->sinks[i]); + test_free(td->dev->pipeline); + td->dev->pipeline = NULL; comp_free(td->dev); return 0; @@ -332,8 +342,10 @@ int main(void) cmocka_set_message_output(CM_OUTPUT_TAP); ret = cmocka_run_group_tests(tests, setup_group, NULL); - for (ti = 0; ti < ARRAY_SIZE(valid_formats) * ARRAY_SIZE(masks); ti++) + for (ti = 0; ti < ARRAY_SIZE(valid_formats) * ARRAY_SIZE(masks); ti++) { free(tests[ti].initial_state); + free((void *)tests[ti].name); + } return ret; } diff --git a/test/cmocka/src/audio/mux/mux_copy.c b/test/cmocka/src/audio/mux/mux_copy.c index 6e391269054a..66b21b0df27c 100644 --- a/test/cmocka/src/audio/mux/mux_copy.c +++ b/test/cmocka/src/audio/mux/mux_copy.c @@ -114,10 +114,7 @@ static struct sof_ipc_comp_process *create_mux_comp_ipc(struct test_data *td) size_t ipc_size = sizeof(struct sof_ipc_comp_process); size_t mux_size = sizeof(struct sof_mux_config) + MUX_MAX_STREAMS * sizeof(struct mux_stream_data); - const struct sof_uuid uuid = { - .a = 0xc607ff4d, .b = 0x9cb6, .c = 0x49dc, - .d = {0xb6, 0x78, 0x7d, 0xa3, 0xc6, 0x3e, 0xa5, 0x57} - }; + const struct sof_uuid uuid = SOF_REG_UUID(mux); int i, j; ipc = calloc(1, ipc_size + mux_size + SOF_UUID_SIZE); @@ -182,6 +179,7 @@ static int setup_test_case(void **state) struct processing_module *mod; struct sof_ipc_comp_process *ipc; size_t sample_size = td->format == SOF_IPC_FRAME_S16_LE ? sizeof(int16_t) : sizeof(int32_t); + struct pipeline *dummy_pipe; ipc = create_mux_comp_ipc(td); dev = comp_new((struct sof_ipc_comp *)ipc); @@ -189,6 +187,13 @@ static int setup_test_case(void **state) if (!dev) return -EINVAL; + /* Add dummy pipeline to bypass comp_check_eos() */ + dummy_pipe = test_malloc(sizeof(*dummy_pipe)); + if (!dummy_pipe) + return -ENOMEM; + dummy_pipe->expect_eos = false; + dev->pipeline = dummy_pipe; + mod = comp_mod(dev); td->dev = dev; td->mod = mod; @@ -206,10 +211,15 @@ static int teardown_test_case(void **state) struct test_data *td = *((struct test_data **)state); int i; + rfree(td->mod->input_buffers); + rfree(td->mod->output_buffers); + for (i = 0; i < MUX_MAX_STREAMS; ++i) free_test_source(td->sources[i]); free_test_sink(td->sink); + test_free(td->dev->pipeline); + td->dev->pipeline = NULL; comp_free(td->dev); return 0; } @@ -350,8 +360,10 @@ int main(void) cmocka_set_message_output(CM_OUTPUT_TAP); ret = cmocka_run_group_tests(tests, setup_group, NULL); - for (ti = 0; ti < ARRAY_SIZE(valid_formats) * ARRAY_SIZE(masks); ti++) + for (ti = 0; ti < ARRAY_SIZE(valid_formats) * ARRAY_SIZE(masks); ti++) { free(tests[ti].initial_state); + free((void *)tests[ti].name); + } return ret; } diff --git a/test/cmocka/src/audio/mux/mux_get_processing_function.c b/test/cmocka/src/audio/mux/mux_get_processing_function.c index af9fd418ec56..0e4f22ff7021 100644 --- a/test/cmocka/src/audio/mux/mux_get_processing_function.c +++ b/test/cmocka/src/audio/mux/mux_get_processing_function.c @@ -40,10 +40,7 @@ static struct sof_ipc_comp_process *create_mux_comp_ipc(struct test_data *td) size_t ipc_size = sizeof(struct sof_ipc_comp_process); size_t mux_size = sizeof(struct sof_mux_config) + MUX_MAX_STREAMS * sizeof(struct mux_stream_data); - const struct sof_uuid uuid = { - .a = 0xc607ff4d, .b = 0x9cb6, .c = 0x49dc, - .d = {0xb6, 0x78, 0x7d, 0xa3, 0xc6, 0x3e, 0xa5, 0x57} - }; + const struct sof_uuid uuid = SOF_REG_UUID(mux); int i, j; ipc = calloc(1, ipc_size + mux_size + SOF_UUID_SIZE); diff --git a/test/cmocka/src/audio/pipeline/pipeline_connect_upstream.c b/test/cmocka/src/audio/pipeline/pipeline_connect_upstream.c index 2a3b14bf2dfe..e911f0238162 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_connect_upstream.c +++ b/test/cmocka/src/audio/pipeline/pipeline_connect_upstream.c @@ -24,6 +24,7 @@ static int setup(void **state) static int teardown(void **state) { + free_standard_connect_objects(*state); free(*state); return 0; } @@ -129,13 +130,13 @@ static void test_audio_pipeline_complete_connect_upstream_ignore_source */ list_item_append(&result.sched_comp->bsource_list, &test_data->b1->sink_list); - test_data->b1->sink = result.sched_comp; - test_data->b1->source = test_data->second; + comp_buffer_set_sink_component(test_data->b1, result.sched_comp); + comp_buffer_set_source_component(test_data->b1, test_data->second); list_item_append(&test_data->b1->source_list, &test_data->second->bsink_list); list_item_append(&test_data->second->bsource_list, &test_data->b2->sink_list); - test_data->b2->sink = test_data->second; + comp_buffer_set_sink_component(test_data->b2, test_data->second); /*Testing component*/ pipeline_complete(&result, test_data->first, test_data->second); @@ -156,14 +157,11 @@ static void test_audio_pipeline_complete_connect_downstream_full(void **state) /*Connecting first comp to second*/ comp = &test_data->second->ipc_config; comp->pipeline_id = PIPELINE_ID_SAME; - list_item_append(&result.sched_comp->bsink_list, - &test_data->b1->source_list); - test_data->b1->source = result.sched_comp; - list_item_append(&test_data->b1->source_list, - &result.sched_comp->bsink_list); - test_data->b1->sink = test_data->second; - list_item_append(&test_data->b1->sink_list, - &test_data->second->bsource_list); + list_item_append(&result.sched_comp->bsink_list, &test_data->b1->source_list); + comp_buffer_set_source_component(test_data->b1, result.sched_comp); + list_item_append(&test_data->b1->source_list, &result.sched_comp->bsink_list); + comp_buffer_set_sink_component(test_data->b1, test_data->second); + list_item_append(&test_data->b1->sink_list, &test_data->second->bsource_list); test_data->first->frames = 0; test_data->second->frames = 0; @@ -189,8 +187,8 @@ static void test_audio_pipeline_complete_connect_upstream_full(void **state) comp->pipeline_id = PIPELINE_ID_SAME; list_item_append(&result.sched_comp->bsource_list, &test_data->b1->sink_list); - test_data->b1->sink = test_data->first; - test_data->b1->source = test_data->second; + comp_buffer_set_sink_component(test_data->b1, test_data->first); + comp_buffer_set_source_component(test_data->b1, test_data->second); /*Testing component*/ pipeline_complete(&result, test_data->first, test_data->second); @@ -212,12 +210,10 @@ static void test_audio_pipeline_complete_connect_upstream_other_pipeline /*Connecting first comp to second*/ comp = &test_data->second->ipc_config; comp->pipeline_id = PIPELINE_ID_DIFFERENT; - list_item_append(&result.sched_comp->bsource_list, - &test_data->b1->sink_list); - test_data->b1->sink = test_data->first; - test_data->b1->source = test_data->second; - list_item_append(&test_data->second->bsource_list, - &test_data->b1->source_list); + list_item_append(&result.sched_comp->bsource_list, &test_data->b1->sink_list); + comp_buffer_set_sink_component(test_data->b1, test_data->first); + comp_buffer_set_source_component(test_data->b1, test_data->second); + list_item_append(&test_data->second->bsource_list, &test_data->b1->source_list); /*Testing component*/ pipeline_complete(&result, test_data->first, test_data->second); diff --git a/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.c b/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.c index af811d74df64..7315ce387562 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.c +++ b/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.c @@ -17,12 +17,12 @@ void cleanup_test_data(struct pipeline_connect_data *data) { list_init(&data->first->bsource_list); list_init(&data->second->bsource_list); - list_init(&data->b1->sink_list); - list_init(&data->b1->source_list); + comp_buffer_reset_sink_list(data->b1); + comp_buffer_reset_source_list(data->b1); list_init(&data->first->bsink_list); list_init(&data->second->bsink_list); - list_init(&data->b2->sink_list); - list_init(&data->b2->source_list); + comp_buffer_reset_sink_list(data->b2); + comp_buffer_reset_source_list(data->b2); } struct pipeline_connect_data *get_standard_connect_objects(void) @@ -30,7 +30,7 @@ struct pipeline_connect_data *get_standard_connect_objects(void) struct pipeline_connect_data *pipeline_connect_data = calloc (sizeof(struct pipeline_connect_data), 1); - struct pipeline *pipe = calloc(sizeof(struct pipeline), 1); + struct pipeline *pipe = &pipeline_connect_data->p; pipe->frames_per_sched = 5; pipe->pipeline_id = PIPELINE_ID_SAME; @@ -49,6 +49,9 @@ struct pipeline_connect_data *get_standard_connect_objects(void) sch->ops = &schedule_mock_ops; list_item_append(&sch->list, &schedulers->list); + /* Bind the scheduler to the task, as schedule_task_init() would */ + pipe->pipe_task->sch = sch; + struct comp_dev *first = calloc(sizeof(struct comp_dev), 1); struct comp_ipc_config *first_comp = &first->ipc_config; @@ -70,20 +73,27 @@ struct pipeline_connect_data *get_standard_connect_objects(void) struct comp_buffer *buffer = calloc(sizeof(struct comp_buffer), 1); - buffer->source = first; - buffer->sink = second; - list_init(&buffer->sink_list); - list_init(&buffer->source_list); + comp_buffer_set_source_component(buffer, first); + comp_buffer_set_sink_component(buffer, second); + comp_buffer_reset_sink_list(buffer); + comp_buffer_reset_source_list(buffer); pipeline_connect_data->b1 = buffer; struct comp_buffer *buffer_2 = calloc(sizeof(struct comp_buffer), 1); - buffer_2->source = second; - list_init(&buffer_2->sink_list); - list_init(&buffer_2->source_list); + comp_buffer_set_source_component(buffer_2, second); + comp_buffer_reset_sink_list(buffer_2); + comp_buffer_reset_source_list(buffer_2); pipeline_connect_data->b2 = buffer_2; - pipeline_connect_data->p = *pipe; - return pipeline_connect_data; } + +void free_standard_connect_objects(struct pipeline_connect_data *data) +{ + free(data->p.pipe_task); + free(data->p.sched_comp); + free(data->second); + free(data->b1); + free(data->b2); +} diff --git a/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.h b/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.h index 6a8c0fce1a12..60eedabbd43b 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.h +++ b/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.h @@ -32,6 +32,7 @@ struct pipeline_connect_data { }; struct pipeline_connect_data *get_standard_connect_objects(void); +void free_standard_connect_objects(struct pipeline_connect_data *data); void cleanup_test_data(struct pipeline_connect_data *data); diff --git a/test/cmocka/src/audio/pipeline/pipeline_free.c b/test/cmocka/src/audio/pipeline/pipeline_free.c index d4d441012a29..9878f4f5e42a 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_free.c +++ b/test/cmocka/src/audio/pipeline/pipeline_free.c @@ -23,7 +23,7 @@ #endif /* mock free() - dont free as we inspect contents */ -void rfree(void *ptr) +void sof_heap_free(struct k_heap *heap, void *addr) { } @@ -36,6 +36,7 @@ static int setup(void **state) static int teardown(void **state) { + free_standard_connect_objects(*state); free(*state); return 0; } diff --git a/test/cmocka/src/audio/pipeline/pipeline_new.c b/test/cmocka/src/audio/pipeline/pipeline_new.c index dda5d1a5c020..a68afe49e4be 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_new.c +++ b/test/cmocka/src/audio/pipeline/pipeline_new.c @@ -49,12 +49,18 @@ static void test_audio_pipeline_pipeline_new_creation(void **state) struct pipeline_new_setup_data *test_data = *state; /*Testing component*/ - struct pipeline *result = pipeline_new(test_data->pipe_id, + struct pipeline *result = pipeline_new(NULL, + test_data->pipe_id, test_data->priority, - test_data->comp_id); + test_data->comp_id, + NULL); /*Pipeline should have been created so pointer can't be null*/ assert_non_null(result); + + rfree(result->msg->tx_data); + rfree(result->msg); + rfree(result); } int main(void) diff --git a/test/cmocka/src/audio/volume/CMakeLists.txt b/test/cmocka/src/audio/volume/CMakeLists.txt index d89927578222..0385441e5878 100644 --- a/test/cmocka/src/audio/volume/CMakeLists.txt +++ b/test/cmocka/src/audio/volume/CMakeLists.txt @@ -34,6 +34,7 @@ add_library(audio_for_volume STATIC ${PROJECT_SOURCE_DIR}/src/ipc/ipc3/helper.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc-common.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc-helper.c + ${PROJECT_SOURCE_DIR}/src/lib/objpool.c ${PROJECT_SOURCE_DIR}/test/cmocka/src/notifier_mocks.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-graph.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-params.c diff --git a/test/cmocka/src/audio/volume/volume_process.c b/test/cmocka/src/audio/volume/volume_process.c index 10afdd1276a3..389a4e75a503 100644 --- a/test/cmocka/src/audio/volume/volume_process.c +++ b/test/cmocka/src/audio/volume/volume_process.c @@ -315,7 +315,7 @@ int main(void) struct vol_test_parameters *parameters; uint32_t volume_values[] = {VOL_MAX, VOL_ZERO_DB, VOL_MINUS_80DB}; int num_tests = ARRAY_SIZE(test_parameters) * ARRAY_SIZE(volume_values); - int i, j; + int i, j, ret; parameters = test_calloc(num_tests, sizeof(struct vol_test_parameters)); for (i = 0; i < ARRAY_SIZE(test_parameters); i++) { @@ -338,5 +338,9 @@ int main(void) cmocka_set_message_output(CM_OUTPUT_TAP); - return cmocka_run_group_tests(tests, NULL, NULL); + ret = cmocka_run_group_tests(tests, NULL, NULL); + + test_free(parameters); + + return ret; } diff --git a/test/cmocka/src/common_mocks.c b/test/cmocka/src/common_mocks.c index 92ba58031680..2c2867346293 100644 --- a/test/cmocka/src/common_mocks.c +++ b/test/cmocka/src/common_mocks.c @@ -18,6 +18,7 @@ #include <user/trace.h> #include <rtos/spinlock.h> #include <sof/audio/component_ext.h> +#include <sof/audio/module_adapter/module/generic.h> #include <rtos/clk.h> #include <sof/lib/notifier.h> #include <rtos/wait.h> @@ -33,9 +34,7 @@ /* global contexts */ WEAK struct ipc *_ipc; -#ifndef __ZEPHYR__ WEAK struct timer *platform_timer; -#endif WEAK struct schedulers *schedulers; WEAK struct sof sof; WEAK struct tr_ctx buffer_tr; @@ -44,33 +43,35 @@ WEAK struct tr_ctx ipc_tr; int host_trace_level = LOG_LEVEL_ERROR; -void WEAK *rballoc_align(uint32_t flags, uint32_t caps, size_t bytes, +void WEAK *rballoc_align(uint32_t flags, size_t bytes, uint32_t alignment) { (void)flags; - (void)caps; return calloc(bytes, 1); } -void WEAK *rzalloc(enum mem_zone zone, uint32_t flags, uint32_t caps, +void WEAK *rzalloc(uint32_t flags, size_t bytes) { - (void)zone; (void)flags; - (void)caps; return calloc(bytes, 1); } -void WEAK *rbrealloc_align(void *ptr, uint32_t flags, uint32_t caps, - size_t bytes, size_t old_bytes, uint32_t alignment) +void WEAK *rmalloc_align(uint32_t flags, size_t bytes, uint32_t alignment) { (void)flags; - (void)caps; - (void)old_bytes; + (void)alignment; - return realloc(ptr, bytes); + return malloc(bytes); +} + +void WEAK *rmalloc(uint32_t flags, size_t bytes) +{ + (void)flags; + + return malloc(bytes); } void WEAK rfree(void *ptr) @@ -78,6 +79,68 @@ void WEAK rfree(void *ptr) free(ptr); } +void WEAK *mod_balloc_align(struct processing_module *mod, size_t size, size_t alignment) +{ + void *ret; + (void)mod; + (void)alignment; + + ret = malloc(size); + + assert(ret); + + return ret; +} + +void WEAK *mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size, + size_t alignment) +{ + void *ret; + (void)mod; + (void)flags; + (void)alignment; + + ret = malloc(size); + + assert(ret); + + return ret; +} + +int WEAK mod_free(struct processing_module *mod, const void *ptr) +{ + (void)mod; + free((void *)ptr); + return 0; +} + +struct k_heap * WEAK sof_sys_heap_get(void) +{ + return NULL; +} + +struct k_heap * WEAK sof_sys_user_heap_get(void) +{ + return NULL; +} + +void WEAK *sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, + size_t alignment) +{ + (void)heap; + (void)flags; + (void)alignment; + + return malloc(bytes); +} + +void WEAK sof_heap_free(struct k_heap *heap, void *addr) +{ + (void)heap; + + free(addr); +} + int WEAK memcpy_s(void *dest, size_t dest_size, const void *src, size_t count) { @@ -152,22 +215,6 @@ volatile void * WEAK task_context_get(void) return NULL; } -#ifndef __ZEPHYR__ -uint32_t WEAK _k_spin_lock_irq(struct k_spinlock *lock) -{ - (void)lock; - - return 0; -} - -void WEAK _k_spin_unlock_irq(struct k_spinlock *lock, uint32_t flags, int line) -{ - (void)lock; - (void)flags; - (void)line; -} -#endif - uint64_t WEAK platform_timer_get(struct timer *timer) { (void)timer; @@ -332,7 +379,6 @@ int WEAK comp_set_state(struct comp_dev *dev, int cmd) return 0; } -#ifndef __ZEPHYR__ uint64_t WEAK clock_ms_to_ticks(int clock, uint64_t ms) { (void)clock; @@ -356,7 +402,6 @@ uint64_t WEAK clock_ns_to_ticks(int clock, uint64_t us) return 0; } -#endif /* __ZEPHYR__ */ #if CONFIG_MULTICORE && !CONFIG_LIBRARY diff --git a/test/cmocka/src/lib/CMakeLists.txt b/test/cmocka/src/lib/CMakeLists.txt index 3059c9de9068..ad3788bc98f0 100644 --- a/test/cmocka/src/lib/CMakeLists.txt +++ b/test/cmocka/src/lib/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(alloc) add_subdirectory(lib) +add_subdirectory(fast-get) diff --git a/test/cmocka/src/lib/alloc/CMakeLists.txt b/test/cmocka/src/lib/alloc/CMakeLists.txt index 4b7649599435..c9ba91a9a1d7 100644 --- a/test/cmocka/src/lib/alloc/CMakeLists.txt +++ b/test/cmocka/src/lib/alloc/CMakeLists.txt @@ -5,7 +5,6 @@ if(BUILD_UNIT_TESTS_HOST) alloc.c ${PROJECT_SOURCE_DIR}/src/lib/alloc.c ${PROJECT_SOURCE_DIR}/src/platform/library/lib/memory.c - ${PROJECT_SOURCE_DIR}/src/spinlock.c ) else() if(CONFIG_CAVS) @@ -15,7 +14,6 @@ else() alloc.c ${PROJECT_SOURCE_DIR}/src/lib/alloc.c ${PROJECT_SOURCE_DIR}/src/debug/panic.c - ${PROJECT_SOURCE_DIR}/src/spinlock.c ${MEMORY_FILE} ) endif() diff --git a/test/cmocka/src/lib/alloc/alloc.c b/test/cmocka/src/lib/alloc/alloc.c index a0c975664542..d666141c45b2 100644 --- a/test/cmocka/src/lib/alloc/alloc.c +++ b/test/cmocka/src/lib/alloc/alloc.c @@ -26,44 +26,43 @@ enum test_type { struct test_case { size_t alloc_size; - int alloc_zone; - uint32_t alloc_caps; + uint32_t alloc_flags; uint16_t alloc_num; enum test_type type; const char *name; }; -#define TEST_CASE(bytes, zone, caps, num, type, name_base) \ - {(bytes), (zone), (caps), (num), (type), \ - ("test_lib_alloc_" name_base "__" #zone "__" #bytes "x" #num)} +#define TEST_CASE(bytes, flags, num, type, name_base) \ + {(bytes), (flags), (num), (type), \ + ("test_lib_alloc_" name_base "__" #flags "__" #bytes "x" #num)} static struct test_case test_cases[] = { /* * rmalloc tests */ - TEST_CASE(1, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 2, TEST_BULK, + TEST_CASE(1, SOF_MEM_FLAG_USER, 2, TEST_BULK, "rmalloc"), - TEST_CASE(4, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 2, TEST_BULK, + TEST_CASE(4, SOF_MEM_FLAG_USER, 2, TEST_BULK, "rmalloc"), - TEST_CASE(256, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 2, TEST_BULK, + TEST_CASE(256, SOF_MEM_FLAG_USER, 2, TEST_BULK, "rmalloc"), - TEST_CASE(1, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 4, TEST_BULK, + TEST_CASE(1, SOF_MEM_FLAG_USER, 4, TEST_BULK, "rmalloc"), - TEST_CASE(4, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 4, TEST_BULK, + TEST_CASE(4, SOF_MEM_FLAG_USER, 4, TEST_BULK, "rmalloc"), - TEST_CASE(256, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 4, TEST_BULK, + TEST_CASE(256, SOF_MEM_FLAG_USER, 4, TEST_BULK, "rmalloc"), - TEST_CASE(1, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 8, TEST_BULK, + TEST_CASE(1, SOF_MEM_FLAG_USER, 8, TEST_BULK, "rmalloc"), - TEST_CASE(4, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 8, TEST_BULK, + TEST_CASE(4, SOF_MEM_FLAG_USER, 8, TEST_BULK, "rmalloc"), - TEST_CASE(256, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 8, TEST_BULK, + TEST_CASE(256, SOF_MEM_FLAG_USER, 8, TEST_BULK, "rmalloc"), - TEST_CASE(16, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 128, TEST_BULK, + TEST_CASE(16, SOF_MEM_FLAG_USER, 128, TEST_BULK, "rmalloc"), /* @@ -71,135 +70,95 @@ static struct test_case test_cases[] = { * the RZONE_BUFFER and RZONE_RUNTIME tests will not work. */ - TEST_CASE(1, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 2, TEST_BULK, + TEST_CASE(1, SOF_MEM_FLAG_USER, 2, TEST_BULK, "rmalloc"), - TEST_CASE(4, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 2, TEST_BULK, + TEST_CASE(4, SOF_MEM_FLAG_USER, 2, TEST_BULK, "rmalloc"), - TEST_CASE(256, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 2, TEST_BULK, + TEST_CASE(256, SOF_MEM_FLAG_USER, 2, TEST_BULK, "rmalloc"), - TEST_CASE(1, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 4, TEST_BULK, + TEST_CASE(1, SOF_MEM_FLAG_USER, 4, TEST_BULK, "rmalloc"), - TEST_CASE(4, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 4, TEST_BULK, + TEST_CASE(4, SOF_MEM_FLAG_USER, 4, TEST_BULK, "rmalloc"), - TEST_CASE(256, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 4, TEST_BULK, + TEST_CASE(256, SOF_MEM_FLAG_USER, 4, TEST_BULK, "rmalloc"), - TEST_CASE(1, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 8, TEST_BULK, + TEST_CASE(1, SOF_MEM_FLAG_USER, 8, TEST_BULK, "rmalloc"), - TEST_CASE(4, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 8, TEST_BULK, + TEST_CASE(4, SOF_MEM_FLAG_USER, 8, TEST_BULK, "rmalloc"), - TEST_CASE(256, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 8, TEST_BULK, + TEST_CASE(256, SOF_MEM_FLAG_USER, 8, TEST_BULK, "rmalloc"), - TEST_CASE(16, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 128, TEST_BULK, + TEST_CASE(16, SOF_MEM_FLAG_USER, 128, TEST_BULK, "rmalloc"), - TEST_CASE(1, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM | - SOF_MEM_CAPS_DMA, 2, TEST_BULK, "rmalloc_dma"), - TEST_CASE(4, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM | - SOF_MEM_CAPS_DMA, 2, TEST_BULK, "rmalloc_dma"), - TEST_CASE(256, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM | - SOF_MEM_CAPS_DMA, 2, TEST_BULK, "rmalloc_dma"), + TEST_CASE(1, (SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA), + 2, TEST_BULK, "rmalloc_dma"), + TEST_CASE(4, (SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA), + 2, TEST_BULK, "rmalloc_dma"), + TEST_CASE(256, (SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA), + 2, TEST_BULK, "rmalloc_dma"), /* * rzalloc tests */ - TEST_CASE(1, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 2, TEST_ZERO, + TEST_CASE(1, SOF_MEM_FLAG_USER, 2, TEST_ZERO, "rzalloc"), - TEST_CASE(4, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 2, TEST_ZERO, + TEST_CASE(4, SOF_MEM_FLAG_USER, 2, TEST_ZERO, "rzalloc"), - TEST_CASE(256, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 2, TEST_ZERO, + TEST_CASE(256, SOF_MEM_FLAG_USER, 2, TEST_ZERO, "rzalloc"), - TEST_CASE(1, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 4, TEST_ZERO, + TEST_CASE(1, SOF_MEM_FLAG_USER, 4, TEST_ZERO, "rzalloc"), - TEST_CASE(4, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 4, TEST_ZERO, + TEST_CASE(4, SOF_MEM_FLAG_USER, 4, TEST_ZERO, "rzalloc"), - TEST_CASE(256, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 4, TEST_ZERO, + TEST_CASE(256, SOF_MEM_FLAG_USER, 4, TEST_ZERO, "rzalloc"), - TEST_CASE(1, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 8, TEST_ZERO, + TEST_CASE(1, SOF_MEM_FLAG_USER, 8, TEST_ZERO, "rzalloc"), - TEST_CASE(4, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 8, TEST_ZERO, + TEST_CASE(4, SOF_MEM_FLAG_USER, 8, TEST_ZERO, "rzalloc"), - TEST_CASE(256, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 8, TEST_ZERO, + TEST_CASE(256, SOF_MEM_FLAG_USER, 8, TEST_ZERO, "rzalloc"), - TEST_CASE(16, SOF_MEM_ZONE_SYS, SOF_MEM_CAPS_RAM, 128, TEST_ZERO, + TEST_CASE(16, SOF_MEM_FLAG_USER, 128, TEST_ZERO, "rzalloc"), - TEST_CASE(1, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 2, TEST_ZERO, + TEST_CASE(1, SOF_MEM_FLAG_USER, 2, TEST_ZERO, "rzalloc"), - TEST_CASE(4, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 2, TEST_ZERO, + TEST_CASE(4, SOF_MEM_FLAG_USER, 2, TEST_ZERO, "rzalloc"), - TEST_CASE(256, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 2, TEST_ZERO, + TEST_CASE(256, SOF_MEM_FLAG_USER, 2, TEST_ZERO, "rzalloc"), - TEST_CASE(1, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 4, TEST_ZERO, + TEST_CASE(1, SOF_MEM_FLAG_USER, 4, TEST_ZERO, "rzalloc"), - TEST_CASE(4, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 4, TEST_ZERO, + TEST_CASE(4, SOF_MEM_FLAG_USER, 4, TEST_ZERO, "rzalloc"), - TEST_CASE(256, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 4, TEST_ZERO, + TEST_CASE(256, SOF_MEM_FLAG_USER, 4, TEST_ZERO, "rzalloc"), - TEST_CASE(1, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 8, TEST_ZERO, + TEST_CASE(1, SOF_MEM_FLAG_USER, 8, TEST_ZERO, "rzalloc"), - TEST_CASE(4, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 8, TEST_ZERO, + TEST_CASE(4, SOF_MEM_FLAG_USER, 8, TEST_ZERO, "rzalloc"), - TEST_CASE(256, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 8, TEST_ZERO, + TEST_CASE(256, SOF_MEM_FLAG_USER, 8, TEST_ZERO, "rzalloc"), - TEST_CASE(16, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM, 128, TEST_ZERO, + TEST_CASE(16, SOF_MEM_FLAG_USER, 128, TEST_ZERO, "rzalloc"), - TEST_CASE(1, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM | - SOF_MEM_CAPS_DMA, 2, TEST_ZERO, "rzalloc_dma"), - TEST_CASE(4, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM | - SOF_MEM_CAPS_DMA, 2, TEST_ZERO, "rzalloc_dma"), - TEST_CASE(256, SOF_MEM_ZONE_RUNTIME, SOF_MEM_CAPS_RAM | - SOF_MEM_CAPS_DMA, 2, TEST_ZERO, "rzalloc_dma"), - - /* - * rballoc tests - */ - - TEST_CASE(4, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 1024, - TEST_IMMEDIATE_FREE, "rballoc"), - - TEST_CASE(1, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 2, TEST_BULK, - "rballoc"), - TEST_CASE(4, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 2, TEST_BULK, - "rballoc"), - TEST_CASE(256, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 2, TEST_BULK, - "rballoc"), - - TEST_CASE(1, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 4, TEST_BULK, - "rballoc"), - TEST_CASE(4, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 4, TEST_BULK, - "rballoc"), - TEST_CASE(256, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 4, TEST_BULK, - "rballoc"), - - TEST_CASE(1, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 8, TEST_BULK, - "rballoc"), - TEST_CASE(4, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 8, TEST_BULK, - "rballoc"), - TEST_CASE(256, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 8, TEST_BULK, - "rballoc"), - - TEST_CASE(16, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 64, TEST_BULK, - "rballoc"), - TEST_CASE(4, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM, 64, TEST_BULK, - "rballoc"), - - TEST_CASE(1, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, - 2, TEST_BULK, "rballoc_dma"), - TEST_CASE(4, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, - 2, TEST_BULK, "rballoc_dma"), - TEST_CASE(256, SOF_MEM_ZONE_BUFFER, SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, - 2, TEST_BULK, "rballoc_dma"), + TEST_CASE(1, (SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA), + 2, TEST_ZERO, "rzalloc_dma"), + TEST_CASE(4, (SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA), + 2, TEST_ZERO, "rzalloc_dma"), + TEST_CASE(256, (SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA), + 2, TEST_ZERO, "rzalloc_dma"), }; static int setup(void **state) @@ -234,11 +193,8 @@ static void *alloc(struct test_case *tc) { void *mem; - if (tc->alloc_zone == SOF_MEM_ZONE_BUFFER) - mem = rballoc(0, tc->alloc_caps, tc->alloc_size); - else - mem = rmalloc(tc->alloc_zone, 0, tc->alloc_caps, - tc->alloc_size); + mem = rmalloc(tc->alloc_flags, + tc->alloc_size); return mem; } @@ -247,10 +203,8 @@ static void alloc_free(void **mem, struct test_case *tc) { int i; - if (tc->alloc_zone != SOF_MEM_ZONE_SYS) { - for (i = 0; i < tc->alloc_num; ++i) - rfree(mem[i]); - } + for (i = 0; i < tc->alloc_num; ++i) + rfree(mem[i]); } static void test_lib_alloc_bulk_free(struct test_case *tc) @@ -288,7 +242,7 @@ static void test_lib_alloc_zero(struct test_case *tc) int i; for (i = 0; i < tc->alloc_num; ++i) { - char *mem = rzalloc(tc->alloc_zone, 0, tc->alloc_caps, + char *mem = rzalloc(tc->alloc_flags, tc->alloc_size); int j; diff --git a/test/cmocka/src/lib/fast-get/CMakeLists.txt b/test/cmocka/src/lib/fast-get/CMakeLists.txt new file mode 100644 index 000000000000..8449320f4e6b --- /dev/null +++ b/test/cmocka/src/lib/fast-get/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: BSD-3-Clause + +cmocka_test(fast-get-tests + fast-get-tests.c + ${PROJECT_SOURCE_DIR}/src/lib/objpool.c + ${PROJECT_SOURCE_DIR}/zephyr/lib/fast-get.c + ${PROJECT_SOURCE_DIR}/src/lib/alloc.c + ${PROJECT_SOURCE_DIR}/src/platform/library/lib/memory.c +) + +target_link_libraries(fast-get-tests PRIVATE "-Wl,--wrap=rzalloc,--wrap=rmalloc,--wrap=rfree") diff --git a/test/cmocka/src/lib/fast-get/fast-get-tests.c b/test/cmocka/src/lib/fast-get/fast-get-tests.c new file mode 100644 index 000000000000..bd4a6fedfea3 --- /dev/null +++ b/test/cmocka/src/lib/fast-get/fast-get-tests.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Intel Corporation. All rights reserved. +// +// Author: Jyri Sarha <jyri.sarha@linux.intel.com> + +#include <sof/lib/fast-get.h> +#include <rtos/sof.h> +#include <rtos/alloc.h> +#include <sof/lib/mm_heap.h> +#include <sof/lib/memory.h> +#include <sof/common.h> + +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <cmocka.h> +#include <assert.h> + +static const int testdata[33][100] = { + { + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + }, + { 2 }, + { 3 }, + { 4 }, + { 5 }, + { 6 }, + { 7 }, + { 8 }, + { 9 }, + { 10 }, + { 11 }, + { 12 }, + { 13 }, + { 14 }, + { 15 }, + { 16 }, + { 17 }, + { 18 }, + { 19 }, + { 20 }, + { 21 }, + { 23 }, + { 24 }, + { 25 }, + { 26 }, + { 27 }, + { 28 }, + { 29 }, + { 30 }, + { 31 }, + { 32 }, + { 33 }, +}; + +static void test_simple_fast_get_put(void **state) +{ + const void *ret; + + (void)state; /* unused */ + + ret = fast_get(NULL, testdata[0], sizeof(testdata[0])); + + assert(ret); + assert(!memcmp(ret, testdata[0], sizeof(testdata[0]))); + + fast_put(NULL, NULL, ret); +} + +static void test_fast_get_size_missmatch_test(void **state) +{ + const void *ret[2]; + + (void)state; /* unused */ + + ret[0] = fast_get(NULL, testdata[0], sizeof(testdata[0])); + + assert(ret[0]); + assert(!memcmp(ret[0], testdata[0], sizeof(testdata[0]))); + + ret[1] = fast_get(NULL, testdata[0], sizeof(testdata[0]) + 1); + assert(!ret[1]); + + fast_put(NULL, NULL, ret); +} + +static void test_over_32_fast_gets_and_puts(void **state) +{ + const void *copy[ARRAY_SIZE(testdata)]; + int i; + + (void)state; /* unused */ + + for (i = 0; i < ARRAY_SIZE(copy); i++) + copy[i] = fast_get(NULL, testdata[i], sizeof(testdata[0])); + + for (i = 0; i < ARRAY_SIZE(copy); i++) + assert(!memcmp(copy[i], testdata[i], sizeof(testdata[0]))); + + for (i = 0; i < ARRAY_SIZE(copy); i++) + fast_put(NULL, NULL, copy[i]); +} + +static void test_fast_get_refcounting(void **state) +{ + const void *copy[2][ARRAY_SIZE(testdata)]; + int i; + (void)state; /* unused */ + + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + copy[0][i] = fast_get(NULL, testdata[i], sizeof(testdata[0])); + + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + copy[1][i] = fast_get(NULL, testdata[i], sizeof(testdata[0])); + + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + assert(copy[0][i] == copy[1][i]); + + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + assert(!memcmp(copy[0][i], testdata[i], sizeof(testdata[0]))); + + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + fast_put(NULL, NULL, copy[0][i]); + + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + assert(!memcmp(copy[1][i], testdata[i], sizeof(testdata[0]))); + + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + fast_put(NULL, NULL, copy[1][i]); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_simple_fast_get_put), + cmocka_unit_test(test_fast_get_size_missmatch_test), + cmocka_unit_test(test_over_32_fast_gets_and_puts), + cmocka_unit_test(test_fast_get_refcounting), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} + +void *__wrap_rzalloc(uint32_t flags, size_t bytes); +void *__wrap_rmalloc(uint32_t flags, size_t bytes); +void __wrap_rfree(void *ptr); + +void *__wrap_rzalloc(uint32_t flags, size_t bytes) +{ + void *ret; + (void)flags; + + ret = malloc(bytes); + + assert(ret); + + memset(ret, 0, bytes); + + return ret; +} + +void *__wrap_rmalloc(uint32_t flags, size_t bytes) +{ + void *ret; + (void)flags; + + ret = malloc(bytes); + + assert(ret); + + return ret; +} + +void __wrap_rfree(void *ptr) +{ + free(ptr); +} diff --git a/test/cmocka/src/list/CMakeLists.txt b/test/cmocka/src/list/CMakeLists.txt deleted file mode 100644 index 5b8c5699512e..000000000000 --- a/test/cmocka/src/list/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -cmocka_test(list_init - list_init.c -) - -cmocka_test(list_is_empty - list_is_empty.c -) - -cmocka_test(list_item_append - list_item_append.c -) - -cmocka_test(list_item_del - list_item_del.c -) - -cmocka_test(list_item_is_last - list_item_is_last.c -) - -cmocka_test(list_item_prepend - list_item_prepend.c -) - -cmocka_test(list_item - list_item.c -) diff --git a/test/cmocka/src/list/list_init.c b/test/cmocka/src/list/list_init.c deleted file mode 100644 index 08ac2a9f0c4f..000000000000 --- a/test/cmocka/src/list/list_init.c +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Janusz Jankowski <janusz.jankowski@linux.intel.com> - -#include <sof/list.h> - -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -static void test_list_list_init_prev_equal_to_root(void **state) -{ - (void) state; /* unused */ - - struct list_item list = {.prev = NULL, .next = NULL}; - - list_init(&list); - - assert_ptr_equal(&list, list.prev); -} - -static void test_list_list_init_next_equal_to_root(void **state) -{ - (void) state; /* unused */ - - struct list_item list = {.prev = NULL, .next = NULL}; - - list_init(&list); - - assert_ptr_equal(&list, list.next); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_list_list_init_prev_equal_to_root), - cmocka_unit_test(test_list_list_init_next_equal_to_root), - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/list/list_is_empty.c b/test/cmocka/src/list/list_is_empty.c deleted file mode 100644 index 300967dd80ec..000000000000 --- a/test/cmocka/src/list/list_is_empty.c +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Janusz Jankowski <janusz.jankowski@linux.intel.com> - -#include <sof/list.h> - -#include <stdlib.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -static void test_list_list_is_empty_when_empty_then_true(void **state) -{ - (void) state; /* unused */ - - struct list_item list; - - list_init(&list); - - assert_true(list_is_empty(&list)); -} - -static void test_list_list_is_empty_when_not_empty_then_false(void **state) -{ - (void) state; /* unused */ - - struct list_item list, item; - - list_init(&list); - list_init(&item); - - list_item_append(&item, &list); - - assert_false(list_is_empty(&list)); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_list_list_is_empty_when_empty_then_true), - cmocka_unit_test(test_list_list_is_empty_when_not_empty_then_false), - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/list/list_item.c b/test/cmocka/src/list/list_item.c deleted file mode 100644 index d8d0b45ab2a8..000000000000 --- a/test/cmocka/src/list/list_item.c +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Janusz Jankowski <janusz.jankowski@linux.intel.com> - -#include <sof/list.h> - -#include <stdlib.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -struct test_list_container { - void *field1; - struct list_item list; - void *field2; -}; - -static void test_list_list_item_when_valid_offset_then_ptr_equal(void **state) -{ - (void) state; /* unused */ - - struct test_list_container container; - - list_init(&(container.list)); - - struct test_list_container *result_container = list_item( - &(container.list), struct test_list_container, list); - - assert_ptr_equal(result_container, &container); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_list_list_item_when_valid_offset_then_ptr_equal), - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/list/list_item_append.c b/test/cmocka/src/list/list_item_append.c deleted file mode 100644 index ff4ba2f7f68c..000000000000 --- a/test/cmocka/src/list/list_item_append.c +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Janusz Jankowski <janusz.jankowski@linux.intel.com> - -#include <sof/list.h> - -#include <stdlib.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -struct test_data { - struct list_item *head; - struct list_item *tail_minus_1; - struct list_item *tail; -}; - -static int setup(void **state) -{ - struct test_data *data = malloc(sizeof(struct test_data)); - - if (!data) - return -1; - - data->head = malloc(sizeof(struct list_item)); - data->tail_minus_1 = malloc(sizeof(struct list_item)); - data->tail = malloc(sizeof(struct list_item)); - - if (!data->head || !data->tail_minus_1 - || !data->tail) { - free(data->head); - free(data->tail_minus_1); - free(data->tail); - - free(data); - - return -1; - } - - list_init(data->head); - list_init(data->tail_minus_1); - list_init(data->tail); - - list_item_append(data->tail_minus_1, data->head); - list_item_append(data->tail, data->head); - - *state = data; - return 0; -} - -static int teardown(void **state) -{ - struct test_data *data = *state; - - free(data->head); - free(data->tail_minus_1); - free(data->tail); - - free(data); - return 0; -} - -static void test_list_list_item_append_head_prev_is_tail(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->head->prev, data->tail); -} - -static void test_list_list_item_append_head_next_is_tail_minus_1(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->head->next, data->tail_minus_1); -} - -static void test_list_list_item_append_tail_minus_1_prev_is_head(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->tail_minus_1->prev, data->head); -} - -static void test_list_list_item_append_tail_minus_1_next_is_tail(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->tail_minus_1->next, data->tail); -} - -static void test_list_list_item_append_tail_prev_is_tail_minus_1(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->tail->prev, data->tail_minus_1); -} - -static void test_list_list_item_append_tail_next_is_head(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->tail->next, data->head); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_list_list_item_append_head_prev_is_tail), - cmocka_unit_test(test_list_list_item_append_head_next_is_tail_minus_1), - cmocka_unit_test(test_list_list_item_append_tail_minus_1_prev_is_head), - cmocka_unit_test(test_list_list_item_append_tail_minus_1_next_is_tail), - cmocka_unit_test(test_list_list_item_append_tail_prev_is_tail_minus_1), - cmocka_unit_test(test_list_list_item_append_tail_next_is_head), - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, setup, teardown); -} diff --git a/test/cmocka/src/list/list_item_del.c b/test/cmocka/src/list/list_item_del.c deleted file mode 100644 index ad6bb81a1237..000000000000 --- a/test/cmocka/src/list/list_item_del.c +++ /dev/null @@ -1,197 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Janusz Jankowski <janusz.jankowski@linux.intel.com> - -#include <sof/list.h> - -#include <stdlib.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -struct test_data { - struct list_item *head; - struct list_item *tail_minus_1; - struct list_item *tail; -}; - -static int setup(void **state) -{ - struct test_data *data = malloc(sizeof(struct test_data)); - - if (!data) - return -1; - - data->head = malloc(sizeof(struct list_item)); - data->tail_minus_1 = malloc(sizeof(struct list_item)); - data->tail = malloc(sizeof(struct list_item)); - - if (!data->head || !data->tail_minus_1 - || !data->tail) { - free(data->head); - free(data->tail_minus_1); - free(data->tail); - - free(data); - - return -1; - } - - list_init(data->head); - list_init(data->tail_minus_1); - list_init(data->tail); - - list_item_append(data->tail_minus_1, data->head); - list_item_append(data->tail, data->head); - - *state = data; - return 0; -} - -static int teardown(void **state) -{ - struct test_data *data = *state; - - free(data->head); - free(data->tail_minus_1); - free(data->tail); - - free(data); - return 0; -} - -static void test_list_list_item_del_when_delete_head_then_tail_minus_1_prev_is_tail(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->head); - - assert_ptr_equal(data->tail_minus_1->prev, data->tail); -} - -static void test_list_list_item_del_when_delete_head_then_tail_minus_1_next_is_tail(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->head); - - assert_ptr_equal(data->tail_minus_1->next, data->tail); -} - -static void test_list_list_item_del_when_delete_head_then_tail_prev_is_tail_minus_1(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->head); - - assert_ptr_equal(data->tail->prev, data->tail_minus_1); -} - -static void test_list_list_item_del_when_delete_head_then_tail_next_is_tail_minus_1(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->head); - - assert_ptr_equal(data->tail->next, data->tail_minus_1); -} - -static void test_list_list_item_del_when_delete_tail_minus_1_then_head_prev_is_tail(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->tail_minus_1); - - assert_ptr_equal(data->head->prev, data->tail); -} - -static void test_list_list_item_del_when_delete_tail_minus_1_then_head_next_is_tail(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->tail_minus_1); - - assert_ptr_equal(data->head->next, data->tail); -} - -static void test_list_list_item_del_when_delete_tail_minus_1_then_tail_prev_is_head(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->tail_minus_1); - - assert_ptr_equal(data->tail->prev, data->head); -} - -static void test_list_list_item_del_when_delete_tail_minus_1_then_tail_next_is_head(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->tail_minus_1); - - assert_ptr_equal(data->tail->next, data->head); -} - -static void test_list_list_item_del_when_delete_tail_then_head_prev_is_tail_minus_1(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->tail); - - assert_ptr_equal(data->head->prev, data->tail_minus_1); -} - -static void test_list_list_item_del_when_delete_tail_then_head_next_is_tail_minus_1(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->tail); - - assert_ptr_equal(data->head->next, data->tail_minus_1); -} - -static void test_list_list_item_del_when_delete_tail_then_tail_minus_1_prev_is_head(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->tail); - - assert_ptr_equal(data->tail_minus_1->prev, data->head); -} - -static void test_list_list_item_del_when_delete_tail_then_tail_minus_1_next_is_head(void **state) -{ - struct test_data *data = *state; - - list_item_del(data->tail); - - assert_ptr_equal(data->tail_minus_1->next, data->head); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_head_then_tail_minus_1_prev_is_tail, setup, teardown), - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_head_then_tail_minus_1_next_is_tail, setup, teardown), - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_head_then_tail_prev_is_tail_minus_1, setup, teardown), - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_head_then_tail_next_is_tail_minus_1, setup, teardown), - - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_tail_minus_1_then_head_prev_is_tail, setup, teardown), - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_tail_minus_1_then_head_next_is_tail, setup, teardown), - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_tail_minus_1_then_tail_prev_is_head, setup, teardown), - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_tail_minus_1_then_tail_next_is_head, setup, teardown), - - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_tail_then_head_prev_is_tail_minus_1, setup, teardown), - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_tail_then_head_next_is_tail_minus_1, setup, teardown), - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_tail_then_tail_minus_1_prev_is_head, setup, teardown), - cmocka_unit_test_setup_teardown(test_list_list_item_del_when_delete_tail_then_tail_minus_1_next_is_head, setup, teardown), - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/list/list_item_is_last.c b/test/cmocka/src/list/list_item_is_last.c deleted file mode 100644 index ffd1abee50bd..000000000000 --- a/test/cmocka/src/list/list_item_is_last.c +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Janusz Jankowski <janusz.jankowski@linux.intel.com> - -#include <sof/list.h> - -#include <stdlib.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -struct test_data { - struct list_item *head; - struct list_item *tail_minus_1; - struct list_item *tail; -}; - -static int setup(void **state) -{ - struct test_data *data = malloc(sizeof(struct test_data)); - - if (!data) - return -1; - - data->head = malloc(sizeof(struct list_item)); - data->tail_minus_1 = malloc(sizeof(struct list_item)); - data->tail = malloc(sizeof(struct list_item)); - - if (!data->head || !data->tail_minus_1 - || !data->tail) { - free(data->head); - free(data->tail_minus_1); - free(data->tail); - - free(data); - - return -1; - } - - list_init(data->head); - list_init(data->tail_minus_1); - list_init(data->tail); - - list_item_append(data->tail_minus_1, data->head); - list_item_append(data->tail, data->head); - - *state = data; - return 0; -} - -static int teardown(void **state) -{ - struct test_data *data = *state; - - free(data->head); - free(data->tail_minus_1); - free(data->tail); - - free(data); - return 0; -} - -static void test_list_list_item_is_last_when_head_then_false(void **state) -{ - struct test_data *data = *state; - - assert_false(list_item_is_last(data->head, data->head)); -} - -static void test_list_list_item_is_last_when_tail_minus_1_then_false(void **state) -{ - struct test_data *data = *state; - - assert_false(list_item_is_last(data->tail_minus_1, data->head)); -} - -static void test_list_list_item_is_last_when_tail_then_true(void **state) -{ - struct test_data *data = *state; - - assert_true(list_item_is_last(data->tail, data->head)); -} - -static void test_list_list_item_is_last_when_not_in_list_then_false(void **state) -{ - struct list_item other_list; - struct test_data *data = *state; - - list_init(&other_list); - - assert_false(list_item_is_last(&other_list, data->head)); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_list_list_item_is_last_when_head_then_false), - cmocka_unit_test(test_list_list_item_is_last_when_tail_minus_1_then_false), - cmocka_unit_test(test_list_list_item_is_last_when_tail_then_true), - cmocka_unit_test(test_list_list_item_is_last_when_not_in_list_then_false), - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, setup, teardown); -} diff --git a/test/cmocka/src/list/list_item_prepend.c b/test/cmocka/src/list/list_item_prepend.c deleted file mode 100644 index e86fa97f8a5e..000000000000 --- a/test/cmocka/src/list/list_item_prepend.c +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Janusz Jankowski <janusz.jankowski@linux.intel.com> - -#include <sof/list.h> - -#include <stdlib.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -struct test_data { - struct list_item *head; - struct list_item *tail_minus_1; - struct list_item *tail; -}; - -static int setup(void **state) -{ - struct test_data *data = malloc(sizeof(struct test_data)); - - if (!data) - return -1; - - data->head = malloc(sizeof(struct list_item)); - data->tail_minus_1 = malloc(sizeof(struct list_item)); - data->tail = malloc(sizeof(struct list_item)); - - if (!data->head || !data->tail_minus_1 - || !data->tail) { - free(data->head); - free(data->tail_minus_1); - free(data->tail); - - free(data); - - return -1; - } - - list_init(data->head); - list_init(data->tail_minus_1); - list_init(data->tail); - - list_item_prepend(data->tail, data->head); - list_item_prepend(data->tail_minus_1, data->head); - - *state = data; - return 0; -} - -static int teardown(void **state) -{ - struct test_data *data = *state; - - free(data->head); - free(data->tail_minus_1); - free(data->tail); - - free(data); - return 0; -} - -static void test_list_list_item_prepend_head_prev_is_tail(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->head->prev, data->tail); -} - -static void test_list_list_item_prepend_head_next_is_tail_minus_1(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->head->next, data->tail_minus_1); -} - -static void test_list_list_item_prepend_tail_minus_1_prev_is_head(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->tail_minus_1->prev, data->head); -} - -static void test_list_list_item_prepend_tail_minus_1_next_is_tail(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->tail_minus_1->next, data->tail); -} - -static void test_list_list_item_prepend_tail_prev_is_tail_minus_1(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->tail->prev, data->tail_minus_1); -} - -static void test_list_list_item_prepend_tail_next_is_head(void **state) -{ - struct test_data *data = *state; - - assert_ptr_equal(data->tail->next, data->head); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_list_list_item_prepend_head_prev_is_tail), - cmocka_unit_test(test_list_list_item_prepend_head_next_is_tail_minus_1), - cmocka_unit_test(test_list_list_item_prepend_tail_minus_1_prev_is_head), - cmocka_unit_test(test_list_list_item_prepend_tail_minus_1_next_is_tail), - cmocka_unit_test(test_list_list_item_prepend_tail_prev_is_tail_minus_1), - cmocka_unit_test(test_list_list_item_prepend_tail_next_is_head), - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, setup, teardown); -} diff --git a/test/cmocka/src/math/CMakeLists.txt b/test/cmocka/src/math/CMakeLists.txt index 07e5c495a382..83180953eb55 100644 --- a/test/cmocka/src/math/CMakeLists.txt +++ b/test/cmocka/src/math/CMakeLists.txt @@ -1,7 +1,5 @@ # SPDX-License-Identifier: BSD-3-Clause -add_subdirectory(numbers) -add_subdirectory(trig) add_subdirectory(arithmetic) add_subdirectory(fft) add_subdirectory(window) diff --git a/test/cmocka/src/math/arithmetic/CMakeLists.txt b/test/cmocka/src/math/arithmetic/CMakeLists.txt index 0e6ab3619227..6625aef444ef 100644 --- a/test/cmocka/src/math/arithmetic/CMakeLists.txt +++ b/test/cmocka/src/math/arithmetic/CMakeLists.txt @@ -1,33 +1,11 @@ # SPDX-License-Identifier: BSD-3-Clause -cmocka_test(scalar_power - scalar_power.c - ${PROJECT_SOURCE_DIR}/src/math/power.c +cmocka_test(a_law_codec + a_law_codec.c + ${PROJECT_SOURCE_DIR}/src/math/a_law.c ) -cmocka_test(base2_logarithm - base2_logarithm.c - ${PROJECT_SOURCE_DIR}/src/math/base2log.c -) - -cmocka_test(exponential - exponential.c - ${PROJECT_SOURCE_DIR}/src/math/exp_fcn.c - ${PROJECT_SOURCE_DIR}/src/math/exp_fcn_hifi.c -) -cmocka_test(square_root - square_root.c - ${PROJECT_SOURCE_DIR}/src/math/sqrt_int16.c -) - -cmocka_test(base_10_logarithm - base_10_logarithm.c - ${PROJECT_SOURCE_DIR}/src/math/log_10.c - ${PROJECT_SOURCE_DIR}/src/math/base2log.c -) - -cmocka_test(base_e_logarithm - base_e_logarithm.c - ${PROJECT_SOURCE_DIR}/src/math/log_e.c - ${PROJECT_SOURCE_DIR}/src/math/base2log.c +cmocka_test(mu_law_codec + mu_law_codec.c + ${PROJECT_SOURCE_DIR}/src/math/mu_law.c ) diff --git a/test/cmocka/src/math/arithmetic/a_law_codec.c b/test/cmocka/src/math/arithmetic/a_law_codec.c new file mode 100644 index 000000000000..a0bc4f7aef41 --- /dev/null +++ b/test/cmocka/src/math/arithmetic/a_law_codec.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <stdio.h> +#include <stdint.h> +#include <setjmp.h> +#include <stdbool.h> +#include <cmocka.h> +#include <sof/math/a_law.h> + +#include "ref_chirp_mono_8k_s16.h" +#include "a_law_codec.h" + +static void test_a_law_encode(void **state) +{ + (void)state; + + uint8_t a_law_sample, a_law_ref; + int i; + + for (i = 0; i < REF_DATA_SAMPLE_COUNT; i++) { + a_law_sample = sofm_a_law_encode(chirp_mono_8k_s16[i]); + a_law_ref = ref_alaw_enc_data[i]; + + if (a_law_sample != a_law_ref) { + printf("%s: difference found at %d, encoded %d, ref %d, lin %d\n", + __func__, i, a_law_sample, a_law_ref, chirp_mono_8k_s16[i]); + assert_true(false); + } + } +} + +static void test_a_law_decode(void **state) +{ + (void)state; + + int16_t s16_sample, s16_ref; + int i; + + for (i = 0; i < REF_DATA_SAMPLE_COUNT; i++) { + s16_sample = sofm_a_law_decode(ref_alaw_enc_data[i]); + s16_ref = ref_alaw_dec_data[i]; + if (s16_sample != s16_ref) { + printf("%s: difference found at %d, decoded %d, ref %d\n", + __func__, i, s16_sample, s16_ref); + assert_true(false); + } + } +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_a_law_encode), + cmocka_unit_test(test_a_law_decode), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/test/cmocka/src/math/arithmetic/a_law_codec.h b/test/cmocka/src/math/arithmetic/a_law_codec.h new file mode 100644 index 000000000000..403b368f074f --- /dev/null +++ b/test/cmocka/src/math/arithmetic/a_law_codec.h @@ -0,0 +1,814 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 13-May-2025 18:29:28 with script a_law_mu_law_test_vectors.m */ + +#include <stdint.h> + +static const uint8_t ref_alaw_enc_data[4000] = { + 168, 169, 174, 172, 173, 163, 161, 167, 165, 185, + 178, 182, 137, 135, 148, 79, 18, 0, 10, 49, + 60, 59, 36, 38, 32, 34, 45, 47, 46, 41, + 40, 43, 42, 42, 42, 42, 42, 42, 43, 40, + 41, 46, 47, 45, 35, 33, 39, 37, 57, 50, + 55, 14, 4, 111, 251, 153, 141, 180, 179, 190, + 165, 167, 161, 163, 173, 172, 174, 169, 168, 171, + 170, 170, 170, 170, 170, 170, 171, 168, 169, 174, + 172, 173, 163, 161, 167, 186, 190, 179, 181, 130, + 157, 205, 23, 1, 11, 49, 60, 59, 36, 38, + 32, 34, 44, 46, 41, 40, 43, 42, 42, 42, + 42, 42, 42, 43, 40, 41, 47, 44, 34, 32, + 38, 36, 56, 61, 54, 14, 5, 102, 236, 132, + 137, 182, 188, 187, 164, 166, 160, 162, 172, 174, + 169, 168, 171, 170, 170, 170, 170, 170, 171, 171, + 168, 174, 175, 173, 163, 161, 164, 186, 188, 177, + 136, 135, 238, 103, 5, 14, 54, 61, 59, 36, + 38, 35, 45, 44, 46, 41, 43, 43, 42, 42, + 42, 42, 42, 43, 40, 41, 47, 44, 34, 32, + 39, 37, 62, 48, 10, 1, 21, 248, 154, 142, + 182, 188, 187, 164, 161, 163, 173, 175, 174, 168, + 171, 170, 170, 170, 170, 170, 171, 171, 169, 174, + 172, 162, 160, 166, 165, 185, 179, 181, 128, 150, + 112, 24, 14, 54, 60, 59, 39, 33, 35, 45, + 47, 41, 40, 43, 42, 42, 42, 42, 42, 43, + 40, 41, 47, 45, 35, 33, 36, 59, 61, 55, + 13, 18, 216, 158, 143, 182, 188, 187, 167, 161, + 162, 172, 175, 169, 168, 171, 170, 170, 170, 170, + 170, 171, 168, 174, 172, 162, 160, 167, 165, 191, + 177, 137, 155, 246, 16, 2, 55, 61, 59, 36, + 33, 35, 44, 46, 41, 40, 43, 42, 42, 42, + 42, 43, 40, 41, 47, 45, 35, 33, 36, 56, + 50, 52, 0, 106, 224, 135, 138, 179, 185, 164, + 166, 163, 173, 175, 169, 168, 171, 170, 170, 170, + 170, 171, 168, 169, 175, 173, 163, 166, 165, 190, + 176, 139, 133, 243, 16, 13, 55, 60, 58, 39, + 32, 34, 47, 46, 40, 43, 42, 42, 42, 42, + 42, 40, 41, 47, 45, 35, 38, 37, 62, 48, + 9, 24, 89, 159, 142, 177, 190, 165, 166, 163, + 173, 175, 169, 168, 170, 170, 170, 170, 170, 171, + 168, 174, 172, 162, 161, 164, 184, 179, 138, 132, + 240, 18, 15, 49, 63, 37, 38, 35, 45, 47, + 41, 43, 42, 42, 42, 42, 42, 43, 41, 47, + 45, 35, 38, 37, 63, 54, 2, 23, 227, 129, + 180, 189, 186, 167, 160, 173, 175, 169, 168, 170, + 170, 170, 170, 170, 171, 169, 175, 173, 163, 166, + 186, 188, 183, 128, 236, 20, 2, 54, 63, 37, + 38, 35, 44, 46, 40, 43, 42, 42, 42, 42, + 43, 40, 46, 44, 35, 33, 37, 63, 54, 13, + 20, 239, 131, 183, 188, 165, 166, 163, 172, 174, + 168, 171, 170, 170, 170, 170, 171, 169, 174, 173, + 163, 166, 186, 189, 181, 135, 247, 30, 8, 51, + 56, 39, 32, 45, 47, 41, 43, 42, 42, 42, + 42, 43, 40, 46, 44, 35, 38, 37, 61, 52, + 7, 118, 158, 136, 179, 187, 167, 160, 173, 175, + 169, 171, 170, 170, 170, 170, 171, 169, 175, 173, + 160, 164, 185, 176, 143, 145, 108, 3, 54, 62, + 36, 33, 34, 47, 41, 43, 42, 42, 42, 42, + 43, 41, 47, 45, 32, 39, 57, 48, 15, 23, + 235, 141, 177, 185, 164, 160, 173, 175, 169, 171, + 170, 170, 170, 170, 168, 169, 172, 162, 166, 165, + 188, 180, 132, 86, 4, 52, 60, 37, 33, 34, + 47, 41, 43, 42, 42, 42, 42, 43, 41, 47, + 34, 33, 37, 60, 52, 5, 219, 135, 180, 191, + 164, 161, 162, 175, 169, 171, 170, 170, 170, 170, + 168, 174, 172, 163, 167, 184, 176, 143, 149, 22, + 14, 51, 59, 38, 35, 44, 41, 40, 42, 42, + 42, 42, 43, 41, 44, 35, 38, 59, 51, 14, + 23, 148, 142, 179, 187, 166, 163, 172, 169, 171, + 170, 170, 170, 170, 168, 174, 172, 160, 167, 185, + 182, 128, 243, 26, 52, 63, 36, 33, 45, 46, + 40, 43, 42, 42, 42, 43, 41, 47, 35, 38, + 59, 51, 15, 105, 146, 139, 189, 165, 161, 162, + 175, 168, 171, 170, 170, 170, 171, 169, 172, 163, + 166, 187, 176, 130, 229, 27, 52, 63, 36, 32, + 45, 46, 40, 42, 42, 42, 42, 40, 46, 45, + 32, 36, 60, 53, 31, 239, 143, 179, 186, 166, + 162, 175, 168, 171, 170, 170, 170, 171, 174, 172, + 160, 164, 191, 180, 155, 102, 13, 51, 58, 38, + 34, 47, 40, 43, 42, 42, 42, 40, 46, 45, + 32, 36, 61, 11, 17, 145, 139, 188, 164, 160, + 173, 174, 168, 170, 170, 170, 171, 169, 175, 163, + 167, 184, 182, 135, 116, 3, 48, 58, 38, 34, + 47, 40, 42, 42, 42, 43, 40, 47, 34, 38, + 59, 49, 1, 222, 128, 176, 187, 166, 162, 174, + 168, 170, 170, 170, 171, 169, 175, 163, 167, 185, + 183, 155, 109, 14, 61, 37, 32, 45, 46, 43, + 42, 42, 42, 43, 46, 45, 33, 37, 50, 12, + 121, 135, 182, 187, 166, 162, 174, 168, 170, 170, + 170, 171, 169, 172, 160, 164, 188, 137, 238, 27, + 55, 56, 38, 34, 47, 40, 42, 42, 42, 43, + 41, 44, 32, 36, 50, 15, 123, 135, 177, 187, + 161, 173, 174, 171, 170, 170, 170, 168, 174, 173, + 166, 187, 182, 132, 98, 9, 60, 36, 35, 47, + 41, 43, 42, 42, 43, 41, 44, 32, 37, 50, + 13, 65, 131, 179, 165, 160, 172, 169, 171, 170, + 170, 171, 169, 172, 163, 164, 189, 140, 246, 0, + 51, 37, 32, 44, 41, 43, 42, 42, 43, 41, + 44, 32, 37, 51, 0, 241, 143, 189, 164, 163, + 175, 168, 170, 170, 170, 171, 174, 162, 166, 185, + 180, 144, 30, 55, 59, 33, 45, 41, 43, 42, + 42, 43, 41, 44, 32, 37, 48, 7, 236, 139, + 190, 167, 162, 174, 171, 170, 170, 170, 168, 172, + 160, 165, 179, 129, 103, 8, 63, 39, 34, 46, + 43, 42, 42, 42, 41, 44, 32, 37, 49, 5, + 148, 181, 185, 166, 173, 169, 171, 170, 170, 171, + 169, 173, 166, 185, 181, 235, 7, 48, 37, 32, + 47, 40, 42, 42, 42, 40, 47, 35, 37, 48, + 7, 234, 181, 184, 161, 173, 169, 171, 170, 170, + 171, 174, 162, 167, 189, 130, 118, 9, 62, 38, + 45, 46, 43, 42, 42, 43, 46, 34, 39, 60, + 13, 241, 136, 190, 166, 173, 169, 171, 170, 170, + 171, 174, 163, 164, 179, 134, 106, 52, 59, 33, + 44, 41, 42, 42, 42, 40, 44, 32, 59, 55, + 20, 135, 179, 164, 163, 174, 171, 170, 170, 171, + 174, 162, 167, 178, 129, 105, 52, 59, 33, 44, + 40, 42, 42, 42, 41, 45, 38, 62, 14, 208, + 137, 190, 166, 173, 169, 170, 170, 170, 169, 172, + 161, 185, 136, 194, 14, 62, 38, 45, 41, 42, + 42, 42, 41, 45, 38, 62, 14, 206, 139, 185, + 161, 172, 168, 170, 170, 171, 169, 162, 167, 178, + 134, 22, 54, 37, 35, 47, 43, 42, 42, 40, + 47, 32, 58, 52, 108, 130, 188, 166, 173, 169, + 170, 170, 170, 169, 173, 167, 178, 135, 18, 49, + 36, 35, 46, 43, 42, 42, 40, 44, 33, 62, + 12, 231, 180, 186, 160, 175, 171, 170, 170, 168, + 172, 161, 185, 137, 116, 53, 59, 32, 47, 43, + 42, 42, 40, 44, 33, 57, 15, 228, 180, 186, + 163, 174, 171, 170, 170, 168, 172, 166, 188, 129, + 19, 48, 36, 34, 41, 42, 42, 43, 41, 34, + 36, 49, 23, 131, 191, 161, 172, 168, 170, 170, + 168, 175, 161, 190, 140, 110, 54, 37, 34, 41, + 43, 42, 43, 46, 34, 37, 55, 102, 142, 184, + 160, 175, 171, 170, 170, 169, 173, 167, 179, 156, + 1, 63, 33, 44, 40, 42, 42, 40, 44, 38, + 61, 26, 132, 189, 166, 172, 168, 170, 170, 168, + 172, 166, 178, 155, 7, 60, 38, 44, 40, 42, + 42, 40, 45, 39, 48, 22, 141, 185, 160, 175, + 171, 170, 170, 169, 162, 165, 180, 208, 53, 37, + 34, 41, 42, 42, 43, 47, 33, 62, 0, 158, + 178, 166, 172, 168, 170, 170, 169, 173, 164, 183, + 252, 10, 37, 35, 41, 42, 42, 43, 47, 33, + 60, 5, 134, 191, 161, 175, 171, 170, 171, 174, + 160, 184, 140, 16, 51, 38, 44, 40, 42, 42, + 41, 34, 58, 11, 227, 177, 167, 173, 168, 170, + 170, 169, 162, 165, 138, 103, 49, 39, 45, 40, + 42, 42, 41, 34, 58, 8, 235, 176, 166, 172, + 171, 170, 170, 174, 163, 184, 131, 25, 60, 33, + 47, 43, 42, 43, 47, 33, 61, 29, 140, 187, + 163, 169, 170, 170, 168, 173, 164, 180, 116, 54, + 39, 44, 40, 42, 42, 46, 32, 62, 4, 129, + 185, 163, 174, 170, 170, 168, 173, 164, 181, 102, + 48, 38, 44, 43, 42, 43, 47, 38, 51, 107, + 138, 165, 173, 168, 170, 170, 174, 160, 190, 133, + 3, 56, 35, 41, 42, 42, 41, 35, 56, 3, + 132, 190, 163, 169, 170, 170, 169, 162, 187, 141, + 26, 62, 32, 41, 42, 42, 41, 34, 59, 3, + 132, 185, 163, 169, 170, 170, 169, 163, 185, 132, + 2, 59, 34, 40, 42, 42, 46, 33, 61, 20, + 181, 164, 172, 171, 170, 171, 172, 167, 183, 121, + 51, 33, 46, 42, 42, 40, 34, 59, 3, 134, + 184, 162, 168, 170, 170, 174, 161, 179, 240, 54, + 38, 47, 43, 42, 40, 34, 58, 3, 129, 187, + 162, 168, 170, 171, 175, 166, 183, 103, 50, 33, + 46, 42, 42, 41, 32, 60, 21, 180, 167, 175, + 171, 170, 168, 162, 184, 135, 12, 37, 45, 43, + 42, 43, 45, 37, 13, 134, 187, 162, 168, 170, + 171, 172, 164, 137, 5, 56, 34, 40, 42, 43, + 44, 36, 9, 133, 184, 162, 168, 170, 171, 172, + 165, 140, 6, 58, 45, 40, 42, 43, 45, 58, + 6, 143, 164, 172, 171, 170, 168, 163, 191, 150, + 52, 38, 47, 42, 42, 46, 33, 48, 253, 189, + 160, 169, 170, 171, 172, 164, 142, 6, 58, 45, + 43, 42, 40, 35, 63, 21, 182, 166, 174, 170, + 170, 175, 167, 181, 25, 56, 45, 43, 42, 40, + 34, 63, 107, 182, 161, 174, 170, 170, 175, 164, + 143, 0, 37, 44, 43, 42, 41, 33, 48, 224, + 191, 163, 168, 170, 168, 162, 190, 234, 49, 33, + 41, 42, 43, 44, 37, 7, 139, 167, 174, 170, + 170, 175, 164, 140, 2, 36, 47, 42, 42, 46, + 39, 11, 135, 165, 172, 171, 170, 174, 166, 181, + 4, 37, 44, 43, 42, 46, 38, 10, 135, 165, + 172, 170, 170, 174, 167, 137, 3, 36, 47, 42, + 42, 47, 36, 0, 136, 167, 174, 170, 171, 172, + 187, 157, 54, 33, 41, 42, 43, 34, 60, 213, + 188, 162, 171, 170, 169, 161, 183, 27, 37, 44, + 42, 42, 47, 37, 7, 181, 161, 169, 170, 171, + 162, 189, 117, 63, 34, 43, 42, 46, 39, 14, + 140, 167, 174, 170, 171, 162, 191, 223, 60, 34, + 43, 42, 46, 39, 13, 137, 166, 169, 170, 171, + 163, 178, 104, 56, 44, 42, 42, 47, 58, 18, + 176, 163, 168, 170, 169, 166, 137, 15, 38, 41, + 42, 40, 35, 48, 157, 165, 175, 170, 171, 173, + 191, 80, 62, 45, 43, 42, 47, 58, 20, 178, + 162, 171, 170, 174, 164, 154, 49, 35, 40, 42, + 46, 39, 1, 183, 160, 168, 170, 169, 167, 131, + 52, 32, 40, 42, 41, 39, 0, 180, 160, 168, + 170, 174, 167, 135, 54, 35, 43, 42, 46, 37, + 31, 179, 162, 171, 170, 175, 187, 230, 63, 45, + 42, 42, 45, 60, 226, 186, 175, 170, 171, 163, + 182, 7, 39, 41, 42, 41, 38, 13, 180, 160, + 168, 170, 175, 165, 238, 60, 45, 42, 43, 34, + 51, 158, 164, 174, 170, 168, 166, 130, 55, 35, + 43, 42, 44, 57, 202, 187, 175, 170, 168, 160, + 138, 8, 32, 40, 42, 47, 59, 89, 184, 175, + 170, 168, 160, 136, 53, 32, 43, 42, 44, 62, + 226, 165, 174, 170, 169, 166, 135, 48, 34, 42, + 43, 34, 49, 128, 166, 168, 170, 175, 184, 66, + 58, 46, 42, 41, 39, 5, 178, 173, 170, 171, + 163, 181, 10, 32, 43, 42, 45, 50, 132, 166, + 168, 170, 175, 185, 98, 37, 41, 42, 46, 37, + 123, 184, 175, 170, 169, 167, 147, 63, 44, 42, + 40, 38, 5, 189, 172, 170, 168, 161, 129, 51, + 45, 42, 40, 33, 0, 179, 173, 170, 168, 161, + 129, 51, 45, 42, 40, 38, 4, 189, 172, 170, + 168, 167, 157, 62, 47, 42, 41, 36, 103, 187, + 174, 170, 174, 187, 102, 36, 41, 42, 47, 60, + 133, 166, 168, 170, 162, 182, 11, 35, 42, 43, + 32, 3, 178, 172, 170, 169, 164, 231, 58, 46, + 42, 47, 63, 154, 166, 171, 170, 162, 181, 55, + 45, 42, 40, 39, 21, 187, 174, 170, 175, 188, + 7, 33, 43, 43, 32, 13, 178, 172, 170, 169, + 186, 110, 39, 40, 42, 34, 53, 182, 173, 170, + 169, 165, 112, 36, 40, 42, 34, 53, 182, 173, + 170, 169, 165, 108, 39, 40, 42, 35, 12, 178, + 175, 170, 174, 190, 7, 32, 43, 43, 38, 17, + 187, 169, 170, 173, 183, 55, 45, 42, 41, 59, + 156, 161, 171, 171, 166, 145, 58, 41, 42, 34, + 10, 176, 172, 170, 175, 188, 13, 35, 42, 40, + 37, 233, 166, 171, 171, 166, 151, 37, 40, 42, + 35, 2, 191, 174, 170, 173, 180, 49, 44, 42, + 47, 51, 138, 173, 170, 174, 190, 3, 35, 42, + 41, 59, 155, 160, 170, 168, 165, 17, 33, 42, + 40, 36, 239, 161, 171, 168, 164, 102, 38, 43, + 43, 36, 230, 166, 171, 168, 164, 111, 33, 43, + 40, 37, 145, 161, 170, 168, 186, 26, 35, 42, + 41, 57, 131, 162, 170, 174, 189, 10, 45, 42, + 47, 54, 177, 175, 170, 173, 142, 63, 41, 42, + 32, 31, 165, 168, 171, 167, 113, 38, 42, 40, + 59, 129, 162, 170, 174, 176, 54, 47, 42, 34, + 3, 184, 168, 170, 166, 84, 38, 42, 40, 56, + 141, 173, 170, 172, 181, 60, 41, 42, 32, 96, + 167, 171, 168, 184, 13, 45, 42, 44, 8, 190, + 169, 170, 166, 101, 33, 42, 46, 50, 182, 175, + 170, 163, 145, 39, 43, 40, 57, 137, 172, 170, + 162, 135, 37, 43, 40, 58, 141, 173, 170, 173, + 129, 37, 43, 40, 59, 140, 172, 170, 162, 154, + 36, 43, 40, 62, 181, 175, 170, 160, 231, 38, + 42, 46, 49, 178, 169, 170, 167, 28, 34, 42, + 45, 0, 165, 171, 168, 191, 55, 46, 42, 33, + 227, 163, 170, 172, 141, 37, 43, 40, 63, 182, + 174, 170, 166, 18, 34, 42, 34, 25, 167, 170, + 174, 182, 63, 40, 43, 56, 181, 175, 170, 166, + 16, 34, 42, 34, 22, 166, 170, 175, 137, 37, + 43, 41, 51, 189, 168, 171, 187, 53, 46, 42, + 39, 134, 172, 170, 161, 108, 34, 42, 34, 99, + 160, 170, 173, 154, 38, 42, 47, 13, 164, 170, + 174, 181, 58, 43, 41, 54, 184, 171, 169, 176, + 62, 40, 40, 50, 188, 168, 168, 178, 61, 40, + 40, 61, 189, 168, 168, 178, 60, 40, 40, 51, + 191, 171, 169, 177, 57, 43, 41, 55, 187, 171, + 174, 139, 37, 42, 47, 3, 167, 170, 172, 159, + 33, 42, 34, 116, 163, 170, 160, 17, 45, 42, + 39, 141, 174, 170, 186, 54, 41, 40, 50, 190, + 171, 174, 136, 36, 42, 44, 16, 160, 170, 160, + 17, 44, 42, 36, 181, 169, 171, 189, 62, 43, + 46, 13, 166, 170, 162, 118, 45, 42, 39, 139, + 169, 171, 178, 56, 43, 47, 5, 160, 170, 160, + 26, 47, 43, 57, 189, 171, 174, 130, 38, 42, + 35, 156, 175, 170, 185, 61, 43, 46, 6, 161, + 170, 161, 0, 46, 43, 50, 187, 170, 172, 254, + 34, 42, 37, 177, 168, 174, 130, 33, 42, 33, + 141, 169, 168, 183, 36, 42, 35, 157, 175, 171, + 178, 58, 42, 45, 225, 172, 171, 191, 56, 42, + 45, 243, 172, 170, 191, 56, 42, 45, 224, 172, + 171, 189, 58, 42, 34, 159, 174, 171, 182, 39, + 42, 33, 140, 169, 169, 141, 32, 42, 36, 176, + 171, 175, 228, 45, 42, 60, 186, 170, 163, 1, + 41, 41, 13, 160, 170, 165, 61, 42, 45, 149, + 175, 168, 181, 33, 42, 36, 179, 171, 173, 111, + 47, 40, 10, 161, 170, 165, 60, 42, 34, 155, + 169, 169, 134, 35, 42, 63, 165, 170, 161, 52, + 43, 44, 252, 175, 168, 142, 32, 42, 57, 186, + 170, 161, 55, 43, 44, 151, 174, 169, 132, 34, + 43, 48, 166, 170, 165, 62, 42, 32, 181, 171, + 172, 18, 41, 41, 22, 172, 171, 136, 35, 42, + 61, 167, 170, 165, 56, 42, 38, 176, 170, 163, + 15, 43, 44, 157, 169, 174, 201, 47, 41, 24, + 172, 171, 143, 34, 43, 55, 160, 170, 178, 38, + 42, 62, 164, 170, 187, 37, 42, 37, 184, 170, + 164, 62, 42, 39, 188, 170, 166, 61, 42, 38, + 178, 170, 161, 51, 42, 33, 179, 170, 161, 50, + 42, 38, 189, 170, 166, 60, 42, 39, 190, 170, + 164, 59, 42, 58, 165, 170, 185, 39, 42, 61, + 166, 170, 177, 32, 43, 11, 162, 171, 134, 44, + 41, 108, 174, 174, 107, 40, 44, 131, 171, 163, + 54, 42, 38, 190, 170, 186, 36, 42, 51, 160, + 171, 143, 45, 40, 97, 174, 175, 4, 43, 35, + 177, 170, 167, 58, 42, 61, 160, 171, 141, 44, + 41, 254, 168, 173, 53, 42, 38, 187, 170, 189, + 32, 43, 7, 175, 174, 25, 43, 32, 178, 170, + 184, 38, 42, 12, 172, 174, 29, 43, 32, 189, + 170, 190, 33, 43, 5, 174, 175, 12, 42, 39, + 165, 170, 180, 45, 41, 148, 171, 160, 63, 42, + 50, 163, 168, 95, 40, 35, 189, 170, 189, 35, + 40, 219, 168, 163, 60, 42, 48, 162, 169, 22, + 43, 33, 186, 170, 139, 47, 47, 142, 170, 165, + 33, 43, 104, 168, 163, 63, 42, 54, 172, 174, + 13, 42, 58, 161, 171, 204, 40, 33, 186, 170, + 130, 46, 45, 176, 170, 176, 45, 46, 142, 170, + 185, 35, 41, 153, 170, 165, 33, 40, 231, 171, + 167, 39, 43, 78, 171, 166, 39, 43, 100, 171, + 166, 36, 43, 120, 171, 166, 39, 43, 217, 171, + 167, 38, 40, 148, 170, 165, 32, 41, 129, 170, + 191, 45, 47, 180, 170, 183, 47, 45, 191, 170, + 132, 40, 33, 167, 171, 110, 42, 59, 162, 174, + 52, 42, 53, 174, 163, 58, 43, 89, 171, 186, + 35, 46, 180, 170, 137, 41, 32, 164, 171, 31, + 42, 61, 172, 173, 57, 42, 119, 171, 187, 34, + 47, 178, 170, 145, 43, 37, 162, 175, 51, 42, + 16, 171, 165, 34, 47, 189, 170, 251, 42, 62, + 172, 173, 59, 43, 144, 170, 177, 46, 32, 166, + 169, 53, 42, 5, 171, 186, 45, 45, 187, 171, + 27, 42, 10, 168, 167, 35, 47, 191, 171, 16, + 42, 53, 168, 167, 34, 44, 184, 171, 7, 42, + 3, 171, 187, 44, 34, 167, 169, 54, 42, 194, + 170, 180, 40, 36, 173, 173, 36, 41, 183, 170, + 123, 42, 8, 168, 187, 44, 32, 161, 175, 62, + 43, 140, 170, 228, 42, 53, 168, 187, 47, 33, + 160, 172, 37, 40, 177, 170, 27, 42, 22, 170, + 180, 40, 57, 174, 166, 34, 34, 166, 175, 59, + 40, 177, 171, 0, 42, 246, 170, 133, 42, 52, + 171, 188, 41, 37, 175, 166, 34, 35, 160, 172, + 39, 46, 187, 169, 61, 43, 183, 171, 15, 42, + 155, 170, 97, 42, 103, 170, 159, 42, 0, 170, + 136, 43, 52, 171, 177, 43, 50, 168, 188, 40, + 62, 169, 185, 41, 59, 169, 187, 46, 58, 174, + 186, 46, 58, 174, 186, 41, 59, 169, 184, 41, + 57, 169, 191, 40, 61, 168, 176, 43, 55, 171, + 138, 42, 13, 170, 133, 42, 104, 170, 119, 42, + 156, 170, 2, 42, 180, 171, 50, 40, 184, 174, + 36, 44, 161, 162, 34, 33, 175, 165, 41, 60, + 171, 180, 42, 5, 170, 126, 42, 130, 171, 48, + 40, 186, 175, 33, 35, 173, 164, 41, 60, 171, + 143, 42, 83, 170, 15, 43, 191, 174, 38, 34, + 173, 164, 41, 48, 170, 158, 42, 135, 171, 61, + 46, 166, 163, 44, 58, 168, 136, 42, 226, 170, + 49, 41, 167, 163, 44, 59, 171, 130, 42, 132, + 171, 57, 47, 163, 167, 41, 55, 170, 104, 42, + 188, 175, 35, 39, 169, 181, 42, 158, 171, 56, + 45, 173, 186, 43, 24, 170, 52, 41, 161, 161, + 41, 53, 170, 1, 40, 164, 163, 46, 49, 170, + 24, 43, 164, 163, 46, 49, 170, 7, 40, 167, + 161, 41, 8, 170, 53, 41, 160, 164, 43, 21, + 170, 62, 45, 175, 176, 42, 130, 169, 32, 36, + 171, 225, 42, 186, 163, 41, 9, 170, 48, 44, + 172, 179, 42, 142, 174, 34, 57, 170, 4, 41, + 160, 165, 42, 146, 168, 32, 37, 170, 18, 40, + 160, 186, 42, 132, 169, 35, 62, 170, 14, 46, + 173, 176, 42, 176, 173, 46, 2, 170, 58, 33, + 171, 91, 40, 160, 184, 42, 139, 175, 47, 9, + 170, 37, 38, 171, 16, 41, 173, 176, 42, 191, + 160, 43, 230, 168, 34, 48, 170, 57, 33, 171, + 28, 46, 172, 139, 42, 164, 164, 42, 180, 173, + 41, 113, 168, 34, 55, 170, 36, 36, 170, 54, + 34, 168, 23, 46, 175, 135, 43, 163, 179, 42, + 164, 165, 42, 189, 160, 42, 137, 173, 40, 150, + 174, 46, 105, 168, 44, 0, 171, 34, 53, 170, + 32, 48, 170, 38, 60, 170, 39, 57, 170, 36, + 59, 170, 37, 59, 170, 37, 59, 170, 37, 56, + 170, 36, 62, 170, 39, 61, 170, 33, 49, 170, + 35, 8, 171, 45, 5, 168, 47, 66, 174, 41, + 133, 173, 43, 180, 161, 42, 185, 165, 42, 166, + 176, 43, 173, 154, 41, 169, 30, 45, 171, 51, + 39, 170, 39, 48, 171, 44, 109, 175, 40, 181, + 161, 42, 164, 179, 43, 172, 196, 44, 171, 51, + 36, 170, 32, 3, 169, 40, 137, 161, 42, 166, + 138, 40, 169, 12, 33, 170, 38, 9, 169, 40, + 181, 167, 42, 163, 156, 47, 171, 63, 63, 171, + 47, 154, 160, 42, 161, 134, 46, 171, 62, 61, + 171, 46, 137, 167, 42, 173, 103, 35, 170, 33, + 27, 172, 42, 164, 139, 46, 171, 56, 49, 169, + 40, 188, 178, 40, 168, 50, 60, 168, 40, 189, + 189, 40, 168, 63, 48, 169, 43, 187, 181, 46, + 170, 39, 6, 172, 42, 160, 217, 32, 170, 44, + 131, 165, 43, 169, 61, 48, 174, 42, 166, 150, + 35, 170, 44, 142, 187, 40, 171, 37, 6, 173, + 42, 172, 14, 56, 168, 43, 167, 232, 32, 170, + 46, 189, 180, 44, 170, 45, 142, 190, 41, 170, + 32, 156, 165, 40, 171, 38, 231, 164, 43, 171, + 38, 251, 164, 40, 171, 33, 150, 165, 40, 170, + 35, 130, 191, 46, 170, 44, 176, 138, 34, 170, + 40, 164, 244, 36, 168, 42, 162, 52, 55, 173, + 42, 168, 39, 235, 187, 46, 170, 46, 184, 148, + 39, 168, 42, 172, 60, 25, 167, 40, 170, 47, + 190, 148, 36, 169, 42, 174, 37, 238, 190, 44, + 170, 43, 160, 53, 14, 161, 40, 170, 46, 165, + 18, 50, 162, 43, 170, 44, 184, 103, 60, 173, + 43, 170, 47, 165, 28, 49, 163, 40, 170, 41, + 161, 52, 4, 165, 47, 170, 42, 175, 36, 130, +}; + +static const int16_t ref_alaw_dec_data[4000] = { + 30208, 29184, 28160, 26112, 25088, 23040, 20992, 18944, 16896, 14592, + 12032, 9984, 7296, 4736, 2240, -424, -3008, -5504, -8064, -10496, + -13056, -15616, -17920, -19968, -22016, -24064, -25088, -27136, -28160, -29184, + -30208, -31232, -32256, -32256, -32256, -32256, -32256, -32256, -31232, -30208, + -29184, -28160, -27136, -25088, -23040, -20992, -18944, -16896, -14592, -12032, + -9472, -7040, -4480, -1696, 976, 3648, 6272, 8960, 11520, 14080, + 16896, 18944, 20992, 23040, 25088, 26112, 28160, 29184, 30208, 31232, + 32256, 32256, 32256, 32256, 32256, 32256, 31232, 30208, 29184, 28160, + 26112, 25088, 23040, 20992, 18944, 16128, 14080, 11520, 8448, 6016, + 3136, 392, -2368, -5248, -7808, -10496, -13056, -15616, -17920, -19968, + -22016, -24064, -26112, -28160, -29184, -30208, -31232, -32256, -32256, -32256, + -32256, -32256, -32256, -31232, -30208, -29184, -27136, -26112, -24064, -22016, + -19968, -17920, -15104, -12544, -9984, -7040, -4224, -1248, 1632, 4480, + 7296, 9984, 13056, 15616, 17920, 19968, 22016, 24064, 26112, 28160, + 29184, 30208, 31232, 32256, 32256, 32256, 32256, 32256, 31232, 31232, + 30208, 28160, 27136, 25088, 23040, 20992, 17920, 16128, 13056, 10496, + 7552, 4736, 1760, -1184, -4224, -7040, -9984, -12544, -15616, -17920, + -19968, -23040, -25088, -26112, -28160, -29184, -31232, -31232, -32256, -32256, + -32256, -32256, -32256, -31232, -30208, -29184, -27136, -26112, -24064, -22016, + -18944, -16896, -14080, -11008, -8064, -5248, -2112, 944, 4032, 7040, + 9984, 13056, 15616, 17920, 20992, 23040, 25088, 27136, 28160, 30208, + 31232, 32256, 32256, 32256, 32256, 32256, 31232, 31232, 29184, 28160, + 26112, 24064, 22016, 19968, 16896, 14592, 11520, 8448, 5504, 2496, + -688, -3776, -7040, -9984, -13056, -15616, -18944, -20992, -23040, -25088, + -27136, -29184, -30208, -31232, -32256, -32256, -32256, -32256, -32256, -31232, + -30208, -29184, -27136, -25088, -23040, -20992, -17920, -15616, -12544, -9472, + -6272, -3008, 216, 3520, 6784, 9984, 13056, 15616, 18944, 20992, + 24064, 26112, 27136, 29184, 30208, 31232, 32256, 32256, 32256, 32256, + 32256, 31232, 30208, 28160, 26112, 24064, 22016, 18944, 16896, 13568, + 10496, 7296, 3904, 624, -2752, -6016, -9472, -12544, -15616, -17920, + -20992, -23040, -26112, -28160, -29184, -30208, -31232, -32256, -32256, -32256, + -32256, -31232, -30208, -29184, -27136, -25088, -23040, -20992, -17920, -15104, + -12032, -8960, -5504, -2016, 1376, 4736, 8064, 11520, 14592, 17920, + 19968, 23040, 25088, 27136, 29184, 30208, 31232, 32256, 32256, 32256, + 32256, 31232, 30208, 29184, 27136, 25088, 23040, 19968, 16896, 14080, + 11008, 7808, 4224, 720, -2752, -6272, -9472, -13056, -16128, -18944, + -22016, -24064, -27136, -28160, -30208, -31232, -32256, -32256, -32256, -32256, + -32256, -30208, -29184, -27136, -25088, -23040, -19968, -16896, -14080, -11008, + -7296, -3776, -200, 3392, 7040, 10496, 14080, 16896, 19968, 23040, + 25088, 27136, 29184, 30208, 32256, 32256, 32256, 32256, 32256, 31232, + 30208, 28160, 26112, 24064, 20992, 17920, 15104, 11520, 8064, 4480, + 688, -3008, -6784, -10496, -13568, -16896, -19968, -23040, -25088, -27136, + -29184, -31232, -32256, -32256, -32256, -32256, -32256, -31232, -29184, -27136, + -25088, -23040, -19968, -16896, -13568, -9984, -6016, -2368, 1440, 5248, + 8960, 12544, 16128, 18944, 22016, 25088, 27136, 29184, 30208, 32256, + 32256, 32256, 32256, 32256, 31232, 29184, 27136, 25088, 23040, 19968, + 16128, 13056, 9472, 5504, 1632, -2240, -6016, -9984, -13568, -16896, + -19968, -23040, -26112, -28160, -30208, -31232, -32256, -32256, -32256, -32256, + -31232, -30208, -28160, -26112, -23040, -20992, -16896, -13568, -9984, -6272, + -2240, 1696, 5760, 9472, 13056, 16896, 19968, 23040, 26112, 28160, + 30208, 31232, 32256, 32256, 32256, 32256, 31232, 29184, 28160, 25088, + 23040, 19968, 16128, 12544, 8448, 4736, 592, -3520, -7552, -11520, + -15104, -18944, -22016, -25088, -27136, -29184, -31232, -32256, -32256, -32256, + -32256, -31232, -30208, -28160, -26112, -23040, -19968, -16896, -12544, -8960, + -4736, -624, 3520, 7552, 11520, 15616, 18944, 22016, 25088, 27136, + 29184, 31232, 32256, 32256, 32256, 32256, 31232, 29184, 27136, 25088, + 22016, 17920, 14592, 11008, 6784, 2624, -1632, -5760, -9984, -14080, + -17920, -20992, -24064, -27136, -29184, -31232, -32256, -32256, -32256, -32256, + -31232, -29184, -27136, -25088, -22016, -18944, -14592, -11008, -6784, -2368, + 1952, 6272, 10496, 14592, 17920, 22016, 25088, 27136, 29184, 31232, + 32256, 32256, 32256, 32256, 30208, 29184, 26112, 24064, 19968, 16896, + 13056, 8960, 4480, -56, -4480, -8960, -13056, -16896, -20992, -24064, + -27136, -29184, -31232, -32256, -32256, -32256, -32256, -31232, -29184, -27136, + -24064, -20992, -16896, -13056, -8960, -4224, 232, 4736, 8960, 13568, + 17920, 20992, 24064, 27136, 29184, 31232, 32256, 32256, 32256, 32256, + 30208, 28160, 26112, 23040, 18944, 15104, 11008, 6784, 2112, -2496, + -7040, -11520, -15616, -19968, -23040, -26112, -29184, -30208, -32256, -32256, + -32256, -32256, -31232, -29184, -26112, -23040, -19968, -15616, -11520, -7040, + -2368, 2240, 7040, 11520, 15616, 19968, 23040, 26112, 29184, 31232, + 32256, 32256, 32256, 32256, 30208, 28160, 26112, 22016, 18944, 14592, + 9984, 5504, 720, -4032, -8960, -13568, -17920, -20992, -25088, -28160, + -30208, -31232, -32256, -32256, -32256, -31232, -29184, -27136, -23040, -19968, + -15616, -11520, -6784, -1824, 3008, 7808, 12544, 16896, 20992, 24064, + 27136, 30208, 31232, 32256, 32256, 32256, 31232, 29184, 26112, 23040, + 19968, 15616, 11008, 6016, 1056, -3904, -8960, -13568, -17920, -22016, + -25088, -28160, -30208, -32256, -32256, -32256, -32256, -30208, -28160, -25088, + -22016, -17920, -13056, -8448, -3392, 1696, 6784, 11520, 16128, 19968, + 24064, 27136, 30208, 31232, 32256, 32256, 32256, 31232, 28160, 26112, + 22016, 17920, 13568, 8960, 3904, -1248, -6272, -11520, -16128, -19968, + -24064, -27136, -30208, -31232, -32256, -32256, -32256, -30208, -28160, -25088, + -22016, -17920, -12544, -7808, -2624, 2624, 7808, 13056, 17920, 22016, + 25088, 28160, 30208, 32256, 32256, 32256, 31232, 29184, 27136, 23040, + 18944, 15104, 9984, 4736, -560, -5760, -11008, -16128, -19968, -24064, + -27136, -30208, -32256, -32256, -32256, -31232, -30208, -27136, -24064, -19968, + -15616, -10496, -5248, 184, 5504, 11008, 15616, 19968, 24064, 28160, + 30208, 32256, 32256, 32256, 31232, 29184, 27136, 23040, 18944, 14592, + 9472, 3904, -1568, -7040, -12544, -16896, -22016, -25088, -28160, -31232, + -32256, -32256, -32256, -31232, -28160, -25088, -20992, -16896, -12032, -6528, + -912, 4736, 9984, 15616, 19968, 24064, 28160, 30208, 32256, 32256, + 32256, 31232, 29184, 26112, 22016, 17920, 13056, 7296, 1760, -3904, + -9472, -15104, -19968, -24064, -27136, -30208, -32256, -32256, -32256, -31232, + -29184, -26112, -22016, -17920, -12032, -6784, -976, 4736, 10496, 15616, + 20992, 25088, 28160, 31232, 32256, 32256, 32256, 30208, 28160, 25088, + 19968, 15616, 9984, 4480, -1504, -7296, -13056, -17920, -23040, -27136, + -29184, -31232, -32256, -32256, -31232, -29184, -26112, -22016, -16896, -12032, + -6272, -328, 5760, 11520, 16896, 22016, 26112, 29184, 31232, 32256, + 32256, 31232, 29184, 26112, 23040, 17920, 12544, 6528, 624, -5504, + -11520, -16896, -22016, -26112, -29184, -31232, -32256, -32256, -31232, -29184, + -26112, -22016, -16896, -11520, -5504, 656, 6784, 12544, 17920, 23040, + 27136, 30208, 32256, 32256, 32256, 31232, 28160, 24064, 19968, 14592, + 8960, 2752, -3520, -9472, -15616, -20992, -25088, -29184, -31232, -32256, + -32256, -31232, -29184, -26112, -22016, -16896, -11008, -4736, 1632, 7808, + 14080, 18944, 24064, 28160, 31232, 32256, 32256, 32256, 30208, 26112, + 22016, 16896, 11520, 5248, -1184, -7552, -13568, -18944, -24064, -28160, + -31232, -32256, -32256, -32256, -29184, -26112, -22016, -16896, -10496, -4224, + 2240, 8448, 14592, 19968, 25088, 29184, 31232, 32256, 32256, 31232, + 29184, 25088, 19968, 14592, 8448, 1952, -4736, -11008, -16896, -22016, + -27136, -30208, -32256, -32256, -32256, -30208, -27136, -23040, -16896, -11008, + -4736, 2016, 8448, 15104, 20992, 25088, 29184, 31232, 32256, 32256, + 31232, 28160, 24064, 18944, 12544, 6016, -624, -7296, -14080, -19968, + -25088, -28160, -31232, -32256, -32256, -31232, -28160, -24064, -18944, -13056, + -6272, 656, 7552, 14080, 19968, 25088, 29184, 31232, 32256, 32256, + 31232, 28160, 23040, 17920, 11520, 4992, -2016, -8960, -15616, -20992, + -26112, -29184, -32256, -32256, -32256, -30208, -26112, -22016, -15616, -9472, + -2240, 4736, 11520, 17920, 23040, 28160, 31232, 32256, 32256, 31232, + 28160, 24064, 18944, 12032, 5248, -1824, -8960, -15616, -20992, -26112, + -30208, -32256, -32256, -32256, -29184, -25088, -19968, -14080, -7040, 88, + 7296, 14080, 19968, 25088, 29184, 32256, 32256, 32256, 29184, 26112, + 20992, 14592, 7552, 376, -7040, -14080, -19968, -25088, -29184, -32256, + -32256, -32256, -29184, -25088, -19968, -14080, -7040, 440, 7808, 14592, + 20992, 26112, 30208, 32256, 32256, 31232, 29184, 24064, 18944, 12032, + 4992, -2496, -9984, -16896, -23040, -27136, -31232, -32256, -32256, -30208, + -27136, -22016, -16128, -8960, -1632, 6016, 13056, 19968, 25088, 29184, + 32256, 32256, 32256, 29184, 25088, 18944, 12032, 4736, -3008, -10496, + -17920, -23040, -28160, -31232, -32256, -32256, -30208, -26112, -20992, -14080, + -6528, 1184, 8960, 16128, 22016, 27136, 31232, 32256, 32256, 30208, + 26112, 20992, 14592, 7296, -560, -8448, -15616, -22016, -27136, -31232, + -32256, -32256, -30208, -26112, -20992, -14592, -6784, 1120, 8960, 16128, + 23040, 28160, 31232, 32256, 32256, 30208, 26112, 19968, 13056, 5248, + -2880, -11008, -17920, -24064, -29184, -32256, -32256, -31232, -29184, -24064, + -17920, -10496, -2368, 5760, 13568, 20992, 26112, 30208, 32256, 32256, + 30208, 27136, 20992, 14080, 6528, -1760, -9984, -16896, -24064, -29184, + -31232, -32256, -31232, -28160, -24064, -16896, -9472, -1248, 7040, 15104, + 22016, 27136, 31232, 32256, 32256, 29184, 25088, 18944, 11520, 3264, + -5248, -13568, -20992, -26112, -30208, -32256, -32256, -30208, -26112, -19968, + -12544, -4032, 4480, 12544, 19968, 26112, 30208, 32256, 32256, 30208, + 26112, 19968, 12032, 3904, -4736, -13056, -19968, -26112, -30208, -32256, + -32256, -30208, -25088, -18944, -11008, -2496, 6272, 14592, 22016, 27136, + 31232, 32256, 32256, 29184, 24064, 16896, 8960, 88, -8448, -16896, + -24064, -29184, -32256, -32256, -31232, -27136, -20992, -14080, -5504, 3520, + 12032, 19968, 26112, 30208, 32256, 32256, 29184, 25088, 17920, 9472, + 816, -8064, -16896, -23040, -29184, -32256, -32256, -31232, -27136, -20992, + -13056, -4224, 4992, 13568, 20992, 27136, 31232, 32256, 31232, 28160, + 22016, 15104, 6528, -2752, -11520, -19968, -26112, -30208, -32256, -32256, + -29184, -24064, -16128, -7808, 1440, 10496, 18944, 25088, 30208, 32256, + 32256, 29184, 24064, 16896, 8064, -1184, -10496, -18944, -25088, -30208, + -32256, -32256, -29184, -24064, -16128, -7552, 1952, 11008, 19968, 26112, + 31232, 32256, 32256, 28160, 23040, 15104, 5760, -3648, -13056, -20992, + -27136, -31232, -32256, -31232, -27136, -20992, -12544, -3136, 6528, 15616, + 23040, 29184, 32256, 32256, 30208, 25088, 17920, 8960, -560, -9984, + -18944, -26112, -30208, -32256, -32256, -28160, -22016, -14080, -4480, 5248, + 14592, 23040, 28160, 32256, 32256, 30208, 25088, 17920, 8448, -1248, + -11008, -19968, -26112, -31232, -32256, -31232, -27136, -19968, -11520, -1952, + 8064, 16896, 25088, 30208, 32256, 32256, 28160, 22016, 14080, 4224, + -5760, -15104, -23040, -29184, -32256, -32256, -29184, -23040, -15104, -5760, + 4480, 14080, 23040, 29184, 32256, 32256, 29184, 24064, 15616, 6272, + -4032, -14080, -22016, -29184, -32256, -32256, -29184, -24064, -15616, -5760, + 4480, 14592, 23040, 29184, 32256, 32256, 29184, 23040, 14592, 4480, + -6016, -15616, -24064, -30208, -32256, -32256, -28160, -20992, -12544, -2240, + 8448, 17920, 26112, 31232, 32256, 31232, 26112, 18944, 9472, -912, + -11520, -20992, -28160, -32256, -32256, -30208, -24064, -15616, -5760, 4992, + 15104, 24064, 30208, 32256, 32256, 28160, 20992, 11520, 688, -9984, + -19968, -27136, -31232, -32256, -30208, -24064, -16128, -5760, 5248, 15616, + 24064, 30208, 32256, 31232, 27136, 19968, 9472, -1184, -12032, -20992, + -28160, -32256, -32256, -29184, -22016, -13056, -2112, 8960, 18944, 27136, + 31232, 32256, 30208, 24064, 15104, 4736, -6528, -16896, -25088, -31232, + -32256, -31232, -25088, -16896, -6272, 4992, 15616, 24064, 30208, 32256, + 31232, 26112, 17920, 7296, -4224, -15104, -24064, -30208, -32256, -31232, + -26112, -17920, -7296, 4224, 15104, 24064, 30208, 32256, 31232, 26112, + 16896, 6528, -4992, -16128, -25088, -30208, -32256, -31232, -25088, -16128, + -4992, 6784, 17920, 26112, 31232, 32256, 30208, 23040, 13568, 2496, + -8960, -19968, -27136, -32256, -32256, -28160, -20992, -11008, 784, 12544, + 22016, 29184, 32256, 31232, 26112, 17920, 7040, -4992, -16128, -25088, + -31232, -32256, -30208, -23040, -13568, -2112, 9984, 19968, 28160, 32256, + 32256, 27136, 18944, 8448, -3648, -15104, -25088, -31232, -32256, -30208, + -24064, -13568, -1952, 9984, 20992, 28160, 32256, 32256, 27136, 17920, + 6784, -5504, -16896, -26112, -31232, -32256, -29184, -20992, -11008, 1376, + 13568, 23040, 30208, 32256, 30208, 24064, 14080, 2016, -10496, -20992, + -29184, -32256, -31232, -26112, -16896, -4736, 7808, 18944, 28160, 32256, + 32256, 27136, 17920, 6528, -6016, -17920, -27136, -32256, -32256, -28160, + -18944, -7808, 4736, 16896, 26112, 31232, 32256, 28160, 19968, 8448, + -4480, -16896, -26112, -31232, -32256, -28160, -19968, -8064, 4736, 16896, + 26112, 32256, 32256, 28160, 18944, 7296, -5760, -17920, -27136, -32256, + -32256, -27136, -17920, -5504, 7552, 18944, 28160, 32256, 31232, 26112, + 15616, 3136, -9984, -20992, -29184, -32256, -31232, -24064, -13056, 8, + 13056, 24064, 31232, 32256, 29184, 20992, 9472, -3904, -16896, -26112, + -32256, -32256, -27136, -16896, -4736, 8448, 20992, 29184, 32256, 31232, + 24064, 12544, -528, -13568, -24064, -31232, -32256, -28160, -18944, -7040, + 6528, 18944, 28160, 32256, 31232, 24064, 13568, 168, -13056, -24064, + -31232, -32256, -28160, -18944, -6272, 7296, 19968, 29184, 32256, 31232, + 23040, 12032, -1888, -15104, -26112, -32256, -32256, -27136, -16128, -3008, + 11008, 23040, 30208, 32256, 29184, 19968, 7296, -6784, -19968, -29184, + -32256, -30208, -23040, -11008, 3136, 16896, 27136, 32256, 31232, 25088, + 13568, -88, -14080, -25088, -31232, -32256, -27136, -16128, -2240, 12032, + 24064, 31232, 32256, 28160, 17920, 4032, -10496, -23040, -30208, -32256, + -28160, -18944, -5248, 9472, 22016, 30208, 32256, 29184, 18944, 5760, + -8960, -22016, -30208, -32256, -29184, -18944, -5504, 8960, 22016, 30208, + 32256, 28160, 18944, 4736, -9984, -23040, -31232, -32256, -28160, -16896, + -3392, 11520, 24064, 31232, 32256, 27136, 15616, 1248, -13568, -25088, + -32256, -32256, -25088, -13056, 1504, 16128, 27136, 32256, 31232, 23040, + 9984, -4736, -18944, -29184, -32256, -29184, -19968, -6272, 8960, 22016, + 30208, 32256, 27136, 16896, 1760, -13056, -25088, -32256, -31232, -24064, + -11520, 3520, 17920, 28160, 32256, 30208, 19968, 6016, -9472, -23040, + -31232, -32256, -26112, -14592, 504, 15616, 27136, 32256, 30208, 22016, + 8064, -7552, -22016, -30208, -32256, -27136, -15616, -200, 15104, 27136, + 32256, 30208, 22016, 7552, -8448, -22016, -31232, -32256, -26112, -14080, + 1504, 16896, 28160, 32256, 29184, 19968, 4736, -11008, -24064, -32256, + -31232, -24064, -10496, 5504, 19968, 30208, 32256, 27136, 15104, -376, + -16128, -28160, -32256, -29184, -18944, -4224, 12032, 25088, 32256, 31232, + 23040, 8448, -8064, -22016, -31232, -32256, -25088, -12032, 4480, 19968, + 30208, 32256, 27136, 14592, -1504, -16896, -29184, -32256, -28160, -16896, + -976, 15104, 27136, 32256, 29184, 18944, 2880, -13568, -26112, -32256, + -30208, -19968, -4224, 12544, 26112, 32256, 30208, 20992, 5248, -11520, + -25088, -32256, -30208, -20992, -5504, 11520, 25088, 32256, 30208, 20992, + 5248, -11520, -25088, -32256, -30208, -19968, -4480, 12544, 26112, 32256, + 30208, 18944, 3136, -14080, -27136, -32256, -29184, -17920, -1184, 15616, + 28160, 32256, 28160, 15616, -1248, -17920, -29184, -32256, -27136, -13056, + 4224, 19968, 30208, 32256, 24064, 9984, -7808, -23040, -32256, -31232, + -22016, -5760, 12032, 26112, 32256, 29184, 17920, 1184, -16128, -28160, + -32256, -27136, -13568, 4032, 19968, 31232, 32256, 24064, 8448, -9472, + -25088, -32256, -30208, -18944, -2112, 15616, 28160, 32256, 27136, 13056, + -4736, -20992, -31232, -31232, -22016, -6272, 12032, 26112, 32256, 29184, + 16128, -1760, -18944, -30208, -32256, -24064, -8448, 9984, 25088, 32256, + 29184, 16896, -688, -17920, -30208, -32256, -24064, -8448, 9984, 25088, + 32256, 29184, 16896, -1632, -18944, -30208, -32256, -23040, -6528, 12032, + 27136, 32256, 28160, 14080, -4736, -22016, -31232, -31232, -19968, -2624, + 15616, 29184, 32256, 25088, 9472, -9472, -25088, -32256, -29184, -15616, + 3264, 20992, 31232, 31232, 19968, 2624, -16128, -29184, -32256, -24064, + -8064, 11008, 26112, 32256, 27136, 13056, -6272, -23040, -32256, -30208, + -16896, 1824, 19968, 31232, 31232, 19968, 2368, -16896, -30208, -32256, + -23040, -6016, 13568, 28160, 32256, 25088, 8960, -10496, -26112, -32256, + -27136, -11520, 8064, 25088, 32256, 28160, 14080, -5760, -23040, -32256, + -29184, -15616, 3904, 22016, 32256, 30208, 16896, -2624, -20992, -32256, + -30208, -17920, 1696, 20992, 31232, 30208, 17920, -1248, -19968, -31232, + -31232, -17920, 1248, 19968, 31232, 30208, 17920, -1696, -20992, -31232, + -30208, -16896, 2624, 20992, 32256, 30208, 16128, -4032, -23040, -32256, + -29184, -14592, 5760, 24064, 32256, 28160, 12544, -8064, -25088, -32256, + -27136, -9984, 10496, 27136, 32256, 25088, 7040, -13568, -29184, -32256, + -22016, -3392, 16896, 30208, 31232, 18944, -656, -19968, -32256, -30208, + -15616, 5248, 24064, 32256, 28160, 11008, -9984, -27136, -32256, -24064, + -5760, 15104, 30208, 32256, 19968, -24, -19968, -32256, -30208, -15104, + 6272, 25088, 32256, 26112, 8448, -13056, -29184, -32256, -22016, -1376, + 18944, 31232, 30208, 15104, -6272, -25088, -32256, -26112, -7552, 14080, + 29184, 32256, 19968, -1056, -20992, -32256, -28160, -12032, 9984, 27136, + 32256, 23040, 2624, -18944, -31232, -30208, -14592, 7296, 26112, 32256, + 24064, 4736, -16896, -31232, -30208, -16128, 6272, 25088, 32256, 25088, + 5248, -16896, -31232, -30208, -15616, 6528, 26112, 32256, 24064, 4032, + -17920, -31232, -30208, -14080, 8448, 27136, 32256, 22016, 1184, -19968, + -32256, -28160, -10496, 12032, 29184, 32256, 18944, -3264, -24064, -32256, + -25088, -5504, 16896, 31232, 30208, 13568, -9472, -28160, -32256, -20992, + 1440, 23040, 32256, 26112, 6272, -16896, -31232, -30208, -13568, 9984, + 28160, 32256, 19968, -3008, -24064, -32256, -24064, -3648, 18944, 32256, + 28160, 9984, -13568, -30208, -31232, -15104, 8448, 27136, 32256, 19968, + -2752, -24064, -32256, -24064, -2496, 19968, 32256, 27136, 7296, -16896, + -31232, -29184, -11520, 12544, 30208, 31232, 15616, -8448, -28160, -32256, + -18944, 4992, 26112, 32256, 20992, -1632, -24064, -32256, -24064, -1440, + 22016, 32256, 25088, 4032, -19968, -32256, -27136, -6272, 17920, 32256, + 28160, 8448, -16128, -31232, -29184, -9984, 15104, 31232, 29184, 11008, + -14080, -30208, -30208, -12032, 13056, 30208, 30208, 12032, -12544, -30208, + -30208, -12544, 12544, 30208, 30208, 12032, -13056, -30208, -30208, -11520, + 13568, 31232, 29184, 10496, -14592, -31232, -29184, -9472, 15616, 31232, + 28160, 7808, -16896, -32256, -27136, -5760, 18944, 32256, 26112, 3392, + -20992, -32256, -24064, -560, 23040, 32256, 22016, -2624, -25088, -32256, + -18944, 6272, 28160, 32256, 16128, -9984, -29184, -30208, -12032, 14080, + 31232, 28160, 7552, -17920, -32256, -26112, -2752, 22016, 32256, 22016, + -2624, -26112, -32256, -17920, 8448, 29184, 31232, 12544, -14080, -31232, + -28160, -6272, 19968, 32256, 24064, -624, -25088, -32256, -18944, 7808, + 29184, 31232, 12032, -15104, -31232, -27136, -4224, 22016, 32256, 22016, + -4032, -27136, -31232, -14592, 12544, 31232, 28160, 6016, -19968, -32256, + -23040, 3264, 27136, 32256, 14592, -12544, -31232, -28160, -4992, 20992, + 32256, 20992, -5504, -28160, -31232, -12032, 15616, 32256, 26112, 880, + -24064, -32256, -16896, 10496, 30208, 28160, 6016, -20992, -32256, -20992, + 6272, 29184, 30208, 9472, -17920, -32256, -23040, 3136, 27136, 31232, + 12032, -16128, -32256, -25088, 1312, 26112, 31232, 13568, -15104, -32256, + -25088, 720, 26112, 32256, 13568, -15104, -32256, -25088, 1376, 26112, + 31232, 12544, -16128, -32256, -24064, 3392, 28160, 31232, 9984, -18944, + -32256, -20992, 6528, 29184, 29184, 6272, -22016, -32256, -17920, 11008, + 31232, 27136, 1120, -25088, -32256, -13056, 16128, 32256, 23040, -5248, + -29184, -29184, -6272, 22016, 32256, 16896, -12544, -32256, -25088, 2112, + 27136, 30208, 8448, -20992, -32256, -17920, 11520, 31232, 25088, -1696, + -27136, -30208, -8064, 20992, 32256, 16896, -13056, -32256, -24064, 3904, + 29184, 29184, 4992, -23040, -32256, -13568, 16896, 32256, 20992, -8960, + -31232, -26112, 816, 27136, 30208, 7040, -22016, -32256, -14592, 16128, + 32256, 20992, -9472, -31232, -26112, 2368, 28160, 29184, 4480, -24064, + -31232, -11008, 19968, 32256, 16896, -14080, -32256, -22016, 8448, 31232, + 26112, -3008, -29184, -29184, -2496, 26112, 31232, 7552, -23040, -32256, + -12544, 18944, 32256, 16896, -15104, -32256, -19968, 11008, 32256, 23040, + -6784, -31232, -26112, 3136, 29184, 28160, 456, -27136, -29184, -3776, + 26112, 31232, 6784, -24064, -31232, -9472, 22016, 32256, 12032, -19968, + -32256, -14080, 17920, 32256, 15616, -16896, -32256, -16896, 15104, 32256, + 17920, -14080, -32256, -18944, 13056, 32256, 19968, -12544, -32256, -19968, + 12032, 32256, 20992, -11520, -32256, -20992, 11520, 32256, 20992, -12032, + -32256, -19968, 12544, 32256, 19968, -13056, -32256, -18944, 14080, 32256, + 17920, -15616, -32256, -16128, 16896, 32256, 14592, -18944, -32256, -12544, + 19968, 32256, 10496, -22016, -31232, -7808, 24064, 31232, 4992, -26112, + -29184, -1632, 28160, 28160, -1952, -30208, -26112, 5760, 31232, 23040, + -9984, -32256, -19968, 14080, 32256, 16128, -17920, -32256, -11520, 22016, + 31232, 6784, -25088, -30208, -1312, 28160, 27136, -4480, -31232, -23040, + 10496, 32256, 18944, -16128, -32256, -12544, 22016, 31232, 6272, -26112, + -29184, 880, 30208, 25088, -8448, -32256, -19968, 15616, 32256, 12544, + -22016, -31232, -4736, 27136, 28160, -3648, -31232, -22016, 12032, 32256, + 15104, -19968, -32256, -6528, 26112, 28160, -3136, -31232, -22016, 12544, + 32256, 14080, -20992, -31232, -4224, 28160, 27136, -6528, -32256, -18944, + 16896, 32256, 8960, -25088, -29184, 2240, 31232, 22016, -13568, -32256, + -12032, 23040, 30208, -168, -30208, -23040, 12544, 32256, 12544, -23040, + -30208, 232, 30208, 23040, -13056, -32256, -11008, 24064, 29184, -2496, + -31232, -20992, 16128, 32256, 7808, -27136, -27136, 7040, 32256, 16896, + -20992, -31232, -1888, 30208, 23040, -13568, -32256, -9984, 26112, 28160, + -6272, -32256, -16128, 20992, 31232, 408, -30208, -20992, 16128, 32256, + 6016, -28160, -25088, 11008, 32256, 11008, -25088, -28160, 7040, 32256, + 14592, -23040, -29184, 3648, 32256, 16896, -20992, -30208, 1184, 31232, + 18944, -18944, -31232, -440, 31232, 19968, -18944, -31232, -1120, 31232, + 19968, -17920, -31232, -944, 31232, 19968, -18944, -31232, 200, 31232, + 18944, -19968, -30208, 2240, 32256, 16896, -22016, -29184, 5248, 32256, + 13568, -25088, -27136, 8960, 32256, 9472, -27136, -25088, 13568, 32256, + 4480, -30208, -20992, 18944, 31232, -1760, -32256, -15616, 24064, 28160, + -8960, -32256, -8448, 28160, 23040, -16128, -31232, -200, 31232, 16128, + -23040, -28160, 8960, 32256, 7296, -29184, -22016, 17920, 31232, -3392, + -32256, -12544, 26112, 25088, -14592, -32256, -592, 31232, 15616, -24064, + -27136, 12032, 32256, 2624, -31232, -16896, 24064, 27136, -11520, -32256, + -2752, 31232, 16896, -24064, -27136, 12544, 32256, 976, -32256, -14080, + 26112, 25088, -15616, -31232, 2752, 32256, 10496, -28160, -22016, 19968, + 29184, -8448, -32256, -4224, 31232, 16128, -25088, -25088, 15616, 31232, + -3904, -32256, -8064, 30208, 18944, -23040, -27136, 13568, 31232, -2752, + -32256, -8448, 30208, 18944, -24064, -26112, 15104, 31232, -4736, -32256, + -5760, 31232, 15616, -26112, -24064, 18944, 29184, -9984, -32256, 376, + 32256, 8960, -30208, -17920, 25088, 25088, -17920, -29184, 9472, 32256, + -976, -32256, -7552, 30208, 15616, -26112, -22016, 20992, 27136, -14080, + -31232, 6528, 32256, 1120, -32256, -8448, 30208, 15616, -27136, -20992, + 22016, 26112, -16896, -30208, 10496, 32256, -3904, -32256, -2496, 32256, + 8960, -30208, -14592, 28160, 19968, -24064, -24064, 19968, 27136, -15616, + -30208, 10496, 31232, -5504, -32256, 624, 32256, 4224, -32256, -8960, + 31232, 13056, -29184, -16896, 27136, 19968, -24064, -23040, 22016, 26112, + -18944, -28160, 15616, 29184, -12544, -31232, 9472, 31232, -6784, -32256, + 3904, 32256, -1312, -32256, -1184, 32256, 3392, -32256, -5504, 32256, + 7552, -31232, -8960, 31232, 10496, -31232, -12032, 30208, 13056, -30208, + -14080, 29184, 14592, -29184, -15616, 29184, 15616, -28160, -16128, 28160, + 16128, -28160, -16128, 28160, 16128, -29184, -15616, 29184, 15104, -29184, + -14592, 29184, 13568, -30208, -12544, 30208, 11008, -31232, -9472, 31232, + 8064, -32256, -6272, 32256, 4224, -32256, -1888, 32256, -592, -32256, + 3264, 32256, -6016, -32256, 8960, 31232, -12032, -30208, 15104, 28160, + -17920, -26112, 20992, 24064, -24064, -20992, 27136, 16896, -29184, -13056, + 31232, 8960, -32256, -4224, 32256, -880, -32256, 6016, 31232, -11008, + -30208, 16128, 27136, -20992, -23040, 25088, 17920, -29184, -13056, 31232, + 6784, -32256, -104, 32256, -6784, -31232, 13568, 28160, -19968, -24064, + 25088, 17920, -29184, -11008, 32256, 3520, -32256, 4736, 31232, -12544, + -28160, 19968, 23040, -26112, -16128, 30208, 7552, -32256, 1504, 32256, + -10496, -29184, 18944, 23040, -26112, -15616, 31232, 6016, -32256, 4480, + 31232, -14592, -27136, 23040, 18944, -29184, -9472, 32256, -1888, -32256, + 13056, 27136, -23040, -18944, 29184, 8448, -32256, 3520, 31232, -15104, + -25088, 25088, 16128, -31232, -3776, 32256, -8960, -29184, 20992, 20992, + -29184, -8448, 32256, -5248, -30208, 17920, 23040, -28160, -10496, 32256, + -3776, -31232, 17920, 23040, -28160, -10496, 32256, -4736, -30208, 18944, + 20992, -29184, -7552, 32256, -8448, -29184, 22016, 17920, -31232, -2112, + 32256, -14080, -25088, 27136, 11008, -32256, 6016, 29184, -22016, -17920, + 31232, 1312, -32256, 16128, 23040, -29184, -7296, 32256, -11008, -26112, + 26112, 11520, -32256, 7040, 28160, -24064, -14592, 32256, -4480, -29184, + 22016, 16896, -32256, 3008, 30208, -22016, -16896, 32256, -3008, -30208, + 22016, 16128, -32256, 4480, 29184, -23040, -14080, 32256, -7040, -28160, + 25088, 11008, -32256, 11008, 25088, -28160, -6016, 32256, -16128, -20992, + 31232, -232, -30208, 22016, 15104, -32256, 7808, 27136, -27136, -7296, + 32256, -16896, -19968, 31232, -2752, -29184, 25088, 11008, -32256, 13568, + 22016, -31232, 1248, 30208, -24064, -11008, 32256, -14592, -20992, 31232, + -3264, -28160, 26112, 7808, -32256, 17920, 17920, -32256, 8960, 25088, + -29184, -656, 30208, -24064, -9472, 32256, -17920, -17920, 32256, -9984, + -24064, 30208, -2368, -28160, 27136, 4736, -31232, 23040, 11520, -32256, + 17920, 16896, -32256, 12544, 22016, -32256, 7296, 25088, -30208, 2496, + 28160, -28160, -1824, 30208, -26112, -5504, 31232, -24064, -8448, 32256, + -22016, -11008, 32256, -19968, -13056, 32256, -18944, -14592, 32256, -17920, + -15616, 32256, -16896, -15616, 32256, -16896, -15616, 32256, -16896, -15104, + 32256, -17920, -14080, 32256, -18944, -12544, 32256, -20992, -10496, 32256, + -23040, -7552, 31232, -25088, -4224, 30208, -27136, -376, 28160, -29184, + 4224, 25088, -31232, 8960, 20992, -32256, 14592, 16896, -32256, 19968, + 11008, -31232, 25088, 4032, -29184, 29184, -3520, -25088, 31232, -11520, + -18944, 32256, -18944, -11008, 31232, -26112, -1568, 27136, -30208, 8448, + 20992, -32256, 17920, 11520, -31232, 26112, 280, -26112, 31232, -11520, + -17920, 32256, -22016, -5760, 29184, -30208, 7296, 20992, -32256, 19968, + 8064, -30208, 29184, -6528, -20992, 32256, -19968, -7296, 29184, -30208, + 8448, 18944, -32256, 23040, 3264, -27136, 31232, -13568, -13568, 31232, + -27136, 4032, 22016, -32256, 20992, 4992, -28160, 31232, -14080, -12544, + 31232, -28160, 7296, 18944, -32256, 25088, -1184, -23040, 32256, -20992, + -3904, 26112, -32256, 17920, 7808, -28160, 31232, -15104, -10496, 29184, + -30208, 13056, 12032, -30208, 30208, -12032, -13056, 30208, -30208, 12544, + 12544, -30208, 30208, -13568, -11008, 29184, -31232, 15616, 8448, -28160, + 32256, -18944, -4992, 26112, -32256, 22016, 200, -22016, 32256, -26112, + 5760, 16896, -31232, 29184, -12544, -11008, 28160, -32256, 19968, 2496, + -23040, 32256, -26112, 7040, 15616, -30208, 31232, -16896, -4992, 25088, + -32256, 26112, -7040, -15104, 30208, -31232, 18944, 1888, -22016, 32256, + -28160, 12544, 8960, -26112, 32256, -25088, 7040, 14080, -29184, 32256, + -22016, 3264, 16896, -30208, 31232, -19968, 1184, 17920, -31232, 31232, + -19968, 976, 17920, -30208, 31232, -20992, 2496, 16896, -30208, 32256, + -23040, 6016, 13568, -28160, 32256, -26112, 11008, 8064, -24064, 32256, + -30208, 17920, 560, -17920, 30208, -32256, 24064, -8960, -9472, 25088, + -32256, 30208, -18944, 1952, 15616, -28160, 32256, -28160, 15104, 2240, + -18944, 30208, -32256, 26112, -13056, -3648, 18944, -30208, 32256, -27136, + 14080, 2240, -17920, 29184, -32256, 28160, -16896, 1760, 14080, -26112, + 32256, -31232, 22016, -8448, -7040, 20992, -30208, 32256, -28160, 16896, + -3008, -12032, 24064, -31232, 32256, -26112, 15104, -1184, -13056, 25088, + -31232, 32256, -27136, 16896, -3264, -10496, 23040, -30208, 32256, -29184, + 20992, -8960, -4480, 16896, -27136, 32256, -32256, 27136, -17920, 6016, +}; diff --git a/test/cmocka/src/math/arithmetic/a_law_mu_law_test_vectors.m b/test/cmocka/src/math/arithmetic/a_law_mu_law_test_vectors.m new file mode 100644 index 000000000000..b9f5b6b6a8e5 --- /dev/null +++ b/test/cmocka/src/math/arithmetic/a_law_mu_law_test_vectors.m @@ -0,0 +1,229 @@ +% a_law_mu_law_test_vectors() - Create A-law and mu-law test vectors +% +% Running this script creates header files ref_chirp_mono_8k_s16.h, +% a_law_codec.h, and mu_law_codec.h. The chirp waveform for test +% input is created with sox, and then ended and decoded as +% A-law and mu-law. + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright(c) 2025 Intel Corporation. + +function a_law_mu_law_test_vectors() + + sox = 0; + alaw = 1; + mulaw = 1; + bits = 16; + ts = 0.5; + fs = 8e3; + t = (0:round(ts*fs - 1))/fs; + x = round(2^(bits - 1) * chirp(t, 100, ts, 3.5e3, 'logarithmic')); + xmax = 2^(bits - 1) - 1; + xmin = -2^(bits - 1); + x = max(min(x, xmax), xmin); + ref_s16_data = int16(x); + + ref_s16_header_fn = 'ref_chirp_mono_8k_s16.h'; + ref_alaw_header_fn = 'a_law_codec.h'; + ref_mulaw_header_fn = 'mu_law_codec.h'; + + close all; + path(path(), '../../../m'); + + if sox + ref_s16 = '/tmp/chirp_mono_8k_s16.raw'; + ref_alaw_enc = '/tmp/ref_alaw_enc.raw'; + ref_alaw_dec = '/tmp/ref_alaw_dec.raw'; + ref_mulaw_enc = '/tmp/ref_mulaw_enc.raw'; + ref_mulaw_dec = '/tmp/ref_mulaw_dec.raw'; + sox_s16_chirp_gen = sprintf('sox -c 1 -r 8000 -b 16 --encoding signed-integer -n %s synth 0.5 sine 100-3500', ref_s16); + sox_alaw_enc = sprintf('sox -c 1 -r 8000 -b 16 --encoding signed-integer %s --encoding a-law %s', ref_s16, ref_alaw_enc); + sox_alaw_dec = sprintf('sox -c 1 -r 8000 --encoding a-law %s -b 16 --encoding signed-integer %s', ref_alaw_enc, ref_alaw_dec); + sox_mulaw_enc = sprintf('sox -c 1 -r 8000 -b 16 --encoding signed-integer %s --encoding a-law %s', ref_s16, ref_mulaw_enc); + sox_mulaw_dec = sprintf('sox -c 1 -r 8000 --encoding a-law %s -b 16 --encoding signed-integer %s', ref_mulaw_enc, ref_mulaw_dec); + system(sox_s16_chirp_gen); + system(sox_alaw_enc); + system(sox_alaw_dec); + system(sox_mulaw_enc); + system(sox_mulaw_dec); + ref_s16_data = readbin(ref_s16, 'int16'); figure; + ref_alaw_enc_data = readbin(ref_alaw_enc, 'uint8'); + ref_alaw_dec_data = readbin(ref_alaw_dec, 'int16'); + ref_mulaw_enc_data = readbin(ref_mulaw_enc, 'uint8'); + ref_mulaw_dec_data = readbin(ref_mulaw_dec, 'int16'); + else + if alaw + ref_alaw_enc_data = alaw_enc(ref_s16_data); + ref_alaw_dec_data = alaw_dec(ref_alaw_enc_data); + end + if mulaw + ref_mulaw_enc_data = mulaw_enc(ref_s16_data); + ref_mulaw_dec_data = mulaw_dec(ref_mulaw_enc_data); + end + end + + if alaw + plot(ref_s16_data); grid on; title('Input s16'); + figure; plot(ref_alaw_enc_data); grid on; title('A-law data'); + figure; plot(ref_alaw_dec_data); grid on; title('A-law decode s16'); + end + + if mulaw + figure; plot(ref_mulaw_enc_data); grid on; title('mu-law data'); + figure; plot(ref_mulaw_dec_data); grid on; title('mu-law decode s16'); + end + + fh = export_headerfile_open(ref_s16_header_fn); + comment = sprintf('Created %s with script a_law_mu_law_test_vectors.m %s', ... + datestr(now, 0), export_get_git_describe()); + export_comment(fh, comment); + fprintf(fh, '#include <stdint.h>\n'); + export_ndefine(fh, 'REF_DATA_SAMPLE_COUNT', length(ref_s16_data)); + export_vector(fh, 16, 'chirp_mono_8k_s16', ref_s16_data); + fclose(fh); + + if alaw + fh = export_headerfile_open(ref_alaw_header_fn); + comment = sprintf('Created %s with script a_law_mu_law_test_vectors.m %s', ... + datestr(now, 0), export_get_git_describe()); + export_comment(fh, comment); + fprintf(fh, '#include <stdint.h>\n'); + export_vector(fh, 8, 'ref_alaw_enc_data', ref_alaw_enc_data); + export_vector(fh, 16, 'ref_alaw_dec_data', ref_alaw_dec_data); + fclose(fh); + end + + if mulaw + fh = export_headerfile_open(ref_mulaw_header_fn); + comment = sprintf('Created %s with script a_law_mu_law_test_vectors.m %s', ... + datestr(now, 0), export_get_git_describe()); + export_comment(fh, comment); + fprintf(fh, '#include <stdint.h>\n'); + export_vector(fh, 8, 'ref_mulaw_enc_data', ref_mulaw_enc_data); + export_vector(fh, 16, 'ref_mulaw_dec_data', ref_mulaw_dec_data); + fclose(fh); + end + +end + +function x = readbin(fn, itype) + fh = fopen(fn, 'r'); + if fh == -1 + fprintf(1, 'Could not open file %s.\n', fn); + error("Failed."); + end + x = fread(fh, inf, itype); + fclose(fh); +end + +% See G.711 alaw compress from +% https://www.itu.int/rec/T-REC-G.191/ +function encoded = alaw_enc(input_samples) + num_samples = length(input_samples); + in16 = int16(input_samples); + encoded_samples = uint8(zeros(num_samples, 1)); + for n = 1:num_samples + if in16(n) < 0 + ix = bitshift(-in16(n) -1, -4); % 1's complement + else + ix = bitshift(in16(n), -4); + end + + if ix > 15 + iexp = 1; + while (ix > 16 + 15) + ix = bitshift(ix, -1); + iexp = iexp + 1; + end + + ix = ix - 16; + ix = ix + bitshift(iexp, 4); + end + + if in16(n) >= 0 + ix = bitor(ix, 128); + end + + encoded(n) = bitxor(ix, 85); + end +end + +% See G.711 alaw expand from +% https://www.itu.int/rec/T-REC-G.191/ +function samples_s16 = alaw_dec(input_bytes) + num_samples = length(input_bytes); + samples_s16 = int16(zeros(num_samples, 1)); + for n = 1:num_samples + ix = bitxor(int16(input_bytes(n)), 85); + ix = bitand(ix, 127); + iexp = bitshift(ix, -4); + mant = bitand(ix, 15); + if iexp > 0 + mant = mant + 16; + end + + mant = bitshift(mant, 4) + 8; + if iexp > 1 + mant = bitshift(mant, iexp - 1); + end + + if input_bytes(n) > 127 + samples_s16(n) = mant; + else + samples_s16(n) = -mant; + end + end +end + +% See G.711 ulaw compress from +% https://www.itu.int/rec/T-REC-G.191/ +function encoded = mulaw_enc(input_samples) + num_samples = length(input_samples); + in16 = int16(input_samples); + encoded_samples = uint8(zeros(num_samples, 1)); + for n = 1:num_samples + if in16(n) < 0 + absno = bitshift(-in16(n) -1, -2) + 33; % 1's complement + else + absno = bitshift(in16(n), -2) + 33; + end + + absno = min(absno, 8191); + i = bitshift(absno, -6); + segno = 1; + while i > 0 + segno = segno + 1; + i = bitshift(i, -1); + end + + high_nibble = 8 - segno; + low_nibble = bitand(bitshift(absno, -segno), 15); + low_nibble = 15 - low_nibble; + encoded(n) = bitor(bitshift(high_nibble, 4), low_nibble); + if in16(n) >= 0 + encoded(n) = bitor(encoded(n), 128); + end + end +end + +% See G.711 alaw expand from +% https://www.itu.int/rec/T-REC-G.191/ +function samples_s16 = mulaw_dec(input_bytes) + num_samples = length(input_bytes); + samples_s16 = int16(zeros(num_samples, 1)); + for n = 1:num_samples + if input_bytes(n) < 128 + sign = -1; + else + sign = 1; + end + + mantissa = -int16(input_bytes(n)) - 1; % 1's complement + exponent = bitand(bitshift(mantissa, -4), 7); + segment = exponent + 1; + mantissa = bitand(mantissa, 15); + step = bitshift(4, segment); + samples_s16(n) = sign * (bitshift(128, exponent) + step * mantissa + step / 2 - 4 * 33); + end +end diff --git a/test/cmocka/src/math/arithmetic/base2_logarithm.c b/test/cmocka/src/math/arithmetic/base2_logarithm.c deleted file mode 100644 index a06e44d09b78..000000000000 --- a/test/cmocka/src/math/arithmetic/base2_logarithm.c +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> -#include <string.h> - -#include <sof/math/log.h> -#include <sof/audio/format.h> -#include <rtos/string.h> -#include <sof/common.h> -#include "log2_tables.h" -/* 'Error[max] = 0.0000236785999981,THD(-dBc) = -92.5128795787487235' */ -#define CMP_TOLERANCE 0.0000236785691029 - -/* testvector in Q32.0 */ -static const uint32_t uv[100] = { - 1ULL, 43383509ULL, 86767017ULL, 130150525ULL, 173534033ULL, 216917541ULL, - 260301049ULL, 303684557ULL, 347068065ULL, 390451573ULL, 433835081ULL, 477218589ULL, - 520602097ULL, 563985605ULL, 607369113ULL, 650752621ULL, 694136129ULL, 737519638ULL, - 780903146ULL, 824286654ULL, 867670162ULL, 911053670ULL, 954437178ULL, 997820686ULL, - 1041204194ULL, 1084587702ULL, 1127971210ULL, 1171354718ULL, 1214738226ULL, 1258121734ULL, - 1301505242ULL, 1344888750ULL, 1388272258ULL, 1431655766ULL, 1475039274ULL, 1518422782ULL, - 1561806290ULL, 1605189798ULL, 1648573306ULL, 1691956814ULL, 1735340322ULL, 1778723830ULL, - 1822107338ULL, 1865490846ULL, 1908874354ULL, 1952257862ULL, 1995641370ULL, 2039024878ULL, - 2082408386ULL, 2125791894ULL, 2169175403ULL, 2212558911ULL, 2255942419ULL, 2299325927ULL, - 2342709435ULL, 2386092943ULL, 2429476451ULL, 2472859959ULL, 2516243467ULL, 2559626975ULL, - 2603010483ULL, 2646393991ULL, 2689777499ULL, 2733161007ULL, 2776544515ULL, 2819928023ULL, - 2863311531ULL, 2906695039ULL, 2950078547ULL, 2993462055ULL, 3036845563ULL, 3080229071ULL, - 3123612579ULL, 3166996087ULL, 3210379595ULL, 3253763103ULL, 3297146611ULL, 3340530119ULL, - 3383913627ULL, 3427297135ULL, 3470680643ULL, 3514064151ULL, 3557447659ULL, 3600831168ULL, - 3644214676ULL, 3687598184ULL, 3730981692ULL, 3774365200ULL, 3817748708ULL, 3861132216ULL, - 3904515724ULL, 3947899232ULL, 3991282740ULL, 4034666248ULL, 4078049756ULL, 4121433264ULL, - 4164816772ULL, 4208200280ULL, 4251583788ULL, 4294967295ULL}; - -static void test_math_arithmetic_base2log_fixed(void **state) -{ - (void)state; - - uint32_t u[100]; - int i; - - memcpy_s((void *)&u[0], sizeof(u), (void *)&uv[0], 100U * sizeof(uint32_t)); - for (i = 0; i < ARRAY_SIZE(log2_lookup_table); i++) { - float y = Q_CONVERT_QTOF(base2_logarithm(u[i]), 0); - float diff = fabs(log2_lookup_table[i] - (double)y / (1 << 16)); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %.16f: value = %.16f, log2 = %.16f\n", __func__, diff, - (double)u[i], (double)y / (1 << 16)); - assert_true(diff <= CMP_TOLERANCE); - } - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_arithmetic_base2log_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/arithmetic/base_10_logarithm.c b/test/cmocka/src/math/arithmetic/base_10_logarithm.c deleted file mode 100644 index 3973df31a515..000000000000 --- a/test/cmocka/src/math/arithmetic/base_10_logarithm.c +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> -// -// - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> -#include <string.h> - -#include <sof/math/log.h> -#include <sof/audio/format.h> -#include <rtos/string.h> -#include <sof/common.h> -#include "log2_tables.h" -/* 'Error[max] = 0.0000071279028671,THD = -102.9407645424143993 ' */ -/* 'Error[max] = rms(log10() - double(log10_int32()))' */ -/* 'THD = 20*log10(Error[max])' */ -#define CMP_TOLERANCE 0.0000071279028671 -/* Natural logarithm log10(X) reference table generated by matlab/Octave */ -/* UQ4.28 */ -static const double common_log10_ref_table[] = { - 0.0000000000000000, 7.6373246662453802, 7.9383546619093615, 8.1144459209650428, - 8.2393846575733427, 8.3362946705813989, 8.4154759166290241, 8.4824227062596371, - 8.5404146532373240, 8.5915671756847054, 8.6373246662453802, 8.6787173514036056, - 8.7165059122930053, 8.7512680193222625, 8.7834527026386606, 8.8134159259684335, - 8.8414446495269665, 8.8677735882125130, 8.8925971719048302, 8.9160782677250818, - 8.9383546624098908, 8.9595439614559940, 8.9797473475226131, 8.9990525026982162, - 9.0175359083740947, 9.0352646753178405, 9.0522980146012202, 9.0686884307751292, - 9.0844826979451199, 9.0997226644895282, 9.1144459212987297, 9.1286863604025754, - 9.1424746448781171, 9.1558386064266184, 9.1688035835820649, 9.1813927108816724, - 9.1936271672907388, 9.2055263908534872, 9.2171082633890631, 9.2283892737852433, - 9.2393846580738721, 9.2501085234534361, 9.2605739571199752, 9.2707931222905753, - 9.2807773431865943, 9.2905371804656394, 9.3000824983621975, 9.3094225246070792, - 9.3185659040380759, 9.3275207466824899, 9.3362946709818218, 9.3448948427358882, - 9.3533280102652014, 9.3616005362239267, 9.3697184264391105, 9.3776873561036460, - 9.3855126936091011, 9.3931995222691196, 9.4007526601535094, 9.4081766782268659, - 9.4154759169627091, 9.4226545015843630, 9.4297163562280168, 9.4366652161756566, - 9.4435046406985137, 9.4502380233502628, 9.4568686022422757, 9.4633994693944423, - 9.4698335793932600, 9.4761737574178788, 9.4824227066886628, 9.4885830153874373, - 9.4946571630937573, 9.5006475267772306, 9.5065563863821918, 9.5123859300375031, - 9.5181382589213257, 9.5238153918078847, 9.5294192693208828, 9.5349517579159713, - 9.5404146536127215, 9.5458096854947918, 9.5511385189953373, 9.5564027589832818, - 9.5616039526647825, 9.5667435923129869, 9.5718231178381536, 9.5768439193242560, - 9.5818073388505756, 9.5867146733402073, 9.5915671761296206, 9.5963660590064990, - 9.6011124940261787, 9.6058076152298781, 9.6104525202710605, 9.6150482719557271, - 9.6195958997020572, 9.6240964009244330, 9.6285507423464711, 9.6329598611462810}; - -/* testvector in Q32.0 */ -static const uint32_t uv[100] = { - 1ULL, 43383509ULL, 86767017ULL, 130150525ULL, 173534033ULL, 216917541ULL, - 260301049ULL, 303684557ULL, 347068065ULL, 390451573ULL, 433835081ULL, 477218589ULL, - 520602097ULL, 563985605ULL, 607369113ULL, 650752621ULL, 694136129ULL, 737519638ULL, - 780903146ULL, 824286654ULL, 867670162ULL, 911053670ULL, 954437178ULL, 997820686ULL, - 1041204194ULL, 1084587702ULL, 1127971210ULL, 1171354718ULL, 1214738226ULL, 1258121734ULL, - 1301505242ULL, 1344888750ULL, 1388272258ULL, 1431655766ULL, 1475039274ULL, 1518422782ULL, - 1561806290ULL, 1605189798ULL, 1648573306ULL, 1691956814ULL, 1735340322ULL, 1778723830ULL, - 1822107338ULL, 1865490846ULL, 1908874354ULL, 1952257862ULL, 1995641370ULL, 2039024878ULL, - 2082408386ULL, 2125791894ULL, 2169175403ULL, 2212558911ULL, 2255942419ULL, 2299325927ULL, - 2342709435ULL, 2386092943ULL, 2429476451ULL, 2472859959ULL, 2516243467ULL, 2559626975ULL, - 2603010483ULL, 2646393991ULL, 2689777499ULL, 2733161007ULL, 2776544515ULL, 2819928023ULL, - 2863311531ULL, 2906695039ULL, 2950078547ULL, 2993462055ULL, 3036845563ULL, 3080229071ULL, - 3123612579ULL, 3166996087ULL, 3210379595ULL, 3253763103ULL, 3297146611ULL, 3340530119ULL, - 3383913627ULL, 3427297135ULL, 3470680643ULL, 3514064151ULL, 3557447659ULL, 3600831168ULL, - 3644214676ULL, 3687598184ULL, 3730981692ULL, 3774365200ULL, 3817748708ULL, 3861132216ULL, - 3904515724ULL, 3947899232ULL, 3991282740ULL, 4034666248ULL, 4078049756ULL, 4121433264ULL, - 4164816772ULL, 4208200280ULL, 4251583788ULL, 4294967295ULL}; - -static void test_math_arithmetic_base10log_fixed(void **state) -{ - (void)state; - - double clogfxp; - double diff; - int i; - - for (i = 0; i < ARRAY_SIZE(common_log10_ref_table); i++) { - clogfxp = log10_int32(uv[i]); - diff = fabs(common_log10_ref_table[i] - (double)clogfxp / (1 << 28)); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %.16f: val = %16d, log10() = %.16f\n", __func__, diff, - uv[i], clogfxp / (1 << 28)); - assert_true(diff <= CMP_TOLERANCE); - } - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_arithmetic_base10log_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/arithmetic/base_e_logarithm.c b/test/cmocka/src/math/arithmetic/base_e_logarithm.c deleted file mode 100644 index c2c1d2083c8b..000000000000 --- a/test/cmocka/src/math/arithmetic/base_e_logarithm.c +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> -#include <string.h> - -#include <sof/math/log.h> -#include <sof/audio/format.h> -#include <rtos/string.h> -#include <sof/common.h> -#include "log2_tables.h" -/* 'Error[max] = 0.0000164133276926,THD(-dBc) = -95.6960671942683234' */ -/* 'Error[max] = rms(log() - double(log_int32()))' */ -/* 'THD = 20*log10(Error[max])' */ -#define CMP_TOLERANCE 0.0000164133276926 - -/* Natural logarithm loge(X) reference table generated by matlab/Octave */ -/* UQ5.27 */ -static const double natural_log_lookup_table[] = { - 0.0000000000000000, 17.5855899268523359, 18.2787371074122831, 18.6842022155204468, - 18.9718842879722267, 19.1950278392864391, 19.3773493960803940, 19.5315000759076511, - 19.6650314685321739, 19.7828145041885577, 19.8881750198463827, 19.9834851996507084, - 20.0704965766403376, 20.1505392860869676, 20.2246472581140395, 20.2936401294912301, - 20.3581786505327571, 20.4188032722644479, 20.4759616860290699, 20.5300289072319480, - 20.5813222015588408, 20.6301123656733907, 20.6766323812583899, 20.7210841437836706, - 20.7636437581607112, 20.8044657526425461, 20.8436864657603671, 20.8814267937103786, - 20.9177944378507625, 20.9528857576336485, 20.9867873092828354, 21.0195771320810394, - 21.0513258303723845, 21.0820974890173112, 21.1119504521464485, 21.1409379890003279, - 21.1691088659487328, 21.1965078407425196, 21.2231760877918916, 21.2491515741640455, - 21.2744693821187845, 21.2991619946810467, 21.3232595462333343, 21.3467900436180038, - 21.3697795618183370, 21.3922524176471107, 21.4142313243436178, 21.4357375295432568, - 21.4567909387206548, 21.4774102259037889, 21.4976129332024932, 21.5174155604805932, - 21.5368336463203107, 21.5558818412742781, 21.5745739742703257, 21.5929231129229997, - 21.6109416184107097, 21.6286411954956677, 21.6460329381935921, 21.6631273715394208, - 21.6799344898427790, 21.6964637917813938, 21.7127243130127638, 21.7287246543415016, - 21.7444730112924880, 21.7599771978118319, 21.7752446699265008, 21.7902825472754031, - 21.8050976330453672, 21.8196964324517815, 21.8340851698895619, 21.8482698048676056, - 21.8622560468288185, 21.8760493689479993, 21.8896550209909755, 21.9030780413106569, - 21.9163232680485471, 21.9293953496040821, 21.9422987544284780, 21.9550377801946830, - 21.9676165623906030, 21.9800390823784895, 21.9923091749598925, 22.0044305354820757, - 22.0164067265188734, 22.0282411841561903, 22.0399372239099236, 22.0514980465667030, - 22.0629267423782807, 22.0742262976204415, 22.0853995982070579, 22.0964494343823858, - 22.1073785049035614, 22.1181894209970018, 22.1288847101032040, 22.1394668194234150, - 22.1499381192805984, 22.1603009063062437, 22.1705574064637361, 22.1807097776854185}; - -/* testvector in Q32.0 */ -static const uint32_t uv[100] = { - 1ULL, 43383509ULL, 86767017ULL, 130150525ULL, 173534033ULL, 216917541ULL, - 260301049ULL, 303684557ULL, 347068065ULL, 390451573ULL, 433835081ULL, 477218589ULL, - 520602097ULL, 563985605ULL, 607369113ULL, 650752621ULL, 694136129ULL, 737519638ULL, - 780903146ULL, 824286654ULL, 867670162ULL, 911053670ULL, 954437178ULL, 997820686ULL, - 1041204194ULL, 1084587702ULL, 1127971210ULL, 1171354718ULL, 1214738226ULL, 1258121734ULL, - 1301505242ULL, 1344888750ULL, 1388272258ULL, 1431655766ULL, 1475039274ULL, 1518422782ULL, - 1561806290ULL, 1605189798ULL, 1648573306ULL, 1691956814ULL, 1735340322ULL, 1778723830ULL, - 1822107338ULL, 1865490846ULL, 1908874354ULL, 1952257862ULL, 1995641370ULL, 2039024878ULL, - 2082408386ULL, 2125791894ULL, 2169175403ULL, 2212558911ULL, 2255942419ULL, 2299325927ULL, - 2342709435ULL, 2386092943ULL, 2429476451ULL, 2472859959ULL, 2516243467ULL, 2559626975ULL, - 2603010483ULL, 2646393991ULL, 2689777499ULL, 2733161007ULL, 2776544515ULL, 2819928023ULL, - 2863311531ULL, 2906695039ULL, 2950078547ULL, 2993462055ULL, 3036845563ULL, 3080229071ULL, - 3123612579ULL, 3166996087ULL, 3210379595ULL, 3253763103ULL, 3297146611ULL, 3340530119ULL, - 3383913627ULL, 3427297135ULL, 3470680643ULL, 3514064151ULL, 3557447659ULL, 3600831168ULL, - 3644214676ULL, 3687598184ULL, 3730981692ULL, 3774365200ULL, 3817748708ULL, 3861132216ULL, - 3904515724ULL, 3947899232ULL, 3991282740ULL, 4034666248ULL, 4078049756ULL, 4121433264ULL, - 4164816772ULL, 4208200280ULL, 4251583788ULL, 4294967295ULL}; - -static void test_math_arithmetic_base_e_log_fixed(void **state) -{ - (void)state; - - double logefxp; - double diff; - int i; - - for (i = 0; i < ARRAY_SIZE(natural_log_lookup_table); i++) { - logefxp = ln_int32(uv[i]); - diff = fabs(natural_log_lookup_table[i] - (double)logefxp / (1 << 27)); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %.16f: value = %16d, log() = %.16f\n", __func__, diff, - uv[i], logefxp / (1 << 27)); - assert_true(diff <= CMP_TOLERANCE); - } - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_arithmetic_base_e_log_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/arithmetic/exponential.c b/test/cmocka/src/math/arithmetic/exponential.c deleted file mode 100644 index f35299fd3f1b..000000000000 --- a/test/cmocka/src/math/arithmetic/exponential.c +++ /dev/null @@ -1,201 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -/* - * Copyright(c) 2022 Intel Corporation. All rights reserved. - * - * Author: Shriram Shastry <malladi.sastry@linux.intel.com> - */ - -#include <stdbool.h> -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> -#include <string.h> -#include <time.h> -#include <stdlib.h> - -#include <sof/math/exp_fcn.h> -#include <sof/audio/format.h> -#include <rtos/string.h> -#include <sof/common.h> - -#define ULP_TOLERANCE 5.60032793 -#define ULP_SCALE 0.0000999999999749 -#define NUMTESTSAMPLES 256 - -#define NUMTESTSAMPLES_MIDDLE_TEST2 100 -#define NUMTESTSAMPLES_SMALL_TEST2 100 -#define NUMTESTSAMPLES_LARGE_TEST2 100 -#define ABS_DELTA_TOLERANCE_TEST1 1.2e-2 -#define REL_DELTA_TOLERANCE_TEST1 2.8e-4 -#define ABS_DELTA_TOLERANCE_TEST2 1.7e-6 -#define REL_DELTA_TOLERANCE_TEST2 3.7e-2 -#define ABS_DELTA_TOLERANCE_TEST3 1.2e-1 -#define REL_DELTA_TOLERANCE_TEST3 7.7e-5 -#define SOFM_EXP_FIXED_ARG_MIN -11.5 -#define SOFM_EXP_FIXED_ARG_MAX 7.6245 - -/* testvector in Q4.28, -5 to +5 */ -/* - * Arguments :double a - * double b - * double *r - * int32_t *b_i - * Return Type :void - */ -static void gen_exp_testvector(double a, double b, double *r, int32_t *b_i) -{ - double a2; - double b2; - - *r = a + rand() % (int32_t)(b - a + 1); - a2 = *r * 268435456; - b2 = fabs(a2); - if (b2 < 4503599627370496LL) - a2 = floor(a2 + 0.5); - - if (a2 < 2147483648LL) - *b_i = (a2 >= -2147483648LL) ? a2 : INT32_MIN; - else - *b_i = INT32_MAX; -} - -static void test_function_sofm_exp_int32(void **state) -{ - (void)state; - - int32_t accum; - int i; - double a_i; - double max_ulp; - double a_tmp = -5.0123456789; - double b_tmp = 5.0123456789; - double r; - int32_t b_i; - - srand((unsigned int)time(NULL)); - for (i = 0; i < NUMTESTSAMPLES; i++) { - gen_exp_testvector(a_tmp, b_tmp, &r, &b_i); - a_i = (double)b_i / (1 << 28); - - accum = sofm_exp_int32(b_i); - max_ulp = fabs(exp(a_i) - (double)accum / (1 << 23)) / ULP_SCALE; - - if (max_ulp > ULP_TOLERANCE) { - printf("%s: ULP for %.16f: value = %.16f, Exp = %.16f\n", __func__, - max_ulp, (double)b_i / (1 << 28), (double)accum / (1 << 23)); - assert_true(max_ulp <= ULP_TOLERANCE); - } - } -} - -static void gen_exp_testvector_linspace_q27(double a, double b, int step_count, - int point, int32_t *value) -{ - double fstep = (b - a) / (step_count - 1); - double fvalue = a + fstep * point; - - *value = (int32_t)round(fvalue * 134217728.0); -} - -static double ref_exp(double value) -{ - if (value < SOFM_EXP_FIXED_ARG_MIN) - return 0.0; - else if (value > SOFM_EXP_FIXED_ARG_MAX) - return 2048.0; - else - return exp(value); -} - -static void test_exp_with_input_value(int32_t ivalue, int32_t *iexp_value, - double *abs_delta_max, double *rel_delta_max, - double abs_delta_tolerance, double rel_delta_tolerance) -{ - double fvalue, fexp_value, ref_exp_value; - double rel_delta, abs_delta; - - *iexp_value = sofm_exp_fixed(ivalue); - fvalue = (double)ivalue / (1 << 27); /* Q5.27 */ - fexp_value = (double)*iexp_value / (1 << 20); /* Q12.20 */ - /* printf("val = %10.6f, exp = %12.6f\n", fvalue, fexp_value); */ - - ref_exp_value = ref_exp(fvalue); - abs_delta = fabs(ref_exp_value - fexp_value); - rel_delta = abs_delta / ref_exp_value; - if (abs_delta > *abs_delta_max) - *abs_delta_max = abs_delta; - - if (rel_delta > *rel_delta_max) - *rel_delta_max = rel_delta; - - if (abs_delta > abs_delta_tolerance) { - printf("%s: Absolute error %g exceeds limit %g, input %g output %g.\n", - __func__, abs_delta, abs_delta_tolerance, fvalue, fexp_value); - assert_true(false); - } - - if (rel_delta > rel_delta_tolerance) { - printf("%s: Relative error %g exceeds limit %g, input %g output %g.\n", - __func__, rel_delta, rel_delta_tolerance, fvalue, fexp_value); - assert_true(false); - } -} - -static void test_function_sofm_exp_fixed(void **state) -{ - (void)state; - - double rel_delta_max, abs_delta_max; - int32_t ivalue, iexp_value; - int i; - - rel_delta_max = 0; - abs_delta_max = 0; - for (i = 0; i < NUMTESTSAMPLES_MIDDLE_TEST2; i++) { - gen_exp_testvector_linspace_q27(-5, 5, NUMTESTSAMPLES_MIDDLE_TEST2, i, &ivalue); - test_exp_with_input_value(ivalue, &iexp_value, &abs_delta_max, &rel_delta_max, - ABS_DELTA_TOLERANCE_TEST1, REL_DELTA_TOLERANCE_TEST1); - - } - - printf("%s: Absolute max error was %.6e (middle).\n", __func__, abs_delta_max); - printf("%s: Relative max error was %.6e (middle).\n", __func__, rel_delta_max); - - rel_delta_max = 0; - abs_delta_max = 0; - for (i = 0; i < NUMTESTSAMPLES_SMALL_TEST2; i++) { - gen_exp_testvector_linspace_q27(-16, -5, NUMTESTSAMPLES_SMALL_TEST2, i, &ivalue); - test_exp_with_input_value(ivalue, &iexp_value, &abs_delta_max, &rel_delta_max, - ABS_DELTA_TOLERANCE_TEST2, REL_DELTA_TOLERANCE_TEST2); - } - - printf("%s: Absolute max error was %.6e (small).\n", __func__, abs_delta_max); - printf("%s: Relative max error was %.6e (small).\n", __func__, rel_delta_max); - - rel_delta_max = 0; - abs_delta_max = 0; - for (i = 0; i < NUMTESTSAMPLES_LARGE_TEST2; i++) { - gen_exp_testvector_linspace_q27(5, 15.9999, NUMTESTSAMPLES_LARGE_TEST2, i, &ivalue); - test_exp_with_input_value(ivalue, &iexp_value, &abs_delta_max, &rel_delta_max, - ABS_DELTA_TOLERANCE_TEST3, REL_DELTA_TOLERANCE_TEST3); - } - - printf("%s: Absolute max error was %.6e (large).\n", __func__, abs_delta_max); - printf("%s: Relative max error was %.6e (large).\n", __func__, rel_delta_max); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_function_sofm_exp_int32), - cmocka_unit_test(test_function_sofm_exp_fixed), - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/arithmetic/mu_law_codec.c b/test/cmocka/src/math/arithmetic/mu_law_codec.c new file mode 100644 index 000000000000..cee690e9e947 --- /dev/null +++ b/test/cmocka/src/math/arithmetic/mu_law_codec.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <stdio.h> +#include <stdint.h> +#include <setjmp.h> +#include <stdbool.h> +#include <cmocka.h> +#include <sof/math/mu_law.h> + +#include "ref_chirp_mono_8k_s16.h" +#include "mu_law_codec.h" + +static void test_mu_law_encode(void **state) +{ + (void)state; + + uint8_t mu_law_sample, mu_law_ref; + int i; + + for (i = 0; i < REF_DATA_SAMPLE_COUNT; i++) { + mu_law_sample = sofm_mu_law_encode(chirp_mono_8k_s16[i]); + mu_law_ref = ref_mulaw_enc_data[i]; + + if (mu_law_sample != mu_law_ref) { + printf("%s: difference found at %d, encoded %d, ref %d, lin %d\n", + __func__, i, mu_law_sample, mu_law_ref, chirp_mono_8k_s16[i]); + assert_true(false); + } + } +} + +static void test_mu_law_decode(void **state) +{ + (void)state; + + int16_t s16_sample, s16_ref; + int i; + + for (i = 0; i < REF_DATA_SAMPLE_COUNT; i++) { + s16_sample = sofm_mu_law_decode(ref_mulaw_enc_data[i]); + s16_ref = ref_mulaw_dec_data[i]; + if (s16_sample != s16_ref) { + printf("%s: difference found at %d, byte %d, decoded %d, ref %d\n", + __func__, i, ref_mulaw_enc_data[i], s16_sample, s16_ref); + assert_true(false); + } + } +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_mu_law_encode), + cmocka_unit_test(test_mu_law_decode), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/test/cmocka/src/math/arithmetic/mu_law_codec.h b/test/cmocka/src/math/arithmetic/mu_law_codec.h new file mode 100644 index 000000000000..802b2c4fd235 --- /dev/null +++ b/test/cmocka/src/math/arithmetic/mu_law_codec.h @@ -0,0 +1,814 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 13-May-2025 18:29:28 with script a_law_mu_law_test_vectors.m */ + +#include <stdint.h> + +static const uint8_t ref_mulaw_enc_data[4000] = { + 130, 131, 132, 134, 135, 137, 139, 141, 143, 147, + 151, 156, 162, 172, 189, 94, 55, 41, 31, 26, + 22, 17, 14, 12, 10, 8, 6, 5, 4, 2, + 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, + 3, 4, 5, 7, 9, 11, 13, 15, 19, 23, + 28, 35, 46, 67, 206, 178, 166, 158, 153, 148, + 143, 141, 139, 137, 135, 134, 132, 131, 130, 129, + 128, 128, 128, 128, 128, 128, 129, 130, 131, 132, + 133, 135, 137, 139, 141, 143, 148, 153, 158, 168, + 182, 223, 60, 43, 32, 27, 21, 17, 14, 11, + 9, 7, 6, 4, 3, 2, 1, 0, 0, 0, + 0, 0, 0, 1, 2, 3, 4, 6, 8, 10, + 12, 14, 18, 23, 28, 36, 47, 74, 196, 173, + 162, 155, 150, 145, 142, 140, 137, 135, 134, 132, + 131, 130, 129, 128, 128, 128, 128, 128, 128, 129, + 130, 132, 133, 135, 137, 139, 141, 144, 149, 155, + 161, 173, 194, 75, 47, 35, 28, 22, 17, 14, + 11, 9, 7, 5, 4, 2, 1, 0, 0, 0, + 0, 0, 0, 1, 2, 3, 5, 6, 8, 10, + 13, 15, 20, 26, 31, 43, 62, 207, 175, 164, + 156, 150, 145, 142, 139, 137, 135, 133, 131, 130, + 129, 128, 128, 128, 128, 128, 128, 129, 130, 132, + 134, 135, 138, 140, 142, 147, 152, 158, 169, 187, + 86, 49, 36, 28, 22, 16, 13, 11, 9, 6, + 5, 3, 2, 1, 0, 0, 0, 0, 0, 1, + 2, 3, 5, 7, 9, 11, 14, 17, 23, 29, + 39, 55, 234, 179, 165, 156, 150, 144, 141, 139, + 136, 134, 132, 131, 130, 129, 128, 128, 128, 128, + 128, 129, 130, 132, 134, 136, 138, 141, 143, 149, + 155, 163, 176, 216, 57, 39, 29, 23, 17, 13, + 11, 8, 6, 4, 3, 1, 0, 0, 0, 0, + 0, 0, 1, 3, 4, 6, 9, 11, 14, 18, + 24, 30, 42, 63, 200, 172, 159, 153, 147, 142, + 139, 137, 135, 133, 131, 130, 128, 128, 128, 128, + 128, 128, 130, 131, 133, 135, 137, 140, 142, 147, + 154, 161, 174, 213, 57, 38, 28, 22, 16, 13, + 10, 8, 5, 3, 2, 1, 0, 0, 0, 0, + 0, 1, 3, 5, 7, 9, 12, 14, 20, 26, + 34, 49, 107, 180, 164, 155, 148, 143, 140, 137, + 135, 133, 131, 129, 128, 128, 128, 128, 128, 129, + 130, 132, 134, 136, 139, 142, 146, 153, 160, 174, + 214, 55, 37, 27, 20, 15, 12, 9, 7, 4, + 3, 1, 0, 0, 0, 0, 0, 1, 3, 5, + 7, 9, 12, 15, 21, 28, 39, 60, 199, 171, + 158, 151, 144, 141, 138, 135, 133, 131, 129, 128, + 128, 128, 128, 128, 129, 131, 133, 135, 137, 140, + 143, 150, 157, 170, 196, 61, 39, 28, 21, 15, + 12, 9, 6, 4, 2, 1, 0, 0, 0, 0, + 1, 2, 4, 6, 8, 11, 15, 20, 28, 39, + 61, 195, 169, 157, 149, 143, 140, 137, 134, 132, + 130, 129, 128, 128, 128, 128, 129, 130, 132, 135, + 137, 140, 144, 151, 158, 173, 216, 51, 34, 25, + 18, 13, 10, 7, 5, 3, 1, 0, 0, 0, + 0, 1, 2, 4, 6, 9, 12, 15, 22, 30, + 44, 88, 179, 161, 153, 145, 141, 138, 135, 132, + 130, 129, 128, 128, 128, 128, 129, 131, 133, 135, + 138, 141, 146, 154, 164, 186, 68, 40, 28, 20, + 14, 11, 8, 5, 3, 1, 0, 0, 0, 0, + 1, 2, 4, 7, 10, 13, 18, 26, 37, 60, + 191, 166, 155, 147, 142, 138, 135, 133, 130, 129, + 128, 128, 128, 128, 129, 131, 133, 136, 139, 143, + 150, 158, 174, 121, 45, 30, 22, 15, 11, 8, + 5, 3, 1, 0, 0, 0, 0, 1, 3, 5, + 8, 11, 15, 22, 30, 46, 233, 172, 157, 149, + 142, 139, 136, 133, 131, 129, 128, 128, 128, 128, + 130, 132, 134, 137, 141, 145, 154, 165, 190, 59, + 35, 25, 16, 12, 9, 6, 3, 1, 0, 0, + 0, 0, 1, 3, 6, 9, 12, 16, 25, 35, + 60, 189, 164, 153, 144, 140, 137, 134, 131, 129, + 128, 128, 128, 128, 130, 132, 134, 137, 141, 147, + 155, 170, 213, 47, 30, 21, 14, 10, 7, 4, + 2, 1, 0, 0, 0, 1, 3, 5, 8, 12, + 16, 25, 37, 65, 183, 160, 151, 143, 139, 135, + 133, 130, 129, 128, 128, 128, 129, 131, 133, 137, + 140, 145, 154, 168, 205, 48, 30, 21, 14, 10, + 7, 4, 2, 0, 0, 0, 0, 2, 4, 7, + 10, 14, 22, 31, 52, 195, 165, 153, 144, 139, + 136, 133, 130, 129, 128, 128, 128, 129, 131, 134, + 138, 142, 148, 158, 176, 74, 38, 25, 16, 11, + 8, 5, 2, 0, 0, 0, 0, 2, 4, 7, + 10, 14, 22, 33, 58, 186, 160, 150, 142, 138, + 135, 132, 129, 128, 128, 128, 129, 131, 133, 136, + 140, 146, 156, 172, 90, 40, 26, 16, 11, 8, + 4, 2, 0, 0, 0, 0, 2, 5, 8, 12, + 17, 27, 43, 236, 169, 154, 144, 139, 136, 132, + 130, 128, 128, 128, 129, 130, 133, 137, 141, 147, + 157, 176, 69, 35, 23, 14, 10, 6, 3, 1, + 0, 0, 0, 1, 4, 7, 10, 15, 24, 38, + 79, 173, 155, 145, 140, 136, 132, 130, 128, 128, + 128, 129, 131, 134, 138, 142, 150, 162, 194, 48, + 29, 18, 12, 8, 5, 2, 0, 0, 0, 1, + 3, 6, 10, 14, 23, 37, 78, 172, 155, 144, + 139, 135, 132, 129, 128, 128, 128, 129, 132, 135, + 139, 145, 155, 174, 70, 34, 22, 14, 9, 5, + 2, 0, 0, 0, 1, 3, 6, 10, 14, 24, + 38, 99, 169, 153, 143, 138, 134, 131, 129, 128, + 128, 128, 130, 133, 137, 142, 151, 165, 216, 42, + 25, 15, 10, 6, 3, 1, 0, 0, 1, 3, + 6, 10, 15, 25, 42, 215, 164, 150, 142, 137, + 133, 130, 128, 128, 128, 129, 132, 135, 140, 146, + 158, 185, 51, 28, 17, 11, 7, 3, 1, 0, + 0, 0, 3, 6, 10, 15, 26, 45, 196, 160, + 148, 140, 136, 132, 129, 128, 128, 128, 130, 133, + 138, 143, 153, 170, 75, 33, 21, 13, 8, 4, + 1, 0, 0, 0, 2, 6, 10, 15, 26, 46, + 189, 158, 146, 140, 135, 131, 129, 128, 128, 129, + 131, 135, 140, 147, 159, 191, 45, 26, 15, 10, + 5, 2, 0, 0, 0, 2, 5, 9, 15, 25, + 45, 191, 158, 146, 139, 135, 131, 129, 128, 128, + 129, 132, 136, 141, 151, 167, 87, 34, 20, 12, + 7, 3, 1, 0, 0, 1, 4, 8, 13, 22, + 39, 215, 162, 148, 140, 135, 131, 129, 128, 128, + 129, 132, 137, 142, 152, 172, 63, 30, 17, 11, + 6, 2, 0, 0, 0, 2, 6, 10, 16, 29, + 61, 172, 152, 142, 136, 132, 129, 128, 128, 129, + 132, 136, 141, 151, 170, 65, 30, 17, 10, 6, + 2, 0, 0, 0, 3, 7, 12, 20, 35, 244, + 162, 148, 140, 134, 131, 128, 128, 128, 130, 134, + 139, 147, 161, 224, 36, 20, 12, 7, 3, 0, + 0, 0, 3, 6, 12, 20, 36, 222, 160, 146, + 139, 134, 130, 128, 128, 129, 131, 135, 141, 151, + 172, 59, 28, 15, 9, 4, 1, 0, 0, 1, + 5, 10, 16, 29, 68, 168, 149, 140, 135, 131, + 128, 128, 128, 131, 135, 141, 152, 173, 55, 27, + 14, 8, 4, 1, 0, 0, 2, 6, 11, 20, + 37, 203, 158, 144, 137, 133, 129, 128, 128, 130, + 133, 139, 147, 163, 90, 31, 17, 10, 5, 1, + 0, 0, 2, 5, 11, 19, 36, 204, 158, 143, + 137, 132, 129, 128, 128, 130, 134, 140, 150, 171, + 56, 26, 14, 8, 3, 0, 0, 0, 3, 8, + 14, 27, 60, 168, 149, 139, 134, 130, 128, 128, + 129, 133, 139, 147, 166, 66, 28, 14, 8, 3, + 0, 0, 0, 3, 8, 15, 29, 74, 163, 146, + 138, 133, 129, 128, 128, 130, 135, 141, 153, 181, + 43, 21, 11, 6, 2, 0, 0, 2, 6, 12, + 23, 47, 174, 150, 140, 134, 130, 128, 128, 130, + 134, 140, 151, 176, 44, 22, 11, 6, 2, 0, + 0, 2, 7, 13, 26, 59, 167, 147, 138, 133, + 129, 128, 128, 131, 136, 143, 158, 244, 30, 15, + 8, 3, 0, 0, 1, 5, 11, 20, 42, 179, + 152, 140, 134, 130, 128, 128, 131, 135, 142, 156, + 210, 31, 15, 8, 3, 0, 0, 1, 5, 11, + 22, 47, 172, 149, 139, 133, 129, 128, 128, 132, + 137, 146, 166, 57, 24, 12, 6, 1, 0, 0, + 3, 8, 15, 33, 199, 155, 141, 134, 130, 128, + 128, 131, 136, 143, 159, 75, 27, 13, 6, 2, + 0, 0, 3, 8, 16, 34, 191, 153, 140, 134, + 129, 128, 128, 132, 137, 146, 168, 50, 22, 11, + 5, 1, 0, 1, 5, 11, 23, 54, 166, 145, + 137, 131, 128, 128, 130, 135, 142, 158, 90, 27, + 13, 6, 1, 0, 0, 4, 10, 20, 45, 170, + 147, 137, 131, 128, 128, 130, 135, 142, 158, 74, + 26, 12, 5, 1, 0, 1, 5, 11, 24, 63, + 160, 143, 135, 130, 128, 128, 132, 138, 148, 174, + 40, 17, 9, 3, 0, 0, 3, 8, 17, 41, + 174, 148, 137, 131, 128, 128, 130, 136, 144, 167, + 47, 20, 9, 3, 0, 0, 2, 8, 17, 40, + 173, 147, 137, 131, 128, 128, 131, 137, 147, 173, + 40, 16, 8, 2, 0, 0, 4, 10, 23, 61, + 159, 142, 134, 129, 128, 129, 133, 141, 156, 79, + 25, 11, 4, 0, 0, 2, 8, 16, 41, 171, + 146, 136, 130, 128, 128, 132, 139, 153, 213, 28, + 12, 5, 0, 0, 2, 8, 16, 41, 171, 145, + 136, 130, 128, 128, 133, 140, 156, 75, 24, 11, + 4, 0, 0, 3, 10, 22, 62, 158, 141, 133, + 129, 128, 130, 136, 145, 173, 38, 15, 7, 1, + 0, 1, 7, 15, 38, 172, 145, 136, 130, 128, + 129, 134, 142, 163, 47, 18, 8, 2, 0, 1, + 6, 14, 35, 175, 146, 136, 130, 128, 129, 134, + 143, 166, 43, 16, 7, 1, 0, 1, 7, 16, + 44, 165, 142, 134, 129, 128, 130, 137, 148, 187, + 29, 12, 4, 0, 0, 3, 11, 26, 211, 151, + 138, 131, 128, 128, 133, 142, 164, 44, 16, 7, + 1, 0, 2, 8, 20, 62, 156, 140, 132, 128, + 128, 132, 141, 159, 50, 18, 7, 1, 0, 2, + 8, 20, 63, 156, 139, 131, 128, 128, 133, 142, + 164, 42, 15, 6, 1, 0, 3, 10, 26, 200, + 149, 136, 130, 128, 130, 136, 148, 191, 27, 11, + 3, 0, 1, 6, 15, 45, 161, 141, 132, 128, + 128, 133, 142, 165, 40, 14, 5, 0, 0, 4, + 12, 32, 172, 143, 134, 128, 128, 132, 140, 159, + 46, 15, 6, 0, 0, 4, 12, 31, 173, 143, + 134, 128, 128, 132, 141, 163, 41, 14, 5, 0, + 0, 5, 14, 41, 162, 140, 132, 128, 128, 134, + 145, 182, 28, 10, 3, 0, 1, 8, 22, 253, + 150, 136, 129, 128, 131, 139, 157, 48, 15, 6, + 0, 0, 5, 14, 44, 159, 139, 131, 128, 129, + 136, 150, 91, 20, 7, 1, 0, 4, 13, 36, + 165, 141, 132, 128, 129, 135, 149, 237, 21, 8, + 1, 0, 4, 13, 38, 162, 140, 131, 128, 129, + 137, 152, 64, 17, 6, 0, 0, 5, 15, 55, + 154, 137, 130, 128, 131, 140, 162, 37, 12, 3, + 0, 1, 9, 26, 182, 143, 133, 128, 128, 135, + 148, 116, 20, 7, 0, 0, 5, 16, 60, 152, + 136, 129, 128, 132, 142, 175, 27, 9, 1, 0, + 4, 13, 43, 157, 138, 130, 128, 131, 141, 169, + 30, 10, 2, 0, 3, 13, 41, 157, 138, 130, + 128, 132, 141, 172, 28, 9, 1, 0, 4, 14, + 52, 153, 136, 129, 128, 133, 145, 202, 21, 7, + 0, 0, 7, 21, 198, 144, 133, 128, 129, 137, + 155, 44, 13, 3, 0, 2, 12, 38, 158, 138, + 129, 128, 133, 143, 194, 21, 7, 0, 0, 8, + 24, 179, 142, 132, 128, 130, 140, 167, 29, 9, + 1, 0, 5, 19, 220, 145, 133, 128, 129, 138, + 160, 33, 10, 2, 0, 5, 17, 107, 146, 133, + 128, 129, 138, 161, 31, 10, 1, 0, 6, 20, + 198, 143, 132, 128, 130, 140, 172, 26, 8, 0, + 0, 8, 27, 169, 140, 130, 128, 133, 145, 95, + 16, 4, 0, 2, 12, 46, 152, 135, 128, 129, + 137, 159, 32, 10, 1, 0, 7, 24, 173, 140, + 130, 128, 133, 147, 70, 14, 3, 0, 4, 15, + 78, 146, 133, 128, 131, 141, 184, 21, 5, 0, + 2, 12, 46, 151, 134, 128, 130, 139, 171, 24, + 7, 0, 1, 11, 42, 153, 135, 128, 129, 139, + 171, 24, 6, 0, 2, 12, 46, 151, 134, 128, + 130, 141, 182, 20, 5, 0, 3, 14, 75, 145, + 132, 128, 132, 145, 74, 14, 3, 0, 5, 22, + 174, 139, 129, 128, 135, 156, 32, 9, 0, 1, + 10, 40, 152, 134, 128, 130, 142, 203, 16, 3, + 0, 5, 21, 175, 139, 129, 128, 136, 159, 28, + 7, 0, 2, 13, 62, 145, 132, 128, 133, 150, + 44, 11, 1, 0, 10, 39, 152, 134, 128, 131, + 144, 66, 13, 2, 0, 8, 31, 155, 135, 128, + 131, 143, 85, 13, 2, 0, 8, 31, 155, 135, + 128, 131, 143, 67, 13, 1, 0, 9, 37, 152, + 133, 128, 132, 148, 45, 10, 0, 1, 12, 58, + 144, 131, 128, 135, 157, 29, 7, 0, 3, 17, + 181, 139, 129, 129, 139, 186, 16, 3, 0, 7, + 31, 153, 133, 128, 132, 150, 38, 9, 0, 2, + 15, 193, 140, 129, 129, 139, 188, 15, 2, 0, + 9, 40, 149, 132, 128, 134, 157, 27, 6, 0, + 5, 24, 160, 135, 128, 132, 148, 41, 9, 0, + 3, 17, 176, 138, 128, 130, 143, 58, 11, 0, + 2, 14, 195, 139, 129, 129, 142, 74, 12, 1, + 1, 14, 202, 140, 129, 129, 142, 67, 11, 0, + 2, 15, 186, 138, 128, 130, 144, 47, 9, 0, + 3, 19, 168, 136, 128, 132, 151, 31, 6, 0, + 5, 28, 154, 133, 128, 135, 164, 20, 3, 0, + 9, 51, 143, 130, 129, 140, 87, 11, 0, 2, + 17, 171, 136, 128, 132, 154, 27, 5, 0, 7, + 40, 146, 130, 128, 140, 124, 12, 0, 2, 18, + 166, 135, 128, 134, 159, 22, 3, 0, 10, 72, + 140, 128, 130, 146, 38, 7, 0, 6, 34, 148, + 130, 128, 140, 77, 10, 0, 3, 24, 156, 132, + 128, 137, 186, 13, 1, 2, 19, 162, 134, 128, + 136, 172, 15, 1, 2, 16, 167, 135, 128, 135, + 171, 15, 1, 2, 17, 165, 134, 128, 136, 175, + 14, 1, 2, 20, 158, 133, 128, 138, 203, 11, + 0, 4, 26, 151, 131, 128, 141, 52, 8, 0, + 7, 41, 143, 129, 130, 149, 29, 4, 0, 11, + 199, 137, 128, 134, 166, 15, 1, 2, 21, 156, + 132, 128, 140, 55, 8, 0, 7, 50, 141, 128, + 132, 156, 20, 2, 1, 17, 159, 133, 128, 140, + 57, 8, 0, 8, 59, 139, 128, 133, 163, 15, + 1, 3, 25, 151, 130, 129, 145, 30, 4, 0, + 13, 172, 134, 128, 138, 68, 8, 0, 8, 71, + 138, 128, 134, 175, 12, 0, 5, 38, 142, 128, + 132, 159, 16, 1, 3, 28, 146, 129, 131, 154, + 20, 1, 2, 24, 150, 130, 130, 151, 22, 2, + 2, 23, 150, 130, 130, 151, 22, 2, 2, 25, + 149, 129, 130, 154, 19, 1, 3, 29, 144, 129, + 132, 160, 14, 0, 5, 40, 141, 128, 134, 180, + 11, 0, 8, 90, 137, 128, 138, 58, 6, 0, + 13, 167, 132, 128, 144, 28, 2, 2, 24, 148, + 129, 132, 161, 14, 0, 6, 57, 138, 128, 138, + 57, 6, 0, 14, 159, 131, 129, 151, 20, 1, + 4, 39, 140, 128, 136, 88, 7, 0, 13, 161, + 131, 129, 152, 18, 0, 5, 46, 138, 128, 138, + 47, 5, 0, 19, 151, 129, 132, 167, 12, 0, + 9, 181, 133, 128, 147, 22, 1, 4, 43, 139, + 128, 139, 42, 4, 1, 24, 145, 128, 134, 207, + 7, 0, 15, 155, 130, 131, 168, 11, 0, 11, + 166, 131, 130, 156, 14, 0, 9, 181, 133, 129, + 151, 16, 0, 7, 201, 134, 128, 149, 18, 0, + 7, 213, 134, 128, 149, 18, 0, 7, 199, 133, + 129, 151, 15, 0, 8, 180, 132, 129, 156, 13, + 0, 10, 165, 131, 131, 167, 10, 0, 14, 154, + 129, 133, 204, 7, 0, 22, 143, 128, 137, 42, + 3, 3, 39, 138, 128, 143, 22, 0, 7, 190, + 132, 130, 159, 11, 0, 14, 153, 129, 134, 67, + 5, 2, 31, 139, 128, 143, 22, 0, 8, 176, + 131, 131, 171, 8, 0, 21, 143, 128, 139, 30, + 1, 6, 210, 133, 130, 163, 10, 0, 19, 144, + 128, 139, 29, 1, 6, 188, 132, 131, 174, 7, + 0, 26, 140, 128, 143, 19, 0, 10, 158, 129, + 134, 55, 3, 3, 59, 134, 129, 161, 9, 0, + 23, 141, 128, 143, 18, 0, 12, 154, 128, 137, + 36, 1, 6, 182, 131, 132, 221, 4, 2, 49, + 134, 129, 165, 8, 0, 29, 138, 128, 152, 12, + 0, 20, 142, 128, 145, 15, 0, 15, 146, 128, + 142, 20, 0, 13, 150, 128, 140, 23, 0, 11, + 152, 128, 139, 25, 0, 11, 153, 128, 139, 24, + 0, 12, 151, 128, 140, 21, 0, 13, 147, 128, + 142, 17, 0, 15, 143, 128, 147, 13, 0, 22, + 139, 128, 155, 10, 0, 32, 136, 129, 172, 6, + 2, 68, 132, 132, 63, 2, 6, 168, 129, 137, + 28, 0, 12, 148, 128, 144, 14, 0, 24, 138, + 128, 165, 6, 2, 73, 131, 133, 46, 1, 9, + 155, 128, 141, 16, 0, 22, 138, 128, 167, 6, + 3, 208, 130, 135, 31, 0, 12, 145, 128, 151, + 10, 1, 44, 133, 132, 50, 1, 9, 151, 128, + 146, 12, 0, 38, 133, 132, 54, 1, 10, 150, + 128, 148, 11, 1, 47, 132, 133, 38, 0, 13, + 143, 128, 157, 7, 3, 189, 129, 138, 21, 0, + 24, 136, 130, 109, 2, 9, 151, 128, 151, 9, + 2, 232, 130, 137, 21, 0, 25, 136, 131, 59, + 1, 11, 144, 128, 161, 5, 5, 164, 128, 143, + 11, 1, 64, 130, 137, 21, 0, 28, 134, 132, + 39, 0, 15, 139, 129, 223, 1, 10, 144, 128, + 167, 4, 7, 153, 128, 154, 6, 4, 163, 128, + 147, 9, 2, 178, 128, 143, 11, 1, 203, 129, + 141, 12, 1, 93, 129, 140, 13, 1, 76, 129, + 140, 13, 1, 79, 129, 140, 13, 1, 235, 129, + 141, 12, 2, 189, 128, 143, 10, 3, 171, 128, + 149, 7, 4, 158, 128, 157, 5, 7, 149, 128, + 174, 2, 11, 141, 129, 66, 0, 17, 136, 132, + 30, 0, 31, 132, 137, 16, 0, 106, 128, 143, + 9, 4, 158, 128, 162, 3, 10, 141, 129, 52, + 0, 23, 134, 135, 19, 0, 89, 128, 145, 7, + 5, 152, 128, 186, 1, 15, 136, 133, 25, 0, + 57, 129, 143, 8, 5, 150, 128, 206, 0, 19, + 134, 135, 17, 1, 185, 128, 155, 4, 10, 140, + 131, 31, 0, 46, 129, 144, 7, 6, 145, 129, + 48, 0, 32, 130, 141, 9, 5, 148, 128, 57, + 0, 31, 130, 141, 8, 6, 146, 129, 44, 0, + 41, 129, 145, 6, 8, 141, 131, 28, 0, 224, + 128, 157, 2, 14, 135, 135, 14, 2, 156, 128, + 78, 0, 33, 129, 145, 5, 10, 139, 132, 20, + 1, 165, 128, 204, 0, 30, 130, 145, 5, 10, + 138, 134, 15, 2, 155, 128, 48, 0, 58, 128, + 158, 1, 19, 132, 140, 8, 8, 140, 133, 17, + 2, 154, 128, 41, 0, 216, 128, 174, 0, 30, + 129, 150, 3, 15, 133, 140, 8, 9, 138, 134, + 13, 4, 145, 131, 23, 1, 156, 128, 37, 0, + 176, 128, 73, 0, 75, 128, 179, 0, 41, 128, + 162, 0, 29, 129, 154, 1, 24, 130, 150, 2, + 20, 131, 146, 3, 17, 131, 144, 3, 16, 132, + 144, 4, 16, 131, 144, 3, 17, 131, 146, 3, + 19, 130, 149, 2, 23, 130, 153, 1, 28, 129, + 160, 0, 39, 128, 175, 0, 64, 128, 89, 0, + 181, 128, 39, 0, 158, 129, 24, 2, 146, 132, + 14, 6, 139, 136, 8, 11, 133, 143, 3, 21, + 129, 158, 0, 47, 128, 80, 0, 167, 129, 25, + 2, 143, 133, 11, 9, 135, 141, 3, 22, 129, + 165, 0, 114, 128, 37, 1, 149, 132, 12, 8, + 135, 142, 3, 25, 128, 179, 0, 173, 129, 23, + 4, 140, 137, 6, 16, 130, 161, 0, 198, 128, + 26, 3, 141, 137, 6, 17, 129, 168, 0, 174, + 129, 19, 5, 137, 141, 3, 29, 128, 64, 0, + 150, 133, 9, 13, 131, 159, 0, 179, 129, 17, + 6, 135, 144, 1, 49, 128, 29, 3, 139, 139, + 3, 31, 128, 43, 2, 142, 137, 4, 27, 128, + 49, 1, 142, 137, 4, 27, 128, 44, 2, 141, + 138, 3, 34, 128, 31, 3, 138, 142, 1, 62, + 128, 20, 7, 133, 154, 0, 168, 131, 10, 14, + 129, 201, 0, 144, 137, 3, 35, 128, 26, 5, + 134, 152, 0, 163, 131, 8, 19, 128, 46, 2, + 138, 143, 0, 183, 130, 10, 15, 128, 55, 2, + 138, 144, 0, 174, 131, 9, 19, 128, 35, 4, + 134, 154, 0, 154, 135, 4, 39, 128, 16, 11, + 129, 104, 1, 138, 145, 0, 160, 133, 5, 35, + 128, 15, 11, 129, 57, 3, 135, 154, 0, 148, + 138, 1, 202, 130, 8, 26, 128, 19, 11, 129, + 53, 3, 134, 161, 0, 142, 142, 0, 158, 135, + 3, 87, 130, 8, 28, 128, 14, 14, 128, 28, + 8, 130, 60, 4, 133, 172, 1, 137, 153, 0, + 142, 143, 0, 151, 138, 0, 163, 135, 2, 187, + 132, 4, 65, 130, 6, 41, 129, 8, 30, 128, + 10, 25, 128, 12, 22, 128, 13, 19, 128, 14, + 17, 128, 15, 16, 128, 15, 16, 128, 14, 18, + 128, 14, 20, 128, 12, 23, 128, 11, 27, 128, + 9, 33, 129, 7, 46, 130, 5, 96, 132, 2, + 175, 135, 1, 157, 139, 0, 147, 143, 0, 140, + 154, 0, 135, 175, 3, 131, 51, 7, 128, 25, + 13, 128, 13, 26, 129, 6, 68, 133, 2, 159, + 139, 0, 142, 153, 1, 134, 230, 6, 129, 25, + 14, 128, 10, 40, 131, 2, 162, 139, 0, 140, + 159, 2, 131, 38, 11, 128, 12, 35, 131, 2, + 158, 141, 0, 137, 181, 5, 129, 20, 20, 129, + 5, 175, 138, 0, 139, 171, 4, 129, 20, 22, + 129, 3, 163, 141, 0, 135, 75, 9, 128, 11, + 48, 134, 0, 142, 161, 4, 129, 18, 27, 130, + 1, 149, 151, 2, 130, 23, 22, 130, 2, 151, + 151, 2, 130, 21, 26, 131, 1, 145, 158, 4, + 128, 13, 43, 134, 0, 138, 235, 10, 128, 6, + 169, 142, 1, 131, 23, 26, 131, 0, 140, 187, + 9, 128, 6, 164, 145, 2, 129, 15, 43, 135, + 0, 134, 36, 18, 130, 1, 141, 192, 10, 128, + 3, 151, 158, 6, 128, 7, 163, 148, 3, 128, + 10, 181, 143, 2, 128, 11, 203, 141, 1, 129, + 12, 206, 141, 1, 128, 11, 187, 143, 2, 128, + 9, 168, 149, 4, 128, 6, 154, 160, 8, 128, + 2, 142, 218, 13, 130, 0, 136, 30, 29, 135, + 0, 130, 13, 191, 145, 4, 128, 4, 146, 189, + 13, 130, 0, 133, 21, 50, 140, 2, 128, 5, + 148, 189, 14, 131, 0, 132, 15, 193, 148, 6, + 128, 1, 138, 31, 35, 139, 2, 128, 4, 142, + 55, 24, 136, 1, 128, 6, 145, 75, 22, 135, + 1, 128, 5, 143, 53, 26, 137, 2, 128, 3, + 139, 30, 46, 143, 5, 128, 0, 133, 14, 168, +}; + +static const int16_t ref_mulaw_dec_data[4000] = { + 30076, 29052, 28028, 25980, 24956, 22908, 20860, 18812, 16764, 14460, + 12412, 9852, 7420, 4860, 2236, -428, -3004, -5628, -8316, -10876, + -12924, -15484, -17788, -19836, -21884, -23932, -25980, -27004, -28028, -30076, + -31100, -31100, -32124, -32124, -32124, -32124, -32124, -32124, -31100, -30076, + -29052, -28028, -27004, -24956, -22908, -20860, -18812, -16764, -14460, -12412, + -9852, -7164, -4348, -1692, 988, 3644, 6396, 8828, 11388, 13948, + 16764, 18812, 20860, 22908, 24956, 25980, 28028, 29052, 30076, 31100, + 32124, 32124, 32124, 32124, 32124, 32124, 31100, 30076, 29052, 28028, + 27004, 24956, 22908, 20860, 18812, 16764, 13948, 11388, 8828, 5884, + 3132, 396, -2364, -5116, -7932, -10364, -13436, -15484, -17788, -20860, + -22908, -24956, -25980, -28028, -29052, -30076, -31100, -32124, -32124, -32124, + -32124, -32124, -32124, -31100, -30076, -29052, -28028, -25980, -23932, -21884, + -19836, -17788, -14972, -12412, -9852, -6908, -4092, -1244, 1628, 4604, + 7420, 10364, 12924, 15484, 17788, 19836, 22908, 24956, 25980, 28028, + 29052, 30076, 31100, 32124, 32124, 32124, 32124, 32124, 32124, 31100, + 30076, 28028, 27004, 24956, 22908, 20860, 18812, 15996, 13436, 10364, + 7676, 4604, 1756, -1180, -4092, -7164, -9852, -12924, -15484, -17788, + -20860, -22908, -24956, -27004, -28028, -30076, -31100, -32124, -32124, -32124, + -32124, -32124, -32124, -31100, -30076, -29052, -27004, -25980, -23932, -21884, + -18812, -16764, -13948, -10876, -8316, -5116, -2108, 924, 4092, 6908, + 9852, 12924, 15484, 17788, 20860, 22908, 24956, 27004, 29052, 30076, + 31100, 32124, 32124, 32124, 32124, 32124, 32124, 31100, 30076, 28028, + 25980, 24956, 21884, 19836, 17788, 14460, 11900, 8828, 5628, 2492, + -684, -3772, -6908, -9852, -12924, -15996, -18812, -20860, -22908, -25980, + -27004, -29052, -30076, -31100, -32124, -32124, -32124, -32124, -32124, -31100, + -30076, -29052, -27004, -24956, -22908, -20860, -17788, -15484, -12412, -9340, + -6140, -3004, 212, 3516, 6652, 9852, 12924, 15996, 18812, 20860, + 23932, 25980, 28028, 29052, 30076, 31100, 32124, 32124, 32124, 32124, + 32124, 31100, 30076, 28028, 25980, 23932, 21884, 18812, 16764, 13436, + 10364, 7164, 3900, 620, -2748, -6140, -9340, -12412, -15484, -18812, + -20860, -23932, -25980, -28028, -29052, -31100, -32124, -32124, -32124, -32124, + -32124, -32124, -31100, -29052, -28028, -25980, -22908, -20860, -17788, -14972, + -11900, -8828, -5372, -1980, 1372, 4860, 8316, 11388, 14460, 17788, + 20860, 22908, 24956, 27004, 29052, 30076, 32124, 32124, 32124, 32124, + 32124, 32124, 30076, 29052, 27004, 24956, 22908, 19836, 17788, 14460, + 10876, 7676, 4348, 716, -2748, -6396, -9852, -12924, -15996, -18812, + -21884, -23932, -27004, -29052, -30076, -31100, -32124, -32124, -32124, -32124, + -32124, -31100, -29052, -27004, -24956, -22908, -19836, -17788, -13948, -10876, + -7420, -3772, -196, 3388, 6908, 10364, 13948, 16764, 19836, 22908, + 24956, 27004, 29052, 31100, 32124, 32124, 32124, 32124, 32124, 31100, + 30076, 28028, 25980, 23932, 20860, 17788, 14972, 11388, 7932, 4348, + 684, -3004, -6652, -10364, -13948, -16764, -19836, -22908, -24956, -28028, + -29052, -31100, -32124, -32124, -32124, -32124, -32124, -31100, -29052, -27004, + -24956, -22908, -19836, -16764, -13436, -9852, -6140, -2364, 1436, 5116, + 8828, 12412, 15996, 18812, 21884, 24956, 27004, 29052, 31100, 32124, + 32124, 32124, 32124, 32124, 31100, 29052, 27004, 24956, 22908, 19836, + 16764, 12924, 9340, 5372, 1628, -2236, -6140, -9852, -13436, -16764, + -19836, -22908, -25980, -28028, -30076, -31100, -32124, -32124, -32124, -32124, + -31100, -30076, -28028, -25980, -23932, -20860, -16764, -13948, -9852, -6140, + -2236, 1692, 5628, 9340, 13436, 16764, 19836, 22908, 25980, 28028, + 30076, 31100, 32124, 32124, 32124, 32124, 31100, 30076, 28028, 24956, + 22908, 19836, 15996, 12412, 8828, 4604, 620, -3516, -7420, -11388, + -14972, -18812, -21884, -24956, -27004, -29052, -31100, -32124, -32124, -32124, + -32124, -31100, -30076, -28028, -25980, -22908, -19836, -16764, -12924, -8828, + -4860, -620, 3516, 7676, 11388, 15484, 18812, 21884, 24956, 28028, + 30076, 31100, 32124, 32124, 32124, 32124, 31100, 29052, 27004, 24956, + 21884, 18812, 14972, 10876, 6908, 2620, -1628, -5884, -9852, -13948, + -17788, -20860, -23932, -27004, -29052, -31100, -32124, -32124, -32124, -32124, + -31100, -30076, -28028, -24956, -21884, -18812, -14972, -10876, -6652, -2364, + 1980, 6396, 10364, 14460, 17788, 21884, 24956, 27004, 30076, 31100, + 32124, 32124, 32124, 32124, 31100, 29052, 27004, 23932, 20860, 16764, + 12924, 8828, 4348, -48, -4604, -8828, -12924, -16764, -20860, -23932, + -27004, -29052, -31100, -32124, -32124, -32124, -32124, -31100, -29052, -27004, + -23932, -20860, -16764, -12924, -8828, -4348, 228, 4860, 9340, 13436, + 17788, 20860, 23932, 27004, 29052, 31100, 32124, 32124, 32124, 32124, + 30076, 28028, 25980, 22908, 18812, 15484, 10876, 6652, 2108, -2492, + -7164, -11388, -15996, -19836, -22908, -25980, -29052, -31100, -32124, -32124, + -32124, -32124, -31100, -29052, -25980, -22908, -19836, -15996, -11388, -7164, + -2364, 2236, 6908, 11388, 15996, 19836, 22908, 25980, 29052, 31100, + 32124, 32124, 32124, 32124, 30076, 28028, 25980, 22908, 18812, 14460, + 10364, 5372, 716, -4092, -8828, -13436, -17788, -21884, -24956, -28028, + -30076, -31100, -32124, -32124, -32124, -31100, -29052, -27004, -23932, -19836, + -15996, -11388, -6652, -1820, 3004, 7932, 12412, 16764, 20860, 24956, + 27004, 30076, 31100, 32124, 32124, 32124, 31100, 29052, 27004, 22908, + 19836, 15484, 10876, 5884, 1052, -3900, -8828, -13436, -17788, -21884, + -24956, -28028, -30076, -32124, -32124, -32124, -32124, -30076, -28028, -24956, + -21884, -17788, -12924, -8316, -3388, 1692, 6652, 11388, 15996, 20860, + 23932, 27004, 30076, 31100, 32124, 32124, 32124, 31100, 29052, 25980, + 21884, 17788, 13948, 8828, 3900, -1244, -6396, -11388, -15996, -20860, + -23932, -27004, -30076, -32124, -32124, -32124, -32124, -30076, -28028, -24956, + -21884, -17788, -12924, -7676, -2620, 2620, 7932, 12924, 17788, 21884, + 24956, 28028, 31100, 32124, 32124, 32124, 31100, 29052, 27004, 23932, + 19836, 14972, 9852, 4860, -556, -5884, -10876, -15996, -20860, -23932, + -28028, -30076, -32124, -32124, -32124, -32124, -30076, -27004, -23932, -19836, + -15484, -10364, -5116, 180, 5628, 10876, 15996, 20860, 23932, 28028, + 30076, 32124, 32124, 32124, 31100, 30076, 27004, 22908, 18812, 14460, + 9340, 3900, -1564, -7164, -12412, -17788, -21884, -25980, -29052, -31100, + -32124, -32124, -32124, -31100, -28028, -24956, -21884, -16764, -11900, -6396, + -924, 4604, 10364, 15484, 19836, 23932, 28028, 30076, 32124, 32124, + 32124, 31100, 29052, 25980, 21884, 17788, 12924, 7420, 1756, -3900, + -9340, -14972, -19836, -23932, -27004, -30076, -32124, -32124, -32124, -31100, + -29052, -25980, -21884, -17788, -12412, -6652, -988, 4860, 10364, 15996, + 20860, 24956, 28028, 31100, 32124, 32124, 32124, 31100, 28028, 24956, + 20860, 15484, 10364, 4348, -1500, -7420, -12924, -17788, -22908, -27004, + -30076, -32124, -32124, -32124, -31100, -29052, -25980, -21884, -17788, -11900, + -6396, -324, 5628, 11388, 16764, 21884, 25980, 29052, 31100, 32124, + 32124, 32124, 30076, 27004, 22908, 17788, 12412, 6652, 620, -5372, + -11388, -16764, -21884, -25980, -29052, -31100, -32124, -32124, -31100, -29052, + -25980, -21884, -16764, -11388, -5372, 652, 6908, 12924, 17788, 22908, + 27004, 30076, 32124, 32124, 32124, 31100, 28028, 24956, 19836, 14972, + 8828, 2748, -3516, -9852, -15484, -20860, -24956, -29052, -31100, -32124, + -32124, -32124, -29052, -25980, -21884, -16764, -10876, -4604, 1628, 7932, + 13948, 19836, 23932, 28028, 31100, 32124, 32124, 32124, 30076, 27004, + 21884, 16764, 11388, 5372, -1180, -7676, -13436, -18812, -23932, -28028, + -31100, -32124, -32124, -32124, -30076, -25980, -21884, -16764, -10876, -4348, + 2236, 8828, 14972, 19836, 24956, 29052, 31100, 32124, 32124, 31100, + 29052, 24956, 19836, 14460, 8316, 1980, -4604, -10876, -16764, -21884, + -27004, -30076, -32124, -32124, -32124, -30076, -27004, -22908, -16764, -11388, + -4604, 1980, 8828, 14972, 20860, 24956, 29052, 31100, 32124, 32124, + 31100, 28028, 23932, 18812, 12412, 6140, -652, -7420, -13948, -19836, + -24956, -29052, -31100, -32124, -32124, -31100, -28028, -23932, -18812, -12924, + -6140, 652, 7420, 13948, 19836, 24956, 29052, 31100, 32124, 32124, + 31100, 28028, 22908, 17788, 11900, 4860, -1980, -8828, -15484, -20860, + -25980, -30076, -32124, -32124, -32124, -30076, -25980, -21884, -15996, -9340, + -2236, 4860, 11900, 17788, 23932, 28028, 31100, 32124, 32124, 31100, + 28028, 23932, 18812, 12412, 5372, -1820, -8828, -15484, -21884, -25980, + -30076, -32124, -32124, -32124, -29052, -24956, -19836, -13948, -7164, 88, + 7420, 13948, 19836, 25980, 29052, 32124, 32124, 32124, 30076, 25980, + 20860, 14460, 7676, 372, -6908, -13948, -19836, -24956, -29052, -32124, + -32124, -32124, -29052, -25980, -19836, -13948, -6908, 428, 7932, 14972, + 20860, 25980, 30076, 32124, 32124, 31100, 29052, 24956, 18812, 12412, + 4860, -2492, -9852, -16764, -22908, -28028, -31100, -32124, -32124, -31100, + -27004, -21884, -15996, -9340, -1628, 5884, 13436, 19836, 24956, 29052, + 32124, 32124, 32124, 29052, 24956, 18812, 11900, 4604, -3004, -10364, + -17788, -23932, -28028, -31100, -32124, -32124, -30076, -25980, -20860, -13948, + -6652, 1180, 8828, 15996, 22908, 27004, 31100, 32124, 32124, 30076, + 27004, 20860, 14460, 7164, -556, -8316, -15484, -21884, -27004, -31100, + -32124, -32124, -30076, -27004, -20860, -14460, -6908, 1116, 8828, 16764, + 22908, 28028, 31100, 32124, 32124, 30076, 25980, 19836, 12924, 5116, + -2876, -10876, -17788, -23932, -29052, -32124, -32124, -32124, -29052, -23932, + -17788, -10364, -2364, 5884, 13436, 20860, 25980, 30076, 32124, 32124, + 31100, 27004, 20860, 14460, 6396, -1756, -9852, -17788, -23932, -29052, + -32124, -32124, -32124, -29052, -23932, -16764, -9340, -1244, 7164, 14972, + 21884, 27004, 31100, 32124, 32124, 30076, 24956, 18812, 11388, 3260, + -5116, -13436, -20860, -25980, -30076, -32124, -32124, -30076, -25980, -19836, + -12412, -4092, 4348, 12924, 19836, 25980, 30076, 32124, 32124, 30076, + 25980, 19836, 12412, 3900, -4860, -12924, -20860, -25980, -30076, -32124, + -32124, -30076, -24956, -18812, -10876, -2492, 6140, 14460, 21884, 27004, + 31100, 32124, 32124, 29052, 23932, 16764, 8828, 88, -8828, -16764, + -23932, -29052, -32124, -32124, -31100, -27004, -20860, -13948, -5372, 3516, + 11900, 19836, 25980, 30076, 32124, 32124, 29052, 24956, 17788, 9852, + 812, -8316, -16764, -23932, -29052, -32124, -32124, -31100, -27004, -20860, + -12924, -4092, 4860, 13436, 20860, 27004, 31100, 32124, 32124, 28028, + 22908, 14972, 6396, -2748, -11900, -19836, -25980, -31100, -32124, -32124, + -29052, -23932, -16764, -7676, 1436, 10364, 18812, 25980, 30076, 32124, + 32124, 29052, 23932, 16764, 8316, -1180, -10364, -18812, -25980, -30076, + -32124, -32124, -29052, -23932, -15996, -7420, 1980, 11388, 19836, 25980, + 31100, 32124, 32124, 28028, 22908, 14972, 5884, -3644, -12924, -20860, + -27004, -31100, -32124, -31100, -27004, -20860, -12412, -3132, 6396, 15484, + 22908, 29052, 32124, 32124, 30076, 24956, 17788, 8828, -556, -10364, + -18812, -25980, -31100, -32124, -32124, -28028, -21884, -13948, -4604, 5372, + 14460, 22908, 29052, 32124, 32124, 30076, 24956, 17788, 8828, -1244, + -10876, -19836, -27004, -31100, -32124, -31100, -27004, -20860, -11900, -1980, + 7932, 16764, 24956, 30076, 32124, 32124, 28028, 21884, 13948, 4348, + -5884, -15484, -22908, -29052, -32124, -32124, -29052, -23932, -15484, -5628, + 4348, 13948, 22908, 29052, 32124, 32124, 30076, 23932, 15996, 6140, + -4092, -13948, -22908, -29052, -32124, -32124, -30076, -23932, -15484, -5884, + 4604, 14460, 22908, 29052, 32124, 32124, 29052, 22908, 14460, 4604, + -5884, -15996, -23932, -30076, -32124, -32124, -28028, -21884, -12412, -2236, + 8316, 17788, 25980, 31100, 32124, 31100, 27004, 18812, 9852, -924, + -11388, -20860, -28028, -32124, -32124, -30076, -23932, -15996, -5628, 5116, + 14972, 23932, 30076, 32124, 32124, 28028, 20860, 11388, 716, -9852, + -19836, -27004, -32124, -32124, -30076, -23932, -15996, -5628, 5116, 15484, + 23932, 30076, 32124, 32124, 27004, 19836, 9852, -1180, -11900, -20860, + -28028, -32124, -32124, -29052, -21884, -12924, -2108, 8828, 18812, 27004, + 31100, 32124, 30076, 23932, 15484, 4604, -6396, -16764, -24956, -31100, + -32124, -31100, -24956, -16764, -6396, 4860, 15484, 23932, 30076, 32124, + 31100, 25980, 17788, 7164, -4092, -14972, -23932, -30076, -32124, -31100, + -25980, -17788, -7164, 4092, 14972, 23932, 30076, 32124, 31100, 25980, + 16764, 6396, -5116, -15996, -24956, -31100, -32124, -31100, -24956, -15996, + -4860, 6652, 17788, 25980, 31100, 32124, 30076, 22908, 13948, 2492, + -9340, -19836, -28028, -32124, -32124, -29052, -20860, -10876, 780, 12412, + 21884, 29052, 32124, 32124, 27004, 17788, 6908, -4860, -15996, -24956, + -31100, -32124, -30076, -23932, -13948, -2108, 9852, 19836, 28028, 32124, + 32124, 28028, 18812, 8316, -3644, -14972, -24956, -31100, -32124, -30076, + -23932, -13948, -1980, 9852, 20860, 29052, 32124, 32124, 27004, 17788, + 6908, -5372, -16764, -25980, -31100, -32124, -29052, -21884, -10876, 1372, + 13436, 23932, 30076, 32124, 30076, 23932, 13948, 1980, -10364, -20860, + -29052, -32124, -31100, -25980, -16764, -4604, 7676, 18812, 28028, 32124, + 32124, 27004, 17788, 6652, -5884, -17788, -27004, -32124, -32124, -28028, + -19836, -7932, 4860, 16764, 25980, 32124, 32124, 28028, 19836, 8316, + -4348, -16764, -25980, -32124, -32124, -28028, -19836, -8316, 4604, 16764, + 25980, 32124, 32124, 28028, 18812, 7164, -5628, -17788, -27004, -32124, + -32124, -27004, -17788, -5628, 7420, 19836, 28028, 32124, 32124, 25980, + 15484, 3132, -9852, -21884, -29052, -32124, -31100, -23932, -12924, 16, + 12924, 23932, 31100, 32124, 29052, 20860, 9340, -3900, -16764, -25980, + -32124, -32124, -27004, -17788, -4860, 8316, 20860, 29052, 32124, 31100, + 23932, 12924, -524, -13948, -24956, -31100, -32124, -28028, -18812, -6908, + 6652, 18812, 28028, 32124, 31100, 24956, 13436, 164, -13436, -23932, + -31100, -32124, -28028, -18812, -6396, 7420, 19836, 29052, 32124, 31100, + 22908, 11900, -1884, -15484, -25980, -32124, -32124, -27004, -16764, -3004, + 10876, 22908, 30076, 32124, 29052, 19836, 7420, -6652, -19836, -29052, + -32124, -31100, -22908, -10876, 3132, 16764, 27004, 32124, 32124, 24956, + 13948, -88, -13948, -24956, -32124, -32124, -27004, -15996, -2364, 11900, + 23932, 31100, 32124, 28028, 17788, 4092, -10364, -22908, -31100, -32124, + -28028, -18812, -5116, 9340, 21884, 30076, 32124, 29052, 18812, 5628, + -8828, -21884, -30076, -32124, -29052, -18812, -5628, 9340, 21884, 30076, + 32124, 28028, 18812, 4860, -9852, -22908, -31100, -32124, -28028, -17788, + -3388, 11388, 23932, 31100, 32124, 27004, 15484, 1244, -13436, -24956, + -32124, -32124, -24956, -13436, 1500, 15996, 27004, 32124, 31100, 22908, + 10364, -4860, -18812, -29052, -32124, -30076, -19836, -6396, 8828, 21884, + 31100, 32124, 27004, 16764, 1756, -13436, -24956, -32124, -32124, -23932, + -11900, 3516, 17788, 28028, 32124, 30076, 19836, 6140, -9340, -22908, + -31100, -32124, -27004, -14460, 492, 15484, 27004, 32124, 31100, 21884, + 7932, -7676, -21884, -30076, -32124, -27004, -15484, -196, 14972, 27004, + 32124, 31100, 21884, 7676, -8316, -21884, -31100, -32124, -25980, -13948, + 1500, 16764, 28028, 32124, 30076, 19836, 4860, -10876, -23932, -32124, + -32124, -23932, -10364, 5628, 19836, 30076, 32124, 27004, 15484, -396, + -15996, -28028, -32124, -30076, -19836, -4348, 11900, 24956, 32124, 31100, + 22908, 8316, -7932, -21884, -31100, -32124, -24956, -11900, 4604, 19836, + 30076, 32124, 27004, 14460, -1500, -17788, -29052, -32124, -28028, -16764, + -988, 14972, 27004, 32124, 29052, 18812, 2876, -13436, -27004, -32124, + -30076, -19836, -4348, 12412, 25980, 32124, 30076, 20860, 5116, -11900, + -24956, -32124, -31100, -20860, -5372, 11388, 24956, 32124, 31100, 20860, + 5116, -11900, -25980, -32124, -30076, -19836, -4348, 12412, 25980, 32124, + 30076, 18812, 3132, -13948, -27004, -32124, -29052, -17788, -1180, 15484, + 28028, 32124, 28028, 15484, -1244, -17788, -29052, -32124, -27004, -12924, + 4348, 20860, 31100, 32124, 24956, 9852, -7932, -22908, -32124, -31100, + -21884, -5884, 11900, 25980, 32124, 30076, 17788, 1180, -15996, -29052, + -32124, -27004, -13436, 4092, 20860, 31100, 32124, 23932, 8316, -9852, + -24956, -32124, -30076, -18812, -2108, 15484, 28028, 32124, 27004, 12924, + -4860, -20860, -31100, -32124, -21884, -6140, 11900, 25980, 32124, 29052, + 15996, -1756, -18812, -30076, -32124, -23932, -8316, 10364, 24956, 32124, + 29052, 16764, -716, -18812, -30076, -32124, -23932, -8316, 10364, 24956, + 32124, 29052, 16764, -1692, -18812, -31100, -32124, -22908, -6652, 11900, + 27004, 32124, 28028, 13948, -4604, -21884, -32124, -31100, -19836, -2620, + 15996, 29052, 32124, 24956, 9340, -9340, -24956, -32124, -29052, -15484, + 3260, 20860, 31100, 31100, 20860, 2620, -15996, -29052, -32124, -24956, + -8316, 11388, 27004, 32124, 28028, 12924, -6396, -22908, -32124, -30076, + -16764, 1820, 19836, 31100, 31100, 20860, 2364, -16764, -30076, -32124, + -22908, -5884, 13436, 28028, 32124, 25980, 9340, -10364, -25980, -32124, + -27004, -11900, 7932, 24956, 32124, 28028, 13948, -5628, -22908, -32124, + -29052, -15484, 3900, 21884, 32124, 30076, 16764, -2620, -20860, -32124, + -30076, -17788, 1692, 20860, 31100, 31100, 17788, -1244, -19836, -31100, + -31100, -17788, 1244, 19836, 31100, 31100, 17788, -1692, -20860, -32124, + -30076, -16764, 2620, 21884, 32124, 30076, 15996, -4092, -22908, -32124, + -29052, -14460, 5884, 23932, 32124, 28028, 12412, -8316, -25980, -32124, + -27004, -9852, 10876, 27004, 32124, 24956, 6908, -13948, -29052, -32124, + -22908, -3516, 16764, 30076, 31100, 19836, -652, -20860, -32124, -30076, + -15484, 5116, 23932, 32124, 28028, 10876, -10364, -27004, -32124, -24956, + -5884, 14972, 30076, 32124, 19836, -24, -19836, -32124, -30076, -14972, + 6396, 24956, 32124, 25980, 8316, -12924, -29052, -32124, -21884, -1372, + 19836, 32124, 30076, 14972, -6396, -24956, -32124, -25980, -7420, 13948, + 30076, 32124, 19836, -1052, -21884, -32124, -29052, -11900, 9852, 28028, + 32124, 22908, 2620, -18812, -31100, -30076, -14460, 7420, 25980, 32124, + 23932, 4860, -16764, -31100, -30076, -15996, 6140, 24956, 32124, 24956, + 5116, -16764, -31100, -30076, -15484, 6652, 25980, 32124, 23932, 4092, + -17788, -31100, -30076, -13948, 8828, 27004, 32124, 21884, 1180, -20860, + -32124, -28028, -10876, 12412, 29052, 32124, 18812, -3388, -23932, -32124, + -24956, -5628, 16764, 31100, 30076, 13436, -9340, -28028, -32124, -20860, + 1436, 22908, 32124, 25980, 6396, -16764, -31100, -30076, -13436, 9852, + 28028, 32124, 19836, -3004, -23932, -32124, -24956, -3644, 18812, 32124, + 28028, 9852, -13948, -30076, -31100, -15484, 8316, 27004, 32124, 19836, + -2748, -23932, -32124, -23932, -2492, 20860, 32124, 27004, 7164, -16764, + -31100, -29052, -11388, 12412, 30076, 31100, 15484, -8828, -28028, -32124, + -18812, 4860, 25980, 32124, 21884, -1628, -23932, -32124, -23932, -1436, + 21884, 32124, 25980, 4092, -19836, -32124, -27004, -6396, 17788, 32124, + 28028, 8316, -15996, -31100, -29052, -9852, 14972, 31100, 29052, 10876, + -13948, -31100, -30076, -11900, 12924, 30076, 30076, 12412, -12924, -30076, + -30076, -12412, 12924, 30076, 30076, 12412, -12924, -30076, -30076, -11388, + 13436, 31100, 30076, 10876, -14460, -31100, -29052, -9340, 15996, 31100, + 28028, 7932, -17788, -32124, -27004, -5884, 18812, 32124, 25980, 3388, + -20860, -32124, -23932, -556, 22908, 32124, 21884, -2620, -25980, -32124, + -18812, 6140, 28028, 32124, 15996, -9852, -30076, -30076, -11900, 13948, + 31100, 28028, 7676, -17788, -32124, -25980, -2748, 21884, 32124, 21884, + -2748, -25980, -32124, -17788, 8316, 29052, 31100, 12412, -13948, -31100, + -28028, -6140, 19836, 32124, 23932, -620, -24956, -32124, -18812, 7676, + 29052, 31100, 11900, -14972, -32124, -27004, -4348, 21884, 32124, 21884, + -4092, -27004, -32124, -14460, 12412, 31100, 28028, 6140, -19836, -32124, + -22908, 3260, 27004, 32124, 14460, -12924, -31100, -28028, -5116, 20860, + 32124, 20860, -5372, -28028, -31100, -11900, 15484, 32124, 25980, 924, + -24956, -32124, -16764, 10364, 30076, 29052, 5884, -20860, -32124, -20860, + 6396, 29052, 30076, 9852, -17788, -32124, -22908, 3260, 27004, 31100, + 12412, -15996, -32124, -24956, 1308, 25980, 32124, 13436, -14972, -32124, + -24956, 716, 25980, 32124, 13436, -14972, -32124, -24956, 1436, 27004, + 31100, 12412, -16764, -32124, -23932, 3388, 28028, 31100, 9852, -18812, + -32124, -21884, 6652, 29052, 29052, 6140, -21884, -32124, -17788, 10876, + 31100, 27004, 1116, -24956, -32124, -12924, 16764, 32124, 22908, -5372, + -29052, -29052, -6140, 21884, 32124, 16764, -12924, -32124, -24956, 2108, + 28028, 30076, 8316, -20860, -32124, -17788, 11388, 31100, 25980, -1692, + -27004, -30076, -8316, 20860, 32124, 16764, -12924, -32124, -23932, 3900, + 29052, 29052, 5116, -23932, -32124, -13436, 16764, 32124, 20860, -8828, + -31100, -25980, 812, 27004, 30076, 7164, -21884, -32124, -14460, 15996, + 32124, 20860, -9340, -31100, -25980, 2364, 28028, 29052, 4348, -24956, + -32124, -10876, 19836, 32124, 16764, -14460, -32124, -21884, 8828, 31100, + 25980, -3004, -29052, -29052, -2492, 25980, 31100, 7676, -22908, -32124, + -12412, 18812, 32124, 16764, -14972, -32124, -19836, 10876, 32124, 22908, + -6908, -31100, -25980, 3132, 29052, 28028, 460, -28028, -30076, -3772, + 25980, 31100, 6652, -23932, -32124, -9340, 21884, 32124, 11900, -19836, + -32124, -13948, 17788, 32124, 15484, -16764, -32124, -16764, 14972, 32124, + 17788, -13948, -32124, -18812, 12924, 32124, 19836, -12412, -32124, -20860, + 11900, 32124, 20860, -11388, -32124, -20860, 11388, 32124, 20860, -11900, + -32124, -19836, 12412, 32124, 19836, -13436, -32124, -18812, 14460, 32124, + 17788, -15484, -32124, -16764, 16764, 32124, 14460, -18812, -32124, -12924, + 20860, 32124, 10364, -21884, -32124, -7932, 23932, 31100, 4860, -25980, + -30076, -1628, 28028, 28028, -1980, -30076, -25980, 5884, 31100, 22908, + -9852, -32124, -19836, 13948, 32124, 15996, -17788, -32124, -11900, 21884, + 32124, 6652, -25980, -30076, -1308, 29052, 27004, -4348, -31100, -22908, + 10364, 32124, 18812, -15996, -32124, -12924, 21884, 32124, 6140, -25980, + -29052, 876, 30076, 24956, -8316, -32124, -19836, 15484, 32124, 12412, + -21884, -31100, -4860, 27004, 28028, -3644, -31100, -22908, 12412, 32124, + 14972, -19836, -32124, -6396, 27004, 28028, -3132, -31100, -21884, 12924, + 32124, 13948, -20860, -31100, -4092, 28028, 27004, -6396, -32124, -18812, + 16764, 32124, 9340, -24956, -29052, 2236, 31100, 21884, -13436, -32124, + -11900, 23932, 30076, -164, -30076, -22908, 12412, 32124, 12412, -22908, + -30076, 244, 30076, 22908, -13436, -32124, -11388, 23932, 29052, -2492, + -31100, -20860, 15996, 32124, 7676, -27004, -27004, 6908, 32124, 16764, + -20860, -31100, -1884, 30076, 22908, -13436, -32124, -9852, 25980, 28028, + -6140, -32124, -16764, 20860, 31100, 396, -31100, -21884, 15996, 32124, + 6140, -28028, -24956, 11388, 32124, 10876, -25980, -28028, 7164, 32124, + 14460, -22908, -30076, 3644, 32124, 16764, -20860, -31100, 1180, 31100, + 18812, -19836, -31100, -460, 31100, 19836, -18812, -31100, -1116, 31100, + 19836, -18812, -31100, -924, 31100, 19836, -18812, -31100, 196, 31100, + 18812, -19836, -30076, 2236, 32124, 16764, -21884, -29052, 5116, 32124, + 13436, -24956, -28028, 8828, 32124, 9340, -27004, -24956, 13436, 32124, + 4348, -30076, -20860, 18812, 31100, -1756, -32124, -15484, 23932, 28028, + -8828, -32124, -8316, 28028, 22908, -15996, -32124, -212, 32124, 16764, + -22908, -28028, 8828, 32124, 7420, -29052, -21884, 18812, 31100, -3388, + -32124, -12412, 25980, 24956, -14460, -32124, -588, 32124, 15484, -24956, + -27004, 11900, 32124, 2620, -31100, -16764, 23932, 27004, -11388, -32124, + -2748, 31100, 16764, -23932, -27004, 12924, 32124, 988, -32124, -14460, + 25980, 24956, -15484, -31100, 2748, 32124, 10364, -28028, -21884, 19836, + 29052, -8316, -32124, -4348, 31100, 15996, -24956, -25980, 15484, 31100, + -3900, -32124, -7932, 30076, 18812, -22908, -27004, 13948, 32124, -2748, + -32124, -8316, 30076, 18812, -23932, -25980, 14972, 31100, -4860, -32124, + -5628, 31100, 15484, -25980, -23932, 18812, 29052, -9852, -32124, 372, + 32124, 9340, -30076, -17788, 24956, 24956, -17788, -30076, 9852, 32124, + -988, -32124, -7676, 31100, 15484, -27004, -21884, 20860, 28028, -13948, + -31100, 6652, 32124, 1116, -32124, -8828, 30076, 15484, -27004, -21884, + 21884, 25980, -16764, -30076, 10364, 32124, -3900, -32124, -2620, 32124, + 8828, -31100, -14460, 28028, 19836, -23932, -23932, 19836, 27004, -15484, + -30076, 10876, 32124, -5628, -32124, 620, 32124, 4348, -32124, -8828, + 31100, 12924, -29052, -16764, 27004, 19836, -23932, -22908, 21884, 25980, + -18812, -28028, 15484, 29052, -12412, -31100, 9852, 32124, -6652, -32124, + 3900, 32124, -1308, -32124, -1180, 32124, 3516, -32124, -5628, 32124, + 7420, -32124, -9340, 31100, 10876, -31100, -11900, 30076, 12924, -30076, + -13948, 29052, 14972, -29052, -15484, 29052, 15996, -29052, -15996, 28028, + 15996, -28028, -15996, 29052, 15996, -29052, -15484, 29052, 14972, -29052, + -14460, 30076, 13436, -30076, -12412, 30076, 11388, -31100, -9852, 31100, + 7932, -32124, -6140, 32124, 4092, -32124, -1884, 32124, -588, -32124, + 3260, 32124, -6140, -32124, 8828, 31100, -11900, -30076, 14972, 28028, + -17788, -25980, 20860, 23932, -23932, -20860, 27004, 16764, -29052, -13436, + 31100, 8828, -32124, -4092, 32124, -876, -32124, 6140, 31100, -11388, + -30076, 16764, 27004, -20860, -22908, 24956, 18812, -29052, -12924, 31100, + 6652, -32124, -104, 32124, -6652, -31100, 13436, 28028, -19836, -23932, + 24956, 17788, -29052, -11388, 32124, 3516, -32124, 4604, 31100, -12412, + -28028, 19836, 22908, -25980, -15996, 30076, 7676, -32124, 1500, 32124, + -10876, -29052, 18812, 22908, -25980, -15484, 31100, 5884, -32124, 4348, + 31100, -14460, -27004, 22908, 18812, -29052, -9340, 32124, -1884, -32124, + 12924, 27004, -22908, -18812, 29052, 8316, -32124, 3516, 31100, -15484, + -25980, 24956, 15996, -31100, -3772, 32124, -9340, -29052, 20860, 20860, + -29052, -8316, 32124, -5116, -30076, 17788, 22908, -28028, -10364, 32124, + -3772, -31100, 17788, 22908, -28028, -10364, 32124, -4860, -30076, 18812, + 21884, -29052, -7420, 32124, -8316, -29052, 21884, 17788, -31100, -2108, + 32124, -13948, -24956, 27004, 10876, -32124, 5884, 29052, -21884, -17788, + 31100, 1308, -32124, 15996, 22908, -29052, -7164, 32124, -10876, -27004, + 25980, 11900, -32124, 7164, 29052, -23932, -14460, 32124, -4348, -30076, + 21884, 16764, -32124, 3004, 30076, -21884, -16764, 32124, -3004, -30076, + 21884, 15996, -32124, 4348, 29052, -22908, -14460, 32124, -7164, -28028, + 25980, 10876, -32124, 10876, 24956, -28028, -6140, 32124, -15996, -20860, + 31100, -244, -31100, 21884, 15484, -32124, 7932, 27004, -27004, -7164, + 32124, -16764, -20860, 31100, -2748, -29052, 24956, 10876, -32124, 13948, + 21884, -31100, 1244, 30076, -23932, -10876, 32124, -14460, -20860, 31100, + -3260, -29052, 25980, 7676, -32124, 17788, 17788, -32124, 8828, 24956, + -29052, -652, 30076, -23932, -9852, 32124, -17788, -17788, 32124, -9852, + -23932, 30076, -2364, -28028, 27004, 4860, -31100, 22908, 11388, -32124, + 17788, 16764, -32124, 12412, 21884, -32124, 7164, 24956, -30076, 2492, + 28028, -28028, -1820, 30076, -25980, -5628, 31100, -23932, -8828, 32124, + -21884, -11388, 32124, -19836, -12924, 32124, -18812, -14460, 32124, -17788, + -15484, 32124, -16764, -15996, 32124, -16764, -15996, 32124, -17788, -14972, + 32124, -17788, -13948, 32124, -19836, -12412, 32124, -20860, -10364, 32124, + -22908, -7676, 31100, -24956, -4348, 30076, -27004, -372, 28028, -30076, + 4092, 24956, -31100, 9340, 20860, -32124, 14460, 16764, -32124, 19836, + 10876, -32124, 24956, 4092, -29052, 29052, -3516, -24956, 32124, -11388, + -18812, 32124, -18812, -10876, 31100, -25980, -1628, 27004, -30076, 8316, + 20860, -32124, 17788, 11388, -31100, 25980, 276, -25980, 31100, -11388, + -17788, 32124, -21884, -5884, 29052, -30076, 7420, 20860, -32124, 19836, + 8316, -30076, 29052, -6396, -20860, 32124, -19836, -7164, 29052, -30076, + 8828, 18812, -32124, 22908, 3260, -27004, 31100, -13948, -13948, 31100, + -27004, 4092, 21884, -32124, 20860, 5116, -28028, 31100, -13948, -12924, + 31100, -29052, 7164, 18812, -32124, 24956, -1180, -22908, 32124, -20860, + -3900, 25980, -32124, 17788, 7676, -28028, 31100, -14972, -10364, 30076, + -31100, 13436, 12412, -30076, 30076, -12412, -12924, 30076, -30076, 12412, + 12412, -30076, 30076, -13436, -10876, 29052, -31100, 15484, 8828, -28028, + 32124, -18812, -5116, 25980, -32124, 21884, 196, -21884, 32124, -25980, + 5628, 17788, -31100, 29052, -12412, -10876, 29052, -32124, 19836, 2492, + -22908, 32124, -25980, 6908, 15484, -30076, 31100, -16764, -5116, 24956, + -32124, 25980, -6908, -14972, 30076, -31100, 18812, 1884, -21884, 32124, + -29052, 12412, 8828, -25980, 32124, -24956, 7164, 13948, -29052, 32124, + -21884, 3260, 16764, -30076, 32124, -20860, 1180, 18812, -31100, 31100, + -19836, 988, 18812, -31100, 32124, -20860, 2492, 16764, -30076, 32124, + -22908, 5884, 13436, -28028, 32124, -25980, 10876, 7932, -23932, 32124, + -30076, 17788, 556, -18812, 30076, -32124, 23932, -8828, -9340, 24956, + -32124, 30076, -18812, 1980, 15484, -28028, 32124, -28028, 14972, 2236, + -18812, 30076, -32124, 27004, -13436, -3644, 19836, -30076, 32124, -27004, + 13948, 2236, -17788, 29052, -32124, 28028, -16764, 1820, 13948, -25980, + 32124, -31100, 21884, -8316, -7164, 20860, -30076, 32124, -28028, 17788, + -3004, -11900, 23932, -31100, 32124, -25980, 15484, -1180, -12924, 24956, + -31100, 32124, -27004, 16764, -3260, -10876, 22908, -30076, 32124, -29052, + 20860, -8828, -4348, 16764, -27004, 32124, -32124, 27004, -17788, 5884, +}; diff --git a/test/cmocka/src/math/arithmetic/ref_chirp_mono_8k_s16.h b/test/cmocka/src/math/arithmetic/ref_chirp_mono_8k_s16.h new file mode 100644 index 000000000000..29c4493969a5 --- /dev/null +++ b/test/cmocka/src/math/arithmetic/ref_chirp_mono_8k_s16.h @@ -0,0 +1,412 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 13-May-2025 18:29:28 with script a_law_mu_law_test_vectors.m */ + +#include <stdint.h> +#define REF_DATA_SAMPLE_COUNT 4000 + +static const int16_t chirp_mono_8k_s16[4000] = { + 30209, 29119, 27848, 26404, 24795, 23030, 21121, 19078, 16914, 14643, + 12277, 9833, 7324, 4767, 2178, -427, -3032, -5620, -8175, -10680, + -13119, -15476, -17736, -19885, -21907, -23791, -25522, -27091, -28485, -29696, + -30715, -31535, -32151, -32557, -32751, -32730, -32494, -32044, -31383, -30515, + -29443, -28176, -26721, -25087, -23284, -21325, -19221, -16987, -14637, -12186, + -9651, -7049, -4398, -1714, 984, 3678, 6349, 8979, 11551, 14045, + 16446, 18736, 20899, 22920, 24784, 26480, 27993, 29313, 30431, 31339, + 32028, 32495, 32734, 32744, 32524, 32076, 31400, 30503, 29389, 28066, + 26542, 24829, 22937, 20879, 18671, 16327, 13863, 11298, 8650, 5936, + 3178, 393, -2396, -5171, -7910, -10594, -13203, -15718, -18120, -20391, + -22515, -24474, -26254, -27842, -29225, -30392, -31334, -32044, -32516, -32745, + -32729, -32467, -31962, -31215, -30233, -29021, -27588, -25946, -24104, -22078, + -19882, -17532, -15046, -12442, -9740, -6962, -4127, -1258, 1624, 4495, + 7334, 10119, 12827, 15438, 17930, 20285, 22482, 24505, 26336, 27962, + 29369, 30544, 31478, 32164, 32594, 32765, 32674, 32323, 31712, 30846, + 29731, 28376, 26791, 24989, 22982, 20787, 18421, 15903, 13254, 10493, + 7645, 4731, 1776, -1196, -4161, -7095, -9972, -12769, -15463, -18031, + -20451, -22702, -24766, -26624, -28260, -29660, -30812, -31705, -32332, -32685, + -32761, -32559, -32080, -31327, -30306, -29025, -27494, -25726, -23735, -21538, + -19153, -16600, -13901, -11079, -8159, -5165, -2123, 940, 3998, 7023, + 9989, 12870, 15640, 18275, 20750, 23043, 25134, 27003, 28634, 30010, + 31119, 31950, 32495, 32749, 32708, 32372, 31743, 30826, 29628, 28161, + 26436, 24468, 22275, 19876, 17293, 14549, 11669, 8678, 5605, 2477, + -676, -3826, -6944, -9999, -12964, -15810, -18511, -21040, -23374, -25490, + -27368, -28988, -30336, -31397, -32161, -32620, -32768, -32603, -32127, -31342, + -30255, -28877, -27219, -25297, -23129, -20734, -18137, -15361, -12433, -9381, + -6234, -3024, 219, 3462, 6674, 9824, 12879, 15809, 18585, 21179, + 23565, 25718, 27616, 29240, 30572, 31599, 32309, 32694, 32750, 32474, + 31870, 30942, 29698, 28151, 26316, 24210, 21855, 19274, 16492, 13538, + 10442, 7235, 3951, 623, -2715, -6027, -9279, -12438, -15469, -18341, + -21023, -23486, -25705, -27654, -29313, -30663, -31689, -32379, -32725, -32723, + -32371, -31673, -30635, -29267, -27582, -25600, -23339, -20823, -18080, -15138, + -12030, -8787, -5446, -2042, 1388, 4805, 8172, 11452, 14609, 17608, + 20414, 22996, 25325, 27375, 29121, 30544, 31627, 32356, 32722, 32721, + 32352, 31617, 30524, 29084, 27313, 25230, 22859, 20224, 17356, 14287, + 11051, 7685, 4228, 719, -2801, -6292, -9713, -13024, -16187, -19164, + -21920, -24422, -26641, -28548, -30122, -31343, -32195, -32667, -32753, -32451, + -31762, -30696, -29262, -27477, -25362, -22942, -20243, -17299, -14144, -10815, + -7353, -3798, -194, 3415, 6987, 10476, 13840, 17037, 20029, 22777, + 25247, 27407, 29232, 30696, 31781, 32472, 32759, 32639, 32111, 31181, + 29859, 28162, 26108, 23725, 21039, 18085, 14900, 11523, 7996, 4364, + 674, -3029, -6696, -10280, -13736, -17017, -20083, -22891, -25406, -27594, + -29426, -30876, -31926, -32559, -32768, -32547, -31900, -30832, -29357, -27494, + -25266, -22701, -19833, -16699, -13339, -9799, -6125, -2366, 1428, 5207, + 8919, 12514, 15943, 19159, 22119, 24781, 27109, 29069, 30635, 31783, + 32497, 32766, 32585, 31955, 30883, 29384, 27478, 25188, 22547, 19589, + 16356, 12891, 9244, 5463, 1602, -2284, -6142, -9916, -13554, -17003, + -20214, -23140, -25740, -27974, -29811, -31222, -32187, -32691, -32725, -32286, + -31381, -30022, -28225, -26018, -23430, -20498, -17265, -13776, -10082, -6237, + -2297, 1680, 5636, 9512, 13251, 16797, 20096, 23099, 25760, 28039, + 29900, 31315, 32260, 32721, 32689, 32164, 31152, 29666, 27730, 25369, + 22621, 19524, 16127, 12479, 8637, 4659, 605, -3462, -7478, -11383, + -15114, -18614, -21827, -24703, -27196, -29265, -30878, -32007, -32634, -32748, + -32344, -31429, -30015, -28124, -25783, -23031, -19908, -16464, -12754, -8836, + -4773, -629, 3529, 7633, 11618, 15417, 18970, 22217, 25105, 27586, + 29618, 31166, 32204, 32714, 32685, 32117, 31018, 29404, 27301, 24742, + 21769, 18431, 14781, 10881, 6796, 2592, -1659, -5886, -10017, -13982, + -17714, -21148, -24226, -26894, -29105, -30821, -32010, -32651, -32732, -32249, + -31209, -29629, -27535, -24962, -21952, -18558, -14838, -10855, -6678, -2381, + 1962, 6274, 10479, 14503, 18275, 21726, 24794, 27424, 29568, 31187, + 32250, 32736, 32636, 31949, 30686, 28869, 26529, 23707, 20452, 16824, + 12886, 8709, 4370, -52, -4478, -8826, -13015, -16968, -20611, -23877, + -26703, -29036, -30832, -32056, -32683, -32699, -32104, -30907, -29127, -26798, + -23962, -20671, -16986, -12976, -8716, -4286, 229, 4744, 9172, 13428, + 17430, 21101, 24369, 27170, 29448, 31158, 32265, 32747, 32592, 31801, + 30388, 28380, 25813, 22738, 19212, 15305, 11092, 6656, 2085, -2532, + -7103, -11536, -15743, -19640, -23146, -26191, -28713, -30659, -31988, -32673, + -32696, -32058, -30767, -28849, -26342, -23295, -19768, -15834, -11571, -7066, + -2412, 2296, 6961, 11486, 15777, 19743, 23302, 26378, 28906, 30830, + 32111, 32717, 32636, 31867, 30425, 28337, 25647, 22410, 18694, 14576, + 10144, 5490, 715, -4079, -8790, -13316, -17559, -21426, -24833, -27704, + -29976, -31597, -32531, -32755, -32263, -31063, -29181, -26654, -23538, -19900, + -15818, -11382, -6690, -1845, 3045, 7872, 12527, 16906, 20909, 24446, + 27436, 29810, 31513, 32504, 32759, 32270, 31047, 29115, 26516, 23309, + 19565, 15369, 10815, 6008, 1059, -3920, -8812, -13504, -17886, -21856, + -25319, -28194, -30412, -31918, -32676, -32666, -31886, -30352, -28099, -25178, + -21657, -17617, -13154, -8374, -3389, 1682, 6717, 11595, 16198, 20414, + 24141, 27286, 29773, 31538, 32538, 32745, 32152, 30773, 28637, 25797, + 22320, 18290, 13804, 8974, 3916, -1242, -6375, -11353, -16053, -20355, + -24152, -27346, -29855, -31616, -32581, -32723, -32038, -30540, -28265, -25269, + -21626, -17428, -12780, -7801, -2617, 2638, 7830, 12825, 17493, 21712, + 25371, 28374, 30641, 32111, 32743, 32519, 31442, 29538, 26856, 23463, + 19447, 14914, 9981, 4779, -555, -5879, -11050, -15931, -20389, -24304, + -27569, -30095, -31811, -32669, -32644, -31733, -29959, -27369, -24030, -20032, + -15482, -10504, -5233, 187, 5606, 10875, 15848, 20387, 24363, 27666, + 30202, 31896, 32701, 32592, 31567, 29655, 26907, 23398, 19224, 14503, + 9366, 3959, -1565, -7050, -12338, -17278, -21727, -25557, -28655, -30931, + -32316, -32768, -32271, -30838, -28508, -25346, -21441, -16907, -11874, -6488, + -908, 4705, 10184, 15367, 20100, 24241, 27667, 30272, 31979, 32732, + 32507, 31309, 29170, 26153, 22345, 17861, 12832, 7411, 1760, -3949, + -9543, -14852, -19711, -23971, -27501, -30189, -31951, -32730, -32500, -31264, + -29059, -25951, -22032, -17425, -12269, -6726, -967, 4827, 10475, 15798, + 20627, 24809, 28210, 30720, 32256, 32767, 32236, 30674, 28130, 24682, + 20440, 15536, 10128, 4388, -1499, -7342, -12952, -18147, -22755, -26625, + -29629, -31666, -32667, -32595, -31451, -29270, -26120, -22103, -17351, -12018, + -6281, -330, 5638, 11422, 16829, 21676, 25798, 29056, 31337, 32561, + 32684, 31698, 29636, 26563, 22581, 17826, 12456, 6654, 619, -5442, + -11321, -16815, -21733, -25901, -29175, -31438, -32608, -32641, -31534, -29322, + -26080, -21918, -16982, -11443, -5494, 654, 6784, 12679, 18128, 22935, + 26929, 29963, 31926, 32745, 32388, 30864, 28225, 24564, 20010, 14727, + 8904, 2751, -3507, -9643, -15431, -20658, -25132, -28684, -31183, -32533, + -32681, -31618, -29381, -26049, -21744, -16624, -10879, -4720, 1620, 7906, + 13899, 19374, 24121, 27959, 30741, 32358, 32745, 31885, 29806, 26585, + 22343, 17239, 11468, 5251, -1175, -7562, -13661, -19235, -24066, -27965, + -30777, -32388, -32734, -31796, -29608, -26253, -21860, -16601, -10680, -4330, + 2197, 8642, 14749, 20272, 24990, 28711, 31283, 32600, 32605, 31295, + 28720, 24979, 20223, 14640, 8457, 1924, -4694, -11126, -17107, -22391, + -26758, -30027, -32059, -32768, -32119, -30137, -26901, -22541, -17238, -11209, + -4705, 2001, 8630, 14900, 20549, 25334, 29051, 31540, 32692, 32454, + 30833, 27894, 23760, 18604, 12645, 6138, -640, -7396, -13839, -19687, + -24687, -28619, -31308, -32634, -32536, -31014, -28131, -24010, -18828, -12813, + -6227, 641, 7486, 14005, 19907, 24927, 28840, 31466, 32686, 32440, + 30737, 27648, 23309, 17914, 11703, 4956, -2023, -8915, -15407, -21201, + -26030, -29671, -31952, -32767, -32072, -29897, -26338, -21556, -15769, -9244, + -2284, 4790, 11645, 17962, 23442, 27825, 30903, 32527, 32616, 31162, + 28230, 23955, 18537, 12231, 5336, -1820, -8896, -15551, -21464, -26348, + -29966, -32139, -32758, -31789, -29275, -25333, -20154, -13985, -7126, 87, + 7303, 14166, 20337, 25509, 29424, 31886, 32767, 32019, 29677, 25852, + 20732, 14569, 7670, 379, -6936, -13909, -20185, -25445, -29420, -31904, + -32768, -31962, -29524, -25574, -20310, -14000, -6964, 437, 7822, 14809, + 21035, 26176, 29960, 32189, 32741, 31583, 28771, 24449, 18838, 12232, + 4975, -2550, -9948, -16825, -22814, -27596, -30913, -32582, -32511, -30700, + -27239, -22312, -16180, -9169, -1657, 5951, 13243, 19823, 25329, 29460, + 31986, 32764, 31748, 28988, 24631, 18914, 12149, 4705, -3005, -10556, + -17526, -23527, -28221, -31342, -32711, -32248, -29972, -26009, -20575, -13975, + -6579, 1196, 8911, 16125, 22427, 27455, 30917, 32612, 32436, 30397, + 26605, 21276, 14712, 7291, -559, -8384, -15727, -22160, -27305, -30856, + -32603, -32436, -30362, -26497, -21065, -14382, -6842, 1110, 9004, 16369, + 22763, 27803, 31182, 32695, 32245, 29853, 25660, 19914, 12957, 5210, + -2861, -10765, -18020, -24181, -28869, -31793, -32768, -31729, -28736, -23968, + -17714, -10358, -2353, 5805, 13609, 20571, 26254, 30300, 32450, 32564, + 30629, 26763, 21205, 14300, 6484, -1751, -9882, -17390, -23795, -28686, + -31743, -32768, -31688, -28567, -23602, -17108, -9501, -1272, 7048, 14915, + 21818, 27302, 31006, 32681, 32213, 29627, 25087, 18888, 11436, 3219, + -5218, -13316, -20534, -26390, -30487, -32548, -32429, -30132, -25806, -19737, + -12330, -4083, 4448, 12684, 20066, 26087, 30333, 32509, 32462, 30188, + 25837, 19704, 12207, 3860, -4762, -13060, -20459, -26441, -30585, -32598, + -32332, -29801, -25176, -18776, -11049, -2535, 6166, 14437, 21691, 27411, + 31183, 32736, 31951, 28879, 23733, 16879, 8804, 88, -8642, -16755, + -23661, -28855, -31955, -32731, -31119, -27230, -21344, -13888, -5404, 3485, + 12125, 19876, 26163, 30516, 32606, 32272, 29532, 24585, 17794, 9665, + 802, -8128, -16454, -23545, -28862, -31999, -32710, -30937, -26806, -20628, + -12868, -4116, 4958, 13660, 21318, 27340, 31255, 32757, 31722, 28223, + 22526, 15070, 6431, -2718, -11662, -19698, -26194, -30633, -32660, -32109, + -29015, -23618, -16341, -7757, 1453, 10554, 18820, 25584, 30300, 32584, + 32245, 29304, 23991, 16730, 8106, -1185, -10387, -18749, -25587, -30337, + -32604, -32194, -29135, -23672, -16249, -7476, 1924, 11173, 19500, 26210, + 30739, 32702, 31928, 28474, 22625, 14865, 5845, -3676, -12895, -21028, + -27382, -31412, -32768, -31326, -27204, -20747, -12504, -3178, 6430, 15491, + 23221, 28946, 32165, 32591, 30181, 25135, 17890, 9072, -549, -10130, + -18828, -25874, -30641, -32701, -31866, -28202, -22026, -13883, -4493, 5306, + 14638, 22665, 28662, 32084, 32615, 30199, 25049, 17622, 8589, -1234, + -10952, -19679, -26614, -31115, -32764, -31402, -27146, -20381, -11726, -1977, + 7963, 17172, 24790, 30102, 32607, 32062, 28510, 22278, 13944, 4288, + -5780, -15311, -23399, -29273, -32368, -32383, -29307, -23427, -15298, -5695, + 4463, 14201, 22578, 28780, 32202, 32506, 29652, 23910, 15834, 6204, + -4041, -13898, -22400, -28707, -32191, -32502, -29600, -23764, -15566, -5814, + 4526, 14422, 22887, 29068, 32340, 32367, 29138, 22969, 14475, 4510, + -5920, -15758, -24003, -29810, -32580, -32022, -28184, -21452, -12510, -2272, + 8208, 17850, 25653, 30803, 32758, 31307, 26592, 19097, 9598, -915, + -11341, -20584, -27666, -31835, -32643, -29995, -24163, -15759, -5669, 5033, + 15207, 23762, 29777, 32600, 31918, 27796, 20669, 11301, 701, -9985, + -19594, -27077, -31613, -32697, -30202, -24392, -15897, -5646, 5238, 15552, + 24154, 30086, 32682, 31645, 27080, 19489, 9712, -1162, -11914, -21336, + -28364, -32197, -32395, -28926, -22173, -12895, -2141, 8866, 18870, 26723, + 31520, 32702, 30123, 24071, 15236, 4631, -6519, -16922, -25367, -30866, + -32768, -30843, -25305, -16795, -6305, 4936, 15605, 24440, 30391, 32745, + 31214, 25968, 17625, 7170, -4151, -14984, -24028, -30193, -32727, -31315, + -26119, -17756, -7233, 4177, 15089, 24171, 30309, 32744, 31169, 25766, + 17190, 6488, -5023, -15923, -24860, -30720, -32768, -30738, -24872, -15894, + -4918, 6683, 17454, 26039, 31349, 32705, 29926, 23352, 13808, 2500, + -9135, -19615, -27596, -32051, -32397, -28581, -21082, -10858, 778, 12322, + 22279, 29351, 32611, 31623, 26506, 17918, 6975, -4893, -16127, -25247, + -31044, -32742, -30106, -23475, -13720, -2129, 9755, 20346, 28224, 32325, + 32089, 27536, 19269, 8394, -3626, -15164, -24655, -30802, -32759, -30249, + -23603, -13721, -1948, 10103, 20773, 28589, 32462, 31848, 26819, 18063, + 6786, -5445, -16927, -26051, -31535, -32599, -29081, -21466, -10817, 1370, + 13373, 23491, 30279, 32765, 30583, 24031, 14037, 2022, -10293, -21138, + -28947, -32586, -31517, -25883, -16489, -4691, 7800, 19164, 27738, 32259, + 32055, 27144, 18234, 6630, -5963, -17685, -26796, -31938, -32336, -27918, + -19330, -7847, 4822, 16777, 26222, 31728, 32455, 28280, 19822, 8353, + -4395, -16485, -26073, -31689, -32464, -28267, -19729, -8151, 4692, 16822, + 26363, 31831, 32367, 27875, 19041, 7232, -5716, -17782, -27070, -32117, + -32117, -27057, -17723, -5579, 7459, 19325, 28129, 32462, 31621, 25728, + 15712, 3168, -9895, -21377, -29423, -32725, -30737, -23767, -12934, 12, + 12966, 23816, 30782, 32714, 29281, 21034, 9318, -3944, -16566, -26457, + -31972, -32181, -27038, -17385, -4822, 8558, 20516, 29041, 32691, 30839, + 23784, 12703, -537, -13698, -24542, -31219, -32580, -28378, -19317, -6939, + 6641, 19090, 28261, 32562, 31238, 24502, 13510, 161, -13227, -24320, + -31173, -32576, -28269, -18994, -6369, 7389, 19853, 28817, 32683, 30752, + 23351, 11785, -1893, -15244, -25877, -31878, -32156, -26647, -16329, -3053, + 10787, 22683, 30470, 32722, 29013, 20006, 7334, -6693, -19503, -28739, + -32691, -30617, -22883, -10908, 3100, 16543, 26920, 32288, 31631, 25057, + 13782, -88, -13954, -25203, -31706, -32221, -26635, -15992, -2302, 11838, + 23732, 31103, 32529, 27720, 17584, 4058, -10262, -22612, -30601, -32668, + -28398, -18604, -5180, 9266, 21914, 30282, 32719, 28731, 19086, 5671, + -8876, -21678, -30196, -32726, -28751, -19045, -5531, 9100, 21921, 30355, + 32697, 28458, 18477, 4756, -9939, -22632, -30739, -32600, -27819, -17356, + -3335, 11381, 23774, 31290, 32368, 26771, 15636, 1256, -13396, -25278, + -31910, -31895, -25220, -13263, 1482, 15929, 27038, 32460, 31037, 23052, + 10179, -4864, -18886, -28899, -32758, -29623, -20146, -6343, 8834, 22123, + 30655, 32577, 27457, 16384, 1747, -13282, -25431, -32042, -31658, -24343, + -11684, 3551, 18018, 28525, 32742, 29719, 20109, 6028, -9406, -22757, + -31041, -32394, -26494, -14646, 502, 15550, 27103, 32545, 30626, 21764, + 7953, -7678, -21573, -30555, -32558, -27105, -15429, -197, 15093, 26915, + 32527, 30615, 21603, 7566, -8242, -22143, -30885, -32410, -26343, -14088, + 1489, 16728, 28033, 32722, 29667, 19574, 4822, -11090, -24371, -31842, + -31701, -23962, -10465, 5561, 20259, 30081, 32638, 27293, 15322, -382, + -16006, -27739, -32705, -29672, -19362, -4289, 11851, 25084, 32136, 31246, + 22615, 8366, -7975, -22344, -31150, -32180, -25155, -11816, 4501, 19699, + 29944, 32636, 27075, 14649, -1505, -17290, -28683, -32767, -28480, -16896, + -970, 15219, 27503, 32707, 29467, 18600, 2904, -13559, -26508, -32562, + -30123, -19806, -4294, 12358, 25775, 32417, 30515, 20551, 5140, -11647, + -25353, -32327, -30691, -20861, -5445, 11443, 25273, 32321, 30671, 20747, + 5208, -11753, -25540, -32402, -30452, -20201, -4425, 12573, 26140, 32544, + 30005, 19199, 3088, -13889, -27035, -32693, -29273, -17703, -1189, 15671, + 28161, 32767, 28180, 15664, -1275, -17868, -29423, -32655, -26627, -13027, + 4291, 20400, 30695, 32215, 24502, 9748, -7822, -23152, -31812, -31281, + -21690, -5797, 11792, 25963, 32573, 29672, 18084, 1186, -16074, -28619, + -32740, -27200, -13611, 4020, 20473, 30852, 32054, 23694, 8248, -9679, + -24718, -32345, -30246, -19028, -2057, 15550, 28460, 32742, 27074, 13155, + -4788, -21282, -31274, -31683, -22359, -6147, 11972, 26409, 32688, 28843, + 16042, -1757, -19024, -30368, -32229, -24001, -8238, 10125, 25316, 32538, + 29489, 17108, -704, -18307, -30102, -32317, -24220, -8375, 10165, 25458, + 32584, 29226, 16442, -1662, -19244, -30601, -32033, -23046, -6545, 12106, + 26814, 32751, 27949, 13958, -4638, -21720, -31641, -31099, -20248, -2665, + 15818, 29045, 32588, 25237, 9428, -9556, -25344, -32612, -28887, -15400, + 3309, 20911, 31426, 31258, 20439, 2634, -16085, -29309, -32487, -24501, + -8073, 11152, 26539, 32754, 27617, 12886, -6340, -23371, -32257, -29870, + -17018, 1816, 20027, 31199, 31376, 20467, 2306, -16688, -29769, -32269, + -23272, -5959, 13498, 28135, 32687, 25493, 9113, -10567, -26443, -32761, + -27205, -11764, 7969, 24813, 32612, 28490, 13928, -5756, -23340, -32342, + -29422, -15627, 3962, 22098, 32040, 30069, 16890, -2605, -21141, -31771, + -30486, -17740, 1696, 20507, 31584, 30715, 18199, -1239, -20220, -31510, + -30778, -18275, 1238, 20292, 31559, 30683, 17970, -1696, -20720, -31726, + -30418, -17274, 2612, 21493, 31984, 29953, 16166, -3986, -22584, -32288, + -29242, -14619, 5811, 23948, 32572, 28222, 12601, -8070, -25525, -32750, + -26817, -10081, 10733, 27227, 32714, 24942, 7034, -13748, -28944, -32336, + -22508, -3453, 17034, 30534, 31474, 19433, -646, -20472, -31827, -29973, + -15650, 5206, 23904, 32621, 27682, 11125, -10120, -27121, -32697, -24465, + -5873, 15222, 29869, 31823, 20219, -23, -20271, -31852, -29778, -14905, + 6395, 24954, 32748, 26378, 8571, -12971, -28888, -32231, -21511, -1380, + 19371, 31641, 30016, 15179, -6362, -25109, -32762, -25901, -7537, 14192, + 29616, 31836, 19828, -1066, -21498, -32287, -28554, -11945, 10070, 27546, + 32554, 22789, 2656, -18702, -31544, -29979, -14690, 7348, 26026, 32743, + 24373, 4744, -17094, -31029, -30574, -15906, 6180, 25399, 32765, 24801, + 5203, -16853, -30997, -30544, -15672, 6621, 25794, 32743, 24135, 4030, + -18012, -31465, -29872, -13958, 8670, 27144, 32554, 22256, 1192, -20466, + -32211, -28313, -10631, 12248, 29161, 31820, 18887, -3327, -23922, -32748, + -25422, -5526, 17120, 31293, 29930, 13672, -9413, -27815, -32317, -20632, + 1417, 22769, 32671, 26099, 6335, -16650, -31210, -29930, -13422, 9938, + 28242, 32117, 19545, -3064, -24115, -32766, -24526, -3610, 19189, 32058, + 28292, 9809, -13798, -30221, -30858, -15338, 8239, 27504, 32307, 20082, + -2757, -24154, -32768, -23995, -2458, 20403, 32396, 27086, 7272, -16455, + -31360, -29404, -11600, 12479, 29828, 31031, 15399, -8615, -27955, -32064, + -18659, 4965, 25884, 32607, 21401, -1603, -23739, -32768, -23659, -1421, + 21622, 32648, 25481, 4080, -19619, -32342, -26922, -6362, 17795, 31930, + 28034, 8266, -16201, -31485, -28868, -9799, 14877, 31064, 29471, 10968, + -13850, -30714, -29878, -11785, 13140, 30467, 30119, 12257, -12757, -30345, + -30210, -12389, 12710, 30361, 30159, 12182, -13000, -30511, -29960, -11631, + 13624, 30786, 29599, 10729, -14574, -31159, -29047, -9464, 15834, 31594, + 28268, 7823, -17381, -32042, -27215, -5795, 19179, 32439, 25835, 3371, + -21180, -32706, -24068, -554, 23319, 32753, 21855, -2643, -25512, -32475, + -19141, 6187, 27652, 31758, 15881, -10019, -29610, -30485, -12047, 14050, + 31232, 28539, 7640, -18154, -32347, -25814, -2700, 22166, 32767, 22230, + -2686, -25879, -32303, -17743, 8373, 29049, 30770, 12367, -14151, -31400, + -28020, -6187, 19741, 32644, 23953, -622, -24801, -32500, -18553, 7784, + 28936, 30727, 11911, -14919, -31728, -27162, -4254, 21547, 32767, 21761, + -4044, -27113, -31707, -14644, 12450, 31029, 28317, 6131, -20294, -32733, + -22558, 3241, 26809, 31771, 14632, -12717, -31205, -27886, -5033, 21366, + 32767, 21111, -5439, -28165, -30980, -11844, 15711, 32114, 25657, 893, + -24525, -32407, -17060, 10547, 30586, 28600, 5972, -20988, -32768, -20789, + 6302, 28823, 30349, 9717, -18036, -32593, -23244, 3196, 27300, 31287, + 12165, -15970, -32287, -24646, 1327, 26328, 31703, 13389, -14958, -32108, + -25155, 726, 26077, 31762, 13438, -15074, -32169, -24834, 1406, 26591, + 31488, 12305, -16317, -32435, -23633, 3370, 27791, 30761, 9931, -18608, + -32720, -21398, 6597, 29463, 29320, 6227, -21763, -32679, -17896, 10997, + 31228, 26786, 1130, -25437, -31813, -12877, 16334, 32523, 22713, -5297, + -29074, -29500, -6179, 22139, 32593, 16687, -12751, -31857, -25076, 2130, + 27615, 30554, 8491, -20545, -32731, -18006, 11561, 31606, 25543, -1670, + -27514, -30522, -8140, 21038, 32675, 17001, -12918, -32021, -24232, 3953, + 28823, 29373, 5083, -23528, -32193, -13504, 16691, 32673, 20760, -8919, + -30973, -26458, 805, 27391, 30369, 7113, -22311, -32415, -14384, 16166, + 32653, 20664, -9390, -31242, -25718, 2394, 28416, 29419, 4461, -24454, + -31737, -10880, 19653, 32719, 16635, -14306, -32475, -21572, 8686, 31158, + 25604, -3032, -28947, -28700, -2456, 26031, 30879, 7623, -22596, -32198, + -12355, 18819, 32741, 16577, -14858, -32610, -20252, 10850, 31915, 23369, + -6907, -30768, -25946, 3119, 29281, 28015, 448, -27556, -29622, -3745, + 25685, 30823, 6744, -23751, -31675, -9431, 21824, 32240, 11800, -19965, + -32574, -13858, 18220, 32733, 15616, -16629, -32767, -17088, 15224, 32719, + 18290, -14026, -32626, -19238, 13055, 32521, 19948, -12322, -32427, -20431, + 11837, 32363, 20696, -11605, -32338, -20747, 11629, 32356, 20585, -11909, + -32416, -20206, 12444, 32507, 19602, -13229, -32612, -18761, 14254, 32709, + 17668, -15508, -32765, -16306, 16972, 32742, 14656, -18622, -32595, -12701, + 20425, 32272, 10425, -22338, -31716, -7819, 24308, 30863, 4880, -26269, + -29649, -1619, 28143, 28009, -1942, -29838, -25882, 5761, 31248, 23216, + -9772, -32257, -19973, 13888, 32743, 16133, -17992, -32579, -11707, 21940, + 31643, 6739, -25561, -29828, -1314, 28661, 27049, -4435, -31029, -23260, + 10322, 32449, 18466, -16113, -32715, -12734, 21522, 31646, 6210, -26228, + -29112, 876, 29888, 25057, -8206, -32159, -19521, 15377, 32734, 12664, + -21921, -31374, -4780, 27328, 27950, -3697, -31083, -22482, 12203, 32726, + 15176, -20071, -31903, -6439, 26578, 28436, -3111, -31012, -22378, 12674, + 32759, 14064, -21319, -31394, -4125, 28072, 26781, -6523, -32033, -19143, + 16743, 32505, 9113, -25286, -29141, 2277, 30948, 22052, -13667, -32754, + -11889, 23513, 30154, -164, -30294, -23187, 12479, 32767, 12584, -23179, + -30232, 237, 30425, 22743, -13305, -32750, -11234, 24366, 29404, -2513, + -31280, -20622, 16081, 32461, 7729, -26819, -27304, 6960, 32366, 16464, + -20496, -31224, -1908, 29871, 23231, -13347, -32714, -9802, 25810, 27969, + -6193, -32314, -16350, 20953, 30890, 403, -30625, -21459, 15927, 32352, + 6112, -28213, -25224, 11191, 32767, 10797, -25556, -27848, 7048, 32531, + 14447, -23026, -29573, 3676, 31983, 17126, -20891, -30634, 1165, 31394, + 18926, -19333, -31224, -446, 30954, 19931, -18462, -31481, -1148, 30780, + 20198, -18334, -31473, -937, 30913, 19739, -18961, -31197, 193, 31324, + 18523, -20307, -30575, 2243, 31907, 16476, -22287, -29461, 5201, 32478, + 13500, -24744, -27646, 9013, 32767, 9495, -27435, -24876, 13554, 32423, + 4402, -30005, -20892, 18580, 31027, -1742, -31979, -15476, 23690, 28132, + -8738, -32768, -8538, 28296, 23334, -16157, -31716, -205, 31620, 16382, + -23286, -28194, 9061, 32756, 7323, -29119, -21760, 18391, 30799, -3339, + -32433, -12368, 26481, 25075, -14517, -31980, -600, 31707, 15446, -24519, + -26818, 12155, 32404, 2639, -31214, -16749, 23691, 27352, -11525, -32462, + -2766, 31259, 16385, -24167, -26805, 12684, 32219, 970, -31818, -14308, + 25863, 25031, -15555, -31410, 2765, 32537, 10333, -28410, -21637, 19861, + 29448, -8363, -32702, -4252, 31080, 16095, -24993, -25501, 15468, 31251, + -3941, -32703, -7965, 29830, 18682, -23170, -26897, 13709, 31695, -2713, + -32636, -8453, 29772, 18495, -23586, -26337, 14904, 31222, -4762, -32764, + -5721, 30954, 15474, -26124, -23577, 18877, 29341, -10003, -32348, 378, + 32466, 9122, -29826, -17701, 24785, 24707, -17871, -29671, 9714, 32323, + -991, -32594, -7643, 30594, 15593, -26588, -22368, 20951, 27601, -14135, + -31062, 6621, 32652, 1111, -32397, -8618, 30427, 15513, -26956, -21484, + 22259, 26301, -16642, -29817, 10428, 31968, -3931, -32761, -2559, 32265, + 8782, -30598, -14525, 27914, 19619, -24390, -23943, 20213, 27421, -15573, + -30019, 10651, 31742, -5614, -32621, 608, 32716, 4238, -32103, -8824, + 30869, 13070, -29109, -16919, 26920, 20335, -24398, -23300, 21632, 25814, + -18705, -27888, 15693, 29543, -12661, -30811, 9665, 31727, -6752, -32330, + 3958, 32663, -1312, -32768, -1164, 32685, 3455, -32454, -5553, 32111, + 7453, -31692, -9155, 31226, 10661, -30743, -11973, 30266, 13099, -29815, + -14043, 29410, 14812, -29065, -15410, 28791, 15843, -28597, -16114, 28489, + 16225, -28472, -16177, 28544, 15969, -28705, -15599, 28949, 15063, -29270, + -14357, 29656, 13474, -30094, -12409, 30567, 11154, -31056, -9703, 31535, + 8051, -31979, -6194, 32355, 4132, -32628, -1865, 32761, -597, -32713, + 3243, 32440, -6052, -31896, 8997, 31037, -12040, -29819, 15136, 28202, + -18226, -26149, 21242, 23634, -24103, -20642, 26722, 17170, -28999, -13234, + 30830, 8870, -32107, -4139, 32726, -873, -32586, 6054, 31602, -11262, + -29708, 16332, 26868, -21075, -23082, 25283, 18391, -28744, -12890, 31243, + 6727, -32585, -108, 32602, -6707, -31175, 13407, 28248, -19644, -23846, + 25050, 18085, -29256, -11184, 31921, 3466, -32763, 4650, 31591, -12664, + -28334, 20019, 23070, -26144, -16041, 30497, 7660, -32618, 1498, 32185, + -10726, -29070, 19235, 23374, -26215, -15455, 30921, 5931, -32758, 4355, + 31369, -14394, -26711, 23101, 19100, -29440, -9225, 32553, -1889, -31894, + 12970, 27339, -22632, -19260, 29553, 8533, -32667, 3519, 31348, -15274, + -25563, 25014, 15944, -31181, -3766, 32653, -9184, -28972, 20850, 20502, + -29226, -8454, 32725, -5235, -30509, 18180, 22726, -27960, -10592, 32577, + -3742, -30907, 17529, 23021, -27936, -10289, 32643, -4786, -30406, 19013, + 21438, -29171, -7506, 32766, -8341, -28693, 22392, 17643, -31135, -2092, + 32173, -14173, -24950, 26936, 11069, -32659, 5958, 29520, -21528, -18083, + 31171, 1337, -31878, 15983, 23130, -28688, -7261, 32711, -11030, -26493, + 26004, 11695, -32678, 7098, 28558, -23694, -14697, 32318, -4403, -29685, + 22127, 16387, -32005, 3038, 30135, -21510, -16864, 31944, -3033, -30028, + 21918, 16156, -32170, 4395, 29331, -23308, -14208, 32548, -7103, -27857, + 25510, 10900, -32768, 11077, 25285, -28186, -6100, 32337, -16103, -21210, + 30790, -237, -30604, 21738, 15243, -32530, 7935, 26832, -27212, -7173, + 32394, -16423, -20359, 31369, -2802, -29271, 24587, 10870, -32731, 13816, + 22246, -30723, 1232, 29756, -24146, -11062, 32718, -14459, -21372, 31251, + -3315, -28600, 26075, 7741, -32265, 18257, 17474, -32432, 8981, 25056, + -29562, -649, 30075, -24357, -9722, 32482, -17607, -17590, 32500, -10076, + -23868, 30528, -2421, -28411, 27049, 4849, -31260, 22560, 11383, -32592, + 17514, 16983, -32661, 12297, 21573, -31755, 7208, 25174, -30164, 2462, + 27874, -28156, -1801, 29801, -25961, -5503, 31098, -23773, -8615, 31914, + -21741, -11138, 32382, -19980, -13092, 32621, -18572, -14507, 32722, -17575, + -15409, 32756, -17023, -15820, 32762, -16936, -15749, 32756, -17317, -15192, + 32724, -18157, -14135, 32625, -19427, -12550, 32390, -21081, -10406, 31924, + -23046, -7672, 31105, -25218, -4328, 29791, -27456, -379, 27830, -29576, + 4132, 25066, -31346, 9106, 21361, -32496, 14369, 16622, -32719, 19661, + 10824, -31701, 24626, 4054, -29151, 28815, -3465, -24849, 31711, -11338, + -18706, 32767, -18989, -10833, 31485, -25676, -1599, 27503, -30544, 8325, + 20720, -32722, 17961, 11402, -31475, 26091, 282, -26390, 31389, -11417, + -17568, 32649, -22050, -5792, 29076, -29749, 7416, 20594, -32764, 19887, + 8101, -29906, 29112, -6444, -21010, 32763, -20185, -7289, 29354, -29874, + 8596, 18893, -32667, 22887, 3292, -27076, 31567, -13701, -13792, 31558, + -27243, 3983, 21995, -32761, 21019, 5066, -27658, 31478, -14069, -12751, + 31003, -28603, 7272, 18812, -32508, 24955, -1199, -23287, 32735, -21190, + -3847, 26394, -32224, 17784, 7755, -28415, 31426, -15051, -10527, 29626, + -30683, 13183, 12214, -30246, 30221, -12282, -12865, 30409, -30160, 12391, + 12502, -30153, 30516, -13510, -11109, 29417, -31202, 15591, 8631, -28038, + 32019, -18518, -5005, 25773, -32652, 22076, 203, -22324, 32663, -25909, + 5707, 17398, -31506, 29478, -12473, -10794, 28581, -32043, 19577, 2530, + -23339, 32699, -26160, 7010, 15455, -30491, 31027, -16934, -5059, 24638, + -32757, 25776, -7021, -14878, 29993, -31595, 19086, 1858, -21925, 32330, + -28627, 12545, 8886, -26461, 32751, -25207, 7118, 13884, -29080, 32279, + -22285, 3279, 16992, -30401, 31679, -20438, 1211, 18430, -30877, 31414, + -19954, 963, 18333, -30712, 31646, -20906, 2545, 16683, -29827, 32236, + -23165, 5940, 13313, -27866, 32739, -26362, 11028, 7983, -24250, 32386, + -29790, 17431, 559, -18305, 30122, -32315, 24302, -8708, -9536, 24774, + -32381, 30137, -18832, 1947, 15451, -28246, 32765, -27801, 14892, 2199, + -18604, 29748, -32607, 26498, -13198, -3613, 19389, -29956, 32602, -26737, + 13987, 2293, -17922, 28978, -32763, 28438, -17172, 1789, 13956, -26311, + 32406, -30905, 22258, -8549, -7039, 20974, -30175, 32681, -28041, 17361, + -3016, -11900, 24250, -31505, 32250, -26431, 15320, -1211, -13067, 24724, + -31549, 32316, -26972, 16615, -3240, -10657, 22555, -30355, 32746, -29397, + 20984, -9030, -4385, 16993, -26725, 32041, -32162, 27156, -17905, 5921, +}; diff --git a/test/cmocka/src/math/arithmetic/scalar_power.c b/test/cmocka/src/math/arithmetic/scalar_power.c deleted file mode 100644 index 8b23791e979e..000000000000 --- a/test/cmocka/src/math/arithmetic/scalar_power.c +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> - -#include <sof/audio/format.h> -#include <sof/math/power.h> -#include <sof/common.h> -#include "power_tables.h" -/* 'Error (max = 0.000034912111005), THD+N = -96.457180359025074' */ -#define CMP_TOLERANCE 0.0000150363575813 - -static void test_math_arithmetic_power_fixed(void **state) -{ - (void)state; - - double p; - int i; - int j; - - for (i = 0; i < ARRAY_SIZE(b); i++) { - for (j = 0; j < ARRAY_SIZE(e); j++) { - p = power_int32(b[i], e[j]); - float diff = fabsf(power_table[i][j] - (double)p / (1 << 15)); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %.16f: base = %.16f", - __func__, diff, (double)b[i] / (1 << 25)); - printf(", exponent = %.16f, power = %.16f\n", - (double)e[j] / (1 << 29), (double)p / (1 << 15)); - assert_true(diff <= CMP_TOLERANCE); - } - } - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_arithmetic_power_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/arithmetic/square_root.c b/test/cmocka/src/math/arithmetic/square_root.c deleted file mode 100644 index f6c03c9c42cf..000000000000 --- a/test/cmocka/src/math/arithmetic/square_root.c +++ /dev/null @@ -1,162 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> - -#include <sof/math/sqrt.h> -#include <sof/audio/format.h> -#include <rtos/string.h> -#include <sof/common.h> - -/* 'Error[max] = 0.0003000860000000,THD(-dBc) = -87.1210823527511309' */ -#define CMP_TOLERANCE 0.0001689942 - -static const double sqrt_ref_table[] = { - 0.0000000000000000, 0.2529127196287289, 0.3580137261684250, 0.4383362543470480, - 0.5060667106469264, 0.5657458434447398, 0.6199010757774179, 0.6695089151758922, - 0.7156864056624241, 0.7590598625931949, 0.8002380017063674, 0.8392530626247365, - 0.8765332548597343, 0.9124250825410271, 0.9468285879714448, 0.9800251112854200, - 1.0121334212938529, 1.0433710015497843, 1.0735864616438677, 1.1029744939820685, - 1.1317074351394887, 1.1596234572049671, 1.1868830634270588, 1.2135304899342250, - 1.2397036881347898, 1.2652391387105444, 1.2902693214499832, 1.3148230929007141, - 1.3390178303517843, 1.3626935069009465, 1.3859648038460428, 1.4089384024417106, - 1.4314580907679415, 1.4536289448738284, 1.4754666899408471, 1.4970674458754356, - 1.5182805344369004, 1.5392012945030940, 1.5598414883410430, 1.5802893574042065, - 1.6003997303408295, 1.6202605162827983, 1.6399552204252408, 1.6593426315110451, - 1.6785061252494731, 1.6974532854396907, 1.7162624043615824, 1.7347972458979175, - 1.7531361407845656, 1.7712851751976586, 1.7893183496097054, 1.8071040368501201, - 1.8247163735084968, 1.8422265952170487, 1.8595062978852748, 1.8766268983537990, - 1.8935927121149891, 1.9104717594746068, 1.9271396388170734, 1.9436645881555799, - 1.9601125007572908, 1.9763617734046062, 1.9924785326635266, 2.0084659685628234, - 2.0243874459327196, 2.0401248429936829, 2.0557417684986605, 2.0712409474756917, - 2.0866835042418388, 2.1019545405705138, 2.1171154277400652, 2.1322257663648099, - 2.1471729232877355, 2.1620167451363552, 2.1767593459084997, 2.1914584719713490, - 2.2060043241401410, 2.2204548907543695, 2.2348120201987909, 2.2491317769308226, - 2.2633070038662453, 2.2773940013752560, 2.2914476694602910, 2.3053627188850347, - 2.3191942802134968, 2.3329438383992445, 2.3466648541067809, 2.3602543890966499, - 2.3737661268541177, 2.3872013883939496, 2.4006123079591588, 2.4138981537908761, - 2.4271112748749282, 2.4403028756693299, 2.4533737931163282, 2.4663754402969551, - 2.4793089069839604, 2.4922242356226696, 2.5050242482608827, 2.5177591878742098, - 2.5304782774210888, 2.5430857547967194, 2.5556310375326090, 2.5681150370943278, - 2.5805859466650203, 2.5929498012639969, 2.6052549809231724, 2.6175023131556161, - 2.6297390257875399, 2.6418728560436060, 2.6539512111660981, 2.6660206330081166, - 2.6779900782816579, 2.6899062628881700, 2.7017698915479462, 2.7136266381449752, - 2.7253870138018930, 2.7370968595849874, 2.7487568212739375, 2.7604117531402812, - 2.7719736453698474, 2.7834875128828940, 2.7949976241045360, 2.8064170328908711, - 2.8177901636300033, 2.8291175744390689, 2.8404427884354582, 2.8516802201728368, - 2.8628735427669523, 2.8740232715872360, 2.8851722218959477, 2.8962361080806240, - 2.9072578897476569, 2.9182798738083706, 2.9292187124939990, 2.9401168530136688, - 2.9509747462702896, 2.9618340496219568, 2.9726126187665289, 2.9833522462156559, - 2.9940941216626773, 3.0047569707257522, 3.0153821145710538, 3.0259699503836783, - 3.0365610688738007, 3.0470753139280951, 3.0575534030495688, 3.0679957066870220, - 3.0784422425351754, 3.0888139284157279, 3.0991509043809078, 3.1094927741514371, - 3.1197612338526808, 3.1299960063872287, 3.1401974211424988, 3.1504045499149789, - 3.1605400917999757, 3.1706432337342845, 3.1807142844611178, 3.1907918051402224, - 3.2007994606816590, 3.2107759235502562, 3.2207593849316032, 3.2306742112715421, - 3.2405587023112234, 3.2504131347991749, 3.2602752232365293, 3.2700702400713046, - 3.2798360048560355, 3.2895727781126838, 3.2993178153786578, 3.3089972636170311, - 3.3186484800856810, 3.3283083869662677, 3.3379037677111065, 3.3474716438306089, - 3.3570122504989461, 3.3665620793882591, 3.3760487375221642, 3.3855088128485207, - 3.3949784839156196, 3.4043859578490805, 3.4137675072784321, 3.4231233453528955, - 3.4324892457042018, 3.4417941928048226, 3.4510740515635128, 3.4603290238249023, - 3.4695944917958350, 3.4788001927748020, 3.4879815975718680, 3.4971738031409019, - 3.5063070962374359, 3.5154166604934614, 3.5245026799003858, 3.5335998818485379, - 3.5426392659640071, 3.5516556438511886, 3.5606491902811768, 3.5696542746637245, - 3.5786025882144274, 3.5875285822032135, 3.5964663647113397, 3.6053481324623839, - 3.6142080737002402, 3.6230463485511746, 3.6318967259718442, 3.6406920594682268, - 3.6494661959833250, 3.6582526566654741, 3.6669847755001657, 3.6756961500510350, - 3.6843869274616097, 3.6930903069956198, 3.7017402474207994, 3.7103700224000571, - 3.7189797723132347, 3.7276023837381045, 3.7361724230822109, 3.7447228493908598, - 3.7532863204297375, 3.7617978476886553, 3.7702901600042669, 3.7787633869263368, - 3.7872498886065071, 3.7956852559847478, 3.8041019184887777, 3.8125000000000000, - 3.8209115711273665, 3.8292727871131094, 3.8376157861196840, 3.8459724266107265, - 3.8542792776341468, 3.8625682639598748, 3.8708395003538962, 3.8791245690071618, - 3.8873605782876637, 3.8955791750874478, 3.9037804693815712, 3.9119957742180653, - 3.9201627238228260, 3.9283126944020128, 3.9364768015796816, 3.9445930655930783, - 3.9526926641056979, 3.9607756993580185, 3.9688730295891301, 3.9769231786332004, - 3.9849570653270532, 3.9930053589840071, 3.9999694823054588, 3.9999694823054588}; -/* testvector in Q4.12 */ -static const uint32_t uv[252] = { - 0U, 262U, 525U, 787U, 1049U, 1311U, - 1574U, 1836U, 2098U, 2360U, 2623U, 2885U, - 3147U, 3410U, 3672U, 3934U, 4196U, 4459U, - 4721U, 4983U, 5246U, 5508U, 5770U, 6032U, - 6295U, 6557U, 6819U, 7081U, 7344U, 7606U, - 7868U, 8131U, 8393U, 8655U, 8917U, 9180U, - 9442U, 9704U, 9966U, 10229U, 10491U, 10753U, - 11016U, 11278U, 11540U, 11802U, 12065U, 12327U, - 12589U, 12851U, 13114U, 13376U, 13638U, 13901U, - 14163U, 14425U, 14687U, 14950U, 15212U, 15474U, - 15737U, 15999U, 16261U, 16523U, 16786U, 17048U, - 17310U, 17572U, 17835U, 18097U, 18359U, 18622U, - 18884U, 19146U, 19408U, 19671U, 19933U, 20195U, - 20457U, 20720U, 20982U, 21244U, 21507U, 21769U, - 22031U, 22293U, 22556U, 22818U, 23080U, 23342U, - 23605U, 23867U, 24129U, 24392U, 24654U, 24916U, - 25178U, 25441U, 25703U, 25965U, 26228U, 26490U, - 26752U, 27014U, 27277U, 27539U, 27801U, 28063U, - 28326U, 28588U, 28850U, 29113U, 29375U, 29637U, - 29899U, 30162U, 30424U, 30686U, 30948U, 31211U, - 31473U, 31735U, 31998U, 32260U, 32522U, 32784U, - 33047U, 33309U, 33571U, 33833U, 34096U, 34358U, - 34620U, 34883U, 35145U, 35407U, 35669U, 35932U, - 36194U, 36456U, 36719U, 36981U, 37243U, 37505U, - 37768U, 38030U, 38292U, 38554U, 38817U, 39079U, - 39341U, 39604U, 39866U, 40128U, 40390U, 40653U, - 40915U, 41177U, 41439U, 41702U, 41964U, 42226U, - 42489U, 42751U, 43013U, 43275U, 43538U, 43800U, - 44062U, 44324U, 44587U, 44849U, 45111U, 45374U, - 45636U, 45898U, 46160U, 46423U, 46685U, 46947U, - 47210U, 47472U, 47734U, 47996U, 48259U, 48521U, - 48783U, 49045U, 49308U, 49570U, 49832U, 50095U, - 50357U, 50619U, 50881U, 51144U, 51406U, 51668U, - 51930U, 52193U, 52455U, 52717U, 52980U, 53242U, - 53504U, 53766U, 54029U, 54291U, 54553U, 54816U, - 55078U, 55340U, 55602U, 55865U, 56127U, 56389U, - 56651U, 56914U, 57176U, 57438U, 57701U, 57963U, - 58225U, 58487U, 58750U, 59012U, 59274U, 59536U, - 59799U, 60061U, 60323U, 60586U, 60848U, 61110U, - 61372U, 61635U, 61897U, 62159U, 62421U, 62684U, - 62946U, 63208U, 63471U, 63733U, 63995U, 64257U, - 64520U, 64782U, 65044U, 65307U, UINT16_MAX, UINT16_MAX}; -static void test_math_arithmetic_sqrt_fixed(void **state) -{ - (void)state; - - uint32_t u[252]; - int i; - double y; - double diff; - - memcpy_s((void *)&u[0], sizeof(u), (void *)&uv[0], 252U * sizeof(uint32_t)); - for (i = 0; i < ARRAY_SIZE(sqrt_ref_table); i++) { - y = Q_CONVERT_QTOF(sqrt_int16(u[i]), 12); - diff = fabs(sqrt_ref_table[i] - y); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %.16f: reftbl = %.16f, sqrt = %.16f\n", __func__, - diff, (double)sqrt_ref_table[i], y); - assert_true(diff <= CMP_TOLERANCE); - } - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_arithmetic_sqrt_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/auditory/auditory.c b/test/cmocka/src/math/auditory/auditory.c index 1e3e903fb5fb..ff222e52fadd 100644 --- a/test/cmocka/src/math/auditory/auditory.c +++ b/test/cmocka/src/math/auditory/auditory.c @@ -14,7 +14,10 @@ #include <string.h> #include <cmocka.h> #include <math.h> +#include <sof/audio/module_adapter/module/generic.h> #include <sof/math/auditory.h> +#include <sof/math/icomplex16.h> +#include <sof/math/icomplex32.h> #include <sof/math/fft.h> #include "ref_hz_to_mel.h" #include "ref_mel_filterbank_16_test1.h" @@ -38,6 +41,8 @@ #undef DEBUGFILES /* Change this to #define to get output data files for debugging */ +struct processing_module dummy; + static void filterbank_16_test(const int16_t *fft_real, const int16_t *fft_imag, const int16_t *ref_mel_log, int num_fft_bins, int num_mel_bins, int norm_slaney, @@ -87,7 +92,7 @@ static void filterbank_16_test(const int16_t *fft_real, const int16_t *fft_imag, fb.scratch_data2 = (int16_t *)fft_out; fb.scratch_length1 = fft_size / sizeof(int16_t); fb.scratch_length2 = fft_size / sizeof(int16_t); - ret = psy_get_mel_filterbank(&fb); + ret = mod_psy_get_mel_filterbank(&dummy, &fb); if (ret < 0) { fprintf(stderr, "Failed Mel filterbank\n"); goto err_get_filterbank; @@ -128,6 +133,10 @@ static void filterbank_16_test(const int16_t *fft_real, const int16_t *fft_imag, assert_true(error_rms < MEL_FB16_MAX_ERROR_RMS); assert_true(delta_max < MEL_FB16_MAX_ERROR_ABS); + free(mel_log); + free(fft_buf); + free(fft_out); + mod_psy_free_mel_filterbank(&dummy, &fb); return; err_get_filterbank: @@ -154,7 +163,8 @@ static void filterbank_32_test(const int32_t *fft_real, const int32_t *fft_imag, float error_rms; float delta_max = 0; int32_t *power_spectra; - int16_t *mel_log; + int32_t *mel_log; + int16_t mel_log_16; int i; const int half_fft = num_fft_bins / 2 + 1; const int fft_size = num_fft_bins * sizeof(struct icomplex32); @@ -172,7 +182,7 @@ static void filterbank_32_test(const int32_t *fft_real, const int32_t *fft_imag, goto err_out_alloc; } - mel_log = malloc(MEL_FILTERBANK_32_TEST1_NUM_MEL_BINS * sizeof(int16_t)); + mel_log = malloc(num_mel_bins * sizeof(int32_t)); if (!mel_log) { fprintf(stderr, "Failed to allocate output vector\n"); goto err_mel_alloc; @@ -190,7 +200,7 @@ static void filterbank_32_test(const int32_t *fft_real, const int32_t *fft_imag, fb.scratch_data2 = (int16_t *)fft_out; fb.scratch_length1 = fft_size / sizeof(int16_t); fb.scratch_length2 = fft_size / sizeof(int16_t); - ret = psy_get_mel_filterbank(&fb); + ret = mod_psy_get_mel_filterbank(&dummy, &fb); if (ret < 0) { fprintf(stderr, "Failed Mel filterbank\n"); goto err_get_filterbank; @@ -206,9 +216,10 @@ static void filterbank_32_test(const int32_t *fft_real, const int32_t *fft_imag, power_spectra = (int32_t *)&fft_buf[0]; psy_apply_mel_filterbank_32(&fb, fft_out, power_spectra, mel_log, shift); - /* Check */ + /* Check: convert Q9.23 output to Q9.7 for comparison with reference */ for (i = 0; i < num_mel_bins; i++) { - delta = (float)ref_mel_log[i] - (float)mel_log[i]; + mel_log_16 = (int16_t)(mel_log[i] >> 16); + delta = (float)ref_mel_log[i] - (float)mel_log_16; sum_squares += delta * delta; if (delta > delta_max) delta_max = delta; @@ -224,13 +235,17 @@ static void filterbank_32_test(const int32_t *fft_real, const int32_t *fft_imag, FILE *fh = fopen("mel_filterbank_32.txt", "w"); for (i = 0; i < num_mel_bins; i++) - fprintf(fh, "%d %d\n", ref_mel_log[i], mel_log[i]); + fprintf(fh, "%d %d\n", ref_mel_log[i], (int16_t)(mel_log[i] >> 16)); fclose(fh); #endif assert_true(error_rms < MEL_FB32_MAX_ERROR_RMS); assert_true(delta_max < MEL_FB32_MAX_ERROR_ABS); + free(mel_log); + free(fft_buf); + free(fft_out); + mod_psy_free_mel_filterbank(&dummy, &fb); return; err_get_filterbank: diff --git a/test/cmocka/src/math/dct/dct.c b/test/cmocka/src/math/dct/dct.c index 4cfe38ef803b..ea35d170e66e 100644 --- a/test/cmocka/src/math/dct/dct.c +++ b/test/cmocka/src/math/dct/dct.c @@ -22,6 +22,8 @@ #define MATRIX_MULT_16_MAX_ERROR_ABS 2.5 #define MATRIX_MULT_16_MAX_ERROR_RMS 1.1 +struct processing_module dummy; + static void dct_matrix_16_test(const int16_t *ref, int num_in, int num_out, enum dct_type type, bool ortho) { @@ -41,7 +43,7 @@ static void dct_matrix_16_test(const int16_t *ref, int num_in, int num_out, dct.num_out = num_out; dct.type = type; dct.ortho = ortho; - ret = dct_initialize_16(&dct); + ret = mod_dct_initialize_16(&dummy, &dct); if (ret) { fprintf(stderr, "Failed to initialize DCT.\n"); exit(EXIT_FAILURE); @@ -69,6 +71,8 @@ static void dct_matrix_16_test(const int16_t *ref, int num_in, int num_out, assert_true(error_rms < MATRIX_MULT_16_MAX_ERROR_RMS); assert_true(delta_max < MATRIX_MULT_16_MAX_ERROR_ABS); + + mod_dct_free_16(&dummy, &dct); } static void test_dct_matrix_16_test1(void **state) diff --git a/test/cmocka/src/math/fft/CMakeLists.txt b/test/cmocka/src/math/fft/CMakeLists.txt index c3d9e47e6ea5..97ac2ee8438f 100644 --- a/test/cmocka/src/math/fft/CMakeLists.txt +++ b/test/cmocka/src/math/fft/CMakeLists.txt @@ -28,3 +28,25 @@ cmocka_test(fft ${PROJECT_SOURCE_DIR}/src/audio/component.c ${PROJECT_SOURCE_DIR}/src/math/numbers.c ) + +cmocka_test(dft3 + dft3.c + ${PROJECT_SOURCE_DIR}/src/math/fft/fft_multi.c + ${PROJECT_SOURCE_DIR}/src/math/fft/fft_multi_generic.c + ${PROJECT_SOURCE_DIR}/src/math/fft/fft_multi_hifi3.c + ${PROJECT_SOURCE_DIR}/src/math/fft/fft_32.c + ${PROJECT_SOURCE_DIR}/src/math/fft/fft_common.c + ${PROJECT_SOURCE_DIR}/test/cmocka/src/notifier_mocks.c + ${PROJECT_SOURCE_DIR}/test/cmocka/src/common_mocks.c +) + +cmocka_test(fft_multi + fft_multi.c + ${PROJECT_SOURCE_DIR}/src/math/fft/fft_multi.c + ${PROJECT_SOURCE_DIR}/src/math/fft/fft_multi_generic.c + ${PROJECT_SOURCE_DIR}/src/math/fft/fft_multi_hifi3.c + ${PROJECT_SOURCE_DIR}/src/math/fft/fft_common.c + ${PROJECT_SOURCE_DIR}/src/math/fft/fft_32.c + ${PROJECT_SOURCE_DIR}/test/cmocka/src/notifier_mocks.c + ${PROJECT_SOURCE_DIR}/test/cmocka/src/common_mocks.c +) diff --git a/test/cmocka/src/math/fft/dft3.c b/test/cmocka/src/math/fft/dft3.c new file mode 100644 index 000000000000..a787d8329993 --- /dev/null +++ b/test/cmocka/src/math/fft/dft3.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +#include <sof/audio/format.h> +#include <sof/math/fft.h> +#include "ref_dft3_32.h" + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <string.h> +#include <cmocka.h> +#include <math.h> + +#define SOFM_DFT3_MAX_ERROR_ABS 3.1 +#define SOFM_DFT3_MAX_ERROR_RMS 1.1 +#define DFT_SIZE 3 + +static void dft3_32_test(const int32_t *in_real, const int32_t *in_imag, + const int32_t *ref_real, const int32_t *ref_imag, int num_tests) + +{ + struct icomplex32 x[DFT_SIZE]; + struct icomplex32 y[DFT_SIZE]; + double delta; + double error_rms; + double delta_max = 0; + double sum_squares = 0; + const int32_t *p_in_real = in_real; + const int32_t *p_in_imag = in_imag; + const int32_t *p_ref_real = ref_real; + const int32_t *p_ref_imag = ref_imag; + int i, j; + + for (i = 0; i < num_tests; i++) { + for (j = 0; j < DFT_SIZE; j++) { + x[j].real = *p_in_real++; + x[j].imag = *p_in_imag++; + } + + dft3_32(x, y); + + for (j = 0; j < DFT_SIZE; j++) { + delta = (double)*p_ref_real - (double)y[j].real; + sum_squares += delta * delta; + if (delta > delta_max) + delta_max = delta; + else if (-delta > delta_max) + delta_max = -delta; + + delta = (double)*p_ref_imag - (double)y[j].imag; + sum_squares += delta * delta; + if (delta > delta_max) + delta_max = delta; + else if (-delta > delta_max) + delta_max = -delta; + + p_ref_real++; + p_ref_imag++; + } + } + + error_rms = sqrt(sum_squares / (double)(2 * DFT_SIZE * num_tests)); + printf("Max absolute error = %5.2f (max %5.2f), error RMS = %5.2f (max %5.2f)\n", + delta_max, SOFM_DFT3_MAX_ERROR_ABS, error_rms, SOFM_DFT3_MAX_ERROR_RMS); + + assert_true(error_rms < SOFM_DFT3_MAX_ERROR_RMS); + assert_true(delta_max < SOFM_DFT3_MAX_ERROR_ABS); +} + +static void dft3_32_test_1(void **state) +{ + (void)state; + + dft3_32_test(input_data_real_q31, input_data_imag_q31, + ref_data_real_q31, ref_data_imag_q31, + REF_SOFM_DFT3_NUM_TESTS); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(dft3_32_test_1), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/test/cmocka/src/math/fft/fft.c b/test/cmocka/src/math/fft/fft.c index cfb2ec8d98bb..dc3dc8e70524 100644 --- a/test/cmocka/src/math/fft/fft.c +++ b/test/cmocka/src/math/fft/fft.c @@ -13,9 +13,12 @@ #include <cmocka.h> #include <stdbool.h> +#include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/buffer.h> #include <sof/audio/component.h> #include <sof/audio/format.h> +#include <sof/math/icomplex16.h> +#include <sof/math/icomplex32.h> #include <sof/math/fft.h> #include "input.h" @@ -39,6 +42,8 @@ #define MIN_SNR_512 125.0 #define MIN_SNR_1024 119.0 +struct processing_module dummy; + /** * \brief Doing Fast Fourier Transform (FFT) for mono real input buffers. * \param[in] src - pointer to input buffer. @@ -59,16 +64,16 @@ static void fft_real(struct comp_buffer *src, struct comp_buffer *dst, uint32_t dst->stream.size < size * sizeof(struct icomplex32)) return; - inb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + inb = rzalloc(SOF_MEM_FLAG_USER, size * sizeof(struct icomplex32)); if (!inb) return; - outb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + outb = rzalloc(SOF_MEM_FLAG_USER, size * sizeof(struct icomplex32)); if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 32); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 32); if (!plan) goto err_plan; @@ -85,7 +90,7 @@ static void fft_real(struct comp_buffer *src, struct comp_buffer *dst, uint32_t *((int32_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -113,17 +118,17 @@ static void ifft_complex(struct comp_buffer *src, struct comp_buffer *dst, uint3 dst->stream.size < size * sizeof(struct icomplex32)) return; - inb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + inb = rzalloc(SOF_MEM_FLAG_USER, size * sizeof(struct icomplex32)); if (!inb) return; - outb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + outb = rzalloc(SOF_MEM_FLAG_USER, size * sizeof(struct icomplex32)); if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 32); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 32); if (!plan) goto err_plan; @@ -140,7 +145,7 @@ static void ifft_complex(struct comp_buffer *src, struct comp_buffer *dst, uint3 *((int32_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -171,17 +176,17 @@ static void fft_real_2(struct comp_buffer *src, struct comp_buffer *dst1, dst2->stream.size < size * sizeof(struct icomplex32)) return; - inb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + inb = rzalloc(SOF_MEM_FLAG_USER, size * sizeof(struct icomplex32)); if (!inb) return; - outb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + outb = rzalloc(SOF_MEM_FLAG_USER, size * sizeof(struct icomplex32)); if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 32); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 32); if (!plan) goto err_plan; @@ -210,7 +215,7 @@ static void fft_real_2(struct comp_buffer *src, struct comp_buffer *dst1, (outb[size - i].real - outb[i].real) / 2; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -265,8 +270,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, false); - struct comp_buffer *sink = buffer_new(&test_buf_desc, false); + struct comp_buffer *source = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *sink = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); struct icomplex32 *out = (struct icomplex32 *)sink->stream.addr; int32_t *in = (int32_t *)source->stream.addr; int fft_size = 256; @@ -300,6 +305,9 @@ static void test_math_fft_256(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_256, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_512(void **state) @@ -307,8 +315,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, false); - struct comp_buffer *sink = buffer_new(&test_buf_desc, false); + struct comp_buffer *source = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *sink = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); struct icomplex32 *out = (struct icomplex32 *)sink->stream.addr; int32_t *in = (int32_t *)source->stream.addr; int fft_size = 512; @@ -342,6 +350,9 @@ static void test_math_fft_512(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_512, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_1024(void **state) @@ -349,8 +360,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, false); - struct comp_buffer *sink = buffer_new(&test_buf_desc, false); + struct comp_buffer *source = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *sink = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); struct icomplex32 *out = (struct icomplex32 *)sink->stream.addr; int32_t *in = (int32_t *)source->stream.addr; int fft_size = 1024; @@ -384,6 +395,9 @@ static void test_math_fft_1024(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_1024, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_1024_ifft(void **state) @@ -391,9 +405,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, false); - struct comp_buffer *intm = buffer_new(&test_buf_desc, false); - struct comp_buffer *sink = buffer_new(&test_buf_desc, false); + struct comp_buffer *source = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *intm = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *sink = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); struct icomplex32 *out = (struct icomplex32 *)sink->stream.addr; float db; int64_t signal = 0; @@ -425,6 +439,10 @@ static void test_math_fft_1024_ifft(void **state) db = 10 * log10((float)signal / noise); printf("%s: SNR: %6.2f dB\n", __func__, db); assert_int_equal(db < FFT_DB_TH, 0); + + buffer_free(source); + buffer_free(intm); + buffer_free(sink); } static void test_math_fft_512_2ch(void **state) @@ -432,9 +450,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, false); - struct comp_buffer *sink1 = buffer_new(&test_buf_desc, false); - struct comp_buffer *sink2 = buffer_new(&test_buf_desc, false); + struct comp_buffer *source = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *sink1 = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *sink2 = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); struct icomplex32 *out1 = (struct icomplex32 *)sink1->stream.addr; struct icomplex32 *out2 = (struct icomplex32 *)sink2->stream.addr; uint32_t fft_size = 512; @@ -467,6 +485,10 @@ static void test_math_fft_512_2ch(void **state) /* the peak should be in range i +/-1 */ assert_in_range(r, i - 1, i + 1); + + buffer_free(source); + buffer_free(sink1); + buffer_free(sink2); } /** @@ -489,16 +511,16 @@ static void fft_real_16(struct comp_buffer *src, struct comp_buffer *dst, uint32 dst->stream.size < size * sizeof(struct icomplex16)) return; - inb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + inb = rzalloc(SOF_MEM_FLAG_USER, size * sizeof(struct icomplex16)); if (!inb) return; - outb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + outb = rzalloc(SOF_MEM_FLAG_USER, size * sizeof(struct icomplex16)); if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 16); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 16); if (!plan) goto err_plan; @@ -515,7 +537,7 @@ static void fft_real_16(struct comp_buffer *src, struct comp_buffer *dst, uint32 *((int16_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -543,17 +565,17 @@ static void ifft_complex_16(struct comp_buffer *src, struct comp_buffer *dst, ui dst->stream.size < size * sizeof(struct icomplex16)) return; - inb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + inb = rzalloc(SOF_MEM_FLAG_USER, size * sizeof(struct icomplex16)); if (!inb) return; - outb = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + outb = rzalloc(SOF_MEM_FLAG_USER, size * sizeof(struct icomplex16)); if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 16); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 16); if (!plan) goto err_plan; @@ -570,7 +592,7 @@ static void ifft_complex_16(struct comp_buffer *src, struct comp_buffer *dst, ui *((int16_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -625,8 +647,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, false); - struct comp_buffer *sink = buffer_new(&test_buf_desc, false); + struct comp_buffer *source = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *sink = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); struct icomplex16 *out = (struct icomplex16 *)sink->stream.addr; int16_t *in = (int16_t *)source->stream.addr; int fft_size = 256; @@ -660,6 +682,9 @@ static void test_math_fft_256_16(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_256_16, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_512_16(void **state) @@ -667,8 +692,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, false); - struct comp_buffer *sink = buffer_new(&test_buf_desc, false); + struct comp_buffer *source = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *sink = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); struct icomplex16 *out = (struct icomplex16 *)sink->stream.addr; int16_t *in = (int16_t *)source->stream.addr; int fft_size = 512; @@ -702,6 +727,9 @@ static void test_math_fft_512_16(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_512_16, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_1024_16(void **state) @@ -709,8 +737,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, false); - struct comp_buffer *sink = buffer_new(&test_buf_desc, false); + struct comp_buffer *source = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *sink = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); struct icomplex16 *out = (struct icomplex16 *)sink->stream.addr; int16_t *in = (int16_t *)source->stream.addr; int fft_size = 1024; @@ -744,6 +772,9 @@ static void test_math_fft_1024_16(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_1024_16, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_1024_ifft_16(void **state) @@ -751,9 +782,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, false); - struct comp_buffer *intm = buffer_new(&test_buf_desc, false); - struct comp_buffer *sink = buffer_new(&test_buf_desc, false); + struct comp_buffer *source = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *intm = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); + struct comp_buffer *sink = buffer_new(NULL, &test_buf_desc, BUFFER_USAGE_NOT_SHARED); struct icomplex16 *out = (struct icomplex16 *)sink->stream.addr; float db; int64_t signal = 0; @@ -784,6 +815,10 @@ static void test_math_fft_1024_ifft_16(void **state) db = 10 * log10((float)signal / noise); printf("%s: SNR: %6.2f dB\n", __func__, db); assert_int_equal(db < FFT_DB_TH_16, 0); + + buffer_free(source); + buffer_free(intm); + buffer_free(sink); } int main(void) diff --git a/test/cmocka/src/math/fft/fft_multi.c b/test/cmocka/src/math/fft/fft_multi.c new file mode 100644 index 000000000000..bf5bd49efb08 --- /dev/null +++ b/test/cmocka/src/math/fft/fft_multi.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +#include <sof/audio/format.h> +#include <sof/math/icomplex16.h> +#include <sof/math/icomplex32.h> +#include <sof/math/fft.h> +#include "ref_fft_multi_96_32.h" +#include "ref_fft_multi_512_32.h" +#include "ref_fft_multi_768_32.h" +#include "ref_fft_multi_1024_32.h" +#include "ref_fft_multi_1536_32.h" +#include "ref_fft_multi_3072_32.h" + +#include "ref_ifft_multi_24_32.h" +#include "ref_ifft_multi_256_32.h" +#include "ref_ifft_multi_1024_32.h" +#include "ref_ifft_multi_1536_32.h" +#include "ref_ifft_multi_3072_32.h" + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <string.h> +#include <cmocka.h> +#include <math.h> + +#define FFT_MAX_ERROR_ABS 1050.0 /* about -126 dB */ +#define FFT_MAX_ERROR_RMS 35.0 /* about -156 dB */ +#define IFFT_MAX_ERROR_ABS 2400000.0 /* about -59 dB */ +#define IFFT_MAX_ERROR_RMS 44000.0 /* about -94 dB */ + +struct processing_module dummy; + +static void fft_multi_32_test(const int32_t *in_real, const int32_t *in_imag, + const int32_t *ref_real, const int32_t *ref_imag, + int num_bins, int num_tests, double max_error_abs, + double max_error_rms, bool do_ifft) +{ + struct icomplex32 *x; + struct icomplex32 *y; + struct fft_multi_plan *plan; + double delta; + double error_rms; + double delta_max = 0; + double sum_squares = 0; + const int32_t *p_in_real = in_real; + const int32_t *p_in_imag = in_imag; + const int32_t *p_ref_real = ref_real; + const int32_t *p_ref_imag = ref_imag; + int i, j; + FILE *fh1, *fh2; + + x = malloc(num_bins * sizeof(struct icomplex32)); + if (!x) { + fprintf(stderr, "Failed to allocate input data buffer.\n"); + assert_true(false); + } + + y = malloc(num_bins * sizeof(struct icomplex32)); + if (!y) { + fprintf(stderr, "Failed to allocate output data buffer.\n"); + assert_true(false); + } + + plan = mod_fft_multi_plan_new(&dummy, x, y, num_bins, 32); + if (!plan) { + fprintf(stderr, "Failed to allocate FFT plan.\n"); + assert_true(false); + } + + fh1 = fopen("debug_fft_multi_in.txt", "w"); + fh2 = fopen("debug_fft_multi_out.txt", "w"); + + for (i = 0; i < num_tests; i++) { + for (j = 0; j < num_bins; j++) { + x[j].real = *p_in_real++; + x[j].imag = *p_in_imag++; + fprintf(fh1, "%d %d\n", x[j].real, x[j].imag); + } + + fft_multi_execute_32(plan, do_ifft); + + for (j = 0; j < num_bins; j++) { + fprintf(fh2, "%d %d %d %d\n", + y[j].real, y[j].imag, *p_ref_real, *p_ref_imag); + delta = (double)*p_ref_real - (double)y[j].real; + sum_squares += delta * delta; + if (delta > delta_max) + delta_max = delta; + else if (-delta > delta_max) + delta_max = -delta; + + delta = (double)*p_ref_imag - (double)y[j].imag; + sum_squares += delta * delta; + if (delta > delta_max) + delta_max = delta; + else if (-delta > delta_max) + delta_max = -delta; + + p_ref_real++; + p_ref_imag++; + } + + } + + mod_fft_multi_plan_free(&dummy, plan); + free(y); + free(x); + fclose(fh1); fclose(fh2); + + error_rms = sqrt(sum_squares / (double)(2 * num_bins * num_tests)); + printf("Max absolute error = %5.2f (limit %5.2f), error RMS = %5.2f (limit %5.2f)\n", + delta_max, max_error_abs, error_rms, max_error_rms); + + assert_true(error_rms < max_error_rms); + assert_true(delta_max < max_error_abs); +} + +static void fft_multi_32_test_1(void **state) +{ + (void)state; + + /* Test FFT */ + fft_multi_32_test(fft_in_real_96_q31, fft_in_imag_96_q31, + fft_ref_real_96_q31, fft_ref_imag_96_q31, + 96, REF_SOFM_FFT_MULTI_96_NUM_TESTS, + FFT_MAX_ERROR_ABS, FFT_MAX_ERROR_RMS, false); + fft_multi_32_test(fft_in_real_512_q31, fft_in_imag_512_q31, + fft_ref_real_512_q31, fft_ref_imag_512_q31, + 512, REF_SOFM_FFT_MULTI_512_NUM_TESTS, + FFT_MAX_ERROR_ABS, FFT_MAX_ERROR_RMS, false); + fft_multi_32_test(fft_in_real_768_q31, fft_in_imag_768_q31, + fft_ref_real_768_q31, fft_ref_imag_768_q31, + 768, REF_SOFM_FFT_MULTI_768_NUM_TESTS, + FFT_MAX_ERROR_ABS, FFT_MAX_ERROR_RMS, false); + fft_multi_32_test(fft_in_real_1024_q31, fft_in_imag_1024_q31, + fft_ref_real_1024_q31, fft_ref_imag_1024_q31, + 1024, REF_SOFM_FFT_MULTI_1024_NUM_TESTS, + FFT_MAX_ERROR_ABS, FFT_MAX_ERROR_RMS, false); + fft_multi_32_test(fft_in_real_1536_q31, fft_in_imag_1536_q31, + fft_ref_real_1536_q31, fft_ref_imag_1536_q31, + 1536, REF_SOFM_FFT_MULTI_1536_NUM_TESTS, + FFT_MAX_ERROR_ABS, FFT_MAX_ERROR_RMS, false); + fft_multi_32_test(fft_in_real_3072_q31, fft_in_imag_3072_q31, + fft_ref_real_3072_q31, fft_ref_imag_3072_q31, + 3072, REF_SOFM_FFT_MULTI_3072_NUM_TESTS, + FFT_MAX_ERROR_ABS, FFT_MAX_ERROR_RMS, false); + fft_multi_32_test(fft_in_real_3072_q31, fft_in_imag_3072_q31, + fft_ref_real_3072_q31, fft_ref_imag_3072_q31, + 3072, REF_SOFM_FFT_MULTI_3072_NUM_TESTS, + FFT_MAX_ERROR_ABS, FFT_MAX_ERROR_RMS, false); + + /* Test IFFT */ + fft_multi_32_test(ifft_in_real_24_q31, ifft_in_imag_24_q31, + ifft_ref_real_24_q31, ifft_ref_imag_24_q31, + 24, REF_SOFM_IFFT_MULTI_24_NUM_TESTS, + IFFT_MAX_ERROR_ABS, IFFT_MAX_ERROR_RMS, true); + fft_multi_32_test(ifft_in_real_256_q31, ifft_in_imag_256_q31, + ifft_ref_real_256_q31, ifft_ref_imag_256_q31, + 256, REF_SOFM_IFFT_MULTI_256_NUM_TESTS, + IFFT_MAX_ERROR_ABS, IFFT_MAX_ERROR_RMS, true); + fft_multi_32_test(ifft_in_real_1024_q31, ifft_in_imag_1024_q31, + ifft_ref_real_1024_q31, ifft_ref_imag_1024_q31, + 1024, REF_SOFM_IFFT_MULTI_1024_NUM_TESTS, + IFFT_MAX_ERROR_ABS, IFFT_MAX_ERROR_RMS, true); + fft_multi_32_test(ifft_in_real_1536_q31, ifft_in_imag_1536_q31, + ifft_ref_real_1536_q31, ifft_ref_imag_1536_q31, + 1536, REF_SOFM_IFFT_MULTI_1536_NUM_TESTS, + IFFT_MAX_ERROR_ABS, IFFT_MAX_ERROR_RMS, true); + fft_multi_32_test(ifft_in_real_3072_q31, ifft_in_imag_3072_q31, + ifft_ref_real_3072_q31, ifft_ref_imag_3072_q31, + 3072, REF_SOFM_IFFT_MULTI_3072_NUM_TESTS, + IFFT_MAX_ERROR_ABS, IFFT_MAX_ERROR_RMS, true); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(fft_multi_32_test_1), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/test/cmocka/src/math/fft/ref_dft3.m b/test/cmocka/src/math/fft/ref_dft3.m new file mode 100644 index 000000000000..c3f55d91b3e3 --- /dev/null +++ b/test/cmocka/src/math/fft/ref_dft3.m @@ -0,0 +1,59 @@ +% ref_dft3 - Generate C header files for DFT3 function unit tests + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright(c) 2025 Intel Corporation. All rights reserved. + +function ref_dft3() + + path(path(), '../../../m'); + opt.describe = export_get_git_describe(); + + N = 3; + num_tests = 100; + scale_q31 = 2^31; + opt.bits = 32; + min_int32 = int32(-2^31); + max_int32 = int32(2^31 - 1); + + % Random values + input_data_real_q31 = int32((2 * rand(N, num_tests) - 1) * scale_q31); + input_data_imag_q31 = int32((2 * rand(N, num_tests) - 1) * scale_q31); + + % Apply max and min values to first two tests + input_data_real_q31(:,1) = [max_int32 max_int32 max_int32]; + input_data_imag_q31(:,1) = [max_int32 max_int32 max_int32]; + input_data_real_q31(:,2) = [min_int32 min_int32 min_int32]; + input_data_imag_q31(:,2) = [min_int32 min_int32 min_int32]; + + % Convert to float for reference DFT + input_data_real_f = double(input_data_real_q31) / scale_q31; + input_data_imag_f = double(input_data_imag_q31) / scale_q31; + input_data_f = complex(input_data_real_f, input_data_imag_f); + + ref_data_f = zeros(N, num_tests); + for i = 1:num_tests + ref_data_f(:,i) = fft(1/N * input_data_f(:,i)); + end + + input_data_vec_f = reshape(input_data_f, N * num_tests, 1); + input_data_real_q31 = int32(real(input_data_vec_f) * scale_q31); + input_data_imag_q31 = int32(imag(input_data_vec_f) * scale_q31); + + ref_data_vec_f = reshape(ref_data_f, N * num_tests, 1); + ref_data_real_q31 = int32(real(ref_data_vec_f) * scale_q31); + ref_data_imag_q31 = int32(imag(ref_data_vec_f) * scale_q31); + + header_fn = sprintf('ref_dft3_32.h'); + fh = export_headerfile_open(header_fn); + comment = sprintf('Created %s with script ref_dft3.m %s', ... + datestr(now, 0), opt.describe); + export_comment(fh, comment); + export_ndefine(fh, 'REF_SOFM_DFT3_NUM_TESTS', num_tests); + export_vector(fh, opt.bits, 'input_data_real_q31', input_data_real_q31); + export_vector(fh, opt.bits, 'input_data_imag_q31', input_data_imag_q31); + export_vector(fh, opt.bits, 'ref_data_real_q31', ref_data_real_q31); + export_vector(fh, opt.bits, 'ref_data_imag_q31', ref_data_imag_q31); + fclose(fh); + fprintf(1, 'Exported %s.\n', header_fn); +end diff --git a/test/cmocka/src/math/fft/ref_dft3_32.h b/test/cmocka/src/math/fft/ref_dft3_32.h new file mode 100644 index 000000000000..dc29c737e552 --- /dev/null +++ b/test/cmocka/src/math/fft/ref_dft3_32.h @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 18-Nov-2025 10:04:16 with script ref_dft3.m v1.9-rc1-6866-g7082edfc2-dirty */ + +#define REF_SOFM_DFT3_NUM_TESTS 100 + +static const int32_t input_data_real_q31[300] = { + 2147483647, 2147483647, 2147483647, -2147483648, -2147483648, -2147483648, + 1162219834, 23816319, -504635601, -893753638, 2096234199, 1926797429, + -1498879994, -1344377511, -1565629944, 470700317, 1534215118, 250204116, + -1513962524, 328839298, -891150595, 1037032885, 2053083918, 214745934, + -1132393293, -684253779, 1290308737, 1492556115, 1767631432, -1476198666, + -1980706125, -152724048, 1304919915, -333340349, -945811108, 555573004, + 508704347, -91940743, -1172534471, 808237431, -864171862, -1701987975, + 667143603, 466065800, -680587634, -1210890266, -1609079348, 376693582, + -1989200673, -866348502, -1518045121, -810592170, -2014026366, 308045234, + -893653199, -71890004, 1798867597, -1165288212, -195853850, 727803849, + -827203566, -763401435, -555032730, 2049556353, -1733329582, 1857973403, + -969720479, 474304971, -118122188, -1414917124, 755553858, 512336983, + -412624469, -654030354, -673412294, -480554119, 2141467418, 982286252, + -333493549, -1792914214, -751632737, 1453631035, -567352454, -1121160722, + 1835418889, 1469373494, 1260799356, 1916321534, 1046738218, -482282675, + -1777733492, 1417780825, -1905923885, 1720942739, -1698447345, 1524731616, + -940329093, 474359626, 869280780, -1587738164, 718005895, -1275483558, + 1311357743, -1127231201, 1170568884, 351336134, 912933315, 929235364, + -1766156248, -751021719, -1575099846, -500683117, 758133192, -1000251215, + -460549792, -872077348, 1190236123, -2094039372, -97472255, 1766680277, + 1682916204, 1878420776, -1937130520, -1305433548, -2023614346, -961620965, + -1144745178, 349170968, -990207654, 2066179435, -409481891, -1640628527, + -1748672103, 1509049194, 2136386712, 749103155, 1869393346, -473447757, + 188132091, 471958830, 565514557, 24038287, 250957039, 555942787, + -1417341343, 1310588913, -1980667608, 1978973460, -1886552564, -931043047, + 240691726, 366351147, 856435514, -2100179945, 1322815981, -1993386310, + -1907183049, 1018981874, -1982669624, -392347504, 283140809, -701932511, + 827970927, 1087003102, 1539141719, 575668370, -284136687, -166908907, + 1086613743, -1578737459, 1755161659, -363056680, -972520979, 1833561918, + -691836837, 2043720743, -142353127, 1166774227, 991149245, -1806872349, + -1973652264, 1188981112, 1911685701, -968798985, 2077908949, -166982863, + 1326781679, -1986923452, -1067800528, 1854266938, 1333307796, -241964941, + -267584968, 886003675, -805272619, 1479927684, 159424368, 139369932, + -313191797, -791964593, 123256824, 1761190835, 267191061, -1066245064, + 2059356024, 983929284, -988243656, -2128354307, 1321996812, 279274571, + -958912371, 115946572, 1492522503, -1102123606, -1958076794, -1473281696, + -511493535, -162111044, -1652434912, 515681118, 1328854757, 1615582785, + 838101882, -981669826, -85699769, 826563860, -1054635732, 276608854, + -285946678, 1081455066, 1239400031, 344174895, -152045930, -1779441010, + -1443541302, -626187735, -7031089, -314268939, 575767023, -18068620, + 857747866, -1026238975, 1741588511, -825216518, -657754491, -1800153864, + 902250246, 1007864270, 1984210739, 1594306126, -365683058, -306799624, + 728125587, -1705315469, -445468326, 1860359390, 1561088340, 996962395, + 636780028, 1069385362, 49149330, -1167618105, -2051885175, 1699344213, + -450653472, 28073512, 1407413309, -1332191163, 1302508825, 589871272, + -769422448, -1945782013, -1273023036, -2144421096, -981418969, 1126299923, + -1473462655, -1468616147, 1514904515, 1873597062, 977229454, -190860952, + -1450912250, -1515509653, -1706549902, -1798566387, -1488199231, 465976855, + 1507852161, 1334015424, -1930050220, -839537711, -519449681, 1802561273, + -1686609113, -988247120, -2018183481, -1422312120, -524629977, 777771469, +}; + +static const int32_t input_data_imag_q31[300] = { + 2147483647, 2147483647, 2147483647, -2147483648, -2147483648, -2147483648, + -447071638, -710569404, -521054814, -1525984216, 1485866355, -1887906218, + 694991588, -1423316381, -526983997, 1416498079, -9059322, -1894876350, + 529729352, -1667720604, -1765426014, 1622805049, 1403298661, -56966777, + 1372247161, -989865104, 226982867, 1200666007, -1172962658, -327728731, + -1770194241, 2063801732, -1222401122, -1437089259, 7163116, -1667845557, + 699401620, -767508329, 1458191154, 2102543710, -386800992, 984597551, + -1002742709, -1568629571, -502851595, -51793840, -709663670, 1748043151, + 1096459944, 1109269442, 1991276284, 1630095127, -412134472, -1039994124, + -769839143, -2071887810, -1473927075, 143017106, 792574136, 1214806759, + -1707309285, -1546417474, 1644851668, 1369929054, -1504595449, -504861820, + 941716193, 1798841734, 1004503064, -548152154, 1433124598, 75564731, + -837059818, -1634446222, 1096996669, 760853936, 158476524, 1288109053, + -545735405, -1072909043, 1216016240, 1728999756, 1301464866, 1708661027, + 424731640, -179953738, 1829344056, -325009476, 1191455307, 1243675521, + 206426657, -785131901, 513197679, -1441381381, -1879255156, -626702268, + 1196431670, -484279907, 2027499180, 947791638, -1004082133, 1126341198, + -762028151, -776494670, -1745568389, -1969907879, 894288459, 106735650, + -272461269, -337916005, -1243196237, -395332730, 1275277656, -1472977807, + -938816844, 1834539458, 1332936891, 878083108, -45073545, -1185953597, + -717818068, -30126320, 1482293565, -1904955333, -932393894, -2110646291, + -525568699, -1934721075, -841727840, 199552072, 402812734, 545621043, + 2041424330, 636650031, 262616779, 2027512409, -1473662400, -2131440924, + 86104846, 858180945, -1162684732, -1853469689, -1511760166, -2140871371, + -16978023, 1565504329, 1807701041, 838301612, -432147051, 1812146715, + 358112650, -1258170956, 688314303, -938717727, 1479050461, -808626808, + -1801201683, -567689961, 409371332, -1131239726, -219900330, 1662293964, + -1591338732, -1898978738, -1394863666, -1673116723, -1385225905, -506268616, + 1968110246, -124595511, 1787454593, 579998873, -556710560, 1912851650, + -99737218, -2012489847, 248120965, 283176403, 1573201156, -759852424, + -1562343755, 1375885975, -1557867556, 135286679, 920363352, 1029195101, + 1429284623, 1861442578, 1690850333, -2039742677, -452522368, 94467724, + 603284320, 370872395, -1416940658, 1020409603, -181807657, -1585188066, + -131317730, 1841147202, 751515590, 1429723577, -1685642094, 1194135059, + 782914220, 1896122751, 1008900429, 937134356, 54677423, -1294082603, + -1394821557, -1413641053, -1995302037, 1412674184, -2090278821, -818075169, + 412258694, -646997248, -1371284669, -943407015, -277753547, -1009224290, + -714869328, 759608215, 1616359360, -754310245, 1178040373, -1748780178, + -283459899, 863462232, 844805157, 302181273, -1799234263, 299774378, + 902067000, 2019733716, -779964295, -1476250288, 174210071, 1848240816, + -417614345, -1449712719, -232573863, -1033791826, -1734572491, 2059952961, + 164824306, -1192574723, -794465893, -2100496663, 1966082659, 662383049, + -1724169177, 1397272869, 443158715, -1466228413, -1048441604, -721618311, + 607147167, 405920890, 1890695467, 1700845925, -861572606, -193465319, + -699440151, -1445722888, -1602829412, 2051117803, -720439151, -1947113131, + -390310420, -1650048864, 841983379, 476615869, -1467229630, 43603884, + -1704704811, -1363183779, 1599254898, 174995960, 1261823464, -2010724063, + -1013060202, 983314876, -1374232138, 2105244869, -1751771177, -2066157313, + -200819569, 997385318, 1618215010, -2057992268, 1973711259, -518966102, + 1974013954, -1632849536, -1429309305, -817476773, -724148800, -1290709464, +}; + +static const int32_t ref_data_real_q31[300] = { + 2147483647, 0, 0, -2147483648, 0, 0, + 227133517, 412835009, 522251308, 1043092663, 5501101, -1942347402, + -1469629150, -273374294, 244123449, 751706517, 403885384, -684891584, + -692091274, -382730503, -439140748, 1101620912, 389248308, -453836336, + -175446112, -829747342, -127199839, 594662960, 204948560, 692944595, + -276170086, 96377032, -1800913071, -241192818, 437459588, -529607120, + -251923622, -262190113, 1022818082, -585974135, 301217124, 1092994442, + 150873923, -49528761, 565798441, -814425344, -907711308, 511246386, + -1457864765, -520281398, -11054510, -838857767, 195380268, -167114671, + 277774798, -758330394, -413097603, -211112738, -598975796, -355199678, + -715212577, -977235544, 865244555, 724733391, 373813241, 951009721, + -204512565, -153298134, -611909779, -49008761, -291060404, -1074847959, + -580022372, -704800693, 872198596, 881066517, -1006907140, -354713496, + -959346833, -347829172, 973682456, -78294047, 648415134, 883509948, + 1521863913, -423256823, 736811799, 826925692, 529623244, 559772598, + -755292184, -886016120, -136425188, 515742337, 241019328, 964181075, + 134437104, -1262471265, 187705067, -715071942, -1051333353, 178667131, + 451565142, 709643787, 150148814, 731168271, 37430845, -417262982, + -1364092604, 60300071, -462363715, -247600380, 666811647, -919894384, + -47463672, -61742871, -351343248, -141610450, -646870758, -1305558164, + 541402153, 134159011, 1007355039, -1430222953, 402526872, -277737467, + -595260621, -590262248, 40777691, 5356339, 989186340, 1071636756, + 632254601, -1082489253, -1298437451, 715016248, 206927757, -172840850, + 408535159, 473172137, -693575205, 276979371, 55138220, -308079304, + -695806679, -430683500, -290851163, -279540717, 481385284, 1777128893, + 487826129, -685469096, 438334693, -923583425, 72097283, -1248693804, + -956956933, -757166358, -193059758, -270379735, -604326575, 482358807, + 1151371916, -307225981, -16175008, 41540925, 13330609, 520796836, + 421012648, -219160773, 884761869, 165994753, -977426920, 448375487, + 403176926, -1200089012, 105075249, 117017041, 1198373149, -148615963, + 375671516, -327760195, -2021563586, 314042367, -672837696, -610003656, + -575980767, 1000626962, 902135484, 981869931, 278296065, 594100942, + -62284637, 413447008, -618747339, 592907328, 848631206, 38389150, + -327299855, 321603581, -307495523, 320712277, -111080778, 1551559336, + 685013884, 943290093, 431052047, -175694308, -586976517, -1365683482, + 216518901, -419804573, -755626699, -1511160699, -162735014, 571772107, + -775346497, 341010250, -77157288, 1153372887, -107688469, -530003300, + -76422571, 209939474, 704584979, 16178994, 1250092749, -439707883, + 678302806, -476738909, -487510576, -529104015, -169292147, 1042571057, + -692253375, 432559237, -1183847163, 81143155, -680957097, 285545004, + 524365801, -184666690, 518048756, -1094374958, -960805926, 1229964365, + 1298108418, -312853206, -83004966, 307274481, 1019861483, 267170162, + -474219403, 876601527, 325743463, 1472803375, 99432249, 288123766, + 585104907, -402779940, 454455062, -506719689, -523315169, -137583247, + 328277783, -344112881, -434818374, 186729645, -405350128, -1113570680, + -1329409166, -439394384, 999381102, -666513381, -1175093926, -302813790, + -475724762, -1354051330, 356313437, 886655188, 1438174035, -451232161, + -1557657268, 733937711, -627192692, -940262921, -338396273, -519907193, + 303939122, 422738425, 781174615, 147857960, 225876137, -1213271808, + -1564346571, -119888274, -2374267, -389723543, -352742313, -679846265, +}; + +static const int32_t ref_data_imag_q31[300] = { + 2147483647, 0, 0, -2147483648, 0, 0, + -559565285, -96304105, 208797753, -642674693, -490566944, -392742579, + -418436263, 492843850, 620584002, -162479198, 418826590, 1160150687, + -967805755, 396586807, 1100948300, 989712311, -214136096, 847228834, + 203121641, 1154569860, 14555660, -100008461, -286075856, 1586750324, + -309597877, -309512615, -1151083749, -1032590567, 231162914, -635661607, + 463361482, -193920471, 429960609, 900113423, 359358464, 843071823, + -1024741292, -320011043, 342009626, 328861880, 382915408, -763571128, + 1399001890, -339399582, 36857636, 59322177, 1455710807, 115062143, + -1438551343, 874397302, -205685102, 716799334, -20254103, -553528124, + -536291697, -525357930, -645659658, -213176072, 1828272435, -245167310, + 1248353664, -324337725, 17700255, 320179058, -504376270, -363954942, + -458169790, -195040098, -183849930, 735813171, -322106397, 347147162, + -134209403, 94829069, -506355072, 1579708550, -85225073, 234516279, + 691373986, -193531340, -73111006, 703373784, -955581942, -72801318, + -21835855, -845339649, 1073602161, -1315779602, 867650731, -993252510, + 913216981, 255611262, 27603427, 356683568, -279916801, 871024871, + -1094697070, 829652208, -496983289, -322961257, -818767315, -828179307, + -617857837, -65192580, 410589148, -197677627, -606429407, 408774304, + 742886502, -245513054, -1436190292, -117648011, 1036000043, -40268923, + 244783059, -1582755347, 620154220, -1649331839, 178759335, -434382829, + -1100672538, -99093384, 674197223, 382661950, -446956360, 263846482, + 980230380, 711693717, 349500233, -525863638, 600368053, 1953007994, + -72799647, 106459459, 52445034, -1835367075, 78990495, -97093109, + 1118742449, -1517964155, 382243683, 739433759, 325265765, -226397912, + -70581334, 355822163, 72871822, -89431358, -1381948327, 532661958, + -653173437, -1440516273, 292488027, 103717969, -901845021, -333112674, + -1628393712, 149048666, -111993686, -1188203748, -208615742, -276297233, + 1210323109, 1341307345, -583520208, 645379988, 777355801, -842736915, + -621368700, -370249428, 891880910, 365508378, -848885248, 766553273, + -581441779, -281824144, -699077833, 694948377, -927875295, 368213597, + 1660525845, 149707323, -380948545, -799265774, -1074980521, -165496382, + -147594648, -112789928, 863668896, -248862040, 628846604, 640425039, + 820448354, -211681376, -740084708, 312738847, 173562512, 943422218, + 1229312467, -792516412, 346118166, -100756941, 217937665, 819953632, + -1601254882, 500599905, -294166579, -498559935, 1095565350, 815668770, + -535341074, 43580441, 904019327, -743461617, -17201447, -182743951, + 553699416, -375640095, -892928649, -441683350, 227983763, -540610658, + 474935830, -333603080, -424792649, -399092871, -119151422, 820425566, + 713945474, 272795891, -84674365, 182066866, -1000584161, -657732993, + -699966976, 940179287, -657826657, -236137119, -728609646, -69045061, + -607405437, 667961820, 104267923, 175989682, -1121244989, -1155241356, + 38754136, -517775113, -1245148200, -1078762776, -356581952, -30883685, + 967921175, -474903778, 114129770, 215269333, 1825674944, -340098353, + -1249330817, 673126435, -123235769, -205478160, 922577240, 1334018723, + -399458635, 198782896, -189634681, -315669959, 1004588949, -212303121, + -489544564, 253688105, -1468848352, -191301546, -154049902, 520347408, + -467992488, -327682427, -217385287, -570894540, 1902191749, 773947660, + 804926920, -1445127833, 439381345, -201082370, -258148124, -1598761774, + -362714962, 871047441, 1465681476, -944111679, 439288366, -312653460, +}; diff --git a/test/cmocka/src/math/fft/ref_fft_multi.m b/test/cmocka/src/math/fft/ref_fft_multi.m new file mode 100644 index 000000000000..57b1218f64dc --- /dev/null +++ b/test/cmocka/src/math/fft/ref_fft_multi.m @@ -0,0 +1,138 @@ +% ref_sofm_dft3 - Generate C header files for DFT3 function unit tests + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright(c) 2025 Intel Corporation. All rights reserved. + +function ref_fft_multi() + + rand('twister', 0); % Set seed to produce same test vectors every time + path(path(), '../../../m'); + opt.describe = export_get_git_describe(); + opt.bits = 32; + opt.fs = 48e3; + opt.ifft = 0; + opt.sine = 1; + opt.rand = 0; + opt.dc = 0; + opt.num_tests = 1; + + N = 96; + make_fft_multi_test_vectors(opt, N); + + N = 512; + make_fft_multi_test_vectors(opt, N); + + N = 768; + make_fft_multi_test_vectors(opt, N); + + N = 1024; + make_fft_multi_test_vectors(opt, N); + + N = 1536; + make_fft_multi_test_vectors(opt, N); + + N = 3072; + make_fft_multi_test_vectors(opt, N); + + opt.ifft = 1; + opt.dc = 0; + opt.sine = 1; + opt.rand = 0; + + N = 24; + make_fft_multi_test_vectors(opt, N); + + N = 256; + make_fft_multi_test_vectors(opt, N); + + N = 1024; + make_fft_multi_test_vectors(opt, N); + + N = 1536; + make_fft_multi_test_vectors(opt, N); + + N = 3072; + make_fft_multi_test_vectors(opt, N); + +end + +function make_fft_multi_test_vectors(opt, N) + + scale_q = 2^(opt.bits - 1); + min_int = int32(-scale_q); + max_int = int32(scale_q - 1); + n = 1; + + input_data_real_q = int32(zeros(N, opt.num_tests)); + input_data_imag_q = int32(zeros(N, opt.num_tests)); + + if opt.dc + input_data_real_q(:,n) = int32(ones(N, 1) * scale_q / N); + n = n + 1; + end + if opt.rand + input_data_real_q(:,n) = int32(2 * (rand(N, 1) - 1) * scale_q * 0.1); + input_data_imag_q(:,n) = int32(2 * (rand(N, 1) - 1) * scale_q * 0.1); + n = n + 1; + end + if opt.sine + ft = 997; + t = (0:(N - 1))'/opt.fs; + x = 10^(-1 / 20) * sin(2 * pi * ft * t) .* kaiser(N, 20); + dither = scale_q / 2^19 * (rand(N, 1) + rand(N, 1) - 1); + input_data_real_q(:,n) = int32(x * scale_q + dither); + if opt.ifft + tmp_fft = fft(double(input_data_real_q(:,n)) / scale_q) / N; + input_data_real_q(:,n) = int32(real(tmp_fft) * scale_q); + input_data_imag_q(:,n) = int32(imag(tmp_fft) * scale_q); + end + n = n + 1; + end + + if opt.ifft + N_half = N/2 + 1; + for i = 1:opt.num_tests + input_data_real_q(N_half + 1:end) = input_data_real_q(N_half - 1:-1:2); + input_data_imag_q(N_half + 1:end) = -input_data_imag_q(N_half - 1:-1:2); + end + end + + input_data_real_f = double(input_data_real_q) / scale_q; + input_data_imag_f = double(input_data_imag_q) / scale_q; + input_data_f = complex(input_data_real_f, input_data_imag_f); + + ref_data_f = zeros(N, opt.num_tests); + for i = 1:opt.num_tests + if opt.ifft + ref_data_f(:,i) = ifft(input_data_f(:,i)) * N; + test_type = 'ifft'; + else + ref_data_f(:,i) = fft(input_data_f(:,i)) / N; + test_type = 'fft'; + end + end + + input_data_vec_f = reshape(input_data_f, N * opt.num_tests, 1); + input_data_real_q = int32(real(input_data_vec_f) * scale_q); + input_data_imag_q = int32(imag(input_data_vec_f) * scale_q); + + ref_data_vec_f = reshape(ref_data_f, N * opt.num_tests, 1); + ref_data_real_q = int32(real(ref_data_vec_f) * scale_q); + ref_data_imag_q = int32(imag(ref_data_vec_f) * scale_q); + + header_fn = sprintf('ref_%s_multi_%d_%d.h', test_type, N, opt.bits); + fh = export_headerfile_open(header_fn); + comment = sprintf('Created %s with script ref_fft_multi.m %s', ... + datestr(now, 0), opt.describe); + export_comment(fh, comment); + dstr = sprintf('REF_SOFM_%s_MULTI_%d_NUM_TESTS', upper(test_type), N); + export_ndefine(fh, dstr, opt.num_tests); + qbits = opt.bits-1; + vstr = sprintf('%s_in_real_%d_q%d', test_type, N, qbits); export_vector(fh, opt.bits, vstr, input_data_real_q); + vstr = sprintf('%s_in_imag_%d_q%d', test_type, N, qbits); export_vector(fh, opt.bits, vstr, input_data_imag_q); + vstr = sprintf('%s_ref_real_%d_q%d', test_type, N, qbits); export_vector(fh, opt.bits, vstr, ref_data_real_q); + vstr = sprintf('%s_ref_imag_%d_q%d', test_type, N, qbits); export_vector(fh, opt.bits, vstr, ref_data_imag_q); + fclose(fh); + fprintf(1, 'Exported %s.\n', header_fn); +end diff --git a/test/cmocka/src/math/fft/ref_fft_multi_1024_32.h b/test/cmocka/src/math/fft/ref_fft_multi_1024_32.h new file mode 100644 index 000000000000..e9482fd88f05 --- /dev/null +++ b/test/cmocka/src/math/fft/ref_fft_multi_1024_32.h @@ -0,0 +1,704 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 20-Nov-2025 16:11:52 with script ref_fft_multi.m v1.9-rc1-6882-ge0b90b605-dirty */ + +#define REF_SOFM_FFT_MULTI_1024_NUM_TESTS 1 + +static const int32_t fft_in_real_1024_q31[1024] = { + -368, 399, 1137, -1510, 917, -915, + 1477, 4004, 26, -670, 19, -245, + 2071, 2623, -2126, 2311, 2688, 609, + -1461, 4166, -310, 1858, -248, -2221, + 2398, -796, -698, -2996, -2571, -2483, + -6926, -3796, -6581, -7667, -9040, -7126, + -9738, -14377, -11690, -11331, -14016, -14971, + -16347, -13087, -10581, -9389, -7947, -3776, + -2708, 3498, 9037, 13136, 16328, 23190, + 32849, 35886, 48147, 54704, 58656, 61210, + 72193, 75724, 79356, 83168, 79591, 79627, + 74772, 71013, 60544, 48856, 38174, 19894, + 7444, -19623, -39518, -64353, -90252, -120797, + -153590, -180846, -212338, -240701, -268837, -292589, + -315071, -330749, -341626, -350148, -349717, -341020, + -321991, -296385, -259725, -214521, -161010, -95406, + -24910, 56696, 146420, 244250, 343559, 452730, + 558328, 663250, 762184, 865981, 953691, 1033614, + 1102113, 1146873, 1184623, 1193892, 1178554, 1142859, + 1077203, 986336, 862134, 713246, 531955, 325661, + 92277, -163732, -444123, -741602, -1049074, -1363826, + -1673315, -1986171, -2284459, -2565083, -2814370, -3040133, + -3213891, -3347594, -3418856, -3434223, -3384851, -3262396, + -3066903, -2788032, -2437241, -2010678, -1507173, -933398, + -292175, 401186, 1147352, 1924628, 2732596, 3549354, + 4364626, 5154297, 5908401, 6604560, 7227639, 7762620, + 8187446, 8485952, 8644128, 8647068, 8487648, 8152221, + 7637666, 6938503, 6053636, 4993121, 3757798, 2362454, + 824586, -836731, -2601505, -4437764, -6320658, -8213153, + -10084097, -11885518, -13592349, -15153379, -16539412, -17701707, + -18614256, -19232046, -19532284, -19487537, -19071832, -18272835, + -17080871, -15486581, -13507411, -11145107, -8429888, -5384383, + -2046831, 1539831, 5322377, 9232369, 13214694, 17192520, + 21092853, 24835370, 28351421, 31545946, 34345883, 36680788, + 38470656, 39655664, 40177693, 39987331, 39049848, 37341196, + 34842396, 31562278, 27514832, 22737753, 17268732, 11184374, + 4553185, -2521582, -9942347, -17586988, -25318003, -33004376, + -40502110, -47661459, -54324353, -60352266, -65595404, -69912251, + -73185900, -75289166, -76129593, -75628186, -73725851, -70384308, + -65592931, -59374400, -51767812, -42836205, -32691229, -21454188, + -9277580, 3661148, 17155201, 30992883, 44929675, 58721466, + 72101400, 84812804, 96588363, 107172798, 116308292, 123771871, + 129349707, 132844569, 134111243, 133017754, 129482950, 123461622, + 114953182, 103996453, 90695125, 75177530, 57638338, 38301433, + 17446062, -4619599, -27538997, -50938883, -74412221, -97544926, + -119890697, -141021854, -160509246, -177915765, -192864953, -204975605, + -213910563, -219386073, -221174163, -219080029, -213000947, -202885489, + -188762284, -170723570, -148948541, -123686136, -95259386, -64055427, + -30526184, 4796392, 41356982, 78546374, 115716100, 152196811, + 187309768, 220376926, 250730546, 277732060, 300774553, 319307850, + 332839493, 340957166, 343321132, 339690110, 329923997, 313993109, + 291964388, 264026987, 230483360, 191744445, 148326011, 100855269, + 50040078, -3320582, -58361692, -114153996, -169724988, -224082501, + -276218832, -325139925, -369868955, -409475994, -443108525, -469982022, + -489407140, -500819525, -503770287, -497957407, -483219505, -459561117, + -427126685, -386245337, -337398907, -281210112, -218478327, -150122739, + -77193519, -857934, 77633280, 156947583, 235700971, 312486893, + 385900471, 454546040, 517078779, 572234396, 618846940, 655866323, + 682385018, 697661309, 701140616, 692455705, 671454559, 638191695, + 592953243, 536228161, 468740763, 391410722, 305371394, 211913742, + 112517115, 8779394, -97571576, -204721044, -310812944, -413944482, + -512242592, -603866176, -687055198, -760155313, -821656150, -870226938, + -904719195, -924232004, -928094286, -915902067, -887526961, -843128897, + -783147032, -708310751, -619625914, -518372450, -406053401, -284426943, + -155438894, -21198654, 116042557, 253946179, 390103902, 522103112, + 647549938, 764131222, 869639373, 962024696, 1039435602, 1100238386, + 1143082131, 1166889988, 1170916785, 1154742462, 1118300936, 1061877010, + 986124238, 892031533, 780943280, 654515630, 514699010, 363722438, + 204041308, 38296251, -130713333, -300089725, -466886857, -628155818, + -781011029, -922654557, -1050458538, -1161990550, -1255074187, -1327830448, + -1378699528, -1406489333, -1410401993, -1390048875, -1345442734, -1277046744, + -1185735381, -1072791871, -939913349, -789148010, -622904148, -443859970, + -254989459, -59453972, 139440960, 338268373, 533579021, 721939184, + 899993480, 1064547333, 1212580705, 1341356167, 1448429738, 1531710189, + 1589513254, 1620570159, 1624075071, 1599693216, 1547576100, 1468358349, + 1363160695, 1233557983, 1081585799, 909666978, 720606772, 517535787, + 303843415, 83155845, -140774037, -364089673, -582915806, -793434722, + -991929280, -1174879622, -1339004843, -1481331242, -1599239695, -1690521084, + -1753414617, -1786655673, -1789471827, -1761622946, -1703404590, -1615638103, + -1499681710, -1357368825, -1191014889, -1003370614, -797569666, -577065119, + -345612065, -107143552, 134247659, 374406599, 609174673, 834479923, + 1046391045, 1241200833, 1415476892, 1566138455, 1690498403, 1786340377, + 1851905391, 1885980406, 1887879581, 1857497280, 1795259750, 1702182967, + 1579787973, 1430138425, 1255747801, 1059596968, 845018463, 615693435, + 375556538, 128723997, -120541681, -367952127, -609245853, -840251626, + -1056983758, -1255713119, -1433002929, -1585806827, -1711487302, -1807896047, + -1873374729, -1906818169, -1907682853, -1875971972, -1812263992, -1717703065, + -1593954268, -1443193039, -1268056578, -1071600342, -857256745, -628746553, + -390033866, -145248896, 101367834, 345584281, 583192434, 810121403, + 1022514754, 1216749114, 1389559178, 1538036051, 1659720826, 1752625201, + 1815263564, 1846687542, 1846482241, 1814804568, 1752335291, 1660298657, + 1540415690, 1394895914, 1226369062, 1037859231, 832714547, 614553921, + 387208246, 154635241, -79138710, -310077686, -534233497, -747807910, + -947188843, -1129059176, -1290398152, -1428596523, -1541438634, -1627173606, + -1684538320, -1712767041, -1711595046, -1681286807, -1622597001, -1536771335, + -1425516195, -1290963285, -1135617456, -962344519, -774276536, -574780100, + -367390670, -155754790, 56472073, 265619298, 468138053, 660610367, + 839838555, 1002881515, 1147110243, 1270246183, 1370408966, 1446132923, + 1496387070, 1520594854, 1518642268, 1490871859, 1438060822, 1361413472, + 1262533951, 1143393613, 1006287680, 853798274, 688736004, 514105396, + 333012732, 148667398, -35733530, -217014467, -392110758, -558100965, + -712261129, -852105187, -975443549, -1080391668, -1165419174, -1229358286, + -1271414669, -1291210466, -1288731328, -1264359862, -1218860857, -1153341530, + -1069241701, -968310686, -852532664, -724155275, -585580585, -439357512, + -288125820, -134567565, 18641167, 168876530, 313606578, 450450547, + 577187923, 691823560, 792614885, 878071523, 947009493, 998553637, + 1032138861, 1047522337, 1044786400, 1024325396, 986827656, 933271381, + 864889514, 783149214, 689722654, 586443194, 475288458, 358321978, + 237687607, 115515445, -6047806, -124934122, -239156594, -346852125, + -446302911, -535987147, -614574458, -680951101, -734251225, -773853212, + -799381512, -810715674, -807980350, -791554564, -762030650, -720222509, + -667136883, -603952781, -532002178, -452725279, -367667954, -278430473, + -186653775, -93972100, -2008492, 87674367, 173587352, 254349650, + 328707091, 395532579, 453881657, 502968672, 542187532, 571122852, + 589545497, 597423743, 594906342, 582312760, 560132475, 529012045, + 489738788, 443207538, 390429237, 332480939, 270507669, 205698013, + 139248854, 72343880, 6161787, -58185019, -119638793, -177222667, + -230069141, -277392475, -318549855, -353017704, -380401245, -400449224, + -413034731, -418173539, -416007937, -406810636, -390947543, -368915371, + -341281976, -308709781, -271917570, -231677874, -188800752, -144107774, + -98436708, -52602612, -7411234, 36384414, 78073041, 117002200, + 152593715, 184344809, 211842274, 234752359, 252842032, 265962120, + 274065260, 277185824, 275449286, 269054677, 258286311, 243480550, + 225049447, 203437341, 179141946, 152679159, 124587493, 95420206, + 65717940, 36017421, 6836042, -21343530, -48068436, -72924828, + -95564270, -115673579, -133003852, -147361340, -158615881, -166696411, + -171587602, -173332374, -172021708, -167813897, -160892709, -151487639, + -139867533, -126332160, -111186743, -94771864, -77414398, -59468599, + -41264688, -23136882, -5393390, 11673173, 27787932, 42720560, + 56258677, 68224110, 78480457, 86924579, 93484306, 98135239, + 100882999, 101760369, 100841495, 98224064, 94030202, 88408482, + 81519998, 73548785, 64683174, 55119877, 45056490, 34697694, + 24240625, 13872761, 3766924, -5911143, -15005474, -23390680, + -30955991, -37604248, -43269353, -47895977, -51454249, -53937007, + -55362525, -55747797, -55145509, -53618025, -51236984, -48085430, + -44268219, -39886204, -35034027, -29836702, -24398794, -18829886, + -13230267, -7714345, -2360118, 2740293, 7512401, 11880497, + 15801966, 19227412, 22118471, 24467824, 26244407, 27468824, + 28135353, 28271925, 27906481, 27074587, 25818645, 24179863, + 22210583, 19974799, 17518427, 14905291, 12182096, 9415316, + 6650447, 3941996, 1322253, -1147115, -3452698, -5548001, + -7414029, -9030592, -10383149, -11471664, -12284872, -12825237, + -13105151, -13137584, -12935370, -12509734, -11898201, -11110368, + -10182305, -9134505, -7994237, -6789150, -5547559, -4288857, + -3040785, -1826870, -664203, 428580, 1435486, 2347513, + 3156311, 3844950, 4416372, 4868942, 5201790, 5414675, + 5520660, 5510424, 5404147, 5214941, 4938663, 4597616, + 4199190, 3756301, 3279832, 2777704, 2263902, 1749437, + 1241556, 754804, 295430, -138960, -532715, -883294, + -1191253, -1456374, -1673086, -1837247, -1953436, -2026864, + -2056034, -2045306, -1996661, -1918087, -1810768, -1676714, + -1527078, -1358080, -1181368, -994156, -808485, -625825, + -444558, -269900, -109532, 35633, 171250, 289167, + 391357, 477326, 547758, 597162, 631158, 651246, + 658747, 652056, 630488, 604961, 565338, 524089, + 468544, 414088, 361691, 302709, 245522, 189197, + 133521, 86065, 35459, -10093, -45678, -78284, + -107849, -127244, -147945, -159990, -166806, -172400, + -172766, -166698, -161371, -155608, -142927, -131151, + -117442, -103171, -87695, -73917, -59685, -43890, + -32345, -17413, -8851, 1262, 10615, 13688, + 22228, 26986, 33290, 32113, 31330, 36857, + 35941, 33027, 31131, 28558, 25825, 25129, + 20114, 20537, 15259, 10616, 7286, 6079, + 2197, 1142, 1303, 2290, -964, -3359, + -1473, -2972, -5153, -4402, -4875, -2764, + -2954, -2435, -6289, -2906, -1971, -1469, + -1069, -1732, -1718, -2575, -802, -2749, + 882, 1954, 1617, -292, -6, 2813, + 1640, -2041, -979, -122, -997, 1850, + 717, 1785, 1849, 1967, +}; + +static const int32_t fft_in_imag_1024_q31[1024] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +}; + +static const int32_t fft_ref_real_1024_q31[1024] = { + 28, -16, 40, -36, -11, 23, + -2, 7, 65, 28, -27, 3, + 62, -17, 36, 122, -55154, 1535502, + -13543813, 57130836, -135763827, 195823639, -176199334, 98119761, + -32279433, 5635597, -409816, 6072, -21, -83, + -21, 67, -30, -1, 1, 3, + 42, -5, 77, 67, -11, -9, + 24, -27, -78, -11, 18, -61, + -28, 16, -7, 46, -11, 10, + -8, -47, 95, 12, -3, -22, + -8, -46, 24, 59, -6, 32, + 26, 18, 35, 8, 52, -23, + -67, -17, -26, -3, -10, -47, + 32, 35, -9, 38, 14, 30, + 36, 2, -7, 63, 32, -84, + 30, 19, -9, 6, 43, 11, + -2, -5, -47, -43, 4, 8, + -22, -6, -30, -63, -43, -14, + 20, 2, 86, -5, 39, -58, + 37, -42, -4, 27, 0, -16, + -30, 20, -67, -31, 40, -74, + 57, -62, -8, -6, 23, 13, + 3, 21, -51, 10, 64, -25, + 11, -3, 12, 38, -22, 18, + -5, 0, 41, -14, 30, -16, + -11, 11, -18, 36, -29, -54, + 20, -14, -6, -28, 21, 15, + 78, -17, 48, -23, -13, 16, + 27, -22, -12, -2, -85, -4, + -23, -43, 64, 6, 1, 31, + 35, 19, 23, -1, 22, 54, + 18, 6, -25, -42, 2, 41, + -18, -40, -43, 31, -26, 37, + -34, 13, 7, -16, 9, 72, + 38, 2, 44, -54, -28, -56, + 1, -58, 51, 59, 84, -48, + 39, -80, 6, 21, -6, 21, + -25, -24, -54, -67, -1, 11, + 4, -80, 3, -12, -24, -59, + -3, 57, -9, -36, -24, -28, + -31, -19, -40, -24, 4, -9, + 5, -64, -16, 25, 19, 53, + 2, -60, 48, -25, 55, -27, + 61, 17, 43, 36, -15, 6, + -98, -38, -4, 63, -14, 57, + 7, 19, -6, 12, -18, 51, + -48, 39, 4, -63, -3, -1, + -59, -15, 16, 61, -8, 12, + 5, 29, -38, 65, 29, -10, + -25, -19, 22, 17, -53, 12, + -29, 13, 7, -8, -27, 3, + 62, -4, -29, -35, 9, 40, + -69, 9, -23, 18, 21, -92, + -42, 20, -15, 5, 26, 20, + 32, 59, -17, 25, -3, 57, + -40, 9, 8, 90, -40, 16, + -119, -32, 26, -35, 18, 21, + -22, 45, 17, 29, -24, -14, + -44, -29, -59, -6, 17, -7, + -33, -37, 14, -53, 16, -17, + -59, -20, -24, -19, -58, -21, + 11, -12, 10, -13, 22, -18, + 4, -30, 53, -46, -6, -51, + 45, -21, 46, -1, 14, -22, + -33, -25, -28, 30, 1, 45, + 78, 6, -26, -6, 17, -27, + 52, -9, 20, -40, -3, 16, + 36, -21, -60, 2, 16, -56, + 13, 0, 20, -3, 46, -8, + -65, -2, -26, -27, 38, -41, + 32, -11, 6, 12, 55, -22, + 23, 47, 56, 25, -4, -27, + -14, -26, 17, -49, -5, 49, + -16, 29, -42, 51, -14, 56, + 18, -62, -31, -10, -38, -22, + -56, -60, -39, 42, 9, 90, + 29, 79, 27, 2, -27, -60, + -20, 7, 26, -6, 86, -94, + 0, -31, 7, -22, 46, 44, + 22, -64, 25, 47, -49, -24, + 62, 5, 7, -59, 40, -3, + -27, 16, 7, -32, -20, -41, + 84, -36, 21, -81, 96, 48, + 58, 16, -48, -16, -72, 29, + 36, 21, -30, -21, -55, 68, + -20, -40, -24, -40, -20, 68, + -55, -21, -30, 21, 36, 29, + -72, -16, -48, 16, 58, 48, + 96, -81, 21, -36, 84, -41, + -20, -32, 7, 16, -27, -3, + 40, -59, 7, 5, 62, -24, + -49, 47, 25, -64, 22, 44, + 46, -22, 7, -31, 0, -94, + 86, -6, 26, 7, -20, -60, + -27, 2, 27, 79, 29, 90, + 9, 42, -39, -60, -56, -22, + -38, -10, -31, -62, 18, 56, + -14, 51, -42, 29, -16, 49, + -5, -49, 17, -26, -14, -27, + -4, 25, 56, 47, 23, -22, + 55, 12, 6, -11, 32, -41, + 38, -27, -26, -2, -65, -8, + 46, -3, 20, 0, 13, -56, + 16, 2, -60, -21, 36, 16, + -3, -40, 20, -9, 52, -27, + 17, -6, -26, 6, 78, 45, + 1, 30, -28, -25, -33, -22, + 14, -1, 46, -21, 45, -51, + -6, -46, 53, -30, 4, -18, + 22, -13, 10, -12, 11, -21, + -58, -19, -24, -20, -59, -17, + 16, -53, 14, -37, -33, -7, + 17, -6, -59, -29, -44, -14, + -24, 29, 17, 45, -22, 21, + 18, -35, 26, -32, -119, 16, + -40, 90, 8, 9, -40, 57, + -3, 25, -17, 59, 32, 20, + 26, 5, -15, 20, -42, -92, + 21, 18, -23, 9, -69, 40, + 9, -35, -29, -4, 62, 3, + -27, -8, 7, 13, -29, 12, + -53, 17, 22, -19, -25, -10, + 29, 65, -38, 29, 5, 12, + -8, 61, 16, -15, -59, -1, + -3, -63, 4, 39, -48, 51, + -18, 12, -6, 19, 7, 57, + -14, 63, -4, -38, -98, 6, + -15, 36, 43, 17, 61, -27, + 55, -25, 48, -60, 2, 53, + 19, 25, -16, -64, 5, -9, + 4, -24, -40, -19, -31, -28, + -24, -36, -9, 57, -3, -59, + -24, -12, 3, -80, 4, 11, + -1, -67, -54, -24, -25, 21, + -6, 21, 6, -80, 39, -48, + 84, 59, 51, -58, 1, -56, + -28, -54, 44, 2, 38, 72, + 9, -16, 7, 13, -34, 37, + -26, 31, -43, -40, -18, 41, + 2, -42, -25, 6, 18, 54, + 22, -1, 23, 19, 35, 31, + 1, 6, 64, -43, -23, -4, + -85, -2, -12, -22, 27, 16, + -13, -23, 48, -17, 78, 15, + 21, -28, -6, -14, 20, -54, + -29, 36, -18, 11, -11, -16, + 30, -14, 41, 0, -5, 18, + -22, 38, 12, -3, 11, -25, + 64, 10, -51, 21, 3, 13, + 23, -6, -8, -62, 57, -74, + 40, -31, -67, 20, -30, -16, + 0, 27, -4, -42, 37, -58, + 39, -5, 86, 2, 20, -14, + -43, -63, -30, -6, -22, 8, + 4, -43, -47, -5, -2, 11, + 43, 6, -9, 19, 30, -84, + 32, 63, -7, 2, 36, 30, + 14, 38, -9, 35, 32, -47, + -10, -3, -26, -17, -67, -23, + 52, 8, 35, 18, 26, 32, + -6, 59, 24, -46, -8, -22, + -3, 12, 95, -47, -8, 10, + -11, 46, -7, 16, -28, -61, + 18, -11, -78, -27, 24, -9, + -11, 67, 77, -5, 42, 3, + 1, -1, -30, 67, -21, -83, + -21, 6072, -409816, 5635597, -32279433, 98119761, + -176199334, 195823639, -135763827, 57130836, -13543813, 1535502, + -55154, 122, 36, -17, 62, 3, + -27, 28, 65, 7, -2, 23, + -11, -36, 40, -16, +}; + +static const int32_t fft_ref_imag_1024_q31[1024] = { + 0, -7, -54, 77, 13, 24, + 39, -30, 30, -28, -25, 2, + 30, -15, 23, -34, 50485, -1395758, + 12235464, -51294594, 121144577, -173660896, 155294491, -85945123, + 28099645, -4875526, 352336, -5061, -5, 10, + -18, 14, -31, -55, 65, -37, + 34, -52, -5, 56, -13, -45, + -15, -15, 11, 44, -21, 3, + 55, 54, 61, -36, -27, -47, + -44, 19, -26, -13, 12, -45, + 35, 51, -67, -9, 11, -54, + 28, 92, 15, -32, -46, 10, + -8, -15, -6, 7, 14, 68, + -19, -68, 20, 27, -51, 92, + 4, -11, 39, -15, 36, -38, + 6, -8, 11, 45, 27, 13, + 24, 48, -2, 20, 6, 3, + -9, 4, 86, 10, 11, 8, + -45, 80, 28, -23, 7, 11, + 6, -50, -66, 34, 102, 95, + 8, 36, 2, -72, -22, 55, + -21, 24, -5, 1, 35, -3, + -68, -20, -2, -7, 49, -65, + -34, -15, 19, 108, 55, 9, + 16, -24, 2, -18, -18, 37, + 67, 16, 15, -11, -7, -23, + 25, -8, 8, -20, 10, 41, + 32, -9, -81, -12, -29, 47, + 5, -31, -17, -67, -17, -32, + 16, -47, 12, -30, 18, -23, + -20, 14, 21, 27, 2, -99, + -28, 22, -11, 8, -15, -44, + -8, -2, 1, -46, 61, -16, + 30, 18, 14, 8, 29, 16, + -69, 29, -43, -33, -2, 23, + 53, -71, -51, -10, -1, -29, + 33, -7, -43, -25, 47, -49, + 44, 17, -16, 55, 53, 48, + 32, 60, -15, -15, 34, -31, + -34, 36, -11, 22, 18, 7, + 49, 48, -19, -70, 50, -15, + -91, 75, 4, -14, 36, 14, + -1, 16, 2, -3, -49, 29, + 44, 64, -74, 11, 42, 11, + -12, -64, -76, -11, 2, -35, + 22, -48, -39, -31, -33, -18, + -33, 34, 8, 66, 43, 8, + -2, 39, 29, -16, 3, 28, + 8, -50, -54, 41, 14, -34, + -2, -33, 23, -8, 21, -29, + 13, 62, 9, -21, -30, 31, + 56, 44, 14, 20, 12, -8, + -2, -7, -1, 40, 30, -1, + 22, -43, 88, 68, 36, -51, + -75, 21, -61, -40, -12, -8, + -57, 5, -1, 28, -41, -17, + 22, 34, -63, -27, 24, 57, + -86, -4, -16, -53, 15, 26, + 14, -27, -23, -48, 16, -28, + -6, -37, 38, -39, -2, 32, + -56, 40, 15, -26, -73, -21, + 28, -62, 4, 76, 23, 49, + -1, -40, 51, -29, 4, 49, + 5, -3, -36, 41, 27, -16, + -11, -47, -12, 4, 2, 32, + -79, 67, -24, 45, 23, -15, + 66, -7, 60, -76, -17, -45, + -20, 17, -3, -13, 2, 9, + 19, 16, 6, -29, 23, -15, + 98, 3, 11, 22, 38, -10, + 2, -12, 20, 32, 30, 34, + 54, 47, -25, -15, -75, 38, + -10, 49, 28, -81, -1, 21, + 6, 39, -68, -31, -11, -45, + -19, 10, -27, -11, 29, -26, + 39, 3, -53, 17, 111, 58, + -3, -27, -26, -16, 57, 19, + 5, 34, 17, 68, -22, 31, + 28, 8, 36, 10, -52, 43, + 4, 35, -34, 2, -8, 40, + 33, -68, -35, 32, 4, 38, + -27, -24, 30, -15, 1, -35, + -19, -33, 43, 9, 15, -30, + -38, -10, -4, -48, 17, -12, + 20, -20, 40, -60, 27, 12, + 47, -13, 0, 13, -47, -12, + -27, 60, -40, 20, -20, 12, + -17, 48, 4, 10, 38, 30, + -15, -9, -43, 33, 19, 35, + -1, 15, -30, 24, 27, -38, + -4, -32, 35, 68, -33, -40, + 8, -2, 34, -35, -4, -43, + 52, -10, -36, -8, -28, -31, + 22, -68, -17, -34, -5, -19, + -57, 16, 26, 27, 3, -58, + -111, -17, 53, -3, -39, 26, + -29, 11, 27, -10, 19, 45, + 11, 31, 68, -39, -6, -21, + 1, 81, -28, -49, 10, -38, + 75, 15, 25, -47, -54, -34, + -30, -32, -20, 12, -2, 10, + -38, -22, -11, -3, -98, 15, + -23, 29, -6, -16, -19, -9, + -2, 13, 3, -17, 20, 45, + 17, 76, -60, 7, -66, 15, + -23, -45, 24, -67, 79, -32, + -2, -4, 12, 47, 11, 16, + -27, -41, 36, 3, -5, -49, + -4, 29, -51, 40, 1, -49, + -23, -76, -4, 62, -28, 21, + 73, 26, -15, -40, 56, -32, + 2, 39, -38, 37, 6, 28, + -16, 48, 23, 27, -14, -26, + -15, 53, 16, 4, 86, -57, + -24, 27, 63, -34, -22, 17, + 41, -28, 1, -5, 57, 8, + 12, 40, 61, -21, 75, 51, + -36, -68, -88, 43, -22, 1, + -30, -40, 1, 7, 2, 8, + -12, -20, -14, -44, -56, -31, + 30, 21, -9, -62, -13, 29, + -21, 8, -23, 33, 2, 34, + -14, -41, 54, 50, -8, -28, + -3, 16, -29, -39, 2, -8, + -43, -66, -8, -34, 33, 18, + 33, 31, 39, 48, -22, 35, + -2, 11, 76, 64, 12, -11, + -42, -11, 74, -64, -44, -29, + 49, 3, -2, -16, 1, -14, + -36, 14, -4, -75, 91, 15, + -50, 70, 19, -48, -49, -7, + -18, -22, 11, -36, 34, 31, + -34, 15, 15, -60, -32, -48, + -53, -55, 16, -17, -44, 49, + -47, 25, 43, 7, -33, 29, + 1, 10, 51, 71, -53, -23, + 2, 33, 43, -29, 69, -16, + -29, -8, -14, -18, -30, 16, + -61, 46, -1, 2, 8, 44, + 15, -8, 11, -22, 28, 99, + -2, -27, -21, -14, 20, 23, + -18, 30, -12, 47, -16, 32, + 17, 67, 17, 31, -5, -47, + 29, 12, 81, 9, -32, -41, + -10, 20, -8, 8, -25, 23, + 7, 11, -15, -16, -67, -37, + 18, 18, -2, 24, -16, -9, + -55, -108, -19, 15, 34, 65, + -49, 7, 2, 20, 68, 3, + -35, -1, 5, -24, 21, -55, + 22, 72, -2, -36, -8, -95, + -102, -34, 66, 50, -6, -11, + -7, 23, -28, -80, 45, -8, + -11, -10, -86, -4, 9, -3, + -6, -20, 2, -48, -24, -13, + -27, -45, -11, 8, -6, 38, + -36, 15, -39, 11, -4, -92, + 51, -27, -20, 68, 19, -68, + -14, -7, 6, 15, 8, -10, + 46, 32, -15, -92, -28, 54, + -11, 9, 67, -51, -35, 45, + -12, 13, 26, -19, 44, 47, + 27, 36, -61, -54, -55, -3, + 21, -44, -11, 15, 15, 45, + 13, -56, 5, 52, -34, 37, + -65, 55, 31, -14, 18, -10, + 5, 5061, -352336, 4875526, -28099645, 85945123, + -155294491, 173660896, -121144577, 51294594, -12235464, 1395758, + -50485, 34, -23, 15, -30, -2, + 25, 28, -30, 30, -39, -24, + -13, -77, 54, 7, +}; diff --git a/test/cmocka/src/math/fft/ref_fft_multi_1536_32.h b/test/cmocka/src/math/fft/ref_fft_multi_1536_32.h new file mode 100644 index 000000000000..3b80ddea426a --- /dev/null +++ b/test/cmocka/src/math/fft/ref_fft_multi_1536_32.h @@ -0,0 +1,1044 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 20-Nov-2025 16:11:52 with script ref_fft_multi.m v1.9-rc1-6882-ge0b90b605-dirty */ + +#define REF_SOFM_FFT_MULTI_1536_NUM_TESTS 1 + +static const int32_t fft_in_real_1536_q31[1536] = { + -1307, -574, -1210, -1522, -1899, 1071, + 855, 2163, 1521, 2259, 1260, -2999, + 433, 1384, -1287, -2171, 1479, 1583, + -1436, 1011, 4189, 2711, -946, -195, + -2543, 1178, -1736, 772, 1522, -171, + -1454, -1564, -1958, -4470, -3253, -3927, + -4950, -5304, -4795, -3937, -4683, -5511, + -5491, -2036, -46, -2309, -4636, 183, + 1165, 889, 2769, 2573, 4187, 7141, + 10550, 8534, 13292, 12890, 13854, 14933, + 14481, 13572, 19470, 17619, 19996, 15501, + 14335, 15941, 10852, 9125, 9930, 6717, + 3435, -122, -7217, -14931, -15699, -19050, + -28226, -29840, -39221, -38444, -45330, -48565, + -53919, -51940, -56165, -59291, -56469, -54002, + -50482, -46240, -39727, -31555, -24931, -13667, + -4067, 7601, 19601, 36606, 49720, 66264, + 82262, 93798, 109492, 123549, 138328, 146587, + 153740, 163017, 163203, 163630, 160765, 157379, + 146736, 132520, 113001, 93878, 69705, 39592, + 12865, -21580, -56672, -95272, -131691, -174549, + -213209, -248628, -283486, -320449, -346051, -370771, + -392071, -407380, -415127, -415461, -403141, -387183, + -367199, -327447, -286189, -235079, -175686, -108377, + -31956, 45401, 128250, 217821, 312206, 403171, + 493176, 576281, 661962, 734196, 802037, 857666, + 899782, 931826, 947158, 943468, 922552, 883848, + 826153, 747513, 653458, 535042, 402552, 250199, + 86048, -86449, -277634, -465706, -659677, -859066, + -1050155, -1237367, -1413054, -1568939, -1705530, -1823177, + -1913070, -1972205, -1997013, -1988742, -1939559, -1853061, + -1727260, -1564661, -1362612, -1120399, -846100, -538521, + -204309, 151603, 528919, 922290, 1315125, 1706894, + 2090470, 2458389, 2799972, 3109863, 3382597, 3609505, + 3778017, 3891544, 3933694, 3912353, 3813931, 3643198, + 3393850, 3071142, 2677376, 2209600, 1677941, 1084818, + 444967, -243363, -962452, -1701393, -2442824, -3187052, + -3905129, -4595717, -5232588, -5810315, -6311599, -6728312, + -7036669, -7235070, -7315570, -7261861, -7076599, -6757898, + -6294514, -5696302, -4963545, -4110784, -3133421, -2057740, + -890886, 352251, 1643641, 2971293, 4311667, 5637297, + 6922700, 8146290, 9279509, 10298347, 11182888, 11906619, + 12445720, 12792796, 12920677, 12821426, 12487235, 11917145, + 11098463, 10047806, 8770879, 7274529, 5582694, 3712279, + 1694100, -446673, -2678418, -4957743, -7246818, -9512063, + -11705023, -13778294, -15700344, -17427663, -18912276, -20124761, + -21027320, -21598948, -21801191, -21628479, -21056400, -20085908, + -18714238, -16955159, -14813766, -12321078, -9504162, -6399966, + -3054231, 482872, 4154302, 7905278, 11666569, 15378054, + 18958123, 22345534, 25474375, 28277167, 30683302, 32642235, + 34096393, 35003550, 35319949, 35025915, 34092432, 32521600, + 30307717, 27471468, 24039684, 20045508, 15546072, 10598856, + 5269966, -350481, -6180026, -12114692, -18059248, -23906672, + -29549875, -34871747, -39782448, -44161036, -47925834, -50975328, + -53235322, -54634944, -55118776, -54647517, -53185173, -50739616, + -47302385, -42904835, -37598374, -31437470, -24504539, -16886940, + -8713803, -96592, 8822281, 17893277, 26962568, 35868287, + 44446216, 52535664, 59974374, 66609968, 72289304, 76896286, + 80294207, 82394351, 83111692, 82389627, 80191979, 76513564, + 71358551, 64784668, 56848569, 47656194, 37330198, 26009511, + 13864615, 1086171, -12123873, -25537363, -38932152, -52068869, + -64704797, -76601691, -87525849, -97258037, -105582362, -112312248, + -117278944, -120341163, -121382694, -120326971, -117128187, -111776250, + -104303150, -94772849, -83295810, -70008000, -55097092, -38780459, + -21296115, -2915789, 16048887, 35294650, 54490243, 73286361, + 91346168, 108333722, 123911975, 137767211, 149615571, 159177154, + 166229885, 170578636, 172063686, 170577539, 166068796, 158531146, + 148010324, 134608279, 118482912, 99845751, 78943021, 56093794, + 31643166, 5972435, -20501213, -47329173, -74051124, -100196883, + -125294427, -148870026, -170477108, -189679210, -206075759, -219304043, + -229055107, -235069748, -237136842, -235122812, -228956016, -218642090, + -204251958, -185931479, -163914657, -138473803, -109988389, -78864741, + -45593192, -10699983, 25253171, 61650957, 97869663, 133278383, + 167232254, 199106861, 228282653, 254196068, 276312161, 294146665, + 307294652, 315410249, 318234645, 315590297, 307394443, 293664335, + 274509339, 250133892, 220842123, 187039901, 149209960, 107922433, + 63810361, 17587760, -29985506, -78117921, -125968455, -172708192, + -217493625, -259497359, -297927725, -332031196, -361123362, -384588415, + -401886494, -412588709, -416366237, -413004376, -402403545, -384595162, + -359740975, -328120781, -290142483, -246340640, -197348989, -143910091, + -86867351, -27143103, 34285708, 96376993, 158069138, 218280055, + 275929446, 329963897, 379373709, 423197160, 460572512, 490705168, + 512948401, 526747189, 531695512, 527540747, 514177226, 491657698, + 460188457, 420160343, 372096220, 316680397, 254738394, 187222293, + 115197014, 39828687, -37626355, -115870108, -193554390, -269321025, + -341820450, -409733063, -471798151, -526831940, -573748345, -611594031, + -639544543, -656949500, -663308649, -658325717, -641880896, -614068050, + -575168915, -525665290, -466238167, -397738580, -321208417, -237834108, + -148957438, -56007249, 39465483, 135841047, 231468773, 324681365, + 413821307, 497283182, 573521157, 641095651, 698712130, 745197774, + 779567711, 801049388, 809057254, 803237808, 783489679, 749925411, + 702911733, 643063728, 571208755, 488423234, 395954144, 295275675, + 187993978, 75865718, -39236308, -155364925, -270531450, -382717564, + -489957676, -590312404, -681949986, -763163139, -832392865, -888277334, + -929664966, -955628349, -965507939, -958906225, -935713724, -896099293, + -840526616, -769729759, -684734549, -586814614, -477494414, -358504690, + -231768214, -99384696, 36447617, 173415519, 309178420, 441371753, + 567666025, 685811530, 793656966, 889216942, 970688561, 1036488980, + 1085290370, 1116036006, 1127980589, 1120686956, 1094053945, 1048302464, + 983994405, 902020613, 803589058, 690200491, 563631899, 425926519, + 279325343, 126250979, -30724886, -188948326, -345694846, -498252679, + -643944275, -780184780, -904516055, -1014670896, -1108601825, -1184506299, + -1240890909, -1276581824, -1290734322, -1282895863, -1252960854, -1201218312, + -1128343320, -1035375507, -923712972, -795088635, -651552657, -495428590, + -329277266, -155868968, 21884630, 200961971, 378296024, 550818202, + 715513308, 869463796, 1009937937, 1134384860, 1240514038, 1326341350, + 1390206244, 1430809681, 1447252889, 1439042709, 1406104903, 1348787986, + 1267878591, 1164563795, 1040427150, 897443541, 737906293, 564423186, + 379869427, 187329491, -9955718, -208626909, -405282321, -596523018, + -779023314, -949576746, -1105159690, -1242989351, -1360560433, -1455708690, + -1526631531, -1571933920, -1590652703, -1582289863, -1546784045, -1484564044, + -1396513095, -1283969795, -1148697739, -992870821, -819029807, -630048695, + -429062628, -219454929, -4764302, 211344971, 425177867, 633047097, + 831343127, 1016615527, 1185591113, 1335287179, 1463017725, 1566460527, + 1643703210, 1693272282, 1714173828, 1705879519, 1668383535, 1602171121, + 1508225260, 1388013119, 1243466543, 1076941063, 891185548, 689291733, + 474640802, 250860397, 21738447, -208811879, -436851181, -658444086, + -869778675, -1067171636, -1247182880, -1406650050, -1542754248, -1653063285, + -1735584343, -1788792418, -1811656971, -1803674070, -1764855225, -1695756123, + -1597458692, -1471529123, -1320042483, -1145495192, -950811122, -739251472, + -514387884, -280038811, -40182539, 201082127, 439625474, 671360194, + 892281969, 1098593058, 1286704310, 1453353848, 1595632929, 1711032396, + 1797519314, 1853535499, 1878057863, 1870596072, 1831203976, 1760492969, + 1659601101, 1530204850, 1374462215, 1194990025, 994815702, 777344707, + 546257874, 305494569, 59165380, -188527365, -433343031, -671080193, + -897665887, -1109212583, -1302074592, -1472935050, -1618847731, -1737293175, + -1826220505, -1884077847, -1909862809, -1903102016, -1863908084, -1792915406, + -1691338340, -1560892199, -1403810772, -1222762623, -1020844224, -801519269, + -568521705, -325842895, -77639026, 171850260, 418354109, 657652397, + 885658006, 1098483323, 1292482492, 1464354264, 1611173802, 1730447918, + 1820147456, 1878774327, 1905345015, 1899436591, 1861181614, 1791269880, + 1690931416, 1561918192, 1406474208, 1227285856, 1027453891, 810423456, + 579930851, 339935975, 94561541, -151995804, -395519520, -631846220, + -856955512, -1067023060, -1258484983, -1428107906, -1573047808, -1690881207, + -1779650546, -1837917712, -1864752691, -1859784222, -1823172826, -1755627369, + -1658388705, -1533199617, -1382280092, -1208279946, -1014241857, -803543612, + -579832950, -346972564, -108975262, 130084072, 366112543, 595091308, + 813135881, 1016560268, 1201935283, 1366175566, 1506546319, 1620740341, + 1706921440, 1763716202, 1790274256, 1786276435, 1751905466, 1687886894, + 1595436847, 1476262351, 1332506505, 1166743251, 981898453, 781224629, + 568212339, 346559921, 120100320, -107291665, -331716427, -549356988, + -756537606, -949779759, -1125851662, -1281839136, -1415194341, -1523750226, + -1605799171, -1660093788, -1685848027, -1682799447, -1651157876, -1591635572, + -1505409467, -1394110995, -1259788475, -1104878691, -932150993, -744662067, + -545708117, -338757382, -127388767, 84763881, 294067482, 496979529, + 690070737, 870117589, 1034133585, 1179439215, 1303678090, 1404887501, + 1481492441, 1532367900, 1556837967, 1554669622, 1526102357, 1471816788, + 1392929409, 1290979584, 1167883699, 1025898547, 867595552, 695801640, + 513558015, 324055197, 130580019, -63531828, -254957837, -440470852, + -616936670, -781439126, -931257387, -1063973979, -1177469886, -1269969396, + -1340089214, -1386823818, -1409580111, -1408192311, -1382898809, -1334344278, + -1263571363, -1172000225, -1061372669, -933760932, -791499808, -637157868, + -473474442, -303337763, -129705392, 44420335, 216069365, 382339648, + 540447254, 687781491, 821934079, 940760571, 1042387135, 1125252799, + 1188147208, 1230201006, 1250924236, 1250187783, 1228227566, 1185647619, + 1123398884, 1042759518, 945299898, 832870179, 707547821, 571626092, + 427527543, 277810041, 125085057, -28010600, -178853506, -324906192, + -463733638, -593048340, -710768042, -815013616, -904172591, -976908539, + -1032173782, -1069239365, -1087698933, -1087470671, -1068778489, -1032179008, + -978515150, -908919940, -824775378, -727706611, -619535673, -502243121, + -377946135, -248861178, -117246162, 14621362, 144491857, 270172298, + 389581420, 500764993, 601939427, 691515419, 768128879, 830643528, + 878195038, 910177424, 926258719, 926396266, 910805964, 879977667, + 834650965, 775805529, 704649184, 622560430, 531100567, 431974140, + 326968596, 217974337, 106897439, -4331905, -113811517, -219713043, + -320271090, -413863122, -498997138, -574345705, -638786489, -691378723, + -731416804, -758409004, -772102118, -772476516, -759734475, -734294552, + -696804594, -648094824, -589172646, -521212233, -445517032, -363502236, + -276673232, -186591246, -94842458, -3022754, 87303105, 174620285, + 257495934, 334583680, 404667701, 466682288, 519703658, 562979891, + 595946616, 618221526, 629610881, 630106942, 619907159, 599363749, + 569010853, 529543975, 481805921, 426750078, 365456250, 299075520, + 228840090, 156015660, 81893049, 7755186, -65128851, -135537978, + -202321503, -264404090, -320822061, -370714643, -413359634, -448173767, + -474696651, -492653799, -501893571, -502433588, -494432932, -478193313, + -454161674, -422891283, -385068437, -341460613, -292938082, -240419450, + -184880948, -127332930, -68805082, -10308903, 47162165, 102642618, + 155226699, 204081975, 248446611, 287663437, 321164632, 348507085, + 369349845, 383472440, 390780777, 391301244, 385159596, 372608714, + 354002348, 329792757, 300514176, 266772038, 229250923, 188660171, + 145771607, 101362438, 56230870, 11158037, -33089190, -75767489, + -116186499, -153708843, -187764622, -217840328, -243526598, -264475454, + -280442868, -291277471, -296907101, -297359175, -292750056, -283273727, + -269212330, -250907995, -228786222, -203299441, -174980678, -144370836, + -112054125, -78619334, -44674297, -10796779, 22429621, 54448874, + 84741856, 112850180, 138327885, 160816025, 180007793, 195653700, + 207572067, 215662380, 219880160, 220249673, 216865158, 209879430, + 199507426, 186012659, 169709832, 150948749, 130113527, 107611242, + 83879355, 59352318, 34467719, 9665911, -14642108, -38040824, + -60157016, -80654418, -99219264, -115589797, -129545820, -140913863, + -149571739, -155444700, -158505797, -158792334, -156363817, -151338055, + -143887461, -134194341, -122498799, -109046102, -94123508, -78025128, + -61059747, -43545883, -25796815, -8129513, 9163546, 25792880, + 41498590, 56033059, 69187641, 80767050, 90630249, 98658995, + 104762234, 108902079, 111059757, 111263586, 109562557, 106046746, + 100833173, 94061670, 85895528, 76519048, 66130807, 54934736, + 43153781, 31007416, 18709409, 6487602, -5465933, -16946274, + -27770029, -37775509, -46814982, -54771683, -61533641, -67030347, + -71205626, -74023788, -75495830, -75627969, -74470032, -72077681, + -68529180, -63937739, -58408135, -52062371, -45042063, -37490140, + -29555197, -21385211, -13122625, -4921524, 3085357, 10759723, + 17992582, 24666389, 30683196, 35971842, 40458997, 44099420, + 46855760, 48721212, 49685704, 49765688, 48994777, 47411331, + 45075651, 42054087, 38424158, 34268812, 29672938, 24740687, + 19571693, 14248378, 8884824, 3562881, -1621239, -6586647, + -11253090, -15555599, -19428913, -22821406, -25700820, -28024865, + -29783485, -30965398, -31574032, -31615670, -31114544, -30104441, + -28614173, -26690187, -24393033, -21759693, -18857738, -15751354, + -12492477, -9153261, -5783717, -2459634, 778698, 3875964, + 6776702, 9449232, 11845786, 13948370, 15720788, 17149101, + 18231430, 18949799, 19315305, 19335514, 19020327, 18395826, + 17478205, 16296941, 14893212, 13283979, 11522416, 9639711, + 7663000, 5644053, 3617443, 1615060, -332168, -2184038, + -3918720, -5508362, -6936545, -8183325, -9232830, -10074356, + -10703608, -11126458, -11331077, -11339686, -11148104, -10770979, + -10228871, -9536383, -8710109, -7770585, -6742184, -5643349, + -4500541, -3328458, -2159579, -1004392, 110110, 1173423, + 2159647, 3069460, 3876884, 4586498, 5177693, 5646960, + 5999906, 6233787, 6347370, 6346598, 6231484, 6021809, + 5711125, 5320225, 4855551, 4327752, 3755975, 3148939, + 2514295, 1870100, 1224054, 591479, -19842, -595926, + -1136695, -1623514, -2058527, -2441755, -2759699, -3009118, + -3195895, -3315318, -3372391, -3367899, -3304971, -3188264, + -3019838, -2809759, -2565867, -2288243, -1979646, -1665042, + -1328619, -993474, -657631, -327993, -16430, 284913, + 562503, 810232, 1034553, 1226932, 1381838, 1513025, + 1599447, 1662854, 1686316, 1682092, 1651127, 1587146, + 1503496, 1397927, 1269542, 1131369, 982502, 824625, + 660881, 493354, 326771, 168908, 16066, -125971, + -261297, -378974, -483268, -576163, -647622, -708224, + -748436, -777452, -785947, -779909, -768879, -735235, + -693141, -644311, -585366, -522056, -451398, -378281, + -301901, -228634, -154426, -81830, -10134, 47735, + 111082, 163294, 207447, 247956, 282325, 307949, + 324908, 333180, 335597, 335296, 325667, 311552, + 293582, 271780, 245119, 219071, 189774, 158232, + 126724, 93564, 64134, 34822, 6228, -19584, + -41721, -63726, -82340, -98638, -109326, -117337, + -126201, -127991, -132091, -130369, -124920, -119589, + -111608, -103992, -92468, -82123, -67954, -61380, + -46424, -35967, -21111, -11739, -5029, 5679, + 13330, 22276, 26343, 35218, 34648, 39078, + 41053, 41092, 46268, 44252, 41586, 40964, + 33470, 36946, 29670, 27351, 23384, 20595, + 14255, 8620, 6966, 7402, 2342, -3982, + -3662, -6609, -4254, -9826, -11984, -13311, + -11772, -11570, -11066, -9660, -9629, -8766, + -9862, -6981, -8621, -6396, -5888, -4708, + -1464, -3442, -1834, -1918, -3426, 1074, + 2306, 544, 72, 3496, 3495, -1310, + 1331, 2847, 5980, 2827, 3263, 1499, + 2773, 1854, 1693, 3452, 2877, -1854, + 724, -2026, -2173, -141, -640, 1167, + 2129, -1066, 1932, -806, -690, -1960, + -506, -1528, -1399, -333, -2033, -851, + -1057, -321, -3212, 2295, -24, -2239, +}; + +static const int32_t fft_in_imag_1536_q31[1536] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +}; + +static const int32_t fft_ref_real_1536_q31[1536] = { + 36, 4, -4, -16, 8, 47, + -34, 30, -82, -15, 32, -63, + -77, -44, 12, -13, 1, -15, + -7, -13, 58, -10, 19, -16, + -13, 92, -848, 92278, -1546050, 10045551, + -33641357, 65657099, -78882771, 59164075, -27128397, 7128059, + -930416, 42760, -189, 12, -18, 9, + -9, -43, -37, 25, -6, 36, + -13, -15, -64, 43, -7, 3, + 16, -4, 46, 43, 15, -30, + 46, -7, 15, -9, 8, -14, + 29, -1, -53, 49, -19, -15, + -29, -11, -10, -29, -25, -11, + -36, 36, -29, -6, 28, 8, + 49, 23, -32, -27, -28, -25, + 14, 28, -6, 8, -39, 10, + 21, -4, -22, 52, 22, -11, + -27, 17, -1, 10, 30, -40, + -5, 5, 0, -18, 28, -29, + 30, 27, -1, -16, 42, -51, + -84, -14, -24, -26, -4, -4, + -36, -57, -39, 22, -4, -36, + 1, -53, 52, -17, -45, -6, + -22, 20, -19, 21, -12, -3, + -18, 38, -43, -24, -32, 48, + 47, 17, -25, -4, 22, 9, + -25, 15, -7, -22, -33, 20, + 19, 37, 36, 42, 39, -20, + 28, 25, -5, -5, 20, 42, + 30, -15, 1, -19, 33, -48, + -4, 24, -38, -18, -30, 44, + 14, 42, 3, 44, -85, 25, + 33, 27, -16, -7, 14, -48, + 35, -12, 1, 18, -37, -82, + 4, 24, -52, -57, 21, -2, + -37, -51, 23, 35, 60, 2, + 19, 32, -23, 3, 54, 7, + -49, 26, -37, 39, 48, 19, + 29, -3, 5, -22, 6, 26, + -5, -11, 13, -16, -38, 38, + -23, 55, -4, 30, -12, 59, + -26, -25, 27, -21, 4, -18, + -24, -17, -41, -56, 39, 22, + -1, -6, -38, -18, -3, 25, + -66, 52, 3, 29, -17, -2, + -36, -23, -8, 20, 21, -41, + -22, -15, 31, -6, 11, 26, + -1, 36, -29, -4, -11, 12, + 47, -8, -5, 0, 35, 8, + -13, -3, -47, -15, 14, -38, + 40, 34, -55, -38, -51, -17, + -13, 9, -33, -10, 9, 56, + 12, 4, 12, -1, -11, 3, + 55, 31, -5, 36, -14, -26, + -4, 10, -12, 8, 5, -70, + 37, -31, -55, -17, -26, -45, + -5, -13, -1, 27, 42, 31, + -5, -39, -57, -22, 14, 9, + 4, -20, -29, 31, -45, 16, + 4, 38, 27, -39, 5, 23, + 36, 39, 36, 51, -3, -4, + -19, -44, -9, -53, -14, 46, + -46, 5, 4, -24, 13, -21, + 2, 40, -26, 31, 21, 41, + -13, 9, -39, -33, -4, -22, + 10, 18, 0, 16, 42, 20, + -8, 12, -18, 11, 8, -30, + -22, 35, -29, 8, 47, -29, + -36, 2, -10, -57, -21, 23, + 9, -91, -49, 6, 14, 3, + 50, -59, -56, -3, 4, -4, + -71, -10, -55, 13, 28, -37, + -6, -50, 17, 4, 52, 7, + -53, 19, 33, -19, 12, -8, + -52, 30, -8, -5, 53, -3, + -13, 10, 2, -25, -14, -43, + 35, -22, 5, 68, -8, -8, + 3, 46, -2, -16, -5, 40, + -14, -28, 6, 65, -22, -5, + -9, -13, -27, 11, 16, -39, + 28, 24, 54, 37, -31, 39, + -15, 68, -3, -42, 8, 40, + 11, -3, -47, 33, -19, 24, + -6, -6, -9, -61, 55, 9, + 24, 11, -35, 19, -1, 5, + 63, -10, -24, -6, -8, -12, + 20, 17, 0, 31, -34, -3, + 32, 66, -38, 0, 7, 32, + 11, 0, 2, -8, -22, -46, + 11, -3, -25, -36, -2, 41, + -19, -17, -29, 30, -1, 70, + 25, 16, -25, -15, 12, 18, + -13, 20, 13, -44, -42, -21, + 4, -39, 32, 21, 60, -11, + -31, 10, -9, 1, 19, -45, + -4, -16, -21, 26, 35, 11, + 18, 38, 1, 6, 51, 13, + -70, 7, 55, 35, -10, -13, + -14, -56, -12, 26, 18, 51, + -24, 4, -35, 16, -1, -45, + 40, 48, 50, 15, 1, -19, + 1, -21, 67, -46, -20, -8, + -7, -2, -24, 16, -39, -1, + 26, 72, 3, -16, -3, 14, + 28, 9, -40, 34, -3, 18, + -8, -41, -51, 45, 28, -37, + 4, 24, 21, -38, 90, -29, + 9, 9, 47, -10, 35, -1, + -30, -11, 11, 38, -24, 10, + -40, 43, -3, -52, 23, 3, + -9, 14, 1, 20, 44, 13, + -35, -9, 36, -39, 37, 4, + 20, -18, 42, 39, -19, 20, + 26, -3, 38, -11, 20, -2, + 29, -60, -22, -23, 37, -30, + 44, -23, 7, -30, 39, -14, + -18, -26, 13, 23, -40, -45, + 3, -2, -14, 35, -10, -33, + 3, -40, -42, -38, 3, -5, + 18, -44, -36, 24, 40, 33, + 37, 18, -13, 19, -5, -13, + -7, -8, -1, -41, -18, -14, + -46, -49, 22, 8, -1, -14, + 0, 40, -15, 65, -35, -29, + 14, 25, -19, 13, -27, -12, + -37, -42, 4, -14, -58, 0, + 62, -16, 26, 19, -29, 23, + -17, 24, -61, 30, 24, 9, + -52, 9, 24, 30, -61, 24, + -17, 23, -29, 19, 26, -16, + 62, 0, -58, -14, 4, -42, + -37, -12, -27, 13, -19, 25, + 14, -29, -35, 65, -15, 40, + 0, -14, -1, 8, 22, -49, + -46, -14, -18, -41, -1, -8, + -7, -13, -5, 19, -13, 18, + 37, 33, 40, 24, -36, -44, + 18, -5, 3, -38, -42, -40, + 3, -33, -10, 35, -14, -2, + 3, -45, -40, 23, 13, -26, + -18, -14, 39, -30, 7, -23, + 44, -30, 37, -23, -22, -60, + 29, -2, 20, -11, 38, -3, + 26, 20, -19, 39, 42, -18, + 20, 4, 37, -39, 36, -9, + -35, 13, 44, 20, 1, 14, + -9, 3, 23, -52, -3, 43, + -40, 10, -24, 38, 11, -11, + -30, -1, 35, -10, 47, 9, + 9, -29, 90, -38, 21, 24, + 4, -37, 28, 45, -51, -41, + -8, 18, -3, 34, -40, 9, + 28, 14, -3, -16, 3, 72, + 26, -1, -39, 16, -24, -2, + -7, -8, -20, -46, 67, -21, + 1, -19, 1, 15, 50, 48, + 40, -45, -1, 16, -35, 4, + -24, 51, 18, 26, -12, -56, + -14, -13, -10, 35, 55, 7, + -70, 13, 51, 6, 1, 38, + 18, 11, 35, 26, -21, -16, + -4, -45, 19, 1, -9, 10, + -31, -11, 60, 21, 32, -39, + 4, -21, -42, -44, 13, 20, + -13, 18, 12, -15, -25, 16, + 25, 70, -1, 30, -29, -17, + -19, 41, -2, -36, -25, -3, + 11, -46, -22, -8, 2, 0, + 11, 32, 7, 0, -38, 66, + 32, -3, -34, 31, 0, 17, + 20, -12, -8, -6, -24, -10, + 63, 5, -1, 19, -35, 11, + 24, 9, 55, -61, -9, -6, + -6, 24, -19, 33, -47, -3, + 11, 40, 8, -42, -3, 68, + -15, 39, -31, 37, 54, 24, + 28, -39, 16, 11, -27, -13, + -9, -5, -22, 65, 6, -28, + -14, 40, -5, -16, -2, 46, + 3, -8, -8, 68, 5, -22, + 35, -43, -14, -25, 2, 10, + -13, -3, 53, -5, -8, 30, + -52, -8, 12, -19, 33, 19, + -53, 7, 52, 4, 17, -50, + -6, -37, 28, 13, -55, -10, + -71, -4, 4, -3, -56, -59, + 50, 3, 14, 6, -49, -91, + 9, 23, -21, -57, -10, 2, + -36, -29, 47, 8, -29, 35, + -22, -30, 8, 11, -18, 12, + -8, 20, 42, 16, 0, 18, + 10, -22, -4, -33, -39, 9, + -13, 41, 21, 31, -26, 40, + 2, -21, 13, -24, 4, 5, + -46, 46, -14, -53, -9, -44, + -19, -4, -3, 51, 36, 39, + 36, 23, 5, -39, 27, 38, + 4, 16, -45, 31, -29, -20, + 4, 9, 14, -22, -57, -39, + -5, 31, 42, 27, -1, -13, + -5, -45, -26, -17, -55, -31, + 37, -70, 5, 8, -12, 10, + -4, -26, -14, 36, -5, 31, + 55, 3, -11, -1, 12, 4, + 12, 56, 9, -10, -33, 9, + -13, -17, -51, -38, -55, 34, + 40, -38, 14, -15, -47, -3, + -13, 8, 35, 0, -5, -8, + 47, 12, -11, -4, -29, 36, + -1, 26, 11, -6, 31, -15, + -22, -41, 21, 20, -8, -23, + -36, -2, -17, 29, 3, 52, + -66, 25, -3, -18, -38, -6, + -1, 22, 39, -56, -41, -17, + -24, -18, 4, -21, 27, -25, + -26, 59, -12, 30, -4, 55, + -23, 38, -38, -16, 13, -11, + -5, 26, 6, -22, 5, -3, + 29, 19, 48, 39, -37, 26, + -49, 7, 54, 3, -23, 32, + 19, 2, 60, 35, 23, -51, + -37, -2, 21, -57, -52, 24, + 4, -82, -37, 18, 1, -12, + 35, -48, 14, -7, -16, 27, + 33, 25, -85, 44, 3, 42, + 14, 44, -30, -18, -38, 24, + -4, -48, 33, -19, 1, -15, + 30, 42, 20, -5, -5, 25, + 28, -20, 39, 42, 36, 37, + 19, 20, -33, -22, -7, 15, + -25, 9, 22, -4, -25, 17, + 47, 48, -32, -24, -43, 38, + -18, -3, -12, 21, -19, 20, + -22, -6, -45, -17, 52, -53, + 1, -36, -4, 22, -39, -57, + -36, -4, -4, -26, -24, -14, + -84, -51, 42, -16, -1, 27, + 30, -29, 28, -18, 0, 5, + -5, -40, 30, 10, -1, 17, + -27, -11, 22, 52, -22, -4, + 21, 10, -39, 8, -6, 28, + 14, -25, -28, -27, -32, 23, + 49, 8, 28, -6, -29, 36, + -36, -11, -25, -29, -10, -11, + -29, -15, -19, 49, -53, -1, + 29, -14, 8, -9, 15, -7, + 46, -30, 15, 43, 46, -4, + 16, 3, -7, 43, -64, -15, + -13, 36, -6, 25, -37, -43, + -9, 9, -18, 12, -189, 42760, + -930416, 7128059, -27128397, 59164075, -78882771, 65657099, + -33641357, 10045551, -1546050, 92278, -848, 92, + -13, -16, 19, -10, 58, -13, + -7, -15, 1, -13, 12, -44, + -77, -63, 32, -15, -82, 30, + -34, 47, 8, -16, -4, 4, +}; + +static const int32_t fft_ref_imag_1536_q31[1536] = { + 0, -51, -47, -1, -37, 43, + 28, -75, -11, -5, 22, -19, + 34, 22, -2, 47, 5, -17, + -59, 34, 2, -3, -6, 15, + -23, -10, -2528, 286363, -4833320, 31628670, + -106676515, 209692355, -253750691, 191701755, -88543033, 23436068, + -3081512, 142772, -625, 11, 6, -13, + 4, -7, -42, 19, -6, -5, + 11, -28, 39, -47, 29, 60, + 39, -3, -48, 25, -47, 5, + -27, 14, -37, 42, 54, 24, + -11, -60, -22, -14, 51, -36, + 53, -48, -50, -5, -52, -23, + -18, -23, -16, -22, 23, 34, + 33, -6, -11, -62, -45, 11, + 19, -2, -39, -18, 20, 4, + 2, 24, 24, 13, -9, -2, + -4, 32, -2, 10, 15, 6, + -29, -7, 45, -29, 18, 26, + 1, -19, -20, 0, 32, 16, + -1, 32, 72, -48, -27, -4, + 69, 22, -7, 6, 22, 56, + -14, 32, -34, -39, 31, -18, + 30, 19, -4, 71, 10, 28, + -23, 22, 13, 12, -2, 21, + 38, -33, 1, -37, -32, 19, + 13, 23, -43, 10, 7, -28, + 65, 25, 4, -24, 13, 17, + 0, -23, 14, 13, -18, -16, + 21, -47, 19, -20, 15, 1, + -50, -2, -21, -33, 9, 44, + 25, 28, 20, -31, 13, 4, + -4, 83, -1, 46, 10, 16, + -14, 17, 16, 15, 32, 24, + -11, -44, 45, -68, 36, -32, + 66, 23, 12, 42, -12, -6, + 50, -68, -14, -46, -36, -9, + 71, -41, -28, -33, 5, -61, + -10, 54, 0, 40, 0, 17, + 3, 4, 6, -20, 6, -7, + 1, -17, 3, -26, -29, 23, + -4, 17, -15, 8, 6, 8, + -23, -20, -3, 38, 13, -32, + 18, -3, -45, -47, -44, -26, + -29, 23, 28, -3, 58, -40, + 53, -9, 5, 35, 8, -1, + -25, 36, -6, -56, -1, 35, + -3, -7, -23, -12, 31, -51, + 5, 77, -38, -42, 49, -1, + -23, -3, 8, 0, 2, 11, + 27, -35, 8, 58, -46, -27, + 14, -10, -15, -45, -16, 2, + 20, 8, 10, 9, 29, -30, + -15, 68, -8, 16, -63, -23, + -5, -37, 7, -31, -25, 44, + -17, -34, 14, 10, 7, 16, + 18, 26, 44, 12, -13, 4, + 25, 6, 29, -47, 24, 8, + -14, 6, 21, -39, -2, -73, + -11, -7, -7, -14, -34, 11, + 74, 43, 17, -28, 18, -49, + 27, 3, -7, -13, 39, 20, + -39, 9, -10, 38, -15, -14, + 3, -43, 12, -31, 18, 44, + -24, -22, -52, -26, 15, -20, + -52, -28, 10, -18, -13, -17, + -16, -77, 16, -59, -102, 15, + 31, -75, -24, 42, 9, 19, + -3, 10, 4, 4, -25, 33, + 18, 22, 2, 34, -32, -18, + -1, 12, -3, -12, -6, 20, + -63, 3, -4, 18, 46, 40, + -15, -30, -4, 26, -31, -1, + -15, 19, -49, -11, 20, 1, + 2, 37, 54, 13, -2, -7, + -19, 9, -5, 4, 101, -42, + -45, 17, 14, -35, -56, 30, + -19, 86, -10, -46, -50, -7, + -22, -6, 0, -15, -6, 9, + -46, 54, -14, -7, 2, 27, + -54, 74, 29, 58, -39, 2, + -78, -8, -65, 47, 17, -40, + -15, 6, 3, 13, 7, -26, + -65, -26, -37, 18, -34, -10, + 11, -44, 3, 4, -28, -16, + 8, -88, -3, 8, 27, 18, + -9, 60, 30, 45, -53, -1, + -11, -1, 31, -4, 18, -5, + -13, -5, 9, -40, 22, 6, + -20, 23, 6, 32, -13, 25, + -5, 25, 12, 29, 8, -5, + -53, 45, 7, -24, -3, -12, + 3, 31, -1, -43, -9, -47, + -14, -38, -34, 57, 22, 45, + -20, -5, -30, -18, -17, -2, + 43, -28, 2, 59, -80, -5, + -16, -51, 39, -21, -21, 24, + 47, -29, 15, -22, 71, 77, + -34, 38, -9, -24, 23, -2, + 17, 33, -23, 52, 2, -25, + -55, -2, -34, 64, 59, 1, + 17, 11, 17, 11, -41, -15, + 13, 9, 32, 21, 17, 30, + -32, -49, 10, 11, 31, -1, + -48, 41, 28, -42, -47, 6, + -6, 2, -71, -44, -27, 51, + -3, 38, -66, -36, 34, -41, + 43, 38, 15, 32, -29, 11, + 3, -20, 23, 20, -54, -10, + 6, 7, -4, -12, 26, -14, + 22, 45, -5, 64, 22, -6, + -41, -30, -14, -8, -100, -26, + 28, 57, -5, -9, 42, -20, + 39, 9, 18, 14, 52, 6, + 2, 7, -93, -29, -15, -20, + 25, 18, 2, -20, -7, 15, + 67, -29, -20, -43, 3, 38, + 16, -32, 20, 43, -2, 41, + 16, -3, -8, -21, 1, -12, + 25, 1, 63, 12, -43, -2, + -23, 8, -7, -14, 24, 24, + 32, -19, 33, 13, -9, 1, + 24, 37, -24, 9, -46, -19, + 38, 71, 32, -26, 5, -66, + -5, 8, -5, 13, -43, -24, + -24, -26, 5, -28, 26, 0, + -20, -20, 2, -14, 60, -8, + -57, -34, 13, 12, 14, -1, + 0, 1, -14, -12, -13, 34, + 57, 8, -60, 14, -2, 20, + 20, 0, -26, 28, -5, 26, + 24, 24, 43, -13, 5, -8, + 5, 66, -5, 26, -32, -71, + -38, 19, 46, -9, 24, -37, + -24, -1, 9, -13, -33, 19, + -32, -24, -24, 14, 7, -8, + 23, 2, 43, -12, -63, -1, + -25, 12, -1, 21, 8, 3, + -16, -41, 2, -43, -20, 32, + -16, -38, -3, 43, 20, 29, + -67, -15, 7, 20, -2, -18, + -25, 20, 15, 29, 93, -7, + -2, -6, -52, -14, -18, -9, + -39, 20, -42, 9, 5, -57, + -28, 26, 100, 8, 14, 30, + 41, 6, -22, -64, 5, -45, + -22, 14, -26, 12, 4, -7, + -6, 10, 54, -20, -23, 20, + -3, -11, 29, -32, -15, -38, + -43, 41, -34, 36, 66, -38, + 3, -51, 27, 44, 71, -2, + 6, -6, 47, 42, -28, -41, + 48, 1, -31, -11, -10, 49, + 32, -30, -17, -21, -32, -9, + -13, 15, 41, -11, -17, -11, + -17, -1, -59, -64, 34, 2, + 55, 25, -2, -52, 23, -33, + -17, 2, -23, 24, 9, -38, + 34, -77, -71, 22, -15, 29, + -47, -24, 21, 21, -39, 51, + 16, 5, 80, -59, -2, 28, + -43, 2, 17, 18, 30, 5, + 20, -45, -22, -57, 34, 38, + 14, 47, 9, 43, 1, -31, + -3, 12, 3, 24, -7, -45, + 53, 5, -8, -29, -12, -25, + 5, -25, 13, -32, -6, -23, + 20, -6, -22, 40, -9, 5, + 13, 5, -18, 4, -31, 1, + 11, 1, 53, -45, -30, -60, + 9, -18, -27, -8, 3, 88, + -8, 16, 28, -4, -3, 44, + -11, 10, 34, -18, 37, 26, + 65, 26, -7, -13, -3, -6, + 15, 40, -17, -47, 65, 8, + 78, -2, 39, -58, -29, -74, + 54, -27, -2, 7, 14, -54, + 46, -9, 6, 15, 0, 6, + 22, 7, 50, 46, 10, -86, + 19, -30, 56, 35, -14, -17, + 45, 42, -101, -4, 5, -9, + 19, 7, 2, -13, -54, -37, + -2, -1, -20, 11, 49, -19, + 15, 1, 31, -26, 4, 30, + 15, -40, -46, -18, 4, -3, + 63, -20, 6, 12, 3, -12, + 1, 18, 32, -34, -2, -22, + -18, -33, 25, -4, -4, -10, + 3, -19, -9, -42, 24, 75, + -31, -15, 102, 59, -16, 77, + 16, 17, 13, 18, -10, 28, + 52, 20, -15, 26, 52, 22, + 24, -44, -18, 31, -12, 43, + -3, 14, 15, -38, 10, -9, + 39, -20, -39, 13, 7, -3, + -27, 49, -18, 28, -17, -43, + -74, -11, 34, 14, 7, 7, + 11, 73, 2, 39, -21, -6, + 14, -8, -24, 47, -29, -6, + -25, -4, 13, -12, -44, -26, + -18, -16, -7, -10, -14, 34, + 17, -44, 25, 31, -7, 37, + 5, 23, 63, -16, 8, -68, + 15, 30, -29, -9, -10, -8, + -20, -2, 16, 45, 15, 10, + -14, 27, 46, -58, -8, 35, + -27, -11, -2, 0, -8, 3, + 23, 1, -49, 42, 38, -77, + -5, 51, -31, 12, 23, 7, + 3, -35, 1, 56, 6, -36, + 25, 1, -8, -35, -5, 9, + -53, 40, -58, 3, -28, -23, + 29, 26, 44, 47, 45, 3, + -18, 32, -13, -38, 3, 20, + 23, -8, -6, -8, 15, -17, + 4, -23, 29, 26, -3, 17, + -1, 7, -6, 20, -6, -4, + -3, -17, 0, -40, 0, -54, + 10, 61, -5, 33, 28, 41, + -71, 9, 36, 46, 14, 68, + -50, 6, 12, -42, -12, -23, + -66, 32, -36, 68, -45, 44, + 11, -24, -32, -15, -16, -17, + 14, -16, -10, -46, 1, -83, + 4, -4, -13, 31, -20, -28, + -25, -44, -9, 33, 21, 2, + 50, -1, -15, 20, -19, 47, + -21, 16, 18, -13, -14, 23, + 0, -17, -13, 24, -4, -25, + -65, 28, -7, -10, 43, -23, + -13, -19, 32, 37, -1, 33, + -38, -21, 2, -12, -13, -22, + 23, -28, -10, -71, 4, -19, + -30, 18, -31, 39, 34, -32, + 14, -56, -22, -6, 7, -22, + -69, 4, 27, 48, -72, -32, + 1, -16, -32, 0, 20, 19, + -1, -26, -18, 29, -45, 7, + 29, -6, -15, -10, 2, -32, + 4, 2, 9, -13, -24, -24, + -2, -4, -20, 18, 39, 2, + -19, -11, 45, 62, 11, 6, + -33, -34, -23, 22, 16, 23, + 18, 23, 52, 5, 50, 48, + -53, 36, -51, 14, 22, 60, + 11, -24, -54, -42, 37, -14, + 27, -5, 47, -25, 48, 3, + -39, -60, -29, 47, -39, 28, + -11, 5, 6, -19, 42, 7, + -4, 13, -6, -11, 625, -142772, + 3081512, -23436068, 88543033, -191701755, 253750691, -209692355, + 106676515, -31628670, 4833320, -286363, 2528, 10, + 23, -15, 6, 3, -2, -34, + 59, 17, -5, -47, 2, -22, + -34, 19, -22, 5, 11, 75, + -28, -43, 37, 1, 47, 51, +}; diff --git a/test/cmocka/src/math/fft/ref_fft_multi_3072_32.h b/test/cmocka/src/math/fft/ref_fft_multi_3072_32.h new file mode 100644 index 000000000000..25e70400ccf6 --- /dev/null +++ b/test/cmocka/src/math/fft/ref_fft_multi_3072_32.h @@ -0,0 +1,2068 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 20-Nov-2025 16:11:52 with script ref_fft_multi.m v1.9-rc1-6882-ge0b90b605-dirty */ + +#define REF_SOFM_FFT_MULTI_3072_NUM_TESTS 1 + +static const int32_t fft_in_real_3072_q31[3072] = { + 372, -3573, -1008, 217, -780, 436, + -1549, -852, -2495, 1920, -990, 2031, + -1837, -1265, 107, -2253, 2173, -458, + 3792, -194, 423, 799, 701, 1111, + -2804, -608, 1177, -1518, 168, 1765, + 705, -254, -3040, 1816, -2288, -285, + -1613, -1936, 688, -3208, -4065, -349, + -966, -1253, -1, 817, 111, -3848, + 205, 1017, -2528, 2877, 174, -1019, + 2896, 307, 1621, 520, 3704, 931, + 823, 2510, 3310, 1172, 4812, 931, + 1606, 2074, 2256, -1087, 2452, 758, + 589, 2385, 1960, -2318, -2127, -4529, + -4734, 105, -4991, -7191, -4860, -5616, + -2791, -5424, -4297, -5662, -8319, -6945, + -5017, -2177, -4699, -1601, 604, -43, + 1878, 3462, 1152, 1164, 2308, 5171, + 8093, 6337, 9436, 9868, 12643, 11458, + 11732, 12804, 8785, 10229, 11049, 12522, + 10680, 5304, 6307, 3106, 6523, 1343, + 258, -3209, -4227, -5295, -7664, -10933, + -9853, -13973, -18784, -16492, -20604, -22894, + -19663, -21716, -19330, -19486, -20742, -19535, + -16630, -15494, -14231, -10701, -8950, -5354, + -2341, 157, 6564, 11704, 18055, 14585, + 21646, 28327, 29665, 32553, 35738, 35431, + 38650, 39954, 38001, 43701, 38676, 35777, + 37697, 30835, 28715, 23077, 16120, 10116, + 1842, -2231, -12878, -19231, -23871, -33268, + -39644, -46730, -52379, -58782, -59834, -67902, + -68580, -70729, -72311, -70437, -71116, -65100, + -62389, -52520, -45857, -39326, -26646, -17904, + -5812, 7728, 15285, 31013, 43597, 56440, + 68135, 76812, 89464, 101782, 109968, 113335, + 121569, 117890, 122090, 118167, 117262, 109348, + 104021, 95523, 81365, 63317, 50309, 32668, + 13461, -7822, -28259, -51658, -72664, -91775, + -115036, -131884, -148209, -161626, -176665, -186642, + -198422, -201251, -204468, -199154, -194769, -184574, + -170630, -155814, -133647, -111067, -82874, -53815, + -23251, 8690, 45733, 77325, 109576, 147709, + 178113, 208648, 234279, 261877, 284629, 296896, + 312298, 317591, 320982, 318739, 305377, 291686, + 270019, 245901, 215298, 175604, 137830, 90294, + 41554, -10071, -62629, -117838, -169306, -223248, + -270854, -323501, -368270, -403786, -438021, -462004, + -483065, -495690, -501584, -494599, -479802, -453999, + -421113, -384132, -333536, -274847, -214043, -141020, + -68871, 9322, 93150, 174657, 257553, 338309, + 414683, 487699, 555110, 613887, 662617, 705407, + 734778, 750029, 756904, 750785, 728812, 693681, + 641368, 582598, 505227, 422816, 325847, 224093, + 111558, -5393, -128174, -253153, -371497, -497447, + -611885, -720876, -818284, -911629, -982314, -1042069, + -1089267, -1113410, -1121889, -1111498, -1080988, -1028361, + -955932, -867286, -759764, -631297, -494221, -341335, + -174492, -1266, 175797, 353877, 535388, 712596, + 885107, 1043835, 1190169, 1319079, 1429815, 1519748, + 1579473, 1619092, 1633179, 1618264, 1574576, 1499577, + 1397206, 1267140, 1106626, 928445, 727130, 507505, + 271402, 21420, -236596, -495465, -757620, -1006830, + -1249141, -1479683, -1690633, -1879331, -2034859, -2165655, + -2256619, -2315157, -2332427, -2310891, -2246487, -2143264, + -1999884, -1816213, -1596280, -1342502, -1052822, -742495, + -407978, -57316, 304579, 672838, 1038655, 1398459, + 1742918, 2065247, 2365675, 2631021, 2853345, 3036470, + 3167820, 3249898, 3281470, 3252625, 3164310, 3019310, + 2822626, 2564728, 2259683, 1900120, 1508700, 1070684, + 603408, 110951, -392666, -903614, -1414802, -1912902, + -2392206, -2845130, -3258570, -3627149, -3940690, -4191313, + -4381803, -4499619, -4541815, -4504007, -4388011, -4192289, + -3919064, -3569292, -3147477, -2658923, -2113464, -1518547, + -874826, -209524, 487728, 1191134, 1892304, 2573893, + 3234254, 3855470, 4423871, 4927377, 5359814, 5713992, + 5972621, 6140505, 6199387, 6153667, 5998277, 5738563, + 5368890, 4896998, 4329184, 3671418, 2930085, 2121158, + 1254388, 347574, -591983, -1544910, -2490043, -3420032, + -4315360, -5152121, -5921191, -6611696, -7199706, -7679390, + -8034751, -8257121, -8346135, -8290828, -8093048, -7744783, + -7254418, -6630540, -5870181, -4992728, -4006965, -2925017, + -1770290, -553992, 701532, 1972732, 3243885, 4485736, + 5676566, 6798847, 7830355, 8753293, 9542274, 10185538, + 10668092, 10977869, 11100656, 11039240, 10778861, 10326862, + 9684417, 8861605, 7863637, 6708489, 5407284, 3980889, + 2454492, 851943, -806049, -2488656, -4160522, -5801884, + -7381535, -8865301, -10234725, -11457830, -12501687, -13359571, + -14004580, -14421804, -14594932, -14515706, -14190718, -13607659, + -12780027, -11711622, -10410644, -8902247, -7209085, -5351692, + -3360190, -1266353, 892180, 3085982, 5277651, 7423286, + 9487880, 11431794, 13220058, 14818486, 16199378, 17322667, + 18173106, 18731015, 18968208, 18891463, 18480248, 17738440, + 16674383, 15296941, 13630301, 11690888, 9508065, 7111137, + 4541597, 1838855, -953433, -3788691, -6620413, -9392119, + -12060485, -14576464, -16894758, -18969314, -20757213, -22224208, + -23337383, -24068281, -24396675, -24314555, -23807617, -22876611, + -21528574, -19784004, -17663705, -15191458, -12403961, -9347173, + -6060577, -2608229, 959950, 4586727, 8204034, 11755744, + 15172504, 18397037, 21372442, 24033132, 26334534, 28221481, + 29661590, 30621139, 31064526, 30984600, 30361616, 29206481, + 27520780, 25328643, 22655207, 19532705, 16011679, 12149179, + 7998202, 3629080, -886601, -5477122, -10060474, -14562086, + -18899133, -22989928, -26765395, -30151720, -33079322, -35496765, + -37343077, -38580863, -39174876, -39103667, -38354970, -36935358, + -34846029, -32114319, -28772721, -24876871, -20476549, -15641187, + -10440364, -4966127, 700841, 6459485, 12215659, 17866676, + 23313028, 28458228, 33210198, 37478907, 41172064, 44232678, + 46576561, 48163284, 48945603, 48900048, 48012912, 46278450, + 43710721, 40344152, 36215687, 31392482, 25936258, 19939304, + 13485840, 6683808, -355573, -7517128, -14679416, -21710106, + -28499406, -34910051, -40834645, -46165701, -50790443, -54626140, + -57579532, -59598013, -60619069, -60618781, -59567039, -57473025, + -54351412, -50233342, -45186383, -39261858, -32564132, -25185248, + -17241901, -8866923, -191879, 8633665, 17460936, 26143204, + 34521609, 42447110, 49780242, 56379237, 62120194, 66881659, + 70575603, 73119678, 74443740, 74499636, 73282198, 70781179, + 67012890, 62026148, 55887344, 48687496, 40526263, 31529575, + 21836507, 11612109, 1012091, -9779981, -20582181, -31204035, + -41466004, -51182619, -60176524, -68284491, -75345078, -81225915, + -85799183, -88971434, -90663991, -90821930, -89419903, -86450743, + -81949463, -75956415, -68564796, -59875217, -50011014, -39129949, + -27400942, -15013360, -2168850, 10917793, 24023847, 36925822, + 49394121, 61211286, 72157333, 82036329, 90656560, 97852309, + 103475793, 107411172, 109549870, 109844745, 108245148, 104766008, + 99424144, 92289308, 83453912, 73051237, 61227750, 48165694, + 34079160, 19189890, 3741027, -12005929, -27789733, -43333372, + -58369825, -72626480, -85852717, -97799740, -108240568, -116984834, + -123841326, -128673829, -131365348, -131830251, -130042187, -125987529, + -119708342, -111271729, -100800507, -88439340, -74371460, -58820447, + -42024813, -24265428, -5823474, 12987814, 31851444, 50439832, + 68434255, 85515447, 101367399, 115712690, 128275627, 138809813, + 147111488, 153005021, 156352343, 157056501, 155072568, 150396562, + 143063101, 133170013, 120845814, 106268769, 89657765, 71271888, + 51399185, 30366381, 8513394, -13791446, -36175759, -58247278, + -79630509, -99940520, -118815593, -135911795, -150904974, -163518047, + -173494300, -180628604, -184757144, -185767143, -183596719, -178244443, + -169749533, -158227572, -143833336, -126769181, -107293920, -85709208, + -62364441, -37631290, -11919266, 14347827, 40716579, 66739386, + 91969993, 115952914, 138266858, 158500447, 176282916, 191272406, + 203177017, 211746908, 216794498, 218182573, 215846442, 209774794, + 200015892, 186692556, 169994049, 150152492, 127483522, 102323384, + 75084856, 46201855, 16153098, -14559068, -45419047, -75892600, + -105455486, -133589527, -159788255, -183572055, -204512930, -222207105, + -236312548, -246537938, -252661829, -254527285, -252044844, -245204000, + -234070892, -218777349, -199540150, -176640610, -150422459, -121292087, + -89721942, -56221556, -21340285, 14334216, 50205554, 85654350, + 120069924, 152846317, 183399211, 211180614, 235673463, 256424814, + 273019784, 285138036, 292514936, 294953678, 292364878, 284724191, + 272110317, 254679055, 232666741, 206401006, 176282044, 142782930, + 106435316, 67827972, 27606004, -13567407, -54989891, -95960432, + -135762579, -173703133, -209109185, -241342374, -269808493, -293980021, + -313386899, -327646179, -336453636, -339592042, -336942587, -328480069, + -314289983, -294549465, -269535128, -239608257, -205233219, -166948378, + -125366856, -81167440, -35076509, 12137668, 59676374, 106721077, + 152465978, 196107885, 236879838, 274040630, 306911433, 334892873, + 357441507, 374108431, 384553642, 388516901, 385863592, 376571435, + 360716345, 338509581, 310254184, 276376144, 237395341, 193917688, + 146647470, 96356984, 43868781, -9933526, -64145444, -117835189, + -170084338, -219972544, -266627410, -309204586, -346936289, -379122173, + -405155218, -424514827, -436810151, -441744679, -439162883, -429030505, + -411439631, -386617413, -354911037, -316798931, -272863878, -223795489, + -170394207, -113517117, -54112101, 6829649, 68271983, 129181249, + 188492354, 245177826, 298242279, 346730695, 389776661, 426578154, + 456438915, 478787617, 493156906, 499218782, 496797130, 485840086, + 466453824, 438883546, 403526720, 360909157, 311693565, 256651431, + 196672699, 132738813, 65908364, -2703538, -71935942, -140613095, + -207543775, -271573069, -331567032, -386461954, -435270224, -477095415, + -511150801, -536776982, -553457499, -560821589, -558658317, -546905800, + -525675660, -495251147, -456064122, -408695891, -353884464, -292507426, + -225550806, -154103971, -79358011, -2561945, 74990922, 151974456, + 227067781, 298963701, 366402727, 428187197, 483209074, 530460127, + 569065103, 598275256, 617513188, 626357580, 624559602, 612058838, + 588971043, 555592552, 512412748, 460076790, 399404508, 331355368, + 257033083, 177659157, 94542334, 9080697, -77291728, -163095921, + -246863323, -327129624, -402505892, -471643480, -533307653, -586384181, + -629887100, -662983451, -685030545, -695536926, -694237467, -681049278, + -656096022, -619710506, -572410016, -514922467, -448143694, -373128295, + -291109814, -203423941, -111523060, -16946439, 78702051, 173797563, + 266709385, 355818638, 439585563, 516517252, 585239763, 644525256, + 693261354, 730544741, 755634274, 768002388, 767333019, 753544351, + 726750519, 687313547, 635808270, 573021365, 499930935, 417715763, + 327699155, 231373047, 130330697, 26255704, -79077473, -183883762, + -286364208, -384749243, -477322091, -562450927, -638620614, -704458584, + -758759964, -800505747, -828885262, -843307676, -843428140, -829125298, + -800541387, -758052984, -702291149, -634095686, -554553702, -464934785, + -366695229, -261454617, -150966943, -37076378, 78289104, 193169085, + 305591559, 413616449, 515365690, 609043518, 692999321, 765716588, + 825874492, 872350263, 904253049, 920935675, 921993322, 907300938, + 876995158, 831492911, 771451746, 697804425, 611711609, 514553983, + 407924116, 293581677, 173416032, 49451086, -76220456, -201456944, + -324120836, -442096257, -553320447, -655855947, -747885861, -827768799, + -894049560, -945498889, -981150629, -1000271847, -1002432788, -987484122, + -955566735, -907106665, -842823854, -763720833, -671044190, -566294105, + -451177423, -327601471, -197612754, -63402956, 72760120, 208568511, + 341689943, 469838167, 590782890, 702408508, 802758269, 890034724, + 962657597, 1019303575, 1058896759, 1080652859, 1084088210, 1069029598, + 1035618264, 984312724, 915867520, 831363489, 732141019, 619797883, + 496179013, 363327875, 223462244, 78928184, -67831872, -214319471, + -358035612, -496500520, -627323350, -748214481, -857046183, -951889165, + -1031049603, -1093062609, -1136780159, -1161344249, -1166220616, -1151212846, + -1116462912, -1062447094, -989978191, -900185174, -794510265, -674662535, + -542611316, -400546431, -250829785, -95990652, 61366328, 218558108, + 372901738, 521744570, 662502854, 792737450, 910165194, 1012696160, + 1098503418, 1166031146, 1214025412, 1241556119, 1248038839, 1233252312, + 1197338095, 1140793802, 1064472412, 969574944, 857621750, 730435938, + 590107881, 438968868, 279545499, 114515179, -53332932, -221139123, + -386045481, -545210951, -695893623, -835474544, -961505113, -1071770327, + -1164307836, -1237438055, -1289820122, -1320452961, -1328709383, -1314332855, + -1277452999, -1218591232, -1138644358, -1038871318, -920887278, -786611045, + -638256294, -478293717, -309395514, -134403655, 43716046, 221948477, + 397235398, 566578363, 727061393, 875885710, 1010467343, 1128436049, + 1227704280, 1306480900, 1363339414, 1397194675, 1407372472, 1393581163, + 1355953850, 1295026075, 1211729278, 1107379980, 983679487, 842642384, + 686602223, 518156042, 340129235, 155518548, -32551931, -220890139, + -406278195, -585537160, -755583489, -913469206, -1056447718, -1182017615, + -1287952094, -1372373602, -1433740315, -1470904340, -1483138314, -1470125229, + -1431990546, -1369269446, -1282934208, -1174373193, -1045338593, -897949621, + -734659284, -558177505, -371469791, -177689875, 19897308, 217914039, + 413000387, 601804247, 781081356, 947739871, 1098873275, 1231848458, + 1344327873, 1434310884, 1500178253, 1540716776, 1555129431, 1543082456, + 1504676705, 1440471424, 1351471197, 1239098180, 1105185347, 951941327, + 781912112, 597936823, 403109189, 200711702, -5827201, -212996516, + -417263748, -615131936, -803202303, -978233490, -1137186723, -1277303294, + -1396118945, -1491537327, -1561856292, -1605781912, -1622476857, -1611576361, + -1573161776, -1507803264, -1416525319, -1300803759, -1162529626, -1003997711, + -827837307, -637004368, -434709124, -224359341, -9529003, 206138691, + 418964803, 625310311, 821624595, 1004540605, 1170892708, 1317790091, + 1442669662, 1543328211, 1617988707, 1665290217, 1684351248, 1674761398, + 1636600581, 1570429050, 1477314812, 1358748196, 1216694357, 1053500806, + 871896317, 674924682, 465908519, 248377622, 26015600, -197400277, + -418050818, -632173339, -836090410, -1026306638, -1199532255, -1352774350, + -1483362532, -1589011002, -1667857340, -1718486144, -1739962335, -1731840810, + -1694189001, -1627581900, -1533073579, -1412215425, -1266999164, -1099845212, + -913551939, -711244528, -496342110, -272477568, -43447743, 186853426, + 414497132, 635604535, 846382113, 1043217377, 1222716978, 1381788493, + 1517666640, 1627985742, 1710809548, 1764671488, 1788582982, 1782076477, + 1745200236, 1678510858, 1583099752, 1460517021, 1312810748, 1142441329, + 952273264, 745504463, 525629176, 296376863, 61629633, -174618632, + -408342794, -635547128, -852353972, -1055045659, -1240135324, -1404435561, + -1545115420, -1659730825, -1746277289, -1803232403, -1829574223, -1824802377, + -1788944079, -1722556598, -1626725028, -1503023090, -1353527120, -1180736052, + -987563716, -777264704, -553397694, -319761871, -80318116, 160854501, + 399645250, 631985939, 853909923, 1061611331, 1251535092, 1420412831, + 1565341387, 1683811150, 1773776008, 1833654782, 1862391453, 1859458840, + 1824851861, 1759129786, 1663371340, 1539171366, 1388613977, 1214226218, + 1018956327, 806101706, 579277790, 342327686, 99281607, -145729280, + -388524088, -624973189, -851026538, -1062835803, -1256769433, -1429499244, + -1578069680, -1699911201, -1792938289, -1855528096, -1886587771, -1885558778, + -1852429664, -1787734857, -1692550025, -1568466400, -1417586538, -1242447341, + -1046019000, -831624085, -602913005, -363765229, -118251153, 129457667, + 375134811, 614592317, 843748087, 1058698271, 1255758464, 1431568802, + 1583117023, 1707808398, 1803500889, 1868550498, 1901833106, 1902758600, + 1871299790, 1807979837, 1713850848, 1590514279, 1440046976, 1265017072, + 1068378419, 853480525, 623981978, 383772466, 136960898, -112268288, + -359659896, -601003283, -832179172, -1049261809, -1248533101, -1426603183, + -1580432180, -1707395953, -1805328349, -1872549473, -1907910206, -1910814775, + -1881202917, -1819574231, -1726982026, -1604991549, -1455688417, -1281609582, + -1085722448, -871357291, -642173873, -402075571, -155147588, 94400620, + 342321129, 584394446, 816488006, 1034659652, 1235193836, 1414674308, + 1570050564, 1698682278, 1798381561, 1867461880, 1904745928, 1909621460, + 1882002289, 1822370756, 1731752675, 1611705013, 1464279579, 1291998030, + 1097801079, 885007491, 657247751, 418407719, 172550487, -76118746, + -323372208, -565006313, -796894006, -1015107018, -1215927812, -1395948753, + -1552119395, -1681790895, -1782774050, -1853366552, -1892385206, -1899187777, + -1873679839, -1816317016, -1728099817, -1610555232, -1465702231, -1296030798, + -1104443064, -894224213, -668970217, -432524377, -188922860, 57680630, + 303083765, 543111971, 773679620, 990878213, 1191015166, 1370695312, + 1526895364, 1656961023, 1758718736, 1830458745, 1870990611, 1879657894, + 1856353863, 1801500924, 1716067064, 1601550638, 1459926812, 1293641207, + 1105551152, 898884149, 677182586, 444237696, 204031857, -39343627, + -281736298, -519024737, -747172550, -962310633, -1160791510, -1339271328, + -1494719175, -1624541086, -1726550849, -1799056437, -1840866215, -1851310975, + -1830256497, -1778117519, -1695817922, -1584815664, -1447032134, -1284862167, + -1101102449, -898911555, -681766646, -453381107, -217659996, 21366015, + 259627334, 493072531, 717731912, 929796840, 1125686578, 1302092995, + 1456042960, 1584965877, 1686703884, 1759582038, 1802411351, 1814517128, + 1795746957, 1746490037, 1667630110, 1560571974, 1427195337, 1269816814, + 1091157415, 894309346, 682655783, 459821541, 229631191, -3993204, + -237059049, -465606052, -685758770, -893780837, -1086166235, -1259671231, + -1411385009, -1538774911, -1639722862, -1712573317, -1756151511, -1769778723, + -1753291016, -1707044018, -1631880689, -1529156784, -1400686108, -1248703573, + -1075859349, -885148396, -679846603, -463496048, -239788111, -12560535, + 214318802, 436987939, 651666136, 854732389, 1042749336, 1212562328, + 1361331574, 1486573736, 1586227826, 1658651760, 1702702242, 1717695626, + 1703457825, 1660303465, 1589051490, 1490989763, 1367859974, 1221822045, + 1055420110, 871556095, 673397091, 464356944, 248014359, 28080829, + -191693218, -407572184, -615900079, -813149545, -995996567, -1161375920, + -1306531882, -1429044334, -1526907572, -1598523621, -1642761569, -1658943247, + -1646894744, -1606892066, -1539710329, -1446580159, -1329162799, -1189527590, + -1030127747, -853735167, -663407611, -462418808, -254229501, -42399820, + 169456638, 377724875, 578889840, 769552187, 946493762, 1106754813, + 1247677619, 1366914015, 1462520817, 1532951923, 1577094138, 1594286405, + 1584336159, 1547503054, 1484508014, 1396513358, 1285105867, 1152266026, + 1000323211, 831943670, 650031253, 457742924, 258379751, 55360097, + -147846433, -347791305, -541082791, -724454616, -894833732, -1049361614, + -1185484687, -1300948925, -1393867554, -1462752654, -1506521824, -1524533384, + -1516574802, -1482884630, -1424136518, -1341432851, -1236268049, -1110524433, + -966418198, -806474656, -633479500, -450427103, -260466143, -66854834, + 127098863, 318089721, 502893013, 678382955, 841619455, 989876004, + 1120697339, 1231931272, 1321770079, 1388772538, 1431906568, 1450534876, + 1444442644, 1413845056, 1359367791, 1282042512, 1183277772, 1064854075, + 928867553, 777701643, 614003268, 440609784, 260505083, 76790900, + -107401371, -288931568, -464730053, -631836635, -787442491, -928965186, + -1054051161, -1160657065, -1247066123, -1311885917, -1354123223, -1373168202, + -1368802284, -1341216760, -1290982804, -1219066595, -1126792942, -1015826842, + -888151193, -746007399, -591889851, -428465269, -258572080, -85121742, + 88920688, 260585671, 426981992, 585294900, 732878617, 867277717, + 986273316, 1087923620, 1170580702, 1232948145, 1274057596, 1293321664, + 1290530992, 1265838308, 1219781089, 1153257231, 1067495900, 964056608, + 844792140, 711809082, 567448255, 414212554, 254760785, 91832000, + -71785113, -233304073, -389994059, -539215391, -678473322, -805453139, + -918071312, -1014479841, -1093139146, -1152809828, -1192574868, -1211869926, + -1210493120, -1188564867, -1146588764, -1085378215, -1006085479, -910161450, + -799328092, -675557523, -541026496, -398078579, -249185492, -96927040, + 56100459, 207288881, 354080272, 494009592, 624733114, 744082407, + 850101449, 941069115, 1015518946, 1072290089, 1110517423, 1129670265, + 1129533115, 1110223700, 1072184544, 1016169922, 943250152, 854763597, + 752304762, 637705517, 512980046, 380314890, 242012700, 100457755, + -41929112, -182717458, -319523659, -450054681, -572124060, -683719153, + -783001820, -868369330, -938460454, -992171022, -1028698784, -1047540077, + -1048477478, -1031607491, -997345635, -946379405, -879674816, -798478560, + -704259631, -598699131, -483675841, -361200006, -233396979, -102482690, + 29303374, 159718607, 286551799, 407675562, 521064808, 624853955, + 717339406, 797022340, 862641000, 913174146, 947865519, 966232390, + 968081056, 953484359, 922809892, 876682824, 816002928, 741894612, + 655708808, 559003777, 453484070, 341012181, 223536838, 103102585, + -18231207, -138395994, -255358187, -367155417, -471922910, -567935035, + -653617482, -727595050, -788689017, -835957241, -868699728, -886469086, + -889064437, -876548172, -849255973, -807751705, -752850349, -685578717, + -607173529, -519046712, -422764499, -320025539, -212631771, -102431653, + 8679050, 118808590, 226088922, 328724742, 424998537, 513330924, + 592282938, 660578068, 717148585, 761116085, 791826700, 808868239, + 812060341, 801441718, 777312861, 740179100, 690781536, 630052357, + 559110226, 479237115, 391866261, 298532311, 200875179, 100588108, + -610935, -100984350, -198848126, -292555400, -380546365, -461371121, + -533714162, -596419791, -648495691, -689153805, -717786679, -734004557, + -737643044, -728735072, -707539194, -674510633, -630315927, -575794155, + -511962755, -439967668, -361115320, -276796807, -188485656, -97721711, + -6063325, 84929152, 173707386, 258789883, 338754416, 412300822, + 478218897, 535461035, 583136381, 620504801, 647030016, 662347093, + 666298302, 658915851, 640421042, 611217389, 571909299, 523236434, + 466118540, 401593676, 330829977, 255074713, 175659977, 93973455, + 11414720, -70601436, -150685191, -227503101, -299773173, -366307069, + -426034100, -477991736, -521372745, -555521252, -579940444, -594295661, + -598442639, -592398963, -576367295, -550703332, -515942267, -472744367, + -421927480, -364422131, -301274182, -233603649, -162596392, -89494303, + -15558951, 57945069, 129779304, 198738559, 263672984, 323523850, + 377322092, 424207594, 463456672, 494471834, 516803451, 530158177, + 534393266, 529522630, 515724338, 493304606, 462743275, 424626320, + 379680922, 328730698, 272703820, 212598528, 149477147, 84438014, + 18611869, -46890812, -110948255, -172487905, -230496546, -284018556, + -332192437, -374254634, -409548650, -437541760, -457837031, -470164722, + -474394574, -470538855, -458739378, -439284058, -412572405, -379141514, + -339620640, -294741156, -245331348, -192260455, -136472440, -78951410, + -20681431, 37338334, 94122301, 148721185, 200232600, 247810779, + 290690901, 328188337, 359735133, 384848064, 403172538, 414463652, + 418610740, 415613591, 405605607, 388825120, 365626134, 336479343, + 301938434, 262645580, 219323579, 172743491, 123741607, 73166108, + 21901695, -29183784, -79217342, -127361553, -172827260, -214863245, + -252797135, -286027063, -314046252, -336431187, -352861785, -363131190, + -367130392, -364860806, -356427781, -342050458, -322027327, -296771219, + -266766470, -232577223, -194827396, -154198752, -111414668, -67220706, + -22389838, 22307679, 66124103, 108321476, 148198106, 185107523, + 218456075, 247717969, 272443667, 292266337, 306907078, 316173250, + 319972907, 318303699, 311259083, 299016458, 281848796, 260101048, + 234203589, 204633082, 171949718, 136725579, 99604730, 61231692, + 22273999, -16596878, -54722051, -91473029, -126228497, -158429158, + -187562194, -213164905, -234846275, -252286330, -265238700, -273536116, + -277094400, -275914375, -270072015, -259723698, -245095661, -226492133, + -204280400, -178876569, -150746899, -120409997, -88411434, -55305328, + -21667576, 11918194, 44883235, 76677980, 106780616, 134691029, + 159972434, 182226557, 201111853, 216348627, 227724715, 235098889, + 238395584, 237611210, 232806177, 224118037, 211737832, 195926515, + 176998172, 155309580, 131268918, 105312714, 77901800, 49526741, + 20677629, -8152943, -36463737, -63797045, -89689774, -113724824, + -135517472, -154731255, -171066319, -184289182, -194215635, -200718014, + -203729844, -203249948, -199333372, -192088472, -181686292, -168339828, + -152317100, -133929642, -113514481, -91450898, -68133602, -43973447, + -19397877, 5181202, 29338391, 52668207, 74790435, 95343031, + 114004002, 130473256, 144509701, 155902177, 164494452, 170183422, + 172913199, 172664116, 169497118, 163505317, 154823158, 143635522, + 130168501, 114678360, 97469233, 78842181, 59141556, 38714750, + 17918761, -2890580, -23352359, -43134629, -61902442, -79359178, + -95219793, -109241655, -121213199, -130959126, -138341127, -143279885, + -145714907, -145650458, -143112905, -138187337, -130992820, -121679590, + -110437544, -97489588, -83076189, -67465699, -50939873, -33792500, + -16322159, 1168621, 18385872, 35036145, 50842116, 65557638, + 78945236, 90795089, 100928151, 109206567, 115506792, 119754384, + 121907623, 121965051, 119953463, 115936809, 110018616, 102324285, + 93009785, 82258499, 70282778, 57293087, 43527865, 29239498, + 14664699, 70861, -14299001, -28213778, -41434394, -53740906, + -64954354, -74898839, -83413372, -90382889, -95713352, -99339509, + -101224772, -101365811, -99785822, -96538276, -91706578, -85398224, + -77737953, -68883543, -59001121, -48272419, -36897641, -25072795, + -13015236, -928046, 10981346, 22514261, 33483859, 43710738, + 53031141, 61298934, 68403208, 74226528, 78703859, 81766293, + 83402166, 83593718, 82365139, 79763031, 75844981, 70710156, + 64464541, 57223854, 49132714, 40341451, 31011508, 21310849, + 11407368, 1476260, -8314581, -17806980, -26836240, -35256930, + -42939854, -49774817, -55645608, -60473208, -64195712, -66770589, + -68169750, -68386355, -67439994, -65369396, -62224639, -58081970, + -53024988, -47151459, -40577074, -33432655, -25843582, -17943272, + -9879653, -1786795, 6204057, 13943017, 21315103, 28198305, + 34483247, 40076675, 44890339, 48859763, 51930920, 54068789, + 55255655, 55479959, 54760676, 53131015, 50625910, 47308295, + 43244014, 38521353, 33230411, 27468337, 21346443, 14969441, + 8451097, 1911594, -4546380, -10811070, -16777372, -22352502, + -27448560, -31988943, -35903458, -39138144, -41648387, -43410944, + -44400727, -44621343, -44081728, -42808165, -40830393, -38198108, + -34962490, -31195794, -26971588, -22366339, -17469059, -12364939, + -7146798, -1904260, 3270688, 8291813, 13081852, 17556488, + 21651104, 25302659, 28458917, 31067904, 33104793, 34537546, + 35361975, 35568405, 35171243, 34183205, 32633364, 30558842, + 28008752, 25031682, 21689735, 18045101, 14159915, 10112948, + 5974900, 1811564, -2298588, -6289153, -10097187, -13660268, + -16919025, -19831526, -22344434, -24432003, -26066684, -27225918, + -27897027, -28086260, -27792985, -27036877, -25834713, -24221524, + -22225205, -19892344, -17274057, -14413387, -11365046, -8183432, + -4931257, -1661870, 1574892, 4716073, 7715537, 10517058, + 13094848, 15384977, 17377333, 19030984, 20328238, 21250991, + 21798830, 21964593, 21748393, 21175692, 20254116, 19005897, + 17462773, 15654865, 13621029, 11397319, 9026624, 6554408, + 4021974, 1473276, -1045124, -3494283, -5828872, -8019481, + -10025125, -11819321, -13375815, -14668543, -15689994, -16418956, + -16857296, -16995023, -16846583, -16415125, -15716033, -14759735, + -13579195, -12195213, -10628145, -8917589, -7096262, -5190286, + -3236944, -1276058, 664754, 2555441, 4356032, 6042109, + 7595282, 8978157, 10184344, 11185233, 11977764, 12548965, + 12893033, 13012020, 12907487, 12584782, 12058266, 11340230, + 10442126, 9390046, 8200237, 6899404, 5512572, 4061687, + 2576181, 1082059, -399648, -1840723, -3216302, -4503358, + -5687931, -6747557, -7663720, -8435769, -9042960, -9483154, + -9751663, -9850907, -9778461, -9539916, -9147874, -8613425, + -7936567, -7146604, -6254913, -5277446, -4230376, -3136291, + -2020988, -890678, 223543, 1308679, 2340192, 3311287, + 4208466, 5007097, 5699297, 6284284, 6744247, 7081498, + 7287208, 7366198, 7318562, 7141633, 6855926, 6457825, + 5963094, 5371511, 4712336, 3985065, 3203226, 2395092, + 1563689, 724529, -106180, -913239, -1684731, -2407744, + -3072538, -3667103, -4189285, -4623149, -4965217, -5220752, + -5374082, -5440210, -5406704, -5282249, -5070729, -4783594, + -4415459, -3989230, -3500736, -2970824, -2398253, -1803663, + -1193152, -574547, 34052, 628024, 1193352, 1723345, + 2216278, 2654349, 3031779, 3355709, 3608106, 3794901, + 3913643, 3960671, 3940274, 3855545, 3701699, 3492897, + 3230771, 2919037, 2567523, 2182907, 1769008, 1336204, + 894476, 450016, 4193, -419198, -833301, -1219488, + -1571324, -1888273, -2167536, -2401825, -2582554, -2722866, + -2806550, -2845009, -2831941, -2765462, -2661468, -2513744, + -2323485, -2105147, -1854412, -1580356, -1286629, -975301, + -656393, -339857, -25917, 279482, 571766, 848201, + 1100367, 1327317, 1524758, 1690162, 1819819, 1918854, + 1980841, 2008787, 1998777, 1955867, 1882817, 1780155, + 1648781, 1489634, 1319263, 1122357, 915235, 703731, + 481879, 255745, 35727, -179285, -387338, -576268, + -757789, -914450, -1054956, -1171327, -1261362, -1329783, + -1378263, -1393224, -1392519, -1361178, -1306723, -1240796, + -1149249, -1040253, -919112, -788188, -644100, -491012, + -342989, -186968, -35569, 111048, 254402, 388767, + 509286, 617211, 714449, 793277, 860190, 907067, + 935048, 948515, 946097, 928525, 896936, 846039, + 783146, 710400, 630008, 540362, 441121, 340845, + 239764, 133643, 30048, -71439, -166063, -251751, + -336514, -413690, -476442, -527614, -569975, -607659, + -628455, -633038, -634976, -620199, -598848, -564510, + -525244, -476398, -419249, -365706, -299017, -231986, + -163672, -92415, -26440, 38907, 105485, 163003, + 216292, 267479, 308792, 345665, 374432, 397776, + 404976, 414881, 412461, 405962, 388957, 369428, + 345535, 309636, 276555, 239076, 192795, 150978, + 104505, 65702, 20859, -25024, -65606, -102706, + -135673, -165912, -198790, -220192, -234479, -251306, + -260362, -266001, -259886, -260002, -248657, -234334, + -217503, -202297, -179055, -150768, -125468, -98832, + -72894, -42018, -16516, 10166, 39386, 62450, + 82544, 102115, 120459, 135598, 149235, 157042, + 158816, 163383, 162876, 159670, 151270, 148796, + 135741, 125439, 109131, 94537, 77595, 61876, + 45016, 28294, 13536, -6488, -22571, -33842, + -48832, -63638, -72140, -79993, -87569, -91387, + -95105, -99573, -95906, -97510, -90434, -89172, + -80757, -73767, -68179, -54591, -49098, -38081, + -30096, -17678, -7483, 5124, 12679, 18818, + 30341, 33042, 42717, 49133, 51057, 55150, + 58448, 56577, 55508, 55179, 54289, 49140, + 48421, 43652, 34986, 33365, 29958, 21943, + 13434, 9563, 6068, -2185, -7641, -11314, + -14491, -18527, -21375, -25536, -28757, -27068, + -31902, -32247, -31210, -32378, -28844, -28972, + -26917, -25630, -19653, -19191, -12051, -13582, + -4826, -5962, -4862, 33, 4819, 6114, + 9049, 8981, 14172, 14118, 15072, 15034, + 13362, 14617, 16282, 17865, 16105, 14323, + 10499, 14625, 9801, 12096, 5293, 8147, + 4763, 1429, -173, 295, 161, -2375, + -3393, -8030, -6053, -7764, -7193, -6627, + -9527, -5178, -9881, -4584, -6991, -9292, + -4680, -4957, -5201, -6648, -1473, -1584, + -1987, -2221, 2201, 2720, -1950, 3637, + 2274, 2021, -940, 2507, 2115, 4251, + 1166, 6089, 4628, 2775, 1047, 4879, + 3630, 4012, 4345, 3681, -266, 1657, + 2323, 829, 3660, 1100, -605, 876, + -165, -2762, 1204, -1477, 1170, 1144, + -1294, 1092, -473, -2287, 641, -3627, + 953, -4014, -3664, 1544, -1398, -3629, + 880, -264, 338, 1087, 1064, 578, + 1306, 2399, 218, -903, 3089, 1797, + 434, 3576, 2306, 1934, 3420, 2750, + 373, -2829, -1670, 851, 1698, 227, + 3297, -3177, -2034, 108, -559, 2858, + -1395, -1436, -3109, 2556, -1476, -899, + 232, -2557, -1521, -2150, 1048, -826, +}; + +static const int32_t fft_in_imag_3072_q31[3072] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +}; + +static const int32_t fft_ref_real_3072_q31[3072] = { + -45, 22, 19, -6, 19, -10, + 21, 10, -22, 11, -4, -26, + -5, -42, 5, 6, 9, -28, + -19, 5, 4, 13, -6, -24, + -4, -32, -14, -5, -21, -19, + -14, 5, 1, 12, 17, -4, + 17, 6, -31, -49, 6, -14, + -10, 43, -3, -29, -20, -4, + 1, -37, 37, -25, 21, -56, + -6, 6, -12, 10, -2790, 237344, + -3579960, 21781560, -69391869, 129763729, -149772245, 107836740, + -47262115, 11753740, -1421223, 57093, -178, -10, + 16, -20, 6, -4, -33, -18, + -22, -12, -20, -5, -33, -9, + 0, 2, -36, 15, 11, 36, + 45, 16, 26, -15, 15, -13, + -4, 17, 24, 17, -4, 0, + 13, -19, 17, -3, 20, 11, + -26, -11, 3, 0, -12, 26, + 20, 10, 42, -8, -16, -56, + 4, -8, 11, 8, 40, -9, + 5, -40, 20, -4, 19, -17, + 11, -9, -21, -16, 31, 31, + 0, 36, -14, 0, 2, -9, + -35, -37, -37, 37, -6, -2, + -35, 3, -19, -11, 11, -3, + -5, -15, -4, 34, 0, 5, + -27, 10, 28, -14, 26, -20, + -27, 2, -4, 32, 12, 13, + -4, -19, 25, 30, 0, 2, + 7, 21, -28, -10, -21, 10, + -4, -8, 8, -1, -8, 35, + -18, -8, -20, 5, -17, 3, + 2, 11, -22, -13, 3, 27, + 8, 34, 6, -17, 31, -17, + 31, -34, -8, 0, 9, 5, + -22, 2, 19, -19, 8, 5, + 16, -8, 26, 6, 4, 21, + 25, -7, 11, -34, -4, 17, + 11, -1, -20, -28, -6, -38, + -7, 17, 15, -11, 32, -1, + 8, 21, -8, 30, -55, -19, + -14, -10, 8, 8, -14, -21, + 15, 27, 5, -12, 9, -24, + -7, -3, -8, -20, -14, -7, + 6, -28, -3, 1, -6, -21, + -21, 2, -22, 44, -5, -25, + -34, 18, 19, 5, 9, 23, + 7, 6, -20, 22, 0, -13, + 51, 11, 2, -16, -6, 0, + 8, -6, 0, 18, 16, 22, + 10, -7, -54, -11, -18, -8, + 5, 27, 12, -17, -24, 13, + 11, 9, 2, -12, 23, 0, + 12, 31, -14, 12, 9, 24, + 2, -1, 32, -8, 11, -9, + 26, 6, -1, -3, 7, 57, + -20, 10, 8, 13, -24, 3, + -7, -29, 46, 30, 0, 22, + -2, -20, 39, 24, -15, -2, + -2, 7, -16, -50, 29, -7, + -22, 23, 19, -21, -29, -22, + 32, -4, 9, -14, -20, -17, + -12, 2, -19, -24, 10, 22, + 10, 14, -15, -3, -41, -20, + 3, 6, 20, 10, 8, -11, + -4, 10, 2, -19, -10, 41, + -8, -6, -36, -35, -11, 0, + -11, 1, -3, -16, 12, -14, + -28, 2, 6, -10, -14, -2, + 14, 10, -7, -13, 37, 17, + -1, 12, 9, -37, 34, -36, + 7, 8, 4, -13, 22, 24, + 19, 0, 24, 26, -33, -30, + 28, 19, -26, 20, -29, -12, + -2, -25, -26, 1, 3, 43, + -4, -12, -23, 4, -19, 21, + -34, -3, 55, -20, -29, -23, + 30, 51, 13, -15, 10, 9, + 17, -28, -23, -16, 64, -1, + 5, 10, -4, 29, 26, -7, + 18, -37, -24, 49, -18, 11, + -15, -29, 34, -2, -15, -17, + -6, 16, -15, 7, 29, -9, + 23, 18, 10, -10, 23, -33, + 28, -19, -1, 31, -13, 5, + -5, -47, -21, 29, 4, 13, + -7, -19, 2, 9, -31, 3, + 3, -3, 4, -1, -32, -34, + -11, -29, 11, -7, 44, 13, + -25, -12, -21, 6, 5, -6, + 71, -5, -4, 25, -4, -6, + -39, 16, -26, 9, -2, -14, + -3, -7, -5, -8, -21, -20, + -25, 9, 10, 2, -44, 2, + 16, 3, 31, 8, -16, -5, + 6, -7, 9, 7, 3, -15, + -13, 11, -44, 11, -4, 14, + 15, 6, -39, -2, -23, 9, + 13, -48, 19, 9, 7, -24, + 15, 43, -17, 40, 6, -26, + -36, 2, -30, 28, 8, -5, + -16, -20, 25, 48, -17, -6, + -45, 31, 7, 5, 27, 21, + 19, 36, -25, 18, 4, 3, + -20, -23, 8, -27, 27, -8, + -20, 23, -18, -13, -12, 13, + 2, 1, 15, 23, -10, 24, + -42, -46, 54, 18, -13, -11, + 5, 24, 12, 12, -19, 6, + -52, -10, 0, -2, -4, -10, + -14, 12, 12, -15, -17, 46, + 26, 20, 38, 16, -9, -12, + 0, -28, -8, -6, 4, -13, + 5, 7, 5, 0, 2, 10, + -15, 9, -2, 39, -13, 9, + 7, 11, -7, 26, 9, -11, + -20, -26, 42, 32, -22, -13, + 10, 39, 10, 6, -15, 25, + -17, -9, 14, -9, -5, -33, + 5, -23, -30, 0, 1, -6, + 3, 37, -15, 7, -4, 17, + 29, 14, 20, 11, -5, -14, + 35, 12, -13, -12, 8, -27, + 0, -8, -7, -8, 30, 23, + -41, 8, -28, 35, 53, 21, + 27, -17, -32, -5, -48, 4, + -8, 19, -2, -29, 17, 6, + -11, 2, -7, 0, 0, 1, + -34, -22, 22, -13, 10, 2, + -15, 22, 0, -47, 9, -1, + -42, -7, -10, 10, -21, -55, + 25, -27, -15, -21, -23, 10, + 2, -35, 20, -20, -3, 2, + -28, 9, 12, 40, 3, 25, + -9, -19, 15, 7, 8, -11, + 19, 10, -1, -15, -11, 32, + -32, -50, 29, -12, 13, 11, + -6, 30, 4, -26, 9, 3, + -4, 13, -32, -16, -9, 10, + 33, 26, 27, -23, -35, 10, + 15, -5, 53, 8, -25, -10, + -5, 7, 9, 11, -4, -34, + -7, 2, -5, 11, -13, -61, + -24, 18, -16, 13, 9, -45, + 10, 31, -9, 13, -3, 11, + 31, -30, 38, -14, -3, 18, + 26, 10, 10, 17, -16, -3, + -6, 37, -36, -17, -3, 30, + 14, 6, -31, -1, 8, -39, + 18, 20, 17, 22, -35, -12, + 0, -5, -6, -2, -37, 20, + -10, -16, -2, -5, 21, -8, + -5, 18, -12, -17, -5, 4, + -33, -8, -33, -23, -25, -14, + -15, 4, 53, -61, -6, 34, + -3, 11, -53, -7, -6, -11, + 28, 4, -16, -6, -13, -3, + 35, 3, -15, -16, 24, 16, + 25, 45, 5, -18, 2, 15, + 19, 42, 33, 17, 39, 8, + 3, 0, -12, -19, -9, 31, + 15, 40, 19, 8, 7, 5, + 14, -33, 8, -3, 16, -33, + -31, -13, -31, 37, -28, -19, + 6, 0, -46, 29, -22, -10, + -8, -2, -42, 29, -35, 10, + 40, 20, 8, 19, -13, 8, + 6, -2, 20, -15, 27, -42, + -11, 13, -1, 30, 31, 29, + 36, -27, 11, 36, 0, 3, + -9, 12, 1, -26, -8, 17, + -18, -9, -44, 23, -8, -36, + 2, 36, 41, 33, -28, -25, + 7, -8, 29, 43, 13, 19, + -7, 19, -19, -6, 34, -3, + 25, 40, 1, 3, -4, 5, + -16, -11, 36, 3, -17, -31, + 13, 3, -13, 3, -5, 6, + -6, -19, 1, -4, -7, 13, + -25, 26, -1, 26, -40, 0, + -1, -34, 21, 31, -22, 23, + 14, -19, 25, -7, 21, 31, + -6, 16, -16, 10, 28, 7, + -28, 7, -33, -6, 8, -31, + -16, -11, -3, -6, -7, 18, + -18, 24, 31, -24, 32, -43, + 9, -8, 12, 25, -21, 13, + -7, -5, -18, -48, -4, -33, + 15, 11, 7, 26, -10, -28, + -20, 8, 40, 15, 56, -35, + -42, 16, 3, -36, -25, 6, + 11, 24, -35, 10, -4, 5, + 17, 25, 73, -2, 72, -20, + -5, 19, 13, -8, -27, -18, + -11, 2, -15, 12, 16, -20, + -23, -12, -5, 47, 12, 9, + -14, 1, -10, 15, -4, -9, + -8, -5, -18, 28, -49, 18, + 35, 11, -8, 12, -10, -13, + 13, -4, -7, 4, 1, -13, + 13, 21, 28, 15, 19, -3, + 15, -8, 38, 31, -15, 21, + -8, -4, -10, 34, 3, -18, + -1, -20, -18, 16, -41, -3, + -10, -4, 15, -25, 2, -11, + -4, -14, 6, -14, -10, -17, + 10, -27, 51, -51, 30, 13, + -15, 4, -12, -55, -3, 17, + -7, -4, 0, -15, -28, -29, + -12, -29, 12, 6, -12, -46, + 9, 4, 9, -21, 10, 4, + 7, -9, -22, 4, -3, -8, + -15, 53, 26, 5, -19, -24, + 13, 16, -16, -26, 20, -35, + -26, 25, -15, 4, -23, 30, + -18, 11, -31, -2, -13, 24, + 3, 9, -1, 1, -1, -7, + 10, 29, -4, -1, 5, 12, + 5, 6, 3, 22, -18, 11, + -26, -4, -10, 10, -13, 7, + 13, 1, 36, -9, 35, 32, + 2, 7, -20, 19, -6, -18, + 15, -8, 33, 20, -9, -18, + 25, 29, 40, -23, -6, 34, + -21, 5, 21, -7, -2, 7, + -16, -3, 2, -18, 23, 9, + 62, 21, 32, 2, 6, -16, + 25, -9, -8, 31, 6, 37, + 14, 30, -36, -15, 4, 16, + 25, -13, 23, 26, 38, -5, + -27, 20, 27, -2, 9, -22, + 47, -3, 6, 42, 12, 17, + 8, -7, 47, 43, 2, 3, + -24, 9, -3, -11, 5, 42, + 13, 7, -23, -36, 22, 26, + -6, 18, -11, -15, -17, 18, + 2, 36, -40, -1, -18, -42, + 33, 56, 10, -1, 16, -2, + 6, -23, 16, 7, -35, -5, + -13, -11, -4, 10, 5, 5, + 33, 0, 8, 23, -19, 31, + -23, 2, -51, -30, -24, -28, + 13, -10, 8, -19, 14, -23, + -8, 3, -14, 17, -36, -21, + 12, 41, -5, 26, -4, -10, + 25, 40, -21, -4, 17, 8, + -22, -3, -38, 22, 5, 28, + 38, 0, -3, 1, 20, -11, + -3, -6, 28, -26, 9, -21, + 5, -14, -2, -42, -14, 23, + -21, -24, -13, 20, -19, -13, + -3, -7, 20, 13, -16, 18, + -14, -2, 14, 31, -1, -12, + -25, -2, 1, -9, -32, 37, + -5, -3, 30, -13, -7, 12, + 31, 12, -7, -13, 30, -3, + -5, 37, -32, -9, 1, -2, + -25, -12, -1, 31, 14, -2, + -14, 18, -16, 13, 20, -7, + -3, -13, -19, 20, -13, -24, + -21, 23, -14, -42, -2, -14, + 5, -21, 9, -26, 28, -6, + -3, -11, 20, 1, -3, 0, + 38, 28, 5, 22, -38, -3, + -22, 8, 17, -4, -21, 40, + 25, -10, -4, 26, -5, 41, + 12, -21, -36, 17, -14, 3, + -8, -23, 14, -19, 8, -10, + 13, -28, -24, -30, -51, 2, + -23, 31, -19, 23, 8, 0, + 33, 5, 5, 10, -4, -11, + -13, -5, -35, 7, 16, -23, + 6, -2, 16, -1, 10, 56, + 33, -42, -18, -1, -40, 36, + 2, 18, -17, -15, -11, 18, + -6, 26, 22, -36, -23, 7, + 13, 42, 5, -11, -3, 9, + -24, 3, 2, 43, 47, -7, + 8, 17, 12, 42, 6, -3, + 47, -22, 9, -2, 27, 20, + -27, -5, 38, 26, 23, -13, + 25, 16, 4, -15, -36, 30, + 14, 37, 6, 31, -8, -9, + 25, -16, 6, 2, 32, 21, + 62, 9, 23, -18, 2, -3, + -16, 7, -2, -7, 21, 5, + -21, 34, -6, -23, 40, 29, + 25, -18, -9, 20, 33, -8, + 15, -18, -6, 19, -20, 7, + 2, 32, 35, -9, 36, 1, + 13, 7, -13, 10, -10, -4, + -26, 11, -18, 22, 3, 6, + 5, 12, 5, -1, -4, 29, + 10, -7, -1, 1, -1, 9, + 3, 24, -13, -2, -31, 11, + -18, 30, -23, 4, -15, 25, + -26, -35, 20, -26, -16, 16, + 13, -24, -19, 5, 26, 53, + -15, -8, -3, 4, -22, -9, + 7, 4, 10, -21, 9, 4, + 9, -46, -12, 6, 12, -29, + -12, -29, -28, -15, 0, -4, + -7, 17, -3, -55, -12, 4, + -15, 13, 30, -51, 51, -27, + 10, -17, -10, -14, 6, -14, + -4, -11, 2, -25, 15, -4, + -10, -3, -41, 16, -18, -20, + -1, -18, 3, 34, -10, -4, + -8, 21, -15, 31, 38, -8, + 15, -3, 19, 15, 28, 21, + 13, -13, 1, 4, -7, -4, + 13, -13, -10, 12, -8, 11, + 35, 18, -49, 28, -18, -5, + -8, -9, -4, 15, -10, 1, + -14, 9, 12, 47, -5, -12, + -23, -20, 16, 12, -15, 2, + -11, -18, -27, -8, 13, 19, + -5, -20, 72, -2, 73, 25, + 17, 5, -4, 10, -35, 24, + 11, 6, -25, -36, 3, 16, + -42, -35, 56, 15, 40, 8, + -20, -28, -10, 26, 7, 11, + 15, -33, -4, -48, -18, -5, + -7, 13, -21, 25, 12, -8, + 9, -43, 32, -24, 31, 24, + -18, 18, -7, -6, -3, -11, + -16, -31, 8, -6, -33, 7, + -28, 7, 28, 10, -16, 16, + -6, 31, 21, -7, 25, -19, + 14, 23, -22, 31, 21, -34, + -1, 0, -40, 26, -1, 26, + -25, 13, -7, -4, 1, -19, + -6, 6, -5, 3, -13, 3, + 13, -31, -17, 3, 36, -11, + -16, 5, -4, 3, 1, 40, + 25, -3, 34, -6, -19, 19, + -7, 19, 13, 43, 29, -8, + 7, -25, -28, 33, 41, 36, + 2, -36, -8, 23, -44, -9, + -18, 17, -8, -26, 1, 12, + -9, 3, 0, 36, 11, -27, + 36, 29, 31, 30, -1, 13, + -11, -42, 27, -15, 20, -2, + 6, 8, -13, 19, 8, 20, + 40, 10, -35, 29, -42, -2, + -8, -10, -22, 29, -46, 0, + 6, -19, -28, 37, -31, -13, + -31, -33, 16, -3, 8, -33, + 14, 5, 7, 8, 19, 40, + 15, 31, -9, -19, -12, 0, + 3, 8, 39, 17, 33, 42, + 19, 15, 2, -18, 5, 45, + 25, 16, 24, -16, -15, 3, + 35, -3, -13, -6, -16, 4, + 28, -11, -6, -7, -53, 11, + -3, 34, -6, -61, 53, 4, + -15, -14, -25, -23, -33, -8, + -33, 4, -5, -17, -12, 18, + -5, -8, 21, -5, -2, -16, + -10, 20, -37, -2, -6, -5, + 0, -12, -35, 22, 17, 20, + 18, -39, 8, -1, -31, 6, + 14, 30, -3, -17, -36, 37, + -6, -3, -16, 17, 10, 10, + 26, 18, -3, -14, 38, -30, + 31, 11, -3, 13, -9, 31, + 10, -45, 9, 13, -16, 18, + -24, -61, -13, 11, -5, 2, + -7, -34, -4, 11, 9, 7, + -5, -10, -25, 8, 53, -5, + 15, 10, -35, -23, 27, 26, + 33, 10, -9, -16, -32, 13, + -4, 3, 9, -26, 4, 30, + -6, 11, 13, -12, 29, -50, + -32, 32, -11, -15, -1, 10, + 19, -11, 8, 7, 15, -19, + -9, 25, 3, 40, 12, 9, + -28, 2, -3, -20, 20, -35, + 2, 10, -23, -21, -15, -27, + 25, -55, -21, 10, -10, -7, + -42, -1, 9, -47, 0, 22, + -15, 2, 10, -13, 22, -22, + -34, 1, 0, 0, -7, 2, + -11, 6, 17, -29, -2, 19, + -8, 4, -48, -5, -32, -17, + 27, 21, 53, 35, -28, 8, + -41, 23, 30, -8, -7, -8, + 0, -27, 8, -12, -13, 12, + 35, -14, -5, 11, 20, 14, + 29, 17, -4, 7, -15, 37, + 3, -6, 1, 0, -30, -23, + 5, -33, -5, -9, 14, -9, + -17, 25, -15, 6, 10, 39, + 10, -13, -22, 32, 42, -26, + -20, -11, 9, 26, -7, 11, + 7, 9, -13, 39, -2, 9, + -15, 10, 2, 0, 5, 7, + 5, -13, 4, -6, -8, -28, + 0, -12, -9, 16, 38, 20, + 26, 46, -17, -15, 12, 12, + -14, -10, -4, -2, 0, -10, + -52, 6, -19, 12, 12, 24, + 5, -11, -13, 18, 54, -46, + -42, 24, -10, 23, 15, 1, + 2, 13, -12, -13, -18, 23, + -20, -8, 27, -27, 8, -23, + -20, 3, 4, 18, -25, 36, + 19, 21, 27, 5, 7, 31, + -45, -6, -17, 48, 25, -20, + -16, -5, 8, 28, -30, 2, + -36, -26, 6, 40, -17, 43, + 15, -24, 7, 9, 19, -48, + 13, 9, -23, -2, -39, 6, + 15, 14, -4, 11, -44, 11, + -13, -15, 3, 7, 9, -7, + 6, -5, -16, 8, 31, 3, + 16, 2, -44, 2, 10, 9, + -25, -20, -21, -8, -5, -7, + -3, -14, -2, 9, -26, 16, + -39, -6, -4, 25, -4, -5, + 71, -6, 5, 6, -21, -12, + -25, 13, 44, -7, 11, -29, + -11, -34, -32, -1, 4, -3, + 3, 3, -31, 9, 2, -19, + -7, 13, 4, 29, -21, -47, + -5, 5, -13, 31, -1, -19, + 28, -33, 23, -10, 10, 18, + 23, -9, 29, 7, -15, 16, + -6, -17, -15, -2, 34, -29, + -15, 11, -18, 49, -24, -37, + 18, -7, 26, 29, -4, 10, + 5, -1, 64, -16, -23, -28, + 17, 9, 10, -15, 13, 51, + 30, -23, -29, -20, 55, -3, + -34, 21, -19, 4, -23, -12, + -4, 43, 3, 1, -26, -25, + -2, -12, -29, 20, -26, 19, + 28, -30, -33, 26, 24, 0, + 19, 24, 22, -13, 4, 8, + 7, -36, 34, -37, 9, 12, + -1, 17, 37, -13, -7, 10, + 14, -2, -14, -10, 6, 2, + -28, -14, 12, -16, -3, 1, + -11, 0, -11, -35, -36, -6, + -8, 41, -10, -19, 2, 10, + -4, -11, 8, 10, 20, 6, + 3, -20, -41, -3, -15, 14, + 10, 22, 10, -24, -19, 2, + -12, -17, -20, -14, 9, -4, + 32, -22, -29, -21, 19, 23, + -22, -7, 29, -50, -16, 7, + -2, -2, -15, 24, 39, -20, + -2, 22, 0, 30, 46, -29, + -7, 3, -24, 13, 8, 10, + -20, 57, 7, -3, -1, 6, + 26, -9, 11, -8, 32, -1, + 2, 24, 9, 12, -14, 31, + 12, 0, 23, -12, 2, 9, + 11, 13, -24, -17, 12, 27, + 5, -8, -18, -11, -54, -7, + 10, 22, 16, 18, 0, -6, + 8, 0, -6, -16, 2, 11, + 51, -13, 0, 22, -20, 6, + 7, 23, 9, 5, 19, 18, + -34, -25, -5, 44, -22, 2, + -21, -21, -6, 1, -3, -28, + 6, -7, -14, -20, -8, -3, + -7, -24, 9, -12, 5, 27, + 15, -21, -14, 8, 8, -10, + -14, -19, -55, 30, -8, 21, + 8, -1, 32, -11, 15, 17, + -7, -38, -6, -28, -20, -1, + 11, 17, -4, -34, 11, -7, + 25, 21, 4, 6, 26, -8, + 16, 5, 8, -19, 19, 2, + -22, 5, 9, 0, -8, -34, + 31, -17, 31, -17, 6, 34, + 8, 27, 3, -13, -22, 11, + 2, 3, -17, 5, -20, -8, + -18, 35, -8, -1, 8, -8, + -4, 10, -21, -10, -28, 21, + 7, 2, 0, 30, 25, -19, + -4, 13, 12, 32, -4, 2, + -27, -20, 26, -14, 28, 10, + -27, 5, 0, 34, -4, -15, + -5, -3, 11, -11, -19, 3, + -35, -2, -6, 37, -37, -37, + -35, -9, 2, 0, -14, 36, + 0, 31, 31, -16, -21, -9, + 11, -17, 19, -4, 20, -40, + 5, -9, 40, 8, 11, -8, + 4, -56, -16, -8, 42, 10, + 20, 26, -12, 0, 3, -11, + -26, 11, 20, -3, 17, -19, + 13, 0, -4, 17, 24, 17, + -4, -13, 15, -15, 26, 16, + 45, 36, 11, 15, -36, 2, + 0, -9, -33, -5, -20, -12, + -22, -18, -33, -4, 6, -20, + 16, -10, -178, 57093, -1421223, 11753740, + -47262115, 107836740, -149772245, 129763729, -69391869, 21781560, + -3579960, 237344, -2790, 10, -12, 6, + -6, -56, 21, -25, 37, -37, + 1, -4, -20, -29, -3, 43, + -10, -14, 6, -49, -31, 6, + 17, -4, 17, 12, 1, 5, + -14, -19, -21, -5, -14, -32, + -4, -24, -6, 13, 4, 5, + -19, -28, 9, 6, 5, -42, + -5, -26, -4, 11, -22, 10, + 21, -10, 19, -6, 19, 22, +}; + +static const int32_t fft_ref_imag_3072_q31[3072] = { + 0, -1, -4, -15, -6, 19, + 1, 14, 47, -16, 15, 7, + 11, -9, -21, 4, 30, 43, + 16, 41, -11, 34, -26, 1, + 5, -11, -9, 45, -15, -18, + 18, -1, -6, 47, 25, -24, + -21, -56, 19, -1, 2, -12, + -15, 28, -26, 5, 15, 0, + 3, -17, 33, 0, -32, -16, + 10, 21, -16, -2, -3984, 340956, + -5154182, 31427830, -100341944, 188051672, -217523306, 156961255, + -68943044, 17183326, -2082337, 83868, -223, -19, + -32, -29, 1, 20, -16, 53, + 22, 26, -19, 7, -22, -18, + 4, 3, -20, 25, -23, 5, + -23, 17, -26, 23, -25, 7, + -19, -41, 14, -20, -1, 11, + 3, -12, -4, 11, 23, 8, + 15, 4, 2, 23, 26, 9, + 30, 31, -20, -17, -38, 39, + -23, 7, 10, 18, 17, 0, + 23, -15, 12, 25, -9, -28, + 34, -19, -23, 6, 11, 1, + -13, -3, 19, 23, -10, -19, + 25, 5, -3, -7, -22, 17, + 43, -32, 10, -10, -43, -34, + 25, 1, 7, -26, 4, 21, + -2, 5, 2, -15, -1, 19, + -19, -1, 37, -18, -44, 15, + -14, 1, 24, -11, -14, 6, + -20, -14, 16, -11, 31, 35, + 14, -4, 3, 17, -22, -21, + 24, -32, 26, 43, -9, -20, + -13, -21, 15, -25, 30, -11, + -14, -2, -28, -23, -21, 8, + 24, -9, -36, -29, 1, 6, + -6, 0, -11, -19, 22, 15, + 29, -28, -12, 18, 18, 4, + 10, -56, 7, -21, -32, 11, + -20, -18, -35, 19, -15, 4, + 42, -7, 43, 2, 9, -11, + 14, 9, -2, 25, 14, -4, + 0, 7, 19, 7, 21, 20, + -9, 20, 22, -22, -18, 21, + -19, 16, 0, 2, -8, -24, + 20, 13, -6, 15, -20, -19, + -35, -21, -1, 0, 22, 11, + 20, 14, -14, 41, 36, -2, + -4, 1, 35, 4, 19, -12, + 3, -5, -26, -26, -33, 12, + 13, -21, -20, 18, -23, -14, + -13, -23, -14, 20, -20, 12, + 16, 7, 7, 12, -9, 15, + -17, 20, 29, 12, -7, -11, + 17, -35, -18, 6, -3, 22, + -10, -12, -21, 21, 12, -4, + -28, 27, -8, -5, -8, 21, + -9, 16, 19, -13, -1, 0, + -40, 34, 1, -22, -7, 5, + 25, 15, -5, -38, 17, 35, + -11, 19, -8, -9, -19, 42, + 10, 10, -63, 3, -39, 18, + -7, 32, -2, 0, 7, 18, + 20, 11, -57, -22, -1, 18, + -13, 13, -11, 5, -32, 16, + -11, 40, 3, 8, -7, -62, + -5, 22, -16, -6, 15, 34, + 20, -55, 16, 36, 19, 30, + 8, 31, -2, 19, -46, -12, + -20, -7, -13, -15, -5, 6, + 9, -12, -6, 23, -7, 7, + -33, -23, -1, -17, -2, 0, + -1, 9, 11, 42, -3, -57, + -42, 3, -13, -30, 26, -13, + 26, -28, 17, -36, -32, 12, + 17, 8, -33, 27, 18, -13, + 3, 24, 3, 47, -8, 7, + 11, -17, 0, -12, -20, 12, + -15, -18, -6, -20, -6, 9, + 19, 20, -13, 4, 18, 3, + 11, -6, 37, 27, 18, -2, + -13, -8, 43, 33, -7, -11, + 7, 30, 3, 9, 17, 20, + -40, 25, 48, 8, 8, 29, + -23, 19, -13, -4, 30, -13, + 27, 18, 43, -1, 35, 28, + -38, -14, -32, 14, 14, -7, + 26, 4, -18, 37, -26, 5, + 18, 38, 6, 20, 15, 13, + 17, 27, 23, 21, 9, 7, + 37, 28, 35, -12, 11, -11, + -26, -5, 18, -56, 11, -31, + -20, 28, -21, 2, 35, -17, + -26, 30, -28, -4, 40, 6, + 19, -6, 11, 0, -1, 17, + 4, 0, -33, -4, 3, 17, + 18, 15, -15, 31, -14, -3, + -19, -8, 2, -50, 2, -5, + -12, 14, 18, -20, -2, 30, + -10, -50, -23, -7, -12, 8, + 6, -1, 39, 6, 0, -58, + 14, 20, 16, -14, -35, 0, + -19, 27, -11, -7, -19, 14, + 10, 0, 43, -18, 33, 5, + -10, 72, 4, -1, -7, -22, + -25, -24, 1, -8, 3, 1, + 45, 3, 22, 5, -12, -23, + -46, 11, 8, -19, 8, 39, + 4, 2, -31, 4, -8, 20, + 17, 33, -11, 4, -23, 8, + 10, -5, -4, 5, 25, -34, + -1, 18, -19, -8, -27, 8, + 5, -39, 48, -20, -13, 32, + 27, -31, 17, -21, 13, -9, + 11, 9, 33, -8, -26, 16, + -38, -1, -19, 6, 1, 2, + -2, 21, 42, -14, 27, 5, + -16, 22, -55, 18, -23, 74, + -14, 15, 2, 16, -8, -28, + -36, 27, 15, 1, 20, -6, + 15, 11, -56, 29, 10, 24, + 31, 13, -38, 24, -18, -16, + 16, 13, 4, -9, -6, 7, + 11, -1, -11, -28, -23, 24, + -4, -4, 22, 29, 10, -41, + -2, -24, -14, 13, -42, -20, + 26, 34, -5, -19, 15, 7, + -44, -15, -44, 21, -2, -37, + 25, 33, 8, 22, 30, -3, + 10, -13, 1, 13, 13, 26, + -26, 20, 37, 17, 22, 21, + 25, 1, 0, -17, -1, -5, + 6, -17, 5, -28, 29, 13, + 6, -32, -5, -30, 4, -3, + -13, -14, 35, 19, 31, 34, + 66, 11, -28, 31, 13, 2, + -6, 2, 52, -22, 5, -6, + 1, -21, 22, -46, -28, -10, + 42, 16, -26, 6, -21, -17, + -18, 5, 18, 11, -53, -3, + -9, 2, -3, 8, -7, 32, + 14, -26, 25, 5, 19, 1, + -3, 4, -10, 20, -12, -19, + -11, -35, 3, 11, -27, -10, + -15, -40, -10, 19, -1, -20, + -30, 2, 49, 21, 32, 16, + -43, -3, -34, -26, 4, -23, + 41, 6, 35, 25, 28, 20, + 3, 14, -12, -3, -14, -9, + 10, 26, 6, -42, 10, 21, + 18, 13, -23, 27, -5, -28, + 11, -2, -5, -19, 19, 12, + 32, -1, -12, -24, -11, -11, + -15, 8, 6, 38, 21, 29, + -17, -4, -40, 2, 11, -10, + 1, 10, -16, -12, -65, -5, + 23, 39, -40, -10, 23, -14, + 2, 38, -5, 3, 15, 19, + -1, 25, -20, -22, -24, -17, + 11, -9, -16, 4, 18, -10, + -5, -14, -24, -13, -20, 38, + -31, 17, -33, -15, -9, -25, + 9, -9, 8, -23, -5, 14, + 45, 10, -11, 9, -2, 2, + -17, -8, 11, -13, -24, -3, + 8, -4, -13, 22, 11, 28, + 4, 14, 28, 10, 16, -35, + 5, -8, -3, -24, 9, -22, + -32, 10, 24, -1, 27, 10, + 0, 13, -26, -3, 2, -13, + 24, 23, -20, -38, 13, 21, + -20, -11, -16, -24, -5, 4, + 21, 35, 9, 12, -2, 1, + 16, 15, -31, 47, 7, -3, + 18, -22, -7, 28, -7, -6, + 18, -6, -5, 6, -35, 11, + 18, 3, 9, 4, -4, 5, + -3, -26, 35, 22, 34, 42, + -24, 9, -24, 10, -23, 34, + -32, 30, -1, 32, 17, 13, + -26, 10, 0, -1, 23, 3, + -14, 59, -49, -35, 3, 1, + -17, -5, 0, 5, -5, 18, + 10, 4, -4, 18, -4, -19, + -33, -4, -5, 26, -9, -18, + 53, -30, 19, 23, 39, -9, + -6, 38, -10, 22, 13, -21, + 8, 1, 17, -21, 1, -18, + 34, 25, -4, -3, 32, 0, + -23, -2, -9, -13, 1, -5, + -2, 31, -29, -11, -16, 2, + -8, -29, -34, -44, -51, -28, + 7, -13, 9, -44, -3, 30, + -15, -33, 25, -26, 7, -21, + 40, 31, -5, 42, -18, -21, + 5, -17, 24, -7, 29, 5, + 17, 15, 3, 23, 19, -6, + -33, 12, -10, -31, 38, 6, + 26, 26, 6, 20, 18, 39, + 30, -6, -17, -13, 22, -49, + 10, -13, -16, 15, 12, 14, + -31, -17, -1, 17, 8, -32, + -28, -15, 9, -30, 23, -12, + 17, -22, -21, -60, -33, -16, + 13, -14, -7, 18, 20, -8, + -11, 3, -6, -35, -15, 27, + 24, 67, 10, -18, 8, -14, + 3, 11, -38, -1, -18, 26, + -21, 39, 3, -3, 34, -45, + 11, 0, 11, -2, -16, -7, + 34, -7, 22, 16, -22, -14, + 17, -15, -32, 9, 37, 5, + 27, -15, 24, 2, -9, -17, + -17, -11, -26, 8, 29, 9, + 21, -41, -3, 36, 8, 43, + 14, -6, 9, 5, -1, -3, + -38, -27, 9, 1, 13, 7, + -6, 54, 20, -18, 9, 0, + 10, 6, -8, 30, -17, -28, + -22, 7, 16, -42, 12, 14, + 29, -2, 21, 19, 0, -23, + 19, -16, -31, -3, -32, -45, + -52, -24, -27, 2, 15, -28, + -11, 24, -14, 9, -4, 6, + 3, 1, -22, 21, 5, 37, + 24, 33, 21, 14, -56, -20, + -12, -26, -20, -12, -42, -17, + -12, 0, 0, -7, -6, 14, + 37, -37, -6, -8, 18, -20, + 24, 12, 11, 14, 20, -24, + 6, -6, -1, -19, -7, 4, + 4, -11, -29, 6, -3, 18, + -37, -37, -26, -24, 17, -17, + -3, -21, 19, -2, 15, -5, + -14, 0, 6, 4, 9, -19, + 8, -13, 15, -14, -14, -28, + 19, -24, 40, 6, -10, -20, + -21, -38, -14, -11, 14, 12, + 31, 30, -1, 9, -5, -4, + -29, -20, 43, -7, -33, -10, + -31, 0, 9, 2, 15, 18, + -11, -11, -3, 12, 32, 31, + -9, -8, 19, -5, -2, -8, + -19, 7, 13, -10, -1, -4, + -38, -6, 6, -34, -14, -4, + -11, 6, 12, -18, 28, 73, + -21, 54, -16, 32, -17, 13, + -3, 5, -2, -5, -1, 22, + 8, 29, 15, -9, -26, -29, + 1, 28, -27, 15, 0, 26, + -28, 17, 7, -7, -4, 4, + -3, -22, -3, -25, -6, 10, + -26, -11, -19, -23, -14, 22, + 0, -10, 22, -5, -3, -11, + 27, -6, 27, -8, 19, -8, + -2, 12, 2, 53, 11, -46, + 0, 46, -11, -53, -2, -12, + 2, 8, -19, 8, -27, 6, + -27, 11, 3, 5, -22, 10, + 0, -22, 14, 23, 19, 11, + 26, -10, 6, 25, 3, 22, + 3, -4, 4, 7, -7, -17, + 28, -26, 0, -15, 27, -28, + -1, 29, 26, 9, -15, -29, + -8, -22, 1, 5, 2, -5, + 3, -13, 17, -32, 16, -54, + 21, -73, -28, 18, -12, -6, + 11, 4, 14, 34, -6, 6, + 38, 4, 1, 10, -13, -7, + 19, 8, 2, 5, -19, 8, + 9, -31, -32, -12, 3, 11, + 11, -18, -15, -2, -9, 0, + 31, 10, 33, 7, -43, 20, + 29, 4, 5, -9, 1, -30, + -31, -12, -14, 11, 14, 38, + 21, 20, 10, -6, -40, 24, + -19, 28, 14, 14, -15, 13, + -8, 19, -9, -4, -6, 0, + 14, 5, -15, 2, -19, 21, + 3, 17, -17, 24, 26, 37, + 37, -18, 3, -6, 29, 11, + -4, -4, 7, 19, 1, 6, + -6, 24, -20, -14, -11, -12, + -24, 20, -18, 8, 6, 37, + -37, -14, 6, 7, 0, 0, + 12, 17, 42, 12, 20, 26, + 12, 20, 56, -14, -21, -33, + -24, -37, -5, -21, 22, -1, + -3, -6, 4, -9, 14, -24, + 11, 28, -15, -2, 27, 24, + 52, 45, 32, 3, 31, 16, + -19, 23, 0, -19, -21, 2, + -29, -14, -12, 42, -16, -7, + 22, 28, 17, -30, 8, -6, + -10, 0, -9, 18, -20, -54, + 6, -7, -13, -1, -9, 27, + 38, 3, 1, -5, -9, 6, + -14, -43, -8, -36, 3, 41, + -21, -9, -29, -8, 26, 11, + 17, 17, 9, -2, -24, 15, + -27, -5, -37, -9, 32, 15, + -17, 14, 22, -16, -22, 7, + -34, 7, 16, 2, -11, 0, + -11, 45, -34, 3, -3, -39, + 21, -26, 18, 1, 38, -11, + -3, 14, -8, 18, -10, -67, + -24, -27, 15, 35, 6, -3, + 11, 8, -20, -18, 7, 14, + -13, 16, 33, 60, 21, 22, + -17, 12, -23, 30, -9, 15, + 28, 32, -8, -17, 1, 17, + 31, -14, -12, -15, 16, 13, + -10, 49, -22, 13, 17, 6, + -30, -39, -18, -20, -6, -26, + -26, -6, -38, 31, 10, -12, + 33, 6, -19, -23, -3, -15, + -17, -5, -29, 7, -24, 17, + -5, 21, 18, -42, 5, -31, + -40, 21, -7, 26, -25, 33, + 15, -30, 3, 44, -9, 13, + -7, 28, 51, 44, 34, 29, + 8, -2, 16, 11, 29, -31, + 2, 5, -1, 13, 9, 2, + 23, 0, -32, 3, 4, -25, + -34, 18, -1, 21, -17, -1, + -8, 21, -13, -22, 10, -38, + 6, 9, -39, -23, -19, 30, + -53, 18, 9, -26, 5, 4, + 33, 19, 4, -18, 4, -4, + -10, -18, 5, -5, 0, 5, + 17, -1, -3, 35, 49, -59, + 14, -3, -23, 1, 0, -10, + 26, -13, -17, -32, 1, -30, + 32, -34, 23, -10, 24, -9, + 24, -42, -34, -22, -35, 26, + 3, -5, 4, -4, -9, -3, + -18, -11, 35, -6, 5, 6, + -18, 6, 7, -28, 7, 22, + -18, 3, -7, -47, 31, -15, + -16, -1, 2, -12, -9, -35, + -21, -4, 5, 24, 16, 11, + 20, -21, -13, 38, 20, -23, + -24, 13, -2, 3, 26, -13, + 0, -10, -27, 1, -24, -10, + 32, 22, -9, 24, 3, 8, + -5, 35, -16, -10, -28, -14, + -4, -28, -11, -22, 13, 4, + -8, 3, 24, 13, -11, 8, + 17, -2, 2, -9, 11, -10, + -45, -14, 5, 23, -8, 9, + -9, 25, 9, 15, 33, -17, + 31, -38, 20, 13, 24, 14, + 5, 10, -18, -4, 16, 9, + -11, 17, 24, 22, 20, -25, + 1, -19, -15, -3, 5, -38, + -2, 14, -23, 10, 40, -39, + -23, 5, 65, 12, 16, -10, + -1, 10, -11, -2, 40, 4, + 17, -29, -21, -38, -6, -8, + 15, 11, 11, 24, 12, 1, + -32, -12, -19, 19, 5, 2, + -11, 28, 5, -27, 23, -13, + -18, -21, -10, 42, -6, -26, + -10, 9, 14, 3, 12, -14, + -3, -20, -28, -25, -35, -6, + -41, 23, -4, 26, 34, 3, + 43, -16, -32, -21, -49, -2, + 30, 20, 1, -19, 10, 40, + 15, 10, 27, -11, -3, 35, + 11, 19, 12, -20, 10, -4, + 3, -1, -19, -5, -25, 26, + -14, -32, 7, -8, 3, -2, + 9, 3, 53, -11, -18, -5, + 18, 17, 21, -6, 26, -16, + -42, 10, 28, 46, -22, 21, + -1, 6, -5, 22, -52, -2, + 6, -2, -13, -31, 28, -11, + -66, -34, -31, -19, -35, 14, + 13, 3, -4, 30, 5, 32, + -6, -13, -29, 28, -5, 17, + -6, 5, 1, 17, 0, -1, + -25, -21, -22, -17, -37, -20, + 26, -26, -13, -13, -1, 13, + -10, 3, -30, -22, -8, -33, + -25, 37, 2, -21, 44, 15, + 44, -7, -15, 19, 5, -34, + -26, 20, 42, -13, 14, 24, + 2, 41, -10, -29, -22, 4, + 4, -24, 23, 28, 11, 1, + -11, -7, 6, 9, -4, -13, + -16, 16, 18, -24, 38, -13, + -31, -24, -10, -29, 56, -11, + -15, 6, -20, -1, -15, -27, + 36, 28, 8, -16, -2, -15, + 14, -74, 23, -18, 55, -22, + 16, -5, -27, 14, -42, -21, + 2, -2, -1, -6, 19, 1, + 38, -16, 26, 8, -33, -9, + -11, 9, -13, 21, -17, 31, + -27, -32, 13, 20, -48, 39, + -5, -8, 27, 8, 19, -18, + 1, 34, -25, -5, 4, 5, + -10, -8, 23, -4, 11, -33, + -17, -20, 8, -4, 31, -2, + -4, -39, -8, 19, -8, -11, + 46, 23, 12, -5, -22, -3, + -45, -1, -3, 8, -1, 24, + 25, 22, 7, 1, -4, -72, + 10, -5, -33, 18, -43, 0, + -10, -14, 19, 7, 11, -27, + 19, 0, 35, 14, -16, -20, + -14, 58, 0, -6, -39, 1, + -6, -8, 12, 7, 23, 50, + 10, -30, 2, 20, -18, -14, + 12, 5, -2, 50, -2, 8, + 19, 3, 14, -31, 15, -15, + -18, -17, -3, 4, 33, 0, + -4, -17, 1, 0, -11, 6, + -19, -6, -40, 4, 28, -30, + 26, 17, -35, -2, 21, -28, + 20, 31, -11, 56, -18, 5, + 26, 11, -11, 12, -35, -28, + -37, -7, -9, -21, -23, -27, + -17, -13, -15, -20, -6, -38, + -18, -5, 26, -37, 18, -4, + -26, 7, -14, -14, 32, 14, + 38, -28, -35, 1, -43, -18, + -27, 13, -30, 4, 13, -19, + 23, -29, -8, -8, -48, -25, + 40, -20, -17, -9, -3, -30, + -7, 11, 7, -33, -43, 8, + 13, 2, -18, -27, -37, 6, + -11, -3, -18, -4, 13, -20, + -19, -9, 6, 20, 6, 18, + 15, -12, 20, 12, 0, 17, + -11, -7, 8, -47, -3, -24, + -3, 13, -18, -27, 33, -8, + -17, -12, 32, 36, -17, 28, + -26, 13, -26, 30, 13, -3, + 42, 57, 3, -42, -11, -9, + 1, 0, 2, 17, 1, 23, + 33, -7, 7, -23, 6, 12, + -9, -6, 5, 15, 13, 7, + 20, 12, 46, -19, 2, -31, + -8, -30, -19, -36, -16, 55, + -20, -34, -15, 6, 16, -22, + 5, 62, 7, -8, -3, -40, + 11, -16, 32, -5, 11, -13, + 13, -18, 1, 22, 57, -11, + -20, -18, -7, 0, 2, -32, + 7, -18, 39, -3, 63, -10, + -10, -42, 19, 9, 8, -19, + 11, -35, -17, 38, 5, -15, + -25, -5, 7, 22, -1, -34, + 40, 0, 1, 13, -19, -16, + 9, -21, 8, 5, 8, -27, + 28, 4, -12, -21, 21, 12, + 10, -22, 3, -6, 18, 35, + -17, 11, 7, -12, -29, -20, + 17, -15, 9, -12, -7, -7, + -16, -12, 20, -20, 14, 23, + 13, 14, 23, -18, 20, 21, + -13, -12, 33, 26, 26, 5, + -3, 12, -19, -4, -35, -1, + 4, 2, -36, -41, 14, -14, + -20, -11, -22, 0, 1, 21, + 35, 19, 20, -15, 6, -13, + -20, 24, 8, -2, 0, -16, + 19, -21, 18, 22, -22, -20, + 9, -20, -21, -7, -19, -7, + 0, 4, -14, -25, 2, -9, + -14, 11, -9, -2, -43, 7, + -42, -4, 15, -19, 35, 18, + 20, -11, 32, 21, -7, 56, + -10, -4, -18, -18, 12, 28, + -29, -15, -22, 19, 11, 0, + 6, -6, -1, 29, 36, 9, + -24, -8, 21, 23, 28, 2, + 14, 11, -30, 25, -15, 21, + 13, 20, 9, -43, -26, 32, + -24, 21, 22, -17, -3, 4, + -14, -35, -31, 11, -16, 14, + 20, -6, 14, 11, -24, -1, + 14, -15, 44, 18, -37, 1, + 19, -19, 1, 15, -2, -5, + 2, -21, -4, 26, -7, -1, + -25, 34, 43, 10, -10, 32, + -43, -17, 22, 7, 3, -5, + -25, 19, 10, -23, -19, 3, + 13, -1, -11, -6, 23, 19, + -34, 28, 9, -25, -12, 15, + -23, 0, -17, -18, -10, -7, + 23, -39, 38, 17, 20, -31, + -30, -9, -26, -23, -2, -4, + -15, -8, -23, -11, 4, 12, + -3, -11, 1, 20, -14, 41, + 19, -7, 25, -23, 26, -17, + 23, -5, 23, -25, 20, -3, + -4, 18, 22, -7, 19, -26, + -22, -53, 16, -20, -1, 29, + 32, 19, 223, -83868, 2082337, -17183326, + 68943044, -156961255, 217523306, -188051672, 100341944, -31427830, + 5154182, -340956, 3984, 2, 16, -21, + -10, 16, 32, 0, -33, 17, + -3, 0, -15, -5, 26, -28, + 15, 12, -2, 1, -19, 56, + 21, 24, -25, -47, 6, 1, + -18, 18, 15, -45, 9, 11, + -5, -1, 26, -34, 11, -41, + -16, -43, -30, -4, 21, 9, + -11, -7, -15, 16, -47, -14, + -1, -19, 6, 15, 4, 1, +}; diff --git a/test/cmocka/src/math/fft/ref_fft_multi_512_32.h b/test/cmocka/src/math/fft/ref_fft_multi_512_32.h new file mode 100644 index 000000000000..2f66b1943af0 --- /dev/null +++ b/test/cmocka/src/math/fft/ref_fft_multi_512_32.h @@ -0,0 +1,364 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 20-Nov-2025 16:11:52 with script ref_fft_multi.m v1.9-rc1-6882-ge0b90b605-dirty */ + +#define REF_SOFM_FFT_MULTI_512_NUM_TESTS 1 + +static const int32_t fft_in_real_512_q31[512] = { + 2377, 340, -1196, 1231, 390, -220, + 1663, -1097, 2649, 2272, 2236, 4342, + 3392, 4062, 6525, 5862, 5260, 4298, + 5946, 6952, 9757, 6742, 5507, 6233, + 2746, -6220, -7167, -15262, -27034, -37541, + -48308, -63366, -79216, -99095, -114978, -136892, + -158310, -176123, -192474, -205758, -221510, -225664, + -228096, -217668, -204746, -176198, -137635, -82142, + -9371, 74606, 179015, 298476, 439502, 594979, + 765297, 950034, 1143794, 1342066, 1544951, 1741581, + 1929492, 2099900, 2239228, 2342857, 2403695, 2406952, + 2348372, 2215760, 1999224, 1685659, 1277296, 767477, + 145652, -576843, -1412213, -2348478, -3374059, -4478609, + -5650739, -6865398, -8098727, -9324264, -10504916, -11605125, + -12596267, -13427768, -14058251, -14447678, -14546148, -14324532, + -13731373, -12741029, -11318240, -9445464, -7106292, -4298630, + -1028803, 2685749, 6812826, 11306975, 16107663, 21145964, + 26323168, 31551295, 36709825, 41672460, 46306375, 50477948, + 54028871, 56821040, 58704348, 59538514, 59202251, 57564674, + 54532854, 50034062, 44008837, 36428878, 27312638, 16697669, + 4668381, -8656667, -23115247, -38512817, -54605837, -71114797, + -87734187, -104118684, -119911490, -134714976, -148144714, -159788322, + -169256899, -176160487, -180148043, -180882561, -178086768, -171520785, + -161024629, -146479642, -127877567, -105271227, -78804161, -48731098, + -15371603, 20843417, 59393829, 99676740, 141010892, 182645196, + 223765608, 263517948, 301016662, 335366499, 365667808, 391049190, + 410689064, 423816593, 429762391, 427948384, 417924213, 399366813, + 372118999, 336184162, 291744393, 239157693, 178963703, 111897394, + 38855262, -39076188, -120670524, -204555997, -289250536, -373165551, + -454647551, -532020754, -603591727, -667697336, -722744462, -767256517, + -799860865, -819376406, -824826855, -815445853, -790753739, -750514716, + -694807177, -624005830, -538798080, -440180087, -329446119, -208181786, + -78228178, 58322457, 199177086, 341868299, 483806041, 622316802, + 754703901, 878291108, 990474654, 1088787157, 1170940744, 1234884629, + 1278855173, 1301396967, 1301443489, 1278304462, 1231723405, 1161876364, + 1069381916, 955316252, 821188818, 668927730, 500846793, 319639136, + 128281798, -69969079, -271643589, -473138138, -670788021, -860891365, + -1039840037, -1204143102, -1350521372, -1475985731, -1577855538, -1653868143, + -1702201550, -1721507212, -1710987200, -1670357852, -1599913631, -1500498908, + -1373524895, -1220918243, -1045119827, -849030441, -635951651, -409549533, + -173768611, 67236847, 309172231, 547685783, 778474962, 997324032, + 1200229451, 1383452973, 1543599999, 1677687708, 1783202582, 1858150469, + 1901102793, 1911207547, 1888235269, 1832550711, 1745137332, 1627554622, + 1481924147, 1310889170, 1117549902, 905412773, 678329960, 440406809, + 195946023, -50663943, -295003900, -532722276, -759616239, -971714214, + -1165343086, -1337202219, -1484407839, -1604573685, -1695818260, -1756812449, + -1786819343, -1785656952, -1753727278, -1692003786, -1601974636, -1485654570, + -1345493052, -1184355718, -1005445656, -812247941, -608443862, -397860620, + -184370436, 28155650, 235957789, 435414812, 623142459, 796038302, + 951331454, 1086646118, 1200032277, 1289966608, 1355409649, 1395802572, + 1411048221, 1401526273, 1368065265, 1311904927, 1234670391, 1138345134, + 1025205425, 897763065, 758730599, 610957451, 457356034, 300870453, + 144392851, -9273089, -157452086, -297686686, -427726193, -545602364, + -649633283, -738464975, -811055534, -866715451, -905106645, -926196810, + -930306878, -918048808, -890310025, -848238628, -793193671, -726739273, + -650563089, -566482249, -476362216, -382121302, -285648791, -188804509, + -93364778, -998556, 86774250, 168572629, 243214304, 309689690, + 367216509, 415201133, 453269644, 481254962, 499186921, 507293573, + 505953135, 495734458, 477315340, 451506885, 419217631, 381418708, + 339130862, 293409409, 245305078, 195852674, 146051406, 96847653, + 49123725, 3659924, -38835925, -77768267, -112648940, -143097159, + -168840927, -189723596, -205688470, -216780356, -223132535, -224963023, + -222563624, -216291546, -206547705, -193779025, -178448674, -161042676, + -142059071, -121973485, -101257674, -80361164, -59693896, -39639548, + -20528876, -2649969, 13743698, 28468278, 41381077, 52378701, + 61415428, 68489302, 73635092, 76919839, 78440949, 78342766, + 76763449, 73871913, 69846273, 64879055, 59156607, 52859212, + 46172815, 39271624, 32308042, 25436123, 18778046, 12454362, + 6550180, 1153222, -3690186, -7931022, -11549357, -14541771, + -16905259, -18670872, -19854696, -20504812, -20665306, -20388254, + -19735543, -18756855, -17510711, -16058137, -14452422, -12750215, + -10996406, -9230387, -7506048, -5841514, -4269596, -2815062, + -1498386, -320570, 699683, 1563959, 2280010, 2842827, + 3263548, 3556194, 3723649, 3782673, 3754077, 3639669, + 3463676, 3234034, 2965500, 2669406, 2362184, 2043555, + 1730398, 1426011, 1139067, 870062, 626287, 406552, + 214758, 52290, -81400, -192447, -276653, -339805, + -380854, -406690, -418638, -414054, -398956, -376437, + -345489, -315906, -280747, -249434, -213100, -176507, + -144467, -112761, -87348, -65472, -45559, -29659, + -17812, -6285, 5913, 11034, 14331, 17585, + 21840, 18597, 16523, 19606, 14800, 12216, + 13421, 8687, 9253, 5262, 7307, 4478, + 87, 917, 3655, 2959, -1190, -1801, + -2753, -174, -122, -410, -480, -795, + -1249, 1770, +}; + +static const int32_t fft_in_imag_512_q31[512] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, +}; + +static const int32_t fft_ref_real_512_q31[512] = { + -45, -91, 39, 13, 39, -12759, + 683966, -8435969, 44965977, -129224628, 221075980, -234823286, + 155575966, -62329239, 13936841, -1458185, 45393, -68, + -11, 94, 12, 28, -47, 61, + 89, -87, -33, 108, -49, -75, + -72, 76, -55, 53, 22, -71, + -24, 83, 42, -17, 71, 73, + 65, -2, 5, 63, -22, 0, + -22, 87, 31, -51, 42, -41, + -5, -51, 46, 32, -65, 92, + -3, 20, -36, -14, -131, -38, + 87, -49, 7, 6, 69, 9, + 26, -43, 11, -80, 145, -61, + 4, -4, -65, 76, 18, 25, + 118, -32, 8, 24, -76, 37, + -41, -23, 110, 126, -66, 55, + 12, -7, 119, -24, 29, -70, + 1, 42, -11, 118, 44, -5, + -28, -2, 33, -101, 36, -67, + 7, 19, -36, -15, 16, 16, + 30, 14, -41, -1, -6, -35, + -23, -50, 77, -11, 10, -28, + 102, 117, 41, 31, 39, 108, + 75, -68, -9, -6, 35, -69, + -52, 37, -81, 30, -76, -50, + 59, 0, 41, -24, 66, 61, + 6, -12, 28, 80, -68, 42, + 21, -62, 1, -103, -21, 7, + 46, 76, -48, 15, -76, 84, + 97, -35, 135, 18, 43, -20, + -22, 42, 54, 49, -48, -16, + -22, 18, -6, -76, 32, -80, + 25, 34, 8, 6, 9, 71, + -1, 97, -137, 52, -9, 0, + 2, 15, 19, -115, -40, 53, + 37, -22, -61, -72, -7, 4, + -41, 4, -44, -28, 16, -12, + -30, 17, 103, -24, 15, 41, + -25, -3, 15, -42, -73, 83, + -4, 49, 2, -96, 58, 85, + -11, -50, -24, -44, -75, -8, + 10, -23, 21, -26, 49, -50, + -40, 15, 87, -18, 58, -18, + 87, 15, -40, -50, 49, -26, + 21, -23, 10, -8, -75, -44, + -24, -50, -11, 85, 58, -96, + 2, 49, -4, 83, -73, -42, + 15, -3, -25, 41, 15, -24, + 103, 17, -30, -12, 16, -28, + -44, 4, -41, 4, -7, -72, + -61, -22, 37, 53, -40, -115, + 19, 15, 2, 0, -9, 52, + -137, 97, -1, 71, 9, 6, + 8, 34, 25, -80, 32, -76, + -6, 18, -22, -16, -48, 49, + 54, 42, -22, -20, 43, 18, + 135, -35, 97, 84, -76, 15, + -48, 76, 46, 7, -21, -103, + 1, -62, 21, 42, -68, 80, + 28, -12, 6, 61, 66, -24, + 41, 0, 59, -50, -76, 30, + -81, 37, -52, -69, 35, -6, + -9, -68, 75, 108, 39, 31, + 41, 117, 102, -28, 10, -11, + 77, -50, -23, -35, -6, -1, + -41, 14, 30, 16, 16, -15, + -36, 19, 7, -67, 36, -101, + 33, -2, -28, -5, 44, 118, + -11, 42, 1, -70, 29, -24, + 119, -7, 12, 55, -66, 126, + 110, -23, -41, 37, -76, 24, + 8, -32, 118, 25, 18, 76, + -65, -4, 4, -61, 145, -80, + 11, -43, 26, 9, 69, 6, + 7, -49, 87, -38, -131, -14, + -36, 20, -3, 92, -65, 32, + 46, -51, -5, -41, 42, -51, + 31, 87, -22, 0, -22, 63, + 5, -2, 65, 73, 71, -17, + 42, 83, -24, -71, 22, 53, + -55, 76, -72, -75, -49, 108, + -33, -87, 89, 61, -47, 28, + 12, 94, -11, -68, 45393, -1458185, + 13936841, -62329239, 155575966, -234823286, 221075980, -129224628, + 44965977, -8435969, 683966, -12759, 39, 13, + 39, -91, +}; + +static const int32_t fft_ref_imag_512_q31[512] = { + 0, 16, -60, 53, -58, -5240, + 284775, -3574190, 19378087, -56632327, 98507314, -106364728, + 71622799, -29159462, 6624575, -704027, 22181, -107, + 40, 52, 20, -56, -24, 12, + 16, -86, -125, 4, -12, 76, + -44, 24, 37, -11, 36, 32, + -10, 83, -45, 12, -22, 42, + -16, -11, 45, 41, 73, 29, + -59, 13, -10, -52, 9, -21, + -69, -51, -41, 13, -9, 102, + 4, 66, 62, -33, 113, -66, + -49, 36, -93, -52, -48, 49, + 56, 71, 1, 36, -56, -60, + -55, 36, -57, -130, 38, 51, + -69, 33, -49, -68, -10, 61, + 6, 29, 56, -41, -5, 18, + 65, 15, 71, 24, 27, -9, + 13, 19, 119, 52, -8, 26, + 60, -36, -5, 29, -25, -5, + -17, 3, 34, 21, -28, -92, + -21, -42, 28, 18, -95, 47, + 71, -4, -1, 47, -16, -27, + -25, 26, 16, 14, -92, 53, + -27, -14, 50, -23, 23, 87, + -45, 49, 156, -12, -49, 1, + 14, -22, -3, -33, -56, -39, + 24, -11, 74, -3, -36, -26, + -10, -5, 62, 48, -2, 58, + -111, 29, -20, 102, 104, -8, + -88, 41, 3, 24, 38, -40, + 79, -96, 11, 14, 23, -8, + 44, 26, -92, 14, 91, 9, + -74, -8, -40, 2, -99, -29, + -44, 10, -3, 49, -43, 11, + -66, -3, -1, 8, -2, 45, + 52, -39, 82, -32, -85, 55, + -59, -25, -58, -78, 34, 70, + -66, 104, -31, -5, 71, -56, + -25, -35, 37, 8, 18, 36, + 35, -15, 70, 86, 0, -54, + -65, -4, 45, 51, -101, 73, + 15, -27, 32, 32, 57, -22, + -3, -55, 46, -60, 0, 60, + -46, 55, 3, 22, -57, -32, + -32, 27, -15, -73, 101, -51, + -45, 4, 65, 54, 0, -86, + -70, 15, -35, -36, -18, -8, + -37, 35, 25, 56, -71, 5, + 31, -104, 66, -70, -34, 78, + 58, 25, 59, -55, 85, 32, + -82, 39, -52, -45, 2, -8, + 1, 3, 66, -11, 43, -49, + 3, -10, 44, 29, 99, -2, + 40, 8, 74, -9, -91, -14, + 92, -26, -44, 8, -23, -14, + -11, 96, -79, 40, -38, -24, + -3, -41, 88, 8, -104, -102, + 20, -29, 111, -58, 2, -48, + -62, 5, 10, 26, 36, 3, + -74, 11, -24, 39, 56, 33, + 3, 22, -14, -1, 49, 12, + -156, -49, 45, -87, -23, 23, + -50, 14, 27, -53, 92, -14, + -16, -26, 25, 27, 16, -47, + 1, 4, -71, -47, 95, -18, + -28, 42, 21, 92, 28, -21, + -34, -3, 17, 5, 25, -29, + 5, 36, -60, -26, 8, -52, + -119, -19, -13, 9, -27, -24, + -71, -15, -65, -18, 5, 41, + -56, -29, -6, -61, 10, 68, + 49, -33, 69, -51, -38, 130, + 57, -36, 55, 60, 56, -36, + -1, -71, -56, -49, 48, 52, + 93, -36, 49, 66, -113, 33, + -62, -66, -4, -102, 9, -13, + 41, 51, 69, 21, -9, 52, + 10, -13, 59, -29, -73, -41, + -45, 11, 16, -42, 22, -12, + 45, -83, 10, -32, -36, 11, + -37, -24, 44, -76, 12, -4, + 125, 86, -16, -12, 24, 56, + -20, -52, -40, 107, -22181, 704027, + -6624575, 29159462, -71622799, 106364728, -98507314, 56632327, + -19378087, 3574190, -284775, 5240, 58, -53, + 60, -16, +}; diff --git a/test/cmocka/src/math/fft/ref_fft_multi_768_32.h b/test/cmocka/src/math/fft/ref_fft_multi_768_32.h new file mode 100644 index 000000000000..e2addddba223 --- /dev/null +++ b/test/cmocka/src/math/fft/ref_fft_multi_768_32.h @@ -0,0 +1,532 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 20-Nov-2025 16:11:52 with script ref_fft_multi.m v1.9-rc1-6882-ge0b90b605-dirty */ + +#define REF_SOFM_FFT_MULTI_768_NUM_TESTS 1 + +static const int32_t fft_in_real_768_q31[768] = { + -241, 3628, 1266, -2634, 3092, 232, + -640, -2125, -647, -471, 2119, 325, + 924, 1109, 2295, 142, 2343, 4363, + 2796, 852, 2382, 3248, 59, -164, + -472, -531, -1894, -3358, -6065, -6495, + -10815, -14044, -14091, -21234, -21055, -28456, + -27657, -28889, -31938, -37655, -37301, -39941, + -37891, -34378, -35403, -25561, -19647, -12509, + -606, 7543, 27322, 43905, 60616, 82045, + 106206, 131271, 155362, 177405, 206514, 230378, + 252852, 269899, 284703, 292311, 298400, 296951, + 287396, 266368, 239466, 199332, 153113, 89801, + 17743, -67554, -159603, -263913, -379403, -500228, + -624420, -747661, -878313, -1008009, -1123947, -1235504, + -1330305, -1415140, -1469543, -1503109, -1506498, -1472749, + -1404180, -1300722, -1150891, -953777, -717782, -430319, + -101128, 266708, 676619, 1119232, 1588541, 2080078, + 2582718, 3082395, 3581368, 4053897, 4495380, 4890271, + 5223260, 5483176, 5660980, 5732018, 5692000, 5528919, + 5231518, 4798517, 4214949, 3489048, 2614503, 1598896, + 445129, -831444, -2217322, -3689401, -5234758, -6824231, + -8425955, -10013777, -11546286, -12986974, -14303728, -15452171, + -16393147, -17098221, -17516838, -17627470, -17394452, -16795021, + -15807984, -14417914, -12622002, -10422907, -7825330, -4853484, + -1537434, 2089436, 5978600, 10075995, 14311269, 18609861, + 22892297, 27073727, 31067236, 34772158, 38090534, 40934898, + 43202133, 44813294, 45679346, 45731324, 44905126, 43149410, + 40438048, 36750358, 32085432, 26463085, 19925175, 12540171, + 4381317, -4438039, -13790945, -23543065, -33528565, -43564061, + -53465445, -63029646, -72045718, -80312846, -87610680, -93744955, + -98520554, -101753835, -103280411, -102966601, -100709277, -96415613, + -90045652, -81592422, -71092553, -58618157, -44282598, -28246494, + -10713843, 8066777, 27824234, 48231529, 68946383, 89591059, + 109773996, 129088677, 147128854, 163468860, 177716203, 189481150, + 198414424, 204188194, 206522572, 205187796, 200015913, 190891669, + 177791058, 160736722, 139852452, 115319077, 87417331, 56488140, + 22961781, -12682422, -49874998, -88011035, -126426119, -164419626, + -201273383, -236244280, -268603859, -297627612, -322626893, -342948091, + -358004727, -367277860, -370342769, -366852815, -356581652, -339422399, + -315383357, -284601000, -247362998, -204058953, -155232745, -101548024, + -43766850, 17205216, 80403869, 144751837, 209130532, 272363524, + 333253552, 390604777, 443225021, 489983715, 529796603, 561679037, + 584753366, 598271174, 601626791, 594389174, 576296927, 547288978, + 507501344, 457258651, 397112676, 327797845, 250251097, 165585699, + 75093904, -19793649, -117512265, -216400732, -314702204, -410646381, + -502420161, -588236711, -666381398, -735199970, -793172141, -838922144, + -871263019, -889212884, -892024318, -879199280, -850513416, -806023413, + -746080576, -671318723, -582662836, -481304796, -368721547, -246617566, + -116917087, 18270872, 156674321, 295907377, 433516862, 567002905, + 693899018, 811767777, 918300703, 1011331647, 1088889407, 1149227101, + 1190877755, 1212675673, 1213778899, 1193712929, 1152364866, 1090009355, + 1007296111, 905266409, 785326540, 649219884, 499038860, 337158886, + 166206194, -10961531, -191342499, -371803627, -549163002, -720223486, + -881850257, -1031031431, -1164911846, -1280868241, -1376550015, -1449939386, + -1499367541, -1523583693, -1521766543, -1493533215, -1438987495, -1358687436, + -1253679050, -1125438417, -975903567, -807401765, -622633116, -424638658, + -216716665, -2389257, 214658063, 430646136, 641770661, 844277440, + 1034504073, 1208988113, 1364494665, 1498093914, 1607219524, 1689717041, + 1743869703, 1768468592, 1762801849, 1726698298, 1660522023, 1565178648, + 1442100556, 1293212702, 1120923589, 928071098, 717883328, 493909272, + 259976392, 20109529, -221543570, -460775430, -693380588, -915279395, + -1122535646, -1311465176, -1478694764, -1621202263, -1736420964, -1822228493, + -1877035711, -1899782713, -1889981357, -1847719295, -1773655476, -1669011369, + -1535556633, -1375568847, -1191799200, -987421289, -765980565, -531317241, + -287522473, -38826774, 210438051, 455926599, 693378607, 918668739, + 1127898672, 1317450221, 1484066329, 1624902389, 1737561435, 1820169914, + 1871370256, 1890370085, 1876956318, 1831481264, 1754859942, 1648550469, + 1514537726, 1355269389, 1173649163, 972947096, 756747847, 528901760, + 293423150, 54461413, -183819750, -417285653, -641919290, -853887630, + -1049609077, -1225812585, -1379604726, -1508498680, -1610479734, -1684014303, + -1728095431, -1742222985, -1726455301, -1681364668, -1608026287, -1508012075, + -1383349677, -1236465382, -1070165680, -887555137, -691989929, -487024198, + -276323896, -63620915, 147368778, 353015035, 549823704, 734499919, + 904012813, 1055637525, 1186997279, 1296126973, 1381461577, 1441882934, + 1476731983, 1485810836, 1469378480, 1428137473, 1363206291, 1276124718, + 1168776500, 1043382186, 902429921, 748648315, 584934734, 414320933, + 239889131, 64740645, -108075141, -275595744, -435033737, -583772214, + -719463613, -840011127, -943642758, -1028922523, -1094765960, -1140450717, + -1165628503, -1170317758, -1154910358, -1120124363, -1067022676, -996950501, + -911527447, -812600545, -702233328, -582607456, -456037458, -324903799, + -191587971, -58477754, 72134075, 198026348, 317140968, 427596570, + 527697948, 615989474, 691267140, 752573081, 799243835, 830886626, + 847377376, 848875628, 835788248, 808780118, 768740386, 716762333, + 654109652, 582210084, 502593426, 416905102, 326822356, 234056696, + 140318147, 47264446, -43493550, -130454209, -212221899, -287551695, + -355341753, -414661156, -464781140, -505142479, -535375283, -555326382, + -564998467, -564605784, -554520170, -535277315, -507545850, -472137486, + -429952101, -381993665, -329320813, -273037272, -214275690, -154161305, + -93793908, -34261274, 23446178, 78376049, 129678588, 176604769, + 218510346, 254869838, 285274876, 309446449, 327216576, 338561446, + 343550216, 342374595, 335330281, 322798847, 305241328, 283205569, + 257276138, 228087926, 196306163, 162614199, 127698298, 92230529, + 56859824, 22218011, -11122306, -42635429, -71849428, -98358438, + -121834503, -141999690, -158667712, -171721547, -181107624, -186849406, + -189032211, -187801396, -183357131, -175951701, -165863098, -153423152, + -138980699, -122894992, -105545878, -87314275, -68566012, -49677861, + -30984026, -12814682, 4531458, 20798958, 35753250, 49203321, + 60992344, 71008612, 79174265, 85454460, 89847498, 92383097, + 93135114, 92195760, 89684369, 85748781, 80536599, 74229321, + 67008217, 59067898, 50589678, 41764861, 32780594, 23799570, + 14993219, 6509774, -1519081, -8981737, -15771145, -21811536, + -27053959, -31440950, -34961449, -37604251, -39392286, -40339728, + -40496531, -39917823, -38657779, -36799506, -34411495, -31574572, + -28386220, -24923452, -21270576, -17508795, -13717544, -9974397, + -6333739, -2866681, 384131, 3368107, 6055198, 8416649, + 10434463, 12091696, 13399827, 14352349, 14958192, 15241456, + 15221308, 14925295, 14374955, 13608579, 12654643, 11552968, + 10327766, 9020876, 7661805, 6278839, 4907365, 3564212, + 2278189, 1064063, -56710, -1068964, -1969870, -2748235, + -3400263, -3926939, -4334024, -4613344, -4777385, -4836237, + -4799867, -4673215, -4466130, -4199935, -3874971, -3511593, + -3118446, -2704701, -2280034, -1857999, -1445532, -1048462, + -672536, -324455, -6582, 276892, 520368, 728589, + 897649, 1032019, 1126293, 1192973, 1228285, 1231327, + 1206481, 1161397, 1102233, 1026682, 938355, 843020, + 739097, 631951, 530386, 428349, 326932, 240431, + 154170, 73476, 6017, -55869, -103578, -144953, + -178246, -202681, -221485, -230703, -235306, -226956, + -222383, -208635, -196477, -178217, -164594, -144650, + -125017, -105575, -87630, -67991, -51183, -39259, + -23108, -11134, 1244, 9731, 12825, 20491, + 23334, 24167, 26047, 27043, 28682, 26990, + 26946, 22875, 20894, 17822, 18266, 15434, + 12288, 11757, 9451, 4447, 6333, 2560, + 3081, 1489, 1911, 2215, -1287, 197, + 1072, -1622, -3627, -2827, -1107, -1453, + -1069, -4722, 633, 1036, -3478, -2766, + 990, -1236, 1683, -3486, 3291, -2011, +}; + +static const int32_t fft_in_imag_768_q31[768] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +}; + +static const int32_t fft_ref_real_768_q31[768] = { + 45, 20, -33, 47, 30, -4, + -56, -17, 21, -19, -368, 43718, + -759260, 5010913, -16911518, 33136889, -39906332, 30002948, + -13815282, 3661837, -487124, 23450, -78, 55, + 58, 54, -44, -50, 69, 7, + -8, 3, 9, 37, -38, 92, + 6, 75, 74, -35, 16, -23, + -30, 7, 60, -2, 33, -28, + 35, 5, -27, 48, -6, 36, + 74, 49, 3, -36, -82, -71, + -17, 44, 13, 9, 1, 0, + 15, 116, 24, 13, -22, -83, + -43, -23, 52, -7, -32, 26, + 77, 12, -9, 61, -27, 64, + 14, -20, 0, 28, 38, -32, + -48, 27, -35, -15, -25, -29, + -33, -64, 12, 25, -34, -17, + -26, 62, 57, 47, -53, 45, + 36, -75, -50, -100, -53, 1, + -23, 12, -27, 126, -25, 11, + -13, -23, -54, 30, -8, -4, + 74, 33, -26, -18, 45, -4, + -28, -84, 42, 19, 2, -15, + -27, 27, 42, -49, 68, -51, + 17, 77, -46, 58, 6, 15, + -72, 32, -8, 97, 1, 21, + 47, -67, -98, 1, 6, 16, + 13, 10, 65, 83, -7, 58, + 34, 29, 33, -47, 53, 8, + -33, 25, -34, 61, -22, -34, + 37, 45, 52, 32, 36, 32, + -29, -13, 53, 46, -110, -40, + -76, 32, -18, -32, -46, -5, + 8, -22, -73, -49, -23, -39, + 6, -27, -34, -56, -42, -34, + -24, -18, 48, -19, -12, 115, + -23, 45, -22, -81, -65, 13, + 42, 28, -15, 43, 9, -18, + -98, -21, 4, 21, 37, -35, + -14, -14, 20, -37, -62, 66, + 10, -1, -26, 1, 35, 2, + -25, -91, -9, 26, 23, -39, + 9, 5, -27, 21, -24, 21, + 12, -26, -71, -17, 26, -31, + -23, 1, 107, -94, -17, 12, + -30, -53, 62, 28, 0, 55, + -109, -29, -79, -80, -53, -30, + -61, -57, -47, 59, -44, -19, + 30, 48, -43, 42, -15, 11, + 1, -23, -38, -12, -47, -30, + -50, -3, -20, -20, 68, -42, + -1, -15, 16, -33, 4, -23, + -59, -24, -39, 5, -34, 67, + -40, 14, 105, 41, -40, 38, + -12, -34, 34, 16, -21, 68, + -42, -32, -32, -12, 8, -58, + 29, 2, 39, 76, 57, 35, + -26, -18, -70, -14, 20, -37, + 23, 18, -47, -72, 69, -24, + -6, 41, -1, 8, 25, -41, + -5, 58, 71, 72, -40, 50, + 32, -28, 55, 50, -52, -27, + 44, 38, -23, 18, 38, 9, + 53, -26, 45, 79, -17, 110, + 32, 110, -17, 79, 45, -26, + 53, 9, 38, 18, -23, 38, + 44, -27, -52, 50, 55, -28, + 32, 50, -40, 72, 71, 58, + -5, -41, 25, 8, -1, 41, + -6, -24, 69, -72, -47, 18, + 23, -37, 20, -14, -70, -18, + -26, 35, 57, 76, 39, 2, + 29, -58, 8, -12, -32, -32, + -42, 68, -21, 16, 34, -34, + -12, 38, -40, 41, 105, 14, + -40, 67, -34, 5, -39, -24, + -59, -23, 4, -33, 16, -15, + -1, -42, 68, -20, -20, -3, + -50, -30, -47, -12, -38, -23, + 1, 11, -15, 42, -43, 48, + 30, -19, -44, 59, -47, -57, + -61, -30, -53, -80, -79, -29, + -109, 55, 0, 28, 62, -53, + -30, 12, -17, -94, 107, 1, + -23, -31, 26, -17, -71, -26, + 12, 21, -24, 21, -27, 5, + 9, -39, 23, 26, -9, -91, + -25, 2, 35, 1, -26, -1, + 10, 66, -62, -37, 20, -14, + -14, -35, 37, 21, 4, -21, + -98, -18, 9, 43, -15, 28, + 42, 13, -65, -81, -22, 45, + -23, 115, -12, -19, 48, -18, + -24, -34, -42, -56, -34, -27, + 6, -39, -23, -49, -73, -22, + 8, -5, -46, -32, -18, 32, + -76, -40, -110, 46, 53, -13, + -29, 32, 36, 32, 52, 45, + 37, -34, -22, 61, -34, 25, + -33, 8, 53, -47, 33, 29, + 34, 58, -7, 83, 65, 10, + 13, 16, 6, 1, -98, -67, + 47, 21, 1, 97, -8, 32, + -72, 15, 6, 58, -46, 77, + 17, -51, 68, -49, 42, 27, + -27, -15, 2, 19, 42, -84, + -28, -4, 45, -18, -26, 33, + 74, -4, -8, 30, -54, -23, + -13, 11, -25, 126, -27, 12, + -23, 1, -53, -100, -50, -75, + 36, 45, -53, 47, 57, 62, + -26, -17, -34, 25, 12, -64, + -33, -29, -25, -15, -35, 27, + -48, -32, 38, 28, 0, -20, + 14, 64, -27, 61, -9, 12, + 77, 26, -32, -7, 52, -23, + -43, -83, -22, 13, 24, 116, + 15, 0, 1, 9, 13, 44, + -17, -71, -82, -36, 3, 49, + 74, 36, -6, 48, -27, 5, + 35, -28, 33, -2, 60, 7, + -30, -23, 16, -35, 74, 75, + 6, 92, -38, 37, 9, 3, + -8, 7, 69, -50, -44, 54, + 58, 55, -78, 23450, -487124, 3661837, + -13815282, 30002948, -39906332, 33136889, -16911518, 5010913, + -759260, 43718, -368, -19, 21, -17, + -56, -4, 30, 47, -33, 20, +}; + +static const int32_t fft_ref_imag_768_q31[768] = { + 0, -32, -5, 26, 5, 43, + -33, 33, 46, -24, -1903, 252986, + -4504301, 30493677, -105611719, 212501965, -262975509, 203317701, + -96347654, 26303114, -3606843, 179333, -945, -2, + -33, -11, -91, -18, -5, -11, + -4, 11, 43, -17, 26, 49, + 13, -31, -13, 4, 27, -2, + -1, 66, -18, -35, 34, -14, + 37, -68, 47, 2, -33, 36, + -10, 44, -5, -19, 8, -19, + -26, -44, 65, -29, -73, -29, + -22, -24, 11, -29, 13, -44, + -26, 44, 76, -44, -30, 26, + 3, -45, -18, 105, -113, 82, + -11, 57, -5, -54, -10, -36, + 0, 11, -10, 40, -33, -29, + 7, 34, -19, -11, -114, 57, + 18, 26, -81, -58, 9, -19, + 0, 92, 77, -34, -14, -76, + 35, -55, -9, 43, 7, 2, + 46, -51, 39, -57, 57, -96, + 9, 36, -6, 91, 12, -133, + -27, 38, 14, 52, 16, 12, + 16, -36, 43, -9, -23, 22, + 31, -5, -90, -25, -34, 61, + -49, 22, -56, 26, 39, -25, + -23, -69, -17, -49, 33, -10, + -86, 125, 10, -22, 62, -77, + -28, -96, -11, 68, 17, -26, + 69, 29, -16, -43, 29, 16, + 71, -13, -4, 26, 51, 21, + -43, -28, -30, -55, 26, 19, + 33, -7, -21, 9, -17, -38, + -41, -34, -14, 14, 6, -43, + -27, 70, 30, -53, -31, -11, + -24, -4, -27, 0, -31, -71, + -4, -17, 44, 29, 18, -32, + -11, -15, -12, -2, 2, -24, + -43, 9, -103, 54, -39, -80, + 41, -118, 17, -16, -35, -76, + 11, -34, -9, -58, -18, -20, + 54, 28, 23, -38, -47, -15, + 7, -104, 11, 59, 29, 37, + -29, -37, 16, 0, -4, 26, + 27, -40, 38, 58, -55, 2, + 42, 21, -51, 47, -5, -77, + -1, -29, 63, 14, 30, -35, + -73, 1, 13, 8, 65, -17, + -2, -21, -66, 87, -17, -134, + 9, -66, -11, 66, -27, -28, + 12, 31, -24, 0, -61, 14, + 58, 20, -46, -17, -14, -14, + -12, -47, 12, -63, 27, -21, + 33, -78, 1, 16, -25, -48, + -41, -96, 137, -59, 4, 18, + 43, 32, -33, -21, -13, 16, + 71, -39, -46, 33, 5, -7, + -11, -19, -13, -16, -59, 45, + -26, -24, -70, -39, 2, 12, + 70, 43, -58, 32, 34, -40, + 44, -32, -28, -26, 23, -7, + 64, -63, 24, 37, -17, 7, + -1, 0, -59, -16, 5, -77, + -16, 51, 19, 44, 16, 62, + 0, -62, -16, -44, -19, -51, + 16, 77, -5, 16, 59, 0, + 1, -7, 17, -37, -24, 63, + -64, 7, -23, 26, 28, 32, + -44, 40, -34, -32, 58, -43, + -70, -12, -2, 39, 70, 24, + 26, -45, 59, 16, 13, 19, + 11, 7, -5, -33, 46, 39, + -71, -16, 13, 21, 33, -32, + -43, -18, -4, 59, -137, 96, + 41, 48, 25, -16, -1, 78, + -33, 21, -27, 63, -12, 47, + 12, 14, 14, 17, 46, -20, + -58, -14, 61, 0, 24, -31, + -12, 28, 27, -66, 11, 66, + -9, 134, 17, -87, 66, 21, + 2, 17, -65, -8, -13, -1, + 73, 35, -30, -14, -63, 29, + 1, 77, 5, -47, 51, -21, + -42, -2, 55, -58, -38, 40, + -27, -26, 4, 0, -16, 37, + 29, -37, -29, -59, -11, 104, + -7, 15, 47, 38, -23, -28, + -54, 20, 18, 58, 9, 34, + -11, 76, 35, 16, -17, 118, + -41, 80, 39, -54, 103, -9, + 43, 24, -2, 2, 12, 15, + 11, 32, -18, -29, -44, 17, + 4, 71, 31, 0, 27, 4, + 24, 11, 31, 53, -30, -70, + 27, 43, -6, -14, 14, 34, + 41, 38, 17, -9, 21, 7, + -33, -19, -26, 55, 30, 28, + 43, -21, -51, -26, 4, 13, + -71, -16, -29, 43, 16, -29, + -69, 26, -17, -68, 11, 96, + 28, 77, -62, 22, -10, -125, + 86, 10, -33, 49, 17, 69, + 23, 25, -39, -26, 56, -22, + 49, -61, 34, 25, 90, 5, + -31, -22, 23, 9, -43, 36, + -16, -12, -16, -52, -14, -38, + 27, 133, -12, -91, 6, -36, + -9, 96, -57, 57, -39, 51, + -46, -2, -7, -43, 9, 55, + -35, 76, 14, 34, -77, -92, + 0, 19, -9, 58, 81, -26, + -18, -57, 114, 11, 19, -34, + -7, 29, 33, -40, 10, -11, + 0, 36, 10, 54, 5, -57, + 11, -82, 113, -105, 18, 45, + -3, -26, 30, 44, -76, -44, + 26, 44, -13, 29, -11, 24, + 22, 29, 73, 29, -65, 44, + 26, 19, -8, 19, 5, -44, + 10, -36, 33, -2, -47, 68, + -37, 14, -34, 35, 18, -66, + 1, 2, -27, -4, 13, 31, + -13, -49, -26, 17, -43, -11, + 4, 11, 5, 18, 91, 11, + 33, 2, 945, -179333, 3606843, -26303114, + 96347654, -203317701, 262975509, -212501965, 105611719, -30493677, + 4504301, -252986, 1903, 24, -46, -33, + 33, -43, -5, -26, 5, 32, +}; diff --git a/test/cmocka/src/math/fft/ref_fft_multi_96_32.h b/test/cmocka/src/math/fft/ref_fft_multi_96_32.h new file mode 100644 index 000000000000..48ed4c1e7ae1 --- /dev/null +++ b/test/cmocka/src/math/fft/ref_fft_multi_96_32.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 20-Nov-2025 16:11:52 with script ref_fft_multi.m v1.9-rc1-6882-ge0b90b605-dirty */ + +#define REF_SOFM_FFT_MULTI_96_NUM_TESTS 1 + +static const int32_t fft_in_real_96_q31[96] = { + 2612, -585, 740, 1771, 10242, 28387, + 67673, 150357, 305252, 583434, 1049075, 1773977, + 2866391, 4421878, 6535194, 9264176, 12595638, 16410151, + 20420570, 24132226, 26792322, 27353105, 24457934, 16442487, + 1411524, -22682595, -57886075, -106071598, -168720146, -246662584, + -339873057, -447258396, -566496507, -693969722, -824813628, -953046420, + -1071834144, -1173876250, -1251869944, -1299031192, -1309635449, -1279509181, + -1206486132, -1090677103, -934610659, -743214358, -523566965, -284489188, + -36038274, 211200645, 446740932, 660913160, 845461777, 994029750, + 1102498010, 1169119233, 1194490190, 1181384510, 1134337335, 1059242451, + 962836599, 852157942, 734074206, 614854055, 499863929, 393334033, + 298286546, 216528461, 148768326, 94769100, 53566286, 23675203, + 3333228, -9343610, -16164205, -18786637, -18606500, -16758603, + -14096842, -11214929, -8500848, -6156283, -4266830, -2826418, + -1788630, -1079523, -614752, -331493, -166234, -76988, + -33171, -13273, -4796, -1383, 2439, 1203, +}; + +static const int32_t fft_in_imag_96_q31[96] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +}; + +static const int32_t fft_ref_real_96_q31[96] = { + -17402140, 14269492, -5584270, -2890773, 4789231, -2333890, + 486956, -35699, 330, 13, 164, 145, + 68, -18, -52, -121, 151, 206, + -21, -66, -30, 131, 0, 78, + -307, 162, -16, -184, 174, -39, + 140, -48, 32, -31, -199, 139, + -187, 137, -72, 272, 156, -11, + -74, 3, 49, 154, -109, 172, + 81, 172, -109, 154, 49, 3, + -74, -11, 156, 272, -72, 137, + -187, 139, -199, -31, 32, -48, + 140, -39, 174, -184, -16, 162, + -307, 78, 0, 131, -30, -66, + -21, 206, 151, -121, -52, -18, + 68, 145, 164, 13, 330, -35699, + 486956, -2333890, 4789231, -2890773, -5584270, 14269492, +}; + +static const int32_t fft_ref_imag_96_q31[96] = { + 0, 179914066, -259234323, 208477801, -102275624, 29288094, + -4318694, 244372, -1937, 98, -53, 13, + -18, 191, 43, 145, 120, 116, + -14, 54, 22, -22, -73, -99, + 113, 41, 26, -65, 99, -120, + -16, 69, -52, -74, 73, -70, + 85, -46, 106, -107, 55, -3, + 13, -45, -98, 68, 77, -85, + 0, 85, -77, -68, 98, 45, + -13, 3, -55, 107, -106, 46, + -85, 70, -73, 74, 52, -69, + 16, 120, -99, 65, -26, -41, + -113, 99, 73, 22, -22, -54, + 14, -116, -120, -145, -43, -191, + 18, -13, 53, -98, 1937, -244372, + 4318694, -29288094, 102275624, -208477801, 259234323, -179914066, +}; diff --git a/test/cmocka/src/math/fft/ref_ifft_multi_1024_32.h b/test/cmocka/src/math/fft/ref_ifft_multi_1024_32.h new file mode 100644 index 000000000000..f9d39f509c2e --- /dev/null +++ b/test/cmocka/src/math/fft/ref_ifft_multi_1024_32.h @@ -0,0 +1,704 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 20-Nov-2025 16:11:52 with script ref_fft_multi.m v1.9-rc1-6882-ge0b90b605-dirty */ + +#define REF_SOFM_IFFT_MULTI_1024_NUM_TESTS 1 + +static const int32_t ifft_in_real_1024_q31[1024] = { + -25, -79, 39, 48, -13, -34, + -8, -8, -21, -23, 43, -46, + -62, -24, -39, 10, -55147, 1535442, + -13543809, 57130805, -135763817, 195823576, -176199328, 98119764, + -32279401, 5635577, -409793, 5971, 1, 4, + 86, 8, -39, -22, 43, 34, + 22, -65, -65, 9, 49, 17, + 54, 42, -41, 100, 11, -49, + 26, 19, -36, 4, -26, 25, + -30, 19, 27, -30, 78, -61, + -71, 7, 2, 33, 51, -3, + 29, 17, 7, 0, -28, 45, + 17, -31, -72, 44, 14, -9, + 38, 11, 35, 10, 68, 34, + -3, 6, 19, 16, 45, -35, + 48, 21, 28, 27, 18, 41, + 5, 35, -2, -5, -69, 14, + -6, 45, 22, 19, 55, 14, + 13, 40, 5, 4, 11, -30, + 59, 18, 94, 41, -92, 27, + -3, -2, 50, 35, -24, 27, + 44, -40, 35, -28, 49, -30, + -3, 11, -54, -28, 6, 45, + -21, 63, -10, -10, -8, -2, + 24, 10, 50, 4, 21, -29, + -10, 39, -61, 16, -28, -29, + -58, 37, 38, -34, 19, -72, + -30, 9, 45, -36, 32, 23, + 38, 59, -59, -23, -31, -60, + 23, -11, 12, -15, -32, 36, + 15, 48, -39, -33, 81, -58, + -2, -73, 50, -70, 19, 8, + 45, -18, -22, 40, -8, 23, + 18, 42, 18, 80, 38, -1, + 7, -4, 3, 23, 23, -59, + -4, 21, -45, -26, 49, -17, + 61, -16, -17, 32, -8, -13, + 32, 77, -72, 50, -6, 9, + 51, 21, -35, -95, -32, -6, + 26, 17, 4, -56, 0, -94, + 3, -5, 3, 7, -57, -44, + -29, -18, 29, -92, -25, -93, + 41, 4, 5, -38, -1, -64, + -81, -63, -21, -41, -51, 41, + -59, -1, 68, -14, 40, -62, + 47, 73, 9, 25, 57, -18, + 15, -25, -39, -49, 1, 11, + 37, -28, 42, -52, 45, 5, + 47, -40, -10, -8, 45, -1, + -28, -33, 63, -44, 38, 15, + 15, -48, 45, -51, -28, -87, + 7, 10, -63, 25, 29, 48, + -1, -36, 10, -44, 41, 33, + 9, 32, -15, -40, -86, 12, + -84, 34, 46, -12, -5, 54, + -19, -8, -46, -26, -4, -57, + -44, -11, -7, -19, 10, -30, + -1, 39, 9, -17, -22, 35, + -14, -7, 5, -41, 27, -2, + -21, 33, 47, 20, 66, 1, + 23, -54, -4, -34, 2, 33, + 56, -7, 26, 11, 20, -30, + -66, -30, -20, 18, 72, -24, + -37, -20, -70, -21, -48, 64, + -45, 15, -46, 19, -41, -8, + -38, 17, -14, -27, 5, -72, + 34, 36, 29, -5, -11, 24, + -10, 26, -16, 30, 22, -18, + 37, 31, -14, 42, -14, -17, + -10, 29, -14, -80, -2, 26, + -10, -21, -87, 20, 76, 1, + 28, -11, 81, 44, 18, -9, + 12, 53, 40, 14, 8, 18, + 4, -3, -19, -4, -15, -8, + 19, -18, -12, -34, 10, -29, + -56, -10, -18, -59, 45, 19, + 12, 25, -4, 12, 34, -27, + 0, 1, 29, -16, 14, 7, + -41, 15, 26, -21, 24, -30, + -9, -24, 26, 14, 76, 0, + 76, 4, -32, 91, -21, -31, + -6, 8, -45, 21, 69, 44, + -9, 0, -7, -27, -14, 14, + -3, -6, 44, -4, 7, -35, + -40, 32, -18, -17, -40, -21, + -17, 51, 31, 51, -17, -21, + -40, -17, -18, 32, -40, -35, + 7, -4, 44, -6, -3, 14, + -14, -27, -7, 0, -9, 44, + 69, 21, -45, 8, -6, -31, + -21, 91, -32, 4, 76, 0, + 76, 14, 26, -24, -9, -30, + 24, -21, 26, 15, -41, 7, + 14, -16, 29, 1, 0, -27, + 34, 12, -4, 25, 12, 19, + 45, -59, -18, -10, -56, -29, + 10, -34, -12, -18, 19, -8, + -15, -4, -19, -3, 4, 18, + 8, 14, 40, 53, 12, -9, + 18, 44, 81, -11, 28, 1, + 76, 20, -87, -21, -10, 26, + -2, -80, -14, 29, -10, -17, + -14, 42, -14, 31, 37, -18, + 22, 30, -16, 26, -10, 24, + -11, -5, 29, 36, 34, -72, + 5, -27, -14, 17, -38, -8, + -41, 19, -46, 15, -45, 64, + -48, -21, -70, -20, -37, -24, + 72, 18, -20, -30, -66, -30, + 20, 11, 26, -7, 56, 33, + 2, -34, -4, -54, 23, 1, + 66, 20, 47, 33, -21, -2, + 27, -41, 5, -7, -14, 35, + -22, -17, 9, 39, -1, -30, + 10, -19, -7, -11, -44, -57, + -4, -26, -46, -8, -19, 54, + -5, -12, 46, 34, -84, 12, + -86, -40, -15, 32, 9, 33, + 41, -44, 10, -36, -1, 48, + 29, 25, -63, 10, 7, -87, + -28, -51, 45, -48, 15, 15, + 38, -44, 63, -33, -28, -1, + 45, -8, -10, -40, 47, 5, + 45, -52, 42, -28, 37, 11, + 1, -49, -39, -25, 15, -18, + 57, 25, 9, 73, 47, -62, + 40, -14, 68, -1, -59, 41, + -51, -41, -21, -63, -81, -64, + -1, -38, 5, 4, 41, -93, + -25, -92, 29, -18, -29, -44, + -57, 7, 3, -5, 3, -94, + 0, -56, 4, 17, 26, -6, + -32, -95, -35, 21, 51, 9, + -6, 50, -72, 77, 32, -13, + -8, 32, -17, -16, 61, -17, + 49, -26, -45, 21, -4, -59, + 23, 23, 3, -4, 7, -1, + 38, 80, 18, 42, 18, 23, + -8, 40, -22, -18, 45, 8, + 19, -70, 50, -73, -2, -58, + 81, -33, -39, 48, 15, 36, + -32, -15, 12, -11, 23, -60, + -31, -23, -59, 59, 38, 23, + 32, -36, 45, 9, -30, -72, + 19, -34, 38, 37, -58, -29, + -28, 16, -61, 39, -10, -29, + 21, 4, 50, 10, 24, -2, + -8, -10, -10, 63, -21, 45, + 6, -28, -54, 11, -3, -30, + 49, -28, 35, -40, 44, 27, + -24, 35, 50, -2, -3, 27, + -92, 41, 94, 18, 59, -30, + 11, 4, 5, 40, 13, 14, + 55, 19, 22, 45, -6, 14, + -69, -5, -2, 35, 5, 41, + 18, 27, 28, 21, 48, -35, + 45, 16, 19, 6, -3, 34, + 68, 10, 35, 11, 38, -9, + 14, 44, -72, -31, 17, 45, + -28, 0, 7, 17, 29, -3, + 51, 33, 2, 7, -71, -61, + 78, -30, 27, 19, -30, 25, + -26, 4, -36, 19, 26, -49, + 11, 100, -41, 42, 54, 17, + 49, 9, -65, -65, 22, 34, + 43, -22, -39, 8, 86, 4, + 1, 5971, -409793, 5635577, -32279401, 98119764, + -176199328, 195823576, -135763817, 57130805, -13543809, 1535442, + -55147, 10, -39, -24, -62, -46, + 43, -23, -21, -8, -8, -34, + -13, 48, 39, -79, +}; + +static const int32_t ifft_in_imag_1024_q31[1024] = { + 0, -83, 39, 95, 15, 7, + -35, 3, -6, -13, 35, 57, + 28, 60, -67, -79, 50487, -1395762, + 12235510, -51294609, 121144602, -173660953, 155294502, -85945073, + 28099679, -4875536, 352396, -5166, 26, -2, + -73, -42, 38, 16, 22, -70, + 59, -3, -20, 45, 5, -16, + 10, 11, 20, -37, -43, -13, + 25, -25, 28, 39, -27, -7, + 46, -10, 59, 84, 14, -82, + 2, 13, 16, -54, 84, 0, + 50, -8, 13, 59, -28, -33, + 81, -5, 42, -22, -37, -7, + -40, -26, -32, -90, 2, 60, + 17, 38, 19, -58, 29, 17, + 38, 31, -21, -77, -3, 43, + -27, 23, 10, 20, -35, 3, + 13, 16, 22, 36, -42, 0, + 5, 4, -38, 51, -37, -83, + 10, -7, -9, 2, -83, -99, + 7, -10, -32, -40, 26, -8, + 16, 62, -15, 28, -21, 111, + 17, 8, 71, 64, -25, 24, + -18, -18, 36, -2, 2, 42, + -4, -32, 19, -76, 28, -83, + 57, -12, -26, -11, -3, -17, + 51, -36, 33, -66, -1, -28, + 16, -7, -62, 24, -47, -23, + -18, -22, 80, -15, -86, 46, + 59, 11, -11, -20, -23, 35, + -5, 16, 29, -15, -20, -53, + 99, 58, -10, 34, 28, -13, + 23, 10, -42, -61, 52, 31, + -5, 9, 0, -50, -56, -47, + 13, 1, -22, -1, -48, 8, + -2, 34, -26, 39, -54, -9, + -9, -30, 15, 6, 46, -36, + -55, 24, 15, 1, -33, 7, + 0, 23, -19, 35, -15, 43, + 83, -21, -32, -11, -44, -1, + 81, 16, -34, 14, -39, -11, + -65, -17, -9, 42, -10, -4, + 24, -34, -15, -9, -15, -10, + -26, 20, 28, 0, -5, -46, + 7, -71, -48, -35, 1, -4, + 120, -22, 4, 1, -37, -2, + -35, -30, 67, -55, -40, -3, + -104, -17, 24, -2, 22, 44, + -32, -34, 11, 58, 10, -21, + 25, 13, 86, 12, -70, -14, + -26, -40, 3, 28, 26, -36, + 12, 32, -15, 10, 52, 40, + -4, 59, 13, -32, -23, -21, + 2, -54, 28, -27, -12, 14, + 69, -74, 0, 42, -32, 16, + 24, -10, 32, -10, 19, -8, + -14, -3, 50, 6, -33, -56, + 40, 6, -39, -29, 18, 7, + 40, -35, -39, 96, -32, 71, + 63, -32, 1, 49, -75, 60, + -56, 7, -51, -9, -30, 11, + 4, -54, 24, 55, -1, 87, + 56, -55, -4, 27, -20, -92, + -29, 49, 15, -32, 9, -32, + 53, 16, 40, -20, 29, 19, + 31, 21, 37, 19, -40, 76, + 25, 49, -8, 10, 26, 61, + -29, 24, 59, -34, 71, -43, + 42, -16, -5, 4, 4, -56, + -18, -56, 9, 30, -26, 1, + -71, 21, 86, -3, -58, 7, + 80, -38, -10, -16, -2, 18, + -14, -3, 15, 27, -17, -67, + -15, 41, -13, 6, 13, 24, + -25, 39, -24, -12, 16, -14, + 23, 26, 10, 53, -49, -49, + -38, 6, 31, -30, -5, -16, + 16, -14, -31, 60, -42, -7, + 66, 52, 16, -12, -36, -9, + -60, -21, 63, -40, -47, -4, + -73, 16, 75, -46, -41, -12, + -19, -48, 5, -22, 19, 14, + 56, 42, -23, -11, 29, -17, + -68, -31, -19, -4, -46, 16, + 55, 23, 22, -15, -9, -7, + -31, -26, 0, 26, 31, 7, + 9, 15, -22, -23, -55, -16, + 46, 4, 19, 31, 68, 17, + -29, 11, 23, -42, -56, -14, + -19, 22, -5, 48, 19, 12, + 41, 46, -75, -16, 73, 4, + 47, 40, -63, 21, 60, 9, + 36, 12, -16, -52, -66, 7, + 42, -60, 31, 14, -16, 16, + 5, 30, -31, -6, 38, 49, + 49, -53, -10, -26, -23, 14, + -16, 12, 24, -39, 25, -24, + -13, -6, 13, -41, 15, 67, + 17, -27, -15, 3, 14, -18, + 2, 16, 10, 38, -80, -7, + 58, 3, -86, -21, 71, -1, + 26, -30, -9, 56, 18, 56, + -4, -4, 5, 16, -42, 43, + -71, 34, -59, -24, 29, -61, + -26, -10, 8, -49, -25, -76, + 40, -19, -37, -21, -31, -19, + -29, 20, -40, -16, -53, 32, + -9, 32, -15, -49, 29, 92, + 20, -27, 4, 55, -56, -87, + 1, -55, -24, 54, -4, -11, + 30, 9, 51, -7, 56, -60, + 75, -49, -1, 32, -63, -71, + 32, -96, 39, 35, -40, -7, + -18, 29, 39, -6, -40, 56, + 33, -6, -50, 3, 14, 8, + -19, 10, -32, 10, -24, -16, + 32, -42, 0, 74, -69, -14, + 12, 27, -28, 54, -2, 21, + 23, 32, -13, -59, 4, -40, + -52, -10, 15, -32, -12, 36, + -26, -28, -3, 40, 26, 14, + 70, -12, -86, -13, -25, 21, + -10, -58, -11, 34, 32, -44, + -22, 2, -24, 17, 104, 3, + 40, 55, -67, 30, 35, 2, + 37, -1, -4, 22, -120, 4, + -1, 35, 48, 71, -7, 46, + 5, 0, -28, -20, 26, 10, + 15, 9, 15, 34, -24, 4, + 10, -42, 9, 17, 65, 11, + 39, -14, 34, -16, -81, 1, + 44, 11, 32, 21, -83, -43, + 15, -35, 19, -23, 0, -7, + 33, -1, -15, -24, 55, 36, + -46, -6, -15, 30, 9, 9, + 54, -39, 26, -34, 2, -8, + 48, 1, 22, -1, -13, 47, + 56, 50, 0, -9, 5, -31, + -52, 61, 42, -10, -23, 13, + -28, -34, 10, -58, -99, 53, + 20, 15, -29, -16, 5, -35, + 23, 20, 11, -11, -59, -46, + 86, 15, -80, 22, 18, 23, + 47, -24, 62, 7, -16, 28, + 1, 66, -33, 36, -51, 17, + 3, 11, 26, 12, -57, 83, + -28, 76, -19, 32, 4, -42, + -2, 2, -36, 18, 18, -24, + 25, -64, -71, -8, -17, -111, + 21, -28, 15, -62, -16, 8, + -26, 40, 32, 10, -7, 99, + 83, -2, 9, 7, -10, 83, + 37, -51, 38, -4, -5, 0, + 42, -36, -22, -16, -13, -3, + 35, -20, -10, -23, 27, -43, + 3, 77, 21, -31, -38, -17, + -29, 58, -19, -38, -17, -60, + -2, 90, 32, 26, 40, 7, + 37, 22, -42, 5, -81, 33, + 28, -59, -13, 8, -50, 0, + -84, 54, -16, -13, -2, 82, + -14, -84, -59, 10, -46, 7, + 27, -39, -28, 25, -25, 13, + 43, 37, -20, -11, -10, 16, + -5, -45, 20, 3, -59, 70, + -22, -16, -38, 42, 73, 2, + -26, 5166, -352396, 4875536, -28099679, 85945073, + -155294502, 173660953, -121144602, 51294609, -12235510, 1395762, + -50487, 79, 67, -60, -28, -57, + -35, 13, 6, -3, 35, -7, + -15, -95, -39, 83, +}; + +static const int32_t ifft_ref_real_1024_q31[1024] = { + 326, 1146, 2786, -3072, -3316, -605, + -2901, -840, -2671, 664, 2057, 956, + -21, -662, 462, 3641, -2217, 610, + -1321, 238, 2943, 688, 1060, 846, + -3792, -1576, 2121, -1631, -211, -2712, + -2722, -3466, -8597, -7806, -10107, -8978, + -8707, -11131, -9732, -15323, -15254, -13081, + -12623, -10274, -13212, -5985, -4940, -4716, + -1004, 3307, 7423, 11870, 21908, 23159, + 29444, 38649, 46299, 51698, 58474, 61509, + 69988, 71541, 78183, 80345, 79248, 80016, + 77508, 69254, 64701, 54919, 38485, 22397, + 7619, -18671, -39738, -64092, -93406, -121566, + -151206, -181934, -213000, -241011, -269356, -295013, + -318042, -331352, -343862, -348224, -349487, -339135, + -319901, -295323, -258729, -214256, -161875, -98338, + -22320, 61463, 148883, 241596, 343430, 449953, + 553092, 660575, 765348, 863233, 956207, 1031827, + 1098053, 1152642, 1181959, 1190748, 1179948, 1146590, + 1076767, 984062, 860947, 715027, 533899, 321992, + 91170, -167866, -444979, -738889, -1046761, -1361827, + -1677156, -1987696, -2285378, -2563978, -2820773, -3038273, + -3217797, -3348348, -3421990, -3434697, -3385794, -3264787, + -3066741, -2788681, -2438638, -2011383, -1505748, -933663, + -291619, 399962, 1144061, 1925860, 2735503, 3549988, + 4362537, 5151016, 5907267, 6604092, 7230123, 7760787, + 8186022, 8488314, 8646197, 8646598, 8484987, 8152712, + 7635835, 6935136, 6051955, 4991930, 3755510, 2363819, + 826364, -834320, -2599066, -4440124, -6321571, -8216197, + -10077901, -11885570, -13588265, -15155182, -16535940, -17702619, + -18613150, -19234858, -19532980, -19487165, -19075195, -18273148, + -17078708, -15490893, -13506877, -11147624, -8430976, -5382361, + -2046368, 1542253, 5318886, 9227859, 13214381, 17188190, + 21089248, 24838424, 28350006, 31546237, 34346432, 36681320, + 38471965, 39655342, 40176918, 39988511, 39053022, 37340045, + 34844574, 31564156, 27518651, 22736319, 17272291, 11186028, + 4553529, -2522282, -9940434, -17585491, -25318423, -33006825, + -40506944, -47660215, -54327081, -60355027, -65599108, -69911020, + -73182968, -75287952, -76129493, -75629810, -73723931, -70383367, + -65595111, -59372093, -51768179, -42837441, -32692074, -21452167, + -9277743, 3657281, 17156928, 30990380, 44930749, 58723629, + 72104522, 84815781, 96588254, 107170396, 116310129, 123773406, + 129346015, 132845872, 134109268, 133017610, 129484530, 123462360, + 114949234, 103998137, 90691090, 75177605, 57635434, 38303041, + 17446134, -4620199, -27539988, -50941560, -74413943, -97543947, + -119891596, -141022922, -160505079, -177918821, -192864296, -204973947, + -213909668, -219387656, -221170208, -219080741, -212996462, -202883444, + -188761959, -170722219, -148945912, -123689848, -95255466, -64056433, + -30529263, 4794075, 41356921, 78547365, 115714160, 152194199, + 187309917, 220377731, 250731557, 277733009, 300773373, 319311844, + 332844739, 340960776, 343321097, 339692071, 329923185, 313994650, + 291963289, 264028543, 230483055, 191743888, 148332347, 100859462, + 50042902, -3319828, -58361358, -114155510, -169723973, -224083369, + -276218550, -325136386, -369863274, -409475668, -443106446, -469980132, + -489407054, -500821595, -503772467, -497957373, -483223160, -459560044, + -427130807, -386246818, -337395714, -281211712, -218478864, -150120760, + -77192341, -857360, 77633043, 156945573, 235703099, 312492496, + 385896495, 454541831, 517077914, 572237251, 618849440, 655864033, + 682381207, 697662138, 701140517, 692454437, 671455926, 638192497, + 592950953, 536228301, 468743311, 391413562, 305373081, 211917193, + 112515196, 8778457, -97574737, -204722093, -310812643, -413944496, + -512244821, -603865242, -687056465, -760154912, -821653865, -870222658, + -904720479, -924233005, -928095122, -915899426, -887528715, -843128402, + -783143163, -708310042, -619630001, -518370643, -406052045, -284427622, + -155436858, -21195452, 116047980, 253948213, 390107041, 522103241, + 647551921, 764128146, 869637593, 962029890, 1039437023, 1100241539, + 1143083583, 1166892820, 1170916692, 1154740779, 1118299769, 1061881018, + 986122536, 892029173, 780944200, 654513839, 514700066, 363723079, + 204041778, 38296711, -130712875, -300087519, -466886151, -628155008, + -781010506, -922657115, -1050458160, -1161992111, -1255074688, -1327830658, + -1378698781, -1406490452, -1410403952, -1390048744, -1345443160, -1277046282, + -1185733013, -1072792031, -939913170, -789152392, -622900774, -443861303, + -254992312, -59450927, 139443874, 338270624, 533579987, 721937713, + 899993623, 1064543298, 1212581744, 1341359152, 1448429579, 1531710980, + 1589512741, 1620569648, 1624074651, 1599696439, 1547574911, 1468356915, + 1363161501, 1233562136, 1081583751, 909664374, 720608445, 517535818, + 303845742, 83153937, -140773909, -364088220, -582915643, -793431776, + -991930383, -1174877083, -1339004161, -1481332999, -1599238488, -1690519489, + -1753417293, -1786653305, -1789473370, -1761623106, -1703406621, -1615638750, + -1499680365, -1357367601, -1191013457, -1003373006, -797566749, -577067164, + -345613976, -107144347, 134245982, 374403491, 609177711, 834477933, + 1046389454, 1241198812, 1415473145, 1566135863, 1690502316, 1786338339, + 1851906157, 1885975091, 1887878900, 1857497793, 1795262548, 1702180329, + 1579789356, 1430135802, 1255748305, 1059597591, 845017078, 615693842, + 375555802, 128728549, -120541875, -367952417, -609239266, -840247912, + -1056986532, -1255711898, -1433001718, -1585806912, -1711490644, -1807893880, + -1873372869, -1906821270, -1907681888, -1875968599, -1812268342, -1717704175, + -1593954721, -1443189071, -1268052547, -1071604372, -857256046, -628745296, + -390036133, -145250986, 101370068, 345578885, 583188397, 810124441, + 1022511584, 1216750332, 1389559157, 1538037301, 1659724323, 1752624907, + 1815261574, 1846685940, 1846484281, 1814806282, 1752336430, 1660299848, + 1540418887, 1394895267, 1226368506, 1037861164, 832714737, 614557244, + 387207300, 154634175, -79136531, -310076941, -534235098, -747807622, + -947193377, -1129055065, -1290399669, -1428593288, -1541436757, -1627178290, + -1684539978, -1712767863, -1711595900, -1681285479, -1622599120, -1536772665, + -1425517966, -1290963494, -1135616184, -962344542, -774274368, -574781562, + -367391560, -155748026, 56468987, 265617545, 468136455, 660612031, + 839839063, 1002881883, 1147108605, 1270245760, 1370406427, 1446131637, + 1496385859, 1520595225, 1518643671, 1490871745, 1438059084, 1361412752, + 1262534324, 1143392079, 1006288158, 853795822, 688738010, 514100456, + 333016242, 148666198, -35733786, -217015994, -392114684, -558100465, + -712257271, -852104103, -975444447, -1080394328, -1165418355, -1229357540, + -1271415577, -1291209572, -1288731220, -1264358312, -1218861398, -1153343168, + -1069242324, -968305532, -852531316, -724153592, -585580472, -439354359, + -288129099, -134568938, 18639437, 168876066, 313606234, 450448228, + 577184171, 691821653, 792615435, 878069759, 947011876, 998555008, + 1032137571, 1047524066, 1044787870, 1024323798, 986830822, 933272555, + 864888321, 783151052, 689717699, 586439370, 475283364, 358327327, + 237682213, 115515955, -6047289, -124936621, -239160418, -346849610, + -446305192, -535984604, -614569358, -680950643, -734254056, -773856112, + -799382239, -810716482, -807980300, -791555184, -762029195, -720221489, + -667137368, -603957468, -532003241, -452726882, -367667281, -278430831, + -186650850, -93967586, -2010105, 87670605, 173583395, 254348294, + 328705558, 395535680, 453880834, 502971400, 542184178, 571117360, + 589547079, 597424930, 594903224, 582311351, 560135788, 529013782, + 489740139, 443210310, 390428155, 332480838, 270509976, 205696632, + 139248261, 72346401, 6164976, -58182531, -119639865, -177226711, + -230066695, -277391885, -318549814, -353018304, -380398777, -400445720, + -413030907, -418170496, -416006843, -406808812, -390949602, -368911794, + -341285549, -308709477, -271916169, -231679042, -188803111, -144109017, + -98433010, -52605797, -7410253, 36387441, 78074158, 117003911, + 152593644, 184341862, 211838920, 234752163, 252840296, 265961426, + 274066892, 277186709, 275448124, 269055850, 258286481, 243481885, + 225049684, 203441735, 179143029, 152678153, 124588986, 95419225, + 65714533, 36014755, 6833670, -21342804, -48066571, -72929222, + -95564180, -115671966, -133002819, -147362366, -158618696, -166699102, + -171586889, -173327948, -172026559, -167814604, -160894287, -151489663, + -139871117, -126329356, -111186960, -94771411, -77414678, -59467657, + -41266314, -23138140, -5391564, 11671033, 27790902, 42722186, + 56256573, 68223974, 78479099, 86918806, 93483066, 98132973, + 100882481, 101761537, 100840788, 98224915, 94030256, 88408558, + 81520765, 73547285, 64681638, 55113243, 45056283, 34698342, + 24242606, 13871476, 3767927, -5908113, -15006947, -23389971, + -30957637, -37604085, -43265955, -47896929, -51453182, -53942389, + -55361586, -55748217, -55150039, -53619207, -51237913, -48086596, + -44270032, -39882417, -35035095, -29835697, -24398261, -18831626, + -13233531, -7709600, -2359060, 2741076, 7508090, 11883351, + 15802228, 19226824, 22123134, 24464432, 26249325, 27466691, + 28134399, 28273722, 27908768, 27072999, 25812506, 24173126, + 22210833, 19974234, 17521274, 14903269, 12184305, 9415050, + 6651964, 3939391, 1325486, -1151329, -3451045, -5548765, + -7411580, -9028634, -10385842, -11469809, -12283476, -12825585, + -13106189, -13133337, -12930778, -12512723, -11898955, -11114197, + -10181485, -9136535, -7996551, -6790865, -5546526, -4288121, + -3042708, -1831404, -666060, 426453, 1433672, 2346296, + 3151055, 3844528, 4418334, 4867341, 5201684, 5417090, + 5517138, 5510524, 5407103, 5212655, 4939564, 4596810, + 4201640, 3756418, 3276626, 2775443, 2263223, 1749530, + 1245083, 755616, 295067, -137266, -531108, -885778, + -1193909, -1455972, -1667698, -1836140, -1951262, -2025669, + -2058551, -2043942, -1998955, -1921219, -1810497, -1674966, + -1525317, -1355771, -1176953, -994191, -810831, -625797, + -442618, -273791, -112000, 39406, 171237, 287439, + 392918, 476625, 546027, 599266, 631420, 652492, + 661672, 651810, 635639, 603428, 568623, 520399, + 472127, 414285, 362057, 300075, 247514, 186936, + 134315, 82093, 36560, -9730, -45362, -81307, + -109537, -129710, -147427, -160759, -168481, -172912, + -172555, -167998, -163837, -153003, -142682, -133355, + -120121, -102416, -88146, -72605, -59067, -43018, + -30225, -20737, -6450, 2671, 9514, 15270, + 21544, 27571, 31312, 30051, 32554, 35022, + 29866, 33834, 34496, 30956, 25856, 24739, + 21090, 18605, 13885, 11395, 12074, 8208, + 6113, 1491, 2436, -1194, 755, -1141, + -1742, -2584, -3779, -2934, -5882, -4082, + -4822, -4378, -850, -2076, -212, 341, + -1712, -2779, -3499, 1149, -151, 92, + -3132, 333, 1147, -3681, -2353, 1598, + 1786, -536, -1080, -780, 238, -2557, + -1215, -478, 1247, 793, +}; + +static const int32_t ifft_ref_imag_1024_q31[1024] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +}; diff --git a/test/cmocka/src/math/fft/ref_ifft_multi_1536_32.h b/test/cmocka/src/math/fft/ref_ifft_multi_1536_32.h new file mode 100644 index 000000000000..1a1b0fc65f4a --- /dev/null +++ b/test/cmocka/src/math/fft/ref_ifft_multi_1536_32.h @@ -0,0 +1,1044 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 20-Nov-2025 16:11:52 with script ref_fft_multi.m v1.9-rc1-6882-ge0b90b605-dirty */ + +#define REF_SOFM_IFFT_MULTI_1536_NUM_TESTS 1 + +static const int32_t ifft_in_real_1536_q31[1536] = { + 99, -4, 22, -33, 37, 83, + 29, 51, 3, 13, -14, -14, + -20, -21, 39, 31, -29, -6, + -26, -52, -4, -9, -9, -9, + 29, -25, -825, 92195, -1546020, 10045581, + -33641397, 65657100, -78882664, 59164046, -27128469, 7128081, + -930292, 42792, -213, 1, 4, 7, + 58, -24, 27, -19, -58, -34, + -1, -41, -4, -16, -22, -20, + -1, 35, 2, 8, 21, -59, + 28, -17, -35, -32, 56, 7, + -45, 10, 19, 26, 13, 7, + -17, 21, -20, 18, 19, -15, + -57, -18, 3, 33, 9, 11, + 9, -17, -5, 34, 23, 55, + -3, -10, 20, -2, 23, -8, + -6, -28, -21, -10, -15, 5, + 4, -21, -58, 16, 24, 45, + -15, -42, 10, -10, -46, -23, + 7, 13, 2, 17, -12, -35, + -31, 17, 30, -5, 1, 11, + 18, -5, 41, -13, -1, 14, + -9, -10, -16, -41, 12, 8, + 21, 13, 91, -53, -38, 19, + 11, 32, 36, 29, -19, 16, + -32, 22, 47, -35, -17, 6, + -1, -2, -34, 27, -12, -7, + -18, 16, -11, 28, 8, 31, + -72, 33, -32, 2, 27, -35, + -26, 2, -35, 9, 33, 1, + -34, -29, -35, 9, 12, -22, + -8, 0, 11, 21, -14, 3, + 41, 11, 27, 8, -14, 7, + -2, -18, 39, 26, -15, 7, + -6, 15, -17, -4, 19, 2, + -33, -11, -27, 0, 37, 45, + -8, 8, 38, 43, -16, -51, + -17, -35, -19, 32, 50, 9, + 2, -23, 36, 8, 34, 41, + -22, -40, 7, 9, -4, 23, + -35, 2, 0, 49, 66, 4, + -9, 18, 2, -25, -30, -21, + 51, -65, -15, -38, 72, 16, + -7, 27, -14, 2, 2, 18, + -45, -18, -17, -10, 17, -63, + -6, 1, -58, -16, -26, -8, + 9, 44, -9, 6, -19, 15, + -48, 28, -12, 51, -17, 42, + 6, -3, 12, -31, 19, -22, + 34, -9, 20, 38, -9, 0, + 40, -14, 31, 39, 74, -19, + -38, 19, 46, -2, -2, 27, + -24, -5, -34, 15, 8, 52, + 36, 53, 20, 31, -6, -4, + 21, -10, -6, 19, 7, -11, + -49, 32, -8, -16, 29, 9, + -6, -3, -2, 20, -7, -13, + 10, -16, -12, -81, -29, -34, + -42, 36, 4, 76, -12, -24, + 40, 39, 8, 9, 33, -8, + 34, 39, 16, 18, -30, -16, + 13, -22, 25, 21, 8, 28, + -17, -18, 2, -42, 40, -44, + 20, -53, -35, 30, 2, 25, + -58, -15, -32, 43, 25, 8, + 7, 6, -34, 27, 21, 56, + -65, 52, 27, -11, 28, 43, + -14, -11, 40, -29, 71, -69, + 28, 0, -11, -57, -33, 17, + 28, -21, -29, 0, -40, 1, + -28, -44, 31, 6, -16, -38, + 1, -41, -17, 46, -10, -21, + 30, 46, 57, -30, 37, -3, + -22, -55, -15, 20, -8, -4, + -29, 13, -11, 11, 3, 5, + -2, 51, -10, -29, -28, -5, + 33, -12, 5, -20, 3, -13, + -9, 7, -25, -38, 33, -13, + -46, -18, -7, -99, -32, -56, + 28, -1, 23, -17, -61, -36, + -14, -20, 17, -14, -11, -19, + 45, -10, 12, -12, -15, 18, + 32, 11, 6, -47, 0, -19, + 49, -23, 40, -36, 35, -19, + 9, -23, -7, -14, -45, 6, + 71, -8, 8, -25, -1, 14, + 39, 39, 61, -3, -42, 20, + 10, 27, -14, 49, -36, 6, + 21, 19, 15, 5, -12, -9, + 15, 6, -45, 19, -43, -4, + 9, 37, 37, 5, -29, 34, + -1, -24, -8, -18, -8, 39, + -19, -1, -12, 54, -36, -14, + 14, -8, 23, -59, -54, -13, + 39, 1, -12, -51, 18, 15, + -14, 5, 28, -15, -30, -5, + 7, 35, 21, -25, -40, -13, + -58, 36, 42, -16, 14, -28, + -50, -17, -10, -20, 2, 7, + -49, 38, -19, -2, -16, 8, + 9, 16, -12, 20, 1, 34, + 38, -9, 43, 31, 30, 0, + -55, -2, 69, 14, -23, 39, + -31, -20, 26, 46, 22, -24, + -1, 29, -24, 24, 6, 34, + -13, 21, 25, -34, 7, 9, + -47, -3, 46, -11, 27, -23, + -13, -21, -24, 5, 9, -49, + -7, 38, -13, 46, 2, 32, + 18, 38, 17, -47, 5, 4, + 8, 5, 34, -11, 26, 14, + 1, -7, 3, 45, -31, 2, + -13, -43, 58, 11, 14, -3, + -57, -28, -23, -5, 28, 42, + -1, 2, -1, 2, 25, -49, + -57, 18, -57, 18, 50, -32, + 26, -3, -23, -6, -60, -28, + 24, -9, 3, 28, 21, -46, + -22, -57, -21, 4, -63, -39, + -46, -51, 2, 20, -35, -47, + -14, 64, -75, 1, -8, 12, + 34, 13, 48, -10, 45, 23, + 12, 12, -6, -61, -45, 3, + 3, 45, -39, 12, 10, -49, + -14, 47, 7, -8, 31, -36, + -45, 9, 5, -2, -2, -8, + 24, -35, 6, -15, -8, 67, + 28, -5, -14, -9, -8, -24, + 131, -24, -8, -9, -14, -5, + 28, 67, -8, -15, 6, -35, + 24, -8, -2, -2, 5, 9, + -45, -36, 31, -8, 7, 47, + -14, -49, 10, 12, -39, 45, + 3, 3, -45, -61, -6, 12, + 12, 23, 45, -10, 48, 13, + 34, 12, -8, 1, -75, 64, + -14, -47, -35, 20, 2, -51, + -46, -39, -63, 4, -21, -57, + -22, -46, 21, 28, 3, -9, + 24, -28, -60, -6, -23, -3, + 26, -32, 50, 18, -57, 18, + -57, -49, 25, 2, -1, 2, + -1, 42, 28, -5, -23, -28, + -57, -3, 14, 11, 58, -43, + -13, 2, -31, 45, 3, -7, + 1, 14, 26, -11, 34, 5, + 8, 4, 5, -47, 17, 38, + 18, 32, 2, 46, -13, 38, + -7, -49, 9, 5, -24, -21, + -13, -23, 27, -11, 46, -3, + -47, 9, 7, -34, 25, 21, + -13, 34, 6, 24, -24, 29, + -1, -24, 22, 46, 26, -20, + -31, 39, -23, 14, 69, -2, + -55, 0, 30, 31, 43, -9, + 38, 34, 1, 20, -12, 16, + 9, 8, -16, -2, -19, 38, + -49, 7, 2, -20, -10, -17, + -50, -28, 14, -16, 42, 36, + -58, -13, -40, -25, 21, 35, + 7, -5, -30, -15, 28, 5, + -14, 15, 18, -51, -12, 1, + 39, -13, -54, -59, 23, -8, + 14, -14, -36, 54, -12, -1, + -19, 39, -8, -18, -8, -24, + -1, 34, -29, 5, 37, 37, + 9, -4, -43, 19, -45, 6, + 15, -9, -12, 5, 15, 19, + 21, 6, -36, 49, -14, 27, + 10, 20, -42, -3, 61, 39, + 39, 14, -1, -25, 8, -8, + 71, 6, -45, -14, -7, -23, + 9, -19, 35, -36, 40, -23, + 49, -19, 0, -47, 6, 11, + 32, 18, -15, -12, 12, -10, + 45, -19, -11, -14, 17, -20, + -14, -36, -61, -17, 23, -1, + 28, -56, -32, -99, -7, -18, + -46, -13, 33, -38, -25, 7, + -9, -13, 3, -20, 5, -12, + 33, -5, -28, -29, -10, 51, + -2, 5, 3, 11, -11, 13, + -29, -4, -8, 20, -15, -55, + -22, -3, 37, -30, 57, 46, + 30, -21, -10, 46, -17, -41, + 1, -38, -16, 6, 31, -44, + -28, 1, -40, 0, -29, -21, + 28, 17, -33, -57, -11, 0, + 28, -69, 71, -29, 40, -11, + -14, 43, 28, -11, 27, 52, + -65, 56, 21, 27, -34, 6, + 7, 8, 25, 43, -32, -15, + -58, 25, 2, 30, -35, -53, + 20, -44, 40, -42, 2, -18, + -17, 28, 8, 21, 25, -22, + 13, -16, -30, 18, 16, 39, + 34, -8, 33, 9, 8, 39, + 40, -24, -12, 76, 4, 36, + -42, -34, -29, -81, -12, -16, + 10, -13, -7, 20, -2, -3, + -6, 9, 29, -16, -8, 32, + -49, -11, 7, 19, -6, -10, + 21, -4, -6, 31, 20, 53, + 36, 52, 8, 15, -34, -5, + -24, 27, -2, -2, 46, 19, + -38, -19, 74, 39, 31, -14, + 40, 0, -9, 38, 20, -9, + 34, -22, 19, -31, 12, -3, + 6, 42, -17, 51, -12, 28, + -48, 15, -19, 6, -9, 44, + 9, -8, -26, -16, -58, 1, + -6, -63, 17, -10, -17, -18, + -45, 18, 2, 2, -14, 27, + -7, 16, 72, -38, -15, -65, + 51, -21, -30, -25, 2, 18, + -9, 4, 66, 49, 0, 2, + -35, 23, -4, 9, 7, -40, + -22, 41, 34, 8, 36, -23, + 2, 9, 50, 32, -19, -35, + -17, -51, -16, 43, 38, 8, + -8, 45, 37, 0, -27, -11, + -33, 2, 19, -4, -17, 15, + -6, 7, -15, 26, 39, -18, + -2, 7, -14, 8, 27, 11, + 41, 3, -14, 21, 11, 0, + -8, -22, 12, 9, -35, -29, + -34, 1, 33, 9, -35, 2, + -26, -35, 27, 2, -32, 33, + -72, 31, 8, 28, -11, 16, + -18, -7, -12, 27, -34, -2, + -1, 6, -17, -35, 47, 22, + -32, 16, -19, 29, 36, 32, + 11, 19, -38, -53, 91, 13, + 21, 8, 12, -41, -16, -10, + -9, 14, -1, -13, 41, -5, + 18, 11, 1, -5, 30, 17, + -31, -35, -12, 17, 2, 13, + 7, -23, -46, -10, 10, -42, + -15, 45, 24, 16, -58, -21, + 4, 5, -15, -10, -21, -28, + -6, -8, 23, -2, 20, -10, + -3, 55, 23, 34, -5, -17, + 9, 11, 9, 33, 3, -18, + -57, -15, 19, 18, -20, 21, + -17, 7, 13, 26, 19, 10, + -45, 7, 56, -32, -35, -17, + 28, -59, 21, 8, 2, 35, + -1, -20, -22, -16, -4, -41, + -1, -34, -58, -19, 27, -24, + 58, 7, 4, 1, -213, 42792, + -930292, 7128081, -27128469, 59164046, -78882664, 65657100, + -33641397, 10045581, -1546020, 92195, -825, -25, + 29, -9, -9, -9, -4, -52, + -26, -6, -29, 31, 39, -21, + -20, -14, -14, 13, 3, 51, + 29, 83, 37, -33, 22, -4, +}; + +static const int32_t ifft_in_imag_1536_q31[1536] = { + 0, 0, 18, -9, 28, 19, + 4, -28, -9, -34, -6, -1, + 0, 31, 9, -9, -65, -34, + 6, 1, -49, -34, -2, 18, + -20, -61, -2523, 286383, -4833354, 31628685, + -106676469, 209692391, -253750715, 191701771, -88543013, 23436058, + -3081460, 142801, -570, -45, -20, -15, + 0, -4, -25, 28, -24, -66, + -10, 11, 37, -2, 10, 5, + 64, -2, 10, -9, 25, 32, + 34, -76, -24, 40, 11, -61, + -57, 0, -18, -22, -30, 32, + -3, -26, 9, 28, 6, -25, + -29, 18, -31, -39, -59, -23, + -14, -71, 33, 9, -12, -61, + 44, -9, 8, 38, 65, 48, + 17, -22, 16, 15, 8, -12, + 36, 16, -55, -24, 13, -22, + -38, -58, 34, -28, 52, -24, + -12, 38, -6, -16, 5, 23, + -11, 21, -21, 11, 52, 0, + -1, 29, -39, 20, 40, 47, + 34, -16, 34, 23, -19, -39, + 14, -28, -10, 5, 23, 22, + 21, 8, -10, 18, -20, 33, + -16, 19, 22, -45, -13, -21, + 6, 23, -19, -18, -15, 15, + -5, -13, 26, -19, -33, 2, + 46, 7, -1, -10, 0, 50, + -4, -34, 23, -3, -36, -76, + -58, 28, 18, 16, 0, 7, + 6, 52, 9, 10, -14, 37, + 43, 28, -21, 37, 16, 4, + -28, -7, -64, -2, 3, -35, + -52, -25, -7, -30, -3, 46, + -24, 27, 64, 17, 2, -23, + 15, -6, -26, 33, 49, 7, + 9, -39, -38, 43, -33, -37, + 58, 16, 48, 23, 34, 24, + -15, -15, 21, 17, -3, -19, + 2, -15, 37, -9, 21, -18, + 26, 89, 39, 29, 1, -17, + 38, 25, -48, -27, -16, 21, + 20, -36, 16, -3, 16, -23, + -8, -34, 29, -62, 47, -39, + -2, 8, -23, -18, -20, 24, + -4, 29, 3, 14, -15, -13, + -36, 21, -15, -29, 15, -13, + -19, 21, -2, 53, -28, 11, + -12, -70, 48, -1, -11, -62, + -18, 7, -14, -2, 22, -40, + 6, -35, 35, 8, 5, -25, + -24, 69, -21, 26, 12, 53, + 21, 17, -3, -42, 39, -7, + 64, 23, -37, 30, -35, 37, + 23, 29, 20, 72, 0, 29, + 49, 38, -76, -39, -63, 33, + -3, -5, -8, 21, -15, -36, + 25, -34, -7, -1, 0, -74, + 15, 5, -9, 59, -12, 3, + -22, 48, -11, -36, -57, 4, + -5, 45, -38, 61, -17, 9, + 67, 11, 7, 22, -10, 13, + -10, 10, 11, -20, -9, 46, + -26, 12, 12, -54, 36, -8, + 7, -27, 24, 2, -26, 9, + -34, -15, 35, 59, 40, 18, + 19, 5, 20, 11, -41, -4, + -54, 50, -30, 19, -28, 3, + 0, 3, -12, -37, -75, 6, + -25, -9, -5, 33, 32, -40, + 38, 33, 21, -11, -24, -15, + 33, -16, -13, 30, -5, 31, + 44, 26, -33, -10, 10, 27, + -14, -2, -76, -6, -12, -29, + -20, -7, 1, 28, 13, -24, + 11, 64, -29, -10, -1, -10, + -30, -61, -10, -8, 23, 16, + -28, 68, -37, -49, -7, 73, + -39, 1, 53, 54, 44, 10, + 8, 14, -19, -6, -10, -6, + 42, -2, -15, 27, -6, -41, + 7, -27, 3, -43, -15, -31, + 15, 2, -17, 18, -37, -1, + -1, 5, 11, 11, -38, 33, + 17, -24, -53, 0, 30, -17, + 39, -20, -9, -6, 26, -18, + -17, 6, 10, -3, -75, -12, + -7, -27, 13, -25, -52, 41, + -19, -1, -78, 7, 23, -15, + 24, 16, -36, -15, -40, 8, + 20, 31, 8, 8, 48, -40, + 4, -29, -2, -1, -14, -56, + -37, -26, -41, 21, -17, -38, + -34, -1, 24, 33, -31, -14, + 8, -23, 6, -51, 28, 2, + 6, 4, 38, 4, -1, -39, + 17, -24, 0, 21, -32, -4, + -22, 6, 23, -67, 11, 31, + 36, 3, 27, 16, 24, -9, + 10, -9, -53, -45, -42, 17, + -24, -1, 15, -1, -8, -11, + -4, -59, 30, -47, -30, -24, + 27, -24, 62, 7, -60, 79, + -6, 2, 47, -20, -5, 41, + -8, 4, 43, -14, 32, -8, + -2, 11, -8, 12, -33, 5, + 24, -17, 8, -44, 37, 28, + -7, 24, -5, 42, -6, -42, + -8, 49, -30, 10, 61, -3, + 23, 48, 25, 45, -43, 4, + -7, -26, -23, -13, 18, -13, + -42, 52, 39, -60, -21, 23, + -71, -35, 9, 3, 1, -8, + 19, 0, -9, 8, -39, 1, + 8, 35, 2, 67, 1, -32, + -11, -16, 32, -16, -78, 14, + 54, -32, -16, 16, 2, -10, + 31, 1, 26, -20, -20, -25, + 1, -13, -16, -64, 0, 45, + -6, -29, 21, 55, 27, 55, + -10, -34, -22, 57, -1, 7, + 2, -6, 14, -9, -28, 13, + 1, 7, 7, 11, -45, -35, + -24, -46, 32, -27, 76, -27, + 4, -14, -7, -37, 24, -8, + -2, 58, 26, 34, -24, 23, + 29, 30, 28, -18, -5, 17, + 0, -17, 5, 18, -28, -30, + -29, -23, 24, -34, -26, -58, + 2, 8, -24, 37, 7, 14, + -4, 27, -76, 27, -32, 46, + 24, 35, 45, -11, -7, -7, + -1, -13, 28, 9, -14, 6, + -2, -7, 1, -57, 22, 34, + 10, -55, -27, -55, -21, 29, + 6, -45, 0, 64, 16, 13, + -1, 25, 20, 20, -26, -1, + -31, 10, -2, -16, 16, 32, + -54, -14, 78, 16, -32, 16, + 11, 32, -1, -67, -2, -35, + -8, -1, 39, -8, 9, 0, + -19, 8, -1, -3, -9, 35, + 71, -23, 21, 60, -39, -52, + 42, 13, -18, 13, 23, 26, + 7, -4, 43, -45, -25, -48, + -23, 3, -61, -10, 30, -49, + 8, 42, 6, -42, 5, -24, + 7, -28, -37, 44, -8, 17, + -24, -5, 33, -12, 8, -11, + 2, 8, -32, 14, -43, -4, + 8, -41, 5, 20, -47, -2, + 6, -79, 60, -7, -62, 24, + -27, 24, 30, 47, -30, 59, + 4, 11, 8, 1, -15, 1, + 24, -17, 42, 45, 53, 9, + -10, 9, -24, -16, -27, -3, + -36, -31, -11, 67, -23, -6, + 22, 4, 32, -21, 0, 24, + -17, 39, 1, -4, -38, -4, + -6, -2, -28, 51, -6, 23, + -8, 14, 31, -33, -24, 1, + 34, 38, 17, -21, 41, 26, + 37, 56, 14, 1, 2, 29, + -4, 40, -48, -8, -8, -31, + -20, -8, 40, 15, 36, -16, + -24, 15, -23, -7, 78, 1, + 19, -41, 52, 25, -13, 27, + 7, 12, 75, 3, -10, -6, + 17, 18, -26, 6, 9, 20, + -39, 17, -30, 0, 53, 24, + -17, -33, 38, -11, -11, -5, + 1, 1, 37, -18, 17, -2, + -15, 31, 15, 43, -3, 27, + -7, 41, 6, -27, 15, 2, + -42, 6, 10, 6, 19, -14, + -8, -10, -44, -54, -53, -1, + 39, -73, 7, 49, 37, -68, + 28, -16, -23, 8, 10, 61, + 30, 10, 1, 10, 29, -64, + -11, 24, -13, -28, -1, 7, + 20, 29, 12, 6, 76, 2, + 14, -27, -10, 10, 33, -26, + -44, -31, 5, -30, 13, 16, + -33, 15, 24, 11, -21, -33, + -38, 40, -32, -33, 5, 9, + 25, -6, 75, 37, 12, -3, + 0, -3, 28, -19, 30, -50, + 54, 4, 41, -11, -20, -5, + -19, -18, -40, -59, -35, 15, + 34, -9, 26, -2, -24, 27, + -7, 8, -36, 54, -12, -12, + 26, -46, 9, 20, -11, -10, + 10, -13, 10, -22, -7, -11, + -67, -9, 17, -61, 38, -45, + 5, -4, 57, 36, 11, -48, + 22, -3, 12, -59, 9, -5, + -15, 74, 0, 1, 7, 34, + -25, 36, 15, -21, 8, 5, + 3, -33, 63, 39, 76, -38, + -49, -29, 0, -72, -20, -29, + -23, -37, 35, -30, 37, -23, + -64, 7, -39, 42, 3, -17, + -21, -53, -12, -26, 21, -69, + 24, 25, -5, -8, -35, 35, + -6, 40, -22, 2, 14, -7, + 18, 62, 11, 1, -48, 70, + 12, -11, 28, -53, 2, -21, + 19, 13, -15, 29, 15, -21, + 36, 13, 15, -14, -3, -29, + 4, -24, 20, 18, 23, -8, + 2, 39, -47, 62, -29, 34, + 8, 23, -16, 3, -16, 36, + -20, -21, 16, 27, 48, -25, + -38, 17, -1, -29, -39, -89, + -26, 18, -21, 9, -37, 15, + -2, 19, 3, -17, -21, 15, + 15, -24, -34, -23, -48, -16, + -58, 37, 33, -43, 38, 39, + -9, -7, -49, -33, 26, 6, + -15, 23, -2, -17, -64, -27, + 24, -46, 3, 30, 7, 25, + 52, 35, -3, 2, 64, 7, + 28, -4, -16, -37, 21, -28, + -43, -37, 14, -10, -9, -52, + -6, -7, 0, -16, -18, -28, + 58, 76, 36, 3, -23, 34, + 4, -50, 0, 10, 1, -7, + -46, -2, 33, 19, -26, 13, + 5, -15, 15, 18, 19, -23, + -6, 21, 13, 45, -22, -19, + 16, -33, 20, -18, 10, -8, + -21, -22, -23, -5, 10, 28, + -14, 39, 19, -23, -34, 16, + -34, -47, -40, -20, 39, -29, + 1, 0, -52, -11, 21, -21, + 11, -23, -5, 16, 6, -38, + 12, 24, -52, 28, -34, 58, + 38, 22, -13, 24, 55, -16, + -36, 12, -8, -15, -16, 22, + -17, -48, -65, -38, -8, 9, + -44, 61, 12, -9, -33, 71, + 14, 23, 59, 39, 31, -18, + 29, 25, -6, -28, -9, 26, + 3, -32, 30, 22, 18, 0, + 57, 61, -11, -40, 24, 76, + -34, -32, -25, 9, -10, 2, + -64, -5, -10, 2, -37, -11, + 10, 66, 24, -28, 25, 4, + 0, 15, 20, 45, 570, -142801, + 3081460, -23436058, 88543013, -191701771, 253750715, -209692391, + 106676469, -31628685, 4833354, -286383, 2523, 61, + 20, -18, 2, 34, 49, -1, + -6, 34, 65, 9, -9, -31, + 0, 1, 6, 34, 9, 28, + -4, -19, -28, 9, -18, 0, +}; + +static const int32_t ifft_ref_real_1536_q31[1536] = { + -208, 1028, -2146, -280, 776, 1608, + 1081, 637, 842, 2274, 792, -115, + 4394, -1464, 1851, 967, -191, -578, + 3180, 1263, 2142, 3402, 586, 3266, + 1202, 1888, -1120, -375, 151, -3604, + -122, 1991, -236, -3107, -2506, -2626, + -4282, -4639, -172, -4654, -4533, -2999, + -15, -5065, -155, -4063, 1261, 721, + 3129, -671, 2662, 2723, 1061, 8426, + 7675, 7229, 12234, 10576, 10304, 13036, + 14434, 17152, 14472, 17043, 18274, 13826, + 13241, 11632, 10311, 8876, 7535, 5023, + 3673, -2123, -7309, -14532, -15667, -19573, + -23310, -31847, -36355, -41917, -44643, -49330, + -54444, -56048, -54924, -55007, -57774, -56197, + -52275, -46488, -40590, -33525, -26331, -14534, + -5315, 9452, 18671, 36735, 52659, 65412, + 79725, 95877, 109849, 123652, 137540, 145200, + 153930, 156815, 164349, 165740, 158411, 156119, + 147951, 133110, 115471, 91519, 70424, 42272, + 11340, -21575, -56827, -94279, -134881, -172055, + -213360, -250037, -284627, -319512, -347581, -372634, + -392288, -406000, -415059, -413205, -406127, -386463, + -366070, -328695, -289256, -232414, -177543, -111152, + -32078, 46657, 132162, 217378, 312255, 401003, + 492486, 578105, 657728, 735235, 800967, 858345, + 901514, 933447, 945826, 945383, 923194, 881957, + 823666, 744892, 650339, 532505, 401713, 249385, + 86826, -91622, -272974, -466517, -662726, -858114, + -1051320, -1236046, -1411686, -1569633, -1705463, -1822427, + -1914305, -1971737, -1997485, -1988663, -1938185, -1857534, + -1732525, -1564796, -1360688, -1122122, -845645, -539384, + -203558, 157006, 530053, 917864, 1312502, 1707075, + 2090197, 2459433, 2801281, 3110743, 3383779, 3607114, + 3778184, 3890401, 3933792, 3914304, 3817403, 3643098, + 3399418, 3073155, 2678505, 2209822, 1678372, 1084276, + 442509, -245337, -960479, -1702598, -2445594, -3185798, + -3906204, -4592220, -5233953, -5810889, -6310512, -6724566, + -7038143, -7235970, -7314842, -7265505, -7076677, -6754784, + -6296018, -5699434, -4969654, -4108742, -3136922, -2059649, + -890244, 353243, 1648727, 2977030, 4314244, 5640043, + 6926146, 8145887, 9277320, 10297821, 11185992, 11903031, + 12448852, 12792884, 12916543, 12821770, 12484853, 11912496, + 11102716, 10052315, 8769831, 7273682, 5584355, 3711104, + 1693775, -447201, -2677090, -4958879, -7247563, -9511744, + -11703465, -13782705, -15702704, -17424542, -18916260, -20127258, + -21032184, -21595619, -21803149, -21624235, -21057140, -20087223, + -18716527, -16953659, -14810811, -12321141, -9503518, -6400778, + -3055652, 480782, 4156075, 7903631, 11669689, 15374606, + 18958814, 22346114, 25474151, 28274296, 30683080, 32639661, + 34096110, 35002560, 35321394, 35025586, 34095720, 32521541, + 30304896, 27471731, 24037163, 20047123, 15547141, 10594808, + 5269683, -351499, -6179407, -12112749, -18058849, -23905328, + -29545744, -34872979, -39781852, -44166629, -47923957, -50978111, + -53236721, -54638099, -55119176, -54643963, -53185424, -50737369, + -47298744, -42907294, -37598036, -31434040, -24498741, -16887429, + -8713123, -94741, 8820257, 17893205, 26963034, 35871054, + 44447851, 52538069, 59975530, 66609377, 72294399, 76892212, + 80292014, 82392141, 83110260, 82389572, 80193927, 76508526, + 71360649, 64780127, 56849853, 47655824, 37328004, 26008147, + 13867342, 1085333, -12120465, -25536048, -38934836, -52068253, + -64705008, -76603397, -87527796, -97258179, -105585075, -112314562, + -117280713, -120338580, -121384153, -120330545, -117127521, -111779505, + -104304143, -94771825, -83291461, -70009055, -55094819, -38774930, + -21294148, -2914662, 16054170, 35299102, 54488431, 73287116, + 91347784, 108331536, 123909356, 137766473, 149616023, 159180965, + 166233868, 170575046, 172064616, 170576428, 166068025, 158531167, + 148009147, 134610545, 118483473, 99844653, 78947786, 56095457, + 31645852, 5973079, -20500963, -47330323, -74052822, -100200161, + -125296303, -148871677, -170474655, -189679049, -206074331, -219306189, + -229059310, -235068628, -237134168, -235123748, -228956546, -218641946, + -204252159, -185934134, -163910290, -138473312, -109988245, -78863628, + -45594336, -10693457, 25250196, 61651254, 97872112, 133279643, + 167232663, 199102751, 228284556, 254194790, 276309629, 294146180, + 307294012, 315412570, 318233653, 315585456, 307396754, 293662441, + 274507454, 250130988, 220841590, 187039402, 149213225, 107920491, + 63808737, 17587427, -29987869, -78118952, -125968080, -172711586, + -217494176, -259499772, -297926602, -332032449, -361127238, -384589906, + -401888592, -412591548, -416368239, -413003605, -402401970, -384597510, + -359738491, -328121730, -290141454, -246339982, -197346613, -143913090, + -86867154, -27145840, 34282217, 96378194, 158069896, 218280353, + 275928983, 329964614, 379369503, 423194148, 460570682, 490705819, + 512949051, 526745521, 531697773, 527540589, 514173891, 491656679, + 460188620, 420159841, 372096451, 316682269, 254737793, 187222598, + 115194822, 39831891, -37626003, -115868772, -193555103, -269324053, + -341819985, -409734768, -471798949, -526832218, -573747752, -611592070, + -639544497, -656948721, -663307112, -658324851, -641879757, -614068853, + -575169661, -525665973, -466233677, -397737653, -321211140, -237834773, + -148953290, -56002184, 39464289, 135838415, 231470672, 324683029, + 413824173, 497281235, 573519966, 641099500, 698711660, 745193260, + 779570707, 801047198, 809057956, 803239996, 783490048, 749925326, + 702910625, 643062665, 571208539, 488421585, 395954303, 295274829, + 187992943, 75867686, -39234688, -155364893, -270526625, -382721173, + -489954333, -590312450, -681948840, -763162502, -832395730, -888280790, + -929662923, -955628164, -965508614, -958905396, -935714163, -896097977, + -840525812, -769729565, -684734615, -586818083, -477494634, -358505054, + -231767635, -99384991, 36447908, 173418741, 309179351, 441372486, + 567665080, 685809850, 793657618, 889220299, 970691248, 1036487321, + 1085290926, 1116036982, 1127985532, 1120690429, 1094052234, 1048304735, + 983994827, 902020022, 803586229, 690197392, 563634712, 425927856, + 279326828, 126252690, -30727602, -188948106, -345698579, -498253663, + -643943557, -780184469, -904517779, -1014672187, -1108602474, -1184506618, + -1240893623, -1276580740, -1290736320, -1282893759, -1252957322, -1201218320, + -1128344799, -1035378921, -923712736, -795091118, -651549487, -495428782, + -329278199, -155867023, 21884624, 200964166, 378296390, 550817084, + 715509842, 869465952, 1009935821, 1134382373, 1240516904, 1326342221, + 1390206083, 1430813800, 1447256973, 1439042403, 1406102963, 1348789380, + 1267880510, 1164559892, 1040430447, 897443767, 737906646, 564425518, + 379875346, 187325754, -9959043, -208628068, -405280556, -596522969, + -779024043, -949576504, -1105159555, -1242986235, -1360557688, -1455707771, + -1526630125, -1571931512, -1590656579, -1582288902, -1546785379, -1484564418, + -1396514081, -1283966465, -1148699380, -992870834, -819030265, -630046527, + -429061869, -219452221, -4767624, 211344570, 425174230, 633047815, + 831345812, 1016614742, 1185594779, 1335289737, 1463018092, 1566456589, + 1643704895, 1693273650, 1714172081, 1705882228, 1668384051, 1602168866, + 1508224931, 1388011642, 1243467936, 1076940537, 891184470, 689290793, + 474641988, 250858324, 21737861, -208816087, -436846641, -658446865, + -869777852, -1067170436, -1247183257, -1406646888, -1542751972, -1653062659, + -1735582597, -1788791763, -1811654306, -1803668814, -1764855539, -1695759994, + -1597456049, -1471530418, -1320042339, -1145497633, -950809867, -739249865, + -514385056, -280041257, -40181383, 201080379, 439624918, 671355509, + 892286064, 1098594389, 1286706868, 1453352441, 1595628823, 1711035463, + 1797521019, 1853538365, 1878059813, 1870600384, 1831206309, 1760492154, + 1659602184, 1530203408, 1374457364, 1194986427, 994818107, 777345237, + 546255918, 305492794, 59165875, -188527458, -433341422, -671079309, + -897668893, -1109214643, -1302074023, -1472937031, -1618848646, -1737290618, + -1826217726, -1884079590, -1909863238, -1903105212, -1863905400, -1792913351, + -1691333260, -1560895247, -1403806747, -1222758514, -1020847804, -801517798, + -568519036, -325840915, -77637046, 171850151, 418353964, 657652106, + 885660159, 1098481666, 1292480155, 1464355516, 1611177051, 1730444441, + 1820150539, 1878772825, 1905343502, 1899434946, 1861181237, 1791267354, + 1690932265, 1561919190, 1406470627, 1227285157, 1027454790, 810422575, + 579933199, 339937735, 94560706, -151998519, -395519648, -631847447, + -856952704, -1067020943, -1258483185, -1428108906, -1573046811, -1690880320, + -1779653406, -1837919413, -1864754559, -1859783641, -1823171173, -1755625833, + -1658386915, -1533198396, -1382281189, -1208279192, -1014238945, -803541923, + -579834919, -346970773, -108971582, 130083337, 366114057, 595094166, + 813132897, 1016558501, 1201938275, 1366176039, 1506542457, 1620740077, + 1706919479, 1763717224, 1790275640, 1786276393, 1751908357, 1687891249, + 1595438012, 1476262486, 1332509163, 1166745659, 981900242, 781222554, + 568211774, 346560641, 120100574, -107289782, -331713541, -549356216, + -756540884, -949779137, -1125851227, -1281843132, -1415192803, -1523754996, + -1605802264, -1660092492, -1685848824, -1682801752, -1651163067, -1591637338, + -1505408041, -1394110256, -1259790097, -1104882900, -932150731, -744661919, + -545709413, -338757446, -127382761, 84765707, 294067250, 496976412, + 690070929, 870113211, 1034134977, 1179439235, 1303678232, 1404885195, + 1481490379, 1532369848, 1556838111, 1554667668, 1526100288, 1471814589, + 1392935146, 1290979951, 1167883446, 1025897621, 867598300, 695803013, + 513556483, 324055689, 130579822, -63530664, -254960711, -440468393, + -616936322, -781437175, -931258704, -1063977475, -1177469159, -1269973586, + -1340088669, -1386818867, -1409579450, -1408193505, -1382898111, -1334344314, + -1263572251, -1171997342, -1061377097, -933764183, -791500540, -637158044, + -473474842, -303339128, -129708618, 44418353, 216071053, 382335233, + 540448165, 687781229, 821938681, 940758749, 1042384718, 1125252993, + 1188147956, 1230202439, 1250926083, 1250188874, 1228226406, 1185647049, + 1123399468, 1042758074, 945299018, 832869534, 707550079, 571621816, + 427526974, 277809022, 125084990, -28007635, -178856734, -324907138, + -463734021, -593052973, -710764745, -815013568, -904171247, -976904534, + -1032170687, -1069237209, -1087700273, -1087470343, -1068778111, -1032176645, + -978516872, -908919323, -824774811, -727708909, -619535342, -502245966, + -377946914, -248858753, -117245647, 14624738, 144489450, 270173067, + 389580624, 500766017, 601940765, 691518395, 768126426, 830640815, + 878191105, 910178934, 926258016, 926396556, 910805951, 879973778, + 834645350, 775805740, 704647514, 622561565, 531103763, 431972981, + 326970096, 217973439, 106899986, -4330812, -113813213, -219710289, + -320272154, -413860814, -498998744, -574348156, -638786776, -691379857, + -731412862, -758411959, -772099815, -772476020, -759732747, -734296127, + -696804018, -648095467, -589173798, -521211860, -445513712, -363500819, + -276669977, -186588833, -94839242, -3023445, 87304541, 174622298, + 257494031, 334584378, 404667892, 466682945, 519706284, 562979312, + 595951179, 618222270, 629608809, 630112956, 619904735, 599360500, + 569008486, 529544706, 481803119, 426750006, 365455529, 299075876, + 228840843, 156016605, 81889836, 7756860, -65127282, -135536293, + -202317721, -264407579, -320823972, -370715300, -413363358, -448173476, + -474700396, -492652588, -501896551, -502436599, -494431331, -478193830, + -454159830, -422893027, -385065038, -341461778, -292933893, -240416823, + -184881223, -127335687, -68805911, -10307038, 47162104, 102643156, + 155228358, 204082912, 248449560, 287665317, 321164977, 348506386, + 369349387, 383472021, 390781163, 391299046, 385158588, 372607442, + 354005897, 329793737, 300515771, 266774740, 229249182, 188658014, + 145771955, 101363895, 56228463, 11154361, -33085315, -75765867, + -116185210, -153712088, -187762879, -217843178, -243525696, -264475607, + -280445626, -291273854, -296909542, -297359668, -292750374, -283274804, + -269211393, -250910393, -228781316, -203300855, -174980799, -144372364, + -112054201, -78621969, -44668588, -10793090, 22429460, 54446787, + 84748044, 112851032, 138327117, 160818678, 180008562, 195655717, + 207575091, 215660629, 219880235, 220245999, 216864942, 209880683, + 199509818, 186014197, 169708472, 150946259, 130109644, 107612785, + 83879303, 59350962, 34464106, 9662772, -14639065, -38039657, + -60160003, -80657250, -99220426, -115593466, -129546162, -140913942, + -149573644, -155442464, -158504321, -158789018, -156361959, -151342314, + -143885404, -134196704, -122497522, -109047150, -94117870, -78022254, + -61057968, -43547261, -25804349, -8129901, 9162869, 25798240, + 41501763, 56035957, 69186490, 80772311, 90633998, 98658424, + 104762522, 108903204, 111057934, 111259018, 109562688, 106046605, + 100834254, 94063360, 85898082, 76517844, 66128784, 54935713, + 43153877, 31006516, 18711362, 6483672, -5469064, -16945311, + -27770754, -37775892, -46818615, -54771112, -61533068, -67026503, + -71200739, -74026465, -75494146, -75627807, -74467061, -72073364, + -68533189, -63937179, -58405371, -52064462, -45039931, -37490040, + -29556752, -21379814, -13124254, -4921292, 3081325, 10761369, + 17992294, 24664939, 30680797, 35969684, 40457241, 44097381, + 46861649, 48722338, 49681754, 49764898, 48992385, 47410889, + 45073356, 42055772, 38424287, 34266273, 29673244, 24744847, + 19568708, 14249149, 8882570, 3560649, -1623890, -6587324, + -11253071, -15553237, -19428909, -22822812, -25697558, -28027913, + -29781633, -30967017, -31573078, -31616950, -31116986, -30105009, + -28612194, -26690950, -24392479, -21758782, -18856741, -15747532, + -12493053, -9151192, -5784785, -2455284, 778428, 3873794, + 6780421, 9450391, 11848188, 13945439, 15721307, 17153486, + 18229833, 18951292, 19317601, 19331829, 19021991, 18391908, + 17477080, 16298631, 14892301, 13286497, 11524410, 9636999, + 7666248, 5643968, 3619164, 1614643, -329494, -2182511, + -3917053, -5510740, -6935551, -8181585, -9230774, -10069505, + -10702745, -11124460, -11330344, -11338179, -11147183, -10771893, + -10229996, -9534288, -8708260, -7772003, -6742108, -5645520, + -4499511, -3330022, -2160619, -1007517, 105958, 1168081, + 2163850, 3069108, 3879602, 4582611, 5175824, 5650631, + 6001619, 6231347, 6348767, 6345832, 6232970, 6020724, + 5711035, 5319768, 4857301, 4330983, 3759052, 3147093, + 2517341, 1869971, 1228320, 593568, -13299, -596644, + -1133926, -1626587, -2061258, -2441661, -2757956, -3009281, + -3195090, -3317069, -3371358, -3369538, -3302704, -3189124, + -3018550, -2810982, -2566460, -2287369, -1982568, -1663786, + -1330037, -993438, -655731, -327480, -11833, 285255, + 559486, 814369, 1035555, 1225864, 1383761, 1511685, + 1599628, 1660692, 1688986, 1684490, 1647570, 1589017, + 1501582, 1394429, 1269741, 1134725, 981075, 823149, + 660159, 493844, 330114, 168814, 14527, -125758, + -257464, -379420, -486743, -577185, -649186, -707958, + -749120, -773688, -786833, -783576, -765253, -738249, + -693765, -642543, -586705, -522856, -450846, -376578, + -301263, -227397, -150470, -82949, -13294, 54367, + 108632, 162347, 208816, 250661, 281292, 304919, + 322777, 332948, 337096, 334473, 326032, 313228, + 295408, 269412, 246699, 215496, 190086, 157695, + 129658, 95562, 61975, 35544, 6711, -22281, + -42869, -59780, -80439, -98610, -110030, -117739, + -124576, -125753, -129948, -128983, -126581, -120301, + -111860, -100762, -94013, -80985, -73587, -61872, + -44448, -35456, -24861, -15228, -2995, 5562, + 13149, 23916, 29909, 35440, 38197, 42010, + 41917, 45141, 44609, 43511, 37540, 35788, + 34531, 31114, 29589, 26982, 24108, 17555, + 14847, 11406, 8428, 3218, 3294, -1756, + -1478, -3498, -8358, -10181, -11537, -11814, + -13888, -11146, -12862, -10178, -12001, -9587, + -8324, -8228, -7163, -2786, -4551, -4214, + -5084, -462, -2985, -2426, -1665, 3391, + 1562, -1694, 4507, 3775, 5534, 2691, + 2039, 5411, 4536, 2785, 1536, 1316, + 3155, 784, -961, 1172, 6, 2598, + 6, -1522, -831, 2692, 3324, -1300, + -1621, -647, -107, 3253, 1955, -1892, + 328, -2424, 701, -926, 497, -2227, + -2074, 2411, -2446, -1601, 854, 603, +}; + +static const int32_t ifft_ref_imag_1536_q31[1536] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +}; diff --git a/test/cmocka/src/math/fft/ref_ifft_multi_24_32.h b/test/cmocka/src/math/fft/ref_ifft_multi_24_32.h new file mode 100644 index 000000000000..8bcfdd9a5674 --- /dev/null +++ b/test/cmocka/src/math/fft/ref_ifft_multi_24_32.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 20-Nov-2025 16:11:52 with script ref_fft_multi.m v1.9-rc1-6882-ge0b90b605-dirty */ + +#define REF_SOFM_IFFT_MULTI_24_NUM_TESTS 1 + +static const int32_t ifft_in_real_24_q31[24] = { + 482922326, -394845603, 213372960, -73385945, 14855847, -1509706, + 52714, 201, 43, 63, -129, -11, + 417, -11, -129, 63, 43, 201, + 52714, -1509706, 14855847, -73385945, 213372960, -394845603, +}; + +static const int32_t ifft_in_imag_24_q31[24] = { + 0, -45964234, 50459274, -26744935, 7515901, -1010620, + 45488, -203, -258, 455, -501, -248, + 0, 248, 501, -455, 258, 203, + -45488, 1010620, -7515901, 26744935, -50459274, 45964234, +}; + +static const int32_t ifft_ref_real_24_q31[24] = { + 3611, 3470, 104050, 1303039, 8697436, 38649256, + 126241459, 320754897, 656625195, 1107910524, 1563494828, 1861834284, + 1878967615, 1607563569, 1161729935, 703464423, 352140415, 142695560, + 45325407, 10719014, 1734754, 163218, 8211, 1653, +}; + +static const int32_t ifft_ref_imag_24_q31[24] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +}; diff --git a/test/cmocka/src/math/fft/ref_ifft_multi_256_32.h b/test/cmocka/src/math/fft/ref_ifft_multi_256_32.h new file mode 100644 index 000000000000..edc4d0e6bcf5 --- /dev/null +++ b/test/cmocka/src/math/fft/ref_ifft_multi_256_32.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 20-Nov-2025 16:11:52 with script ref_fft_multi.m v1.9-rc1-6882-ge0b90b605-dirty */ + +#define REF_SOFM_IFFT_MULTI_256_NUM_TESTS 1 + +static const int32_t ifft_in_real_256_q31[256] = { + -104443, 1525281, -13889136, 60179033, -146702250, 217202408, + -201034199, 115601193, -39529650, 7259750, -570251, 9887, + -10, -25, -68, -107, 25, -62, + -37, -112, 27, -50, -122, 55, + 55, -9, -19, -74, 31, 1, + -21, 24, -93, -138, 2, 128, + 31, -108, -62, -21, 153, 60, + -104, 65, 61, 63, 82, 19, + -92, -12, -63, -10, -8, 72, + 6, -41, -35, 2, 172, 109, + 7, 87, -64, -88, 4, 133, + 19, -113, 0, 93, 82, 106, + 17, 44, 38, -76, -19, -96, + 25, 37, 52, -61, -129, 25, + -116, -18, -62, -88, -142, -17, + 88, 52, 70, 8, -36, -104, + 138, 103, 24, -9, 60, 17, + -86, 24, -150, 13, -84, 138, + -114, -4, 17, 65, 0, 9, + 22, 13, -110, -64, 50, 52, + -37, 79, -79, -85, -120, -34, + 76, -81, 60, -81, 76, -34, + -120, -85, -79, 79, -37, 52, + 50, -64, -110, 13, 22, 9, + 0, 65, 17, -4, -114, 138, + -84, 13, -150, 24, -86, 17, + 60, -9, 24, 103, 138, -104, + -36, 8, 70, 52, 88, -17, + -142, -88, -62, -18, -116, 25, + -129, -61, 52, 37, 25, -96, + -19, -76, 38, 44, 17, 106, + 82, 93, 0, -113, 19, 133, + 4, -88, -64, 87, 7, 109, + 172, 2, -35, -41, 6, 72, + -8, -10, -63, -12, -92, 19, + 82, 63, 61, 65, -104, 60, + 153, -21, -62, -108, 31, 128, + 2, -138, -93, 24, -21, 1, + 31, -74, -19, -9, 55, 55, + -122, -50, 27, -112, -37, -62, + 25, -107, -68, -25, -10, 9887, + -570251, 7259750, -39529650, 115601193, -201034199, 217202408, + -146702250, 60179033, -13889136, 1525281, +}; + +static const int32_t ifft_in_imag_256_q31[256] = { + 0, -1104526, 9802224, -41374276, 98231553, -141609308, + 127580058, -71388104, 23746028, -4240611, 323629, -5337, + 32, -60, -129, -15, -27, 102, + 58, -169, -92, 19, 75, 5, + -81, 131, -54, -36, -21, -15, + 118, -72, -77, 65, -42, 118, + -9, -18, 106, 80, -7, 88, + 41, 65, 32, -107, -22, -1, + 67, 45, 7, -109, 47, -25, + -53, -44, -33, -24, 2, 179, + -68, 105, 153, 16, -75, -42, + 11, -113, -44, -22, -63, -25, + 6, 2, 26, -87, 111, 106, + -53, -51, -36, -51, -27, 235, + -114, -20, -69, 10, -97, 83, + -57, -37, -69, -148, -34, 75, + 76, -38, 60, 29, 152, 37, + 141, 35, 52, -103, 96, -39, + -4, 38, -124, 18, 162, -48, + 52, -93, 94, -33, -1, 129, + 54, -27, 16, 64, 44, -43, + -45, 22, 0, -22, 45, 43, + -44, -64, -16, 27, -54, -129, + 1, 33, -94, 93, -52, 48, + -162, -18, 124, -38, 4, 39, + -96, 103, -52, -35, -141, -37, + -152, -29, -60, 38, -76, -75, + 34, 148, 69, 37, 57, -83, + 97, -10, 69, 20, 114, -235, + 27, 51, 36, 51, 53, -106, + -111, 87, -26, -2, -6, 25, + 63, 22, 44, 113, -11, 42, + 75, -16, -153, -105, 68, -179, + -2, 24, 33, 44, 53, 25, + -47, 109, -7, -45, -67, 1, + 22, 107, -32, -65, -41, -88, + 7, -80, -106, 18, 9, -118, + 42, -65, 77, 72, -118, 15, + 21, 36, 54, -131, 81, -5, + -75, -19, 92, 169, -58, -102, + 27, 15, 129, 60, -32, 5337, + -323629, 4240611, -23746028, 71388104, -127580058, 141609308, + -98231553, 41374276, -9802224, 1104526, +}; + +static const int32_t ifft_ref_real_256_q31[256] = { + -1569, -830, -1909, -1488, 3415, 3228, + 2188, 5284, 6862, 8740, 14431, 22319, + 31495, 39307, 50570, 64256, 80688, 97686, + 111687, 123695, 129388, 123769, 106202, 69953, + 5001, -90529, -229211, -419412, -662837, -975167, + -1362616, -1829929, -2378158, -3009308, -3713257, -4488081, + -5304582, -6149738, -6981956, -7751361, -8417790, -8914691, + -9158092, -9075448, -8582552, -7568550, -5957542, -3636565, + -521174, 3464467, 8388636, 14295537, 21192186, 29060893, + 37842039, 47439021, 57690475, 68385421, 79264186, 90000101, + 100216705, 109496356, 117359992, 123303230, 126792865, 127286147, + 124251244, 117173422, 105589837, 89107796, 67418137, 40323152, + 7767654, -30165152, -73203423, -120914317, -172649439, -227578442, + -284684073, -342740508, -400372402, -456051421, -508121756, -554862914, + -594502691, -625273094, -645469812, -653507615, -647957114, -627616785, + -591570790, -539212509, -470319052, -385064318, -284054609, -168344268, + -39430444, 100735569, 249803271, 405020394, 563321689, 721358446, + 875594019, 1022376304, 1158027755, 1278948253, 1381696559, 1463114882, + 1520394842, 1551181119, 1553662138, 1526604042, 1469444535, 1382288632, + 1265978107, 1122031888, 952680234, 760801123, 549852852, 323835818, + 87168988, -155419072, -398954843, -638404904, -868755989, -1085152640, + -1283040981, -1458244948, -1607111733, -1726568155, -1814231913, -1868441101, + -1888300566, -1873720889, -1825365598, -1744688034, -1633837210, -1495617661, + -1333406076, -1151061358, -952804289, -743116848, -526638885, -308020361, + -91818428, 117599868, 316184921, 500269979, 666664268, 812707094, + 936326727, 1036037706, 1110986476, 1160919766, 1186188110, 1187665485, + 1166746402, 1125255573, 1065389168, 989631979, 900676276, 801355102, + 694539705, 583089310, 469753347, 357133296, 247607391, 143289840, + 46010628, -42730106, -121763798, -190243820, -247669626, -293855572, + -328899891, -353164563, -367242673, -371922368, -368136646, -356940054, + -339446602, -316817655, -290210974, -260754391, -229500117, -197441719, + -165470302, -134343018, -104720510, -77121551, -51962267, -29512549, + -9954815, 6654740, 20324394, 31163846, 39337881, 45058213, + 48577520, 50167506, 50120504, 48722648, 46250707, 42973219, + 39131997, 34949970, 30607270, 26272771, 22078954, 18121182, + 14480497, 11206366, 8326540, 5845185, 3759796, 2057048, + 705551, -326115, -1083775, -1602381, -1917835, -2073023, + -2101305, -2038436, -1903566, -1728329, -1527768, -1319424, + -1111624, -920902, -739460, -586382, -452219, -337529, + -243069, -171574, -119157, -73001, -40498, -22362, + -7395, -1426, 8844, 10381, 5185, 10614, + 6251, 4908, 6476, 3273, 608, 2586, + -939, 517, -2100, 59, +}; + +static const int32_t ifft_ref_imag_256_q31[256] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +}; diff --git a/test/cmocka/src/math/fft/ref_ifft_multi_3072_32.h b/test/cmocka/src/math/fft/ref_ifft_multi_3072_32.h new file mode 100644 index 000000000000..9fc9c64978d3 --- /dev/null +++ b/test/cmocka/src/math/fft/ref_ifft_multi_3072_32.h @@ -0,0 +1,2068 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. + */ + +/* Created 20-Nov-2025 16:11:53 with script ref_fft_multi.m v1.9-rc1-6882-ge0b90b605-dirty */ + +#define REF_SOFM_IFFT_MULTI_3072_NUM_TESTS 1 + +static const int32_t ifft_in_real_3072_q31[3072] = { + -59, -1, -55, 24, -14, 0, + -14, -29, -16, 30, -13, 24, + 23, -8, -29, -3, -6, -29, + -25, -14, -20, 1, -8, 2, + 7, -21, -15, 18, -56, 0, + -26, 43, -5, 7, 42, -26, + -13, -5, -24, -8, -11, -27, + 20, -6, -4, -1, 14, -21, + -23, 31, 4, -7, 21, 31, + 51, -20, -8, -5, -2784, 237345, + -3580001, 21781536, -69391859, 129763784, -149772281, 107836784, + -47262139, 11753785, -1421192, 57131, -155, -28, + -24, 6, -19, 20, -3, 7, + -19, -9, -52, 28, -31, 44, + -14, 8, -3, -37, 7, -25, + 13, 29, 2, 70, 13, 16, + -4, 40, -34, 7, -23, 26, + -20, 9, 21, 6, -31, -27, + -19, 12, 20, -15, 15, -3, + -34, 34, -24, 39, 62, 3, + -38, 21, -21, 39, 2, -4, + 8, 9, -25, -17, 35, 14, + -4, 13, 30, -13, 7, 18, + 22, -27, 8, -34, -15, 5, + 0, 18, -26, -22, 16, 6, + -19, -15, -12, -19, 11, 25, + -6, 6, -1, 40, 24, -17, + 0, -30, 2, -3, 15, 6, + 32, -2, -6, 8, -44, -28, + -11, -17, -16, 24, -4, 9, + 11, 22, -16, 9, 13, -10, + 11, -31, 10, -39, -9, 3, + 24, 7, -32, 31, -9, -22, + -17, 7, -17, 22, 8, -11, + 0, 6, 20, 22, -25, 18, + 1, 6, -21, -8, -1, -2, + 22, -1, -30, 13, -8, -21, + -21, -22, 15, -17, 40, -15, + -21, 7, -6, 9, 37, -3, + 13, -10, -52, 31, -8, 23, + 39, 14, -4, 5, -9, -38, + -9, -4, 10, 2, 42, -27, + 2, 28, -15, -16, -22, 17, + 0, -15, 14, -11, 4, -17, + -24, 4, 6, -15, -2, 40, + 7, 1, 22, -2, 0, -10, + -2, 31, -5, 20, -12, -6, + 0, 12, 1, -35, 7, -26, + 11, -47, 3, -34, 23, 1, + -8, 0, 11, 18, 26, -1, + -31, 23, 10, -17, -12, 7, + 5, -21, 19, 10, -14, 11, + 12, -10, 49, 0, 5, -16, + -9, 24, 11, 21, -29, -15, + -31, -21, -5, 46, -25, 1, + 62, -18, -32, -8, 4, 5, + -22, -27, 38, -15, 19, 3, + -22, 8, 16, -27, 18, -31, + -25, -22, 23, -34, 1, 39, + 1, -11, 2, 40, 19, 29, + -29, -3, 4, 33, -26, 1, + 15, 3, -8, 65, 29, 3, + -7, 26, -25, 10, -4, 14, + 40, -30, 1, 11, 5, 17, + 9, 8, -6, -13, 18, 27, + -1, -25, 15, 85, -20, 6, + -32, -29, 31, 13, -17, -4, + 9, -3, 8, 11, -11, -38, + -26, 7, -19, 13, 28, 32, + 20, 1, -8, 11, 13, 1, + 8, 20, 40, 2, -41, -7, + -13, 6, 0, 45, -8, 26, + 13, 9, 7, 31, -19, -28, + -18, -19, 10, 13, -5, -32, + 18, -26, -23, 19, -23, -3, + -7, -9, 4, 3, -12, 7, + 14, -14, 29, 22, 0, 63, + -6, 5, -24, -13, 7, 34, + -9, 9, 9, 21, 4, 7, + 3, 17, 31, -27, -38, -47, + 17, 12, -11, -14, 15, -10, + -3, 22, 11, 14, 2, -16, + 23, 5, -48, -18, -21, 38, + -23, 8, -7, -19, 31, 29, + -14, -7, 22, 6, 38, 1, + 22, 24, -9, -2, 20, -70, + 21, 20, -42, -1, -39, -7, + -7, 26, -57, -18, 28, 22, + -4, 11, -13, 12, -16, -5, + -9, -5, 9, 3, 4, -38, + -2, -2, -20, 4, -34, -21, + 15, -54, -8, -47, -17, 25, + -26, 20, 6, 12, -20, 21, + -10, -7, 32, -26, 16, -3, + -9, 1, -3, -3, 6, -9, + -11, 18, 0, -23, -17, 1, + 1, -13, -9, -1, 7, 8, + -16, -7, 19, 15, -38, 4, + 21, 20, 3, -1, 5, -2, + -7, 25, -66, 41, -9, -20, + -17, -22, 11, -16, 4, 17, + 6, 22, -20, 14, -4, -2, + 22, -5, 32, 16, 36, -1, + -6, 0, -20, 8, -2, 14, + -29, -2, 6, 14, -4, 9, + 23, -4, 4, -21, -11, -20, + -13, -22, -30, 14, -18, 39, + 27, -24, 24, -19, 24, 29, + 1, -29, 14, 22, -2, -4, + -34, -26, 7, 24, -22, 4, + 24, -19, -35, 11, -4, 10, + -12, -21, 22, 7, 14, 17, + 8, 11, 9, 23, 3, -15, + -6, 20, -11, -17, -28, 33, + -6, 2, -12, -19, -13, -18, + -7, 45, 18, -20, -1, 2, + 15, -1, 37, 9, -15, -12, + 23, 10, 0, 29, -23, 42, + -15, 7, -22, -9, 2, 6, + -30, -26, 56, -18, 2, -1, + -20, -25, 30, 25, -15, 29, + 20, -11, -25, 29, 4, -26, + 9, -8, -14, 29, 13, 4, + -29, 2, -5, -12, 3, 27, + -9, -13, 42, 10, -6, -18, + -6, -3, -26, -40, -8, -11, + 17, -3, 10, -23, -24, -8, + -30, -8, -6, 18, 30, -6, + 24, -1, 3, -1, -35, 9, + -10, -6, -20, -2, -32, 15, + -48, 14, 19, -15, -10, -22, + -19, -26, -59, 3, -3, 39, + 4, 1, 16, 38, -25, 17, + 10, 57, 28, 5, 31, 19, + 2, 18, 16, -26, -6, 28, + -54, -12, -12, -12, -20, 1, + 21, 22, -22, -4, -11, 26, + -1, 0, -2, -8, 13, 35, + 30, -28, -10, -3, -15, -45, + -4, 3, -6, 23, 42, 2, + 29, -35, 45, 0, 2, 6, + -15, 16, -5, 0, -11, 4, + 22, -20, 36, 37, -14, 10, + 6, 5, 19, 35, -3, 44, + -22, -13, -22, 5, 15, 14, + -33, 9, -23, -17, 13, -9, + -17, 9, -25, -14, -17, 31, + 3, -4, -27, -16, 25, 1, + 16, -34, 6, -21, -15, 16, + -25, 3, 23, 17, -4, 14, + 8, -10, 31, 9, 21, 5, + 6, 14, 14, 20, -25, -3, + 12, 2, 37, -25, -14, -1, + -17, -19, -14, 0, 14, 18, + 24, -42, 22, -5, -12, -13, + -21, -1, -31, 25, -17, -38, + -10, -21, -18, 33, 19, 20, + -16, -7, -27, -9, -10, -11, + 17, 9, 10, -33, 23, -23, + 13, 17, -8, 2, -19, -9, + 18, -4, 31, 11, -21, -2, + 2, -2, -11, -15, 12, -20, + 0, 11, -3, -22, -6, 6, + 12, 13, 19, -1, 16, 21, + 11, 1, 7, 9, -31, 29, + 6, -12, -27, -41, -21, 16, + 23, 17, -16, -52, 12, 63, + -6, -37, 26, -16, 52, 28, + -32, -12, -4, 10, -46, 12, + -17, -5, 72, 10, 43, -9, + -27, 43, 14, 26, -39, -16, + 13, -3, -23, -4, 11, 9, + -2, -22, 8, 26, -5, 13, + -18, -9, -18, 5, 29, -35, + 3, 23, 21, 17, -18, -40, + 43, -38, 18, -3, -7, 28, + -1, 27, -15, -31, -30, 2, + 9, -18, -3, -21, -10, -13, + -26, 5, -6, 18, 32, 41, + 11, -1, -4, 14, 22, -39, + 2, -20, -17, 22, -8, 2, + 20, 32, -1, -9, 3, 1, + -34, -8, -20, 3, -18, 12, + 13, -10, -26, -45, 15, -32, + -12, 0, -38, -2, 0, -6, + 10, 1, -17, -1, 17, 15, + -7, -29, 9, 17, -10, -6, + -33, -8, -11, -4, 37, 11, + 28, 9, 0, 3, 18, -24, + -36, -8, -9, 38, 16, 47, + -19, -9, -22, 24, 22, -22, + 10, 40, 2, -10, 1, 3, + -17, 2, -22, -7, 33, -17, + -9, 18, 37, 6, 21, -23, + 17, -30, -54, -9, 31, 13, + -7, -23, 30, 2, 47, 21, + 28, -34, 3, 32, -40, -7, + 27, 8, 33, -28, -14, 48, + -21, -57, 38, -14, -40, 1, + -9, -21, 3, 24, 6, 19, + 10, 1, 9, 12, -15, 3, + 9, 21, -2, 8, 6, -51, + 10, 16, -25, 15, 13, 18, + -8, 20, -24, -19, 10, 11, + -17, -15, -14, 47, 9, 14, + 20, -24, -10, 17, -4, 7, + -8, 9, -19, 5, 6, 27, + 7, 36, 26, -22, -4, -30, + -19, -3, -30, 33, 7, -31, + 23, 7, -34, 23, 31, -20, + 8, 33, 31, 8, -1, -1, + -39, 19, -22, -50, -27, -23, + -13, 18, -8, -5, -1, 8, + 25, 14, 7, -29, 21, 0, + 28, 35, 26, 18, 7, -1, + -18, -25, 33, -23, -5, -28, + -37, 28, -1, -13, 5, -18, + -11, -8, 1, -18, -4, 1, + 2, -20, 8, -23, -21, 31, + 20, 12, -4, -5, -4, -10, + 9, -41, -12, 32, 30, -5, + -30, 1, -23, -11, 22, -21, + 30, -14, -29, -15, 23, 0, + -6, 7, -15, -18, 26, -3, + 5, -3, -2, 0, 26, 36, + -17, -6, 14, 0, 3, -19, + 1, 23, 20, 6, 15, -8, + -33, -15, -26, -14, 10, -23, + -25, 11, 0, -18, -4, -2, + -3, -11, 21, -40, 15, 19, + -10, 21, 12, -44, -21, 16, + 22, 8, -18, -13, -12, -8, + 0, -52, -4, -9, -20, -3, + 16, 21, -16, -35, -23, 4, + 11, -18, 10, 3, -26, -34, + -24, -33, -6, -28, -21, 57, + 0, 22, 9, -31, 8, -9, + -4, 24, 22, 22, 19, -10, + 17, 38, 43, 10, 27, 21, + 7, 8, 3, -57, -9, -36, + 3, -13, 3, 18, 34, 23, + -22, -31, -8, -3, 24, 28, + -48, -24, 25, -13, 2, 9, + 6, -22, 4, -46, -30, 9, + -13, -4, 9, -24, -2, -21, + -20, 1, -36, 0, -23, -21, + -37, -21, 3, 17, 4, -34, + 5, -36, -13, -4, -25, -18, + 20, -40, -2, -26, -9, -7, + -4, -34, -16, -26, 22, -12, + -17, -24, -40, -3, -26, 37, + -14, 23, -8, 0, -35, 2, + 11, 5, -7, -11, 54, 9, + -25, 26, -59, 0, -5, 40, + -13, -6, -12, 43, 11, 9, + -25, -16, -47, -28, 6, -3, + -27, -3, 6, -28, -47, -16, + -25, 9, 11, 43, -12, -6, + -13, 40, -5, 0, -59, 26, + -25, 9, 54, -11, -7, 5, + 11, 2, -35, 0, -8, 23, + -14, 37, -26, -3, -40, -24, + -17, -12, 22, -26, -16, -34, + -4, -7, -9, -26, -2, -40, + 20, -18, -25, -4, -13, -36, + 5, -34, 4, 17, 3, -21, + -37, -21, -23, 0, -36, 1, + -20, -21, -2, -24, 9, -4, + -13, 9, -30, -46, 4, -22, + 6, 9, 2, -13, 25, -24, + -48, 28, 24, -3, -8, -31, + -22, 23, 34, 18, 3, -13, + 3, -36, -9, -57, 3, 8, + 7, 21, 27, 10, 43, 38, + 17, -10, 19, 22, 22, 24, + -4, -9, 8, -31, 9, 22, + 0, 57, -21, -28, -6, -33, + -24, -34, -26, 3, 10, -18, + 11, 4, -23, -35, -16, 21, + 16, -3, -20, -9, -4, -52, + 0, -8, -12, -13, -18, 8, + 22, 16, -21, -44, 12, 21, + -10, 19, 15, -40, 21, -11, + -3, -2, -4, -18, 0, 11, + -25, -23, 10, -14, -26, -15, + -33, -8, 15, 6, 20, 23, + 1, -19, 3, 0, 14, -6, + -17, 36, 26, 0, -2, -3, + 5, -3, 26, -18, -15, 7, + -6, 0, 23, -15, -29, -14, + 30, -21, 22, -11, -23, 1, + -30, -5, 30, 32, -12, -41, + 9, -10, -4, -5, -4, 12, + 20, 31, -21, -23, 8, -20, + 2, 1, -4, -18, 1, -8, + -11, -18, 5, -13, -1, 28, + -37, -28, -5, -23, 33, -25, + -18, -1, 7, 18, 26, 35, + 28, 0, 21, -29, 7, 14, + 25, 8, -1, -5, -8, 18, + -13, -23, -27, -50, -22, 19, + -39, -1, -1, 8, 31, 33, + 8, -20, 31, 23, -34, 7, + 23, -31, 7, 33, -30, -3, + -19, -30, -4, -22, 26, 36, + 7, 27, 6, 5, -19, 9, + -8, 7, -4, 17, -10, -24, + 20, 14, 9, 47, -14, -15, + -17, 11, 10, -19, -24, 20, + -8, 18, 13, 15, -25, 16, + 10, -51, 6, 8, -2, 21, + 9, 3, -15, 12, 9, 1, + 10, 19, 6, 24, 3, -21, + -9, 1, -40, -14, 38, -57, + -21, 48, -14, -28, 33, 8, + 27, -7, -40, 32, 3, -34, + 28, 21, 47, 2, 30, -23, + -7, 13, 31, -9, -54, -30, + 17, -23, 21, 6, 37, 18, + -9, -17, 33, -7, -22, 2, + -17, 3, 1, -10, 2, 40, + 10, -22, 22, 24, -22, -9, + -19, 47, 16, 38, -9, -8, + -36, -24, 18, 3, 0, 9, + 28, 11, 37, -4, -11, -8, + -33, -6, -10, 17, 9, -29, + -7, 15, 17, -1, -17, 1, + 10, -6, 0, -2, -38, 0, + -12, -32, 15, -45, -26, -10, + 13, 12, -18, 3, -20, -8, + -34, 1, 3, -9, -1, 32, + 20, 2, -8, 22, -17, -20, + 2, -39, 22, 14, -4, -1, + 11, 41, 32, 18, -6, 5, + -26, -13, -10, -21, -3, -18, + 9, 2, -30, -31, -15, 27, + -1, 28, -7, -3, 18, -38, + 43, -40, -18, 17, 21, 23, + 3, -35, 29, 5, -18, -9, + -18, 13, -5, 26, 8, -22, + -2, 9, 11, -4, -23, -3, + 13, -16, -39, 26, 14, 43, + -27, -9, 43, 10, 72, -5, + -17, 12, -46, 10, -4, -12, + -32, 28, 52, -16, 26, -37, + -6, 63, 12, -52, -16, 17, + 23, 16, -21, -41, -27, -12, + 6, 29, -31, 9, 7, 1, + 11, 21, 16, -1, 19, 13, + 12, 6, -6, -22, -3, 11, + 0, -20, 12, -15, -11, -2, + 2, -2, -21, 11, 31, -4, + 18, -9, -19, 2, -8, 17, + 13, -23, 23, -33, 10, 9, + 17, -11, -10, -9, -27, -7, + -16, 20, 19, 33, -18, -21, + -10, -38, -17, 25, -31, -1, + -21, -13, -12, -5, 22, -42, + 24, 18, 14, 0, -14, -19, + -17, -1, -14, -25, 37, 2, + 12, -3, -25, 20, 14, 14, + 6, 5, 21, 9, 31, -10, + 8, 14, -4, 17, 23, 3, + -25, 16, -15, -21, 6, -34, + 16, 1, 25, -16, -27, -4, + 3, 31, -17, -14, -25, 9, + -17, -9, 13, -17, -23, 9, + -33, 14, 15, 5, -22, -13, + -22, 44, -3, 35, 19, 5, + 6, 10, -14, 37, 36, -20, + 22, 4, -11, 0, -5, 16, + -15, 6, 2, 0, 45, -35, + 29, 2, 42, 23, -6, 3, + -4, -45, -15, -3, -10, -28, + 30, 35, 13, -8, -2, 0, + -1, 26, -11, -4, -22, 22, + 21, 1, -20, -12, -12, -12, + -54, 28, -6, -26, 16, 18, + 2, 19, 31, 5, 28, 57, + 10, 17, -25, 38, 16, 1, + 4, 39, -3, 3, -59, -26, + -19, -22, -10, -15, 19, 14, + -48, 15, -32, -2, -20, -6, + -10, 9, -35, -1, 3, -1, + 24, -6, 30, 18, -6, -8, + -30, -8, -24, -23, 10, -3, + 17, -11, -8, -40, -26, -3, + -6, -18, -6, 10, 42, -13, + -9, 27, 3, -12, -5, 2, + -29, 4, 13, 29, -14, -8, + 9, -26, 4, 29, -25, -11, + 20, 29, -15, 25, 30, -25, + -20, -1, 2, -18, 56, -26, + -30, 6, 2, -9, -22, 7, + -15, 42, -23, 29, 0, 10, + 23, -12, -15, 9, 37, -1, + 15, 2, -1, -20, 18, 45, + -7, -18, -13, -19, -12, 2, + -6, 33, -28, -17, -11, 20, + -6, -15, 3, 23, 9, 11, + 8, 17, 14, 7, 22, -21, + -12, 10, -4, 11, -35, -19, + 24, 4, -22, 24, 7, -26, + -34, -4, -2, 22, 14, -29, + 1, 29, 24, -19, 24, -24, + 27, 39, -18, 14, -30, -22, + -13, -20, -11, -21, 4, -4, + 23, 9, -4, 14, 6, -2, + -29, 14, -2, 8, -20, 0, + -6, -1, 36, 16, 32, -5, + 22, -2, -4, 14, -20, 22, + 6, 17, 4, -16, 11, -22, + -17, -20, -9, 41, -66, 25, + -7, -2, 5, -1, 3, 20, + 21, 4, -38, 15, 19, -7, + -16, 8, 7, -1, -9, -13, + 1, 1, -17, -23, 0, 18, + -11, -9, 6, -3, -3, 1, + -9, -3, 16, -26, 32, -7, + -10, 21, -20, 12, 6, 20, + -26, 25, -17, -47, -8, -54, + 15, -21, -34, 4, -20, -2, + -2, -38, 4, 3, 9, -5, + -9, -5, -16, 12, -13, 11, + -4, 22, 28, -18, -57, 26, + -7, -7, -39, -1, -42, 20, + 21, -70, 20, -2, -9, 24, + 22, 1, 38, 6, 22, -7, + -14, 29, 31, -19, -7, 8, + -23, 38, -21, -18, -48, 5, + 23, -16, 2, 14, 11, 22, + -3, -10, 15, -14, -11, 12, + 17, -47, -38, -27, 31, 17, + 3, 7, 4, 21, 9, 9, + -9, 34, 7, -13, -24, 5, + -6, 63, 0, 22, 29, -14, + 14, 7, -12, 3, 4, -9, + -7, -3, -23, 19, -23, -26, + 18, -32, -5, 13, 10, -19, + -18, -28, -19, 31, 7, 9, + 13, 26, -8, 45, 0, 6, + -13, -7, -41, 2, 40, 20, + 8, 1, 13, 11, -8, 1, + 20, 32, 28, 13, -19, 7, + -26, -38, -11, 11, 8, -3, + 9, -4, -17, 13, 31, -29, + -32, 6, -20, 85, 15, -25, + -1, 27, 18, -13, -6, 8, + 9, 17, 5, 11, 1, -30, + 40, 14, -4, 10, -25, 26, + -7, 3, 29, 65, -8, 3, + 15, 1, -26, 33, 4, -3, + -29, 29, 19, 40, 2, -11, + 1, 39, 1, -34, 23, -22, + -25, -31, 18, -27, 16, 8, + -22, 3, 19, -15, 38, -27, + -22, 5, 4, -8, -32, -18, + 62, 1, -25, 46, -5, -21, + -31, -15, -29, 21, 11, 24, + -9, -16, 5, 0, 49, -10, + 12, 11, -14, 10, 19, -21, + 5, 7, -12, -17, 10, 23, + -31, -1, 26, 18, 11, 0, + -8, 1, 23, -34, 3, -47, + 11, -26, 7, -35, 1, 12, + 0, -6, -12, 20, -5, 31, + -2, -10, 0, -2, 22, 1, + 7, 40, -2, -15, 6, 4, + -24, -17, 4, -11, 14, -15, + 0, 17, -22, -16, -15, 28, + 2, -27, 42, 2, 10, -4, + -9, -38, -9, 5, -4, 14, + 39, 23, -8, 31, -52, -10, + 13, -3, 37, 9, -6, 7, + -21, -15, 40, -17, 15, -22, + -21, -21, -8, 13, -30, -1, + 22, -2, -1, -8, -21, 6, + 1, 18, -25, 22, 20, 6, + 0, -11, 8, 22, -17, 7, + -17, -22, -9, 31, -32, 7, + 24, 3, -9, -39, 10, -31, + 11, -10, 13, 9, -16, 22, + 11, 9, -4, 24, -16, -17, + -11, -28, -44, 8, -6, -2, + 32, 6, 15, -3, 2, -30, + 0, -17, 24, 40, -1, 6, + -6, 25, 11, -19, -12, -15, + -19, 6, 16, -22, -26, 18, + 0, 5, -15, -34, 8, -27, + 22, 18, 7, -13, 30, 13, + -4, 14, 35, -17, -25, 9, + 8, -4, 2, 39, -21, 21, + -38, 3, 62, 39, -24, 34, + -34, -3, 15, -15, 20, 12, + -19, -27, -31, 6, 21, 9, + -20, 26, -23, 7, -34, 40, + -4, 16, 13, 70, 2, 29, + 13, -25, 7, -37, -3, 8, + -14, 44, -31, 28, -52, -9, + -19, 7, -3, 20, -19, 6, + -24, -28, -155, 57131, -1421192, 11753785, + -47262139, 107836784, -149772281, 129763784, -69391859, 21781536, + -3580001, 237345, -2784, -5, -8, -20, + 51, 31, 21, -7, 4, 31, + -23, -21, 14, -1, -4, -6, + 20, -27, -11, -8, -24, -5, + -13, -26, 42, 7, -5, 43, + -26, 0, -56, 18, -15, -21, + 7, 2, -8, 1, -20, -14, + -25, -29, -6, -3, -29, -8, + 23, 24, -13, 30, -16, -29, + -14, 0, -14, 24, -55, -1, +}; + +static const int32_t ifft_in_imag_3072_q31[3072] = { + 0, 10, -20, -15, 21, -8, + 63, -15, -9, -25, 3, -7, + -21, -6, -5, -35, 2, 43, + -21, 1, -6, 0, 13, 8, + -6, -7, 1, -1, 7, 3, + -10, 68, 17, 12, -28, -34, + 26, 4, -5, -17, -4, 11, + -21, -2, -21, -7, 13, -33, + -11, 10, 19, 6, -5, 16, + -7, 50, -5, 33, -4068, 340975, + -5154185, 31427845, -100341977, 188051721, -217523237, 156961250, + -68943059, 17183334, -2082308, 83903, -220, 19, + -10, -17, 24, 8, 30, -1, + -16, -1, -1, 7, -30, -32, + 4, 12, -10, 52, 41, 0, + -23, -1, 33, -13, -27, 33, + -23, -27, 2, -53, -7, 17, + -5, 54, 6, -1, 7, 11, + -8, 25, -10, 22, -9, 25, + 0, -26, -27, 3, -5, -19, + -24, -7, 29, -1, 15, 8, + 27, 33, 25, 16, -57, -14, + 13, 11, -22, 24, -22, 10, + -17, 8, 10, 43, 19, 15, + -19, -12, -13, -26, 2, 11, + 29, 29, -29, 24, 20, -31, + 16, 4, 5, -21, -16, -21, + -22, 5, -5, 22, -15, -2, + 29, -21, -3, -5, 9, 6, + 4, 6, 7, -3, -5, -27, + 31, 6, -2, 8, -36, -3, + 43, 2, -8, -16, -23, -44, + -17, -8, 33, -37, -8, 13, + -24, 3, -12, 35, -26, -13, + -22, -2, -5, 5, -23, 5, + -20, 2, -20, 21, 42, 17, + -19, 2, 31, -31, 10, 23, + 4, 20, -11, 9, 15, -5, + 13, -20, -45, 34, -6, -10, + -25, 5, -17, -14, 25, -27, + 9, 5, -7, 7, -24, 10, + -5, -10, -8, 3, -34, -43, + -10, 8, 23, 11, 36, 18, + -26, -11, -1, -3, -19, -4, + -31, -31, -15, 12, 15, 44, + 39, -13, 20, 45, -2, -4, + 7, 5, -7, 32, 9, -4, + -4, -1, -13, 22, 10, -35, + -1, 2, 31, 16, 36, 37, + -21, -14, -42, -34, 32, -26, + 9, 25, -9, 8, -18, -2, + 2, 13, 38, 24, -9, -17, + -4, -1, -10, 2, -1, 45, + 28, -25, 18, 10, -46, -19, + 30, 1, -46, -13, 10, -7, + -27, 22, 2, 23, -24, -13, + -22, -15, -30, 27, 16, 3, + -55, 29, 24, 5, 29, -3, + 1, 15, -18, -6, 22, 11, + 19, -8, 25, -12, 15, 14, + 31, -46, -10, 18, -38, -10, + 22, 16, -2, 8, 4, 37, + 22, 30, 42, 48, -30, -5, + 21, -15, -13, -13, -31, 27, + -4, -26, 2, -15, 33, -17, + -39, 7, -20, -1, 14, -19, + 21, 4, 22, -20, -18, 23, + -2, -9, 38, -23, 8, 35, + -9, -7, 3, 7, -5, -5, + 46, 20, 35, 21, -28, 17, + -33, 19, 22, -23, 30, 14, + 34, -12, -25, -19, -14, 21, + -20, 22, 4, 8, -9, 20, + 24, -36, 0, -24, -18, -4, + 6, 11, -4, -26, -22, -15, + -36, 16, -32, 23, -3, 14, + -51, -36, -5, 14, 8, 10, + 41, -12, -20, 25, 1, -24, + 16, 12, 43, 14, -17, 4, + -60, -28, -4, -41, 44, 6, + 1, -4, 6, -1, -1, -14, + -9, 3, -14, -38, 0, 14, + 1, 35, -9, -14, 22, 39, + -21, -29, 15, 32, 4, 23, + 19, 20, 1, -40, -29, 31, + 6, -33, -14, -15, 11, -8, + -13, -36, -35, -8, -7, 2, + 21, -17, -19, -2, 38, 19, + -5, 4, 15, -21, 51, 52, + 18, 1, 45, -7, -11, -22, + -7, 1, -49, -6, -12, 24, + -7, -46, -63, 1, -13, -15, + -25, 3, 27, 10, 9, -33, + -6, -36, 6, 1, -25, -7, + 13, -5, -4, 2, -5, 3, + -33, -36, -2, -26, -27, -16, + -6, -10, 37, -29, 18, 3, + -18, -4, -7, -1, -7, -4, + 3, 46, -12, -30, -7, -12, + -6, 5, -25, -9, 1, 12, + 31, 17, -7, 20, -36, 10, + 0, 13, 16, -16, 10, 17, + 23, -14, 10, -4, -17, -1, + -8, -8, -25, 24, 3, 7, + -16, 59, 2, 28, 25, -1, + 14, -3, -30, -27, -17, 25, + 46, -14, -22, 21, 18, -9, + 13, 23, -5, -23, -18, -5, + -35, 7, 12, -18, -17, 8, + 3, -47, 1, -16, -6, 38, + 38, 20, -3, 41, 71, 0, + 3, 31, 29, -9, 5, -20, + 23, 19, -30, 14, 30, 45, + 14, -29, -6, -9, -12, 14, + -11, 26, -6, -20, -26, 20, + -2, -5, 30, 1, 3, -2, + -36, 13, 5, -7, 30, 18, + -8, -16, 9, 24, 4, 8, + -18, -15, -7, 6, -44, 2, + 9, -18, -21, 3, 4, 1, + -13, -12, 18, -5, 7, -11, + -17, -26, 10, 12, -7, 24, + 7, -12, 39, 21, -16, 37, + -10, -12, -36, -9, -9, 17, + -29, -37, 6, -3, 28, 19, + -37, 17, -21, 7, 4, -5, + 22, 10, -2, -13, 26, -5, + -5, 6, -22, -2, 19, -5, + 15, 15, -2, 9, -15, 11, + -18, -5, -24, 21, 40, -33, + -9, -3, 40, -14, -15, 32, + 31, 13, -23, -17, 32, 10, + 14, 7, 18, -30, -13, -27, + -11, -27, -52, -15, -18, 15, + 42, -7, 17, 10, -1, -30, + -13, -21, 7, -3, 37, 19, + 8, -22, -6, -28, -7, 43, + 9, -24, -27, -33, -7, 27, + -21, 21, 28, -20, -44, 14, + 29, 6, -6, -4, 2, -18, + 13, -5, 14, 21, 15, -2, + 57, -2, 25, -4, 28, 20, + -10, -9, -29, 16, -43, 27, + 12, -9, -1, -21, 47, -45, + -15, -26, -1, 18, 22, -20, + 3, -22, 19, -55, 5, 19, + -4, -15, -11, 0, -14, -9, + -47, 15, 21, -17, -3, 3, + 6, 43, 14, 9, 10, -38, + -1, -22, 13, 6, 11, -17, + 52, -1, -7, 4, 12, -22, + 1, -13, -4, -30, -17, 7, + 6, 39, -5, -34, -15, 21, + -15, -10, -15, 6, -24, -23, + 0, -18, -23, -22, -44, 1, + -16, -3, 22, 3, -14, 4, + 18, -1, -6, 10, 3, 6, + 19, -1, -4, 11, 1, -9, + -3, 6, 22, -11, 6, 5, + -6, -9, -4, 0, -7, -43, + -29, 1, 2, 28, 9, 34, + 19, -2, 1, 7, -9, 16, + 9, 5, -2, 6, -10, 25, + -3, -28, -46, -8, 10, -10, + 0, 36, 1, 10, -2, 14, + 12, 28, -6, 22, -1, -2, + -18, -15, 15, 7, -2, -4, + 28, 17, -6, 5, 8, 22, + -12, -52, 8, 33, 7, 8, + -26, -19, -11, 8, 1, 18, + 12, -38, 25, 9, 22, -6, + 16, 9, 34, -33, 27, -22, + -6, -24, 0, -28, -5, 25, + -6, 36, -4, -38, 6, -14, + 1, -21, -17, 27, -73, -21, + 19, 20, 13, -13, -28, 21, + 2, 34, -2, -33, -8, 28, + 5, 18, 3, 16, -35, 7, + 14, 1, -20, -11, 33, -16, + 20, 15, -21, -21, 10, 9, + 3, -27, -10, -1, -2, 22, + 6, 34, -34, -25, 7, 37, + 8, -33, -16, 5, 5, 5, + 17, 5, -5, 3, 37, -18, + -9, 10, -20, 6, -5, 56, + 26, -11, -17, 5, 10, 7, + 5, -23, 51, 15, -24, -15, + -20, -24, -16, 23, -22, -5, + -18, 30, 23, -35, 2, 23, + 12, 20, -9, -3, 25, -4, + 0, 2, 47, -24, -10, 12, + 14, 22, -7, 18, -14, 10, + 20, -6, 9, 20, 0, -2, + -32, 22, -17, -12, 26, -39, + -2, -16, 29, 2, 16, 13, + 8, -14, 3, -15, 3, 3, + 2, -26, -46, 9, 14, -16, + -29, 36, 1, 49, 25, -45, + 23, 7, -1, 13, -3, 24, + -15, -23, -9, -13, -10, -7, + 28, -14, -14, 29, 1, -7, + -10, 5, 17, 4, 24, 27, + -4, 31, 8, 10, 22, -18, + 27, -12, -47, 24, 3, 8, + 8, -12, -7, -10, -50, -38, + 28, 11, 18, -6, 38, 22, + -1, 15, -15, 8, -27, 27, + -50, 10, -15, 20, 10, 1, + -15, -12, -13, 1, 6, -22, + 17, -3, 23, 13, -17, -12, + 20, -27, -23, -6, 0, -12, + 15, -23, 18, -3, -2, -37, + -32, 28, 20, 0, -33, 10, + -25, 3, -16, -6, 5, 5, + -3, -28, 5, 33, -11, -18, + 31, 34, -2, -2, -53, 15, + 12, -3, 9, 12, 11, 30, + -18, 25, 34, 3, 43, 15, + -18, 43, -5, -10, 2, -6, + 45, 19, 18, -15, -9, 26, + 3, -21, -25, -7, 17, 4, + -7, -27, 11, 5, 18, -40, + 28, 1, 0, -7, 38, -26, + 9, 15, 12, 3, 9, 15, + -34, 51, -1, -30, 4, 45, + 13, 9, 13, -15, 17, 25, + 22, -21, 30, 27, -52, -41, + 40, -37, -8, -44, 45, 26, + 1, 20, -5, 4, 13, 30, + 19, -7, 4, -6, -10, -8, + -19, -30, 4, -35, 4, 10, + -2, -6, 1, 50, -3, 2, + 14, 0, 10, 24, 3, 36, + -13, 4, -21, -15, -4, -9, + 18, -26, -4, 13, 11, -16, + 17, 1, -15, -4, 14, -14, + 4, -23, -2, 3, 12, -8, + 32, 10, -4, 6, 2, 11, + -31, 20, 7, -37, 7, 23, + -18, -30, -31, 20, -1, 10, + -18, 17, 31, -10, -12, -9, + -3, -16, -44, -16, -10, -6, + -21, -10, -13, 7, 6, -1, + -18, 10, -9, 23, -14, -31, + -21, -8, 32, 11, 35, 11, + -18, 1, -8, -29, 7, 6, + -16, -4, 9, 10, -4, 0, + -12, -7, 13, 9, -23, 7, + -18, -16, 23, 46, -39, 17, + -9, -18, 9, 11, 18, 7, + -18, 1, -20, 8, -1, -7, + 21, -2, 13, -23, -12, 8, + -28, 17, -12, -36, 33, 10, + 34, -8, -2, 44, -2, 11, + 19, -17, -11, 55, 26, 4, + -14, -41, 5, 3, 49, -44, + 0, 44, -49, -3, -5, 41, + 14, -4, -26, -55, 11, 17, + -19, -11, 2, -44, 2, 8, + -34, -10, -33, 36, 12, -17, + 28, -8, 12, 23, -13, 2, + -21, 7, 1, -8, 20, -1, + 18, -7, -18, -11, -9, 18, + 9, -17, 39, -46, -23, 16, + 18, -7, 23, -9, -13, 7, + 12, 0, 4, -10, -9, 4, + 16, -6, -7, 29, 8, -1, + 18, -11, -35, -11, -32, 8, + 21, 31, 14, -23, 9, -10, + 18, 1, -6, -7, 13, 10, + 21, 6, 10, 16, 44, 16, + 3, 9, 12, 10, -31, -17, + 18, -10, 1, -20, 31, 30, + 18, -23, -7, 37, -7, -20, + 31, -11, -2, -6, 4, -10, + -32, 8, -12, -3, 2, 23, + -4, 14, -14, 4, 15, -1, + -17, 16, -11, -13, 4, 26, + -18, 9, 4, 15, 21, -4, + 13, -36, -3, -24, -10, 0, + -14, -2, 3, -50, -1, 6, + 2, -10, -4, 35, -4, 30, + 19, 8, 10, 6, -4, 7, + -19, -30, -13, -4, 5, -20, + -1, -26, -45, 44, 8, 37, + -40, 41, 52, -27, -30, 21, + -22, -25, -17, 15, -13, -9, + -13, -45, -4, 30, 1, -51, + 34, -15, -9, -3, -12, -15, + -9, 26, -38, 7, 0, -1, + -28, 40, -18, -5, -11, 27, + 7, -4, -17, 7, 25, 21, + -3, -26, 9, 15, -18, -19, + -45, 6, -2, 10, 5, -43, + 18, -15, -43, -3, -34, -25, + 18, -30, -11, -12, -9, 3, + -12, -15, 53, 2, 2, -34, + -31, 18, 11, -33, -5, 28, + 3, -5, -5, 6, 16, -3, + 25, -10, 33, 0, -20, -28, + 32, 37, 2, 3, -18, 23, + -15, 12, 0, 6, 23, 27, + -20, 12, 17, -13, -23, 3, + -17, 22, -6, -1, 13, 12, + 15, -1, -10, -20, 15, -10, + 50, -27, 27, -8, 15, -15, + 1, -22, -38, 6, -18, -11, + -28, 38, 50, 10, 7, 12, + -8, -8, -3, -24, 47, 12, + -27, 18, -22, -10, -8, -31, + 4, -27, -24, -4, -17, -5, + 10, 7, -1, -29, 14, 14, + -28, 7, 10, 13, 9, 23, + 15, -24, 3, -13, 1, -7, + -23, 45, -25, -49, -1, -36, + 29, 16, -14, -9, 46, 26, + -2, -3, -3, 15, -3, 14, + -8, -13, -16, -2, -29, 16, + 2, 39, -26, 12, 17, -22, + 32, 2, 0, -20, -9, 6, + -20, -10, 14, -18, 7, -22, + -14, -12, 10, 24, -47, -2, + 0, 4, -25, 3, 9, -20, + -12, -23, -2, 35, -23, -30, + 18, 5, 22, -23, 16, 24, + 20, 15, 24, -15, -51, 23, + -5, -7, -10, -5, 17, 11, + -26, -56, 5, -6, 20, -10, + 9, 18, -37, -3, 5, -5, + -17, -5, -5, -5, 16, 33, + -8, -37, -7, 25, 34, -34, + -6, -22, 2, 1, 10, 27, + -3, -9, -10, 21, 21, -15, + -20, 16, -33, 11, 20, -1, + -14, -7, 35, -16, -3, -18, + -5, -28, 8, 33, 2, -34, + -2, -21, 28, 13, -13, -20, + -19, 21, 73, -27, 17, 21, + -1, 14, -6, 38, 4, -36, + 6, -25, 5, 28, 0, 24, + 6, 22, -27, 33, -34, -9, + -16, 6, -22, -9, -25, 38, + -12, -18, -1, -8, 11, 19, + 26, -8, -7, -33, -8, 52, + 12, -22, -8, -5, 6, -17, + -28, 4, 2, -7, -15, 15, + 18, 2, 1, -22, 6, -28, + -12, -14, 2, -10, -1, -36, + 0, 10, -10, 8, 46, 28, + 3, -25, 10, -6, 2, -5, + -9, -16, 9, -7, -1, 2, + -19, -34, -9, -28, -2, -1, + 29, 43, 7, 0, 4, 9, + 6, -5, -6, 11, -22, -6, + 3, 9, -1, -11, 4, 1, + -19, -6, -3, -10, 6, 1, + -18, -4, 14, -3, -22, 3, + 16, -1, 44, 22, 23, 18, + 0, 23, 24, -6, 15, 10, + 15, -21, 15, 34, 5, -39, + -6, -7, 17, 30, 4, 13, + -1, 22, -12, -4, 7, 1, + -52, 17, -11, -6, -13, 22, + 1, 38, -10, -9, -14, -43, + -6, -3, 3, 17, -21, -15, + 47, 9, 14, 0, 11, 15, + 4, -19, -5, 55, -19, 22, + -3, 20, -22, -18, 1, 26, + 15, 45, -47, 21, 1, 9, + -12, -27, 43, -16, 29, 9, + 10, -20, -28, 4, -25, 2, + -57, 2, -15, -21, -14, 5, + -13, 18, -2, 4, 6, -6, + -29, -14, 44, 20, -28, -21, + 21, -27, 7, 33, 27, 24, + -9, -43, 7, 28, 6, 22, + -8, -19, -37, 3, -7, 21, + 13, 30, 1, -10, -17, 7, + -42, -15, 18, 15, 52, 27, + 11, 27, 13, 30, -18, -7, + -14, -10, -32, 17, 23, -13, + -31, -32, 15, 14, -40, 3, + 9, 33, -40, -21, 24, 5, + 18, -11, 15, -9, 2, -15, + -15, 5, -19, 2, 22, -6, + 5, 5, -26, 13, 2, -10, + -22, 5, -4, -7, 21, -17, + 37, -19, -28, 3, -6, 37, + 29, -17, 9, 9, 36, 12, + 10, -37, 16, -21, -39, 12, + -7, -24, 7, -12, -10, 26, + 17, 11, -7, 5, -18, 12, + 13, -1, -4, -3, 21, 18, + -9, -2, 44, -6, 7, 15, + 18, -8, -4, -24, -9, 16, + 8, -18, -30, 7, -5, -13, + 36, 2, -3, -1, -30, 5, + 2, -20, 26, 20, 6, -26, + 11, -14, 12, 9, 6, 29, + -14, -45, -30, -14, 30, -19, + -23, 20, -5, 9, -29, -31, + -3, 0, -71, -41, 3, -20, + -38, -38, 6, 16, -1, 47, + -3, -8, 17, 18, -12, -7, + 35, 5, 18, 23, 5, -23, + -13, 9, -18, -21, 22, 14, + -46, -25, 17, 27, 30, 3, + -14, 1, -25, -28, -2, -59, + 16, -7, -3, -24, 25, 8, + 8, 1, 17, 4, -10, 14, + -23, -17, -10, 16, -16, -13, + 0, -10, 36, -20, 7, -17, + -31, -12, -1, 9, 25, -5, + 6, 12, 7, 30, 12, -46, + -3, 4, 7, 1, 7, 4, + 18, -3, -18, 29, -37, 10, + 6, 16, 27, 26, 2, 36, + 33, -3, 5, -2, 4, 5, + -13, 7, 25, -1, -6, 36, + 6, 33, -9, -10, -27, -3, + 25, 15, 13, -1, 63, 46, + 7, -24, 12, 6, 49, -1, + 7, 22, 11, 7, -45, -1, + -18, -52, -51, 21, -15, -4, + 5, -19, -38, 2, 19, 17, + -21, -2, 7, 8, 35, 36, + 13, 8, -11, 15, 14, 33, + -6, -31, 29, 40, -1, -20, + -19, -23, -4, -32, -15, 29, + 21, -39, -22, 14, 9, -35, + -1, -14, 0, 38, 14, -3, + 9, 14, 1, 1, -6, 4, + -1, -6, -44, 41, 4, 28, + 60, -4, 17, -14, -43, -12, + -16, 24, -1, -25, 20, 12, + -41, -10, -8, -14, 5, 36, + 51, -14, 3, -23, 32, -16, + 36, 15, 22, 26, 4, -11, + -6, 4, 18, 24, 0, 36, + -24, -20, 9, -8, -4, -22, + 20, -21, 14, 19, 25, 12, + -34, -14, -30, 23, -22, -19, + 33, -17, 28, -21, -35, -20, + -46, 5, 5, -7, -3, 7, + 9, -35, -8, 23, -38, 9, + 2, -23, 18, 20, -22, -4, + -21, 19, -14, 1, 20, -7, + 39, 17, -33, 15, -2, 26, + 4, -27, 31, 13, 13, 15, + -21, 5, 30, -48, -42, -30, + -22, -37, -4, -8, 2, -16, + -22, 10, 38, -18, 10, 46, + -31, -14, -15, 12, -25, 8, + -19, -11, -22, 6, 18, -15, + -1, 3, -29, -5, -24, -29, + 55, -3, -16, -27, 30, 15, + 22, 13, 24, -23, -2, -22, + 27, 7, -10, 13, 46, -1, + -30, 19, 46, -10, -18, 25, + -28, -45, 1, -2, 10, 1, + 4, 17, 9, -24, -38, -13, + -2, 2, 18, -8, 9, -25, + -9, 26, -32, 34, 42, 14, + 21, -37, -36, -16, -31, -2, + 1, 35, -10, -22, 13, 1, + 4, 4, -9, -32, 7, -5, + -7, 4, 2, -45, -20, 13, + -39, -44, -15, -12, 15, 31, + 31, 4, 19, 3, 1, 11, + 26, -18, -36, -11, -23, -8, + 10, 43, 34, -3, 8, 10, + 5, -10, 24, -7, 7, -5, + -9, 27, -25, 14, 17, -5, + 25, 10, 6, -34, 45, 20, + -13, 5, -15, -9, 11, -20, + -4, -23, -10, 31, -31, -2, + 19, -17, -42, -21, 20, -2, + 20, -5, 23, -5, 5, 2, + 22, 13, 26, -35, 12, -3, + 24, -13, 8, 37, -33, 8, + 17, 44, 23, 16, 8, -2, + -43, 3, 36, -8, 2, -6, + -31, 27, 5, 3, -7, -6, + -4, -6, -9, 5, 3, 21, + -29, 2, 15, -22, 5, -5, + 22, 21, 16, 21, -5, -4, + -16, 31, -20, -24, 29, -29, + -29, -11, -2, 26, 13, 12, + 19, -15, -19, -43, -10, -8, + 17, -10, 22, -24, 22, -11, + -13, 14, 57, -16, -25, -33, + -27, -8, -15, 1, -29, 7, + 24, 19, 5, -3, 27, 26, + 0, -25, 9, -22, 10, -25, + 8, -11, -7, 1, -6, -54, + 5, -17, 7, 53, -2, 27, + 23, -33, 27, 13, -33, 1, + 23, 0, -41, -52, 10, -12, + -4, 32, 30, -7, 1, 1, + 16, 1, -30, -8, -24, 17, + 10, -19, 220, -83903, 2082308, -17183334, + 68943059, -156961250, 217523237, -188051721, 100341977, -31427845, + 5154185, -340975, 4068, -33, 5, -50, + 7, -16, 5, -6, -19, -10, + 11, 33, -13, 7, 21, 2, + 21, -11, 4, 17, 5, -4, + -26, 34, 28, -12, -17, -68, + 10, -3, -7, 1, -1, 7, + 6, -8, -13, 0, 6, -1, + 21, -43, -2, 35, 5, 6, + 21, 7, -3, 25, 9, 15, + -63, 8, -21, 15, 20, -10, +}; + +static const int32_t ifft_ref_real_3072_q31[3072] = { + -1954, 1267, -1428, -189, -2328, -332, + -2139, 2088, 1120, -504, -2966, -2008, + -3174, 846, -914, 1141, -2101, -1347, + 3027, -1403, -1333, 362, 1668, -927, + 1181, -1244, -225, -358, 228, -2786, + 2981, -1883, 1268, -3378, 837, -534, + -1694, -1442, -1609, 233, 657, 23, + -1344, 662, -1927, -982, -3378, -381, + -779, 844, 2776, 2991, -1622, -1119, + 3870, 265, -548, 2619, 4851, -163, + 1724, 2204, 750, 902, 2561, 4782, + 3436, 2236, 3459, 607, -2115, 1150, + 684, 206, -433, -699, -4322, -665, + -1792, -1032, -2476, -4106, -4595, -7403, + -5622, -4960, -3025, -6094, -4879, -5786, + -6701, -500, -3185, -2761, -3410, -1888, + 2902, 3236, 1579, 1072, 6289, 5865, + 3737, 7878, 10582, 11262, 5716, 8054, + 10346, 11274, 12870, 8232, 10221, 8739, + 9892, 9425, 8387, 2936, 1194, 3767, + 3503, -909, -5905, -5029, -9175, -10882, + -13511, -12505, -18920, -17241, -21785, -18975, + -18165, -21109, -20486, -23023, -18012, -19889, + -16786, -16232, -16213, -12552, -11375, -5925, + -3013, -68, 6753, 11006, 10410, 17275, + 18657, 26177, 27511, 30865, 35720, 36178, + 40779, 42618, 39224, 37957, 35824, 38634, + 33522, 32862, 26097, 23825, 18366, 10697, + 2542, -3672, -8849, -17950, -25991, -35087, + -41498, -47572, -51102, -58015, -62956, -68385, + -70399, -70984, -75068, -68763, -72106, -66894, + -60619, -53553, -47109, -36855, -27916, -17365, + -9085, 4803, 17617, 31120, 43881, 55889, + 67189, 80156, 92141, 98698, 106521, 111873, + 119040, 120646, 121770, 119358, 115558, 112068, + 103408, 89951, 80567, 66268, 48447, 35386, + 11202, -5637, -31755, -52096, -69437, -90322, + -113541, -131335, -149125, -165772, -176375, -189568, + -193607, -198890, -199959, -201103, -193177, -183881, + -169659, -150640, -131600, -112287, -80475, -51938, + -22370, 9892, 41497, 76822, 111071, 143854, + 174132, 205505, 236130, 261930, 279611, 299838, + 309539, 319576, 321418, 317950, 307013, 292425, + 272196, 248900, 217268, 174794, 134153, 89526, + 39276, -11100, -64816, -117792, -169261, -224363, + -272702, -320621, -363995, -405013, -436618, -461801, + -484416, -498480, -498357, -493096, -476616, -455593, + -423250, -379896, -334722, -274426, -209798, -142911, + -68726, 10645, 91081, 174972, 259533, 339980, + 415872, 486041, 556745, 615719, 664094, 704463, + 734385, 750620, 754842, 747862, 725129, 692003, + 643234, 579508, 509962, 422076, 326650, 221229, + 109587, -7844, -129406, -252356, -374193, -495182, + -610853, -720845, -820495, -906599, -985383, -1044324, + -1087653, -1116727, -1119971, -1110995, -1079312, -1030261, + -955116, -868440, -755018, -634629, -491612, -340000, + -174008, -2545, 175459, 357679, 534472, 711584, + 880611, 1044734, 1187234, 1319178, 1429981, 1514941, + 1579514, 1621514, 1632752, 1615925, 1570986, 1497739, + 1396079, 1264505, 1111550, 930262, 727987, 506360, + 270114, 20615, -236580, -496428, -752595, -1006049, + -1248329, -1478414, -1689987, -1875964, -2034697, -2162770, + -2260013, -2312597, -2336506, -2314000, -2246916, -2147191, + -1999537, -1819161, -1598211, -1339436, -1053219, -741591, + -404819, -52105, 309008, 673402, 1040004, 1399854, + 1743725, 2065359, 2364137, 2627629, 2852233, 3037607, + 3171927, 3252277, 3278896, 3252821, 3166834, 3019401, + 2821154, 2565178, 2259733, 1902289, 1505911, 1071868, + 604387, 114568, -390538, -901979, -1414555, -1914667, + -2392421, -2844993, -3257702, -3627354, -3937513, -4197246, + -4382927, -4499670, -4541377, -4505222, -4388437, -4193254, + -3917142, -3572652, -3149370, -2664511, -2114061, -1520182, + -878438, -206493, 488632, 1187065, 1887697, 2573079, + 3234344, 3854568, 4423382, 4930050, 5363304, 5713011, + 5974276, 6138366, 6197414, 6153614, 6000228, 5736857, + 5367596, 4895708, 4327978, 3670697, 2930826, 2121844, + 1253041, 345643, -591645, -1542721, -2491418, -3421573, + -4314585, -5153975, -5923671, -6613787, -7199081, -7676067, + -8032673, -8261748, -8344694, -8289718, -8091735, -7743502, + -7254200, -6625856, -5868940, -4992277, -4003982, -2924878, + -1768018, -551110, 699523, 1970706, 3241390, 4481897, + 5675977, 6800856, 7836039, 8754662, 9546004, 10185660, + 10671856, 10976049, 11105194, 11035120, 10778861, 10326591, + 9683699, 8861631, 7867395, 6705779, 5405603, 3980232, + 2454384, 850530, -805109, -2486513, -4160748, -5805891, + -7382307, -8869688, -10233575, -11456331, -12505369, -13360134, + -14001774, -14417847, -14592276, -14519772, -14192650, -13609416, + -12782143, -11705217, -10409849, -8901823, -7209623, -5352473, + -3361810, -1266846, 895532, 3091918, 5277170, 7420525, + 9489624, 11432011, 13218921, 14821879, 16198902, 17320553, + 18176905, 18728063, 18968219, 18889211, 18474356, 17736672, + 16676488, 15301851, 13630777, 11691303, 9503862, 7109981, + 4543576, 1837027, -952943, -3787629, -6616674, -9389765, + -12060838, -14575923, -16896520, -18966998, -20757833, -22225876, + -23339580, -24064965, -24399452, -24313960, -23801953, -22874513, + -21529058, -19786854, -17661695, -15187331, -12403054, -9343646, + -6061675, -2608238, 960215, 4587200, 8203769, 11754426, + 15171453, 18398050, 21370217, 24031857, 26331810, 28224976, + 29662244, 30620056, 31063943, 30981748, 30362653, 29208928, + 27521429, 25329400, 22653382, 19531351, 16013837, 12153017, + 7998716, 3631447, -887872, -5478882, -10065002, -14563158, + -18898704, -22992346, -26766793, -30153622, -33084231, -35497471, + -37346046, -38578296, -39177363, -39107071, -38357663, -36931725, + -34843569, -32109203, -28776745, -24879474, -20480119, -15636363, + -10440654, -4962221, 700614, 6457439, 12213225, 17863443, + 23312919, 28460670, 33212090, 37476766, 41174535, 44229347, + 46576727, 48162205, 48947682, 48902130, 48012213, 46278804, + 43713794, 40343588, 36215821, 31390803, 25937800, 19941472, + 13486924, 6681309, -359302, -7516992, -14675702, -21708040, + -28497166, -34910721, -40834521, -46165672, -50790519, -54624928, + -57581677, -59595573, -60621295, -60618413, -59571237, -57474927, + -54349703, -50239530, -45184393, -39261870, -32559111, -25183391, + -17240783, -8864180, -195070, 8633884, 17462285, 26142836, + 34521640, 42450999, 49782997, 56376985, 62114562, 66884038, + 70577659, 73119273, 74442582, 74504938, 73280556, 70778132, + 67008877, 62027743, 55891005, 48684209, 40526777, 31524482, + 21837075, 11608676, 1013426, -9776897, -20582082, -31205608, + -41468126, -51178912, -60175566, -68283677, -75344704, -81222512, + -85802753, -88973444, -90664439, -90820751, -89418368, -86452620, + -81948797, -75958944, -68566242, -59877640, -50011282, -39132078, + -27402568, -15013504, -2168131, 10918713, 24020964, 36927546, + 49396361, 61209585, 72158752, 82038947, 90660079, 97855090, + 103473914, 107407932, 109551924, 109843422, 108249115, 104763010, + 99421497, 92289068, 83455070, 73050647, 61227870, 48169481, + 34081773, 19187156, 3739342, -12004598, -27791472, -43333230, + -58365766, -72626836, -85851549, -97795818, -108239741, -116981970, + -123840767, -128671350, -131359123, -131835146, -130042269, -125987174, + -119707501, -111272601, -100798435, -88436623, -74369612, -58823550, + -42030940, -24264150, -5826716, 12986473, 31848307, 50441973, + 68433889, 85512134, 101368634, 115713840, 128269407, 138806740, + 147108818, 153002353, 156352203, 157056990, 155072795, 150393409, + 143062822, 133169262, 120845178, 106267660, 89657885, 71273294, + 51399725, 30366288, 8514011, -13792699, -36174735, -58248196, + -79627543, -99936507, -118812766, -135906620, -150905421, -163518325, + -173495056, -180624235, -184755195, -185764212, -183594689, -178240626, + -169750794, -158228079, -143834201, -126764583, -107293151, -85713607, + -62363318, -37632655, -11918011, 14346364, 40717861, 66742307, + 91968909, 115955469, 138267475, 158501540, 176282366, 191273980, + 203176778, 211748630, 216793410, 218187466, 215847622, 209772219, + 200013871, 186692507, 169996463, 150155667, 127480051, 102325892, + 75082013, 46198998, 16151019, -14561432, -45418844, -75894680, + -105459536, -133586607, -159787579, -183572791, -204511701, -222205628, + -236312691, -246538905, -252660476, -254524141, -252042329, -245203169, + -234069735, -218776002, -199541362, -176642414, -150419791, -121291048, + -89722588, -56220440, -21344396, 14334015, 50206743, 85657746, + 120072210, 152844393, 183400551, 211180477, 235674009, 256422421, + 273023557, 285141522, 292508799, 294952686, 292362193, 284725036, + 272111181, 254677613, 232669346, 206404757, 176282500, 142783969, + 106437823, 67830506, 27604415, -13569950, -54991741, -95959498, + -135761919, -173705841, -209109551, -241337116, -269805490, -293980085, + -313391229, -327649859, -336454096, -339589981, -336941047, -328484687, + -314290618, -294554567, -269534232, -239604639, -205232447, -166945906, + -125368449, -81167635, -35075166, 12139805, 59675747, 106722917, + 152463819, 196110460, 236875290, 274037087, 306914105, 334892098, + 357442746, 374110440, 384551660, 388518382, 385864545, 376568060, + 360714253, 338512455, 310255664, 276379501, 237393220, 193922019, + 146648837, 96353228, 43872047, -9932907, -64141763, -117837085, + -170085645, -219975310, -266629410, -309200944, -346939392, -379119852, + -405153604, -424514398, -436807953, -441745719, -439164716, -429031904, + -411439319, -386617372, -354913267, -316797073, -272860523, -223800373, + -170393396, -113518291, -54112519, 6827960, 68275656, 129182673, + 188492573, 245180555, 298245210, 346732971, 389775867, 426573829, + 456438737, 478787157, 493153292, 499220637, 496795613, 485840102, + 466452793, 438881992, 403526130, 360909673, 311691302, 256650303, + 196670827, 132739707, 65907805, -2700984, -71937130, -140610726, + -207548644, -271569377, -331569987, -386464900, -435269685, -477092614, + -511151438, -536775753, -553458247, -560822864, -558660166, -546903818, + -525680344, -495253593, -456060540, -408696645, -353886403, -292506414, + -225548912, -154104305, -79357989, -2561325, 74990181, 151972303, + 227066091, 298962161, 366405218, 428188514, 483211372, 530459862, + 569062016, 598277372, 617510900, 626356585, 624560000, 612060937, + 588968499, 555591130, 512411217, 460077642, 399402792, 331356454, + 257035710, 177661517, 94544543, 9078357, -77292654, -163096706, + -246858480, -327129277, -402500612, -471640542, -533309915, -586386059, + -629889889, -662987333, -685024657, -695536650, -694236254, -681048472, + -656096749, -619709358, -572413134, -514919077, -448139426, -373131135, + -291109258, -203418830, -111520436, -16947282, 78700085, 173795497, + 266706134, 355821766, 439583391, 516516093, 585243211, 644522213, + 693263322, 730544442, 755633273, 768005415, 767338814, 753543170, + 726752740, 687313915, 635809216, 573019067, 499930312, 417713744, + 327700363, 231372022, 130329737, 26257105, -79076016, -183887358, + -286366416, -384750216, -477320353, -562449725, -638616288, -704458907, + -758758447, -800507282, -828883506, -843307951, -843426655, -829126268, + -800540682, -758051926, -702285573, -634098007, -554555308, -464934509, + -366696843, -261459008, -150968810, -37078553, 78287202, 193169274, + 305590106, 413617022, 515363932, 609041209, 692999791, 765716620, + 825874328, 872350899, 904255173, 920933942, 921991897, 907302345, + 876995606, 831491084, 771450963, 697802833, 611711188, 514553522, + 407924872, 293581426, 173412732, 49450008, -76218165, -201462064, + -324123571, -442093130, -553318187, -655856510, -747889886, -827768644, + -894047369, -945499331, -981148121, -1000271653, -1002435558, -987487658, + -955564675, -907105489, -842828582, -763719588, -671045492, -566295061, + -451176469, -327596047, -197610656, -63402519, 72763028, 208568268, + 341689279, 469837824, 590779804, 702411793, 802756107, 890031701, + 962659652, 1019302373, 1058894770, 1080652653, 1084089892, 1069029267, + 1035616997, 984310463, 915868643, 831368539, 732138036, 619797618, + 496178710, 363330656, 223463581, 78932936, -67831952, -214321056, + -358035511, -496501573, -627322734, -748210245, -857045845, -951889207, + -1031046097, -1093063589, -1136783070, -1161342438, -1166218018, -1151211372, + -1116459710, -1062446233, -989977050, -900187067, -794513962, -674664651, + -542612066, -400545709, -250835618, -95987277, 61364836, 218559073, + 372902420, 521744972, 662503466, 792739349, 910160054, 1012694129, + 1098502669, 1166028599, 1214023809, 1241553437, 1248036967, 1233254419, + 1197341171, 1140794021, 1064475666, 969571958, 857622760, 730435171, + 590108274, 438970794, 279545597, 114515489, -53334992, -221140870, + -386048025, -545211956, -695892850, -835473083, -961502732, -1071771032, + -1164306249, -1237436513, -1289821237, -1320457758, -1328710489, -1314334805, + -1277454667, -1218590303, -1138644363, -1038872942, -920883135, -786610219, + -638256404, -478293472, -309391820, -134402940, 43720522, 221947038, + 397237986, 566582584, 727057401, 875882937, 1010467192, 1128437030, + 1227705429, 1306486153, 1363337657, 1397194988, 1407374023, 1393581661, + 1355955920, 1295029129, 1211727393, 1107379233, 983675309, 842639668, + 686599942, 518157159, 340132910, 155517872, -32551047, -220888680, + -406281117, -585536670, -755581427, -913471547, -1056447125, -1182018238, + -1287955758, -1372371364, -1433739680, -1470903413, -1483138046, -1470128386, + -1431988068, -1369264203, -1282936733, -1174373434, -1045338297, -897950837, + -734656662, -558176986, -371475445, -177689527, 19892513, 217915644, + 412997957, 601805608, 781081716, 947733928, 1098870125, 1231847160, + 1344327293, 1434310121, 1500180677, 1540715667, 1555129526, 1543084250, + 1504675269, 1440471194, 1351469669, 1239099003, 1105185102, 951940796, + 781910283, 597941305, 403111530, 200712781, -5824762, -212994191, + -417261433, -615130588, -803202090, -978230008, -1137190856, -1277301705, + -1396119506, -1491538873, -1561855656, -1605779457, -1622481182, -1611573682, + -1573160731, -1507799779, -1416525935, -1300804137, -1162532566, -1003997496, + -827842473, -637007723, -434707419, -224363857, -9529147, 206141110, + 418961991, 625309440, 821625264, 1004543936, 1170892474, 1317789291, + 1442668348, 1543329576, 1617986419, 1665291150, 1684353298, 1674763544, + 1636596958, 1570432320, 1477313125, 1358749421, 1216693848, 1053501196, + 871900049, 674928292, 465909734, 248374414, 26011493, -197396416, + -418047432, -632168499, -836088206, -1026306899, -1199532237, -1352774708, + -1483362122, -1589013138, -1667859380, -1718486820, -1739959414, -1731839850, + -1694188625, -1627580629, -1533073593, -1412212813, -1266996403, -1099843876, + -913551827, -711245725, -496342808, -272475963, -43448807, 186852460, + 414501321, 635605431, 846385683, 1043217713, 1222718789, 1381788185, + 1517669181, 1627982917, 1710811456, 1764671245, 1788582254, 1782075582, + 1745195237, 1678510734, 1583094073, 1460515358, 1312808363, 1142439233, + 952272960, 745500972, 525630752, 296374628, 61627773, -174619248, + -408338841, -635548976, -852356373, -1055039545, -1240132943, -1404437242, + -1545116122, -1659725677, -1746274508, -1803234452, -1829578860, -1824800936, + -1788947477, -1722558810, -1626723784, -1503026676, -1353526848, -1180736873, + -987560877, -777264714, -553400924, -319762014, -80323054, 160850975, + 399648300, 631989745, 853911556, 1061611842, 1251535835, 1420413179, + 1565341882, 1683813544, 1773777276, 1833658423, 1862393559, 1859456468, + 1824850431, 1759130098, 1663373112, 1539169746, 1388612600, 1214226013, + 1018956148, 806102039, 579277584, 342326951, 99278560, -145730951, + -388522944, -624972370, -851028582, -1062836348, -1256765856, -1429496044, + -1578067280, -1699914608, -1792940108, -1855530759, -1886589380, -1885556536, + -1852427918, -1787733942, -1692547773, -1568470823, -1417588696, -1242446357, + -1046016840, -831625333, -602914593, -363764440, -118246447, 129457933, + 375133133, 614592525, 843753094, 1058698702, 1255759245, 1431571485, + 1583116729, 1707807432, 1803502380, 1868552397, 1901829488, 1902756563, + 1871297545, 1807976709, 1713849715, 1590510399, 1440048829, 1265014746, + 1068377633, 853481494, 623978067, 383777980, 136958703, -112263451, + -359658453, -601001951, -832182190, -1049261424, -1248533642, -1426603203, + -1580431454, -1707395036, -1805325977, -1872546489, -1907914848, -1910818076, + -1881207464, -1819578191, -1726983553, -1604994703, -1455689253, -1281612422, + -1085724274, -871362313, -642175923, -402075595, -155149216, 94400503, + 342322888, 584392163, 816484983, 1034660863, 1235192607, 1414675018, + 1570047568, 1698683993, 1798381542, 1867461297, 1904749062, 1909622838, + 1882001675, 1822371202, 1731754856, 1611708739, 1464279918, 1291998989, + 1097800233, 885005516, 657247259, 418403559, 172550621, -76116588, + -323374830, -565003771, -796896074, -1015106272, -1215927587, -1395951522, + -1552119510, -1681791215, -1782773966, -1853368131, -1892388366, -1899186924, + -1873682131, -1816320639, -1728100774, -1610554472, -1465704675, -1296028376, + -1104443620, -894227806, -668969691, -432525248, -188924505, 57679224, + 303082074, 543110898, 773680753, 990874742, 1191013320, 1370694105, + 1526894338, 1656961319, 1758722067, 1830459298, 1870994518, 1879662164, + 1856352631, 1801500505, 1716070729, 1601552060, 1459928482, 1293641204, + 1105547943, 898884127, 677184136, 444236544, 204030905, -39343464, + -281738664, -519025295, -747170062, -962310760, -1160794862, -1339268137, + -1494721598, -1624539903, -1726553534, -1799057804, -1840866292, -1851309234, + -1830258511, -1778116140, -1695821581, -1584818150, -1447033124, -1284862132, + -1101101431, -898908590, -681765683, -453380283, -217663348, 21366067, + 259626629, 493069110, 717729127, 929798100, 1125685812, 1302090661, + 1456045329, 1584967615, 1686708061, 1759581633, 1802411603, 1814515303, + 1795749950, 1746490361, 1667630949, 1560573113, 1427192494, 1269816696, + 1091161725, 894307502, 682653795, 459821740, 229630215, -3991130, + -237055717, -465609152, -685757243, -893783125, -1086168150, -1259671175, + -1411386186, -1538775234, -1639723774, -1712577604, -1756151022, -1769776508, + -1753292116, -1707041151, -1631881051, -1529159258, -1400681659, -1248706757, + -1075861775, -885147434, -679849203, -463492936, -239788150, -12560413, + 214318410, 436985739, 651670077, 854731189, 1042749355, 1212561343, + 1361329636, 1486571568, 1586224427, 1658655883, 1702702675, 1717693933, + 1703455417, 1660303044, 1589054484, 1490989879, 1367857293, 1221819477, + 1055425710, 871558841, 673398885, 464352943, 248016103, 28083145, + -191694062, -407575006, -615898089, -813149104, -995999398, -1161377159, + -1306529815, -1429044289, -1526909689, -1598526684, -1642758694, -1658946878, + -1646894078, -1606895102, -1539711606, -1446581982, -1329160129, -1189527998, + -1030131177, -853735906, -663406443, -462421125, -254228780, -42401115, + 169451502, 377727713, 578892455, 769550429, 946492399, 1106757984, + 1247674256, 1366915397, 1462519769, 1532950547, 1577092743, 1594289529, + 1584334455, 1547501541, 1484506909, 1396511141, 1285109652, 1152267535, + 1000325188, 831938878, 650030018, 457742667, 258382869, 55359579, + -147847679, -347788933, -541079146, -724454918, -894832674, -1049365889, + -1185484078, -1300945379, -1393867499, -1462752000, -1506525019, -1524534111, + -1516573574, -1482884349, -1424138055, -1341436489, -1236269034, -1110525776, + -966421500, -806481853, -633479129, -450426376, -260462875, -66851522, + 127097697, 318089971, 502889675, 678382853, 841616839, 989876013, + 1120699644, 1231929704, 1321767154, 1388773428, 1431909652, 1450532073, + 1444440429, 1413846257, 1359367356, 1282038972, 1183278349, 1064856624, + 928864074, 777700150, 614008311, 440608109, 260508254, 76791586, + -107397743, -288930379, -464730860, -631837850, -787440176, -928960132, + -1054050908, -1160662595, -1247065451, -1311883567, -1354123178, -1373165346, + -1368802620, -1341217886, -1290981329, -1219063811, -1126791045, -1015827089, + -888150371, -746008746, -591888502, -428466615, -258572737, -85123526, + 88914651, 260589405, 426977848, 585294445, 732875277, 867275801, + 986273147, 1087921573, 1170581642, 1232944255, 1274053918, 1293320897, + 1290533012, 1265841361, 1219785598, 1153259730, 1067496103, 964053892, + 844793457, 711808351, 567446758, 414212914, 254760236, 91832935, + -71784776, -233305320, -389993434, -539216020, -678471866, -805456788, + -918066920, -1014479691, -1093137391, -1152807458, -1192573206, -1211874921, + -1210490051, -1188568015, -1146583692, -1085373537, -1006089058, -910161528, + -799331029, -675561646, -541023592, -398076238, -249186890, -96927127, + 56101333, 207288357, 354082194, 494010022, 624734728, 744083114, + 850106912, 941064500, 1015518034, 1072287608, 1110518956, 1129673954, + 1129534807, 1110224999, 1072183624, 1016175030, 943253900, 854764740, + 752304975, 637704638, 512982470, 380314468, 242013120, 100454613, + -41930954, -182719906, -319522396, -450050709, -572124797, -683715081, + -783002819, -868369891, -938459121, -992172259, -1028703484, -1047537853, + -1048477454, -1031613185, -997345311, -946374992, -879676080, -798477569, + -704258873, -598700531, -483679417, -361196098, -233396476, -102482455, + 29308002, 159719299, 286554702, 407677229, 521069555, 624855049, + 717336577, 797022777, 862641869, 913174983, 947866087, 966234173, + 968080713, 953484175, 922811838, 876683918, 816003691, 741894095, + 655709798, 559004050, 453483583, 341011967, 223540020, 103099760, + -18233260, -138395689, -255355128, -367156398, -471920516, -567930301, + -653616510, -727591722, -788690875, -835956443, -868701664, -886467574, + -889061508, -876552359, -849257612, -807750695, -752853186, -685576819, + -607171911, -519042242, -422762779, -320026739, -212630774, -102428770, + 8682967, 118812009, 226087388, 328720449, 424999500, 513333030, + 592286422, 660577795, 717148715, 761115072, 791827347, 808872127, + 812061714, 801441574, 777310902, 740181390, 690785229, 630053428, + 559110814, 479238032, 391861521, 298534506, 200878658, 100590430, + -607287, -100989423, -198849315, -292555237, -380548523, -461371351, + -533713558, -596424172, -648498641, -689151697, -717782049, -734005256, + -737643908, -728733948, -707537411, -674510484, -630317318, -575800816, + -511961435, -439971506, -361118572, -276793246, -188485832, -97722445, + -6061637, 84927343, 173708384, 258790208, 338756360, 412298791, + 478220506, 535463826, 583135683, 620504631, 647031770, 662348437, + 666300618, 658915978, 640416389, 611220585, 571908297, 523234948, + 466117071, 401592604, 330825586, 255073642, 175660907, 93972958, + 11416894, -70596785, -150687862, -227501411, -299770818, -366304718, + -426033185, -477990740, -521373453, -555521652, -579935619, -594295837, + -598441014, -592403331, -576366581, -550704622, -515936356, -472738946, + -421926566, -364421956, -301273613, -233600973, -162593440, -89496920, + -15564081, 57945801, 129777276, 198735962, 263673192, 323522023, + 377324214, 424207890, 463459128, 494471178, 516806828, 530161704, + 534390205, 529525253, 515722595, 493310268, 462743131, 424629406, + 379680615, 328731908, 272704910, 212598522, 149476632, 84436692, + 18611043, -46890106, -110946726, -172490471, -230497005, -284018193, + -332193404, -374253518, -409544375, -437542950, -457836446, -470163396, + -474396436, -470538010, -458741499, -439285478, -412576250, -379140208, + -339618079, -294740527, -245328608, -192258120, -136474880, -78950323, + -20684043, 37337800, 94123822, 148719315, 200232263, 247809979, + 290690028, 328191762, 359737003, 384846037, 403167797, 414462578, + 418612328, 415616471, 405608074, 388824822, 365627908, 336478576, + 301938852, 262645553, 219323761, 172742000, 123743307, 73167648, + 21900080, -29183756, -79218352, -127364108, -172827967, -214863012, + -252796088, -286026643, -314042942, -336429977, -352864310, -363132718, + -367129059, -364863616, -356429040, -342048284, -322028244, -296774094, + -266768316, -232579633, -194825815, -154197159, -111415846, -67221548, + -22393396, 22309840, 66124542, 108316468, 148196551, 185105519, + 218455448, 247719513, 272444601, 292265988, 306909294, 316172902, + 319976012, 318306257, 311259813, 299016336, 281847408, 260104006, + 234201035, 204634435, 171943983, 136726029, 99607937, 61229245, + 22277383, -16592151, -54723400, -91468534, -126228236, -158430959, + -187562953, -213164354, -234846478, -252284778, -265235499, -273534395, + -277099121, -275918277, -270073506, -259721509, -245096765, -226492670, + -204280869, -178875510, -150747495, -120413922, -88411837, -55306424, + -21669900, 11917494, 44880837, 76678439, 106778103, 134689892, + 159972738, 182223956, 201108612, 216348810, 227726051, 235104451, + 238398771, 237610161, 232803839, 224116370, 211735335, 195925346, + 176994801, 155311385, 131268473, 105311188, 77899862, 49524551, + 20673231, -8152563, -36466660, -63795119, -89689631, -113724103, + -135516162, -154729334, -171063592, -184287496, -194214077, -200713055, + -203732664, -203253125, -199335834, -192088497, -181685639, -168336364, + -152320108, -133926606, -113516594, -91451969, -68135088, -43975393, + -19395029, 5179829, 29338263, 52667285, 74792697, 95346363, + 114000498, 130472557, 144507874, 155901496, 164498743, 170184919, + 172911765, 172668424, 169499571, 163505275, 154819428, 143630524, + 130166712, 114681138, 97470938, 78844567, 59142464, 38718237, + 17918794, -2890238, -23353533, -43135381, -61900242, -79354061, + -95218074, -109237355, -121211123, -130960785, -138345116, -143280745, + -145714419, -145646556, -143111878, -138189432, -130990829, -121678718, + -110439552, -97488855, -83077526, -67467936, -50938253, -33790970, + -16323372, 1170024, 18382855, 35032469, 50844610, 65556934, + 78945328, 90799046, 100930128, 109201569, 115507170, 119753539, + 121907093, 121964702, 119952242, 115936776, 110019754, 102325119, + 93008244, 82261389, 70284961, 57293131, 43529865, 29234651, + 14669782, 72779, -14296826, -28212097, -41430023, -53743152, + -64955789, -74894358, -83414010, -90383998, -95716201, -99336816, + -101228066, -101364256, -99783104, -96540755, -91706720, -85398404, + -77736086, -68883213, -58999854, -48272828, -36895247, -25073075, + -13017290, -929976, 10982581, 22515118, 33483816, 43708142, + 53031199, 61303563, 68404150, 74229401, 78705238, 81769841, + 83400870, 83592764, 82367919, 79764133, 75845584, 70713662, + 64463816, 57222981, 49132592, 40343881, 31010088, 21309507, + 11408987, 1476574, -8313780, -17805847, -26834606, -35257362, + -42940370, -49768901, -55642345, -60471386, -64198025, -66767863, + -68164088, -68386583, -67440978, -65373000, -62227670, -58079637, + -53020760, -47150844, -40578759, -33434938, -25844740, -17946248, + -9882139, -1783854, 6202175, 13941288, 21315238, 28196425, + 34483059, 40077359, 44886111, 48859936, 51928205, 54068948, + 55255999, 55479035, 54764175, 53128559, 50625402, 47303227, + 43241873, 38519687, 33230138, 27466783, 21346265, 14970247, + 8455675, 1911983, -4545824, -10812044, -16774603, -22355449, + -27449074, -31989201, -35898928, -39137158, -41646925, -43408685, + -44400739, -44620314, -44085374, -42807115, -40826602, -38193991, + -34964509, -31193892, -26972036, -22367527, -17466953, -12367218, + -7146262, -1904869, 3267821, 8291041, 13080466, 17561039, + 21651499, 25306067, 28460581, 31066869, 33106592, 34537018, + 35360504, 35569033, 35167687, 34177966, 32634704, 30560883, + 28009270, 25036520, 21689186, 18040253, 14161727, 10113724, + 5974160, 1812535, -2298571, -6293363, -10098147, -13659222, + -16921043, -19827946, -22345389, -24432435, -26066901, -27223379, + -27898523, -28085752, -27792084, -27035106, -25834265, -24220063, + -22225270, -19894969, -17274748, -14414396, -11365505, -8185495, + -4931060, -1659560, 1575182, 4715237, 7711549, 10523077, + 13090914, 15387506, 17376138, 19029662, 20325401, 21250905, + 21795069, 21961365, 21753118, 21177274, 20250113, 19008061, + 17460596, 15654912, 13623473, 11397730, 9025297, 6557050, + 4019253, 1474121, -1045141, -3489662, -5831327, -8019809, + -10026099, -11818538, -13371276, -14669502, -15687477, -16419232, + -16856866, -16994403, -16845308, -16412914, -15714736, -14760202, + -13578426, -12191116, -10629600, -8921647, -7092202, -5190448, + -3239217, -1275934, 663046, 2554298, 4356076, 6044040, + 7594214, 8980359, 10182478, 11188168, 11974521, 12546254, + 12895773, 13014200, 12908086, 12587362, 12058446, 11338623, + 10439693, 9387813, 8201196, 6899320, 5509481, 4064219, + 2576865, 1080047, -400703, -1839939, -3214850, -4504065, + -5687108, -6747572, -7663672, -8435009, -9043227, -9484985, + -9753642, -9849076, -9779353, -9541923, -9151368, -8610339, + -7937707, -7149141, -6254080, -5276073, -4231361, -3138920, + -2020649, -894056, 222733, 1305993, 2340866, 3311888, + 4207117, 5005958, 5703280, 6283490, 6745544, 7082468, + 7287202, 7363976, 7317850, 7144786, 6853114, 6459652, + 5959086, 5371726, 4711175, 3985262, 3204339, 2395324, + 1564483, 723119, -105777, -909733, -1683889, -2405419, + -3074924, -3671133, -4188416, -4623151, -4966669, -5217822, + -5376505, -5438699, -5406246, -5282262, -5074698, -4786421, + -4415698, -3989649, -3503458, -2971553, -2398392, -1804213, + -1193619, -576390, 32462, 628385, 1194781, 1727140, + 2213574, 2652369, 3033564, 3352595, 3609052, 3797641, + 3911246, 3962598, 3939600, 3852699, 3701594, 3492114, + 3230424, 2916926, 2563901, 2181899, 1765468, 1336348, + 897255, 451524, 10400, -423355, -833387, -1217639, + -1571274, -1889254, -2165240, -2398526, -2581778, -2722473, + -2806177, -2843650, -2829585, -2769524, -2663939, -2516691, + -2327935, -2105389, -1854132, -1579438, -1284757, -976868, + -663162, -345625, -29806, 277631, 573265, 848377, + 1098155, 1323542, 1523169, 1692667, 1820388, 1921574, + 1980041, 2009485, 2000458, 1958506, 1882804, 1781576, + 1650184, 1491210, 1315288, 1123764, 920326, 700329, + 478507, 256533, 32026, -180003, -384095, -577687, + -756750, -917410, -1053764, -1170111, -1262779, -1332577, + -1375847, -1391609, -1392675, -1362480, -1311761, -1240430, + -1148291, -1039811, -917895, -784334, -643710, -496828, + -337593, -185408, -35103, 113070, 255859, 384329, + 506227, 617511, 714746, 795605, 860777, 906972, + 935925, 948904, 945758, 926027, 895773, 846226, + 784240, 710311, 628903, 537754, 444898, 341692, + 241505, 133447, 30958, -72515, -164395, -255320, + -334239, -410321, -475067, -526756, -573940, -605247, + -622819, -637482, -631446, -619838, -596390, -563572, + -523754, -477660, -426306, -363560, -295189, -230207, + -163718, -95093, -25083, 39224, 104809, 164493, + 216339, 268715, 307770, 343381, 376591, 393894, + 409214, 415048, 414650, 407176, 388288, 370122, + 344328, 309042, 277273, 235390, 198767, 149968, + 107391, 64774, 22734, -22484, -65777, -100024, + -134431, -168338, -196571, -218070, -239916, -252287, + -260207, -264251, -263475, -255361, -249920, -233428, + -219729, -200561, -178348, -152486, -126879, -98039, + -68509, -40108, -12510, 10116, 37364, 62735, + 83265, 105535, 122744, 134992, 146756, 157803, + 160999, 161373, 164013, 160462, 154774, 144884, + 134790, 126783, 107178, 92058, 76572, 57882, + 43557, 26865, 12612, -4122, -19611, -34312, + -50182, -64020, -71989, -80713, -88451, -93341, + -97703, -97951, -98271, -96134, -93821, -85291, + -81741, -74008, -66399, -57833, -47278, -35028, + -26476, -14656, -4700, 3292, 15438, 21244, + 29516, 33116, 42333, 47158, 49673, 56057, + 53914, 56647, 58612, 53778, 50181, 53182, + 46382, 38717, 37541, 30440, 26852, 21271, + 13076, 9386, 4881, -3217, -6456, -9167, + -14339, -21479, -24043, -24056, -31348, -29829, + -29018, -30209, -31831, -31798, -28027, -29569, + -25967, -24517, -21618, -18204, -15378, -12502, + -9278, -7266, -3404, 3091, 4309, 6623, + 9973, 9739, 10030, 12920, 16929, 18390, + 15259, 16991, 14629, 15567, 17209, 11571, + 14371, 12597, 11641, 9273, 6978, 8908, + 3725, -56, 2695, -189, -624, -3726, + -4651, -5443, -6305, -5793, -8874, -6473, + -7155, -7928, -4337, -5197, -10879, -8256, + -9328, -5819, -4801, -1061, -4140, -2848, + -5058, 450, 134, -988, -2654, -529, + 1305, -1503, 1327, 2653, 2727, 3765, + 1663, 2376, 5098, 3599, 2627, 4534, + 1709, 4472, 1626, 4200, -688, 1716, + 455, 2684, -1687, -2322, 540, 278, + 2327, 931, -1176, -108, -3519, -317, + -1225, -1108, -971, -844, -2534, -1462, + -554, -41, -29, -263, -2482, 614, + -2090, 576, -2654, -2080, 656, 174, + -297, -1757, 738, -493, 1359, 229, + 934, -956, -1365, -707, 3858, 1771, + 799, -1000, -779, -93, -1114, 804, + -1730, -1932, -731, 1052, 108, -1784, + -1167, -1073, 2003, 441, -543, -445, + -1474, 253, -2753, 1985, -2835, 1736, +}; + +static const int32_t ifft_ref_imag_3072_q31[3072] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +}; diff --git a/test/cmocka/src/math/matrix/matrix.c b/test/cmocka/src/math/matrix/matrix.c index 66200bc3e632..63632ba58c4b 100644 --- a/test/cmocka/src/math/matrix/matrix.c +++ b/test/cmocka/src/math/matrix/matrix.c @@ -4,6 +4,7 @@ // // Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> +#include <sof/audio/module_adapter/module/generic.h> #include <errno.h> #include <stdlib.h> #include <stdio.h> @@ -23,6 +24,8 @@ #define MATRIX_MULT_16_MAX_ERROR_ABS 1.5 #define MATRIX_MULT_16_MAX_ERROR_RMS 0.5 +struct processing_module dummy; + static void matrix_mult_16_test(const int16_t *a_ref, const int16_t *b_ref, const int16_t *c_ref, int elementwise, int a_rows, int a_columns, int b_rows, int b_columns, int c_rows, int c_columns, @@ -38,20 +41,20 @@ static void matrix_mult_16_test(const int16_t *a_ref, const int16_t *b_ref, cons int16_t x; int i, j, k; - a_matrix = mat_matrix_alloc_16b(a_rows, a_columns, a_frac); + a_matrix = mod_mat_matrix_alloc_16b(&dummy, a_rows, a_columns, a_frac); if (!a_matrix) exit(EXIT_FAILURE); - b_matrix = mat_matrix_alloc_16b(b_rows, b_columns, b_frac); + b_matrix = mod_mat_matrix_alloc_16b(&dummy, b_rows, b_columns, b_frac); if (!b_matrix) { - free(a_matrix); + mod_free(&dummy, a_matrix); exit(EXIT_FAILURE); } - c_matrix = mat_matrix_alloc_16b(c_rows, c_columns, c_frac); + c_matrix = mod_mat_matrix_alloc_16b(&dummy, c_rows, c_columns, c_frac); if (!c_matrix) { - free(a_matrix); - free(b_matrix); + mod_free(&dummy, a_matrix); + mod_free(&dummy, b_matrix); exit(EXIT_FAILURE); } @@ -83,6 +86,10 @@ static void matrix_mult_16_test(const int16_t *a_ref, const int16_t *b_ref, cons assert_true(error_rms < MATRIX_MULT_16_MAX_ERROR_RMS); assert_true(delta_max < MATRIX_MULT_16_MAX_ERROR_ABS); + + mod_free(&dummy, a_matrix); + mod_free(&dummy, b_matrix); + mod_free(&dummy, c_matrix); } static void test_matrix_mult_16_test1(void **state) diff --git a/test/cmocka/src/math/numbers/CMakeLists.txt b/test/cmocka/src/math/numbers/CMakeLists.txt deleted file mode 100644 index 7a8c71670daf..000000000000 --- a/test/cmocka/src/math/numbers/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -cmocka_test(gcd - gcd.c - ${PROJECT_SOURCE_DIR}/src/math/numbers.c -) - -cmocka_test(ceil_divide - ceil_divide.c - ${PROJECT_SOURCE_DIR}/src/math/numbers.c -) -target_link_libraries(ceil_divide PRIVATE -lm) - -cmocka_test(find_equal_int16 - find_equal_int16.c - ${PROJECT_SOURCE_DIR}/src/math/numbers.c -) - -cmocka_test(find_min_int16 - find_min_int16.c - ${PROJECT_SOURCE_DIR}/src/math/numbers.c -) - -cmocka_test(find_max_abs_int32 - find_max_abs_int32.c - ${PROJECT_SOURCE_DIR}/src/math/numbers.c -) - -cmocka_test(norm_int32 - norm_int32.c - ${PROJECT_SOURCE_DIR}/src/math/numbers.c -) diff --git a/test/cmocka/src/math/numbers/ceil_divide.c b/test/cmocka/src/math/numbers/ceil_divide.c deleted file mode 100644 index 578df9b281b3..000000000000 --- a/test/cmocka/src/math/numbers/ceil_divide.c +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> - -#include <sof/math/numbers.h> - -#include <stdio.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <stdint.h> -#include <cmocka.h> - -static void test_math_numbers_ceil_divide(void **state) -{ - (void)state; - - int params[8] = { - -1000, - 300, - 123, - -10, - 1337, - -6, - 999, - -2 - }; - - int i, j; - - for (i = 0; i < 8; ++i) { - for (j = 0; j < 8; ++j) { - int ref = ceilf((float)params[i] / (float)params[j]); - int r = ceil_divide(params[i], params[j]); - - if (r != ref) { - printf("%s: %d / %d = %d (ref: %d)\n", __func__, - params[i], params[j], r, ref); - } - - assert_int_equal(r, ref); - } - } - -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_numbers_ceil_divide) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/numbers/find_equal_int16.c b/test/cmocka/src/math/numbers/find_equal_int16.c deleted file mode 100644 index fc202f50f75b..000000000000 --- a/test/cmocka/src/math/numbers/find_equal_int16.c +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> - -#include <sof/math/numbers.h> - -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -static void test_math_numbers_find_equal_int16_for_5_123_5_10_123_500_123_n_123_equals_1_4_and_6 - (void **state) -{ - (void)state; - - int16_t r[4]; - int16_t vec[] = {5, 123, 5, 10, 123, 500, 123}; - int16_t template[] = {1, 4, 6}; - - int r_num = find_equal_int16(r, vec, 123, 7, 4); - - assert_int_equal(r_num, 3); - assert_memory_equal(r, template, sizeof(int16_t) * 3); -} - -static void test_math_numbers_find_equal_int16_for_1_2_3_4_5_n_0_equals_nothing - (void **state) -{ - (void)state; - - int16_t r[4]; - int16_t vec[] = {1, 2, 3, 4, 5}; - - int r_num = find_equal_int16(r, vec, 0, 5, 4); - - assert_int_equal(r_num, 0); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test - (test_math_numbers_find_equal_int16_for_5_123_5_10_123_500_123_n_123_equals_1_4_and_6), - cmocka_unit_test - (test_math_numbers_find_equal_int16_for_1_2_3_4_5_n_0_equals_nothing) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/numbers/find_max_abs_int32.c b/test/cmocka/src/math/numbers/find_max_abs_int32.c deleted file mode 100644 index aa669887dcab..000000000000 --- a/test/cmocka/src/math/numbers/find_max_abs_int32.c +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> - -#include <sof/math/numbers.h> -#include <sof/common.h> - -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -static void test_math_numbers_find_max_abs_int32_for_neg100_99_98_50_equals_100 - (void **state) -{ - (void)state; - - int32_t vec[] = {-100, 99, 98, 50}; - int r = find_max_abs_int32(vec, ARRAY_SIZE(vec)); - - assert_int_equal(r, 100); -} - -static void test_math_numbers_find_max_abs_int32_for_neg100_99_98_50_101_equals_101 - (void **state) -{ - (void)state; - - int32_t vec[] = {-100, 99, 98, 50, 101}; - int r = find_max_abs_int32(vec, ARRAY_SIZE(vec)); - - assert_int_equal(r, 101); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test - (test_math_numbers_find_max_abs_int32_for_neg100_99_98_50_equals_100), - cmocka_unit_test - (test_math_numbers_find_max_abs_int32_for_neg100_99_98_50_101_equals_101) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/numbers/find_min_int16.c b/test/cmocka/src/math/numbers/find_min_int16.c deleted file mode 100644 index 919898fe5710..000000000000 --- a/test/cmocka/src/math/numbers/find_min_int16.c +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> - -#include <sof/math/numbers.h> -#include <sof/common.h> - -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -static void test_math_numbers_find_min_int16_for_2_equals_2(void **state) -{ - (void)state; - - int16_t vec[] = {2}; - int r = find_min_int16(vec, ARRAY_SIZE(vec)); - - assert_int_equal(r, 2); -} - -static void test_math_numbers_find_min_int16_for_5_2_3_4_1_equals_1 - (void **state) -{ - (void)state; - - int16_t vec[] = {5, 2, 3, 4, 1}; - int r = find_min_int16(vec, ARRAY_SIZE(vec)); - - assert_int_equal(r, 1); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test - (test_math_numbers_find_min_int16_for_2_equals_2), - cmocka_unit_test - (test_math_numbers_find_min_int16_for_5_2_3_4_1_equals_1) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/numbers/gcd.c b/test/cmocka/src/math/numbers/gcd.c deleted file mode 100644 index 23f2dad2191a..000000000000 --- a/test/cmocka/src/math/numbers/gcd.c +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Marcin Maka <marcin.maka@linux.intel.com> -// Janusz Jankowski <janusz.jankowski@linux.intel.com> - -#include <sof/math/numbers.h> - -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -static void test_math_numbers_gcd_for_5083_and_391_equals_391(void **state) -{ - int r; - - (void)state; - - r = gcd(5083, 391); - assert_int_equal(r, 391); -} - -static void test_math_numbers_gcd_for_12_and_9_equals_3(void **state) -{ - int r; - - (void)state; - - r = gcd(12, 9); - assert_int_equal(r, 3); -} - -static void test_math_numbers_gcd_for_5_and_0_equals_5(void **state) -{ - int r; - - (void)state; - - r = gcd(5, 0); - assert_int_equal(r, 5); -} - -static void test_math_numbers_gcd_for_0_and_5_equals_5(void **state) -{ - int r; - - (void)state; - - r = gcd(0, 5); - assert_int_equal(r, 5); -} - -static void test_math_numbers_gcd_for_0_and_0_equals_0(void **state) -{ - int r; - - (void)state; - - r = gcd(0, 0); - assert_int_equal(r, 0); -} - -static void test_math_numbers_gcd_for_neg_4_and_14_equals_2(void **state) -{ - int r; - - (void)state; - - r = gcd(-4, 14); - assert_int_equal(r, 2); -} - -static void test_math_numbers_gcd_for_4_and_neg_14_equals_2(void **state) -{ - int r; - - (void)state; - - r = gcd(4, -14); - assert_int_equal(r, 2); -} - -static void test_math_numbers_gcd_for_neg_4_and_neg_14_equals_2(void **state) -{ - int r; - - (void)state; - - r = gcd(-4, -14); - assert_int_equal(r, 2); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test - (test_math_numbers_gcd_for_5083_and_391_equals_391), - cmocka_unit_test(test_math_numbers_gcd_for_12_and_9_equals_3), - cmocka_unit_test(test_math_numbers_gcd_for_5_and_0_equals_5), - cmocka_unit_test(test_math_numbers_gcd_for_0_and_5_equals_5), - cmocka_unit_test(test_math_numbers_gcd_for_0_and_0_equals_0), - cmocka_unit_test - (test_math_numbers_gcd_for_neg_4_and_14_equals_2), - cmocka_unit_test - (test_math_numbers_gcd_for_4_and_neg_14_equals_2), - cmocka_unit_test - (test_math_numbers_gcd_for_neg_4_and_neg_14_equals_2) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/numbers/norm_int32.c b/test/cmocka/src/math/numbers/norm_int32.c deleted file mode 100644 index 7397d2359c7a..000000000000 --- a/test/cmocka/src/math/numbers/norm_int32.c +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> - -#include <sof/math/numbers.h> - -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -static void test_math_numbers_norm_int32_for_0_equals_31(void **state) -{ - (void)state; - - int r = norm_int32(0); - - assert_int_equal(r, 31); -} - -static void test_math_numbers_norm_int32_for_35_equals_10(void **state) -{ - (void)state; - - int r = norm_int32(35); - - assert_int_equal(r, 25); -} - -static void test_math_numbers_norm_int32_for_2147483647_equals_0(void **state) -{ - (void)state; - - int r = norm_int32(2147483647); - - assert_int_equal(r, 0); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_numbers_norm_int32_for_0_equals_31), - cmocka_unit_test - (test_math_numbers_norm_int32_for_35_equals_10), - cmocka_unit_test - (test_math_numbers_norm_int32_for_2147483647_equals_0) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/trig/CMakeLists.txt b/test/cmocka/src/math/trig/CMakeLists.txt deleted file mode 100644 index 2d39eecd27b0..000000000000 --- a/test/cmocka/src/math/trig/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause - -cmocka_test(sin_32b_fixed - sin_32b_fixed.c - ${PROJECT_SOURCE_DIR}/src/math/trig.c -) - -cmocka_test(cos_32b_fixed - cos_32b_fixed.c - ${PROJECT_SOURCE_DIR}/src/math/trig.c -) - -cmocka_test(sin_16b_fixed - sin_16b_fixed.c - ${PROJECT_SOURCE_DIR}/src/math/trig.c -) - -cmocka_test(cos_16b_fixed - cos_16b_fixed.c - ${PROJECT_SOURCE_DIR}/src/math/trig.c -) - -cmocka_test(asin_32b_fixed - asin_32b_fixed.c - ${PROJECT_SOURCE_DIR}/src/math/trig.c -) - -cmocka_test(acos_32b_fixed - acos_32b_fixed.c - ${PROJECT_SOURCE_DIR}/src/math/trig.c -) - -cmocka_test(asin_16b_fixed - asin_16b_fixed.c - ${PROJECT_SOURCE_DIR}/src/math/trig.c -) - -cmocka_test(acos_16b_fixed - acos_16b_fixed.c - ${PROJECT_SOURCE_DIR}/src/math/trig.c -) - -cmocka_test(lut_sin_16b_fixed - lut_sin_16b_fixed.c - ${PROJECT_SOURCE_DIR}/src/math/lut_trig.c -) diff --git a/test/cmocka/src/math/trig/acos_16b_fixed.c b/test/cmocka/src/math/trig/acos_16b_fixed.c deleted file mode 100644 index b0454b104dd9..000000000000 --- a/test/cmocka/src/math/trig/acos_16b_fixed.c +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> -// - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> - -#include <sof/audio/format.h> -#include <sof/math/trig.h> -#include <sof/common.h> -#include "trig_tables.h" -/* ' Error (max = 0.000059799232976), THD+N = -89.824298401466635 (dBc)' */ -#define CMP_TOLERANCE 0.0001196862 -#define _M_PI 3.14159265358979323846 /* pi */ - -static void test_math_trig_acos_16b_fixed(void **state) -{ - (void)state; - double u; - double v; - int indx; - int b_i; - - for (indx = 0; indx < ARRAY_SIZE(degree_table); ++indx) { - /* convert angle unit degrees to radians */ - /* angleInRadians = pi/180 * angleInDegrees & const Q2.30 format */ - u = (0.017453292519943295 * (double)degree_table[indx] * 0x40000000); - v = fabs(u); - /* GitHub macro Q_CONVERT_FLOAT is inaccurate, so replaced with below */ - u = (v >= 0.5) ? floor(u + 0.5) : 0.0; - b_i = (int)u; - - float r = Q_CONVERT_QTOF(acos_fixed_16b(b_i), 13); - float diff = fabsf(acos_ref_table[indx] - r); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %.16f deg = %.10f\n", __func__, - ((180 / _M_PI) * b_i) / (1 << 30), diff); - } - - assert_true(diff <= CMP_TOLERANCE); - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_trig_acos_16b_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/trig/acos_32b_fixed.c b/test/cmocka/src/math/trig/acos_32b_fixed.c deleted file mode 100644 index 01c7a754ba75..000000000000 --- a/test/cmocka/src/math/trig/acos_32b_fixed.c +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> -// - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> - -#include <sof/audio/format.h> -#include <sof/math/trig.h> -#include <sof/common.h> -#include "trig_tables.h" -/* 'Error (max = 0.000000026077032), THD+N = -157.948952635422842 (dBc)' */ -#define CMP_TOLERANCE 0.000000060077032 -#define _M_PI 3.14159265358979323846 /* pi */ - -static void test_math_trig_acos_32b_fixed(void **state) -{ - (void)state; - double u; - double v; - int indx; - int b_i; - - for (indx = 0; indx < ARRAY_SIZE(degree_table); ++indx) { - /* convert angle unit degrees to radians */ - /* angleInRadians = pi/180 * angleInDegrees & const Q2.30 format */ - u = (0.017453292519943295 * (double)degree_table[indx] * 0x40000000); - v = fabs(u); - /* GitHub macro Q_CONVERT_FLOAT is inaccurate, so replaced with below */ - u = (v >= 0.5) ? floor(u + 0.5) : 0.0; - b_i = (int)u; - - float r = Q_CONVERT_QTOF(acos_fixed_32b(b_i), 29); - float diff = fabsf(acos_ref_table[indx] - r); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %.16f deg = %.10f\n", __func__, - ((180 / _M_PI) * b_i) / (1 << 30), diff); - } - - assert_true(diff <= CMP_TOLERANCE); - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_trig_acos_32b_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/trig/asin_16b_fixed.c b/test/cmocka/src/math/trig/asin_16b_fixed.c deleted file mode 100644 index 8361c8aa5858..000000000000 --- a/test/cmocka/src/math/trig/asin_16b_fixed.c +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> - -#include <sof/audio/format.h> -#include <sof/math/trig.h> -#include <sof/common.h> -#include "trig_tables.h" -/* 'Error (max = 0.000059799232976), THD+N = -89.824298401466635 (dBc) */ -#define CMP_TOLERANCE 0.0001152158 -#define _M_PI 3.14159265358979323846 /* pi */ - -static void test_math_trig_asin_16b_fixed(void **state) -{ - (void)state; - - double u; - double v; - int indx; - int b_i; - - for (indx = 0; indx < ARRAY_SIZE(degree_table); ++indx) { - /* convert angle unit degrees to radians */ - /* angleInRadians = pi/180 * angleInDegrees & const Q2.30 format */ - u = (0.017453292519943295 * (double)degree_table[indx] * 0x40000000); - v = fabs(u); - /* GitHub macro Q_CONVERT_FLOAT is inaccurate, so replaced with below */ - u = (v >= 0.5) ? floor(u + 0.5) : 0.0; - b_i = (int)u; - - float r = Q_CONVERT_QTOF(asin_fixed_16b(b_i), 13); - float diff = fabsf(asin_ref_table[indx] - r); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %.16f deg = %.10f\n", __func__, - ((180 / _M_PI) * b_i) / (1 << 30), diff); - } - - assert_true(diff <= CMP_TOLERANCE); - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_trig_asin_16b_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/trig/asin_32b_fixed.c b/test/cmocka/src/math/trig/asin_32b_fixed.c deleted file mode 100644 index f830711a9761..000000000000 --- a/test/cmocka/src/math/trig/asin_32b_fixed.c +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> - -#include <sof/audio/format.h> -#include <sof/math/trig.h> -#include <sof/common.h> -#include "trig_tables.h" -/* 'Error (max = 0.000000027939677), THD+N = -157.454534077921551 (dBc)' */ -#define CMP_TOLERANCE 0.000000068141916 -#define _M_PI 3.14159265358979323846 /* pi */ - -static void test_math_trig_asin_32b_fixed(void **state) -{ - (void)state; - - double u; - double v; - int indx; - int b_i; - - for (indx = 0; indx < ARRAY_SIZE(degree_table); ++indx) { - /* convert angle unit degrees to radians */ - /* angleInRadians = pi/180 * angleInDegrees & const Q2.30 format */ - u = (0.017453292519943295 * (double)degree_table[indx] * 0x40000000); - v = fabs(u); - /* GitHub macro Q_CONVERT_FLOAT is inaccurate, so replaced with below */ - u = (v >= 0.5) ? floor(u + 0.5) : 0.0; - b_i = (int)u; - - float r = Q_CONVERT_QTOF(asin_fixed_32b(b_i), 29); - float diff = fabsf(asin_ref_table[indx] - r); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %.16f deg = %.10f\n", __func__, - ((180 / _M_PI) * b_i) / (1 << 30), diff); - } - - assert_true(diff <= CMP_TOLERANCE); - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_trig_asin_32b_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/trig/cos_16b_fixed.c b/test/cmocka/src/math/trig/cos_16b_fixed.c deleted file mode 100644 index 2049a03c23f8..000000000000 --- a/test/cmocka/src/math/trig/cos_16b_fixed.c +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> -// - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> - -#include <sof/audio/format.h> -#include <sof/math/trig.h> -#include "trig_tables.h" -/* 'Error (max = 0.000061), THD+N = -91.518584' */ -#define CMP_TOLERANCE 0.000065 -#define _M_PI 3.14159265358979323846 /* pi */ - -static void test_math_trig_cos_fixed(void **state) -{ - (void)state; - int theta; - - for (theta = 0; theta < 360; ++theta) { - double rad = _M_PI * (theta / 180.0); - int32_t rad_q28 = Q_CONVERT_FLOAT(rad, 28); - - float r = Q_CONVERT_QTOF(cos_fixed_16b(rad_q28), 15); - float diff = fabsf(cos_ref_table[theta] - r); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %d deg = %.10f\n", __func__, - theta, diff); - } - - assert_true(diff <= CMP_TOLERANCE); - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_trig_cos_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/trig/cos_32b_fixed.c b/test/cmocka/src/math/trig/cos_32b_fixed.c deleted file mode 100644 index d9c2282852dd..000000000000 --- a/test/cmocka/src/math/trig/cos_32b_fixed.c +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2021 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> -// - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> - -#include <sof/audio/format.h> -#include <sof/math/trig.h> -#include "trig_tables.h" -/* 'Error (max = 0.000000011175871), THD+N = -170.674358910916226' */ -#define CMP_TOLERANCE 0.0000000611175871 -#define _M_PI 3.14159265358979323846 /* pi */ - -static void test_math_trig_cos_fixed(void **state) -{ - (void)state; - int theta; - - for (theta = 0; theta < 360; ++theta) { - double rad = _M_PI * (theta / 180.0); - int32_t rad_q28 = Q_CONVERT_FLOAT(rad, 28); - - float r = Q_CONVERT_QTOF(cos_fixed_32b(rad_q28), 31); - float diff = fabsf(cos_ref_table[theta] - r); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %d deg = %.10f\n", __func__, - theta, diff); - } - - assert_true(diff <= CMP_TOLERANCE); - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_trig_cos_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/trig/lut_sin_16b_fixed.c b/test/cmocka/src/math/trig/lut_sin_16b_fixed.c deleted file mode 100644 index b95390022903..000000000000 --- a/test/cmocka/src/math/trig/lut_sin_16b_fixed.c +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2024 Intel Corporation. All rights reserved. -// -// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> -// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> - -#include <sof/audio/format.h> -#include <sof/math/lut_trig.h> - -#include "trig_tables.h" - -#define CMP_TOLERANCE 3.1e-5 -#define _M_PI 3.14159265358979323846 /* pi */ - -static void test_math_trig_lut_sin_fixed(void **state) -{ - (void)state; - - int theta; - - for (theta = 0; theta < 360; ++theta) { - double rad = _M_PI / 180.0 * theta; - int32_t rad_q28 = Q_CONVERT_FLOAT(rad, 28); - float r = Q_CONVERT_QTOF(sofm_lut_sin_fixed_16b(rad_q28), 15); - float diff = fabsf(sin_ref_table[theta] - r); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %d deg = %g\n", __func__, - theta, diff); - } - - assert_true(diff <= CMP_TOLERANCE); - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_trig_lut_sin_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/trig/sin_16b_fixed.c b/test/cmocka/src/math/trig/sin_16b_fixed.c deleted file mode 100644 index 47864c41d669..000000000000 --- a/test/cmocka/src/math/trig/sin_16b_fixed.c +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Shriram Shastry <malladi.sastry@linux.intel.com> - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> - -#include <sof/audio/format.h> -#include <sof/math/trig.h> -#include "trig_tables.h" -/* 'Error (max = 0.000061), THD+N = -91.502670' */ -#define CMP_TOLERANCE 0.000065 -#define _M_PI 3.14159265358979323846 /* pi */ - -static void test_math_trig_sin_fixed(void **state) -{ - (void)state; - - int theta; - - for (theta = 0; theta < 360; ++theta) { - double rad = _M_PI * (theta / 180.0); - int32_t rad_q28 = Q_CONVERT_FLOAT(rad, 28); - - float r = Q_CONVERT_QTOF(sin_fixed_16b(rad_q28), 15); - float diff = fabsf(sin_ref_table[theta] - r); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %d deg = %.10f\n", __func__, - theta, diff); - } - - assert_true(diff <= CMP_TOLERANCE); - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_trig_sin_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/trig/sin_32b_fixed.c b/test/cmocka/src/math/trig/sin_32b_fixed.c deleted file mode 100644 index 6db3ffcbc862..000000000000 --- a/test/cmocka/src/math/trig/sin_32b_fixed.c +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> - -#include <stdio.h> -#include <stdint.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <math.h> -#include <cmocka.h> - -#include <sof/audio/format.h> -#include <sof/math/trig.h> -#include "trig_tables.h" -/* 'Error (max = 0.000000011175871), THD+N = -170.152933168271659' */ -#define CMP_TOLERANCE 0.0000000611175871 -#define _M_PI 3.14159265358979323846 /* pi */ - -static void test_math_trig_sin_fixed(void **state) -{ - (void)state; - - int theta; - - for (theta = 0; theta < 360; ++theta) { - double rad = _M_PI * (theta / 180.0); - int32_t rad_q28 = Q_CONVERT_FLOAT(rad, 28); - - float r = Q_CONVERT_QTOF(sin_fixed_32b(rad_q28), 31); - float diff = fabsf(sin_ref_table[theta] - r); - - if (diff > CMP_TOLERANCE) { - printf("%s: diff for %d deg = %.10f\n", __func__, - theta, diff); - } - - assert_true(diff <= CMP_TOLERANCE); - } -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_math_trig_sin_fixed) - }; - - cmocka_set_message_output(CM_OUTPUT_TAP); - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/cmocka/src/math/window/window.c b/test/cmocka/src/math/window/window.c index 3e04c452f6bd..82e0f66a6bec 100644 --- a/test/cmocka/src/math/window/window.c +++ b/test/cmocka/src/math/window/window.c @@ -54,7 +54,7 @@ static float test_window(char *window_name, const int16_t *ref_win, int window_l if (!strcmp(window_name, "rectangular")) { win_rectangular_16b(win, window_length); } else if (!strcmp(window_name, "blackman")) { - win_blackman_16b(win, window_length, WIN_BLACKMAN_A0); + win_blackman_16b(win, window_length, WIN_BLACKMAN_A0_Q15); } else if (!strcmp(window_name, "hamming")) { win_hamming_16b(win, window_length); } else if (!strcmp(window_name, "povey")) { diff --git a/test/cmocka/src/notifier_mocks.c b/test/cmocka/src/notifier_mocks.c index 1b82028b9515..bfdb0d488ffe 100644 --- a/test/cmocka/src/notifier_mocks.c +++ b/test/cmocka/src/notifier_mocks.c @@ -58,7 +58,7 @@ int notifier_register(void *receiver, void *caller, enum notify_id type, if (type >= NOTIFIER_ID_COUNT) return -EINVAL; - handle = rzalloc(0, 0, 0, sizeof(struct callback_handle)); + handle = rzalloc(SOF_MEM_FLAG_USER, sizeof(struct callback_handle)); if (!handle) return -ENOMEM; diff --git a/test/cmocka/src/util.h b/test/cmocka/src/util.h index 5ef231ceba64..38561e81e42e 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, false); + struct comp_buffer *buffer = buffer_new(NULL, &desc, BUFFER_USAGE_NOT_SHARED); memset(buffer->stream.addr, 0, buffer_size); @@ -42,7 +42,7 @@ static inline struct comp_buffer *create_test_sink(struct comp_dev *dev, static inline void free_test_sink(struct comp_buffer *buffer) { - free(buffer->sink); + free(comp_buffer_get_sink_component(buffer)); buffer_free(buffer); } @@ -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, false); + struct comp_buffer *buffer = buffer_new(NULL, &desc, BUFFER_USAGE_NOT_SHARED); memset(buffer->stream.addr, 0, buffer_size); diff --git a/test/ztest/unit/common/alloc.c b/test/ztest/unit/common/alloc.c new file mode 100644 index 000000000000..d00dc3c7b831 --- /dev/null +++ b/test/ztest/unit/common/alloc.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright(c) 2026 Intel Corporation. All rights reserved. */ + +#include <zephyr/ztest.h> +#include <sof/common.h> + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +void *__wrap_rzalloc(uint32_t flags, size_t bytes) +{ + void *ret; + (void)flags; + + ret = malloc(bytes); + + zassert_not_null(ret, "Memory allocation should not fail"); + + memset(ret, 0, bytes); + + return ret; +} + +void __wrap_rfree(void *ptr) +{ + free(ptr); +} + +struct k_heap; +void *__wrap_sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, size_t alignment) +{ + void *ret; + + (void)flags; + (void)heap; + + if (alignment) + ret = aligned_alloc(alignment, ALIGN_UP(bytes, alignment)); + else + ret = malloc(bytes); + + zassert_not_null(ret, "Memory allocation should not fail"); + + return ret; +} + +void __wrap_sof_heap_free(struct k_heap *heap, void *ptr) +{ + (void)heap; + + free(ptr); +} + +struct k_heap *__wrap_sof_sys_heap_get(void) +{ + return NULL; +} diff --git a/test/ztest/unit/fast-get/CMakeLists.txt b/test/ztest/unit/fast-get/CMakeLists.txt new file mode 100644 index 000000000000..39b79142d8bd --- /dev/null +++ b/test/ztest/unit/fast-get/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(test_fast_get) + +set(SOF_ROOT "${PROJECT_SOURCE_DIR}/../../../..") + +# Include SOF CMake functions +include(${SOF_ROOT}/scripts/cmake/misc.cmake) + +target_include_directories(app PRIVATE + ${SOF_ROOT}/zephyr/include + ${SOF_ROOT}/src/include + ${SOF_ROOT}/src/platform/posix/include +) + +# Define SOF-specific configurations for unit testing +target_compile_definitions(app PRIVATE + -DCONFIG_ZEPHYR_POSIX=1 +) + +target_sources(app PRIVATE + test_fast_get_ztest.c + ${SOF_ROOT}/src/lib/objpool.c + ${SOF_ROOT}/zephyr/lib/fast-get.c + ${SOF_ROOT}/test/ztest/unit/common/alloc.c +) + +target_link_libraries(app PRIVATE "-Wl,--wrap=rzalloc,--wrap=rfree,--wrap=sof_heap_alloc,--wrap=sof_heap_free") + +# Add RELATIVE_FILE definitions for SOF trace functionality +sof_append_relative_path_definitions(app) diff --git a/test/ztest/unit/fast-get/prj.conf b/test/ztest/unit/fast-get/prj.conf new file mode 100644 index 000000000000..d34c7781cd0a --- /dev/null +++ b/test/ztest/unit/fast-get/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_SOF_FULL_ZEPHYR_APPLICATION=n diff --git a/test/ztest/unit/fast-get/test_fast_get_ztest.c b/test/ztest/unit/fast-get/test_fast_get_ztest.c new file mode 100644 index 000000000000..3022d80e5ab7 --- /dev/null +++ b/test/ztest/unit/fast-get/test_fast_get_ztest.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. + +#include <zephyr/ztest.h> +#include <sof/common.h> +#include <sof/lib/fast-get.h> +#include <stdlib.h> + +static const int testdata[33][100] = { + { + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 9, 0, + }, + { 2 }, + { 3 }, + { 4 }, + { 5 }, + { 6 }, + { 7 }, + { 8 }, + { 9 }, + { 10 }, + { 11 }, + { 12 }, + { 13 }, + { 14 }, + { 15 }, + { 16 }, + { 17 }, + { 18 }, + { 19 }, + { 20 }, + { 21 }, + { 23 }, + { 24 }, + { 25 }, + { 26 }, + { 27 }, + { 28 }, + { 29 }, + { 30 }, + { 31 }, + { 32 }, + { 33 }, +}; + +/** + * @brief Test basic fast_get and fast_put functionality + * + * Tests that fast_get can allocate memory for data and fast_put can free it. + * Verifies that the returned pointer is valid and data is correctly copied. + */ +ZTEST(fast_get_suite, test_simple_fast_get_put) +{ + const void *ret; + + ret = fast_get(NULL, testdata[0], sizeof(testdata[0])); + + zassert_not_null(ret, "fast_get should return valid pointer"); + zassert_mem_equal(ret, testdata[0], sizeof(testdata[0]), + "Returned data should match original data"); + + fast_put(NULL, NULL, ret); +} + +/** + * @brief Test fast_get size mismatch behavior + * + * Tests that fast_get returns NULL when requested size doesn't match + * previously allocated size for the same data pointer. + */ +ZTEST(fast_get_suite, test_fast_get_size_missmatch_test) +{ + const void *ret[2]; + + ret[0] = fast_get(NULL, testdata[0], sizeof(testdata[0])); + + zassert_not_null(ret[0], "First fast_get should succeed"); + zassert_mem_equal(ret[0], testdata[0], sizeof(testdata[0]), + "Returned data should match original data"); + + ret[1] = fast_get(NULL, testdata[0], sizeof(testdata[0]) + 1); + zassert_is_null(ret[1], "fast_get with different size should return NULL"); + + fast_put(NULL, NULL, ret[0]); +} + +/** + * @brief Test multiple fast_get and fast_put operations + * + * Tests that fast_get can handle more than 32 allocations and that + * all data is correctly stored and can be retrieved. + */ +ZTEST(fast_get_suite, test_over_32_fast_gets_and_puts) +{ + const void *copy[ARRAY_SIZE(testdata)]; + int i; + + for (i = 0; i < ARRAY_SIZE(copy); i++) + copy[i] = fast_get(NULL, testdata[i], sizeof(testdata[0])); + + for (i = 0; i < ARRAY_SIZE(copy); i++) + zassert_mem_equal(copy[i], testdata[i], sizeof(testdata[0]), + "Data at index %d should match original", i); + + for (i = 0; i < ARRAY_SIZE(copy); i++) + fast_put(NULL, NULL, copy[i]); +} + +/** + * @brief Test fast_get reference counting functionality + * + * Tests that fast_get implements proper reference counting - multiple + * fast_get calls for the same data should return the same pointer, + * and the data should remain valid until all references are released. + */ +ZTEST(fast_get_suite, test_fast_get_refcounting) +{ + const void *copy[2][ARRAY_SIZE(testdata)]; + int i; + + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + copy[0][i] = fast_get(NULL, testdata[i], sizeof(testdata[0])); + + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + copy[1][i] = fast_get(NULL, testdata[i], sizeof(testdata[0])); + + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + zassert_equal_ptr(copy[0][i], copy[1][i], + "Same data should return same pointer (refcounting)"); + + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + zassert_mem_equal(copy[0][i], testdata[i], sizeof(testdata[0]), + "Data should match original after multiple fast_get calls"); + + /* Release first set of references */ + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + fast_put(NULL, NULL, copy[0][i]); + + /* Data should still be valid through second set of references */ + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + zassert_mem_equal(copy[1][i], testdata[i], sizeof(testdata[0]), + "Data should remain valid after partial fast_put"); + + /* Release second set of references */ + for (i = 0; i < ARRAY_SIZE(copy[0]); i++) + fast_put(NULL, NULL, copy[1][i]); +} + +/** + * @brief Define and initialize the fast_get test suite + */ +ZTEST_SUITE(fast_get_suite, NULL, NULL, NULL, NULL, NULL); diff --git a/test/ztest/unit/fast-get/testcase.yaml b/test/ztest/unit/fast-get/testcase.yaml new file mode 100644 index 000000000000..e3648bfc4e5d --- /dev/null +++ b/test/ztest/unit/fast-get/testcase.yaml @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright(c) 2025 Intel Corporation. All rights reserved. +# +# These contents may have been developed with support from one or more Intel-operated +# generative artificial intelligence solutions. + +tests: + sof.unit.fast_get: + tags: fast_get memory cache + platform_allow: native_sim + integration_platforms: + - native_sim + build_only: false diff --git a/test/ztest/unit/list/CMakeLists.txt b/test/ztest/unit/list/CMakeLists.txt new file mode 100644 index 000000000000..a6ecea3a7ae1 --- /dev/null +++ b/test/ztest/unit/list/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(test_list) + +set(SOF_ROOT "${PROJECT_SOURCE_DIR}/../../../..") + +target_include_directories(app PRIVATE ${SOF_ROOT}/src/include) + +target_sources(app PRIVATE test_list_ztest.c) diff --git a/test/ztest/unit/list/prj.conf b/test/ztest/unit/list/prj.conf new file mode 100644 index 000000000000..d34c7781cd0a --- /dev/null +++ b/test/ztest/unit/list/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_SOF_FULL_ZEPHYR_APPLICATION=n diff --git a/test/ztest/unit/list/test_list_ztest.c b/test/ztest/unit/list/test_list_ztest.c new file mode 100644 index 000000000000..38dc72a3f9f5 --- /dev/null +++ b/test/ztest/unit/list/test_list_ztest.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. + +#include <zephyr/ztest.h> +#include <sof/list.h> + +/** + * @brief Test list_init functionality + * + * Tests that list.prev and list.next point to the list itself after initialization + */ +ZTEST(sof_list_suite, test_list_init) +{ + struct list_item list = {.prev = NULL, .next = NULL}; + + list_init(&list); + + /* Verify that prev and next pointers point to the list itself after initialization */ + zassert_equal(&list, list.prev, "list.prev should point to itself after list_init"); + zassert_equal(&list, list.next, "list.next should point to itself after list_init"); +} + +/** + * @brief Test list_is_empty functionality + * + * Tests that list_is_empty returns true for empty lists and false for non-empty lists + */ +ZTEST(sof_list_suite, test_list_is_empty) +{ + struct list_item list; + struct list_item item; + + /* Test when list is empty */ + list_init(&list); + zassert_true(list_is_empty(&list), "list_is_empty should return true for empty list"); + + /* Test when list is not empty */ + list_item_append(&item, &list); + zassert_false(list_is_empty(&list), "list_is_empty should return false for non-empty list"); +} + +/** + * @brief Test list_item_append functionality + * + * Tests that list_item_append correctly appends an item to the end of the list + */ +ZTEST(sof_list_suite, test_list_item_append) +{ + struct list_item head; + struct list_item item1; + struct list_item item2; + + /* Initialize list */ + list_init(&head); + + /* Append first item */ + list_item_append(&item1, &head); + zassert_equal(&item1, head.next, "head->next should point to item1"); + zassert_equal(&item1, head.prev, "head->prev should point to item1"); + zassert_equal(&head, item1.next, "item1->next should point to head"); + zassert_equal(&head, item1.prev, "item1->prev should point to head"); + + /* Append second item */ + list_item_append(&item2, &head); + zassert_equal(&item1, head.next, "head->next should still point to item1"); + zassert_equal(&item2, head.prev, "head->prev should now point to item2"); + zassert_equal(&item2, item1.next, "item1->next should now point to item2"); + zassert_equal(&head, item1.prev, "item1->prev should still point to head"); + zassert_equal(&head, item2.next, "item2->next should point to head"); + zassert_equal(&item1, item2.prev, "item2->prev should point to item1"); +} + +/** + * @brief Test list_item_prepend functionality + * + * Tests that list_item_prepend correctly prepends an item to the beginning of the list + */ +ZTEST(sof_list_suite, test_list_item_prepend) +{ + struct list_item head; + struct list_item item1; + struct list_item item2; + + /* Initialize list */ + list_init(&head); + + /* Prepend first item */ + list_item_prepend(&item1, &head); + zassert_equal(&item1, head.next, "head->next should point to item1"); + zassert_equal(&item1, head.prev, "head->prev should point to item1"); + zassert_equal(&head, item1.next, "item1->next should point to head"); + zassert_equal(&head, item1.prev, "item1->prev should point to head"); + + /* Prepend second item */ + list_item_prepend(&item2, &head); + zassert_equal(&item2, head.next, "head->next should now point to item2"); + zassert_equal(&item1, head.prev, "head->prev should still point to item1"); + zassert_equal(&item1, item2.next, "item2->next should point to item1"); + zassert_equal(&head, item2.prev, "item2->prev should point to head"); + zassert_equal(&head, item1.next, "item1->next should still point to head"); + zassert_equal(&item2, item1.prev, "item1->prev should now point to item2"); +} + +/** + * @brief Test list_item_del functionality + * + * Tests that list_item_del correctly removes an item from a list + */ +ZTEST(sof_list_suite, test_list_item_del) +{ + struct list_item head; + struct list_item item1; + struct list_item item2; + + /* Initialize list */ + list_init(&head); + + /* Add items to list */ + list_item_append(&item1, &head); + list_item_append(&item2, &head); + + /* Remove first item */ + list_item_del(&item1); + + /* Check that item1 is properly removed and initialized */ + zassert_equal(&item1, item1.next, "item1->next should point to itself after deletion"); + zassert_equal(&item1, item1.prev, "item1->prev should point to itself after deletion"); + + /* Check that head and item2 are properly linked */ + zassert_equal(&item2, head.next, "head->next should point to item2"); + zassert_equal(&item2, head.prev, "head->prev should point to item2"); + zassert_equal(&head, item2.next, "item2->next should point to head"); + zassert_equal(&head, item2.prev, "item2->prev should point to head"); +} + +/** + * @brief Test list_item_is_last functionality + * + * Tests that list_item_is_last correctly identifies the last item in a list + */ +ZTEST(sof_list_suite, test_list_item_is_last) +{ + struct list_item head; + struct list_item item1; + struct list_item item2; + + /* Initialize list */ + list_init(&head); + + /* Add items to list */ + list_item_append(&item1, &head); + list_item_append(&item2, &head); + + /* Check item positions */ + zassert_false(list_item_is_last(&item1, &head), + "item1 should not be the last item in the list"); + zassert_true(list_item_is_last(&item2, &head), + "item2 should be the last item in the list"); +} + +/** + * @brief Test list_relink functionality + * + * Tests that list_relink correctly updates references when a list head is moved + */ +ZTEST(sof_list_suite, test_list_relink) +{ + struct list_item old_head; + struct list_item new_head; + struct list_item item1; + struct list_item item2; + + /* Test case 1: Empty list relinking */ + list_init(&old_head); + new_head = old_head; /* Copy the old head structure */ + + list_relink(&new_head, &old_head); + + /* After relinking empty list, new_head should be properly initialized */ + zassert_equal(&new_head, new_head.next, + "Empty list: new_head->next should point to itself"); + zassert_equal(&new_head, new_head.prev, + "Empty list: new_head->prev should point to itself"); + + /* Test case 2: Non-empty list relinking */ + list_init(&old_head); + list_item_append(&item1, &old_head); + list_item_append(&item2, &old_head); + + /* Verify initial state - items point to old_head */ + zassert_equal(&old_head, item1.prev, "Initial: item1 prev should point to old_head"); + zassert_equal(&old_head, item2.next, "Initial: item2 next should point to old_head"); + + /* Simulate moving list to new location by copying head structure */ + new_head = old_head; + /* Now new_head.next points to item1, new_head.prev points to item2 */ + /* But item1.prev and item2.next still point to &old_head */ + + /* Perform the relinking */ + list_relink(&new_head, &old_head); + + /* After relinking, items should now point to new_head instead of old_head */ + zassert_equal(&new_head, item1.prev, "After relink: item1 prev should point to new_head"); + zassert_equal(&new_head, item2.next, "After relink: item2 next should point to new_head"); + zassert_equal(&item1, new_head.next, "After relink: new_head next should point to item1"); + zassert_equal(&item2, new_head.prev, "After relink: new_head prev should point to item2"); + + /* Verify list integrity - items should still be properly linked */ + zassert_equal(&item2, item1.next, "After relink: item1 next should point to item2"); + zassert_equal(&item1, item2.prev, "After relink: item2 prev should point to item1"); +} + +ZTEST_SUITE(sof_list_suite, NULL, NULL, NULL, NULL, NULL); diff --git a/test/ztest/unit/list/testcase.yaml b/test/ztest/unit/list/testcase.yaml new file mode 100644 index 000000000000..38b1697f5d2c --- /dev/null +++ b/test/ztest/unit/list/testcase.yaml @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright(c) 2025 Intel Corporation. All rights reserved. +# +# These contents may have been developed with support from one or more Intel-operated +# generative artificial intelligence solutions. + +tests: + sof.unit.list: + platform_allow: native_sim + harness: ztest + tags: unit diff --git a/test/ztest/unit/math/advanced/functions/CMakeLists.txt b/test/ztest/unit/math/advanced/functions/CMakeLists.txt new file mode 100644 index 000000000000..615fc86a7db6 --- /dev/null +++ b/test/ztest/unit/math/advanced/functions/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(test_math_advanced_functions) + +set(SOF_ROOT "${PROJECT_SOURCE_DIR}/../../../../../..") + +# Set SOF top directory for UUID registry generation +set(sof_top_dir ${SOF_ROOT}) + +# Include SOF CMake utilities for proper SOF source compilation +include(${SOF_ROOT}/scripts/cmake/misc.cmake) +include(${SOF_ROOT}/scripts/cmake/uuid-registry.cmake) + +target_include_directories(app PRIVATE + ${SOF_ROOT}/zephyr/include + ${SOF_ROOT}/src/include + ${SOF_ROOT}/src/platform/posix/include + ${SOF_ROOT}/test/cmocka/include + ${PROJECT_BINARY_DIR}/include/generated # For uuid-registry.h +) + +# Define SOF-specific configurations for unit testing +target_compile_definitions(app PRIVATE + -DCONFIG_ZEPHYR_POSIX=1 + -DCONFIG_LIBRARY=1 + -DUNIT_TEST=1 +) + +target_sources(app PRIVATE + test_scalar_power_ztest.c + test_base2_logarithm_ztest.c + test_base10_logarithm_ztest.c + test_base_e_logarithm_ztest.c + test_exponential_ztest.c + test_square_root_ztest.c + ${SOF_ROOT}/src/math/power.c + ${SOF_ROOT}/src/math/base2log.c + ${SOF_ROOT}/src/math/log_10.c + ${SOF_ROOT}/src/math/log_e.c + ${SOF_ROOT}/src/math/exp_fcn.c + ${SOF_ROOT}/src/math/sqrt_int16.c + # Note: exp_fcn_hifi.c is conditionally compiled only for Xtensa HiFi platforms. + # TODO: Enable these tests on Xtensa platforms to also test HiFi-optimized code paths. + ${SOF_ROOT}/src/math/exp_fcn_hifi.c +) + +# Apply SOF relative path definitions for proper compilation +sof_append_relative_path_definitions(app) diff --git a/test/ztest/unit/math/advanced/functions/prj.conf b/test/ztest/unit/math/advanced/functions/prj.conf new file mode 100644 index 000000000000..d34c7781cd0a --- /dev/null +++ b/test/ztest/unit/math/advanced/functions/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_SOF_FULL_ZEPHYR_APPLICATION=n diff --git a/test/ztest/unit/math/advanced/functions/test_base10_logarithm_ztest.c b/test/ztest/unit/math/advanced/functions/test_base10_logarithm_ztest.c new file mode 100644 index 000000000000..b880cfd388a5 --- /dev/null +++ b/test/ztest/unit/math/advanced/functions/test_base10_logarithm_ztest.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. All rights reserved. +// +// Converted from CMock to Ztest +// +// Original test from sof/test/cmocka/src/math/arithmetic/base_10_logarithm.c: +// Author: Shriram Shastry <malladi.sastry@linux.intel.com> + +#include <zephyr/ztest.h> +#include <stdint.h> +#include <math.h> + +#include <sof/math/log.h> + +/* 'Error[max] = 0.0000071279028671,THD = -102.9407645424143993 ' */ +/* 'Error[max] = rms(log10() - double(log10_int32()))' */ +/* 'THD = 20*log10(Error[max])' */ +#define CMP_TOLERANCE 0.0000071279028671 + +/* Base-10 logarithm log10(X) reference table generated by matlab/Octave */ +/* UQ4.28 */ +static const double common_log10_ref_table[] = { + 0.0000000000000000, 7.6373246662453802, 7.9383546619093615, 8.1144459209650428, + 8.2393846575733427, 8.3362946705813989, 8.4154759166290241, 8.4824227062596371, + 8.5404146532373240, 8.5915671756847054, 8.6373246662453802, 8.6787173514036056, + 8.7165059122930053, 8.7512680193222625, 8.7834527026386606, 8.8134159259684335, + 8.8414446495269665, 8.8677735882125130, 8.8925971719048302, 8.9160782677250818, + 8.9383546624098908, 8.9595439614559940, 8.9797473475226131, 8.9990525026982162, + 9.0175359083740947, 9.0352646753178405, 9.0522980146012202, 9.0686884307751292, + 9.0844826979451199, 9.0997226644895282, 9.1144459212987297, 9.1286863604025754, + 9.1424746448781171, 9.1558386064266184, 9.1688035835820649, 9.1813927108816724, + 9.1936271672907388, 9.2055263908534872, 9.2171082633890631, 9.2283892737852433, + 9.2393846580738721, 9.2501085234534361, 9.2605739571199752, 9.2707931222905753, + 9.2807773431865943, 9.2905371804656394, 9.3000824983621975, 9.3094225246070792, + 9.3185659040380759, 9.3275207466824899, 9.3362946709818218, 9.3448948427358882, + 9.3533280102652014, 9.3616005362239267, 9.3697184264391105, 9.3776873561036460, + 9.3855126936091011, 9.3931995222691196, 9.4007526601535094, 9.4081766782268659, + 9.4154759169627091, 9.4226545015843630, 9.4297163562280168, 9.4366652161756566, + 9.4435046406985137, 9.4502380233502628, 9.4568686022422757, 9.4633994693944423, + 9.4698335793932600, 9.4761737574178788, 9.4824227066886628, 9.4885830153874373, + 9.4946571630937573, 9.5006475267772306, 9.5065563863821918, 9.5123859300375031, + 9.5181382589213257, 9.5238153918078847, 9.5294192693208828, 9.5349517579159713, + 9.5404146536127215, 9.5458096854947918, 9.5511385189953373, 9.5564027589832818, + 9.5616039526647825, 9.5667435923129869, 9.5718231178381536, 9.5768439193242560, + 9.5818073388505756, 9.5867146733402073, 9.5915671761296206, 9.5963660590064990, + 9.6011124940261787, 9.6058076152298781, 9.6104525202710605, 9.6150482719557271, + 9.6195958997020572, 9.6240964009244330, 9.6285507423464711, 9.6329598611462810}; + +/* testvector in Q32.0 */ +static const uint32_t uv[100] = { + 1ULL, 43383509ULL, 86767017ULL, 130150525ULL, 173534033ULL, 216917541ULL, + 260301049ULL, 303684557ULL, 347068065ULL, 390451573ULL, 433835081ULL, 477218589ULL, + 520602097ULL, 563985605ULL, 607369113ULL, 650752621ULL, 694136129ULL, 737519638ULL, + 780903146ULL, 824286654ULL, 867670162ULL, 911053670ULL, 954437178ULL, 997820686ULL, + 1041204194ULL, 1084587702ULL, 1127971210ULL, 1171354718ULL, 1214738226ULL, 1258121734ULL, + 1301505242ULL, 1344888750ULL, 1388272258ULL, 1431655766ULL, 1475039274ULL, 1518422782ULL, + 1561806290ULL, 1605189798ULL, 1648573306ULL, 1691956814ULL, 1735340322ULL, 1778723830ULL, + 1822107338ULL, 1865490846ULL, 1908874354ULL, 1952257862ULL, 1995641370ULL, 2039024878ULL, + 2082408386ULL, 2125791894ULL, 2169175403ULL, 2212558911ULL, 2255942419ULL, 2299325927ULL, + 2342709435ULL, 2386092943ULL, 2429476451ULL, 2472859959ULL, 2516243467ULL, 2559626975ULL, + 2603010483ULL, 2646393991ULL, 2689777499ULL, 2733161007ULL, 2776544515ULL, 2819928023ULL, + 2863311531ULL, 2906695039ULL, 2950078547ULL, 2993462055ULL, 3036845563ULL, 3080229071ULL, + 3123612579ULL, 3166996087ULL, 3210379595ULL, 3253763103ULL, 3297146611ULL, 3340530119ULL, + 3383913627ULL, 3427297135ULL, 3470680643ULL, 3514064151ULL, 3557447659ULL, 3600831168ULL, + 3644214676ULL, 3687598184ULL, 3730981692ULL, 3774365200ULL, 3817748708ULL, 3861132216ULL, + 3904515724ULL, 3947899232ULL, 3991282740ULL, 4034666248ULL, 4078049756ULL, 4121433264ULL, + 4164816772ULL, 4208200280ULL, 4251583788ULL, 4294967295ULL}; + +ZTEST(math_advanced_functions_suite, test_math_arithmetic_base10log_fixed) +{ + double clogfxp; + double diff; + int i; + + BUILD_ASSERT(ARRAY_SIZE(uv) == ARRAY_SIZE(common_log10_ref_table), + "Test vector size must match reference table size"); + + for (i = 0; i < ARRAY_SIZE(common_log10_ref_table); i++) { + clogfxp = log10_int32(uv[i]); + diff = fabs(common_log10_ref_table[i] - (double)clogfxp / (1 << 28)); + + if (diff > CMP_TOLERANCE) { + zassert_true(diff <= CMP_TOLERANCE, + "log10_int32(%u): delta %.16f > tolerance (got %.16f)", + uv[i], diff, clogfxp / (1 << 28)); + } + } +} \ No newline at end of file diff --git a/test/ztest/unit/math/advanced/functions/test_base2_logarithm_ztest.c b/test/ztest/unit/math/advanced/functions/test_base2_logarithm_ztest.c new file mode 100644 index 000000000000..52d1eb0e6a0b --- /dev/null +++ b/test/ztest/unit/math/advanced/functions/test_base2_logarithm_ztest.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. +// +// Converted from CMock to Ztest +// +// Original test from sof/test/cmocka/src/math/arithmetic/base2_logarithm.c +// Author: Shriram Shastry <malladi.sastry@linux.intel.com> + +#include <zephyr/ztest.h> +#include <sof/audio/format.h> +#include <sof/math/log.h> +#include <math.h> +#include <rtos/string.h> + +/* Test data tables from MATLAB-generated reference */ +#include "log2_tables.h" + +/* 'Error[max] = 0.0000236785999981,THD(-dBc) = -92.5128795787487235' */ +#define CMP_TOLERANCE 0.0000236785691029f + +/* testvector in Q32.0 */ +static const uint32_t uv[100] = { + 1ULL, 43383509ULL, 86767017ULL, 130150525ULL, 173534033ULL, 216917541ULL, + 260301049ULL, 303684557ULL, 347068065ULL, 390451573ULL, 433835081ULL, 477218589ULL, + 520602097ULL, 563985605ULL, 607369113ULL, 650752621ULL, 694136129ULL, 737519638ULL, + 780903146ULL, 824286654ULL, 867670162ULL, 911053670ULL, 954437178ULL, 997820686ULL, + 1041204194ULL, 1084587702ULL, 1127971210ULL, 1171354718ULL, 1214738226ULL, 1258121734ULL, + 1301505242ULL, 1344888750ULL, 1388272258ULL, 1431655766ULL, 1475039274ULL, 1518422782ULL, + 1561806290ULL, 1605189798ULL, 1648573306ULL, 1691956814ULL, 1735340322ULL, 1778723830ULL, + 1822107338ULL, 1865490846ULL, 1908874354ULL, 1952257862ULL, 1995641370ULL, 2039024878ULL, + 2082408386ULL, 2125791894ULL, 2169175403ULL, 2212558911ULL, 2255942419ULL, 2299325927ULL, + 2342709435ULL, 2386092943ULL, 2429476451ULL, 2472859959ULL, 2516243467ULL, 2559626975ULL, + 2603010483ULL, 2646393991ULL, 2689777499ULL, 2733161007ULL, 2776544515ULL, 2819928023ULL, + 2863311531ULL, 2906695039ULL, 2950078547ULL, 2993462055ULL, 3036845563ULL, 3080229071ULL, + 3123612579ULL, 3166996087ULL, 3210379595ULL, 3253763103ULL, 3297146611ULL, 3340530119ULL, + 3383913627ULL, 3427297135ULL, 3470680643ULL, 3514064151ULL, 3557447659ULL, 3600831168ULL, + 3644214676ULL, 3687598184ULL, 3730981692ULL, 3774365200ULL, 3817748708ULL, 3861132216ULL, + 3904515724ULL, 3947899232ULL, 3991282740ULL, 4034666248ULL, 4078049756ULL, 4121433264ULL, + 4164816772ULL, 4208200280ULL, 4251583788ULL, 4294967295ULL}; + +/** + * @brief Test base-2 logarithm function with fixed-point arithmetic + * + * This test validates the base2_logarithm() function against MATLAB-generated + * reference values. It tests 100 uniformly distributed input values across + * the full uint32_t range, checking that the fixed-point logarithm calculation + * stays within acceptable tolerance. + * + * Input values: Q32.0 format (unsigned 32-bit integers) + * Result: Q16.16 fixed-point format + * Reference: MATLAB log2() function results + */ +ZTEST(math_advanced_functions_suite, test_math_arithmetic_base2log_fixed) +{ + uint32_t u[100]; + int i, ret; + + BUILD_ASSERT(ARRAY_SIZE(uv) == ARRAY_SIZE(log2_lookup_table), + "Test vector size must match reference table size"); + + ret = memcpy_s((void *)&u[0], sizeof(u), (void *)&uv[0], 100U * sizeof(uint32_t)); + zassert_equal(ret, 0, "memcpy_s failed with error code %d", ret); + + for (i = 0; i < ARRAY_SIZE(u); i++) { + float y = Q_CONVERT_QTOF(base2_logarithm(u[i]), 0); + float delta = fabsf((float)(log2_lookup_table[i] - (double)y / (1 << 16))); + + zassert_true(delta <= CMP_TOLERANCE, + "base2_logarithm(%u): delta %.16f > tolerance (expected %.16f, got %.16f)", + u[i], (double)delta, log2_lookup_table[i], (double)y / (1 << 16)); + } +} diff --git a/test/ztest/unit/math/advanced/functions/test_base_e_logarithm_ztest.c b/test/ztest/unit/math/advanced/functions/test_base_e_logarithm_ztest.c new file mode 100644 index 000000000000..e400b8b76a59 --- /dev/null +++ b/test/ztest/unit/math/advanced/functions/test_base_e_logarithm_ztest.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. +// +// Converted from CMock to Ztest +// +// Original test from sof/test/cmocka/src/math/arithmetic/base_e_logarithm.c +// Author: Shriram Shastry <malladi.sastry@linux.intel.com> + +#include <zephyr/ztest.h> +#include <stdint.h> +#include <math.h> + +#include <sof/math/log.h> + +/* 'Error[max] = 0.0000164133276926,THD(-dBc) = -95.6960671942683234' */ +/* 'Error[max] = rms(log() - double(log_int32()))' */ +/* 'THD = 20*log10(Error[max])' */ +#define CMP_TOLERANCE 0.0000164133276926 + +/* Natural logarithm loge(X) reference table generated by matlab/Octave */ +/* UQ5.27 */ +static const double natural_log_lookup_table[] = { + 0.0000000000000000, 17.5855899268523359, 18.2787371074122831, 18.6842022155204468, + 18.9718842879722267, 19.1950278392864391, 19.3773493960803940, 19.5315000759076511, + 19.6650314685321739, 19.7828145041885577, 19.8881750198463827, 19.9834851996507084, + 20.0704965766403376, 20.1505392860869676, 20.2246472581140395, 20.2936401294912301, + 20.3581786505327571, 20.4188032722644479, 20.4759616860290699, 20.5300289072319480, + 20.5813222015588408, 20.6301123656733907, 20.6766323812583899, 20.7210841437836706, + 20.7636437581607112, 20.8044657526425461, 20.8436864657603671, 20.8814267937103786, + 20.9177944378507625, 20.9528857576336485, 20.9867873092828354, 21.0195771320810394, + 21.0513258303723845, 21.0820974890173112, 21.1119504521464485, 21.1409379890003279, + 21.1691088659487328, 21.1965078407425196, 21.2231760877918916, 21.2491515741640455, + 21.2744693821187845, 21.2991619946810467, 21.3232595462333343, 21.3467900436180038, + 21.3697795618183370, 21.3922524176471107, 21.4142313243436178, 21.4357375295432568, + 21.4567909387206548, 21.4774102259037889, 21.4976129332024932, 21.5174155604805932, + 21.5368336463203107, 21.5558818412742781, 21.5745739742703257, 21.5929231129229997, + 21.6109416184107097, 21.6286411954956677, 21.6460329381935921, 21.6631273715394208, + 21.6799344898427790, 21.6964637917813938, 21.7127243130127638, 21.7287246543415016, + 21.7444730112924880, 21.7599771978118319, 21.7752446699265008, 21.7902825472754031, + 21.8050976330453672, 21.8196964324517815, 21.8340851698895619, 21.8482698048676056, + 21.8622560468288185, 21.8760493689479993, 21.8896550209909755, 21.9030780413106569, + 21.9163232680485471, 21.9293953496040821, 21.9422987544284780, 21.9550377801946830, + 21.9676165623906030, 21.9800390823784895, 21.9923091749598925, 22.0044305354820757, + 22.0164067265188734, 22.0282411841561903, 22.0399372239099236, 22.0514980465667030, + 22.0629267423782807, 22.0742262976204415, 22.0853995982070579, 22.0964494343823858, + 22.1073785049035614, 22.1181894209970018, 22.1288847101032040, 22.1394668194234150, + 22.1499381192805984, 22.1603009063062437, 22.1705574064637361, 22.1807097776854185}; + +/* testvector in Q32.0 */ +static const uint32_t uv[100] = { + 1ULL, 43383509ULL, 86767017ULL, 130150525ULL, 173534033ULL, 216917541ULL, + 260301049ULL, 303684557ULL, 347068065ULL, 390451573ULL, 433835081ULL, 477218589ULL, + 520602097ULL, 563985605ULL, 607369113ULL, 650752621ULL, 694136129ULL, 737519638ULL, + 780903146ULL, 824286654ULL, 867670162ULL, 911053670ULL, 954437178ULL, 997820686ULL, + 1041204194ULL, 1084587702ULL, 1127971210ULL, 1171354718ULL, 1214738226ULL, 1258121734ULL, + 1301505242ULL, 1344888750ULL, 1388272258ULL, 1431655766ULL, 1475039274ULL, 1518422782ULL, + 1561806290ULL, 1605189798ULL, 1648573306ULL, 1691956814ULL, 1735340322ULL, 1778723830ULL, + 1822107338ULL, 1865490846ULL, 1908874354ULL, 1952257862ULL, 1995641370ULL, 2039024878ULL, + 2082408386ULL, 2125791894ULL, 2169175403ULL, 2212558911ULL, 2255942419ULL, 2299325927ULL, + 2342709435ULL, 2386092943ULL, 2429476451ULL, 2472859959ULL, 2516243467ULL, 2559626975ULL, + 2603010483ULL, 2646393991ULL, 2689777499ULL, 2733161007ULL, 2776544515ULL, 2819928023ULL, + 2863311531ULL, 2906695039ULL, 2950078547ULL, 2993462055ULL, 3036845563ULL, 3080229071ULL, + 3123612579ULL, 3166996087ULL, 3210379595ULL, 3253763103ULL, 3297146611ULL, 3340530119ULL, + 3383913627ULL, 3427297135ULL, 3470680643ULL, 3514064151ULL, 3557447659ULL, 3600831168ULL, + 3644214676ULL, 3687598184ULL, 3730981692ULL, 3774365200ULL, 3817748708ULL, 3861132216ULL, + 3904515724ULL, 3947899232ULL, 3991282740ULL, 4034666248ULL, 4078049756ULL, 4121433264ULL, + 4164816772ULL, 4208200280ULL, 4251583788ULL, 4294967295ULL}; + +/** + * @brief Test natural (base-e) logarithm function with fixed-point arithmetic + * + * This test validates the ln_int32() function against MATLAB-generated reference + * values. It tests 100 uniformly distributed input values across the full uint32_t + * range, checking that the fixed-point logarithm calculation stays within acceptable + * tolerance. + * + * Input values: Q32.0 format (unsigned 32-bit integers) + * Result: UQ5.27 fixed-point format + * Reference: MATLAB log() function results + */ +ZTEST(math_advanced_functions_suite, test_math_arithmetic_base_e_log_fixed) +{ + int i; + + BUILD_ASSERT(ARRAY_SIZE(uv) == ARRAY_SIZE(natural_log_lookup_table), + "Test vector size must match reference table size"); + + for (i = 0; i < ARRAY_SIZE(uv); i++) { + double logefxp = ln_int32(uv[i]); + double diff = fabs(natural_log_lookup_table[i] - logefxp / (1 << 27)); + + zassert_true(diff <= CMP_TOLERANCE, + "ln_int32(%u): diff %.16f > tolerance (expected %.16f, got %.16f)", + uv[i], diff, natural_log_lookup_table[i], logefxp / (1 << 27)); + } +} diff --git a/test/ztest/unit/math/advanced/functions/test_exponential_ztest.c b/test/ztest/unit/math/advanced/functions/test_exponential_ztest.c new file mode 100644 index 000000000000..1fd03b6bb5af --- /dev/null +++ b/test/ztest/unit/math/advanced/functions/test_exponential_ztest.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2022-2026 Intel Corporation. + * + * These contents may have been developed with support from one or more Intel-operated + * generative artificial intelligence solutions. + * + * Converted from CMock to Ztest + * + * Original test from sof/test/cmocka/src/math/arithmetic/exponential.c + * + * Author: Shriram Shastry <malladi.sastry@linux.intel.com> + * Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + */ + +#include <zephyr/ztest.h> +#include <zephyr/logging/log.h> +#include <sof/math/exp_fcn.h> +#include <sof/audio/format.h> +#include <sof/common.h> +#include <math.h> +#include <rtos/string.h> + +LOG_MODULE_REGISTER(test_exponential, LOG_LEVEL_INF); + +#define ULP_TOLERANCE 1.0 +#define ULP_SCALE 1.9073e-06 /* For exp() output Q13.19, 1 / 2^19 */ +#define NUMTESTSAMPLES 256 + +#define NUMTESTSAMPLES_TEST2 100 +#define ABS_DELTA_TOLERANCE_TEST2 2.0e-6 +#define REL_DELTA_TOLERANCE_TEST2 1000.0 /* rel. error is large with values near zero */ +#define NUMTESTSAMPLES_TEST3 100 +#define ABS_DELTA_TOLERANCE_TEST3 2.0e-6 +#define REL_DELTA_TOLERANCE_TEST3 10.0e-2 +#define SOFM_EXP_FIXED_ARG_MIN -11.5 +#define SOFM_EXP_FIXED_ARG_MAX 7.6245 + +#define NUMTESTSAMPLES_TEST4 100 +#define ABS_DELTA_TOLERANCE_TEST4 2.5e-5 +#define REL_DELTA_TOLERANCE_TEST4 1000.0 /* rel. error is large with values near zero */ + +/** + * Saturates input to 32 bits + * @param x Input value + * @return Saturated output value + */ +static int32_t saturate32(int64_t x) +{ + if (x < INT32_MIN) + return INT32_MIN; + else if (x > INT32_MAX) + return INT32_MAX; + + return x; +} + +/** + * Generates linearly spaced values for a vector with end points and number points in + * desired fractional Q-format for 32 bit integer. If the test values exceed int32_t + * range, the values are saturated to INT32_MIN to INT32_MAX range. + * + * @param a First value of test vector + * @param b Last value of test vector + * @param step_count Number of values in vector + * @param point Calculate n-th point of vector 0 .. step_count - 1 + * @param qformat Number of fractional bits y in Qx.y format + * @param fout Pointer to calculated test vector value, double + * @param iout Pointer to calculated test vector value, int32_t + */ +static void gen_testvector_linspace_int32(double a, double b, int step_count, int point, + int qformat, double *fout, int32_t *iout) +{ + double fstep = (b - a) / (step_count - 1); + double fvalue = a + fstep * point; + int64_t itmp; + + itmp = (int64_t)round(fvalue * (double)(1 << qformat)); + *iout = saturate32(itmp); + *fout = (double)*iout / (1 << qformat); +} + +/** + * Calculate reference exponent value + * @param x Input value + * @param qformat Fractional bits y in Qx.y format + * @return Saturated exponent value to match fractional format + */ +static double ref_exp(double x, int qformat) +{ + double yf; + int64_t yi; + + yf = exp(x); + yi = yf * (1 << qformat); + + if (yi > INT32_MAX) + yi = INT32_MAX; + else if (yi < INT32_MIN) + yi = INT32_MIN; + + yf = (double)yi / (1 << qformat); + return yf; +} + +/** + * Calculates test exponent function and compares result to reference exponent. + * @param ivalue Fractional format input value Q5.27 + * @param iexp_value Fractional format output value Q12.20 + * @param abs_delta_max Calculated absolute error + * @param rel_delta_max Calculated relative error + * @param abs_delta_tolerance Tolerance for absolute error + * @param rel_delta_tolerance Tolerance for relative error + */ +static void test_exp_with_input_value(int32_t ivalue, int32_t *iexp_value, + double *abs_delta_max, double *rel_delta_max, + double abs_delta_tolerance, double rel_delta_tolerance) +{ + double fvalue, fexp_value, ref_exp_value; + double rel_delta, abs_delta; + double eps = 1e-9; + + *iexp_value = sofm_exp_fixed(ivalue); + fvalue = (double)ivalue / (1 << 27); /* Q5.27 */ + fexp_value = (double)*iexp_value / (1 << 20); /* Q12.20 */ + ref_exp_value = ref_exp(fvalue, 20); + abs_delta = fabs(ref_exp_value - fexp_value); + rel_delta = abs_delta / (ref_exp_value + eps); + + if (abs_delta > *abs_delta_max) + *abs_delta_max = abs_delta; + + if (rel_delta > *rel_delta_max) + *rel_delta_max = rel_delta; + + zassert_true(abs_delta <= abs_delta_tolerance, + "sofm_exp_fixed: Absolute error %g exceeds limit %g, input %g output %g", + abs_delta, abs_delta_tolerance, fvalue, fexp_value); + + zassert_true(rel_delta <= rel_delta_tolerance, + "sofm_exp_fixed: Relative error %g exceeds limit %g, input %g output %g", + rel_delta, rel_delta_tolerance, fvalue, fexp_value); +} + +/** + * Reference function for dB to linear conversion + * @param x Input value + * @param qformat Fractional bits y in Qx.y format for saturation + * @return Saturated linear value + */ +static double ref_db2lin(double x, int qformat) +{ + double fref; + int64_t iref; + + fref = pow(10, x / 20); + iref = fref * (1 << qformat); + return (double)saturate32(iref) / (1 << qformat); +} + +/** + * @brief Test sofm_exp_approx() function with ULP error validation + * + * This test validates the sofm_exp_approx() exponential approximation function + * against the C standard library exp() function. It tests 256 linearly spaced + * input values and checks that the ULP (Unit in the Last Place) error stays + * within acceptable tolerance. + * + * Input values: Q28 format, range -8 to 8 + * Result: Q19 format + * Validation: ULP error < 1.0 ULP + */ +ZTEST(math_advanced_functions_suite, test_function_sofm_exp_approx) +{ + int32_t accum; + int i; + double a_i; + double max_ulp = 0; + double ulp; + double a_tmp = -8; + double b_tmp = 8; + int32_t b_i; + + for (i = 0; i < NUMTESTSAMPLES; i++) { + gen_testvector_linspace_int32(a_tmp, b_tmp, NUMTESTSAMPLES, i, 28, &a_i, &b_i); + accum = sofm_exp_approx(b_i); + ulp = fabs(exp(a_i) - (double)accum / (1 << 19)) / ULP_SCALE; + if (ulp > max_ulp) + max_ulp = ulp; + + zassert_true(ulp <= ULP_TOLERANCE, + "sofm_exp_approx: ULP %.16f exceeds tolerance, value=%.16f, exp=%.16f", + ulp, (double)b_i / (1 << 28), (double)accum / (1 << 19)); + } + + LOG_INF("Worst-case ULP: %g ULP_SCALE %g", max_ulp, ULP_SCALE); +} + +/** + * @brief Test sofm_exp_fixed() function with absolute and relative error validation + * + * This test validates the sofm_exp_fixed() fixed-point exponential function + * against a reference implementation. It performs two sub-tests with different + * input ranges and tolerance requirements. + * + * Sub-test 1: Coarse grid across max range + * - Input values: Q27 format, range -16 to 16 + * - Result: Q20 format + * - Tolerances: abs 2.0e-6, rel 1000.0 + * + * Sub-test 2: Fine grid across typical range + * - Input values: Q27 format, range -11.5 to 7.6245 + * - Result: Q20 format + * - Tolerances: abs 2.0e-6, rel 10.0e-2 + */ +ZTEST(math_advanced_functions_suite, test_function_sofm_exp_fixed) +{ + double rel_delta_max, abs_delta_max; + double tmp; + int32_t ivalue, iexp_value; + int i; + + /* Test max int32_t range with coarse grid */ + rel_delta_max = 0; + abs_delta_max = 0; + for (i = 0; i < NUMTESTSAMPLES_TEST2; i++) { + gen_testvector_linspace_int32(-16, 16, NUMTESTSAMPLES_TEST2, i, 27, &tmp, &ivalue); + test_exp_with_input_value(ivalue, &iexp_value, &abs_delta_max, &rel_delta_max, + ABS_DELTA_TOLERANCE_TEST2, REL_DELTA_TOLERANCE_TEST2); + } + + LOG_INF("Absolute max error was %.6e (max range)", abs_delta_max); + LOG_INF("Relative max error was %.6e (max range)", rel_delta_max); + + /* Test max int32_t middle range with fine grid */ + rel_delta_max = 0; + abs_delta_max = 0; + for (i = 0; i < NUMTESTSAMPLES_TEST3; i++) { + gen_testvector_linspace_int32(SOFM_EXP_FIXED_ARG_MIN, SOFM_EXP_FIXED_ARG_MAX, + NUMTESTSAMPLES_TEST3, i, 27, &tmp, &ivalue); + test_exp_with_input_value(ivalue, &iexp_value, &abs_delta_max, &rel_delta_max, + ABS_DELTA_TOLERANCE_TEST3, REL_DELTA_TOLERANCE_TEST3); + } + + LOG_INF("Absolute max error was %.6e (middle)", abs_delta_max); + LOG_INF("Relative max error was %.6e (middle)", rel_delta_max); +} + +/** + * @brief Test sofm_db2lin_fixed() function for dB to linear conversion + * + * This test validates the sofm_db2lin_fixed() function that converts decibel + * values to linear scale using fixed-point arithmetic. It compares against + * a reference implementation using floating-point pow(10, x/20). + * + * Input values: Q24 format, range -128 to 128 dB + * Result: Q20 format + * Tolerances: abs 2.5e-5, rel 1000.0 + */ +ZTEST(math_advanced_functions_suite, test_function_sofm_db2lin_fixed) +{ + double abs_delta, rel_delta, abs_delta_max, rel_delta_max; + double fin, fout, fref; + double eps = 1e-9; + int32_t iin, iout; + int i; + + rel_delta_max = 0; + abs_delta_max = 0; + for (i = 0; i < NUMTESTSAMPLES_TEST4; i++) { + gen_testvector_linspace_int32(-128, 128, NUMTESTSAMPLES_TEST4, i, 24, &fin, &iin); + iout = sofm_db2lin_fixed(iin); + fout = (double)iout / (1 << 20); + fref = ref_db2lin(fin, 20); + abs_delta = fabs(fref - fout); + rel_delta = abs_delta / (fref + eps); + if (abs_delta > abs_delta_max) + abs_delta_max = abs_delta; + + if (rel_delta > rel_delta_max) + rel_delta_max = rel_delta; + + zassert_true(abs_delta <= ABS_DELTA_TOLERANCE_TEST4, + "sofm_db2lin_fixed: Absolute error %g exceeds limit %g, input %g output %g", + abs_delta, ABS_DELTA_TOLERANCE_TEST4, fin, fout); + + zassert_true(rel_delta <= REL_DELTA_TOLERANCE_TEST4, + "sofm_db2lin_fixed: Relative error %g exceeds limit %g, input %g output %g", + rel_delta, REL_DELTA_TOLERANCE_TEST4, fin, fout); + } + + LOG_INF("Absolute max error was %.6e", abs_delta_max); + LOG_INF("Relative max error was %.6e", rel_delta_max); +} diff --git a/test/ztest/unit/math/advanced/functions/test_scalar_power_ztest.c b/test/ztest/unit/math/advanced/functions/test_scalar_power_ztest.c new file mode 100644 index 000000000000..a3c2d6fe911c --- /dev/null +++ b/test/ztest/unit/math/advanced/functions/test_scalar_power_ztest.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. +// +// Converted from CMock to Ztest +// +// Original test from sof/test/cmocka/src/math/arithmetic/scalar_power.c: +// Author: Shriram Shastry <malladi.sastry@linux.intel.com> + +#include <zephyr/ztest.h> +#include <zephyr/logging/log.h> +#include <sof/audio/format.h> +#include <sof/math/power.h> +#include <sof/common.h> +#include <math.h> + +LOG_MODULE_REGISTER(test_scalar_power, LOG_LEVEL_INF); + +/* Test data tables from MATLAB-generated reference */ +#include "power_tables.h" + +/* Error tolerance: max error = 0.000034912111005, THD+N = -96.457180359025074 */ +#define CMP_TOLERANCE 0.0000150363575813f + +/** + * @brief Test scalar power function with fixed-point arithmetic + * + * This test validates the power_int32() function against MATLAB-generated + * reference values. It tests 64 base values against 6 exponent values, + * checking that the fixed-point power calculation stays within acceptable + * tolerance. + * + * Base values: Fixed-point Q6.25 format (range -1.0 to 1.0) + * Exponent values: Fixed-point Q2.29 format + * Result: Fixed-point Q16.15 format + */ +ZTEST(math_advanced_functions_suite, test_math_arithmetic_power_fixed) +{ + double p; + int i; + int j; + + for (i = 0; i < ARRAY_SIZE(b); i++) { + for (j = 0; j < ARRAY_SIZE(e); j++) { + p = power_int32(b[i], e[j]); + float delta = fabsf((float)(power_table[i][j] - (double)p / (1 << 15))); + + zassert_true(delta <= CMP_TOLERANCE, + "Power calc error: delta=%f > %f at b[%d]=%d, e[%d]=%d", + (double)delta, (double)CMP_TOLERANCE, i, b[i], j, e[j]); + } + } +} + +ZTEST_SUITE(math_advanced_functions_suite, NULL, NULL, NULL, NULL, NULL); diff --git a/test/ztest/unit/math/advanced/functions/test_square_root_ztest.c b/test/ztest/unit/math/advanced/functions/test_square_root_ztest.c new file mode 100644 index 000000000000..2dcb45ffa0ff --- /dev/null +++ b/test/ztest/unit/math/advanced/functions/test_square_root_ztest.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. All rights reserved. +// +// Converted from CMock to Ztest +// +// Original test from sof/test/cmocka/src/math/arithmetic/square_root.c: +// Author: Shriram Shastry <malladi.sastry@linux.intel.com> + +#include <zephyr/ztest.h> +#include <stdint.h> +#include <math.h> + +#include <sof/math/sqrt.h> +#include <sof/audio/format.h> +#include <rtos/string.h> +#include <sof/common.h> + +/* 'Error[max] = 0.0003000860000000,THD(-dBc) = -87.1210823527511309' */ +#define CMP_TOLERANCE 0.0001689942 + +static const double sqrt_ref_table[] = { + 0.0000000000000000, 0.2529127196287289, 0.3580137261684250, 0.4383362543470480, + 0.5060667106469264, 0.5657458434447398, 0.6199010757774179, 0.6695089151758922, + 0.7156864056624241, 0.7590598625931949, 0.8002380017063674, 0.8392530626247365, + 0.8765332548597343, 0.9124250825410271, 0.9468285879714448, 0.9800251112854200, + 1.0121334212938529, 1.0433710015497843, 1.0735864616438677, 1.1029744939820685, + 1.1317074351394887, 1.1596234572049671, 1.1868830634270588, 1.2135304899342250, + 1.2397036881347898, 1.2652391387105444, 1.2902693214499832, 1.3148230929007141, + 1.3390178303517843, 1.3626935069009465, 1.3859648038460428, 1.4089384024417106, + 1.4314580907679415, 1.4536289448738284, 1.4754666899408471, 1.4970674458754356, + 1.5182805344369004, 1.5392012945030940, 1.5598414883410430, 1.5802893574042065, + 1.6003997303408295, 1.6202605162827983, 1.6399552204252408, 1.6593426315110451, + 1.6785061252494731, 1.6974532854396907, 1.7162624043615824, 1.7347972458979175, + 1.7531361407845656, 1.7712851751976586, 1.7893183496097054, 1.8071040368501201, + 1.8247163735084968, 1.8422265952170487, 1.8595062978852748, 1.8766268983537990, + 1.8935927121149891, 1.9104717594746068, 1.9271396388170734, 1.9436645881555799, + 1.9601125007572908, 1.9763617734046062, 1.9924785326635266, 2.0084659685628234, + 2.0243874459327196, 2.0401248429936829, 2.0557417684986605, 2.0712409474756917, + 2.0866835042418388, 2.1019545405705138, 2.1171154277400652, 2.1322257663648099, + 2.1471729232877355, 2.1620167451363552, 2.1767593459084997, 2.1914584719713490, + 2.2060043241401410, 2.2204548907543695, 2.2348120201987909, 2.2491317769308226, + 2.2633070038662453, 2.2773940013752560, 2.2914476694602910, 2.3053627188850347, + 2.3191942802134968, 2.3329438383992445, 2.3466648541067809, 2.3602543890966499, + 2.3737661268541177, 2.3872013883939496, 2.4006123079591588, 2.4138981537908761, + 2.4271112748749282, 2.4403028756693299, 2.4533737931163282, 2.4663754402969551, + 2.4793089069839604, 2.4922242356226696, 2.5050242482608827, 2.5177591878742098, + 2.5304782774210888, 2.5430857547967194, 2.5556310375326090, 2.5681150370943278, + 2.5805859466650203, 2.5929498012639969, 2.6052549809231724, 2.6175023131556161, + 2.6297390257875399, 2.6418728560436060, 2.6539512111660981, 2.6660206330081166, + 2.6779900782816579, 2.6899062628881700, 2.7017698915479462, 2.7136266381449752, + 2.7253870138018930, 2.7370968595849874, 2.7487568212739375, 2.7604117531402812, + 2.7719736453698474, 2.7834875128828940, 2.7949976241045360, 2.8064170328908711, + 2.8177901636300033, 2.8291175744390689, 2.8404427884354582, 2.8516802201728368, + 2.8628735427669523, 2.8740232715872360, 2.8851722218959477, 2.8962361080806240, + 2.9072578897476569, 2.9182798738083706, 2.9292187124939990, 2.9401168530136688, + 2.9509747462702896, 2.9618340496219568, 2.9726126187665289, 2.9833522462156559, + 2.9940941216626773, 3.0047569707257522, 3.0153821145710538, 3.0259699503836783, + 3.0365610688738007, 3.0470753139280951, 3.0575534030495688, 3.0679957066870220, + 3.0784422425351754, 3.0888139284157279, 3.0991509043809078, 3.1094927741514371, + 3.1197612338526808, 3.1299960063872287, 3.1401974211424988, 3.1504045499149789, + 3.1605400917999757, 3.1706432337342845, 3.1807142844611178, 3.1907918051402224, + 3.2007994606816590, 3.2107759235502562, 3.2207593849316032, 3.2306742112715421, + 3.2405587023112234, 3.2504131347991749, 3.2602752232365293, 3.2700702400713046, + 3.2798360048560355, 3.2895727781126838, 3.2993178153786578, 3.3089972636170311, + 3.3186484800856810, 3.3283083869662677, 3.3379037677111065, 3.3474716438306089, + 3.3570122504989461, 3.3665620793882591, 3.3760487375221642, 3.3855088128485207, + 3.3949784839156196, 3.4043859578490805, 3.4137675072784321, 3.4231233453528955, + 3.4324892457042018, 3.4417941928048226, 3.4510740515635128, 3.4603290238249023, + 3.4695944917958350, 3.4788001927748020, 3.4879815975718680, 3.4971738031409019, + 3.5063070962374359, 3.5154166604934614, 3.5245026799003858, 3.5335998818485379, + 3.5426392659640071, 3.5516556438511886, 3.5606491902811768, 3.5696542746637245, + 3.5786025882144274, 3.5875285822032135, 3.5964663647113397, 3.6053481324623839, + 3.6142080737002402, 3.6230463485511746, 3.6318967259718442, 3.6406920594682268, + 3.6494661959833250, 3.6582526566654741, 3.6669847755001657, 3.6756961500510350, + 3.6843869274616097, 3.6930903069956198, 3.7017402474207994, 3.7103700224000571, + 3.7189797723132347, 3.7276023837381045, 3.7361724230822109, 3.7447228493908598, + 3.7532863204297375, 3.7617978476886553, 3.7702901600042669, 3.7787633869263368, + 3.7872498886065071, 3.7956852559847478, 3.8041019184887777, 3.8125000000000000, + 3.8209115711273665, 3.8292727871131094, 3.8376157861196840, 3.8459724266107265, + 3.8542792776341468, 3.8625682639598748, 3.8708395003538962, 3.8791245690071618, + 3.8873605782876637, 3.8955791750874478, 3.9037804693815712, 3.9119957742180653, + 3.9201627238228260, 3.9283126944020128, 3.9364768015796816, 3.9445930655930783, + 3.9526926641056979, 3.9607756993580185, 3.9688730295891301, 3.9769231786332004, + 3.9849570653270532, 3.9930053589840071, 3.9999694823054588, 3.9999694823054588}; + +/* testvector in Q4.12 */ +static const uint32_t uv[252] = { + 0U, 262U, 525U, 787U, 1049U, 1311U, + 1574U, 1836U, 2098U, 2360U, 2623U, 2885U, + 3147U, 3410U, 3672U, 3934U, 4196U, 4459U, + 4721U, 4983U, 5246U, 5508U, 5770U, 6032U, + 6295U, 6557U, 6819U, 7081U, 7344U, 7606U, + 7868U, 8131U, 8393U, 8655U, 8917U, 9180U, + 9442U, 9704U, 9966U, 10229U, 10491U, 10753U, + 11016U, 11278U, 11540U, 11802U, 12065U, 12327U, + 12589U, 12851U, 13114U, 13376U, 13638U, 13901U, + 14163U, 14425U, 14687U, 14950U, 15212U, 15474U, + 15737U, 15999U, 16261U, 16523U, 16786U, 17048U, + 17310U, 17572U, 17835U, 18097U, 18359U, 18622U, + 18884U, 19146U, 19408U, 19671U, 19933U, 20195U, + 20457U, 20720U, 20982U, 21244U, 21507U, 21769U, + 22031U, 22293U, 22556U, 22818U, 23080U, 23342U, + 23605U, 23867U, 24129U, 24392U, 24654U, 24916U, + 25178U, 25441U, 25703U, 25965U, 26228U, 26490U, + 26752U, 27014U, 27277U, 27539U, 27801U, 28063U, + 28326U, 28588U, 28850U, 29113U, 29375U, 29637U, + 29899U, 30162U, 30424U, 30686U, 30948U, 31211U, + 31473U, 31735U, 31998U, 32260U, 32522U, 32784U, + 33047U, 33309U, 33571U, 33833U, 34096U, 34358U, + 34620U, 34883U, 35145U, 35407U, 35669U, 35932U, + 36194U, 36456U, 36719U, 36981U, 37243U, 37505U, + 37768U, 38030U, 38292U, 38554U, 38817U, 39079U, + 39341U, 39604U, 39866U, 40128U, 40390U, 40653U, + 40915U, 41177U, 41439U, 41702U, 41964U, 42226U, + 42489U, 42751U, 43013U, 43275U, 43538U, 43800U, + 44062U, 44324U, 44587U, 44849U, 45111U, 45374U, + 45636U, 45898U, 46160U, 46423U, 46685U, 46947U, + 47210U, 47472U, 47734U, 47996U, 48259U, 48521U, + 48783U, 49045U, 49308U, 49570U, 49832U, 50095U, + 50357U, 50619U, 50881U, 51144U, 51406U, 51668U, + 51930U, 52193U, 52455U, 52717U, 52980U, 53242U, + 53504U, 53766U, 54029U, 54291U, 54553U, 54816U, + 55078U, 55340U, 55602U, 55865U, 56127U, 56389U, + 56651U, 56914U, 57176U, 57438U, 57701U, 57963U, + 58225U, 58487U, 58750U, 59012U, 59274U, 59536U, + 59799U, 60061U, 60323U, 60586U, 60848U, 61110U, + 61372U, 61635U, 61897U, 62159U, 62421U, 62684U, + 62946U, 63208U, 63471U, 63733U, 63995U, 64257U, + 64520U, 64782U, 65044U, 65307U, UINT16_MAX, UINT16_MAX}; + +ZTEST(math_advanced_functions_suite, test_math_arithmetic_sqrt_fixed) +{ + uint32_t u[ARRAY_SIZE(uv)]; + int i; + double y; + double diff; + int ret; + + BUILD_ASSERT(ARRAY_SIZE(uv) == ARRAY_SIZE(sqrt_ref_table), + "Test vector size must match reference table size"); + + ret = memcpy_s(u, sizeof(u), uv, sizeof(uv)); + zassert_equal(ret, 0, "memcpy_s failed: %d", ret); + + for (i = 0; i < ARRAY_SIZE(sqrt_ref_table); i++) { + y = (double)Q_CONVERT_QTOF(sofm_sqrt_int16(u[i]), 12); + diff = fabs(sqrt_ref_table[i] - y); + + if (diff > CMP_TOLERANCE) { + zassert_true(diff <= CMP_TOLERANCE, + "sqrt delta=%f ref=%f actual=%f index=%d", + diff, sqrt_ref_table[i], y, i); + } + } +} diff --git a/test/ztest/unit/math/advanced/functions/testcase.yaml b/test/ztest/unit/math/advanced/functions/testcase.yaml new file mode 100644 index 000000000000..1d58ccae0591 --- /dev/null +++ b/test/ztest/unit/math/advanced/functions/testcase.yaml @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright(c) 2025 Intel Corporation. All rights reserved. +# +# Math advanced functions unit tests for Ztest framework +# +# These contents may have been developed with support from one or more Intel-operated +# generative artificial intelligence solutions. +# + +tests: + sof.unit.math.advanced.functions: + tags: math advanced functions power logarithm base2 base10 exponential exp db2lin sqrt log10 + platform_allow: native_sim + integration_platforms: + - native_sim + build_only: false diff --git a/test/ztest/unit/math/basic/arithmetic/CMakeLists.txt b/test/ztest/unit/math/basic/arithmetic/CMakeLists.txt new file mode 100644 index 000000000000..b71031491abf --- /dev/null +++ b/test/ztest/unit/math/basic/arithmetic/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(test_math_arithmetic) + +set(SOF_ROOT "${PROJECT_SOURCE_DIR}/../../../../../..") + +target_include_directories(app PRIVATE + ${SOF_ROOT}/zephyr/include + ${SOF_ROOT}/src/include +) + +# Define SOF-specific configurations for unit testing +target_compile_definitions(app PRIVATE + -DCONFIG_ZEPHYR_POSIX=1 + -DCONFIG_LIBRARY=1 + -DCONFIG_NUMBERS_VECTOR_FIND=1 + -DCONFIG_NUMBERS_NORM=1 + -DUNIT_TEST=1 +) + +target_sources(app PRIVATE + test_gcd_ztest.c + test_ceil_divide_ztest.c + test_find_equal_int16_ztest.c + test_find_min_int16_ztest.c + test_find_max_abs_int32_ztest.c + test_norm_int32_ztest.c + test_crc32_ztest.c + ${SOF_ROOT}/src/math/numbers.c +) + +# Link math library for ceil_divide test +target_link_libraries(app PRIVATE m) diff --git a/test/ztest/unit/math/basic/arithmetic/prj.conf b/test/ztest/unit/math/basic/arithmetic/prj.conf new file mode 100644 index 000000000000..d34c7781cd0a --- /dev/null +++ b/test/ztest/unit/math/basic/arithmetic/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_SOF_FULL_ZEPHYR_APPLICATION=n diff --git a/test/ztest/unit/math/basic/arithmetic/test_ceil_divide_ztest.c b/test/ztest/unit/math/basic/arithmetic/test_ceil_divide_ztest.c new file mode 100644 index 000000000000..e9ad0c7833a7 --- /dev/null +++ b/test/ztest/unit/math/basic/arithmetic/test_ceil_divide_ztest.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. +// +// Converted from CMock to Ztest +// Original file: sof/test/cmocka/src/math/numbers/ceil_divide.c +// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> + +#include <zephyr/ztest.h> +#include <sof/math/numbers.h> +#include <math.h> + +/** + * @brief Test ceil_divide function with various parameter combinations + * + * Tests ceil_divide against reference ceilf implementation with multiple + * positive and negative integer combinations + */ +ZTEST(math_arithmetic_suite, test_math_numbers_ceil_divide) +{ + int params[8] = { + -1000, + 300, + 123, + -10, + 1337, + -6, + 999, + -2 + }; + + int i, j; + + for (i = 0; i < ARRAY_SIZE(params); ++i) { + for (j = 0; j < ARRAY_SIZE(params); ++j) { + int ref = ceilf((float)params[i] / (float)params[j]); + int r = ceil_divide(params[i], params[j]); + + zassert_equal(r, ref, + "ceil_divide(%d, %d) = %d, expected %d", + params[i], params[j], r, ref); + } + } +} diff --git a/test/ztest/unit/math/basic/arithmetic/test_crc32_ztest.c b/test/ztest/unit/math/basic/arithmetic/test_crc32_ztest.c new file mode 100644 index 000000000000..7485fc13dbc8 --- /dev/null +++ b/test/ztest/unit/math/basic/arithmetic/test_crc32_ztest.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. All rights reserved. +// +// Author: Tomasz Leman <tomasz.m.leman@intel.com> + +#include <zephyr/ztest.h> +#include <sof/math/numbers.h> +#include <stdint.h> + +/** + * @brief Test crc32 with an empty buffer + * + * With zero bytes the outer loop does not execute and the function returns + * ~(~base) == 0 for base == 0. + */ +ZTEST(math_arithmetic_suite, test_math_numbers_crc32_empty_buffer) +{ + uint8_t data[1] = {0}; + uint32_t result = crc32(0, data, 0); + + zassert_equal(result, 0x00000000U, + "crc32 of empty buffer with base=0 should be 0x00000000"); +} + +/** + * @brief Test crc32 with a single zero byte + * + * Exercises one iteration of the outer loop and all 8 iterations of the + * inner bit-processing loop. + */ +ZTEST(math_arithmetic_suite, test_math_numbers_crc32_single_zero_byte) +{ + uint8_t data[] = {0x00}; + uint32_t result = crc32(0, data, sizeof(data)); + + zassert_equal(result, 0xD202EF8DU, + "crc32({0x00}, base=0) should be 0xD202EF8D"); +} + +/** + * @brief Test crc32 with a single 0xFF byte + * + * Exercises the branch where (cur & 1) is false in the inner loop. + */ +ZTEST(math_arithmetic_suite, test_math_numbers_crc32_single_ff_byte) +{ + uint8_t data[] = {0xFF}; + uint32_t result = crc32(0, data, sizeof(data)); + + zassert_equal(result, 0xFF000000U, + "crc32({0xFF}, base=0) should be 0xFF000000"); +} + +/** + * @brief Test crc32 against the well-known CRC-32 check value + * + * The string "123456789" must produce 0xCBF43926 — the standard reference + * value for CRC-32 (ISO 3309 / ITU-T V.42). + */ +ZTEST(math_arithmetic_suite, test_math_numbers_crc32_known_vector_123456789) +{ + const uint8_t data[] = "123456789"; + uint32_t result = crc32(0, data, sizeof(data) - 1); /* exclude NUL */ + + zassert_equal(result, 0xCBF43926U, + "crc32(\"123456789\", base=0) should be 0xCBF43926"); +} + +/** + * @brief Test crc32 with a non-zero base + * + * A non-zero base changes the initial CRC register value (~base), allowing + * incremental / chained CRC computation. Verifies the result differs from the + * base=0 case and matches the expected precomputed value. + */ +ZTEST(math_arithmetic_suite, test_math_numbers_crc32_nonzero_base) +{ + uint8_t data[] = {0xAB, 0xCD, 0xEF}; + uint32_t result_base0 = crc32(0x00000000U, data, sizeof(data)); + uint32_t result_nonzero = crc32(0xDEADBEEFU, data, sizeof(data)); + + zassert_equal(result_base0, 0x648D3D79U, + "crc32({0xAB,0xCD,0xEF}, base=0) should be 0x648D3D79"); + zassert_equal(result_nonzero, 0x1412F659U, + "crc32({0xAB,0xCD,0xEF}, base=0xDEADBEEF) should be 0x1412F659"); + zassert_not_equal(result_base0, result_nonzero, + "Different bases must yield different CRC values"); +} + +/** + * @brief Test crc32 over a four-byte all-zeros buffer + * + * Exercises multiple iterations of the outer byte loop, producing a result + * that differs from the single-byte zero-byte case. + */ +ZTEST(math_arithmetic_suite, test_math_numbers_crc32_four_zero_bytes) +{ + uint8_t data[] = {0x00, 0x00, 0x00, 0x00}; + uint32_t result = crc32(0, data, sizeof(data)); + + zassert_equal(result, 0x2144DF1CU, + "crc32({0,0,0,0}, base=0) should be 0x2144DF1C"); +} diff --git a/test/ztest/unit/math/basic/arithmetic/test_find_equal_int16_ztest.c b/test/ztest/unit/math/basic/arithmetic/test_find_equal_int16_ztest.c new file mode 100644 index 000000000000..268b031eb3e2 --- /dev/null +++ b/test/ztest/unit/math/basic/arithmetic/test_find_equal_int16_ztest.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. +// +// Converted from CMock to Ztest +// Original tests from test/cmocka/src/math/numbers/find_equal_int16.c: +// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> + +#include <zephyr/ztest.h> +#include <sof/math/numbers.h> + +/** + * @brief Test find_equal_int16 function with array containing matches + * + * Tests that find_equal_int16 correctly finds all indices where value 123 + * appears in the array [5, 123, 5, 10, 123, 500, 123] + */ +ZTEST(math_arithmetic_suite, test_math_numbers_find_equal_int16_matches) +{ + int16_t r[4]; + int16_t vec[] = {5, 123, 5, 10, 123, 500, 123}; + int16_t template[] = {1, 4, 6}; + + int r_num = find_equal_int16(r, vec, 123, 7, 4); + + zassert_equal(r_num, 3, "Should find 3 occurrences of 123"); + zassert_mem_equal(r, template, sizeof(int16_t) * 3, + "Result indices should match expected template"); +} + +/** + * @brief Test find_equal_int16 function with no matches + * + * Tests that find_equal_int16 returns 0 when searching for value 0 + * in array [1, 2, 3, 4, 5] where it doesn't exist + */ +ZTEST(math_arithmetic_suite, test_math_numbers_find_equal_int16_no_matches) +{ + int16_t r[4]; + int16_t vec[] = {1, 2, 3, 4, 5}; + + int r_num = find_equal_int16(r, vec, 0, 5, 4); + + zassert_equal(r_num, 0, "Should find 0 occurrences of 0"); +} diff --git a/test/ztest/unit/math/basic/arithmetic/test_find_max_abs_int32_ztest.c b/test/ztest/unit/math/basic/arithmetic/test_find_max_abs_int32_ztest.c new file mode 100644 index 000000000000..7b978188c9a7 --- /dev/null +++ b/test/ztest/unit/math/basic/arithmetic/test_find_max_abs_int32_ztest.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. +// +// Converted from CMock to Ztest +// Original tests from test/cmocka/src/math/numbers/find_max_abs_int32.c: +// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> + +#include <zephyr/ztest.h> +#include <sof/math/numbers.h> +#include <sof/common.h> + +/** + * @brief Test find_max_abs_int32 function with negative maximum absolute value + * + * Tests that find_max_abs_int32 correctly finds maximum absolute value + * in array [-100, 99, 98, 50] where -100 has the largest absolute value + */ +ZTEST(math_arithmetic_suite, test_math_numbers_find_max_abs_int32_negative_max) +{ + int32_t vec[] = {-100, 99, 98, 50}; + int32_t r = find_max_abs_int32(vec, ARRAY_SIZE(vec)); + + zassert_equal(r, 100, "find_max_abs_int32([-100, 99, 98, 50]) should return 100"); +} + +/** + * @brief Test find_max_abs_int32 function with positive maximum absolute value + * + * Tests that find_max_abs_int32 correctly finds maximum absolute value + * in array [-100, 99, 98, 50, 101] where 101 has the largest absolute value + */ +ZTEST(math_arithmetic_suite, test_math_numbers_find_max_abs_int32_positive_max) +{ + int32_t vec[] = {-100, 99, 98, 50, 101}; + int32_t r = find_max_abs_int32(vec, ARRAY_SIZE(vec)); + + zassert_equal(r, 101, "find_max_abs_int32([-100, 99, 98, 50, 101]) should return 101"); +} diff --git a/test/ztest/unit/math/basic/arithmetic/test_find_min_int16_ztest.c b/test/ztest/unit/math/basic/arithmetic/test_find_min_int16_ztest.c new file mode 100644 index 000000000000..ac9225081a43 --- /dev/null +++ b/test/ztest/unit/math/basic/arithmetic/test_find_min_int16_ztest.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. +// +// Converted from CMock to Ztest +// Original tests from test/cmocka/src/math/numbers/find_min_int16.c: +// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> + +#include <zephyr/ztest.h> +#include <sof/math/numbers.h> +#include <sof/common.h> + +/** + * @brief Test find_min_int16 function with single element array + * + * Tests that find_min_int16 returns the single element when array has one item + */ +ZTEST(math_arithmetic_suite, test_math_numbers_find_min_int16_for_2_equals_2) +{ + int16_t vec[] = {2}; + int r = find_min_int16(vec, ARRAY_SIZE(vec)); + + zassert_equal(r, 2, "find_min_int16([2]) should return 2"); +} + +/** + * @brief Test find_min_int16 function with multiple elements + * + * Tests that find_min_int16 correctly finds minimum value in array [5, 2, 3, 4, 1] + */ +ZTEST(math_arithmetic_suite, test_math_numbers_find_min_int16_for_5_2_3_4_1_equals_1) +{ + int16_t vec[] = {5, 2, 3, 4, 1}; + int r = find_min_int16(vec, ARRAY_SIZE(vec)); + + zassert_equal(r, 1, "find_min_int16([5, 2, 3, 4, 1]) should return 1"); +} diff --git a/test/ztest/unit/math/basic/arithmetic/test_gcd_ztest.c b/test/ztest/unit/math/basic/arithmetic/test_gcd_ztest.c new file mode 100644 index 000000000000..508afaecb8e1 --- /dev/null +++ b/test/ztest/unit/math/basic/arithmetic/test_gcd_ztest.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. +// +// Converted from CMock to Ztest +// Original tests from test/cmocka/src/math/numbers/gcd.c: +// Author: Marcin Maka <marcin.maka@linux.intel.com> +// Janusz Jankowski <janusz.jankowski@linux.intel.com> + +#include <zephyr/ztest.h> +#include <sof/math/numbers.h> + +/** + * @brief Test GCD function with typical case + * + * Tests that gcd(5083, 391) returns 391 + */ +ZTEST(math_arithmetic_suite, test_math_numbers_gcd_for_5083_and_391_equals_391) +{ + int r; + + r = gcd(5083, 391); + zassert_equal(r, 391, "gcd(5083, 391) should equal 391"); +} + +/** + * @brief Test GCD function with small positive numbers + * + * Tests that gcd(12, 9) returns 3 + */ +ZTEST(math_arithmetic_suite, test_math_numbers_gcd_for_12_and_9_equals_3) +{ + int r; + + r = gcd(12, 9); + zassert_equal(r, 3, "gcd(12, 9) should equal 3"); +} + +/** + * @brief Test GCD function with zero second argument + * + * Tests that gcd(5, 0) returns 5 + */ +ZTEST(math_arithmetic_suite, test_math_numbers_gcd_for_5_and_0_equals_5) +{ + int r; + + r = gcd(5, 0); + zassert_equal(r, 5, "gcd(5, 0) should equal 5"); +} + +/** + * @brief Test GCD function with zero first argument + * + * Tests that gcd(0, 5) returns 5 + */ +ZTEST(math_arithmetic_suite, test_math_numbers_gcd_for_0_and_5_equals_5) +{ + int r; + + r = gcd(0, 5); + zassert_equal(r, 5, "gcd(0, 5) should equal 5"); +} + +/** + * @brief Test GCD function with both arguments zero + * + * Tests that gcd(0, 0) returns 0 + */ +ZTEST(math_arithmetic_suite, test_math_numbers_gcd_for_0_and_0_equals_0) +{ + int r; + + r = gcd(0, 0); + zassert_equal(r, 0, "gcd(0, 0) should equal 0"); +} + +/** + * @brief Test GCD function with negative first argument + * + * Tests that gcd(-4, 14) returns 2 + */ +ZTEST(math_arithmetic_suite, test_math_numbers_gcd_for_neg_4_and_14_equals_2) +{ + int r; + + r = gcd(-4, 14); + zassert_equal(r, 2, "gcd(-4, 14) should equal 2"); +} + +/** + * @brief Test GCD function with negative second argument + * + * Tests that gcd(4, -14) returns 2 + */ +ZTEST(math_arithmetic_suite, test_math_numbers_gcd_for_4_and_neg_14_equals_2) +{ + int r; + + r = gcd(4, -14); + zassert_equal(r, 2, "gcd(4, -14) should equal 2"); +} + +/** + * @brief Test GCD function with both arguments negative + * + * Tests that gcd(-4, -14) returns 2 + */ +ZTEST(math_arithmetic_suite, test_math_numbers_gcd_for_neg_4_and_neg_14_equals_2) +{ + int r; + + r = gcd(-4, -14); + zassert_equal(r, 2, "gcd(-4, -14) should equal 2"); +} + +/** + * @brief Define and initialize the math arithmetic test suite + */ +ZTEST_SUITE(math_arithmetic_suite, NULL, NULL, NULL, NULL, NULL); diff --git a/test/ztest/unit/math/basic/arithmetic/test_norm_int32_ztest.c b/test/ztest/unit/math/basic/arithmetic/test_norm_int32_ztest.c new file mode 100644 index 000000000000..4e3d1b830817 --- /dev/null +++ b/test/ztest/unit/math/basic/arithmetic/test_norm_int32_ztest.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. +// +// Converted from CMock to Ztest +// Original tests from test/cmocka/src/math/numbers/norm_int32.c: +// Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com> + +#include <zephyr/ztest.h> +#include <sof/math/numbers.h> + +/** + * @brief Test norm_int32 function with zero value + * + * Tests that norm_int32(0) returns 31 (number of leading zeros in 32-bit zero) + */ +ZTEST(math_arithmetic_suite, test_math_numbers_norm_int32_for_0_equals_31) +{ + int r = norm_int32(0); + + zassert_equal(r, 31, "norm_int32(0) should return 31"); +} + +/** + * @brief Test norm_int32 function with small positive value + * + * Tests that norm_int32(35) returns 25 (number of leading zeros) + */ +ZTEST(math_arithmetic_suite, test_math_numbers_norm_int32_for_35_equals_25) +{ + int r = norm_int32(35); + + zassert_equal(r, 25, "norm_int32(35) should return 25"); +} + +/** + * @brief Test norm_int32 function with maximum positive value + * + * Tests that norm_int32(INT32_MAX) returns 0 (no leading zeros in max int32) + */ +ZTEST(math_arithmetic_suite, test_math_numbers_norm_int32_for_int32_max_equals_0) +{ + int r = norm_int32(INT32_MAX); + + zassert_equal(r, 0, "norm_int32(INT32_MAX) should return 0"); +} diff --git a/test/ztest/unit/math/basic/arithmetic/testcase.yaml b/test/ztest/unit/math/basic/arithmetic/testcase.yaml new file mode 100644 index 000000000000..8afd7eca7daa --- /dev/null +++ b/test/ztest/unit/math/basic/arithmetic/testcase.yaml @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright(c) 2025 Intel Corporation. All rights reserved. +# +# Math basic arithmetic unit tests converted from CMock to Ztest +# +# These contents may have been developed with support from one or more Intel-operated +# generative artificial intelligence solutions. +# + +tests: + sof.unit.math.basic.arithmetic: + tags: math arithmetic numbers + platform_allow: native_sim + integration_platforms: + - native_sim + build_only: false diff --git a/test/ztest/unit/math/basic/complex/CMakeLists.txt b/test/ztest/unit/math/basic/complex/CMakeLists.txt new file mode 100644 index 000000000000..db756e341b5b --- /dev/null +++ b/test/ztest/unit/math/basic/complex/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(test_math_complex) + +set(SOF_ROOT "${PROJECT_SOURCE_DIR}/../../../../../..") + +target_include_directories(app PRIVATE + ${SOF_ROOT}/zephyr/include + ${SOF_ROOT}/src/include +) + +# Define SOF-specific configurations for unit testing +target_compile_definitions(app PRIVATE + -DCONFIG_ZEPHYR_POSIX=1 + -DCONFIG_LIBRARY=1 + -DUNIT_TEST=1 +) + +target_sources(app PRIVATE + test_complex_polar.c + ${SOF_ROOT}/src/math/complex.c + ${SOF_ROOT}/src/math/sqrt_int32.c + ${SOF_ROOT}/src/math/trig.c + ${SOF_ROOT}/src/math/atan2.c +) + +# Link math library for standard math functions +target_link_libraries(app PRIVATE m) diff --git a/test/ztest/unit/math/basic/complex/prj.conf b/test/ztest/unit/math/basic/complex/prj.conf new file mode 100644 index 000000000000..d34c7781cd0a --- /dev/null +++ b/test/ztest/unit/math/basic/complex/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_SOF_FULL_ZEPHYR_APPLICATION=n diff --git a/test/ztest/unit/math/basic/complex/test_complex_polar.c b/test/ztest/unit/math/basic/complex/test_complex_polar.c new file mode 100644 index 000000000000..22d5e1d3471b --- /dev/null +++ b/test/ztest/unit/math/basic/complex/test_complex_polar.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include <math.h> +#include <sof/common.h> +#include <sof/math/icomplex32.h> +#include <zephyr/logging/log.h> +#include <zephyr/ztest.h> + +/* Test data tables from Octave generated reference */ +#include "test_complex_polar_tables.h" + +LOG_MODULE_REGISTER(test_complex_polar, LOG_LEVEL_INF); + +#define COMPLEX_ABS_TOL 1.2e-8 +#define MAGNITUDE_ABS_TOL 7.1e-8 +#define ANGLE_ABS_TOL 2.0e-5 + +/** + * @brief Test complex to polar conversion function + * + * This test validates the icomplex32_to_polar() function against + * Octave-generated reference values. The test includes 1000 data points. + * + * Complex number values are Q1.31 -1.0 to +1.0 + * Polar magnitude values are Q2.30 0 to +2.0 + * Polar angle values are Q3.29 from -pi to +pi + */ +ZTEST(math_complex, test_icomplex32_to_polar) +{ + struct icomplex32 complex, complex_mag_max, complex_ang_max; + struct ipolar32 polar; + double ref_magnitude, ref_angle; + double magnitude, angle; + double delta_mag, delta_ang; + double magnitude_scale_q30 = 1.0 / 1073741824.0; /* 1.0 / 2^30 */ + double angle_scale_q29 = 1.0 / 536870912.0; /* 1.0 / 2^29 */ + double delta_mag_max = 0; + double delta_ang_max = 0; + int i; + + for (i = 0; i < TEST_COMPLEX_POLAR_NUM_POINTS; i++) { + complex.real = test_real_values[i]; + complex.imag = test_imag_values[i]; + ref_magnitude = magnitude_scale_q30 * test_magnitude_values[i]; + ref_angle = angle_scale_q29 * test_angle_values[i]; + sofm_icomplex32_to_polar(&complex, &polar); + + magnitude = magnitude_scale_q30 * polar.magnitude; + delta_mag = fabs(ref_magnitude - magnitude); + if (delta_mag > delta_mag_max) { + delta_mag_max = delta_mag; + complex_mag_max = complex; + } + + angle = angle_scale_q29 * polar.angle; + delta_ang = fabs(ref_angle - angle); + if (delta_ang > delta_ang_max) { + delta_ang_max = delta_ang; + complex_ang_max = complex; + } + + zassert_true(delta_mag <= MAGNITUDE_ABS_TOL, "Magnitude calc error at (%d, %d)", + complex.real, complex.imag); + zassert_true(delta_ang <= ANGLE_ABS_TOL, "Angle calc error at (%d, %d)", + complex.real, complex.imag); + } + + /* Re-run worst cases to print info */ + sofm_icomplex32_to_polar(&complex_mag_max, &polar); + printf("delta_mag_max = %g at (%d, %d) -> (%d, %d)\n", delta_mag_max, complex_mag_max.real, + complex_mag_max.imag, polar.magnitude, polar.angle); + + sofm_icomplex32_to_polar(&complex_ang_max, &polar); + printf("delta_ang_max = %g at (%d, %d) -> (%d, %d)\n", delta_ang_max, complex_ang_max.real, + complex_ang_max.imag, polar.magnitude, polar.angle); +} + +ZTEST(math_complex, test_ipolar32_to_complex) +{ + struct icomplex32 complex; + struct ipolar32 polar, polar_real_max, polar_imag_max; + double ref_real, ref_imag; + double real, imag; + double delta_real, delta_imag; + double scale_q31 = 1.0 / 2147483648.0; + double delta_real_max = 0; + double delta_imag_max = 0; + int i; + + for (i = 0; i < TEST_COMPLEX_POLAR_NUM_POINTS; i++) { + polar.magnitude = test_magnitude_values[i]; + polar.angle = test_angle_values[i]; + ref_real = scale_q31 * test_real_values[i]; + ref_imag = scale_q31 * test_imag_values[i]; + sofm_ipolar32_to_complex(&polar, &complex); + + real = scale_q31 * complex.real; + delta_real = fabs(ref_real - real); + if (delta_real > delta_real_max) { + delta_real_max = delta_real; + polar_real_max = polar; + } + + imag = scale_q31 * complex.imag; + delta_imag = fabs(ref_imag - imag); + if (delta_imag > delta_imag_max) { + delta_imag_max = delta_imag; + polar_imag_max = polar; + } + + zassert_true(delta_real <= COMPLEX_ABS_TOL, "Real calc error at (%d, %d)", + polar.magnitude, polar.angle); + zassert_true(delta_imag <= COMPLEX_ABS_TOL, "Imag calc error at (%d, %d)", + polar.magnitude, polar.angle); + } + + /* Re-run worst cases to print info */ + sofm_ipolar32_to_complex(&polar_real_max, &complex); + printf(" INFO - delta_real_max = %g at (%d, %d) -> (%d, %d)\n", delta_real_max, + polar_real_max.magnitude, polar_real_max.angle, complex.real, complex.imag); + + sofm_ipolar32_to_complex(&polar_imag_max, &complex); + printf(" INFO - delta_imag_max = %g at (%d, %d) -> (%d, %d)\n", delta_imag_max, + polar_imag_max.magnitude, polar_imag_max.angle, complex.real, complex.imag); +} + +ZTEST_SUITE(math_complex, NULL, NULL, NULL, NULL, NULL); diff --git a/test/ztest/unit/math/basic/complex/test_complex_polar_reference.m b/test/ztest/unit/math/basic/complex/test_complex_polar_reference.m new file mode 100644 index 000000000000..5f7bed37b682 --- /dev/null +++ b/test/ztest/unit/math/basic/complex/test_complex_polar_reference.m @@ -0,0 +1,78 @@ +function test_complex_polar_reference() + + % Make a box flattened spiral of (re,im) values to exercise the + % Q1.31 complex numbers range + q31_scale = 2^31; + num_points = 1000; + magnitude0 = linspace(0, sqrt(2), num_points); + angle0 = pi/4 + linspace(0, 10*2*pi, num_points); + re = max(min(magnitude0 .* cos(angle0), 1), -1); + im = max(min(magnitude0 .* sin(angle0), 1), -1); + ref_re = int32(re * q31_scale); + ref_im = int32(im * q31_scale); + re = double(ref_re)/q31_scale; + im = double(ref_im)/q31_scale; + figure(1) + plot(re, im) + grid on + + % In polar format magnitude is Q2.30 and angle Q3.29 + q29_scale = 2^29; + q30_scale = 2^30; + magnitude = sqrt(re.^2 + im.^2); + phase = angle(complex(re, im)); + ref_magnitude = int32(magnitude * q30_scale); + ref_angle = int32(phase * q29_scale); + magnitude = double(ref_magnitude)/q30_scale; + phase = double(ref_angle)/q29_scale; + + figure(2) + subplot(2,1,1); + plot(magnitude); + grid on + subplot(2,1,2); + plot(phase); + grid on + + fh = export_headerfile('test_complex_polar_tables.h'); + dn = 'TEST_COMPLEX_POLAR_NUM_POINTS'; + vl = 6; + export_define(fh, dn, num_points); + export_array(fh, 'test_real_values', dn, vl, ref_re); + export_array(fh, 'test_imag_values', dn, vl, ref_im); + export_array(fh, 'test_magnitude_values', dn, vl, ref_magnitude); + export_array(fh, 'test_angle_values', dn, vl, ref_angle); + fclose(fh); + +end + +function fh = export_headerfile(headerfn) + fh = fopen(headerfn, 'w'); + fprintf(fh, '/* SPDX-License-Identifier: BSD-3-Clause\n'); + fprintf(fh, ' *\n'); + fprintf(fh, ' * Copyright(c) %s Intel Corporation.\n', ... + datestr(now, 'yyyy')); + fprintf(fh, ' */\n\n'); +end + +function export_define(fh, dn, val) + fprintf(fh, '#define %s %d\n', dn, val); +end + +function export_array(fh, vn, size_str, vl, data) + fprintf(fh, '\n'); + fprintf(fh, 'static const int32_t %s[%s] = {\n', vn, size_str); + + n = length(data); + k = 0; + for i = 1:vl:n + fprintf(fh, '\t'); + for j = 1:min(vl, n-k) + k = k + 1; + fprintf(fh, '%12d,', data(k)); + end + fprintf(fh, '\n'); + end + + fprintf(fh, '};\n'); +end diff --git a/test/ztest/unit/math/basic/complex/test_complex_polar_tables.h b/test/ztest/unit/math/basic/complex/test_complex_polar_tables.h new file mode 100644 index 000000000000..638768767ae6 --- /dev/null +++ b/test/ztest/unit/math/basic/complex/test_complex_polar_tables.h @@ -0,0 +1,686 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + */ + +#define TEST_COMPLEX_POLAR_NUM_POINTS 1000 + +static const int32_t test_real_values[TEST_COMPLEX_POLAR_NUM_POINTS] = { + 0, 2010271, 3725920, 5124845, 6187393, 6896488, + 7237756, 7199623, 6773402, 5953363, 4736785, 3123990, + 1118360, -1273667, -4042611, -7175994, -10658392, -14471508, + -18594262, -23002899, -27671114, -32570187, -37669141, -42934909, + -48332514, -53825266, -59374967, -64942126, -70486186, -75965757, + -81338858, -86563159, -91596238, -96395831, -100920087, -105127827, + -108978795, -112433915, -115455535, -118007677, -120056267, -121569369, + -122517407, -122873369, -122613014, -121715052, -120161316, -117936927, + -115030428, -111433912, -107143132, -102157588, -96480602, -90119364, + -83084968, -75392423, -67060644, -58112422, -48574376, -38476879, + -27853971, -16743244, -5185716, 6774328, 19089497, 31709487, + 44581284, 57649387, 70856046, 84141512, 97444305, 110701494, + 123848984, 136821814, 149554472, 161981203, 174036334, 185654596, + 196771457, 207323444, 217248478, 226486192, 234978262, 242668716, + 249504251, 255434527, 260412465, 264394521, 267340956, 269216089, + 269988529, 269631397, 268122524, 265444636, 261585512, 256538120, + 250300736, 242877038, 234276169, 224512787, 213607079, 201584756, + 188477021, 174320506, 159157195, 143034304, 126004153, 108123999, + 89455850, 70066259, 50026081, 29410226, 8297371, -13230336, + -35087593, -57186288, -79435849, -101743616, -124015229, -146155020, + -168066426, -189652405, -210815858, -231460066, -251489116, -270808344, + -289324766, -306947511, -323588255, -339161636, -353585678, -366782188, + -378677155, -389201124, -398289563, -405883204, -411928378, -416377312, + -419188416, -420326545, -419763226, -417476873, -413452963, -407684185, + -400170564, -390919549, -379946071, -367272574, -352929002, -336952767, + -319388673, -300288814, -279712434, -257725762, -234401803, -209820111, + -184066521, -157232854, -129416598, -100720550, -71252444, -41124543, + -10453216, 20641515, 52036441, 83605659, 115221069, 146752903, + 178070250, 209041601, 239535398, 269420591, 298567200, 326846870, + 354133435, 380303474, 405236856, 428817285, 450932827, 471476430, + 490346422, 507446994, 522688663, 535988713, 547271612, 556469398, + 563522043, 568377780, 570993410, 571334557, 569375910, 565101409, + 558504407, 549587788, 538364050, 524855342, 509093464, 491119833, + 470985394, 448750502, 424484760, 398266816, 370184118, 340332636, + 308816539, 275747839, 241246001, 205437508, 168455409, 130438820, + 91532404, 51885823, 11653162, -29007671, -69935565, -110966841, + -151935909, -192675939, -233019531, -272799413, -311849123, -350003711, + -387100428, -422979418, -457484405, -490463364, -521769184, -551260318, + -578801413, -604263917, -627526666, -648476446, -667008521, -683027136, + -696445987, -707188646, -715188962, -720391416, -722751431, -722235644, + -718822138, -712500616, -703272542, -691151224, -676161857, -658341510, + -637739067, -614415122, -588441819, -559902651, -528892197, -495515829, + -459889360, -422138650, -382399165, -340815504, -297540866, -252736498, + -206571092, -159220151, -110865324, -61693712, -11897138, 38328592, + 88784468, 139269058, 189579315, 239511395, 288861476, 337426598, + 385005490, 431399405, 476412946, 519854889, 561538988, 601284771, + 638918316, 674273001, 707190239, 737520175, 765122358, 789866376, + 811632461, 830312042, 845808268, 858036480, 866924641, 872413711, + 874457976, 873025324, 868097468, 859670112, 847753061, 832370279, + 813559881, 791374074, 765879040, 737154758, 705294769, 670405888, + 632607856, 592032937, 548825466, 503141340, 455147462, 405021134, + 352949406, 299128380, 243762474, 187063647, 129250588, 70547873, + 11185092, -48604046, -108582637, -168511515, -228150215, -287257925, + -345594471, -402921282, -459002370, -513605298, -566502143, -617470444, + -666294131, -712764442, -756680808, -797851714, -836095524, -871241275, + -903129435, -931612608, -956556208, -977839072, -995354034, -1009008434, + -1018724582, -1024440155, -1026108541, -1023699117, -1017197463, -1006605519, + -991941664, -973240745, -950554022, -923949063, -893509556, -859335070, + -821540743, -780256901, -735628623, -687815235, -636989754, -583338260, + -527059225, -468362778, -407469927, -344611725, -280028399, -213968429, + -146687596, -78447990, -9516990, 59833783, 129329538, 198693400, + 267647516, 335914167, 403216884, 469281571, 533837615, 596618999, + 657365393, 715823231, 771746768, 824899108, 875053204, 921992824, + 965513473, 1005423279, 1041543829, 1073710959, 1101775481, 1125603867, + 1145078861, 1160100036, 1170584284, 1176466239, 1177698625, 1174252547, + 1166117690, 1153302463, 1135834055, 1113758421, 1087140193, 1056062514, + 1020626795, 980952399, 937176255, 889452389, 837951397, 782859836, + 724379560, 662726978, 598132266, 530838500, 461100754, 389185126, + 315367731, 239933637, 163175768, 85393765, 6892818, -72017533, + -151024619, -229813879, -308070111, -385478738, -461727067, -536505555, + -609509063, -680438101, -749000052, -814910383, -877893819, -937685487, + -994032034, -1046692688, -1095440283, -1140062237, -1180361463, -1216157237, + -1247285993, -1273602059, -1294978319, -1311306812, -1322499248, -1328487452, + -1329223727, -1324681139, -1314853718, -1299756576, -1279425943, -1253919113, + -1223314312, -1187710477, -1147226950, -1102003096, -1052197829, -997989064, + -939573091, -877163865, -810992232, -741305080, -668364414, -592446383, + -513840229, -432847191, -349779351, -264958429, -178714543, -91384921, + -3312582, 85155009, 173667311, 261872102, 349416872, 435950238, + 521123353, 604591309, 686014536, 765060179, 841403464, 914729020, + 984732190, 1051120287, 1113613817, 1171947650, 1225872142, 1275154193, + 1319578251, 1358947246, 1393083452, 1421829276, 1445047976, 1462624287, + 1474464972, 1480499286, 1480679346, 1474980420, 1463401119, 1445963494, + 1422713045, 1393718635, 1359072305, 1318889005, 1273306222, 1222483522, + 1166602002, 1105863652, 1040490631, 970724462, 896825138, 819070164, + 737753515, 653184524, 565686712, 475596548, 383262159, 289041982, + 193303378, 96421195, -1223696, -99245902, -197257024, -294867199, + -391686652, -487327250, -581404058, -673536888, -763351836, -850482796, + -934572954, -1015276244, -1092258774, -1165200200, -1233795059, -1297754046, + -1356805225, -1410695180, -1459190100, -1502076781, -1539163558, -1570281144, + -1595283397, -1614047983, -1626476954, -1632497230, -1632060983, -1625145921, + -1611755471, -1591918856, -1565691082, -1533152805, -1494410107, -1449594166, + -1398860823, -1342390050, -1280385322, -1213072890, -1140700959, -1063538782, + -981875656, -896019849, -806297430, -713051040, -616638580, -517431842, + -415815073, -312183493, -206941750, -100502348, 6715973, 114289887, + 221793148, 328798283, 434878288, 539608337, 642567479, 743340331, + 841518752, 936703496, 1028505836, 1116549146, 1200470449, 1279921905, + 1354572256, 1424108199, 1488235698, 1546681223, 1599192907, 1645541631, + 1685522007, 1718953282, 1745680143, 1765573419, 1778530688, 1784476774, + 1783364142, 1775173175, 1759912353, 1737618309, 1708355783, 1672217452, + 1629323661, 1579822034, 1523886975, 1461719066, 1393544352, 1319613531, + 1240201029, 1155603995, 1066141184, 972151767, 873994039, 772044064, + 666694228, 558351735, 447437031, 334382174, 219629153, 103628158, + -13164188, -130286620, -247275059, -363664447, -478990597, -592792047, + -704611899, -813999660, -920513054, -1023719807, -1123199405, -1218544801, + -1309364080, -1395282072, -1475941891, -1551006421, -1620159719, -1683108337, + -1739582565, -1789337578, -1832154489, -1867841304, -1896233769, -1917196112, + -1930621670, -1936433411, -1934584326, -1925057716, -1907867350, -1883057503, + -1850702880, -1810908409, -1763808919, -1709568693, -1648380911, -1580466964, + -1506075665, -1425482338, -1338987809, -1246917285, -1149619133, -1047463566, + -940841237, -830161746, -715852069, -598354909, -478126986, -355637260, + -231365102, -105798420, 20568260, 147235736, 273702109, 399464766, + 524022380, 646876907, 767535579, 885512881, 1000332498, 1111529244, + 1218650944, 1321260268, 1418936519, 1511277353, 1597900434, 1678445014, + 1752573434, 1819972530, 1880354956, 1933460397, 1979056689, 2016940822, + 2046939832, 2068911577, 2082745395, 2088362629, 2085717041, 2074795083, + 2055616049, 2028232093, 1992728115, 1949221519, 1897861838, 1838830236, + 1772338873, 1698630153, 1617975845, 1530676089, 1437058282, 1337475852, + 1232306929, 1121952911, 1006836935, 887402254, 764110532, 637440063, + 507883912, 375948001, 242149128, 107012950, -28928090, -165136854, + -301073636, -436198297, -569972415, -701861428, -831336767, -957877980, + -1080974821, -1200129303, -1314857719, -1424692595, -1529184604, -1627904392, + -1720444345, -1806420269, -1885472979, -1957269800, -2021505955, -2077905857, + -2126224286, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2134427233, -2087152629, + -2031478388, -1967602767, -1895757115, -1816205050, -1729241491, -1635191576, + -1534409444, -1427276909, -1314202015, -1195617484, -1071979063, -943763772, + -811468066, -675605914, -536706801, -395313667, -251980784, -107271583, + 38243559, 183989571, 329388955, 473864078, 616839468, 757744102, + 896013690, 1031092931, 1162437746, 1289517467, 1411816980, 1528838814, + 1640105159, 1745159817, 1843570071, 1934928464, 2018854482, 2094996135, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2095882397, 2018631901, 1933188085, + 1839869214, 1739025602, 1631038305, 1516317685, 1395301849, 1268454981, + 1136265566, 999244503, 857923137, 712851198, 564594663, 413733548, + 260859639, 106574173, -48514532, -203793467, -358647365, -512461128, + -664622282, -814523405, -961564559, -1105155685, -1244718977, -1379691200, + -1509525966, -1633695942, -1751694994, -1863040244, -1967274048, -2063965870, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2140959504, -2049575701, -1949855636, -1842174985, -1726941891, -1604595423, + -1475603904, -1340463117, -1199694407, -1053842666, -903474228, -749174669, + -591546527, -431206951, -268785283, -104920590, 59740851, 224548104, + 388848145, 551988449, 713319584, 872197794, 1027987568, 1180064182, + 1327816205, 1470647954, 1607981896, 1739260983, 1863950908, 1981542280, + 2091552701, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2059197392, 1944636555, + 1822117240, 1692107383, 1555105670, 1411639621, 1262263565, 1107556498, + 948119841, 784575098, 617561439, 447733201, 275757323, 102310727, + -71922343, -246253024, -419990557, -592445023, -762930082, -930765707, + -1095280893, -1255816341, -1411727102, -1562385162, -1707181977, -1845530925, + -1976869684, -2100662514, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2046407157, -1916561405, -1778850838, -1633804651, -1481982238, + -1323971036, -1160384254, -991858494, -819051274, -642638465, -463311644, + -281775385, -98744494, 85058813, 268907750, 452073843, 633829815, + 813452467, 990225566, 1163442693, 1332410066, 1496449324, 1654900245, + 1807123402, 1952502745, 2090448093, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, +}; + +static const int32_t test_imag_values[TEST_COMPLEX_POLAR_NUM_POINTS] = { + 0, 2280495, 4804675, 7544043, 10468320, 13545649, + 16742800, 20025381, 23358065, 26704813, 30029111, 33294205, + 36463340, 39499998, 42368139, 45032439, 47458523, 49613195, + 51464665, 52982763, 54139155, 54907533, 55263817, 55186324, + 54655939, 53656265, 52173763, 50197872, 47721119, 44739207, + 41251086, 37259012, 32768581, 27788749, 22331828, 16413469, + 10052626, 3271493, -3904569, -11447125, -19324782, -27503316, + -35945824, -44612882, -53462730, -62451464, -71533245, -80660524, + -89784269, -98854220, -107819134, -116627055, -125225582, -133562147, + -141584294, -149239968, -156477796, -163247376, -169499562, -175186750, + -180263151, -184685069, -188411163, -191402709, -193623847, -195041816, + -195627177, -195354030, -194200203, -192147436, -189181540, -185292545, + -180474822, -174727190, -168053001, -160460202, -151961376, -142573766, + -132319265, -121224392, -109320247, -96642432, -83230957, -69130128, + -54388396, -39058203, -23195794, -6861013, 9882924, 26969672, + 44330020, 61892171, 79582039, 97323560, 115039017, 132649379, + 150074644, 167234202, 184047196, 200432896, 216311074, 231602379, + 246228722, 260113649, 273182721, 285363882, 296587829, 306788366, + 315902751, 323872039, 330641397, 336160422, 340383425, 343269713, + 344783842, 344895851, 343581478, 340822348, 336606140, 330926726, + 323784289, 315185406, 305143109, 293676920, 280812849, 266583368, + 251027358, 234190024, 216122776, 196883092, 176534343, 155145589, + 132791360, 109551391, 85510349, 60757523, 35386492, 9494776, + -16816541, -43443203, -70278199, -97212191, -124133959, -150930858, + -177489291, -203695186, -229434484, -254593631, -279060074, -302722755, + -325472612, -347203067, -367810515, -387194804, -405259702, -421913360, + -437068750, -450644099, -462563293, -472756271, -481159391, -487715772, + -492375618, -495096503, -495843637, -494590097, -491317033, -486013829, + -478678244, -469316510, -457943399, -444582251, -429264969, -412031974, + -392932124, -372022602, -349368756, -325043912, -299129152, -271713045, + -242891359, -212766730, -181448298, -149051321, -115696746, -81510765, + -46624336, -11172682, 24705234, 60867249, 97168571, 133462352, + 169600285, 205433208, 240811719, 275586798, 309610431, 342736240, + 374820102, 405720778, 435300526, 463425704, 489967369, 514801854, + 537811332, 558884360, 577916399, 594810315, 609476843, 621835035, + 631812669, 639346627, 644383234, 646878573, 646798747, 644120109, + 638829452, 630924157, 620412291, 607312670, 591654878, 573479230, + 552836704, 529788822, 504407482, 476774755, 446982629, 415132713, + 381335905, 345712005, 308389303, 269504118, 229200302, 187628715, + 144946659, 101317283, 56908963, 11894650, -33548800, -79241326, + -125000369, -170641608, -215979698, -260829021, -305004451, -348322109, + -390600134, -431659438, -471324465, -509423935, -545791581, -580266864, + -612695679, -642931032, -670833695, -696272835, -719126612, -739282748, + -756639051, -771103915, -782596769, -791048488, -796401763, -798611419, + -797644690, -793481442, -786114351, -775549022, -761804063, -744911098, + -724914741, -701872496, -675854626, -646943948, -615235591, -580836694, + -543866053, -504453723, -462740564, -418877743, -373026195, -325356033, + -276045917, -225282393, -173259184, -120176451, -66240028, -11660620, + 43347018, 98564927, 153772807, 208748896, 263270860, 317116694, + 370065621, 421899000, 472401226, 521360624, 568570334, 613829180, + 656942528, 697723108, 735991831, 771578561, 804322866, 834074727, + 860695216, 884057126, 904045564, 920558492, 933507222, 942816860, + 948426696, 950290537, 948376986, 942669659, 933167350, 919884121, + 902849348, 882107693, 857719013, 829758219, 798315059, 763493846, + 725413129, 684205295, 640016118, 593004254, 543340674, 491208047, + 436800076, 380320774, 321983708, 262011190, 200633431, 138087661, + 74617206, 10470549, -54099646, -118837530, -183485081, -247783134, + -311472418, -374294603, -435993344, -496315331, -555011323, -611837177, + -666554862, -718933455, -768750105, -815790985, -859852197, -900740653, + -938274911, -972285972, -1002618031, -1029129172, -1051692022, -1070194342, + -1084539559, -1094647244, -1100453524, -1101911425, -1098991157, -1091680325, + -1079984072, -1063925154, -1043543944, -1018898360, -990063728, -957132573, + -920214336, -879435024, -834936792, -786877452, -735429928, -680781633, + -623133796, -562700722, -499709000, -434396656, -367012256, -297813959, + -227068533, -155050322, -82040188, -8324413, 65806424, 140058591, + 214136368, 287743222, 360582998, 432361108, 502785721, 571568950, + 638428026, 703086462, 765275191, 824733684, 881211039, 934467032, + 984273140, 1030413508, 1072685885, 1110902496, 1144890869, 1174494601, + 1199574061, 1220007038, 1235689307, 1246535140, 1252477736, 1253469580, + 1249482727, 1240509005, 1226560146, 1207667830, 1183883652, 1155279014, + 1121944928, 1083991746, 1041548804, 994764001, 943803283, 888850071, + 830104601, 767783203, 702117507, 633353587, 561751041, 487582013, + 411130162, 332689574, 252563637, 171063864, 88508687, 5222207, + -78467074, -162227550, -245725826, -328628042, -410601210, -491314552, + -570440832, -647657683, -722648920, -795105831, -864728447, -931226783, + -994322041, -1053747774, -1109251010, -1160593320, -1207551838, -1249920218, + -1287509538, -1320149123, -1347687313, -1369992150, -1386951992, -1398476047, + -1404494823, -1404960503, -1399847223, -1389151273, -1372891207, -1351107860, + -1323864282, -1291245579, -1253358666, -1210331933, -1162314819, -1109477306, + -1052009323, -990120072, -924037270, -854006320, -780289398, -703164480, + -622924289, -539875196, -454336043, -366636924, -277117911, -186127736, + -94022433, -1163946, 92081298, 185343827, 278252596, 370436457, + 461525644, 551153259, 638956742, 724579345, 807671574, 887892617, + 964911740, 1038409650, 1108079811, 1173629724, 1234782149, 1291276269, + 1342868805, 1389335049, 1430469836, 1466088443, 1496027403, 1520145244, + 1538323138, 1550465462, 1556500276, 1556379693, 1550080173, 1537602702, + 1518972892, 1494240964, 1463481650, 1426793984, 1384301002, 1336149343, + 1282508749, 1223571484, 1159551643, 1090684388, 1017225083, 939448359, + 857647080, 772131254, 683226852, 591274574, 496628537, 399654920, + 300730542, 200241404, 98581176, -3850338, -106648779, -209406823, + -311715799, -413167311, -513354874, -611875536, -708331500, -802331731, + -893493540, -981444140, -1065822168, -1146279171, -1222481036, -1294109383, + -1360862883, -1422458528, -1478632818, -1529142890, -1573767555, -1612308258, + -1644589953, -1670461882, -1689798263, -1702498883, -1708489584, -1707722653, + -1700177108, -1685858871, -1664800843, -1637062866, -1602731579, -1561920169, + -1514768007, -1461440191, -1402126973, -1337043088, -1266426988, -1190539966, + -1109665203, -1024106706, -934188176, -840251780, -742656855, -641778531, + -538006296, -431742487, -323400735, -213404354, -102184684, 9820593, + 122169183, 234415920, 346114537, 456819433, 566087456, 673479672, + 778563134, 880912619, 980112355, 1075757704, 1167456813, 1254832216, + 1337522390, 1415183239, 1487489533, 1554136256, 1614839895, 1669339637, + 1717398481, 1758804263, 1793370582, 1820937624, 1841372888, 1854571804, + 1860458238, 1858984887, 1850133564, 1833915363, 1810370710, 1779569298, + 1741609902, 1696620080, 1644755759, 1586200705, 1521165879, 1449888687, + 1372632115, 1289683769, 1201354806, 1107978767, 1009910327, 907523945, + 801212438, 691385473, 578467993, 462898573, 345127714, 225616089, + 104832744, -16746748, -138642154, -260370483, -381447896, -501391630, + -619721926, -735963941, -849649659, -960319774, -1067525541, -1170830599, + -1269812742, -1364065646, -1453200533, -1536847770, -1614658403, -1686305606, + -1751486049, -1809921176, -1861358393, -1905572145, -1942364901, -1971568024, + -1993042528, -2006679721, -2012401729, -2010161898, -1999945075, -1981767762, + -1955678145, -1921755996, -1880112455, -1830889673, -1774260348, -1710427123, + -1639621871, -1562104859, -1478163796, -1388112772, -1292291083, -1191061960, + -1084811190, -973945653, -858891760, -740093820, -618012319, -493122141, + -365910719, -236876134, -106525162, 24628712, 156067320, 287269855, + 417714940, 546882693, 674256803, 799326595, 921589072, 1040550941, + 1155730603, 1266660098, 1372887010, 1473976304, 1569512113, 1659099440, + 1742365791, 1818962720, 1888567281, 1950883387, 2005643062, 2052607583, + 2091568519, 2122348637, 2144802698, 2147483647, 2147483647, 2147483647, + 2147483647, 2129411660, 2100718805, 2063618704, 2018235083, 1964724911, + 1903277871, 1834115693, 1757491361, 1673688197, 1583018816, 1485823964, + 1382471243, 1273353720, 1158888438, 1039514824, 915692999, 787902012, + 656637981, 522412174, 385749013, 247184030, 107261763, -33466378, + -174444288, -315113364, -454914717, -593291393, -729690591, -863565873, + -994379352, -1121603851, -1244725030, -1363243461, -1476676654, -1584561022, + -1686453767, -1781934703, -1870607982, -1952103729, -2026079585, -2092222141, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2098121767, -2031804437, -1957262673, -1874770773, -1784635305, + -1687193971, -1582814348, -1471892505, -1354851496, -1232139760, -1104229395, + -971614348, -834808505, -694343705, -550767672, -404641875, -256539338, + -107042392, 43259617, 193772649, 343900318, 493046257, 640616484, + 786021771, 928679993, 1068018461, 1203476217, 1334506296, 1460577931, + 1581178701, 1695816616, 1804022117, 1905350001, 1999381249, 2085724755, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2079864332, + 1991456543, 1894942798, 1790686072, 1679080943, 1560552105, 1435552756, + 1304562862, 1168087321, 1026654016, 880811774, 731128237, 578187655, + 422588602, 264941637, 105866910, -54008284, -214051971, -373630004, + -532108568, -688856702, -843248811, -994667159, -1142504345, -1286165736, + -1425071859, -1558660737, -1686390161, -1807739892, -1922213774, -2029341764, + -2128681858, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2107545118, -2004607307, -1893491944, -1774620780, + -1648447297, -1515454979, -1376155464, -1231086572, -1080810233, -925910312, + -766990339, -604671161, -439588511, -272390527, -103735200, 65712212, + 235281808, 404301694, 572100644, 738010765, 901370158, 1061525555, + 1217834934, 1369670091, 1516419162, 1657489093, 1792308030, 1920327639, + 2041025335, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2113625473, + 1995608424, 1869430904, 1735575344, 1594555664, 1446915305, 1293225136, + 1134081244, 970102629, 801928792, 630217245, 455640938, 278885624, + 100647162, -78371218, -257461692, -435914639, -613021457, -788077372, + -960384243, -1129253349, -1294008139, -1453986944, -1608545631, -1757060198, + -1898929290, -2033576637, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2097032362, -1963508376, -1821933528, -1672852323, + -1516840140, -1354501017, -1186465312, -1013387253, -835942395, -654824984, + -470745238, -284426564, -96602715, 91985099, 280591136, 468468072, + 654869963, 839055203, 1020289478, 1197848691, 1371021856, 1539113946, + 1701448678, 1857371236, 2006250910, 2147483647, +}; + +static const int32_t test_magnitude_values[TEST_COMPLEX_POLAR_NUM_POINTS] = { + 0, 1520020, 3040040, 4560061, 6080081, 7600101, + 9120121, 10640142, 12160162, 13680182, 15200203, 16720223, + 18240243, 19760264, 21280284, 22800304, 24320324, 25840345, + 27360365, 28880385, 30400406, 31920426, 33440446, 34960466, + 36480486, 38000507, 39520527, 41040547, 42560567, 44080588, + 45600608, 47120628, 48640648, 50160669, 51680689, 53200710, + 54720730, 56240750, 57760770, 59280791, 60800811, 62320831, + 63840852, 65360871, 66880892, 68400912, 69920932, 71440953, + 72960973, 74480993, 76001014, 77521034, 79041054, 80561074, + 82081094, 83601115, 85121135, 86641156, 88161176, 89681196, + 91201216, 92721237, 94241257, 95761277, 97281297, 98801318, + 100321338, 101841358, 103361378, 104881399, 106401419, 107921439, + 109441459, 110961479, 112481500, 114001520, 115521541, 117041561, + 118561581, 120081601, 121601622, 123121642, 124641662, 126161682, + 127681703, 129201723, 130721743, 132241764, 133761784, 135281804, + 136801824, 138321845, 139841865, 141361885, 142881905, 144401926, + 145921946, 147441966, 148961987, 150482007, 152002027, 153522047, + 155042068, 156562088, 158082108, 159602128, 161122148, 162642169, + 164162189, 165682210, 167202229, 168722250, 170242270, 171762290, + 173282311, 174802331, 176322351, 177842371, 179362392, 180882412, + 182402432, 183922453, 185442473, 186962493, 188482514, 190002534, + 191522554, 193042574, 194562595, 196082615, 197602635, 199122655, + 200642676, 202162696, 203682716, 205202736, 206722757, 208242777, + 209762797, 211282818, 212802838, 214322858, 215842878, 217362899, + 218882919, 220402939, 221922959, 223442980, 224963000, 226483020, + 228003040, 229523061, 231043081, 232563101, 234083122, 235603142, + 237123162, 238643183, 240163203, 241683223, 243203243, 244723263, + 246243284, 247763304, 249283325, 250803344, 252323365, 253843385, + 255363405, 256883426, 258403446, 259923466, 261443486, 262963507, + 264483527, 266003547, 267523568, 269043588, 270563608, 272083628, + 273603648, 275123669, 276643689, 278163709, 279683730, 281203750, + 282723771, 284243790, 285763811, 287283831, 288803851, 290323872, + 291843892, 293363912, 294883932, 296403953, 297923973, 299443993, + 300964014, 302484034, 304004054, 305524074, 307044095, 308564115, + 310084135, 311604155, 313124176, 314644196, 316164216, 317684237, + 319204257, 320724277, 322244297, 323764318, 325284338, 326804358, + 328324378, 329844399, 331364419, 332884439, 334404460, 335924480, + 337444500, 338964520, 340484540, 342004561, 343524581, 345044601, + 346564622, 348084642, 349604662, 351124682, 352644703, 354164723, + 355684743, 357204764, 358724784, 360244804, 361764825, 363284845, + 364804865, 366324885, 367844906, 369364925, 370884946, 372404966, + 373924987, 375445007, 376965027, 378485047, 380005068, 381525088, + 383045108, 384565128, 386085149, 387605169, 389125189, 390645210, + 392165230, 393685250, 395205270, 396725290, 398245311, 399765331, + 401285351, 402805372, 404325392, 405845412, 407365433, 408885452, + 410405473, 411925493, 413445514, 414965534, 416485554, 418005574, + 419525595, 421045615, 422565635, 424085655, 425605676, 427125696, + 428645716, 430165737, 431685757, 433205777, 434725797, 436245818, + 437765838, 439285858, 440805879, 442325899, 443845919, 445365939, + 446885960, 448405980, 449926000, 451446020, 452966041, 454486061, + 456006081, 457526101, 459046122, 460566142, 462086162, 463606182, + 465126203, 466646223, 468166243, 469686264, 471206284, 472726304, + 474246324, 475766344, 477286365, 478806385, 480326406, 481846426, + 483366446, 484886466, 486406487, 487926507, 489446527, 490966547, + 492486568, 494006588, 495526608, 497046628, 498566649, 500086669, + 501606689, 503126709, 504646730, 506166750, 507686770, 509206791, + 510726811, 512246831, 513766851, 515286872, 516806892, 518326912, + 519846932, 521366953, 522886973, 524406993, 525927014, 527447034, + 528967054, 530487074, 532007095, 533527115, 535047135, 536567156, + 538087176, 539607196, 541127216, 542647237, 544167257, 545687277, + 547207298, 548727318, 550247338, 551767358, 553287378, 554807399, + 556327419, 557847439, 559367459, 560887480, 562407500, 563927520, + 565447540, 566967561, 568487581, 570007601, 571527622, 573047642, + 574567662, 576087683, 577607703, 579127723, 580647743, 582167764, + 583687784, 585207804, 586727824, 588247845, 589767865, 591287885, + 592807905, 594327926, 595847946, 597367966, 598887986, 600408007, + 601928027, 603448047, 604968068, 606488088, 608008108, 609528128, + 611048149, 612568169, 614088189, 615608209, 617128230, 618648250, + 620168270, 621688291, 623208311, 624728331, 626248351, 627768372, + 629288392, 630808412, 632328432, 633848453, 635368473, 636888493, + 638408513, 639928534, 641448554, 642968574, 644488595, 646008615, + 647528635, 649048656, 650568676, 652088696, 653608716, 655128736, + 656648757, 658168777, 659688797, 661208817, 662728838, 664248858, + 665768878, 667288899, 668808919, 670328939, 671848959, 673368980, + 674889000, 676409020, 677929041, 679449061, 680969081, 682489101, + 684009122, 685529142, 687049162, 688569182, 690089203, 691609223, + 693129243, 694649264, 696169284, 697689304, 699209324, 700729345, + 702249365, 703769385, 705289406, 706809426, 708329446, 709849466, + 711369487, 712889507, 714409527, 715929547, 717449568, 718969588, + 720489608, 722009629, 723529649, 725049669, 726569689, 728089710, + 729609730, 731129750, 732649770, 734169790, 735689811, 737209831, + 738729851, 740249872, 741769892, 743289912, 744809933, 746329953, + 747849973, 749369993, 750890013, 752410034, 753930054, 755450075, + 756970095, 758490115, 760010135, 761530155, 763050176, 764570196, + 766090216, 767610237, 769130257, 770650277, 772170297, 773690318, + 775210338, 776730358, 778250379, 779770399, 781290419, 782810439, + 784330460, 785850480, 787370500, 788890520, 790410540, 791930561, + 793450581, 794970601, 796490622, 798010642, 799530662, 801050682, + 802570703, 804090723, 805610743, 807130764, 808650784, 810170804, + 811690824, 813210845, 814730865, 816250885, 817770905, 819290925, + 820810946, 822330966, 823850986, 825371007, 826891027, 828411047, + 829931068, 831451088, 832971108, 834491129, 836011148, 837531169, + 839051189, 840571210, 842091230, 843611250, 845131270, 846651290, + 848171311, 849691331, 851211351, 852731372, 854251392, 855771412, + 857291432, 858811453, 860331473, 861851493, 863371513, 864891534, + 866411554, 867931574, 869451595, 870971615, 872491635, 874011655, + 875531676, 877051696, 878571716, 880091737, 881611757, 883131777, + 884651797, 886171818, 887691838, 889211858, 890731879, 892251898, + 893771919, 895291939, 896811960, 898331980, 899852000, 901372020, + 902892040, 904412061, 905932081, 907452101, 908972122, 910492142, + 912012162, 913532182, 915052203, 916572223, 918092243, 919612263, + 921132284, 922652304, 924172324, 925692345, 927212365, 928732385, + 930252405, 931772426, 933292446, 934812466, 936332486, 937852507, + 939372527, 940892547, 942412567, 943932588, 945452608, 946972629, + 948492649, 950012669, 951532689, 953052709, 954572730, 956092750, + 957612770, 959132791, 960652811, 962172831, 963692851, 965212872, + 966732892, 968252912, 969772932, 971292953, 972812973, 974332993, + 975853013, 977373034, 978893054, 980413074, 981933095, 983453115, + 984973135, 986493155, 988013176, 989533196, 991053216, 992573236, + 994093257, 995613277, 997133297, 998653318, 1000173338, 1001693358, + 1003213378, 1004733399, 1006253419, 1007773439, 1009293459, 1010813480, + 1012333500, 1013853520, 1015373541, 1016893561, 1018413581, 1019933601, + 1021453621, 1022973642, 1024493662, 1026013682, 1027533703, 1029053723, + 1030573743, 1032093763, 1033613784, 1035133804, 1036653824, 1038173844, + 1039693865, 1041213885, 1042733905, 1044253925, 1045773946, 1047293966, + 1048813986, 1050334007, 1051854027, 1053374047, 1054894067, 1056414088, + 1057934108, 1059454128, 1060974149, 1062494169, 1064014189, 1065534210, + 1067054230, 1068574250, 1070094270, 1071614290, 1073134311, 1074654331, + 1076174351, 1077694372, 1079214392, 1075074159, 1073839239, 1076911811, + 1084242979, 1086814493, 1088334513, 1089854534, 1091374554, 1092894574, + 1094414594, 1095934615, 1097454635, 1098974655, 1100494676, 1102014696, + 1103534716, 1105054737, 1106574756, 1108094777, 1109614797, 1111134818, + 1112654838, 1105056616, 1090927165, 1080831389, 1075080358, 1073872201, + 1077278612, 1085239887, 1097569294, 1113965966, 1127855041, 1129375061, + 1130895081, 1132415101, 1133935122, 1135455142, 1136975162, 1138495183, + 1140015203, 1141535223, 1143055243, 1144575264, 1146095284, 1147615304, + 1147842154, 1125625312, 1106767840, 1091782821, 1081108266, 1075080603, + 1073912076, 1077675529, 1086299119, 1099571869, 1117159003, 1138624405, + 1163456762, 1168895588, 1170415608, 1171935628, 1173455649, 1174975669, + 1176495689, 1178015709, 1179535730, 1181055750, 1182575770, 1184095790, + 1178528792, 1152019016, 1128472330, 1108493464, 1092636841, 1081376258, + 1075074891, 1073959660, 1078104106, 1087422807, 1101678336, 1120499386, + 1143406778, 1169843210, 1199202803, 1208416115, 1209936135, 1211456155, + 1212976175, 1214496196, 1216016216, 1217536236, 1219056257, 1220576277, + 1214782434, 1184290462, 1156256689, 1131353486, 1110231186, 1093487707, + 1081634615, 1075063262, 1074015791, 1078565922, 1088613102, 1103891120, + 1123989412, 1148383036, 1176466363, 1207585929, 1241069231, 1247936642, + 1249456662, 1250976682, 1252496703, 1254016723, 1255536743, 1257056764, + 1256340945, 1222304586, 1190137018, 1160551098, 1134265678, 1111978752, + 1094333946, 1081882629, 1075045792, 1074081342, 1079062587, 1089872171, + 1106212632, 1127631320, 1153554786, 1183326749, 1216244445, 1251589821, + 1285937149, 1287457169, 1288977189, 1290497210, 1292017230, 1293537250, + 1295057270, 1265753470, 1229934215, 1196063374, 1164898247, 1137205863, + 1113733957, 1095174125, 1082119627, 1075022598, 1074157226, 1079595743, + 1091202192, 1108645262, 1131427290, 1158923532, 1190424762, 1225177282, + 1262416521, 1301392660, 1325457676, 1326977696, 1328497716, 1330017737, + 1331537757, 1314181286, 1275293091, 1237665157, 1202064555, 1169294223, + 1140171061, 1115494647, 1096006851, 1082344979, 1074993838, 1074244398, + 1080167064, 1092605358, 1111191383, 1135379441, 1164490680, 1197760673, + 1234383241, 1273546443, 1314459308, 1356369797, 1364978203, 1366498223, + 1368018243, 1367014394, 1325711098, 1284952570, 1245491401, 1208135693, + 1173735197, 1143158355, 1117258715, 1096830779, 1082558095, 1074959708, + 1074343851, 1080778257, 1094083873, 1113853348, 1139489834, 1170257537, + 1205334627, 1243860995, 1284976598, 1327849145, 1371692050, 1402978709, + 1404498730, 1406018750, 1380571240, 1337375582, 1294724866, 1253407084, + 1214272034, 1178217417, 1146164888, 1119024105, 1097644601, 1082758423, + 1074920447, 1074456615, 1081431059, 1095639949, 1116633481, 1143760460, + 1176225309, 1213146647, 1253609098, 1296703903, 1341557403, 1387348781, + 1433319440, 1442499237, 1439174558, 1394273675, 1349166748, 1304603136, + 1261406489, 1220468930, 1182737216, 1149187866, 1120788809, 1098447051, + 1082945449, 1074876329, 1074583759, 1082127233, 1097275806, 1119534083, + 1148193248, 1182395100, 1221196638, 1263625993, 1308725200, 1355579289, + 1403333621, 1451202345, 1480499743, 1454909890, 1408112903, 1361076863, + 1314580734, 1269484051, 1226721846, 1187291007, 1152224555, 1122550865, + 1099236905, 1083118701, 1074827672, 1074726392, 1082868575, 1098993670, + 1122557424, 1152790055, 1188767916, 1229484394, 1273910019, 1321037258, + 1369909999, 1419640265, 1469415592, 1518500249, +}; + +static const int32_t test_angle_values[TEST_COMPLEX_POLAR_NUM_POINTS] = { + 0, 455423907, 489190152, 522956546, 556722871, 590489235, + 624255603, 658021957, 691788319, 725554680, 759321041, 793087401, + 826853754, 860620121, 894386476, 928152832, 961919193, 995685560, + 1029451923, 1063218283, 1096984641, 1130751002, 1164517360, 1198283724, + 1232050084, 1265816445, 1299582805, 1333349167, 1367115527, 1400881883, + 1434648246, 1468414607, 1502180969, 1535947328, 1569713687, 1603480052, + 1637246411, 1671012770, -1668480294, -1634713934, -1600947572, -1567181214, + -1533414852, -1499648491, -1465882130, -1432115770, -1398349410, -1364583047, + -1330816690, -1297050328, -1263283967, -1229517604, -1195751244, -1161984884, + -1128218524, -1094452163, -1060685802, -1026919441, -993153083, -959386722, + -925620362, -891853999, -858087640, -824321279, -790554919, -756788558, + -723022197, -689255837, -655489475, -621723114, -587956754, -554190394, + -520424032, -486657673, -452891312, -419124952, -385358590, -351592230, + -317825870, -284059508, -250293147, -216526788, -182760426, -148994067, + -115227706, -81461345, -47694984, -13928624, 19837736, 53604097, + 87370458, 121136819, 154903180, 188669541, 222435900, 256202261, + 289968622, 323734982, 357501343, 391267703, 425034064, 458800425, + 492566785, 526333147, 560099507, 593865868, 627632228, 661398588, + 695164950, 728931309, 762697671, 796464031, 830230391, 863996753, + 897763113, 931529473, 965295834, 999062194, 1032828555, 1066594916, + 1100361277, 1134127638, 1167893998, 1201660359, 1235426719, 1269193079, + 1302959441, 1336725801, 1370492162, 1404258523, 1438024883, 1471791244, + 1505557604, 1539323965, 1573090326, 1606856686, 1640623046, 1674389407, + -1665103658, -1631337297, -1597570937, -1563804577, -1530038216, -1496271855, + -1462505495, -1428739134, -1394972773, -1361206413, -1327440051, -1293673691, + -1259907330, -1226140970, -1192374609, -1158608249, -1124841888, -1091075528, + -1057309167, -1023542806, -989776446, -956010085, -922243724, -888477363, + -854711003, -820944642, -787178282, -753411921, -719645561, -685879201, + -652112840, -618346479, -584580118, -550813757, -517047396, -483281036, + -449514676, -415748315, -381981955, -348215594, -314449234, -280682873, + -246916512, -213150151, -179383790, -145617431, -111851070, -78084709, + -44318349, -10551988, 23214373, 56980733, 90747094, 124513454, + 158279815, 192046176, 225812537, 259578897, 293345258, 327111619, + 360877979, 394644339, 428410700, 462177061, 495943422, 529709782, + 563476143, 597242504, 631008864, 664775225, 698541586, 732307946, + 766074307, 799840668, 833607028, 867373388, 901139749, 934906110, + 968672470, 1002438831, 1036205191, 1069971552, 1103737913, 1137504273, + 1171270634, 1205036995, 1238803355, 1272569716, 1306336077, 1340102437, + 1373868797, 1407635158, 1441401519, 1475167879, 1508934240, 1542700601, + 1576466962, 1610233322, 1643999683, 1677766044, -1661727022, -1627960661, + -1594194301, -1560427940, -1526661580, -1492895219, -1459128858, -1425362498, + -1391596137, -1357829777, -1324063416, -1290297056, -1256530695, -1222764334, + -1188997973, -1155231613, -1121465252, -1087698892, -1053932531, -1020166170, + -986399810, -952633449, -918867088, -885100728, -851334367, -817568007, + -783801646, -750035285, -716268925, -682502564, -648736204, -614969843, + -581203483, -547437121, -513670761, -479904400, -446138040, -412371679, + -378605318, -344838958, -311072598, -277306237, -243539876, -209773516, + -176007155, -142240794, -108474434, -74708073, -40941712, -7175351, + 26591009, 60357370, 94123730, 127890091, 161656451, 195422812, + 229189173, 262955533, 296721894, 330488255, 364254615, 398020976, + 431787337, 465553697, 499320058, 533086418, 566852779, 600619139, + 634385500, 668151861, 701918221, 735684582, 769450943, 803217303, + 836983664, 870750024, 904516385, 938282746, 972049107, 1005815467, + 1039581828, 1073348188, 1107114549, 1140880909, 1174647270, 1208413631, + 1242179992, 1275946352, 1309712712, 1343479073, 1377245434, 1411011795, + 1444778155, 1478544515, 1512310876, 1546077237, 1579843598, 1613609958, + 1647376319, 1681142680, -1658350386, -1624584025, -1590817665, -1557051304, + -1523284944, -1489518583, -1455752222, -1421985862, -1388219501, -1354453140, + -1320686780, -1286920419, -1253154059, -1219387698, -1185621337, -1151854977, + -1118088616, -1084322256, -1050555895, -1016789534, -983023174, -949256813, + -915490452, -881724092, -847957731, -814191371, -780425010, -746658649, + -712892289, -679125928, -645359567, -611593207, -577826846, -544060486, + -510294125, -476527764, -442761404, -408995043, -375228683, -341462322, + -307695961, -273929601, -240163240, -206396879, -172630519, -138864158, + -105097798, -71331437, -37565076, -3798716, 29967645, 63734006, + 97500366, 131266727, 165033087, 198799448, 232565809, 266332170, + 300098530, 333864891, 367631251, 401397612, 435163972, 468930333, + 502696694, 536463054, 570229415, 603995776, 637762136, 671528497, + 705294857, 739061218, 772827579, 806593940, 840360300, 874126660, + 907893021, 941659382, 975425742, 1009192103, 1042958464, 1076724824, + 1110491185, 1144257546, 1178023906, 1211790267, 1245556628, 1279322988, + 1313089349, 1346855709, 1380622070, 1414388430, 1448154791, 1481921152, + 1515687512, 1549453873, 1583220234, 1616986594, 1650752955, 1684519316, + -1654973750, -1621207390, -1587441029, -1553674668, -1519908307, -1486141947, + -1452375586, -1418609226, -1384842865, -1351076504, -1317310144, -1283543783, + -1249777423, -1216011062, -1182244701, -1148478341, -1114711980, -1080945620, + -1047179259, -1013412898, -979646538, -945880177, -912113816, -878347456, + -844581095, -810814734, -777048374, -743282013, -709515652, -675749292, + -641982931, -608216571, -574450210, -540683850, -506917489, -473151128, + -439384768, -405618407, -371852046, -338085686, -304319325, -270552965, + -236786604, -203020243, -169253882, -135487522, -101721161, -67954801, + -34188440, -422080, 33344281, 67110642, 100877002, 134643363, + 168409723, 202176084, 235942445, 269708806, 303475166, 337241527, + 371007887, 404774248, 438540609, 472306969, 506073330, 539839690, + 573606051, 607372412, 641138772, 674905133, 708671493, 742437854, + 776204215, 809970575, 843736936, 877503297, 911269657, 945036018, + 978802379, 1012568739, 1046335100, 1080101460, 1113867821, 1147634182, + 1181400542, 1215166903, 1248933264, 1282699624, 1316465985, 1350232345, + 1383998706, 1417765067, 1451531427, 1485297788, 1519064148, 1552830509, + 1586596870, 1620363230, 1654129591, -1685363475, -1651597114, -1617830753, + -1584064393, -1550298032, -1516531672, -1482765311, -1448998950, -1415232589, + -1381466229, -1347699868, -1313933508, -1280167147, -1246400786, -1212634426, + -1178868065, -1145101704, -1111335344, -1077568983, -1043802623, -1010036262, + -976269901, -942503541, -908737180, -874970820, -841204459, -807438098, + -773671738, -739905377, -706139016, -672372656, -638606295, -604839935, + -571073574, -537307213, -503540853, -469774492, -436008132, -402241771, + -368475410, -334709050, -300942689, -267176328, -233409968, -199643607, + -165877247, -132110886, -98344525, -64578165, -30811804, 2954557, + 36720917, 70487278, 104253638, 138019999, 171786360, 205552720, + 239319081, 273085441, 306851802, 340618163, 374384523, 408150884, + 441917245, 475683605, 509449966, 543216326, 576982687, 610749048, + 644515408, 678281769, 712048130, 745814490, 779580851, 813347211, + 847113572, 880879933, 914646293, 948412654, 982179014, 1015945375, + 1049711736, 1083478096, 1117244457, 1151010818, 1184777178, 1218543539, + 1252309900, 1286076260, 1319842621, 1353608981, 1387375342, 1421141703, + 1454908063, 1488674424, 1522440785, 1556207145, 1589973506, 1623739866, + 1657506227, -1681986838, -1648220478, -1614454117, -1580687756, -1546921396, + -1513155035, -1479388675, -1445622314, -1411855954, -1378089593, -1344323232, + -1310556872, -1276790511, -1243024150, -1209257790, -1175491429, -1141725069, + -1107958708, -1074192347, -1040425987, -1006659626, -972893265, -939126905, + -905360544, -871594184, -837827823, -804061462, -770295102, -736528741, + -702762380, -668996020, -635229659, -601463299, -567696938, -533930577, + -500164217, -466397856, -432631495, -398865135, -365098774, -331332414, + -297566053, -263799692, -230033332, -196266971, -162500611, -128734250, + -94967889, -61201529, -27435168, 6331193, 40097553, 73863914, + 107630275, 141396635, 175162996, 208929356, 242695717, 276462078, + 310228438, 343994799, 377761160, 411527520, 445293881, 479060241, + 512826602, 546592963, 580359323, 614125684, 647892044, 681658405, + 715424766, 749191126, 782957487, 816583731, 850546442, 884517983, + 918095853, 951789290, 985555651, 1019322011, 1053088372, 1086854732, + 1120621093, 1154387454, 1188153814, 1221920175, 1255686536, 1289452896, + 1323219257, 1356985618, 1390751978, 1424518339, 1458284699, 1492051060, + 1525817421, 1558515203, 1591210057, 1625104467, 1659836538, -1678263796, + -1643114188, -1608409583, -1574557824, -1541916605, -1509778399, -1476012039, + -1442245678, -1408479317, -1374712957, -1340946596, -1307180236, -1273413875, + -1239647514, -1205881154, -1172114793, -1138348432, -1104582072, -1070815711, + -1037277627, -1006953160, -974798160, -941049125, -906023309, -870110480, + -833754977, -797429519, -761604435, -726717287, -693147741, -661201051, + -631101277, -598086662, -564320302, -530553941, -496787581, -463021220, + -429254859, -395488499, -361722138, -327955777, -294189417, -260423056, + -228107767, -199050376, -167890154, -134786733, -99988130, -63832335, + -26738468, 10813442, 48312328, 85251237, 121161768, 155642038, + 188374348, 219131472, 247773022, 279838714, 313605074, 347371435, + 381137795, 414904156, 448670517, 482436877, 516203238, 549969599, + 582037330, 609501076, 639262763, 671246375, 705289776, 741133442, + 778417896, 816693154, 855441427, 894111101, 932156768, 969078115, + 1004450907, 1037945710, 1069333432, 1098479713, 1125331797, 1157764090, + 1191530450, 1225296811, 1259063172, 1292829532, 1326595893, 1360362254, + 1393549421, 1419174932, 1447210699, 1477661220, 1510456009, 1545431067, + 1582315409, 1620727322, 1660184395, -1673130488, -1633292893, -1594147962, + -1556228930, -1519982405, -1485748705, -1453757368, -1424135103, -1396921696, + -1371336321, -1337569960, -1303803600, -1270037239, -1236270878, -1202504518, + -1168738157, -1142902306, -1116829630, -1088239207, -1057115054, -1023521125, + -987622598, -949701839, -910163545, -869524163, -828383495, -787381090, + -747144824, -708241805, -671140908, -636192336, -603624541, -573554891, + -546008662, -520941146, -493410945, -459644584, -425878223, -392111863, + -358345502, -329925268, -305960772, -279458857, -250330735, -218547869, + -184166647, -147352692, -108399636, -67735914, -25913657, 16422928, + 58586777, 99905998, 139778742, 177714100, 213353127, 246470106, + 276958755, 304809839, 330086146, 352899001, 384514432, 418280792, + 452047153, 485034379, 506829690, 531112614, 558026402, 587675688, + 620102643, 655259517, 692981020, 732962399, 774750734, 817756500, + 861288724, 904610383, 947003720, 987831357, 1026580736, 1062885451, + 1096524280, 1127403811, 1155532370, 1180991934, 1203912500, 1228673447, + 1262439808, 1296206168, 1321710457, 1343731052, 1368315799, 1395624655, + 1425779004, 1458835741, 1494756849, 1533378191, 1574384078, 1617296344, + 1661486321, -1667045600, -1622570045, -1579111903, -1537344766, -1497802318, + -1460856986, -1426723649, -1395481024, -1367101734, -1341483576, -1318477274, + -1297908655, -1266660603, -1234499623, -1214714269, -1192483396, -1167612757, + -1139925070, -1109281313, -1075608776, -1038934618, -999420963, -957394220, + -913358561, -867983604, -822061263, -776436023, -731922866, -689232184, + -648918104, -611357492, -576756938, -545178627, -516574676, -490821684, + -467750585, -447169895, -422501587, -397647381, -377724508, -355297630, + -330156367, -302105515, -270987551, -236712861, -199296591, -158897953, + -115853835, -70695178, -24134408, 22982226, 69752633, 115310525, + 158908241, 199972059, 238122394, 273162971, 305049991, 333853246, + 359718224, 382834217, 403410102, 421657428, +}; diff --git a/test/ztest/unit/math/basic/complex/testcase.yaml b/test/ztest/unit/math/basic/complex/testcase.yaml new file mode 100644 index 000000000000..729fbd762b58 --- /dev/null +++ b/test/ztest/unit/math/basic/complex/testcase.yaml @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright(c) 2026 Intel Corporation. +# +# Math basic complex numbers unit tests +# + +common: + tags: + - SOF + - unit_test + - math + - complex + integration_platforms: + - native_sim + arch_exclude: xtensa # Test is for host builds only + +tests: + sof.unit.math.basic.complex: + platform_allow: + - native_sim diff --git a/test/ztest/unit/math/basic/trigonometry/CMakeLists.txt b/test/ztest/unit/math/basic/trigonometry/CMakeLists.txt new file mode 100644 index 000000000000..48d009abbee8 --- /dev/null +++ b/test/ztest/unit/math/basic/trigonometry/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(test_math_trigonometry) + +set(SOF_ROOT "${PROJECT_SOURCE_DIR}/../../../../../..") + +target_include_directories(app PRIVATE + ${SOF_ROOT}/zephyr/include + ${SOF_ROOT}/src/include +) + +# Define SOF-specific configurations for unit testing +target_compile_definitions(app PRIVATE + -DCONFIG_ZEPHYR_POSIX=1 + -DCONFIG_LIBRARY=1 + -DUNIT_TEST=1 +) + +target_sources(app PRIVATE + trig_test.c + ${SOF_ROOT}/src/math/trig.c + ${SOF_ROOT}/src/math/lut_trig.c + ${SOF_ROOT}/src/math/atan2.c +) + +# Link math library for standard math functions +target_link_libraries(app PRIVATE m) diff --git a/test/ztest/unit/math/basic/trigonometry/atan2_tables.h b/test/ztest/unit/math/basic/trigonometry/atan2_tables.h new file mode 100644 index 000000000000..f7ec1e6587fa --- /dev/null +++ b/test/ztest/unit/math/basic/trigonometry/atan2_tables.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2026 Intel Corporation. + */ + +#ifndef __ATAN2_TABLES_H__ +#define __ATAN2_TABLES_H__ + +#include <stdint.h> + +#define ATAN2_TEST_TABLE_SIZE 256 + +static const int32_t atan2_test_y[ATAN2_TEST_TABLE_SIZE] = { + 0, 593678131, -532114458, 826669466, 85578803, 2092045542, + -1879009088, -1576694240, 1539058893, 1401024205, -1764925184, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, -1002953741, 562543872, 1322188032, + -1091606067, -400921101, 2147483647, -1690120538, 2050372122, -350646912, + -1880522864, 320130202, 1583472563, 1870898586, 1777558605, 1275437645, + 2147483647, 645138560, 1016824371, 1133248230, -1409419475, -65799642, + 751321472, -554752, -481011942, -1824835690, 1120701542, 1219868109, + 1276479565, -1402484230, 1094266906, 345378458, 1388947226, 1235927757, + -67347315, -113975488, 352132070, 646445466, -175333594, 1313648794, + 498544640, 689375667, 1101318170, -1891416384, 973726336, 260722458, + 2049027200, 1619159731, 659320781, 811575142, 2062582016, 1804117709, + -556148173, 2147483647, -1581181395, -1384873248, -2147483648, 1919463322, + -715849728, 1482341555, -2106111198, 2147483647, -1581934605, -2147483648, + 2147483647, -1977711542, -1219287520, -1913594461, -1213455936, 1750786893, + -420132698, -222367974, -435172250, -2087889971, -919525235, 834603827, + -1669661664, 2147483647, 1584016051, 2082185882, 212862848, 1926648627, + -1889370525, -1133371149, 2147483647, -125891533, 629086234, -580819290, + -814994048, -940839821, -2147483648, -11732723, -499195981, 2003249459, + -1797551043, 1543991962, 703381043, -200345024, 1618129075, 1901467674, + 2147483647, 747880038, 2017725389, 1628990106, -2147483648, 2147483647, + -451489280, 486361498, -2132152282, -58571955, 157509299, -834756314, + 1251017293, 1892762010, -1455901638, 90604237, -957637261, -2147483648, + 752198656, -1829826099, -1725792499, -569240883, 42635648, -1498449850, + -437911232, -23190746, -661963034, -324850381, -2134133197, 297851418, + 980486426, -357129907, 1688064717, -819664806, 1316280909, 13885414, + -1496825299, 18689510, 1180361037, -324324774, 370182912, 2146612582, + -652058458, -259263629, 277880346, -1507396774, -1420640883, 1603635123, + 1512286899, 925569638, 64723789, 2101077862, 2046962227, -1243819526, + 1021511040, -1659139469, 1906461286, 1168691814, 1900425472, 195734528, + -689034931, 510480538, -1956886624, 965214694, -1640061773, -2146964829, + -1588224, -1125154624, 34522470, 1535756570, 692508749, 292941158, + -143428173, 715886899, 1614379853, 33759053, -1082890266, 610783923, + 1470741325, 1262575846, -53151718, 2033863603, 844302131, 19598797, + 654380390, -411747354, -1558739706, -1846029434, 1652960461, -2147483648, + -587736512, -595937408, 1554227840, 562723533, 1592959667, -46749261, + 1489178803, 582155622, -2126878934, -1168122701, -2147483648, 1081324570, + 1864094003, 1138184397, -547145984, 772395853, -41048269, 1008931123, + -844305651, 1003180570, 2147483647, 2147483647, -715760602, -2035354781, + -1371158131, 1678904832, 494394701, -1407855398, 440926182, 2082209818, + -1291104390, 1887003290, 744169114, -1480452019, 2087889126, 23236224, + -1745024160, -72790784, 523330227, -115015155, 1655730278, 923114086, + 880698086, 1312830746, 132706534, -978800064, +}; + +static const int32_t atan2_test_x[ATAN2_TEST_TABLE_SIZE] = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -1399816141, + -230097050, -1261376090, -2081157232, -440471258, -876176998, -1642130829, + -171532698, 104774067, -928553894, 803256115, 1159264128, -451441549, + 1477543373, -1407978810, -155422643, -1755391194, 1797471949, -2131587568, + -251177766, -2147483648, -868828787, 1321866445, -550897318, -288342067, + 158300877, 370411853, 1242460877, 560164634, 560658278, 1170291584, + -1531339462, 1861627750, 881152307, -76744870, 1266329293, -808628198, + 779498650, -1042297485, 29521254, -2147483648, -1831276832, 315334554, + 1677842637, -314975091, 1873312179, 1370099174, -853027507, 1308034816, + 1094235366, 2147483647, 268095872, 2147483647, -834663949, 838375578, + -574429504, -707173350, 1876573952, 874547379, 1613107021, -2076715221, + 1954203187, -1230503296, 1975324314, 1574426445, 150468173, -2147483648, + -2045228592, 102846515, -1659941536, 2147483647, 523171686, -919468352, + 1801804365, 25905792, -2147483648, 2100982400, -2147483648, -592549478, + 774778470, -794157056, -687915571, 1915112320, -1895780832, -651402752, + -1753523904, -2127834438, -1292520768, -72287987, 471997645, -1600389824, + 1050780826, 909749350, 1526121907, -480663181, 1690915917, 152633958, + 1151843968, -1504568947, -2135539402, 799874662, 1630831770, -643009382, + -1334604269, -2147483648, -1856544518, 1010088781, 1164046259, 914998093, + 2147483647, 560258406, 1061672550, 1741415526, 730181760, -1559917498, + 1348011034, 280000230, 247261696, 1805741133, -998184000, 2003341542, + 182103398, -343834726, -665013325, 681587456, -965692570, 773658266, + -854945766, -1014991155, -663706278, 200810086, -2147483648, 1065857690, + -1146915827, -2147483648, 1094864461, 1700262502, -1050449382, -713241830, + -1989792816, -1679438253, -2144952374, 1737513395, -76085786, -999872192, + 1268036915, 1857466829, 1334412570, 351298253, 1767924506, -206440256, + -2147483648, -1185212653, 2030329805, 2147483647, 1363327539, 848855885, + 1660833434, 1357533338, -1650400646, 991000525, 2106705357, 2147483647, + -1964598170, 1936573338, 799362995, 406677427, -395381466, 2147483647, + -1469184218, 204290944, 1538024576, 2093231642, 2147483647, -1031910246, + -2147483648, 2147483647, -172979558, 1774660941, 795639117, 1787846861, + 1848797773, 282311603, -379224384, -889636070, -1874511760, -1696152198, + -96912922, 1257014528, 1355642675, -28044262, -1442693542, -2147483648, + 586790195, 170231987, -474024038, 1662995277, -139357645, -447027750, + -774900826, 2147483647, 1843413581, 1234652954, -991492621, -2147483648, + -272780570, -1956468659, 1327163059, 1548914611, 1038220902, 2147483647, + -1708905722, 550796928, -1898930634, 1387736064, -1010688026, -1955962237, + 2147483647, 1687800013, -538678554, -2051015613, 1152012083, -1856525088, + -784337101, 361366016, 1829781043, -926315456, 584568653, -421916493, + 1094186931, 1752872986, -1590665542, -714551270, 1503289216, -2001796262, + -554735245, -1757686726, -904190426, -2083870624, -561217114, -885333222, + -314317274, 1836398643, -1568309389, 2094263142, +}; + +static const int32_t atan2_test_ref[ATAN2_TEST_TABLE_SIZE] = { + 0, 843314857, -843314857, 843314857, 843314857, 843314857, + -843314857, -843314857, 843314857, 843314857, -843314857, 1686629713, + 1686629713, 1686629713, 1686629713, 1686629713, 1686629713, 1686629713, + 1686629713, 0, 1686629713, -480774686, 242550644, 1019958505, + -341607303, -1537697774, 882102887, -1275141377, 456892678, -1599098184, + -914601725, 1607182223, 1112734724, 513084281, 1004661107, 962680342, + 803811086, 563496816, 368216934, 596849638, -640053917, -30153818, + 1441750136, -159984, -268264737, -865880079, 388944604, 1157587081, + 548989894, -1186440684, 828834606, 1601018220, 1338258195, 709198926, + -21538024, -1500229594, 99753206, 236681525, -1577795578, 422807062, + 229517388, 166764936, 715116877, -387665176, 1223768840, 161868893, + 990055806, 1064389455, 181392893, 401616028, 486983396, 1302621340, + -148853162, 1122663950, -362401539, -387315937, -805759192, 1295041388, + -1505874184, 806125749, -1201663508, 421657428, -671841804, -1060503213, + 468530021, -836282855, -1409396260, -396616142, -1410500034, 1018520658, + -266761868, -1540056775, -1383811666, -444815486, -1444175423, 1199116908, + -1278122081, 1262504863, 1210753289, 861946112, 227456622, 1215451470, + -570823003, -480185572, 511613552, -1549105769, 191218374, -705349581, + -330593881, -1386609757, -1263475094, -7874366, -159473626, 1010064033, + -1186190715, 1351971671, 1492198979, -105120786, 508515064, 602528322, + 421657428, 498137329, 583272798, 403755854, -667353222, 1180588320, + -173509607, 562873277, -781331817, -17408120, 1602606516, -211958872, + 765710697, 939789547, -1073348055, 70950927, -1267220800, -657671271, + 1299248585, -1115207171, -1040423529, -661241101, 1675972201, -511381404, + -1490815052, -1680832252, -291950578, -101352536, -1088879133, 1474249986, + 1440830194, -1574140544, 1328665659, -236647292, 874313438, 1679174565, + -465981743, 5401720, 388810509, -400234846, 110813576, 894787567, + -1528364782, -1571011137, 73024931, -328578059, -432708387, 581946141, + 396542676, 321267954, 1665586022, 606704001, 413936026, -281848594, + 1429206964, -380316068, 630163376, 663532294, 953439316, 48798797, + -1451193270, 638942546, -485695493, 231958476, -350157942, -1083853093, + -1686232657, -259102718, 1580872968, 382979880, 384511044, 87192252, + -41566736, 641651025, 967182272, 1666266823, -1405387221, 1501063583, + 878640321, 422842424, -21038732, 850717120, 1402364287, 1681730150, + 450864858, -632841657, -1001810229, -449635784, 888470538, -953498287, + -1338255336, -145327507, 376072239, 229590563, 1142214026, -1674944244, + 940578011, 1531360468, -543807078, -346902051, -601547020, 250433321, + 1241668689, 601343996, -1536018589, 272669402, -1664837116, 1430957794, + -201109884, 287908177, 975262018, 1252638885, -298470119, -1240320708, + -1122270737, 729495693, 141675968, -1155748018, 346943281, 950647349, + -465878468, 441432301, 1451702422, -1084733681, 508293499, 1680398164, + -1008559815, -1664409066, 1404948145, -1657028209, 1018764798, 1253757970, + 1027356695, 333210160, 1641308961, -234723315, +}; + +#endif /* __ATAN2_TABLES_H__ */ diff --git a/test/ztest/unit/math/basic/trigonometry/atan2_tables.m b/test/ztest/unit/math/basic/trigonometry/atan2_tables.m new file mode 100644 index 000000000000..37728a20e0d7 --- /dev/null +++ b/test/ztest/unit/math/basic/trigonometry/atan2_tables.m @@ -0,0 +1,95 @@ +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright(c) 2026 Intel Corporation. + +function atan2_tables() + + % Create random test points with bias to min/max values + q31_scale = 2^31; + q29_scale = 2^29; + num_points = 256; + rand('seed', 42); + x = max(min(2.2 * rand(num_points, 1) - 1.1, 1), -1); + y = max(min(2.2 * rand(num_points, 1) - 1.1, 1), -1); + + % Force 1st test point to be (0, 0) to ensure it is tested + x(1) = 0; + y(1) = 0; + + % Then force 10 test points to have x = 0, the reference values are 0 or pi + x(2:11) = 0; + + % And force 10 test points to have y = 0, the reference values are +/-pi + y(12:21) = 0; + + % Quantize input values + ref_x = int32(x * q31_scale); + ref_y = int32(y * q31_scale); + x = double(ref_x)/q31_scale; + y = double(ref_y)/q31_scale; + a = atan2(y, x); + ref_a = int32(a * q29_scale); + + figure(1) + subplot(2,1,1) + plot(x, y, 'o'); + grid on; + subplot(2,1,2) + plot(a, 'o'); + grid on; + + fn = 'atan2_tables.h'; + fh = export_headerfile(fn); + dn = 'ATAN2_TEST_TABLE_SIZE'; + vl = 6; + fu = export_ifndef(fh, fn); + export_define(fh, dn, num_points); + export_array(fh, 'atan2_test_y', dn, vl, ref_y); + export_array(fh, 'atan2_test_x', dn, vl, ref_x); + export_array(fh, 'atan2_test_ref', dn, vl, ref_a); + export_fclose(fh, fu); + +end + +function [fh] = export_headerfile(headerfn) + fh = fopen(headerfn, 'w'); + fprintf(fh, '/* SPDX-License-Identifier: BSD-3-Clause\n'); + fprintf(fh, ' *\n'); + fprintf(fh, ' * Copyright(c) %s Intel Corporation.\n', ... + datestr(now, 'yyyy')); + fprintf(fh, ' */\n\n'); +end + +function fu = export_ifndef(fh, fn) + fu = sprintf('__%s__', upper(strrep(fn, '.', '_'))); + fprintf(fh, '#ifndef %s\n', fu); + fprintf(fh, '#define %s\n\n', fu); + fprintf(fh, '#include <stdint.h>\n\n'); +end + +function export_define(fh, dn, val) + fprintf(fh, '#define %s %d\n', dn, val); +end + +function export_array(fh, vn, size_str, vl, data) + fprintf(fh, '\n'); + fprintf(fh, 'static const int32_t %s[%s] = {\n', vn, size_str); + + n = length(data); + k = 0; + for i = 1:vl:n + fprintf(fh, '\t'); + for j = 1:min(vl, n-k) + k = k + 1; + fprintf(fh, '%12d,', data(k)); + end + fprintf(fh, '\n'); + end + + fprintf(fh, '};\n'); +end + +function export_fclose(fh, fu) + fprintf(fh, "\n#endif /* %s */\n", fu); + fclose(fh); +end diff --git a/test/ztest/unit/math/basic/trigonometry/prj.conf b/test/ztest/unit/math/basic/trigonometry/prj.conf new file mode 100644 index 000000000000..d34c7781cd0a --- /dev/null +++ b/test/ztest/unit/math/basic/trigonometry/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_SOF_FULL_ZEPHYR_APPLICATION=n diff --git a/test/ztest/unit/math/basic/trigonometry/testcase.yaml b/test/ztest/unit/math/basic/trigonometry/testcase.yaml new file mode 100644 index 000000000000..90bb941c4a22 --- /dev/null +++ b/test/ztest/unit/math/basic/trigonometry/testcase.yaml @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright(c) 2025 Intel Corporation. All rights reserved. +# +# Math basic trigonometry unit tests converted from CMock to Ztest +# +# These contents may have been developed with support from one or more Intel-operated +# generative artificial intelligence solutions. +# + +common: + tags: + - SOF + - unit_test + - math + - trigonometry + integration_platforms: + - native_sim + arch_exclude: xtensa # Test is for host builds only + +tests: + sof.unit.math.basic.trigonometry: + platform_allow: + - native_sim diff --git a/test/cmocka/include/trig_tables.h b/test/ztest/unit/math/basic/trigonometry/trig_tables.h similarity index 100% rename from test/cmocka/include/trig_tables.h rename to test/ztest/unit/math/basic/trigonometry/trig_tables.h diff --git a/test/ztest/unit/math/basic/trigonometry/trig_test.c b/test/ztest/unit/math/basic/trigonometry/trig_test.c new file mode 100644 index 000000000000..0e9471712891 --- /dev/null +++ b/test/ztest/unit/math/basic/trigonometry/trig_test.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. +// +// Converted from CMock to Ztest +// +// Original tests from sof/test/cmocka/src/math/trig/: +// - sin_32b_fixed.c (Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com>) +// - sin_16b_fixed.c (Author: Shriram Shastry <malladi.sastry@linux.intel.com>) +// - cos_32b_fixed.c (Author: Shriram Shastry <malladi.sastry@linux.intel.com>) +// - cos_16b_fixed.c (Author: Shriram Shastry <malladi.sastry@linux.intel.com>) +// - asin_32b_fixed.c (Author: Shriram Shastry <malladi.sastry@linux.intel.com>) +// - asin_16b_fixed.c (Author: Shriram Shastry <malladi.sastry@linux.intel.com>) +// - acos_32b_fixed.c (Author: Shriram Shastry <malladi.sastry@linux.intel.com>) +// - acos_16b_fixed.c (Author: Shriram Shastry <malladi.sastry@linux.intel.com>) +// - lut_sin_16b_fixed.c (Authors: Slawomir Blauciak <slawomir.blauciak@linux.intel.com>, +// Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>) + +#define _USE_MATH_DEFINES +#include <math.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <zephyr/ztest.h> +#include <sof/audio/format.h> +#include <sof/audio/format_generic.h> +#include <sof/math/trig.h> +#include <sof/math/cordic.h> +#include <sof/math/lut_trig.h> +#include "trig_tables.h" +#include "atan2_tables.h" + +/* Define M_PI if not available */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +/* Conversion factor from degrees to radians (PI/180) */ +#define DEGREES_TO_RADIANS 0.017453292519943295 + +#define CMP_TOLERANCE_32B 0.0000000611175871f +#define CMP_TOLERANCE_16B 0.000065f +#define CMP_TOLERANCE_ASIN_32B 0.000000068141916f +#define CMP_TOLERANCE_ACOS_32B 0.000000060077032f +#define CMP_TOLERANCE_ASIN_16B 0.0001152158f +#define CMP_TOLERANCE_ACOS_16B 0.0001196862f +#define CMP_TOLERANCE_SIN 3.1e-5f +#define CMP_TOLERANCE_ATAN2 2.0e-5 /* ~0.001 degrees in radians */ + +/* + * Helper function for rounding double values to nearest integer + * Implements custom rounding: round to 0 if absolute value < 0.5, otherwise round normally + */ +static inline int32_t round_to_nearest_int(double value) +{ + double abs_value = fabs(value); + + return (int32_t) (abs_value >= 0.5) ? floor(value + 0.5) : 0.0; +} + +/* Test sin_32b_fixed function */ +ZTEST(trigonometry, test_sin_32b_fixed) +{ + int theta; + float delta; + double rad; + int32_t sin_val; + + for (theta = 0; theta < ARRAY_SIZE(sin_ref_table); ++theta) { + rad = M_PI * ((double)theta / 180.0); + sin_val = sin_fixed_32b(Q_CONVERT_FLOAT(rad, 28)); + delta = fabsf(sin_ref_table[theta] - Q_CONVERT_QTOF(sin_val, 31)); + zassert_true(delta <= CMP_TOLERANCE_32B, + "sin_32b_fixed failed for angle %d", theta); + } +} + +/* Test sin_16b_fixed function */ +ZTEST(trigonometry, test_sin_16b_fixed) +{ + int theta; + float delta; + double rad; + int16_t sin_val; + + for (theta = 0; theta < ARRAY_SIZE(sin_ref_table); ++theta) { + rad = M_PI * ((double)theta / 180.0); + sin_val = sin_fixed_16b(Q_CONVERT_FLOAT(rad, 28)); + delta = fabsf(sin_ref_table[theta] - Q_CONVERT_QTOF(sin_val, 15)); + zassert_true(delta <= CMP_TOLERANCE_16B, + "sin_16b_fixed failed for angle %d", theta); + } +} + +/* Test cos_32b_fixed function */ +ZTEST(trigonometry, test_cos_32b_fixed) +{ + int theta; + float delta; + double rad; + int32_t cos_val; + + for (theta = 0; theta < ARRAY_SIZE(cos_ref_table); ++theta) { + rad = M_PI * ((double)theta / 180.0); + cos_val = cos_fixed_32b(Q_CONVERT_FLOAT(rad, 28)); + delta = fabsf(cos_ref_table[theta] - Q_CONVERT_QTOF(cos_val, 31)); + zassert_true(delta <= CMP_TOLERANCE_32B, + "cos_32b_fixed failed for angle %d", theta); + } +} + +/* Test cos_16b_fixed function */ +ZTEST(trigonometry, test_cos_16b_fixed) +{ + int theta; + float delta; + double rad; + int16_t cos_val; + + for (theta = 0; theta < ARRAY_SIZE(cos_ref_table); ++theta) { + rad = M_PI * ((double)theta / 180.0); + cos_val = cos_fixed_16b(Q_CONVERT_FLOAT(rad, 28)); + delta = fabsf(cos_ref_table[theta] - Q_CONVERT_QTOF(cos_val, 15)); + zassert_true(delta <= CMP_TOLERANCE_16B, + "cos_16b_fixed failed for angle %d", theta); + } +} + +/* Test asin_32b_fixed function */ +ZTEST(trigonometry, test_asin_32b_fixed) +{ + int index; + float delta; + double u; + int32_t asin_val, input_val; + + for (index = 0; index < ARRAY_SIZE(degree_table); ++index) { + /* Convert degree to input value in Q2.30 format like original test */ + /* angleInRadians = PI/180 * angleInDegrees & const Q2.30 format */ + u = (DEGREES_TO_RADIANS * degree_table[index] * 0x40000000); + input_val = round_to_nearest_int(u); + + asin_val = asin_fixed_32b(input_val); + delta = fabsf(asin_ref_table[index] - Q_CONVERT_QTOF(asin_val, 29)); + zassert_true(delta <= CMP_TOLERANCE_ASIN_32B, + "asin_32b_fixed failed for index %d", index); + } +} + +/* Test asin_16b_fixed function */ +ZTEST(trigonometry, test_asin_16b_fixed) +{ + int index; + float delta; + double u; + int16_t asin_val; + int32_t input_val; + + for (index = 0; index < ARRAY_SIZE(degree_table); ++index) { + /* Convert degree to input value in Q2.30 format like original test */ + /* angleInRadians = PI/180 * angleInDegrees & const Q2.30 format */ + u = (DEGREES_TO_RADIANS * degree_table[index] * 0x40000000); + input_val = round_to_nearest_int(u); + + asin_val = asin_fixed_16b(input_val); + delta = fabsf(asin_ref_table[index] - Q_CONVERT_QTOF(asin_val, 13)); + zassert_true(delta <= CMP_TOLERANCE_ASIN_16B, + "asin_16b_fixed failed for index %d", index); + } +} + +/* Test acos_32b_fixed function */ +ZTEST(trigonometry, test_acos_32b_fixed) +{ + int index; + float delta; + double u; + int32_t acos_val, input_val; + + for (index = 0; index < ARRAY_SIZE(degree_table); ++index) { + /* Convert degree to input value in Q2.30 format like original test */ + /* angleInRadians = PI/180 * angleInDegrees & const Q2.30 format */ + u = (DEGREES_TO_RADIANS * degree_table[index] * 0x40000000); + input_val = round_to_nearest_int(u); + + acos_val = acos_fixed_32b(input_val); + delta = fabsf(acos_ref_table[index] - Q_CONVERT_QTOF(acos_val, 29)); + zassert_true(delta <= CMP_TOLERANCE_ACOS_32B, + "acos_32b_fixed failed for index %d", index); + } +} + +/* Test acos_16b_fixed function */ +ZTEST(trigonometry, test_acos_16b_fixed) +{ + int index; + float delta; + double u; + int16_t acos_val; + int32_t input_val; + + for (index = 0; index < ARRAY_SIZE(degree_table); ++index) { + /* Convert degree to input value in Q2.30 format like original test */ + /* angleInRadians = PI/180 * angleInDegrees & const Q2.30 format */ + u = (DEGREES_TO_RADIANS * degree_table[index] * 0x40000000); + input_val = round_to_nearest_int(u); + + acos_val = acos_fixed_16b(input_val); + delta = fabsf(acos_ref_table[index] - Q_CONVERT_QTOF(acos_val, 13)); + zassert_true(delta <= CMP_TOLERANCE_ACOS_16B, + "acos_16b_fixed failed for index %d", index); + } +} + +/* Test sin lookup table function */ +ZTEST(trigonometry, test_sin_lut_16b_fixed) +{ + int theta; + float delta; + double rad; + int16_t sin_val; + + for (theta = 0; theta < ARRAY_SIZE(sin_ref_table); ++theta) { + rad = M_PI * (double)theta / 180.0; + sin_val = sofm_lut_sin_fixed_16b(Q_CONVERT_FLOAT(rad, 28)); + delta = fabsf(sin_ref_table[theta] - Q_CONVERT_QTOF(sin_val, 15)); + zassert_true(delta <= CMP_TOLERANCE_SIN, + "sin_lut_16b_fixed failed for angle %d", theta); + } +} + +/* Test sofm_atan2_32b function */ +ZTEST(trigonometry, test_atan2) +{ + double reference; + double result; + double delta; + double delta_max = 0.0; + int32_t result_q29_max = 0; + int32_t result_q29; + int i_max = 0; + int i; + + /* Note that the first atan2_test_y[], atan2_test_x[] have forced to + * zero y or x, values to test edge cases where x == 0 or y == 0. See + * script atan2_tables.m for details. + */ + for (i = 0; i < ATAN2_TEST_TABLE_SIZE; ++i) { + result_q29 = sofm_atan2_32b(atan2_test_y[i], atan2_test_x[i]); + result = Q_CONVERT_QTOD(result_q29, 29); + reference = Q_CONVERT_QTOD(atan2_test_ref[i], 29); + delta = fabs(reference - result); + if (i == 0 || delta > delta_max) { + result_q29_max = result_q29; + delta_max = delta; + i_max = i; + } + zassert_true(delta <= CMP_TOLERANCE_ATAN2, + "sofm_atan2_32b failed for input %d: (%d, %d) result %d, expected %d", + i, atan2_test_y[i], atan2_test_x[i], result_q29, atan2_test_ref[i]); + } + printf(" INFO - Maximum delta for atan2 test %d: %.6e (%d, %d) result %d\n", + i_max, delta_max, atan2_test_y[i_max], atan2_test_x[i_max], result_q29_max); +} + +ZTEST_SUITE(trigonometry, NULL, NULL, NULL, NULL, NULL); diff --git a/test/ztest/unit/objpool/CMakeLists.txt b/test/ztest/unit/objpool/CMakeLists.txt new file mode 100644 index 000000000000..2ce499607463 --- /dev/null +++ b/test/ztest/unit/objpool/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(test_objpool) + +set(SOF_ROOT "${PROJECT_SOURCE_DIR}/../../../..") + +# Include SOF CMake functions +include(${SOF_ROOT}/scripts/cmake/misc.cmake) + +target_include_directories(app PRIVATE + ${SOF_ROOT}/zephyr/include + ${SOF_ROOT}/src/include + ${SOF_ROOT}/src/platform/posix/include +) + +# Define SOF-specific configurations for unit testing +target_compile_definitions(app PRIVATE + -DCONFIG_ZEPHYR_POSIX=1 +) + +target_sources(app PRIVATE + test_objpool_ztest.c + ${SOF_ROOT}/test/ztest/unit/common/alloc.c + ${SOF_ROOT}/src/lib/objpool.c +) + +target_link_libraries(app PRIVATE "-Wl,--wrap=rzalloc,--wrap=sof_heap_alloc,--wrap=sof_heap_free,--wrap=sof_sys_heap_get") + +# Add RELATIVE_FILE definitions for SOF trace functionality +sof_append_relative_path_definitions(app) diff --git a/test/ztest/unit/objpool/prj.conf b/test/ztest/unit/objpool/prj.conf new file mode 100644 index 000000000000..d34c7781cd0a --- /dev/null +++ b/test/ztest/unit/objpool/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_SOF_FULL_ZEPHYR_APPLICATION=n diff --git a/test/ztest/unit/objpool/test_objpool_ztest.c b/test/ztest/unit/objpool/test_objpool_ztest.c new file mode 100644 index 000000000000..596fb3accd70 --- /dev/null +++ b/test/ztest/unit/objpool/test_objpool_ztest.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#define DATA_SIZE 5 +#define ALIGNED_SIZE ALIGN_UP(DATA_SIZE, sizeof(int)) + +#include <zephyr/ztest.h> +#include <sof/objpool.h> +#include <sof/common.h> +#include <sof/list.h> + +#include <rtos/alloc.h> + +#include <stdlib.h> +#include <string.h> + +ZTEST(objpool_suite, test_objpool_wrong_size) +{ + struct objpool_head head = {.list = LIST_INIT(head.list)}; + /* new object pool of 2 blocks */ + uint8_t *block1 = objpool_alloc(&head, DATA_SIZE, 0); + /* should fail because of a different size */ + uint8_t *block2 = objpool_alloc(&head, DATA_SIZE + 1, 0); + /* second block in the first object pool */ + uint8_t *block3 = objpool_alloc(&head, DATA_SIZE, 0); + /* new object pool of 4 blocks */ + uint8_t *block4 = objpool_alloc(&head, DATA_SIZE, 0); + /* should fail because of a different size */ + uint8_t *block5 = objpool_alloc(&head, DATA_SIZE * 2, 0); + /* should fail because of different flags */ + uint8_t *block6 = objpool_alloc(&head, DATA_SIZE * 2, SOF_MEM_FLAG_COHERENT); + + zassert_not_null(block1); + zassert_is_null(block2); + zassert_not_null(block3); + zassert_not_null(block4); + zassert_is_null(block5); + zassert_is_null(block6); + + zassert_not_ok(objpool_free(&head, block1 + 1)); + zassert_ok(objpool_free(&head, block1)); + zassert_not_ok(objpool_free(&head, block3 + 1)); + zassert_ok(objpool_free(&head, block3)); + zassert_not_ok(objpool_free(&head, block4 + 1)); + zassert_ok(objpool_free(&head, block4)); +} + +ZTEST(objpool_suite, test_objpool) +{ + struct objpool_head head = {.list = LIST_INIT(head.list)}; + void *blocks[62]; /* 2 + 4 + 8 + 16 + 32 */ + unsigned int k = 0; + + /* Loop over all powers: 2^1..2^5 */ + for (unsigned int i = 1; i <= 5; i++) { + unsigned int n = 1 << i; + uint8_t *start; + + for (unsigned int j = 0; j < n; j++) { + uint8_t *block = objpool_alloc(&head, DATA_SIZE, 0); + + zassert_not_null(block, "allocation failed loop %u iter %u", i, j); + + if (!j) + start = block; + else + zassert_equal(block, start + ALIGNED_SIZE * j, "wrong pointer"); + + blocks[k++] = block; + } + } + + while (k--) + zassert_ok(objpool_free(&head, blocks[k]), "free failed"); +} + +struct test_objpool_data { + char cnt; + uint8_t reserved[DATA_SIZE - sizeof(char)]; +} __packed; + +static unsigned int test_objpool_check; + +static bool test_objpool_cb(void *data, void *arg) +{ + struct test_objpool_data *odata = data; + + zassert_equal(test_objpool_check++, odata->cnt, "Counter mismatch"); + zassert_equal((unsigned int)arg, 2, "Wrong argument"); + + return odata->cnt == (unsigned int)arg; +} + +ZTEST(objpool_suite, test_objpool_iterate) +{ + struct objpool_head head = {.list = LIST_INIT(head.list)}; + unsigned int i; + + for (i = 0; i < 4; i++) { + struct test_objpool_data *odata = objpool_alloc(&head, sizeof(*odata), 0); + + zassert_not_null(odata, "allocation failed loop %u", i); + + odata->cnt = i; + } + + int ret = objpool_iterate(&head, test_objpool_cb, (void *)2); + + zassert_equal(test_objpool_check, 3); + + zassert_ok(ret); + + /* Reset for a possible rerun */ + test_objpool_check = 0; +} + +ZTEST_SUITE(objpool_suite, NULL, NULL, NULL, NULL, NULL); diff --git a/test/ztest/unit/objpool/testcase.yaml b/test/ztest/unit/objpool/testcase.yaml new file mode 100644 index 000000000000..5558c1f50a6b --- /dev/null +++ b/test/ztest/unit/objpool/testcase.yaml @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright(c) 2025 Intel Corporation. +# +# Object pool allocator unit tests for Ztest framework + +tests: + sof.unit.objpool: + tags: unit + platform_allow: native_sim + integration_platforms: + - native_sim + build_only: false diff --git a/third_party/include/dax_inf.h b/third_party/include/dax_inf.h new file mode 100644 index 000000000000..8e25f52fc4a7 --- /dev/null +++ b/third_party/include/dax_inf.h @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE + * + * Copyright(c) 2025 Dolby Laboratories. All rights reserved. + * + * Author: Jun Lai <jun.lai@dolby.com> + */ + +#ifndef DAX_INF_H +#define DAX_INF_H + +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +enum dax_device { + DAX_DEVICE_UNSUPPORTED = -1, + DAX_DEVICE_SPEAKER = 0, + DAX_DEVICE_HEADPHONE = 1, +}; + +enum dax_frame_fmt { + DAX_FMT_UNSUPPORTED = -1, + DAX_FMT_SHORT_16 = 4, + DAX_FMT_INT = 5, + DAX_FMT_FLOAT = 7, +}; + +enum dax_sample_rate { + DAX_RATE_UNSUPPORTED = -1, +}; + +enum dax_channels { + DAX_CHANNLES_UNSUPPORTED = -1, +}; + +enum dax_buffer_fmt { + DAX_BUFFER_LAYOUT_UNSUPPORTED = -1, + DAX_BUFFER_LAYOUT_INTERLEAVED, + DAX_BUFFER_LAYOUT_NONINTERLEAVED, +}; + +enum dax_param_id { + DAX_PARAM_ID_ENABLE = 0x08001026, + DAX_PARAM_ID_TUNING_FILE = 0x08001027, + DAX_PARAM_ID_PROFILE = 0x08001028, + DAX_PARAM_ID_ENDPOINT = 0x08001029, + DAX_PARAM_ID_TUNING_DEVICE = 0x08001030, + DAX_PARAM_ID_CP_ENABLE = 0x08001031, + DAX_PARAM_ID_OUT_DEVICE = 0x08001032, + DAX_PARAM_ID_ABSOLUTE_VOLUME = 0x08001033, + DAX_PARAM_ID_CTC_ENABLE = 0x08001034, +}; + +struct dax_media_fmt { + enum dax_frame_fmt data_format; + uint32_t sampling_rate; + uint32_t num_channels; + enum dax_buffer_fmt layout; + uint32_t bytes_per_sample; +}; + +struct dax_buffer { + void *addr; + uint32_t size; /* Total buffer size in bytes */ + uint32_t avail; /* Available bytes for reading */ + uint32_t free; /* Free bytes for writing */ +}; + +struct sof_dax { + /* SOF module parameters */ + uint32_t sof_period_bytes; + + /* DAX state parameters */ + uint32_t period_bytes; + uint32_t period_us; + int32_t endpoint; + int32_t tuning_device; + void *blob_handler; + void *p_dax; + struct dax_media_fmt input_media_format; + struct dax_media_fmt output_media_format; + + /* DAX control parameters */ + int32_t enable; + int32_t profile; + int32_t out_device; + int32_t ctc_enable; + int32_t content_processing_enable; + int32_t volume; + uint32_t update_flags; /* Deprecated */ + + /* DAX buffers */ + struct dax_buffer persist_buffer; /* Used for dax instance */ + struct dax_buffer scratch_buffer; /* Used for dax process */ + struct dax_buffer input_buffer; + struct dax_buffer output_buffer; + struct dax_buffer tuning_file_buffer; +}; + +/** + * @brief Query the persistent memory requirements for the DAX module + * + * @param[in] dax_ctx Pointer to the DAX context structure + * + * @return Size of required persistent memory in bytes + */ +uint32_t dax_query_persist_memory(struct sof_dax *dax_ctx); + +/** + * @brief Query the scratch memory requirements for the DAX module + * + * @param[in] dax_ctx Pointer to the DAX context structure + * + * @return Size of required scratch memory in bytes + */ +uint32_t dax_query_scratch_memory(struct sof_dax *dax_ctx); + +/** + * @brief Query the number of frames in a processing period + * + * @param[in] dax_ctx Pointer to the DAX context structure + * + * @return Number of frames per period + */ +uint32_t dax_query_period_frames(struct sof_dax *dax_ctx); + +/** + * @brief Free the DAX module + * + * @param[in] dax_ctx Pointer to the DAX context structure + * + * This function free all resources built on persistent buffer. + * DO NOT USE THE INSTANCE AFTER CALLING FREE. + * + * @return 0 on success, negative error code on failure + */ +int dax_free(struct sof_dax *dax_ctx); + +/** + * @brief Initialize the DAX module + * + * @param[in] dax_ctx Pointer to the DAX context structure + * + * @return 0 on success, negative error code on failure + */ +int dax_init(struct sof_dax *dax_ctx); + +/** + * @brief Process audio data through the DAX module + * + * If DAX is disabled or the DAX instance is invalid (dax_ctx->p_dax is NULL), + * the dax_process will by default perform only copy operations, without any + * audio processing. + * + * @param[in] dax_ctx Pointer to the DAX context structure + * + * @return Bytes of processed. negative error code on failure + */ +int dax_process(struct sof_dax *dax_ctx); + +/** + * @brief Set a parameter value for the DAX module + * + * @param[in] id Parameter identifier + * @param[in] val Pointer to parameter value + * @param[in] val_sz Size of parameter value in bytes + * @param[in] dax_ctx Pointer to the DAX context structure + * + * @return 0 on success, negative error code on failure + */ +int dax_set_param(uint32_t id, const void *val, uint32_t val_sz, struct sof_dax *dax_ctx); + +/** + * @brief Enable/Disable the DAX module + * + * @param[in] enable 0:disable, 1:enable. + * @param[in] dax_ctx Pointer to the DAX context structure + * + * @return 0 on success, negative error code on failure + */ +int dax_set_enable(int32_t enable, struct sof_dax *dax_ctx); + +/** + * @brief Set the volume for the DAX module + * + * @param[in] volume Value to apply + * @param[in] dax_ctx Pointer to the DAX context structure + * + * @return 0 or positive code on success, negative error code on failure + */ +int dax_set_volume(int32_t volume, struct sof_dax *dax_ctx); + +/** + * @brief Update the output device configuration + * + * @param[in] out_device Output device identifier. Supported devices: + * 0: speaker + * 1: headphone + * @param[in] dax_ctx Pointer to the DAX context structure + * + * @return 0 on success, negative error code on failure + */ +int dax_set_device(int32_t out_device, struct sof_dax *dax_ctx); + +/** + * @brief Enable/Disable crosstalk cancellation feature + * + * @param[in] enable 0:disable, 1:enable. + * @param[in] dax_ctx Pointer to the DAX context structure + * + * @return 0 on success, negative error code on failure + */ +int dax_set_ctc_enable(int32_t enable, struct sof_dax *dax_ctx); + +/** + * @brief Get the DAX module version string + * + * @return Pointer to null-terminated version string + */ +const char *dax_get_version(void); + +/** + * @brief Find parameters in a buffer based on query criteria + * + * @param[in] query_id ID of the parameter to search for. Supported query IDs: + * - DAX_PARAM_ID_PROFILE + * - DAX_PARAM_ID_TUNING_DEVICE + * - DAX_PARAM_ID_CP_ENABLE + * @param[in] query_val Value to match when searching + * @param[out] query_sz Pointer to store the size of the found parameters + * @param[in] dax_ctx Pointer to the DAX context structure + * + * @return Pointer to the found parameters, or NULL if not found + */ +void *dax_find_params(uint32_t query_id, + int32_t query_val, + uint32_t *query_sz, + struct sof_dax *dax_ctx); + +#endif /* DAX_INF_H */ diff --git a/third_party/include/nxp/eap/EAP_Includes/EAP16.h b/third_party/include/nxp/eap/EAP_Includes/EAP16.h new file mode 100644 index 000000000000..4bcee38dee12 --- /dev/null +++ b/third_party/include/nxp/eap/EAP_Includes/EAP16.h @@ -0,0 +1,1033 @@ +/* Copyright 2004-2025 NXP + * + * SPDX-License-Identifier: MIT + * This license applies ONLY to this header file EAP16.h + * + * 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. + * + */ + +/***************************************************************************************** + + $Author: beq03888 $ + $Revision: 16643 $ + $Date: 2011-10-14 09:00:36 +0200 (Fri, 14 Oct 2011) $ + +*****************************************************************************************/ + +/****************************************************************************************/ +/* */ +/* Header file for the application layer interface of Concert Sound, Bass Enhancement */ +/* and volume management bundle. */ +/* */ +/* This files includes all definitions, types, structures and function */ +/* prototypes required by the calling layer. All other types, structures and */ +/* functions are private. */ +/* */ +/****************************************************************************************/ +/* */ +/* Note: 1 */ +/* ======= */ +/* The algorithm can execute either with separate input and output buffers or with */ +/* a common buffer, i.e. the data is processed in-place. */ +/* */ +/****************************************************************************************/ +/* */ +/* Note: 2 */ +/* ======= */ +/* Three data formats are support Stereo and Mono. The input data is */ +/* interleaved as follows: ----- */ +/* */ +/* Byte Offset Stereo Input Mono Input */ +/* =========== ============ ==================== */ +/* 0 Left Sample #1 Mono Sample #1 */ +/* 2 Right Sample #1 Mono Sample #1 */ +/* 4 Left Sample #2 Mono Sample #2 */ +/* 6 Right Sample #2 Mono Sample #2 */ +/* . . . */ +/* . . . */ +/* */ +/* For output buffer there is 3 cases : */ +/* ------ */ +/* 1) CROSSOVER is DISABLE */ +/* Byte Offset Stereo Input/Output Mono Input/Output */ +/* =========== =================== ================= */ +/* 0 Left Sample #1 Mono Sample #1 */ +/* 2 Right Sample #1 Mono Sample #1 */ +/* 4 Left Sample #2 Mono Sample #2 */ +/* 6 Right Sample #2 Mono Sample #2 */ +/* . . . */ +/* . . . */ +/* */ +/* 2) CROSSOVER is ENABLE & input/output in STEREO */ +/* pOutData[0] will be the output Low band and pOutData[1] the High band */ +/* Stereo Input pOutData[0] in stereo pOutData[1] in stereo */ +/* =================== ===================== ===================== */ +/* Left Sample #1 Left Sample LB #1 Left Sample HB #1 */ +/* Right Sample #1 Right Sample LB #1 Right Sample HB #1 */ +/* Left Sample #2 Left Sample LB #2 Left Sample HB #2 */ +/* Right Sample #2 Right Sample LB #2 Right Sample HB #2 */ +/* . . . */ +/* . . . */ +/* */ +/* 3) CROSSOVER is ENABLE & input/output in MONO */ +/* pOutData[0] will be the output Low band and pOutData[1] the High band */ +/* Mono Input pOutData[0] in mono pOutData[1] in mono */ +/* =============== ===================== ===================== */ +/* MONO Sample #1 MONO Sample LB #1 MONO Sample HB #1 */ +/* MONO Sample #2 MONO Sample LB #2 MONO Sample HB #2 */ +/* MONO Sample #3 MONO Sample LB #3 MONO Sample HB #3 */ +/* MONO Sample #4 MONO Sample LB #4 MONO Sample HB #4 */ +/* . . . */ +/* . . . */ +/* */ +/****************************************************************************************/ + +#ifndef __LVM_H__ +#define __LVM_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#ifdef ALGORITHM_CS +#define ALGORITHM_VIRTUALIZER +#endif /* ALGORITHM_CS */ + +#ifdef ALGORITHM_DBE +#define ALGORITHM_BASS +#else +#ifdef ALGORITHM_PB +#define ALGORITHM_BASS +#endif /* ALGORITHM_PB */ +#endif /* ALGORITHM_DBE */ + + +/****************************************************************************************/ +/* */ +/* Includes */ +/* */ +/****************************************************************************************/ + +#include "LVC_Types.h" + + +/****************************************************************************************/ +/* */ +/* Definitions */ +/* */ +/****************************************************************************************/ + +/* MAXIMAL VALUE LIMIT */ +#define LVM_MAX_NUM_CHANNELS 2 /* Maximum number of interleaved input channels */ +#define MAX_INTERNAL_BLOCKSIZE 1024 /* Maximum internal block size authorized (multiple of 64)*/ +#define LVM_HEADROOM_MAX_NBANDS 5 /* Headroom management */ +#define LVM_EQNB_MAX_BANDS_NBR 10 /* EQNB Maximal band number */ +#define LVM_PSA_MAX_NUMBANDS 64 /* Maximum Number of PSA Bands*/ + +/* Memory table*/ +#define LVM_NR_MEMORY_REGIONS 4 /* Number of memory regions */ + +/* Concert Sound effect level presets */ +#ifdef ALGORITHM_VIRTUALIZER +#define LVM_CS_EFFECT_NONE 0 /* 0% effect, minimum value */ +#define LVM_CS_EFFECT_LOW 16384 /* 50% effect */ +#define LVM_CS_EFFECT_MED 24576 /* 75% effect */ +#define LVM_CS_EFFECT_HIGH 32767 /* 100% effect, maximum value */ +#endif /*end ALGORITHM_VIRTUALIZER */ + +#ifdef ALGORITHM_TE +#define LVM_TE_LOW_MIPS 32767 /* Treble enhancement 6dB Mips saving mode */ +#endif /* end ALGORITHM_TE */ + +/* Bass enhancement effect level presets */ +#ifdef ALGORITHM_BASS +#define LVM_BE_0DB 0 /* 0dB boost, no effect */ +#define LVM_BE_3DB 3 /* +3dB boost */ +#define LVM_BE_6DB 6 /* +6dB boost */ +#define LVM_BE_9DB 9 /* +9dB boost */ +#define LVM_BE_12DB 12 /* +12dB boost */ +#define LVM_BE_15DB 15 /* +15dB boost */ +#endif /* end ALGORITHM_BASS */ + +/****************************************************************************************/ +/* */ +/* Types */ +/* */ +/****************************************************************************************/ + +/* Instance handle */ +typedef void *LVM_Handle_t; + + +/* Status return values */ +typedef enum +{ + LVM_SUCCESS = 0, /* Successful return from a routine */ + LVM_ALIGNMENTERROR = 1, /* Memory alignment error */ + LVM_NULLADDRESS = 2, /* NULL allocation address */ + LVM_INVALIDNUMSAMPLES = 3, /* Invalid number of samples */ + LVM_WRONGAUDIOTIME = 4, /* Wrong time value for audio time*/ + LVM_ALGORITHMDISABLED = 5, /* Algorithm is disabled*/ + LVM_NOT_INITIALIZED = 6, /* Process function was called for a non-initialized module */ + LVM_INVALIDNXPPLATFORM = 7, /* Invalid NXP platform */ + // OUT OF RANGE HANDLE Must stay at the end of the enum + LVM_OUTOFRANGE = 8, /* Out of range control parameter (without details) */ + /* OUT OF RANGE WITH DETAILS */ + LVM_OUTOFRANGE_GENERAL_PARAMS = 9, + LVM_OUTOFRANGE_SPEAKER_TYPES = 10, + LVM_OUTOFRANGE_VIRTUALIZER_OM = 11, + LVM_OUTOFRANGE_VIRTUALIZER_TYPE = 12, + LVM_OUTOFRANGE_VIRTUALIZER_REVERB = 13, + LVM_OUTOFRANGE_CS_EFFECT = 14, + LVM_OUTOFRANGE_USER_EQNB = 15, + LVM_OUTOFRANGE_USER_EQNB_BAND_DEF = 16, + LVM_OUTOFRANGE_PRODUCT_EQNB = 17, + LVM_OUTOFRANGE_PRODUCT_EQNB_BAND_DEF = 18, + LVM_OUTOFRANGE_BE = 19, + LVM_OUTOFRANGE_PB = 20, + LVM_OUTOFRANGE_VC_LEVEL = 21, + LVM_OUTOFRANGE_VC_BALANCE = 22, + LVM_OUTOFRANGE_TE = 23, + LVM_OUTOFRANGE_LM = 24, + LVM_OUTOFRANGE_LM_SPEAKER_CUTOFF = 25, + LVM_OUTOFRANGE_AVL = 26, + LVM_OUTOFRANGE_TG_OM = 27, + LVM_OUTOFRANGE_TG = 28, + LVM_OUTOFRANGE_PSA_RATE = 29, + LVM_OUTOFRANGE_PSA_ENABLE = 30, + LVM_OUTOFRANGE_PSA_NUMBAND = 31, + LVM_OUTOFRANGE_LIMP_OM = 32, + LVM_OUTOFRANGE_LIMP_THRESHOLD = 33, + LVM_OUTOFRANGE_LIMR_OM = 34, + LVM_OUTOFRANGE_LIMR_THRESHOLD = 35, + LVM_OUTOFRANGE_LIMR_REFERENCE = 36, + LVM_OUTOFRANGE_CS_AP_MODE = 37, + LVM_OUTOFRANGE_CS_AP = 38, + LVM_OUTOFRANGE_XO_OPERATINGMODE = 39, + LVM_OUTOFRANGE_XO_CUTOFFFREQUENCY = 40, + + + LVM_RETURNSTATUS_DUMMY = LVM_MAXENUM +} LVM_ReturnStatus_en; + + +/* Buffer Management mode */ +typedef enum +{ + LVM_MANAGED_BUFFERS = 0, + LVM_UNMANAGED_BUFFERS = 1, + LVM_BUFFERS_DUMMY = LVM_MAXENUM +} LVM_BufferMode_en; + + + +/* Output device type */ +typedef enum +{ + LVM_HEADPHONES = 0, + LVM_MOBILE_SPEAKERS_SMALL = 2, + LVM_MOBILE_SPEAKERS_MEDIUM = 3, + LVM_MOBILE_SPEAKERS_LARGE = 4, + LVM_SPEAKERTYPE_MAX = LVM_MAXENUM +} LVM_OutputDeviceType_en; + +typedef enum +{ + LVM_IMXRT1050 = 1, // I.MXRT1050 : EAP running on Cortex-M7 + LVM_IMXRT1060 = 2, // I.MXRT1060 : EAP running on Cortex-M7 + LVM_IMXRT1064 = 3, // I.MXRT1064 : EAP running on Cortex-M7 + LVM_IMXRT1170 = 4, // I.MXRT1170 : EAP running on Cortex-M7 + LVM_LPC55 = 5, // LPC55 : EAP running on Cortex-M33 + LVM_IMXRT500 = 6, // I.MXRT500 : EAP running on FusionF1 + LVM_IMXRT600 = 7, // I.MXRT600 : EAP running on HIFI4 + LVM_MAX_PLATFORM = LVM_MAXENUM, +}EAP_NXPPlatform_en; + +/* Virtualizer mode selection*/ +#ifdef ALGORITHM_VIRTUALIZER +typedef enum +{ + LVM_CONCERTSOUND = 0, + LVM_VIRTUALIZERTYPE_DUMMY = LVM_MAXENUM +} LVM_VirtualizerType_en; +#endif /* ALGORITHM_VIRTUALIZER */ + +/* N-Band Equaliser operating mode */ +#if (ALGORITHM_EQNB) || (ALGORITHM_PR_EQNB) +typedef enum +{ + LVM_EQNB_OFF = 0, + LVM_EQNB_ON = 1, + LVM_EQNB_DUMMY = LVM_MAXENUM +} LVM_EQNB_Mode_en; +#endif /* ALGORITHM_EQNB || ALGORITHM_PR_EQNB*/ + +/* Filter mode control */ +typedef enum +{ + LVM_EQNB_FILTER_OFF = 0, + LVM_EQNB_FILTER_ON = 1, + LVM_EQNB_FILTER_DUMMY = LVM_MAXENUM +} LVM_EQNB_FilterMode_en; + +/* Bass Enhancement operating mode */ +#ifdef ALGORITHM_BASS +typedef enum +{ + LVM_BE_OFF = 0, + LVM_BE_ON = 1, + LVM_BE_DUMMY = LVM_MAXENUM +} LVM_BE_Mode_en; + +/* Bass Enhancement centre frequency selection control */ +typedef enum +{ + LVM_BE_CENTRE_55Hz = 0, + LVM_BE_CENTRE_66Hz = 1, + LVM_BE_CENTRE_78Hz = 2, + LVM_BE_CENTRE_90Hz = 3, + LVM_BE_CENTRE_DUMMY = LVM_MAXENUM +} LVM_BE_CentreFreq_en; + +/* Bass Enhancement HPF selection control */ +typedef enum +{ + LVM_BE_HPF_OFF = 0, + LVM_BE_HPF_ON = 1, + LVM_BE_HPF_DUMMY = LVM_MAXENUM +} LVM_BE_FilterSelect_en; + + +#endif /* ALGORITHM_BASS */ + +/* Volume Control operating mode */ +typedef enum +{ + LVM_VC_OFF = 0, + LVM_VC_ON = 1, + LVM_VC_DUMMY = LVM_MAXENUM +} LVM_VC_Mode_en; + +/* Treble Enhancement operating mode */ +#ifdef ALGORITHM_TE +typedef enum +{ + LVM_TE_OFF = 0, + LVM_TE_ON = 1, + LVM_TE_DUMMY = LVM_MAXENUM +} LVM_TE_Mode_en; +#endif /* ALGORITHM_TE */ + +/* Loudness Maximiser operating mode */ +#ifdef ALGORITHM_LM +typedef enum +{ + LVM_LM_OFF = 0, + LVM_LM_ON = 1, + LVM_LM_DUMMY = LVM_MAXENUM +}LVM_LM_Mode_en; + +/* Loudness Maximiser effect setting */ +typedef enum +{ + LVM_LM_GENTLE = 0, + LVM_LM_MEDIUM = 1, + LVM_LM_EXTREME = 2, + LVM_LM_EFFECT_DUMMY = LVM_MAXENUM +}LVM_LM_Effect_en; +#endif /* ALGORITHM_LM */ + +/* AVL operating mode */ +#ifdef ALGORITHM_AVL +typedef enum +{ + LVM_AVL_OFF = 0, + LVM_AVL_ON = 1, + LVM_AVL_DUMMY = LVM_MAXENUM +} LVM_AVL_Mode_en; +#endif /* ALGORITHM_AVL */ + +/* Headroom management operating mode */ +typedef enum +{ + LVM_HEADROOM_OFF = 0, + LVM_HEADROOM_ON = 1, + LVM_Headroom_DUMMY = LVM_MAXENUM +} LVM_Headroom_Mode_en; + +/* Tone Generator operating mode */ +#ifdef ALGORITHM_TG +typedef enum +{ + LVM_TG_OFF = 0, + LVM_TG_CONTINUOUS = 1, + LVM_TG_ONESHOT = 2, + LVM_TG_DUMMY = LVM_MAXENUM +} LVM_TG_Mode_en; + +/* Tone Generator sweep mode */ +typedef enum +{ + LVM_TG_SWEEPLIN = 0, + LVM_TG_SWEEPLOG = 1, + LVM_TG_SWEEP_DUMMY = LVM_MAXENUM +} LVM_TG_SweepMode_en; +#endif /* ALGORITHM_TG */ + +#ifdef ALGORITHM_XO +typedef enum +{ + LVM_XO_MODE_OFF = 0, + LVM_XO_MODE_ON = 1 +}LVM_XO_MODE_en; +#endif /*ALGORITHM_XO*/ + + +#ifdef ALGORITHM_PSA +typedef enum +{ + LVM_PSA_SPEED_SLOW, /* Peak decaying at slow speed */ + LVM_PSA_SPEED_MEDIUM, /* Peak decaying at medium speed */ + LVM_PSA_SPEED_FAST, /* Peak decaying at fast speed */ + LVM_PSA_SPEED_DUMMY = LVM_MAXENUM +} LVM_PSA_DecaySpeed_en; + +typedef enum +{ + LVM_PSA_OFF = 0, + LVM_PSA_ON = 1, + LVM_PSA_DUMMY = LVM_MAXENUM +} LVM_PSA_Mode_en; +#endif /* ALGORITHM_PSA */ + +#ifdef ALGORITHM_LIMP +typedef enum +{ + LVM_LIMP_OFF = 0, + LVM_LIMP_ON = 1, + LVM_LIMP_DUMMY = LVM_MAXENUM +} LVM_LIMP_Mode_en; +#endif /* ALGORITHM_LIMP */ + +#ifdef ALGORITHM_LIMR +typedef enum +{ + LVM_LIMR_OFF = 0, + LVM_LIMR_ON = 1, + LVM_LIMR_DUMMY = LVM_MAXENUM +} LVM_LIMR_Mode_en; + +typedef enum +{ + LVM_LIMR_REF_INPUT = 0, + LVM_LIMR_REF_0DBFS = 1, + LVM_LIMR_REF_DUMMY = LVM_MAXENUM +} LVM_LIMR_Reference_en; +#endif /* ALGORITHM_LIMR */ + +// Adavanced parameter mode +typedef enum +{ + LVM_AP_DEFAULT = 0, + LVM_AP_MANUAL = 1, + LVM_AP_DUMMY = LVM_MAXENUM +} LVM_AP_MODE_en; + +/****************************************************************************************/ +/* */ +/* Structures */ +/* */ +/****************************************************************************************/ + +/* Version information */ +typedef struct +{ + LVM_CHAR *pVersionNumber; /* Pointer to the version number in the format X.YY.ZZ */ + LVM_CHAR *pPlatform; /* Pointer to the library platform type */ +} LVM_VersionInfo_st; + +/* Memory table containing the region definitions */ +typedef struct +{ + LVM_MemoryRegion_st Region[LVM_NR_MEMORY_REGIONS]; /* One definition for each region */ +} LVM_MemTab_t; + + +/* N-Band equaliser band definition */ +typedef struct +{ + LVM_INT16 Gain; /* Band gain in dB */ + LVM_UINT16 Frequency; /* Band centre frequency in Hz */ + LVM_UINT16 QFactor; /* Band quality factor (x100) */ +} LVM_EQNB_BandDef_t; + +/* Headroom band definition */ +typedef struct +{ + LVM_UINT16 Limit_Low; /* Low frequency limit of the band in Hertz */ + LVM_UINT16 Limit_High; /* High frequency limit of the band in Hertz */ + LVM_INT16 Headroom_Offset; /* Headroom = biggest band gain - Headroom_Offset */ +} LVM_HeadroomBandDef_t; + +/* Control Parameter structure */ +typedef struct +{ + /* General parameters */ + LVM_Mode_en OperatingMode; /* Bundle operating mode On/Bypass */ + LVM_Fs_en SampleRate; /* Sample rate */ + LVM_Format_en SourceFormat; /* Input data format */ + LVM_OutputDeviceType_en SpeakerType; /* Output device type */ + LVM_SpeakerType_en SpeakerTypeInternal; /* Device speaker type, mono or stereo */ + +#ifdef ALGORITHM_CS + /* Concert Sound Virtualizer parameters*/ + LVM_Mode_en VirtualizerOperatingMode; /* Virtualizer operating mode On/Off */ + LVM_VirtualizerType_en VirtualizerType; /* Virtualizer type: ConcertSound, CinemaSound Music or CinemaSound Movie */ + LVM_UINT16 VirtualizerReverbLevel; /* Virtualizer reverb level in % */ + LVM_INT16 CS_EffectLevel; /* Concert Sound effect level */ +#endif /* ALGORITHM_CS */ + +#ifdef ALGORITHM_EQNB + /* N-Band Equaliser parameters */ + LVM_EQNB_Mode_en EQNB_OperatingMode; /* N-Band Equaliser operating mode */ + LVM_EQNB_FilterMode_en EQNB_LPF_Mode; /* Low pass filter */ + LVM_INT16 EQNB_LPF_CornerFreq; + LVM_EQNB_FilterMode_en EQNB_HPF_Mode; /* High pass filter */ + LVM_INT16 EQNB_HPF_CornerFreq; + LVM_UINT16 EQNB_NBands; /* Number of bands */ + LVM_EQNB_BandDef_t *pEQNB_BandDefinition; /* Pointer to equaliser definitions */ +#endif /* ALGORITHM_EQNB */ + +#ifdef ALGORITHM_PR_EQNB + /* N-Band Equaliser parameters */ + LVM_EQNB_Mode_en PR_EQNB_OperatingMode; /* N-Band Equaliser operating mode */ + LVM_EQNB_FilterMode_en PR_EQNB_LPF_Mode; /* Low pass filter */ + LVM_INT16 PR_EQNB_LPF_CornerFreq; + LVM_EQNB_FilterMode_en PR_EQNB_HPF_Mode; /* High pass filter */ + LVM_INT16 PR_EQNB_HPF_CornerFreq; + LVM_UINT16 PR_EQNB_NBands; /* Number of bands */ + LVM_EQNB_BandDef_t *pPR_EQNB_BandDefinition; /* Pointer to equaliser definitions */ +#endif /* ALGORITHM_PR_EQNB */ + +#ifdef ALGORITHM_DBE + /* Bass Enhancement parameters */ + LVM_BE_Mode_en BE_OperatingMode; /* Bass Enhancement operating mode */ + LVM_INT16 BE_EffectLevel; /* Bass Enhancement effect level */ + LVM_BE_CentreFreq_en BE_CentreFreq; /* Bass Enhancement centre frequency */ + LVM_BE_FilterSelect_en BE_HPF; /* Bass Enhancement high pass filter selector */ + +#endif /* ALGORITHM_DBE */ +#ifdef ALGORITHM_PB + /* Bass Enhancement parameters */ + LVM_BE_Mode_en BE_OperatingMode; /* Bass Enhancement operating mode */ + LVM_INT16 BE_EffectLevel; /* Bass Enhancement effect level */ + LVM_BE_CentreFreq_en BE_CentreFreq; /* Bass Enhancement centre frequency */ + LVM_BE_FilterSelect_en BE_HPF; /* Bass Enhancement high pass filter selector */ + +#endif /* ALGORITHM_PB */ + /* Volume Control parameters */ + LVM_INT16 VC_EffectLevel; /* Volume Control setting in dBs */ + LVM_INT16 VC_Balance; /* Left Right Balance control in dB (-96 to 96 dB), -ve values reduce */ + +#ifdef ALGORITHM_TE + /* Treble Enhancement parameters */ + LVM_TE_Mode_en TE_OperatingMode; /* Treble Enhancement On/Off */ + LVM_INT16 TE_EffectLevel; /* Treble Enhancement gain dBs */ + +#endif /* ALGORITHM_TE */ +#ifdef ALGORITHM_LM + /* Loudness Maximiser parameters */ + LVM_LM_Mode_en LM_OperatingMode; /* Loudness Maximiser operating mode */ + LVM_LM_Effect_en LM_EffectLevel; /* Loudness Maximiser effect level */ + LVM_UINT16 LM_Attenuation; /* Loudness Maximiser output attenuation */ + LVM_UINT16 LM_CompressorGain; /* Loudness Maximiser output compressor gain */ + LVM_UINT16 LM_SpeakerCutOff; /* Loudness Maximiser speaker cut off frequency */ + +#endif /* ALGORITHM_LM */ + +#ifdef ALGORITHM_AVL + /* AVL parameters */ + LVM_AVL_Mode_en AVL_OperatingMode; /* AVL operating mode */ + +#endif /* ALGORITHM_AVL */ + +#ifdef ALGORITHM_TG + /* Tone Generator parameters */ + LVM_TG_Mode_en TG_OperatingMode; /* Tone generator mode */ + LVM_TG_SweepMode_en TG_SweepMode; /* Log or linear sweep */ + LVM_UINT16 TG_StartFrequency; /* Sweep start frequency in Hz */ + LVM_INT16 TG_StartAmplitude; /* Sweep start amplitude in dBr */ + LVM_UINT16 TG_StopFrequency; /* Sweep stop frequency in Hz */ + LVM_INT16 TG_StopAmplitude; /* Sweep stop amplitude in dBr */ + LVM_UINT16 TG_SweepDuration; /* Sweep duration in seconds, 0 for infinite duration tone */ + LVM_Callback pTG_CallBack; /* End of sweep callback */ + LVM_INT16 TG_CallBackID; /* Callback ID*/ + void *pTGAppMemSpace; /* Application instance handle or memory area */ +#endif /* ALGORITHM_TG */ + +#ifdef ALGORITHM_PSA + /* General Control */ + LVM_PSA_Mode_en PSA_Enable; + + /* Spectrum Analyzer parameters */ + LVM_PSA_DecaySpeed_en PSA_PeakDecayRate; /* Peak value decay rate*/ + LVM_UINT16 PSA_NumBands; /* Number of Bands*/ +#endif /* ALGORITHM_PSA */ + +#ifdef ALGORITHM_LIMP + LVM_LIMP_Mode_en LIMP_OperatingMode; /* LIMP operating mode */ + LVM_INT16 LIMP_Threshold; /* LIMP threshold in dB */ +#endif /* ALGORITHM_LIMP */ + +#ifdef ALGORITHM_LIMR + LVM_LIMR_Mode_en LIMR_OperatingMode; /* LIMR operating mode */ + LVM_LIMR_Reference_en LIMR_Reference; /* LIMR reference input */ + LVM_INT16 LIMR_Threshold; /* LIMR threshold in dB */ +#endif /* ALGORITHM_LIMR */ + +#ifdef ALGORITHM_CS + LVM_AP_MODE_en CS_AP_Mode; /* concert sound advanced paramameter mode */ + LVM_INT16 CS_AP_MidGain; /* MidChannelGain */ + LVM_UINT16 CS_AP_MidCornerFreq; /* Shelving Filter Corner Frequency */ + LVM_UINT16 CS_AP_SideHighPassCutoff; /* SideBoost HighPassFilter Corner Frequency */ + LVM_UINT16 CS_AP_SideLowPassCutoff; /* SideBoost LowPassFilter Corner Frequency */ + LVM_INT16 CS_AP_SideGain; /* Side Channel Gain */ +#endif + +#ifdef ALGORITHM_XO + LVM_Mode_en XO_OperatingMode; /* Crossover operating mode*/ + LVM_UINT16 XO_cutoffFrequency; /* Crossover cut-off frequency*/ + +#endif/*ALGORITHM_XO*/ +} LVM_ControlParams_t; + + +/* Instance Parameter structure */ +typedef struct +{ + /* General */ + LVM_BufferMode_en BufferMode; /* Buffer management mode */ + LVM_UINT16 MaxBlockSize; /* Maximum processing block size */ + + /* N-Band Equaliser */ + LVM_UINT16 EQNB_NumBands; /* Maximum number of User equaliser bands */ + LVM_UINT16 PR_EQNB_NumBands; /* Maximum number of Product equaliser bands */ + EAP_NXPPlatform_en Platform; /* NXP Platform where EAP is playing on (LVM_IMXRT1050,LVM_IMXRT1060, LVM_IMXRT1064, LVM_IMXRT1170, LVM_LPC55, LVM_IMXRT500, LVM_IMXRT600)*/ + + +#ifdef ALGORITHM_PSA + /* PSA */ + LVM_UINT16 PSA_HistorySize; /* PSA History size in ms: 200 to 5000 */ + LVM_UINT16 PSA_MaxBands; /* Maximum number of bands: 6 to 64 */ + LVM_UINT16 PSA_SpectrumUpdateRate; /* Spectrum update rate : 10 to 25*/ + LVM_PSA_Mode_en PSA_Included; /* Controls the instance memory allocation for PSA: ON/OFF */ +#endif /* ALGORITHM_PSA */ +} LVM_InstParams_t; + + +/* Headroom management parameter structure */ +typedef struct +{ + LVM_Headroom_Mode_en Headroom_OperatingMode; /* Headroom Control On/Off */ + LVM_HeadroomBandDef_t *pHeadroomDefinition; /* Pointer to headroom bands definition */ + LVM_UINT16 NHeadroomBands; /* Number of headroom bands */ +} LVM_HeadroomParams_t; + + +/****************************************************************************************/ +/* */ +/* Function Prototypes */ +/* */ +/****************************************************************************************/ + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetVersionInfo */ +/* */ +/* DESCRIPTION: */ +/* This function is used to retrieve information about the library's version. */ +/* */ +/* PARAMETERS: */ +/* pVersion Pointer to an empty version info structure */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS when pVersion is NULL */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetVersionInfo(LVM_VersionInfo_st *pVersion); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetMemoryTable */ +/* */ +/* DESCRIPTION: */ +/* This function is used for memory allocation and free. It can be called in */ +/* two ways: */ +/* */ +/* hInstance = NULL Returns the memory requirements */ +/* hInstance = Instance handle Returns the memory requirements and */ +/* allocated base addresses for the instance */ +/* */ +/* When this function is called for memory allocation (hInstance=NULL) the memory */ +/* base address pointers are NULL on return. */ +/* */ +/* When the function is called for free (hInstance = Instance Handle) the memory */ +/* table returns the allocated memory and base addresses used during initialisation. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pMemoryTable Pointer to an empty memory definition table */ +/* pInstParams Pointer to the instance parameters */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS When one of pMemoryTable or pInstParams is NULL */ +/* LVM_OUTOFRANGE When any of the Instance parameters are out of range */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetMemoryTable(LVM_Handle_t hInstance, + LVM_MemTab_t *pMemoryTable, + LVM_InstParams_t *pInstParams); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetInstanceHandle */ +/* */ +/* DESCRIPTION: */ +/* This function is used to create a bundle instance. It returns the created instance */ +/* handle through phInstance. All parameters are set to their default, inactive state. */ +/* */ +/* PARAMETERS: */ +/* phInstance pointer to the instance handle */ +/* pMemoryTable Pointer to the memory definition table */ +/* pInstParams Pointer to the instance parameters */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Initialisation succeeded */ +/* LVM_ALIGNMENTERROR Instance or scratch memory on incorrect alignment */ +/* LVM_NULLADDRESS Instance or scratch memory has a NULL pointer */ +/* */ +/* NOTES: */ +/* 1. This function must not be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetInstanceHandle(LVM_Handle_t *phInstance, + LVM_MemTab_t *pMemoryTable, + LVM_InstParams_t *pInstParams); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_ClearAudioBuffers */ +/* */ +/* DESCRIPTION: */ +/* This function is used to clear the internal audio buffers of the bundle. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance handle */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Buffers Cleared */ +/* LVM_NULLADDRESS Instance is NULL */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_ClearAudioBuffers(LVM_Handle_t hInstance); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetControlParameters */ +/* */ +/* DESCRIPTION: */ +/* Request the LifeVibes module parameters. The current parameter set is returned */ +/* via the parameter pointer. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance handle */ +/* pParams Pointer to an empty parameter structure */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS when any of hInstance or pParams is NULL */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetControlParameters(LVM_Handle_t hInstance, + LVM_ControlParams_t *pParams); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_SetControlParameters */ +/* */ +/* DESCRIPTION: */ +/* Sets or changes the LifeVibes module parameters. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance handle */ +/* pParams Pointer to a parameter structure */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS When hInstance, pParams or any control pointers are NULL */ +/* LVM_OUTOFRANGE When any of the control parameters are out of range */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_SetControlParameters(LVM_Handle_t hInstance, + LVM_ControlParams_t *pParams); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_Process */ +/* */ +/* DESCRIPTION: */ +/* Process function for the LifeVibes module. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance handle */ +/* pInData Pointer to the input data */ +/* pOutData Pointer to the output data */ +/* NumSamples Number of samples in the input buffer */ +/* AudioTime Audio Time of the current input data in milli-seconds */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_INVALIDNUMSAMPLES When the NumSamples is not a valied multiple in unmanaged */ +/* buffer mode */ +/* LVM_ALIGNMENTERROR When either the input our output buffers are not 32-bit */ +/* aligned in unmanaged mode */ +/* LVM_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */ +/* */ +/* NOTES: */ +/* 1. The input and output buffers must be 32-bit aligned */ +/* 2. Number of samples is defined as follows: */ +/* MONO the number of samples in the block */ +/* MONOINSTEREO the number of sample pairs in the block */ +/* STEREO the number of sample pairs in the block */ +/* */ +/* 3. If Crossover Disable, pOutData[0] MUST be initialize as a non-null pointer */ +/* 4. If Crossover Enable, pOutData[0] & pOutData[1] MUST be initialize as */ +/* a non-null pointer */ +/* */ +/* */ +/* */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance, + const LVM_INT16 *pInData, + LVM_INT16 **pOutData, + LVM_UINT16 NumSamples, + LVM_UINT32 AudioTime); + + +#ifdef ALGORITHM_AVL +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetAVLGain */ +/* */ +/* DESCRIPTION: */ +/* This function is used to retrieve the AVL last generated gain in Q16.15 */ +/* linear values. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pAVL_Gain Pointer to the gain */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS When hInstance or pAVL_Gain are null addresses */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetAVLGain( LVM_Handle_t hInstance, + LVM_INT32 *pAVL_Gain); + + +#endif /* ALGORITHM_AVL */ + +#ifdef ALGORITHM_EQNB +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_SetHeadroomParams */ +/* */ +/* DESCRIPTION: */ +/* This function is used to set the automatic headroom management parameters. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pHeadroomParams Pointer to headroom parameter structure */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_SetHeadroomParams( LVM_Handle_t hInstance, + LVM_HeadroomParams_t *pHeadroomParams); + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetHeadroomParams */ +/* */ +/* DESCRIPTION: */ +/* This function is used to get the automatic headroom management parameters. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pHeadroomParams Pointer to headroom parameter structure (output) */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS When hInstance or pHeadroomParams are NULL */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetHeadroomParams( LVM_Handle_t hInstance, + LVM_HeadroomParams_t *pHeadroomParams); +#endif /* ALGORITHM_EQNB */ + +#ifdef ALGORITHM_PSA +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetSpectrum */ +/* */ +/* DESCRIPTION: */ +/* This function is used to retrieve Spectral information at a given Audio time */ +/* for display usage */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pCurrentPeaks Pointer to location where currents peaks are to be saved */ +/* pPastPeaks Pointer to location where past peaks are to be saved */ +/* pCentreFreqs Pointer to location where centre frequency of each band is */ +/* to be saved */ +/* AudioTime Audio time at which the spectral information is needed */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS If any of input addresses are NULL */ +/* LVM_WRONGAUDIOTIME Failure due to audio time error */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetSpectrum( LVM_Handle_t hInstance, + LVM_INT8 *pCurrentPeaks, + LVM_INT8 *pPastPeaks, + LVM_UINT16 *pCentreFreqs, + LVM_UINT32 AudioTime); + + +#endif /* ALGORITHM_PSA */ + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_SetVolumeNoSmoothing */ +/* */ +/* DESCRIPTION: */ +/* This function is used to set output volume without any smoothing */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pParams Control Parameters, only volume value is used here */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS If any of input addresses are NULL */ +/* LVM_OUTOFRANGE When any of the control parameters are out of range */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_SetVolumeNoSmoothing( LVM_Handle_t hInstance, + LVM_ControlParams_t *pParams); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __LVM_H__ */ + diff --git a/third_party/include/nxp/eap/EAP_Includes/EAP32.h b/third_party/include/nxp/eap/EAP_Includes/EAP32.h new file mode 100644 index 000000000000..d69a335405a8 --- /dev/null +++ b/third_party/include/nxp/eap/EAP_Includes/EAP32.h @@ -0,0 +1,1016 @@ +/* Copyright 2004-2025 NXP + * + * SPDX-License-Identifier: MIT + * This license applies ONLY to this header file EAP32.h + * + * 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. + * + */ + +/****************************************************************************************/ +/* */ +/* Header file for the application layer interface of Concert Sound, Bass Enhancement */ +/* and volume management bundle. */ +/* */ +/* This files includes all definitions, types, structures and function */ +/* prototypes required by the calling layer. All other types, structures and */ +/* functions are private. */ +/* */ +/****************************************************************************************/ +/* */ +/* Note: 1 */ +/* ======= */ +/* The algorithm can execute either with separate input and output buffers or with */ +/* a common buffer, i.e. the data is processed in-place. */ +/* */ +/****************************************************************************************/ +/* */ +/* Note: 2 */ +/* ======= */ +/* Three data formats are support Stereo,Mono-In-Stereo and Mono. The data is */ +/* interleaved as follows: */ +/* */ +/* Byte Offset Stereo Input Mono Input */ +/* =========== ============ ==================== */ +/* 0 Left Sample #1 Mono Sample #1 */ +/* 2 Right Sample #1 Mono Sample #1 */ +/* 4 Left Sample #2 Mono Sample #2 */ +/* 6 Right Sample #2 Mono Sample #2 */ +/* . . . */ +/* . . . */ +/* */ +/* For output buffer there is 3 cases : */ +/* ------ */ +/* 1) CROSSOVER is DISABLE */ +/* Byte Offset Stereo Input/Output Mono Input/Output */ +/* =========== =================== ================= */ +/* 0 Left Sample #1 Mono Sample #1 */ +/* 2 Right Sample #1 Mono Sample #1 */ +/* 4 Left Sample #2 Mono Sample #2 */ +/* 6 Right Sample #2 Mono Sample #2 */ +/* . . . */ +/* . . . */ +/* */ +/* 2) CROSSOVER is ENABLE & input/output in STEREO */ +/* pOutData[0] will be the output Low band and pOutData[1] the High band */ +/* Stereo Input pOutData[0] in stereo pOutData[1] in stereo */ +/* =================== ===================== ===================== */ +/* Left Sample #1 Left Sample LB #1 Left Sample HB #1 */ +/* Right Sample #1 Right Sample LB #1 Right Sample HB #1 */ +/* Left Sample #2 Left Sample LB #2 Left Sample HB #2 */ +/* Right Sample #2 Right Sample LB #2 Right Sample HB #2 */ +/* . . . */ +/* . . . */ +/* */ +/* 3) CROSSOVER is ENABLE & input/output in MONO */ +/* pOutData[0] will be the output Low band and pOutData[1] the High band */ +/* Mono Input pOutData[0] in mono pOutData[1] in mono */ +/* =============== ===================== ===================== */ +/* MONO Sample #1 MONO Sample LB #1 MONO Sample HB #1 */ +/* MONO Sample #2 MONO Sample LB #2 MONO Sample HB #2 */ +/* MONO Sample #3 MONO Sample LB #3 MONO Sample HB #3 */ +/* MONO Sample #4 MONO Sample LB #4 MONO Sample HB #4 */ +/* . . . */ +/* . . . */ +/* */ +/****************************************************************************************/ + +#ifndef __LVM_H__ +#define __LVM_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#ifdef ALGORITHM_CS +#define ALGORITHM_VIRTUALIZER +#endif /* ALGORITHM_CS */ + +#ifdef ALGORITHM_DBE +#define ALGORITHM_BASS +#else +#ifdef ALGORITHM_PB +#define ALGORITHM_BASS +#endif /* ALGORITHM_PB */ +#endif /* ALGORITHM_DBE */ + + +/****************************************************************************************/ +/* */ +/* Includes */ +/* */ +/****************************************************************************************/ + +#include "LVC_Types.h" + + +/****************************************************************************************/ +/* */ +/* Definitions */ +/* */ +/****************************************************************************************/ + +/* MAXIMAL VALUE LIMIT */ +#define LVM_MAX_NUM_CHANNELS 2 /* Maximum number of interleaved input channels */ +#define MAX_INTERNAL_BLOCKSIZE 1024 /* Maximum internal block size authorized (multiple of 64)*/ +#define LVM_HEADROOM_MAX_NBANDS 5 /* Headroom management */ +#define LVM_EQNB_MAX_BANDS_NBR 10 /* EQNB Maximal band number */ +#define LVM_PSA_MAX_NUMBANDS 64 /* Maximum Number of PSA Bands*/ + +/* Memory table*/ +#define LVM_NR_MEMORY_REGIONS 4 /* Number of memory regions */ + +/* Concert Sound effect level presets */ +#ifdef ALGORITHM_VIRTUALIZER +#define LVM_CS_EFFECT_NONE 0 /* 0% effect, minimum value */ +#define LVM_CS_EFFECT_LOW 16384 /* 50% effect */ +#define LVM_CS_EFFECT_MED 24576 /* 75% effect */ +#define LVM_CS_EFFECT_HIGH 32767 /* 100% effect, maximum value */ +#endif /*end ALGORITHM_VIRTUALIZER */ + +#ifdef ALGORITHM_TE +#define LVM_TE_LOW_MIPS 32767 /* Treble enhancement 6dB Mips saving mode */ +#endif /* end ALGORITHM_TE */ + +/* Bass enhancement effect level presets */ +#ifdef ALGORITHM_BASS +#define LVM_BE_0DB 0 /* 0dB boost, no effect */ +#define LVM_BE_3DB 3 /* +3dB boost */ +#define LVM_BE_6DB 6 /* +6dB boost */ +#define LVM_BE_9DB 9 /* +9dB boost */ +#define LVM_BE_12DB 12 /* +12dB boost */ +#define LVM_BE_15DB 15 /* +15dB boost */ +#endif /* end ALGORITHM_BASS */ + +/****************************************************************************************/ +/* */ +/* Types */ +/* */ +/****************************************************************************************/ + +/* Instance handle */ +typedef void *LVM_Handle_t; + + +/* Status return values */ +typedef enum +{ + LVM_SUCCESS = 0, /* Successful return from a routine */ + LVM_ALIGNMENTERROR = 1, /* Memory alignment error */ + LVM_NULLADDRESS = 2, /* NULL allocation address */ + LVM_INVALIDNUMSAMPLES = 3, /* Invalid number of samples */ + LVM_WRONGAUDIOTIME = 4, /* Wrong time value for audio time*/ + LVM_ALGORITHMDISABLED = 5, /* Algorithm is disabled*/ + LVM_NOT_INITIALIZED = 6, /* Process function was called for a non-initialized module */ + LVM_INVALIDNXPPLATFORM = 7, /* Invalid NXP platform */ + // OUT OF RANGE HANDLE Must stay at the end of the enum + LVM_OUTOFRANGE = 8, /* Out of range control parameter (without details) */ + /* OUT OF RANGE WITH DETAILS */ + LVM_OUTOFRANGE_GENERAL_PARAMS = 9, + LVM_OUTOFRANGE_SPEAKER_TYPES = 10, + LVM_OUTOFRANGE_VIRTUALIZER_OM = 11, + LVM_OUTOFRANGE_VIRTUALIZER_TYPE = 12, + LVM_OUTOFRANGE_VIRTUALIZER_REVERB = 13, + LVM_OUTOFRANGE_CS_EFFECT = 14, + LVM_OUTOFRANGE_USER_EQNB = 15, + LVM_OUTOFRANGE_USER_EQNB_BAND_DEF = 16, + LVM_OUTOFRANGE_PRODUCT_EQNB = 17, + LVM_OUTOFRANGE_PRODUCT_EQNB_BAND_DEF = 18, + LVM_OUTOFRANGE_BE = 19, + LVM_OUTOFRANGE_PB = 20, + LVM_OUTOFRANGE_VC_LEVEL = 21, + LVM_OUTOFRANGE_VC_BALANCE = 22, + LVM_OUTOFRANGE_TE = 23, + LVM_OUTOFRANGE_LM = 24, + LVM_OUTOFRANGE_LM_SPEAKER_CUTOFF = 25, + LVM_OUTOFRANGE_AVL = 26, + LVM_OUTOFRANGE_TG_OM = 27, + LVM_OUTOFRANGE_TG = 28, + LVM_OUTOFRANGE_PSA_RATE = 29, + LVM_OUTOFRANGE_PSA_ENABLE = 30, + LVM_OUTOFRANGE_PSA_NUMBAND = 31, + LVM_OUTOFRANGE_LIMP_OM = 32, + LVM_OUTOFRANGE_LIMP_THRESHOLD = 33, + LVM_OUTOFRANGE_LIMR_OM = 34, + LVM_OUTOFRANGE_LIMR_THRESHOLD = 35, + LVM_OUTOFRANGE_LIMR_REFERENCE = 36, + LVM_OUTOFRANGE_CS_AP_MODE = 37, + LVM_OUTOFRANGE_CS_AP = 38, + LVM_OUTOFRANGE_XO_OPERATINGMODE = 39, + LVM_OUTOFRANGE_XO_CUTOFFFREQUENCY = 40, + LVM_OUTOFRANGE_FBSP_OPERATINGMODE = 41, + + + LVM_RETURNSTATUS_DUMMY = LVM_MAXENUM +} LVM_ReturnStatus_en; + + +/* Buffer Management mode */ +typedef enum +{ + LVM_MANAGED_BUFFERS = 0, + LVM_UNMANAGED_BUFFERS = 1, + LVM_BUFFERS_DUMMY = LVM_MAXENUM +} LVM_BufferMode_en; + + + +/* Output device type */ +typedef enum +{ + LVM_HEADPHONES = 0, + LVM_MOBILE_SPEAKERS_SMALL = 2, + LVM_MOBILE_SPEAKERS_MEDIUM = 3, + LVM_MOBILE_SPEAKERS_LARGE = 4, + LVM_SPEAKERTYPE_MAX = LVM_MAXENUM +} LVM_OutputDeviceType_en; +typedef enum +{ + LVM_IMXRT1050 = 1, // I.MXRT1050 : EAP running on Cortex-M7 + LVM_IMXRT1060 = 2, // I.MXRT1060 : EAP running on Cortex-M7 + LVM_IMXRT1064 = 3, // I.MXRT1064 : EAP running on Cortex-M7 + LVM_IMXRT1170 = 4, // I.MXRT1170 : EAP running on Cortex-M7 + LVM_LPC55 = 5, // LPC55 : EAP running on Cortex-M33 + LVM_IMXRT500 = 6, // I.MXRT500 : EAP running on FusionF1 + LVM_IMXRT600 = 7, // I.MXRT600 : EAP running on HIFI4 + LVM_MAX_PLATFORM = LVM_MAXENUM, +}EAP_NXPPlatform_en; +/* Virtualizer mode selection*/ +#ifdef ALGORITHM_VIRTUALIZER +typedef enum +{ + LVM_CONCERTSOUND = 0, + LVM_VIRTUALIZERTYPE_DUMMY = LVM_MAXENUM +} LVM_VirtualizerType_en; +#endif /* ALGORITHM_VIRTUALIZER */ + +/* N-Band Equaliser operating mode */ +#if defined (ALGORITHM_EQNB) || defined (ALGORITHM_PR_EQNB) +typedef enum +{ LVM_EQNB_OFF = 0, + LVM_EQNB_ON = 1, + LVM_EQNB_DUMMY = LVM_MAXENUM +} LVM_EQNB_Mode_en; +#endif /* ALGORITHM_EQNB || ALGORITHM_PR_EQNB*/ + +/* Filter mode control */ +typedef enum +{ + LVM_EQNB_FILTER_OFF = 0, + LVM_EQNB_FILTER_ON = 1, + LVM_EQNB_FILTER_DUMMY = LVM_MAXENUM +} LVM_EQNB_FilterMode_en; + +/* Bass Enhancement operating mode */ +#ifdef ALGORITHM_BASS +typedef enum +{ + LVM_BE_OFF = 0, + LVM_BE_ON = 1, + LVM_BE_DUMMY = LVM_MAXENUM +} LVM_BE_Mode_en; + +/* Bass Enhancement centre frequency selection control */ +typedef enum +{ + LVM_BE_CENTRE_55Hz = 0, + LVM_BE_CENTRE_66Hz = 1, + LVM_BE_CENTRE_78Hz = 2, + LVM_BE_CENTRE_90Hz = 3, + LVM_BE_CENTRE_DUMMY = LVM_MAXENUM +} LVM_BE_CentreFreq_en; + +/* Bass Enhancement HPF selection control */ +typedef enum +{ + LVM_BE_HPF_OFF = 0, + LVM_BE_HPF_ON = 1, + LVM_BE_HPF_DUMMY = LVM_MAXENUM +} LVM_BE_FilterSelect_en; + + +#endif /* ALGORITHM_BASS */ + +/* Volume Control operating mode */ +typedef enum +{ + LVM_VC_OFF = 0, + LVM_VC_ON = 1, + LVM_VC_DUMMY = LVM_MAXENUM +} LVM_VC_Mode_en; + +/* Treble Enhancement operating mode */ +#ifdef ALGORITHM_TE +typedef enum +{ + LVM_TE_OFF = 0, + LVM_TE_ON = 1, + LVM_TE_DUMMY = LVM_MAXENUM +} LVM_TE_Mode_en; +#endif /* ALGORITHM_TE */ + +/* Loudness Maximiser operating mode */ +#ifdef ALGORITHM_LM +typedef enum +{ + LVM_LM_OFF = 0, + LVM_LM_ON = 1, + LVM_LM_DUMMY = LVM_MAXENUM +}LVM_LM_Mode_en; + +/* Loudness Maximiser effect setting */ +typedef enum +{ + LVM_LM_GENTLE = 0, + LVM_LM_MEDIUM = 1, + LVM_LM_EXTREME = 2, + LVM_LM_EFFECT_DUMMY = LVM_MAXENUM +}LVM_LM_Effect_en; +#endif /* ALGORITHM_LM */ + +/* AVL operating mode */ +#ifdef ALGORITHM_AVL +typedef enum +{ + LVM_AVL_OFF = 0, + LVM_AVL_ON = 1, + LVM_AVL_DUMMY = LVM_MAXENUM +} LVM_AVL_Mode_en; +#endif /* ALGORITHM_AVL */ + +/* Headroom management operating mode */ +typedef enum +{ + LVM_HEADROOM_OFF = 0, + LVM_HEADROOM_ON = 1, + LVM_Headroom_DUMMY = LVM_MAXENUM +} LVM_Headroom_Mode_en; + +/* Tone Generator operating mode */ +#ifdef ALGORITHM_TG +typedef enum +{ + LVM_TG_OFF = 0, + LVM_TG_CONTINUOUS = 1, + LVM_TG_ONESHOT = 2, + LVM_TG_DUMMY = LVM_MAXENUM +} LVM_TG_Mode_en; + +/* Tone Generator sweep mode */ +typedef enum +{ + LVM_TG_SWEEPLIN = 0, + LVM_TG_SWEEPLOG = 1, + LVM_TG_SWEEP_DUMMY = LVM_MAXENUM +} LVM_TG_SweepMode_en; +#endif /* ALGORITHM_TG */ + +#ifdef ALGORITHM_XO +typedef enum +{ + LVM_XO_MODE_OFF = 0, + LVM_XO_MODE_ON = 1 +}LVM_XO_MODE_en; +#endif /*ALGORITHM_XO*/ + + +#ifdef ALGORITHM_PSA +typedef enum +{ + LVM_PSA_SPEED_SLOW, /* Peak decaying at slow speed */ + LVM_PSA_SPEED_MEDIUM, /* Peak decaying at medium speed */ + LVM_PSA_SPEED_FAST, /* Peak decaying at fast speed */ + LVM_PSA_SPEED_DUMMY = LVM_MAXENUM +} LVM_PSA_DecaySpeed_en; + +typedef enum +{ + LVM_PSA_OFF = 0, + LVM_PSA_ON = 1, + LVM_PSA_DUMMY = LVM_MAXENUM +} LVM_PSA_Mode_en; +#endif /* ALGORITHM_PSA */ + +#ifdef ALGORITHM_LIMP +typedef enum +{ + LVM_LIMP_OFF = 0, + LVM_LIMP_ON = 1, + LVM_LIMP_DUMMY = LVM_MAXENUM +} LVM_LIMP_Mode_en; +#endif /* ALGORITHM_LIMP */ + +#ifdef ALGORITHM_LIMR +typedef enum +{ + LVM_LIMR_OFF = 0, + LVM_LIMR_ON = 1, + LVM_LIMR_DUMMY = LVM_MAXENUM +} LVM_LIMR_Mode_en; + +typedef enum +{ + LVM_LIMR_REF_INPUT = 0, + LVM_LIMR_REF_0DBFS = 1, + LVM_LIMR_REF_DUMMY = LVM_MAXENUM +} LVM_LIMR_Reference_en; +#endif /* ALGORITHM_LIMR */ + +// Adavanced parameter mode +typedef enum +{ + LVM_AP_DEFAULT = 0, + LVM_AP_MANUAL = 1, + LVM_AP_DUMMY = LVM_MAXENUM +} LVM_AP_MODE_en; + +/****************************************************************************************/ +/* */ +/* Structures */ +/* */ +/****************************************************************************************/ + +/* Version information */ +typedef struct +{ + LVM_CHAR *pVersionNumber; /* Pointer to the version number in the format X.YY.ZZ */ + LVM_CHAR *pPlatform; /* Pointer to the library platform type */ +} LVM_VersionInfo_st; + +/* Memory table containing the region definitions */ +typedef struct +{ + LVM_MemoryRegion_st Region[LVM_NR_MEMORY_REGIONS]; /* One definition for each region */ +} LVM_MemTab_t; + + +/* N-Band equaliser band definition */ +typedef struct +{ + LVM_INT16 Gain; /* Band gain in dB */ + LVM_UINT16 Frequency; /* Band centre frequency in Hz */ + LVM_UINT16 QFactor; /* Band quality factor (x100) */ +} LVM_EQNB_BandDef_t; + +/* Headroom band definition */ +typedef struct +{ + LVM_UINT16 Limit_Low; /* Low frequency limit of the band in Hertz */ + LVM_UINT16 Limit_High; /* High frequency limit of the band in Hertz */ + LVM_INT16 Headroom_Offset; /* Headroom = biggest band gain - Headroom_Offset */ +} LVM_HeadroomBandDef_t; + +/* Control Parameter structure */ +typedef struct +{ + /* General parameters */ + LVM_Mode_en OperatingMode; /* Bundle operating mode On/Bypass */ + LVM_Fs_en SampleRate; /* Sample rate */ + LVM_Format_en SourceFormat; /* Input data format */ + LVM_OutputDeviceType_en SpeakerType; /* Output device type */ + LVM_SpeakerType_en SpeakerTypeInternal; /* Device speaker type, mono or stereo */ + +#ifdef ALGORITHM_CS + /* Concert Sound Virtualizer parameters*/ + LVM_Mode_en VirtualizerOperatingMode; /* Virtualizer operating mode On/Off */ + LVM_VirtualizerType_en VirtualizerType; /* Virtualizer type: ConcertSound, CinemaSound Music or CinemaSound Movie */ + LVM_UINT16 VirtualizerReverbLevel; /* Virtualizer reverb level in % */ + LVM_INT16 CS_EffectLevel; /* Concert Sound effect level */ +#endif /* ALGORITHM_CS */ + +#ifdef ALGORITHM_EQNB + /* N-Band Equaliser parameters */ + LVM_EQNB_Mode_en EQNB_OperatingMode; /* N-Band Equaliser operating mode */ + LVM_EQNB_FilterMode_en EQNB_LPF_Mode; /* Low pass filter */ + LVM_INT16 EQNB_LPF_CornerFreq; + LVM_EQNB_FilterMode_en EQNB_HPF_Mode; /* High pass filter */ + LVM_INT16 EQNB_HPF_CornerFreq; + LVM_UINT16 EQNB_NBands; /* Number of bands */ + LVM_EQNB_BandDef_t *pEQNB_BandDefinition; /* Pointer to equaliser definitions */ +#endif /* ALGORITHM_EQNB */ + +#ifdef ALGORITHM_PR_EQNB + /* N-Band Equaliser parameters */ + LVM_EQNB_Mode_en PR_EQNB_OperatingMode; /* N-Band Equaliser operating mode */ + LVM_EQNB_FilterMode_en PR_EQNB_LPF_Mode; /* Low pass filter */ + LVM_INT16 PR_EQNB_LPF_CornerFreq; + LVM_EQNB_FilterMode_en PR_EQNB_HPF_Mode; /* High pass filter */ + LVM_INT16 PR_EQNB_HPF_CornerFreq; + LVM_UINT16 PR_EQNB_NBands; /* Number of bands */ + LVM_EQNB_BandDef_t *pPR_EQNB_BandDefinition; /* Pointer to equaliser definitions */ +#endif /* ALGORITHM_PR_EQNB */ + +#ifdef ALGORITHM_DBE + /* Bass Enhancement parameters */ + LVM_BE_Mode_en BE_OperatingMode; /* Bass Enhancement operating mode */ + LVM_INT16 BE_EffectLevel; /* Bass Enhancement effect level */ + LVM_BE_CentreFreq_en BE_CentreFreq; /* Bass Enhancement centre frequency */ + LVM_BE_FilterSelect_en BE_HPF; /* Bass Enhancement high pass filter selector */ + +#endif /* ALGORITHM_DBE */ +#ifdef ALGORITHM_PB + /* Bass Enhancement parameters */ + LVM_BE_Mode_en BE_OperatingMode; /* Bass Enhancement operating mode */ + LVM_INT16 BE_EffectLevel; /* Bass Enhancement effect level */ + LVM_BE_CentreFreq_en BE_CentreFreq; /* Bass Enhancement centre frequency */ + LVM_BE_FilterSelect_en BE_HPF; /* Bass Enhancement high pass filter selector */ + +#endif /* ALGORITHM_PB */ + /* Volume Control parameters */ + LVM_INT16 VC_EffectLevel; /* Volume Control setting in dBs */ + LVM_INT16 VC_Balance; /* Left Right Balance control in dB (-96 to 96 dB), -ve values reduce */ + +#ifdef ALGORITHM_TE + /* Treble Enhancement parameters */ + LVM_TE_Mode_en TE_OperatingMode; /* Treble Enhancement On/Off */ + LVM_INT16 TE_EffectLevel; /* Treble Enhancement gain dBs */ + +#endif /* ALGORITHM_TE */ +#ifdef ALGORITHM_LM + /* Loudness Maximiser parameters */ + LVM_LM_Mode_en LM_OperatingMode; /* Loudness Maximiser operating mode */ + LVM_LM_Effect_en LM_EffectLevel; /* Loudness Maximiser effect level */ + LVM_UINT16 LM_Attenuation; /* Loudness Maximiser output attenuation */ + LVM_UINT16 LM_CompressorGain; /* Loudness Maximiser output compressor gain */ + LVM_UINT16 LM_SpeakerCutOff; /* Loudness Maximiser speaker cut off frequency */ + +#endif /* ALGORITHM_LM */ + +#ifdef ALGORITHM_AVL + /* AVL parameters */ + LVM_AVL_Mode_en AVL_OperatingMode; /* AVL operating mode */ + +#endif /* ALGORITHM_AVL */ + +#ifdef ALGORITHM_TG + /* Tone Generator parameters */ + LVM_TG_Mode_en TG_OperatingMode; /* Tone generator mode */ + LVM_TG_SweepMode_en TG_SweepMode; /* Log or linear sweep */ + LVM_UINT16 TG_StartFrequency; /* Sweep start frequency in Hz */ + LVM_INT16 TG_StartAmplitude; /* Sweep start amplitude in dBr */ + LVM_UINT16 TG_StopFrequency; /* Sweep stop frequency in Hz */ + LVM_INT16 TG_StopAmplitude; /* Sweep stop amplitude in dBr */ + LVM_UINT16 TG_SweepDuration; /* Sweep duration in seconds, 0 for infinite duration tone */ + LVM_Callback pTG_CallBack; /* End of sweep callback */ + LVM_INT16 TG_CallBackID; /* Callback ID*/ + void *pTGAppMemSpace; /* Application instance handle or memory area */ +#endif /* ALGORITHM_TG */ + +#ifdef ALGORITHM_PSA + /* General Control */ + LVM_PSA_Mode_en PSA_Enable; + + /* Spectrum Analyzer parameters */ + LVM_PSA_DecaySpeed_en PSA_PeakDecayRate; /* Peak value decay rate*/ + LVM_UINT16 PSA_NumBands; /* Number of Bands*/ +#endif /* ALGORITHM_PSA */ + +#ifdef ALGORITHM_LIMP + LVM_LIMP_Mode_en LIMP_OperatingMode; /* LIMP operating mode */ + LVM_INT16 LIMP_Threshold; /* LIMP threshold in dB */ +#endif /* ALGORITHM_LIMP */ + +#ifdef ALGORITHM_LIMR + LVM_LIMR_Mode_en LIMR_OperatingMode; /* LIMR operating mode */ + LVM_LIMR_Reference_en LIMR_Reference; /* LIMR reference input */ + LVM_INT16 LIMR_Threshold; /* LIMR threshold in dB */ +#endif /* ALGORITHM_LIMR */ + +#ifdef ALGORITHM_CS + LVM_AP_MODE_en CS_AP_Mode; /* concert sound advanced paramameter mode */ + LVM_INT16 CS_AP_MidGain; /* MidChannelGain */ + LVM_UINT16 CS_AP_MidCornerFreq; /* Shelving Filter Corner Frequency */ + LVM_UINT16 CS_AP_SideHighPassCutoff; /* SideBoost HighPassFilter Corner Frequency */ + LVM_UINT16 CS_AP_SideLowPassCutoff; /* SideBoost LowPassFilter Corner Frequency */ + LVM_INT16 CS_AP_SideGain; /* Side Channel Gain */ +#endif + +#ifdef ALGORITHM_XO + LVM_Mode_en XO_OperatingMode; /* Crossover operating mode*/ + LVM_UINT16 XO_cutoffFrequency; /* Crossover cut-off frequency*/ + +#endif/*ALGORITHM_XO*/ + +} LVM_ControlParams_t; + + +/* Instance Parameter structure */ +typedef struct +{ + /* General */ + LVM_BufferMode_en BufferMode; /* Buffer management mode */ + LVM_UINT16 MaxBlockSize; /* Maximum processing block size */ + + /* N-Band Equaliser */ + LVM_UINT16 EQNB_NumBands; /* Maximum number of User equaliser bands */ + LVM_UINT16 PR_EQNB_NumBands; /* Maximum number of Product equaliser bands */ + EAP_NXPPlatform_en Platform; /* NXP Platform where EAP is playing on (LVM_IMXRT1050,LVM_IMXRT1060, LVM_IMXRT1064, LVM_IMXRT1170, LVM_LPC55, LVM_IMXRT500, LVM_IMXRT600)*/ +#ifdef ALGORITHM_PSA + /* PSA */ + LVM_UINT16 PSA_HistorySize; /* PSA History size in ms: 200 to 5000 */ + LVM_UINT16 PSA_MaxBands; /* Maximum number of bands: 6 to 64 */ + LVM_UINT16 PSA_SpectrumUpdateRate; /* Spectrum update rate : 10 to 25*/ + LVM_PSA_Mode_en PSA_Included; /* Controls the instance memory allocation for PSA: ON/OFF */ +#endif /* ALGORITHM_PSA */ +} LVM_InstParams_t; + + +/* Headroom management parameter structure */ +typedef struct +{ + LVM_Headroom_Mode_en Headroom_OperatingMode; /* Headroom Control On/Off */ + LVM_HeadroomBandDef_t *pHeadroomDefinition; /* Pointer to headroom bands definition */ + LVM_UINT16 NHeadroomBands; /* Number of headroom bands */ +} LVM_HeadroomParams_t; + + +/****************************************************************************************/ +/* */ +/* Function Prototypes */ +/* */ +/****************************************************************************************/ + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetVersionInfo */ +/* */ +/* DESCRIPTION: */ +/* This function is used to retrieve information about the library's version. */ +/* */ +/* PARAMETERS: */ +/* pVersion Pointer to an empty version info structure */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS when pVersion is NULL */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetVersionInfo(LVM_VersionInfo_st *pVersion); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetMemoryTable */ +/* */ +/* DESCRIPTION: */ +/* This function is used for memory allocation and free. It can be called in */ +/* two ways: */ +/* */ +/* hInstance = NULL Returns the memory requirements */ +/* hInstance = Instance handle Returns the memory requirements and */ +/* allocated base addresses for the instance */ +/* */ +/* When this function is called for memory allocation (hInstance=NULL) the memory */ +/* base address pointers are NULL on return. */ +/* */ +/* When the function is called for free (hInstance = Instance Handle) the memory */ +/* table returns the allocated memory and base addresses used during initialisation. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pMemoryTable Pointer to an empty memory definition table */ +/* pInstParams Pointer to the instance parameters */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS When one of pMemoryTable or pInstParams is NULL */ +/* LVM_OUTOFRANGE When any of the Instance parameters are out of range */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetMemoryTable(LVM_Handle_t hInstance, + LVM_MemTab_t *pMemoryTable, + LVM_InstParams_t *pInstParams); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetInstanceHandle */ +/* */ +/* DESCRIPTION: */ +/* This function is used to create a bundle instance. It returns the created instance */ +/* handle through phInstance. All parameters are set to their default, inactive state. */ +/* */ +/* PARAMETERS: */ +/* phInstance pointer to the instance handle */ +/* pMemoryTable Pointer to the memory definition table */ +/* pInstParams Pointer to the instance parameters */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Initialisation succeeded */ +/* LVM_ALIGNMENTERROR Instance or scratch memory on incorrect alignment */ +/* LVM_NULLADDRESS Instance or scratch memory has a NULL pointer */ +/* */ +/* NOTES: */ +/* 1. This function must not be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetInstanceHandle(LVM_Handle_t *phInstance, + LVM_MemTab_t *pMemoryTable, + LVM_InstParams_t *pInstParams); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_ClearAudioBuffers */ +/* */ +/* DESCRIPTION: */ +/* This function is used to clear the internal audio buffers of the bundle. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance handle */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Buffers Cleared */ +/* LVM_NULLADDRESS Instance is NULL */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_ClearAudioBuffers(LVM_Handle_t hInstance); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetControlParameters */ +/* */ +/* DESCRIPTION: */ +/* Request the LifeVibes module parameters. The current parameter set is returned */ +/* via the parameter pointer. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance handle */ +/* pParams Pointer to an empty parameter structure */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS when any of hInstance or pParams is NULL */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetControlParameters(LVM_Handle_t hInstance, + LVM_ControlParams_t *pParams); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_SetControlParameters */ +/* */ +/* DESCRIPTION: */ +/* Sets or changes the LifeVibes module parameters. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance handle */ +/* pParams Pointer to a parameter structure */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS When hInstance, pParams or any control pointers are NULL */ +/* LVM_OUTOFRANGE When any of the control parameters are out of range */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_SetControlParameters(LVM_Handle_t hInstance, + LVM_ControlParams_t *pParams); + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_Process */ +/* */ +/* DESCRIPTION: */ +/* Process function for the LifeVibes module. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance handle */ +/* pInData Pointer to the input data */ +/* pOutData Pointer to the output data */ +/* NumSamples Number of samples in the input buffer */ +/* AudioTime Audio Time of the current input data in milli-seconds */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_INVALIDNUMSAMPLES When the NumSamples is not a valied multiple in unmanaged */ +/* buffer mode */ +/* LVM_ALIGNMENTERROR When either the input our output buffers are not 32-bit */ +/* aligned in unmanaged mode */ +/* LVM_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */ +/* */ +/* NOTES: */ +/* 1. The input and output buffers must be 32-bit aligned */ +/* 2. Number of samples is defined as follows: */ +/* MONO the number of samples in the block */ +/* MONOINSTEREO the number of sample pairs in the block */ +/* STEREO the number of sample pairs in the block */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance, + const LVM_INT32 *pInData, + LVM_INT32 **pOutData, + LVM_UINT16 NumSamples, + LVM_UINT32 AudioTime); + + +#ifdef ALGORITHM_AVL +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetAVLGain */ +/* */ +/* DESCRIPTION: */ +/* This function is used to retrieve the AVL last generated gain in Q16.15 */ +/* linear values. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pAVL_Gain Pointer to the gain */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS When hInstance or pAVL_Gain are null addresses */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetAVLGain( LVM_Handle_t hInstance, + LVM_INT32 *pAVL_Gain); + + +#endif /* ALGORITHM_AVL */ + +#ifdef ALGORITHM_EQNB +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_SetHeadroomParams */ +/* */ +/* DESCRIPTION: */ +/* This function is used to set the automatic headroom management parameters. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pHeadroomParams Pointer to headroom parameter structure */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_SetHeadroomParams( LVM_Handle_t hInstance, + LVM_HeadroomParams_t *pHeadroomParams); + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetHeadroomParams */ +/* */ +/* DESCRIPTION: */ +/* This function is used to get the automatic headroom management parameters. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pHeadroomParams Pointer to headroom parameter structure (output) */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS When hInstance or pHeadroomParams are NULL */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetHeadroomParams( LVM_Handle_t hInstance, + LVM_HeadroomParams_t *pHeadroomParams); +#endif /* ALGORITHM_EQNB */ + +#ifdef ALGORITHM_PSA +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_GetSpectrum */ +/* */ +/* DESCRIPTION: */ +/* This function is used to retrieve Spectral information at a given Audio time */ +/* for display usage */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pCurrentPeaks Pointer to location where currents peaks are to be saved */ +/* pPastPeaks Pointer to location where past peaks are to be saved */ +/* pCentreFreqs Pointer to location where centre frequency of each band is */ +/* to be saved */ +/* AudioTime Audio time at which the spectral information is needed */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS If any of input addresses are NULL */ +/* LVM_WRONGAUDIOTIME Failure due to audio time error */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_GetSpectrum( LVM_Handle_t hInstance, + LVM_INT8 *pCurrentPeaks, + LVM_INT8 *pPastPeaks, + LVM_UINT16 *pCentreFreqs, + LVM_UINT32 AudioTime); + + +#endif /* ALGORITHM_PSA */ + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVM_SetVolumeNoSmoothing */ +/* */ +/* DESCRIPTION: */ +/* This function is used to set output volume without any smoothing */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance Handle */ +/* pParams Control Parameters, only volume value is used here */ +/* */ +/* RETURNS: */ +/* LVM_SUCCESS Succeeded */ +/* LVM_NULLADDRESS If any of input addresses are NULL */ +/* LVM_OUTOFRANGE When any of the control parameters are out of range */ +/* */ +/* NOTES: */ +/* 1. This function may be interrupted by the LVM_Process function */ +/* */ +/****************************************************************************************/ +#ifdef __DLL_EXPORT +__declspec(dllexport) +#endif /* __DLL_EXPORT */ +LVM_ReturnStatus_en LVM_SetVolumeNoSmoothing( LVM_Handle_t hInstance, + LVM_ControlParams_t *pParams); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __LVM_H__ */ + + diff --git a/third_party/include/nxp/eap/EAP_Includes/LVC_Types.h b/third_party/include/nxp/eap/EAP_Includes/LVC_Types.h new file mode 100644 index 000000000000..6d3501daf8e6 --- /dev/null +++ b/third_party/include/nxp/eap/EAP_Includes/LVC_Types.h @@ -0,0 +1,417 @@ +/* Copyright 2004-2025 NXP + * + * SPDX-License-Identifier: MIT + * This license applies ONLY to this header file LVC_Types.h + * + * 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. + * + */ + +/**************************************************************************************** + + $Author: beq07720 $ + $Revision: 130089 $ + $Date: 2019-07-24 07:46:43 +0200 (Wed, 24 Jul 2019) $ + +*****************************************************************************************/ + +/** @file + * Header file defining the standard LifeVibes types for use in the application layer + * interface of all LifeVibes modules + */ + +#ifndef LVC_TYPES_H +#define LVC_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/****************************************************************************************/ +/* */ +/* definitions */ +/* */ +/****************************************************************************************/ + +#define LVM_NULL (void *)0 ///< NULL pointer + +#define LVM_TRUE 1 ///< Boolean True +#define LVM_FALSE 0 ///< Boolean False + +#define LVM_MAXINT_8 127 ///< Maximum positive integer size +#define LVM_MAXINT_16 32767 ///< Maximum signed int 16 bits number +#define LVM_MAXUINT_16 65535U ///< Maximum un-signed int 16 bits number +#define LVM_MAXINT_32 2147483647 ///< Maximum signed int 32 bits number +#define LVM_MAXUINT_32 4294967295U ///< Maximum un-signed int 32 bits number +#define LVM_MININT_32 0x80000000U ///< Minimum signed int 32 bit number in 2's complement form + +#define LVM_MAXENUM 2147483647 ///< Maximum value for enumerator +#define LVM_MODULEID_MASK 0xFF00 ///< Mask to extract the calling module ID from callbackId +#define LVM_EVENTID_MASK 0x00FF ///< Mask to extract the callback event from callbackId + +/* Memory table*/ +#define LVM_MEMREGION_PERSISTENT_SLOW_DATA 0 ///< Offset to the instance memory region +#define LVM_MEMREGION_PERSISTENT_FAST_DATA 1 ///< Offset to the persistent data memory region +#define LVM_MEMREGION_PERSISTENT_FAST_COEF 2 ///< Offset to the persistent coefficient memory region +#define LVM_MEMREGION_TEMPORARY_FAST 3 ///< Offset to temporary memory region + +#define LVM_NR_MEMORY_REGIONS 4 ///< Number of memory regions + +#define LVM_MODE_LVWIREFORMAT_LENGTH (4) ///< Number of bytes to encode @ref LVM_Mode_en in LVWireFormat +#define LVM_CONFIG_LVWIREFORMAT_LENGTH (4) ///< Number of bytes to encode @ref LVM_Config_en in LVWireFormat +#define LVM_FS_LVWIREFORMAT_LENGTH (4) ///< Number of bytes to encode @ref LVM_Fs_en sample Rate in LVWireFormat +#define LVM_CHANNELTYPE_LVWIREFORMAT_LENGTH (4) ///< Number of bytes to encode @ref LVM_ChannelType_en in LVWireFormat + +#define LVM_CHAR_LVWIREFORMAT_LENGTH (1) ///< Number of bytes to encode ASCII character in LVWireFormat +#define LVM_INT8_LVWIREFORMAT_LENGTH (1) ///< Number of bytes to encode Signed 8-bit word in LVWireFormat +#define LVM_UINT8_LVWIREFORMAT_LENGTH (1) ///< Number of bytes to encode Unsigned 8-bit word in LVWireFormat + +#define LVM_INT16_LVWIREFORMAT_LENGTH (2) ///< Number of bytes to encode Signed 16-bit word in LVWireFormat +#define LVM_UINT16_LVWIREFORMAT_LENGTH (2) ///< Number of bytes to encode Unsigned 16-bit word in LVWireFormat + +#define LVM_INT32_LVWIREFORMAT_LENGTH (4) ///< Number of bytes to encode Signed 32-bit word in LVWireFormat +#define LVM_UINT32_LVWIREFORMAT_LENGTH (4) ///< Number of bytes to encode Unsigned 32-bit word in LVWireFormat + + +/****************************************************************************************/ +/* */ +/* Basic types */ +/* */ +/****************************************************************************************/ + +typedef char LVM_CHAR; ///< ASCII character + +typedef char LVM_INT8; ///< Signed 8-bit word +typedef unsigned char LVM_UINT8; ///< Unsigned 8-bit word + +typedef short LVM_INT16; ///< Signed 16-bit word +typedef unsigned short LVM_UINT16; ///< Unsigned 16-bit word + +#if (defined __LP64__) && __LP64__ +typedef int LVM_INT32; ///< Signed 32-bit word +typedef unsigned int LVM_UINT32; ///< Unsigned 32-bit word +// Type macros +#define LVM_PRINTF_FORMAT_SPECIFIER_INT32 "d" +#define LVM_PRINTF_FORMAT_SPECIFIER_UINT32 "u" +#elif defined(TOOLCHAIN_ADK) // CSR ADK +typedef int LVM_INT32; ///< Signed 32-bit word +typedef unsigned int LVM_UINT32; ///< Unsigned 32-bit word +// Type macros +#define LVM_PRINTF_FORMAT_SPECIFIER_INT32 "d" +#define LVM_PRINTF_FORMAT_SPECIFIER_UINT32 "u" +#else // (defined __LP64__) && __LP64__ +typedef long LVM_INT32; ///< Signed 32-bit word +typedef unsigned long LVM_UINT32; ///< Unsigned 32-bit word +// Type macros +#define LVM_PRINTF_FORMAT_SPECIFIER_INT32 "li" +#define LVM_PRINTF_FORMAT_SPECIFIER_UINT32 "lu" +#endif // (defined __LP64__) && __LP64__ + +typedef float LVM_FLOAT; ///< Single Precision floating point type +typedef double LVM_DOUBLE; ///< Double Precision floating point type + +/****************************************************************************************/ +/* */ +/* Standard Enumerated types */ +/* */ +/****************************************************************************************/ + +/** +The @ref LVM_Mode_en enumerated type is used to set the operating mode of a particular feature inside the LifeVibes modules. +The feature can be separately set to enable the feature processing (i.e., ON) or to disable all feature processing +modules (i.e., OFF). +*/ +typedef enum +{ + LVM_MODE_OFF = 0, ///< LVM module disabled + LVM_MODE_ON = 1, ///< LVM module enabled + LVM_MODE_MUTE = 2, ///< LVM module muted + LVM_MODE_DUMMY = LVM_MAXENUM +} LVM_Mode_en; + +/** +Sets stream Format +*/ +typedef enum +{ + LVM_STEREO = 0, ///<Stereo stream + LVM_MONOINSTEREO = 1, ///<Mono in stereo stream + LVM_MONO = 2, ///<Mono stream + LVM_5DOT1 = 3, ///<stream 5.1 formatted + LVM_7DOT1 = 4, ///<stream 7.1 formatted + LVM_SOURCE_DUMMY = LVM_MAXENUM +} LVM_Format_en; + +/** +Sets Speaker type +*/ +typedef enum +{ + LVM_SPEAKER_MONO = 0, ///< Mono type speaker + LVM_SPEAKER_STEREO = 1, ///< Stereo type speaker + LVM_SPEAKER_DUMMY = LVM_MAXENUM +} LVM_SpeakerType_en; + +/** +Sets Word length +*/ +typedef enum +{ + LVM_16_BIT = 0, ///< 16 bit word length + LVM_32_BIT = 1, ///< 32 bit word length + LVM_WORDLENGTH_DUMMY = LVM_MAXENUM +} LVM_WordLength_en; + +/** +The LVM product supports the sample rates specified in @ref LVM_Fs_en. The input and output sample rates are always the same. +*/ +typedef enum +{ + LVM_FS_8000 = 0, ///< 8k sampling rate + LVM_FS_11025 = 1, ///< 11.025k sampling rate + LVM_FS_12000 = 2, ///< 12k sampling rate + LVM_FS_16000 = 3, ///< 16k sampling rate + LVM_FS_22050 = 4, ///< 22.050k sampling rate + LVM_FS_24000 = 5, ///< 24k sampling rate + LVM_FS_32000 = 6, ///< 32k sampling rate + LVM_FS_44100 = 7, ///< 44.1k sampling rate + LVM_FS_48000 = 8, ///< 48k sampling rate + LVM_FS_96000 = 9, + LVM_FS_COUNT = 10, ///< Max sampling rate count + LVM_FS_INVALID = LVM_MAXENUM-1, + LVM_FS_DUMMY = LVM_MAXENUM +} LVM_Fs_en; + +/** +The LVM product supports the sample rates specified in @ref LVM_Fs_HDAudio_en. The input and output sample rates are always the same. +*/ +typedef enum +{ + LVM_FS_HDAUDIO_8000 = 0, ///< 8k sampling rate + LVM_FS_HDAUDIO_11025 = 1, ///< 11.025k sampling rate + LVM_FS_HDAUDIO_16000 = 2, ///< 16k sampling rate + LVM_FS_HDAUDIO_22050 = 3, ///< 22.050k sampling rate + LVM_FS_HDAUDIO_32000 = 4, ///< 32k sampling rate + LVM_FS_HDAUDIO_44100 = 5, ///< 44.1k sampling rate + LVM_FS_HDAUDIO_48000 = 6, ///< 48k sampling rate + LVM_FS_HDAUDIO_88200 = 7, ///< 88.2k sampling rate + LVM_FS_HDAUDIO_96000 = 8, ///< 96k sampling rate + LVM_FS_HDAUDIO_176400 = 9, ///< 176.4k sampling rate + LVM_FS_HDAUDIO_192000 = 10, ///< 192k sampling rate + LVM_FS_HDAUDIO_COUNT = 11, ///< Max sampling rate count + LVM_FS_HDAUDIO_INVALID = LVM_MAXENUM-1, + LVM_FS_HDAUDIO_DUMMY = LVM_MAXENUM +} LVM_Fs_HDAudio_en; + +/** +The @ref LVM_PcmFormat_en enumerated type identifies the different PCM formats that can be configured +*/ +typedef enum { + LVM_PCMFORMAT_16_BIT = 0, ///< PCM signed Q0.15 + LVM_PCMFORMAT_32_BIT = 1, ///< PCM signed Q0.31 + LVM_PCMFORMAT_8_24_BIT = 2, ///< PCM signed Q7.24 + LVM_PCMFORMAT_COUNT = 3, ///< Max PCM Format count + LVM_PCMFORMAT_DUMMY = LVM_MAXENUM +} LVM_PcmFormat_en; + +/** +The enumerated type is used to select the reset mode for the module. +@ref LVM_RESET_SOFT is used to select a soft reset (or partial reset) and @ref LVM_RESET_HARD is +used to select a hard reset (full re-initialization). +*/ +typedef enum +{ +/** +<table border> + <tr> + <td><b>Name</b></td> + <td><b>MODE</b></td> + </tr> + <tr> + <td>ResetType</td> + <td>@ref LVM_RESET_SOFT</td> + </tr> + <tr> + <td></td> + <td>@ref LVM_RESET_HARD</td> + </tr> +</table> +*/ + LVM_RESET_SOFT = 0, ///< Reset type for LVM where a partial reset of the module should be performed + LVM_RESET_HARD = 1, ///< Reset type for LVM where a full reset of the module should be performed + LVM_RESET_DUMMY = LVM_MAXENUM +} LVM_ResetType_en; + +/** +The @ref LVM_MemoryTypes_en enumerated type identifies the memory region types so that they can be correctly placed in memory +by the calling application. +The module initially has no permanent memory storage and makes no use of persistent memory allocation internally. +The calling application must allocate memory for the module to use. + +Four memory regions are required: +@li @ref LVM_MEMREGION_PERSISTENT_SLOW_DATA : this type of memory is used to store all the control data that needs to be saved between two consecutive calls to the process function. +@li @ref LVM_MEMREGION_PERSISTENT_FAST_DATA : this type of memory is used to store data such as filter history +@li @ref LVM_MEMREGION_PERSISTENT_FAST_COEF : this type of memory is used to store filter coefficients. +@li @ref LVM_MEMREGION_TEMPORARY_FAST (scratch): this type of memory is used to store temporary data. This memory can be reused by the application in between calls to the process function. + +This collection of memory regions forms the module instance. + +Typically the memory is allocated by the application dynamically; however, it can be allocated statically if required. +The sizes of the memory regions can be found by running the GetMemoryTable functions on a simulator and noting +the returned values. Alternatively contact NXP who can provide the figures. +It is possible that these memory sizes will change between release versions of the library and hence the dynamic memory allocation method is preferred where possible. +On some target platforms the placement of memory regions is critical for achieving optimal performance of the module. +*/ +typedef enum +{ + LVM_PERSISTENT_SLOW_DATA = LVM_MEMREGION_PERSISTENT_SLOW_DATA, ///< Persistent slow memory region + LVM_PERSISTENT_FAST_DATA = LVM_MEMREGION_PERSISTENT_FAST_DATA, ///< Persistent fast memory region + LVM_PERSISTENT_FAST_COEF = LVM_MEMREGION_PERSISTENT_FAST_COEF, ///< Persisten fast memory for coefficient storage + LVM_TEMPORARY_FAST = LVM_MEMREGION_TEMPORARY_FAST, ///< Temporary fast memory region + LVM_MEMORYTYPE_DUMMY = LVM_MAXENUM +} LVM_MemoryTypes_en; + +/** +Sets mod of Configuration +*/ +typedef enum +{ + LVM_CONFIG_HANDSET = 0, ///< Handset configuration + LVM_CONFIG_SPEAKERPHONE = 1, ///< Speaker mod configuration + LVM_CONFIG_STEREOHEADSET = 2, ///< Stereo Headset configuration + LVM_CONFIG_HEADSET_ENDFIRE = 3, ///< Close-microphone endfire headset configuration + LVM_CONFIG_HEADSET_CALLING = 4, ///< Ear cup mics for calling + LVM_CONFIG_HEADSET_CALLING_BOOM = 5, ///< Ear cup and boom mics for calling + LVM_CONFIG_HEADSET_FRONTEND = 6, ///< Ear cup mics for frontend pre enhancement + LVM_CONFIG_HEADSET_FRONTEND_BOOM = 7, ///< Ear cup and boom mics for frontend pre enhancement + LVM_CONFIG_DUMMY = LVM_MAXENUM +} LVM_Config_en; + +/** +Sets Channel Type +*/ +typedef enum +{ + LVM_MICROPHONE_CHANNEL = 0, ///< Microphone Channel + LVM_SPEAKER_CHANNEL = 1, ///< Speaker Channel + LVM_SPEAKER_AS_MIC_CHANNEL = 2, ///< Speaker or Receiver behaving as a Microphone Channel + LVM_MICROPHONE_AS_FAREND_REFERENCE_CHANNEL = 3, ///< Microphone as Farend Reference Channel + LVM_CHANNEL_DUMMY = LVM_MAXENUM +} LVM_ChannelType_en; + +/** +Sets Tunability of tuning parameters +*/ +typedef enum +{ + LVM_TUNABILITY_BASIC = 0, ///< Basic tuning parameter, always visible + LVM_TUNABILITY_ADVANCED = 1, ///< Expert tuning parameter, only visible in advanced tuning mode + LVM_TUNABILITY_RESERVED = 2, ///< Reserved tuning parameter, not visible + LVM_TUNABILITY_DUMMY = LVM_MAXENUM +} LVM_Tunability_en; + +/** +Sets Volume Dependence +*/ +typedef enum +{ + LVM_VOLUME_DEPENDENT = 0, ///< Volume dependent + LVM_VOLUME_INDEPENDENT = 1, ///< Volume independent + LVM_VOLUMEDEPENDENCE_DUMMY = LVM_MAXENUM +} LVM_VolumeDependence_en; + +/** +The @ref LVM_MemoryRegion_st type defines a memory region by specifying its size in bytes, its region type and its base pointer. +@see LVM_MemoryTypes_en +*/ +typedef struct +{ + LVM_UINT32 Size; ///< The size of the memory region in bytes + LVM_MemoryTypes_en Type; ///< Type of memory region + void *pBaseAddress; ///< Pointer to the memory region base address +} LVM_MemoryRegion_st; + +/** +The LVM_MemoryTable_st type defines the memory requirements of the module as an array of region definitions. +The number of required memory regions is given by the constant @ref LVM_NR_MEMORY_REGIONS +@see LVM_MemoryRegion_st +*/ +typedef struct +{ + LVM_MemoryRegion_st Region[LVM_NR_MEMORY_REGIONS]; ///< One definition of all memory regions +} LVM_MemoryTable_st; + +/** +The LVM_ContextTable_st type defines a memory region by specifying its size in bytes and its base pointer. +@see LVM_ContextTable_st +*/ +typedef struct +{ + LVM_UINT32 ContextTableLength; ///< its size in bytes + LVM_CHAR *pContext; ///< its base pointer +} LVM_ContextTable_st; + +/** +Beats Per Minute Structure +*/ +typedef struct +{ + LVM_INT16 ShortTermMinimum; ///< Beats per minute in Q9.6 format + LVM_INT16 ShortTermAverage; ///< Beats per minute in Q9.6 format + LVM_INT16 ShortTermMaximum; ///< Beats per minute in Q9.6 format + + LVM_INT16 Confidence; ///< Beat confidence level: 0 = no confidence, 32767 = maximum confidence + LVM_INT16 Strength; ///< Beat strength level: 0 = no beat, 32767 = maximum strength beat + LVM_INT16 LongTermMinimum; ///< Beats per minute in Q9.6 format + LVM_INT16 LongTermAverage; ///< Beats per minute in Q9.6 format + LVM_INT16 LongTermMaximum; ///< Beats per minute in Q9.6 format + +} LVM_BPMModuleStats_st; + + +/****************************************************************************************/ +/* */ +/* Standard Function Prototypes */ +/* */ +/****************************************************************************************/ +/** +@brief General purpose callback function + +@param pCallbackData Pointer to the callback data structure +@param pGeneralPurpose General purpose pointer (e.g. to a data structure needed in the callback) +@param PresetLength General purpose variable (e.g. to be used as callback ID) +@return \ref LVM_INT32 +*/ +typedef LVM_INT32 (*LVM_Callback)(void *pCallbackData, + void *pGeneralPurpose, + LVM_INT16 GeneralPurpose ); + +/****************************************************************************************/ +/* */ +/* End of file */ +/* */ +/****************************************************************************************/ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LVC_TYPES_H */ diff --git a/tools/ctl/CMakeLists.txt b/tools/ctl/CMakeLists.txt index 70735f88da65..5c4c2dd315b5 100644 --- a/tools/ctl/CMakeLists.txt +++ b/tools/ctl/CMakeLists.txt @@ -4,6 +4,9 @@ add_executable(sof-ctl ctl.c ) +target_link_directories(sof-ctl BEFORE + PRIVATE "${SOF_ROOT_SOURCE_DIRECTORY}/../tools/lib") + target_link_libraries(sof-ctl PRIVATE "-lasound" ) @@ -13,6 +16,7 @@ target_compile_options(sof-ctl PRIVATE ) target_include_directories(sof-ctl PRIVATE + "${SOF_ROOT_SOURCE_DIRECTORY}/../tools/include" "${SOF_ROOT_SOURCE_DIRECTORY}/src/include" "${SOF_ROOT_SOURCE_DIRECTORY}" ) diff --git a/tools/ctl/ctl.c b/tools/ctl/ctl.c index 1d89c2c15fd9..c669349b68f9 100644 --- a/tools/ctl/ctl.c +++ b/tools/ctl/ctl.c @@ -20,6 +20,8 @@ #define BUFFER_SIZE_OFFSET 1 #define BUFFER_ABI_OFFSET 2 +#define BUFFER_TLV_HEADER_BYTES ((BUFFER_ABI_OFFSET) * sizeof(uint32_t)) + /* Definitions for multiple IPCs */ enum sof_ipc_type { SOF_IPC_TYPE_3, @@ -103,6 +105,7 @@ static void header_init(struct ctl_data *ctl_data) hdr->magic = ctl_data->magic; hdr->type = ctl_data->type; hdr->abi = SOF_ABI_VERSION; + ctl_data->buffer[BUFFER_TAG_OFFSET] = SOF_CTRL_CMD_BINARY; } /* Returns the number of bytes written to the control buffer */ @@ -117,7 +120,7 @@ static int read_setup(struct ctl_data *ctl_data) int separator; int n = 0; FILE *fh; - int data_start_int_index = BUFFER_ABI_OFFSET; + int data_start_int_index = 0; int data_int_index; /* open input file */ @@ -131,7 +134,7 @@ static int read_setup(struct ctl_data *ctl_data) if (ctl_data->no_abi) { header_init(ctl_data); abi_size = sizeof(struct sof_abi_hdr); - data_start_int_index += abi_size / sizeof(uint32_t); + data_start_int_index += (abi_size + BUFFER_TLV_HEADER_BYTES) / sizeof(uint32_t); } if (ctl_data->binary) { @@ -163,6 +166,8 @@ static int read_setup(struct ctl_data *ctl_data) if (ctl_data->no_abi) { hdr->size = n; n += abi_size; + ctl_data->buffer[BUFFER_SIZE_OFFSET] = n; + n += BUFFER_TLV_HEADER_BYTES; } if (n > n_max) { @@ -206,16 +211,16 @@ static void hex_data_dump(struct ctl_data *ctl_data) int i; /* calculate the dumping units */ - n = ctl_data->buffer[BUFFER_SIZE_OFFSET] / sizeof(uint16_t); + n = (ctl_data->buffer[BUFFER_SIZE_OFFSET] + BUFFER_TLV_HEADER_BYTES) / sizeof(uint16_t); /* exclude the type and size header */ - int_offset = 2; + int_offset = 0; /* exclude abi header if '-r' specified */ if (ctl_data->no_abi) { - int_offset += sizeof(struct sof_abi_hdr) / + int_offset += (sizeof(struct sof_abi_hdr) + BUFFER_TLV_HEADER_BYTES) / sizeof(uint32_t); - n -= sizeof(struct sof_abi_hdr) / + n -= (sizeof(struct sof_abi_hdr) + BUFFER_TLV_HEADER_BYTES) / sizeof(uint16_t); } @@ -242,11 +247,11 @@ static void csv_data_dump(struct ctl_data *ctl_data, FILE *fh) int i; int s = 0; - config = &ctl_data->buffer[BUFFER_ABI_OFFSET]; - n = ctl_data->buffer[BUFFER_SIZE_OFFSET] / sizeof(uint32_t); + config = &ctl_data->buffer[0]; + n = (ctl_data->buffer[BUFFER_SIZE_OFFSET] + BUFFER_TLV_HEADER_BYTES) / sizeof(uint32_t); if (ctl_data->no_abi) - s = sizeof(struct sof_abi_hdr) / sizeof(uint32_t); + s = (sizeof(struct sof_abi_hdr) + BUFFER_TLV_HEADER_BYTES) / sizeof(uint32_t); /* Print out in CSV txt formal */ for (i = s; i < n; i++) { @@ -298,10 +303,7 @@ static int buffer_alloc(struct ctl_data *ctl_data) return -EINVAL; } - ctl_data->buffer[BUFFER_TAG_OFFSET] = SOF_CTRL_CMD_BINARY; - ctl_data->buffer_size = buffer_size; - return 0; } @@ -429,7 +431,7 @@ static int ctl_free(struct ctl_data *ctl_data) return ret; } -static void ctl_dump(struct ctl_data *ctl_data) +static void ctl_dump(struct ctl_data *ctl_data, size_t dump_size) { FILE *fh; int offset = 0; @@ -445,13 +447,16 @@ static void ctl_dump(struct ctl_data *ctl_data) return; } - offset = BUFFER_ABI_OFFSET; - n = ctl_data->buffer[BUFFER_SIZE_OFFSET]; + if (dump_size) + n = dump_size; + else + n = ctl_data->buffer[BUFFER_SIZE_OFFSET] + BUFFER_TLV_HEADER_BYTES; if (ctl_data->no_abi) { - offset += sizeof(struct sof_abi_hdr) / - sizeof(int); + offset = sizeof(struct sof_abi_hdr) / sizeof(int) + + BUFFER_ABI_OFFSET; n -= sizeof(struct sof_abi_hdr); + n -= BUFFER_ABI_OFFSET * sizeof(uint32_t); } n = fwrite(&ctl_data->buffer[offset], 1, n, fh); @@ -476,7 +481,7 @@ static void ctl_dump(struct ctl_data *ctl_data) static int ctl_set_get(struct ctl_data *ctl_data) { int ret; - size_t n; + size_t read_size, ref_size; if (!ctl_data->buffer) { fprintf(stderr, "Error: No buffer for set/get!\n"); @@ -488,14 +493,22 @@ static int ctl_set_get(struct ctl_data *ctl_data) ctl_data->input_file); fprintf(stdout, "into device %s control %s.\n", ctl_data->dev, ctl_data->cname); - n = read_setup(ctl_data); - if (n < 1) { + read_size = read_setup(ctl_data); + if (read_size < 1) { fprintf(stderr, "Error: failed data read from %s.\n", ctl_data->input_file); return -EINVAL; } - ctl_data->buffer[BUFFER_SIZE_OFFSET] = n; + ref_size = ctl_data->buffer[BUFFER_SIZE_OFFSET] + BUFFER_TLV_HEADER_BYTES; + if (read_size != ref_size) { + fprintf(stderr, + "Error: Blob TLV header size %u (plus %lu) does not match with read bytes count %zu.\n", + ctl_data->buffer[BUFFER_SIZE_OFFSET], BUFFER_TLV_HEADER_BYTES, + read_size); + return -EINVAL; + } + ret = snd_ctl_elem_tlv_write(ctl_data->ctl, ctl_data->id, ctl_data->buffer); if (ret < 0) { @@ -589,6 +602,13 @@ int main(int argc, char *argv[]) } } + /* All arguments are switches, error if something still remains in command line */ + if (optind < argc) { + fprintf(stderr, "Error: Non-supported argument %s.\n", + argv[optind]); + return -EINVAL; + } + switch (ipc_type) { case 3: ctl_data->ipc_type = SOF_IPC_TYPE_3; @@ -629,8 +649,8 @@ int main(int argc, char *argv[]) hdr = (struct sof_abi_hdr *) &ctl_data->buffer[BUFFER_ABI_OFFSET]; hdr->size = ctl_data->print_abi_size; - ctl_data->buffer[BUFFER_SIZE_OFFSET] = ctl_data->ctrl_size; - ctl_dump(ctl_data); + ctl_data->buffer[BUFFER_SIZE_OFFSET] = ctl_data->ctrl_size + hdr->size; + ctl_dump(ctl_data, sizeof(struct sof_abi_hdr) + BUFFER_TLV_HEADER_BYTES); buffer_free(ctl_data); goto out_fd_close; } @@ -668,7 +688,7 @@ int main(int argc, char *argv[]) } /* dump the tlv buffer to a file or stdout */ - ctl_dump(ctl_data); + ctl_dump(ctl_data, 0); data_free: ret = ctl_free(ctl_data); diff --git a/tools/ctl/ipc3/eq_fir/flat.txt b/tools/ctl/ipc3/eq_fir/flat.txt new file mode 100644 index 000000000000..ed8f327e17ee --- /dev/null +++ b/tools/ctl/ipc3/eq_fir/flat.txt @@ -0,0 +1 @@ +3,88,4607827,0,56,50450433,0,0,0,0,56,65538,0,0,0,0,0,4294901764,0,0,0,0,16384,0 diff --git a/tools/ctl/ipc3/eq_fir/loudness.txt b/tools/ctl/ipc3/eq_fir/loudness.txt new file mode 100644 index 000000000000..40cc0f19924e --- /dev/null +++ b/tools/ctl/ipc3/eq_fir/loudness.txt @@ -0,0 +1 @@ +3,616,4607827,0,584,50450433,0,0,0,0,584,131076,0,0,0,0,65537,65537,4294901764,0,0,0,0,16384,0,252,0,0,0,0,65537,65537,65537,65537,131073,131074,131074,196611,196611,262147,262148,327685,393221,393222,458759,524296,589833,655370,720907,786444,851981,983054,1048591,1179665,1245202,1376276,1507350,1638424,1769498,1966109,2162719,2359330,2621478,2818089,3080237,3407922,3670070,3997755,4325440,4718661,5046347,5505105,5963863,6422622,6815845,7274604,7733362,8192121,8781953,9568396,10420376,11272357,12058802,12976318,14155982,15335649,16056559,16515324,16711960,24117551,70844611,3920495315,3920522431,70845139,24117443,16711983,16515352,16056572,15335663,14156001,12976334,12058814,11272370,10420389,9568408,8781964,8192129,7733369,7274610,6815852,6422629,5963870,5505111,5046353,4718667,4325445,3997760,3670075,3407926,3080242,2818093,2621481,2359334,2162722,1966111,1769501,1638426,1507352,1376278,1245204,1179666,1048593,983055,851982,786445,720908,655371,589834,524297,458760,393223,393222,327685,262149,262148,196611,196611,131075,131074,131074,65537,65537,65537,65537,1,0 diff --git a/tools/ctl/ipc3/eq_fir/mid.txt b/tools/ctl/ipc3/eq_fir/mid.txt new file mode 100644 index 000000000000..3d1f8b502d51 --- /dev/null +++ b/tools/ctl/ipc3/eq_fir/mid.txt @@ -0,0 +1 @@ +3,160,4607827,0,128,50450433,0,0,0,0,128,65538,0,0,0,0,0,65576,0,0,0,0,1202154746,4222755303,3873958283,4024953600,4126012299,4176934804,4217764409,4250664050,4273864222,4288806716,2490349,6750285,8126582,7733371,6488174,4980824,3473472,2293804,1245211,1245197 diff --git a/tools/ctl/ipc3/eq_fir/pass.txt b/tools/ctl/ipc3/eq_fir/pass.txt new file mode 100644 index 000000000000..501ef2821697 --- /dev/null +++ b/tools/ctl/ipc3/eq_fir/pass.txt @@ -0,0 +1 @@ +3,88,4607827,0,56,50450433,0,0,0,0,56,65538,0,0,0,0,4294967295,4294901764,0,0,0,0,16384,0 diff --git a/tools/ctl/ipc3/eq_fir_flat.txt b/tools/ctl/ipc3/eq_fir_flat.txt deleted file mode 100644 index 4be59009db77..000000000000 --- a/tools/ctl/ipc3/eq_fir_flat.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,56,50331648,0,0,0,0,56,65538,0,0,0,0,0,4294901764,0,0,0,0,16384,0, diff --git a/tools/ctl/ipc3/eq_fir_loudness.txt b/tools/ctl/ipc3/eq_fir_loudness.txt deleted file mode 100644 index e9dd0d864a87..000000000000 --- a/tools/ctl/ipc3/eq_fir_loudness.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,584,50413568,0,0,0,0,584,131076,0,0,0,0,65537,65537,4294901764,0,0,0,0,16384,0,252,0,0,0,0,65537,65537,65537,65537,131073,131074,131074,196611,196611,262147,262148,327685,393221,393222,458759,524296,589833,655370,720907,786444,851981,983054,1048591,1179665,1245202,1376276,1507350,1638424,1769498,1966109,2162719,2359330,2621478,2818089,3080237,3407922,3670070,3997755,4325440,4718661,5046347,5505105,5963863,6422622,6815845,7274604,7733362,8192121,8781953,9568396,10420376,11272357,12058802,12976318,14155982,15335649,16056559,16515324,16711960,24117551,70844611,3920495315,3920522431,70845139,24117443,16711983,16515352,16056572,15335663,14156001,12976334,12058814,11272370,10420389,9568408,8781964,8192129,7733369,7274610,6815852,6422629,5963870,5505111,5046353,4718667,4325445,3997760,3670075,3407926,3080242,2818093,2621481,2359334,2162722,1966111,1769501,1638426,1507352,1376278,1245204,1179666,1048593,983055,851982,786445,720908,655371,589834,524297,458760,393223,393222,327685,262149,262148,196611,196611,131075,131074,131074,65537,65537,65537,65537,1,0, diff --git a/tools/ctl/ipc3/eq_fir_mid.txt b/tools/ctl/ipc3/eq_fir_mid.txt deleted file mode 100644 index aac92e71de89..000000000000 --- a/tools/ctl/ipc3/eq_fir_mid.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,128,50380800,0,0,0,0,128,65538,0,0,0,0,0,65576,0,0,0,0,1202154746,4222755303,3873958283,4024953600,4126012299,4176934804,4217764409,4250664050,4273864222,4288806716,2490349,6750285,8126582,7733371,6488174,4980824,3473472,2293804,1245211,1245197, diff --git a/tools/ctl/ipc3/eq_fir_pass.txt b/tools/ctl/ipc3/eq_fir_pass.txt deleted file mode 100644 index 5ba02fc7d7fd..000000000000 --- a/tools/ctl/ipc3/eq_fir_pass.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,56,50331648,0,0,0,0,56,65538,0,0,0,0,4294967295,4294901764,0,0,0,0,16384,0, diff --git a/tools/ctl/ipc3/eq_iir/bandpass.txt b/tools/ctl/ipc3/eq_iir/bandpass.txt new file mode 100644 index 000000000000..214dc382fd85 --- /dev/null +++ b/tools/ctl/ipc3/eq_iir/bandpass.txt @@ -0,0 +1 @@ +3,148,4607827,0,116,50450433,0,0,0,0,116,2,1,0,0,0,0,0,0,2,2,0,0,0,0,3316150158,2048164275,513807534,3267352229,513807534,0,16384,3867454526,1191025347,38870735,77741469,38870735,4294967292,24197 diff --git a/tools/ctl/ipc3/eq_iir/bassboost.txt b/tools/ctl/ipc3/eq_iir/bassboost.txt new file mode 100644 index 000000000000..82e849f5603e --- /dev/null +++ b/tools/ctl/ipc3/eq_iir/bassboost.txt @@ -0,0 +1 @@ +3,148,4607827,0,116,50450433,0,0,0,0,116,2,1,0,0,0,0,0,0,2,2,0,0,0,0,3227172081,2141520527,536653443,3221660410,536653443,0,16384,3260252783,2107733822,161646111,3961037800,172645501,4294967294,27910 diff --git a/tools/ctl/ipc3/eq_iir/bundle.txt b/tools/ctl/ipc3/eq_iir/bundle.txt new file mode 100644 index 000000000000..ef8a861b777f --- /dev/null +++ b/tools/ctl/ipc3/eq_iir/bundle.txt @@ -0,0 +1 @@ +3,440,4607827,0,408,50450433,0,0,0,0,408,2,5,0,0,0,0,2,2,1,1,0,0,0,0,0,0,0,0,538145694,0,32690,3,3,0,0,0,0,3237960220,2130690484,297056159,3694463533,303476880,0,16384,3302357025,2064935920,245217319,3776455865,274003881,0,16384,4106268671,4130185751,69182517,4179658584,365641401,4294967292,25468,2,2,0,0,0,0,3227172081,2141520527,536653443,3221660410,536653443,0,16384,3260252783,2107733822,161646111,3961037800,172645501,4294967294,27910,2,2,0,0,0,0,3316150158,2048164275,513807534,3267352229,513807534,0,16384,3867454526,1191025347,38870735,77741469,38870735,4294967292,24197,1,1,0,0,0,0,3240919741,2127607086,533187596,3228592105,533187596,4294967292,20433 diff --git a/tools/ctl/ipc3/eq_iir/flat.txt b/tools/ctl/ipc3/eq_iir/flat.txt new file mode 100644 index 000000000000..25fc6796f600 --- /dev/null +++ b/tools/ctl/ipc3/eq_iir/flat.txt @@ -0,0 +1 @@ +3,120,4607827,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,538145694,0,32690 diff --git a/tools/ctl/ipc3/eq_iir/highpass_20hz_0db_48khz.txt b/tools/ctl/ipc3/eq_iir/highpass_20hz_0db_48khz.txt new file mode 100644 index 000000000000..e642a5fc82b2 --- /dev/null +++ b/tools/ctl/ipc3/eq_iir/highpass_20hz_0db_48khz.txt @@ -0,0 +1 @@ +3,120,4607827,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3225193546,2143508228,537150400,3220666496,537150400,0,32690 diff --git a/tools/ctl/ipc3/eq_iir/highpass_30hz_0db_48khz.txt b/tools/ctl/ipc3/eq_iir/highpass_30hz_0db_48khz.txt new file mode 100644 index 000000000000..4bc0d715fd96 --- /dev/null +++ b/tools/ctl/ipc3/eq_iir/highpass_30hz_0db_48khz.txt @@ -0,0 +1 @@ +3,120,4607827,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3227172081,2141520527,536653443,3221660410,536653443,0,32690 diff --git a/tools/ctl/ipc3/eq_iir/highpass_40hz_0db_48khz.txt b/tools/ctl/ipc3/eq_iir/highpass_40hz_0db_48khz.txt new file mode 100644 index 000000000000..b132779d1ace --- /dev/null +++ b/tools/ctl/ipc3/eq_iir/highpass_40hz_0db_48khz.txt @@ -0,0 +1 @@ +3,120,4607827,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3229146956,2139532835,536156946,3222653403,536156946,0,32690 diff --git a/tools/ctl/ipc3/eq_iir/highpass_50hz_0db_48khz.txt b/tools/ctl/ipc3/eq_iir/highpass_50hz_0db_48khz.txt new file mode 100644 index 000000000000..c25060036801 --- /dev/null +++ b/tools/ctl/ipc3/eq_iir/highpass_50hz_0db_48khz.txt @@ -0,0 +1 @@ +3,120,4607827,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3231118179,2137545158,535660909,3223645479,535660909,0,32690 diff --git a/tools/ctl/ipc3/eq_iir/loudness.txt b/tools/ctl/ipc3/eq_iir/loudness.txt new file mode 100644 index 000000000000..1cf6a66fa25a --- /dev/null +++ b/tools/ctl/ipc3/eq_iir/loudness.txt @@ -0,0 +1 @@ +3,236,4607827,0,204,50450433,0,0,0,0,204,4,2,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,538145694,0,32690,3,3,0,0,0,0,3237960220,2130690484,297056159,3694463533,303476880,0,16384,3302357025,2064935920,245217319,3776455865,274003881,0,16384,4106268671,4130185751,69182517,4179658584,365641401,4294967292,25468 diff --git a/tools/ctl/ipc3/eq_iir/pass.txt b/tools/ctl/ipc3/eq_iir/pass.txt new file mode 100644 index 000000000000..ce79acad80fd --- /dev/null +++ b/tools/ctl/ipc3/eq_iir/pass.txt @@ -0,0 +1 @@ +3,120,4607827,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,4294967295,4294967295,1,1,0,0,0,0,0,0,0,0,538145694,0,32690 diff --git a/tools/ctl/ipc3/eq_iir_bandpass.txt b/tools/ctl/ipc3/eq_iir_bandpass.txt deleted file mode 100644 index 7c6e3f410a82..000000000000 --- a/tools/ctl/ipc3/eq_iir_bandpass.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,116,50331648,0,0,0,0,116,2,1,0,0,0,0,0,0,2,2,0,0,0,0,3316150158,2048164275,513807534,3267352229,513807534,0,16384,3867454526,1191025347,38870735,77741469,38870735,4294967292,24197, diff --git a/tools/ctl/ipc3/eq_iir_bassboost.txt b/tools/ctl/ipc3/eq_iir_bassboost.txt deleted file mode 100644 index 1c874bfebba8..000000000000 --- a/tools/ctl/ipc3/eq_iir_bassboost.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,116,50331648,0,0,0,0,116,2,1,0,0,0,0,0,0,2,2,0,0,0,0,3227172081,2141520527,536653443,3221660410,536653443,0,16384,3260252783,2107733822,161646111,3961037800,172645501,4294967294,27910, diff --git a/tools/ctl/ipc3/eq_iir_bundle.txt b/tools/ctl/ipc3/eq_iir_bundle.txt deleted file mode 100644 index cad5b7446b97..000000000000 --- a/tools/ctl/ipc3/eq_iir_bundle.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,408,50397184,0,0,0,0,408,2,5,0,0,0,0,2,2,1,1,0,0,0,0,0,0,0,0,538145694,0,32690,3,3,0,0,0,0,3237960220,2130690484,297056159,3694463533,303476880,0,16384,3302357025,2064935920,245217319,3776455865,274003881,0,16384,4106268671,4130185751,69182517,4179658584,365641401,4294967292,25468,2,2,0,0,0,0,3227172081,2141520527,536653443,3221660410,536653443,0,16384,3260252783,2107733822,161646111,3961037800,172645501,4294967294,27910,2,2,0,0,0,0,3316150158,2048164275,513807534,3267352229,513807534,0,16384,3867454526,1191025347,38870735,77741469,38870735,4294967292,24197,1,1,0,0,0,0,3231118179,2137545158,535660909,3223645479,535660909,4294967292,20432, diff --git a/tools/ctl/ipc3/eq_iir_flat.txt b/tools/ctl/ipc3/eq_iir_flat.txt deleted file mode 100644 index b62751a8d79f..000000000000 --- a/tools/ctl/ipc3/eq_iir_flat.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,88,50331648,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,538145694,0,32690, diff --git a/tools/ctl/ipc3/eq_iir_highpass_20hz_0db_48khz.txt b/tools/ctl/ipc3/eq_iir_highpass_20hz_0db_48khz.txt deleted file mode 100644 index b8a91e11868f..000000000000 --- a/tools/ctl/ipc3/eq_iir_highpass_20hz_0db_48khz.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,88,50380800,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3225193546,2143508228,537150400,3220666496,537150400,0,32690, diff --git a/tools/ctl/ipc3/eq_iir_highpass_30hz_0db_48khz.txt b/tools/ctl/ipc3/eq_iir_highpass_30hz_0db_48khz.txt deleted file mode 100644 index d5077e402bfd..000000000000 --- a/tools/ctl/ipc3/eq_iir_highpass_30hz_0db_48khz.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,88,50380800,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3227172081,2141520527,536653443,3221660410,536653443,0,32690, diff --git a/tools/ctl/ipc3/eq_iir_highpass_40hz_0db_48khz.txt b/tools/ctl/ipc3/eq_iir_highpass_40hz_0db_48khz.txt deleted file mode 100644 index ebbd75c3c248..000000000000 --- a/tools/ctl/ipc3/eq_iir_highpass_40hz_0db_48khz.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,88,50380800,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3229146956,2139532835,536156946,3222653403,536156946,0,32690, diff --git a/tools/ctl/ipc3/eq_iir_highpass_50hz_0db_48khz.txt b/tools/ctl/ipc3/eq_iir_highpass_50hz_0db_48khz.txt deleted file mode 100644 index 19d82f920b67..000000000000 --- a/tools/ctl/ipc3/eq_iir_highpass_50hz_0db_48khz.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,88,50380800,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3231118179,2137545158,535660909,3223645479,535660909,0,32690, diff --git a/tools/ctl/ipc3/eq_iir_loudness.txt b/tools/ctl/ipc3/eq_iir_loudness.txt deleted file mode 100644 index 76a52301d281..000000000000 --- a/tools/ctl/ipc3/eq_iir_loudness.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,204,50331648,0,0,0,0,204,4,2,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,538145694,0,32690,3,3,0,0,0,0,3237960220,2130690484,297056159,3694463533,303476880,0,16384,3302357025,2064935920,245217319,3776455865,274003881,0,16384,4106268671,4130185751,69182517,4179658584,365641401,4294967292,25468, diff --git a/tools/ctl/ipc3/eq_iir_pass.txt b/tools/ctl/ipc3/eq_iir_pass.txt deleted file mode 100644 index e8545206de29..000000000000 --- a/tools/ctl/ipc3/eq_iir_pass.txt +++ /dev/null @@ -1 +0,0 @@ -4607827,0,88,50331648,0,0,0,0,88,2,1,0,0,0,0,4294967295,4294967295,1,1,0,0,0,0,0,0,0,0,538145694,0,32690, diff --git a/tools/ctl/ipc4/drc/generic_notebook_speaker.txt b/tools/ctl/ipc4/drc/generic_notebook_speaker.txt deleted file mode 100644 index 104210eec4d9..000000000000 --- a/tools/ctl/ipc4/drc/generic_notebook_speaker.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,108,50438144,0,0,0,0,108,0,0,0,0,1,3875536896,251658240,167772160,6442451,60380940,107374182,12708444,2327743,4292230659,5305422,162898102,73470028,7456540,4286019447,2062296,5,4423680,294359,2477728,622039,46513, diff --git a/tools/ctl/ipc4/drc/passthrough.txt b/tools/ctl/ipc4/drc/passthrough.txt index 910b8e56f758..e650ab9a26e3 100644 --- a/tools/ctl/ipc4/drc/passthrough.txt +++ b/tools/ctl/ipc4/drc/passthrough.txt @@ -1 +1 @@ -877023059,0,108,50438144,0,0,0,0,108,0,0,0,0,0,3892314112,503316480,201326592,6442451,67748529,89478485,2030160,9723989,4285175934,33474947,575096676,24401431,7456540,4286019447,2062296,5,4423680,294359,2477728,622039,46513, +3,140,877023059,0,108,50450433,0,0,0,0,108,0,0,0,0,0,3892314112,503316480,201326592,6442451,67748529,89478485,2030160,9723989,4285175934,33474947,575096676,24401431,7456540,4286019447,2062296,5,4423680,294359,2477728,622039,46513 diff --git a/tools/ctl/ipc4/drc/speaker_default.txt b/tools/ctl/ipc4/drc/speaker_default.txt new file mode 100644 index 000000000000..03d17e103040 --- /dev/null +++ b/tools/ctl/ipc4/drc/speaker_default.txt @@ -0,0 +1 @@ +3,140,877023059,0,108,50450433,0,0,0,0,108,0,0,0,0,1,3791650816,335544320,167772160,6442451,33954698,107374182,12228399,1969176,4292887072,5305422,137666458,81276115,7456540,4286019447,2062296,5,4423680,294359,2477728,622039,46513 diff --git a/tools/ctl/ipc4/eq_fir/flat.txt b/tools/ctl/ipc4/eq_fir/flat.txt new file mode 100644 index 000000000000..5fd026ca0c20 --- /dev/null +++ b/tools/ctl/ipc4/eq_fir/flat.txt @@ -0,0 +1 @@ +3,88,877023059,0,56,50450433,0,0,0,0,56,65538,0,0,0,0,0,4294901764,0,0,0,0,16384,0 diff --git a/tools/ctl/ipc4/eq_fir/loudness.txt b/tools/ctl/ipc4/eq_fir/loudness.txt new file mode 100644 index 000000000000..e5093f015b0e --- /dev/null +++ b/tools/ctl/ipc4/eq_fir/loudness.txt @@ -0,0 +1 @@ +3,616,877023059,0,584,50450433,0,0,0,0,584,131076,0,0,0,0,65537,65537,4294901764,0,0,0,0,16384,0,252,0,0,0,0,65537,65537,65537,65537,131073,131074,131074,196611,196611,262147,262148,327685,393221,393222,458759,524296,589833,655370,720907,786444,851981,983054,1048591,1179665,1245202,1376276,1507350,1638424,1769498,1966109,2162719,2359330,2621478,2818089,3080237,3407922,3670070,3997755,4325440,4718661,5046347,5505105,5963863,6422622,6815845,7274604,7733362,8192121,8781953,9568396,10420376,11272357,12058802,12976318,14155982,15335649,16056559,16515324,16711960,24117551,70844611,3920495315,3920522431,70845139,24117443,16711983,16515352,16056572,15335663,14156001,12976334,12058814,11272370,10420389,9568408,8781964,8192129,7733369,7274610,6815852,6422629,5963870,5505111,5046353,4718667,4325445,3997760,3670075,3407926,3080242,2818093,2621481,2359334,2162722,1966111,1769501,1638426,1507352,1376278,1245204,1179666,1048593,983055,851982,786445,720908,655371,589834,524297,458760,393223,393222,327685,262149,262148,196611,196611,131075,131074,131074,65537,65537,65537,65537,1,0 diff --git a/tools/ctl/ipc4/eq_fir/mid.txt b/tools/ctl/ipc4/eq_fir/mid.txt new file mode 100644 index 000000000000..36d74f693e46 --- /dev/null +++ b/tools/ctl/ipc4/eq_fir/mid.txt @@ -0,0 +1 @@ +3,160,877023059,0,128,50450433,0,0,0,0,128,65538,0,0,0,0,0,65576,0,0,0,0,1202154746,4222755303,3873958283,4024953600,4126012299,4176934804,4217764409,4250664050,4273864222,4288806716,2490349,6750285,8126582,7733371,6488174,4980824,3473472,2293804,1245211,1245197 diff --git a/tools/ctl/ipc4/eq_fir/pass.txt b/tools/ctl/ipc4/eq_fir/pass.txt new file mode 100644 index 000000000000..5decf09aed40 --- /dev/null +++ b/tools/ctl/ipc4/eq_fir/pass.txt @@ -0,0 +1 @@ +3,88,877023059,0,56,50450433,0,0,0,0,56,65538,0,0,0,0,4294967295,4294901764,0,0,0,0,16384,0 diff --git a/tools/ctl/ipc4/eq_fir_flat.txt b/tools/ctl/ipc4/eq_fir_flat.txt deleted file mode 100644 index 8e6670a76d18..000000000000 --- a/tools/ctl/ipc4/eq_fir_flat.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,56,50438144,0,0,0,0,56,65538,0,0,0,0,0,4294901764,0,0,0,0,16384,0, diff --git a/tools/ctl/ipc4/eq_fir_loudness.txt b/tools/ctl/ipc4/eq_fir_loudness.txt deleted file mode 100644 index 969f50369e1e..000000000000 --- a/tools/ctl/ipc4/eq_fir_loudness.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,584,50438144,0,0,0,0,584,131076,0,0,0,0,65537,65537,4294901764,0,0,0,0,16384,0,252,0,0,0,0,65537,65537,65537,65537,131073,131074,131074,196611,196611,262147,262148,327685,393221,393222,458759,524296,589833,655370,720907,786444,851981,983054,1048591,1179665,1245202,1376276,1507350,1638424,1769498,1966109,2162719,2359330,2621478,2818089,3080237,3407922,3670070,3997755,4325440,4718661,5046347,5505105,5963863,6422622,6815845,7274604,7733362,8192121,8781953,9568396,10420376,11272357,12058802,12976318,14155982,15335649,16056559,16515324,16711960,24117551,70844611,3920495315,3920522431,70845139,24117443,16711983,16515352,16056572,15335663,14156001,12976334,12058814,11272370,10420389,9568408,8781964,8192129,7733369,7274610,6815852,6422629,5963870,5505111,5046353,4718667,4325445,3997760,3670075,3407926,3080242,2818093,2621481,2359334,2162722,1966111,1769501,1638426,1507352,1376278,1245204,1179666,1048593,983055,851982,786445,720908,655371,589834,524297,458760,393223,393222,327685,262149,262148,196611,196611,131075,131074,131074,65537,65537,65537,65537,1,0, diff --git a/tools/ctl/ipc4/eq_fir_mid.txt b/tools/ctl/ipc4/eq_fir_mid.txt deleted file mode 100644 index d62ef102fb4e..000000000000 --- a/tools/ctl/ipc4/eq_fir_mid.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,128,50438144,0,0,0,0,128,65538,0,0,0,0,0,65576,0,0,0,0,1202154746,4222755303,3873958283,4024953600,4126012299,4176934804,4217764409,4250664050,4273864222,4288806716,2490349,6750285,8126582,7733371,6488174,4980824,3473472,2293804,1245211,1245197, diff --git a/tools/ctl/ipc4/eq_fir_pass.txt b/tools/ctl/ipc4/eq_fir_pass.txt deleted file mode 100644 index d095c87b1aea..000000000000 --- a/tools/ctl/ipc4/eq_fir_pass.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,56,50438144,0,0,0,0,56,65538,0,0,0,0,4294967295,4294901764,0,0,0,0,16384,0, diff --git a/tools/ctl/ipc4/eq_iir/bandpass.txt b/tools/ctl/ipc4/eq_iir/bandpass.txt new file mode 100644 index 000000000000..3509ec8c7cf2 --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/bandpass.txt @@ -0,0 +1 @@ +3,148,877023059,0,116,50450433,0,0,0,0,116,2,1,0,0,0,0,0,0,2,2,0,0,0,0,3316150158,2048164275,513807534,3267352229,513807534,0,16384,3867454526,1191025347,38870735,77741469,38870735,4294967292,24197 diff --git a/tools/ctl/ipc4/eq_iir/bassboost.txt b/tools/ctl/ipc4/eq_iir/bassboost.txt new file mode 100644 index 000000000000..8d96a8c7fc68 --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/bassboost.txt @@ -0,0 +1 @@ +3,148,877023059,0,116,50450433,0,0,0,0,116,2,1,0,0,0,0,0,0,2,2,0,0,0,0,3227172081,2141520527,536653443,3221660410,536653443,0,16384,3260252783,2107733822,161646111,3961037800,172645501,4294967294,27910 diff --git a/tools/ctl/ipc4/eq_iir/flat.txt b/tools/ctl/ipc4/eq_iir/flat.txt new file mode 100644 index 000000000000..cb78a292eda8 --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/flat.txt @@ -0,0 +1 @@ +3,120,877023059,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,538145694,0,32690 diff --git a/tools/ctl/ipc4/eq_iir/highpass_20hz_0db_48khz.txt b/tools/ctl/ipc4/eq_iir/highpass_20hz_0db_48khz.txt new file mode 100644 index 000000000000..6d2ced3f43a3 --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/highpass_20hz_0db_48khz.txt @@ -0,0 +1 @@ +3,120,877023059,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3225193546,2143508228,537150400,3220666496,537150400,0,32690 diff --git a/tools/ctl/ipc4/eq_iir/highpass_30hz_0db_48khz.txt b/tools/ctl/ipc4/eq_iir/highpass_30hz_0db_48khz.txt new file mode 100644 index 000000000000..a87e38ddcbfa --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/highpass_30hz_0db_48khz.txt @@ -0,0 +1 @@ +3,120,877023059,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3227172081,2141520527,536653443,3221660410,536653443,0,32690 diff --git a/tools/ctl/ipc4/eq_iir/highpass_40hz_0db_48khz.txt b/tools/ctl/ipc4/eq_iir/highpass_40hz_0db_48khz.txt new file mode 100644 index 000000000000..3aafc5060347 --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/highpass_40hz_0db_48khz.txt @@ -0,0 +1 @@ +3,120,877023059,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3229146956,2139532835,536156946,3222653403,536156946,0,32690 diff --git a/tools/ctl/ipc4/eq_iir/highpass_40hz_20db_48khz.txt b/tools/ctl/ipc4/eq_iir/highpass_40hz_20db_48khz.txt new file mode 100644 index 000000000000..4a4f1459a3ac --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/highpass_40hz_20db_48khz.txt @@ -0,0 +1 @@ +3,120,877023059,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3229146956,2139532835,536156946,3222653403,536156946,4294967292,20432 diff --git a/tools/ctl/ipc4/eq_iir/highpass_40hz_30db_48khz.txt b/tools/ctl/ipc4/eq_iir/highpass_40hz_30db_48khz.txt new file mode 100644 index 000000000000..d997e8f3131b --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/highpass_40hz_30db_48khz.txt @@ -0,0 +1 @@ +3,120,877023059,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3229146956,2139532835,536156946,3222653403,536156946,4294967291,32305 diff --git a/tools/ctl/ipc4/eq_iir/highpass_40hz_40db_48khz.txt b/tools/ctl/ipc4/eq_iir/highpass_40hz_40db_48khz.txt new file mode 100644 index 000000000000..082ed00b7e31 --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/highpass_40hz_40db_48khz.txt @@ -0,0 +1 @@ +3,120,877023059,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3229146956,2139532835,536156946,3222653403,536156946,4294967289,25539 diff --git a/tools/ctl/ipc4/eq_iir/highpass_50hz_0db_48khz.txt b/tools/ctl/ipc4/eq_iir/highpass_50hz_0db_48khz.txt new file mode 100644 index 000000000000..b7822d4dc230 --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/highpass_50hz_0db_48khz.txt @@ -0,0 +1 @@ +3,120,877023059,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3231118179,2137545158,535660909,3223645479,535660909,0,32690 diff --git a/tools/ctl/ipc4/eq_iir/loudness.txt b/tools/ctl/ipc4/eq_iir/loudness.txt new file mode 100644 index 000000000000..fed1b4f25578 --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/loudness.txt @@ -0,0 +1 @@ +3,236,877023059,0,204,50450433,0,0,0,0,204,4,2,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,538145694,0,32690,3,3,0,0,0,0,3237960220,2130690484,297056159,3694463533,303476880,0,16384,3302357025,2064935920,245217319,3776455865,274003881,0,16384,4106268671,4130185751,69182517,4179658584,365641401,4294967292,25468 diff --git a/tools/ctl/ipc4/eq_iir/pass.txt b/tools/ctl/ipc4/eq_iir/pass.txt new file mode 100644 index 000000000000..ee0d545ef39e --- /dev/null +++ b/tools/ctl/ipc4/eq_iir/pass.txt @@ -0,0 +1 @@ +3,120,877023059,0,88,50450433,0,0,0,0,88,2,1,0,0,0,0,4294967295,4294967295,1,1,0,0,0,0,0,0,0,0,538145694,0,32690 diff --git a/tools/ctl/ipc4/eq_iir_bandpass.txt b/tools/ctl/ipc4/eq_iir_bandpass.txt deleted file mode 100644 index 6163013a65cb..000000000000 --- a/tools/ctl/ipc4/eq_iir_bandpass.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,116,50438144,0,0,0,0,116,2,1,0,0,0,0,0,0,2,2,0,0,0,0,3316150158,2048164275,513807534,3267352229,513807534,0,16384,3867454526,1191025347,38870735,77741469,38870735,4294967292,24197, diff --git a/tools/ctl/ipc4/eq_iir_bassboost.txt b/tools/ctl/ipc4/eq_iir_bassboost.txt deleted file mode 100644 index 92bb845c5142..000000000000 --- a/tools/ctl/ipc4/eq_iir_bassboost.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,116,50438144,0,0,0,0,116,2,1,0,0,0,0,0,0,2,2,0,0,0,0,3227172081,2141520527,536653443,3221660410,536653443,0,16384,3260252783,2107733822,161646111,3961037800,172645501,4294967294,27910, diff --git a/tools/ctl/ipc4/eq_iir_flat.txt b/tools/ctl/ipc4/eq_iir_flat.txt deleted file mode 100644 index 6b787a743fd5..000000000000 --- a/tools/ctl/ipc4/eq_iir_flat.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,88,50438144,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,538145694,0,32690, diff --git a/tools/ctl/ipc4/eq_iir_highpass_20hz_0db_48khz.txt b/tools/ctl/ipc4/eq_iir_highpass_20hz_0db_48khz.txt deleted file mode 100644 index bbe8a81eeaa6..000000000000 --- a/tools/ctl/ipc4/eq_iir_highpass_20hz_0db_48khz.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,88,50438144,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3225193546,2143508228,537150400,3220666496,537150400,0,32690, diff --git a/tools/ctl/ipc4/eq_iir_highpass_30hz_0db_48khz.txt b/tools/ctl/ipc4/eq_iir_highpass_30hz_0db_48khz.txt deleted file mode 100644 index c7ffbd526f1c..000000000000 --- a/tools/ctl/ipc4/eq_iir_highpass_30hz_0db_48khz.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,88,50438144,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3227172081,2141520527,536653443,3221660410,536653443,0,32690, diff --git a/tools/ctl/ipc4/eq_iir_highpass_40hz_0db_48khz.txt b/tools/ctl/ipc4/eq_iir_highpass_40hz_0db_48khz.txt deleted file mode 100644 index 62c504c1276b..000000000000 --- a/tools/ctl/ipc4/eq_iir_highpass_40hz_0db_48khz.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,88,50438144,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3229146956,2139532835,536156946,3222653403,536156946,0,32690, diff --git a/tools/ctl/ipc4/eq_iir_highpass_50hz_0db_48khz.txt b/tools/ctl/ipc4/eq_iir_highpass_50hz_0db_48khz.txt deleted file mode 100644 index 8630e65c6cd6..000000000000 --- a/tools/ctl/ipc4/eq_iir_highpass_50hz_0db_48khz.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,88,50438144,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3231118179,2137545158,535660909,3223645479,535660909,0,32690, diff --git a/tools/ctl/ipc4/eq_iir_loudness.txt b/tools/ctl/ipc4/eq_iir_loudness.txt deleted file mode 100644 index 4ab0bb1f3187..000000000000 --- a/tools/ctl/ipc4/eq_iir_loudness.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,204,50438144,0,0,0,0,204,4,2,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,538145694,0,32690,3,3,0,0,0,0,3237960220,2130690484,297056159,3694463533,303476880,0,16384,3302357025,2064935920,245217319,3776455865,274003881,0,16384,4106268671,4130185751,69182517,4179658584,365641401,4294967292,25468, diff --git a/tools/ctl/ipc4/eq_iir_pass.txt b/tools/ctl/ipc4/eq_iir_pass.txt deleted file mode 100644 index 29830d0fdf0f..000000000000 --- a/tools/ctl/ipc4/eq_iir_pass.txt +++ /dev/null @@ -1 +0,0 @@ -877023059,0,88,50438144,0,0,0,0,88,2,1,0,0,0,0,4294967295,4294967295,1,1,0,0,0,0,0,0,0,0,538145694,0,32690, diff --git a/tools/debug_stream/debug_stream.py b/tools/debug_stream/debug_stream.py index 9c3706d90f99..39770cab4cd3 100644 --- a/tools/debug_stream/debug_stream.py +++ b/tools/debug_stream/debug_stream.py @@ -46,7 +46,6 @@ class DebugStreamRecord(ctypes.Structure): ("size_words", ctypes.c_uint), ] - class CPUInfo(ctypes.Structure): """ Thread Info record header @@ -73,6 +72,17 @@ class ThreadInfo(ctypes.Structure): ] +class TextMsg(ctypes.Structure): + """ + Text Msg record header + """ + + _pack_ = 1 + _fields_ = [ + ("hdr", DebugStreamRecord), + ] + + WSIZE = ctypes.sizeof(ctypes.c_uint) @@ -83,6 +93,7 @@ class RecordPrinter: RECORD_ID_UNINITIALIZED = 0 RECORD_ID_THREAD_INFO = 1 + RECORD_ID_TEXT_MSG = 2 def print_record(self, record, cpu): """prints debug-stream record""" @@ -92,7 +103,9 @@ def print_record(self, record, cpu): ) if recp.contents.id == self.RECORD_ID_THREAD_INFO: return self.print_thread_info(record, cpu) - logging.warning("cpu %u: Unsupported recodrd type %u", cpu, recp.contents.id) + if recp.contents.id == self.RECORD_ID_TEXT_MSG: + return self.print_text_msg(record, cpu) + logging.warning("cpu %u: Unsupported record type %u", cpu, recp.contents.id) return True def print_thread_info(self, record, cpu): @@ -141,6 +154,18 @@ def print_thread_info(self, record, cpu): ) return True + def print_text_msg(self, record, cpu): + """prints text-msg record""" + if len(record) - ctypes.sizeof(TextMsg) < 0: + logging.info("Buffer end reached, parsing failed") + return False + buffer = ( + ctypes.c_ubyte * (len(record) - ctypes.sizeof(TextMsg)) + ).from_address(ctypes.addressof(record) + ctypes.sizeof(TextMsg)) + payload = bytes(buffer) + msg = payload.split(b"\0", 1)[0].decode("utf-8", errors="replace") + print("CPU %u:\n%s" % (cpu, msg)) + return True class DebugStreamSectionDescriptor(ctypes.Structure): """ diff --git a/tools/demo-gui/demo-gui/sof_controller_engine.py b/tools/demo-gui/demo-gui/sof_controller_engine.py index 25d40b820b8a..c1dd6c1d9294 100644 --- a/tools/demo-gui/demo-gui/sof_controller_engine.py +++ b/tools/demo-gui/demo-gui/sof_controller_engine.py @@ -6,7 +6,7 @@ import re import math -# Global variables to store the aplay/arecord process, paused state, current file, detected device, volume control, and EQ numid +# Global variables aplay_process = None arecord_process = None paused = None @@ -14,7 +14,8 @@ device_string = None volume_control = None eq_numid = None - +is_muted = False +previous_volume = 50 # Store the previous volume level extra_audio_paths = [] def initialize_device(): @@ -22,24 +23,20 @@ def initialize_device(): try: output = subprocess.check_output(["aplay", "-l"], text=True, stderr=subprocess.DEVNULL) - match = re.search(r"card (\d+):.*\[.*sof.*\]", output, re.IGNORECASE) if match: card_number = match.group(1) device_string = f"hw:{card_number}" print(f"Detected SOF card: {device_string}") else: - print("No SOF card found.") raise RuntimeError("SOF card not found. Ensure the device is connected and recognized by the system.") controls_output = subprocess.check_output(["amixer", f"-D{device_string}", "controls"], text=True, stderr=subprocess.DEVNULL) - volume_match = re.search(r"numid=(\d+),iface=MIXER,name='(.*Master Playback Volume.*)'", controls_output) if volume_match: volume_control = volume_match.group(2) print(f"Detected Volume Control: {volume_control}") else: - print("Master GUI Playback Volume control not found.") raise RuntimeError("Volume control not found.") eq_match = re.search(r"numid=(\d+),iface=MIXER,name='EQIIR1\.0 eqiir_coef_1'", controls_output) @@ -47,33 +44,38 @@ def initialize_device(): eq_numid = eq_match.group(1) print(f"Detected EQ numid: {eq_numid}") else: - print("EQ control not found.") raise RuntimeError("EQ control not found.") except subprocess.CalledProcessError as e: print(f"Failed to run device detection commands: {e}") raise + except RuntimeError as e: + print(e) + raise def scale_volume(user_volume): normalized_volume = user_volume / 100.0 - scaled_volume = 31 * (math.sqrt(normalized_volume)) + scaled_volume = 31 * math.sqrt(normalized_volume) return int(round(scaled_volume)) def scan_for_files(directory_name: str, file_extension: str, extra_paths: list = None): found_files = [] dir_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), directory_name) - if os.path.exists(dir_path): - found_files.extend([f for f in os.listdir(dir_path) if f.endswith(file_extension)]) - else: - print(f"Error: The '{directory_name}' directory is missing. It should be located in the same folder as this script.") - - if extra_paths: - for path in extra_paths: - if os.path.exists(path): - found_files.extend([f for f in os.listdir(path) if f.endswith(file_extension)]) - else: - print(f"Warning: The directory '{path}' does not exist.") + try: + if os.path.exists(dir_path): + found_files.extend([f for f in os.listdir(dir_path) if f.endswith(file_extension)]) + else: + print(f"Error: The '{directory_name}' directory is missing. It should be located in the same folder as this script.") + + if extra_paths: + for path in extra_paths: + if os.path.exists(path): + found_files.extend([f for f in os.listdir(path) if f.endswith(file_extension)]) + else: + print(f"Warning: The directory '{path}' does not exist.") + except Exception as e: + print(f"Error scanning for files: {e}") return found_files @@ -86,11 +88,16 @@ def execute_command(command: str, data: int = 0, file_name: str = None): 'eq': lambda x: handle_eq(file_name), 'play': lambda x: handle_play(file_name), 'pause': lambda x: handle_pause(), + 'stop': lambda x: handle_stop(), + 'mute': lambda x: handle_mute(), 'record': lambda x: handle_record(start=data, filename=file_name) } command_function = command_switch.get(command, lambda x: handle_unknown_command(data)) - command_function(data) + try: + command_function(data) + except Exception as e: + print(f"Error executing command '{command}': {e}") def handle_volume(data: int): amixer_command = f"amixer -D{device_string} cset name='{volume_control}' {data}" @@ -100,6 +107,10 @@ def handle_volume(data: int): print(f"Failed to set volume: {e}") def handle_eq(eq_file_name: str): + if not eq_file_name: + print("No EQ file name provided.") + return + ctl_command = f"./sof-ctl -D{device_string} -n {eq_numid} -s {eq_file_name}" try: subprocess.run(ctl_command, shell=True, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) @@ -109,39 +120,44 @@ def handle_eq(eq_file_name: str): def handle_play(play_file_name: str): global aplay_process, paused, current_file - if paused and paused is not None and current_file == play_file_name: - os.kill(aplay_process.pid, signal.SIGCONT) - print("Playback resumed.") - paused = False + if not play_file_name: + print("No file name provided for playback.") return - if aplay_process is not None: - if aplay_process.poll() is None: - if current_file == play_file_name: - print("Playback is already in progress.") - return + try: + if paused and current_file == play_file_name: + os.kill(aplay_process.pid, signal.SIGCONT) + print("Playback resumed.") + paused = False + return + + if aplay_process is not None: + if aplay_process.poll() is None: + if current_file == play_file_name: + print("Playback is already in progress.") + return + else: + os.kill(aplay_process.pid, signal.SIGKILL) + print("Stopping current playback to play a new file.") else: - os.kill(aplay_process.pid, signal.SIGKILL) - print("Stopping current playback to play a new file.") - else: - print("Previous process is not running, starting new playback.") + print("Previous process is not running, starting new playback.") - default_audio_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'audios') - file_path = next((os.path.join(path, play_file_name) for path in [default_audio_dir] + extra_audio_paths if os.path.exists(os.path.join(path, play_file_name))), None) + default_audio_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'audios') + file_path = next((os.path.join(path, play_file_name) for path in [default_audio_dir] + extra_audio_paths if os.path.exists(os.path.join(path, play_file_name))), None) - if file_path is None: - print(f"Error: File '{play_file_name}' not found in the default 'audios' directory or any provided paths.") - return - - aplay_command = f"aplay -D{device_string} '{file_path}'" + if file_path is None: + print(f"Error: File '{play_file_name}' not found in the default 'audios' directory or any provided paths.") + return - try: + aplay_command = f"aplay -D{device_string} '{file_path}'" aplay_process = subprocess.Popen(aplay_command, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) current_file = play_file_name print(f"Playing file: {play_file_name}.") paused = False except subprocess.CalledProcessError as e: print(f"Failed to play file: {e}") + except Exception as e: + print(f"Error during playback: {e}") def handle_pause(): global aplay_process, paused @@ -161,6 +177,37 @@ def handle_pause(): except Exception as e: print(f"Failed to pause playback: {e}") +def handle_stop(): + global aplay_process, paused, current_file + + if aplay_process is None: + print("No playback process to stop.") + return + + if aplay_process.poll() is not None: + print("Playback process has already finished.") + return + + try: + os.kill(aplay_process.pid, signal.SIGKILL) + aplay_process = None + paused = False + current_file = None + print("Playback stopped.") + except Exception as e: + print(f"Failed to stop playback: {e}") + +def handle_mute(): + if not is_muted: + previous_volume = scale_volume(50) # Assume 50 is the current volume + handle_volume(0) + is_muted = True + print("Audio muted.") + else: + handle_volume(previous_volume) + is_muted = False + print("Audio unmuted.") + def handle_record(start: bool, filename: str): global arecord_process @@ -174,7 +221,6 @@ def handle_record(start: bool, filename: str): return record_command = f"arecord -D{device_string} -f cd -t wav {filename}" - try: arecord_process = subprocess.Popen(record_command, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) print(f"Started recording: {filename}") @@ -189,7 +235,7 @@ def handle_record(start: bool, filename: str): try: os.kill(arecord_process.pid, signal.SIGINT) arecord_process = None - print(f"Stopped recording.") + print("Stopped recording.") except Exception as e: print(f"Failed to stop recording: {e}") diff --git a/tools/demo-gui/demo-gui/sof_demo_gui.py b/tools/demo-gui/demo-gui/sof_demo_gui.py index 37174de7b1a7..3f18287adf2a 100644 --- a/tools/demo-gui/demo-gui/sof_demo_gui.py +++ b/tools/demo-gui/demo-gui/sof_demo_gui.py @@ -12,13 +12,19 @@ def __init__(self, audio_paths, config_paths): super().__init__(title="SOF Demo Gui") self.set_resizable(False) self.set_border_width(10) + self.apply_css() + self.init_ui(audio_paths, config_paths) + sof_ctl.initialize_device() + self.is_muted = False + self.previous_volume = 50 # Store the previous volume level + def apply_css(self): css_provider = Gtk.CssProvider() css = """ * { font-family: "Segoe UI", "Arial", sans-serif; font-size: 14px; - color: #FFFFFF; + color: #020202; } window { background-color: #2C3E50; @@ -32,67 +38,89 @@ def __init__(self, audio_paths, config_paths): } button, togglebutton { background-color: #3b3b3b; - background: #3b3b3b; border: none; padding: 10px; - color: #3b3b3b; + color: #020202; } button:hover, togglebutton:hover { background-color: #A9A9A9; - color: #A9A9A9; + color: #020202; } togglebutton:checked { background-color: #A9A9A9; - color: #A9A9A9; + color: #020202; } scale { background-color: #34495E; border-radius: 5px; + color: #FFFFFF; } label { - color: #A9A9A9; + color: #020202; } headerbar { background-color: #2C3E50; - color: #2C3E50; + color: #FFFFFF; } headerbar.titlebar { - background: #2C3E50; + background-color: #2C3E50; } """ css_provider.load_from_data(css.encode('utf-8')) screen = Gdk.Screen.get_default() Gtk.StyleContext.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) + def init_ui(self, audio_paths, config_paths): main_grid = Gtk.Grid() main_grid.set_row_spacing(10) main_grid.set_column_spacing(10) self.add(main_grid) + control_frame = self.create_control_frame() + main_grid.attach(control_frame, 0, 0, 1, 1) + + file_frame = self.create_file_frame() + main_grid.attach(file_frame, 0, 1, 1, 1) + + record_frame = self.create_record_frame() + main_grid.attach(record_frame, 0, 2, 1, 1) + + self.scan_and_populate_dropdowns(audio_paths, config_paths) + + def create_control_frame(self): control_frame = Gtk.Frame(label="Playback and Volume Control") control_grid = Gtk.Grid() control_grid.set_row_spacing(10) control_grid.set_column_spacing(10) control_frame.add(control_grid) - main_grid.attach(control_frame, 0, 0, 1, 1) - - self.play_pause_button = Gtk.ToggleButton(label="Play") - self.play_pause_button.connect("toggled", self.on_play_pause_toggled) - control_grid.attach(self.play_pause_button, 0, 0, 1, 1) volume_adjustment = Gtk.Adjustment(value=100, lower=0, upper=100, step_increment=1, page_increment=5, page_size=0) self.volume_button = Gtk.Scale(name="volume", orientation=Gtk.Orientation.HORIZONTAL, adjustment=volume_adjustment) self.volume_button.set_digits(0) self.volume_button.set_hexpand(True) self.volume_button.connect("value-changed", self.on_volume_changed) - control_grid.attach(self.volume_button, 1, 0, 1, 1) + control_grid.attach(self.volume_button, 0, 0, 2, 1) + + self.play_pause_button = Gtk.ToggleButton(label="Play") + self.play_pause_button.connect("toggled", self.on_play_pause_toggled) + control_grid.attach(self.play_pause_button, 0, 1, 1, 1) + self.stop_button = Gtk.Button(label="Stop") + self.stop_button.connect("clicked", self.on_stop_clicked) + control_grid.attach(self.stop_button, 1, 1, 1, 1) + + self.mute_button = Gtk.Button(label="Mute") + self.mute_button.connect("clicked", self.on_mute_clicked) + control_grid.attach(self.mute_button, 0, 2, 2, 1) + + return control_frame + + def create_file_frame(self): file_frame = Gtk.Frame(label="File Selection") file_grid = Gtk.Grid() file_grid.set_row_spacing(10) file_grid.set_column_spacing(10) file_frame.add(file_grid) - main_grid.attach(file_frame, 0, 1, 1, 1) self.wav_dropdown = Gtk.ComboBoxText() self.wav_dropdown.connect("changed", self.on_wav_file_selected) @@ -113,6 +141,9 @@ def __init__(self, audio_paths, config_paths): self.apply_eq_button.connect("clicked", self.on_apply_eq_clicked) file_grid.attach(self.apply_eq_button, 1, 2, 1, 1) + return file_frame + + def create_record_frame(self): record_frame = Gtk.Frame(label="Recording Control") record_grid = Gtk.Grid() record_grid.set_row_spacing(10) @@ -120,7 +151,6 @@ def __init__(self, audio_paths, config_paths): record_grid.set_hexpand(True) record_grid.set_vexpand(True) record_frame.add(record_grid) - main_grid.attach(record_frame, 0, 2, 1, 1) self.record_button = Gtk.ToggleButton(label="Record") self.record_button.connect("toggled", self.on_record_toggled) @@ -130,8 +160,7 @@ def __init__(self, audio_paths, config_paths): self.record_index = 1 - self.scan_and_populate_dropdowns(audio_paths, config_paths) - sof_ctl.initialize_device() + return record_frame def scan_and_populate_dropdowns(self, audio_paths, config_paths): wav_files = sof_ctl.scan_for_files('audios', '.wav', extra_paths=audio_paths) @@ -167,6 +196,21 @@ def on_play_pause_toggled(self, widget): widget.set_label("Play") sof_ctl.execute_command(command="pause") + def on_stop_clicked(self, widget): + self.play_pause_button.set_active(False) + sof_ctl.execute_command(command="stop") + + def on_mute_clicked(self, widget): + if not self.is_muted: + self.previous_volume = self.volume_button.get_value() + self.volume_button.set_value(0) + self.is_muted = True + widget.set_label("Unmute") + else: + self.volume_button.set_value(self.previous_volume) + self.is_muted = False + widget.set_label("Mute") + def on_record_toggled(self, widget): if widget.get_active(): widget.set_label("Stop Recording") diff --git a/tools/logger/convert.c b/tools/logger/convert.c index 4e0a6cdc59ae..834ee5a1b243 100644 --- a/tools/logger/convert.c +++ b/tools/logger/convert.c @@ -126,8 +126,14 @@ static const char *format_uid(uint32_t uid_ptr, int use_colors, bool be, bool up const struct sof_uuid_entry *uid_entry; char *str; + /* + * The whole struct sof_uuid_entry is read at uid_ptr, so require that + * many bytes to remain in the uids region; a bare ">=" upper bound + * would accept a pointer whose entry straddles the end of the buffer. + */ if (uid_ptr < uids_dict->base_address || - uid_ptr >= uids_dict->base_address + uids_dict->data_length) { + uid_ptr + sizeof(struct sof_uuid_entry) > + uids_dict->base_address + uids_dict->data_length) { str = calloc(1, strlen(BAD_PTR_STR) + 1 + 6); if (!str) { log_err("can't allocate memory\n"); diff --git a/tools/logger/filter.c b/tools/logger/filter.c index 0943f68d16b2..7a3d53c37246 100644 --- a/tools/logger/filter.c +++ b/tools/logger/filter.c @@ -104,7 +104,7 @@ static char *filter_parse_component_name(char *input_str, struct filter_element */ if (strlen(scan_format_string) == 0) { ret = snprintf(scan_format_string, sizeof(scan_format_string), - "%%%d[^0-9* ]s", UUID_NAME_MAX_LEN); + "%%%d[^0-9* ]s", UUID_NAME_MAX_LEN - 1); if (ret <= 0) return NULL; } diff --git a/tools/mtrace/mtrace-reader.c b/tools/mtrace/mtrace-reader.c new file mode 100644 index 000000000000..ae5eb31d68a8 --- /dev/null +++ b/tools/mtrace/mtrace-reader.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. +// +// Author: Kai Vehmanen <kai.vehmanen@linux.intel.com> +// +// Compile instructions: +// gcc -o mtrace-reader mtrace-reader.c -Wall -O2 +// + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdint.h> + +#define READ_BUFFER 16384 +#define MTRACE_FILE "/sys/kernel/debug/sof/mtrace/core0" + +uint8_t buffer[READ_BUFFER]; + +int main(void) +{ + ssize_t read_bytes; + uint32_t data_len; + uint32_t header; + int fd; + + fd = open(MTRACE_FILE, O_RDONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + while (1) { + read_bytes = read(fd, buffer, READ_BUFFER); + + /* handle end-of-file */ + if (read_bytes == 0) + continue; + + if (read_bytes <= 4) + continue; + + header = *(uint32_t *)buffer; + data_len = header; + if (data_len > read_bytes - 4) + continue; + + if (write(STDOUT_FILENO, buffer + 4, data_len) < 0) { + perror("write"); + return -1; + } + } + + close(fd); + + return 0; +} diff --git a/tools/plugin/README.md b/tools/plugin/README.md index ce0cad4ea4cd..e225437b404f 100644 --- a/tools/plugin/README.md +++ b/tools/plugin/README.md @@ -1,11 +1,11 @@ -##ALSA Plugin +# 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 +### Features * aplay & arecord usage working today * alsamixer & amixer usage not working today * modules are loaded as SO shared libraries. @@ -16,10 +16,10 @@ framework for SOF infrastructure and processing. * alsa sink and alsa source modules available. * pipelines can block (non blocking and mmap todo) -#License +### License Code is a mixture of LGPL and BSD 3c. -#Usage +### Usage Please build as cmake project, for IPC4 (functional) IPC3 is not functional and not supported @@ -37,7 +37,7 @@ then (use default ALSA prefix atm) sudo cmake --install build-plugin/ 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/" +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 ``` @@ -108,35 +108,54 @@ where -n is the numid of the kcontrol, -i is the IPC version and -p is the param Note: Bytes controls must have tlv_read/tlv_write and tlv_callback access. -# Instructions for testing OpenVino noise suppression model with the SOF plugin: -1. Fetch the model from the Open Model zoo repository ex: noise-suppression-poconetlike-0001.xml +## Instructions for testing OpenVino noise suppression model with the SOF plugin: +1. Prepare Open Model Zoo repository: -https://docs.openvino.ai/archive/2023.0/omz_demos.html#build-the-demo-applications-on-linux + - Clone repo: + ``` + git clone --recurse-submodules https://github.com/openvinotoolkit/open_model_zoo.git + ``` + + - Build demo applications: + https://docs.openvino.ai/2023.3/omz_demos.html#a-name-build-demos-linux-a-build-the-demo-applications-on-linux 2. Source OpenVino environment and get OpenCV https://www.intel.com/content/www/us/en/developer/tools/openvino-toolkit-download.html 3. Worth building and running the demo noise suppression application in the open model zoo repository to make sure OpenVino and OpenCV are configured properly. +Fetch the model, e.g., `noise-suppression-poconetlike-0001.xml`, by running this demo: + + https://docs.openvino.ai/2023.3/omz_demos_noise_suppression_demo_cpp.html 4. Set environment variable NOISE_SUPPRESSION_MODEL_NAME to point to the model file ``` -export NOISE_SUPPRESSION_MODEL_NAME="~/open_model_zoo/demos/noise_suppression_demo/cpp/intel/noise-suppression-poconetlike-0001/FP16/noise-suppression-poconetlike-0001.xml" +export NOISE_SUPPRESSION_MODEL_NAME=~/open_model_zoo/demos/noise_suppression_demo/cpp/intel/noise-suppression-poconetlike-0001/FP16/noise-suppression-poconetlike-0001.xml + +``` +5. Set environment variable OpenVINO_DIR to include CMake files (e.g., OpenVINOConfig.cmake) for building the plugin: +``` +export OpenVINO_DIR=~/openvino_env/lib/python3.10/site-packages/openvino/cmake ``` -5. Enable noise suppression by setting NOISE_SUPPRESSION=true in the tplg-targets for the sof-plugin topology +6. Update environment variable LD_LIBRARY_PATH to include necessary directories for the plugin: + +``` +export LD_LIBRARY_PATH=~/work/sof/sof/build-plugin/sof_ep/install/lib:~/work/sof/sof/build-plugin/modules/:~/work/sof/sof/build-plugin/modules/ov_noise_suppression/ +``` + +7. Enable noise suppression by setting NOISE_SUPPRESSION=true in the tplg-targets for the sof-plugin topology + +8. Rebuild the plugin: Remove the previous build-build directory and rebuild it by following the usage steps above. -6. Start capture using the following command. This uses the 16K capture from the DMIC from +9. Start capture using the following command. This uses the 16K capture from the DMIC from PCM hw device 0,7. Currently, only 16K capture is supported but in the future this will be expanded to work with 48K capture. ``` -arecord -Dsof:plugin:1:0:7:16k2c16b -f dat -r 16000 --period-size=2048 file_ns_16k.wa +arecord -Dsof:plugin:1:0:7:16k2c16b -f dat -r 16000 --period-size=2048 file_ns_16k.wav ``` -#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. +### TODO Items for single pipeline E2E audio +Use hw_params instead of hardcoded config +Add support for 24-bit and 16-bit audio +Remove duplication of kcontrols when alsamixer is opened/closed repeatedly \ No newline at end of file diff --git a/tools/plugin/alsaplug/CMakeLists.txt b/tools/plugin/alsaplug/CMakeLists.txt index eddcc0759220..d60104d8245d 100644 --- a/tools/plugin/alsaplug/CMakeLists.txt +++ b/tools/plugin/alsaplug/CMakeLists.txt @@ -17,7 +17,7 @@ target_include_directories(asound_module_pcm_sof PRIVATE ${sof_source_directory}/src/audio) target_compile_options(asound_module_pcm_sof PRIVATE -DPIC -g -O3 -Wmissing-prototypes - -Wimplicit-fallthrough -DCONFIG_LIBRARY -imacros${config_h}) + -Wno-stringop-truncation -Wimplicit-fallthrough -DCONFIG_LIBRARY -imacros${config_h}) install(TARGETS asound_module_pcm_sof DESTINATION /usr/lib/x86_64-linux-gnu/alsa-lib) @@ -49,7 +49,7 @@ target_include_directories(asound_module_ctl_sof PRIVATE ${sof_source_directory}/src/audio) target_compile_options(asound_module_ctl_sof PRIVATE -DPIC -g -O3 -Wmissing-prototypes - -Wimplicit-fallthrough -Wall -Werror -DCONFIG_LIBRARY -imacros${config_h}) + -Wimplicit-fallthrough -Wno-stringop-truncation -Wall -Werror -DCONFIG_LIBRARY -imacros${config_h}) install(TARGETS asound_module_ctl_sof DESTINATION /usr/lib/x86_64-linux-gnu/alsa-lib) diff --git a/tools/plugin/alsaplug/ctl.c b/tools/plugin/alsaplug/ctl.c index f45bf4f9b0e1..85a31177cfca 100644 --- a/tools/plugin/alsaplug/ctl.c +++ b/tools/plugin/alsaplug/ctl.c @@ -31,8 +31,7 @@ typedef struct snd_sof_ctl { struct plug_shm_glb_state *glb; snd_ctl_ext_t ext; - struct plug_mq_desc ipc_tx; - struct plug_mq_desc ipc_rx; + struct plug_socket_desc ipc; struct plug_shm_desc shm_ctx; int subscribed; int updated[MAX_CTLS]; @@ -232,8 +231,7 @@ static int plug_ctl_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long /* send the IPC message */ memcpy(msg, &config, sizeof(config)); - err = plug_mq_cmd_tx_rx(&ctl->ipc_tx, &ctl->ipc_rx, - msg, size, reply_data, reply_data_size); + err = plug_ipc_cmd_tx_rx(&ctl->ipc, msg, size, reply_data, reply_data_size); free(msg); if (err < 0) { SNDERR("failed to set volume for control %s\n", mixer_ctl->hdr.name); @@ -325,8 +323,7 @@ static int plug_ctl_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, lon memcpy(msg + sizeof(config), &volume, sizeof(volume)); /* send the message and check status */ - err = plug_mq_cmd_tx_rx(&ctl->ipc_tx, &ctl->ipc_rx, - msg, size, &reply, sizeof(reply)); + err = plug_ipc_cmd_tx_rx(&ctl->ipc, msg, size, &reply, sizeof(reply)); free(msg); if (err < 0) { SNDERR("failed to set volume control %s\n", mixer_ctl->hdr.name); @@ -426,8 +423,7 @@ static int plug_ctl_read_enumerated(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, /* send the IPC message */ memcpy(msg, &config, sizeof(config)); - err = plug_mq_cmd_tx_rx(&ctl->ipc_tx, &ctl->ipc_rx, - msg, size, reply_data, reply_data_size); + err = plug_ipc_cmd_tx_rx(&ctl->ipc, msg, size, reply_data, reply_data_size); free(msg); if (err < 0) { SNDERR("failed to get enum items for control %s\n", enum_ctl->hdr.name); @@ -516,7 +512,7 @@ static int plug_ctl_write_enumerated(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, free(data); /* send the message and check status */ - err = plug_mq_cmd_tx_rx(&ctl->ipc_tx, &ctl->ipc_rx, msg, msg_size, &reply, sizeof(reply)); + err = plug_ipc_cmd_tx_rx(&ctl->ipc, msg, msg_size, &reply, sizeof(reply)); free(msg); if (err < 0) { SNDERR("failed to set enum control %s\n", enum_ctl->hdr.name); @@ -573,8 +569,7 @@ static int plug_ctl_get_bytes_data(snd_sof_ctl_t *ctl, snd_ctl_ext_key_t key, /* send the IPC message */ memcpy(msg, &config, sizeof(config)); - err = plug_mq_cmd_tx_rx(&ctl->ipc_tx, &ctl->ipc_rx, - msg, size, reply_data, reply_data_size); + err = plug_ipc_cmd_tx_rx(&ctl->ipc, msg, size, reply_data, reply_data_size); free(msg); if (err < 0) { SNDERR("failed to get bytes data for control %s\n", bytes_ctl->hdr.name); @@ -633,9 +628,8 @@ static int plug_ctl_write_bytes(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int err; /* send IPC with kcontrol data */ - err = plug_send_bytes_data(&ctl->ipc_tx, &ctl->ipc_rx, - ctl->glb->ctl[key].module_id, ctl->glb->ctl[key].instance_id, - abi); + err = plug_send_bytes_data(&ctl->ipc, ctl->glb->ctl[key].module_id, + ctl->glb->ctl[key].instance_id, abi); if (err < 0) { SNDERR("failed to set bytes data for control %s\n", bytes_ctl->hdr.name); return err; @@ -644,6 +638,7 @@ static int plug_ctl_write_bytes(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, return 0; } +/* TLV ops used for TLV bytes control callback */ /* TLV ops used for TLV bytes control callback */ 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) @@ -653,12 +648,26 @@ static int plug_tlv_rw(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int op_flag, struct sof_abi_hdr *abi = (struct sof_abi_hdr *)(tlv + 2); /* skip TLV header */ int data_size; + /* only bytes and volume controls have tlv callback set */ + if (bytes_ctl->hdr.ops.info != SND_SOC_TPLG_CTL_BYTES) { + struct snd_soc_tplg_mixer_control *mixer_ctl = CTL_GET_TPLG_MIXER(ctl, key); + struct snd_soc_tplg_ctl_hdr *hdr = &mixer_ctl->hdr; + struct snd_soc_tplg_ctl_tlv *mixer_tlv = &hdr->tlv; + + /* set the dbscale values */ + tlv[0] = SND_CTL_TLVT_DB_SCALE; + tlv[1] = sizeof(int) * 2; + tlv[2] = mixer_tlv->scale.min; + tlv[3] = mixer_tlv->scale.mute << 16 | mixer_tlv->scale.step; + + return 0; + } + /* send IPC with kcontrol data if op_flag is > 0 else send IPC to get kcontrol data */ if (op_flag) { int err; - err = plug_send_bytes_data(&ctl->ipc_tx, &ctl->ipc_rx, - ctl->glb->ctl[key].module_id, + err = plug_send_bytes_data(&ctl->ipc, ctl->glb->ctl[key].module_id, ctl->glb->ctl[key].instance_id, abi); if (err < 0) { SNDERR("failed to set bytes data for control %s\n", bytes_ctl->hdr.name); @@ -731,6 +740,7 @@ static void plug_ctl_close(snd_ctl_ext_t *ext) snd_sof_ctl_t *ctl = ext->private_data; /* TODO: munmap */ + close(ctl->ipc.socket_fd); free(ctl); } @@ -777,34 +787,17 @@ SND_CTL_PLUGIN_DEFINE_FUNC(sof) goto error; } - /* init IPC tx message queue name */ - err = plug_mq_init(&ctl->ipc_tx, "sof", "ipc-tx", 0); + /* init IPC socket name */ + err = plug_socket_path_init(&ctl->ipc, "sof", "ipc", 0); if (err < 0) { SNDERR("error: invalid name for IPC tx mq %s\n", plug->tplg_file); goto error; } - /* open the sof-pipe IPC tx message queue */ - err = plug_mq_open(&ctl->ipc_tx); - if (err < 0) { - SNDERR("error: failed to open sof-pipe IPC mq %s: %s", - ctl->ipc_tx.queue_name, strerror(err)); - goto error; - } - - /* init IPC rx message queue name */ - err = plug_mq_init(&ctl->ipc_rx, "sof", "ipc-rx", 0); - if (err < 0) { - SNDERR("error: invalid name for IPC rx mq %s\n", plug->tplg_file); - goto error; - } - - /* open the sof-pipe IPC rx message queue */ - err = plug_mq_open(&ctl->ipc_rx); + err = plug_create_client_socket(&ctl->ipc); if (err < 0) { - SNDERR("error: failed to open sof-pipe IPC mq %s: %s", - ctl->ipc_rx.queue_name, strerror(err)); - goto error; + SNDERR("failed to connect to SOF pipe IPC socket : %s", strerror(err)); + return -errno; } /* create a SHM mapping for low latency stream position */ @@ -831,9 +824,6 @@ SND_CTL_PLUGIN_DEFINE_FUNC(sof) 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_tx.mq; - ctl->ext.callback = &sof_ext_callback; ctl->ext.private_data = ctl; ctl->ext.tlv.c = plug_tlv_rw; diff --git a/tools/plugin/alsaplug/pcm.c b/tools/plugin/alsaplug/pcm.c index 5ed7d832eaa8..ed5224c829b5 100644 --- a/tools/plugin/alsaplug/pcm.c +++ b/tools/plugin/alsaplug/pcm.c @@ -8,11 +8,12 @@ #include <sys/poll.h> #include <string.h> #include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/stat.h> -#include <mqueue.h> #include <fcntl.h> #include <sys/mman.h> #include <semaphore.h> @@ -42,10 +43,6 @@ typedef struct snd_sof_pcm { /* 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 shm_pcm; @@ -55,15 +52,15 @@ typedef struct snd_sof_pcm { 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 plug_socket_desc *ipc) { 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)); + ret = plug_ipc_cmd_tx_rx(ipc, pipe_state, sizeof(*pipe_state), + &reply, sizeof(reply)); if (ret < 0) SNDERR("failed pipeline %d set state %d\n", pipe_info->instance_id, state); @@ -97,8 +94,7 @@ static int plug_pipelines_set_state(snd_sof_plug_t *plug, int state) int ret; ret = plug_pipeline_set_state(plug, state, &pipe_state, pipe_info, - &pcm->pipeline_ipc_tx[i], - &pcm->pipeline_ipc_rx[i]); + &plug->ipc); if (ret < 0) return ret; } @@ -111,7 +107,7 @@ static int plug_pipelines_set_state(snd_sof_plug_t *plug, int state) int ret; ret = plug_pipeline_set_state(plug, state, &pipe_state, pipe_info, - &pcm->pipeline_ipc_tx[i], &pcm->pipeline_ipc_rx[i]); + &plug->ipc); if (ret < 0) return ret; } @@ -482,38 +478,6 @@ static int plug_pcm_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) 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); @@ -671,8 +635,6 @@ static int plug_pcm_hw_free(snd_pcm_ioplug_t *io) 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(plug->glb_ctx.fd); @@ -680,11 +642,10 @@ static int plug_pcm_hw_free(snd_pcm_ioplug_t *io) 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); } + close(plug->ipc.socket_fd); return 0; } @@ -957,31 +918,15 @@ static int plug_init_sof_pipe(snd_sof_plug_t *plug, snd_pcm_t **pcmp, 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); + err = plug_socket_path_init(&plug->ipc, "sof", "ipc", 0); if (err < 0) { - SNDERR("error: invalid name for IPC mq %s\n", plug->tplg_file); + SNDERR("error: invalid name for IPC socket %s\n", plug->tplg_file); return err; } - /* open the sof-pipe IPC message queue */ - err = plug_mq_open(&plug->ipc_rx); + err = plug_create_client_socket(&plug->ipc); if (err < 0) { - SNDERR("error: failed to open sof-pipe IPC mq %s: %s", - plug->ipc_rx.queue_name, strerror(err)); + SNDERR("failed to connect to SOF pipe IPC socket : %s", strerror(err)); return -errno; } diff --git a/tools/plugin/alsaplug/plugin.c b/tools/plugin/alsaplug/plugin.c index deb767a4133f..52bbdcfc70e1 100644 --- a/tools/plugin/alsaplug/plugin.c +++ b/tools/plugin/alsaplug/plugin.c @@ -29,7 +29,6 @@ #include <stdlib.h> #include <sys/wait.h> #include <sys/stat.h> -#include <mqueue.h> #include <fcntl.h> #include <sys/mman.h> #include <semaphore.h> @@ -41,27 +40,6 @@ #include "plugin.h" #include "common.h" -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. */ diff --git a/tools/plugin/alsaplug/plugin.h b/tools/plugin/alsaplug/plugin.h index dcc6f550ff53..7f4009267d24 100644 --- a/tools/plugin/alsaplug/plugin.h +++ b/tools/plugin/alsaplug/plugin.h @@ -39,8 +39,7 @@ typedef struct snd_sof_plug { 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; + struct plug_socket_desc ipc; struct plug_shm_desc glb_ctx; diff --git a/tools/plugin/alsaplug/tplg.c b/tools/plugin/alsaplug/tplg.c index b3f04f4ee456..140a0aac91c6 100644 --- a/tools/plugin/alsaplug/tplg.c +++ b/tools/plugin/alsaplug/tplg.c @@ -16,7 +16,6 @@ #include <sys/wait.h> #include <sys/stat.h> #include <signal.h> -#include <mqueue.h> #include <fcntl.h> #include <sys/mman.h> #include <semaphore.h> @@ -926,8 +925,7 @@ static int plug_set_up_widget_ipc(snd_sof_plug_t *plug, struct tplg_comp_info *c 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)); + ret = plug_ipc_cmd_tx_rx(&plug->ipc, msg, size, &reply, sizeof(reply)); free(msg); if (ret < 0) { SNDERR("error: can't set up widget %s\n", comp_info->name); @@ -944,7 +942,7 @@ static int plug_set_up_widget_ipc(snd_sof_plug_t *plug, struct tplg_comp_info *c static int plug_set_up_pipeline(snd_sof_plug_t *plug, struct tplg_pipeline_info *pipe_info) { - struct ipc4_pipeline_create msg; + struct ipc4_pipeline_create msg = {{ 0 }}; struct ipc4_message_reply reply; int ret; @@ -955,8 +953,7 @@ static int plug_set_up_pipeline(snd_sof_plug_t *plug, struct tplg_pipeline_info 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)); + ret = plug_ipc_cmd_tx_rx(&plug->ipc, &msg, sizeof(msg), &reply, sizeof(reply)); if (ret < 0) { SNDERR("error: can't set up pipeline %s\n", pipe_info->name); return ret; @@ -1002,6 +999,12 @@ static int plug_prepare_widget(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_i } if (i == pipeline_list->count) { + if (pipeline_list->count >= TPLG_MAX_PCM_PIPELINES) { + SNDERR("error: too many pipelines for PCM, max %d\n", + TPLG_MAX_PCM_PIPELINES); + return -EINVAL; + } + pipeline_list->pipelines[pipeline_list->count] = comp_info->pipe_info; pipeline_list->count++; } @@ -1113,8 +1116,7 @@ static int plug_set_up_route(snd_sof_plug_t *plug, struct tplg_route_info *route 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)); + ret = plug_ipc_cmd_tx_rx(&plug->ipc, &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); @@ -1174,8 +1176,8 @@ static int plug_set_up_widget(snd_sof_plug_t *plug, struct tplg_comp_info *comp_ abi = (struct sof_abi_hdr *)ctl->data; /* send IPC with kcontrol data */ - ret = plug_send_bytes_data(&plug->ipc_tx, &plug->ipc_rx, - comp_info->module_id, comp_info->instance_id, abi); + ret = plug_send_bytes_data(&plug->ipc, comp_info->module_id, + comp_info->instance_id, abi); if (ret < 0) { SNDERR("failed to set bytes data for widget %s\n", comp_info->name); return ret; @@ -1339,8 +1341,7 @@ static int plug_delete_pipeline(snd_sof_plug_t *plug, struct tplg_pipeline_info 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)); + ret = plug_ipc_cmd_tx_rx(&plug->ipc, &msg, sizeof(msg), &reply, sizeof(reply)); if (ret < 0) { SNDERR("error: can't delete pipeline %s\n", pipe_info->name); return ret; @@ -1383,8 +1384,7 @@ static int plug_free_route(snd_sof_plug_t *plug, struct tplg_route_info *route_i 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)); + ret = plug_ipc_cmd_tx_rx(&plug->ipc, &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); diff --git a/tools/plugin/alsaplug/tplg_ctl.c b/tools/plugin/alsaplug/tplg_ctl.c index 6424b54825ba..ad2709153806 100644 --- a/tools/plugin/alsaplug/tplg_ctl.c +++ b/tools/plugin/alsaplug/tplg_ctl.c @@ -13,7 +13,6 @@ #include <stdlib.h> #include <sys/wait.h> #include <sys/stat.h> -#include <mqueue.h> #include <fcntl.h> #include <sys/mman.h> #include <semaphore.h> diff --git a/tools/plugin/common.c b/tools/plugin/common.c index 46629f061201..f20cb14e0b0e 100644 --- a/tools/plugin/common.c +++ b/tools/plugin/common.c @@ -23,6 +23,8 @@ #include <stdio.h> #include <string.h> #include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> #include <unistd.h> #include <stdlib.h> #include <assert.h> @@ -94,14 +96,10 @@ static const char *suffix_name(const char *longname) /* * Initialise the IPC object. */ -int plug_mq_init(struct plug_mq_desc *ipc, const char *tplg, const char *type, int index) +int plug_socket_path_init(struct plug_socket_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); + snprintf(ipc->path, NAME_SIZE, "/tmp/%s-%s", tplg, type); return 0; } @@ -178,12 +176,45 @@ int plug_shm_open(struct plug_shm_desc *shm) return 0; } -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) +static int plug_socket_timed_wait(struct plug_socket_desc *ipc, fd_set *fds, int timeout_ms, + bool write) +{ + struct timeval timeout; + int result; + + /* Set the timeout for select */ + timeout.tv_sec = 0; + timeout.tv_usec = timeout_ms * 1000; + + /* now wait for socket to be readable/writable */ + if (write) + result = select(ipc->socket_fd + 1, NULL, fds, NULL, &timeout); + else + result = select(ipc->socket_fd + 1, fds, NULL, NULL, &timeout); + + if (result == -1) { + SNDERR("error waiting for socket to be %s\n", write ? "writable" : "readable"); + return result; + } + + if (result == 0) { + SNDERR("IPC Socket %s timeout\n", write ? "write" : "read"); + return -ETIMEDOUT; + } + + /* socket ready for read/write */ + if (FD_ISSET(ipc->socket_fd, fds)) + return 0; + + /* socket not ready */ + return -EINVAL; +} + +static int plug_ipc_cmd_tx(struct plug_socket_desc *ipc, void *msg, size_t len) { - struct timespec ts; - ssize_t ipc_size; + fd_set write_fds; char mailbox[IPC3_MAX_MSG_SIZE]; + ssize_t bytes; int err; if (len > IPC3_MAX_MSG_SIZE) { @@ -193,55 +224,90 @@ int plug_mq_cmd_tx_rx(struct plug_mq_desc *ipc_tx, struct plug_mq_desc *ipc_rx, 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)); + /* Wait for the socket to be writable */ + FD_ZERO(&write_fds); + FD_SET(ipc->socket_fd, &write_fds); + + err = plug_socket_timed_wait(ipc, &write_fds, 20, true); + if (err < 0) + return err; + + bytes = send(ipc->socket_fd, mailbox, IPC3_MAX_MSG_SIZE, 0); + if (bytes == -1) { + SNDERR("failed to send IPC message : %s\n", strerror(errno)); return -errno; } - /* IPCs should be read under 10ms */ - plug_timespec_add_ms(&ts, 10); + return bytes; +} + +static int plug_ipc_cmd_rx(struct plug_socket_desc *ipc, char mailbox[IPC3_MAX_MSG_SIZE]) +{ + fd_set read_fds; + int err; + + /* Wait for the socket to be readable */ + FD_ZERO(&read_fds); + FD_SET(ipc->socket_fd, &read_fds); + + err = plug_socket_timed_wait(ipc, &read_fds, 200, false); + if (err < 0) + return err; + + memset(mailbox, 0, IPC3_MAX_MSG_SIZE); + return recv(ipc->socket_fd, mailbox, IPC3_MAX_MSG_SIZE, 0); +} + +int plug_ipc_cmd_tx_rx(struct plug_socket_desc *ipc, void *msg, size_t len, void *reply, + size_t rlen) +{ + char mailbox[IPC3_MAX_MSG_SIZE]; + ssize_t bytes; + int err; - /* 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)); + /* send IPC message */ + bytes = plug_ipc_cmd_tx(ipc, msg, len); + if (bytes == -1) { + SNDERR("failed to send IPC message : %s\n", 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)); + /* wait for response */ + memset(mailbox, 0, IPC3_MAX_MSG_SIZE); + bytes = plug_ipc_cmd_rx(ipc, mailbox); + if (bytes == -1) { + SNDERR("failed to read IPC message reply %s\n", 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)); + /* no response or connection lost, try to restablish connection */ + if (bytes == 0) { + close(ipc->socket_fd); + err = plug_create_client_socket(ipc); + if (err < 0) { + SNDERR("failed to reestablish connection to SOF pipe IPC socket : %s", + strerror(err)); + return -errno; + } - /* ok, its a long IPC or valgrind, wait longer */ - plug_timespec_add_ms(&ts, 800); + /* send IPC message again */ + bytes = plug_ipc_cmd_tx(ipc, msg, len); + if (bytes == -1) { + SNDERR("failed to send IPC message : %s\n", strerror(errno)); + return -errno; + } - 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)); + /* wait for response */ + memset(mailbox, 0, IPC3_MAX_MSG_SIZE); + bytes = plug_ipc_cmd_rx(ipc, mailbox); + if (bytes == -1) { + SNDERR("failed to read IPC message reply %s\n", 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); + /* connection lost again, quit now */ + if (bytes == 0) + return -errno; } /* do the message work */ @@ -265,8 +331,8 @@ void plug_ctl_ipc_message(struct ipc4_module_large_config *config, int param_id, config->extension.r.large_param_id = param_id; } -int plug_send_bytes_data(struct plug_mq_desc *ipc_tx, struct plug_mq_desc *ipc_rx, - uint32_t module_id, uint32_t instance_id, struct sof_abi_hdr *abi) +int plug_send_bytes_data(struct plug_socket_desc *ipc, uint32_t module_id, uint32_t instance_id, + struct sof_abi_hdr *abi) { struct ipc4_module_large_config config = {{ 0 }}; struct ipc4_message_reply reply; @@ -292,7 +358,7 @@ int plug_send_bytes_data(struct plug_mq_desc *ipc_tx, struct plug_mq_desc *ipc_r memcpy(msg + sizeof(config), abi->data, abi->size); /* send the message and check status */ - err = plug_mq_cmd_tx_rx(ipc_tx, ipc_rx, msg, msg_size, &reply, sizeof(reply)); + err = plug_ipc_cmd_tx_rx(ipc, msg, msg_size, &reply, sizeof(reply)); free(msg); if (err < 0) { SNDERR("failed to send IPC to set bytes data\n"); @@ -306,3 +372,95 @@ int plug_send_bytes_data(struct plug_mq_desc *ipc_tx, struct plug_mq_desc *ipc_r return 0; } + +int plug_socket_create(struct plug_socket_desc *ipc) +{ + struct sockaddr_un addr; + int sockfd; + + /* Check if the socket path already exists */ + if (access(ipc->path, F_OK) != -1) { + /* If it exists, remove it */ + if (unlink(ipc->path) == -1) { + SNDERR("unlink previous socket file"); + return -EINVAL; + } + } + + /* Create the socket */ + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd == -1) { + SNDERR("failed to create new socket"); + return sockfd; + } + + ipc->socket_fd = sockfd; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, ipc->path, sizeof(addr.sun_path) - 1); + + /* Bind the socket to the address */ + if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + SNDERR("failed to bind new socket for IPC path\n"); + close(sockfd); + return -EINVAL; + } + + if (listen(sockfd, MAX_IPC_CLIENTS) == -1) { + SNDERR("failed to listen on socket for IPC\n"); + return -EINVAL; + } + + return 0; +} + +static int set_socket_nonblocking(int sockfd) +{ + int flags = fcntl(sockfd, F_GETFL, 0); + + if (flags == -1) { + SNDERR("fcntl(F_GETFL) failed"); + return -EINVAL; + } + + flags |= O_NONBLOCK; + if (fcntl(sockfd, F_SETFL, flags) == -1) { + SNDERR("fcntl(F_SETFL) failed"); + return -EINVAL; + } + + return 0; +} + +int plug_create_client_socket(struct plug_socket_desc *ipc) +{ + struct sockaddr_un addr; + int sockfd; + + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd == -1) { + SNDERR("error: failed to create sof-pipe IPC socket\n"); + return sockfd; + } + + if (set_socket_nonblocking(sockfd) < 0) { + close(sockfd); + return -EINVAL; + } + ipc->socket_fd = sockfd; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, ipc->path, sizeof(addr.sun_path) - 1); + + /* Connect to the server (non-blocking) */ + if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + if (errno != EINPROGRESS) { + SNDERR("failed to connect to ipc socket"); + return -errno; + } + } + + return sockfd; +} diff --git a/tools/plugin/common.h b/tools/plugin/common.h index 002f3843c3e7..a64100c397cc 100644 --- a/tools/plugin/common.h +++ b/tools/plugin/common.h @@ -9,7 +9,6 @@ #define __SOF_PLUGIN_COMMON_H__ #include <stdint.h> -#include <mqueue.h> #include <semaphore.h> #include <alsa/asoundlib.h> #include <ipc/control.h> @@ -39,6 +38,8 @@ #define NUM_EP_CONFIGS 8 +#define MAX_IPC_CLIENTS 5 + /* * Run with valgrind * valgrind --trace-children=yes aplay -v -Dsof:blah.tplg,1,hw:1,2 -f dat /dev/zero @@ -161,11 +162,9 @@ struct plug_shm_desc { void *addr; }; -struct plug_mq_desc { - /* IPC message queue */ - mqd_t mq; - struct mq_attr attr; - char queue_name[NAME_SIZE]; +struct plug_socket_desc { + int socket_fd; + char path[NAME_SIZE]; }; struct plug_sem_desc { @@ -265,18 +264,13 @@ 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); +int plug_socket_path_init(struct plug_socket_desc *ipc, const char *tplg, const char *type, + int index); -void plug_mq_free(struct plug_mq_desc *ipc); +void plug_socket_free(struct plug_socket_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); +int plug_ipc_cmd_tx_rx(struct plug_socket_desc *ipc, void *msg, size_t len, void *reply, + size_t rlen); /* * Locking @@ -324,7 +318,11 @@ static inline void data_dump(void *vdata, size_t bytes) void plug_ctl_ipc_message(struct ipc4_module_large_config *config, int param_id, size_t size, uint32_t module_id, uint32_t instance_id, uint32_t type); -int plug_send_bytes_data(struct plug_mq_desc *ipc_tx, struct plug_mq_desc *ipc_rx, - uint32_t module_id, uint32_t instance_id, struct sof_abi_hdr *abi); +int plug_send_bytes_data(struct plug_socket_desc *ipc, uint32_t module_id, uint32_t instance_id, + struct sof_abi_hdr *abi); + +int plug_socket_create(struct plug_socket_desc *ipc); + +int plug_create_client_socket(struct plug_socket_desc *ipc); #endif diff --git a/tools/plugin/modules/alsa.c b/tools/plugin/modules/alsa.c index b261de40ee80..69442c687136 100644 --- a/tools/plugin/modules/alsa.c +++ b/tools/plugin/modules/alsa.c @@ -147,7 +147,7 @@ static struct comp_dev *alsa_new(const struct comp_driver *drv, dev->ipc_config = *config; /* allocate memory for file comp data */ - cd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); if (!cd) goto error; diff --git a/tools/plugin/modules/ov_noise_suppression/CMakeLists.txt b/tools/plugin/modules/ov_noise_suppression/CMakeLists.txt index 039e9056ee45..fcf1439d0510 100644 --- a/tools/plugin/modules/ov_noise_suppression/CMakeLists.txt +++ b/tools/plugin/modules/ov_noise_suppression/CMakeLists.txt @@ -39,4 +39,22 @@ set_target_properties(sof_ns INSTALL_RPATH "${sof_install_directory}/alsa-lib" INSTALL_RPATH_USE_LINK_PATH TRUE ) + +# Regression test for the input-shape validation guard. Gated on +# OpenVINO_FOUND alongside the module itself, so a host without +# OpenVINO simply skips it. +add_executable(test_ns_shape_validation test_ns_shape_validation.cpp) +target_link_libraries(test_ns_shape_validation PRIVATE sof_ns_interface) +target_include_directories(test_ns_shape_validation PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${sof_source_directory}/src/include + ${sof_source_directory}/posix/include + ${sof_source_directory}/src/arch/host/include + ${sof_source_directory}/src/platform/posix/include) +set_target_properties(test_ns_shape_validation PROPERTIES LINKER_LANGUAGE CXX) + +add_test(NAME ns_shape_zero + COMMAND test_ns_shape_validation --dim 0 --dim 480) +add_test(NAME ns_shape_overflow + COMMAND test_ns_shape_validation --dim 9223372036854775807 --dim 1024) endif() diff --git a/tools/plugin/modules/ov_noise_suppression/noise_suppression_interface.cpp b/tools/plugin/modules/ov_noise_suppression/noise_suppression_interface.cpp index fa74736d062f..6e8356a7440e 100644 --- a/tools/plugin/modules/ov_noise_suppression/noise_suppression_interface.cpp +++ b/tools/plugin/modules/ov_noise_suppression/noise_suppression_interface.cpp @@ -12,6 +12,7 @@ #include "noise_suppression_interface.h" #define NS_MAX_SOURCE_CHANNELS 2 +#define NS_MAX_SHAPE_DIM (1u << 24) extern "C" { struct ns_data { @@ -85,6 +86,9 @@ extern "C" { nd->infer_request[i] = compiled_model.create_infer_request(); nd->inp_shape = nd->model->input("input").get_shape(); + for (auto dim : nd->inp_shape) + if (!dim || dim > NS_MAX_SHAPE_DIM) + return -EINVAL; return 0; } @@ -141,6 +145,9 @@ extern "C" { ov::Shape state_shape; state_shape = nd->model->input(inp_state_name).get_shape(); + for (auto dim : state_shape) + if (!dim || dim > NS_MAX_SHAPE_DIM) + return -EINVAL; if (nd->iter > 0) { /* * set input state by corresponding output state from prev diff --git a/tools/plugin/modules/ov_noise_suppression/test_ns_shape_validation.cpp b/tools/plugin/modules/ov_noise_suppression/test_ns_shape_validation.cpp new file mode 100644 index 000000000000..35a224581423 --- /dev/null +++ b/tools/plugin/modules/ov_noise_suppression/test_ns_shape_validation.cpp @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. All rights reserved. +// +// Author: Pally Mediratta <mediratta01.pally@gmail.com> + +#include <cstdio> +#include <cstdlib> +#include <fstream> +#include <string> +#include <vector> +#include <unistd.h> + +#include "noise_suppression_interface.h" + +static void usage(const char *prog) +{ + std::printf( +"Usage: %s [--model PATH | --dim N [--dim N ...]] [--expect ok|reject]\n" +"\n" +"Regression test for the OpenVINO noise-suppression plugin's input-shape\n" +"validation (commit \"tools: plugin: ov_noise_suppression: validate model\n" +"input shape dimensions\"). Invokes ov_ns_init() against either:\n" +"\n" +" --model PATH a caller-supplied OpenVINO model XML file, or\n" +" --dim N [--dim N ...] a minimal synthesized model XML built from the\n" +" given input port dimensions and written to a\n" +" temporary file.\n" +"\n" +" --expect ok|reject expected outcome (default: reject).\n" +" \"ok\": ov_ns_init() must return 0.\n" +" \"reject\": ov_ns_init() must return non-zero.\n" +"\n" +"Returns 0 on PASS, 1 on FAIL, 2 on usage error.\n" +"\n" +"Examples:\n" +" %s --dim 0 --dim 480 # zero dim, expect reject\n" +" %s --dim 9223372036854775807 --dim 1024 # overflow, expect reject\n" +" %s --model real_model.xml --expect ok # real model, expect accept\n", + prog, prog, prog, prog); +} + +static int write_mock_model(const std::string &path, + const std::vector<long long> &dims) +{ + std::ofstream f(path); + if (!f) + return -1; + + f << "<?xml version=\"1.0\"?><net><layers>" + "<layer id=\"0\" name=\"input\" type=\"Parameter\">" + "<output><port id=\"0\" precision=\"FP32\">"; + for (auto d : dims) + f << "<dim>" << d << "</dim>"; + f << "</port></output></layer></layers></net>"; + return f ? 0 : -1; +} + +int main(int argc, char **argv) +{ + std::string model_path; + std::vector<long long> dims; + bool expect_reject = true; + + for (int i = 1; i < argc; i++) { + std::string a = argv[i]; + if (a == "-h" || a == "--help") { + usage(argv[0]); + return 0; + } + if (a == "--model" && i + 1 < argc) { + model_path = argv[++i]; + } else if (a == "--dim" && i + 1 < argc) { + dims.push_back(std::strtoll(argv[++i], nullptr, 0)); + } else if (a == "--expect" && i + 1 < argc) { + std::string v = argv[++i]; + if (v == "ok") { + expect_reject = false; + } else if (v == "reject") { + expect_reject = true; + } else { + std::fprintf(stderr, + "unknown --expect value: %s\n", + v.c_str()); + usage(argv[0]); + return 2; + } + } else { + std::fprintf(stderr, "unknown or incomplete arg: %s\n", + a.c_str()); + usage(argv[0]); + return 2; + } + } + + std::string scratch; + if (model_path.empty()) { + if (dims.empty()) { + std::fprintf(stderr, + "must supply --model PATH or one or more --dim N\n"); + usage(argv[0]); + return 2; + } + + char tmpl[] = "/tmp/ns_shape_test_XXXXXX.xml"; + int fd = mkstemps(tmpl, 4); + if (fd < 0) { + std::perror("mkstemps"); + return 2; + } + close(fd); + scratch = tmpl; + if (write_mock_model(scratch, dims) != 0) { + std::fprintf(stderr, "failed to write mock model %s\n", + scratch.c_str()); + std::remove(scratch.c_str()); + return 2; + } + model_path = scratch; + } + + struct noise_suppression_data *nd = + (struct noise_suppression_data *)std::calloc(1, sizeof(*nd)); + if (!nd) { + std::perror("calloc"); + if (!scratch.empty()) + std::remove(scratch.c_str()); + return 2; + } + + int ret = ov_ns_init(nd, model_path.c_str()); + + if (!scratch.empty()) + std::remove(scratch.c_str()); + + bool rejected = (ret != 0); + bool pass = (rejected == expect_reject); + + std::printf("%s: ov_ns_init() returned %d (%s), expected %s\n", + pass ? "PASS" : "FAIL", + ret, + rejected ? "rejected" : "accepted", + expect_reject ? "reject" : "ok"); + + ov_ns_free(nd); + std::free(nd); + + return pass ? 0 : 1; +} diff --git a/tools/plugin/modules/shm.c b/tools/plugin/modules/shm.c index 63f9e002e0d2..0ddf297adcd1 100644 --- a/tools/plugin/modules/shm.c +++ b/tools/plugin/modules/shm.c @@ -113,7 +113,7 @@ static struct comp_dev *shm_new(const struct comp_driver *drv, dev->ipc_config = *config; /* allocate memory for shm comp data */ - cd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); if (!cd) goto error; diff --git a/tools/plugin/pipe/CMakeLists.txt b/tools/plugin/pipe/CMakeLists.txt index 80114d0f6d2f..244fb3199e38 100644 --- a/tools/plugin/pipe/CMakeLists.txt +++ b/tools/plugin/pipe/CMakeLists.txt @@ -15,7 +15,7 @@ target_include_directories(sof-pipe PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${sof_source_directory}/src/audio) -target_compile_options(sof-pipe PRIVATE -DPIC -g -O3 -Wall -Werror -DCONFIG_LIBRARY -imacros${config_h}) +target_compile_options(sof-pipe PRIVATE -DPIC -g -O3 -Wall -Werror -Wno-stringop-truncation -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) diff --git a/tools/plugin/pipe/ipc4.c b/tools/plugin/pipe/ipc4.c index 632c161015b4..90157971d05e 100644 --- a/tools/plugin/pipe/ipc4.c +++ b/tools/plugin/pipe/ipc4.c @@ -14,12 +14,12 @@ #include <sys/poll.h> #include <string.h> #include <sys/types.h> +#include <sys/socket.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/stat.h> #include <signal.h> -#include <mqueue.h> #include <fcntl.h> #include <sys/mman.h> #include <semaphore.h> @@ -311,58 +311,36 @@ int pipe_ipc_do(struct sof_pipe *sp, void *mailbox, size_t bytes) return err; } -int pipe_ipc_process(struct sof_pipe *sp, struct plug_mq_desc *tx_mq, struct plug_mq_desc *rx_mq) +static void *handle_ipc_client(void *data) { - ssize_t ipc_size; + struct sof_pipe *sp = data; + struct plug_socket_desc *ipc_socket = &sp->ipc_socket; + struct timespec ts; + int client_id = sp->new_client_id; + int clientfd = sp->client_sock_ids[client_id]; char mailbox[IPC3_MAX_MSG_SIZE] = {0}; + ssize_t ipc_size; 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); + ipc_size = recv(clientfd, mailbox, IPC3_MAX_MSG_SIZE, 0); + if (ipc_size < 0) { + fprintf(sp->log, "error: can't read IPC socket %s : %s\n", + ipc_socket->path, strerror(errno)); 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)); + /* connection lost */ + if (ipc_size == 0) { + close(clientfd); 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); + fprintf(sp->log, "sof-pipe: IPC %s garbage read\n", ipc_socket->path); ts.tv_sec = 0; ts.tv_nsec = 20 * 1000 * 1000; /* 20 ms */ nanosleep(&ts, NULL); @@ -371,77 +349,78 @@ int pipe_ipc_process(struct sof_pipe *sp, struct plug_mq_desc *tx_mq, struct plu /* 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); + err = send(clientfd, 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)); + close(clientfd); break; } } - fprintf(sp->log, "***sof-pipe: IPC %s thread finished !!\n", tx_mq->queue_name); - return 0; + close(clientfd); + sp->client_sock_ids[client_id] = 0; + return NULL; } -int plug_mq_cmd(struct plug_mq_desc *ipc, void *msg, size_t len, void *reply, size_t rlen) +int pipe_ipc_process(struct sof_pipe *sp, struct plug_socket_desc *ipc_socket) { - struct timespec ts; - ssize_t ipc_size; - char mailbox[IPC3_MAX_MSG_SIZE]; + pthread_t thread_id; 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); + /* 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"); - /* 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)); + /* create the IPC socket */ + err = plug_socket_create(ipc_socket); + if (err < 0) { + fprintf(sp->log, "error: can't create TX IPC socket : %s\n", + strerror(errno)); return -errno; } - /* IPCs should be read under 10ms */ - plug_timespec_add_ms(&ts, 10); + /* let main() know we are ready */ + fprintf(sp->log, "sof-pipe: IPC %s socket ready\n", ipc_socket->path); - /* 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; - } + /* main PCM IPC handling loop */ + while (1) { + int clientfd, i; - /* 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; - } + /* Accept a connection from a client */ + clientfd = accept(ipc_socket->socket_fd, NULL, NULL); + if (clientfd == -1) { + fprintf(sp->log, "IPC %s socket accept failed\n", ipc_socket->path); + return -errno; + } - /* IPCs should be processed under 20ms */ - plug_timespec_add_ms(&ts, 20); + for (i = 0; i < MAX_IPC_CLIENTS; i++) { + if (!sp->client_sock_ids[i]) { + sp->client_sock_ids[i] = clientfd; + sp->new_client_id = i; + break; + } + } - 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; + /* create a new thread for each new IPC client */ + if (pthread_create(&thread_id, NULL, handle_ipc_client, sp) != 0) { + fprintf(sp->log, "Client IPC thread creation failed"); + close(clientfd); + sp->client_sock_ids[i] = 0; + continue; + } + + fprintf(sp->log, "Client IPC thread created client id %d\n", clientfd); + /* Detach the thread */ + pthread_detach(thread_id); } - /* do the message work */ - //printf("cmd got IPC %ld reply bytes\n", ipc_size); - if (rlen && reply) - memcpy(reply, mailbox, rlen); + close(ipc_socket->socket_fd); + fprintf(sp->log, "***sof-pipe: IPC %s thread finished !!\n", ipc_socket->path); return 0; } diff --git a/tools/plugin/pipe/main.c b/tools/plugin/pipe/main.c index 3d9c831dba0b..68861fc0af2a 100644 --- a/tools/plugin/pipe/main.c +++ b/tools/plugin/pipe/main.c @@ -19,7 +19,6 @@ #include <sys/wait.h> #include <sys/stat.h> #include <signal.h> -#include <mqueue.h> #include <fcntl.h> #include <sys/mman.h> #include <semaphore.h> @@ -53,15 +52,12 @@ static void shutdown(struct sof_pipe *sp) 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); + plug_socket_free(&sp->ipc_socket); pthread_mutex_destroy(&sp->ipc_lock); @@ -211,37 +207,13 @@ void plug_shm_free(struct plug_shm_desc *shm) 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) +void plug_socket_free(struct plug_socket_desc *ipc) { - mq_close(ipc->mq); - mq_unlink(ipc->queue_name); + unlink(ipc->path); } /* @@ -359,16 +331,12 @@ int main(int argc, char *argv[], char *env[]) /* 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); + ret = plug_socket_path_init(&sp.ipc_socket, "sof", "ipc", 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); + ret = pipe_ipc_process(&sp, &sp.ipc_socket); out: fprintf(sp.log, "shutdown main\n"); diff --git a/tools/plugin/pipe/pipe.h b/tools/plugin/pipe/pipe.h index 3cc95bf8401e..8f8fb26080ea 100644 --- a/tools/plugin/pipe/pipe.h +++ b/tools/plugin/pipe/pipe.h @@ -10,7 +10,6 @@ #include <stdatomic.h> #include <stdint.h> -#include <mqueue.h> #include <pthread.h> #include <signal.h> @@ -29,8 +28,6 @@ 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; @@ -72,8 +69,10 @@ struct sof_pipe { /* 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 */ + struct plug_socket_desc ipc_socket; /* queue used by plugin to send IPCs */ + int client_sock_ids[MAX_IPC_CLIENTS]; + int client_count; + int new_client_id; /* module SO handles */ struct sof_pipe_module module[MAX_MODULE_ID]; @@ -100,7 +99,7 @@ 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_process(struct sof_pipe *sp, struct plug_socket_desc *ipc_socket); int pipe_ipc_new(struct sof_pipe *sp, int pri, int core); void pipe_ipc_free(struct sof_pipe *sp); diff --git a/tools/plugin/pipe/pipeline.c b/tools/plugin/pipe/pipeline.c index 831b60a3b6a9..2985e46d04ad 100644 --- a/tools/plugin/pipe/pipeline.c +++ b/tools/plugin/pipe/pipeline.c @@ -17,7 +17,6 @@ #include <sys/wait.h> #include <sys/stat.h> #include <signal.h> -#include <mqueue.h> #include <fcntl.h> #include <sys/mman.h> #include <semaphore.h> @@ -181,12 +180,6 @@ static void *pipe_ipc_process_thread(void *arg) 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; } @@ -297,18 +290,6 @@ int pipe_thread_new(struct sof_pipe *sp, struct pipeline *p) 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) @@ -367,11 +348,6 @@ int pipe_thread_free(struct sof_pipe *sp, int pipeline_id) 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); diff --git a/tools/probes/probes_demux.c b/tools/probes/probes_demux.c index a411eef117b9..b92aaf88a19b 100644 --- a/tools/probes/probes_demux.c +++ b/tools/probes/probes_demux.c @@ -23,6 +23,7 @@ #define APP_NAME "sof-probes" #define PACKET_MAX_SIZE 4096 /**< Size limit for probe data packet */ +#define PACKET_DATA_SIZE_MAX (16u * 1024u * 1024u) /**< Sanity limit for packet data size */ #define DATA_READ_LIMIT 4096 /**< Data limit for file read */ #define FILES_LIMIT 32 /**< Maximum num of probe output files */ #define FILE_PATH_LIMIT 128 /**< Path limit for probe output files */ @@ -125,7 +126,17 @@ int init_wave(struct dma_frame_parser *p, uint32_t buffer_id, uint32_t format) p->files[i].header.fmt.subchunk_size = 16; p->files[i].header.fmt.audio_format = 1; p->files[i].header.fmt.num_channels = ((format & PROBE_MASK_NB_CHANNELS) >> PROBE_SHIFT_NB_CHANNELS) + 1; - p->files[i].header.fmt.sample_rate = sample_rate[(format & PROBE_MASK_SAMPLE_RATE) >> PROBE_SHIFT_SAMPLE_RATE]; + /* the sample-rate field is 4 bits (0-15) but the table has fewer + * entries; fall back to a valid default (48000 Hz) for an out-of-range + * index so the read stays in bounds and the WAV header keeps a usable + * rate + */ + uint32_t rate_idx = (format & PROBE_MASK_SAMPLE_RATE) >> PROBE_SHIFT_SAMPLE_RATE; + + if (rate_idx >= sizeof(sample_rate) / sizeof(sample_rate[0])) + p->files[i].header.fmt.sample_rate = 48000; + else + p->files[i].header.fmt.sample_rate = sample_rate[rate_idx]; p->files[i].header.fmt.bits_per_sample = (((format & PROBE_MASK_CONTAINER_SIZE) >> PROBE_SHIFT_CONTAINER_SIZE) + 1) * 8; p->files[i].header.fmt.byte_rate = p->files[i].header.fmt.sample_rate * p->files[i].header.fmt.num_channels * @@ -194,6 +205,12 @@ int process_sync(struct dma_frame_parser *p) { struct probe_data_packet *temp_packet; + if (p->packet->data_size_bytes > PACKET_DATA_SIZE_MAX) { + fprintf(stderr, "error: packet data size %u exceeds maximum %u\n", + p->packet->data_size_bytes, PACKET_DATA_SIZE_MAX); + return -EINVAL; + } + /* request to copy data_size from probe packet and 64-bit checksum */ p->total_data_to_copy = p->packet->data_size_bytes + sizeof(uint64_t); diff --git a/tools/rimage/.checkpatch.conf b/tools/rimage/.checkpatch.conf deleted file mode 100644 index 98ddafcb3fb1..000000000000 --- a/tools/rimage/.checkpatch.conf +++ /dev/null @@ -1,6 +0,0 @@ ---codespell ---codespellfile scripts/spelling.txt ---ignore C99_COMMENT_TOLERANCE ---no-tree ---strict --g diff --git a/tools/rimage/README.md b/tools/rimage/README.md index 9f32fffa5cb1..797bb662f6d6 100644 --- a/tools/rimage/README.md +++ b/tools/rimage/README.md @@ -1,15 +1,10 @@ # 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. +`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. +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: @@ -19,87 +14,109 @@ $ 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. +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 tomlc99 changes with SOF Continuous Integration -This section is about leveraging SOF validation to test tomlc99 changes -_before_ submitting them to the tomlc99 repository. +This section is about leveraging SOF validation to test tomlc99 changes _before_ submitting them to the tomlc99 repository. -Nothing here is actually specific to SOF and tomlc99; 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. +Nothing here is actually specific to SOF and tomlc99; 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 tomlc99. -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 tomlc99 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 + tomlc99 is a great idea. +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 tomlc99 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 + tomlc99 is a great idea. -Obviously, you also need to be familiar with regular Github pull -requests. +Obviously, you also need to be familiar with regular GitHub pull requests. ### Run SOF tests on unmerged tomlc99 commits -First, push the tomlc99 commits you want to be tested to any branch of -your tomlc99 fork on Github. Do _not_ submit an tomlc99 pull request yet. - -Note your tomlc99 fork must have been created using the actual "fork" -button on Github so Github is aware of the connection with the upstream -tomlc99 repo. In the top-left corner you should see `forked from -thesofproject/tomlc99` under the name of your fork. If not then search -the Internet for "re-attach detached github fork". - -Then, **pretend** these tomlc99 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 tomlc99 commits to -test. The only SOF commit in this SOF TEST pull request is an SOF commit -that updates the tomlc99 pointer to the SHA of your last tomlc99 -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 tomlc99 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 tomlc99 commits has been checked out. - -Iterate and force-push your tomlc99 branch and your SOF TEST pull request -until all the SOF tests pass. Then you can submit your tomlc99 pull -request as usual. In the comments section of the tomlc99 pull request, -point at your test results on the SOF side to impress the tomlc99 -reviewers and get your tomlc99 changes merged faster. - -Finally, after your tomlc99 changes have been merged, you can if you want -submit one final SOF pull request that points to the final tomlc99 -SHA. Or, if your tomlc99 change is not urgently needed, you can just wait -for someone else to do it later. If you do it, copy the tomlc99 git log ---oneline in the SOF commit message. Find some good (and less good) -commit message examples for submodule updates at -https://github.com/thesofproject/sof/commits/main/rimage +First, push the tomlc99 commits you want to be tested to any branch of your tomlc99 fork on GitHub. Do _not_ submit a tomlc99 pull request yet. + +Note your tomlc99 fork must have been created using the actual "fork" button on GitHub so GitHub is aware of the connection with the upstream tomlc99 repo. In the top-left corner you should see `forked from thesofproject/tomlc99` under the name of your fork. If not then search the Internet for "re-attach detached github fork". + +Then, **pretend** these tomlc99 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 tomlc99 commits to test. The only SOF commit in this SOF TEST pull request is an SOF commit that updates the tomlc99 pointer to the SHA of your last tomlc99 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 tomlc99 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 tomlc99 commits has been checked out. + +Iterate and force-push your tomlc99 branch and your SOF TEST pull request until all the SOF tests pass. Then you can submit your tomlc99 pull request as usual. In the comments section of the tomlc99 pull request, point at your test results on the SOF side to impress the tomlc99 reviewers and get your tomlc99 changes merged faster. + +Finally, after your tomlc99 changes have been merged, you can if you want submit one final SOF pull request that points to the final tomlc99 SHA. Or, if your tomlc99 change is not urgently needed, you can just wait for someone else to do it later. If you do it, copy the tomlc99 git log --oneline in the SOF commit message. Find some good (and less good) commit message examples for submodule updates at https://github.com/thesofproject/sof/commits/main/rimage + +## Deep Dive: ELF to Image Conversion and Manifest Structure + +`rimage` is responsible for converting standard ELF libraries and executables into DSP-compatible firmware images. It parses input ELF files, extracts loadable sections, calculates cryptographic hashes and signatures, and encapsulates them with platform-specific manifests. + +### The Build Process (ELF to Image) + +```mermaid +graph TD + A[Command Line Args] --> B[Initialize ADSP Config] + C[Input ELF Files] --> D[Parse ELF Headers & Sections] + D --> E[Register Modules & Metadata] + B --> F[Allocate Manifest Memory] + E --> F + F --> G["Copy .text, .rodata to Image Buffer"] + G --> H["Hash Module Segments (SHA-256 / SHA-384)"] + H --> I["Finalize Manifest Headers (CSS/CSE/FW Desc)"] + I --> J[Sign Root Manifest with RSA Key] + J --> K[Write Output Files] + K --> L[.ri Signed Image] + K --> M[.uns Unsigned Module] + K --> N[.met Manifest Metadata] +``` + +1. **Configuration Initialization**: `rimage` parses its command-line arguments to find the ADSP machine configuration (e.g., Apollolake `apl`, Tigerlake `tgl`, Meteorlake `mtl`). This configuration defines the specific sizes, offsets, and versions the firmware image will require. +2. **Parsing ELF Files**: The `module_open()` and `module_parse_sections()` functions read the ELF headers (`.text`, `.rodata`, `.bss`). These sections are extracted to form the payload of the modules. +3. **Module Registration**: `rimage` reads either the `.module` metadata section directly from the embedded ELF, or a corresponding `TOML` configuration file, which holds instructions on module attributes (e.g., UUID, thread affinity, entry points). +4. **Manifest and Memory Allocation**: Space is pre-allocated for the firmware image. `man_init_image_xxx()` loads the ADSP template manifest into the start of the image buffer. Then, `man_copy_elf_sections()` copies `.text` and `.rodata` sections directly into the buffer, aligning properties sequentially up to `MAN_PAGE_SIZE` (4096 bytes). +5. **Cryptographic Hashing**: Using `hash_sha256()` or `hash_sha384()` (depending on the platform), `rimage` generates a cryptographic digest of each module's `.text` and `.rodata` block. These hash digests are stored in the respective `sof_man_module` entries of the manifest. +6. **Manifest Signing**: Once all modules and internal structures are mapped, the entire structure is finalized with converged security headers (`ri_css_xxx_hdr_create`, `ri_cse_create`). The root manifest signature is then signed (`ri_manifest_sign_...()`) with an RSA private key. +7. **Writing the Payload**: Finally, the newly encapsulated firmware is written to a `.ri` file (`man_write_fw_mod()`). `rimage` also outputs a stripped `.uns` (unsigned module payload) and `.met` (manifest metadata) file for debugging. + +### Manifest Structure + +```mermaid +graph TD + A[FW Image Manifest] + A --> B[1. CSS Header] + A --> C[2. CSE Header] + A --> D[3. Firmware Descriptor] + A --> E[4. Module Entries Array] + A --> F[5. ADSP Extension Metadata] + + B --> B1("RSA Signatures") + B --> B2("Public Key & Modulus") + + C --> C1("Security Partitions Directory") + + D --> D1("Versions & Build IDs") + D --> D2("num_module_entries") + + E --> E1[Module 0] + E --> E2[Module N] + E1 --> E1a("UUID, Entry Point") + E1 --> E1b("Segment Relative Offsets") + E1 --> E1c("SHA Hash of Sub-Segments") + + F --> F1("Proprietary Components") + F --> F2("Hardware Specific Hashes") +``` + +The firmware image begins with a structured Manifest. Different platforms use altered sizes and variants (e.g., v1.5, v1.8, v2.5, ace_v1.5), but they typically follow the same overarching hierarchy (note: ordering of CSS and CSE headers may be swapped depending on the manifest version - e.g., v1.8+/v2.5 places CSE first): + +1. **CSS Header** (CSS header struct, e.g. `struct css_header_v1_8`, `struct css_header_v2_5`): Cryptographic Signature Structure. Defines the fundamental size, modulus, public key, and RSA signatures used to authenticate the firmware image on the CSME/DSP side. +2. **CSE Header** (CSE partition directory header struct, e.g. `struct CsePartitionDirHeader`, `struct CsePartitionDirHeader_v2_5`): Converged Security Engine Header. A directory mapping security partitions to the ADSP firmware metadata. +3. **Firmware Descriptor** (`struct sof_man_fw_desc` and versioned variants): + - `header`: Holds the basic firmware versions, build IDs, `preload_page_count`, and the `num_module_entries`. +4. **Module Entries** (`struct sof_man_module`): An array corresponding to each module contained in the image. + - `struct_id`: Has the literal value `"$AME"`. + - `name`, `uuid`, `entry_point`, `affinity`. + - `segment`: Details on the relative position `file_offset` and memory offset `v_base_addr` of `.text`, `.rodata`, and `.bss` partitions. + - `hash`: SHA-256 or SHA-384 digest of the active segment. +5. **ADSP Extension Metadata** (e.g., `sof_man_adsp_meta_file_ext_v2_5`): Additional proprietary component descriptors attached after the base manifest, frequently hashed recursively for verification integrity. diff --git a/tools/rimage/config/acp_7_0.toml b/tools/rimage/config/acp_7_0.toml index 40e9236e26bb..916bcb24f047 100644 --- a/tools/rimage/config/acp_7_0.toml +++ b/tools/rimage/config/acp_7_0.toml @@ -16,5 +16,5 @@ host_offset = "0x0" [[adsp.mem_zone]] type = "SRAM" base = "0x6000C000" -size = "0x27A000" +size = "0x274000" host_offset = "0x0" \ No newline at end of file diff --git a/tools/rimage/config/acp_7_x.toml b/tools/rimage/config/acp_7_x.toml new file mode 100644 index 000000000000..7787bb3c6e1c --- /dev/null +++ b/tools/rimage/config/acp_7_x.toml @@ -0,0 +1,20 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "acp_7_x" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x7F000000" +size = "0x20000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "DRAM" +base = "0xE0000000" +size = "0x20000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "SRAM" +base = "0x6000C000" +size = "0x274000" +host_offset = "0x0" \ No newline at end of file diff --git a/tools/rimage/config/imx8m_cm7.toml b/tools/rimage/config/imx8m_cm7.toml new file mode 100644 index 000000000000..2ba4fb5d16f6 --- /dev/null +++ b/tools/rimage/config/imx8m_cm7.toml @@ -0,0 +1,15 @@ +version = [1, 0] + +[adsp] +name = "imx8m_cm7" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x0000000" +size = "0x2000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "SRAM" +base = "0x80000000" +size = "0x100000" +host_offset = "0x0" diff --git a/tools/rimage/config/imx95.toml b/tools/rimage/config/imx95.toml index 69e6811be3bc..2aa395b53956 100644 --- a/tools/rimage/config/imx95.toml +++ b/tools/rimage/config/imx95.toml @@ -4,6 +4,6 @@ version = [1, 0] name = "imx95" [[adsp.mem_zone]] -type = "DRAM" +type = "SRAM" base = "0x80000000" size = "0x100000" diff --git a/tools/rimage/config/lnl.toml.h b/tools/rimage/config/lnl.toml.h index 7cb581fc357a..faefbb8acadb 100644 --- a/tools/rimage/config/lnl.toml.h +++ b/tools/rimage/config/lnl.toml.h @@ -2,7 +2,7 @@ [[module.entry]] name = "BRNGUP" - uuid = "2B79E4F3-4675-F649-89DF-3BC194A91AEB" + uuid = UUIDREG_STR_BRNGUP affinity_mask = "0x1" instance_count = "1" domain_types = "0" @@ -15,7 +15,7 @@ #if CONFIG_COLD_STORE_EXECUTE_DRAM [[module.entry]] name = "COLD" - uuid = "D406D134-C3C1-402C-8AEC-6821C0C2B0E6" + uuid = UUIDREG_STR_COLD affinity_mask = "3" instance_count = "1" domain_types = "0" @@ -28,7 +28,7 @@ [[module.entry]] name = "BASEFW" - uuid = "0E398C32-5ADE-BA4B-93B1-C50432280EE4" + uuid = UUIDREG_STR_BASEFW affinity_mask = "3" instance_count = "1" domain_types = "0" @@ -38,6 +38,10 @@ index = __COUNTER__ +#if defined(CONFIG_COMP_TESTER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <debug/tester/tester.toml> +#endif + #if defined(CONFIG_COMP_MIXIN_MIXOUT) || defined(LLEXT_FORCE_ALL_MODULAR) #include <audio/mixin_mixout/mixin_mixout.toml> #endif @@ -58,6 +62,10 @@ #include <audio/src/src.toml> #endif +#if defined(CONFIG_CADENCE_CODEC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/module_adapter/module/cadence.toml> +#endif + #if defined(CONFIG_COMP_SEL) || defined(LLEXT_FORCE_ALL_MODULAR) #include <audio/selector/selector.toml> #endif @@ -134,5 +142,29 @@ #include <audio/mfcc/mfcc.toml> #endif +#if defined(CONFIG_COMP_TEMPLATE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/template/template.toml> +#endif + +#if defined(CONFIG_COMP_LEVEL_MULTIPLIER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/level_multiplier/level_multiplier.toml> +#endif + +#if defined(CONFIG_COMP_SOUND_DOSE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/sound_dose/sound_dose.toml> +#endif + +#if defined(CONFIG_COMP_TONE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/tone/tone.toml> +#endif + +#if defined(CONFIG_COMP_STFT_PROCESS) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/stft_process/stft_process.toml> +#endif + +#if defined(CONFIG_COMP_PHASE_VOCODER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/phase_vocoder/phase_vocoder.toml> +#endif + [module] count = __COUNTER__ diff --git a/tools/rimage/config/mt8365.toml b/tools/rimage/config/mt8365.toml new file mode 100644 index 000000000000..1cec40f48ca5 --- /dev/null +++ b/tools/rimage/config/mt8365.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "mt8365" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x40020000" +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.h b/tools/rimage/config/mtl.toml.h index eb61190b96fc..62672713dbae 100644 --- a/tools/rimage/config/mtl.toml.h +++ b/tools/rimage/config/mtl.toml.h @@ -2,7 +2,7 @@ [[module.entry]] name = "BRNGUP" - uuid = "2B79E4F3-4675-F649-89DF-3BC194A91AEB" + uuid = UUIDREG_STR_BRNGUP affinity_mask = "0x1" instance_count = "1" domain_types = "0" @@ -15,7 +15,7 @@ #if CONFIG_COLD_STORE_EXECUTE_DRAM [[module.entry]] name = "COLD" - uuid = "D406D134-C3C1-402C-8AEC-6821C0C2B0E6" + uuid = UUIDREG_STR_COLD affinity_mask = "3" instance_count = "1" domain_types = "0" @@ -28,7 +28,7 @@ [[module.entry]] name = "BASEFW" - uuid = "0E398C32-5ADE-BA4B-93B1-C50432280EE4" + uuid = UUIDREG_STR_BASEFW affinity_mask = "3" instance_count = "1" domain_types = "0" @@ -38,6 +38,10 @@ index = __COUNTER__ +#if defined(CONFIG_COMP_TESTER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <debug/tester/tester.toml> +#endif + #if defined(CONFIG_COMP_MIXIN_MIXOUT) || defined(LLEXT_FORCE_ALL_MODULAR) #include <audio/mixin_mixout/mixin_mixout.toml> #endif @@ -74,6 +78,10 @@ #include <audio/mux/mux.toml> #endif +#if defined(CONFIG_CADENCE_CODEC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/module_adapter/module/cadence.toml> +#endif + #ifdef CONFIG_SAMPLE_KEYPHRASE #include <samples/audio/detect_test.toml> #endif @@ -114,6 +122,10 @@ #include <audio/dcblock/dcblock.toml> #endif +#if defined(CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/module_adapter/module/dolby/dax.toml> +#endif + #if defined(CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING) || defined(LLEXT_FORCE_ALL_MODULAR) #include <audio/google/google_rtc_audio_processing.toml> #endif @@ -130,8 +142,8 @@ #include <audio/codec/dts/dts.toml> #endif -#ifdef CONFIG_CADENCE_CODEC -#include <audio/module_adapter/module/cadence.toml> +#if defined(CONFIG_WAVES_CODEC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/module_adapter/module/waves/waves.toml> #endif #if defined(CONFIG_COMP_RTNR) || defined(LLEXT_FORCE_ALL_MODULAR) @@ -146,5 +158,33 @@ #include <audio/mfcc/mfcc.toml> #endif +#if defined(CONFIG_COMP_TEMPLATE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/template/template.toml> +#endif + +#if defined(CONFIG_COMP_TENSORFLOW) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/tensorflow/tflmcly.toml> +#endif + +#if defined(CONFIG_COMP_LEVEL_MULTIPLIER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/level_multiplier/level_multiplier.toml> +#endif + +#if defined(CONFIG_COMP_SOUND_DOSE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/sound_dose/sound_dose.toml> +#endif + +#if defined(CONFIG_COMP_TONE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/tone/tone.toml> +#endif + +#if defined(CONFIG_COMP_STFT_PROCESS) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/stft_process/stft_process.toml> +#endif + +#if defined(CONFIG_COMP_PHASE_VOCODER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/phase_vocoder/phase_vocoder.toml> +#endif + [module] count = __COUNTER__ diff --git a/tools/rimage/config/nvl.toml.h b/tools/rimage/config/nvl.toml.h new file mode 100644 index 000000000000..cb12069f671f --- /dev/null +++ b/tools/rimage/config/nvl.toml.h @@ -0,0 +1,162 @@ +#include "platform-nvl.toml" + +[[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" + +index = __COUNTER__ + +#if CONFIG_COLD_STORE_EXECUTE_DRAM +[[module.entry]] +name = "COLD" +uuid = UUIDREG_STR_COLD +affinity_mask = "3" +instance_count = "1" +domain_types = "0" +load_type = "0" +module_type = "0" +auto_start = "0" + +index = __COUNTER__ +#endif + +[[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" + +index = __COUNTER__ + +#if defined(CONFIG_COMP_TESTER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <debug/tester/tester.toml> +#endif + +#if defined(CONFIG_COMP_MIXIN_MIXOUT) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/mixin_mixout/mixin_mixout.toml> +#endif + +#if defined(CONFIG_COMP_COPIER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/copier/copier.toml> +#endif + +#if defined(CONFIG_COMP_VOLUME) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/volume/volume.toml> +#endif + +#if defined(CONFIG_COMP_ASRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/asrc/asrc.toml> +#endif + +#if defined(CONFIG_COMP_SRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/src/src.toml> +#endif + +#if defined(CONFIG_CADENCE_CODEC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/module_adapter/module/cadence.toml> +#endif + +#if defined(CONFIG_COMP_SEL) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/selector/selector.toml> +#endif + +#if defined(CONFIG_COMP_UP_DOWN_MIXER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/up_down_mixer/up_down_mixer.toml> +#endif + +#ifdef CONFIG_PROBE +#include <probe/probe.toml> +#endif + +#if defined(CONFIG_COMP_MUX) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/mux/mux.toml> +#endif + +#ifdef CONFIG_SAMPLE_KEYPHRASE +#include <samples/audio/detect_test.toml> +#endif + +#if defined(CONFIG_COMP_KPB) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/kpb.toml> +#endif + +#if defined(CONFIG_SAMPLE_SMART_AMP) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <samples/audio/smart_amp_test.toml> +#endif + +#if defined(CONFIG_COMP_IIR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/eq_iir/eq_iir.toml> +#endif + +#if defined(CONFIG_COMP_FIR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/eq_fir/eq_fir.toml> +#endif + +#if defined(CONFIG_COMP_ARIA) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/aria/aria.toml> +#endif + +#if defined(CONFIG_COMP_DRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/drc/drc.toml> +#endif + +#if defined(CONFIG_COMP_CROSSOVER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/crossover/crossover.toml> +#endif + +#if defined(CONFIG_COMP_MULTIBAND_DRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/multiband_drc/multiband_drc.toml> +#endif + +#if defined(CONFIG_COMP_DCBLOCK) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/dcblock/dcblock.toml> +#endif + +#if defined(CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/google/google_rtc_audio_processing.toml> +#endif + +#if defined(CONFIG_COMP_TDFB) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/tdfb/tdfb.toml> +#endif + +#if defined(CONFIG_COMP_RTNR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/rtnr/rtnr.toml> +#endif + +#if defined(CONFIG_COMP_IGO_NR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/igo_nr/igo_nr.toml> +#endif + +#if defined(CONFIG_COMP_MFCC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/mfcc/mfcc.toml> +#endif + +#if defined(CONFIG_COMP_SOUND_DOSE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/sound_dose/sound_dose.toml> +#endif + +#if defined(CONFIG_COMP_TONE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/tone/tone.toml> +#endif + +#if defined(CONFIG_COMP_STFT_PROCESS) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/stft_process/stft_process.toml> +#endif + +#if defined(CONFIG_COMP_PHASE_VOCODER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/phase_vocoder/phase_vocoder.toml> +#endif + +[module] +count = __COUNTER__ diff --git a/tools/rimage/config/platform-nvl.toml b/tools/rimage/config/platform-nvl.toml new file mode 100644 index 000000000000..89e3ce083ed2 --- /dev/null +++ b/tools/rimage/config/platform-nvl.toml @@ -0,0 +1,56 @@ +version = [3, 0] + +[adsp] +name = "nvl" +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" +[[signed_pkg.module]] +name = "ADSP.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x40000" diff --git a/tools/rimage/config/platform-tgl-h.toml b/tools/rimage/config/platform-tgl-h.toml new file mode 100644 index 000000000000..8e98866d9bcb --- /dev/null +++ b/tools/rimage/config/platform-tgl-h.toml @@ -0,0 +1,60 @@ +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" diff --git a/tools/rimage/config/platform-tgl.toml b/tools/rimage/config/platform-tgl.toml new file mode 100644 index 000000000000..ffbf15862ac4 --- /dev/null +++ b/tools/rimage/config/platform-tgl.toml @@ -0,0 +1,60 @@ +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" diff --git a/tools/rimage/config/platform.toml b/tools/rimage/config/platform.toml index 37c4d2a7b624..978323fa4ebc 100644 --- a/tools/rimage/config/platform.toml +++ b/tools/rimage/config/platform.toml @@ -2,4 +2,8 @@ #include "platform-mtl.toml" #elif CONFIG_LUNARLAKE #include "platform-lnl.toml" +#elif CONFIG_SOC_ACE30 +#include "platform-ptl.toml" +#elif CONFIG_SOC_ACE40 +#include "platform-nvl.toml" #endif diff --git a/tools/rimage/config/ptl.toml.h b/tools/rimage/config/ptl.toml.h index 38f6c2adf597..e7a53d1b1820 100644 --- a/tools/rimage/config/ptl.toml.h +++ b/tools/rimage/config/ptl.toml.h @@ -2,7 +2,7 @@ [[module.entry]] name = "BRNGUP" -uuid = "2B79E4F3-4675-F649-89DF-3BC194A91AEB" +uuid = UUIDREG_STR_BRNGUP affinity_mask = "0x1" instance_count = "1" domain_types = "0" @@ -15,7 +15,7 @@ index = __COUNTER__ #if CONFIG_COLD_STORE_EXECUTE_DRAM [[module.entry]] name = "COLD" -uuid = "D406D134-C3C1-402C-8AEC-6821C0C2B0E6" +uuid = UUIDREG_STR_COLD affinity_mask = "3" instance_count = "1" domain_types = "0" @@ -28,7 +28,7 @@ index = __COUNTER__ [[module.entry]] name = "BASEFW" -uuid = "0E398C32-5ADE-BA4B-93B1-C50432280EE4" +uuid = UUIDREG_STR_BASEFW affinity_mask = "3" instance_count = "1" domain_types = "0" @@ -38,6 +38,10 @@ auto_start = "0" index = __COUNTER__ +#if defined(CONFIG_COMP_TESTER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <debug/tester/tester.toml> +#endif + #if defined(CONFIG_COMP_MIXIN_MIXOUT) || defined(LLEXT_FORCE_ALL_MODULAR) #include <audio/mixin_mixout/mixin_mixout.toml> #endif @@ -58,6 +62,10 @@ index = __COUNTER__ #include <audio/src/src.toml> #endif +#if defined(CONFIG_CADENCE_CODEC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/module_adapter/module/cadence.toml> +#endif + #if defined(CONFIG_COMP_SEL) || defined(LLEXT_FORCE_ALL_MODULAR) #include <audio/selector/selector.toml> #endif @@ -98,6 +106,10 @@ index = __COUNTER__ #include <audio/aria/aria.toml> #endif +#if defined(CONFIG_COMP_DOLBY_DAX_AUDIO_PROCESSING) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/module_adapter/module/dolby/dax.toml> +#endif + #if defined(CONFIG_COMP_DRC) || defined(LLEXT_FORCE_ALL_MODULAR) #include <audio/drc/drc.toml> #endif @@ -118,10 +130,18 @@ index = __COUNTER__ #include <audio/google/google_rtc_audio_processing.toml> #endif +#if defined(CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/google/google_ctc_audio_processing.toml> +#endif + #if defined(CONFIG_COMP_TDFB) || defined(LLEXT_FORCE_ALL_MODULAR) #include <audio/tdfb/tdfb.toml> #endif +#if defined(CONFIG_DTS_CODEC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/codec/dts/dts.toml> +#endif + #if defined(CONFIG_COMP_RTNR) || defined(LLEXT_FORCE_ALL_MODULAR) #include <audio/rtnr/rtnr.toml> #endif @@ -134,5 +154,29 @@ index = __COUNTER__ #include <audio/mfcc/mfcc.toml> #endif +#if defined(CONFIG_COMP_TEMPLATE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/template/template.toml> +#endif + +#if defined(CONFIG_COMP_LEVEL_MULTIPLIER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/level_multiplier/level_multiplier.toml> +#endif + +#if defined(CONFIG_COMP_SOUND_DOSE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/sound_dose/sound_dose.toml> +#endif + +#if defined(CONFIG_COMP_TONE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/tone/tone.toml> +#endif + +#if defined(CONFIG_COMP_STFT_PROCESS) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/stft_process/stft_process.toml> +#endif + +#if defined(CONFIG_COMP_PHASE_VOCODER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/phase_vocoder/phase_vocoder.toml> +#endif + [module] count = __COUNTER__ diff --git a/tools/rimage/config/tgl-h.toml b/tools/rimage/config/tgl-h.toml deleted file mode 100644 index 6146fb89eef8..000000000000 --- a/tools/rimage/config/tgl-h.toml +++ /dev/null @@ -1,564 +0,0 @@ -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 = 25 - [[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" - init_config = "1" - 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] - - # RTNR module config - [[module.entry]] - name = "RTNR" - uuid = "5C7CA334-E15D-11EB-BA80-0242AC130004" - 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] - - # IGO_NR module config - [[module.entry]] - name = "IGO_NR" - uuid = "696AE2BC-2877-11EB-ADC1-0242AC120002" - 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] - - # MFCC module config - [[module.entry]] - name = "MFCC" - uuid = "DB10A773-1AA4-4CEA-A21F-2D57A5C982EB" - 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.h b/tools/rimage/config/tgl-h.toml.h new file mode 100644 index 000000000000..ea5dc5d4b262 --- /dev/null +++ b/tools/rimage/config/tgl-h.toml.h @@ -0,0 +1,136 @@ +#include "platform-tgl-h.toml" + + [[module.entry]] + name = "BRNGUP" + uuid = UUIDREG_STR_BRNGUP + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + index = __COUNTER__ + + [[module.entry]] + name = "BASEFW" + uuid = UUIDREG_STR_BASEFW + affinity_mask = "3" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + index = __COUNTER__ + +#if defined(CONFIG_COMP_MIXIN_MIXOUT) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/mixin_mixout/mixin_mixout.toml> +#endif + +#if defined(CONFIG_COMP_COPIER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/copier/copier.toml> +#endif + +#if defined(CONFIG_COMP_VOLUME) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/volume/volume.toml> +#endif + +#ifdef CONFIG_PROBE +#include <probe/probe.toml> +#endif + +#if defined(CONFIG_COMP_SRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/src/src.toml> +#endif + +#if defined(CONFIG_CADENCE_CODEC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/module_adapter/module/cadence.toml> +#endif + +#if defined(CONFIG_SAMPLE_SMART_AMP) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <samples/audio/smart_amp_test.toml> +#endif + +#if defined(CONFIG_COMP_IIR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/eq_iir/eq_iir.toml> +#endif + +#if defined(CONFIG_COMP_FIR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/eq_fir/eq_fir.toml> +#endif + +#ifdef CONFIG_SAMPLE_KEYPHRASE +#include <samples/audio/detect_test.toml> +#endif + +#if defined(CONFIG_COMP_KPB) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/kpb.toml> +#endif + +#if defined(CONFIG_COMP_SEL) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/selector/selector.toml> +#endif + +#if defined(CONFIG_COMP_ARIA) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/aria/aria.toml> +#endif + +#if defined(CONFIG_COMP_DRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/drc/drc.toml> +#endif + +#if defined(CONFIG_COMP_CROSSOVER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/crossover/crossover.toml> +#endif + +#if defined(CONFIG_COMP_MULTIBAND_DRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/multiband_drc/multiband_drc.toml> +#endif + +#if defined(CONFIG_COMP_DCBLOCK) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/dcblock/dcblock.toml> +#endif + +#if defined(CONFIG_COMP_TDFB) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/tdfb/tdfb.toml> +#endif + +#if defined(CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/google/google_rtc_audio_processing.toml> +#endif + +#if defined(CONFIG_COMP_RTNR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/rtnr/rtnr.toml> +#endif + +#if defined(CONFIG_COMP_IGO_NR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/igo_nr/igo_nr.toml> +#endif + +#if defined(CONFIG_COMP_MFCC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/mfcc/mfcc.toml> +#endif + +#if defined(CONFIG_COMP_ASRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/asrc/asrc.toml> +#endif + +#if defined(CONFIG_COMP_TEMPLATE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/template/template.toml> +#endif + +#if defined(CONFIG_COMP_LEVEL_MULTIPLIER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/level_multiplier/level_multiplier.toml> +#endif + +#if defined(CONFIG_COMP_SOUND_DOSE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/sound_dose/sound_dose.toml> +#endif + +#if defined(CONFIG_COMP_STFT_PROCESS) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/stft_process/stft_process.toml> +#endif + +[module] +count = __COUNTER__ diff --git a/tools/rimage/config/tgl.toml b/tools/rimage/config/tgl.toml deleted file mode 100644 index 8bd36d4c8da6..000000000000 --- a/tools/rimage/config/tgl.toml +++ /dev/null @@ -1,564 +0,0 @@ -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 = 25 - [[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" - init_config = "1" - 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] - - # RTNR module config - [[module.entry]] - name = "RTNR" - uuid = "5C7CA334-E15D-11EB-BA80-0242AC130004" - 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] - - # IGO_NR module config - [[module.entry]] - name = "IGO_NR" - uuid = "696AE2BC-2877-11EB-ADC1-0242AC120002" - 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] - - # MFCC module config - [[module.entry]] - name = "MFCC" - uuid = "DB10A773-1AA4-4CEA-A21F-2D57A5C982EB" - 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.toml.h b/tools/rimage/config/tgl.toml.h new file mode 100644 index 000000000000..2ca246880727 --- /dev/null +++ b/tools/rimage/config/tgl.toml.h @@ -0,0 +1,136 @@ +#include "platform-tgl.toml" + + [[module.entry]] + name = "BRNGUP" + uuid = UUIDREG_STR_BRNGUP + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + index = __COUNTER__ + + [[module.entry]] + name = "BASEFW" + uuid = UUIDREG_STR_BASEFW + affinity_mask = "3" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + index = __COUNTER__ + +#if defined(CONFIG_COMP_MIXIN_MIXOUT) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/mixin_mixout/mixin_mixout.toml> +#endif + +#if defined(CONFIG_COMP_COPIER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/copier/copier.toml> +#endif + +#if defined(CONFIG_COMP_VOLUME) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/volume/volume.toml> +#endif + +#ifdef CONFIG_PROBE +#include <probe/probe.toml> +#endif + +#if defined(CONFIG_COMP_SRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/src/src.toml> +#endif + +#if defined(CONFIG_CADENCE_CODEC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/module_adapter/module/cadence.toml> +#endif + +#if defined(CONFIG_SAMPLE_SMART_AMP) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <samples/audio/smart_amp_test.toml> +#endif + +#if defined(CONFIG_COMP_IIR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/eq_iir/eq_iir.toml> +#endif + +#if defined(CONFIG_COMP_FIR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/eq_fir/eq_fir.toml> +#endif + +#ifdef CONFIG_SAMPLE_KEYPHRASE +#include <samples/audio/detect_test.toml> +#endif + +#if defined(CONFIG_COMP_KPB) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/kpb.toml> +#endif + +#if defined(CONFIG_COMP_SEL) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/selector/selector.toml> +#endif + +#if defined(CONFIG_COMP_ARIA) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/aria/aria.toml> +#endif + +#if defined(CONFIG_COMP_DRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/drc/drc.toml> +#endif + +#if defined(CONFIG_COMP_CROSSOVER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/crossover/crossover.toml> +#endif + +#if defined(CONFIG_COMP_MULTIBAND_DRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/multiband_drc/multiband_drc.toml> +#endif + +#if defined(CONFIG_COMP_DCBLOCK) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/dcblock/dcblock.toml> +#endif + +#if defined(CONFIG_COMP_TDFB) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/tdfb/tdfb.toml> +#endif + +#if defined(CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/google/google_rtc_audio_processing.toml> +#endif + +#if defined(CONFIG_COMP_RTNR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/rtnr/rtnr.toml> +#endif + +#if defined(CONFIG_COMP_IGO_NR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/igo_nr/igo_nr.toml> +#endif + +#if defined(CONFIG_COMP_MFCC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/mfcc/mfcc.toml> +#endif + +#if defined(CONFIG_COMP_ASRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/asrc/asrc.toml> +#endif + +#if defined(CONFIG_COMP_TEMPLATE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/template/template.toml> +#endif + +#if defined(CONFIG_COMP_LEVEL_MULTIPLIER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/level_multiplier/level_multiplier.toml> +#endif + +#if defined(CONFIG_COMP_SOUND_DOSE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/sound_dose/sound_dose.toml> +#endif + +#if defined(CONFIG_COMP_STFT_PROCESS) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/stft_process/stft_process.toml> +#endif + +[module] +count = __COUNTER__ diff --git a/tools/rimage/config/wcl.toml.h b/tools/rimage/config/wcl.toml.h new file mode 100644 index 000000000000..27d00f1444be --- /dev/null +++ b/tools/rimage/config/wcl.toml.h @@ -0,0 +1,166 @@ +#include "platform-ptl.toml" + +[[module.entry]] +name = "BRNGUP" +uuid = UUIDREG_STR_BRNGUP +affinity_mask = "0x1" +instance_count = "1" +domain_types = "0" +load_type = "0" +module_type = "0" +auto_start = "0" + +index = __COUNTER__ + +#if CONFIG_COLD_STORE_EXECUTE_DRAM +[[module.entry]] +name = "COLD" +uuid = UUIDREG_STR_COLD +affinity_mask = "3" +instance_count = "1" +domain_types = "0" +load_type = "0" +module_type = "0" +auto_start = "0" + +index = __COUNTER__ +#endif + +[[module.entry]] +name = "BASEFW" +uuid = UUIDREG_STR_BASEFW +affinity_mask = "3" +instance_count = "1" +domain_types = "0" +load_type = "0" +module_type = "0" +auto_start = "0" + +index = __COUNTER__ + +#if defined(CONFIG_COMP_TESTER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <debug/tester/tester.toml> +#endif + +#if defined(CONFIG_COMP_MIXIN_MIXOUT) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/mixin_mixout/mixin_mixout.toml> +#endif + +#if defined(CONFIG_COMP_COPIER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/copier/copier.toml> +#endif + +#if defined(CONFIG_COMP_VOLUME) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/volume/volume.toml> +#endif + +#if defined(CONFIG_COMP_ASRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/asrc/asrc.toml> +#endif + +#if defined(CONFIG_COMP_SRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/src/src.toml> +#endif + +#if defined(CONFIG_CADENCE_CODEC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/module_adapter/module/cadence.toml> +#endif + +#if defined(CONFIG_COMP_SEL) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/selector/selector.toml> +#endif + +#if defined(CONFIG_COMP_UP_DOWN_MIXER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/up_down_mixer/up_down_mixer.toml> +#endif + +#ifdef CONFIG_PROBE +#include <probe/probe.toml> +#endif + +#if defined(CONFIG_COMP_MUX) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/mux/mux.toml> +#endif + +#ifdef CONFIG_SAMPLE_KEYPHRASE +#include <samples/audio/detect_test.toml> +#endif + +#if defined(CONFIG_COMP_KPB) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/kpb.toml> +#endif + +#if defined(CONFIG_SAMPLE_SMART_AMP) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <samples/audio/smart_amp_test.toml> +#endif + +#if defined(CONFIG_COMP_IIR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/eq_iir/eq_iir.toml> +#endif + +#if defined(CONFIG_COMP_FIR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/eq_fir/eq_fir.toml> +#endif + +#if defined(CONFIG_COMP_ARIA) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/aria/aria.toml> +#endif + +#if defined(CONFIG_COMP_DRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/drc/drc.toml> +#endif + +#if defined(CONFIG_COMP_CROSSOVER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/crossover/crossover.toml> +#endif + +#if defined(CONFIG_COMP_MULTIBAND_DRC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/multiband_drc/multiband_drc.toml> +#endif + +#if defined(CONFIG_COMP_DCBLOCK) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/dcblock/dcblock.toml> +#endif + +#if defined(CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/google/google_rtc_audio_processing.toml> +#endif + +#if defined(CONFIG_COMP_TDFB) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/tdfb/tdfb.toml> +#endif + +#if defined(CONFIG_COMP_RTNR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/rtnr/rtnr.toml> +#endif + +#if defined(CONFIG_COMP_IGO_NR) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/igo_nr/igo_nr.toml> +#endif + +#if defined(CONFIG_COMP_MFCC) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/mfcc/mfcc.toml> +#endif + +#if defined(CONFIG_COMP_TEMPLATE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/template/template.toml> +#endif + +#if defined(CONFIG_COMP_SOUND_DOSE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/sound_dose/sound_dose.toml> +#endif + +#if defined(CONFIG_COMP_TONE) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/tone/tone.toml> +#endif + +#if defined(CONFIG_COMP_STFT_PROCESS) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/stft_process/stft_process.toml> +#endif + +#if defined(CONFIG_COMP_PHASE_VOCODER) || defined(LLEXT_FORCE_ALL_MODULAR) +#include <audio/phase_vocoder/phase_vocoder.toml> +#endif + +[module] +count = __COUNTER__ diff --git a/tools/rimage/scripts/checkpatch.pl b/tools/rimage/scripts/checkpatch.pl deleted file mode 100755 index ce33a3b0ac98..000000000000 --- a/tools/rimage/scripts/checkpatch.pl +++ /dev/null @@ -1,6845 +0,0 @@ -#!/usr/bin/env perl -# SPDX-License-Identifier: GPL-2.0 -# -# (c) 2001, Dave Jones. (the file handling bit) -# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit) -# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite) -# (c) 2008-2010 Andy Whitcroft <apw@canonical.com> -# (c) 2010-2018 Joe Perches <joe@perches.com> - -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: - <rev> - <rev>^ - <rev>~n - multiple git commits with: - <rev1>..<rev2> - <rev1>...<rev2> - <rev>-<count> - 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 - "<inputfile>.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 <joe@smith.com" bad - if ($name ne "" && $address !~ /^<[^>]+>$/) { - $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/(?<!\\)"/\\"/g; ##escape quotes - $name = "\"$name\""; - } - - return ($name, $address, $comment); -} - -sub format_email { - my ($name, $address) = @_; - - my $formatted_email; - - $name = trim($name); - $name =~ s/^\"|\"$//g; - $address = trim($address); - - if ($name =~ /[^\w \-]/i) { ##has "must quote" chars - $name =~ s/(?<!\\)"/\\"/g; ##escape quotes - $name = "\"$name\""; - } - - if ("$name" eq "") { - $formatted_email = "$address"; - } else { - $formatted_email = "$name <$address>"; - } - - 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-<architecture>\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/" </ </; - # Don't force email to have quotes - # Allow just an angle bracketed address - if ("$dequoted$comment" ne $email && - "<$email_address>$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> (\"<title line>\")' - 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/src/adsp_config.c b/tools/rimage/src/adsp_config.c index 7dd30864ff54..6cc7434e74bc 100644 --- a/tools/rimage/src/adsp_config.c +++ b/tools/rimage/src/adsp_config.c @@ -270,11 +270,11 @@ static int parse_cse(const toml_table_t *toml, struct parse_ctx *pctx, hdr->header_length = sizeof(struct CsePartitionDirHeader); /* configurable fields */ - hdr->header_version = parse_uint32_key(cse, &ctx, "header_version", 1, &ret); + hdr->header_version = parse_uint8_key(cse, &ctx, "header_version", 1, &ret); if (ret < 0) return ret; - hdr->entry_version = parse_uint32_key(cse, &ctx, "entry_version", 1, &ret); + hdr->entry_version = parse_uint8_key(cse, &ctx, "entry_version", 1, &ret); if (ret < 0) return ret; @@ -382,11 +382,11 @@ static int parse_cse_v2_5(const toml_table_t *toml, struct parse_ctx *pctx, hdr->header_length = sizeof(struct CsePartitionDirHeader_v2_5); /* configurable fields */ - hdr->header_version = parse_uint32_key(cse, &ctx, "header_version", 2, &ret); + hdr->header_version = parse_uint8_key(cse, &ctx, "header_version", 2, &ret); if (ret < 0) return ret; - hdr->entry_version = parse_uint32_key(cse, &ctx, "entry_version", 1, &ret); + hdr->entry_version = parse_uint8_key(cse, &ctx, "entry_version", 1, &ret); if (ret < 0) return ret; @@ -771,11 +771,11 @@ static int parse_signed_pkg(const toml_table_t *toml, struct parse_ctx *pctx, if (ret < 0) return ret; - out->fw_type = parse_uint32_hex_key(signed_pkg, &ctx, "fw_type", 0, &ret); + out->fw_type = parse_uint8_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); + out->fw_sub_type = parse_uint8_hex_key(signed_pkg, &ctx, "fw_sub_type", 0, &ret); if (ret < 0) return ret; @@ -835,15 +835,15 @@ static int parse_signed_pkg(const toml_table_t *toml, struct parse_ctx *pctx, if (ret < 0) return err_key_parse("module", NULL); - mod->type = parse_uint32_hex_key(module, &ctx, "type", 0x03, &ret); + mod->type = parse_uint8_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); + mod->hash_algo = parse_uint8_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); + mod->hash_size = parse_uint16_hex_key(module, &ctx, "hash_size", 0x20, &ret); if (ret < 0) return err_key_parse("module", NULL); @@ -929,11 +929,11 @@ static int parse_signed_pkg_v2_5(const toml_table_t *toml, struct parse_ctx *pct if (ret < 0) return ret; - out->fw_type = parse_uint32_hex_key(signed_pkg, &ctx, "fw_type", 0, &ret); + out->fw_type = parse_uint8_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); + out->fw_sub_type = parse_uint8_hex_key(signed_pkg, &ctx, "fw_sub_type", 0, &ret); if (ret < 0) return ret; @@ -993,15 +993,15 @@ static int parse_signed_pkg_v2_5(const toml_table_t *toml, struct parse_ctx *pct if (ret < 0) return err_key_parse("module", NULL); - mod->type = parse_uint32_hex_key(module, &ctx, "type", 0x03, &ret); + mod->type = parse_uint8_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); + mod->hash_algo = parse_uint8_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); + mod->hash_size = parse_uint16_hex_key(module, &ctx, "hash_size", 0x30, &ret); if (ret < 0) return err_key_parse("module", NULL); @@ -1079,11 +1079,11 @@ static int parse_signed_pkg_ace_v1_5(const toml_table_t *toml, struct parse_ctx if (ret < 0) return ret; - out->fw_type = parse_uint32_hex_key(signed_pkg, &ctx, "fw_type", 0, &ret); + out->fw_type = parse_uint8_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); + out->fw_sub_type = parse_uint8_hex_key(signed_pkg, &ctx, "fw_sub_type", 0, &ret); if (ret < 0) return ret; @@ -1121,11 +1121,11 @@ static int parse_signed_pkg_ace_v1_5(const toml_table_t *toml, struct parse_ctx if (ret < 0) return err_key_parse("module", NULL); - mod->type = parse_uint32_hex_key(module, &ctx, "type", 0x03, &ret); + mod->type = parse_uint8_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); + mod->hash_algo = parse_uint8_hex_key(module, &ctx, "hash_algo", 0x00, &ret); if (ret < 0) return err_key_parse("module", NULL); @@ -1256,7 +1256,7 @@ static int parse_partition_info_ext(const toml_table_t *toml, struct parse_ctx * if (ret < 0) return err_key_parse("module", NULL); - mod->type = parse_uint32_hex_key(module, &ctx, "type", 0x03, &ret); + mod->type = parse_uint8_hex_key(module, &ctx, "type", 0x03, &ret); if (ret < 0) return err_key_parse("module", NULL); @@ -1910,14 +1910,14 @@ static int parse_module(const toml_table_t *toml, struct parse_ctx *pctx, if (ret < 0) return err_key_parse("uuid", NULL); - parse_uuid(buf, mod_man->uuid); + 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, + mod_man->instance_max_count = parse_uint16_hex_key(mod_entry, &ctx_entry, "instance_count", 1, &ret); if (ret < 0) return err_key_parse("instance_count", NULL); @@ -1952,7 +1952,7 @@ static int parse_module(const toml_table_t *toml, struct parse_ctx *pctx, 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)); + 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) diff --git a/tools/rimage/src/elf_file.c b/tools/rimage/src/elf_file.c index 991766d45062..c40d3a69abfb 100644 --- a/tools/rimage/src/elf_file.c +++ b/tools/rimage/src/elf_file.c @@ -531,10 +531,23 @@ int elf_strings_read_by_index(const struct elf_file *elf, int index, struct elf_ int elf_strings_get(const struct elf_strings *strings, int index, char **str) { - if (index >= strings->section.header.data.size) + size_t size = strings->section.header.data.size; + const char *base = (const char *)strings->section.data; + + if (index < 0 || (size_t)index >= size) + return -EINVAL; + + /* + * A crafted ELF may provide a string table that is not NUL-terminated; + * make sure a terminator exists within the section before strdup() so + * it cannot read past the end of the mapped section. + */ + if (strnlen(base + index, size - index) == size - index) { + fprintf(stderr, "error: unterminated string in string table\n"); return -EINVAL; + } - *str = strdup((const char *)strings->section.data + index); + *str = strdup(base + index); if (!*str) return -ENOMEM; diff --git a/tools/rimage/src/ext_manifest.c b/tools/rimage/src/ext_manifest.c index 03a157c08397..8beaa4943a7b 100644 --- a/tools/rimage/src/ext_manifest.c +++ b/tools/rimage/src/ext_manifest.c @@ -69,6 +69,12 @@ static int ext_man_validate(uint32_t section_size, const void *section_data) /* copy each head to local struct to omit memory align issues */ while (offset < section_size) { + /* make sure a whole header remains before copying it out */ + if (offset + sizeof(head) > section_size) { + fprintf(stderr, + "error: extended manifest header straddles section end\n"); + return -EINVAL; + } 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); @@ -150,10 +156,12 @@ int ext_man_write(struct image *image) /* 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; + if (ret) + /* ext_man_validate() already returns a negative errno; do not + * overwrite it with -errno, which is not set on validation + * failure and would mask the error + */ goto out; - } /* write extended metadata to file */ count = fwrite(ext_man, 1, ext_man->full_size, image->out_ext_man_fd); diff --git a/tools/rimage/src/hash.c b/tools/rimage/src/hash.c index 0604670e9c6e..9aff3ae3625a 100644 --- a/tools/rimage/src/hash.c +++ b/tools/rimage/src/hash.c @@ -174,7 +174,10 @@ int hash_single(const void *data, size_t size, const EVP_MD *algo, void *output, if (algo_out_size <= 0) return -EINVAL; - if (output_len > algo_out_size) + /* EVP_Digest writes algo_out_size bytes into output, so the buffer + * must be at least that large; reject an undersized output buffer + */ + if (output_len < (size_t)algo_out_size) return -ENOBUFS; if (!EVP_Digest(data, size, output, NULL, algo, NULL)) { diff --git a/tools/rimage/src/include/rimage/cavs/cavs_ext_manifest.h b/tools/rimage/src/include/rimage/cavs/cavs_ext_manifest.h index 4002f37fddb1..e135dbbfc191 100644 --- a/tools/rimage/src/include/rimage/cavs/cavs_ext_manifest.h +++ b/tools/rimage/src/include/rimage/cavs/cavs_ext_manifest.h @@ -27,7 +27,7 @@ #define EXTENDED_MANIFEST_VERSION_MAJOR 0x0001 #define EXTENDED_MANIFEST_VERSION_MINOR 0x0000 -#define FW_MAX_EXT_MODULE_NUM 32 +#define FW_MAX_EXT_MODULE_NUM 48 struct uuid_t { uint32_t d0; diff --git a/tools/rimage/src/include/rimage/module.h b/tools/rimage/src/include/rimage/module.h index 1fd3f6c020b7..bd4b93608078 100644 --- a/tools/rimage/src/include/rimage/module.h +++ b/tools/rimage/src/include/rimage/module.h @@ -127,10 +127,11 @@ void module_close(struct module *module); * @param module module structure * @param mem_cfg memory configration structure * @param verbose verbose logging selection + * @param ignore_detached do not mark detached sections * @return error code */ void module_parse_sections(struct module *module, const struct memory_config *mem_cfg, - bool verbose); + bool verbose, bool ignore_detached); /** * Read module section to memory buffer diff --git a/tools/rimage/src/include/rimage/rimage.h b/tools/rimage/src/include/rimage/rimage.h index 20eafb8dfd95..139b55951fdc 100644 --- a/tools/rimage/src/include/rimage/rimage.h +++ b/tools/rimage/src/include/rimage/rimage.h @@ -65,6 +65,9 @@ struct image { /* Output image is a loadable module */ bool loadable_module; + + /* Do not mark detached sections */ + bool ignore_detached; }; struct memory_zone { diff --git a/tools/rimage/src/include/rimage/sof/user/manifest.h b/tools/rimage/src/include/rimage/sof/user/manifest.h index 829b1b134810..3f20d89ff495 100644 --- a/tools/rimage/src/include/rimage/sof/user/manifest.h +++ b/tools/rimage/src/include/rimage/sof/user/manifest.h @@ -26,6 +26,7 @@ #define SOF_MAN_MOD_TYPE_BUILTIN 0 #define SOF_MAN_MOD_TYPE_MODULE 1 #define SOF_MAN_MOD_TYPE_LLEXT 2 /* Zephyr LLEXT-style dynamically linked */ +#define SOF_MAN_MOD_TYPE_LLEXT_AUX 3 /* Zephyr LLEXT-style dynamically linked auxiliary */ /* module init config */ #define SOF_MAN_MOD_INIT_CONFIG_BASE_CFG 0 /* Base config only */ @@ -41,7 +42,16 @@ struct sof_man_module_type { uint32_t domain_dp:1; uint32_t lib_code:1; uint32_t init_config:4; /* SOF_MAN_MOD_INIT_CONFIG_ */ - uint32_t rsvd_:20; + /* The init_config field overlaps with the following fields, so core_type was trimmed to + * ensure proper placement of remaining fields. + * uint32_t domain_rtos:1; + * uint32_t core_type:8; + */ + uint32_t core_type:5; + uint32_t user_mode:1; + uint32_t large_param:1; + uint32_t stack_on_bss:1; + uint32_t rsvd_:12; }; /* segment flags.type */ @@ -86,13 +96,28 @@ struct sof_man_segment_desc { #define SOF_MAN_MOD_SHA384_LEN 48 #define SOF_MAN_MOD_ID {'$', 'A', 'M', 'E'} +struct sof_man_uuid { + uint32_t a; + uint16_t b; + uint16_t c; + uint8_t d[8]; +}; + +struct sof_man_runtime_info { + uint16_t module_id; + uint16_t state_flags; +}; + /* * 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 */ + union { + uint8_t struct_id[SOF_MAN_MOD_ID_LEN]; /* SOF_MAN_MOD_ID */ + struct sof_man_runtime_info runtime_info; + }; uint8_t name[SOF_MAN_MOD_NAME_LEN]; - uint8_t uuid[16]; + struct sof_man_uuid uuid; struct sof_man_module_type type; uint8_t hash[SOF_MAN_MOD_SHA256_LEN]; uint32_t entry_point; diff --git a/tools/rimage/src/include/rimage/toml_utils.h b/tools/rimage/src/include/rimage/toml_utils.h index 22f257c2c65d..8bbbdaca17fa 100644 --- a/tools/rimage/src/include/rimage/toml_utils.h +++ b/tools/rimage/src/include/rimage/toml_utils.h @@ -65,6 +65,10 @@ int assert_everything_parsed(const toml_table_t *table, struct parse_ctx *ctx); */ uint32_t parse_uint32_hex_key(const toml_table_t *table, struct parse_ctx *ctx, const char *key, int64_t def, int *error); +uint16_t parse_uint16_hex_key(const toml_table_t *table, struct parse_ctx *ctx, + const char *key, int64_t def, int *error); +uint8_t parse_uint8_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 @@ -77,6 +81,8 @@ uint32_t parse_uint32_hex_key(const toml_table_t *table, struct parse_ctx *ctx, */ uint32_t parse_uint32_key(const toml_table_t *table, struct parse_ctx *ctx, const char *key, int64_t def, int *error); +uint8_t parse_uint8_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 @@ -115,7 +121,7 @@ void parse_str_key(const toml_table_t *table, struct parse_ctx *ctx, const char * Parse UUID hex string into a byte array. The endianness of the output * is architecture-dependent: do not use in any portable code. */ -void parse_uuid(const char *buf, uint8_t *uuid); +void parse_uuid(const char *buf, void *uuid); /** version is stored as toml array with integer number, something like: * "version = [1, 8]" diff --git a/tools/rimage/src/manifest.c b/tools/rimage/src/manifest.c index d7a1fbe58e4e..22eddfa00c74 100644 --- a/tools/rimage/src/manifest.c +++ b/tools/rimage/src/manifest.c @@ -12,6 +12,7 @@ #include <unistd.h> #include <errno.h> #include <string.h> +#include <stdbool.h> #include <time.h> #include <sys/time.h> @@ -26,6 +27,33 @@ #include <rimage/misc_utils.h> #include <rimage/hash.h> +static bool cse_header_is_valid(const struct image *image, const void *buffer, size_t size) +{ + if (image->adsp->man_v2_5 || image->adsp->man_ace_v1_5) { + const struct CsePartitionDirHeader_v2_5 *cse_hdr = buffer; + + if (size < sizeof(*cse_hdr)) + return false; + + return cse_hdr->header_marker == CSE_HEADER_MAKER && + cse_hdr->nb_entries == MAN_CSE_PARTS && + cse_hdr->header_length >= sizeof(*cse_hdr); + } + + if (image->adsp->man_v1_5 || image->adsp->man_v1_5_sue || image->adsp->man_v1_8) { + const struct CsePartitionDirHeader *cse_hdr = buffer; + + if (size < sizeof(*cse_hdr)) + return false; + + return cse_hdr->header_marker == CSE_HEADER_MAKER && + cse_hdr->nb_entries == MAN_CSE_PARTS && + cse_hdr->header_length >= sizeof(*cse_hdr); + } + + return false; +} + static int man_open_rom_file(struct image *image) { uint32_t size; @@ -205,13 +233,14 @@ static void man_get_section_manifest(struct image *image, 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); + memcpy(&man_module->uuid, &sof_mod->module.uuid, sizeof(man_module->uuid)); man_module->affinity_mask = sof_mod->module.affinity_mask; man_module->instance_max_count = sof_mod->module.instance_max_count; 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; + man_module->type.user_mode = sof_mod->module.type.user_mode; /* text segment */ segment = &man_module->segment[SOF_MAN_SEGMENT_TEXT]; @@ -533,21 +562,37 @@ static int man_module_create_reloc(struct image *image, struct manifest_module * return -ENOEXEC; } + /* + * n_mod comes from the (potentially untrusted) ELF and each manifest + * consumes a sof_man_module descriptor slot written into fw_image. + * Bound the cumulative count across all input modules (this ELF adds + * n_mod to the running output_mod_cfg_count) so a crafted .module + * section cannot overflow the fixed manifest descriptor array. + */ + if (modules->output_mod_cfg_count + n_mod > MAX_MODULES) { + fprintf(stderr, "error: too many module manifests (%u + %u > %u).\n", + modules->output_mod_cfg_count, n_mod, MAX_MODULES); + elf_section_free(§ion); + return -ENOEXEC; + } + unsigned int i; for (i = 0, sof_mod = section.data; i < n_mod; i++, sof_mod++) { - int j = man_module_find_cfg(modules, &sof_mod->module); - - if (j < 0) { - elf_section_free(§ion); - return j; - } - - /* Found a TOML manifest, matching ELF */ if (i) (*man_module)++; - /* Use manifest created using toml files as template */ - **man_module = modules->mod_man[j]; + + if (sof_mod->module.type.load_type != SOF_MAN_MOD_TYPE_LLEXT_AUX) { + int j = man_module_find_cfg(modules, &sof_mod->module); + + if (j < 0) { + elf_section_free(§ion); + return j; + } + + /* Found a TOML manifest, matching ELF: use as a template */ + **man_module = modules->mod_man[j]; + } /* Use .manifest to update individual fields */ man_get_section_manifest(image, sof_mod, *man_module); man_module_fill_reloc(module, *man_module); @@ -723,6 +768,9 @@ static int man_create_modules_in_config(struct image *image, struct sof_man_fw_d SOF_MAN_MODULE_OFFSET(0)); i < modules->output_mod_cfg_count; i++, man_module++) { + if (man_module->type.load_type == SOF_MAN_MOD_TYPE_LLEXT_AUX) + continue; + int j = man_module_find_cfg(modules, man_module); if (j < 0) @@ -1624,8 +1672,8 @@ int man_write_fw_ace_v1_5(struct image *image) int verify_image(struct image *image) { FILE *in_file; - int ret; - void *buffer; + int ret = -EINVAL; + void *buffer = NULL; size_t size, read, i; /* is verify supported for target ? */ @@ -1658,11 +1706,25 @@ int verify_image(struct image *image) ret = file_error("unable to read whole file", image->verify_file); goto out; } - for (i = 0; i < size; i += sizeof(uint32_t)) { + for (i = 0; i + sizeof(uint32_t) <= size; i += sizeof(uint32_t)) { /* find CSE header marker "$CPD" */ - if (*(uint32_t *)(buffer + i) == CSE_HEADER_MAKER) { + if (cse_header_is_valid(image, buffer + i, size - i)) { image->fw_image = buffer + i; + /* size of the image from the CSE header to the end of the + * file, used by v1.5 verification and the signed-payload + * bounds checks + */ + image->image_end = size - i; ret = image->adsp->verify_firmware(image); + /* verify_firmware() returns 1 = valid, 0 = invalid and + * < 0 = error (OpenSSL RSA_verify semantics); map valid + * to 0 and invalid to -EINVAL, and leave a < 0 error code + * as-is, so the CLI exit code reflects the result + */ + if (ret == 1) + ret = 0; + else if (ret == 0) + ret = -EINVAL; goto out; } } @@ -1670,9 +1732,14 @@ int verify_image(struct image *image) /* no header found */ fprintf(stderr, "error: could not find valid CSE header $CPD in %s\n", image->verify_file); + ret = -EINVAL; out: + free(buffer); fclose(in_file); - return 0; + /* propagate verification result so callers (and the exit code) can + * detect a failed/missing verification instead of always seeing success + */ + return ret; } @@ -1711,9 +1778,9 @@ int resign_image(struct image *image) fclose(in_file); - for (i = 0; i < size; i += sizeof(uint32_t)) { + for (i = 0; i + sizeof(uint32_t) <= size; i += sizeof(uint32_t)) { /* find CSE header marker "$CPD" */ - if (*(uint32_t *)(buffer + i) == CSE_HEADER_MAKER) { + if (cse_header_is_valid(image, buffer + i, size - i)) { image->fw_image = buffer + i; break; } @@ -1725,10 +1792,10 @@ int resign_image(struct image *image) goto out; } - image->image_end = size; + image->image_end = size - i; /* check that key size matches */ - if (image->adsp->man_v2_5) { + if (image->adsp->man_v2_5 || image->adsp->man_ace_v1_5) { key_size = 384; } else { key_size = 256; @@ -1750,6 +1817,8 @@ int resign_image(struct image *image) ret = ri_manifest_sign_v1_8(image); else if (image->adsp->man_v2_5) ret = ri_manifest_sign_v2_5(image); + else if (image->adsp->man_ace_v1_5) + ret = ri_manifest_sign_ace_v1_5(image); else ret = -EINVAL; @@ -1766,7 +1835,33 @@ int resign_image(struct image *image) goto out; } - man_write_fw_mod(image); + /* Rewrite content before CSE header */ + size = fwrite(buffer, 1, i, image->out_fd); + if (size != i) { + ret = file_error("Extended manifest write error", image->out_file); + goto out; + } + + ret = man_write_fw_mod(image); + if (ret < 0) + goto out; + + /* fclose() closes the stream even when it reports an error, so clear the + * handle first to stop the caller's cleanup from closing it a second time. + */ + ret = fclose(image->out_fd); + image->out_fd = NULL; + if (ret) { + ret = file_error("unable to close file after signing", image->out_file); + goto out; + } + + /* validate the re-signed output with the same private key */ + image->verify_file = image->out_file; + ret = verify_image(image); + image->verify_file = NULL; + if (ret < 0) + unlink(image->out_file); out: free(buffer); diff --git a/tools/rimage/src/module.c b/tools/rimage/src/module.c index 7ca44ca661e5..d35765c591ac 100644 --- a/tools/rimage/src/module.c +++ b/tools/rimage/src/module.c @@ -310,12 +310,14 @@ static enum module_section_type get_section_type(const struct elf_section_header } } -void module_parse_sections(struct module *module, const struct memory_config *mem_cfg, bool verbose) +void module_parse_sections(struct module *module, const struct memory_config *mem_cfg, bool verbose, + bool ignore_detached) { const uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); uint16_t i; struct module_section *out_section = module->sections; + size_t cold_text_size = 0, cold_data_size = 0; fprintf(stdout, " Found %d sections, listing valid sections...\n", module->elf.sections_count); @@ -343,7 +345,7 @@ void module_parse_sections(struct module *module, const struct memory_config *me out_section->size = sect->data.size; out_section->type = get_section_type(sect); out_section->rom = section_is_rom(mem_cfg, sect); - out_section->detached = section_is_detached(mem_cfg, sect); + out_section->detached = !ignore_detached && section_is_detached(mem_cfg, sect); out_section->address = sect->data.vaddr; out_section->load_address = find_physical_address(&module->elf, sect->data.vaddr); @@ -361,15 +363,18 @@ void module_parse_sections(struct module *module, const struct memory_config *me 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; + if (out_section->detached) + cold_data_size += out_section->size; fprintf(stdout, "\tDATA"); break; case MST_TEXT: info = &module->text; + if (out_section->detached) + cold_text_size += out_section->size; fprintf(stdout, "\tTEXT"); break; @@ -415,14 +420,33 @@ void module_parse_sections(struct module *module, const struct memory_config *me sections_info_finalize(&module->bss); size_t fw_size = module->data.size + module->text.size; + size_t rounded, start, end, 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, + + /* MST_TEXT */ + start = module->text.start; + end = module->text.end + cold_text_size; + size = module->text.size + cold_text_size; + rounded = ALIGN_UP(end, MAN_PAGE_SIZE) - start; + fprintf(stdout, + " module: text %zu (0x%zx) bytes, including %zu (0x%zx) %zu%% efficiency bytes\n", + size, size, cold_text_size, cold_text_size, + rounded ? (cold_text_size * 100 + rounded / 2) / rounded : 0); + + /* MST_DATA */ + start = module->data.start; + end = module->data.end + cold_data_size; + size = module->data.size + cold_data_size; + rounded = ALIGN_UP(end, MAN_PAGE_SIZE) - start; + fprintf(stdout, + "\tdata %zu (0x%zx) bytes, including %zu (0x%zx) %zu%% efficiency bytes\n", + size, size, cold_data_size, cold_data_size, + rounded ? (cold_data_size * 100 + rounded / 2) / rounded : 0); + + /* MST_BSS */ + fprintf(stdout, "\tbss %zu (0x%zx) bytes\n", module->bss.size, module->bss.size); } diff --git a/tools/rimage/src/pkcs1_5.c b/tools/rimage/src/pkcs1_5.c index de063ee03bec..cbd31bc101bf 100644 --- a/tools/rimage/src/pkcs1_5.c +++ b/tools/rimage/src/pkcs1_5.c @@ -929,9 +929,28 @@ int ri_manifest_verify_v1_8(struct image *image) MAN_RSA_SIGNATURE_LEN); char *const data2 = (char *)man + MAN_SIG_PKG_OFFSET_V1_8; + + /* css.size and css.header_len come from the (untrusted) image; reject + * a reversed ordering that would underflow the unsigned size2 below. + */ + if (man->css.size < man->css.header_len) { + fprintf(stderr, "error: invalid css size %u < header_len %u\n", + man->css.size, man->css.header_len); + return -EINVAL; + } + unsigned const size2 = (man->css.size - man->css.header_len) * sizeof(uint32_t); + /* size2 is derived from untrusted css fields and is hashed starting at + * data2; make sure that range stays within the verified image buffer. + */ + if (image->image_end < MAN_SIG_PKG_OFFSET_V1_8 || + size2 > image->image_end - MAN_SIG_PKG_OFFSET_V1_8) { + fprintf(stderr, "error: signed payload size 0x%x exceeds image\n", size2); + return -EINVAL; + } + return pkcs_v1_5_verify_man_v1_8(image, man, data1, size1, data2, size2); } @@ -946,9 +965,28 @@ int ri_manifest_verify_v2_5(struct image *image) MAN_RSA_SIGNATURE_LEN_2_5); char *const data2 = (char *)man + MAN_SIG_PKG_OFFSET_V2_5; + + /* css.size and css.header_len come from the (untrusted) image; reject + * a reversed ordering that would underflow the unsigned size2 below. + */ + if (man->css.size < man->css.header_len) { + fprintf(stderr, "error: invalid css size %u < header_len %u\n", + man->css.size, man->css.header_len); + return -EINVAL; + } + unsigned const size2 = (man->css.size - man->css.header_len) * sizeof(uint32_t); + /* size2 is derived from untrusted css fields and is hashed starting at + * data2; make sure that range stays within the verified image buffer. + */ + if (image->image_end < MAN_SIG_PKG_OFFSET_V2_5 || + size2 > image->image_end - MAN_SIG_PKG_OFFSET_V2_5) { + fprintf(stderr, "error: signed payload size 0x%x exceeds image\n", size2); + return -EINVAL; + } + return pkcs_v1_5_verify_man_v2_5(image, man, data1, size1, data2, size2); } diff --git a/tools/rimage/src/rimage.c b/tools/rimage/src/rimage.c index fb8aba95611d..2245288dfece 100644 --- a/tools/rimage/src/rimage.c +++ b/tools/rimage/src/rimage.c @@ -6,6 +6,7 @@ #include <stdlib.h> #include <stdio.h> #include <unistd.h> +#include <getopt.h> #include <errno.h> #include <string.h> #include <stdbool.h> @@ -32,8 +33,10 @@ static void usage(char *name) 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 -q resign binary from infile and validate the output signature\n"); fprintf(stdout, "\t -p set PV bit\n"); + fprintf(stdout, "\t -d ignore detached sections\n"); + fprintf(stdout, "\t -Q, --quiet suppress informational stdout logs\n"); } int main(int argc, char *argv[]) @@ -45,12 +48,18 @@ int main(int argc, char *argv[]) int use_ext_man = 0; unsigned int pv_bit = 0; bool imr_type_override = false; + bool quiet = false; + static const struct option long_options[] = { + { "quiet", no_argument, NULL, 'Q' }, + { NULL, 0, NULL, 0 } + }; 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) { + while ((opt = getopt_long(argc, argv, "ho:va:s:k:ri:f:b:ec:y:q:pldQ", + long_options, NULL)) != -1) { switch (opt) { case 'o': image.out_file = optarg; @@ -101,6 +110,13 @@ int main(int argc, char *argv[]) case 'l': image.loadable_module = true; break; + case 'd': + /* ignore detached sections */ + image.ignore_detached = true; + break; + case 'Q': + quiet = true; + break; default: /* getopt's default error message is good enough */ return 1; @@ -128,6 +144,11 @@ int main(int argc, char *argv[]) return -EINVAL; } + if (image.in_file && image.verify_file) { + fprintf(stderr, "error: resign and verify modes are mutually exclusive\n"); + return -EINVAL; + } + /* firmware version: major.minor.micro */ if (image.fw_ver_string) { ret = sscanf(image.fw_ver_string, "%hu.%hu.%hu", @@ -153,6 +174,10 @@ int main(int argc, char *argv[]) return -EINVAL; } } + + if (quiet && !freopen("/dev/null", "w", stdout)) + fprintf(stderr, "error: unable to redirect stdout: %s\n", strerror(errno)); + /* find machine */ heap_adsp = malloc(sizeof(struct adsp)); if (!heap_adsp) { @@ -225,7 +250,8 @@ int main(int argc, char *argv[]) if (ret < 0) goto out; - module_parse_sections(&image.module[i].file, &image.adsp->mem, image.verbose); + module_parse_sections(&image.module[i].file, &image.adsp->mem, image.verbose, + image.ignore_detached); /* When there is more than one module, then first one is bootloader. * Does not apply to building a image of a loadable module. */ diff --git a/tools/rimage/src/toml_utils.c b/tools/rimage/src/toml_utils.c index 7570c5b1f7bb..40a73fa1514c 100644 --- a/tools/rimage/src/toml_utils.c +++ b/tools/rimage/src/toml_utils.c @@ -151,11 +151,12 @@ uint32_t parse_uint32_hex_key(const toml_table_t *table, struct parse_ctx *ctx, *error = err_key_parse(key, NULL); return UINT32_MAX; } + errno = 0; val = strtoul(temp_s, 0, 0); free(temp_s); /* assert parsing success and value is within uint32_t range */ - if (errno < 0) { + if (errno != 0) { *error = err_key_parse(key, "can't convert hex value"); return UINT32_MAX; } @@ -166,6 +167,106 @@ uint32_t parse_uint32_hex_key(const toml_table_t *table, struct parse_ctx *ctx, return (uint32_t)val; } +/** + * 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 UINT16_MAX value for error cases + */ +uint16_t parse_uint16_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; + unsigned long val; /* strtoul return type */ + int ret; + + raw = toml_raw_in(table, key); + if (!raw) { + if (def < 0 || def > UINT16_MAX) { + *error = err_key_not_found(key); + return UINT16_MAX; + } + *error = 0; + return (uint16_t)def; + } + + ret = toml_rtos(raw, &temp_s); + if (ret < 0) { + *error = err_key_parse(key, NULL); + return UINT16_MAX; + } + errno = 0; + val = strtoul(temp_s, 0, 0); + free(temp_s); + + if (errno != 0) { + *error = err_key_parse(key, "can't convert hex value"); + return UINT16_MAX; + } + if (val > UINT16_MAX) { + *error = log_err(-ERANGE, "key %s out of uint16_t hex range", key); + return UINT16_MAX; + } + + *error = 0; + ++ctx->key_cnt; + return (uint16_t)val; +} + +/** + * 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 UINT8_MAX value for error cases + */ +uint8_t parse_uint8_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; + unsigned long val; + int ret; + + raw = toml_raw_in(table, key); + if (!raw) { + if (def < 0 || def > UINT8_MAX) { + *error = err_key_not_found(key); + return UINT8_MAX; + } + *error = 0; + return (uint8_t)def; + } + + ret = toml_rtos(raw, &temp_s); + if (ret < 0) { + *error = err_key_parse(key, NULL); + return UINT8_MAX; + } + errno = 0; + val = strtoul(temp_s, 0, 0); + free(temp_s); + + if (errno != 0) { + *error = err_key_parse(key, "can't convert hex value"); + return UINT8_MAX; + } + if (val > UINT8_MAX) { + *error = log_err(-ERANGE, "key %s out of uint8_t hex range", key); + return UINT8_MAX; + } + + *error = 0; + ++ctx->key_cnt; + return (uint8_t)val; +} + /** * Parse integer value from key in given toml table * @param table toml table where key is specified @@ -176,7 +277,7 @@ uint32_t parse_uint32_hex_key(const toml_table_t *table, struct parse_ctx *ctx, * @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) + int64_t def, int *error) { toml_raw_t raw; int64_t val; @@ -210,6 +311,48 @@ uint32_t parse_uint32_key(const toml_table_t *table, struct parse_ctx *ctx, cons return (uint32_t)val; } +/** + * Parse unsigned 8-bit 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 UINT8_MAX value for error cases + */ +uint8_t parse_uint8_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; + + raw = toml_raw_in(table, key); + if (!raw) { + if (def < 0 || def > UINT8_MAX) { + *error = err_key_not_found(key); + return UINT8_MAX; + } else { + *error = 0; + return (uint8_t)def; + } + } + + ret = toml_rtoi(raw, &val); + if (ret < 0) { + *error = err_key_parse(key, "can't convert to integer value"); + return UINT8_MAX; + } + if (val < 0 || val > UINT8_MAX) { + *error = log_err(-ERANGE, "key %s out of uint8_t range", key); + return UINT8_MAX; + } + + *error = 0; + ++ctx->key_cnt; + return (uint8_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 @@ -290,7 +433,7 @@ void parse_str_key(const toml_table_t *table, struct parse_ctx *ctx, const char dst[capacity - 1] = 0; } -void parse_uuid(const char *buf, uint8_t *uuid) +void parse_uuid(const char *buf, void *uuid) { struct uuid_t id; uint32_t d[11]; diff --git a/tools/sof_ri_info/sof_ri_info.py b/tools/sof_ri_info/sof_ri_info.py index 4033aeedd9d3..5fca3a42a3be 100755 --- a/tools/sof_ri_info/sof_ri_info.py +++ b/tools/sof_ri_info/sof_ri_info.py @@ -508,6 +508,55 @@ 0x6c, 0xa0, 0x50, 0x65, 0x92, 0x39, 0x96, 0x34, 0x61, 0xa4, 0xeb, 0x6b, 0x11, 0xd9, 0xbe, 0xb8]) +PTL_INTEL_PROD_KEY = bytes([0x89, 0xa8, 0x6a, 0xff, 0x6b, 0x1a, 0x78, 0xae, + 0x96, 0x0f, 0x50, 0x1a, 0xfb, 0xfc, 0x7b, 0x71, + 0x62, 0x00, 0x50, 0x03, 0x5b, 0x28, 0x32, 0x1c, + 0xe9, 0x99, 0x8a, 0xeb, 0xf0, 0xc0, 0xf9, 0x08, + 0xa5, 0xec, 0xc5, 0xeb, 0xc0, 0x8e, 0x99, 0x9c, + 0x31, 0x1c, 0x9e, 0xdf, 0x33, 0x5f, 0x8b, 0x27, + 0xc6, 0x82, 0x05, 0x50, 0xfb, 0xfa, 0xcb, 0x3d, + 0x96, 0x7a, 0x39, 0xcd, 0x03, 0x77, 0x69, 0xce, + 0x04, 0x1e, 0x10, 0x52, 0x01, 0x96, 0xb4, 0x1d, + 0x46, 0x28, 0x49, 0xc9, 0x43, 0x31, 0x23, 0x04, + 0xe1, 0x0f, 0x49, 0x84, 0x3f, 0xdf, 0xe8, 0xe8, + 0x69, 0x49, 0x60, 0x3a, 0x25, 0x71, 0x14, 0x2c, + 0xee, 0x06, 0x3f, 0x5b, 0x79, 0x67, 0x9a, 0xb4, + 0x5b, 0xa3, 0xf9, 0x64, 0xb9, 0xfe, 0xf6, 0x07, + 0x0c, 0x8e, 0x09, 0x79, 0xda, 0xbc, 0xb9, 0xd6, + 0x50, 0xe4, 0xef, 0x82, 0x0d, 0x6d, 0x30, 0x9c, + 0xa6, 0xa9, 0xbf, 0x9c, 0x88, 0x68, 0xe7, 0x95, + 0xa7, 0x6e, 0x09, 0xa8, 0xa7, 0x92, 0xd5, 0x2f, + 0x3f, 0x22, 0x19, 0x97, 0x0a, 0x41, 0x3f, 0x21, + 0x67, 0x1a, 0x80, 0xb4, 0x10, 0xdd, 0xaa, 0x3b, + 0xd3, 0x1b, 0x83, 0xc7, 0x02, 0x3c, 0x89, 0x88, + 0xd1, 0x3f, 0xdb, 0xdf, 0xf2, 0xaa, 0x79, 0x5f, + 0xbf, 0xf6, 0x6d, 0x3c, 0x6f, 0xbd, 0x90, 0x31, + 0xa8, 0x7d, 0x05, 0x9a, 0x7f, 0x0d, 0x51, 0x44, + 0xee, 0x0d, 0xa2, 0x26, 0x08, 0x4d, 0x39, 0x4b, + 0xd1, 0x4d, 0x7d, 0x24, 0xd1, 0xdb, 0x69, 0x42, + 0xf9, 0x81, 0x3a, 0xc7, 0xe6, 0x1f, 0x09, 0x4d, + 0x67, 0x90, 0x0e, 0xcc, 0xe6, 0x5e, 0xd0, 0x5d, + 0xc0, 0x72, 0x07, 0xb8, 0x29, 0xc5, 0x38, 0xb2, + 0x95, 0x24, 0xef, 0x92, 0xf0, 0x43, 0x06, 0x07, + 0xe5, 0xe3, 0x7c, 0x9f, 0xba, 0x68, 0x59, 0x76, + 0x41, 0xd3, 0xac, 0x8c, 0x0a, 0xe0, 0xc0, 0xd9, + 0x50, 0x21, 0xd6, 0x8f, 0xdf, 0x8d, 0x31, 0xa7, + 0x7f, 0xf9, 0x38, 0xc5, 0x4b, 0x6e, 0x32, 0xbf, + 0x73, 0x0d, 0x93, 0x3a, 0x47, 0xad, 0x3a, 0xbd, + 0xbe, 0x5b, 0x2b, 0xaf, 0xff, 0xc9, 0x7f, 0x37, + 0x30, 0x29, 0x13, 0x0e, 0x61, 0xe6, 0x93, 0xb9, + 0x2c, 0x28, 0x3e, 0x8d, 0x38, 0x3f, 0xea, 0xf4, + 0xf4, 0xf3, 0x23, 0x0c, 0xd2, 0x06, 0x05, 0x22, + 0x51, 0x64, 0x72, 0x6f, 0xfa, 0x1b, 0x7e, 0x81, + 0x22, 0x76, 0xc9, 0x8d, 0xbb, 0xa0, 0xe0, 0xa7, + 0xa4, 0xf9, 0x55, 0x24, 0x9c, 0x4c, 0xd1, 0x80, + 0x97, 0x44, 0x55, 0xe1, 0xfc, 0xa8, 0x6c, 0x8a, + 0x41, 0x67, 0x2f, 0x02, 0x32, 0x05, 0xe5, 0xb7, + 0x7f, 0x8e, 0xda, 0x4d, 0x25, 0x91, 0xf2, 0xc0, + 0x0b, 0xf2, 0x1f, 0x28, 0xeb, 0x5d, 0x05, 0xfe, + 0x70, 0x64, 0xcf, 0x7c, 0xec, 0x79, 0xf8, 0x2e, + 0x84, 0x49, 0x82, 0xa4, 0xf2, 0x20, 0xf6, 0xbd]) + COMMUNITY_KEY = bytes([0x85, 0x00, 0xe1, 0x68, 0xaa, 0xeb, 0xd2, 0x07, 0x1b, 0x7c, 0x5e, 0xed, 0xd6, 0xe7, 0xe5, 0xf9, 0xc1, 0x0e, 0x47, 0xd4, 0x4c, 0xab, 0x8c, 0xf0, @@ -601,6 +650,7 @@ MTL_INTEL_PROD_KEY : 'MTL Intel prod key', LNL_INTEL_PROD_KEY : 'LNL Intel prod key', ARL_S_INTEL_PROD_KEY : 'ARL-S Intel prod key', + PTL_INTEL_PROD_KEY : 'PTL Intel prod key', COMMUNITY_KEY : 'Community key', COMMUNITY_KEY2 : 'Community 3k key'} @@ -796,14 +846,25 @@ def parse_cse_manifest(reader): nb_entries = reader.read_dw() reader.info('# of entries {}'.format(nb_entries)) hdr.add_a(Adec('nb_entries', nb_entries)) - # read version (1byte for header ver and 1 byte for entry ver) - ver = reader.read_w() - hdr.add_a(Ahex('header_version', ver)) + # read version bytes + hdr.add_a(Ahex('header_version', reader.read_b())) + hdr.add_a(Ahex('entry_version', reader.read_b())) header_length = reader.read_b() hdr.add_a(Ahex('header_length', header_length)) - hdr.add_a(Ahex('checksum', reader.read_b())) + legacy_or_unused = reader.read_b() + # The v2.5 header (length 20) moves the checksum to a trailing CRC32 dword + # and leaves this byte unused. The legacy v1.x header (length 16) keeps the + # single-byte BSD checksum here, so discriminate on the v2.5 header length. + if header_length >= 20: + hdr.add_a(Ahex('not_used', legacy_or_unused)) + else: + hdr.add_a(Ahex('checksum', legacy_or_unused)) hdr.add_a(Astring('partition_name', reader.read_string(4))) + # CSE v2.5 extends header with a CRC32 checksum dword + if header_length >= 20: + hdr.add_a(Ahex('checksum32', reader.read_dw())) + reader.set_offset(cse_mft.file_offset + header_length) # Read entries nb_index = 0 @@ -812,13 +873,13 @@ def parse_cse_manifest(reader): entry_name = reader.read_string(12) entry_offset = reader.read_dw() entry_length = reader.read_dw() - # reserved field - reader.read_dw() + entry_reserved = reader.read_dw() hdr_entry = Component('cse_hdr_entry', 'Entry', reader.get_offset()) hdr_entry.add_a(Astring('entry_name', entry_name)) hdr_entry.add_a(Ahex('entry_offset', entry_offset)) hdr_entry.add_a(Ahex('entry_length', entry_length)) + hdr_entry.add_a(Ahex('entry_reserved', entry_reserved)) hdr.add_comp(hdr_entry) assert cse_mft.file_offset == reader.ext_mft_length @@ -866,12 +927,16 @@ def parse_css_manifest_4(css_mft, reader, size_limit): hdr = Component('css_mft_hdr', 'Header', reader.get_offset()) css_mft.add_comp(hdr) - hdr.add_a(Auint('type', reader.read_dw())) + header_type = reader.read_dw() + hdr.add_a(Auint('type', header_type)) + hdr.add_a(Auint('header_type', header_type)) header_len_dw = reader.read_dw() hdr.add_a(Auint('header_len_dw', header_len_dw)) hdr.add_a(Auint('header_version', reader.read_dw())) hdr.add_a(Auint('reserved0', reader.read_dw(), 'red')) - hdr.add_a(Ahex('mod_vendor', reader.read_dw())) + module_vendor = reader.read_dw() + hdr.add_a(Ahex('mod_vendor', module_vendor)) + hdr.add_a(Ahex('module_vendor', module_vendor)) date_start = reader.get_offset() hdr.add_a(Auint('date_start', date_start)) hdr.add_a(Adate('date', hex(reader.read_dw()))) @@ -880,10 +945,17 @@ def parse_css_manifest_4(css_mft, reader, size_limit): hdr.add_a(Auint('size', size)) hdr.add_a(Astring('header_id', reader.read_string(4))) hdr.add_a(Auint('padding', reader.read_dw())) - hdr.add_a(Aversion('fw_version', reader.read_w(), reader.read_w(), - reader.read_w(), reader.read_w())) + fw_major = reader.read_w() + fw_minor = reader.read_w() + fw_hotfix = reader.read_w() + fw_build = reader.read_w() + hdr.add_a(Auint('fw_major_version', fw_major)) + hdr.add_a(Auint('fw_minor_version', fw_minor)) + hdr.add_a(Auint('fw_hotfix_version', fw_hotfix)) + hdr.add_a(Auint('fw_build_version', fw_build)) + hdr.add_a(Aversion('fw_version', fw_major, fw_minor, fw_hotfix, fw_build)) hdr.add_a(Auint('svn', reader.read_dw())) - reader.read_bytes(18*4) + hdr.add_a(Abytes('reserved1', reader.read_bytes(18*4))) modulus_size = reader.read_dw() hdr.add_a(Adec('modulus_size', modulus_size)) exponent_size = reader.read_dw() @@ -915,56 +987,196 @@ def parse_css_manifest_4(css_mft, reader, size_limit): if ext_type == 0xffffffff: continue reader.set_offset(reader.get_offset() - 4) - css_mft.add_comp(parse_mft_extension(reader, ext_idx)) + css_mft.add_comp(parse_mft_extension(reader, ext_idx, size_limit)) ext_idx += 1 - assert reader.get_offset() == size_limit # wrong extension length + if reader.get_offset() != size_limit: + reader.info('warning: CSS extension parser finished at 0x{:x}, expected 0x{:x}; clamping'.format( + reader.get_offset(), size_limit)) + reader.set_offset(size_limit) css_mft.length = reader.get_offset() - css_mft.file_offset return css_mft -def parse_mft_extension(reader, ext_id): +def parse_mft_extension(reader, ext_id, max_end=None): """ Parses mft extension from sof binary """ begin_off = reader.get_offset() ext_type = reader.read_dw() ext_len = reader.read_dw() - if ext_type == 15: + ext_end = begin_off + ext_len + if max_end is not None and ext_end > max_end: + reader.info('warning: extension 0x{:x} length 0x{:x} exceeds CSS entry end; truncating'.format(ext_type, ext_len)) + ext_end = max_end + if ext_type == 3: + reader.info("Partition info extension") + ext = PartitionInfoExtension(ext_id, reader.get_offset()-8) + ext.add_a(Astring('name', reader.read_string(4))) + ext.add_a(Auint('partition_length', reader.read_dw())) + ext.add_a(Abytes('hash', reader.read_bytes(32))) + ext.add_a(Auint('vcn', reader.read_dw())) + ext.add_a(Auint('part_version', reader.read_dw())) + ext.add_a(Auint('fmt_version', reader.read_dw())) + ext.add_a(Auint('instance_id', reader.read_dw())) + ext.add_a(Auint('part_flags', reader.read_dw())) + ext.add_a(Abytes('reserved', reader.read_bytes(20), 'red')) + + mod_idx = 0 + while reader.get_offset() < ext_end: + mod = Component('partition_info_module_{}'.format(mod_idx), + 'Partition Info Module', reader.get_offset()) + mod.add_a(Astring('name', chararr_to_string(reader.read_bytes(12), 12))) + mod.add_a(Auint('type', reader.read_b())) + mod.add_a(Abytes('reserved', reader.read_bytes(3), 'red')) + mod.add_a(Auint('meta_size', reader.read_dw())) + mod.add_a(Abytes('hash', reader.read_bytes(32))) + ext.add_comp(mod) + mod_idx += 1 + + if reader.get_offset() > ext_end: + raise Exception('Malformed partition info extension length') + if reader.get_offset() < ext_end: + reader.ff_data(ext_end - reader.get_offset()) + elif ext_type == 15: reader.info("Plat Fw Auth extension") ext = PlatFwAuthExtension(ext_id, reader.get_offset()-8) ext.add_a(Astring('name', reader.read_string(4))) ext.add_a(Auint('vcn', reader.read_dw())) ext.add_a(Abytes('bitmap', reader.read_bytes(16), 'red')) ext.add_a(Auint('svn', reader.read_dw())) + + # Signed package info extension common fields + ext.add_a(Auint('fw_type', reader.read_b())) + ext.add_a(Auint('fw_sub_type', reader.read_b())) + ext.add_a(Abytes('reserved', reader.read_bytes(14), 'red')) + + mod_idx = 0 + while reader.get_offset() < ext_end: + mod = Component('signed_pkg_module_{}'.format(mod_idx), + 'Signed Package Module', reader.get_offset()) + mod.add_a(Astring('name', chararr_to_string(reader.read_bytes(12), 12))) + mod.add_a(Auint('type', reader.read_b())) + mod.add_a(Auint('hash_algo', reader.read_b())) + hash_size = reader.read_w() + mod.add_a(Auint('hash_size', hash_size)) + mod.add_a(Auint('meta_size', reader.read_dw())) + mod.add_a(Abytes('hash', reader.read_bytes(hash_size))) + ext.add_comp(mod) + mod_idx += 1 + + if reader.get_offset() > ext_end: + raise Exception('Malformed signed package extension length') + if reader.get_offset() < ext_end: + reader.ff_data(ext_end - reader.get_offset()) + elif ext_type == 0x16: + reader.info("Info extension 0x16") + ext = InfoExtension0x16(ext_id, reader.get_offset()-8) + ext.add_a(Astring('name', reader.read_string(4))) + ext.add_a(Auint('size', reader.read_dw())) + ext.add_a(Auint('data0', reader.read_dw())) + ext.add_a(Auint('data1', reader.read_dw())) + ext.add_a(Auint('data2', reader.read_dw())) + ext.add_a(Auint('data3', reader.read_dw())) + ext.add_a(Auint('data4', reader.read_dw())) + ext.add_a(Abytes('hash', reader.read_bytes(48))) + ext.add_a(Auint('data1_0', reader.read_dw())) + ext.add_a(Auint('data1_1', reader.read_dw())) + ext.add_a(Auint('data1_2', reader.read_dw())) + ext.add_a(Auint('data1_3', reader.read_dw())) + ext.add_a(Auint('data1_4', reader.read_dw())) read_len = reader.get_offset() - begin_off - reader.ff_data(ext_len - read_len) + effective_len = ext_end - begin_off + if read_len < effective_len: + reader.ff_data(effective_len - read_len) elif ext_type == 17: reader.info("ADSP metadata file extension") ext = AdspMetadataFileExt(ext_id, reader.get_offset()-8) ext.add_a(Auint('adsp_imr_type', reader.read_dw(), 'red')) - # skip reserved part - reader.read_bytes(16) - reader.read_dw() - reader.read_dw() - # - ext.add_a(Auint('version', reader.read_dw())) - ext.add_a(Abytes('sha_hash', reader.read_bytes(32))) - ext.add_a(Auint('base_offset', reader.read_dw())) - ext.add_a(Auint('limit_offset', reader.read_dw())) - ext.add_a(Abytes('attributes', reader.read_bytes(16))) + ext.add_a(Abytes('reserved', reader.read_bytes(16), 'red')) + + comp_desc = Component('adsp_comp_desc', 'Component Descriptor', + reader.get_offset()) + comp_desc_res0 = reader.read_dw() + comp_desc_res1 = reader.read_dw() + comp_desc_ver = reader.read_dw() + comp_desc.add_a(Auint('reserved0', comp_desc_res0)) + comp_desc.add_a(Auint('reserved1', comp_desc_res1)) + comp_desc.add_a(Auint('version', comp_desc_ver)) + ext.add_a(Auint('comp_desc_reserved0', comp_desc_res0)) + ext.add_a(Auint('comp_desc_reserved1', comp_desc_res1)) + ext.add_a(Auint('version', comp_desc_ver)) + + remaining = ext_end - reader.get_offset() + if remaining >= 72: + hash_len = 48 + else: + hash_len = 32 + + comp_hash = reader.read_bytes(hash_len) + comp_desc.add_a(Abytes('hash', comp_hash)) + ext.add_a(Abytes('sha_hash', comp_hash)) + + base_offset = reader.read_dw() + limit_offset = reader.read_dw() + comp_desc.add_a(Auint('base_offset', base_offset)) + comp_desc.add_a(Auint('limit_offset', limit_offset)) + ext.add_a(Auint('base_offset', base_offset)) + ext.add_a(Auint('limit_offset', limit_offset)) + + attr0 = reader.read_dw() + attr1 = reader.read_dw() + attr2 = reader.read_dw() + attr3 = reader.read_dw() + comp_desc.add_a(Auint('attribute0', attr0)) + comp_desc.add_a(Auint('attribute1', attr1)) + comp_desc.add_a(Auint('attribute2', attr2)) + comp_desc.add_a(Auint('attribute3', attr3)) + ext.add_a(Abytes('attributes', struct.pack('IIII', attr0, attr1, + attr2, attr3))) + ext.add_comp(comp_desc) + + read_len = reader.get_offset() - begin_off + effective_len = ext_end - begin_off + if read_len < effective_len: + reader.ff_data(effective_len - read_len) + elif read_len > effective_len: + raise Exception('Malformed ADSP metadata file extension length') elif ext_type == 35: reader.info("Signed package info extension") ext = SignedPkgInfoExtension(ext_id, reader.get_offset()-8) ext.add_a(Astring('name', reader.read_string(4))) ext.add_a(Auint('vcn', reader.read_dw())) ext.add_a(Auint('svn', reader.read_dw())) - ext.add_a(Auint('partition_usage', reader.read_b(), 'red')) - read_len = reader.get_offset() - begin_off - reader.ff_data(ext_len - read_len) + ext.add_a(Auint('partition_usage', reader.read_b())) + ext.add_a(Auint('reserved0', reader.read_b(), 'red')) + ext.add_a(Auint('fw_type', reader.read_b())) + ext.add_a(Auint('fw_sub_type', reader.read_b())) + number_of_modules = reader.read_b() + ext.add_a(Auint('number_of_modules', number_of_modules)) + ext.add_a(Auint('boot_strap_svn', reader.read_b())) + ext.add_a(Abytes('reserved', reader.read_bytes(14), 'red')) + + mod_idx = 0 + while reader.get_offset() < ext_end: + mod = Component('signed_pkg_ace_module_{}'.format(mod_idx), + 'Signed Package Module', reader.get_offset()) + mod.add_a(Astring('name', chararr_to_string(reader.read_bytes(12), 12))) + mod.add_a(Auint('type', reader.read_b())) + mod.add_a(Auint('hash_algo', reader.read_b())) + mod.add_a(Abytes('reserved', reader.read_bytes(2), 'red')) + mod.add_a(Auint('meta_size', reader.read_dw())) + mod.add_a(Abytes('hash', reader.read_bytes(48))) + ext.add_comp(mod) + mod_idx += 1 + + if reader.get_offset() > ext_end: + raise Exception('Malformed signed package ACE extension length') + if reader.get_offset() < ext_end: + reader.ff_data(ext_end - reader.get_offset()) else: reader.info("Other extension") ext = MftExtension(ext_id, 'Other Extension', reader.get_offset()-8) - reader.ff_data(ext_len-8) + reader.ff_data(max(0, ext_end - reader.get_offset())) ext.add_a(Auint('type', ext_type)) ext.add_a(Auint('length', ext_len)) reader.info("... end of extension") @@ -987,16 +1199,22 @@ def parse_adsp_manifest_hdr(reader): reader.get_offset() -4) hdr.add_a(Astring('sig', sig)) - hdr.add_a(Auint('size', reader.read_dw())) + header_len = reader.read_dw() + hdr.add_a(Auint('header_len', header_len)) + hdr.add_a(Auint('size', header_len)) hdr.add_a(Astring('name', chararr_to_string(reader.read_bytes(8), 8))) - hdr.add_a(Auint('preload', reader.read_dw())) + preload_page_count = reader.read_dw() + hdr.add_a(Auint('preload_page_count', preload_page_count)) + hdr.add_a(Auint('preload', preload_page_count)) hdr.add_a(Auint('fw_image_flags', reader.read_dw())) hdr.add_a(Auint('feature_mask', reader.read_dw())) hdr.add_a(Aversion('build_version', reader.read_w(), reader.read_w(), reader.read_w(), reader.read_w())) hdr.add_a(Adec('num_module_entries', reader.read_dw())) - hdr.add_a(Ahex('hw_buf_base_addr', reader.read_dw())) + fw_compat = reader.read_dw() + hdr.add_a(Ahex('fw_compat', fw_compat)) + hdr.add_a(Ahex('hw_buf_base_addr', fw_compat)) hdr.add_a(Auint('hw_buf_length', reader.read_dw())) hdr.add_a(Ahex('load_offset', reader.read_dw())) @@ -1031,7 +1249,9 @@ def parse_adsp_manifest_mod_entry(index, reader): mod.add_a(Adec('cfg_count', reader.read_w())) mod.add_a(Auint('affinity_mask', reader.read_dw())) mod.add_a(Adec('instance_max_count', reader.read_w())) - mod.add_a(Auint('instance_stack_size', reader.read_w())) + instance_bss_size = reader.read_w() + mod.add_a(Auint('instance_bss_size', instance_bss_size)) + mod.add_a(Auint('instance_stack_size', instance_bss_size)) for i in range(0, 3): seg_flags = reader.read_dw() mod.add_a(Astring('seg_'+repr(i)+'_flags', @@ -1042,15 +1262,42 @@ def parse_adsp_manifest_mod_entry(index, reader): return mod +def parse_adsp_manifest_mod_config(index, reader): + """ Parses ADSP manifest module config from sof binary + """ + cfg = Component('mod_cfg_'+repr(index), 'Module Config', + reader.get_offset()) + cfg.add_a(Auint('par0', reader.read_dw())) + cfg.add_a(Auint('par1', reader.read_dw())) + cfg.add_a(Auint('par2', reader.read_dw())) + cfg.add_a(Auint('par3', reader.read_dw())) + cfg.add_a(Auint('is_pages', reader.read_dw())) + cfg.add_a(Auint('cps', reader.read_dw())) + cfg.add_a(Auint('ibs', reader.read_dw())) + cfg.add_a(Auint('obs', reader.read_dw())) + cfg.add_a(Auint('module_flags', reader.read_dw())) + cfg.add_a(Auint('cpc', reader.read_dw())) + cfg.add_a(Auint('obls', reader.read_dw())) + return cfg + def parse_adsp_manifest(reader, name): """ Parses ADSP manifest from sof binary """ adsp_mft = AdspManifest(name, reader.get_offset()) adsp_mft.add_comp(parse_adsp_manifest_hdr(reader)) num_module_entries = adsp_mft.cdir['adsp_mft_hdr'].adir['num_module_entries'].val + # Each module advertises its own cfg_count; the configs are packed + # contiguously after the module entries, so the total number written is the + # sum of every module's cfg_count (which can exceed num_module_entries). + num_mod_configs = 0 for i in range(0, num_module_entries): mod_entry = parse_adsp_manifest_mod_entry(i, reader) adsp_mft.add_comp(mod_entry) + num_mod_configs += mod_entry.adir['cfg_count'].val + + for i in range(0, num_mod_configs): + mod_cfg = parse_adsp_manifest_mod_config(i, reader) + adsp_mft.add_comp(mod_cfg) return adsp_mft @@ -1406,10 +1653,19 @@ def __init__(self, offset): def dump_info(self, pref, comp_filter): hdr = self.cdir['cse_mft_hdr'] - print('{}{} ver {} checksum {} partition name {}'. - format(pref, - self.name, hdr.adir['header_version'], - hdr.adir['checksum'], hdr.adir['partition_name'])) + out = '{}{} header_ver {} entry_ver {} partition name {}'.format( + pref, + self.name, + hdr.adir['header_version'], + hdr.adir['entry_version'], + hdr.adir['partition_name']) + if 'checksum' in hdr.adir: + out += ' checksum {}'.format(hdr.adir['checksum']) + if 'not_used' in hdr.adir: + out += ' not_used {}'.format(hdr.adir['not_used']) + if 'checksum32' in hdr.adir: + out += ' checksum32 {}'.format(hdr.adir['checksum32']) + print(out) self.dump_comp_info(pref, comp_filter + ['Header']) class CssManifest(Component): @@ -1454,6 +1710,7 @@ def dump_info(self, pref, comp_filter): print('{}{} type {} file offset 0x{:x} length {}'. format(pref, self.name, self.adir['type'], self.file_offset, self.adir['length'])) + self.dump_comp_info(pref, comp_filter) class PlatFwAuthExtension(MftExtension): """ Platform FW Auth Extension @@ -1469,6 +1726,9 @@ def dump_info(self, pref, comp_filter): out += ' vcn {}'.format(self.adir['vcn']) out += ' bitmap {}'.format(self.adir['bitmap']) out += ' svn {}'.format(self.adir['svn']) + out += ' fw_type {}'.format(self.adir['fw_type']) + out += ' fw_sub_type {}'.format(self.adir['fw_sub_type']) + out += ' reserved {}'.format(self.adir['reserved']) print(out) class SignedPkgInfoExtension(MftExtension): @@ -1485,6 +1745,54 @@ def dump_info(self, pref, comp_filter): out += ' vcn {}'.format(self.adir['vcn']) out += ' svn {}'.format(self.adir['svn']) out += ' partition_usage {}'.format(self.adir['partition_usage']) + out += ' reserved0 {}'.format(self.adir['reserved0']) + out += ' fw_type {}'.format(self.adir['fw_type']) + out += ' fw_sub_type {}'.format(self.adir['fw_sub_type']) + out += ' number_of_modules {}'.format(self.adir['number_of_modules']) + out += ' boot_strap_svn {}'.format(self.adir['boot_strap_svn']) + out += ' reserved {}'.format(self.adir['reserved']) + print(out) + +class PartitionInfoExtension(MftExtension): + """ Partition info Extension + """ + def __init__(self, ext_id, offset): + super(PartitionInfoExtension, + self).__init__(ext_id, 'Partition info Extension', offset) + + def dump_info(self, pref, comp_filter): + super().dump_info(pref, comp_filter) + out = '{}'.format(pref) + out += ' name {}'.format(self.adir['name']) + out += ' partition_length {}'.format(self.adir['partition_length']) + out += ' hash {}'.format(self.adir['hash']) + out += ' vcn {}'.format(self.adir['vcn']) + out += ' part_version {}'.format(self.adir['part_version']) + out += ' fmt_version {}'.format(self.adir['fmt_version']) + out += ' instance_id {}'.format(self.adir['instance_id']) + out += ' part_flags {}'.format(self.adir['part_flags']) + out += ' reserved {}'.format(self.adir['reserved']) + print(out) + +class InfoExtension0x16(MftExtension): + """ info_ext_0x16 Extension + """ + def __init__(self, ext_id, offset): + super(InfoExtension0x16, + self).__init__(ext_id, 'Info Extension 0x16', offset) + + def dump_info(self, pref, comp_filter): + super().dump_info(pref, comp_filter) + out = '{}'.format(pref) + out += ' name {}'.format(self.adir['name']) + out += ' size {}'.format(self.adir['size']) + out += ' data [{}, {}, {}, {}, {}]'.format( + self.adir['data0'], self.adir['data1'], self.adir['data2'], + self.adir['data3'], self.adir['data4']) + out += ' hash {}'.format(self.adir['hash']) + out += ' data1 [{}, {}, {}, {}, {}]'.format( + self.adir['data1_0'], self.adir['data1_1'], self.adir['data1_2'], + self.adir['data1_3'], self.adir['data1_4']) print(out) class AdspMetadataFileExt(MftExtension): @@ -1503,6 +1811,12 @@ def dump_info(self, pref, comp_filter): out += ' limit offset {}'.format(self.adir['limit_offset']) print(out) print('{} IMR type {}'.format(pref, self.adir['adsp_imr_type'])) + print('{} Reserved {}'.format(pref, self.adir['reserved'])) + print('{} Component desc reserved0 {}'.format(pref, + self.adir['comp_desc_reserved0'])) + print('{} Component desc reserved1 {}'.format(pref, + self.adir['comp_desc_reserved1'])) + print('{} SHA hash {}'.format(pref, self.adir['sha_hash'])) print('{} Attributes'.format(pref)) print('{} {}'.format(pref, self.adir['attributes'])) @@ -1519,6 +1833,7 @@ def dump_info(self, pref, comp_filter): out += ' build ver {}'.format(hdr.adir['build_version']) out += ' feature mask {}'.format(hdr.adir['feature_mask']) out += ' image flags {}'.format(hdr.adir['fw_image_flags']) + out += ' fw compat {}'.format(hdr.adir['fw_compat']) print(out) print('{} HW buffers base address {} length {}'. format(pref, @@ -1731,6 +2046,13 @@ def dump_info(self): DspMemorySegment('l2 lpsram', 0xbe800000, 1*64*1024) ]) +PTL_MEMORY_SPACE = DspMemory('Intel Pantherlake', + [ + DspMemorySegment('imr', 0xb0000000, 16*1024*1024), + DspMemorySegment('l2 hpsram', 0xbe000000, 30*64*1024), + DspMemorySegment('l2 lpsram', 0xbe800000, 1*64*1024) + ]) + DSP_MEM_SPACE_EXT = { 'apl' : APL_MEMORY_SPACE, 'glk' : APL_MEMORY_SPACE, @@ -1747,10 +2069,16 @@ def dump_info(self): 'ehl' : TGL_LP_MEMORY_SPACE, 'adl' : TGL_LP_MEMORY_SPACE, 'rpl' : TGL_LP_MEMORY_SPACE, + 'mtl' : TGL_LP_MEMORY_SPACE, + 'lnl' : TGL_LP_MEMORY_SPACE, + 'arl' : TGL_LP_MEMORY_SPACE, 'tgl-h' : TGL_H_MEMORY_SPACE, 'adl-s' : TGL_H_MEMORY_SPACE, 'rpl-s' : TGL_H_MEMORY_SPACE, + 'arl-s' : TGL_H_MEMORY_SPACE, + 'ptl' : PTL_MEMORY_SPACE, + 'nvl' : PTL_MEMORY_SPACE, } @@ -1873,6 +2201,7 @@ def main(args): comp_filter = [] if args.headers or args.no_modules: comp_filter.append('Module Entry') + comp_filter.append('Module Config') if args.no_headers: comp_filter.append('CSE Manifest') fw_bin.dump_info('', comp_filter) diff --git a/tools/test/audio/process_test.m b/tools/test/audio/process_test.m index 70df2978a439..1af293b1967a 100644 --- a/tools/test/audio/process_test.m +++ b/tools/test/audio/process_test.m @@ -442,7 +442,7 @@ function test_result_print(t, testverbose, testacronym, test) %% FIXME: get unique string to keep all the incremental logs for i = 1:length(test.ph) - title(test.ph(i), tstr); + title(test.ph(i), tstr, 'Interpreter', 'none'); end for i = 1:length(test.fh) diff --git a/tools/test/audio/src_test.m b/tools/test/audio/src_test.m index 28b86ba5d25a..6b28b62693d9 100644 --- a/tools/test/audio/src_test.m +++ b/tools/test/audio/src_test.m @@ -1,9 +1,9 @@ -function [n_fail, n_pass, n_na] = src_test(bits_in, bits_out, fs_in_list, fs_out_list, full_test, show_plots, comp) +function [n_fail, n_pass, n_na] = src_test(bits_in, bits_out, fs_in_list, fs_out_list, full_test, show_plots, comp, xtrun) %% % src_test - test with SRC test bench objective audio quality parameters % -% src_test(bits_in, bits_out, fs_in, fs_out) +% src_test(bits_in, bits_out, fs_in, fs_out, full_test, show_plots, comp, xtrun) % % bits_in - input word length % bits_out - output word length @@ -12,13 +12,17 @@ % full_test - set to 0 for chirp only, 1 for all, default 1 % show_plots - set to 1 to see plots, default 0 % comp - set to 'src' or 'asrc', default 'src' +% xtrun - set to 'xt-run' or 'xt-run --turbo' to test with xt-testbench +% +% E.g. +% src_test(32, 32, 44100, 48000, 1, 1, 'src', 'xt-run --turbo'); % % A default in-out matrix with 32 bits data is tested if the % parameters are omitted. % % SPDX-License-Identifier: BSD-3-Clause -% Copyright(c) 2016 Intel Corporation. All rights reserved. +% Copyright(c) 2016-2025 Intel Corporation. % Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> addpath('std_utils'); @@ -51,6 +55,9 @@ if nargin < 7 comp = 'src'; end +if nargin < 8 + xtrun = ''; +end if isempty(fs_in_list) fs_in_list = default_in; end @@ -58,7 +65,6 @@ fs_out_list = default_out; end - %% Generic test pass/fail criteria % Note that AAP and AIP are relaxed a bit from THD+N due to inclusion % of point Fs/2 to test. The stopband of kaiser FIR is not equiripple @@ -80,6 +86,7 @@ t.bits_out = bits_out; % Output word length t.full_test = full_test; % 0 is quick check only, 1 is full set t.comp = comp; % Component to test +t.xtrun = xtrun; %% Show graphics or not. With visible plot windows Octave may freeze if too % many windows are kept open. As workaround setting close windows to @@ -450,6 +457,7 @@ test.fs = t.fs1; test.fs1 = t.fs1; test.fs2 = t.fs2; +test.xtrun = t.xtrun; test.coef_bits = 24; % No need to use actual word length in test test.att_rec_db = 0; % Not used in simulation test test.quick = 0; % Test speed is no issue in simulation @@ -478,9 +486,9 @@ function src_test_result_print(t, testverbose, testacronym, ph) tstr = sprintf('%s SRC %d, %d', testverbose, t.fs1, t.fs2); if nargin > 3 && ~isempty(ph) - title(ph, tstr); + title(ph, tstr, 'Interpreter', 'none'); else - title(tstr); + title(tstr, 'Interpreter', 'none'); end pfn = sprintf('plots/%s_src_%d_%d.png', testacronym, t.fs1, t.fs2); print(pfn, '-dpng'); diff --git a/tools/test/audio/tdfb_enable.sh b/tools/test/audio/tdfb_enable.sh new file mode 100644 index 000000000000..ce7422be62ca --- /dev/null +++ b/tools/test/audio/tdfb_enable.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +amixer -c0 cset name='Analog Playback TDFB track' off +amixer -c0 cset name='Analog Playback TDFB angle set' 90 +amixer -c0 cset name='Analog Playback TDFB beam' on diff --git a/tools/test/audio/tdfb_test.m b/tools/test/audio/tdfb_test.m index ab153c04f803..0c75c3cf1053 100644 --- a/tools/test/audio/tdfb_test.m +++ b/tools/test/audio/tdfb_test.m @@ -1,31 +1,36 @@ -function tdfb_test() +function tdfb_test(xtrun) -% tdfb_test() +% tdfb_test(xtrun) % Inputs -% None +% xtrun - set to 'xt-run' or 'xt-run --turbo' to test with xt-testbench % % Outputs % None, to be added later when automatic pass/fail is possible to % determine. So far only visual check enabled. % SPDX-License-Identifier: BSD-3-Clause -% Copyright(c) 2020 Intel Corporation. All rights reserved. +% Copyright(c) 2020-2025 Intel Corporation. % Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> +if nargin < 1 + xtrun = ''; +end + % General settings cfg.delete_files = 1; cfg.do_plots = 1; -cfg.tunepath = '../../tune/tdfb/data'; +cfg.tunepath = '../../../src/audio/tdfb/tune/data'; +cfg.xtrun = xtrun; % Arrays to test. Since the two beams configurations are merge of two designs (pm90deg) % need to specify a compatible data file identifier for a single beam design (az0el0deg) -array_data_list = {'line2_50mm_az0el0deg_48khz', 'line4_28mm_az0el0deg_48khz', 'circular8_100mm_az0el0deg_48khz'}; -tdfb_name_list = {'', 'line4_28mm_pm90deg_48khz', 'circular8_100mm_pm30deg_48khz'}; +array_data_list = {'line2_50mm_az0el0deg_48khz'}; +tdfb_name_list = {''}; %% Prepare addpath('std_utils'); addpath('test_utils'); -addpath('../../tune/tdfb'); +addpath('../../../src/audio/tdfb/tune'); for i = 1:length(array_data_list) @@ -72,7 +77,7 @@ function tdfb_test() test.nch_out = bf.num_output_channels; test.ch_in = 1:test.nch_in; test.ch_out = 1:test.nch_out; -test.extra_opts=''; +test.extra_opts='-s tdfb_enable.sh'; if length(arrayid) test.comp = sprintf('tdfb_%s', arrayid); end @@ -119,6 +124,7 @@ function tdfb_test() test = test_defaults(bf, tdfb); test.fn_in = fullfile(cfg.tunepath, simcap_fn); test.fn_out = 'sinerot.raw'; +test.xtrun = cfg.xtrun; % Run test test = test_run_comp(test); @@ -202,7 +208,7 @@ function tdfb_test() hold off grid on; legend('ch1 in','ch1 out'); - title(tstr); + title(tstr, 'Interpreter', 'none'); end end diff --git a/tools/testbench/README.md b/tools/testbench/README.md index fb5ef9085312..d4030adc426d 100644 --- a/tools/testbench/README.md +++ b/tools/testbench/README.md @@ -14,6 +14,15 @@ * Allows easy use of conventional debugger, profiler, leak and memory check tools usage for DSP firmware code. +### Prerequisites + +Before running the SOF testbench, install the required dependencies: + +``` +sudo apt install valgrind octave-signal octave # For Ubuntu/Debian +sudo dnf install valgrind octave-signal octave # For Fedora +``` + ### Quick how-to The simplest way to build and execute testbench is with supplied @@ -55,6 +64,72 @@ directions, use -p 1,2,3,4 and provide multiple input and output files separated with comma. Use e.g. -i i1.raw,i2.raw -o o1.raw,o2.raw. +### Apply controls to simulation + +The testbench supports shell script like amixer and sleep commands for +the controls. Create e.g. this script file as controls.sh: + +``` +#!/bin/sh + +# Example test sequence for DRC and volume components + +amixer -c0 cset name='Post Mixer Analog Playback DRC switch' off +amixer -c0 cset name='Post Mixer Analog Playback Volume' 40,30 +sleep 1 +amixer -c0 cset name='Post Mixer Analog Playback Volume' 0 +sleep 1 +amixer -c0 cset name='Post Mixer Analog Playback Volume' 45 +``` + +Then generarate sine wave (997 Hz, -3 dB level, 3 seconds) with sox +and check the impact to processed signal with next commands: + +``` +sox -n --encoding signed-integer -L -r 48000 -c 2 -b 32 in.raw synth 3 sine 997 norm -3 + +tools/testbench/build_testbench/install/bin/sof-testbench4 -r 48000 -c 2 -b S32_LE -p 1,2 \ + -t tools/build_tools/topology/topology2/production/sof-hda-generic.tplg \ +-i in.raw -o out.raw -s controls.sh + +sox --encoding signed-integer -L -r 48000 -c 2 -b 32 out.raw out.wav +``` + +As second example apply in one second intervals bytes control blobs +for IIR equalizer. The impact is easiest to hear with pink noise +signal. Create the control script below and run the following commands +to create the input, run testbench, and convert to wav for examining +the output. + +``` +#!/bin/sh + +# Example test sequence for IIR equalizer, switch other processing off + +amixer -c0 cset name='Post Mixer Analog Playback DRC switch' off +amixer -c0 cset name='Post Mixer Analog Playback Volume' 45 +sof-ctl -c name='Post Mixer Analog Playback FIR Eq bytes' -s tools/ctl/ipc4/eq_fir/pass.txt +sof-ctl -c name='Post Mixer Analog Playback IIR Eq bytes' -s tools/ctl/ipc4/eq_iir/pass.txt +sleep 1 +sof-ctl -c name='Post Mixer Analog Playback IIR Eq bytes' -s tools/ctl/ipc4/eq_iir/loudness.txt +sleep 1 +sof-ctl -c name='Post Mixer Analog Playback IIR Eq bytes' -s tools/ctl/ipc4/eq_iir/bandpass.txt +sleep 1 +sof-ctl -c name='Post Mixer Analog Playback IIR Eq bytes' -s tools/ctl/ipc4/eq_iir/bassboost.txt +sleep 1 +sof-ctl -c name='Post Mixer Analog Playback IIR Eq bytes' -s tools/ctl/ipc4/eq_iir/highpass_50hz_0db_48khz.txt +``` + +``` +sox -n --encoding signed-integer -L -r 48000 -c 2 -b 32 in.raw synth 5 pinknoise norm -20 + +tools/testbench/build_testbench/install/bin/sof-testbench4 -r 48000 -c 2 -b S32_LE -p 1,2 \ + -t tools/build_tools/topology/topology2/production/sof-hda-generic.tplg \ + -i in.raw -o out.raw -s controls.sh + +sox --encoding signed-integer -L -r 48000 -c 2 -b 32 out.raw out.wav +``` + ### Run testbench with helper script The scripts/sof-testbench-helper.sh simplifies the task. See the help diff --git a/tools/testbench/file.c b/tools/testbench/file.c index 99c3f475a011..6e48cc184c38 100644 --- a/tools/testbench/file.c +++ b/tools/testbench/file.c @@ -27,7 +27,6 @@ #include "testbench/file_ipc4.h" #include "../../src/audio/copier/copier.h" - SOF_DEFINE_REG_UUID(file); DECLARE_TR_CTX(file_tr, SOF_UUID(file_uuid), LOG_LEVEL_INFO); LOG_MODULE_REGISTER(file, CONFIG_SOF_LOG_LEVEL); @@ -534,7 +533,7 @@ static int file_init_set_dai_data(struct processing_module *mod) struct dai_data *dd; struct copier_data *ccd = module_get_private_data(mod); - dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); + dd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*dd)); if (!dd) return -ENOMEM; @@ -559,7 +558,7 @@ static int file_init_set_dai_data(struct processing_module *mod) struct dai_data *dd; struct comp_dev *dev = mod->dev; - dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); + dd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*dd)); if (!dd) return -ENOMEM; @@ -601,14 +600,14 @@ static int file_init(struct processing_module *mod) tb_debug_print("file_init()\n"); - ccd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*ccd)); + ccd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*ccd)); if (!ccd) return -ENOMEM; mod_data->private = ccd; /* File component data is placed to copier's ipcgtw_data */ - cd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); if (!cd) { free(ccd); return -ENOMEM; @@ -632,8 +631,8 @@ static int file_init(struct processing_module *mod) /* set file comp mode */ cd->fs.mode = ipc_file->mode; - cd->rate = ipc_file->rate; - cd->channels = ipc_file->channels; + cd->fs.rate = ipc_file->rate; + cd->fs.channels = ipc_file->channels; cd->frame_fmt = ipc_file->frame_fmt; dev->direction = ipc_file->direction; dev->direction_set = true; @@ -669,7 +668,8 @@ static int file_init(struct processing_module *mod) } /* Change to DAI type is needed to avoid uninitialized hw params in - * pipeline_params, A file host can be left as SOF_COMP_MODULE_ADAPTER + * pipeline_params. For capture the file write is the host so set + * SOF_COMP_HOST to skip sink check in module_adapter_prepare(). */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { dev->ipc_config.type = SOF_COMP_DAI; @@ -678,6 +678,8 @@ static int file_init(struct processing_module *mod) fprintf(stderr, "error: failed set dai data.\n"); goto error; } + } else { + dev->ipc_config.type = SOF_COMP_HOST; } break; @@ -817,6 +819,14 @@ static int file_prepare(struct processing_module *mod, /* set file function */ stream = &buffer->stream; + + /* + * Real copier/DAI components call ipc4_update_buffer_format() to populate + * valid_sample_fmt; the testbench file component is the host endpoint stub + * so propagate cd->frame_fmt to the buffer's valid format too. + */ + audio_stream_set_valid_fmt(stream, cd->frame_fmt); + switch (audio_stream_get_frm_fmt(stream)) { case SOF_IPC_FRAME_S16_LE: cd->file_func = file_s16; @@ -859,8 +869,8 @@ static int file_get_hw_params(struct comp_dev *dev, tb_debug_print("file_hw_params()\n"); params->direction = dir; - params->rate = cd->rate; - params->channels = cd->channels; + params->rate = cd->fs.rate; + params->channels = cd->fs.channels; params->buffer_fmt = 0; params->frame_fmt = cd->frame_fmt; return 0; diff --git a/tools/testbench/include/testbench/file.h b/tools/testbench/include/testbench/file.h index 889649094429..dd1735026564 100644 --- a/tools/testbench/include/testbench/file.h +++ b/tools/testbench/include/testbench/file.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2018 Intel Corporation. All rights reserved. + * Copyright(c) 2018-2026 Intel Corporation. * * Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> * Liam Girdwood <liam.r.girdwood@linux.intel.com> @@ -13,7 +13,7 @@ #include <stdint.h> -#define FILE_MAX_COPIES_TIMEOUT 3 +#define FILE_MAX_COPIES_TIMEOUT 16 /**< Convert with right shift a bytes count to samples count */ #define FILE_BYTES_TO_S16_SAMPLES(s) ((s) >> 1) @@ -42,6 +42,8 @@ struct file_state { FILE *rfh, *wfh; /* read/write file handle */ char *fn; int copy_count; + int channels; + int rate; int n; enum file_mode mode; enum file_format f_format; @@ -56,8 +58,6 @@ struct file_comp_data; struct file_comp_data { struct file_state fs; enum sof_ipc_frame frame_fmt; - uint32_t channels; - uint32_t rate; int sample_container_bytes; int (*file_func)(struct file_comp_data *cd, struct audio_stream *sink, struct audio_stream *source, uint32_t frames); diff --git a/tools/testbench/include/testbench/topology_ipc4.h b/tools/testbench/include/testbench/topology_ipc4.h index 4a3d9ec96826..0f5d0699e08f 100644 --- a/tools/testbench/include/testbench/topology_ipc4.h +++ b/tools/testbench/include/testbench/topology_ipc4.h @@ -48,6 +48,10 @@ int tb_new_process(struct testbench_prm *tp); int tb_pipelines_set_state(struct testbench_prm *tp, int state, int dir); int tb_send_bytes_data(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx, uint32_t module_id, uint32_t instance_id, struct sof_abi_hdr *abi); +int tb_send_volume_control(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx, + struct tb_ctl *ctl, int *control_values, int num_values); +int tb_send_alsa_control(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx, struct tb_ctl *ctl, + int *control_values, int num_values, int param_id); int tb_set_reset_state(struct testbench_prm *tp); int tb_set_running_state(struct testbench_prm *tp); int tb_set_up_pipeline(struct testbench_prm *tp, struct tplg_pipeline_info *pipe_info); diff --git a/tools/testbench/include/testbench/utils.h b/tools/testbench/include/testbench/utils.h index 9d11dcab2641..a52688cb93dc 100644 --- a/tools/testbench/include/testbench/utils.h +++ b/tools/testbench/include/testbench/utils.h @@ -19,6 +19,11 @@ #define TB_MAX_INPUT_FILE_NUM 16 #define TB_MAX_OUTPUT_FILE_NUM 16 #define TB_MAX_PIPELINES_NUM 16 +#define TB_MAX_CMD_CHARS 256 +#define TB_MAX_CTL_NAME_CHARS 128 +#define TB_MAX_VOLUME_SIZE 120 +#define TB_MAX_BYTES_DATA_SIZE 8192 +#define TB_MAX_BLOB_CONTENT_CHARS 32768 /* number of widgets types supported in testbench */ #define TB_NUM_WIDGETS_SUPPORTED 16 @@ -32,14 +37,35 @@ struct file_comp_lookup { struct file_state *state; }; +struct tb_ctl { + struct tplg_comp_info *comp_info; + unsigned int module_id; + unsigned int instance_id; + unsigned int type; + unsigned int volume_table[TB_MAX_VOLUME_SIZE]; + unsigned int index; + char *data; + char name[TB_MAX_CTL_NAME_CHARS]; + 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; + }; +}; + +struct tb_glb_state { + char magic[8]; /* SOF_MAGIC */ + uint32_t num_ctls; /* number of ctls */ + size_t size; /* size of this structure in bytes */ + struct tb_ctl *ctl; +}; + #if CONFIG_IPC_MAJOR_4 #define TB_NAME_SIZE 256 #define TB_MAX_CONFIG_COUNT 2 #define TB_MAX_CONFIG_NAME_SIZE 64 -#define TB_MAX_VOLUME_SIZE 120 -#define TB_MAX_DATA_SIZE 512 -#define TB_MAX_CTLS 16 +#define TB_MAX_CTLS 32 struct tb_mq_desc { char queue_name[TB_NAME_SIZE]; @@ -55,27 +81,6 @@ struct tb_config { int channels; unsigned long format; }; - -struct tb_ctl { - unsigned int module_id; - unsigned int instance_id; - unsigned int type; - unsigned int volume_table[TB_MAX_VOLUME_SIZE]; - unsigned int index; - char data[TB_MAX_DATA_SIZE]; - 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; - }; -}; - -struct tb_glb_state { - char magic[8]; /* SOF_MAGIC */ - uint32_t num_ctls; /* number of ctls */ - size_t size; /* size of this structure in bytes */ - struct tb_ctl *ctl; -}; #endif /* @@ -93,6 +98,7 @@ struct testbench_prm { char *output_file[TB_MAX_OUTPUT_FILE_NUM]; /* output file names */ char *tplg_file; /* topology file to use */ char *bits_in; /* input bit format */ + char *control_file; int input_file_num; /* number of input files */ int output_file_num; /* number of output files */ int pipeline_num; @@ -100,8 +106,6 @@ struct testbench_prm { bool copy_check; int trace_level; int dynamic_pipeline_iterations; - int tick_period_us; - int pipeline_duration_ms; char *pipeline_string; int output_file_index; int input_file_index; @@ -125,6 +129,9 @@ struct testbench_prm { /* topology */ struct tplg_context tplg; + FILE *control_fh; + struct tb_glb_state glb_ctx; + #if CONFIG_IPC_MAJOR_4 struct list_item widget_list; struct list_item route_list; @@ -138,12 +145,23 @@ struct testbench_prm { struct tb_config config[TB_MAX_CONFIG_COUNT]; int num_configs; int period_frames; - struct tb_glb_state glb_ctx; #endif }; +/** + * @brief Record of heap memory usage for a module. + * + * Stores the maximum heap usage observed for a specific module, + * used for profiling and memory analysis in testbench. + */ +struct tb_heap_usage_record { + char *module_name; /**< Name of the module */ + size_t heap_max; /**< Maximum heap usage in bytes */ +}; + extern int debug; +int tb_decode_enum(struct snd_soc_tplg_enum_control *enum_ctl, char *token); int tb_find_file_components(struct testbench_prm *tp); int tb_free_all_pipelines(struct testbench_prm *tp); int tb_load_topology(struct testbench_prm *tp); @@ -152,12 +170,28 @@ int tb_pipeline_params(struct testbench_prm *tp, struct ipc *ipc, struct pipelin int tb_pipeline_reset(struct ipc *ipc, struct pipeline *p); int tb_pipeline_start(struct ipc *ipc, struct pipeline *p); int tb_pipeline_stop(struct ipc *ipc, struct pipeline *p); +int tb_read_controls(struct testbench_prm *tp, int64_t *sleep_ns); +int tb_set_bytes_control(struct testbench_prm *tp, struct tb_ctl *ctl, uint32_t *data); +int tb_set_enum_control(struct testbench_prm *tp, struct tb_ctl *ctl, char *control_params); int tb_set_reset_state(struct testbench_prm *tp); +int tb_set_mixer_control(struct testbench_prm *tp, struct tb_ctl *ctl, char *control_params); int tb_set_running_state(struct testbench_prm *tp); int tb_set_up_all_pipelines(struct testbench_prm *tp); int tb_setup(struct sof *sof, struct testbench_prm *tp); bool tb_is_pipeline_enabled(struct testbench_prm *tp, int pipeline_id); bool tb_schedule_pipeline_check_state(struct testbench_prm *tp); + +/** + * @brief Collect heap usage statistics for all modules. + * + * Iterates over the active modules in the testbench and records the maximum + * heap usage for each one into the provided array. + * + * @param tp Pointer to testbench parameters. + * @param rec Array of heap usage records to populate. + * @param count Pointer to an integer that receives the number of records written. + */ +void tb_collect_heap_usage(struct testbench_prm *tp, struct tb_heap_usage_record *rec, int *count); void tb_debug_print(char *message); void tb_free(struct sof *sof); void tb_free_topology(struct testbench_prm *tp); diff --git a/tools/testbench/testbench.c b/tools/testbench/testbench.c index 58236e986616..670f34c1ab27 100644 --- a/tools/testbench/testbench.c +++ b/tools/testbench/testbench.c @@ -128,9 +128,8 @@ static void print_usage(char *executable) printf(" 4 shows debug traces and previous, plus other testbench debug messages\n"); printf(" -p <pipeline1,pipeline2,...>\n"); printf(" -C <number of copy() iterations>\n"); - printf(" -D <pipeline duration in ms>\n"); printf(" -P <number of dynamic pipeline iterations>\n"); - printf(" -T <microseconds for tick, 0 for batch mode>\n\n"); + printf(" -s <script file to set controls, with amixer and sleep commands>\n\n"); printf("Options for input and output format override:\n"); printf(" -b <input_format>, S16_LE, S24_LE, or S32_LE\n"); printf(" -c <input channels>\n"); @@ -148,7 +147,7 @@ static int parse_input_args(int argc, char **argv, struct testbench_prm *tp) int option = 0; int ret = 0; - while ((option = getopt(argc, argv, "hd:i:o:t:b:r:R:c:n:C:P:p:T:D:")) != -1) { + while ((option = getopt(argc, argv, "hd:i:o:t:b:r:R:c:n:C:P:p:s:")) != -1) { switch (option) { /* input sample file */ case 'i': @@ -218,14 +217,9 @@ static int parse_input_args(int argc, char **argv, struct testbench_prm *tp) ret = parse_pipelines(optarg, tp); break; - /* Microseconds for tick, 0 = batch (tickless) */ - case 'T': - tp->tick_period_us = atoi(optarg); - break; - - /* pipeline duration in millisec, 0 = realtime (tickless) */ - case 'D': - tp->pipeline_duration_ms = atoi(optarg); + /* control script file name */ + case 's': + tp->control_file = strdup(optarg); break; /* print usage */ @@ -246,7 +240,9 @@ static int parse_input_args(int argc, char **argv, struct testbench_prm *tp) return ret; } -static void test_pipeline_stats(struct testbench_prm *tp, long long delta_t) +static void test_pipeline_stats(struct testbench_prm *tp, long long delta_t, + struct tb_heap_usage_record *heap_records, + int heap_records_count) { long long file_cycles, pipeline_cycles; float pipeline_mcps; @@ -290,22 +286,28 @@ static void test_pipeline_stats(struct testbench_prm *tp, long long delta_t) frames_out = n_out / tp->channels_out; printf("Input sample (frame) count: %d (%d)\n", n_in, n_in / tp->channels_in); printf("Output sample (frame) count: %d (%d)\n", n_out, frames_out); + if (heap_records_count > 0) { + for (i = 0; i < heap_records_count; i++) + printf("Heap usage for module %s: %u bytes\n", + heap_records[i].module_name, (uint32_t)heap_records[i].heap_max); + } + + printf("\n"); if (tp->total_cycles) { pipeline_cycles = tp->total_cycles - file_cycles; pipeline_mcps = (float)pipeline_cycles * tp->fs_out / frames_out / 1e6; + if (tb_check_trace(LOG_LEVEL_DEBUG)) + printf("Warning: Use -d 3 or smaller value to avoid traces to increase MCPS.\n"); + printf("Total execution cycles: %lld\n", tp->total_cycles); printf("File component cycles: %lld\n", file_cycles); printf("Pipeline cycles: %lld\n", pipeline_cycles); - printf("Pipeline MCPS: %6.2f\n", pipeline_mcps); - if (tb_check_trace(LOG_LEVEL_DEBUG)) - printf("Warning: Use -d 3 or smaller value to avoid traces to increase MCPS.\n"); + printf("Pipeline MCPS: %6.2f\n\n", pipeline_mcps); } if (delta_t) - printf("Total execution time: %lld us, %.2f x realtime\n", - delta_t, (float)frames_out / tp->fs_out * 1000000 / delta_t); - - printf("\n"); + printf("Total execution time: %lld us, %.2f x realtime\n\n", delta_t, + (float)frames_out / tp->fs_out * 1000000 / delta_t); } /* @@ -314,13 +316,16 @@ static void test_pipeline_stats(struct testbench_prm *tp, long long delta_t) */ static int pipline_test(struct testbench_prm *tp) { - int dp_count = 0; - struct timespec ts; - struct timespec td0, td1; - long long delta_t; + struct tb_heap_usage_record heap_usage_records[TB_NUM_WIDGETS_SUPPORTED]; + struct file_state *out_stat; + struct timespec td0 = {0}, td1 = {0}; + long long delta_t = 0; + int64_t next_control_ns; + int64_t time_ns; + float samples_to_ns; int err; - int nsleep_time; - int nsleep_limit; + int heap_usage_records_count = 0; + int dp_count = 0; /* build, run and teardown pipelines */ while (dp_count < tp->dynamic_pipeline_iterations) { @@ -356,45 +361,53 @@ static int pipline_test(struct testbench_prm *tp) break; } + /* Use first file writer to create simulation time. Calculate coefficient + * to calculate current time from file write samples count + */ + out_stat = tp->fw[0].state; + samples_to_ns = 1.0e9 / ((float)out_stat->channels * out_stat->rate); + + /* Apply initial controls time to call again controls handler */ + err = tb_read_controls(tp, &next_control_ns); + if (err) { + fprintf(stderr, "error: failed to read control commands.\n"); + goto out; + } + tb_gettime(&td0); - /* sleep to let the pipeline work - we exit at timeout OR - * if copy iterations OR max_samples is reached (whatever first) - */ - nsleep_time = 0; - ts.tv_sec = tp->tick_period_us / 1000000; - ts.tv_nsec = (tp->tick_period_us % 1000000) * 1000; - if (!tp->copy_check) - nsleep_limit = INT_MAX; - else - nsleep_limit = tp->copy_iterations * - tp->pipeline_duration_ms; - - while (nsleep_time < nsleep_limit) { -#if defined __XCC__ - err = 0; -#else - /* wait for next tick */ - err = nanosleep(&ts, &ts); -#endif - if (err == 0) { - nsleep_time += tp->tick_period_us; /* sleep fully completed */ - if (tb_schedule_pipeline_check_state(tp)) - break; - } else { - if (err == EINTR) { - continue; /* interrupted - keep going */ - } else { - printf("error: sleep failed: %s\n", strerror(err)); + while (true) { + if (tp->copy_check) { + if (tp->copy_iterations-- <= 0) break; + } + + if (tb_schedule_pipeline_check_state(tp)) + break; + + if (next_control_ns) { + time_ns = (int64_t)(samples_to_ns * out_stat->n); + if (time_ns >= next_control_ns) { + err = tb_read_controls(tp, &next_control_ns); + if (err) { + fprintf(stderr, + "error: failed to read control commands.\n"); + goto out; + } + + if (next_control_ns) + next_control_ns += time_ns; } } } tb_schedule_pipeline_check_state(tp); /* Once more to flush out remaining data */ - tb_gettime(&td1); + delta_t = (td1.tv_sec - td0.tv_sec) * 1000000; + delta_t += (td1.tv_nsec - td0.tv_nsec) / 1000; + tb_collect_heap_usage(tp, heap_usage_records, &heap_usage_records_count); +out: err = tb_set_reset_state(tp); if (err < 0) { fprintf(stderr, "error: pipeline reset %d failed %d\n", @@ -402,12 +415,7 @@ static int pipline_test(struct testbench_prm *tp) break; } - /* TODO: This should be printed after reset and free to get cleaner output - * but the file internal status would be lost there. - */ - delta_t = (td1.tv_sec - td0.tv_sec) * 1000000; - delta_t += (td1.tv_nsec - td0.tv_nsec) / 1000; - test_pipeline_stats(tp, delta_t); + test_pipeline_stats(tp, delta_t, heap_usage_records, heap_usage_records_count); err = tb_free_all_pipelines(tp); if (err < 0) { @@ -438,7 +446,6 @@ int main(int argc, char **argv) tp->pipeline_string = calloc(1, TB_DEBUG_MSG_LEN); tp->pipelines[0] = 1; tp->pipeline_num = 1; - tp->pipeline_duration_ms = 5000; tp->copy_iterations = 1; tp->trace_level = LOG_LEVEL_INFO; @@ -450,6 +457,9 @@ int main(int argc, char **argv) if (!tp->channels_out) tp->channels_out = tp->channels_in; + if (!tp->fs_out) + tp->fs_out = tp->fs_in; + /* check mandatory args */ if (!tp->tplg_file) { fprintf(stderr, "topology file not specified, use -t file.tplg\n"); @@ -486,6 +496,16 @@ int main(int argc, char **argv) goto out; } + if (tp->control_file) { + tp->control_fh = fopen(tp->control_file, "r"); + if (!tp->control_fh) { + fprintf(stderr, "error: opening script %s (%s).\n", + tp->control_file, strerror(errno)); + ret = -errno; + goto out; + } + } + /* build, run and teardown pipelines */ pipline_test(tp); @@ -497,6 +517,10 @@ int main(int argc, char **argv) /* free all other data */ free(tp->bits_in); free(tp->tplg_file); + free(tp->control_file); + if (tp->control_fh) + fclose(tp->control_fh); + for (i = 0; i < tp->output_file_num; i++) free(tp->output_file[i]); diff --git a/tools/testbench/topology_ipc3.c b/tools/testbench/topology_ipc3.c index b95dc9859e68..331ab2ff1103 100644 --- a/tools/testbench/topology_ipc3.c +++ b/tools/testbench/topology_ipc3.c @@ -98,7 +98,8 @@ static int tb_register_graph(struct tplg_context *ctx, struct tplg_comp_info *te for (i = 0; i < num_connections; i++) { ret = tplg_create_graph(ctx, num_comps, pipeline_id, temp_comp_list, - pipeline_string, &connection, i); + pipeline_string, sizeof(pipeline_string), + &connection, i); if (ret < 0) return ret; diff --git a/tools/testbench/topology_ipc4.c b/tools/testbench/topology_ipc4.c index 3b018be3e2ce..9c4900f92fed 100644 --- a/tools/testbench/topology_ipc4.c +++ b/tools/testbench/topology_ipc4.c @@ -1055,8 +1055,8 @@ static inline int tb_insert_comp(struct testbench_prm *tp) list_item_append(&comp_info->item, &tp->widget_list); - printf("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, + printf("debug: loading comp_id %d: pipeline_id %d: widget %s type %d size %d at offset %ld is_pages %d\n", + comp_id, ctx->pipeline_id, ctx->widget->name, ctx->widget->id, ctx->widget->size, ctx->tplg_offset, comp_info->basecfg.is_pages); return 0; @@ -1286,6 +1286,7 @@ static int tb_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, struct snd_soc_tplg_mixer_control *tplg_mixer; struct snd_soc_tplg_enum_control *tplg_enum; struct snd_soc_tplg_bytes_control *tplg_bytes; + struct sof_abi_hdr *abi; if (glb->num_ctls >= TB_MAX_CTLS) { fprintf(stderr, "Error: Too many controls already.\n"); @@ -1316,6 +1317,8 @@ static int tb_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, ctl->type = tplg_ctl->type; tlv = &tplg_ctl->tlv; scale = &tlv->scale; + ctl->comp_info = comp_info; + strncpy(ctl->name, tplg_ctl->name, TB_MAX_CTL_NAME_CHARS); /* populate the volume table */ for (i = 0; i < tplg_mixer->max + 1 ; i++) { @@ -1338,6 +1341,8 @@ static int tb_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, ctl->enum_ctl = *tplg_enum; ctl->index = index; ctl->type = tplg_ctl->type; + ctl->comp_info = comp_info; + strncpy(ctl->name, tplg_ctl->name, TB_MAX_CTL_NAME_CHARS); break; case SND_SOC_TPLG_CTL_BYTES: { @@ -1349,7 +1354,33 @@ static int tb_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, ctl->bytes_ctl = *tplg_bytes; ctl->index = index; ctl->type = tplg_ctl->type; - memcpy(ctl->data, tplg_bytes->priv.data, tplg_bytes->priv.size); + if (tplg_bytes->priv.size > TB_MAX_BYTES_DATA_SIZE) { + fprintf(stderr, "Error: Too large bytes data size %d\n", + tplg_bytes->priv.size); + return -EINVAL; + } + + if (tplg_bytes->priv.size >= sizeof(struct sof_abi_hdr)) { + abi = (struct sof_abi_hdr *)tplg_bytes->priv.data; + if (abi->size > TB_MAX_BYTES_DATA_SIZE) { + fprintf(stderr, + "Error: ABI payload size %u exceeds max %d\n", + abi->size, TB_MAX_BYTES_DATA_SIZE); + return -EINVAL; + } + if (tplg_bytes->priv.size < + sizeof(struct sof_abi_hdr) + abi->size) { + fprintf(stderr, + "Error: bytes data size %d is smaller than ABI header + payload (%zu + %u)\n", + tplg_bytes->priv.size, + sizeof(struct sof_abi_hdr), abi->size); + return -EINVAL; + } + ctl->data = tplg_bytes->priv.data; + } + + ctl->comp_info = comp_info; + strncpy(ctl->name, tplg_ctl->name, TB_MAX_CTL_NAME_CHARS); break; } default: @@ -1735,4 +1766,146 @@ int tb_send_bytes_data(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx, return ret; } +int tb_send_volume_control(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx, + struct tb_ctl *ctl, int *control_values, int num_values) +{ + struct ipc4_module_large_config config = {{ 0 }}; + struct ipc4_peak_volume_config volume; + struct ipc4_message_reply reply; + struct ipc4_peak_volume_config *volume_config; + void *msg; + bool all_channels_equal = true; + int max_val; + int size; + int ret; + int val; + int i; + + volume_config = ctl->comp_info->ipc_payload + sizeof(struct ipc4_base_module_cfg); + max_val = ctl->mixer_ctl.max; + val = control_values[0]; + for (i = 0; i < num_values; i++) { + if (i > 0 && control_values[i] != val) + all_channels_equal = false; + + if (control_values[i] < 0 || control_values[i] > max_val) { + fprintf(stderr, "error: control value %d is illegal.\n", control_values[i]); + return -EINVAL; + } + } + + for (i = 0; i < num_values; i++) { + if (all_channels_equal) { + volume.channel_id = IPC4_ALL_CHANNELS_MASK; + volume.target_volume = ctl->volume_table[val]; + } else { + volume.channel_id = i; + volume.target_volume = ctl->volume_table[control_values[i]]; + } + + /* get curve duration and type from topology */ + volume.curve_type = volume_config->curve_type; + volume.curve_duration = volume_config->curve_duration; + + /* configure the IPC message */ + tb_ctl_ipc_message(&config, IPC4_VOLUME, sizeof(volume), ctl->module_id, + ctl->instance_id, SOF_IPC4_MOD_LARGE_CONFIG_SET); + config.extension.r.final_block = 1; + config.extension.r.init_block = 1; + + size = sizeof(config) + sizeof(volume); + msg = calloc(size, 1); + if (!msg) + return -ENOMEM; + + memcpy(msg, &config, sizeof(config)); + memcpy(msg + sizeof(config), &volume, sizeof(volume)); + + /* send the message and check status */ + ret = tb_mq_cmd_tx_rx(ipc_tx, ipc_rx, msg, size, &reply, sizeof(reply)); + free(msg); + if (ret < 0) { + fprintf(stderr, "failed to set volume control %s\n", ctl->name); + return ret; + } + + if (reply.primary.r.status != IPC4_SUCCESS) { + fprintf(stderr, "volume control %s set failed with status %d\n", + ctl->name, reply.primary.r.status); + return -EINVAL; + } + + if (all_channels_equal) + break; + } + + return 0; +} + +int tb_send_alsa_control(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx, + struct tb_ctl *ctl, int *control_values, int num_values, int param_id) +{ + struct ipc4_module_large_config config = {{ 0 }}; + struct sof_ipc4_control_msg_payload *data; + struct ipc4_message_reply reply; + void *msg; + int data_size; + int msg_size; + int ret; + int i; + + /* size of control data */ + data_size = num_values * sizeof(struct sof_ipc4_ctrl_value_chan) + sizeof(*data); + + /* allocate memory for control data */ + data = calloc(data_size, 1); + if (!data) + return -ENOMEM; + + /* set param ID and number of channels */ + data->id = ctl->index; + data->num_elems = num_values; + + /* set the enum values */ + for (i = 0; i < data->num_elems; i++) { + data->chanv[i].channel = i; + data->chanv[i].value = control_values[i]; + } + + /* configure the IPC message */ + tb_ctl_ipc_message(&config, param_id, data_size, ctl->module_id, ctl->instance_id, + SOF_IPC4_MOD_LARGE_CONFIG_SET); + config.extension.r.final_block = 1; + config.extension.r.init_block = 1; + + /* allocate memory for IPC message */ + msg_size = sizeof(config) + data_size; + msg = calloc(msg_size, 1); + if (!msg) { + free(data); + return -ENOMEM; + } + + /* set the IPC message data */ + memcpy(msg, &config, sizeof(config)); + memcpy(msg + sizeof(config), data, data_size); + free(data); + + /* send the message and check status */ + ret = tb_mq_cmd_tx_rx(ipc_tx, ipc_rx, msg, msg_size, &reply, sizeof(reply)); + free(msg); + if (ret < 0) { + fprintf(stderr, "error: failed to set control %s\n", ctl->name); + return ret; + } + + if (reply.primary.r.status != IPC4_SUCCESS) { + fprintf(stderr, "error: control %s set failed with status %d\n", + ctl->name, reply.primary.r.status); + return -EINVAL; + } + + return 0; +} + #endif /* CONFIG_IPC_MAJOR_4 */ diff --git a/tools/testbench/utils.c b/tools/testbench/utils.c index 6af8fbd73b2d..91c08c62aab1 100644 --- a/tools/testbench/utils.c +++ b/tools/testbench/utils.c @@ -6,8 +6,12 @@ #include <platform/lib/ll_schedule.h> #include <sof/audio/component.h> #include <sof/ipc/topology.h> +#include <sof/ipc/msg.h> +#include <sof/ipc/notification_pool.h> #include <sof/lib/notifier.h> +#include <ctype.h> +#include <errno.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -209,6 +213,13 @@ void tb_free(struct sof *sof) } free(*arch_schedulers_get()); + /* Drain IPC message queue to free queued notifications */ + while (!list_is_empty(&sof->ipc->msg_list)) + ipc_send_queued_msg(); + + /* Free notification pool items */ + ipc_notification_pool_free(); + /* free IPC data */ iipc = sof->ipc->private; free(sof->ipc->comp_data); @@ -256,3 +267,328 @@ void tb_getcycles(uint64_t *cycles) *cycles = 0; #endif } + +static void tb_trim_line(char *new, char *line) +{ + int i = 0; + int j = 0; + int n = strlen(line); + bool in_quotes = false; + + /* Trim begin */ + while (isspace((int)line[i]) && i < n) + i++; + + /* Copy line with multiple blanks removed, change single quotes to + * double quotes, don't remove blanks from inside quotes. + */ + while (i < n) { + if (!isspace((int)line[i])) { + if (line[i] == '\'') + new[j] = '\"'; + else + new[j] = line[i]; + if (new[j] == '\"') + in_quotes = !in_quotes; + j++; + i++; + } else if (in_quotes || ((i + 1) < n && !isspace((int)line[i + 1]))) { + new[j] = ' '; + j++; + i++; + } else { + i++; + } + } + new[j] = 0; +} + +static int tb_parse_sleep(char *line, int64_t *sleep_ns) +{ + char *token = strtok(line, "sleep "); + + *sleep_ns = (int64_t)(atof(token) * 1e9); + printf("Info: Next control will be applied after %lld ns.\n", (long long)*sleep_ns); + return 0; +} + +int tb_decode_enum(struct snd_soc_tplg_enum_control *enum_ctl, char *token) +{ + int enum_items = enum_ctl->items; + int i; + + for (i = 0; i < enum_items; i++) { + if (strcmp(enum_ctl->texts[i], token) == 0) + return i; + } + + return -EINVAL; +} + +static struct tb_ctl *tb_find_control_by_name(struct testbench_prm *tp, char *name) +{ + struct tb_glb_state *glb = &tp->glb_ctx; + struct tb_ctl *ctl; + int i; + + for (i = 0; i < glb->num_ctls; i++) { + ctl = &glb->ctl[i]; + if (strcmp(ctl->name, name) == 0) + return ctl; + } + + return NULL; +} + +static int tb_parse_amixer(struct testbench_prm *tp, char *line) +{ + char *line_end; + char *name_str; + char *end_str; + char control_name[TB_MAX_CTL_NAME_CHARS] = {0}; + char control_params[TB_MAX_CTL_NAME_CHARS] = {0}; + char *find_cset_name_str = "cset name=\""; + char *find_end_str = "\" "; + int find_len = strlen(find_cset_name_str); + int find_end_len = strlen(find_end_str); + int len; + struct tb_ctl *ctl; + int ret; + + name_str = strstr(line, find_cset_name_str); + if (!name_str) { + fprintf(stderr, "error: no control name in script line: %s\n", line); + return -EINVAL; + } + + end_str = strstr(&name_str[find_len], find_end_str); + if (!end_str) { + fprintf(stderr, "error: no control name end quote in script line: %s\n", line); + return -EINVAL; + } + + len = end_str - name_str - find_len; + if (len < 0 || len >= TB_MAX_CTL_NAME_CHARS) { + fprintf(stderr, "error: control name too long in script line: %s\n", line); + return -EINVAL; + } + memcpy(control_name, name_str + find_len, len); + + line_end = line + strlen(line); + len = line_end - end_str - find_end_len; + if (len < 0 || len >= TB_MAX_CTL_NAME_CHARS) { + fprintf(stderr, "error: control value too long in script line: %s\n", line); + return -EINVAL; + } + memcpy(control_params, &end_str[find_end_len], len); + + printf("Info: Setting control name '%s' to value (%s)\n", control_name, control_params); + + ctl = tb_find_control_by_name(tp, control_name); + if (!ctl) { + fprintf(stderr, "error: control %s not found in topology.\n", control_name); + return -EINVAL; + } + + switch (ctl->type) { + case SND_SOC_TPLG_TYPE_MIXER: + ret = tb_set_mixer_control(tp, ctl, control_params); + break; + case SND_SOC_TPLG_TYPE_ENUM: + ret = tb_set_enum_control(tp, ctl, control_params); + break; + default: + fprintf(stderr, "error: control %s type %d is not supported.\n", + control_name, ctl->type); + ret = -EINVAL; + } + + return ret; +} + +static int tb_parse_sofctl(struct testbench_prm *tp, char *line) +{ + struct tb_ctl *ctl; + uint32_t *blob_bin = NULL; + char *blob_name = NULL; + char *blob_str = NULL; + char *control_name = NULL; + char *end; + char *find_ctl_name_str = "-c name=\""; + char *find_end_str = "\" "; + char *find_set_switch_str = "-s"; + char *name_str; + char *rest; + char *token; + int copy_len; + int find_len = strlen(find_ctl_name_str); + int n = 0; + int ret = 0; + FILE *fh; + + name_str = strstr(line, find_ctl_name_str); + if (!name_str) { + fprintf(stderr, "error: no control name in script line: %s\n", line); + return -EINVAL; + } + + end = strstr(&name_str[find_len], find_end_str); + if (!end) { + fprintf(stderr, "error: no control name end quote in script line: %s\n", line); + return -EINVAL; + } + + copy_len = end - name_str - find_len; + control_name = strndup(name_str + find_len, copy_len); + if (!control_name) { + fprintf(stderr, "error: failed to duplicate control name.\n"); + return -errno; + } + + name_str = strstr(line, find_set_switch_str); + if (!name_str) { + fprintf(stderr, "error: no sof-ctl control set switch in command: %s.\n", + line); + ret = -EINVAL; + goto err; + } + + name_str += strlen(find_set_switch_str) + 1; + end = line + strlen(line); + copy_len = end - name_str; + blob_name = strndup(name_str, copy_len); + if (!blob_name) { + fprintf(stderr, "error: failed to duplicate blob name.\n"); + ret = -errno; + goto err; + } + + ctl = tb_find_control_by_name(tp, control_name); + if (!ctl) { + fprintf(stderr, "error: control %s not found in topology.\n", control_name); + ret = -EINVAL; + goto err; + } + + if (ctl->type != SND_SOC_TPLG_TYPE_BYTES) { + fprintf(stderr, "error: control %s type %d is not supported.\n", + control_name, ctl->type); + ret = -EINVAL; + goto err; + } + + blob_str = malloc(TB_MAX_BLOB_CONTENT_CHARS); + if (!blob_str) { + fprintf(stderr, "error: failed to allocate memory for blob file content.\n"); + ret = -ENOMEM; + goto err; + } + + blob_bin = malloc(TB_MAX_BYTES_DATA_SIZE); + if (!blob_bin) { + fprintf(stderr, "error: failed to allocate memory for blob data.\n"); + ret = -ENOMEM; + goto err; + } + + printf("Info: Setting control name '%s' to blob '%s'\n", control_name, blob_name); + fh = fopen(blob_name, "r"); + if (!fh) { + fprintf(stderr, "error: could not open file.\n"); + ret = -errno; + goto err; + } + + end = fgets(blob_str, TB_MAX_BLOB_CONTENT_CHARS, fh); + fclose(fh); + if (!end) { + fprintf(stderr, "error: failed to read data from blob file.\n"); + ret = -ENODATA; + goto err; + } + + rest = blob_str; + while ((token = strtok_r(rest, ",", &rest))) { + if (n == TB_MAX_BYTES_DATA_SIZE) { + fprintf(stderr, "error: data read exceeds max control data size.\n"); + ret = -EINVAL; + goto err; + } + + blob_bin[n] = atoi(token); + n++; + } + + if (n < 2) { + fprintf(stderr, "error: at least two values are required in the blob file.\n"); + ret = -EINVAL; + goto err; + } + + /* Ignore TLV header from beginning. */ + ret = tb_set_bytes_control(tp, ctl, &blob_bin[2]); + +err: + free(blob_str); + free(blob_bin); + free(blob_name); + free(control_name); + return ret; +} + +int tb_read_controls(struct testbench_prm *tp, int64_t *sleep_ns) +{ + char *sleep_cmd = "sleep "; + char *amixer_cmd = "amixer "; + char *sofctl_cmd = "sof-ctl "; + char *raw_line; + char *line; + int ret = 0; + + *sleep_ns = 0; + if (!tp->control_fh) + return 0; + + raw_line = malloc(TB_MAX_CMD_CHARS); + assert(raw_line); + + line = malloc(TB_MAX_CMD_CHARS); + assert(line); + + while (fgets(raw_line, TB_MAX_CMD_CHARS, tp->control_fh)) { + tb_trim_line(line, raw_line); + if (line[0] == '#' || strlen(line) == 0) + continue; + + if (strncmp(line, sleep_cmd, strlen(sleep_cmd)) == 0) { + ret = tb_parse_sleep(line, sleep_ns); + if (ret) { + fprintf(stderr, "error: failed parse of sleep command.\n"); + break; + } + break; + } + + if (strncmp(line, amixer_cmd, strlen(amixer_cmd)) == 0) { + ret = tb_parse_amixer(tp, line); + if (ret) { + fprintf(stderr, "error: failed parse of amixer command.\n"); + break; + } + continue; + } + + if (strncmp(line, sofctl_cmd, strlen(sofctl_cmd)) == 0) { + ret = tb_parse_sofctl(tp, line); + if (ret) { + fprintf(stderr, "error: failed parse of sof-ctl command.\n"); + break; + } + continue; + } + } + + free(line); + free(raw_line); + return ret; +} diff --git a/tools/testbench/utils_ipc3.c b/tools/testbench/utils_ipc3.c index ca98a5f0baf4..32c368efeb9a 100644 --- a/tools/testbench/utils_ipc3.c +++ b/tools/testbench/utils_ipc3.c @@ -24,8 +24,6 @@ int tb_setup(struct sof *sof, struct testbench_prm *tp) { struct ll_schedule_domain domain = {0}; - domain.next_tick = tp->tick_period_us; - /* init components */ sys_comp_init(sof); sys_comp_selector_init(); @@ -34,6 +32,7 @@ int tb_setup(struct sof *sof, struct testbench_prm *tp) sys_comp_module_crossover_interface_init(); sys_comp_module_dcblock_interface_init(); sys_comp_module_demux_interface_init(); + sys_comp_module_dolby_dax_audio_processing_interface_init(); sys_comp_module_drc_interface_init(); sys_comp_module_eq_fir_interface_init(); sys_comp_module_eq_iir_interface_init(); @@ -426,4 +425,25 @@ int tb_set_up_all_pipelines(struct testbench_prm *tp) return 0; } +/* No support in IPC3 version */ +int tb_set_enum_control(struct testbench_prm *tp, struct tb_ctl *ctl, char *control_params) +{ + return 0; +} + +int tb_set_mixer_control(struct testbench_prm *tp, struct tb_ctl *ctl, char *control_params) +{ + return 0; +} + +int tb_set_bytes_control(struct testbench_prm *tp, struct tb_ctl *ctl, uint32_t *data) +{ + return 0; +} + +void tb_collect_heap_usage(struct testbench_prm *tp, struct tb_heap_usage_record *rec, int *count) +{ + *count = 0; +} + #endif /* CONFIG_IPC_MAJOR_3 */ diff --git a/tools/testbench/utils_ipc4.c b/tools/testbench/utils_ipc4.c index 83bc3d36af94..6fed07e7b89b 100644 --- a/tools/testbench/utils_ipc4.c +++ b/tools/testbench/utils_ipc4.c @@ -4,6 +4,7 @@ #if CONFIG_IPC_MAJOR_4 +#include <sof/audio/module_adapter/module/generic.h> #include <sof/audio/component_ext.h> #include <sof/lib/notifier.h> #include <sof/audio/component_ext.h> @@ -38,16 +39,16 @@ int tb_setup(struct sof *sof, struct testbench_prm *tp) int bits; int krate; - domain.next_tick = tp->tick_period_us; - /* init components */ sys_comp_init(sof); /* Module adapter components */ sys_comp_module_aria_interface_init(); + sys_comp_module_asrc_interface_init(); sys_comp_module_crossover_interface_init(); sys_comp_module_dcblock_interface_init(); sys_comp_module_demux_interface_init(); + sys_comp_module_dolby_dax_audio_processing_interface_init(); sys_comp_module_drc_interface_init(); sys_comp_module_eq_fir_interface_init(); sys_comp_module_eq_iir_interface_init(); @@ -55,16 +56,20 @@ int tb_setup(struct sof *sof, struct testbench_prm *tp) sys_comp_module_gain_interface_init(); sys_comp_module_google_rtc_audio_processing_interface_init(); sys_comp_module_igo_nr_interface_init(); + sys_comp_module_level_multiplier_interface_init(); sys_comp_module_mfcc_interface_init(); sys_comp_module_mixin_interface_init(); sys_comp_module_mixout_interface_init(); sys_comp_module_multiband_drc_interface_init(); sys_comp_module_mux_interface_init(); + sys_comp_module_phase_vocoder_interface_init(); sys_comp_module_rtnr_interface_init(); sys_comp_module_selector_interface_init(); + sys_comp_module_sound_dose_interface_init(); sys_comp_module_src_interface_init(); - sys_comp_module_asrc_interface_init(); + sys_comp_module_stft_process_interface_init(); sys_comp_module_tdfb_interface_init(); + sys_comp_module_template_interface_init(); sys_comp_module_volume_interface_init(); /* other necessary initializations */ @@ -286,7 +291,8 @@ static int tb_set_up_widget(struct testbench_prm *tp, struct tplg_comp_info *com /* send the bytes data from kcontrols associated with current widget */ if (ctl->module_id != comp_info->module_id || ctl->instance_id != comp_info->instance_id || - ctl->type != SND_SOC_TPLG_TYPE_BYTES) + ctl->type != SND_SOC_TPLG_TYPE_BYTES || + !ctl->data) continue; abi = (struct sof_abi_hdr *)ctl->data; @@ -629,4 +635,111 @@ void tb_free_topology(struct testbench_prm *tp) tb_debug_print("freed all pipelines, widgets, routes and pcms\n"); } +int tb_set_enum_control(struct testbench_prm *tp, struct tb_ctl *ctl, char *control_params) +{ + int control_values[PLATFORM_MAX_CHANNELS]; + char *token, *rest; + int ret = 0; + int n = 0; + + rest = control_params; + while ((token = strtok_r(rest, ",", &rest))) { + if (n == PLATFORM_MAX_CHANNELS) { + fprintf(stderr, + "error: number of control values exceeds max channels count.\n"); + return -EINVAL; + } + + control_values[n] = tb_decode_enum(&ctl->enum_ctl, token); + if (control_values[n] < 0) { + fprintf(stderr, + "error: not able to decode enum %s.\n", token); + return -EINVAL; + } + n++; + } + + ret = tb_send_alsa_control(&tp->ipc_tx, &tp->ipc_rx, ctl, control_values, n, + SOF_IPC4_ENUM_CONTROL_PARAM_ID); + return ret; +} + +int tb_set_mixer_control(struct testbench_prm *tp, struct tb_ctl *ctl, char *control_params) +{ + int control_values[PLATFORM_MAX_CHANNELS]; + char *token, *rest; + int n = 0; + int ret; + + rest = control_params; + while ((token = strtok_r(rest, ",", &rest))) { + if (n == PLATFORM_MAX_CHANNELS) { + fprintf(stderr, + "error: number of control values exceeds max channels count.\n"); + return -EINVAL; + } + + if (strcmp(token, "on") == 0) + control_values[n] = 1; + else if (strcmp(token, "off") == 0) + control_values[n] = 0; + else + control_values[n] = atoi(token); + + n++; + } + + if (ctl->mixer_ctl.max == 1) + ret = tb_send_alsa_control(&tp->ipc_tx, &tp->ipc_rx, ctl, control_values, n, + SOF_IPC4_SWITCH_CONTROL_PARAM_ID); + else + ret = tb_send_volume_control(&tp->ipc_tx, &tp->ipc_rx, ctl, control_values, n); + + return ret; +} + +int tb_set_bytes_control(struct testbench_prm *tp, struct tb_ctl *ctl, uint32_t *data) +{ + return tb_send_bytes_data(&tp->ipc_tx, &tp->ipc_rx, + ctl->module_id, ctl->instance_id, + (struct sof_abi_hdr *)data); +} + +void tb_collect_heap_usage(struct testbench_prm *tp, struct tb_heap_usage_record *records, + int *count_out) +{ + struct list_item *item; + size_t hwm; + int count = 0; + + list_for_item(item, &tp->widget_list) { + struct tplg_comp_info *info = container_of(item, struct tplg_comp_info, item); + uint32_t comp_id = IPC4_COMP_ID(info->module_id, info->instance_id); + struct comp_dev *dev = ipc4_get_comp_dev(comp_id); + + if (!dev || !dev->mod) + continue; + + /* In testbench environment, skip AIF/DAI because they are not real components. */ + if (info->type == SND_SOC_TPLG_DAPM_AIF_IN || + info->type == SND_SOC_TPLG_DAPM_AIF_OUT || + info->type == SND_SOC_TPLG_DAPM_DAI_IN || + info->type == SND_SOC_TPLG_DAPM_DAI_OUT) + continue; + + if (count >= TB_NUM_WIDGETS_SUPPORTED) { + fprintf(stderr, "Error: Too many components for heap records, max %d.\n", + TB_NUM_WIDGETS_SUPPORTED); + break; + } + + module_adapter_heap_usage(dev->mod, &hwm); + records[count].module_name = info->name; + records[count].heap_max = hwm; + count++; + } + + *count_out = count; +} + #endif /* CONFIG_IPC_MAJOR_4 */ diff --git a/tools/topology/CMakeLists.txt b/tools/topology/CMakeLists.txt index 33722120e41b..92a7acf6e5a6 100644 --- a/tools/topology/CMakeLists.txt +++ b/tools/topology/CMakeLists.txt @@ -1,18 +1,19 @@ set(SOF_TOPOLOGY_BINARY_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - +set(SOF_ALSA_TOOLS_DIR "${SOF_ROOT_SOURCE_DIRECTORY}/../tools/bin") +set(ALSATPLG_CMD "${SOF_ALSA_TOOLS_DIR}/alsatplg") function(alsatplg_version OUT_STATUS OUT_VERSION) - execute_process(COMMAND alsatplg --version + execute_process(COMMAND ${ALSATPLG_CMD} --version RESULT_VARIABLE status OUTPUT_VARIABLE stdout OUTPUT_STRIP_TRAILING_WHITESPACE) - message(DEBUG "alsatplg --version: status=${status}, output=${stdout}") + message(DEBUG "${ALSATPLG_CMD} --version: status=${status}, output=${stdout}") set(${OUT_STATUS} "${status}" PARENT_SCOPE) # Some error messages have already been printed on stderr if(NOT status EQUAL 0) - message(WARNING "alsatplg --version returned status: ${status}, + message(WARNING "${ALSATPLG_CMD} --version returned status: ${status}, ${stdout}") return() endif() @@ -32,7 +33,7 @@ endfunction() # Longer story in #5192. alsatplg_version(STATUS ALSATPLG_VERSION_NUMBER) if(NOT STATUS EQUAL 0) - message(WARNING "alsatplg failed: ${STATUS}; all topologies skipped") + message(WARNING "${ALSATPLG_CMD} failed: ${STATUS}; all topologies skipped") return() else() if(${ALSATPLG_VERSION_NUMBER} VERSION_LESS "1.2.5") @@ -67,7 +68,7 @@ macro(add_alsatplg_command) # permissions are hardcoded and only the user can read # the -o(utput) file. # See bug https://github.com/alsa-project/alsa-utils/issues/126 - COMMAND alsatplg \$\${VERBOSE:+-v 1} -c ${ARGV0} -o ${ARGV1} + COMMAND ${ALSATPLG_CMD} \$\${VERBOSE:+-v 1} -c ${ARGV0} -o ${ARGV1} USES_TERMINAL ) endmacro() @@ -94,7 +95,7 @@ macro(add_alsatplg2_command conf_header conf_target input_name output_name inclu COMMAND cat ${conf_header} ${input_name}.conf > ${output_name}.conf # -p to pre-process Topology2.0 conf file - COMMAND ALSA_CONFIG_DIR=${CMAKE_SOURCE_DIR}/topology/topology2 alsatplg \$\${VERBOSE:+-v 1} + COMMAND ALSA_CONFIG_DIR=${CMAKE_SOURCE_DIR}/topology/topology2 ${ALSATPLG_CMD} \$\${VERBOSE:+-v 1} -I ${include_path} -D "'${defines}'" -p -c ${output_name}.conf -o ${output_name}.tplg USES_TERMINAL ) diff --git a/tools/topology/README.md b/tools/topology/README.md new file mode 100644 index 000000000000..8d10954a906a --- /dev/null +++ b/tools/topology/README.md @@ -0,0 +1,22 @@ +# SOF Topology Tools (`tools/topology`) + +The `tools/topology` directory contains the build infrastructure and source files used to generate Advanced Linux Sound Architecture (ALSA) topology (`.tplg`) binaries for Sound Open Firmware. + +ALSA topology files describe the audio DSP graph (pipelines, widgets, routes, DAIs) and are loaded dynamically by the Linux kernel SOF driver during initialization. This allows a single generic driver to support a wide variety of hardware configurations and routing paths without requiring source code changes in the kernel. + +## Directory Structure + +To support the evolution of the SOF topology syntax, the configuration files are split into two main versions: + +- [`topology1/`](topology1/README.md): Contains the legacy (v1) `m4`-based ALSA topology generation scripts and configuration files. Topology v1 heavily relies on `m4` macro preprocessing to generate the final `.conf` files before being compiled by `alsatplg`. +- [`topology2/`](topology2/README.md): Contains the newer (v2) ALSA topology generation files. Topology v2 introduces a more structured, object-oriented syntax natively supported by newer versions of the `alsatplg` compiler (specifically the pre-processor `-p` flag), reducing reliance on external macro languages. + +## Build Process + +The topology build process is managed by `CMakeLists.txt` in this root directory. It performs the following key steps: + +1. **Compiler Detection**: It locates the `alsatplg` tool (usually built in `tools/bin/alsatplg` alongside the firmware) and checks its version. +2. **Feature Validation**: It ensures the `alsatplg` version is at least `1.2.5`. Older versions are known to silently corrupt certain topology structures (e.g., converting `codec_consumer` to `codec_master`). If the tool is too old, topology generation is safely skipped with a warning. +3. **Target Generation**: It provides macros (`add_alsatplg_command` and `add_alsatplg2_command`) used by the subdirectories to invoke the topology compiler on the pre-processed `.conf` files to generate the final `.tplg` binaries. + +The `topologies` CMake target is the master target that depends on the generation targets inside both `topology1` and `topology2`. diff --git a/tools/topology/topology1/CMakeLists.txt b/tools/topology/topology1/CMakeLists.txt index c7e870b16837..95d81a01629f 100644 --- a/tools/topology/topology1/CMakeLists.txt +++ b/tools/topology/topology1/CMakeLists.txt @@ -56,6 +56,7 @@ set(TPLGS "sof-imx8mp-micfil\;sof-imx8mp-micfil" "sof-imx8mp-btsco-dual-8ch\;sof-imx8mp-btsco-dual-8ch" "sof-imx8-wm8960\;sof-imx8mp-wm8960\;-DCODEC=wm8960\;-DRATE=48000\;-DPPROC=volume\;-DSAI_INDEX=3" + "sof-imx8-wm8960\;sof-imx8mp-eap-wm8960\;-DCODEC=wm8960\;-DRATE=48000\;-DPPROC=eap\;-DSAI_INDEX=3" "sof-imx8-wm8960\;sof-imx8mp-wm8904\;-DCODEC=wm8904\;-DRATE=44100\;-DPPROC=volume\;-DSAI_INDEX=3" "sof-imx8-wm8960\;sof-imx8mp-wm8962\;-DCODEC=wm8962\;-DRATE=48000\;-DPPROC=volume\;-DSAI_INDEX=3" "sof-imx8-wm8960\;sof-imx8mp-eq-iir-wm8960\;-DCODEC=wm8960\;-DRATE=48000\;-DPPROC=eq-iir-volume\;-DSAI_INDEX=3" @@ -99,6 +100,12 @@ set(TPLGS "sof-mt8188-mt6359\;sof-mt8188" "sof-mt8188-mt6359\;sof-mt8188-waves\;-DWAVES=1" "sof-mt8196-mt6681\;sof-mt8196" + "sof-mt8196-mt6681\;sof-mt8196-waves\;-DWAVES=1" + "sof-mt8196-mt6681\;sof-mt8196-dts\;-DDTS=`DTS'" + "sof-mt8196-mt6681\;sof-mt8196-google-ctc\;-DGOOGLE_CTC=1" + "sof-mt8196-mt6681\;sof-mt8196-waves-google-ctc\;-DWAVES=1\;-DGOOGLE_CTC=1" + "sof-mt8365-mt6357\;sof-mt8365" + "sof-mt8365-mt6357\;sof-mt8365-waves\;-DWAVES=1" "sof-acp-renoir\;sof-acp" "sof-rn-rt5682-rt1019\;sof-rn-rt5682-rt1019" @@ -114,6 +121,10 @@ set(TPLGS "sof-acp_6_3\;sof-acp_6_3" "sof-acp_6_3_sdw\;sof-acp_6_3-rt711-l0-rt1316-l0-rt714-l1" "sof-acp_7_0\;sof-acp_7_0" + "sof-acp_7_0_sdw\;sof-acp_7_0-rt722-l0" + "sof-acp_7_x_sdw\;sof-acp7x-rt721-l0" + "sof-acp_7_x_i2s\;sof-acp7x" + "sof-acp_7_x_i2s_24bit\;sof-acp7x-24bit" ) # This empty 'production/' source subdirectory exists only to create the diff --git a/tools/topology/topology1/README.md b/tools/topology/topology1/README.md new file mode 100644 index 000000000000..78253bb06ee2 --- /dev/null +++ b/tools/topology/topology1/README.md @@ -0,0 +1,86 @@ +# ALSA Topology v1 (`tools/topology/topology1`) + +This directory contains the source files and `m4` macros used to generate version 1 of the ALSA topology binary files (`.tplg`) for Sound Open Firmware. + +## Overview + +Topology v1 relies heavily on the `m4` macro processor to handle the complexity and reusability of DSP graph definitions. Because raw ALSA configuration files for complex audio routing can become extremely verbose and repetitive, SOF uses `m4` to define logical blocks (like DAIs, SSPs, pipelines, and volume controls) that can be easily instantiated and connected. + +## Structure + +The core generation components include: + +- **`m4/`**: This directory contains the foundational macro definitions. These macros define how base elements like widgets (e.g., `PGA`, `Mixer`, `SRC`), pipelines, and routing paths are constructed in the ALSA `.conf` format. +- **`common/`**: Contains shared components and standard pipeline definitions that are reused across multiple different hardware platforms. +- **`platform/`**: Contains macros and configurations specific to individual hardware architectures (e.g., Intel cAVS, IMX). +- **Platform `.m4` files**: At the root of `topology1`, there are numerous `.m4` files (e.g., `sof-cavs-nocodec.m4`, `sof-imx8-wm8960.m4`). These are the top-level files that instantiate the macros to build a complete topology graph for a specific board or hardware configuration. + +## Component Assembly + +Building a topology in v1 is essentially a process of calling nested `m4` macros to piece together the DSP pipeline. Here's how the ingredients combine: + +1. **Base Macros (`m4/`)**: Define the raw ALSA syntax for things like a single PGA volume control or a DAI link. +2. **Pipelines (`common/`)**: Define a logical sequence of base widgets. For example, a "Playback Pipeline" macro might chain together a Host PCM, a Buffer, a Volume Control (PGA), and an output Buffer. +3. **Top-Level File (`*.m4`)**: Instantiates the pipelines, defines the physical DAI hardware connections, and sets up routing lines between the pipelines and the DAIs. + +```mermaid +graph TD + subgraph "Base Ingredients (m4/)" + A[Widget: PCM] + B[Widget: PGA Volume] + C[Widget: DAI] + D[Widget: Mixer] + end + + subgraph "Recipes (common/ & platform/)" + P1[Playback Pipeline] + P1 -.->|Includes| A + P1 -.->|Includes| B + + P2[Capture Pipeline] + P2 -.->|Includes| D + P2 -.->|Includes| C + end + + subgraph "The Meal (sof-board.m4)" + Top[Top-Level Topology] + Top ==>|Instantiates| P1 + Top ==>|Instantiates| P2 + Top ==>|Defines| Routes[Audio Routes] + Routes -.->|Connects Pipeline to DAI| Top + end +``` + +## Build Flow + +### Architecture Diagram + +```mermaid +flowchart TD + m4_core(["m4/ (Core Macros)"]) -.-> m4_plat(["platform/ (Platform Macros)"]) + m4_comp(["common/ (Shared Components)"]) -.-> m4_plat + + m4_plat -.-> m4_top(["sof-*.m4 (Top-level Platform File)"]) + + m4_top -->|"m4 processor"| conf["ALSA .conf Output"] + + conf -->|"alsatplg"| tplg["ALSA .tplg Binary"] +``` + +When the SOF build system compiles a v1 topology: + +1. The `m4` processor takes a top-level platform `.m4` file. +2. It expands all the macros defined in `m4/`, `common/`, and `platform/`. +3. The output is a raw ALSA `.conf` text file. +4. The `alsatplg` compiler parses this `.conf` file and compiles it into the final `.tplg` binary format loaded by the kernel. + +### Build Instructions + +Topologies are built automatically as part of the standard SOF CMake build process. To explicitly build all topologies (including v1): + +```bash +# From your build directory: +make topologies1 +# OR +cmake --build . --target topologies1 +``` diff --git a/tools/topology/topology1/m4/dai.m4 b/tools/topology/topology1/m4/dai.m4 index cd968c6c61fd..4dc5d5ec5135 100644 --- a/tools/topology/topology1/m4/dai.m4 +++ b/tools/topology/topology1/m4/dai.m4 @@ -155,7 +155,7 @@ define(`DO_DAI_CONFIG', `' ` id "'$3`"' `' -` ifelse($1, `SSP', $5, $1, `HDA', $5, $1, `ALH', $5, $1, `ESAI', $5, $1, `SAI', $5, $1, `MICFIL', $5, $1, `AFE', $5, $1, `ACP', $5, $1, `ACPSP', $5, $1,`ACPSP_VIRTUAL', $5, $1, `ACPHS', $5, $1, `ACPHS_VIRTUAL', $5, $1, `ACP_SDW', $5, $1, `ACPDMIC', $5, `}')' +` ifelse($1, `SSP', $5, $1, `HDA', $5, $1, `ALH', $5, $1, `ESAI', $5, $1, `SAI', $5, $1, `MICFIL', $5, $1, `AFE', $5, $1, `ACP', $5, $1, `ACPSP', $5, $1,`ACPSP_VIRTUAL', $5, $1, `ACPHS', $5, $1, `ACPHS_VIRTUAL', $5, $1, `ACP_SDW', $5, $1, `ACPDMIC', $5, $1, `ACPTDM', $5, `}')' `ifelse($1, `DMIC', $5, `')' `SectionVendorTuples."'N_DAI_CONFIG($1$2)`_tuples_common" {' ` tokens "sof_dai_tokens"' diff --git a/tools/topology/topology1/m4/eap.m4 b/tools/topology/topology1/m4/eap.m4 new file mode 100644 index 000000000000..1d223ad2cbdf --- /dev/null +++ b/tools/topology/topology1/m4/eap.m4 @@ -0,0 +1,69 @@ +divert(-1) + +dnl Define macro for EAP (Essential Audio Processing) widget +DECLARE_SOF_RT_UUID("eap", eap_uuid, 0x127f4eec, 0x23fa, 0x11f0, + 0xa4, 0xa6, 0xbf, 0x0c, 0xd6, 0xb4, 0x58, 0x3b) + +dnl EAP(name) +define(`N_EAP', `EAP'PIPELINE_ID`.'$1) + +dnl W_EAP(name, format, periods_sink, periods_source, core, kcontrols_list) +define(`W_EAP', +`SectionVendorTuples."'N_EAP($1)`_tuples_uuid" {' +` tokens "sof_comp_tokens"' +` tuples."uuid" {' +` SOF_TKN_COMP_UUID' STR(eap_uuid) +` }' +`}' +`SectionData."'N_EAP($1)`_data_uuid" {' +` tuples "'N_EAP($1)`_tuples_uuid"' +`}' +`SectionVendorTuples."'N_EAP($1)`_tuples_w" {' +` tokens "sof_comp_tokens"' +` tuples."word" {' +` SOF_TKN_COMP_PERIOD_SINK_COUNT' STR($3) +` SOF_TKN_COMP_PERIOD_SOURCE_COUNT' STR($4) +` SOF_TKN_COMP_CORE_ID' STR($5) +` }' +`}' +`SectionData."'N_EAP($1)`_data_w" {' +` tuples "'N_EAP($1)`_tuples_w"' +`}' +`SectionVendorTuples."'N_EAP($1)`_tuples_str" {' +` tokens "sof_comp_tokens"' +` tuples."string" {' +` SOF_TKN_COMP_FORMAT' STR($2) +` }' +`}' +`SectionData."'N_EAP($1)`_data_str" {' +` tuples "'N_EAP($1)`_tuples_str"' +`}' +`SectionVendorTuples."'N_EAP($1)`_tuples_str_type" {' +` tokens "sof_process_tokens"' +` tuples."string" {' +` SOF_TKN_PROCESS_TYPE' "EAP" +` }' +`}' +`SectionData."'N_EAP($1)`_data_str_type" {' +` tuples "'N_EAP($1)`_tuples_str_type"' +`}' +`SectionWidget."'N_EAP($1)`" {' +` index "'PIPELINE_ID`"' +` type "effect"' +` no_pm "true"' +` data [' +` "'N_EAP($1)`_data_uuid"' +` "'N_EAP($1)`_data_w"' +` "'N_EAP($1)`_data_str"' +` "'N_EAP($1)`_data_str_type"' +` ]' +` enum [' + $6 + $7 +` ]' +` bytes [' + $8 +` ]' +`}') + +divert(0)dnl diff --git a/tools/topology/topology1/m4/eap_controls.m4 b/tools/topology/topology1/m4/eap_controls.m4 new file mode 100644 index 000000000000..56bbb904a2a2 --- /dev/null +++ b/tools/topology/topology1/m4/eap_controls.m4 @@ -0,0 +1,12 @@ + +# EAP supported Audio Processing algorithms +CONTROLENUM_LIST(DEF_EAP_CFG_VALUES, + LIST(` ', `"Off"', `"AutoVolumeLeveler"', `"ConcertSound"', `"LoudnessMaximiser"', `"MusicEnhancerRMSLimiter"', `"VoiceEnhancer"')) + +# TDFB enum control +C_CONTROLENUM(DEF_EAP_CFG, PIPELINE_ID, + DEF_EAP_CFG_VALUES, + LIST(` ', ENUM_CHANNEL(FC, 3, 0)), + CONTROLENUM_OPS(enum, + 257 binds the mixer control to enum get/put handlers, + 257, 257)) diff --git a/tools/topology/topology1/m4/google_ctc_audio_processing.m4 b/tools/topology/topology1/m4/google_ctc_audio_processing.m4 new file mode 100644 index 000000000000..d5823814e862 --- /dev/null +++ b/tools/topology/topology1/m4/google_ctc_audio_processing.m4 @@ -0,0 +1,68 @@ +divert(-1) + +dnl Define macro for CTC Processing effect widget +DECLARE_SOF_RT_UUID("google-ctc-audio-processing", google_ctc_audio_processing_uuid, +0xbf0e1bbc, 0xdc6a, 0x45fe, 0xbc, 0x90, 0x25, 0x54, 0xcb, 0x13, 0x7a, 0xb4) + +dnl N_GOOGLE_CTC_AUDIO_PROCESSING(name) +define(`N_GOOGLE_CTC_AUDIO_PROCESSING', `GOOGLE_CTC_AUDIO_PROCESSING'PIPELINE_ID`.'$1) + +dnl W_GOOGLE_CTC_AUDIO_PROCESSING(name, format, periods_sink, periods_source, core, kcontrols_list) +define(`W_GOOGLE_CTC_AUDIO_PROCESSING', +`SectionVendorTuples."'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_tuples_uuid" {' +` tokens "sof_comp_tokens"' +` tuples."uuid" {' +` SOF_TKN_COMP_UUID' STR(google_ctc_audio_processing_uuid) +` }' +`}' +`SectionData."'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_data_uuid" {' +` tuples "'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_tuples_uuid"' +`}' +`SectionVendorTuples."'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_tuples_w" {' +` tokens "sof_comp_tokens"' +` tuples."word" {' +` SOF_TKN_COMP_PERIOD_SINK_COUNT' STR($3) +` SOF_TKN_COMP_PERIOD_SOURCE_COUNT' STR($4) +` SOF_TKN_COMP_CORE_ID' STR($5) +` }' +`}' +`SectionData."'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_data_w" {' +` tuples "'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_tuples_w"' +`}' +`SectionVendorTuples."'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_tuples_str" {' +` tokens "sof_comp_tokens"' +` tuples."string" {' +` SOF_TKN_COMP_FORMAT' STR($2) +` }' +`}' +`SectionData."'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_data_str" {' +` tuples "'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_tuples_str"' +`}' +`SectionVendorTuples."'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_tuples_str_type" {' +` tokens "sof_process_tokens"' +` tuples."string" {' +` SOF_TKN_PROCESS_TYPE' "GOOGLE_CTC_AUDIO_PROCESSING" +` }' +`}' +`SectionData."'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_data_str_type" {' +` tuples "'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_tuples_str_type"' +`}' +`SectionWidget."'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`" {' +` index "'PIPELINE_ID`"' +` type "effect"' +` no_pm "true"' +` data [' +` "'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_data_uuid"' +` "'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_data_w"' +` "'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_data_str"' +` "'N_GOOGLE_CTC_AUDIO_PROCESSING($1)`_data_str_type"' +` ]' +` bytes [' + $6 +` ]' +` mixer [' + $7 +` ]' +`}') + +divert(0)dnl diff --git a/tools/topology/topology1/m4/google_ctc_audio_processing_coef_default.m4 b/tools/topology/topology1/m4/google_ctc_audio_processing_coef_default.m4 new file mode 100644 index 000000000000..8b8283c0a21a --- /dev/null +++ b/tools/topology/topology1/m4/google_ctc_audio_processing_coef_default.m4 @@ -0,0 +1,6 @@ +CONTROLBYTES_PRIV(DEF_CTC_PRIV, +` bytes "0x53,0x4f,0x46,0x00,0x00,0x00,0x00,0x00,' +` 0x00,0x00,0x00,0x00,0x00,0xd0,0x01,0x03,' +` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' +` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00"' +) diff --git a/tools/topology/topology1/platform/common/acp-tdm.m4 b/tools/topology/topology1/platform/common/acp-tdm.m4 new file mode 100644 index 000000000000..22e72b0d5ea4 --- /dev/null +++ b/tools/topology/topology1/platform/common/acp-tdm.m4 @@ -0,0 +1,74 @@ +divert(-1) + +dnl ACPTDM related macros + +dnl ACP_CLOCK(clock, freq, codec_provider, polarity) +dnl polarity is optional +define(`ACP_CLOCK', + $1 STR($3) + $1_freq STR($2)) + `ifelse($4, `inverted', `$1_invert "true"',`')') + +dnl ACP_TDM(slots, width, tx_mask, rx_mask) +define(`ACP_TDM', +` tdm_slots 'STR($1) +` tdm_slot_width 'STR($2) +` tx_slots 'STR($3) +` rx_slots 'STR($4) +) + +dnl ACP_CONFIG(format, mclk, bclk, fsync, tdm, tdm_config_data) +define(`ACPTDM_CONFIG', +` format "'$1`"' +` '$2 +` '$3 +` '$4 +` '$5 +`}' +$6 +) + +dnl ACPTDM_VIRTUAL_CONFIG(format, mclk, bclk, fsync, tdm, tdm_config_data) +define(`ACPTDM_VIRTUAL_CONFIG', +` format "'$1`"' +` '$2 +` '$3 +` '$4 +` '$5 +`}' +$6 +) + +dnl ACPTDM_CONFIG_DATA(type, idx, rate, channel,i2s_tdm_mode) +#i2s_tdm_mode 1-> tdm mode, 0->i2s mode +define(`ACPTDM_CONFIG_DATA', +`SectionVendorTuples."'N_DAI_CONFIG($1$2)`_tuples" {' +` tokens "sof_acp_tokens"' +` tuples."word" {' +` SOF_TKN_AMD_ACP_RATE' STR($3) +` SOF_TKN_AMD_ACP_CH' STR($4) +` SOF_TKN_AMD_ACP_I2S_TDM_MODE' STR($5) +` SOF_TKN_AMD_ACP_I2S_BITDEPTH' STR($6) +` }' +`}' +`SectionData."'N_DAI_CONFIG($1$2)`_data" {' +` tuples "'N_DAI_CONFIG($1$2)`_tuples"' +`}' +) + +dnl ACPTDM_VIRTUAL_CONFIG_DATA(type, idx, rate, channel,i2s_tdm_mode) +#i2s_tdm_mode 1-> tdm mode, 0->i2s mode +define(`ACPTDM_VIRTUAL_CONFIG_DATA', +`SectionVendorTuples."'N_DAI_CONFIG($1$2)`_tuples" {' +` tokens "sof_acp_tokens"' +` tuples."word" {' +` SOF_TKN_AMD_ACP_RATE' STR($3) +` SOF_TKN_AMD_ACP_CH' STR($4) +` SOF_TKN_AMD_ACP_I2S_TDM_MODE' STR($5) +` }' +`}' +`SectionData."'N_DAI_CONFIG($1$2)`_data" {' +` tuples "'N_DAI_CONFIG($1$2)`_tuples"' +`}' +) +divert(0)dnl diff --git a/tools/topology/topology1/platform/mediatek/mt8365.m4 b/tools/topology/topology1/platform/mediatek/mt8365.m4 new file mode 100644 index 000000000000..fa7eca700d68 --- /dev/null +++ b/tools/topology/topology1/platform/mediatek/mt8365.m4 @@ -0,0 +1,23 @@ +# +# MT8365 differentiation for pipelines and components +# + +include(`memory.m4') + +define(`PLATFORM_DAI_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE)) +define(`PLATFORM_HOST_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE)) +define(`PLATFORM_PASS_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE)) +define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE)) + +# Low Latency PCM Configuration +W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "50000"')) +W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens) + +# Media PCM Configuration +W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "100000"')) +W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens) + +# DAI schedule Configuration - scheduled by IRQ +W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "5000"')) +W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens) + diff --git a/tools/topology/topology1/sof-acp_7_0_sdw.m4 b/tools/topology/topology1/sof-acp_7_0_sdw.m4 new file mode 100644 index 000000000000..ca03f0cd2749 --- /dev/null +++ b/tools/topology/topology1/sof-acp_7_0_sdw.m4 @@ -0,0 +1,150 @@ +#Required Topology for rt722 with ACP DMIC Card for ACP_7_0 +# +# PCM Description DAI LINK DAI BE +# 0       HS Playback 0 SDW0-PIN0-Playback-SimpleJack       AUDIO_TX +# 1       HS Capture 1 SDW0-PIN3-Capture-SimpleJack    AUDIO_RX +# 2       Speaker playback 2 SDW0-PIN1-Playback-SmartAmp    BT_TX +# 4       SDW DMIC 4 SDW0-PIN5-Capture-SmartMic    HS_RX + +# +# Define the pipelines +# +# PCM0 ----> buffer ----> AUDIO_TX +# PCM1 <---- buffer <---- AUDIO_RX +# PCM2 ----> buffer ----> BT_TX +# PCM4 <---- buffer <---- HS_RX + +# Include topology builder +include(`utils.m4') +include(`dai.m4') +include(`pipeline.m4') +include(`acp-sdw.m4') +include(`acp-dmic.m4') + +# Include TLV library +include(`common/tlv.m4') + +# Include Token library +include(`sof/tokens.m4') + +# Include ACP DSP configuration +include(`platform/amd/acp.m4') + +DEBUG_START + +#/**********************************************************************************/ +# PCM 0, HS Playback, DAI link id 0, Dai index 0(Audio_Tx), BE SW0-PIN0-PLAYBACK + +#Driver dai index and dai BE +#DAI Index(Instance * 64 + base_index) DAI_BE +#0(AUDIO_TX) SDW0-PIN0-PLAYBACK-SimpleJack +#1(BT_TX) SDW0-PIN1-PLAYBACK-SmartAmp +#2(HS_TX) SDW0-PIN2-PLAYBACK +#3(AUDIO_RX) SDW0-PIN3-CAPTURE-SimpleJack +#4(BT_RX) SDW0-PIN4-CAPTURE-SmartAmp +#5(HS_RX) SDW0-PIN5-CAPTURE + +define(DI_SDW0_ACP_SW_Audio_TX, 0) +define(DI_SDW0_ACP_SW_BT_TX, 1) +define(DI_SDW0_ACP_SW_HS_TX, 2) +define(DI_SDW0_ACP_SW_Audio_RX, 3) +define(DI_SDW0_ACP_SW_BT_RX, 4) +define(DI_SDW0_ACP_SW_HS_RX, 5) +define(DI_SDW1_ACP_P1_SW_BT_RX, 68) +define(DI_SDW1_ACP_P1_SW_BT_TX, 65) + +define(DAI_BE_SDW0_ACP_SW_HS_TX, SDW0-PIN2-PLAYBACK) +define(DAI_BE_SDW1_ACP_P1_SW_BT_RX, SDW1-PIN1-CAPTURE-SmartMic) +define(DAI_BE_SDW1_ACP_P1_SW_BT_TX, SDW1-PIN1-PLAYBACK) +define(DAI_BE_ACP_SW_Audio_RX, SDW0-PIN3-CAPTURE-SimpleJack) +define(DAI_BE_SDW0_ACP_SW_Audio_TX, SDW0-PIN0-PLAYBACK-SimpleJack) +define(DAI_BE_SDW0_ACP_SW_BT_RX, SDW0-PIN4-CAPTURE-SmartAmp) +define(DAI_BE_SDW0_ACP_SW_BT_TX, SDW0-PIN1-PLAYBACK-SmartAmp) +define(DAI_BE_SDW0_ACP_SW_HS_RX, SDW0-PIN5-CAPTURE-SmartMic) + +#pipeline: name of the predefined pipeline +#pipe id: pipeline ID. This should be a unique ID identifying the pipeline +#pcm: PCM ID. This will be used to bind to the correct front end DAI link + +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) +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 0, 0, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +dnl DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) +DAI_ADD(sof/pipe-dai-playback.m4, 0, ACP_SDW, DI_SDW0_ACP_SW_Audio_TX, DAI_BE_SDW0_ACP_SW_Audio_TX, + PIPELINE_SOURCE_0, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_DMA) + +dnl DAI_CONFIG(type, dai_index, link_id, name, acphs_config/acpdmic_config) +dnl ACPHS_CONFIG(format, mclk, bclk, fsync, tdm, acphs_config_data) +dnl ACP_CLOCK(clock, freq, codec_provider, polarity) +dnl ACPHS_CONFIG_DATA(type, idx, valid bits, mclk_id) +dnl mclk_id is optional +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_Audio_TX, 0, DAI_BE_SDW0_ACP_SW_Audio_TX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_Audio_TX, 48000, 2))) + +PCM_PLAYBACK_ADD(ACP-SW0-PIN0-Playback-HS, 0, PIPELINE_PCM_0) +#/**********************************************************************************/ + + +#/**********************************************************************************/ +#PCM 1, HS Capture, DAI link id 1, Dai index 3(Audio_RX), BE SW0-PIN0-CAPTURE +# Capture pipeline 1 on PCM 1 using max 2 channels of s16le. +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 1, 1, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Capture DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-capture.m4, 1, ACP_SDW, DI_SDW0_ACP_SW_Audio_RX, DAI_BE_ACP_SW_Audio_RX, + PIPELINE_SINK_1, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_DMA) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_Audio_RX, 1, DAI_BE_ACP_SW_Audio_RX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_Audio_RX, 48000, 2))) + +PCM_CAPTURE_ADD(ACP-SW0-PIN0-Capture-HS, 1, PIPELINE_PCM_1) +#/**********************************************************************************/ + +#/**********************************************************************************/ +#PCM 2, Speaker Playback, DAI link id 2, Dai index 1(BT_TX), BE SW0-PIN1-PLAYBACK +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 2, 2, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# playback DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-playback.m4, 2, ACP_SDW, DI_SDW0_ACP_SW_BT_TX, DAI_BE_SDW0_ACP_SW_BT_TX, + PIPELINE_SOURCE_2, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_DMA) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_BT_TX, 2, DAI_BE_SDW0_ACP_SW_BT_TX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_BT_TX, 48000, 2))) + +PCM_PLAYBACK_ADD(ACP-SW0-PIN2-Playback-SPK, 2, PIPELINE_PCM_2) +#/**********************************************************************************/ + +#/**********************************************************************************/ +#PCM 4, SDW Capture, DAI link id 4, Dai index 5(HS_RX), BE SDW0-PIN5-CAPTURE-SmartMic +# Capture pipeline 1 on PCM 1 using max 2 channels of s16le. +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 4, 4, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Capture DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-capture.m4, 4, ACP_SDW, DI_SDW0_ACP_SW_HS_RX, DAI_BE_SDW0_ACP_SW_HS_RX, + PIPELINE_SINK_4, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_DMA) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_HS_RX, 4, DAI_BE_SDW0_ACP_SW_HS_RX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_HS_RX, 48000, 2))) + +PCM_CAPTURE_ADD(ACP-SW0-PIN5-CAPTURE-DMIC, 4, PIPELINE_PCM_4) +#/**********************************************************************************/ + +DEBUG_END diff --git a/tools/topology/topology1/sof-acp_7_x_i2s.m4 b/tools/topology/topology1/sof-acp_7_x_i2s.m4 new file mode 100644 index 000000000000..6f633f700a56 --- /dev/null +++ b/tools/topology/topology1/sof-acp_7_x_i2s.m4 @@ -0,0 +1,187 @@ +# +# Topology for ACP_7_X with TDM. +# +# Include topology builder +include(`utils.m4') +include(`dai.m4') +include(`pipeline.m4') +include(`acp-tdm.m4') + +# Include TLV library +include(`common/tlv.m4') + +# Include Token library +include(`sof/tokens.m4') + +# Include ACP DSP configuration +include(`platform/amd/acp.m4') + +# +# Pipeline Graph (16-bit / s16le): +# +# PLAYBACK: +# [Host PCM ] -> [Passthrough Pipeline ] -> [ACPTDM DAI ] +# s16le 2ch s16le 48kHz s16le 2ch +# | +# [acp-i2s0-codec] +# I2S bclk=3.072MHz +# fsync=48kHz, 2ch +# | +# CAPTURE: +# [ACPTDM DAI ] -> [Passthrough Pipeline ] -> [Host PCM ] +# s16le 2ch s16le 48kHz s16le 2ch +# + +DEBUG_START +#====================================================================== +# Playback pipeline 1 on PCM 0 using max 2 channels of s16le. + +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) +# Playback pipeline 0 on PCM 0, dai index 0, link id 0 using max 2 channels of s16le. + +# Schedule 96 frames per 2000us deadline on core 0 with priority 0 +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 0, 0, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Capture pipeline 3 on PCM 0, dai index 0 using max 2 channels of s16le. +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 3, 0, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) +#=========================================================================== +dnl DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) + +# Schedule 96 frames per 2000us deadline on core 0 with priority 0 + +# playback DAI is ACPTDM using 2 periods +DAI_ADD(sof/pipe-dai-playback.m4, + 0, ACPTDM, 0, acp-i2s0-codec, + PIPELINE_SOURCE_0, 2, s16le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +# Capture DAI is ACPTDM using 2 periods +DAI_ADD(sof/pipe-dai-capture.m4, + 3, ACPTDM, 0, acp-i2s0-codec, + PIPELINE_SINK_3, 2, s16le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) +#=========================================================================== +# playback DAI is ACPTDM using 2 periods + +dnl DAI_CONFIG(type, dai_index, link_id, name, ACPTDM_config/acpdmic_config) +dnl ACPTDM_CONFIG(format, mclk, bclk, fsync, tdm, ACPTDM_config_data) +dnl ACP_CLOCK(clock, freq, codec_provider, polarity) +dnl ACPTDM_CONFIG_DATA(type, idx, valid bits, mclk_id) +dnl mclk_id is optional + +DAI_CONFIG(ACPTDM, 0, 0, acp-i2s0-codec, + ACPTDM_CONFIG(I2S, ACP_CLOCK(mclk, 49152000, codec_mclk_in), + ACP_CLOCK(bclk, 3072000, codec_consumer), + ACP_CLOCK(fsync, 48000, codec_consumer), + ACP_TDM(2, 32, 3, 3),ACPTDM_CONFIG_DATA(ACPTDM, 0, 48000, 2, 0, 0)) +) +dnl PCM_DUPLEX_ADD(name, pcm_id, playback_pipeline, capture_pipeline) +PCM_DUPLEX_ADD(I2STDM0, 0, PIPELINE_PCM_0, PIPELINE_PCM_3) + +#==================================================================================================================== +# TDM instance 1 + +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) + +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 1, 1, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 4, 1, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +dnl DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) + +DAI_ADD(sof/pipe-dai-playback.m4, + 1, ACPTDM, 1, acp-i2s1-codec, + PIPELINE_SOURCE_1, 2, s16le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_ADD(sof/pipe-dai-capture.m4, + 4, ACPTDM, 1, acp-i2s1-codec, + PIPELINE_SINK_4, 2, s16le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) +dnl DAI_CONFIG(type, dai_index, link_id, name, ACPTDM_config/acpdmic_config) +dnl ACPTDM_CONFIG(format, mclk, bclk, fsync, tdm, ACPTDM_config_data) +dnl ACP_CLOCK(clock, freq, codec_provider, polarity) +dnl ACPTDM_CONFIG_DATA(type, idx, valid bits, mclk_id) +dnl mclk_id is optional + +DAI_CONFIG(ACPTDM, 1, 1, acp-i2s1-codec, + ACPTDM_CONFIG(I2S, ACP_CLOCK(mclk, 49152000, codec_mclk_in), + ACP_CLOCK(bclk, 3072000, codec_consumer), + ACP_CLOCK(fsync, 48000, codec_consumer), + ACP_TDM(2, 32, 3, 3), ACPTDM_CONFIG_DATA(ACPTDM, 1, 48000, 2, 0))) + +dnl PCM_DUPLEX_ADD(name, pcm_id, playback_pipeline, capture_pipeline) +PCM_DUPLEX_ADD(I2STDM1, 1, PIPELINE_PCM_1, PIPELINE_PCM_4) + +#==================================================================================================================== +# TDM instance 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) + +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 2, 2, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 5, 2, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +dnl DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) + +DAI_ADD(sof/pipe-dai-playback.m4, + 2, ACPTDM, 2, acp-i2s2-codec, + PIPELINE_SOURCE_2, 2, s16le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_ADD(sof/pipe-dai-capture.m4, + 5, ACPTDM, 2, acp-i2s2-codec, + PIPELINE_SINK_5, 2, s16le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +dnl DAI_CONFIG(type, dai_index, link_id, name, ACPTDM_config/acpdmic_config) +dnl ACPTDM_CONFIG(format, mclk, bclk, fsync, tdm, ACPTDM_config_data) +dnl ACP_CLOCK(clock, freq, codec_provider, polarity) +dnl ACPTDM_CONFIG_DATA(type, idx, valid bits, mclk_id) +dnl mclk_id is optional + +DAI_CONFIG(ACPTDM, 2, 2, acp-i2s2-codec, + ACPTDM_CONFIG(I2S, ACP_CLOCK(mclk, 49152000, codec_mclk_in), + ACP_CLOCK(bclk, 3072000, codec_consumer), + ACP_CLOCK(fsync, 48000, codec_consumer), + ACP_TDM(2, 32, 3, 3), ACPTDM_CONFIG_DATA(ACPTDM, 2, 48000, 2, 0))) + +dnl PCM_DUPLEX_ADD(name, pcm_id, playback_pipeline, capture_pipeline) +PCM_DUPLEX_ADD(I2STDM2, 2, PIPELINE_PCM_2, PIPELINE_PCM_5) +#==================================================================================================================== + +DEBUG_END diff --git a/tools/topology/topology1/sof-acp_7_x_i2s_24bit.m4 b/tools/topology/topology1/sof-acp_7_x_i2s_24bit.m4 new file mode 100644 index 000000000000..dabf7927d90c --- /dev/null +++ b/tools/topology/topology1/sof-acp_7_x_i2s_24bit.m4 @@ -0,0 +1,165 @@ +# +# Topology for ACP_7_x with TDM (24-bit). +# +# Include topology builder +include(`utils.m4') +include(`dai.m4') +include(`pipeline.m4') +include(`acp-tdm.m4') + +# Include TLV library +include(`common/tlv.m4') + +# Include Token library +include(`sof/tokens.m4') + +# Include ACP DSP configuration +include(`platform/amd/acp.m4') + +# +# Pipeline Graph (24-bit / s24le): +# +# PLAYBACK/CAPTURE: +# TDM0, TDM1, TDM2 each expose a duplex PCM. +# Host side uses s32le; DAI side uses s24le (frame_fmt=1). +# + +DEBUG_START +#====================================================================== +# Playback/Capture pipelines for three TDM instances (24-bit). + +# TDM instance 0 + +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) +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 0, 0, 2, s32le, + 2000, 0, 0, + 48000, 48000, 48000) + +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 3, 0, 2, s32le, + 2000, 0, 0, + 48000, 48000, 48000) + +dnl DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) +DAI_ADD(sof/pipe-dai-playback.m4, + 0, ACPTDM, 0, acp-i2s0-codec, + PIPELINE_SOURCE_0, 2, s24le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_ADD(sof/pipe-dai-capture.m4, + 3, ACPTDM, 0, acp-i2s0-codec, + PIPELINE_SINK_3, 2, s24le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +dnl DAI_CONFIG(type, dai_index, link_id, name, ACPTDM_config/acpdmic_config) +dnl ACPTDM_CONFIG(format, mclk, bclk, fsync, tdm, ACPTDM_config_data) +dnl ACP_CLOCK(clock, freq, codec_provider, polarity) +dnl ACPTDM_CONFIG_DATA(type, idx, rate, tdm_mode, frame_fmt(0 for s16le, 1 for s24le, 2 for s32le)) +dnl mclk_id is optional +DAI_CONFIG(ACPTDM, 0, 0, acp-i2s0-codec, + ACPTDM_CONFIG(I2S, ACP_CLOCK(mclk, 49152000, codec_mclk_in), + ACP_CLOCK(bclk, 3072000, codec_consumer), + ACP_CLOCK(fsync, 48000, codec_consumer), + ACP_TDM(2, 32, 3, 3), ACPTDM_CONFIG_DATA(ACPTDM, 0, 48000, 2, 0, 1))) + +dnl PCM_DUPLEX_ADD(name, pcm_id, playback_pipeline, capture_pipeline) +PCM_DUPLEX_ADD(I2STDM0, 0, PIPELINE_PCM_0, PIPELINE_PCM_3) + +#============================ +# TDM instance 1 + +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) +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 1, 1, 2, s32le, + 2000, 0, 0, + 48000, 48000, 48000) + +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 4, 1, 2, s32le, + 2000, 0, 0, + 48000, 48000, 48000) + +dnl DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) +DAI_ADD(sof/pipe-dai-playback.m4, + 1, ACPTDM, 1, acp-i2s1-codec, + PIPELINE_SOURCE_1, 2, s24le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_ADD(sof/pipe-dai-capture.m4, + 4, ACPTDM, 1, acp-i2s1-codec, + PIPELINE_SINK_4, 2, s24le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +dnl DAI_CONFIG(type, dai_index, link_id, name, ACPTDM_config/acpdmic_config) +dnl ACPTDM_CONFIG(format, mclk, bclk, fsync, tdm, ACPTDM_config_data) +dnl ACP_CLOCK(clock, freq, codec_provider, polarity) +dnl ACPTDM_CONFIG_DATA(type, idx, rate, tdm_mode, frame_fmt(0 for s16le, 1 for s24le, 2 for s32le)) +dnl mclk_id is optional +DAI_CONFIG(ACPTDM, 1, 1, acp-i2s1-codec, + ACPTDM_CONFIG(I2S, ACP_CLOCK(mclk, 49152000, codec_mclk_in), + ACP_CLOCK(bclk, 3072000, codec_consumer), + ACP_CLOCK(fsync, 48000, codec_consumer), + ACP_TDM(2, 32, 3, 3), ACPTDM_CONFIG_DATA(ACPTDM, 1, 48000, 2, 0, 1))) + +dnl PCM_DUPLEX_ADD(name, pcm_id, playback_pipeline, capture_pipeline) +PCM_DUPLEX_ADD(I2STDM1, 1, PIPELINE_PCM_1, PIPELINE_PCM_4) + +#============================ +# TDM instance 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) +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 2, 2, 2, s32le, + 2000, 0, 0, + 48000, 48000, 48000) + +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 5, 2, 2, s32le, + 2000, 0, 0, + 48000, 48000, 48000) + +dnl DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) +DAI_ADD(sof/pipe-dai-playback.m4, + 2, ACPTDM, 2, acp-i2s2-codec, + PIPELINE_SOURCE_2, 2, s24le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_ADD(sof/pipe-dai-capture.m4, + 5, ACPTDM, 2, acp-i2s2-codec, + PIPELINE_SINK_5, 2, s24le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +dnl DAI_CONFIG(type, dai_index, link_id, name, ACPTDM_config/acpdmic_config) +dnl ACPTDM_CONFIG(format, mclk, bclk, fsync, tdm, ACPTDM_config_data) +dnl ACP_CLOCK(clock, freq, codec_provider, polarity) +dnl ACPTDM_CONFIG_DATA(type, idx, rate, tdm_mode, frame_fmt(0 for s16le, 1 for s24le, 2 for s32le)) +dnl mclk_id is optional +DAI_CONFIG(ACPTDM, 2, 2, acp-i2s2-codec, + ACPTDM_CONFIG(I2S, ACP_CLOCK(mclk, 49152000, codec_mclk_in), + ACP_CLOCK(bclk, 3072000, codec_consumer), + ACP_CLOCK(fsync, 48000, codec_consumer), + ACP_TDM(2, 32, 3, 3), ACPTDM_CONFIG_DATA(ACPTDM, 2, 48000, 2, 0, 1))) + +dnl PCM_DUPLEX_ADD(name, pcm_id, playback_pipeline, capture_pipeline) +PCM_DUPLEX_ADD(I2STDM2, 2, PIPELINE_PCM_2, PIPELINE_PCM_5) + +DEBUG_END diff --git a/tools/topology/topology1/sof-acp_7_x_sdw.m4 b/tools/topology/topology1/sof-acp_7_x_sdw.m4 new file mode 100644 index 000000000000..99ee0e6b3040 --- /dev/null +++ b/tools/topology/topology1/sof-acp_7_x_sdw.m4 @@ -0,0 +1,132 @@ +#Required Topology for rt721 with ACP DMIC Card for ACP_7_X +# +# PCM Description DAI LINK DAI BE +# 0 HS Playback 0 SDW0-PIN0-PLAYBACK AUDIO_TX +# 1 HS Capture 1 SDW0-PIN11-CAPTURE AUDIO_RX +# 2 Speaker playback 2 SDW0-PIN4-PLAYBACK BT_TX +# 4 SDW DMIC 4 SDW0-PIN16-CAPTURE HS_RX + +# +# Define the pipelines +# +# PCM0 ----> buffer ----> AUDIO_TX +# PCM1 <---- buffer <---- AUDIO_RX +# PCM2 ----> buffer ----> BT_TX +# PCM4 <---- buffer <---- HS_RX + +# Include topology builder +include(`utils.m4') +include(`dai.m4') +include(`pipeline.m4') +include(`acp-sdw.m4') +include(`acp-dmic.m4') + +# Include TLV library +include(`common/tlv.m4') + +# Include Token library +include(`sof/tokens.m4') + +# Include ACP DSP configuration +include(`platform/amd/acp.m4') + +DEBUG_START + +define(DI_SDW0_ACP_SW_AUDIO_0_TX, 0 ) +define(DI_SDW0_ACP_SW_AUDIO_4_TX, 4 ) +define(DI_SDW0_ACP_SW_AUDIO_0_RX, 11) +define(DI_SDW0_ACP_SW_AUDIO_5_RX, 16) + +define(DAI_BE_SDW0_ACP_SW_AUDIO_4_TX, SDW0-PIN4-PLAYBACK) +define(DAI_BE_SDW0_ACP_SW_AUDIO_0_TX, SDW0-PIN0-PLAYBACK) + +define(DAI_BE_SDW0_ACP_SW_AUDIO_0_RX, SDW0-PIN11-CAPTURE) +define(DAI_BE_SDW0_ACP_SW_AUDIO_5_RX, SDW0-PIN16-CAPTURE) + +#pipeline: name of the predefined pipeline +#pipe id: pipeline ID. This should be a unique ID identifying the pipeline +#pcm: PCM ID. This will be used to bind to the correct front end DAI link + +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 DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) + +dnl DAI_CONFIG(type, dai_index, link_id, name, acphs_config/acpdmic_config) +dnl ACPHS_CONFIG(format, mclk, bclk, fsync, tdm, acphs_config_data) +dnl ACP_CLOCK(clock, freq, codec_provider, polarity) +dnl ACPHS_CONFIG_DATA(type, idx, valid bits, mclk_id) +dnl mclk_id is optional + +#/**********************************************************************************/ +# PCM 0, HS Playback, DAI link id 0, Dai index 0(Audio_Tx), BE SW0-PIN0-PLAYBACK +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 0, 0, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +DAI_ADD(sof/pipe-dai-playback.m4, 0, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_TX, DAI_BE_SDW0_ACP_SW_AUDIO_0_TX, +PIPELINE_SOURCE_0, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_TX, 0, DAI_BE_SDW0_ACP_SW_AUDIO_0_TX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_TX, 48000, 2))) +PCM_PLAYBACK_ADD(ACP-SW0-PIN0-Playback-HS, 0, PIPELINE_PCM_0) + +#/**********************************************************************************/ +#PCM 2, Speaker Playback, PIPE line 2, DAI link id 2, Dai index 4(DI_SDW0_ACP_SW_AUDIO_4_TX), DAI BE SDW0-PIN4-PLAYBACK-SmartAmp +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 2, 2, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# playback DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-playback.m4, 2, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_4_TX, DAI_BE_SDW0_ACP_SW_AUDIO_4_TX, + PIPELINE_SOURCE_2, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_4_TX, 2, DAI_BE_SDW0_ACP_SW_AUDIO_4_TX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_4_TX, 48000, 2))) + +PCM_PLAYBACK_ADD(ACP-SW0-PIN4-Playback-SPK, 2, PIPELINE_PCM_2) +#/**********************************************************************************/ + +#/**********************************************************************************/ +#PCM 1, HS Capture, DAI link id 1, Dai index 11(DI_SDW0_ACP_SW_AUDIO_0_RX), BE DAI_BE_SDW0_ACP_SW_AUDIO_0_RX +# Capture pipeline 1 on PCM 1 using max 2 channels of s16le. +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 1, 1, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Capture DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-capture.m4, 1, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_RX, DAI_BE_SDW0_ACP_SW_AUDIO_0_RX, + PIPELINE_SINK_1, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_RX, 1, DAI_BE_SDW0_ACP_SW_AUDIO_0_RX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_RX, 48000, 2))) + +PCM_CAPTURE_ADD(ACP-SW0-PIN11-Capture-HS, 1, PIPELINE_PCM_1) +#/**********************************************************************************/ +#/**********************************************************************************/ +#PCM 4, SDW Capture, DAI link id 4, Dai index 16(DI_SDW0_ACP_SW_AUDIO_5_RX), BE SDW0-PIN16-CAPTURE-SmartMic +# Capture pipeline 1 on PCM 1 using max 2 channels of s16le. +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 4, 4, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Capture DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-capture.m4, 4, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_5_RX, DAI_BE_SDW0_ACP_SW_AUDIO_5_RX, + PIPELINE_SINK_4, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_5_RX, 4, DAI_BE_SDW0_ACP_SW_AUDIO_5_RX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_5_RX, 48000, 2))) + +PCM_CAPTURE_ADD(ACP-SW0-PIN16-CAPTURE-DMIC, 4, PIPELINE_PCM_4) +#/**********************************************************************************/ + +DEBUG_END \ No newline at end of file diff --git a/tools/topology/topology1/sof-acp_7_x_sdw_24bit.m4 b/tools/topology/topology1/sof-acp_7_x_sdw_24bit.m4 new file mode 100644 index 000000000000..7b34e3625501 --- /dev/null +++ b/tools/topology/topology1/sof-acp_7_x_sdw_24bit.m4 @@ -0,0 +1,139 @@ +#Required Topology for rt721 with ACP DMIC Card for ACP_7_X +# +# PCM Description DAI LINK DAI BE +# 0 HS Playback 0 SDW0-PIN0-PLAYBACK AUDIO_TX +# 1 HS Capture 1 SDW0-PIN11-CAPTURE AUDIO_RX +# 2 Speaker playback 2 SDW0-PIN4-PLAYBACK BT_TX +# 4 SDW DMIC 4 SDW0-PIN16-CAPTURE HS_RX + +# +# Define the pipelines +# +# PCM0 ----> buffer ----> AUDIO_TX +# PCM1 <---- buffer <---- AUDIO_RX +# PCM2 ----> buffer ----> BT_TX +# PCM4 <---- buffer <---- HS_RX + +# Include topology builder +include(`utils.m4') +include(`dai.m4') +include(`pipeline.m4') +include(`acp-sdw.m4') +include(`acp-dmic.m4') + +# Include TLV library +include(`common/tlv.m4') + +# Include Token library +include(`sof/tokens.m4') + +# Include ACP DSP configuration +include(`platform/amd/acp.m4') + +DEBUG_START + +#/**********************************************************************************/ +# PCM 0, HS Playback, DAI link id 0, Dai index 0(Audio_Tx), BE SW0-PIN0-PLAYBACK + +#Driver dai index and dai BE +#DAI Index(Instance * 64 + base_index) DAI_BE +#0(DI_SDW0_ACP_SW_AUDIO_0_TX) SDW0-PIN0-PLAYBACK-SimpleJack +# DI_SDW0_ACP_SW_AUDIO_4_TX SDW0-PIN4-PLAYBACK-SmartAmp + +define(DI_SDW0_ACP_SW_AUDIO_0_TX, 0) +define(DI_SDW0_ACP_SW_AUDIO_4_TX, 4) +define(DI_SDW0_ACP_SW_AUDIO_0_RX, 11) +define(DI_SDW0_ACP_SW_AUDIO_5_RX, 16) + + +define(DAI_BE_SDW0_ACP_SW_AUDIO_4_TX, SDW0-PIN4-PLAYBACK-SmartAmp) +define(DAI_BE_SDW0_ACP_SW_AUDIO_0_TX, SDW0-PIN0-PLAYBACK-SimpleJack) + +define(DAI_BE_SDW0_ACP_SW_AUDIO_0_RX, SDW0-PIN11-CAPTURE-SimpleJack) +define(DAI_BE_SDW0_ACP_SW_AUDIO_5_RX, SDW0-PIN16-CAPTURE-SmartMic) + +#pipeline: name of the predefined pipeline +#pipe id: pipeline ID. This should be a unique ID identifying the pipeline +#pcm: PCM ID. This will be used to bind to the correct front end DAI link + +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 DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) + +dnl DAI_CONFIG(type, dai_index, link_id, name, acphs_config/acpdmic_config) +dnl ACPHS_CONFIG(format, mclk, bclk, fsync, tdm, acphs_config_data) +dnl ACP_CLOCK(clock, freq, codec_provider, polarity) +dnl ACPHS_CONFIG_DATA(type, idx, valid bits, mclk_id) +dnl mclk_id is optional + +#/**********************************************************************************/ +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 0, 0, 2, s32le, + 2000, 0, 0, + 48000, 48000, 48000) + +DAI_ADD(sof/pipe-dai-playback.m4, 0, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_TX, DAI_BE_SDW0_ACP_SW_AUDIO_0_TX, +PIPELINE_SOURCE_0, 2, s24le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_TX, 0, DAI_BE_SDW0_ACP_SW_AUDIO_0_TX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_TX, 48000, 2))) +PCM_PLAYBACK_ADD(ACP-SW0-PIN0-Playback-HS, 0, PIPELINE_PCM_0) + +#/**********************************************************************************/ +#PCM 2, Speaker Playback, PIPE line 2, DAI link id 2, Dai index 4(DI_SDW0_ACP_SW_AUDIO_4_TX), DAI BE SDW0-PIN4-PLAYBACK-SmartAmp +PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4, + 2, 2, 2, s32le, + 2000, 0, 0, + 48000, 48000, 48000) + +# playback DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-playback.m4, 2, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_4_TX, DAI_BE_SDW0_ACP_SW_AUDIO_4_TX, + PIPELINE_SOURCE_2, 2, s24le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_4_TX, 2, DAI_BE_SDW0_ACP_SW_AUDIO_4_TX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_4_TX, 48000, 2))) + +PCM_PLAYBACK_ADD(ACP-SW0-PIN4-Playback-SPK, 2, PIPELINE_PCM_2) +#/**********************************************************************************/ + +#/**********************************************************************************/ +#PCM 1, HS Capture, DAI link id 1, Dai index 11(DI_SDW0_ACP_SW_AUDIO_0_RX), BE DAI_BE_SDW0_ACP_SW_AUDIO_0_RX +# Capture pipeline 1 on PCM 1 using max 2 channels of s24le. +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 1, 1, 2, s32le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Capture DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-capture.m4, 1, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_RX, DAI_BE_SDW0_ACP_SW_AUDIO_0_RX, + PIPELINE_SINK_1, 2, s24le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_RX, 1, DAI_BE_SDW0_ACP_SW_AUDIO_0_RX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_RX, 48000, 2))) + +PCM_CAPTURE_ADD(ACP-SW0-PIN11-Capture-HS, 1, PIPELINE_PCM_1) +#/**********************************************************************************/ +#/**********************************************************************************/ +#PCM 4, SDW Capture, DAI link id 4, Dai index 16(DI_SDW0_ACP_SW_AUDIO_5_RX), BE SDW0-PIN16-CAPTURE-SmartMic +# Capture pipeline 1 on PCM 1 using max 2 channels of s24le. +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 4, 4, 2, s32le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Capture DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-capture.m4, 4, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_5_RX, DAI_BE_SDW0_ACP_SW_AUDIO_5_RX, + PIPELINE_SINK_4, 2, s24le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_5_RX, 4, DAI_BE_SDW0_ACP_SW_AUDIO_5_RX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_5_RX, 48000, 2))) + +PCM_CAPTURE_ADD(ACP-SW0-PIN16-CAPTURE-DMIC, 4, PIPELINE_PCM_4) + +DEBUG_END diff --git a/tools/topology/topology1/sof-acp_7_x_sdw_volume_comp.m4 b/tools/topology/topology1/sof-acp_7_x_sdw_volume_comp.m4 new file mode 100644 index 000000000000..1743a6c93830 --- /dev/null +++ b/tools/topology/topology1/sof-acp_7_x_sdw_volume_comp.m4 @@ -0,0 +1,229 @@ +#Required Topology for rt721 with ACP DMIC Card for ACP_7_X +# +# PCM Description DAI LINK DAI BE +# 0 HS Playback 0 SDW0-PIN0-PLAYBACK AUDIO_TX +# 1 HS Capture 1 SDW0-PIN11-CAPTURE AUDIO_RX +# 2 Speaker playback 2 SDW0-PIN4-PLAYBACK BT_TX +# 4 SDW DMIC 4 SDW0-PIN16-CAPTURE HS_RX + +# +# Define the pipelines +# +# PCM0 ----> buffer ----> AUDIO_TX +# PCM1 <---- buffer <---- AUDIO_RX +# PCM2 ----> buffer ----> BT_TX +# PCM4 <---- buffer <---- HS_RX + +# Include topology builder +include(`utils.m4') +include(`dai.m4') +include(`pipeline.m4') +include(`acp-sdw.m4') +include(`acp-dmic.m4') + +# Include TLV library +include(`common/tlv.m4') + +# Include Token library +include(`sof/tokens.m4') + +# Include ACP DSP configuration +include(`platform/amd/acp.m4') + +DEBUG_START + +#/**********************************************************************************/ +# PCM 0, HS Playback, DAI link id 0, Dai index 0(Audio_Tx), BE SW0-PIN0-PLAYBACK + +#Driver dai index and dai BE +#DAI Index(Instance * 64 + base_index) DAI_BE +#0(DI_SDW0_ACP_SW_AUDIO_0_TX) SDW0-PIN0-PLAYBACK-SimpleJack +# DI_SDW0_ACP_SW_AUDIO_4_TX SDW0-PIN4-PLAYBACK-SmartAmp + +define(DI_SDW0_ACP_SW_AUDIO_0_TX, 0 ) +define(DI_SDW0_ACP_SW_AUDIO_1_TX, 1 ) +define(DI_SDW0_ACP_SW_AUDIO_2_TX, 2 ) +define(DI_SDW0_ACP_SW_AUDIO_3_TX, 3 ) +define(DI_SDW0_ACP_SW_AUDIO_4_TX, 4 ) +define(DI_SDW0_ACP_SW_AUDIO_5_TX, 5 ) +define(DI_SDW0_ACP_SW_AUDIO_6_TX, 6 ) +define(DI_SDW0_ACP_SW_AUDIO_7_TX, 7 ) +define(DI_SDW0_ACP_SW_AUDIO_8_TX, 8 ) +define(DI_SDW0_ACP_SW_AUDIO_9_TX, 9 ) +define(DI_SDW0_ACP_SW_AUDIO_10_TX, 10) +define(DI_SDW0_ACP_SW_AUDIO_0_RX, 11) +define(DI_SDW0_ACP_SW_AUDIO_1_RX, 12) +define(DI_SDW0_ACP_SW_AUDIO_2_RX, 13) +define(DI_SDW0_ACP_SW_AUDIO_3_RX, 14) +define(DI_SDW0_ACP_SW_AUDIO_4_RX, 15) +define(DI_SDW0_ACP_SW_AUDIO_5_RX, 16) +define(DI_SDW0_ACP_SW_AUDIO_6_RX, 17) +define(DI_SDW0_ACP_SW_AUDIO_7_RX, 18) +define(DI_SDW0_ACP_SW_AUDIO_8_RX, 19) +define(DI_SDW0_ACP_SW_AUDIO_9_RX, 20) +define(DI_SDW0_ACP_SW_AUDIO_10_RX, 21) + +define(DI_SDW1_ACP_SW_AUDIO_0_TX, 64) +define(DI_SDW1_ACP_SW_AUDIO_1_TX, 65) +define(DI_SDW1_ACP_SW_AUDIO_2_TX, 66) +define(DI_SDW1_ACP_SW_AUDIO_3_TX, 67) +define(DI_SDW1_ACP_SW_AUDIO_4_TX, 68) +define(DI_SDW1_ACP_SW_AUDIO_5_TX, 69) +define(DI_SDW1_ACP_SW_AUDIO_6_TX, 70) +define(DI_SDW1_ACP_SW_AUDIO_7_TX, 71) +define(DI_SDW1_ACP_SW_AUDIO_8_TX, 72) +define(DI_SDW1_ACP_SW_AUDIO_9_TX, 73) +define(DI_SDW1_ACP_SW_AUDIO_10_TX, 74) +define(DI_SDW1_ACP_SW_AUDIO_0_RX, 75) +define(DI_SDW1_ACP_SW_AUDIO_1_RX, 76) +define(DI_SDW1_ACP_SW_AUDIO_2_RX, 77) +define(DI_SDW1_ACP_SW_AUDIO_3_RX, 78) +define(DI_SDW1_ACP_SW_AUDIO_4_RX, 79) +define(DI_SDW1_ACP_SW_AUDIO_5_RX, 80) +define(DI_SDW1_ACP_SW_AUDIO_6_RX, 81) +define(DI_SDW1_ACP_SW_AUDIO_7_RX, 82) +define(DI_SDW1_ACP_SW_AUDIO_8_RX, 83) +define(DI_SDW1_ACP_SW_AUDIO_9_RX, 84) +define(DI_SDW1_ACP_SW_AUDIO_10_RX, 85) + +define(DI_SDW2_ACP_SW_AUDIO_0_TX, 128) +define(DI_SDW2_ACP_SW_AUDIO_1_TX, 129) +define(DI_SDW2_ACP_SW_AUDIO_2_TX, 130) +define(DI_SDW2_ACP_SW_AUDIO_3_TX, 131) +define(DI_SDW2_ACP_SW_AUDIO_4_TX, 132) +define(DI_SDW2_ACP_SW_AUDIO_5_TX, 133) +define(DI_SDW2_ACP_SW_AUDIO_6_TX, 134) +define(DI_SDW2_ACP_SW_AUDIO_7_TX, 135) +define(DI_SDW2_ACP_SW_AUDIO_8_TX, 136) +define(DI_SDW2_ACP_SW_AUDIO_9_TX, 137) +define(DI_SDW2_ACP_SW_AUDIO_10_TX, 138) +define(DI_SDW2_ACP_SW_AUDIO_0_RX, 139) +define(DI_SDW2_ACP_SW_AUDIO_1_RX, 140) +define(DI_SDW2_ACP_SW_AUDIO_2_RX, 141) +define(DI_SDW2_ACP_SW_AUDIO_3_RX, 142) +define(DI_SDW2_ACP_SW_AUDIO_4_RX, 143) +define(DI_SDW2_ACP_SW_AUDIO_5_RX, 144) +define(DI_SDW2_ACP_SW_AUDIO_6_RX, 145) +define(DI_SDW2_ACP_SW_AUDIO_7_RX, 146) +define(DI_SDW2_ACP_SW_AUDIO_8_RX, 147) +define(DI_SDW2_ACP_SW_AUDIO_9_RX, 148) +define(DI_SDW2_ACP_SW_AUDIO_10_RX, 149) + +define(DI_SDW3_ACP_SW_AUDIO_0_TX, 192) +define(DI_SDW3_ACP_SW_AUDIO_1_TX, 193) +define(DI_SDW3_ACP_SW_AUDIO_2_TX, 194) +define(DI_SDW3_ACP_SW_AUDIO_3_TX, 195) +define(DI_SDW3_ACP_SW_AUDIO_4_TX, 196) +define(DI_SDW3_ACP_SW_AUDIO_5_TX, 197) +define(DI_SDW3_ACP_SW_AUDIO_6_TX, 198) +define(DI_SDW3_ACP_SW_AUDIO_7_TX, 199) +define(DI_SDW3_ACP_SW_AUDIO_8_TX, 200) +define(DI_SDW3_ACP_SW_AUDIO_9_TX, 201) +define(DI_SDW3_ACP_SW_AUDIO_10_TX, 202) +define(DI_SDW3_ACP_SW_AUDIO_0_RX, 203) +define(DI_SDW3_ACP_SW_AUDIO_1_RX, 204) +define(DI_SDW3_ACP_SW_AUDIO_2_RX, 205) +define(DI_SDW3_ACP_SW_AUDIO_3_RX, 206) +define(DI_SDW3_ACP_SW_AUDIO_4_RX, 207) +define(DI_SDW3_ACP_SW_AUDIO_5_RX, 208) +define(DI_SDW3_ACP_SW_AUDIO_6_RX, 209) +define(DI_SDW3_ACP_SW_AUDIO_7_RX, 210) +define(DI_SDW3_ACP_SW_AUDIO_8_RX, 211) +define(DI_SDW3_ACP_SW_AUDIO_9_RX, 212) +define(DI_SDW3_ACP_SW_AUDIO_10_RX, 213) + + +define(DAI_BE_SDW0_ACP_SW_AUDIO_4_TX, SDW0-PIN4-PLAYBACK-SmartAmp) +define(DAI_BE_SDW0_ACP_SW_AUDIO_0_TX, SDW0-PIN0-PLAYBACK-SimpleJack) +#define(DAI_BE_SDW1_ACP_SW_AUDIO_4_TX, SDW1-PIN4-PLAYBACK-SmartAmp) + +define(DAI_BE_SDW0_ACP_SW_AUDIO_0_RX, SDW0-PIN11-CAPTURE-SimpleJack) +define(DAI_BE_SDW0_ACP_SW_AUDIO_4_RX, SDW0-PIN15-CAPTURE-SmartMic) +define(DAI_BE_SDW0_ACP_SW_AUDIO_5_RX, SDW0-PIN16-CAPTURE-SmartMic) + +#pipeline: name of the predefined pipeline +#pipe id: pipeline ID. This should be a unique ID identifying the pipeline +#pcm: PCM ID. This will be used to bind to the correct front end DAI link + +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 DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) + +dnl DAI_CONFIG(type, dai_index, link_id, name, acphs_config/acpdmic_config) +dnl ACPHS_CONFIG(format, mclk, bclk, fsync, tdm, acphs_config_data) +dnl ACP_CLOCK(clock, freq, codec_provider, polarity) +dnl ACPHS_CONFIG_DATA(type, idx, valid bits, mclk_id) +dnl mclk_id is optional + +#/**********************************************************************************/ +PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, + 0, 0, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +DAI_ADD(sof/pipe-dai-playback.m4, 0, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_TX, DAI_BE_SDW0_ACP_SW_AUDIO_0_TX, +PIPELINE_SOURCE_0, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_TX, 0, DAI_BE_SDW0_ACP_SW_AUDIO_0_TX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_TX, 48000, 2))) +PCM_PLAYBACK_ADD(ACP-SW0-PIN0-Playback-HS, 0, PIPELINE_PCM_0) + +#/**********************************************************************************/ +#PCM 2, Speaker Playback, PIPE line 2, DAI link id 2, Dai index 4(DI_SDW0_ACP_SW_AUDIO_4_TX), DAI BE SDW0-PIN4-PLAYBACK-SmartAmp +PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, + 2, 2, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# playback DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-playback.m4, 2, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_4_TX, DAI_BE_SDW0_ACP_SW_AUDIO_4_TX, + PIPELINE_SOURCE_2, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_4_TX, 2, DAI_BE_SDW0_ACP_SW_AUDIO_4_TX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_4_TX, 48000, 2))) + +PCM_PLAYBACK_ADD(ACP-SW0-PIN4-Playback-SPK, 2, PIPELINE_PCM_2) +#/**********************************************************************************/ + +#/**********************************************************************************/ +#PCM 1, HS Capture, DAI link id 1, Dai index 11(DI_SDW0_ACP_SW_AUDIO_0_RX), BE DAI_BE_SDW0_ACP_SW_AUDIO_0_RX +# Capture pipeline 1 on PCM 1 using max 2 channels of s16le. +PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4, + 1, 1, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Capture DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-capture.m4, 1, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_RX, DAI_BE_SDW0_ACP_SW_AUDIO_0_RX, + PIPELINE_SINK_1, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_RX, 1, DAI_BE_SDW0_ACP_SW_AUDIO_0_RX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_0_RX, 48000, 2))) + +PCM_CAPTURE_ADD(ACP-SW0-PIN11-Capture-HS, 1, PIPELINE_PCM_1) +#/**********************************************************************************/ +#/**********************************************************************************/ +#PCM 4, SDW Capture, DAI link id 4, Dai index 16(DI_SDW0_ACP_SW_AUDIO_5_RX), BE SDW0-PIN16-CAPTURE-SmartMic +# Capture pipeline 1 on PCM 1 using max 2 channels of s16le. +PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4, + 4, 4, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Capture DAI is ACP soundwire using 2 periods +DAI_ADD(sof/pipe-dai-capture.m4, 4, ACP_SDW, DI_SDW0_ACP_SW_AUDIO_5_RX, DAI_BE_SDW0_ACP_SW_AUDIO_5_RX, + PIPELINE_SINK_4, 2, s16le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +DAI_CONFIG(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_5_RX, 4, DAI_BE_SDW0_ACP_SW_AUDIO_5_RX, + ACP_SDW_CONFIG(ACP_SDW_CONFIG_DATA(ACP_SDW, DI_SDW0_ACP_SW_AUDIO_5_RX, 48000, 2))) + +PCM_CAPTURE_ADD(ACP-SW0-PIN16-CAPTURE-DMIC, 4, PIPELINE_PCM_4) +#/**********************************************************************************/ + +DEBUG_END diff --git a/tools/topology/topology1/sof-imx8mp-btsco-dual-8ch.m4 b/tools/topology/topology1/sof-imx8mp-btsco-dual-8ch.m4 index 8c581b7a760a..207a4a2e6eb5 100644 --- a/tools/topology/topology1/sof-imx8mp-btsco-dual-8ch.m4 +++ b/tools/topology/topology1/sof-imx8mp-btsco-dual-8ch.m4 @@ -79,7 +79,7 @@ dnl deadline, priority, core) DAI_ADD(sof/pipe-dai-playback.m4, 1, SAI, 2, sai2-bt-sco-pcm-wb, PIPELINE_SOURCE_1, 2, s16le, - DEADLINE, 0, 0, SCHEDULE_TIME_DOMAIN_DMA) + DEADLINE, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) # capture DAI SAI2 using 2 periods DAI_ADD(sof/pipe-dai-capture.m4, @@ -91,7 +91,7 @@ DAI_ADD(sof/pipe-dai-capture.m4, DAI_ADD(sof/pipe-dai-playback.m4, 3, SAI, 3, sai3-bt-sco-pcm-wb, PIPELINE_SOURCE_3, 2, s16le, - DEADLINE, 0, 0, SCHEDULE_TIME_DOMAIN_DMA) + DEADLINE, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) # capture DAI SAI3 using 2 periods DAI_ADD(sof/pipe-dai-capture.m4, diff --git a/tools/topology/topology1/sof-imx8mp-compr-pcm-cap-wm8960.m4 b/tools/topology/topology1/sof-imx8mp-compr-pcm-cap-wm8960.m4 index 9eb27880c4f5..c86876be902d 100644 --- a/tools/topology/topology1/sof-imx8mp-compr-pcm-cap-wm8960.m4 +++ b/tools/topology/topology1/sof-imx8mp-compr-pcm-cap-wm8960.m4 @@ -75,7 +75,7 @@ dnl period, priority, core, time_domain) DAI_ADD(sof/pipe-dai-capture.m4, 1, SAI, 3, sai3-wm8960-hifi, PIPELINE_SOURCE_1, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_DMA) + 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) # PCM Low Latency, id 0 diff --git a/tools/topology/topology1/sof-imx8mp-compr-pcm-wm8960.m4 b/tools/topology/topology1/sof-imx8mp-compr-pcm-wm8960.m4 index c518430b01c5..73f787e6900c 100644 --- a/tools/topology/topology1/sof-imx8mp-compr-pcm-wm8960.m4 +++ b/tools/topology/topology1/sof-imx8mp-compr-pcm-wm8960.m4 @@ -75,7 +75,7 @@ dnl period, priority, core, time_domain) DAI_ADD(sof/pipe-dai-playback.m4, 1, SAI, 3, sai3-wm8960-hifi, PIPELINE_SOURCE_1, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_DMA) + 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) # PCM Low Latency, id 0 diff --git a/tools/topology/topology1/sof-imx8mp-compr-wm8960.m4 b/tools/topology/topology1/sof-imx8mp-compr-wm8960.m4 index e74caff6b27c..de620e1e3644 100644 --- a/tools/topology/topology1/sof-imx8mp-compr-wm8960.m4 +++ b/tools/topology/topology1/sof-imx8mp-compr-wm8960.m4 @@ -91,7 +91,7 @@ dnl period, priority, core, time_domain) DAI_ADD(sof/pipe-dai-playback.m4, 1, SAI, 3, DAI_BE_NAME, PIPELINE_SOURCE_1, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_DMA) + 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) # PCM Low Latency, id 0 diff --git a/tools/topology/topology1/sof-imx8mp-micfil.m4 b/tools/topology/topology1/sof-imx8mp-micfil.m4 index f8bf88bb5335..ccbc060fddc5 100644 --- a/tools/topology/topology1/sof-imx8mp-micfil.m4 +++ b/tools/topology/topology1/sof-imx8mp-micfil.m4 @@ -20,11 +20,11 @@ include(`platform/imx/imx8.m4') # Capture pipeline 3 on PCM 1 using max 4 channels of s32le. PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, 1, 0, 4, s32le, - 2000, 0, 0, + 1000, 0, 0, 48000, 48000, 48000) DAI_ADD(sof/pipe-dai-capture.m4, 1, MICFIL, 2, micfil-dmic-hifi, -PIPELINE_SINK_1, 2, s32le, 2000, 0, 0, SCHEDULE_TIME_DOMAIN_DMA) +PIPELINE_SINK_1, 2, s32le, 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) dnl DAI_CONFIG(type, dai_index, link_id, name, acpdmic_config) DAI_CONFIG(MICFIL, 0, 0, micfil-dmic-hifi, diff --git a/tools/topology/topology1/sof-mt8196-mt6681.m4 b/tools/topology/topology1/sof-mt8196-mt6681.m4 index e52c8c84fa0e..c406c6d387c8 100644 --- a/tools/topology/topology1/sof-mt8196-mt6681.m4 +++ b/tools/topology/topology1/sof-mt8196-mt6681.m4 @@ -37,7 +37,12 @@ dnl time_domain, sched_comp) define(`ENDPOINT_NAME', `Speakers') # Low Latency playback pipeline 1 on PCM 16 using max 2 channels of s16le # Set 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(ifdef(`WAVES', sof/pipe-waves-codec-playback.m4, sof/pipe-passthrough-playback.m4), +PIPELINE_PCM_ADD( + ifdef(`DTS', sof/pipe-eq-iir-dts-codec-playback.m4, + ifdef(`WAVES', ifdef(`GOOGLE_CTC', sof/pipe-waves-codec-ctc-playback.m4, + sof/pipe-waves-codec-playback.m4), + ifdef(`GOOGLE_CTC', sof/pipe-ctc-playback.m4, + sof/pipe-passthrough-playback.m4))), 1, 0, 2, s16le, 1000, 0, 0, 48000, 48000, 48000) @@ -46,7 +51,7 @@ undefine(`ENDPOINT_NAME') define(`ENDPOINT_NAME', `Headphones') # Low Latency playback pipeline 2 on PCM 17 using max 2 channels of s16le # Set 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(ifdef(`WAVES', sof/pipe-waves-codec-playback.m4, sof/pipe-passthrough-playback.m4), +PIPELINE_PCM_ADD(ifdef(`DTS', sof/pipe-eq-iir-dts-codec-playback.m4, ifdef(`WAVES', sof/pipe-waves-codec-playback.m4, sof/pipe-passthrough-playback.m4)), 2, 1, 2, s16le, 1000, 0, 0, 48000, 48000, 48000) diff --git a/tools/topology/topology1/sof-mt8365-mt6357.m4 b/tools/topology/topology1/sof-mt8365-mt6357.m4 new file mode 100644 index 000000000000..7ba3420d57f9 --- /dev/null +++ b/tools/topology/topology1/sof-mt8365-mt6357.m4 @@ -0,0 +1,128 @@ +# +# Topology for MT8365 board with mt6357 +# + +# Include topology builder +include(`utils.m4') +include(`dai.m4') +include(`pipeline.m4') +include(`afe.m4') +include(`pcm.m4') +include(`buffer.m4') + +# Include TLV library +include(`common/tlv.m4') + +# Include Token library +include(`sof/tokens.m4') + +# Include DSP configuration +include(`platform/mediatek/mt8365.m4') + +# +# Define the pipelines +# +# PCM16 ---> AFE (Speaker - rt1019) +# PCM17 ---> AFE (Headset playback - rt5682) +# PCM18 <--- AFE (DMIC - MT6365) +# PCM19 <--- AFE (Headset record - rt5682) + + +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) + +define(`ENDPOINT_NAME', `Speakers') +# Low Latency playback pipeline 1 on PCM 16 using max 2 channels of s16le +# Set 1000us deadline with priority 0 on core 0 +PIPELINE_PCM_ADD(ifdef(`WAVES', sof/pipe-waves-codec-playback.m4, sof/pipe-passthrough-playback.m4), + 1, 16, 2, s16le, + 1000, 0, 0, + 48000, 48000, 48000) +undefine(`ENDPOINT_NAME') + +define(`ENDPOINT_NAME', `Headphones') +# Low Latency playback pipeline 2 on PCM 17 using max 2 channels of s16le +# Set 1000us deadline with priority 0 on core 0 +PIPELINE_PCM_ADD(ifdef(`WAVES', sof/pipe-waves-codec-playback.m4, sof/pipe-passthrough-playback.m4), + 2, 17, 2, s16le, + 1000, 0, 0, + 48000, 48000, 48000) +undefine(`ENDPOINT_NAME') + +# Low Latency capture pipeline 3 on PCM 18 using max 2 channels of s16le +# Set 2000us deadline with priority 0 on core 0 +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 3, 18, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Low Latency capture pipeline 4 on PCM 19 using max 2 channels of s16le +# Set 2000us deadline with priority 0 on core 0 +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 4, 19, 2, s16le, + 2000, 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) + + +# playback DAI is AFE using 2 periods +# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0 +DAI_ADD(sof/pipe-dai-playback.m4, + 1, AFE, 0, AFE_SOF_DL1, + PIPELINE_SOURCE_1, 2, s16le, + 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +# playback DAI is AFE using 2 periods +# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0 +DAI_ADD(sof/pipe-dai-playback.m4, + 2, AFE, 1, AFE_SOF_DL2, + PIPELINE_SOURCE_2, 2, s16le, + 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +# capture DAI is AFE using 2 periods +# Buffers use s16le format, with 48 frame per 2000us on core 0 with priority 0 +DAI_ADD(sof/pipe-dai-capture.m4, + 3, AFE, 2, AFE_SOF_AWB, + PIPELINE_SINK_3, 2, s16le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +# capture DAI is AFE using 2 periods +# Buffers use s16le format, with 48 frame per 2000us on core 0 with priority 0 +DAI_ADD(sof/pipe-dai-capture.m4, + 4, AFE, 3, AFE_SOF_VUL, + PIPELINE_SINK_4, 2, s16le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +#SCHEDULE_TIME_DOMAIN_DMA +dnl PCM_PLAYBACK_ADD(name, pcm_id, playback) + +# PCM Low Latency, id 0 +PCM_PLAYBACK_ADD(SOF_DL1, 16, PIPELINE_PCM_1) +PCM_PLAYBACK_ADD(SOF_DL2, 17, PIPELINE_PCM_2) +PCM_CAPTURE_ADD(SOF_AWB, 18, PIPELINE_PCM_3) +PCM_CAPTURE_ADD(SOF_VUL, 19, PIPELINE_PCM_4) + +dnl DAI_CONFIG(type, dai_index, link_id, name, afe_config) + +DAI_CONFIG(AFE, 0, 0, AFE_SOF_DL1, + AFE_CONFIG(AFE_CONFIG_DATA(AFE, 0, 48000, 2, s16le))) + +DAI_CONFIG(AFE, 1, 0, AFE_SOF_DL2, + AFE_CONFIG(AFE_CONFIG_DATA(AFE, 1, 48000, 2, s16le))) + +DAI_CONFIG(AFE, 2, 0, AFE_SOF_AWB, + AFE_CONFIG(AFE_CONFIG_DATA(AFE, 2, 48000, 2, s16le))) + +DAI_CONFIG(AFE, 3, 0, AFE_SOF_VUL, + AFE_CONFIG(AFE_CONFIG_DATA(AFE, 3, 48000, 2, s16le))) diff --git a/tools/topology/topology1/sof/pipe-ctc-playback.m4 b/tools/topology/topology1/sof/pipe-ctc-playback.m4 new file mode 100644 index 000000000000..ae34f7fb200f --- /dev/null +++ b/tools/topology/topology1/sof/pipe-ctc-playback.m4 @@ -0,0 +1,94 @@ +# CTC Pipeline and PCM +# +# Pipeline Endpoints for connection are :- +# +# host PCM_P --> B0 --> CTC --> B1 --> sink DAI0 + +# Include topology builder +include(`utils.m4') +include(`buffer.m4') +include(`pcm.m4') +include(`dai.m4') +include(`bytecontrol.m4') +include(`mixercontrol.m4') +include(`pipeline.m4') +include(`google_ctc_audio_processing.m4') + +# +# Controls +# + +# Host "Playback with codec adapter" PCM +# with 2 sink and 0 source periods +W_PCM_PLAYBACK(PCM_ID, CTC Processing Playback, 2, 0, SCHEDULE_CORE) + +define(DEF_CTC_PRIV, concat(`ctc_priv_', PIPELINE_ID)) +define(DEF_CTC_BYTES, concat(`ctc_bytes_', PIPELINE_ID)) +include(`google_ctc_audio_processing_coef_default.m4') + +# CTC Bytes control +C_CONTROLBYTES(DEF_CTC_BYTES, PIPELINE_ID, + CONTROLBYTES_OPS(bytes, + 258 binds the mixer control to bytes get/put handlers, + 258, 258), + CONTROLBYTES_EXTOPS(258 binds the mixer control to bytes get/put handlers, + 258, 258), + , , , + CONTROLBYTES_MAX(void, 4244), + , + DEF_CTC_PRIV) + +define(DEF_CTC_SWITCH, concat(`ctc_enable_', PIPELINE_ID)) +define(`CONTROL_NAME', `DEF_CTC_SWITCH') +C_CONTROLMIXER(DEF_CTC_SWITCH, PIPELINE_ID, + CONTROLMIXER_OPS(volsw, 259 binds the mixer control to switch get/put handlers, 259, 259), + CONTROLMIXER_MAX(max 1 indicates switch type control, 1), + false, + , + Channel register and shift for Front Center, + LIST(` ', KCONTROL_CHANNEL(FC, 3, 0)), + "1") +undefine(`CONTROL_NAME') + +# +# Components and Buffers +# + +W_GOOGLE_CTC_AUDIO_PROCESSING(0, PIPELINE_FORMAT, 2, 2, SCHEDULE_CORE, + LIST(` ', "DEF_CTC_BYTES"), + LIST(` ', "DEF_CTC_SWITCH")) + +# Playback Buffers +W_BUFFER(0, COMP_BUFFER_SIZE(2, + COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), + PLATFORM_HOST_MEM_CAP) +W_BUFFER(1, COMP_BUFFER_SIZE(DAI_PERIODS, + COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), + PLATFORM_DAI_MEM_CAP) + +# +# Pipeline Graph +# +# host PCM_P --> B0 --> CTC -> B1 --> sink DAI0 + +P_GRAPH(pipe-ctc-playback, PIPELINE_ID, + LIST(` ', + `dapm(N_BUFFER(0), N_PCMP(PCM_ID))', + `dapm(N_GOOGLE_CTC_AUDIO_PROCESSING(0), N_BUFFER(0))', + `dapm(N_BUFFER(1), N_GOOGLE_CTC_AUDIO_PROCESSING(0))')) + +# +# Pipeline Source and Sinks +# +indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(1)) +indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), CTC Processing Playback PCM_ID) + +# +# PCM Configuration +# + +PCM_CAPABILITIES(CTC Processing Playback PCM_ID, CAPABILITY_FORMAT_NAME(PIPELINE_FORMAT), PCM_MIN_RATE, PCM_MAX_RATE, 2, PIPELINE_CHANNELS, 2, 16, 192, 16384, 65536, 65536) + +undefine(`DEF_CTC_PRIV') +undefine(`DEF_CTC_BYTES') +undefine(`DEF_CTC_SWITCH') diff --git a/tools/topology/topology1/sof/pipe-eap-playback.m4 b/tools/topology/topology1/sof/pipe-eap-playback.m4 new file mode 100644 index 000000000000..fe71aba97652 --- /dev/null +++ b/tools/topology/topology1/sof/pipe-eap-playback.m4 @@ -0,0 +1,70 @@ +# Low Latency Passthrough with volume Pipeline and PCM +# +# Pipeline Endpoints for connection are :- +# +# host PCM_P --> B0 --> EAP 0 --> B1 --> sink DAI0 + +# Include topology builder +include(`utils.m4') +include(`buffer.m4') +include(`pcm.m4') +include(`dai.m4') +include(`mixercontrol.m4') +include(`bytecontrol.m4') +include(`enumcontrol.m4') +include(`pipeline.m4') +include(`eap.m4') + +# +# Controls +# +# Include defines for EAP controls +include(`eap_controls.m4') + +# +# Components and Buffers +# +# Host "EAP Playback" PCM +# with 2 sink and 0 source periods +W_PCM_PLAYBACK(PCM_ID, EAP Playback, 2, 0) + +# "EAP 0" has x sink period and 2 source periods +W_EAP(0, PIPELINE_FORMAT, DAI_PERIODS, 2, SCHEDULE_CORE, + LIST(` ', "DEF_EAP_CFG")) + +# Playback Buffers +W_BUFFER(0, COMP_BUFFER_SIZE(2, + COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, + COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), + PLATFORM_HOST_MEM_CAP) +W_BUFFER(1, COMP_BUFFER_SIZE(DAI_PERIODS, + COMP_SAMPLE_SIZE(DAI_FORMAT), PIPELINE_CHANNELS, + COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), + PLATFORM_DAI_MEM_CAP) + +# +# Pipeline Graph +# +# host PCM_P --> B0 --> EAP --> B1 --> sink DAI0 +P_GRAPH(pipe-eap-playback, PIPELINE_ID, + LIST(` ', + `dapm(N_BUFFER(0), N_PCMP(PCM_ID))', + `dapm(N_EAP(0), N_BUFFER(0))', + `dapm(N_BUFFER(1), N_EAP(0))')) + +# +# Pipeline Source and Sinks +# +indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(1)) +indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), + EAP Playback PCM_ID) + +# +# PCM Configuration + +# +PCM_CAPABILITIES(EAP Playback PCM_ID, `S16_LE', + PCM_MIN_RATE, PCM_MAX_RATE, 2, PIPELINE_CHANNELS, + 2, 16, 192, 16384, 65536, 65536) + +undefine(`DAI_EAP_CFG') diff --git a/tools/topology/topology1/sof/pipe-rtnr-capture.m4 b/tools/topology/topology1/sof/pipe-rtnr-capture.m4 index fd64a79ac9c2..b40f6bc6d286 100644 --- a/tools/topology/topology1/sof/pipe-rtnr-capture.m4 +++ b/tools/topology/topology1/sof/pipe-rtnr-capture.m4 @@ -42,7 +42,7 @@ CONTROLBYTES_PRIV(DEF_RTNR_PRIV, # RTNR Bytes control with max value of 255 C_CONTROLBYTES_READONLY(DEF_RTNR_BYTES, PIPELINE_ID, CONTROLBYTES_OPS(bytes, 258 binds the mixer control to bytes get handlers, 258), - CONTROLBYTES_EXTOPS(258 binds the mixer control to bytes get handlers, 258), + CONTROLBYTES_EXTOPS(258 binds the mixer control to bytes get/put handlers, 258, 258), , , , CONTROLBYTES_MAX(, 256), , diff --git a/tools/topology/topology1/sof/pipe-rtnr-google-rtc-audio-processing-capture.m4 b/tools/topology/topology1/sof/pipe-rtnr-google-rtc-audio-processing-capture.m4 index 4009f61ac100..6e5f3cd7aacc 100644 --- a/tools/topology/topology1/sof/pipe-rtnr-google-rtc-audio-processing-capture.m4 +++ b/tools/topology/topology1/sof/pipe-rtnr-google-rtc-audio-processing-capture.m4 @@ -44,7 +44,7 @@ CONTROLBYTES_PRIV(DEF_RTNR_PRIV, # RTNR Bytes control with max value of 255 C_CONTROLBYTES_READONLY(DEF_RTNR_BYTES, PIPELINE_ID, CONTROLBYTES_OPS(bytes, 258 binds the mixer control to bytes get/put handlers, 258), - CONTROLBYTES_EXTOPS(258 binds the mixer control to bytes get/put handlers, 258), + CONTROLBYTES_EXTOPS(258 binds the mixer control to bytes get/put handlers, 258, 258), , , , CONTROLBYTES_MAX(, 256), , diff --git a/tools/topology/topology1/sof/pipe-waves-codec-ctc-playback.m4 b/tools/topology/topology1/sof/pipe-waves-codec-ctc-playback.m4 new file mode 100644 index 000000000000..b885fcd10a94 --- /dev/null +++ b/tools/topology/topology1/sof/pipe-waves-codec-ctc-playback.m4 @@ -0,0 +1,155 @@ +# Low Latency Waves codec and CTC Pipeline and PCM +# +# Pipeline Endpoints for connection are :- +# +# host PCM_P --> B0 --> Waves codec --> B1 --> CTC --> B2 --> sink DAI0 + +# Include topology builder +include(`utils.m4') +include(`buffer.m4') +include(`pcm.m4') +include(`dai.m4') +include(`pipeline.m4') +include(`bytecontrol.m4') +include(`mixercontrol.m4') +include(`google_ctc_audio_processing.m4') + +ifdef(`ENDPOINT_NAME',`',`fatal_error(`Pipe requires ENDPOINT_NAME to be defined: Speakers, Headphones, etc.')') + +# Waves codec setup config +define(`CA_SETUP_CONTROLBYTES', +`` bytes "0x53,0x4f,0x46,0x00,' +` 0x00,0x00,0x00,0x00,' +` 0x0C,0x00,0x00,0x00,' +` 0x00,0x10,0x00,0x03,' +` 0x00,0x00,0x00,0x00,' +` 0x00,0x00,0x00,0x00,' +` 0x00,0x00,0x00,0x00,' +` 0x00,0x00,0x00,0x00,' + +` 0x00,0x00,0x00,0x00,' +` 0x0c,0x00,0x00,0x00,' +` 0x00,0x00,0x00,0x00"'' +) +define(`CA_SETUP_CONTROLBYTES_MAX', 8192) +define(`CA_SETUP_CONTROLBYTES_NAME', `Waves' `ENDPOINT_NAME' `Setup ') + +define(`CA_SCHEDULE_CORE', 0) + +DECLARE_SOF_RT_UUID("Waves codec", waves_codec_uuid, 0xd944281a, 0xafe9, + 0x4695, 0xa0, 0x43, 0xd7, 0xf6, 0x2b, 0x89, 0x53, 0x8e); +define(`CA_UUID', waves_codec_uuid) + +# Include codec_adapter after CA_UUID definition +include(`codec_adapter.m4') + +define(CA_SETUP_CONFIG, concat(`ca_setup_config_', PIPELINE_ID)) +define(CA_SETUP_CONTROLBYTES_NAME_PIPE, concat(CA_SETUP_CONTROLBYTES_NAME, PIPELINE_ID)) + +# Codec adapter setup config +CONTROLBYTES_PRIV(CA_SETUP_CONFIG, CA_SETUP_CONTROLBYTES) + +# Codec adapter Bytes control for setup config +C_CONTROLBYTES(CA_SETUP_CONTROLBYTES_NAME_PIPE, PIPELINE_ID, + CONTROLBYTES_OPS(bytes), + CONTROLBYTES_EXTOPS(void, 258, 258), + , , , + CONTROLBYTES_MAX(void, CA_SETUP_CONTROLBYTES_MAX), + , + CA_SETUP_CONFIG) + +define(DEF_CTC_PRIV, concat(`ctc_priv_', PIPELINE_ID)) +define(DEF_CTC_BYTES, concat(`ctc_bytes_', PIPELINE_ID)) +include(`google_ctc_audio_processing_coef_default.m4') + +# CTC Bytes control +C_CONTROLBYTES(DEF_CTC_BYTES, PIPELINE_ID, + CONTROLBYTES_OPS(bytes, + 258 binds the mixer control to bytes get/put handlers, + 258, 258), + CONTROLBYTES_EXTOPS(258 binds the mixer control to bytes get/put handlers, + 258, 258), + , , , + CONTROLBYTES_MAX(void, 4244), + , + DEF_CTC_PRIV) + +define(DEF_CTC_SWITCH, concat(`ctc_enable_', PIPELINE_ID)) +define(`CONTROL_NAME', `DEF_CTC_SWITCH') +C_CONTROLMIXER(DEF_CTC_SWITCH, PIPELINE_ID, + CONTROLMIXER_OPS(volsw, 259 binds the mixer control to switch get/put handlers, 259, 259), + CONTROLMIXER_MAX(max 1 indicates switch type control, 1), + false, + , + Channel register and shift for Front Center, + LIST(` ', KCONTROL_CHANNEL(FC, 3, 0)), + "1") +undefine(`CONTROL_NAME') + +# +# Components and Buffers +# + +# For codec developers, please define the schedule core of codec adapter if it you would like it to +# be different from SCHEDULE_CORE. +ifdef(`CA_SCHEDULE_CORE',`', `define(`CA_SCHEDULE_CORE', `SCHEDULE_CORE')') + +# Host "Playback with codec adapter" PCM +# with DAI_PERIODS sink and 0 source periods +W_PCM_PLAYBACK(PCM_ID, Passthrough Playback, DAI_PERIODS, 0, SCHEDULE_CORE) + +W_CODEC_ADAPTER(0, PIPELINE_FORMAT, DAI_PERIODS, DAI_PERIODS, CA_SCHEDULE_CORE, + LIST(` ', "CA_SETUP_CONTROLBYTES_NAME_PIPE")) + +W_GOOGLE_CTC_AUDIO_PROCESSING(0, PIPELINE_FORMAT, DAI_PERIODS, DAI_PERIODS, SCHEDULE_CORE, + LIST(` ', "DEF_CTC_BYTES"), + LIST(` ', "DEF_CTC_SWITCH")) + +# Playback Buffers +W_BUFFER(0, COMP_BUFFER_SIZE(DAI_PERIODS, + COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), + PLATFORM_HOST_MEM_CAP, SCHEDULE_CORE) +W_BUFFER(1, COMP_BUFFER_SIZE(DAI_PERIODS, + COMP_SAMPLE_SIZE(DAI_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), + PLATFORM_DAI_MEM_CAP, SCHEDULE_CORE) +W_BUFFER(2, COMP_BUFFER_SIZE(DAI_PERIODS, + COMP_SAMPLE_SIZE(DAI_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), + PLATFORM_DAI_MEM_CAP, SCHEDULE_CORE) + +# +# Pipeline Graph +# +# host PCM_P --> B0 --> Waves codec --> B1 --> CTC --> B2 --> sink DAI0 + +P_GRAPH(pipe-codec-adapter-ctc-playback, PIPELINE_ID, + LIST(` ', + `dapm(N_BUFFER(0), N_PCMP(PCM_ID))', + `dapm(N_CODEC_ADAPTER(0), N_BUFFER(0))', + `dapm(N_BUFFER(1), N_CODEC_ADAPTER(0))', + `dapm(N_GOOGLE_CTC_AUDIO_PROCESSING(0), N_BUFFER(1))', + `dapm(N_BUFFER(2), N_GOOGLE_CTC_AUDIO_PROCESSING(0))', +)) + +# +# Pipeline Source and Sinks +# +indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(2)) +indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Playback PCM_ID) + +# +# PCM Configuration +# + +PCM_CAPABILITIES(Passthrough Playback PCM_ID, CAPABILITY_FORMAT_NAME(PIPELINE_FORMAT), PCM_MIN_RATE, PCM_MAX_RATE, 2, PIPELINE_CHANNELS, 2, 16, 192, 16384, 65536, 65536) + +undefine(`DEF_CTC_PRIV') +undefine(`DEF_CTC_BYTES') +undefine(`DEF_CTC_SWITCH') + +undefine(`CA_SETUP_CONTROLBYTES_NAME_PIPE') +undefine(`CA_SETUP_PARAMS') + +undefine(`CA_SCHEDULE_CORE') +undefine(`CA_SETUP_CONTROLBYTES_NAME') +undefine(`CA_SETUP_CONTROLBYTES_MAX') +undefine(`CA_SETUP_CONTROLBYTES') diff --git a/tools/topology/topology1/sof/tokens.m4 b/tools/topology/topology1/sof/tokens.m4 index b9748bb52fbc..a9a12f5264b6 100644 --- a/tools/topology/topology1/sof/tokens.m4 +++ b/tools/topology/topology1/sof/tokens.m4 @@ -141,6 +141,7 @@ SectionVendorTokens."sof_acp_tokens" { SOF_TKN_AMD_ACP_RATE "1700" SOF_TKN_AMD_ACP_CH "1701" SOF_TKN_AMD_ACP_I2S_TDM_MODE "1702" + SOF_TKN_AMD_ACP_I2S_BITDEPTH "1703" } SectionVendorTokens."sof_acpdmic_tokens" { diff --git a/tools/topology/topology2/README.md b/tools/topology/topology2/README.md new file mode 100644 index 000000000000..bea7ffcfdcde --- /dev/null +++ b/tools/topology/topology2/README.md @@ -0,0 +1,401 @@ +# ALSA Topology v2 (`tools/topology/topology2`) + +This directory contains the ALSA Topology v2 source files for Sound Open Firmware. + +This readme is a quick intro to the topic. Please refer to full documentation +at https://thesofproject.github.io/latest/developer_guides/topology2/topology2.html + +## Overview + +Topology v2 is a modernization of the ALSA topology infrastructure. It aims to solve the verbosity and complexity issues of Topology v1 without relying as heavily on external macro processors like `m4`. + +Topology v2 introduces an object-oriented pre-processing layer directly into the newer `alsatplg` compiler (invoked via the `-p` flag). This allows the configuration files to define classes, objects, and attributes natively within the ALSA configuration syntax. + +Building topologies requires `alsatplg` version 1.2.7 or later. The version check is +enforced in `CMakeLists.txt` at configure time. + +## Key Advantages + +- **Object-Oriented Syntax**: Topology v2 allows for the definition of classes (`Class.Widget`, `Class.Pipeline`) and object instantiation, making the topology files much easier to read, maintain, and extend. +- **Reduced Pre-Processing**: By handling templating and instantiation inside the `alsatplg` tool itself, the build process is cleaner and errors are easier to trace back to the source files, as opposed to deciphering expanded `m4` output. +- **Dynamic Variables**: Attributes can be parameterized and passed down to nested objects, allowing for highly flexible definitions of audio pipelines. + +Topology2 uses a class-based object model built on four core concepts: + +* **Classes** (`Class.Pipeline`, `Class.Widget`, `Class.PCM`) define reusable templates + with default attribute values +* **Objects** (`Object.Pipeline`, `Object.Widget`, `Object.PCM`) instantiate classes with + specific parameter values +* **Define blocks** provide variable substitution using `$VARIABLE` syntax, enabling + parameterized topologies +* **IncludeByKey** enables conditional includes based on variable values, used primarily + for platform-specific overrides + +## Structure and Component Assembly + +Topology v2 shifts the source code layout from macro definitions to class definitions, leveraging the structured nature of the newer compiler. + +The directory is built around these core parts: + +- **`include/`**: Contains the base ALSA topology class definitions. + - `components/`: Base classes for individual processing nodes (e.g., PGA, Mixer, SRC). + - `pipelines/`: Reusable pipeline class definitions that instantiate and connect several base components. + - `dais/`: Definitions for Digital Audio Interfaces (hardware endpoints). + - `controls/`: Definitions for volume, enum, and byte controls. +- **`platform/`**: Hardware-specific configurations and overrides (e.g., Intel-specific IPC attributes). +- **Top-Level `.conf` files**: The board-specific configurations (e.g., `cavs-rt5682.conf`). These behave like standard ALSA `.conf` files but utilize the `@include` directive to import classes and instantiate them dynamically. + +### Detailed Directory Layout + +```text +tools/topology/topology2/ +├── CMakeLists.txt # Build system entry point +├── get_abi.sh # ABI version extraction script +├── cavs-sdw.conf # SoundWire topology entry point +├── sof-hda-generic.conf # HDA generic topology entry point +├── cavs-mixin-mixout-hda.conf # HDA with mixer pipelines +├── cavs-nocodec.conf # SSP nocodec topology +├── ... # Other top-level .conf entry points +├── include/ +│ ├── common/ # Core class definitions (PCM, route, audio formats) +│ ├── components/ # Widget/component classes (gain, mixin, EQ, DRC) +│ ├── controls/ # Control classes (mixer, enum, bytes) +│ ├── dais/ # DAI classes (SSP, DMIC, HDA, ALH) +│ └── pipelines/ # Pipeline template classes +│ └── cavs/ # CAVS-architecture pipeline classes +├── platform/ +│ └── intel/ # Platform-specific overrides (tgl, mtl, lnl, ptl) +├── production/ # CMake targets for production topologies +│ ├── tplg-targets-ace1.cmake # Intel ACE1 (MTL) targets +│ ├── tplg-targets-ace2.cmake # Intel ACE2 (LNL) targets +│ ├── tplg-targets-ace3.cmake # Intel ACE3 (PTL) targets +│ └── ... # Additional platform target files +├── development/ # CMake targets for development/testing +└── doc/ # Doxygen documentation source +``` + +```mermaid +graph TD + subgraph "Class Definitions (include/)" + C_Comp[Class: components/pga.conf] + C_Pipe[Class: pipelines/volume-playback.conf] + C_DAI[Class: dais/ssp.conf] + end + + subgraph "Pipeline Object" + C_Pipe -.->|Instantiates| C_Comp + end + + subgraph "Top-Level Topology (board.conf)" + Board[cavs-board.conf] + Board -->|"@include"| C_Pipe + Board -->|"@include"| C_DAI + + Obj_Pipe[Object.Pipeline.volume-playback.1] + Obj_DAI[Object.Dai.SSP.1] + + Board -.->|Instantiates| Obj_Pipe + Board -.->|Instantiates| Obj_DAI + + Routes[Object.Base.route] + Board -.->|Connects Objects| Routes + end +``` + +## Architecture and Build Flow + +Unlike v1, Topology v2 processes objects and classes within the `alsatplg` compiler itself. + +### Diagram + +```mermaid +flowchart TD + conf_classes(["Class Definitions (.conf)"]) -.-> conf_objs(["Object Instantiations (.conf)"]) + + conf_objs -->|"alsatplg -p (Pre-processor Engine)"| tplg["ALSA .tplg Binary"] + + subgraph alsatplg_internal [alsatplg Internal Processing] + direction TB + parse["Parse Classes & Objects"] --> resolve["Resolve Attributes"] + resolve --> validate["Validate Topologies"] + end + + conf_objs -.-> alsatplg_internal + alsatplg_internal -.-> tplg +``` + +When building a v2 topology, the `CMakeLists.txt` in `tools/topology/` provides the `add_alsatplg2_command` macro. This macro specifically passes the `-p` flag to `alsatplg`, instructing it to use the new pre-processor engine to resolve the classes and objects defined in the `.conf` files before compiling them into the `.tplg` binary. + +### Build Instructions + +Topologies are built automatically as part of the standard SOF CMake build process. To explicitly build Topology v2 configurations: + +```bash +# From your build directory: +make topologies2 +# OR +cmake --build . --target topologies2 +``` + +To build a specific topology target: + +```bash +make sof-lnl-sdw-cs42l43-l0-cs35l56-l12 +``` + +## Best Practices for Adding New Topology Definitions + +### Topology Structure + +A top-level topology `.conf` file follows a layered configuration pattern: + +```conf +# 1. Search directories +<searchdir:include> +<searchdir:include/common> +<searchdir:include/components> +<searchdir:include/dais> +<searchdir:include/pipelines/cavs> +<searchdir:platform/intel> + +# 2. Include class files +<vendor-token.conf> +<tokens.conf> +<pcm.conf> +<host-copier-gain-mixin-playback.conf> +<mixout-gain-alh-dai-copier-playback.conf> + +# 3. Define block (default variable values) +Define { + PLATFORM "" + NUM_HDMIS 3 + DEEP_BUFFER_PCM_ID 31 +} + +# 4. Platform overrides (conditional includes) +IncludeByKey.PLATFORM { + "mtl" "platform/intel/mtl.conf" + "lnl" "platform/intel/lnl.conf" + "ptl" "platform/intel/ptl.conf" +} + +# 5. Conditional feature includes +IncludeByKey.NUM_HDMIS { + "3" "platform/intel/hdmi-generic.conf" +} + +# 6. DAI, Pipeline, PCM objects +# 7. Route definitions +``` + +### Reusing Existing Bases + +The most common way to add a new topology is to reuse an existing base `.conf` file and +override variables through a cmake target entry. Targets are defined in +`production/tplg-targets-*.cmake` files using a tuple format: + +```text +"input-conf;output-name;variables" +``` + +For example, to add a new SoundWire topology variant for ACE2 (Lunar Lake): + +```text +"cavs-sdw\;sof-lnl-sdw-cs42l43-l0-cs35l56-l12\;PLATFORM=lnl,NUM_SDW_AMP_LINKS=2" +``` + +The first element is the base `.conf` file (without extension), the second is the output +`.tplg` filename, and the third is a comma-separated list of variable overrides. + +### Creating a New Base Topology + +When existing bases do not cover a new use case, create a new top-level `.conf` file: + +1. Create a new `.conf` file in `tools/topology/topology2/` following the layered + structure described above +2. Include the required class files from `include/` directories via search directives +3. Define default variables in a `Define` block +4. Add `IncludeByKey.PLATFORM` entries for platform-specific overrides +5. Instantiate DAI, Pipeline, and PCM objects with appropriate IDs +6. Define routes connecting FE mixin outputs to BE mixout inputs +7. Register the topology as a cmake target in the appropriate + `production/tplg-targets-*.cmake` file + +### PCM ID Conventions + +PCM IDs identify audio streams exposed to userspace via ALSA. Each PCM ID must be unique +within a single topology. Different topology families (Intel SoundWire vs HDA) use different +default ID ranges for the same endpoint types. + +**Intel SoundWire PCM IDs:** + +| Endpoint | Default PCM ID | Override Variable | +|---|---|---| +| Jack (playback/capture) | 0 | — | +| Speaker amplifier | 2 | — | +| SDW DMIC | 4 | — | +| HDMI 1 | 5 | `HDMI1_PCM_ID` | +| HDMI 2 | 6 | `HDMI2_PCM_ID` | +| HDMI 3 | 7 | `HDMI3_PCM_ID` | +| PCH DMIC0 | 10 | `DMIC0_PCM_ID` | +| PCH DMIC1 | 11 | `DMIC1_PCM_ID` | +| Jack Echo Ref | 11 | `SDW_JACK_ECHO_REF_PCM_ID` | +| Speaker Echo Ref | 12 | `SDW_SPK_ECHO_REF_PCM_ID` | +| Bluetooth | 2 or 20 | `BT_PCM_ID` | +| Deep Buffer (Jack) | 31 | `DEEP_BUFFER_PCM_ID` | +| Deep Buffer (Speaker) | 35 | `DEEP_BUFFER_PCM_ID_2` | +| DMIC Deep Buffer | 46 | `DMIC0_DEEP_BUFFER_PCM_ID` | +| Compress Jack Out | 50 | `COMPR_PCM_ID` | +| Compress Speaker | 52 | `COMPR_2_PCM_ID` | + +> **Note:** Bluetooth defaults to PCM ID 2 in some topologies and 20 in others. Use the +> `BT_PCM_ID` override variable to set the correct value when BT coexists with a speaker +> amplifier (which also uses PCM ID 2 by default). + +**Intel HDA PCM IDs:** + +| Endpoint | Default PCM ID | Override Variable | +|---|---|---| +| HDA Analog | 0 | — | +| HDMI 1 | 3 | `HDMI1_PCM_ID` | +| HDMI 2 | 4 | `HDMI2_PCM_ID` | +| HDMI 3 | 5 | `HDMI3_PCM_ID` | +| DMIC0 | 6 | `DMIC0_PCM_ID` | +| Deep Buffer | 31 | `DEEP_BUFFER_PCM_ID` | +| Compress HDA Analog | 50 | `COMPR_PCM_ID` | + +Key rules: + +* PCM ID 0 is always the primary playback endpoint +* PCM IDs must be unique within a single topology +* When features coexist (SDW + PCH DMIC + HDMI), adjust IDs via `Define` overrides in + cmake targets to avoid conflicts +* Different topology families (SDW vs HDA) use different default ID ranges for the same + endpoint types + +### Pipeline ID Conventions + +Pipeline IDs are set via the `index` attribute on pipeline objects. Front-end (FE) and +back-end (BE) pipelines are paired, with the FE pipeline at index N and the BE pipeline +at index N+1. + +In SoundWire topologies, pipeline indexes follow the convention documented in +`sdw-amp-generic.conf` and `sdw-dmic-generic.conf`: pipeline index = PCM ID × 10. HDMI +pipelines use a stride-10 pattern where the host pipeline is at N0 and the DAI pipeline +is at N1 (50/51, 60/61, 70/71, 80/81). + +**Intel SoundWire Pipeline IDs:** + +| Pipeline | Default Index | Override Variable | +|---|---|---| +| Jack Playback FE / BE | 0 / 1 | — | +| Jack Capture FE / BE | 10 / 11 | — | +| Deep Buffer (Jack) | 15 | `DEEP_BUFFER_PIPELINE_ID` | +| Deep Buffer (Speaker) | 16 | `DEEP_BUFFER_PIPELINE_ID_2` | +| Speaker FE / BE | 20 / 21 | — | +| Speaker Echo Ref FE / BE | 22 / 23 | — | +| SDW DMIC FE / BE | 40 / 41 | `SDW_DMIC_HOST_PIPELINE_ID` | +| HDMI 1 Host / DAI | 50 / 51 | `HDMI1_HOST_PIPELINE_ID` / `HDMI1_DAI_PIPELINE_ID` | +| HDMI 2 Host / DAI | 60 / 61 | `HDMI2_HOST_PIPELINE_ID` / `HDMI2_DAI_PIPELINE_ID` | +| HDMI 3 Host / DAI | 70 / 71 | `HDMI3_HOST_PIPELINE_ID` / `HDMI3_DAI_PIPELINE_ID` | +| HDMI 4 Host / DAI | 80 / 81 | `HDMI4_HOST_PIPELINE_ID` / `HDMI4_DAI_PIPELINE_ID` | +| Compress Jack / Speaker | 90 / 92 | `COMPR_PIPELINE_ID` / `COMPR_2_PIPELINE_ID` | +| PCH DMIC0 Host / DAI | 100 / 101 | `DMIC0_HOST_PIPELINE_ID` / `DMIC0_DAI_PIPELINE_ID` | + +**Intel HDA Pipeline IDs:** + +| Pipeline | Default Index | Override Variable | +|---|---|---| +| Analog Playback FE / BE | 1 / 2 | — | +| Analog Capture FE / BE | 3 / 4 | — | +| DMIC0 Host / DAI | 11 / 12 | `DMIC0_HOST_PIPELINE_ID` / `DMIC0_DAI_PIPELINE_ID` | +| Deep Buffer | 15 | `DEEP_BUFFER_PIPELINE_ID` | +| HDMI 1 Host / DAI | 50 / 51 | `HDMI1_HOST_PIPELINE_ID` / `HDMI1_DAI_PIPELINE_ID` | +| HDMI 2 Host / DAI | 60 / 61 | `HDMI2_HOST_PIPELINE_ID` / `HDMI2_DAI_PIPELINE_ID` | +| HDMI 3 Host / DAI | 70 / 71 | `HDMI3_HOST_PIPELINE_ID` / `HDMI3_DAI_PIPELINE_ID` | +| HDMI 4 Host / DAI | 80 / 81 | `HDMI4_HOST_PIPELINE_ID` / `HDMI4_DAI_PIPELINE_ID` | +| Compress HDA Analog Host / DAI | 90 / 91 | `COMPR_PIPELINE_ID` | + +Key rules: + +* FE and BE pipelines are paired: FE = N, BE = N+1 +* SDW convention: pipeline index = PCM ID × 10 (documented in `sdw-amp-generic.conf` and + `sdw-dmic-generic.conf`) +* HDMI uses stride-10: Host = N0, DAI = N1 +* Pipeline IDs must be unique within a single topology +* When adding new endpoints, select IDs in unused ranges that do not conflict with + existing assignments + +### Widget Naming + +Widget names follow the convention `<type>.<pipeline-index>.<instance>`. Examples: + +* `gain.1.1` — gain widget in pipeline 1, instance 1 +* `mixin.15.1` — mixin widget in pipeline 15, instance 1 +* `host-copier.0.playback` — host copier in pipeline 0, playback direction +* `dai-copier.1.ALH` — DAI copier in pipeline 1, ALH type + +### Route Definitions + +Routes connect FE pipeline mixin outputs to BE pipeline mixout inputs. This is the +primary mechanism for linking front-end and back-end pipelines: + +```conf +Object.Base.route [ + { + source "mixin.15.1" + sink "mixout.2.1" + } +] +``` + +Multiple FE pipelines can feed into a single BE mixout. For example, both a normal +playback pipeline and a deep buffer pipeline can route to the same DAI output: + +```text +host-copier.0 -> gain.0 -> mixin.0 ─┐ + ├─> mixout.1 -> gain.1 -> dai-copier.1 -> DAI +host-copier.15 -> gain.15 -> mixin.15┘ +``` + +### Platform Overrides + +Platform-specific configurations are applied using the `IncludeByKey.PLATFORM` mechanism. +Each platform `.conf` file under `platform/intel/` contains `Define` blocks that override +variables such as `DMIC_DRIVER_VERSION`, `SSP_BLOB_VERSION`, and `NUM_HDMIS`. + +Supported platforms: + +* `tgl` — Intel Tiger Lake / Alder Lake (CAVS 2.5) +* `mtl` — Intel Meteor Lake (ACE 1.x) +* `lnl` — Intel Lunar Lake (ACE 2.x) +* `ptl` — Intel Panther Lake (ACE 3.x) + +```conf +IncludeByKey.PLATFORM { + "mtl" "platform/intel/mtl.conf" + "lnl" "platform/intel/lnl.conf" + "ptl" "platform/intel/ptl.conf" +} +``` + +### Registering CMake Targets + +Production topologies are registered in `production/tplg-targets-*.cmake` files. Each +target is a semicolon-separated tuple: + +```text +"input-conf;output-name;variable1=value1,variable2=value2" +``` + +Select the cmake file matching the target platform generation: + +| Platform | CMake Target File | +|---|---| +| Tiger Lake / Alder Lake | `tplg-targets-cavs25.cmake` | +| Meteor Lake | `tplg-targets-ace1.cmake` | +| Lunar Lake | `tplg-targets-ace2.cmake` | +| Panther Lake | `tplg-targets-ace3.cmake` | +| HDA generic | `tplg-targets-hda-generic.cmake` | + +Development and testing topologies go in `development/tplg-targets.cmake`. diff --git a/tools/topology/topology2/cavs-benchmark-hda.conf b/tools/topology/topology2/cavs-benchmark-hda.conf index bd4aaf2229c4..d1357caa20ab 100644 --- a/tools/topology/topology2/cavs-benchmark-hda.conf +++ b/tools/topology/topology2/cavs-benchmark-hda.conf @@ -1,18 +1,177 @@ -<include/components/dcblock.conf> -<include/components/rtnr.conf> -<include/components/igo_nr.conf> -<include/components/src_lite.conf> -<include/components/asrc.conf> -<include/components/tdfb.conf> +<searchdir:include> +<searchdir:include/common> +<searchdir:include/components> +<searchdir:include/dais> +<searchdir:include/pipelines> +<searchdir:include/pipelines/cavs> +<searchdir:platform> +<searchdir:platform/intel> + +<vendor-token.conf> +<tokens.conf> +<virtual.conf> +<host-gateway-playback.conf> +<host-gateway-capture.conf> +<dai-copier.conf> +<io-gateway.conf> +<io-gateway-capture.conf> +<mixout-dai-copier-playback.conf> +<mixout-aria-gain-mixin-playback.conf> +<host-copier-gain-mixin-playback.conf> +<highpass-capture-be.conf> +<data.conf> +<pcm.conf> +<pcm_caps.conf> +<fe_dai.conf> +<hda.conf> +<hw_config_simple.conf> +<manifest.conf> +<route.conf> +<common_definitions.conf> +<module-copier.conf> + +<aria.conf> +<asrc.conf> +<dcblock.conf> +<dolby-dax.conf> +<drc.conf> +<eqiir.conf> +<eqfir.conf> +<gain.conf> +<igo_nr.conf> +<level_multiplier.conf> +<mfcc.conf> +<micsel.conf> +<mixin.conf> +<mixout.conf> +<multiband_drc.conf> +<phase_vocoder.conf> +<rtnr.conf> +<sound_dose.conf> +<src.conf> +<src_lite.conf> +<stft_process.conf> +<tdfb.conf> +<template_comp.conf> Define { + HDA_CONFIG "none" + PLATFORM "none" ANALOG_PLAYBACK_PCM 'Analog Playback' ANALOG_CAPTURE_PCM 'Analog Capture' HDA_ANALOG_DAI_NAME 'Analog' HDA_ANALOG_CAPTURE_RATE 48000 HDA_ANALOG_PLAYBACK_RATE 48000 + BENCH_PLAYBACK_HOST_PIPELINE 1 + BENCH_PLAYBACK_DAI_PIPELINE 2 + BENCH_CAPTURE_HOST_PIPELINE 3 + BENCH_CAPTURE_DAI_PIPELINE 4 + BENCH_PLAYBACK_DAI_COPIER "dai-copier.HDA.Analog.playback" + BENCH_CAPTURE_DAI_COPIER "dai-copier.HDA.Analog.capture" + BENCH_PCM_CHANNELS_MIN 2 + BENCH_PCM_CHANNELS_MAX 2 } +# override defaults with platform-specific config +IncludeByKey.PLATFORM { + "mtl" "platform/intel/mtl.conf" + "lnl" "platform/intel/lnl.conf" + "ptl" "platform/intel/ptl.conf" +} + +Object.Widget.virtual [ + { + name 'codec0_in' + type input + index 1 + } + { + name 'codec1_in' + type input + index 2 + } + { + name 'codec0_out' + type output + index 3 + } + { + name 'codec1_out' + type output + index 4 + } + { + name 'codec2_in' + type input + index 5 + } + { + name 'codec2_out' + type output + index 6 + } + { + name 'iDisp1_out' + type output + index 7 + } + { + name 'iDisp2_out' + type output + index 8 + } + { + name 'iDisp3_out' + type output + index 9 + } + { + name 'iDisp3 Tx' + type out_drv + index 0 + } + { + name 'iDisp2 Tx' + type out_drv + index 1 + } + { + name 'iDisp1 Tx' + type out_drv + index 2 + } + { + name 'Analog CPU Playback' + type out_drv + index 3 + } + { + name 'Digital CPU Playback' + type out_drv + index 4 + } + { + name 'Alt Analog CPU Playback' + type out_drv + index 5 + } + { + name 'Analog CPU Capture' + type input + index 6 + } + { + name 'Digital CPU Capture' + type input + index 7 + } + { + name 'Alt Analog CPU Capture' + type input + index 8 + } +] + Object.Dai.HDA [ { name $HDA_ANALOG_DAI_NAME @@ -37,18 +196,120 @@ Object.PCM.pcm [ direction "playback" name $ANALOG_PLAYBACK_PCM formats 'S32_LE,S24_LE,S16_LE' - rates "8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,176400,192000" + rates "8000,11025,16000,22050,24000,32000,44100,48000,64000,88200,96000,176400,192000" + channels_min $BENCH_PCM_CHANNELS_MIN + channels_max $BENCH_PCM_CHANNELS_MAX } Object.PCM.pcm_caps.2 { direction "capture" name $ANALOG_CAPTURE_PCM formats 'S32_LE,S24_LE,S16_LE' - rates "8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,176400,192000" + rates "8000,11025,16000,22050,24000,32000,44100,48000,64000,88200,96000,176400,192000" + channels_min $BENCH_PCM_CHANNELS_MIN + channels_max $BENCH_PCM_CHANNELS_MAX } direction duplex } ] +Object.Pipeline { + io-gateway [ + { + index $BENCH_PLAYBACK_DAI_PIPELINE + 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 + IncludeByKey.BENCH_MODULE_FORMAT { + "s16" { + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + } + ] + } + "s24" { + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 24 + } + ] + } + "s32" { + 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 + } + ] + } + } + ] + io-gateway-capture [ + { + index $BENCH_CAPTURE_DAI_PIPELINE + 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 + } + ] + IncludeByKey.BENCH_MODULE_FORMAT { + "s16" { + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + ] + } + "s24" { + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 24 + } + ] + } + "s32" { + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + } + } + ] +} + IncludeByKey.BENCH_CONFIG { "benchmark" { Object.Pipeline { @@ -308,7 +569,7 @@ IncludeByKey.BENCH_CONFIG { index 5 direction capture - Object.Widget.dai-copier."1" { + Object.Widget.dai-copier.1 { dai_type "HDA" type "dai_out" copier_type "HDA" @@ -429,6 +690,22 @@ IncludeByKey.BENCH_CONFIG { <include/bench/dcblock_s32.conf> } + # + # DOLBY_DAX component + # + + "dolby-dax16" { + <include/bench/dolby-dax_s16.conf> + } + + "dolby-dax24" { + <include/bench/dolby-dax_s24.conf> + } + + "dolby-dax32" { + <include/bench/dolby-dax_s32.conf> + } + # # DRC component # @@ -526,6 +803,84 @@ IncludeByKey.BENCH_CONFIG { <include/bench/igo_nr_s32.conf> } + # + # Level Multiplier component + # + + "level_multiplier16" { + <include/bench/level_multiplier_s16.conf> + } + + "level_multiplier24" { + <include/bench/level_multiplier_s24.conf> + } + + "level_multiplier32" { + <include/bench/level_multiplier_s32.conf> + } + + # + # MFCC component + # + + "mfcc16" { + <include/bench/mfcc_s16.conf> + } + + "mfcc24" { + <include/bench/mfcc_s24.conf> + } + + "mfcc32" { + <include/bench/mfcc_s32.conf> + } + + "mfccmel16" { + <include/bench/mfccmel_s16.conf> + } + "mfccmel24" { + <include/bench/mfccmel_s24.conf> + } + "mfccmel32" { + <include/bench/mfccmel_s32.conf> + } + + # + # Micsel component + # + + "^micsel16$" { + <include/bench/micsel_s16.conf> + } + + "^micsel24$" { + <include/bench/micsel_s24.conf> + } + + "^micsel32$" { + <include/bench/micsel_s32.conf> + } + + "^micsel_multich32$" { + <include/bench/micsel_multich_s32.conf> + } + + # + # Phase Vocoder component + # + + "phase_vocoder16" { + <include/bench/phase_vocoder_s16.conf> + } + + "phase_vocoder24" { + <include/bench/phase_vocoder_s24.conf> + } + + "phase_vocoder32" { + <include/bench/phase_vocoder_s32.conf> + } + # # RTNR component # @@ -542,6 +897,22 @@ IncludeByKey.BENCH_CONFIG { <include/bench/rtnr_s32.conf> } + # + # Sound Dose component + # + + "sound_dose16" { + <include/bench/sound_dose_s16.conf> + } + + "sound_dose24" { + <include/bench/sound_dose_s24.conf> + } + + "sound_dose32" { + <include/bench/sound_dose_s32.conf> + } + # # SRC component # @@ -574,6 +945,56 @@ IncludeByKey.BENCH_CONFIG { <include/bench/src_lite_s32.conf> } + # + # stft_process component, with five different blob configurations. + # + + "stft_process_192_48_16" { + <include/bench/stft_process_s16.conf> + } + "stft_process_192_48_24" { + <include/bench/stft_process_s24.conf> + } + "stft_process_192_48_32" { + <include/bench/stft_process_s32.conf> + } + "stft_process_512_128_16" { + <include/bench/stft_process_s16.conf> + } + "stft_process_512_128_24" { + <include/bench/stft_process_s24.conf> + } + "stft_process_512_128_32" { + <include/bench/stft_process_s32.conf> + } + "stft_process_768_120_16" { + <include/bench/stft_process_s16.conf> + } + "stft_process_768_120_24" { + <include/bench/stft_process_s24.conf> + } + "stft_process_768_120_32" { + <include/bench/stft_process_s32.conf> + } + "stft_process_1024_256_16" { + <include/bench/stft_process_s16.conf> + } + "stft_process_1024_256_24" { + <include/bench/stft_process_s24.conf> + } + "stft_process_1024_256_32" { + <include/bench/stft_process_s32.conf> + } + "stft_process_1536_240_16" { + <include/bench/stft_process_s16.conf> + } + "stft_process_1536_240_24" { + <include/bench/stft_process_s24.conf> + } + "stft_process_1536_240_32" { + <include/bench/stft_process_s32.conf> + } + # # tdfb component # @@ -589,4 +1010,20 @@ IncludeByKey.BENCH_CONFIG { "tdfb32" { <include/bench/tdfb_s32.conf> } + + # + # template_comp component + # + + "template_comp16" { + <include/bench/template_comp_s16.conf> + } + + "template_comp24" { + <include/bench/template_comp_s24.conf> + } + + "template_comp32" { + <include/bench/template_comp_s32.conf> + } } diff --git a/tools/topology/topology2/cavs-benchmark-sdw.conf b/tools/topology/topology2/cavs-benchmark-sdw.conf new file mode 100644 index 000000000000..b19a26d74e7f --- /dev/null +++ b/tools/topology/topology2/cavs-benchmark-sdw.conf @@ -0,0 +1,632 @@ +<searchdir:include> +<searchdir:include/common> +<searchdir:include/components> +<searchdir:include/dais> +<searchdir:include/pipelines> +<searchdir:include/pipelines/cavs> +<searchdir:platform> +<searchdir:platform/intel> + +<vendor-token.conf> +<tokens.conf> +<virtual.conf> +<host-gateway-playback.conf> +<host-gateway-capture.conf> +<data.conf> +<pcm.conf> +<pcm_caps.conf> +<fe_dai.conf> +<intel/hw_config_cardinal_clk.conf> +<manifest.conf> +<route.conf> +<common_definitions.conf> +<pipeline.conf> +<alh.conf> +<dai.conf> +<host.conf> +<input_audio_format.conf> +<output_audio_format.conf> +<alh-dai-copier.conf> +<controls/bytes.conf> +<controls/mixer.conf> + +<aria.conf> +<asrc.conf> +<dcblock.conf> +<drc.conf> +<eqiir.conf> +<eqfir.conf> +<gain.conf> +<igo_nr.conf> +<level_multiplier.conf> +<mfcc.conf> +<micsel.conf> +<multiband_drc.conf> +<phase_vocoder.conf> +<rtnr.conf> +<sound_dose.conf> +<src.conf> +<src_lite.conf> +<stft_process.conf> +<tdfb.conf> +<template_comp.conf> + +Define { + PLATFORM "none" + SDW_JACK_OUT_STREAM 'SDW0-Playback' + SDW_JACK_IN_STREAM 'SDW0-Capture' + SDW_JACK_OUT_BE_ID 0 + SDW_JACK_IN_BE_ID 1 + NUM_SDW_AMP_LINKS 0 + SDW_DMIC 0 + SDW_JACK true + PASSTHROUGH false + SDW_ANALOG_CAPTURE_CH 2 + SDW_LINK_VALID_BITS 24 + ANALOG_PLAYBACK_PCM "Jack Out" + ANALOG_CAPTURE_PCM "Jack In" + JACK_RATE 48000 + BENCH_PLAYBACK_HOST_PIPELINE 1 + BENCH_PLAYBACK_DAI_PIPELINE 2 + BENCH_CAPTURE_HOST_PIPELINE 3 + BENCH_CAPTURE_DAI_PIPELINE 4 + BENCH_PLAYBACK_DAI_COPIER "alh-copier.SDW0-Playback.0" + BENCH_CAPTURE_DAI_COPIER "alh-copier.SDW0-Capture.0" + BENCH_PCM_CHANNELS_MIN 2 + BENCH_PCM_CHANNELS_MAX 2 +} + +# override defaults with platform-specific config +IncludeByKey.PLATFORM { + "mtl" "platform/intel/mtl.conf" + "lnl" "platform/intel/lnl.conf" + "ptl" "platform/intel/ptl.conf" +} + +IncludeByKey.SDW_JACK_OUT_STREAM { + "Playback-SimpleJack" { + Define { + BENCH_PLAYBACK_DAI_COPIER "alh-copier.Playback-SimpleJack.0" + BENCH_CAPTURE_DAI_COPIER "alh-copier.Capture-SimpleJack.0" + } + } +} + +# +# List of all DAIs +# +Object.Dai.ALH [ + { + dai_index 0 + id $SDW_JACK_OUT_BE_ID + direction "playback" + name $SDW_JACK_OUT_STREAM + default_hw_conf_id 0 + rate $JACK_RATE + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH2" + } + } + { + dai_index 10 + id $SDW_JACK_IN_BE_ID + direction "capture" + name $SDW_JACK_IN_STREAM + default_hw_conf_id 0 + rate $JACK_RATE + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH3" + } + } +] + +Object.PCM.pcm [ + { + name "$ANALOG_PLAYBACK_PCM" + id 0 + direction "playback" + Object.Base.fe_dai.1 { + name "$ANALOG_PLAYBACK_PCM" + } + + Object.PCM.pcm_caps.1 { + name $ANALOG_PLAYBACK_PCM + formats 'S16_LE,S24_LE,S32_LE' + rates "8000,11025,16000,22050,24000,32000,44100,48000,64000,88200,96000,176400,192000" + channels_min $BENCH_PCM_CHANNELS_MIN + channels_max $BENCH_PCM_CHANNELS_MAX + } + } + { + name "$ANALOG_CAPTURE_PCM" + id 1 + direction "capture" + Object.Base.fe_dai.1 { + name "$ANALOG_CAPTURE_PCM" + } + + Object.PCM.pcm_caps.1 { + name $ANALOG_CAPTURE_PCM + formats 'S16_LE,S24_LE,S32_LE' + rates "8000,11025,16000,22050,24000,32000,44100,48000,64000,88200,96000,176400,192000" + channels_min $BENCH_PCM_CHANNELS_MIN + channels_max $BENCH_PCM_CHANNELS_MAX + } + } +] + +Object.Widget { + alh-copier [ + { + stream_name $SDW_JACK_OUT_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + index $BENCH_PLAYBACK_DAI_PIPELINE + type dai_in + direction playback + num_input_pins 1 + num_input_audio_formats 1 + num_output_audio_formats 1 + IncludeByKey.BENCH_MODULE_FORMAT { + "s16" { + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + ] + } + "s24" { + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + ] + } + "s32" { + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + } + } + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + pipeline [ + { + index $BENCH_PLAYBACK_DAI_PIPELINE + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] +} + +Object.Widget { + alh-copier [ + { + stream_name $SDW_JACK_IN_STREAM + direction "capture" + type "dai_out" + index $BENCH_CAPTURE_DAI_PIPELINE + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + IncludeByKey.BENCH_MODULE_FORMAT { + "s16" { + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + ] + } + "s24" { + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + ] + } + "s32" { + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + } + ] + + pipeline [ + { + index $BENCH_CAPTURE_DAI_PIPELINE + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] +} + +IncludeByKey.BENCH_CONFIG { + # + # Aria component + # + + "aria24" { + <include/bench/aria_s24.conf> + } + + # + # ASRC component + # + + # '^' indicates the start of the string and '$' means the end of string + # manually adding '^' and '$' for whole string precise matching + + "^asrc16$" { + <include/bench/asrc_s16.conf> + } + + "^asrc24$" { + <include/bench/asrc_s24.conf> + } + + "^asrc32$" { + <include/bench/asrc_s32.conf> + } + + # + # DCblock component + # + + "dcblock16" { + <include/bench/dcblock_s16.conf> + } + + "dcblock24" { + <include/bench/dcblock_s24.conf> + } + + "dcblock32" { + <include/bench/dcblock_s32.conf> + } + + # + # DRC component + # + + "drc16" { + <include/bench/drc_s16.conf> + } + + "drc24" { + <include/bench/drc_s24.conf> + } + + "drc32" { + <include/bench/drc_s32.conf> + } + + # Multiband-DRC component + # Note: Due to alsatplg regexp match feature in IncludeByKey call it e.g. drc_multiband16 + # to not match multiband_drc16 with drc16 and get error "No variable defined + # for BENCH_DRC_PARAMS" when building these. + + "drc_multiband16" { + <include/bench/multiband_drc_s16.conf> + } + + "drc_multiband24" { + <include/bench/multiband_drc_s24.conf> + } + + "drc_multiband32" { + <include/bench/multiband_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> + } + + # + # Gain component + # + + "gain16" { + <include/bench/gain_s16.conf> + } + + "gain24" { + <include/bench/gain_s24.conf> + } + + "gain32" { + <include/bench/gain_s32.conf> + } + + # + # IGO NR component + # + + "igo_nr16" { + <include/bench/igo_nr_s16.conf> + } + + "igo_nr24" { + <include/bench/igo_nr_s24.conf> + } + + "igo_nr32" { + <include/bench/igo_nr_s32.conf> + } + + # + # Level Multiplier component + # + + "level_multiplier16" { + <include/bench/level_multiplier_s16.conf> + } + + "level_multiplier24" { + <include/bench/level_multiplier_s24.conf> + } + + "level_multiplier32" { + <include/bench/level_multiplier_s32.conf> + } + + # MFCC benchmark configs are intentionally not enabled in the SDW + # benchmark topology because the SDW ALH DAI/coprocessor side is + # constrained to $JACK_RATE while MFCC bench configs operate in a + # different rate domain. Re-enable only after adding a matching rate + # override or explicit sample-rate conversion. + + # + # Micsel component + # + + "^micsel16$" { + <include/bench/micsel_s16.conf> + } + + "^micsel24$" { + <include/bench/micsel_s24.conf> + } + + "^micsel32$" { + <include/bench/micsel_s32.conf> + } + + "^micsel_multich32$" { + <include/bench/micsel_multich_s32.conf> + } + + # + # Phase Vocoder component + # + + "phase_vocoder16" { + <include/bench/phase_vocoder_s16.conf> + } + + "phase_vocoder24" { + <include/bench/phase_vocoder_s24.conf> + } + + "phase_vocoder32" { + <include/bench/phase_vocoder_s32.conf> + } + + # + # RTNR component + # + + "rtnr16" { + <include/bench/rtnr_s16.conf> + } + + "rtnr24" { + <include/bench/rtnr_s24.conf> + } + + "rtnr32" { + <include/bench/rtnr_s32.conf> + } + + # + # Sound Dose component + # + + "sound_dose16" { + <include/bench/sound_dose_s16.conf> + } + + "sound_dose24" { + <include/bench/sound_dose_s24.conf> + } + + "sound_dose32" { + <include/bench/sound_dose_s32.conf> + } + + # + # SRC component + # + + "^src16$" { + <include/bench/src_s16.conf> + } + + "^src24$" { + <include/bench/src_s24.conf> + } + + "^src32$" { + <include/bench/src_s32.conf> + } + + # + # src_lite component + # + + "src_lite16" { + <include/bench/src_lite_s16.conf> + } + + "src_lite24" { + <include/bench/src_lite_s24.conf> + } + + "src_lite32" { + <include/bench/src_lite_s32.conf> + } + + # + # stft_process component, with five different blob configurations. + # + + "stft_process_192_48_16" { + <include/bench/stft_process_s16.conf> + } + "stft_process_192_48_24" { + <include/bench/stft_process_s24.conf> + } + "stft_process_192_48_32" { + <include/bench/stft_process_s32.conf> + } + "stft_process_512_128_16" { + <include/bench/stft_process_s16.conf> + } + "stft_process_512_128_24" { + <include/bench/stft_process_s24.conf> + } + "stft_process_512_128_32" { + <include/bench/stft_process_s32.conf> + } + "stft_process_768_120_16" { + <include/bench/stft_process_s16.conf> + } + "stft_process_768_120_24" { + <include/bench/stft_process_s24.conf> + } + "stft_process_768_120_32" { + <include/bench/stft_process_s32.conf> + } + "stft_process_1024_256_16" { + <include/bench/stft_process_s16.conf> + } + "stft_process_1024_256_24" { + <include/bench/stft_process_s24.conf> + } + "stft_process_1024_256_32" { + <include/bench/stft_process_s32.conf> + } + "stft_process_1536_240_16" { + <include/bench/stft_process_s16.conf> + } + "stft_process_1536_240_24" { + <include/bench/stft_process_s24.conf> + } + "stft_process_1536_240_32" { + <include/bench/stft_process_s32.conf> + } + + # + # tdfb component + # + + "tdfb16" { + <include/bench/tdfb_s16.conf> + } + + "tdfb24" { + <include/bench/tdfb_s24.conf> + } + + "tdfb32" { + <include/bench/tdfb_s32.conf> + } + + # + # template_comp component + # + + "template_comp16" { + <include/bench/template_comp_s16.conf> + } + + "template_comp24" { + <include/bench/template_comp_s24.conf> + } + + "template_comp32" { + <include/bench/template_comp_s32.conf> + } +} \ No newline at end of file diff --git a/tools/topology/topology2/cavs-es83x6.conf b/tools/topology/topology2/cavs-es83x6.conf index fbd9c82d3139..6a5fc31054b7 100644 --- a/tools/topology/topology2/cavs-es83x6.conf +++ b/tools/topology/topology2/cavs-es83x6.conf @@ -38,6 +38,7 @@ <pipeline.conf> <dai.conf> <host.conf> +<bt-default.conf> <dmic-default.conf> <hdmi-default.conf> <hdmi-in-default.conf> @@ -61,12 +62,14 @@ Define { HEADSET_HW_CONFIG_NAME 'HEADSET HWCFG' HEADSET_PCM_NAME "Headset" HEADSET_PCM_ID 0 + INCLUDE_BT_OFFLOAD false } # override defaults with platform-specific config IncludeByKey.PLATFORM { "mtl" "platform/intel/mtl.conf" "lnl" "platform/intel/lnl.conf" + "ptl" "platform/intel/ptl.conf" } # include HDMI config if needed. @@ -74,6 +77,10 @@ IncludeByKey.NUM_HDMIS { "[3-4]" "platform/intel/hdmi-generic.conf" } +IncludeByKey.INCLUDE_BT_OFFLOAD { + "true" "platform/intel/bt-generic.conf" +} + IncludeByKey.HEADSET_CODEC { "true" { # diff --git a/tools/topology/topology2/cavs-mixin-mixout-dax-hda.conf b/tools/topology/topology2/cavs-mixin-mixout-dax-hda.conf new file mode 100644 index 000000000000..bed5549d36bd --- /dev/null +++ b/tools/topology/topology2/cavs-mixin-mixout-dax-hda.conf @@ -0,0 +1,446 @@ +<include/components/tdfb.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_CAPTURE_RATE 48000 + HDA_ANALOG_PLAYBACK_RATE 48000 + EFX_FIR_PARAMS 'passthrough' + EFX_IIR_PARAMS 'passthrough' + EFX_DRC_PARAMS 'passthrough' + HDA_MIC_ENHANCED_CAPTURE 'false' + DOLBY_DAX_CORE_ID 0 +} + +# include deep buffer config if buffer size is in 1 - 1000 ms. +IncludeByKey.DEEPBUFFER_FW_DMA_MS{ + "[1-1000]" "platform/intel/deep-buffer.conf" +} + +Object.Dai.HDA [ + { + name $HDA_ANALOG_DAI_NAME + dai_index 0 + id 4 + default_hw_conf_id 4 + Object.Base.hw_config.1 { + name "HDA0" + } + direction duplex + } +] + +Object.Pipeline { + mixout-gain-dax-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" + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $HDA_ANALOG_PLAYBACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $HDA_ANALOG_PLAYBACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $ANALOG_PLAYBACK_PCM Volume' + } + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $HDA_ANALOG_PLAYBACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $HDA_ANALOG_PLAYBACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + Object.Widget.dolby-dax.1 { + core_id $DOLBY_DAX_CORE_ID + Object.Control { + mixer."1" { + name 'DAX $ANALOG_PLAYBACK_PCM Switch' + } + mixer."2" { + name 'DAX $ANALOG_PLAYBACK_PCM Switch CP' + } + mixer."3" { + name 'DAX $ANALOG_PLAYBACK_PCM Switch CTC' + } + mixer."4" { + name 'DAX $ANALOG_PLAYBACK_PCM Volume' + } + enum."1" { + name 'DAX $ANALOG_PLAYBACK_PCM Profile' + } + enum."2" { + name 'DAX $ANALOG_PLAYBACK_PCM Device' + } + bytes."1" { + name 'DAX $ANALOG_PLAYBACK_PCM Tuning' + max 8192 + } + } + } + } + ] + + host-copier-gain-mixin-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_rate $HDA_ANALOG_PLAYBACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $HDA_ANALOG_PLAYBACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate $HDA_ANALOG_PLAYBACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $HDA_ANALOG_PLAYBACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $ANALOG_PLAYBACK_PCM Volume' + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $HDA_ANALOG_PLAYBACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $HDA_ANALOG_PLAYBACK_RATE + 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_rate $HDA_ANALOG_CAPTURE_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $HDA_ANALOG_CAPTURE_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_rate $HDA_ANALOG_CAPTURE_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_rate $HDA_ANALOG_CAPTURE_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + dai-copier-eqiir-module-copier-capture [ + { + index 4 + + 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_rate $HDA_ANALOG_CAPTURE_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $HDA_ANALOG_CAPTURE_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + Object.Widget.eqiir.1 { + Object.Control.bytes."1" { + name '$ANALOG_CAPTURE_PCM IIR Eq' + <include/components/eqiir/highpass_40hz_0db_48khz.conf> + } + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $HDA_ANALOG_CAPTURE_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $HDA_ANALOG_CAPTURE_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + Object.Widget.module-copier."2" { + stream_name $HDA_ANALOG_DAI_NAME + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $HDA_ANALOG_CAPTURE_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $HDA_ANALOG_CAPTURE_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] +} + +IncludeByKey.HDA_MIC_ENHANCED_CAPTURE { + "true" { + Object.Widget.tdfb.1 { + index 3 + + Object.Control { + bytes."1" { + name 'Analog Capture TDFB bytes' + max 16384 + IncludeByKey.EFX_HDA_MIC_TDFB_PARAMS { + "line2_pass" "include/components/tdfb/line2_pass.conf" + "line2_generic_pm10deg" "include/components/tdfb/line2_generic_pm10deg_48khz.conf" + "line2_50mm" "include/components/tdfb/line2_50mm_pm0_30_90deg_48khz.conf" + "line2_68mm" "include/components/tdfb/line2_68mm_pm0_30_90deg_48khz.conf" + "line2_74mm" "include/components/tdfb/line2_74mm_pm0_30_90deg_48khz.conf" + } + } + mixer."1" { + name 'Analog Capture TDFB beam switch' + } + enum."1" { + name 'Analog Capture TDFB angle set enum' + } + # Tracking is disabled from this topology, causes high MCPS + #mixer."2" { + # name 'Analog Capture TDFB track switch' + #} + #enum."2" { + # name 'Analog Capture TDFB angle estimate enum' + #} + } + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $HDA_ANALOG_CAPTURE_RATE + in_channels 2 + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_channels 2 + out_rate $HDA_ANALOG_CAPTURE_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + Object.Widget.drc.1 { + index 3 + + Object.Control { + bytes."1" { + name 'Analog Capture DRC bytes' + IncludeByKey.EFX_HDA_MIC_DRC_PARAMS { + "passthrough" "include/components/drc/passthrough.conf" + "amic_default" "include/components/drc/amic_default.conf" + } + } + mixer."1" { + name 'Analog Capture DRC switch' + } + } + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $HDA_ANALOG_CAPTURE_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_rate $HDA_ANALOG_CAPTURE_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } +} + +Object.PCM.pcm [ + { + id 0 + name 'HDA Analog' + Object.Base.fe_dai.1 { + name "HDA Analog" + } + Object.PCM.pcm_caps.1 { + direction "playback" + name $ANALOG_PLAYBACK_PCM + formats 'S32_LE,S24_LE,S16_LE' + rate_min $HDA_ANALOG_PLAYBACK_RATE + rate_max $HDA_ANALOG_PLAYBACK_RATE + } + Object.PCM.pcm_caps.2 { + direction "capture" + name $ANALOG_CAPTURE_PCM + formats 'S32_LE,S24_LE,S16_LE' + rate_min $HDA_ANALOG_CAPTURE_RATE + rate_max $HDA_ANALOG_CAPTURE_RATE + } + direction duplex + } +] + +# top-level pipeline connections +Object.Base.route [ + { + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + source 'dolby-dax.2.1' + } + { + source 'mixin.1.1' + sink 'mixout.2.1' + } + { + source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' + sink 'eqiir.4.1' + } + { + source 'host-copier.0.playback' + sink 'gain.1.1' + } +] + +IncludeByKey.HDA_MIC_ENHANCED_CAPTURE { + "true" { + Object.Base.route [ + { + source 'module-copier.4.2' + sink 'tdfb.3.1' + } + { + source 'tdfb.3.1' + sink 'drc.3.1' + } + { + source 'drc.3.1' + sink 'host-copier.0.capture' + } + ] + } + "false" { + Object.Base.route [ + { + source 'module-copier.4.2' + sink 'host-copier.0.capture' + } + ] + } +} diff --git a/tools/topology/topology2/cavs-mixin-mixout-dax-ssp.conf b/tools/topology/topology2/cavs-mixin-mixout-dax-ssp.conf new file mode 100644 index 000000000000..23440bc5d163 --- /dev/null +++ b/tools/topology/topology2/cavs-mixin-mixout-dax-ssp.conf @@ -0,0 +1,371 @@ +# +# Pipeline definitions +# +# PCM0 ---> gain ----> Mixin ----> Mixout ----> gain ----> DAX ----> CTC ----> SSP0 +# PCM1 ---> gain ----> Mixin ----> Mixout ----> gain ----> DAX ----> CTC ----> SSP1 +# +# The gain before mixin is for the different routes(e.g., deepbuffer, headset). + +Define { + DOLBY_DAX_CORE_ID 0 + SSP_HEADSET_DAX "false" + USE_CTC_SPK "false" +} + + +# Pipeline ID:1 PCM ID: 0 +Object.Pipeline { + # playback pipelines + host-copier-gain-mixin-playback [ + { + index $HEADSET_HOST_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name '$HEADSET_PLAYBACK_PCM_STREAM_NAME' + pcm_id $HEADSET_PCM_ID + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $HEADSET_PCM_NAME Playback Volume' + } + } + } + { + index $SPEAKER_HOST_PIPELINE_ID + core_id $SPEAKER_PCM_CORE_ID + + Object.Widget.host-copier.1 { + stream_name '$SPEAKER_PLAYBACK_PCM_STREAM_NAME' + pcm_id $SPEAKER_PCM_ID + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $SPEAKER_PCM_NAME Playback Volume' + } + } + Object.Widget.pipeline.1 { + core $SPEAKER_PCM_CORE_ID + } + } + ] + + IncludeByKey.SSP_HEADSET_DAX { + "true" { + mixout-gain-dax-dai-copier-playback [ + { + index $HEADSET_DAI_PIPELINE_ID + stream_name "$HEADSET_CODEC_NAME" + + Object.Widget.dai-copier.1 { + dai_index $HEADSET_SSP_DAI_INDEX + dai_type "SSP" + copier_type "SSP" + stream_name "$HEADSET_CODEC_NAME" + node_type $I2S_LINK_OUTPUT_CLASS + + IncludeByKey.SSP_HS_FMT_24 { + "true" { + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_sample_type $SAMPLE_TYPE_LSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + "false" { + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + } + + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $HEADSET_PCM_NAME Playback Volume' + } + } + + Object.Widget.dolby-dax.1 { + core_id $DOLBY_DAX_CORE_ID + Object.Control { + mixer."1" { + name 'DAX Headphone Switch' + } + mixer."2" { + name 'DAX Headphone Switch CP' + } + mixer."3" { + name 'DAX Headphone Switch CTC' + } + mixer."4" { + name 'DAX Headphone Volume' + } + enum."1" { + name 'DAX Headphone Profile' + } + enum."2" { + name 'DAX Headphone Device' + } + bytes."1" { + name 'DAX Headphone Tuning' + max 8192 + } + } + } + } + ] + } + "false" { + mixout-gain-dai-copier-playback [ + { + index $HEADSET_DAI_PIPELINE_ID + + Object.Widget.dai-copier.1 { + dai_index $HEADSET_SSP_DAI_INDEX + dai_type "SSP" + copier_type "SSP" + stream_name "$HEADSET_CODEC_NAME" + node_type $I2S_LINK_OUTPUT_CLASS + + IncludeByKey.SSP_HS_FMT_24 { + "true" { + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_sample_type $SAMPLE_TYPE_LSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + "false" { + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + } + + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $HEADSET_PCM_NAME Playback Volume' + } + } + } + ] + } + } + + IncludeByKey.USE_CTC_SPK { + "true" { + mixout-gain-dax-ctc-dai-copier-playback [ + { + index $SPEAKER_DAI_PIPELINE_ID + core_id $SPEAKER_PCM_CORE_ID + stream_name "$SPEAKER_CODEC_NAME" + + Object.Widget.dai-copier.1 { + dai_index $SPEAKER_SSP_DAI_INDEX + dai_type "SSP" + copier_type "SSP" + stream_name "$SPEAKER_CODEC_NAME" + node_type $I2S_LINK_OUTPUT_CLASS + + IncludeByKey.SSP_SPK_FMT_24 { + "true" { + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_sample_type $SAMPLE_TYPE_LSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + "false" { + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + } + + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $SPEAKER_PCM_NAME Playback Volume' + } + } + + Object.Widget.dolby-dax.1 { + core_id $DOLBY_DAX_CORE_ID + Object.Control { + mixer."1" { + name 'DAX Speaker Switch' + } + mixer."2" { + name 'DAX Speaker Switch CP' + } + mixer."3" { + name 'DAX Speaker Switch CTC' + } + mixer."4" { + name 'DAX Speaker Volume' + } + enum."1" { + name 'DAX Speaker Profile' + } + enum."2" { + name 'DAX Speaker Device' + } + bytes."1" { + name 'DAX Speaker Tuning' + max 8192 + } + } + } + + Object.Widget.pipeline.1 { + core $SPEAKER_PCM_CORE_ID + } + } + ] + } + "false" { + mixout-gain-dax-dai-copier-playback [ + { + index $SPEAKER_DAI_PIPELINE_ID + core_id $SPEAKER_PCM_CORE_ID + stream_name "$SPEAKER_CODEC_NAME" + + Object.Widget.dai-copier.1 { + dai_index $SPEAKER_SSP_DAI_INDEX + dai_type "SSP" + copier_type "SSP" + stream_name "$SPEAKER_CODEC_NAME" + node_type $I2S_LINK_OUTPUT_CLASS + + IncludeByKey.SSP_SPK_FMT_24 { + "true" { + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_sample_type $SAMPLE_TYPE_LSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + "false" { + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + } + + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $SPEAKER_PCM_NAME Playback Volume' + } + } + + Object.Widget.dolby-dax.1 { + core_id $DOLBY_DAX_CORE_ID + Object.Control { + mixer."1" { + name 'DAX Speaker Switch' + } + mixer."2" { + name 'DAX Speaker Switch CP' + } + mixer."3" { + name 'DAX Speaker Switch CTC' + } + mixer."4" { + name 'DAX Speaker Volume' + } + enum."1" { + name 'DAX Speaker Profile' + } + enum."2" { + name 'DAX Speaker Device' + } + bytes."1" { + name 'DAX Speaker Tuning' + max 8192 + } + } + } + + Object.Widget.pipeline.1 { + core $SPEAKER_PCM_CORE_ID + } + } + ] + } + } +} + +Object.Base.route [ + { + source "mixin.$HEADSET_HOST_PIPELINE_ID.1" + sink "mixout.$HEADSET_DAI_PIPELINE_ID.1" + } + { + source "mixin.$SPEAKER_HOST_PIPELINE_ID.1" + sink "mixout.$SPEAKER_DAI_PIPELINE_ID.1" + } +] + +IncludeByKey.SSP_HEADSET_DAX { + "true" { + Object.Base.route [ + { + source "dolby-dax.$HEADSET_DAI_PIPELINE_ID.1" + sink "dai-copier.SSP.$HEADSET_CODEC_NAME.playback" + } + ] + } + "false" { + Object.Base.route [ + { + source "gain.$HEADSET_DAI_PIPELINE_ID.1" + sink "dai-copier.SSP.$HEADSET_CODEC_NAME.playback" + } + ] + } +} + +IncludeByKey.USE_CTC_SPK { + "true" { + Object.Base.route [ + { + source "ctc.$SPEAKER_DAI_PIPELINE_ID.1" + sink "dai-copier.SSP.$SPEAKER_CODEC_NAME.playback" + } + ] + } + "false" { + Object.Base.route [ + { + source "dolby-dax.$SPEAKER_DAI_PIPELINE_ID.1" + sink "dai-copier.SSP.$SPEAKER_CODEC_NAME.playback" + } + ] + } +} diff --git a/tools/topology/topology2/cavs-mixin-mixout-hda.conf b/tools/topology/topology2/cavs-mixin-mixout-hda.conf index 83742186fb8b..e83499754107 100644 --- a/tools/topology/topology2/cavs-mixin-mixout-hda.conf +++ b/tools/topology/topology2/cavs-mixin-mixout-hda.conf @@ -9,6 +9,8 @@ Define { DEEP_BUFFER_PIPELINE_SRC 'mixin.15.1' DEEP_BUFFER_PIPELINE_SINK 'mixout.2.1' DEEP_BUFFER_PCM_NAME 'Deepbuffer HDA Analog' + COMPR_PIPELINE_SINK 'mixout.2.1' + COMPR_PCM_NAME 'Compress HDA Analog' HDA_ANALOG_CAPTURE_RATE 48000 HDA_ANALOG_PLAYBACK_RATE 48000 EFX_FIR_PARAMS 'passthrough' @@ -22,6 +24,10 @@ IncludeByKey.DEEPBUFFER_FW_DMA_MS{ "[1-1000]" "platform/intel/deep-buffer.conf" } +IncludeByKey.COMPRESSED { + "true" "platform/intel/compr.conf" +} + Object.Dai.HDA [ { name $HDA_ANALOG_DAI_NAME diff --git a/tools/topology/topology2/cavs-nocodec-bt.conf b/tools/topology/topology2/cavs-nocodec-bt.conf index 0e9217b5481e..fe69a352f075 100644 --- a/tools/topology/topology2/cavs-nocodec-bt.conf +++ b/tools/topology/topology2/cavs-nocodec-bt.conf @@ -63,6 +63,7 @@ IncludeByKey.PLATFORM { "adl" "platform/intel/tgl.conf" "mtl" "platform/intel/mtl.conf" "lnl" "platform/intel/lnl.conf" + "ptl" "platform/intel/ptl.conf" } # include DMIC config if needed. @@ -81,15 +82,58 @@ Object.Dai.SSP [ direction "duplex" name NoCodec-0 default_hw_conf_id 0 - sample_bits 32 + sample_bits 16 quirks "lbm_mode" - io_clk $MCLK + io_clk $BT_MCLK Object.Base.hw_config.1 { - name "SSP0" - id 0 - bclk_freq 3072000 - tdm_slot_width 32 - # TODO: remove this. Needs alsaptlg change. + id 0 + name "BT-SCO-WB" + mclk_freq $BT_MCLK + bclk_freq 256000 + bclk_invert true + tdm_slot_width 16 + format "DSP_A" + bclk "codec_consumer" + fsync "codec_consumer" + fsync_freq 16000 + tdm_slots 1 + tx_slots 1 + rx_slots 1 + Object.Base.link_config.1 { + clock_source 1 + } + } + Object.Base.hw_config.2 { + id 1 + name "BT-SCO-NB" + mclk_freq $BT_MCLK + bclk_freq 128000 + bclk_invert true + tdm_slot_width 16 + format "DSP_A" + bclk "codec_consumer" + fsync "codec_consumer" + fsync_freq 8000 + tdm_slots 1 + tx_slots 1 + rx_slots 1 + Object.Base.link_config.1 { + clock_source 1 + } + } + Object.Base.hw_config.3 { + id 2 + name "BT-A2DP" + mclk_freq $BT_MCLK + bclk_freq 1536000 + tdm_slot_width 16 + format "DSP_A" + bclk "codec_consumer" + fsync "codec_consumer" + fsync_freq 48000 + tdm_slots 2 + tx_slots 3 + rx_slots 3 Object.Base.link_config.1 { clock_source 1 } @@ -101,16 +145,58 @@ Object.Dai.SSP [ direction "duplex" name NoCodec-1 default_hw_conf_id 0 - sample_bits 32 + sample_bits 16 quirks "lbm_mode" - io_clk $MCLK - + io_clk $BT_MCLK Object.Base.hw_config.1 { - name "SSP1" - id 0 - bclk_freq 3072000 - tdm_slot_width 32 - # TODO: remove this. Needs alsaptlg change. + id 0 + name "BT-SCO-WB" + mclk_freq $BT_MCLK + bclk_freq 256000 + bclk_invert true + tdm_slot_width 16 + format "DSP_A" + bclk "codec_consumer" + fsync "codec_consumer" + fsync_freq 16000 + tdm_slots 1 + tx_slots 1 + rx_slots 1 + Object.Base.link_config.1 { + clock_source 1 + } + } + Object.Base.hw_config.2 { + id 1 + name "BT-SCO-NB" + mclk_freq $BT_MCLK + bclk_freq 128000 + bclk_invert true + tdm_slot_width 16 + format "DSP_A" + bclk "codec_consumer" + fsync "codec_consumer" + fsync_freq 8000 + tdm_slots 1 + tx_slots 1 + rx_slots 1 + Object.Base.link_config.1 { + clock_source 1 + } + } + Object.Base.hw_config.3 { + id 2 + name "BT-A2DP" + mclk_freq $BT_MCLK + bclk_freq 1536000 + tdm_slot_width 16 + format "DSP_A" + bclk "codec_consumer" + fsync "codec_consumer" + fsync_freq 48000 + tdm_slots 2 + tx_slots 3 + rx_slots 3 Object.Base.link_config.1 { clock_source 1 } @@ -130,7 +216,7 @@ Object.Pipeline { index 2 direction playback Object.Widget.pipeline.1 { - stream_name 'NoCodec-0' + stream_name "dai-copier.SSP.NoCodec-0.playback" } Object.Widget.dai-copier.1 { @@ -140,13 +226,49 @@ Object.Pipeline { stream_name "NoCodec-0" node_type $I2S_LINK_OUTPUT_CLASS num_input_pins 1 + num_input_audio_formats 3 + num_output_audio_formats 3 + num_input_pins 1 + + CombineArrays.Object.Base.output_audio_format [ + # array of 2ch format with range of rates + { + out_rate [ + 8000 + 16000 + ] + out_channels [ 1 ] + } + # 2ch 16-bit 48k + { + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 2 ] + } + ] + CombineArrays.Object.Base.input_audio_format [ + # array of 2ch format with range of rates + { + in_rate [ + 8000 + 16000 + ] + in_channels [ 1 ] + } + # 2ch 16-bit 48k + { + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 2 ] + } + ] } } { index 4 direction playback Object.Widget.pipeline.1 { - stream_name 'NoCodec-1' + stream_name "dai-copier.SSP.NoCodec-1.playback" } Object.Widget.dai-copier.1 { @@ -156,6 +278,42 @@ Object.Pipeline { stream_name "NoCodec-1" node_type $I2S_LINK_OUTPUT_CLASS num_input_pins 1 + num_input_audio_formats 3 + num_output_audio_formats 3 + num_input_pins 1 + + CombineArrays.Object.Base.output_audio_format [ + # array of 2ch format with range of rates + { + out_rate [ + 8000 + 16000 + ] + out_channels [ 1 ] + } + # 2ch 16-bit 48k + { + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 2 ] + } + ] + CombineArrays.Object.Base.input_audio_format [ + # array of 2ch format with range of rates + { + in_rate [ + 8000 + 16000 + ] + in_channels [ 1 ] + } + # 2ch 16-bit 48k + { + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 2 ] + } + ] } } ] @@ -164,21 +322,89 @@ Object.Pipeline { { index 1 Object.Widget.pipeline.1 { - stream_name 'NoCodec-0' + stream_name "dai-copier.SSP.NoCodec-0.playback" } Object.Widget.host-copier.1 { stream_name 'SSP0 Playback' pcm_id 0 + num_input_audio_formats 3 + num_output_audio_formats 3 + CombineArrays.Object.Base.output_audio_format [ + # array of 2ch format with range of rates + { + out_rate [ + 8000 + 16000 + ] + out_channels [ 1 ] + } + # 2ch 16-bit 48k + { + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 2 ] + } + ] + CombineArrays.Object.Base.input_audio_format [ + # array of 2ch format with range of rates + { + in_rate [ + 8000 + 16000 + ] + in_channels [ 1 ] + } + # 2ch 16-bit 48k + { + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 2 ] + } + ] } } { index 3 Object.Widget.pipeline.1 { - stream_name 'NoCodec-1' + stream_name "dai-copier.SSP.NoCodec-1.playback" } Object.Widget.host-copier.1 { stream_name 'SSP1 Playback' pcm_id 1 + num_input_audio_formats 3 + num_output_audio_formats 3 + CombineArrays.Object.Base.output_audio_format [ + # array of 2ch format with range of rates + { + out_rate [ + 8000 + 16000 + ] + out_channels [ 1 ] + } + # 2ch 16-bit 48k + { + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 2 ] + } + ] + CombineArrays.Object.Base.input_audio_format [ + # array of 2ch format with range of rates + { + in_rate [ + 8000 + 16000 + ] + in_channels [ 1 ] + } + # 2ch 16-bit 48k + { + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 2 ] + } + ] } } ] @@ -188,21 +414,89 @@ Object.Pipeline { { index 5 Object.Widget.pipeline.1 { - stream_name 'NoCodec-0' + stream_name "dai-copier.SSP.NoCodec-0.capture" } Object.Widget.host-copier.1 { stream_name 'SSP0 Capture' pcm_id 0 + num_input_audio_formats 3 + num_output_audio_formats 3 + CombineArrays.Object.Base.output_audio_format [ + # array of 2ch format with range of rates + { + out_rate [ + 8000 + 16000 + ] + out_channels [ 1 ] + } + # 2ch 16-bit 48k + { + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 2 ] + } + ] + CombineArrays.Object.Base.input_audio_format [ + # array of 2ch format with range of rates + { + in_rate [ + 8000 + 16000 + ] + in_channels [ 1 ] + } + # 2ch 16-bit 48k + { + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 2 ] + } + ] } } { index 9 Object.Widget.pipeline.1 { - stream_name 'NoCodec-1' + stream_name "dai-copier.SSP.NoCodec-1.capture" } Object.Widget.host-copier.1 { stream_name 'SSP1 Capture' pcm_id 1 + num_input_audio_formats 3 + num_output_audio_formats 3 + CombineArrays.Object.Base.output_audio_format [ + # array of 2ch format with range of rates + { + out_rate [ + 8000 + 16000 + ] + out_channels [ 1 ] + } + # 2ch 16-bit 48k + { + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 2 ] + } + ] + CombineArrays.Object.Base.input_audio_format [ + # array of 2ch format with range of rates + { + in_rate [ + 8000 + 16000 + ] + in_channels [ 1 ] + } + # 2ch 16-bit 48k + { + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 2 ] + } + ] } } ] @@ -212,7 +506,7 @@ Object.Pipeline { index 6 direction capture Object.Widget.pipeline.1 { - stream_name 'NoCodec-0' + stream_name "dai-copier.SSP.NoCodec-0.capture" } Object.Widget.dai-copier."1" { @@ -222,16 +516,40 @@ Object.Pipeline { copier_type "SSP" stream_name "NoCodec-0" node_type $I2S_LINK_INPUT_CLASS - Object.Base.input_audio_format [ + num_input_audio_formats 3 + num_output_audio_formats 3 + num_input_pins 1 + + CombineArrays.Object.Base.output_audio_format [ + # array of 2ch format with range of rates + { + out_rate [ + 8000 + 16000 + ] + out_channels [ 1 ] + } + # 2ch 16-bit 48k { - in_bit_depth 32 - in_valid_bit_depth 32 + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 2 ] } ] - Object.Base.output_audio_format [ + CombineArrays.Object.Base.input_audio_format [ + # array of 2ch format with range of rates { - out_bit_depth 32 - out_valid_bit_depth 32 + in_rate [ + 8000 + 16000 + ] + in_channels [ 1 ] + } + # 2ch 16-bit 48k + { + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 2 ] } ] } @@ -240,7 +558,7 @@ Object.Pipeline { index 10 direction capture Object.Widget.pipeline.1 { - stream_name 'NoCodec-1' + stream_name "dai-copier.SSP.NoCodec-1.capture" } Object.Widget.dai-copier."1" { @@ -250,16 +568,40 @@ Object.Pipeline { copier_type "SSP" stream_name "NoCodec-1" node_type $I2S_LINK_INPUT_CLASS - Object.Base.input_audio_format [ + num_input_audio_formats 3 + num_output_audio_formats 3 + num_input_pins 1 + + CombineArrays.Object.Base.output_audio_format [ + # array of 2ch format with range of rates + { + out_rate [ + 8000 + 16000 + ] + out_channels [ 1 ] + } + # 2ch 16-bit 48k { - in_bit_depth 32 - in_valid_bit_depth 32 + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 2 ] } ] - Object.Base.output_audio_format [ + CombineArrays.Object.Base.input_audio_format [ + # array of 2ch format with range of rates + { + in_rate [ + 8000 + 16000 + ] + in_channels [ 1 ] + } + # 2ch 16-bit 48k { - out_bit_depth 32 - out_valid_bit_depth 32 + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 2 ] } ] } @@ -279,13 +621,19 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { direction "playback" name "SSP0 Playback" - formats 'S32_LE' + formats 'S16_LE' + rates '8000,16000,48000' + channels_min 1 + channels_max 2 } Object.PCM.pcm_caps.2 { direction "capture" name "SSP0 Capture" - formats 'S32_LE' + formats 'S16_LE' + rates '8000,16000,48000' + channels_min 1 + channels_max 2 } } { @@ -299,13 +647,19 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { direction "playback" name "SSP1 Playback" - formats 'S32_LE' + formats 'S16_LE' + rates '8000,16000,48000' + channels_min 1 + channels_max 2 } Object.PCM.pcm_caps.2 { direction "capture" name "SSP1 Capture" - formats 'S32_LE' + formats 'S16_LE' + rates '8000,16000,48000' + channels_min 1 + channels_max 2 } } ] diff --git a/tools/topology/topology2/cavs-nocodec.conf b/tools/topology/topology2/cavs-nocodec.conf index 4f66a8c08c9e..aec5016de76d 100644 --- a/tools/topology/topology2/cavs-nocodec.conf +++ b/tools/topology/topology2/cavs-nocodec.conf @@ -19,6 +19,7 @@ <dai-kpb-be.conf> <wov-detect.conf> <host-copier-gain-mixin-playback.conf> +<host-copier-micsel-gain-mixin-playback.conf> <host-copier-gain-src-mixin-playback.conf> <mixout-gain-dai-copier-playback.conf> <mixout-gain-smart-amp-dai-copier-playback.conf> @@ -51,6 +52,7 @@ <output_audio_format.conf> <dmic-default.conf> <ssp-default.conf> +<deep-buffer-default.conf> Define { MCLK 24576000 @@ -94,6 +96,9 @@ Define { SSP2_PCM_CORE_ID 2 DMIC0_PCM_0_NAME "DMIC SFX1" DMIC0_PCM_1_NAME "DMIC SFX2" + SRC_DOMAIN "default" + # Keep DP_SRC_CORE_ID == SSP2_PCM_CORE_ID, no nested define resolvation ATM + DP_SRC_CORE_ID 2 } # override defaults with platform-specific config @@ -103,6 +108,7 @@ IncludeByKey.PLATFORM { "mtl" "platform/intel/mtl.conf" "lnl" "platform/intel/lnl.conf" "ptl" "platform/intel/ptl.conf" + "nvl" "platform/intel/ptl.conf" # Note: Assume same configuration as PTL } # include DMIC config if needed. @@ -204,22 +210,464 @@ Object.Dai.SSP [ # PCM2 ---> gain ---> SRC ---> Mixin ---> Mixout ---> gain ---> SSP2 # PCM4 ---> gain ---> Mixin -------------------------->\ # PCM3 ---> gain ---> Mixin ---->\ \ -# PCM0 ---> gain ---> Mixin ---> Mixout ---> Mixin ---> Mixout ---> gain ---> smart_amp ---> SSP0 -# / -# /---------------------------------------------------------------------->/ -# SSP0 ---> PCM0 +# PCM0 ---> micsel ---> gain ---> Mixin ---> Mixout ---> Mixin ---> Mixout ---> gain ---> smart_amp ---> SSP0 +# / +# /---------------------------------------------------------------------------------->/ +# SSP0 ---> gain ---> module-copier ---> module-copier ---> gain ---> PCM0 +# \----> module-copier ---> gain ---> PCM0.1 # SSP1 ---> PCM1 # SSP2 ---> SRC ---> PCM2 IncludeByKey.PASSTHROUGH { "false" { - Object.Pipeline.host-copier-gain-mixin-playback [ + Object.Pipeline.host-copier-micsel-gain-mixin-playback [ { index 1 Object.Widget.host-copier.1 { stream_name 'SSP0 Playback' pcm_id 0 + num_input_audio_formats 49 + num_output_audio_formats 7 + + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_POINT_1 + } + { + 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 16 + in_valid_bit_depth 16 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + 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 24 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_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 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_POINT_1 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + 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 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_POINT_1 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + in_sample_type $SAMPLE_TYPE_A_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + in_sample_type $SAMPLE_TYPE_A_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_POINT_1 + in_sample_type $SAMPLE_TYPE_A_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + in_sample_type $SAMPLE_TYPE_A_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + in_sample_type $SAMPLE_TYPE_A_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + in_sample_type $SAMPLE_TYPE_A_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + in_sample_type $SAMPLE_TYPE_A_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + in_sample_type $SAMPLE_TYPE_MU_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + in_sample_type $SAMPLE_TYPE_MU_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_POINT_1 + in_sample_type $SAMPLE_TYPE_MU_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + in_sample_type $SAMPLE_TYPE_MU_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + in_sample_type $SAMPLE_TYPE_MU_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + in_sample_type $SAMPLE_TYPE_MU_LAW + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + in_sample_type $SAMPLE_TYPE_MU_LAW + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + out_sample_type $SAMPLE_TYPE_LSB_INTEGER + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 2 + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + out_sample_type $SAMPLE_TYPE_LSB_INTEGER + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 3 + out_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + out_ch_map $CHANNEL_MAP_2_POINT_1 + out_sample_type $SAMPLE_TYPE_LSB_INTEGER + } + { + 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_sample_type $SAMPLE_TYPE_LSB_INTEGER + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 5 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + out_ch_map $CHANNEL_MAP_5_POINT_0 + out_sample_type $SAMPLE_TYPE_LSB_INTEGER + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 6 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + out_sample_type $SAMPLE_TYPE_LSB_INTEGER + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 8 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + out_sample_type $SAMPLE_TYPE_LSB_INTEGER + } + ] + } + Object.Widget.micsel.1 { + Object.Control.bytes.1 { + name 'Pre Mixer $SSP0_PCM_NAME Playback Micsel Bytes' + <include/components/micsel/downmix_71_to_stereo_with_lfe.conf> + } } Object.Widget.gain.1 { curve_type "windows_fade" @@ -245,6 +693,17 @@ IncludeByKey.PASSTHROUGH { name 'Pre Mixer $SSP2_PCM_NAME Playback Volume' } } + Object.Widget.src.1 { + scheduler_domain "$SRC_DOMAIN" + IncludeByKey.SRC_DOMAIN { + "DP" { + core_id $DP_SRC_CORE_ID + domain_id 0 + stack_bytes_requirement 2048 + heap_bytes_requirement "$[(24 * 1024)]" + } + } + } Object.Widget.pipeline.1 { core $SSP2_PCM_CORE_ID } @@ -320,12 +779,91 @@ IncludeByKey.PASSTHROUGH { Object.Widget.host-copier.1 { stream_name 'SSP0 Capture' pcm_id $SSP0_PCM_ID + num_input_audio_formats 1 + num_output_audio_formats 7 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 8 + out_valid_bit_depth 8 + out_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + { + out_bit_depth 8 + out_valid_bit_depth 8 + out_sample_type $SAMPLE_TYPE_A_LAW + } + { + out_bit_depth 8 + out_valid_bit_depth 8 + out_sample_type $SAMPLE_TYPE_MU_LAW + } + { + 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 32 + out_valid_bit_depth 32 + out_sample_type $SAMPLE_TYPE_FLOAT + } + ] } Object.Widget.gain.1 { curve_type "windows_fade" Object.Control.mixer.1 { name 'Post Demux $SSP0_PCM_NAME Capture Volume' } + + num_input_audio_formats 1 + + Object.Base.input_audio_format [ + # 32-bit 48KHz 2ch + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.module-copier.2 { + num_input_audio_formats 1 + + Object.Base.input_audio_format [ + # 32-bit 48KHz 2ch + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] } } @@ -341,6 +879,43 @@ IncludeByKey.PASSTHROUGH { Object.Control.mixer.1 { name 'Post Demux $SSP0_CAPTURE_PCM Volume' } + + num_input_audio_formats 1 + + Object.Base.input_audio_format [ + # 32-bit 48KHz 2ch + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.module-copier.2 { + num_input_audio_formats 1 + + Object.Base.input_audio_format [ + # 32-bit 48KHz 2ch + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] } } ] @@ -512,36 +1087,16 @@ IncludeByKey.PASSTHROUGH { stream_name "NoCodec-0" node_type $I2S_LINK_OUTPUT_CLASS num_input_pins 1 - num_input_audio_formats 3 + num_input_audio_formats 1 Object.Base.input_audio_format [ - { - in_rate $SSP0_RATE - in_bit_depth 16 - in_valid_bit_depth 16 - } - { - in_rate $SSP0_RATE - in_bit_depth 32 - in_valid_bit_depth 24 - } { in_rate $SSP0_RATE in_bit_depth 32 in_valid_bit_depth 32 } ] - num_output_audio_formats 3 + num_output_audio_formats 1 Object.Base.output_audio_format [ - { - out_rate $SSP0_RATE - out_bit_depth 16 - out_valid_bit_depth 16 - } - { - out_rate $SSP0_RATE - out_bit_depth 32 - out_valid_bit_depth 24 - } { out_rate $SSP0_RATE out_bit_depth 32 @@ -561,36 +1116,16 @@ IncludeByKey.PASSTHROUGH { stream_name "NoCodec-2" node_type $I2S_LINK_OUTPUT_CLASS num_input_pins 1 - num_input_audio_formats 3 + num_input_audio_formats 1 Object.Base.input_audio_format [ - { - in_rate $SSP2_RATE - in_bit_depth 16 - in_valid_bit_depth 16 - } - { - in_rate $SSP2_RATE - in_bit_depth 32 - in_valid_bit_depth 24 - } { in_rate $SSP2_RATE in_bit_depth 32 in_valid_bit_depth 32 } ] - num_output_audio_formats 3 + num_output_audio_formats 1 Object.Base.output_audio_format [ - { - out_rate $SSP2_RATE - out_bit_depth 16 - out_valid_bit_depth 16 - } - { - out_rate $SSP2_RATE - out_bit_depth 32 - out_valid_bit_depth 24 - } { out_rate $SSP2_RATE out_bit_depth 32 @@ -625,18 +1160,8 @@ IncludeByKey.PASSTHROUGH { in_valid_bit_depth 32 } ] - num_output_audio_formats 3 + num_output_audio_formats 1 Object.Base.output_audio_format [ - { - out_rate $SSP0_RATE - out_bit_depth 16 - out_valid_bit_depth 16 - } - { - out_rate $SSP0_RATE - out_bit_depth 32 - out_valid_bit_depth 24 - } { out_rate $SSP0_RATE out_bit_depth 32 @@ -669,18 +1194,8 @@ IncludeByKey.PASSTHROUGH { in_valid_bit_depth 32 } ] - num_output_audio_formats 3 + num_output_audio_formats 1 Object.Base.output_audio_format [ - { - out_rate $SSP2_RATE - out_bit_depth 16 - out_valid_bit_depth 16 - } - { - out_rate $SSP2_RATE - out_bit_depth 32 - out_valid_bit_depth 24 - } { out_rate $SSP2_RATE out_bit_depth 32 @@ -698,18 +1213,8 @@ IncludeByKey.PASSTHROUGH { Object.Widget.host-copier.1 { stream_name 'SSP0 Capture' pcm_id 0 - num_input_audio_formats 3 + num_input_audio_formats 1 Object.Base.input_audio_format [ - { - in_rate $SSP0_RATE - in_bit_depth 16 - in_valid_bit_depth 16 - } - { - in_rate $SSP0_RATE - in_bit_depth 32 - in_valid_bit_depth 24 - } { in_rate $SSP0_RATE in_bit_depth 32 @@ -743,18 +1248,8 @@ IncludeByKey.PASSTHROUGH { Object.Widget.host-copier.1 { stream_name 'SSP2 Capture' pcm_id 2 - num_input_audio_formats 3 + num_input_audio_formats 1 Object.Base.input_audio_format [ - { - in_rate $SSP2_RATE - in_bit_depth 16 - in_valid_bit_depth 16 - } - { - in_rate $SSP2_RATE - in_bit_depth 32 - in_valid_bit_depth 24 - } { in_rate $SSP2_RATE in_bit_depth 32 @@ -883,6 +1378,15 @@ IncludeByKey.PASSTHROUGH { Object.Widget.src.1 { index 11 rate_in 48000 + scheduler_domain "$SRC_DOMAIN" + IncludeByKey.SRC_DOMAIN { + "DP" { + core_id $DP_SRC_CORE_ID + domain_id 0 + stack_bytes_requirement 2048 + heap_bytes_requirement "$[(24 * 1024)]" + } + } <include/components/src_format_s32_convert_from_48k.conf> } @@ -1078,7 +1582,7 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { direction "playback" name "SSP0 Playback" - formats 'S16_LE,S24_LE,S32_LE' + formats 'S16_LE,S24_LE,S32_LE,U8,A_LAW,MU_LAW,FLOAT_LE' IncludeByKey.SSP0_RATE { "48000" { rates '48000' @@ -1090,12 +1594,18 @@ Object.PCM.pcm [ rates '192000' } } + IncludeByKey.PASSTHROUGH { + "false" { + channels_min 1 + channels_max 8 + } + } } Object.PCM.pcm_caps.2 { direction "capture" name "SSP0 Capture" - formats 'S16_LE,S24_LE,S32_LE' + formats 'S16_LE,S24_LE,S32_LE,U8,A_LAW,MU_LAW,FLOAT_LE' IncludeByKey.SSP0_RATE { "48000" { rates '48000' @@ -1188,14 +1698,14 @@ IncludeByKey.PASSTHROUGH { direction "playback" name "SSP2 Playback" formats 'S16_LE,S24_LE,S32_LE' - rates "8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,176400,192000" + rates "8000,11025,16000,22050,24000,32000,44100,48000,64000,88200,96000,176400,192000" } Object.PCM.pcm_caps.2 { direction "capture" name "SSP2 Capture" formats 'S16_LE,S24_LE,S32_LE' - rates "8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,176400,192000" + rates "8000,11025,16000,22050,24000,32000,44100,48000,64000,88200,96000,176400,192000" } } ] @@ -1311,7 +1821,7 @@ IncludeByKey.PASSTHROUGH { } { source 'host-copier.0.playback' - sink 'gain.1.1' + sink 'micsel.1.1' } { source 'host-copier.2.playback' @@ -1530,36 +2040,16 @@ IncludeByKey.SSP1_ENABLED { copier_type "SSP" stream_name "NoCodec-1" node_type $I2S_LINK_OUTPUT_CLASS - num_input_audio_formats 3 + num_input_audio_formats 1 Object.Base.input_audio_format [ - { - in_rate $SSP1_RATE - in_bit_depth 16 - in_valid_bit_depth 16 - } - { - in_rate $SSP1_RATE - in_bit_depth 32 - in_valid_bit_depth 24 - } { in_rate $SSP1_RATE in_bit_depth 32 in_valid_bit_depth 32 } ] - num_output_audio_formats 3 + num_output_audio_formats 1 Object.Base.output_audio_format [ - { - out_rate $SSP1_RATE - out_bit_depth 16 - out_valid_bit_depth 16 - } - { - out_rate $SSP1_RATE - out_bit_depth 32 - out_valid_bit_depth 24 - } { out_rate $SSP1_RATE out_bit_depth 32 @@ -1593,18 +2083,8 @@ IncludeByKey.SSP1_ENABLED { in_valid_bit_depth 32 } ] - num_output_audio_formats 3 + num_output_audio_formats 1 Object.Base.output_audio_format [ - { - out_rate $SSP1_RATE - out_bit_depth 16 - out_valid_bit_depth 16 - } - { - out_rate $SSP1_RATE - out_bit_depth 32 - out_valid_bit_depth 24 - } { out_rate $SSP1_RATE out_bit_depth 32 diff --git a/tools/topology/topology2/cavs-rt5682.conf b/tools/topology/topology2/cavs-rt5682.conf index 13612730599a..99ccfbfbef56 100644 --- a/tools/topology/topology2/cavs-rt5682.conf +++ b/tools/topology/topology2/cavs-rt5682.conf @@ -20,6 +20,8 @@ <mixout-gain-dai-copier-playback.conf> <mixout-gain-eqiir-dts-dai-copier-playback.conf> <mixout-gain-ctc-dai-copier-playback.conf> +<mixout-gain-dax-dai-copier-playback.conf> +<mixout-gain-dax-ctc-dai-copier-playback.conf> <deepbuffer-playback.conf> <dai-copier-be.conf> <dai-copier-gain-eqiir-module-copier-capture.conf> @@ -45,6 +47,7 @@ <dmic-default.conf> <hdmi-default.conf> <bt-default.conf> +<deep-buffer-default.conf> <input_pin_binding.conf> <output_pin_binding.conf> <input_audio_format.conf> @@ -121,12 +124,16 @@ Define { DMIC_PIPELINE_PRIORITY 1 ECHO_REF_PIPELINE_PRIORITY 0 PLAYBACK_PIPELINE_SRC "volume" + USE_CTC_SPK "false" + DOLBY_DAX_CORE_ID 0 + SSP_HEADSET_DAX "false" SSP_SPK_FMT_24 false SSP_HS_FMT_24 false } # override defaults with platform-specific config IncludeByKey.PLATFORM { + "adl" "platform/intel/tgl.conf" "mtl" "platform/intel/mtl.conf" "lnl" "platform/intel/lnl.conf" "ptl" "platform/intel/ptl.conf" @@ -164,6 +171,7 @@ IncludeByKey.PLAYBACK_PIPELINE_SRC { "volume" "cavs-mixin-mixout-ssp.conf" "dts" "cavs-mixin-mixout-eqiir-dts-ssp.conf" "ctc" "cavs-mixin-mixout-ctc-ssp.conf" + "dax" "cavs-mixin-mixout-dax-ssp.conf" } diff --git a/tools/topology/topology2/cavs-sdw.conf b/tools/topology/topology2/cavs-sdw.conf index 4a88c4bd0bad..bcec2711a333 100644 --- a/tools/topology/topology2/cavs-sdw.conf +++ b/tools/topology/topology2/cavs-sdw.conf @@ -13,14 +13,25 @@ <virtual.conf> <host-copier-gain-mixin-playback.conf> <mixout-gain-alh-dai-copier-playback.conf> +<mixout-gain-ctc-alh-dai-copier-playback.conf> +<mixout-gain-dax-alh-dai-copier-playback.conf> +<mixout-gain-dax-ctc-alh-dai-copier-playback.conf> +<mixout-gain-micsel-eqiir-eqfir-alh-dai-copier-playback.conf> <mixout-gain-eqiir-eqfir-drc-alh-dai-copier-playback.conf> +<mixout-gain-eqiir-eqfir-drc-micsel-eqiir-eqfir-alh-dai-copier-playback.conf> +<mixout-gain-eqiir-dts-alh-dai-copier-playback.conf> +<mixout-gain-eqiir-dts-ctc-alh-dai-copier-playback.conf> <dai-copier-gain-eqiir-module-copier-capture.conf> <gain-capture.conf> <gain-copier-capture.conf> <deepbuffer-playback.conf> +<deepbuffer-capture.conf> +<compr-playback.conf> <host-gateway-playback.conf> <host-gateway-capture.conf> <host-gateway-tdfb-drc-capture.conf> +<host-gateway-src-mfcc-capture.conf> +<src.conf> <io-gateway.conf> <io-gateway-capture.conf> <highpass-capture-be.conf> @@ -31,6 +42,7 @@ <alh.conf> <hda.conf> <dmic.conf> +<ctc.conf> <intel/hw_config_cardinal_clk.conf> <manifest.conf> <route.conf> @@ -48,6 +60,9 @@ <intel/ssp_aux_config.conf> <ssp.conf> <bt-default.conf> +<deep-buffer-default.conf> +<compr-default.conf> +<siggen-host-copier-capture.conf> Define { PLATFORM "none" @@ -65,16 +80,29 @@ Define { DMIC0_ID 4 DMIC1_ID 5 DMIC0_PCM_CAPS 'Gain Capture 13' + DEEP_BUFFER_PIPELINE_ID 15 DEEP_BUFFER_PCM_ID 31 DEEP_BUFFER_PIPELINE_SRC 'mixin.15.1' DEEP_BUFFER_PIPELINE_SINK 'mixout.1.1' DEEP_BUFFER_PCM_NAME 'Deepbuffer Jack Out' + DEEP_BUFFER_PIPELINE_ID_2 16 + DEEP_BUFFER_PCM_ID_2 35 + DEEP_BUFFER_PIPELINE_SRC_2 'mixin.16.1' + DEEP_BUFFER_PIPELINE_SINK_2 'mixout.21.1' + DEEP_BUFFER_PCM_NAME_2 'Deepbuffer Speaker' + + COMPR_PIPELINE_SINK 'mixout.1.1' + COMPR_PCM_NAME 'Compress Jack Out' + COMPR_2_PIPELINE_SINK 'mixout.21.1' + COMPR_2_PCM_NAME 'Compress Speaker' + SDW_JACK_OUT_STREAM 'SDW0-Playback' SDW_JACK_IN_STREAM 'SDW0-Capture' SDW_JACK_OUT_BE_ID 0 SDW_JACK_IN_BE_ID 1 NUM_SDW_AMP_LINKS 0 + NUM_SDW_AMP_CTC_LINKS 0 SDW_DMIC 0 SDW_JACK true PASSTHROUGH false @@ -92,6 +120,15 @@ Define { EFX_MIC_TDFB_PARAMS "line2_generic_pm10deg" EFX_MIC_DRC_PARAMS "dmic_default" DMIC0_DAI_EQIIR "highpass_40hz_20db" + SDW_AMP_NUM_CHANNELS 2 + SDW_AMP_XOVER false + SDW_AMP_XOVER_SELECTOR_PARAMS default + SDW_AMP_XOVER_EQIIR_PARAMS default + SDW_AMP_XOVER_EQFIR_PARAMS default + DOLBY_DAX_CORE_ID 0 + SDW_AMP_PIPELINE_SRC "generic" + SDW_JACK_PIPELINE_SRC "generic" + SDW_ECHO_REF_DAI "false" } # override defaults with platform-specific config @@ -99,6 +136,7 @@ IncludeByKey.PLATFORM { "mtl" "platform/intel/mtl.conf" "lnl" "platform/intel/lnl.conf" "ptl" "platform/intel/ptl.conf" + "nvl" "platform/intel/ptl.conf" # Note: Assume same configuration as PTL } IncludeByKey.ADD_BT { @@ -119,8 +157,66 @@ IncludeByKey.NUM_HDMIS { "[3-4]" "platform/intel/hdmi-generic.conf" } -IncludeByKey.NUM_SDW_AMP_LINKS { -"[1-3]" "platform/intel/sdw-amp-generic.conf" +IncludeByKey.SDW_ECHO_REF_DAI { + "true" { + Object.Widget.alh-copier [ + { + stream_name "Loopback_Virtual" + direction "capture" + type "dai_out" + IncludeByKey.SDW_SPK_ECHO_REF { + "true" {index $SDW_SPK_ECHO_REF_PIPELINE_ID} + "false" {index $SDW_JACK_ECHO_REF_PIPELINE_ID} + } + dai_index 25 + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } +} + +IncludeByKey.SDW_AMP_XOVER { + "false" { + IncludeByKey.NUM_SDW_AMP_LINKS { + "[1-3]" { + IncludeByKey.SDW_AMP_PIPELINE_SRC { + "dax" "platform/intel/sdw-amp-dax.conf" + "dts" "platform/intel/sdw-amp-dts.conf" + "generic" "platform/intel/sdw-amp-generic.conf" + } + } + } + IncludeByKey.NUM_SDW_AMP_CTC_LINKS { + "[1-3]" { + IncludeByKey.SDW_AMP_PIPELINE_SRC { + "dax" "platform/intel/sdw-amp-dax-ctc.conf" + "dts" "platform/intel/sdw-amp-dts-ctc.conf" + "generic" "platform/intel/sdw-amp-generic-ctc.conf" + } + } + } + } + "true" { + IncludeByKey.NUM_SDW_AMP_LINKS { + "[1-3]" "platform/intel/sdw-amp-xover.conf" + } + } } IncludeByKey.SDW_DMIC { @@ -128,6 +224,63 @@ IncludeByKey.SDW_DMIC { } IncludeByKey.SDW_JACK { -"true" "platform/intel/sdw-jack-generic.conf" +"true" { + IncludeByKey.SDW_JACK_PIPELINE_SRC { + "dax" "platform/intel/sdw-jack-dax.conf" + "dts" "platform/intel/sdw-jack-dts.conf" + "generic" "platform/intel/sdw-jack-generic.conf" + } +} +"false" { + Define { + # disable compressed audio for Jack + COMPRESSED_1 false + } + } } +IncludeByKey.NUM_SDW_AMP_LINKS { + "[1-3]" { + Define { + # Enable compressed audio for Speaker + COMPRESSED_2 true + } + } +} + +IncludeByKey.NUM_SDW_AMP_CTC_LINKS { + "[1-3]" { + Define { + # Enable compressed audio for Speaker + COMPRESSED_2 true + } + } +} + +IncludeByKey.COMPRESSED { + "true" "platform/intel/compr.conf" +} + +IncludeByKey.SDW_JACK_ECHO_REF { + "true" "platform/intel/sdw-jack-echo-ref.conf" +} + +IncludeByKey.SDW_SPK_ECHO_REF { + "true" "platform/intel/sdw-amp-echo-ref.conf" +} + +IncludeByKey.SDW_JACK_AUDIO_FEATURE_CAPTURE { + "true" "platform/intel/sdw-jack-audio-feature.conf" +} + +IncludeByKey.SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE { + "true" "platform/intel/sdw-jack-audio-feature-compress.conf" +} + +IncludeByKey.SDW_DMIC_AUDIO_FEATURE_CAPTURE { + "true" "platform/intel/sdw-dmic-audio-feature.conf" +} + +IncludeByKey.SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE { + "true" "platform/intel/sdw-dmic-audio-feature-compress.conf" +} diff --git a/tools/topology/topology2/development/tplg-targets-bench.cmake b/tools/topology/topology2/development/tplg-targets-bench.cmake index 527dbfce3a20..2dd4f28bc07c 100644 --- a/tools/topology/topology2/development/tplg-targets-bench.cmake +++ b/tools/topology/topology2/development/tplg-targets-bench.cmake @@ -10,31 +10,57 @@ set(sampleformats "16" "24" "32") set(components "asrc" "dcblock" + "dolby-dax" "drc" "drc_multiband" "eqiir" "eqfir" "gain" "igo_nr" + "level_multiplier" + "mfcc" + "mfccmel" + "micsel" + "phase_vocoder" "rtnr" + "sound_dose" "src" "src_lite" + "stft_process_192_48_" + "stft_process_512_128_" + "stft_process_768_120_" + "stft_process_1024_256_" + "stft_process_1536_240_" "tdfb" + "template_comp" ) set(component_parameters "BENCH_ASRC_PARAMS=default" "BENCH_DCBLOCK_PARAMS=default" - "BENCH_DRC_PARAMS=enabled" + "BENCH_DOLBY-DAX_PARAMS=default" + "BENCH_DRC_PARAMS=default_speaker_mic" "BENCH_DRC_MULTIBAND_PARAMS=default" "BENCH_EQIIR_PARAMS=loudness" "BENCH_EQFIR_PARAMS=loudness" "BENCH_GAIN_PARAMS=default" "BENCH_IGO_NR_PARAMS=default" + "BENCH_LEVEL_MULTIPLIER_PARAMS=default" + "BENCH_MFCC_PARAMS=default" + "BENCH_MFCC_PARAMS=mel80" + "BENCH_MICSEL_PARAMS=passthrough" + "BENCH_PHASE_VOCODER_PARAMS=default" "BENCH_RTNR_PARAMS=default" + "BENCH_SOUND_DOSE_PARAMS=default" "BENCH_SRC_PARAMS=default" "BENCH_SRC_LITE_PARAMS=default" + "BENCH_STFT_PROCESS_PARAMS=hann_192_48" + "BENCH_STFT_PROCESS_PARAMS=hann_512_128" + "BENCH_STFT_PROCESS_PARAMS=hann_768_120" + "BENCH_STFT_PROCESS_PARAMS=hann_1024_256" + "BENCH_STFT_PROCESS_PARAMS=hann_1536_240" "BENCH_TDFB_PARAMS=default" + "BENCH_TEMPLATE_COMP_PARAMS=default" ) set(components_s24 @@ -45,19 +71,47 @@ set(component_parameters_s24 "BENCH_ARIA_PARAMS=param_2" ) +set(components_s32 + "micsel_multich" +) + +set(component_parameters_s32 + "BENCH_MICSEL_PARAMS=default" +) + +set (plat "mtl") + # Add components with all sample formats foreach(sf ${sampleformats}) foreach(comp bench_param IN ZIP_LISTS components component_parameters) - set(item "sof-hda-generic\;sof-hda-benchmark-${comp}${sf}\;HDA_CONFIG=benchmark,BENCH_CONFIG=${comp}${sf},${bench_param}") - #message(STATUS "Item=" ${item}) + set(item "cavs-benchmark-hda\;sof-hda-benchmark-${comp}${sf}\;PLATFORM=${plat},BENCH_MODULE_FORMAT=s${sf},BENCH_CONFIG=${comp}${sf},${bench_param}") + list(APPEND TPLGS "${item}") + set(item "cavs-benchmark-sdw\;sof-${plat}-sdw-benchmark-${comp}${sf}-sdw0\;PLATFORM=${plat},BENCH_MODULE_FORMAT=s${sf},BENCH_CONFIG=${comp}${sf},${bench_param}") + list(APPEND TPLGS "${item}") + set(item "cavs-benchmark-sdw\;sof-${plat}-sdw-benchmark-${comp}${sf}-simplejack\;PLATFORM=${plat},SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,BENCH_MODULE_FORMAT=s${sf},BENCH_CONFIG=${comp}${sf},${bench_param}") list(APPEND TPLGS "${item}") + #message(STATUS "Item=" ${item}) endforeach() endforeach() # Add components with single format set (sf "24") foreach(comp bench_param IN ZIP_LISTS components_s24 component_parameters_s24) - set(item "sof-hda-generic\;sof-hda-benchmark-${comp}${sf}\;HDA_CONFIG=benchmark,BENCH_CONFIG=${comp}${sf},${bench_param}") - #message(STATUS "Item=" ${item}) + set(item "cavs-benchmark-hda\;sof-hda-benchmark-${comp}${sf}\;PLATFORM=${plat},BENCH_MODULE_FORMAT=s${sf},BENCH_CONFIG=${comp}${sf},${bench_param}") + list(APPEND TPLGS "${item}") + set(item "cavs-benchmark-sdw\;sof-${plat}-sdw-benchmark-${comp}${sf}-sdw0\;PLATFORM=${plat},BENCH_MODULE_FORMAT=s${sf},BENCH_CONFIG=${comp}${sf},${bench_param}") + list(APPEND TPLGS "${item}") + set(item "cavs-benchmark-sdw\;sof-${plat}-sdw-benchmark-${comp}${sf}-simplejack\;PLATFORM=${plat},SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,BENCH_MODULE_FORMAT=s${sf},BENCH_CONFIG=${comp}${sf},${bench_param}") + list(APPEND TPLGS "${item}") +endforeach() + +set (sf "32") +foreach(comp bench_param IN ZIP_LISTS components_s32 component_parameters_s32) + #message(STATUS "Bench_param=" ${bench_param}) + set(item "cavs-benchmark-hda\;sof-hda-benchmark-${comp}${sf}\;PLATFORM=${plat},BENCH_MODULE_FORMAT=s${sf},BENCH_CONFIG=${comp}${sf},${bench_param}") + list(APPEND TPLGS "${item}") + set(item "cavs-benchmark-sdw\;sof-${plat}-sdw-benchmark-${comp}${sf}-sdw0\;PLATFORM=${plat},BENCH_MODULE_FORMAT=s${sf},BENCH_CONFIG=${comp}${sf},${bench_param}") + list(APPEND TPLGS "${item}") + set(item "cavs-benchmark-sdw\;sof-${plat}-sdw-benchmark-${comp}${sf}-simplejack\;PLATFORM=${plat},SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,BENCH_MODULE_FORMAT=s${sf},BENCH_CONFIG=${comp}${sf},${bench_param}") list(APPEND TPLGS "${item}") endforeach() diff --git a/tools/topology/topology2/development/tplg-targets.cmake b/tools/topology/topology2/development/tplg-targets.cmake index 1a5f5a6679ad..d6285209dce0 100644 --- a/tools/topology/topology2/development/tplg-targets.cmake +++ b/tools/topology/topology2/development/tplg-targets.cmake @@ -58,11 +58,11 @@ NHLT_BIN=nhlt-sof-lnl-nocodec-fpga-4ch.bin,PASSTHROUGH=true,DMIC_IO_CLK=19200000 # HDA topology with passthrough analog codec pipelines "sof-hda-generic\;sof-hda-passthrough\;HDA_CONFIG=passthrough" # HDA topology with passthrough analog codec pipelines using CHAIN_DMA -"sof-hda-generic\;sof-hda-passthrough-chain-dma\;HDA_CONFIG=passthrough\;CODEC_HDA_CHAIN_DMA=true" +"sof-hda-generic\;sof-hda-passthrough-chain-dma\;HDA_CONFIG=passthrough,CODEC_HDA_CHAIN_DMA=true" -# SSP topology for PTL +# SSP topology for PTL, includes Data Processing SRC "cavs-nocodec\;sof-ptl-nocodec\;PLATFORM=ptl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ -PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-nocodec.bin" +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-nocodec.bin,SRC_DOMAIN=DP" # SSP topology for PTL with 96 kHz DMIC "cavs-nocodec\;sof-ptl-nocodec-dmic-4ch-96k\;PLATFORM=ptl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ @@ -97,6 +97,10 @@ NHLT_BIN=nhlt-sof-ptl-nocodec-fpga-dmic-4ch-96k.bin,PASSTHROUGH=true,DMIC_IO_CLK PDM1_MIC_B_ENABLE=1,DMIC0_RATE=96000,SSP0_RATE=96000,PREPROCESS_PLUGINS=nhlt,\ NHLT_BIN=nhlt-sof-ptl-nocodec-fpga-dmic-4ch-96k-ssp0-96k.bin,PASSTHROUGH=true,DMIC_IO_CLK=19200000" +# SSP topology for NVL (limit to DSP cores 0/1) +"cavs-nocodec\;sof-nvl-nocodec\;PLATFORM=nvl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,SSP2_PCM_CORE_ID=0,DP_SRC_CORE_ID=0,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-nvl-nocodec.bin" + # Topology for PTL with max98357a and rt5682 "cavs-rt5682\;sof-ptl-max98357a-rt5682-ssp2-ssp0\;PLATFORM=ptl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ PDM1_MIC_B_ENABLE=1,DMIC0_PCM_ID=99,PREPROCESS_PLUGINS=nhlt,\ @@ -280,9 +284,17 @@ PLATFORM=mtl" "cavs-nocodec-bt\;sof-nocodec-bt-mtl-lbm\;BT_LOOPBACK_MODE=true,PLATFORM=mtl,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-nocodec-bt-mtl-lbm.bin" +# BT offload for ptl +"cavs-nocodec-bt\;sof-nocodec-bt-ptl\;PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-nocodec-bt-ptl.bin,\ +PLATFORM=ptl" +# BT offload loopback test topology (lbm) for ptl +"cavs-nocodec-bt\;sof-nocodec-bt-ptl-lbm\;BT_LOOPBACK_MODE=true,PLATFORM=ptl,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-nocodec-bt-ptl-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\;HDA_CONFIG=benchmark,BENCH_CONFIG=benchmark,BENCH_ARIA_PARAMS=param_1" +"cavs-benchmark-hda\;sof-hda-benchmark-generic\;HDA_CONFIG=benchmark,BENCH_CONFIG=benchmark,\ +BENCH_ARIA_PARAMS=param_1,BENCH_MODULE_FORMAT=s24" # Topology to test IPC4 Crossover "development/cavs-nocodec-crossover\;sof-tgl-nocodec-crossover-2way\;PLATFORM=tgl,\ @@ -292,6 +304,26 @@ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-tgl-nocodec-crossover.bin,EFX_CROSSOVE "development/cavs-nocodec-rtcaec\;sof-tgl-nocodec-rtcaec\;PLATFORM=tgl,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-tgl-nocodec-rtcaec.bin" +# SSP test topology for Data Processing SRC on MTL +"cavs-nocodec\;sof-mtl-nocodec-dp-test\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-nocodec.bin,SRC_DOMAIN=DP" +# SSP test topology for Data Processing SRC on LNL +"cavs-nocodec\;sof-lnl-nocodec-dp-test\;PLATFORM=lnl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-lnl-nocodec.bin,SRC_DOMAIN=DP" +# SSP test topology for PTL with no DP +"cavs-nocodec\;sof-ptl-nocodec-dp-test\;PLATFORM=ptl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-nocodec.bin" + +# SSP test topology for Data Processing on core 1 SRC for MTL +"cavs-nocodec\;sof-mtl-nocodec-dp-core-test\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-nocodec.bin,SRC_DOMAIN=DP,DP_SRC_CORE_ID=1" +# SSP test topology for Data Processing on core 1 SRC for LNL +"cavs-nocodec\;sof-lnl-nocodec-dp-core-test\;PLATFORM=lnl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-lnl-nocodec.bin,SRC_DOMAIN=DP,DP_SRC_CORE_ID=1" +# SSP test topology for Data Processing on core 1 SRC for PTL +"cavs-nocodec\;sof-ptl-nocodec-dp-core-test\;PLATFORM=ptl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-nocodec.bin,SRC_DOMAIN=DP,DP_SRC_CORE_ID=1" + # Add MFCC to 16 kHz DMIC1, 2ch with NHLT - cAVS "sof-hda-generic\;sof-hda-generic-cavs25-2ch-mfcc\;HDA_CONFIG=mix,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-cavs25-2ch-mfcc.bin,\ @@ -341,7 +373,147 @@ 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,\ DEEP_BUF_SPK=true,PLAYBACK_PIPELINE_SRC=ctc,SSP_SPK_FMT_24=true,SSP_HS_FMT_24=true" +# mtl-rt1019-rt5650 with DAX +"cavs-rt5682\;sof-mtl-rt1019-rt5682-dax\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ +PDM1_MIC_B_ENABLE=1,DMIC0_PCM_ID=99,SPK_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-mtl-rt1019-rt5682.bin,DEEPBUFFER_FW_DMA_MS=10,HEADSET_SSP_DAI_INDEX=2,\ +SPEAKER_SSP_DAI_INDEX=0,HEADSET_CODEC_NAME=SSP2-Codec,SPEAKER_CODEC_NAME=SSP0-Codec,\ +INCLUDE_ECHO_REF=true,PLAYBACK_PIPELINE_SRC=dax,DOLBY_DAX_CORE_ID=2,SSP_HEADSET_DAX=true,\ +BT_NAME=SSP1-BT,BT_INDEX=1,BT_ID=7,BT_PCM_NAME=Bluetooth,DEEP_BUF_SPK=true" + # CS35L56 SSP2 "cavs-cs35l56\;sof-tgl-cs35l56-ssp2\;PLATFORM=tgl,PREPROCESS_PLUGINS=nhlt,\ NHLT_BIN=nhlt-sof-tgl-cs35l56-ssp2.bin" + +# Topology for Google Brya +"cavs-rt5682\;sof-adl-max98357a-rt5682\;PLATFORM=adl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ +PDM1_MIC_B_ENABLE=1,DMIC0_PCM_ID=99,PREPROCESS_PLUGINS=nhlt,NUM_HDMIS=4,\ +NHLT_BIN=nhlt-sof-adl-max98357a-rt5682.bin,SPK_ID=7,DEEPBUFFER_FW_DMA_MS=10,INCLUDE_ECHO_REF=true,\ +INCLUDE_BT_OFFLOAD=false,DEEP_BUF_SPK=true,SPEAKER_CODEC_NAME=SSP2-Codec,SPEAKER_SSP_DAI_INDEX=2" + +# RT721 eval board with PCH-DMIC, sof_sdw_quirk_table with SOC_SDW_PCH_DMIC +# Enable FLOAT_LE and U8 PCM formats +"cavs-sdw\;sof-ptl-rt721-4ch-allfmt\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt721-4ch-allfmt.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,PCM_FORMAT_ALL=true" + +# Deep buffer DMIC0 +"sof-hda-generic\;sof-hda-generic-2ch-dmicdeepbuf\;HDA_CONFIG=mix,\ +NUM_DMICS=2,DMIC0_DEEP_BUFFER=true,DEEPBUFFER_FW_DMA_MS=10,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"sof-hda-generic\;sof-hda-generic-4ch-dmicdeepbuf\;HDA_CONFIG=mix,\ +NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_DEEP_BUFFER=true,DEEPBUFFER_FW_DMA_MS=10,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +# Deep buffer DMIC0 with tplg NHLT for PTL, 2ch and 4ch +"sof-hda-generic\;sof-hda-generic-ace3-2ch-dmicdeepbuf\;PLATFORM=ptl,HDA_CONFIG=mix,NUM_DMICS=2,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace3-2ch-dmicdeepbuf.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,\ +EFX_DMIC0_DRC_PARAMS=dmic_default,DMIC0_DEEP_BUFFER=true,DEEPBUFFER_FW_DMA_MS=10" + +"sof-hda-generic\;sof-hda-generic-ace3-4ch-dmicdeepbuf\;PLATFORM=ptl,HDA_CONFIG=mix,\ +NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-hda-generic-ace3-4ch-dmicdeepbuf.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line4_pass,\ +EFX_DMIC0_DRC_PARAMS=dmic_default,DMIC0_DEEP_BUFFER=true,DEEPBUFFER_FW_DMA_MS=10" + +# Deep buffer DMIC0 with RT721 eval board with PCH-DMIC +"cavs-sdw\;sof-ptl-rt721-4ch-dmicdeepbuf\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt721-4ch-dmicdeepbuf.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,DMIC0_DEEP_BUFFER=true" + +# RT721 eval board with PCH-DMIC, sof_sdw_quirk_table with SOC_SDW_PCH_DMIC +# Enable echo reference capture from jack and speaker output +"cavs-sdw\;sof-ptl-rt721-4ch-echoref\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt721-4ch-echoref.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,SDW_JACK_ECHO_REF=true,SDW_SPK_ECHO_REF=true,SDW_ECHO_REF_DAI=true" + +# RT721 eval board with PCH-DMIC, sof_sdw_quirk_table with SOC_SDW_PCH_DMIC +# Enable echo reference capture from jack and speaker output +# Enable SSP2 BT +"cavs-sdw\;sof-ptl-rt721-4ch-ssp2bt-echoref\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt721-4ch-echoref.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +BT_NAME=SSP2-BT,BT_PCM_ID=20,BT_ID=10,BT_PCM_NAME=Bluetooth,ADD_BT=true,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,SDW_JACK_ECHO_REF=true,SDW_SPK_ECHO_REF=true,SDW_ECHO_REF_DAI=true" + +# RT722 with PCH-DMIC and echo reference capture from jack and speaker output +"cavs-sdw\;sof-ptl-rt722-4ch-echoref\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt722-4ch-echoref.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +SDW_JACK_ECHO_REF=true,SDW_SPK_ECHO_REF=true,SDW_ECHO_REF_DAI=true" + +# Soundwire topologies with compressed support +"cavs-sdw\;sof-arl-cs42l43-l0-compr\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=1,SDW_DMIC=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,COMPRESSED=true" + +"cavs-sdw\;sof-mtl-rt713-l0-rt1316-l12-compr\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,COMPRESSED=true" + +"cavs-sdw\;sof-ptl-rt721-compr\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,COMPRESSED=true" + +"cavs-sdw\;sof-ptl-rt722-compr\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,COMPRESSED=true" + +# Soundwire topologies with MFCC audio features capture +"cavs-sdw\;sof-mtl-rt713-l0-rt1316-l12-mfcc-mel-normal\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,SDW_JACK_AUDIO_FEATURE_CAPTURE=true" + +"cavs-sdw\;sof-arl-cs42l43-l0-cs35l56-l23-mfcc-mel-normal\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,SDW_DMIC=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +SDW_JACK_AUDIO_FEATURE_CAPTURE=true,SDW_DMIC_AUDIO_FEATURE_CAPTURE=true" + +# Soundwire topologies with compress MFCC mel audio features capture +"cavs-sdw\;sof-mtl-rt713-l0-rt1316-l12-mfcc-mel-compr\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE=true,\ +MFCC_FRAME_BYTES=344,MFCC_BLOB=mel" + +# Soundwire topologies with compress MFCC cepstral audio features capture +"cavs-sdw\;sof-mtl-rt713-l0-rt1316-l12-mfcc-ceps-compr\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE=true,\ +MFCC_FRAME_BYTES=76,MFCC_BLOB=ceps" + +"cavs-sdw\;sof-arl-cs42l43-l0-cs35l56-l23-mfcc-mel-compr\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,SDW_DMIC=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE=true,SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE=true,\ +MFCC_FRAME_BYTES=344,MFCC_BLOB=mel" + +"cavs-sdw\;sof-arl-cs42l43-l0-cs35l56-l23-mfcc-ceps-compr\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,SDW_DMIC=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE=true,SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE=true,\ +MFCC_FRAME_BYTES=76,MFCC_BLOB=ceps" + +# Soundwire compressed feature topologies +"cavs-sdw\;sof-sdca-jack-compr\;SDW_JACK=false,NUM_HDMIS=0,COMPRESSED=true,\ +COMPRESSED_1=true,COMPRESSED_2=false" + +"cavs-sdw\;sof-sdca-amp-compr\;SDW_JACK=false,NUM_HDMIS=0,COMPRESSED=true,\ +COMPRESSED_1=false,COMPRESSED_2=true" + ) diff --git a/tools/topology/topology2/include/bench/aria_hda_route.conf b/tools/topology/topology2/include/bench/aria_hda_route.conf deleted file mode 100644 index ba50d062b11d..000000000000 --- a/tools/topology/topology2/include/bench/aria_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # Created with script "./bench_comp_generate.sh aria" - Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'aria.1.1' - } - { - sink 'aria.1.1' - source 'host-copier.0.playback' - } - { - source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' - sink 'aria.3.2' - } - { - source 'aria.3.2' - sink 'host-copier.0.capture' - } - ] diff --git a/tools/topology/topology2/include/bench/aria_route.conf b/tools/topology/topology2/include/bench/aria_route.conf new file mode 100644 index 000000000000..441523691a51 --- /dev/null +++ b/tools/topology/topology2/include/bench/aria_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh aria" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'aria.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'aria.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'aria.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'aria.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/aria_s24.conf b/tools/topology/topology2/include/bench/aria_s24.conf index c8b0be21704c..eaaa34b18bf3 100644 --- a/tools/topology/topology2/include/bench/aria_s24.conf +++ b/tools/topology/topology2/include/bench/aria_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh aria" Object.Widget.aria.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/aria_controls_playback.conf> } Object.Widget.aria.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/aria_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s24.conf> - <include/bench/aria_hda_route.conf> + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/aria_route.conf> diff --git a/tools/topology/topology2/include/bench/asrc_hda_route.conf b/tools/topology/topology2/include/bench/asrc_hda_route.conf deleted file mode 100644 index 853085a164b1..000000000000 --- a/tools/topology/topology2/include/bench/asrc_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # Created with script "./bench_comp_generate.sh asrc" - Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'asrc.1.1' - } - { - sink 'asrc.1.1' - source 'host-copier.0.playback' - } - { - source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' - sink 'asrc.3.2' - } - { - source 'asrc.3.2' - sink 'host-copier.0.capture' - } - ] diff --git a/tools/topology/topology2/include/bench/asrc_route.conf b/tools/topology/topology2/include/bench/asrc_route.conf new file mode 100644 index 000000000000..24985bff6176 --- /dev/null +++ b/tools/topology/topology2/include/bench/asrc_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh asrc" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'asrc.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'asrc.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'asrc.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'asrc.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/asrc_s16.conf b/tools/topology/topology2/include/bench/asrc_s16.conf index 82647eea960f..a87d2a601c71 100644 --- a/tools/topology/topology2/include/bench/asrc_s16.conf +++ b/tools/topology/topology2/include/bench/asrc_s16.conf @@ -1,17 +1,19 @@ # Created with script "./bench_comp_generate.sh asrc" + # Edited/added: + # - operation mode 1 for push for playback, 2 for pull for playback + # - rate_out 48000 for the fixed playback sink rate + # - rate_out 0 for the capture PCM defined sink rate Object.Widget.asrc.1 { - index 1 - asynchronous_mode 0 - operation_mode 0 - rate_out 48000 + index $BENCH_PLAYBACK_HOST_PIPELINE + operation_mode 1 + rate_out 48000 <include/components/src_format_s16_convert_to_48k.conf> } Object.Widget.asrc.2 { - index 3 - rate_in 48000 - asynchronous_mode 0 - operation_mode 1 + index $BENCH_CAPTURE_HOST_PIPELINE + operation_mode 2 + rate_out 0 <include/components/src_format_s16_convert_from_48k.conf> } - <include/bench/host_io_gateway_pipelines_src_s16.conf> - <include/bench/asrc_hda_route.conf> + <include/bench/host_gateway_pipelines_src_s16.conf> + <include/bench/asrc_route.conf> diff --git a/tools/topology/topology2/include/bench/asrc_s24.conf b/tools/topology/topology2/include/bench/asrc_s24.conf index 4121e4aa7447..ef06b0e8e10b 100644 --- a/tools/topology/topology2/include/bench/asrc_s24.conf +++ b/tools/topology/topology2/include/bench/asrc_s24.conf @@ -1,17 +1,19 @@ # Created with script "./bench_comp_generate.sh asrc" + # Edited/added: + # - operation mode 1 for push for playback, 2 for pull for playback + # - rate_out 48000 for the fixed playback sink rate + # - rate_out 0 for the capture PCM defined sink rate Object.Widget.asrc.1 { - index 1 - asynchronous_mode 0 - operation_mode 0 - rate_out 48000 + index $BENCH_PLAYBACK_HOST_PIPELINE + operation_mode 1 + rate_out 48000 <include/components/src_format_s24_convert_to_48k.conf> } Object.Widget.asrc.2 { - index 3 - asynchronous_mode 0 - operation_mode 1 - rate_in 48000 + index $BENCH_CAPTURE_HOST_PIPELINE + operation_mode 2 + rate_out 0 <include/components/src_format_s24_convert_from_48k.conf> } - <include/bench/host_io_gateway_pipelines_src_s24.conf> - <include/bench/asrc_hda_route.conf> + <include/bench/host_gateway_pipelines_src_s24.conf> + <include/bench/asrc_route.conf> diff --git a/tools/topology/topology2/include/bench/asrc_s32.conf b/tools/topology/topology2/include/bench/asrc_s32.conf index 2de2edaa08b5..9671f717a3d9 100644 --- a/tools/topology/topology2/include/bench/asrc_s32.conf +++ b/tools/topology/topology2/include/bench/asrc_s32.conf @@ -1,17 +1,19 @@ # Created with script "./bench_comp_generate.sh asrc" + # Edited/added: + # - operation mode 1 for push for playback, 2 for pull for playback + # - rate_out 48000 for the fixed playback sink rate + # - rate_out 0 for the capture PCM defined sink rate Object.Widget.asrc.1 { - index 1 - asynchronous_mode 0 - operation_mode 0 - rate_out 48000 + index $BENCH_PLAYBACK_HOST_PIPELINE + operation_mode 1 + rate_out 48000 <include/components/src_format_s32_convert_to_48k.conf> } Object.Widget.asrc.2 { - index 3 - asynchronous_mode 0 - operation_mode 1 - rate_in 48000 + index $BENCH_CAPTURE_HOST_PIPELINE + operation_mode 2 + rate_out 0 <include/components/src_format_s32_convert_from_48k.conf> } - <include/bench/host_io_gateway_pipelines_src_s32.conf> - <include/bench/asrc_hda_route.conf> + <include/bench/host_gateway_pipelines_src_s32.conf> + <include/bench/asrc_route.conf> diff --git a/tools/topology/topology2/include/bench/bench_comp_generate.sh b/tools/topology/topology2/include/bench/bench_comp_generate.sh index 638628ccce57..3a9c5aa9c229 100755 --- a/tools/topology/topology2/include/bench/bench_comp_generate.sh +++ b/tools/topology/topology2/include/bench/bench_comp_generate.sh @@ -28,41 +28,41 @@ generate_comp () cat > "$fn" <<EOF_COMP # Created with script "${FULL_CMD[@]}" Object.Widget.${comp}.1 { - index 1 + index \$BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_${format}.conf> <include/bench/${comp}_controls_playback.conf> } Object.Widget.${comp}.2 { - index 3 + index \$BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_${format}.conf> <include/bench/${comp}_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_${format}.conf> - <include/bench/${comp}_hda_route.conf> + <include/bench/host_gateway_pipelines_${format}.conf> + <include/bench/${comp}_route.conf> EOF_COMP } generate_route () { - fn=${comp}_hda_route.conf + fn=${comp}_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 '\$BENCH_PLAYBACK_DAI_COPIER' + source '${comp}.\$BENCH_PLAYBACK_HOST_PIPELINE.1' } { - sink '${comp}.1.1' + sink '${comp}.\$BENCH_PLAYBACK_HOST_PIPELINE.1' source 'host-copier.0.playback' } { - source 'dai-copier.HDA.\$HDA_ANALOG_DAI_NAME.capture' - sink '${comp}.3.2' + source '\$BENCH_CAPTURE_DAI_COPIER' + sink '${comp}.\$BENCH_CAPTURE_HOST_PIPELINE.2' } { - source '${comp}.3.2' + source '${comp}.\$BENCH_CAPTURE_HOST_PIPELINE.2' sink 'host-copier.0.capture' } ] diff --git a/tools/topology/topology2/include/bench/dcblock_hda_route.conf b/tools/topology/topology2/include/bench/dcblock_hda_route.conf deleted file mode 100644 index 2b494c67e839..000000000000 --- a/tools/topology/topology2/include/bench/dcblock_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # 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_route.conf b/tools/topology/topology2/include/bench/dcblock_route.conf new file mode 100644 index 000000000000..16a1674cbf53 --- /dev/null +++ b/tools/topology/topology2/include/bench/dcblock_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh dcblock" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'dcblock.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'dcblock.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'dcblock.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'dcblock.$BENCH_CAPTURE_HOST_PIPELINE.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 index ae90114a2a16..6e825a2a03ac 100644 --- a/tools/topology/topology2/include/bench/dcblock_s16.conf +++ b/tools/topology/topology2/include/bench/dcblock_s16.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh dcblock" Object.Widget.dcblock.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/dcblock_control_bytes_playback.conf> } Object.Widget.dcblock.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <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> + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/dcblock_route.conf> diff --git a/tools/topology/topology2/include/bench/dcblock_s24.conf b/tools/topology/topology2/include/bench/dcblock_s24.conf index ae24936a05a9..7f8d04082a03 100644 --- a/tools/topology/topology2/include/bench/dcblock_s24.conf +++ b/tools/topology/topology2/include/bench/dcblock_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh dcblock" Object.Widget.dcblock.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/dcblock_control_bytes_playback.conf> } Object.Widget.dcblock.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <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> + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/dcblock_route.conf> diff --git a/tools/topology/topology2/include/bench/dcblock_s32.conf b/tools/topology/topology2/include/bench/dcblock_s32.conf index 37bea24dd7a3..8b2996a981cf 100644 --- a/tools/topology/topology2/include/bench/dcblock_s32.conf +++ b/tools/topology/topology2/include/bench/dcblock_s32.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh dcblock" Object.Widget.dcblock.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/dcblock_control_bytes_playback.conf> } Object.Widget.dcblock.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <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> + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/dcblock_route.conf> diff --git a/tools/topology/topology2/include/bench/dolby-dax_controls_capture.conf b/tools/topology/topology2/include/bench/dolby-dax_controls_capture.conf new file mode 100644 index 000000000000..dde79828ea06 --- /dev/null +++ b/tools/topology/topology2/include/bench/dolby-dax_controls_capture.conf @@ -0,0 +1,28 @@ + # Created initially with script "./bench_comp_generate.sh dolby-dax" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in DOLBY-DAX + mixer."1" { + name 'DAX $ANALOG_CAPTURE_PCM Playback Switch' + } + mixer."2" { + name 'DAX $ANALOG_CAPTURE_PCM Playback Switch CP' + } + mixer."3" { + name 'DAX $ANALOG_CAPTURE_PCM Playback Switch CTC' + } + mixer."4" { + name 'DAX $ANALOG_CAPTURE_PCM Playback Volume' + } + enum."1" { + name 'DAX $ANALOG_CAPTURE_PCM Playback Profile' + } + enum."2" { + name 'DAX $ANALOG_CAPTURE_PCM Playback Device' + } + bytes."1" { + name 'DAX $ANALOG_CAPTURE_PCM Playback Tuning' + max 8192 + <include/components/dax/default.conf> + } + } diff --git a/tools/topology/topology2/include/bench/dolby-dax_controls_playback.conf b/tools/topology/topology2/include/bench/dolby-dax_controls_playback.conf new file mode 100644 index 000000000000..9c56043a2ed0 --- /dev/null +++ b/tools/topology/topology2/include/bench/dolby-dax_controls_playback.conf @@ -0,0 +1,28 @@ + # Created initially with script "./bench_comp_generate.sh dolby-dax" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in DOLBY-DAX + mixer."1" { + name 'DAX $ANALOG_PLAYBACK_PCM Playback Switch' + } + mixer."2" { + name 'DAX $ANALOG_PLAYBACK_PCM Playback Switch CP' + } + mixer."3" { + name 'DAX $ANALOG_PLAYBACK_PCM Playback Switch CTC' + } + mixer."4" { + name 'DAX $ANALOG_PLAYBACK_PCM Playback Volume' + } + enum."1" { + name 'DAX $ANALOG_PLAYBACK_PCM Playback Profile' + } + enum."2" { + name 'DAX $ANALOG_PLAYBACK_PCM Playback Device' + } + bytes."1" { + name 'DAX $ANALOG_PLAYBACK_PCM Playback Tuning' + max 8192 + <include/components/dax/default.conf> + } + } diff --git a/tools/topology/topology2/include/bench/dolby-dax_route.conf b/tools/topology/topology2/include/bench/dolby-dax_route.conf new file mode 100644 index 000000000000..1f5e0dc0dc80 --- /dev/null +++ b/tools/topology/topology2/include/bench/dolby-dax_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh dolby-dax" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'dolby-dax.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'dolby-dax.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'dolby-dax.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'dolby-dax.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/dolby-dax_s16.conf b/tools/topology/topology2/include/bench/dolby-dax_s16.conf new file mode 100644 index 000000000000..a4f622cebad3 --- /dev/null +++ b/tools/topology/topology2/include/bench/dolby-dax_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh dolby-dax" + Object.Widget.dolby-dax.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/dolby-dax_controls_playback.conf> + } + Object.Widget.dolby-dax.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/dolby-dax_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/dolby-dax_route.conf> diff --git a/tools/topology/topology2/include/bench/dolby-dax_s24.conf b/tools/topology/topology2/include/bench/dolby-dax_s24.conf new file mode 100644 index 000000000000..b74c5d32af75 --- /dev/null +++ b/tools/topology/topology2/include/bench/dolby-dax_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh dolby-dax" + Object.Widget.dolby-dax.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/dolby-dax_controls_playback.conf> + } + Object.Widget.dolby-dax.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/dolby-dax_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/dolby-dax_route.conf> diff --git a/tools/topology/topology2/include/bench/dolby-dax_s32.conf b/tools/topology/topology2/include/bench/dolby-dax_s32.conf new file mode 100644 index 000000000000..b239e4d5dab6 --- /dev/null +++ b/tools/topology/topology2/include/bench/dolby-dax_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh dolby-dax" + Object.Widget.dolby-dax.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s32.conf> + <include/bench/dolby-dax_controls_playback.conf> + } + Object.Widget.dolby-dax.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s32.conf> + <include/bench/dolby-dax_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/dolby-dax_route.conf> diff --git a/tools/topology/topology2/include/bench/drc_controls_capture.conf b/tools/topology/topology2/include/bench/drc_controls_capture.conf index c586f940b578..42d8044a6398 100644 --- a/tools/topology/topology2/include/bench/drc_controls_capture.conf +++ b/tools/topology/topology2/include/bench/drc_controls_capture.conf @@ -8,6 +8,7 @@ "default" "include/components/drc/default.conf" "enabled" "include/components/drc/enabled.conf" "passthrough" "include/components/drc/passthrough.conf" + "default_speaker_mic" "include/components/drc/dmic_default.conf" } } mixer."1" { diff --git a/tools/topology/topology2/include/bench/drc_controls_playback.conf b/tools/topology/topology2/include/bench/drc_controls_playback.conf index 36217ab08965..2cab24d5325d 100644 --- a/tools/topology/topology2/include/bench/drc_controls_playback.conf +++ b/tools/topology/topology2/include/bench/drc_controls_playback.conf @@ -8,6 +8,7 @@ "default" "include/components/drc/default.conf" "enabled" "include/components/drc/enabled.conf" "passthrough" "include/components/drc/passthrough.conf" + "default_speaker_mic" "include/components/drc/speaker_default.conf" } } mixer."1" { diff --git a/tools/topology/topology2/include/bench/drc_hda_route.conf b/tools/topology/topology2/include/bench/drc_hda_route.conf deleted file mode 100644 index 8e9f475bd777..000000000000 --- a/tools/topology/topology2/include/bench/drc_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # 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_route.conf b/tools/topology/topology2/include/bench/drc_route.conf new file mode 100644 index 000000000000..7814bbd3c663 --- /dev/null +++ b/tools/topology/topology2/include/bench/drc_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh drc" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'drc.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'drc.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'drc.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'drc.$BENCH_CAPTURE_HOST_PIPELINE.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 index a91888928d25..cce34d391e14 100644 --- a/tools/topology/topology2/include/bench/drc_s16.conf +++ b/tools/topology/topology2/include/bench/drc_s16.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh drc" Object.Widget.drc.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/drc_controls_playback.conf> } Object.Widget.drc.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/drc_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s16.conf> - <include/bench/drc_hda_route.conf> + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/drc_route.conf> diff --git a/tools/topology/topology2/include/bench/drc_s24.conf b/tools/topology/topology2/include/bench/drc_s24.conf index 4eb39eef9ad6..325916d4bd34 100644 --- a/tools/topology/topology2/include/bench/drc_s24.conf +++ b/tools/topology/topology2/include/bench/drc_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh drc" Object.Widget.drc.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/drc_controls_playback.conf> } Object.Widget.drc.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/drc_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s24.conf> - <include/bench/drc_hda_route.conf> + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/drc_route.conf> diff --git a/tools/topology/topology2/include/bench/drc_s32.conf b/tools/topology/topology2/include/bench/drc_s32.conf index beda0c0b210e..3c1cedddf439 100644 --- a/tools/topology/topology2/include/bench/drc_s32.conf +++ b/tools/topology/topology2/include/bench/drc_s32.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh drc" Object.Widget.drc.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/drc_controls_playback.conf> } Object.Widget.drc.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/drc_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s32.conf> - <include/bench/drc_hda_route.conf> + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/drc_route.conf> diff --git a/tools/topology/topology2/include/bench/eqfir_hda_route.conf b/tools/topology/topology2/include/bench/eqfir_hda_route.conf deleted file mode 100644 index fd30c793326c..000000000000 --- a/tools/topology/topology2/include/bench/eqfir_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # 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_route.conf b/tools/topology/topology2/include/bench/eqfir_route.conf new file mode 100644 index 000000000000..345eb6f7e803 --- /dev/null +++ b/tools/topology/topology2/include/bench/eqfir_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh eqfir" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'eqfir.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'eqfir.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'eqfir.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'eqfir.$BENCH_CAPTURE_HOST_PIPELINE.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 index 461323944062..06c60c2e6541 100644 --- a/tools/topology/topology2/include/bench/eqfir_s16.conf +++ b/tools/topology/topology2/include/bench/eqfir_s16.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh eqfir" Object.Widget.eqfir.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/eqfir_control_bytes_playback.conf> } Object.Widget.eqfir.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <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> + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/eqfir_route.conf> diff --git a/tools/topology/topology2/include/bench/eqfir_s24.conf b/tools/topology/topology2/include/bench/eqfir_s24.conf index ce2b303fe8f3..c90264d29607 100644 --- a/tools/topology/topology2/include/bench/eqfir_s24.conf +++ b/tools/topology/topology2/include/bench/eqfir_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh eqfir" Object.Widget.eqfir.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/eqfir_control_bytes_playback.conf> } Object.Widget.eqfir.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <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> + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/eqfir_route.conf> diff --git a/tools/topology/topology2/include/bench/eqfir_s32.conf b/tools/topology/topology2/include/bench/eqfir_s32.conf index 0e3dfa3732b4..2ad841cda0f5 100644 --- a/tools/topology/topology2/include/bench/eqfir_s32.conf +++ b/tools/topology/topology2/include/bench/eqfir_s32.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh eqfir" Object.Widget.eqfir.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/eqfir_control_bytes_playback.conf> } Object.Widget.eqfir.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <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> + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/eqfir_route.conf> diff --git a/tools/topology/topology2/include/bench/eqiir_hda_route.conf b/tools/topology/topology2/include/bench/eqiir_hda_route.conf deleted file mode 100644 index 5f066b741969..000000000000 --- a/tools/topology/topology2/include/bench/eqiir_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # 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_route.conf b/tools/topology/topology2/include/bench/eqiir_route.conf new file mode 100644 index 000000000000..c08418ff51da --- /dev/null +++ b/tools/topology/topology2/include/bench/eqiir_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh eqiir" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'eqiir.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'eqiir.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'eqiir.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'eqiir.$BENCH_CAPTURE_HOST_PIPELINE.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 index bcb01383e3d5..a343fdae4d0d 100644 --- a/tools/topology/topology2/include/bench/eqiir_s16.conf +++ b/tools/topology/topology2/include/bench/eqiir_s16.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh eqiir" Object.Widget.eqiir.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/eqiir_control_bytes_playback.conf> } Object.Widget.eqiir.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <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> + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/eqiir_route.conf> diff --git a/tools/topology/topology2/include/bench/eqiir_s24.conf b/tools/topology/topology2/include/bench/eqiir_s24.conf index aa327545beec..00eb91a9c426 100644 --- a/tools/topology/topology2/include/bench/eqiir_s24.conf +++ b/tools/topology/topology2/include/bench/eqiir_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh eqiir" Object.Widget.eqiir.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/eqiir_control_bytes_playback.conf> } Object.Widget.eqiir.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <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> + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/eqiir_route.conf> diff --git a/tools/topology/topology2/include/bench/eqiir_s32.conf b/tools/topology/topology2/include/bench/eqiir_s32.conf index c6bf9b4e0fb7..9e6d19bcecb0 100644 --- a/tools/topology/topology2/include/bench/eqiir_s32.conf +++ b/tools/topology/topology2/include/bench/eqiir_s32.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh eqiir" Object.Widget.eqiir.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/eqiir_control_bytes_playback.conf> } Object.Widget.eqiir.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <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> + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/eqiir_route.conf> diff --git a/tools/topology/topology2/include/bench/gain_hda_route.conf b/tools/topology/topology2/include/bench/gain_hda_route.conf deleted file mode 100644 index 9f4eb3a2bcab..000000000000 --- a/tools/topology/topology2/include/bench/gain_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # Created with script "./bench_comp_generate.sh gain" - Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'gain.1.1' - } - { - sink 'gain.1.1' - source 'host-copier.0.playback' - } - { - source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' - sink 'gain.3.2' - } - { - source 'gain.3.2' - sink 'host-copier.0.capture' - } - ] diff --git a/tools/topology/topology2/include/bench/gain_route.conf b/tools/topology/topology2/include/bench/gain_route.conf new file mode 100644 index 000000000000..6c22cb63fbfb --- /dev/null +++ b/tools/topology/topology2/include/bench/gain_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh gain" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'gain.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'gain.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'gain.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'gain.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/gain_s16.conf b/tools/topology/topology2/include/bench/gain_s16.conf index 3c3098c48f7c..0d736ece9d9e 100644 --- a/tools/topology/topology2/include/bench/gain_s16.conf +++ b/tools/topology/topology2/include/bench/gain_s16.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh gain" Object.Widget.gain.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/gain_controls_playback.conf> } Object.Widget.gain.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/gain_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s16.conf> - <include/bench/gain_hda_route.conf> + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/gain_route.conf> diff --git a/tools/topology/topology2/include/bench/gain_s24.conf b/tools/topology/topology2/include/bench/gain_s24.conf index cb9ba3f416fd..cd2d1809aea1 100644 --- a/tools/topology/topology2/include/bench/gain_s24.conf +++ b/tools/topology/topology2/include/bench/gain_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh gain" Object.Widget.gain.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/gain_controls_playback.conf> } Object.Widget.gain.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/gain_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s24.conf> - <include/bench/gain_hda_route.conf> + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/gain_route.conf> diff --git a/tools/topology/topology2/include/bench/gain_s32.conf b/tools/topology/topology2/include/bench/gain_s32.conf index a9607383f59c..afac93e97f1b 100644 --- a/tools/topology/topology2/include/bench/gain_s32.conf +++ b/tools/topology/topology2/include/bench/gain_s32.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh gain" Object.Widget.gain.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/gain_controls_playback.conf> } Object.Widget.gain.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/gain_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s32.conf> - <include/bench/gain_hda_route.conf> + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/gain_route.conf> diff --git a/tools/topology/topology2/include/bench/host_gateway_pipelines_multich_s32.conf b/tools/topology/topology2/include/bench/host_gateway_pipelines_multich_s32.conf new file mode 100644 index 000000000000..95c57c8a48af --- /dev/null +++ b/tools/topology/topology2/include/bench/host_gateway_pipelines_multich_s32.conf @@ -0,0 +1,438 @@ + Object.Pipeline { + host-gateway-playback [ + { + index $BENCH_PLAYBACK_HOST_PIPELINE + Object.Widget.host-copier.1 { + stream_name $ANALOG_PLAYBACK_PCM + pcm_id 0 + num_input_audio_formats 21 + num_output_audio_formats 7 + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_POINT_1 + } + + { + 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 24 + 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 + } + + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 2 + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 3 + out_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + out_ch_map $CHANNEL_MAP_2_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 32 + out_valid_bit_depth 32 + out_channels 5 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + out_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 6 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 8 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + } + } + ] + + host-gateway-capture [ + { + index $BENCH_CAPTURE_HOST_PIPELINE + Object.Widget.host-copier.1 { + stream_name $ANALOG_CAPTURE_PCM + pcm_id 0 + num_output_audio_formats 21 + num_input_audio_formats 7 + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_channels 2 + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_channels 2 + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 2 + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_channels 3 + out_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + out_ch_map $CHANNEL_MAP_2_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_channels 3 + out_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + out_ch_map $CHANNEL_MAP_2_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 3 + out_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + out_ch_map $CHANNEL_MAP_2_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 + } + { + 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 5 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + out_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_channels 5 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + out_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 5 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + out_ch_map $CHANNEL_MAP_5_POINT_0 + } + + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_channels 6 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_channels 6 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 6 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_channels 8 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_channels 8 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 8 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_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 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/host_gateway_pipelines_s16.conf b/tools/topology/topology2/include/bench/host_gateway_pipelines_s16.conf new file mode 100644 index 000000000000..317c42ce824b --- /dev/null +++ b/tools/topology/topology2/include/bench/host_gateway_pipelines_s16.conf @@ -0,0 +1,66 @@ + Object.Pipeline { + host-gateway-playback [ + { + index $BENCH_PLAYBACK_HOST_PIPELINE + 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 + } + ] + } + } + ] + + host-gateway-capture [ + { + index $BENCH_CAPTURE_HOST_PIPELINE + 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 + } + ] + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/host_gateway_pipelines_s16_16k.conf b/tools/topology/topology2/include/bench/host_gateway_pipelines_s16_16k.conf new file mode 100644 index 000000000000..483a087a885f --- /dev/null +++ b/tools/topology/topology2/include/bench/host_gateway_pipelines_s16_16k.conf @@ -0,0 +1,74 @@ + Object.Pipeline { + host-gateway-playback [ + { + index $BENCH_PLAYBACK_HOST_PIPELINE + 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_rate 16000 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_rate 16000 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_rate 16000 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_rate 16000 + } + ] + } + } + ] + + host-gateway-capture [ + { + index $BENCH_CAPTURE_HOST_PIPELINE + 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 + in_rate 16000 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_rate 16000 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_rate 16000 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_rate 16000 + } + ] + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/host_gateway_pipelines_s24.conf b/tools/topology/topology2/include/bench/host_gateway_pipelines_s24.conf new file mode 100644 index 000000000000..4f2a17a5f0e5 --- /dev/null +++ b/tools/topology/topology2/include/bench/host_gateway_pipelines_s24.conf @@ -0,0 +1,66 @@ + Object.Pipeline { + host-gateway-playback [ + { + index $BENCH_PLAYBACK_HOST_PIPELINE + 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 + } + ] + } + } + ] + + host-gateway-capture [ + { + index $BENCH_CAPTURE_HOST_PIPELINE + 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 + } + ] + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/host_gateway_pipelines_s24_16k.conf b/tools/topology/topology2/include/bench/host_gateway_pipelines_s24_16k.conf new file mode 100644 index 000000000000..4fc5b1eaf715 --- /dev/null +++ b/tools/topology/topology2/include/bench/host_gateway_pipelines_s24_16k.conf @@ -0,0 +1,74 @@ + Object.Pipeline { + host-gateway-playback [ + { + index $BENCH_PLAYBACK_HOST_PIPELINE + 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_rate 16000 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_rate 16000 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_rate 16000 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_rate 16000 + } + ] + } + } + ] + + host-gateway-capture [ + { + index $BENCH_CAPTURE_HOST_PIPELINE + 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 + in_rate 16000 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_rate 16000 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_rate 16000 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_rate 16000 + } + ] + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/host_gateway_pipelines_s32.conf b/tools/topology/topology2/include/bench/host_gateway_pipelines_s32.conf new file mode 100644 index 000000000000..4ee80bf7c0a9 --- /dev/null +++ b/tools/topology/topology2/include/bench/host_gateway_pipelines_s32.conf @@ -0,0 +1,66 @@ + Object.Pipeline { + host-gateway-playback [ + { + index $BENCH_PLAYBACK_HOST_PIPELINE + 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 + } + ] + } + } + ] + + host-gateway-capture [ + { + index $BENCH_CAPTURE_HOST_PIPELINE + 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 + } + ] + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/host_gateway_pipelines_s32_16k.conf b/tools/topology/topology2/include/bench/host_gateway_pipelines_s32_16k.conf new file mode 100644 index 000000000000..229e686feeba --- /dev/null +++ b/tools/topology/topology2/include/bench/host_gateway_pipelines_s32_16k.conf @@ -0,0 +1,74 @@ + Object.Pipeline { + host-gateway-playback [ + { + index $BENCH_PLAYBACK_HOST_PIPELINE + 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_rate 16000 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_rate 16000 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_rate 16000 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_rate 16000 + } + ] + } + } + ] + + host-gateway-capture [ + { + index $BENCH_CAPTURE_HOST_PIPELINE + 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 + in_rate 16000 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_rate 16000 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_rate 16000 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_rate 16000 + } + ] + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/host_gateway_pipelines_src_s16.conf b/tools/topology/topology2/include/bench/host_gateway_pipelines_src_s16.conf new file mode 100644 index 000000000000..88526649833e --- /dev/null +++ b/tools/topology/topology2/include/bench/host_gateway_pipelines_src_s16.conf @@ -0,0 +1,24 @@ + Object.Pipeline { + host-gateway-playback [ + { + index $BENCH_PLAYBACK_HOST_PIPELINE + Object.Widget.host-copier.1 { + stream_name $ANALOG_PLAYBACK_PCM + pcm_id 0 + <include/components/src_format_sxx_to_s16_convert.conf> + } + } + ] + + host-gateway-capture [ + { + index $BENCH_CAPTURE_HOST_PIPELINE + Object.Widget.host-copier.1 { + stream_name $ANALOG_CAPTURE_PCM + pcm_id 0 + <include/components/src_format_s16_to_sxx_convert.conf> + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/host_gateway_pipelines_src_s24.conf b/tools/topology/topology2/include/bench/host_gateway_pipelines_src_s24.conf new file mode 100644 index 000000000000..c8b259281c4e --- /dev/null +++ b/tools/topology/topology2/include/bench/host_gateway_pipelines_src_s24.conf @@ -0,0 +1,24 @@ + Object.Pipeline { + host-gateway-playback [ + { + index $BENCH_PLAYBACK_HOST_PIPELINE + Object.Widget.host-copier.1 { + stream_name $ANALOG_PLAYBACK_PCM + pcm_id 0 + <include/components/src_format_sxx_to_s24_convert.conf> + } + } + ] + + host-gateway-capture [ + { + index $BENCH_CAPTURE_HOST_PIPELINE + Object.Widget.host-copier.1 { + stream_name $ANALOG_CAPTURE_PCM + pcm_id 0 + <include/components/src_format_s24_to_sxx_convert.conf> + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/host_gateway_pipelines_src_s32.conf b/tools/topology/topology2/include/bench/host_gateway_pipelines_src_s32.conf new file mode 100644 index 000000000000..bd6c82c6b479 --- /dev/null +++ b/tools/topology/topology2/include/bench/host_gateway_pipelines_src_s32.conf @@ -0,0 +1,24 @@ + Object.Pipeline { + host-gateway-playback [ + { + index $BENCH_PLAYBACK_HOST_PIPELINE + Object.Widget.host-copier.1 { + stream_name $ANALOG_PLAYBACK_PCM + pcm_id 0 + <include/components/src_format_sxx_to_s32_convert.conf> + } + } + ] + + host-gateway-capture [ + { + index $BENCH_CAPTURE_HOST_PIPELINE + Object.Widget.host-copier.1 { + stream_name $ANALOG_CAPTURE_PCM + pcm_id 0 + <include/components/src_format_s32_to_sxx_convert.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 deleted file mode 100644 index b6ecea830367..000000000000 --- a/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s16.conf +++ /dev/null @@ -1,126 +0,0 @@ - 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 deleted file mode 100644 index 4cac2acd2b8b..000000000000 --- a/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s24.conf +++ /dev/null @@ -1,126 +0,0 @@ - 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 deleted file mode 100644 index c598efcd3e06..000000000000 --- a/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s32.conf +++ /dev/null @@ -1,126 +0,0 @@ - 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/host_io_gateway_pipelines_src_s16.conf b/tools/topology/topology2/include/bench/host_io_gateway_pipelines_src_s16.conf deleted file mode 100644 index 0cb65c2e21c9..000000000000 --- a/tools/topology/topology2/include/bench/host_io_gateway_pipelines_src_s16.conf +++ /dev/null @@ -1,84 +0,0 @@ - Object.Pipeline { - host-gateway-playback [ - { - index 1 - - Object.Widget.host-copier.1 { - stream_name $ANALOG_PLAYBACK_PCM - pcm_id 0 - <include/components/src_format_sxx_to_s16_convert.conf> - } - } - ] - - 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 - <include/components/src_format_s16_to_sxx_convert.conf> - } - } - ] - - 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_src_s24.conf b/tools/topology/topology2/include/bench/host_io_gateway_pipelines_src_s24.conf deleted file mode 100644 index 8da4d8410273..000000000000 --- a/tools/topology/topology2/include/bench/host_io_gateway_pipelines_src_s24.conf +++ /dev/null @@ -1,84 +0,0 @@ - Object.Pipeline { - host-gateway-playback [ - { - index 1 - - Object.Widget.host-copier.1 { - stream_name $ANALOG_PLAYBACK_PCM - pcm_id 0 - <include/components/src_format_sxx_to_s24_convert.conf> - } - } - ] - - 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 - <include/components/src_format_s24_to_sxx_convert.conf> - } - } - ] - - 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_src_s32.conf b/tools/topology/topology2/include/bench/host_io_gateway_pipelines_src_s32.conf deleted file mode 100644 index d82273e2a803..000000000000 --- a/tools/topology/topology2/include/bench/host_io_gateway_pipelines_src_s32.conf +++ /dev/null @@ -1,84 +0,0 @@ - Object.Pipeline { - host-gateway-playback [ - { - index 1 - - Object.Widget.host-copier.1 { - stream_name $ANALOG_PLAYBACK_PCM - pcm_id 0 - <include/components/src_format_sxx_to_s32_convert.conf> - } - } - ] - - 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 - <include/components/src_format_s32_to_sxx_convert.conf> - } - } - ] - - 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/igo_nr_hda_route.conf b/tools/topology/topology2/include/bench/igo_nr_hda_route.conf deleted file mode 100644 index a5d08cf3229f..000000000000 --- a/tools/topology/topology2/include/bench/igo_nr_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # Created with script "./bench_comp_generate.sh igo_nr" - Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'igo_nr.1.1' - } - { - sink 'igo_nr.1.1' - source 'host-copier.0.playback' - } - { - source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' - sink 'igo_nr.3.2' - } - { - source 'igo_nr.3.2' - sink 'host-copier.0.capture' - } - ] diff --git a/tools/topology/topology2/include/bench/igo_nr_route.conf b/tools/topology/topology2/include/bench/igo_nr_route.conf new file mode 100644 index 000000000000..be977194fe9e --- /dev/null +++ b/tools/topology/topology2/include/bench/igo_nr_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh igo_nr" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'igo_nr.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'igo_nr.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'igo_nr.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'igo_nr.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/igo_nr_s16.conf b/tools/topology/topology2/include/bench/igo_nr_s16.conf index 944b905409ec..6704a9803abc 100644 --- a/tools/topology/topology2/include/bench/igo_nr_s16.conf +++ b/tools/topology/topology2/include/bench/igo_nr_s16.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh igo_nr" Object.Widget.igo_nr.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/igo_nr_controls_playback.conf> } Object.Widget.igo_nr.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/igo_nr_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s16.conf> - <include/bench/igo_nr_hda_route.conf> + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/igo_nr_route.conf> diff --git a/tools/topology/topology2/include/bench/igo_nr_s24.conf b/tools/topology/topology2/include/bench/igo_nr_s24.conf index 40963c48b5eb..84ef21346784 100644 --- a/tools/topology/topology2/include/bench/igo_nr_s24.conf +++ b/tools/topology/topology2/include/bench/igo_nr_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh igo_nr" Object.Widget.igo_nr.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/igo_nr_controls_playback.conf> } Object.Widget.igo_nr.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/igo_nr_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s24.conf> - <include/bench/igo_nr_hda_route.conf> + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/igo_nr_route.conf> diff --git a/tools/topology/topology2/include/bench/igo_nr_s32.conf b/tools/topology/topology2/include/bench/igo_nr_s32.conf index ff81fe8e5ed8..5582b7349462 100644 --- a/tools/topology/topology2/include/bench/igo_nr_s32.conf +++ b/tools/topology/topology2/include/bench/igo_nr_s32.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh igo_nr" Object.Widget.igo_nr.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/igo_nr_controls_playback.conf> } Object.Widget.igo_nr.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/igo_nr_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s32.conf> - <include/bench/igo_nr_hda_route.conf> + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/igo_nr_route.conf> diff --git a/tools/topology/topology2/include/bench/level_multiplier_controls_capture.conf b/tools/topology/topology2/include/bench/level_multiplier_controls_capture.conf new file mode 100644 index 000000000000..3a9a85dbf545 --- /dev/null +++ b/tools/topology/topology2/include/bench/level_multiplier_controls_capture.conf @@ -0,0 +1,17 @@ + # Created initially with script "./bench_comp_generate.sh level_multiplier" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in LEVEL_MULTIPLIER + bytes."1" { + name '$ANALOG_CAPTURE_PCM Level Multiplier bytes' + IncludeByKey.BENCH_LEVEL_MULTIPLIER_PARAMS { + "default" "include/components/level_multiplier/gain_0_db.conf" + } + } + #mixer."1" { + # name '$ANALOG_CAPTURE_PCM LEVEL_MULTIPLIER switch or volume' + #} + #enum."1" { + # name '$ANALOG_CAPTURE_PCM LEVEL_MULTIPLIER enum' + #} + } diff --git a/tools/topology/topology2/include/bench/level_multiplier_controls_playback.conf b/tools/topology/topology2/include/bench/level_multiplier_controls_playback.conf new file mode 100644 index 000000000000..59371f0eed4b --- /dev/null +++ b/tools/topology/topology2/include/bench/level_multiplier_controls_playback.conf @@ -0,0 +1,17 @@ + # Created initially with script "./bench_comp_generate.sh level_multiplier" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in LEVEL_MULTIPLIER + bytes."1" { + name '$ANALOG_PLAYBACK_PCM Level Multiplier bytes' + IncludeByKey.BENCH_LEVEL_MULTIPLIER_PARAMS { + "default" "include/components/level_multiplier/gain_0_db.conf" + } + } + #mixer."1" { + # name '$ANALOG_PLAYBACK_PCM LEVEL_MULTIPLIER switch or volume' + #} + #enum."1" { + # name '$ANALOG_PLAYBACK_PCM LEVEL_MULTIPLIER enum' + #} + } diff --git a/tools/topology/topology2/include/bench/level_multiplier_route.conf b/tools/topology/topology2/include/bench/level_multiplier_route.conf new file mode 100644 index 000000000000..f63ab98782c4 --- /dev/null +++ b/tools/topology/topology2/include/bench/level_multiplier_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh level_multiplier" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'level_multiplier.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'level_multiplier.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'level_multiplier.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'level_multiplier.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/level_multiplier_s16.conf b/tools/topology/topology2/include/bench/level_multiplier_s16.conf new file mode 100644 index 000000000000..33b9d56ad278 --- /dev/null +++ b/tools/topology/topology2/include/bench/level_multiplier_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh level_multiplier" + Object.Widget.level_multiplier.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/level_multiplier_controls_playback.conf> + } + Object.Widget.level_multiplier.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/level_multiplier_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/level_multiplier_route.conf> diff --git a/tools/topology/topology2/include/bench/level_multiplier_s24.conf b/tools/topology/topology2/include/bench/level_multiplier_s24.conf new file mode 100644 index 000000000000..bd4b245a0bf3 --- /dev/null +++ b/tools/topology/topology2/include/bench/level_multiplier_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh level_multiplier" + Object.Widget.level_multiplier.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/level_multiplier_controls_playback.conf> + } + Object.Widget.level_multiplier.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/level_multiplier_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/level_multiplier_route.conf> diff --git a/tools/topology/topology2/include/bench/level_multiplier_s32.conf b/tools/topology/topology2/include/bench/level_multiplier_s32.conf new file mode 100644 index 000000000000..58b6f06d22a5 --- /dev/null +++ b/tools/topology/topology2/include/bench/level_multiplier_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh level_multiplier" + Object.Widget.level_multiplier.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s32.conf> + <include/bench/level_multiplier_controls_playback.conf> + } + Object.Widget.level_multiplier.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s32.conf> + <include/bench/level_multiplier_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/level_multiplier_route.conf> diff --git a/tools/topology/topology2/include/bench/mfcc_controls_capture.conf b/tools/topology/topology2/include/bench/mfcc_controls_capture.conf new file mode 100644 index 000000000000..8788387ec8c7 --- /dev/null +++ b/tools/topology/topology2/include/bench/mfcc_controls_capture.conf @@ -0,0 +1,18 @@ + # Created initially with script "./bench_comp_generate.sh mfcc" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in MFCC + bytes."1" { + name '$ANALOG_CAPTURE_PCM MFCC bytes' + IncludeByKey.BENCH_MFCC_PARAMS { + "default" "include/components/mfcc/default.conf" + "mel80" "include/components/mfcc/mel80.conf" + } + } + mixer."1" { + name '$ANALOG_CAPTURE_PCM MFCC switch' + } + #enum."1" { + # name '$ANALOG_CAPTURE_PCM MFCC enum' + #} + } diff --git a/tools/topology/topology2/include/bench/mfcc_controls_playback.conf b/tools/topology/topology2/include/bench/mfcc_controls_playback.conf new file mode 100644 index 000000000000..007dbb91cd4f --- /dev/null +++ b/tools/topology/topology2/include/bench/mfcc_controls_playback.conf @@ -0,0 +1,18 @@ + # Created initially with script "./bench_comp_generate.sh mfcc" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in MFCC + bytes."1" { + name '$ANALOG_PLAYBACK_PCM MFCC bytes' + IncludeByKey.BENCH_MFCC_PARAMS { + "default" "include/components/mfcc/default.conf" + "mel80" "include/components/mfcc/mel80.conf" + } + } + mixer."1" { + name '$ANALOG_PLAYBACK_PCM MFCC switch' + } + #enum."1" { + # name '$ANALOG_PLAYBACK_PCM MFCC enum' + #} + } diff --git a/tools/topology/topology2/include/bench/mfcc_route.conf b/tools/topology/topology2/include/bench/mfcc_route.conf new file mode 100644 index 000000000000..d4ce9af5f85d --- /dev/null +++ b/tools/topology/topology2/include/bench/mfcc_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh mfcc" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'mfcc.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'mfcc.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'mfcc.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'mfcc.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/mfcc_s16.conf b/tools/topology/topology2/include/bench/mfcc_s16.conf new file mode 100644 index 000000000000..ec89bffb90a1 --- /dev/null +++ b/tools/topology/topology2/include/bench/mfcc_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh mfcc" + Object.Widget.mfcc.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s16_16k.conf> + <include/bench/mfcc_controls_playback.conf> + } + Object.Widget.mfcc.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s16_16k.conf> + <include/bench/mfcc_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s16_16k.conf> + <include/bench/mfcc_route.conf> diff --git a/tools/topology/topology2/include/bench/mfcc_s24.conf b/tools/topology/topology2/include/bench/mfcc_s24.conf new file mode 100644 index 000000000000..73571fabe5f2 --- /dev/null +++ b/tools/topology/topology2/include/bench/mfcc_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh mfcc" + Object.Widget.mfcc.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s24_16k.conf> + <include/bench/mfcc_controls_playback.conf> + } + Object.Widget.mfcc.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s24_16k.conf> + <include/bench/mfcc_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s24_16k.conf> + <include/bench/mfcc_route.conf> diff --git a/tools/topology/topology2/include/bench/mfcc_s32.conf b/tools/topology/topology2/include/bench/mfcc_s32.conf new file mode 100644 index 000000000000..75c01eaf4a43 --- /dev/null +++ b/tools/topology/topology2/include/bench/mfcc_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh mfcc" + Object.Widget.mfcc.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s32_16k.conf> + <include/bench/mfcc_controls_playback.conf> + } + Object.Widget.mfcc.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s32_16k.conf> + <include/bench/mfcc_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s32_16k.conf> + <include/bench/mfcc_route.conf> diff --git a/tools/topology/topology2/include/bench/mfccmel_s16.conf b/tools/topology/topology2/include/bench/mfccmel_s16.conf new file mode 100644 index 000000000000..ec89bffb90a1 --- /dev/null +++ b/tools/topology/topology2/include/bench/mfccmel_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh mfcc" + Object.Widget.mfcc.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s16_16k.conf> + <include/bench/mfcc_controls_playback.conf> + } + Object.Widget.mfcc.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s16_16k.conf> + <include/bench/mfcc_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s16_16k.conf> + <include/bench/mfcc_route.conf> diff --git a/tools/topology/topology2/include/bench/mfccmel_s24.conf b/tools/topology/topology2/include/bench/mfccmel_s24.conf new file mode 100644 index 000000000000..73571fabe5f2 --- /dev/null +++ b/tools/topology/topology2/include/bench/mfccmel_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh mfcc" + Object.Widget.mfcc.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s24_16k.conf> + <include/bench/mfcc_controls_playback.conf> + } + Object.Widget.mfcc.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s24_16k.conf> + <include/bench/mfcc_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s24_16k.conf> + <include/bench/mfcc_route.conf> diff --git a/tools/topology/topology2/include/bench/mfccmel_s32.conf b/tools/topology/topology2/include/bench/mfccmel_s32.conf new file mode 100644 index 000000000000..75c01eaf4a43 --- /dev/null +++ b/tools/topology/topology2/include/bench/mfccmel_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh mfcc" + Object.Widget.mfcc.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s32_16k.conf> + <include/bench/mfcc_controls_playback.conf> + } + Object.Widget.mfcc.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s32_16k.conf> + <include/bench/mfcc_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s32_16k.conf> + <include/bench/mfcc_route.conf> diff --git a/tools/topology/topology2/include/bench/micsel_controls_capture.conf b/tools/topology/topology2/include/bench/micsel_controls_capture.conf new file mode 100644 index 000000000000..b51669298b90 --- /dev/null +++ b/tools/topology/topology2/include/bench/micsel_controls_capture.conf @@ -0,0 +1,18 @@ + # Created initially with script "./bench_comp_generate.sh micsel" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in MICSEL + bytes."1" { + name '$ANALOG_CAPTURE_PCM MICSEL bytes' + IncludeByKey.BENCH_MICSEL_PARAMS { + "passthrough" "include/components/micsel/passthrough.conf" + "default" "include/components/micsel/upmix_stereo_to_71.conf" + } + } + #mixer."1" { + # name '$ANALOG_CAPTURE_PCM MICSEL switch or volume' + #} + #enum."1" { + # name '$ANALOG_CAPTURE_PCM MICSEL enum' + #} + } diff --git a/tools/topology/topology2/include/bench/micsel_controls_playback.conf b/tools/topology/topology2/include/bench/micsel_controls_playback.conf new file mode 100644 index 000000000000..69dc0270d926 --- /dev/null +++ b/tools/topology/topology2/include/bench/micsel_controls_playback.conf @@ -0,0 +1,18 @@ + # Created initially with script "./bench_comp_generate.sh micsel" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in MICSEL + bytes."1" { + name '$ANALOG_PLAYBACK_PCM MICSEL bytes' + IncludeByKey.BENCH_MICSEL_PARAMS { + "passthrough" "include/components/micsel/passthrough.conf" + "default" "include/components/micsel/downmix_71_to_stereo_with_lfe.conf" + } + } + #mixer."1" { + # name '$ANALOG_PLAYBACK_PCM MICSEL switch or volume' + #} + #enum."1" { + # name '$ANALOG_PLAYBACK_PCM MICSEL enum' + #} + } diff --git a/tools/topology/topology2/include/bench/micsel_hda_route.conf b/tools/topology/topology2/include/bench/micsel_hda_route.conf new file mode 100644 index 000000000000..1ab5115e710f --- /dev/null +++ b/tools/topology/topology2/include/bench/micsel_hda_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh micsel" + Object.Base.route [ + { + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + source 'micsel.1.1' + } + { + sink 'micsel.1.1' + source 'host-copier.0.playback' + } + { + source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' + sink 'micsel.3.2' + } + { + source 'micsel.3.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/micsel_multich_s32.conf b/tools/topology/topology2/include/bench/micsel_multich_s32.conf new file mode 100644 index 000000000000..30ad60ccb76e --- /dev/null +++ b/tools/topology/topology2/include/bench/micsel_multich_s32.conf @@ -0,0 +1,138 @@ + # Created with script "./bench_comp_generate.sh micsel" + Object.Widget.micsel.1 { + index 1 + num_input_audio_formats 7 + num_output_audio_formats 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_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 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 2 + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + ] + <include/bench/micsel_controls_playback.conf> + } + Object.Widget.micsel.2 { + index 3 + num_input_audio_formats 1 + num_output_audio_formats 7 + + # 32-bit 48KHz 2ch + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 2 + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 3 + out_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + out_ch_map $CHANNEL_MAP_2_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 32 + out_valid_bit_depth 32 + out_channels 5 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + out_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 6 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 8 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + <include/bench/micsel_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_multich_s32.conf> + <include/bench/micsel_route.conf> diff --git a/tools/topology/topology2/include/bench/micsel_route.conf b/tools/topology/topology2/include/bench/micsel_route.conf new file mode 100644 index 000000000000..1164ddb2e694 --- /dev/null +++ b/tools/topology/topology2/include/bench/micsel_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh micsel" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'micsel.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'micsel.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'micsel.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'micsel.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/micsel_s16.conf b/tools/topology/topology2/include/bench/micsel_s16.conf new file mode 100644 index 000000000000..a807f8695ad8 --- /dev/null +++ b/tools/topology/topology2/include/bench/micsel_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh micsel" + Object.Widget.micsel.1 { + index 1 + <include/bench/one_input_output_format_s16.conf> + <include/bench/micsel_controls_playback.conf> + } + Object.Widget.micsel.2 { + index 3 + <include/bench/one_input_output_format_s16.conf> + <include/bench/micsel_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/micsel_route.conf> diff --git a/tools/topology/topology2/include/bench/micsel_s24.conf b/tools/topology/topology2/include/bench/micsel_s24.conf new file mode 100644 index 000000000000..3823935c1db3 --- /dev/null +++ b/tools/topology/topology2/include/bench/micsel_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh micsel" + Object.Widget.micsel.1 { + index 1 + <include/bench/one_input_output_format_s24.conf> + <include/bench/micsel_controls_playback.conf> + } + Object.Widget.micsel.2 { + index 3 + <include/bench/one_input_output_format_s24.conf> + <include/bench/micsel_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/micsel_route.conf> diff --git a/tools/topology/topology2/include/bench/micsel_s32.conf b/tools/topology/topology2/include/bench/micsel_s32.conf new file mode 100644 index 000000000000..fe1e8cc556e6 --- /dev/null +++ b/tools/topology/topology2/include/bench/micsel_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh micsel" + Object.Widget.micsel.1 { + index 1 + <include/bench/one_input_output_format_s32.conf> + <include/bench/micsel_controls_playback.conf> + } + Object.Widget.micsel.2 { + index 3 + <include/bench/one_input_output_format_s32.conf> + <include/bench/micsel_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/micsel_route.conf> diff --git a/tools/topology/topology2/include/bench/multiband_drc_hda_route.conf b/tools/topology/topology2/include/bench/multiband_drc_hda_route.conf deleted file mode 100644 index 41a218510856..000000000000 --- a/tools/topology/topology2/include/bench/multiband_drc_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # Created with script "./bench_comp_generate.sh multiband_drc" - Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'multiband_drc.1.1' - } - { - sink 'multiband_drc.1.1' - source 'host-copier.0.playback' - } - { - source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' - sink 'multiband_drc.3.2' - } - { - source 'multiband_drc.3.2' - sink 'host-copier.0.capture' - } - ] diff --git a/tools/topology/topology2/include/bench/multiband_drc_route.conf b/tools/topology/topology2/include/bench/multiband_drc_route.conf new file mode 100644 index 000000000000..1a59ed86f982 --- /dev/null +++ b/tools/topology/topology2/include/bench/multiband_drc_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh multiband_drc" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'multiband_drc.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'multiband_drc.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'multiband_drc.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'multiband_drc.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/multiband_drc_s16.conf b/tools/topology/topology2/include/bench/multiband_drc_s16.conf index cc36cb8ab341..f29665f35799 100644 --- a/tools/topology/topology2/include/bench/multiband_drc_s16.conf +++ b/tools/topology/topology2/include/bench/multiband_drc_s16.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh multiband_drc" Object.Widget.multiband_drc.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/multiband_drc_controls_playback.conf> } Object.Widget.multiband_drc.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/multiband_drc_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s16.conf> - <include/bench/multiband_drc_hda_route.conf> + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/multiband_drc_route.conf> diff --git a/tools/topology/topology2/include/bench/multiband_drc_s24.conf b/tools/topology/topology2/include/bench/multiband_drc_s24.conf index 93f9e33d1416..110258f4c866 100644 --- a/tools/topology/topology2/include/bench/multiband_drc_s24.conf +++ b/tools/topology/topology2/include/bench/multiband_drc_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh multiband_drc" Object.Widget.multiband_drc.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/multiband_drc_controls_playback.conf> } Object.Widget.multiband_drc.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/multiband_drc_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s24.conf> - <include/bench/multiband_drc_hda_route.conf> + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/multiband_drc_route.conf> diff --git a/tools/topology/topology2/include/bench/multiband_drc_s32.conf b/tools/topology/topology2/include/bench/multiband_drc_s32.conf index 3d2aadab0924..8bf433fbe94f 100644 --- a/tools/topology/topology2/include/bench/multiband_drc_s32.conf +++ b/tools/topology/topology2/include/bench/multiband_drc_s32.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh multiband_drc" Object.Widget.multiband_drc.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/multiband_drc_controls_playback.conf> } Object.Widget.multiband_drc.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/multiband_drc_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s32.conf> - <include/bench/multiband_drc_hda_route.conf> + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/multiband_drc_route.conf> diff --git a/tools/topology/topology2/include/bench/one_input_output_format_s16_16k.conf b/tools/topology/topology2/include/bench/one_input_output_format_s16_16k.conf new file mode 100644 index 000000000000..eca8c45d8bc9 --- /dev/null +++ b/tools/topology/topology2/include/bench/one_input_output_format_s16_16k.conf @@ -0,0 +1,19 @@ + num_input_audio_formats 1 + num_output_audio_formats 1 + + # 16-bit 16kHz + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_rate 16000 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_rate 16000 + } + ] + diff --git a/tools/topology/topology2/include/bench/one_input_output_format_s24_16k.conf b/tools/topology/topology2/include/bench/one_input_output_format_s24_16k.conf new file mode 100644 index 000000000000..742151e6948d --- /dev/null +++ b/tools/topology/topology2/include/bench/one_input_output_format_s24_16k.conf @@ -0,0 +1,19 @@ + num_input_audio_formats 1 + num_output_audio_formats 1 + + # 24-bit 16kHz + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_rate 16000 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_rate 16000 + } + ] + diff --git a/tools/topology/topology2/include/bench/one_input_output_format_s32_16k.conf b/tools/topology/topology2/include/bench/one_input_output_format_s32_16k.conf new file mode 100644 index 000000000000..ae4608b5ab76 --- /dev/null +++ b/tools/topology/topology2/include/bench/one_input_output_format_s32_16k.conf @@ -0,0 +1,19 @@ + num_input_audio_formats 1 + num_output_audio_formats 1 + + # 32-bit 16kHz + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_rate 16000 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_rate 16000 + } + ] + diff --git a/tools/topology/topology2/include/bench/one_input_output_format_s32_dp128.conf b/tools/topology/topology2/include/bench/one_input_output_format_s32_dp128.conf new file mode 100644 index 000000000000..379ee73f9eff --- /dev/null +++ b/tools/topology/topology2/include/bench/one_input_output_format_s32_dp128.conf @@ -0,0 +1,19 @@ + 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 + ibs 1024 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + obs 1024 + } + ] + diff --git a/tools/topology/topology2/include/bench/one_input_output_format_s32_dp192.conf b/tools/topology/topology2/include/bench/one_input_output_format_s32_dp192.conf new file mode 100644 index 000000000000..b3989ce90f36 --- /dev/null +++ b/tools/topology/topology2/include/bench/one_input_output_format_s32_dp192.conf @@ -0,0 +1,19 @@ + 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 + ibs 1536 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + obs 1536 + } + ] + diff --git a/tools/topology/topology2/include/bench/one_input_output_format_s32_dp256.conf b/tools/topology/topology2/include/bench/one_input_output_format_s32_dp256.conf new file mode 100644 index 000000000000..d753c1ea114f --- /dev/null +++ b/tools/topology/topology2/include/bench/one_input_output_format_s32_dp256.conf @@ -0,0 +1,19 @@ + 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 + ibs 2048 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + obs 2048 + } + ] + diff --git a/tools/topology/topology2/include/bench/one_input_output_format_s32_dp_5ms.conf b/tools/topology/topology2/include/bench/one_input_output_format_s32_dp_5ms.conf new file mode 100644 index 000000000000..097f75fb121e --- /dev/null +++ b/tools/topology/topology2/include/bench/one_input_output_format_s32_dp_5ms.conf @@ -0,0 +1,22 @@ + num_input_audio_formats 1 + num_output_audio_formats 1 + + # 32-bit 48KHz 2ch, ibs/obs is set to match + # 5 ms or 240 stereo frames period. + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 2 + ibs 1920 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 2 + obs 1920 + } + ] + diff --git a/tools/topology/topology2/include/bench/phase_vocoder_controls_capture.conf b/tools/topology/topology2/include/bench/phase_vocoder_controls_capture.conf new file mode 100644 index 000000000000..c25aaebfcc58 --- /dev/null +++ b/tools/topology/topology2/include/bench/phase_vocoder_controls_capture.conf @@ -0,0 +1,17 @@ + # Created initially with script "./bench_comp_generate.sh phase_vocoder" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in PHASE_VOCODER + bytes."1" { + name '$ANALOG_CAPTURE_PCM Phase Vocoder bytes' + IncludeByKey.BENCH_PHASE_VOCODER_PARAMS { + "default" "include/components/phase_vocoder/hann_1024_256.conf" + } + } + mixer."1" { + name '$ANALOG_CAPTURE_PCM Phase Vocoder enable' + } + enum."1" { + name '$ANALOG_CAPTURE_PCM Phase Vocoder speed' + } + } diff --git a/tools/topology/topology2/include/bench/phase_vocoder_controls_playback.conf b/tools/topology/topology2/include/bench/phase_vocoder_controls_playback.conf new file mode 100644 index 000000000000..fb6c3da0e369 --- /dev/null +++ b/tools/topology/topology2/include/bench/phase_vocoder_controls_playback.conf @@ -0,0 +1,17 @@ + # Created initially with script "./bench_comp_generate.sh phase_vocoder" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in PHASE_VOCODER + bytes."1" { + name '$ANALOG_PLAYBACK_PCM Phase Vocoder bytes' + IncludeByKey.BENCH_PHASE_VOCODER_PARAMS { + "default" "include/components/phase_vocoder/hann_1024_256.conf" + } + } + mixer."1" { + name '$ANALOG_PLAYBACK_PCM Phase Vocoder enable' + } + enum."1" { + name '$ANALOG_PLAYBACK_PCM Phase Vocoder speed' + } + } diff --git a/tools/topology/topology2/include/bench/phase_vocoder_route.conf b/tools/topology/topology2/include/bench/phase_vocoder_route.conf new file mode 100644 index 000000000000..4213b01c87ed --- /dev/null +++ b/tools/topology/topology2/include/bench/phase_vocoder_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh phase_vocoder" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'phase_vocoder.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'phase_vocoder.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'phase_vocoder.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'phase_vocoder.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/phase_vocoder_s16.conf b/tools/topology/topology2/include/bench/phase_vocoder_s16.conf new file mode 100644 index 000000000000..c5fdb6aeef5c --- /dev/null +++ b/tools/topology/topology2/include/bench/phase_vocoder_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh phase_vocoder" + Object.Widget.phase_vocoder.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/phase_vocoder_controls_playback.conf> + } + Object.Widget.phase_vocoder.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/phase_vocoder_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/phase_vocoder_route.conf> diff --git a/tools/topology/topology2/include/bench/phase_vocoder_s24.conf b/tools/topology/topology2/include/bench/phase_vocoder_s24.conf new file mode 100644 index 000000000000..9865e4e8f8b7 --- /dev/null +++ b/tools/topology/topology2/include/bench/phase_vocoder_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh phase_vocoder" + Object.Widget.phase_vocoder.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/phase_vocoder_controls_playback.conf> + } + Object.Widget.phase_vocoder.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/phase_vocoder_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/phase_vocoder_route.conf> diff --git a/tools/topology/topology2/include/bench/phase_vocoder_s32.conf b/tools/topology/topology2/include/bench/phase_vocoder_s32.conf new file mode 100644 index 000000000000..46f9cad71989 --- /dev/null +++ b/tools/topology/topology2/include/bench/phase_vocoder_s32.conf @@ -0,0 +1,21 @@ + # Created with script "./bench_comp_generate.sh phase_vocoder" + Object.Widget.phase_vocoder.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + scheduler_domain DP + domain_id 123 + stack_bytes_requirement 4096 + heap_bytes_requirement 49152 + <include/bench/one_input_output_format_s32_dp_5ms.conf> + <include/bench/phase_vocoder_controls_playback.conf> + } + Object.Widget.phase_vocoder.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + scheduler_domain DP + domain_id 123 + stack_bytes_requirement 4096 + heap_bytes_requirement 49152 + <include/bench/one_input_output_format_s32_dp_5ms.conf> + <include/bench/phase_vocoder_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/phase_vocoder_route.conf> diff --git a/tools/topology/topology2/include/bench/rtnr_hda_route.conf b/tools/topology/topology2/include/bench/rtnr_hda_route.conf deleted file mode 100644 index 71f6de968f1b..000000000000 --- a/tools/topology/topology2/include/bench/rtnr_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # Created with script "./bench_comp_generate.sh rtnr" - Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'rtnr.1.1' - } - { - sink 'rtnr.1.1' - source 'host-copier.0.playback' - } - { - source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' - sink 'rtnr.3.2' - } - { - source 'rtnr.3.2' - sink 'host-copier.0.capture' - } - ] diff --git a/tools/topology/topology2/include/bench/rtnr_route.conf b/tools/topology/topology2/include/bench/rtnr_route.conf new file mode 100644 index 000000000000..9238049baf79 --- /dev/null +++ b/tools/topology/topology2/include/bench/rtnr_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh rtnr" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'rtnr.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'rtnr.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'rtnr.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'rtnr.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/rtnr_s16.conf b/tools/topology/topology2/include/bench/rtnr_s16.conf index 94dd01873a18..e30c3843bf08 100644 --- a/tools/topology/topology2/include/bench/rtnr_s16.conf +++ b/tools/topology/topology2/include/bench/rtnr_s16.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh rtnr" Object.Widget.rtnr.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/rtnr_controls_playback.conf> } Object.Widget.rtnr.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/rtnr_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s16.conf> - <include/bench/rtnr_hda_route.conf> + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/rtnr_route.conf> diff --git a/tools/topology/topology2/include/bench/rtnr_s24.conf b/tools/topology/topology2/include/bench/rtnr_s24.conf index 1a1475ee02a1..bcd9d2443e53 100644 --- a/tools/topology/topology2/include/bench/rtnr_s24.conf +++ b/tools/topology/topology2/include/bench/rtnr_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh rtnr" Object.Widget.rtnr.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/rtnr_controls_playback.conf> } Object.Widget.rtnr.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/rtnr_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s24.conf> - <include/bench/rtnr_hda_route.conf> + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/rtnr_route.conf> diff --git a/tools/topology/topology2/include/bench/rtnr_s32.conf b/tools/topology/topology2/include/bench/rtnr_s32.conf index b03d77b80b4a..239294c41afd 100644 --- a/tools/topology/topology2/include/bench/rtnr_s32.conf +++ b/tools/topology/topology2/include/bench/rtnr_s32.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh rtnr" Object.Widget.rtnr.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/rtnr_controls_playback.conf> } Object.Widget.rtnr.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/rtnr_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s32.conf> - <include/bench/rtnr_hda_route.conf> + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/rtnr_route.conf> diff --git a/tools/topology/topology2/include/bench/sound_dose_controls_capture.conf b/tools/topology/topology2/include/bench/sound_dose_controls_capture.conf new file mode 100644 index 000000000000..38cbbc70b615 --- /dev/null +++ b/tools/topology/topology2/include/bench/sound_dose_controls_capture.conf @@ -0,0 +1,33 @@ + # Created initially with script "./bench_comp_generate.sh sound_dose" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in SOUND_DOSE + bytes."1" { + name '$ANALOG_CAPTURE_PCM Sound Dose setup bytes' + max 44 + IncludeByKey.BENCH_SOUND_DOSE_PARAMS { + "default" "include/components/sound_dose/setup_sens_100db.conf" + } + } + bytes."2" { + name '$ANALOG_CAPTURE_PCM Sound Dose volume bytes' + max 44 + <include/components/sound_dose/setup_vol_0db.conf> + } + bytes."3" { + name '$ANALOG_CAPTURE_PCM Sound Dose gain bytes' + max 44 + <include/components/sound_dose/setup_gain_0db.conf> + } + bytes."4" { + name '$ANALOG_CAPTURE_PCM Sound Dose data bytes' + max 256 + <include/components/sound_dose/setup_data_init.conf> + } + #mixer."1" { + # name '$ANALOG_CAPTURE_PCM SOUND_DOSE switch or volume' + #} + #enum."1" { + # name '$ANALOG_CAPTURE_PCM SOUND_DOSE enum' + #} + } diff --git a/tools/topology/topology2/include/bench/sound_dose_controls_playback.conf b/tools/topology/topology2/include/bench/sound_dose_controls_playback.conf new file mode 100644 index 000000000000..e0d83ffc0c2b --- /dev/null +++ b/tools/topology/topology2/include/bench/sound_dose_controls_playback.conf @@ -0,0 +1,33 @@ + # Created initially with script "./bench_comp_generate.sh sound_dose" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in SOUND_DOSE + bytes."1" { + name '$ANALOG_PLAYBACK_PCM Sound Dose setup bytes' + max 44 + IncludeByKey.BENCH_SOUND_DOSE_PARAMS { + "default" "include/components/sound_dose/setup_sens_100db.conf" + } + } + bytes."2" { + name '$ANALOG_PLAYBACK_PCM Sound Dose volume bytes' + max 44 + <include/components/sound_dose/setup_vol_0db.conf> + } + bytes."3" { + name '$ANALOG_PLAYBACK_PCM Sound Dose gain bytes' + max 44 + <include/components/sound_dose/setup_gain_0db.conf> + } + bytes."4" { + name '$ANALOG_PLAYBACK_PCM Sound Dose data bytes' + max 256 + <include/components/sound_dose/setup_data_init.conf> + } + #mixer."1" { + # name '$ANALOG_PLAYBACK_PCM SOUND_DOSE switch or volume' + #} + #enum."1" { + # name '$ANALOG_PLAYBACK_PCM SOUND_DOSE enum' + #} + } diff --git a/tools/topology/topology2/include/bench/sound_dose_route.conf b/tools/topology/topology2/include/bench/sound_dose_route.conf new file mode 100644 index 000000000000..20f4b164e14d --- /dev/null +++ b/tools/topology/topology2/include/bench/sound_dose_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh sound_dose" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'sound_dose.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'sound_dose.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'sound_dose.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'sound_dose.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/sound_dose_s16.conf b/tools/topology/topology2/include/bench/sound_dose_s16.conf new file mode 100644 index 000000000000..3aec94858e08 --- /dev/null +++ b/tools/topology/topology2/include/bench/sound_dose_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh sound_dose" + Object.Widget.sound_dose.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/sound_dose_controls_playback.conf> + } + Object.Widget.sound_dose.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/sound_dose_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/sound_dose_route.conf> diff --git a/tools/topology/topology2/include/bench/sound_dose_s24.conf b/tools/topology/topology2/include/bench/sound_dose_s24.conf new file mode 100644 index 000000000000..fe59e8e2fb4c --- /dev/null +++ b/tools/topology/topology2/include/bench/sound_dose_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh sound_dose" + Object.Widget.sound_dose.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/sound_dose_controls_playback.conf> + } + Object.Widget.sound_dose.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/sound_dose_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/sound_dose_route.conf> diff --git a/tools/topology/topology2/include/bench/sound_dose_s32.conf b/tools/topology/topology2/include/bench/sound_dose_s32.conf new file mode 100644 index 000000000000..5e3146a8076f --- /dev/null +++ b/tools/topology/topology2/include/bench/sound_dose_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh sound_dose" + Object.Widget.sound_dose.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s32.conf> + <include/bench/sound_dose_controls_playback.conf> + } + Object.Widget.sound_dose.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s32.conf> + <include/bench/sound_dose_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/sound_dose_route.conf> diff --git a/tools/topology/topology2/include/bench/src_hda_route.conf b/tools/topology/topology2/include/bench/src_hda_route.conf deleted file mode 100644 index 1c72c0f0601e..000000000000 --- a/tools/topology/topology2/include/bench/src_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # Created with script "./bench_comp_generate.sh src" - Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'src.1.1' - } - { - sink 'src.1.1' - source 'host-copier.0.playback' - } - { - source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' - sink 'src.3.2' - } - { - source 'src.3.2' - sink 'host-copier.0.capture' - } - ] diff --git a/tools/topology/topology2/include/bench/src_lite_hda_route.conf b/tools/topology/topology2/include/bench/src_lite_hda_route.conf deleted file mode 100644 index 3e3f03b02aa2..000000000000 --- a/tools/topology/topology2/include/bench/src_lite_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # Created with script "./bench_comp_generate.sh src_lite" - Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'src_lite.1.1' - } - { - sink 'src_lite.1.1' - source 'host-copier.0.playback' - } - { - source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' - sink 'src_lite.3.2' - } - { - source 'src_lite.3.2' - sink 'host-copier.0.capture' - } - ] diff --git a/tools/topology/topology2/include/bench/src_lite_route.conf b/tools/topology/topology2/include/bench/src_lite_route.conf new file mode 100644 index 000000000000..65713b5e62be --- /dev/null +++ b/tools/topology/topology2/include/bench/src_lite_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh src_lite" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'src_lite.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'src_lite.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'src_lite.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'src_lite.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/src_lite_s16.conf b/tools/topology/topology2/include/bench/src_lite_s16.conf index fdf803739ec4..559d47a1af4b 100644 --- a/tools/topology/topology2/include/bench/src_lite_s16.conf +++ b/tools/topology/topology2/include/bench/src_lite_s16.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh src_lite" Object.Widget.src_lite.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE rate_out 48000 <include/components/src_format_s16_convert_to_48k.conf> } Object.Widget.src_lite.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE rate_in 48000 <include/components/src_format_s16_convert_from_48k.conf> } - <include/bench/host_io_gateway_pipelines_src_s16.conf> - <include/bench/src_lite_hda_route.conf> + <include/bench/host_gateway_pipelines_src_s16.conf> + <include/bench/src_lite_route.conf> diff --git a/tools/topology/topology2/include/bench/src_lite_s24.conf b/tools/topology/topology2/include/bench/src_lite_s24.conf index eab349d84739..319a5e8d3475 100644 --- a/tools/topology/topology2/include/bench/src_lite_s24.conf +++ b/tools/topology/topology2/include/bench/src_lite_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh src_lite" Object.Widget.src_lite.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE rate_out 48000 <include/components/src_format_s24_convert_to_48k.conf> } Object.Widget.src_lite.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE rate_in 48000 <include/components/src_format_s24_convert_from_48k.conf> } - <include/bench/host_io_gateway_pipelines_src_s24.conf> - <include/bench/src_lite_hda_route.conf> + <include/bench/host_gateway_pipelines_src_s24.conf> + <include/bench/src_lite_route.conf> diff --git a/tools/topology/topology2/include/bench/src_lite_s32.conf b/tools/topology/topology2/include/bench/src_lite_s32.conf index 33406cc0e45d..8339d191e39a 100644 --- a/tools/topology/topology2/include/bench/src_lite_s32.conf +++ b/tools/topology/topology2/include/bench/src_lite_s32.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh src_lite" Object.Widget.src_lite.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE rate_out 48000 <include/components/src_format_s32_convert_to_48k.conf> } Object.Widget.src_lite.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE rate_in 48000 <include/components/src_format_s32_convert_from_48k.conf> } - <include/bench/host_io_gateway_pipelines_src_s32.conf> - <include/bench/src_lite_hda_route.conf> + <include/bench/host_gateway_pipelines_src_s32.conf> + <include/bench/src_lite_route.conf> diff --git a/tools/topology/topology2/include/bench/src_route.conf b/tools/topology/topology2/include/bench/src_route.conf new file mode 100644 index 000000000000..aac36eb913df --- /dev/null +++ b/tools/topology/topology2/include/bench/src_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh src" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'src.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'src.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'src.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'src.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/src_s16.conf b/tools/topology/topology2/include/bench/src_s16.conf index 7c8568c88f3c..73a84b407be4 100644 --- a/tools/topology/topology2/include/bench/src_s16.conf +++ b/tools/topology/topology2/include/bench/src_s16.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh src" Object.Widget.src.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE rate_out 48000 <include/components/src_format_s16_convert_to_48k.conf> } Object.Widget.src.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE rate_in 48000 <include/components/src_format_s16_convert_from_48k.conf> } - <include/bench/host_io_gateway_pipelines_src_s16.conf> - <include/bench/src_hda_route.conf> + <include/bench/host_gateway_pipelines_src_s16.conf> + <include/bench/src_route.conf> diff --git a/tools/topology/topology2/include/bench/src_s24.conf b/tools/topology/topology2/include/bench/src_s24.conf index e16d2047aa49..355411b644eb 100644 --- a/tools/topology/topology2/include/bench/src_s24.conf +++ b/tools/topology/topology2/include/bench/src_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh src" Object.Widget.src.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE rate_out 48000 <include/components/src_format_s24_convert_to_48k.conf> } Object.Widget.src.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE rate_in 48000 <include/components/src_format_s24_convert_from_48k.conf> } - <include/bench/host_io_gateway_pipelines_src_s24.conf> - <include/bench/src_hda_route.conf> + <include/bench/host_gateway_pipelines_src_s24.conf> + <include/bench/src_route.conf> diff --git a/tools/topology/topology2/include/bench/src_s32.conf b/tools/topology/topology2/include/bench/src_s32.conf index 3f2fa413d2bb..4262fa535d2b 100644 --- a/tools/topology/topology2/include/bench/src_s32.conf +++ b/tools/topology/topology2/include/bench/src_s32.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh src" Object.Widget.src.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE rate_out 48000 <include/components/src_format_s32_convert_to_48k.conf> } Object.Widget.src.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE rate_in 48000 <include/components/src_format_s32_convert_from_48k.conf> } - <include/bench/host_io_gateway_pipelines_src_s32.conf> - <include/bench/src_hda_route.conf> + <include/bench/host_gateway_pipelines_src_s32.conf> + <include/bench/src_route.conf> diff --git a/tools/topology/topology2/include/bench/stft_process_controls_capture.conf b/tools/topology/topology2/include/bench/stft_process_controls_capture.conf new file mode 100644 index 000000000000..67acf222d764 --- /dev/null +++ b/tools/topology/topology2/include/bench/stft_process_controls_capture.conf @@ -0,0 +1,21 @@ + # Created initially with script "./bench_comp_generate.sh stft_process" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in STFT_PROCESS + bytes."1" { + name '$ANALOG_CAPTURE_PCM STFT_PROCESS bytes' + IncludeByKey.BENCH_STFT_PROCESS_PARAMS { + "hann_192_48" "include/components/stft_process/hann_192_48.conf" + "hann_512_128" "include/components/stft_process/hann_512_128.conf" + "hann_768_120" "include/components/stft_process/hann_768_120.conf" + "hann_1024_256" "include/components/stft_process/hann_1024_256.conf" + "hann_1536_240" "include/components/stft_process/hann_1536_240.conf" + } + } + #mixer."1" { + # name '$ANALOG_CAPTURE_PCM STFT_PROCESS switch or volume' + #} + #enum."1" { + # name '$ANALOG_CAPTURE_PCM STFT_PROCESS enum' + #} + } diff --git a/tools/topology/topology2/include/bench/stft_process_controls_playback.conf b/tools/topology/topology2/include/bench/stft_process_controls_playback.conf new file mode 100644 index 000000000000..82c702555e40 --- /dev/null +++ b/tools/topology/topology2/include/bench/stft_process_controls_playback.conf @@ -0,0 +1,21 @@ + # Created initially with script "./bench_comp_generate.sh stft_process" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in STFT_PROCESS + bytes."1" { + name '$ANALOG_PLAYBACK_PCM STFT_PROCESS bytes' + IncludeByKey.BENCH_STFT_PROCESS_PARAMS { + "hann_192_48" "include/components/stft_process/hann_192_48.conf" + "hann_512_128" "include/components/stft_process/hann_512_128.conf" + "hann_768_120" "include/components/stft_process/hann_768_120.conf" + "hann_1024_256" "include/components/stft_process/hann_1024_256.conf" + "hann_1536_240" "include/components/stft_process/hann_1536_240.conf" + } + } + #mixer."1" { + # name '$ANALOG_PLAYBACK_PCM STFT_PROCESS switch or volume' + #} + #enum."1" { + # name '$ANALOG_PLAYBACK_PCM STFT_PROCESS enum' + #} + } diff --git a/tools/topology/topology2/include/bench/stft_process_route.conf b/tools/topology/topology2/include/bench/stft_process_route.conf new file mode 100644 index 000000000000..dcc4dc3feebc --- /dev/null +++ b/tools/topology/topology2/include/bench/stft_process_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh stft_process" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'stft_process.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'stft_process.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'stft_process.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'stft_process.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/stft_process_s16.conf b/tools/topology/topology2/include/bench/stft_process_s16.conf new file mode 100644 index 000000000000..ebe14bcd0c21 --- /dev/null +++ b/tools/topology/topology2/include/bench/stft_process_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh stft_process" + Object.Widget.stft_process.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/stft_process_controls_playback.conf> + } + Object.Widget.stft_process.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/stft_process_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/stft_process_route.conf> diff --git a/tools/topology/topology2/include/bench/stft_process_s24.conf b/tools/topology/topology2/include/bench/stft_process_s24.conf new file mode 100644 index 000000000000..b75f35a3a486 --- /dev/null +++ b/tools/topology/topology2/include/bench/stft_process_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh stft_process" + Object.Widget.stft_process.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/stft_process_controls_playback.conf> + } + Object.Widget.stft_process.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/stft_process_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/stft_process_route.conf> diff --git a/tools/topology/topology2/include/bench/stft_process_s32.conf b/tools/topology/topology2/include/bench/stft_process_s32.conf new file mode 100644 index 000000000000..d0d16557bbee --- /dev/null +++ b/tools/topology/topology2/include/bench/stft_process_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh stft_process" + Object.Widget.stft_process.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s32.conf> + <include/bench/stft_process_controls_playback.conf> + } + Object.Widget.stft_process.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s32.conf> + <include/bench/stft_process_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/stft_process_route.conf> diff --git a/tools/topology/topology2/include/bench/tdfb_hda_route.conf b/tools/topology/topology2/include/bench/tdfb_hda_route.conf deleted file mode 100644 index a78857d44b64..000000000000 --- a/tools/topology/topology2/include/bench/tdfb_hda_route.conf +++ /dev/null @@ -1,19 +0,0 @@ - # Created with script "./bench_comp_generate.sh tdfb" - Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'tdfb.1.1' - } - { - sink 'tdfb.1.1' - source 'host-copier.0.playback' - } - { - source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' - sink 'tdfb.3.2' - } - { - source 'tdfb.3.2' - sink 'host-copier.0.capture' - } - ] diff --git a/tools/topology/topology2/include/bench/tdfb_route.conf b/tools/topology/topology2/include/bench/tdfb_route.conf new file mode 100644 index 000000000000..809dd627d6de --- /dev/null +++ b/tools/topology/topology2/include/bench/tdfb_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh tdfb" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'tdfb.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'tdfb.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'tdfb.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'tdfb.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/tdfb_s16.conf b/tools/topology/topology2/include/bench/tdfb_s16.conf index c2b1abd253eb..d08eea403981 100644 --- a/tools/topology/topology2/include/bench/tdfb_s16.conf +++ b/tools/topology/topology2/include/bench/tdfb_s16.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh tdfb" Object.Widget.tdfb.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/tdfb_controls_playback.conf> } Object.Widget.tdfb.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s16.conf> <include/bench/tdfb_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s16.conf> - <include/bench/tdfb_hda_route.conf> + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/tdfb_route.conf> diff --git a/tools/topology/topology2/include/bench/tdfb_s24.conf b/tools/topology/topology2/include/bench/tdfb_s24.conf index f57bdea003f1..418e48b53c04 100644 --- a/tools/topology/topology2/include/bench/tdfb_s24.conf +++ b/tools/topology/topology2/include/bench/tdfb_s24.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh tdfb" Object.Widget.tdfb.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/tdfb_controls_playback.conf> } Object.Widget.tdfb.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s24.conf> <include/bench/tdfb_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s24.conf> - <include/bench/tdfb_hda_route.conf> + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/tdfb_route.conf> diff --git a/tools/topology/topology2/include/bench/tdfb_s32.conf b/tools/topology/topology2/include/bench/tdfb_s32.conf index 5c74b11c1036..95e36dfdff34 100644 --- a/tools/topology/topology2/include/bench/tdfb_s32.conf +++ b/tools/topology/topology2/include/bench/tdfb_s32.conf @@ -1,13 +1,13 @@ # Created with script "./bench_comp_generate.sh tdfb" Object.Widget.tdfb.1 { - index 1 + index $BENCH_PLAYBACK_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/tdfb_controls_playback.conf> } Object.Widget.tdfb.2 { - index 3 + index $BENCH_CAPTURE_HOST_PIPELINE <include/bench/one_input_output_format_s32.conf> <include/bench/tdfb_controls_capture.conf> } - <include/bench/host_io_gateway_pipelines_s32.conf> - <include/bench/tdfb_hda_route.conf> + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/tdfb_route.conf> diff --git a/tools/topology/topology2/include/bench/template_comp_controls_capture.conf b/tools/topology/topology2/include/bench/template_comp_controls_capture.conf new file mode 100644 index 000000000000..b05f70fa5899 --- /dev/null +++ b/tools/topology/topology2/include/bench/template_comp_controls_capture.conf @@ -0,0 +1,17 @@ + # Created initially with script "./bench_comp_generate.sh template_comp" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in TEMPLATE_COMP + #bytes."1" { + # name '$ANALOG_CAPTURE_PCM TEMPLATE_COMP bytes' + # IncludeByKey.BENCH_TEMPLATE_COMP_PARAMS { + # "default" "include/components/template_comp/default.conf" + # } + #} + mixer."1" { + name '$ANALOG_CAPTURE_PCM TEMPLATE_COMP switch' + } + #enum."1" { + # name '$ANALOG_CAPTURE_PCM TEMPLATE_COMP enum' + #} + } diff --git a/tools/topology/topology2/include/bench/template_comp_controls_playback.conf b/tools/topology/topology2/include/bench/template_comp_controls_playback.conf new file mode 100644 index 000000000000..5e86efe6aa42 --- /dev/null +++ b/tools/topology/topology2/include/bench/template_comp_controls_playback.conf @@ -0,0 +1,17 @@ + # Created initially with script "./bench_comp_generate.sh template_comp" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in TEMPLATE_COMP + #bytes."1" { + # name '$ANALOG_PLAYBACK_PCM TEMPLATE_COMP bytes' + # IncludeByKey.BENCH_TEMPLATE_COMP_PARAMS { + # "default" "include/components/template_comp/default.conf" + # } + #} + mixer."1" { + name '$ANALOG_PLAYBACK_PCM TEMPLATE_COMP switch' + } + #enum."1" { + # name '$ANALOG_PLAYBACK_PCM TEMPLATE_COMP enum' + #} + } diff --git a/tools/topology/topology2/include/bench/template_comp_route.conf b/tools/topology/topology2/include/bench/template_comp_route.conf new file mode 100644 index 000000000000..9fe72d672489 --- /dev/null +++ b/tools/topology/topology2/include/bench/template_comp_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh template_comp" + Object.Base.route [ + { + sink '$BENCH_PLAYBACK_DAI_COPIER' + source 'template_comp.$BENCH_PLAYBACK_HOST_PIPELINE.1' + } + { + sink 'template_comp.$BENCH_PLAYBACK_HOST_PIPELINE.1' + source 'host-copier.0.playback' + } + { + source '$BENCH_CAPTURE_DAI_COPIER' + sink 'template_comp.$BENCH_CAPTURE_HOST_PIPELINE.2' + } + { + source 'template_comp.$BENCH_CAPTURE_HOST_PIPELINE.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/template_comp_s16.conf b/tools/topology/topology2/include/bench/template_comp_s16.conf new file mode 100644 index 000000000000..57ab83eca6fa --- /dev/null +++ b/tools/topology/topology2/include/bench/template_comp_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh template_comp" + Object.Widget.template_comp.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/template_comp_controls_playback.conf> + } + Object.Widget.template_comp.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s16.conf> + <include/bench/template_comp_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s16.conf> + <include/bench/template_comp_route.conf> diff --git a/tools/topology/topology2/include/bench/template_comp_s24.conf b/tools/topology/topology2/include/bench/template_comp_s24.conf new file mode 100644 index 000000000000..83573abf19fe --- /dev/null +++ b/tools/topology/topology2/include/bench/template_comp_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh template_comp" + Object.Widget.template_comp.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/template_comp_controls_playback.conf> + } + Object.Widget.template_comp.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s24.conf> + <include/bench/template_comp_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s24.conf> + <include/bench/template_comp_route.conf> diff --git a/tools/topology/topology2/include/bench/template_comp_s32.conf b/tools/topology/topology2/include/bench/template_comp_s32.conf new file mode 100644 index 000000000000..e05a346b82d7 --- /dev/null +++ b/tools/topology/topology2/include/bench/template_comp_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh template_comp" + Object.Widget.template_comp.1 { + index $BENCH_PLAYBACK_HOST_PIPELINE + <include/bench/one_input_output_format_s32.conf> + <include/bench/template_comp_controls_playback.conf> + } + Object.Widget.template_comp.2 { + index $BENCH_CAPTURE_HOST_PIPELINE + <include/bench/one_input_output_format_s32.conf> + <include/bench/template_comp_controls_capture.conf> + } + <include/bench/host_gateway_pipelines_s32.conf> + <include/bench/template_comp_route.conf> diff --git a/tools/topology/topology2/include/common/common_definitions.conf b/tools/topology/topology2/include/common/common_definitions.conf index 9da9fcb78f34..06f0f425c5e2 100644 --- a/tools/topology/topology2/include/common/common_definitions.conf +++ b/tools/topology/topology2/include/common/common_definitions.conf @@ -34,6 +34,8 @@ Define { SAMPLE_TYPE_SIGNED_INTEGER 2 # Signed Integer SAMPLE_TYPE_UNSIGNED_INTEGER 3 # Unsigned Integer SAMPLE_TYPE_FLOAT 4 # Float + SAMPLE_TYPE_A_LAW 5 # A-law + SAMPLE_TYPE_MU_LAW 6 # mu-law # Copier type HDA_HOST_OUTPUT_CLASS 0 # HD/A host output (-> DSP) @@ -65,4 +67,12 @@ Define { SSP_BLOB_VERSION_1_0 0x100 SSP_BLOB_VERSION_1_5 0x105 SSP_BLOB_VERSION_3_0 0x300 + + PCM_FORMAT_ALL false # Basic s16/s24/s32, no float, 8-bit etc. + SDW_JACK_ECHO_REF false # No echo reference for 3.5mm jack + SDW_SPK_ECHO_REF false # No echo reference for speaker + SDW_JACK_AUDIO_FEATURE_CAPTURE false # No audio features capture for jack + SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE false # No compress audio features capture for jack + SDW_DMIC_AUDIO_FEATURE_CAPTURE false # No audio features capture for microphone + SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE false # No compress audio features capture for microphone } diff --git a/tools/topology/topology2/include/common/input_audio_format.conf b/tools/topology/topology2/include/common/input_audio_format.conf index 795f3cdb46b0..7c220516ed48 100644 --- a/tools/topology/topology2/include/common/input_audio_format.conf +++ b/tools/topology/topology2/include/common/input_audio_format.conf @@ -98,6 +98,8 @@ Class.Base."input_audio_format" { $SAMPLE_TYPE_SIGNED_INTEGER $SAMPLE_TYPE_UNSIGNED_INTEGER $SAMPLE_TYPE_FLOAT + $SAMPLE_TYPE_A_LAW + $SAMPLE_TYPE_MU_LAW ] } } diff --git a/tools/topology/topology2/include/common/output_audio_format.conf b/tools/topology/topology2/include/common/output_audio_format.conf index 915edc000820..7930402a26f2 100644 --- a/tools/topology/topology2/include/common/output_audio_format.conf +++ b/tools/topology/topology2/include/common/output_audio_format.conf @@ -103,6 +103,8 @@ Class.Base."output_audio_format" { $SAMPLE_TYPE_SIGNED_INTEGER $SAMPLE_TYPE_UNSIGNED_INTEGER $SAMPLE_TYPE_FLOAT + $SAMPLE_TYPE_A_LAW + $SAMPLE_TYPE_MU_LAW ] } } diff --git a/tools/topology/topology2/include/common/pcm.conf b/tools/topology/topology2/include/common/pcm.conf index 01e9358bf758..ba014d084bee 100644 --- a/tools/topology/topology2/include/common/pcm.conf +++ b/tools/topology/topology2/include/common/pcm.conf @@ -25,9 +25,9 @@ Class.PCM."pcm" { DefineAttribute."direction" { constraints { !valid_values [ - playback - capture - duplex + "playback" + "capture" + "duplex" ] } } diff --git a/tools/topology/topology2/include/common/tokens.conf b/tools/topology/topology2/include/common/tokens.conf index dadfc162483c..d03092360591 100644 --- a/tools/topology/topology2/include/common/tokens.conf +++ b/tools/topology/topology2/include/common/tokens.conf @@ -25,6 +25,10 @@ Object.Base.VendorToken { num_input_audio_formats 415 num_output_audio_formats 416 no_wname_in_kcontrol_name 417 + scheduler_domain 418 + domain_id 419 + stack_bytes_requirement 420 + heap_bytes_requirement 421 } "2" { @@ -63,9 +67,7 @@ Object.Base.VendorToken { "7" { name "asrc" - rate_in 320 - rate_out 321 - asynchronous_mode 322 + rate_out 321 operation_mode 323 } @@ -82,6 +84,8 @@ Object.Base.VendorToken { lp_mode 207 use_chain_dma 209 kcps 210 + direction 211 + direction_valid 212 } "9" { diff --git a/tools/topology/topology2/include/components/asrc.conf b/tools/topology/topology2/include/components/asrc.conf index 1adcb9b457de..5ea82b0e7882 100644 --- a/tools/topology/topology2/include/components/asrc.conf +++ b/tools/topology/topology2/include/components/asrc.conf @@ -8,7 +8,6 @@ # Object.Widget.asrc."N" { # format "s24le" # rate_out 48000 -# asynchronous_mode 1 # operation_mode 0 # } # @@ -32,24 +31,12 @@ Class.Widget."asrc" { # Bespoke attributes for ASRC # - # Source sample rate - DefineAttribute."rate_in" { - # Token set reference name and type - token_ref "asrc.word" - - } - # Target sample rate DefineAttribute."rate_out" { # Token set reference name and type token_ref "asrc.word" } - DefineAttribute."asynchronous_mode" { - # Token set reference name and type - token_ref "asrc.word" - } - DefineAttribute."operation_mode" { # Token set reference name and type token_ref "asrc.word" @@ -66,7 +53,6 @@ Class.Widget."asrc" { ] !mandatory [ - "asynchronous_mode" "operation_mode" "num_input_audio_formats" "num_output_audio_formats" diff --git a/tools/topology/topology2/include/components/dax/default.conf b/tools/topology/topology2/include/components/dax/default.conf new file mode 100644 index 000000000000..944157bb59c1 --- /dev/null +++ b/tools/topology/topology2/include/components/dax/default.conf @@ -0,0 +1,830 @@ +Object.Base.data."dolby_data" { + bytes " + 0x53,0x4f,0x46,0x34,0x01,0x00,0x00,0x00, + 0xb4,0x19,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x27,0x10,0x00,0x08,0x78,0x19,0x00,0x00, + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x28,0x10,0x00,0x08,0x54,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0xeb,0x08,0x01,0x00, + 0xac,0x00,0x00,0x00,0x14,0x00,0x00,0x00, + 0x2f,0x00,0x00,0x00,0x8d,0x00,0x00,0x00, + 0xea,0x00,0x00,0x00,0x48,0x01,0x00,0x00, + 0xd5,0x01,0x00,0x00,0x90,0x02,0x00,0x00, + 0x4c,0x03,0x00,0x00,0x07,0x04,0x00,0x00, + 0x21,0x05,0x00,0x00,0x98,0x06,0x00,0x00, + 0xca,0x08,0x00,0x00,0xb8,0x0b,0x00,0x00, + 0xa6,0x0e,0x00,0x00,0x50,0x12,0x00,0x00, + 0xb5,0x16,0x00,0x00,0xd5,0x1b,0x00,0x00, + 0x28,0x23,0x00,0x00,0xf2,0x2b,0x00,0x00, + 0x33,0x36,0x00,0x00,0xe8,0x4c,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,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,0x00,0x00,0x00,0x00, + 0xe6,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0xe5,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xe8,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0xe9,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x40,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x42,0x07,0x01,0x00, + 0x28,0x00,0x00,0x00,0x67,0x00,0x00,0x00, + 0x38,0x7f,0x00,0x00,0x9c,0x2b,0x00,0x00, + 0xe2,0x13,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x4c,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x4b,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x2d,0x00,0x00,0x00,0x29,0x10,0x00,0x08, + 0x90,0x01,0x00,0x00,0x00,0x00,0x00,0x00, + 0xea,0x08,0x01,0x00,0xac,0x00,0x00,0x00, + 0x14,0x00,0x00,0x00,0x2f,0x00,0x00,0x00, + 0x8d,0x00,0x00,0x00,0xea,0x00,0x00,0x00, + 0x48,0x01,0x00,0x00,0xd5,0x01,0x00,0x00, + 0x90,0x02,0x00,0x00,0x4c,0x03,0x00,0x00, + 0x07,0x04,0x00,0x00,0x21,0x05,0x00,0x00, + 0x98,0x06,0x00,0x00,0xca,0x08,0x00,0x00, + 0xb8,0x0b,0x00,0x00,0xa6,0x0e,0x00,0x00, + 0x50,0x12,0x00,0x00,0xb5,0x16,0x00,0x00, + 0xd5,0x1b,0x00,0x00,0x28,0x23,0x00,0x00, + 0xf2,0x2b,0x00,0x00,0x33,0x36,0x00,0x00, + 0xe8,0x4c,0x00,0x00,0x9d,0x00,0x00,0x00, + 0xa7,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xcb,0x00,0x00,0x00, + 0xbc,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, + 0xc0,0x00,0x00,0x00,0xcd,0x00,0x00,0x00, + 0xd5,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xd1,0x00,0x00,0x00,0xc1,0x00,0x00,0x00, + 0x9f,0x00,0x00,0x00,0x86,0x00,0x00,0x00, + 0x61,0x00,0x00,0x00,0x47,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0xa6,0xff,0xff,0xff, + 0xe5,0xfe,0xff,0xff,0x43,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x6a,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x68,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe7,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x38,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x39,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x3a,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x50,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x01,0x00,0x00,0x36,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xe4,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x57,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x3c,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x3d,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3e,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0xff,0xff,0xff,0x3f,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0xff,0xff,0xff, + 0x48,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x76,0x74,0x6c,0x65, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x44,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x29,0x10,0x00,0x08, + 0x90,0x01,0x00,0x00,0x01,0x00,0x00,0x00, + 0xea,0x08,0x01,0x00,0xac,0x00,0x00,0x00, + 0x14,0x00,0x00,0x00,0x2f,0x00,0x00,0x00, + 0x8d,0x00,0x00,0x00,0xea,0x00,0x00,0x00, + 0x48,0x01,0x00,0x00,0xd5,0x01,0x00,0x00, + 0x90,0x02,0x00,0x00,0x4c,0x03,0x00,0x00, + 0x07,0x04,0x00,0x00,0x21,0x05,0x00,0x00, + 0x98,0x06,0x00,0x00,0xca,0x08,0x00,0x00, + 0xb8,0x0b,0x00,0x00,0xa6,0x0e,0x00,0x00, + 0x50,0x12,0x00,0x00,0xb5,0x16,0x00,0x00, + 0xd5,0x1b,0x00,0x00,0x28,0x23,0x00,0x00, + 0xf2,0x2b,0x00,0x00,0x33,0x36,0x00,0x00, + 0xe8,0x4c,0x00,0x00,0x9d,0x00,0x00,0x00, + 0xa7,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xcb,0x00,0x00,0x00, + 0xbc,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, + 0xc0,0x00,0x00,0x00,0xcd,0x00,0x00,0x00, + 0xd5,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xd1,0x00,0x00,0x00,0xc1,0x00,0x00,0x00, + 0x9f,0x00,0x00,0x00,0x86,0x00,0x00,0x00, + 0x61,0x00,0x00,0x00,0x47,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0xa6,0xff,0xff,0xff, + 0xe5,0xfe,0xff,0xff,0x43,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x6a,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x68,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe7,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x38,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x39,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x3a,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x50,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x01,0x00,0x00,0x36,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xe4,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x57,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x3c,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x3d,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3e,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0xff,0xff,0xff,0x3f,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0xff,0xff,0xff, + 0x48,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x76,0x74,0x6c,0x65, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x44,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x28,0x10,0x00,0x08, + 0x54,0x04,0x00,0x00,0x01,0x00,0x00,0x00, + 0xeb,0x08,0x01,0x00,0xac,0x00,0x00,0x00, + 0x14,0x00,0x00,0x00,0x2f,0x00,0x00,0x00, + 0x8d,0x00,0x00,0x00,0xea,0x00,0x00,0x00, + 0x48,0x01,0x00,0x00,0xd5,0x01,0x00,0x00, + 0x90,0x02,0x00,0x00,0x4c,0x03,0x00,0x00, + 0x07,0x04,0x00,0x00,0x21,0x05,0x00,0x00, + 0x98,0x06,0x00,0x00,0xca,0x08,0x00,0x00, + 0xb8,0x0b,0x00,0x00,0xa6,0x0e,0x00,0x00, + 0x50,0x12,0x00,0x00,0xb5,0x16,0x00,0x00, + 0xd5,0x1b,0x00,0x00,0x28,0x23,0x00,0x00, + 0xf2,0x2b,0x00,0x00,0x33,0x36,0x00,0x00, + 0xe8,0x4c,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,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, + 0x00,0x00,0x00,0x00,0xe6,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe5,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xe8,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe9,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x40,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x42,0x07,0x01,0x00,0x28,0x00,0x00,0x00, + 0x67,0x00,0x00,0x00,0x38,0x7f,0x00,0x00, + 0x9c,0x2b,0x00,0x00,0xe2,0x13,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x4c,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x4b,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x2d,0x00,0x00,0x00, + 0x29,0x10,0x00,0x08,0x90,0x01,0x00,0x00, + 0x00,0x00,0x00,0x00,0xea,0x08,0x01,0x00, + 0xac,0x00,0x00,0x00,0x14,0x00,0x00,0x00, + 0x2f,0x00,0x00,0x00,0x8d,0x00,0x00,0x00, + 0xea,0x00,0x00,0x00,0x48,0x01,0x00,0x00, + 0xd5,0x01,0x00,0x00,0x90,0x02,0x00,0x00, + 0x4c,0x03,0x00,0x00,0x07,0x04,0x00,0x00, + 0x21,0x05,0x00,0x00,0x98,0x06,0x00,0x00, + 0xca,0x08,0x00,0x00,0xb8,0x0b,0x00,0x00, + 0xa6,0x0e,0x00,0x00,0x50,0x12,0x00,0x00, + 0xb5,0x16,0x00,0x00,0xd5,0x1b,0x00,0x00, + 0x28,0x23,0x00,0x00,0xf2,0x2b,0x00,0x00, + 0x33,0x36,0x00,0x00,0xe8,0x4c,0x00,0x00, + 0x9d,0x00,0x00,0x00,0xa7,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xcb,0x00,0x00,0x00,0xbc,0x00,0x00,0x00, + 0xc0,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, + 0xcd,0x00,0x00,0x00,0xd5,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xd1,0x00,0x00,0x00, + 0xc1,0x00,0x00,0x00,0x9f,0x00,0x00,0x00, + 0x86,0x00,0x00,0x00,0x61,0x00,0x00,0x00, + 0x47,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0xa6,0xff,0xff,0xff,0xe5,0xfe,0xff,0xff, + 0x43,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x6a,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x68,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xe7,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x38,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x39,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x3a,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x50,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x01,0x00,0x00, + 0x36,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0xe4,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x57,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x3c,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x3d,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x3e,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0xff,0xff,0xff, + 0x3f,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0xff,0xff,0xff,0x48,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x76,0x74,0x6c,0x65,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x44,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x29,0x10,0x00,0x08,0x90,0x01,0x00,0x00, + 0x01,0x00,0x00,0x00,0xea,0x08,0x01,0x00, + 0xac,0x00,0x00,0x00,0x14,0x00,0x00,0x00, + 0x2f,0x00,0x00,0x00,0x8d,0x00,0x00,0x00, + 0xea,0x00,0x00,0x00,0x48,0x01,0x00,0x00, + 0xd5,0x01,0x00,0x00,0x90,0x02,0x00,0x00, + 0x4c,0x03,0x00,0x00,0x07,0x04,0x00,0x00, + 0x21,0x05,0x00,0x00,0x98,0x06,0x00,0x00, + 0xca,0x08,0x00,0x00,0xb8,0x0b,0x00,0x00, + 0xa6,0x0e,0x00,0x00,0x50,0x12,0x00,0x00, + 0xb5,0x16,0x00,0x00,0xd5,0x1b,0x00,0x00, + 0x28,0x23,0x00,0x00,0xf2,0x2b,0x00,0x00, + 0x33,0x36,0x00,0x00,0xe8,0x4c,0x00,0x00, + 0x9d,0x00,0x00,0x00,0xa7,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xcb,0x00,0x00,0x00,0xbc,0x00,0x00,0x00, + 0xc0,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, + 0xcd,0x00,0x00,0x00,0xd5,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xd1,0x00,0x00,0x00, + 0xc1,0x00,0x00,0x00,0x9f,0x00,0x00,0x00, + 0x86,0x00,0x00,0x00,0x61,0x00,0x00,0x00, + 0x47,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0xa6,0xff,0xff,0xff,0xe5,0xfe,0xff,0xff, + 0x43,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x6a,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x68,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xe7,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x38,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x39,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x3a,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x50,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x01,0x00,0x00, + 0x36,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0xe4,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x57,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x3c,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x3d,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x3e,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0xff,0xff,0xff, + 0x3f,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0xff,0xff,0xff,0x48,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x76,0x74,0x6c,0x65,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x44,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x28,0x10,0x00,0x08,0x54,0x04,0x00,0x00, + 0x02,0x00,0x00,0x00,0xeb,0x08,0x01,0x00, + 0xac,0x00,0x00,0x00,0x14,0x00,0x00,0x00, + 0x2f,0x00,0x00,0x00,0x8d,0x00,0x00,0x00, + 0xea,0x00,0x00,0x00,0x48,0x01,0x00,0x00, + 0xd5,0x01,0x00,0x00,0x90,0x02,0x00,0x00, + 0x4c,0x03,0x00,0x00,0x07,0x04,0x00,0x00, + 0x21,0x05,0x00,0x00,0x98,0x06,0x00,0x00, + 0xca,0x08,0x00,0x00,0xb8,0x0b,0x00,0x00, + 0xa6,0x0e,0x00,0x00,0x50,0x12,0x00,0x00, + 0xb5,0x16,0x00,0x00,0xd5,0x1b,0x00,0x00, + 0x28,0x23,0x00,0x00,0xf2,0x2b,0x00,0x00, + 0x33,0x36,0x00,0x00,0xe8,0x4c,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,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,0x00,0x00,0x00,0x00, + 0xe6,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xe5,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe8,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xe9,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x40,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x42,0x07,0x01,0x00, + 0x28,0x00,0x00,0x00,0x67,0x00,0x00,0x00, + 0x38,0x7f,0x00,0x00,0x9c,0x2b,0x00,0x00, + 0xe2,0x13,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x4c,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x4b,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x2d,0x00,0x00,0x00,0x29,0x10,0x00,0x08, + 0x90,0x01,0x00,0x00,0x00,0x00,0x00,0x00, + 0xea,0x08,0x01,0x00,0xac,0x00,0x00,0x00, + 0x14,0x00,0x00,0x00,0x2f,0x00,0x00,0x00, + 0x8d,0x00,0x00,0x00,0xea,0x00,0x00,0x00, + 0x48,0x01,0x00,0x00,0xd5,0x01,0x00,0x00, + 0x90,0x02,0x00,0x00,0x4c,0x03,0x00,0x00, + 0x07,0x04,0x00,0x00,0x21,0x05,0x00,0x00, + 0x98,0x06,0x00,0x00,0xca,0x08,0x00,0x00, + 0xb8,0x0b,0x00,0x00,0xa6,0x0e,0x00,0x00, + 0x50,0x12,0x00,0x00,0xb5,0x16,0x00,0x00, + 0xd5,0x1b,0x00,0x00,0x28,0x23,0x00,0x00, + 0xf2,0x2b,0x00,0x00,0x33,0x36,0x00,0x00, + 0xe8,0x4c,0x00,0x00,0x9d,0x00,0x00,0x00, + 0xa7,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xcb,0x00,0x00,0x00, + 0xbc,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, + 0xc0,0x00,0x00,0x00,0xcd,0x00,0x00,0x00, + 0xd5,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xd1,0x00,0x00,0x00,0xc1,0x00,0x00,0x00, + 0x9f,0x00,0x00,0x00,0x86,0x00,0x00,0x00, + 0x61,0x00,0x00,0x00,0x47,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0xa6,0xff,0xff,0xff, + 0xe5,0xfe,0xff,0xff,0x43,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x6a,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x68,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe7,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x38,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x39,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x3a,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x50,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x01,0x00,0x00,0x36,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xe4,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x57,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x3c,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x3d,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3e,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0xff,0xff,0xff,0x3f,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0xff,0xff,0xff, + 0x48,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x76,0x74,0x6c,0x65, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x44,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x29,0x10,0x00,0x08, + 0x90,0x01,0x00,0x00,0x01,0x00,0x00,0x00, + 0xea,0x08,0x01,0x00,0xac,0x00,0x00,0x00, + 0x14,0x00,0x00,0x00,0x2f,0x00,0x00,0x00, + 0x8d,0x00,0x00,0x00,0xea,0x00,0x00,0x00, + 0x48,0x01,0x00,0x00,0xd5,0x01,0x00,0x00, + 0x90,0x02,0x00,0x00,0x4c,0x03,0x00,0x00, + 0x07,0x04,0x00,0x00,0x21,0x05,0x00,0x00, + 0x98,0x06,0x00,0x00,0xca,0x08,0x00,0x00, + 0xb8,0x0b,0x00,0x00,0xa6,0x0e,0x00,0x00, + 0x50,0x12,0x00,0x00,0xb5,0x16,0x00,0x00, + 0xd5,0x1b,0x00,0x00,0x28,0x23,0x00,0x00, + 0xf2,0x2b,0x00,0x00,0x33,0x36,0x00,0x00, + 0xe8,0x4c,0x00,0x00,0x9d,0x00,0x00,0x00, + 0xa7,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xcb,0x00,0x00,0x00, + 0xbc,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, + 0xc0,0x00,0x00,0x00,0xcd,0x00,0x00,0x00, + 0xd5,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xd1,0x00,0x00,0x00,0xc1,0x00,0x00,0x00, + 0x9f,0x00,0x00,0x00,0x86,0x00,0x00,0x00, + 0x61,0x00,0x00,0x00,0x47,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0xa6,0xff,0xff,0xff, + 0xe5,0xfe,0xff,0xff,0x43,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x6a,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x68,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe7,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x38,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x39,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x3a,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x50,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x01,0x00,0x00,0x36,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xe4,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x57,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x3c,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x3d,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3e,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0xff,0xff,0xff,0x3f,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0xff,0xff,0xff, + 0x48,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x76,0x74,0x6c,0x65, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x44,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x28,0x10,0x00,0x08, + 0x54,0x04,0x00,0x00,0x03,0x00,0x00,0x00, + 0xeb,0x08,0x01,0x00,0xac,0x00,0x00,0x00, + 0x14,0x00,0x00,0x00,0x2f,0x00,0x00,0x00, + 0x8d,0x00,0x00,0x00,0xea,0x00,0x00,0x00, + 0x48,0x01,0x00,0x00,0xd5,0x01,0x00,0x00, + 0x90,0x02,0x00,0x00,0x4c,0x03,0x00,0x00, + 0x07,0x04,0x00,0x00,0x21,0x05,0x00,0x00, + 0x98,0x06,0x00,0x00,0xca,0x08,0x00,0x00, + 0xb8,0x0b,0x00,0x00,0xa6,0x0e,0x00,0x00, + 0x50,0x12,0x00,0x00,0xb5,0x16,0x00,0x00, + 0xd5,0x1b,0x00,0x00,0x28,0x23,0x00,0x00, + 0xf2,0x2b,0x00,0x00,0x33,0x36,0x00,0x00, + 0xe8,0x4c,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,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, + 0x00,0x00,0x00,0x00,0xe6,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe5,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xe8,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe9,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x40,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x42,0x07,0x01,0x00,0x28,0x00,0x00,0x00, + 0x23,0x00,0x00,0x00,0xff,0x7f,0x00,0x00, + 0xff,0x7f,0x00,0x00,0xff,0x7f,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x4c,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x4b,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x2d,0x00,0x00,0x00, + 0x29,0x10,0x00,0x08,0x90,0x01,0x00,0x00, + 0x00,0x00,0x00,0x00,0xea,0x08,0x01,0x00, + 0xac,0x00,0x00,0x00,0x14,0x00,0x00,0x00, + 0x2f,0x00,0x00,0x00,0x8d,0x00,0x00,0x00, + 0xea,0x00,0x00,0x00,0x48,0x01,0x00,0x00, + 0xd5,0x01,0x00,0x00,0x90,0x02,0x00,0x00, + 0x4c,0x03,0x00,0x00,0x07,0x04,0x00,0x00, + 0x21,0x05,0x00,0x00,0x98,0x06,0x00,0x00, + 0xca,0x08,0x00,0x00,0xb8,0x0b,0x00,0x00, + 0xa6,0x0e,0x00,0x00,0x50,0x12,0x00,0x00, + 0xb5,0x16,0x00,0x00,0xd5,0x1b,0x00,0x00, + 0x28,0x23,0x00,0x00,0xf2,0x2b,0x00,0x00, + 0x33,0x36,0x00,0x00,0xe8,0x4c,0x00,0x00, + 0x9d,0x00,0x00,0x00,0xa7,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xcb,0x00,0x00,0x00,0xbc,0x00,0x00,0x00, + 0xc0,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, + 0xcd,0x00,0x00,0x00,0xd5,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xd1,0x00,0x00,0x00, + 0xc1,0x00,0x00,0x00,0x9f,0x00,0x00,0x00, + 0x86,0x00,0x00,0x00,0x61,0x00,0x00,0x00, + 0x47,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0xa6,0xff,0xff,0xff,0xe5,0xfe,0xff,0xff, + 0x43,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x6a,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x68,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xe7,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x38,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x39,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x08,0x00,0x00,0x00, + 0x3a,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x50,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x01,0x00,0x00, + 0x36,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0xe4,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x57,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x3c,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x3d,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x3e,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0xff,0xff,0xff, + 0x3f,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0xff,0xff,0xff,0x48,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x76,0x74,0x6c,0x65,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x44,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x29,0x10,0x00,0x08,0x90,0x01,0x00,0x00, + 0x01,0x00,0x00,0x00,0xea,0x08,0x01,0x00, + 0xac,0x00,0x00,0x00,0x14,0x00,0x00,0x00, + 0x2f,0x00,0x00,0x00,0x8d,0x00,0x00,0x00, + 0xea,0x00,0x00,0x00,0x48,0x01,0x00,0x00, + 0xd5,0x01,0x00,0x00,0x90,0x02,0x00,0x00, + 0x4c,0x03,0x00,0x00,0x07,0x04,0x00,0x00, + 0x21,0x05,0x00,0x00,0x98,0x06,0x00,0x00, + 0xca,0x08,0x00,0x00,0xb8,0x0b,0x00,0x00, + 0xa6,0x0e,0x00,0x00,0x50,0x12,0x00,0x00, + 0xb5,0x16,0x00,0x00,0xd5,0x1b,0x00,0x00, + 0x28,0x23,0x00,0x00,0xf2,0x2b,0x00,0x00, + 0x33,0x36,0x00,0x00,0xe8,0x4c,0x00,0x00, + 0x9d,0x00,0x00,0x00,0xa7,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0xcb,0x00,0x00,0x00,0xbc,0x00,0x00,0x00, + 0xc0,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, + 0xcd,0x00,0x00,0x00,0xd5,0x00,0x00,0x00, + 0xda,0x00,0x00,0x00,0xd1,0x00,0x00,0x00, + 0xc1,0x00,0x00,0x00,0x9f,0x00,0x00,0x00, + 0x86,0x00,0x00,0x00,0x61,0x00,0x00,0x00, + 0x47,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0xa6,0xff,0xff,0xff,0xe5,0xfe,0xff,0xff, + 0x43,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x6a,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x68,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xe7,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x38,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x39,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x08,0x00,0x00,0x00, + 0x3a,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x50,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x01,0x00,0x00, + 0x36,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0xe4,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x57,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x3c,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x3d,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x3e,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0xff,0xff,0xff, + 0x3f,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0xff,0xff,0xff,0x48,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x76,0x74,0x6c,0x65,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x44,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x30,0x10,0x00,0x08,0xb0,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xec,0x08,0x01,0x00,0x00,0x01,0x00,0x00, + 0x14,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x2f,0x00,0x00,0x00,0x8d,0x00,0x00,0x00, + 0xea,0x00,0x00,0x00,0x48,0x01,0x00,0x00, + 0xd5,0x01,0x00,0x00,0x90,0x02,0x00,0x00, + 0x4c,0x03,0x00,0x00,0x07,0x04,0x00,0x00, + 0x21,0x05,0x00,0x00,0x98,0x06,0x00,0x00, + 0xca,0x08,0x00,0x00,0xb8,0x0b,0x00,0x00, + 0xa6,0x0e,0x00,0x00,0x50,0x12,0x00,0x00, + 0xb5,0x16,0x00,0x00,0xd5,0x1b,0x00,0x00, + 0x28,0x23,0x00,0x00,0xf2,0x2b,0x00,0x00, + 0x33,0x36,0x00,0x00,0xe8,0x4c,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,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,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,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,0x00,0x00,0x00,0x00,0x00,0x00, + 0xf5,0x08,0x01,0x00,0x4c,0x01,0x00,0x00, + 0x14,0x00,0x00,0x00,0x2f,0x00,0x00,0x00, + 0x8d,0x00,0x00,0x00,0xea,0x00,0x00,0x00, + 0x48,0x01,0x00,0x00,0xd5,0x01,0x00,0x00, + 0x90,0x02,0x00,0x00,0x4c,0x03,0x00,0x00, + 0x07,0x04,0x00,0x00,0x21,0x05,0x00,0x00, + 0x98,0x06,0x00,0x00,0xca,0x08,0x00,0x00, + 0xb8,0x0b,0x00,0x00,0xa6,0x0e,0x00,0x00, + 0x50,0x12,0x00,0x00,0xb5,0x16,0x00,0x00, + 0xd5,0x1b,0x00,0x00,0x28,0x23,0x00,0x00, + 0xf2,0x2b,0x00,0x00,0x33,0x36,0x00,0x00, + 0xe8,0x4c,0x00,0x00,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,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,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,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,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, + 0x00,0x00,0x00,0x00,0xed,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x4a,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x49,0x07,0x01,0x00, + 0x28,0x00,0x00,0x00,0x67,0x00,0x00,0x00, + 0x38,0x7f,0x00,0x00,0x2a,0x1a,0x00,0x00, + 0xe2,0x13,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x64,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x65,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x0c,0x00,0x00,0x00,0xf6,0x08,0x01,0x00, + 0x1c,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00, + 0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00, + 0x63,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x5b,0x07,0x01,0x00, + 0x48,0x01,0x00,0x00,0x01,0x00,0x00,0x00, + 0xc0,0xf9,0xff,0xff,0x00,0x00,0x00,0x00, + 0xa0,0xfb,0xff,0xff,0x70,0xfe,0xff,0xff, + 0x10,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xc0,0xf9,0xff,0xff,0x00,0x00,0x00,0x00, + 0xa0,0xfb,0xff,0xff,0x70,0xfe,0xff,0xff, + 0x10,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xc0,0xf9,0xff,0xff,0x00,0x00,0x00,0x00, + 0xa0,0xfb,0xff,0xff,0x70,0xfe,0xff,0xff, + 0x10,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xc0,0xf9,0xff,0xff,0x00,0x00,0x00,0x00, + 0xa0,0xfb,0xff,0xff,0x70,0xfe,0xff,0xff, + 0x10,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xc0,0xf9,0xff,0xff,0x00,0x00,0x00,0x00, + 0xa0,0xfb,0xff,0xff,0x70,0xfe,0xff,0xff, + 0x10,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xc0,0xf9,0xff,0xff,0x00,0x00,0x00,0x00, + 0xa0,0xfb,0xff,0xff,0x70,0xfe,0xff,0xff, + 0x10,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xc0,0xf9,0xff,0xff,0x00,0x00,0x00,0x00, + 0xa0,0xfb,0xff,0xff,0x70,0xfe,0xff,0xff, + 0x10,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xc0,0xf9,0xff,0xff,0x00,0x00,0x00,0x00, + 0xa0,0xfb,0xff,0xff,0x70,0xfe,0xff,0xff, + 0x10,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xe1,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0xe3,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x0a,0x00,0x00,0x00,0xe2,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x41,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x59,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x3b,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xf4,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xf7,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x5a,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x30,0x10,0x00,0x08,0x68,0x03,0x00,0x00, + 0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xec,0x08,0x01,0x00,0x00,0x01,0x00,0x00, + 0x14,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x2f,0x00,0x00,0x00,0x8d,0x00,0x00,0x00, + 0xea,0x00,0x00,0x00,0x48,0x01,0x00,0x00, + 0xd5,0x01,0x00,0x00,0x90,0x02,0x00,0x00, + 0x4c,0x03,0x00,0x00,0x07,0x04,0x00,0x00, + 0x21,0x05,0x00,0x00,0x98,0x06,0x00,0x00, + 0xca,0x08,0x00,0x00,0xb8,0x0b,0x00,0x00, + 0xa6,0x0e,0x00,0x00,0x50,0x12,0x00,0x00, + 0xb5,0x16,0x00,0x00,0xd5,0x1b,0x00,0x00, + 0x28,0x23,0x00,0x00,0xf2,0x2b,0x00,0x00, + 0x33,0x36,0x00,0x00,0xe8,0x4c,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,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,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,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,0x00,0x00,0x00,0x00,0x00,0x00, + 0xf5,0x08,0x01,0x00,0x4c,0x01,0x00,0x00, + 0x14,0x00,0x00,0x00,0x2f,0x00,0x00,0x00, + 0x8d,0x00,0x00,0x00,0xea,0x00,0x00,0x00, + 0x48,0x01,0x00,0x00,0xd5,0x01,0x00,0x00, + 0x90,0x02,0x00,0x00,0x4c,0x03,0x00,0x00, + 0x07,0x04,0x00,0x00,0x21,0x05,0x00,0x00, + 0x98,0x06,0x00,0x00,0xca,0x08,0x00,0x00, + 0xb8,0x0b,0x00,0x00,0xa6,0x0e,0x00,0x00, + 0x50,0x12,0x00,0x00,0xb5,0x16,0x00,0x00, + 0xd5,0x1b,0x00,0x00,0x28,0x23,0x00,0x00, + 0xf2,0x2b,0x00,0x00,0x33,0x36,0x00,0x00, + 0xe8,0x4c,0x00,0x00,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,0x40,0xff,0xff,0xff, + 0x40,0xff,0xff,0xff,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,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,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,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, + 0x00,0x00,0x00,0x00,0xed,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x4a,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x49,0x07,0x01,0x00, + 0x28,0x00,0x00,0x00,0x67,0x00,0x00,0x00, + 0x38,0x7f,0x00,0x00,0x2a,0x1a,0x00,0x00, + 0xe2,0x13,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x64,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x65,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x0c,0x00,0x00,0x00,0xf6,0x08,0x01,0x00, + 0x1c,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00, + 0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00, + 0x63,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0xe1,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0xe3,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x0a,0x00,0x00,0x00,0xe2,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x41,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0xa0,0x00,0x00,0x00,0x59,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3b,0x07,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xf4,0x08,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xf7,0x08,0x01,0x00,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x5a,0x07,0x01,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x26,0x10,0x00,0x08,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x28,0x10,0x00,0x08, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x32,0x10,0x00,0x08,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x31,0x10,0x00,0x08, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x34,0x10,0x00,0x08,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00" +} \ No newline at end of file diff --git a/tools/topology/topology2/include/components/decoder.conf b/tools/topology/topology2/include/components/decoder.conf new file mode 100644 index 000000000000..b01a1c56d050 --- /dev/null +++ b/tools/topology/topology2/include/components/decoder.conf @@ -0,0 +1,63 @@ +# +# Decoder widget component definition +# +# A generic decoder widget. All attributes defined herein are namespaced +# by alsatplg to "Object.Widget.decoder.N.attribute_name" +# +# Usage: this component can be used by declaring in a parent object. i.e. +# +# Object.Widget.decoder."N" { +# index 1 +# no_pm "true" +# } +# +# Where N is the unique instance number for decoder widget in the same alsaconf node. + +Class.Widget."decoder" { + # + # Pipeline ID for the decoder widget object + # + DefineAttribute."index" {} + + # + # decoder object instance + # + DefineAttribute."instance" {} + + #include common component definition + <include/components/widget-common.conf> + + # Attribute categories + attributes { + # + # The decoder widget name would be constructed using the index and instance attributes. + # For ex: "decoder.1.1" or "decoder.10.2" etc. + # + !constructor [ + "index" + "instance" + ] + + # + # immutable attributes cannot be modified in the object instance + # + !immutable [ + "type" + ] + + # + # decoder widget objects instantiated within the same alsaconf node must have unique + # instance attribute + # + unique "instance" + } + + # Default attribute values for decoder widget + type "decoder" + + # cadence codec UUID + uuid "43:84:21:d8:f3:5f:4c:4a:b3:88:6c:fe:07:b9:56:aa" + no_pm "true" + num_output_pins 1 + num_input_pins 1 +} diff --git a/tools/topology/topology2/include/components/dolby-dax.conf b/tools/topology/topology2/include/components/dolby-dax.conf new file mode 100644 index 000000000000..87b317da0261 --- /dev/null +++ b/tools/topology/topology2/include/components/dolby-dax.conf @@ -0,0 +1,164 @@ +<include/controls/mixer.conf> +<include/controls/enum.conf> + +Class.Widget."dolby-dax" { + DefineAttribute."index" { + type "integer" + } + + DefineAttribute."instance" { + type "integer" + } + + <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" + } + + Object.Control { + # Enable/Disable DAX module + mixer."1" { + Object.Base.channel.1 { + name "fc" + } + Object.Base.ops.1 { + name "ctl" + info "volsw" + ## get = 259 binds the mixer control to switch get/put handlers + get 259 + put 259 + } + + #max 1 indicates switch type control + max 1 + } + # Enable/Disable DAX content processing feature + mixer."2" { + Object.Base.channel.1 { + name "fc" + } + Object.Base.ops.1 { + name "ctl" + info "volsw" + ## get = 259 binds the mixer control to switch get/put handlers + get 259 + put 259 + } + + #max 1 indicates switch type control + max 1 + } + # Enable/Disable DAX crosstalk cancellation feature + mixer."3" { + Object.Base.channel.1 { + name "fc" + } + Object.Base.ops.1 { + name "ctl" + info "volsw" + ## get = 259 binds the mixer control to switch get/put handlers + get 259 + put 259 + } + + #max 1 indicates switch type control + max 1 + } + # Set volume to DAX module, range from 0 to 25 + mixer."4" { + Object.Base.channel.1 { + name "fc" + } + Object.Base.ops.1 { + name "ctl" + info "volsw" + get 256 + put 256 + } + max 25 + + Object.Base.tlv.1 { + name "vtlv_m50s200" + Object.Base.scale.1 { + name m0s131072 + min -5000 + step 200 + } + } + } + # Set profile to DAX module + enum."1" { + Object.Base { + channel.1 { + name "fc" + } + text.0 { + name "profiles" + !values [ + "0" # dynamic + "1" # movie + "2" # music + "3" # voice + ] + } + ops.1 { + name "ctl" + info "enum" + #257 binds the mixer control to enum get/put handlers + get 257 + put 257 + } + } + } + # Set output device to DAX module + enum."2" { + Object.Base { + channel.1 { + name "fc" + } + text.0 { + name "devices" + !values [ + "0" # speaker + "1" # 3.5mm wired headphone + ] + } + ops.1 { + name "ctl" + info "enum" + #257 binds the mixer control to enum get/put handlers + get 257 + put 257 + } + } + } + # Set binary effect parameters to DAX module + bytes."1" {} + } + + uuid "8b:6c:f6:40:a5:5a:45:43:89:19:53:ec:43:1a:aa:98" + type "effect" + no_pm "true" + cpc 675000 + num_input_pins 1 + num_output_pins 1 +} diff --git a/tools/topology/topology2/include/components/encoder.conf b/tools/topology/topology2/include/components/encoder.conf new file mode 100644 index 000000000000..cde2346e3885 --- /dev/null +++ b/tools/topology/topology2/include/components/encoder.conf @@ -0,0 +1,63 @@ +# +# Encoder widget component definition +# +# A generic encoder widget. All attributes defined herein are namespaced +# by alsatplg to "Object.Widget.encoder.N.attribute_name" +# +# Usage: this component can be used by declaring in a parent object. i.e. +# +# Object.Widget.encoder."N" { +# index 1 +# no_pm "true" +# } +# +# Where N is the unique instance number for encoder widget in the same alsaconf node. + +Class.Widget."encoder" { + # + # Pipeline ID for the encoder widget object + # + DefineAttribute."index" {} + + # + # encoder object instance + # + DefineAttribute."instance" {} + + #include common component definition + <include/components/widget-common.conf> + + # Attribute categories + attributes { + # + # The encoder widget name would be constructed using the index and instance attributes. + # For ex: "encoder.1.1" or "encoder.10.2" etc. + # + !constructor [ + "index" + "instance" + ] + + # + # immutable attributes cannot be modified in the object instance + # + !immutable [ + "type" + ] + + # + # encoder widget objects instantiated within the same alsaconf node must have unique + # instance attribute + # + unique "instance" + } + + # Default attribute values for encoder widget + type "encoder" + + # cadence codec UUID + uuid "43:84:21:d8:f3:5f:4c:4a:b3:88:6c:fe:07:b9:56:aa" + no_pm "true" + num_output_pins 1 + num_input_pins 1 +} diff --git a/tools/topology/topology2/include/components/eqiir/highpass_100hz_16db_16khz.conf b/tools/topology/topology2/include/components/eqiir/highpass_100hz_16db_16khz.conf new file mode 100644 index 000000000000..264bf3f13431 --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/highpass_100hz_16db_16khz.conf @@ -0,0 +1,20 @@ +# 100 Hz second order high-pass, gain 16 dB, created with sof_example_iir_eq.m 04-Feb-2026 +# cd src/audio/eq_iir/tune; octave --no-window-system sof_example_iir_eq.m +Object.Base.data."iir_eq" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xf5,0x18,0x75,0xc3, + 0x6b,0x52,0x72,0x7c,0x6e,0x92,0x32,0x1f, + 0x24,0xdb,0x9a,0xc1,0x6e,0x92,0x32,0x1f, + 0xfd,0xff,0xff,0xff,0xb8,0x64,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/highpass_100hz_16db_48khz.conf b/tools/topology/topology2/include/components/eqiir/highpass_100hz_16db_48khz.conf new file mode 100644 index 000000000000..856f1cd6328c --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/highpass_100hz_16db_48khz.conf @@ -0,0 +1,20 @@ +# 100 Hz second order high-pass, gain 16 dB, created with sof_example_iir_eq.m 04-Feb-2026 +# cd src/audio/eq_iir/tune; octave --no-window-system sof_example_iir_eq.m +Object.Base.data."iir_eq" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xbd,0x82,0x2c,0xc1, + 0x2e,0xb5,0xd0,0x7e,0x0c,0xcc,0xc7,0x1f, + 0xe9,0x67,0x70,0xc0,0x0c,0xcc,0xc7,0x1f, + 0xfd,0xff,0xff,0xff,0xb8,0x64,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/highpass_20hz_16db_16khz.conf b/tools/topology/topology2/include/components/eqiir/highpass_20hz_16db_16khz.conf new file mode 100644 index 000000000000..0f84b2c22601 --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/highpass_20hz_16db_16khz.conf @@ -0,0 +1,20 @@ +# 20 Hz second order high-pass, gain 16 dB, created with sof_example_iir_eq.m 04-Feb-2026 +# cd src/audio/eq_iir/tune; octave --no-window-system sof_example_iir_eq.m +Object.Base.data."iir_eq" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x3c,0xf9,0xb4,0xc0, + 0x79,0x05,0x4a,0x7f,0x92,0xf9,0xe5,0x1f, + 0xdc,0x0c,0x34,0xc0,0x92,0xf9,0xe5,0x1f, + 0xfd,0xff,0xff,0xff,0xb7,0x64,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/highpass_20hz_16db_48khz.conf b/tools/topology/topology2/include/components/eqiir/highpass_20hz_16db_48khz.conf new file mode 100644 index 000000000000..5a57e789c335 --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/highpass_20hz_16db_48khz.conf @@ -0,0 +1,20 @@ +# 20 Hz second order high-pass, gain 16 dB, created with sof_example_iir_eq.m 04-Feb-2026 +# cd src/audio/eq_iir/tune; octave --no-window-system sof_example_iir_eq.m +Object.Base.data."iir_eq" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x4a,0x8c,0x3c,0xc0, + 0x04,0x57,0xc3,0x7f,0xc0,0x43,0x04,0x20, + 0x80,0x78,0xf7,0xbf,0xc0,0x43,0x04,0x20, + 0xfd,0xff,0xff,0xff,0xb7,0x64,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/highpass_30hz_16db_16khz.conf b/tools/topology/topology2/include/components/eqiir/highpass_30hz_16db_16khz.conf new file mode 100644 index 000000000000..f1e2369164d4 --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/highpass_30hz_16db_16khz.conf @@ -0,0 +1,20 @@ +# 30 Hz second order high-pass, gain 16 dB, created with sof_example_iir_eq.m 04-Feb-2026 +# cd src/audio/eq_iir/tune; octave --no-window-system sof_example_iir_eq.m +Object.Base.data."iir_eq" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x98,0xb5,0x0e,0xc1, + 0x17,0x09,0xef,0x7e,0xbf,0x54,0xcf,0x1f, + 0x82,0x56,0x61,0xc0,0xbf,0x54,0xcf,0x1f, + 0xfd,0xff,0xff,0xff,0xb7,0x64,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/highpass_30hz_16db_48khz.conf b/tools/topology/topology2/include/components/eqiir/highpass_30hz_16db_48khz.conf new file mode 100644 index 000000000000..490ac534dec7 --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/highpass_30hz_16db_48khz.conf @@ -0,0 +1,20 @@ +# 30 Hz second order high-pass, gain 16 dB, created with sof_example_iir_eq.m 04-Feb-2026 +# cd src/audio/eq_iir/tune; octave --no-window-system sof_example_iir_eq.m +Object.Base.data."iir_eq" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xf1,0xbc,0x5a,0xc0, + 0x8f,0x02,0xa5,0x7f,0x83,0xae,0xfc,0x1f, + 0xfa,0xa2,0x06,0xc0,0x83,0xae,0xfc,0x1f, + 0xfd,0xff,0xff,0xff,0xb7,0x64,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/highpass_40hz_16db_16khz.conf b/tools/topology/topology2/include/components/eqiir/highpass_40hz_16db_16khz.conf new file mode 100644 index 000000000000..54e8d8b37839 --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/highpass_40hz_16db_16khz.conf @@ -0,0 +1,20 @@ +# 40 Hz second order high-pass, gain 16 dB, created with sof_example_iir_eq.m 04-Feb-2026 +# cd src/audio/eq_iir/tune; octave --no-window-system sof_example_iir_eq.m +Object.Base.data."iir_eq" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xba,0xf2,0x67,0xc1, + 0xc3,0x0d,0x94,0x7e,0xff,0xbf,0xb8,0x1f, + 0x03,0x80,0x8e,0xc0,0xff,0xbf,0xb8,0x1f, + 0xfd,0xff,0xff,0xff,0xb7,0x64,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/highpass_40hz_16db_48khz.conf b/tools/topology/topology2/include/components/eqiir/highpass_40hz_16db_48khz.conf new file mode 100644 index 000000000000..1fbc3f74740a --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/highpass_40hz_16db_48khz.conf @@ -0,0 +1,20 @@ +# 40 Hz second order high-pass, gain 16 dB, created with sof_example_iir_eq.m 04-Feb-2026 +# cd src/audio/eq_iir/tune; octave --no-window-system sof_example_iir_eq.m +Object.Base.data."iir_eq" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x4c,0xdf,0x78,0xc0, + 0x23,0xae,0x86,0x7f,0x12,0x1b,0xf5,0x1f, + 0xdb,0xc9,0x15,0xc0,0x12,0x1b,0xf5,0x1f, + 0xfd,0xff,0xff,0xff,0xb7,0x64,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/highpass_50hz_16db_16khz.conf b/tools/topology/topology2/include/components/eqiir/highpass_50hz_16db_16khz.conf new file mode 100644 index 000000000000..431a8f1c9335 --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/highpass_50hz_16db_16khz.conf @@ -0,0 +1,20 @@ +# 50 Hz second order high-pass, gain 16 dB, created with sof_example_iir_eq.m 04-Feb-2026 +# cd src/audio/eq_iir/tune; octave --no-window-system sof_example_iir_eq.m +Object.Base.data."iir_eq" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x57,0xb1,0xc0,0xc1, + 0xd2,0x13,0x39,0x7e,0x45,0x3b,0xa2,0x1f, + 0x76,0x89,0xbb,0xc0,0x45,0x3b,0xa2,0x1f, + 0xfd,0xff,0xff,0xff,0xb7,0x64,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/highpass_50hz_16db_48khz.conf b/tools/topology/topology2/include/components/eqiir/highpass_50hz_16db_48khz.conf new file mode 100644 index 000000000000..29e57256981f --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/highpass_50hz_16db_48khz.conf @@ -0,0 +1,20 @@ +# 50 Hz second order high-pass, gain 16 dB, created with sof_example_iir_eq.m 04-Feb-2026 +# cd src/audio/eq_iir/tune; octave --no-window-system sof_example_iir_eq.m +Object.Base.data."iir_eq" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x58,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x63,0xf3,0x96,0xc0, + 0xc6,0x59,0x68,0x7f,0x6d,0x89,0xed,0x1f, + 0x27,0xed,0x24,0xc0,0x6d,0x89,0xed,0x1f, + 0xfd,0xff,0xff,0xff,0xb7,0x64,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/xover_lr4_2000hz_hhll_48khz.conf b/tools/topology/topology2/include/components/eqiir/xover_lr4_2000hz_hhll_48khz.conf new file mode 100644 index 000000000000..8338a33decb2 --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/xover_lr4_2000hz_hhll_48khz.conf @@ -0,0 +1,35 @@ +# LR4 filter bank coefficients 08-Sep-2025 +# cd src/audio/eq_iir/tune; octave sof_example_lr4.m +Object.Base.data."IIR" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0xcc,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xcc,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x2d,0x3a,0xcd,0xd3, + 0xc0,0xf5,0x82,0x68,0xb9,0x41,0x76,0x00, + 0x72,0x83,0xec,0x00,0xb9,0x41,0x76,0x00, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x2d,0x3a,0xcd,0xd3,0xc0,0xf5,0x82,0x68, + 0xb9,0x41,0x76,0x00,0x72,0x83,0xec,0x00, + 0xb9,0x41,0x76,0x00,0xff,0xff,0xff,0xff, + 0x65,0x7f,0x00,0x00,0x02,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x7e,0x70,0xdd,0xd6, + 0xc0,0xf5,0x82,0x68,0xb6,0x9e,0x44,0x1a, + 0x94,0xc2,0x76,0xcb,0xb6,0x9e,0x44,0x1a, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x7e,0x70,0xdd,0xd6,0xc0,0xf5,0x82,0x68, + 0xb6,0x9e,0x44,0x1a,0x94,0xc2,0x76,0xcb, + 0xb6,0x9e,0x44,0x1a,0xfe,0xff,0xff,0xff, + 0x92,0x41,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/xover_lr4_2000hz_lhlh_48khz.conf b/tools/topology/topology2/include/components/eqiir/xover_lr4_2000hz_lhlh_48khz.conf new file mode 100644 index 000000000000..a7c04f3372a7 --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/xover_lr4_2000hz_lhlh_48khz.conf @@ -0,0 +1,35 @@ +# LR4 filter bank coefficients 08-Sep-2025 +# cd src/audio/eq_iir/tune; octave sof_example_lr4.m +Object.Base.data."IIR" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0xcc,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xcc,0x00,0x00,0x00,0x04,0x00,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, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x2d,0x3a,0xcd,0xd3, + 0xc0,0xf5,0x82,0x68,0xb9,0x41,0x76,0x00, + 0x72,0x83,0xec,0x00,0xb9,0x41,0x76,0x00, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x2d,0x3a,0xcd,0xd3,0xc0,0xf5,0x82,0x68, + 0xb9,0x41,0x76,0x00,0x72,0x83,0xec,0x00, + 0xb9,0x41,0x76,0x00,0xff,0xff,0xff,0xff, + 0x65,0x7f,0x00,0x00,0x02,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x7e,0x70,0xdd,0xd6, + 0xc0,0xf5,0x82,0x68,0xb6,0x9e,0x44,0x1a, + 0x94,0xc2,0x76,0xcb,0xb6,0x9e,0x44,0x1a, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x7e,0x70,0xdd,0xd6,0xc0,0xf5,0x82,0x68, + 0xb6,0x9e,0x44,0x1a,0x94,0xc2,0x76,0xcb, + 0xb6,0x9e,0x44,0x1a,0xfe,0xff,0xff,0xff, + 0x92,0x41,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/eqiir/xover_lr4_2000hz_llhh_48khz.conf b/tools/topology/topology2/include/components/eqiir/xover_lr4_2000hz_llhh_48khz.conf new file mode 100644 index 000000000000..8612f617c9be --- /dev/null +++ b/tools/topology/topology2/include/components/eqiir/xover_lr4_2000hz_llhh_48khz.conf @@ -0,0 +1,35 @@ +# LR4 filter bank coefficients 08-Sep-2025 +# cd src/audio/eq_iir/tune; octave sof_example_lr4.m +Object.Base.data."IIR" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0xcc,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xcc,0x00,0x00,0x00,0x04,0x00,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,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x2d,0x3a,0xcd,0xd3, + 0xc0,0xf5,0x82,0x68,0xb9,0x41,0x76,0x00, + 0x72,0x83,0xec,0x00,0xb9,0x41,0x76,0x00, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x2d,0x3a,0xcd,0xd3,0xc0,0xf5,0x82,0x68, + 0xb9,0x41,0x76,0x00,0x72,0x83,0xec,0x00, + 0xb9,0x41,0x76,0x00,0xff,0xff,0xff,0xff, + 0x65,0x7f,0x00,0x00,0x02,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x7e,0x70,0xdd,0xd6, + 0xc0,0xf5,0x82,0x68,0xb6,0x9e,0x44,0x1a, + 0x94,0xc2,0x76,0xcb,0xb6,0x9e,0x44,0x1a, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x7e,0x70,0xdd,0xd6,0xc0,0xf5,0x82,0x68, + 0xb6,0x9e,0x44,0x1a,0x94,0xc2,0x76,0xcb, + 0xb6,0x9e,0x44,0x1a,0xfe,0xff,0xff,0xff, + 0x92,0x41,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/level_multiplier.conf b/tools/topology/topology2/include/components/level_multiplier.conf new file mode 100644 index 000000000000..784abe4a6bb7 --- /dev/null +++ b/tools/topology/topology2/include/components/level_multiplier.conf @@ -0,0 +1,65 @@ +# +# +# A generic level_multiplier component. All attributes defined herein are namespaced +# by alsatplg to "Object.Widget.level_multiplier.attribute_name" +# +# Usage: this component can be used by declaring in the parent object. i.e. +# +# Object.Widget.level_multiplier."N" { +# index 1 +# } +# } + +# +# Where M is pipeline ID and N is a unique integer in the parent object. + +Class.Widget."level_multiplier" { + # + # Pipeline ID + # + DefineAttribute."index" { + type "integer" + } + + # + # Unique instance for 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 level_multiplier + # + # 30397456-4661-4644-97e5-39a9e5ab1778 + uuid "56:74:39:30:61:46:44:46:97:e5:39:a9:e5:ab:17:78" + type "effect" + no_pm "true" + num_input_pins 1 + num_output_pins 1 +} diff --git a/tools/topology/topology2/include/components/level_multiplier/gain_-10_db.conf b/tools/topology/topology2/include/components/level_multiplier/gain_-10_db.conf new file mode 100644 index 000000000000..7c1407a75f68 --- /dev/null +++ b/tools/topology/topology2/include/components/level_multiplier/gain_-10_db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_level_multiplier_blobs.m 19-Aug-2025 +# cd tools/tune/level_multiplier; octave sof_level_multiplier_blobs.m +Object.Base.data."level_multiplier_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x01,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x27,0x7a,0x28,0x00" +} diff --git a/tools/topology/topology2/include/components/level_multiplier/gain_-20_db.conf b/tools/topology/topology2/include/components/level_multiplier/gain_-20_db.conf new file mode 100644 index 000000000000..8c962a9a6c4d --- /dev/null +++ b/tools/topology/topology2/include/components/level_multiplier/gain_-20_db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_level_multiplier_blobs.m 19-Aug-2025 +# cd tools/tune/level_multiplier; octave sof_level_multiplier_blobs.m +Object.Base.data."level_multiplier_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x01,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xcd,0xcc,0x0c,0x00" +} diff --git a/tools/topology/topology2/include/components/level_multiplier/gain_-30_db.conf b/tools/topology/topology2/include/components/level_multiplier/gain_-30_db.conf new file mode 100644 index 000000000000..5f4d179ff1b0 --- /dev/null +++ b/tools/topology/topology2/include/components/level_multiplier/gain_-30_db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_level_multiplier_blobs.m 19-Aug-2025 +# cd tools/tune/level_multiplier; octave sof_level_multiplier_blobs.m +Object.Base.data."level_multiplier_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x01,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x37,0x0c,0x04,0x00" +} diff --git a/tools/topology/topology2/include/components/level_multiplier/gain_-40_db.conf b/tools/topology/topology2/include/components/level_multiplier/gain_-40_db.conf new file mode 100644 index 000000000000..5f17d0c3c15b --- /dev/null +++ b/tools/topology/topology2/include/components/level_multiplier/gain_-40_db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_level_multiplier_blobs.m 19-Aug-2025 +# cd tools/tune/level_multiplier; octave sof_level_multiplier_blobs.m +Object.Base.data."level_multiplier_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x01,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xae,0x47,0x01,0x00" +} diff --git a/tools/topology/topology2/include/components/level_multiplier/gain_0_db.conf b/tools/topology/topology2/include/components/level_multiplier/gain_0_db.conf new file mode 100644 index 000000000000..dcdf92a889df --- /dev/null +++ b/tools/topology/topology2/include/components/level_multiplier/gain_0_db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_level_multiplier_blobs.m 19-Aug-2025 +# cd tools/tune/level_multiplier; octave sof_level_multiplier_blobs.m +Object.Base.data."level_multiplier_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x01,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x80,0x00" +} diff --git a/tools/topology/topology2/include/components/level_multiplier/gain_10_db.conf b/tools/topology/topology2/include/components/level_multiplier/gain_10_db.conf new file mode 100644 index 000000000000..981d8c8996a0 --- /dev/null +++ b/tools/topology/topology2/include/components/level_multiplier/gain_10_db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_level_multiplier_blobs.m 19-Aug-2025 +# cd tools/tune/level_multiplier; octave sof_level_multiplier_blobs.m +Object.Base.data."level_multiplier_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x01,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x84,0xc5,0x94,0x01" +} diff --git a/tools/topology/topology2/include/components/level_multiplier/gain_20_db.conf b/tools/topology/topology2/include/components/level_multiplier/gain_20_db.conf new file mode 100644 index 000000000000..bffe8376ab90 --- /dev/null +++ b/tools/topology/topology2/include/components/level_multiplier/gain_20_db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_level_multiplier_blobs.m 19-Aug-2025 +# cd tools/tune/level_multiplier; octave sof_level_multiplier_blobs.m +Object.Base.data."level_multiplier_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x01,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x05" +} diff --git a/tools/topology/topology2/include/components/level_multiplier/gain_30_db.conf b/tools/topology/topology2/include/components/level_multiplier/gain_30_db.conf new file mode 100644 index 000000000000..804145ae4c07 --- /dev/null +++ b/tools/topology/topology2/include/components/level_multiplier/gain_30_db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_level_multiplier_blobs.m 19-Aug-2025 +# cd tools/tune/level_multiplier; octave sof_level_multiplier_blobs.m +Object.Base.data."level_multiplier_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x01,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x25,0xb7,0xcf,0x0f" +} diff --git a/tools/topology/topology2/include/components/level_multiplier/gain_40_db.conf b/tools/topology/topology2/include/components/level_multiplier/gain_40_db.conf new file mode 100644 index 000000000000..063e3ede5399 --- /dev/null +++ b/tools/topology/topology2/include/components/level_multiplier/gain_40_db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_level_multiplier_blobs.m 19-Aug-2025 +# cd tools/tune/level_multiplier; octave sof_level_multiplier_blobs.m +Object.Base.data."level_multiplier_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x01,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x32" +} diff --git a/tools/topology/topology2/include/components/mfcc.conf b/tools/topology/topology2/include/components/mfcc.conf index 221df8f2d437..bf908e685048 100644 --- a/tools/topology/topology2/include/components/mfcc.conf +++ b/tools/topology/topology2/include/components/mfcc.conf @@ -13,6 +13,8 @@ # # Where M is pipeline ID and N is a unique integer in the parent object. +<include/controls/mixer.conf> + Class.Widget."mfcc" { # # Pipeline ID @@ -45,7 +47,6 @@ Class.Widget."mfcc" { !immutable [ "uuid" - "type" ] !deprecated [ "preload_count" @@ -53,6 +54,26 @@ Class.Widget."mfcc" { unique "instance" } + # + # MFCC Widget switch control to optionally notify VAD state changes + # + 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 mfcc # diff --git a/tools/topology/topology2/include/components/mfcc/ceps13_compress_dtx.conf b/tools/topology/topology2/include/components/mfcc/ceps13_compress_dtx.conf new file mode 100644 index 000000000000..7056b9e7cb4b --- /dev/null +++ b/tools/topology/topology2/include/components/mfcc/ceps13_compress_dtx.conf @@ -0,0 +1,24 @@ +# Exported MFCC configuration 26-May-2026 +# cd src/audio/mfcc/tune; octave setup_mfcc.m +Object.Base.data."mfcc_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x74,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x14,0x00,0xf4,0x01, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0x3e,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xc3,0x35,0x00,0x2c,0x00,0x00,0x00,0x00, + 0x90,0x01,0xa0,0x00,0x00,0x00,0x14,0x00, + 0x0d,0x00,0x17,0x00,0x00,0x00,0x00,0x64, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01, + 0x01,0x00,0x00,0x00,0x01,0x01,0x01,0x01, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/mfcc/default.conf b/tools/topology/topology2/include/components/mfcc/default.conf index 1f9141886de9..0ac19fa71d04 100644 --- a/tools/topology/topology2/include/components/mfcc/default.conf +++ b/tools/topology/topology2/include/components/mfcc/default.conf @@ -1,12 +1,12 @@ -# Exported MFCC configuration 24-Jul-2024 -# cd tools/tune/mfcc; octave setup_mfcc.m +# Exported MFCC configuration 26-May-2026 +# cd src/audio/mfcc/tune; octave setup_mfcc.m Object.Base.data."mfcc_config" { bytes " 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, - 0x68,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x74,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x74,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, @@ -14,9 +14,11 @@ Object.Base.data."mfcc_config" { 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0xc3,0x35,0x00,0x2c,0xff,0xff,0x00,0x00, + 0xc3,0x35,0x00,0x2c,0x00,0x00,0x00,0x00, 0x90,0x01,0xa0,0x00,0x00,0x00,0x14,0x00, 0x0d,0x00,0x17,0x00,0x00,0x00,0x00,0x64, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, - 0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00" + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00" } diff --git a/tools/topology/topology2/include/components/mfcc/mel80.conf b/tools/topology/topology2/include/components/mfcc/mel80.conf new file mode 100644 index 000000000000..b18baadd459b --- /dev/null +++ b/tools/topology/topology2/include/components/mfcc/mel80.conf @@ -0,0 +1,24 @@ +# Exported MFCC configuration 26-May-2026 +# cd src/audio/mfcc/tune; octave setup_mfcc.m +Object.Base.data."mfcc_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x74,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x74,0x00,0x00,0x00,0x00,0x02,0x00,0x04, + 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,0x80,0x3e,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x90,0x01,0xa0,0x00,0x40,0x1f,0x00,0x00, + 0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x01,0x00,0x00,0x01,0x01,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/mfcc/mel80_compress.conf b/tools/topology/topology2/include/components/mfcc/mel80_compress.conf new file mode 100644 index 000000000000..f26f2af6980c --- /dev/null +++ b/tools/topology/topology2/include/components/mfcc/mel80_compress.conf @@ -0,0 +1,24 @@ +# Exported MFCC configuration 26-May-2026 +# cd src/audio/mfcc/tune; octave setup_mfcc.m +Object.Base.data."mfcc_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x74,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x74,0x00,0x00,0x00,0x00,0x02,0x00,0x04, + 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,0x80,0x3e,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x90,0x01,0xa0,0x00,0x40,0x1f,0x00,0x00, + 0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x01,0x00,0x00,0x01,0x01,0x00,0x01,0x01, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/mfcc/mel80_compress_dtx.conf b/tools/topology/topology2/include/components/mfcc/mel80_compress_dtx.conf new file mode 100644 index 000000000000..d225811ca4d1 --- /dev/null +++ b/tools/topology/topology2/include/components/mfcc/mel80_compress_dtx.conf @@ -0,0 +1,24 @@ +# Exported MFCC configuration 26-May-2026 +# cd src/audio/mfcc/tune; octave setup_mfcc.m +Object.Base.data."mfcc_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x74,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x74,0x00,0x00,0x00,0x00,0x02,0x00,0x04, + 0x00,0x00,0x00,0x00,0x14,0x00,0xf4,0x01, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0x3e,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x90,0x01,0xa0,0x00,0x40,0x1f,0x00,0x00, + 0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x01,0x00,0x00,0x01,0x01,0x01,0x01,0x01, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/micsel.conf b/tools/topology/topology2/include/components/micsel.conf index 32c4e1d5d520..bccfe2a85bfe 100644 --- a/tools/topology/topology2/include/components/micsel.conf +++ b/tools/topology/topology2/include/components/micsel.conf @@ -64,8 +64,6 @@ Class.Widget."micsel" { # type "effect" - num_input_audio_formats 1 - num_output_audio_formats 1 #UUID: 32FE92C1-1E17-4FC2-9758-C7F3542E980A uuid "c1:92:fe:32:17:1e:c2:4f:97:58:c7:f3:54:2e:98:0a" no_pm "true" diff --git a/tools/topology/topology2/include/components/micsel/downmix_51_to_mono_with_lfe.conf b/tools/topology/topology2/include/components/micsel/downmix_51_to_mono_with_lfe.conf new file mode 100644 index 000000000000..76aa09754ebe --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/downmix_51_to_mono_with_lfe.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x6e,0x00,0x6e,0x00, + 0x9c,0x00,0xec,0x01,0x4e,0x00,0x4e,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,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,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" +} diff --git a/tools/topology/topology2/include/components/micsel/downmix_51_to_stereo_with_lfe.conf b/tools/topology/topology2/include/components/micsel/downmix_51_to_stereo_with_lfe.conf new file mode 100644 index 000000000000..0fb37e1d840b --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/downmix_51_to_stereo_with_lfe.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, + 0xb5,0x00,0x96,0x01,0xb5,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0xb5,0x00,0x96,0x01,0x00,0x00,0xb5,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,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/micsel/downmix_71_to_51.conf b/tools/topology/topology2/include/components/micsel/downmix_71_to_51.conf new file mode 100644 index 000000000000..93fe5fb1c3f9 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/downmix_71_to_51.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00, + 0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02, + 0x00,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" +} diff --git a/tools/topology/topology2/include/components/micsel/downmix_71_to_mono_with_lfe.conf b/tools/topology/topology2/include/components/micsel/downmix_71_to_mono_with_lfe.conf new file mode 100644 index 000000000000..1e67d36bf839 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/downmix_71_to_mono_with_lfe.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xa4,0x00,0xa4,0x00, + 0xe8,0x00,0x00,0x00,0x74,0x00,0x74,0x00, + 0x74,0x00,0x74,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,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,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" +} diff --git a/tools/topology/topology2/include/components/micsel/downmix_71_to_stereo_with_lfe.conf b/tools/topology/topology2/include/components/micsel/downmix_71_to_stereo_with_lfe.conf new file mode 100644 index 000000000000..b94ea59c1a9e --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/downmix_71_to_stereo_with_lfe.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xda,0x00,0x00,0x00, + 0x9a,0x00,0x59,0x01,0x9a,0x00,0x00,0x00, + 0x9a,0x00,0x00,0x00,0x00,0x00,0xda,0x00, + 0x9a,0x00,0x59,0x01,0x00,0x00,0x9a,0x00, + 0x00,0x00,0x9a,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/micsel/downmix_stereo_to_mono.conf b/tools/topology/topology2/include/components/micsel/downmix_stereo_to_mono.conf new file mode 100644 index 000000000000..510d303eb2d9 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/downmix_stereo_to_mono.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x02,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,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,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/micsel/passthrough.conf b/tools/topology/topology2/include/components/micsel/passthrough.conf new file mode 100644 index 000000000000..0b795084ba29 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/passthrough.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x04" +} diff --git a/tools/topology/topology2/include/components/micsel/stereo_endpoint_playback_updownmix.conf b/tools/topology/topology2/include/components/micsel/stereo_endpoint_playback_updownmix.conf new file mode 100644 index 000000000000..70500ef0e0fa --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/stereo_endpoint_playback_updownmix.conf @@ -0,0 +1,75 @@ +# Exported with script sof_selector_blobs.m 10-Mar-2026 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x10,0x02,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x08,0x0c,0x0c,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x04,0x01,0x02,0x00,0x01, + 0xd5,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xd5,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,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, + 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, + 0x06,0x02,0x08,0x01,0x00,0x01,0x00,0x00, + 0xb5,0x00,0x96,0x01,0xb5,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0xb5,0x00,0x96,0x01,0x00,0x00,0xb5,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,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x08,0x02,0x0c,0x01, + 0xda,0x00,0x00,0x00,0x9a,0x00,0x59,0x01, + 0x9a,0x00,0x00,0x00,0x9a,0x00,0x00,0x00, + 0x00,0x00,0xda,0x00,0x9a,0x00,0x59,0x01, + 0x00,0x00,0x9a,0x00,0x00,0x00,0x9a,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,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/micsel/upmix_mono_to_51.conf b/tools/topology/topology2/include/components/micsel/upmix_mono_to_51.conf new file mode 100644 index 000000000000..c19828913473 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/upmix_mono_to_51.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 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,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,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,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,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/micsel/upmix_mono_to_71.conf b/tools/topology/topology2/include/components/micsel/upmix_mono_to_71.conf new file mode 100644 index 000000000000..c19828913473 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/upmix_mono_to_71.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 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,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,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,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,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/micsel/upmix_mono_to_stereo.conf b/tools/topology/topology2/include/components/micsel/upmix_mono_to_stereo.conf new file mode 100644 index 000000000000..33ef4a7672f2 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/upmix_mono_to_stereo.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xd5,0x02,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xd5,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,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,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" +} diff --git a/tools/topology/topology2/include/components/micsel/upmix_stereo_to_51.conf b/tools/topology/topology2/include/components/micsel/upmix_stereo_to_51.conf new file mode 100644 index 000000000000..b411410cab70 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/upmix_stereo_to_51.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 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,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,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" +} diff --git a/tools/topology/topology2/include/components/micsel/upmix_stereo_to_71.conf b/tools/topology/topology2/include/components/micsel/upmix_stereo_to_71.conf new file mode 100644 index 000000000000..b411410cab70 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/upmix_stereo_to_71.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 04-Jun-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 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,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,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" +} diff --git a/tools/topology/topology2/include/components/micsel/xover_selector_lr_to_llrr.conf b/tools/topology/topology2/include/components/micsel/xover_selector_lr_to_llrr.conf new file mode 100644 index 000000000000..4b4be2b34840 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/xover_selector_lr_to_llrr.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 08-Sep-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 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,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" +} diff --git a/tools/topology/topology2/include/components/micsel/xover_selector_lr_to_lrlr.conf b/tools/topology/topology2/include/components/micsel/xover_selector_lr_to_lrlr.conf new file mode 100644 index 000000000000..70489a0a0040 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/xover_selector_lr_to_lrlr.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 08-Sep-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 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,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" +} diff --git a/tools/topology/topology2/include/components/micsel/xover_selector_lr_to_rrll.conf b/tools/topology/topology2/include/components/micsel/xover_selector_lr_to_rrll.conf new file mode 100644 index 000000000000..d88ba2063cd6 --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/xover_selector_lr_to_rrll.conf @@ -0,0 +1,26 @@ +# Exported with script sof_selector_blobs.m 08-Sep-2025 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,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,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" +} diff --git a/tools/topology/topology2/include/components/phase_vocoder.conf b/tools/topology/topology2/include/components/phase_vocoder.conf new file mode 100644 index 000000000000..c0541c2ce69d --- /dev/null +++ b/tools/topology/topology2/include/components/phase_vocoder.conf @@ -0,0 +1,121 @@ +# +# +# A PHASE_VOCODER component for SOF. All attributes defined herein are namespaced +# by alsatplg to "Object.Widget.phase_vocoder.attribute_name" +# +# Usage: this component can be used by declaring in the parent object. e.g. +# +# Object.Widget.phase_vocoder."N" { +# index 1 +# } + +# +# Where N is a unique integer in the parent object. + +Class.Widget."phase_vocoder" { + # + # Pipeline ID + # + DefineAttribute."index" { + type "integer" + } + + # + # Unique instance for PHASE_VOCODER 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" + } + + Object.Control { + # Switch controls + 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 + } + + # Enum controls + enum."1" { + Object.Base { + channel.1 { + name "fc" + reg 3 + shift 0 + } + text.0 { + name "phase_vocoder_speed_enum" + !values [ + "0.5" + "0.6" + "0.7" + "0.8" + "0.9" + "1.0" + "1.1" + "1.2" + "1.3" + "1.4" + "1.5" + "1.6" + "1.7" + "1.8" + "1.9" + "2.0" + ] + } + ops.1 { + name "ctl" + info "enum" + #257 binds the mixer control to enum get/put handlers + get 257 + put 257 + } + } + } + } + + # + # Default attributes for phase_vocoder + # + + uuid "7a:cb:fb:09:c5:a9:57:4a:84:34:44:40:e5:98:ab:24" + type "effect" + no_pm "true" + num_input_pins 1 + num_output_pins 1 +} diff --git a/tools/topology/topology2/include/components/phase_vocoder/hann_1024_256.conf b/tools/topology/topology2/include/components/phase_vocoder/hann_1024_256.conf new file mode 100644 index 000000000000..fbce252b333a --- /dev/null +++ b/tools/topology/topology2/include/components/phase_vocoder/hann_1024_256.conf @@ -0,0 +1,17 @@ +# Exported PHASE_VOCODER configuration 17-Jun-2026 +# cd src/audio/phase_vocoder/tune; octave setup_phase_vocoder.m +Object.Base.data."phase_vocoder_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,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,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0xbb,0x00,0x00, + 0x01,0xb0,0x6a,0x55,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/phase_vocoder/hann_1024_256_mono.conf b/tools/topology/topology2/include/components/phase_vocoder/hann_1024_256_mono.conf new file mode 100644 index 000000000000..9aa3a2bdc326 --- /dev/null +++ b/tools/topology/topology2/include/components/phase_vocoder/hann_1024_256_mono.conf @@ -0,0 +1,17 @@ +# Exported PHASE_VOCODER configuration 17-Jun-2026 +# cd src/audio/phase_vocoder/tune; octave setup_phase_vocoder.m +Object.Base.data."phase_vocoder_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,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,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0xbb,0x00,0x00, + 0x01,0xb0,0x6a,0x55,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x04,0x00,0x01,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/phase_vocoder/hann_256_128.conf b/tools/topology/topology2/include/components/phase_vocoder/hann_256_128.conf new file mode 100644 index 000000000000..839b9e7e54ed --- /dev/null +++ b/tools/topology/topology2/include/components/phase_vocoder/hann_256_128.conf @@ -0,0 +1,17 @@ +# Exported PHASE_VOCODER configuration 17-Jun-2026 +# cd src/audio/phase_vocoder/tune; octave setup_phase_vocoder.m +Object.Base.data."phase_vocoder_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,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,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0xbb,0x00,0x00, + 0xab,0x00,0x56,0xab,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01,0x80,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/phase_vocoder/hann_512_128.conf b/tools/topology/topology2/include/components/phase_vocoder/hann_512_128.conf new file mode 100644 index 000000000000..0cf41f15424d --- /dev/null +++ b/tools/topology/topology2/include/components/phase_vocoder/hann_512_128.conf @@ -0,0 +1,17 @@ +# Exported PHASE_VOCODER configuration 17-Jun-2026 +# cd src/audio/phase_vocoder/tune; octave setup_phase_vocoder.m +Object.Base.data."phase_vocoder_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,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,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0xbb,0x00,0x00, + 0x60,0x15,0x80,0x55,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x02,0x80,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/phase_vocoder/hann_512_256.conf b/tools/topology/topology2/include/components/phase_vocoder/hann_512_256.conf new file mode 100644 index 000000000000..1197148a532e --- /dev/null +++ b/tools/topology/topology2/include/components/phase_vocoder/hann_512_256.conf @@ -0,0 +1,17 @@ +# Exported PHASE_VOCODER configuration 17-Jun-2026 +# cd src/audio/phase_vocoder/tune; octave setup_phase_vocoder.m +Object.Base.data."phase_vocoder_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,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,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0xbb,0x00,0x00, + 0xc0,0x2a,0x00,0xab,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/pipeline.conf b/tools/topology/topology2/include/components/pipeline.conf index 3a69354e30d2..caf972250f3e 100644 --- a/tools/topology/topology2/include/components/pipeline.conf +++ b/tools/topology/topology2/include/components/pipeline.conf @@ -102,6 +102,32 @@ Class.Widget."pipeline" { } } + DefineAttribute."direction" { + type "string" + token_ref "scheduler.word" + constraints { + !valid_values [ + "playback" + "capture" + ] + !tuple_values [ + 0 + 1 + ] + } + } + + DefineAttribute."direction_valid" { + type "string" + token_ref "scheduler.bool" + constraints { + !valid_values [ + "true" + "false" + ] + } + } + # Skip setting up the pipeline in the DSP in the case of chained DMA mode DefineAttribute."use_chain_dma" { type "string" @@ -144,4 +170,5 @@ Class.Widget."pipeline" { type "scheduler" no_pm "true" kcps $KCPS_PIPELINE_DEFAULT + direction_valid "true" } diff --git a/tools/topology/topology2/include/components/siggen.conf b/tools/topology/topology2/include/components/siggen.conf new file mode 100644 index 000000000000..ba806f8ae7dc --- /dev/null +++ b/tools/topology/topology2/include/components/siggen.conf @@ -0,0 +1,79 @@ +# +# Signal generator +# +# A generic siggen widget. All attributes defined herein are namespaced +# by alsatplg to "Object.Widget.siggen.N.attribute_name" +# +# Usage: this component can be used by declaring in a parent object. i.e. +# +# Object.Widget.siggen."N" { +# index 1 +# format s32le +# no_pm "true" +# } +# +# Where N is the unique instance number for siggen widget in the same alsaconf node. + +Class.Widget."siggen" { + # + # Pipeline ID for the siggen widget object + # + DefineAttribute."index" {} + + # + # siggen object instance + # + DefineAttribute."instance" {} + + #include common component definition + <include/components/widget-common.conf> + + # Attribute categories + attributes { + # + # The siggen widget name would be constructed using the index and instance attributes. + # For ex: "siggen.1.1" or "siggen.10.2" etc. + # + !constructor [ + "index" + "instance" + ] + + # + # immutable attributes cannot be modified in the object instance + # + !immutable [ + "uuid" + "type" + ] + + # + # deprecated attributes should not be added in the object instance + # + !deprecated [ + "preload_count" + ] + + # + # siggen widget objects instantiated within the same alsaconf node must have unique + # instance attribute + # + unique "instance" + } + + # siggen only supports one output pin with 32-bit audio format + num_output_pins 1 + num_output_audio_formats 1 + + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + + # Default attribute values for siggen widget + type "effect" + uuid "94:f8:e3:04:5c:2c:2e:4f:8d:c1:69:4e:ea:ab:53:fa" + no_pm "true" +} diff --git a/tools/topology/topology2/include/components/sound_dose.conf b/tools/topology/topology2/include/components/sound_dose.conf new file mode 100644 index 000000000000..264da305e35d --- /dev/null +++ b/tools/topology/topology2/include/components/sound_dose.conf @@ -0,0 +1,67 @@ +# +# +# A Sound Dose component. All attributes defined herein are namespaced +# by alsatplg to "Object.Widget.sound_dose.attribute_name" +# +# Usage: this component can be used by declaring in the parent object. i.e. +# +# Object.Widget.sound_dose."N" { +# index 1 +# } +# } + +# +# Where M is pipeline ID and N is a unique integer in the parent object. + +Class.Widget."sound_dose" { + # + # Pipeline ID + # + DefineAttribute."index" { + type "integer" + } + + # + # Unique instance for Sound Dose 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 sound_dose + # + + # uuid a43f9d7c-ea75-44d5-942d967991a33809 + + uuid "7c:9d:3f:a4:75:ea:d5:44:94:2d:96:79:91:a3:38:09" + type "effect" + no_pm "true" + num_input_pins 1 + num_output_pins 1 +} diff --git a/tools/topology/topology2/include/components/sound_dose/setup_data_init.conf b/tools/topology/topology2/include/components/sound_dose/setup_data_init.conf new file mode 100644 index 000000000000..c75e8ed60392 --- /dev/null +++ b/tools/topology/topology2/include/components/sound_dose/setup_data_init.conf @@ -0,0 +1,9 @@ +# Exported with script sof_sound_dose_blobs.m 17-Sep-2025 +# cd src/audio/sound_dose/tune; octave sof_sound_dose_blobs.m +Object.Base.data."sound_dose_config" { + bytes " + 0x53,0x4f,0x46,0x34,0xca,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/sound_dose/setup_gain_0db.conf b/tools/topology/topology2/include/components/sound_dose/setup_gain_0db.conf new file mode 100644 index 000000000000..4d64fab9a11c --- /dev/null +++ b/tools/topology/topology2/include/components/sound_dose/setup_gain_0db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_sound_dose_blobs.m 17-Sep-2025 +# cd src/audio/sound_dose/tune; octave sof_sound_dose_blobs.m +Object.Base.data."sound_dose_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x02,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/sound_dose/setup_sens_0db.conf b/tools/topology/topology2/include/components/sound_dose/setup_sens_0db.conf new file mode 100644 index 000000000000..ff32c00a6714 --- /dev/null +++ b/tools/topology/topology2/include/components/sound_dose/setup_sens_0db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_sound_dose_blobs.m 17-Sep-2025 +# cd src/audio/sound_dose/tune; octave sof_sound_dose_blobs.m +Object.Base.data."sound_dose_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/sound_dose/setup_sens_100db.conf b/tools/topology/topology2/include/components/sound_dose/setup_sens_100db.conf new file mode 100644 index 000000000000..5c54f455a25c --- /dev/null +++ b/tools/topology/topology2/include/components/sound_dose/setup_sens_100db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_sound_dose_blobs.m 17-Sep-2025 +# cd src/audio/sound_dose/tune; octave sof_sound_dose_blobs.m +Object.Base.data."sound_dose_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x10,0x27,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/sound_dose/setup_vol_0db.conf b/tools/topology/topology2/include/components/sound_dose/setup_vol_0db.conf new file mode 100644 index 000000000000..d75c1503a44b --- /dev/null +++ b/tools/topology/topology2/include/components/sound_dose/setup_vol_0db.conf @@ -0,0 +1,10 @@ +# Exported with script sof_sound_dose_blobs.m 17-Sep-2025 +# cd src/audio/sound_dose/tune; octave sof_sound_dose_blobs.m +Object.Base.data."sound_dose_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x01,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/src_format_s32_convert_from_48k.conf b/tools/topology/topology2/include/components/src_format_s32_convert_from_48k.conf index 5cd13dae1492..7982d2d171ec 100644 --- a/tools/topology/topology2/include/components/src_format_s32_convert_from_48k.conf +++ b/tools/topology/topology2/include/components/src_format_s32_convert_from_48k.conf @@ -39,5 +39,6 @@ in_rate 48000 in_bit_depth 32 in_valid_bit_depth 32 + ibs 512 } ] diff --git a/tools/topology/topology2/include/components/stft_process.conf b/tools/topology/topology2/include/components/stft_process.conf new file mode 100644 index 000000000000..7e78352ddc4e --- /dev/null +++ b/tools/topology/topology2/include/components/stft_process.conf @@ -0,0 +1,64 @@ +# +# +# A STFT_PROCESS component for SOF. All attributes defined herein are namespaced +# by alsatplg to "Object.Widget.stft_process.attribute_name" +# +# Usage: this component can be used by declaring in the parent object. i.e. +# +# Object.Widget.stft_process."N" { +# index 1 +# } +# } + +# +# Where M is pipeline ID and N is a unique integer in the parent object. + +Class.Widget."stft_process" { + # + # Pipeline ID + # + DefineAttribute."index" { + type "integer" + } + + # + # Unique instance for STFT_PROCESS 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 stft_process + # + uuid "a6:6e:11:0d:50:91:de:46:98:b8:b2:b3:a7:91:da:29" + type "effect" + no_pm "true" + num_input_pins 1 + num_output_pins 1 +} diff --git a/tools/topology/topology2/include/components/stft_process/hann_1024_256.conf b/tools/topology/topology2/include/components/stft_process/hann_1024_256.conf new file mode 100644 index 000000000000..761398162213 --- /dev/null +++ b/tools/topology/topology2/include/components/stft_process/hann_1024_256.conf @@ -0,0 +1,17 @@ +# Exported STFT_PROCESS configuration 22-Dec-2025 +# cd tools/tune/stft_process; octave setup_stft_process.m +Object.Base.data."stft_process_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,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,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0xbb,0x00,0x00, + 0x01,0xb0,0x6a,0x55,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/stft_process/hann_1536_240.conf b/tools/topology/topology2/include/components/stft_process/hann_1536_240.conf new file mode 100644 index 000000000000..497693eefde8 --- /dev/null +++ b/tools/topology/topology2/include/components/stft_process/hann_1536_240.conf @@ -0,0 +1,17 @@ +# Exported STFT_PROCESS configuration 22-Dec-2025 +# cd tools/tune/stft_process; octave setup_stft_process.m +Object.Base.data."stft_process_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,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,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0xbb,0x00,0x00, + 0x5f,0x3a,0x5e,0x35,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x06,0xf0,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/stft_process/hann_192_48.conf b/tools/topology/topology2/include/components/stft_process/hann_192_48.conf new file mode 100644 index 000000000000..4ed5586b1f54 --- /dev/null +++ b/tools/topology/topology2/include/components/stft_process/hann_192_48.conf @@ -0,0 +1,17 @@ +# Exported STFT_PROCESS configuration 22-Dec-2025 +# cd tools/tune/stft_process; octave setup_stft_process.m +Object.Base.data."stft_process_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,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,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0xbb,0x00,0x00, + 0xf1,0xb4,0xc7,0x55,0x00,0x00,0x00,0x00, + 0x00,0x00,0xc0,0x00,0x30,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/stft_process/hann_512_128.conf b/tools/topology/topology2/include/components/stft_process/hann_512_128.conf new file mode 100644 index 000000000000..61f9c20b0cdd --- /dev/null +++ b/tools/topology/topology2/include/components/stft_process/hann_512_128.conf @@ -0,0 +1,17 @@ +# Exported STFT_PROCESS configuration 22-Dec-2025 +# cd tools/tune/stft_process; octave setup_stft_process.m +Object.Base.data."stft_process_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,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,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0xbb,0x00,0x00, + 0x60,0x15,0x80,0x55,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x02,0x80,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/stft_process/hann_768_120.conf b/tools/topology/topology2/include/components/stft_process/hann_768_120.conf new file mode 100644 index 000000000000..23aa3e4da281 --- /dev/null +++ b/tools/topology/topology2/include/components/stft_process/hann_768_120.conf @@ -0,0 +1,17 @@ +# Exported STFT_PROCESS configuration 22-Dec-2025 +# cd tools/tune/stft_process; octave setup_stft_process.m +Object.Base.data."stft_process_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,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,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0xbb,0x00,0x00, + 0x61,0x22,0x67,0x35,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x03,0x78,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/template_comp.conf b/tools/topology/topology2/include/components/template_comp.conf new file mode 100644 index 000000000000..20bc1a8a9465 --- /dev/null +++ b/tools/topology/topology2/include/components/template_comp.conf @@ -0,0 +1,86 @@ +# +# A TEMPLATE_COMP component. All attributes defined herein are namespaced +# by alsatplg to "Object.Widget.template_comp.attribute_name" +# +# Usage: this component can be used by declaring in the parent object. i.e. +# +# Object.Widget.template_comp."N" { +# index 1 +# } +# } + +# +# Where M is pipeline ID and N is a unique integer in the parent object. + +<include/controls/mixer.conf> + +Class.Widget."template_comp" { + # + # Pipeline ID + # + DefineAttribute."index" { + type "integer" + } + + # + # Unique instance for TEMPLATE_COMP 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" + } + + # + # template_comp 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 template_comp + # + + uuid "af:e1:2d:a6:64:59:2e:4e:b1:67:7f:dc:97:27:9a:29" + type "effect" + no_pm "true" + num_input_pins 1 + num_output_pins 1 +} diff --git a/tools/topology/topology2/include/components/widget-common.conf b/tools/topology/topology2/include/components/widget-common.conf index 3c398300ef89..14ccd8fcf86a 100644 --- a/tools/topology/topology2/include/components/widget-common.conf +++ b/tools/topology/topology2/include/components/widget-common.conf @@ -119,3 +119,42 @@ DefineAttribute."no_wname_in_kcontrol_name" { } no_wname_in_kcontrol_name "true" + +## widget format +DefineAttribute."scheduler_domain" { + type "string" + # Token set reference name and type + token_ref "comp.string" + constraints { + !valid_values [ + # Low Latency + "LL" + # Data Processing + "DP" + # Use manifest value + "default" + ] + } +} + +## Userspace domain id +DefineAttribute."domain_id" { + # Token set reference name and type + token_ref "comp.word" +} + +## Stack size requirement in bytes for this component. Zero indicates default stack size. +DefineAttribute."stack_bytes_requirement" { + # Token set reference name and type + token_ref "comp.word" +} + +## Heap size requirement in bytes for this component. +DefineAttribute."heap_bytes_requirement" { + # Token set reference name and type + token_ref "comp.word" +} + +# These default values are here until we have measured module specific numbers +stack_bytes_requirement 8192 +heap_bytes_requirement 24576 diff --git a/tools/topology/topology2/include/formats/compr_input_audio_formats.conf b/tools/topology/topology2/include/formats/compr_input_audio_formats.conf new file mode 100644 index 000000000000..8d5694400988 --- /dev/null +++ b/tools/topology/topology2/include/formats/compr_input_audio_formats.conf @@ -0,0 +1,107 @@ + # All input formats for e.g. host-copier, decoder, + # and module-copier + num_input_audio_formats 40 + CombineArrays.Object.Base.input_audio_format [ + { + in_channels [ 1 ] + in_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + in_bit_depth [ 8 ] + in_valid_bit_depth [ 8 ] + in_sample_type [ $SAMPLE_TYPE_UNSIGNED_INTEGER ] + in_ch_map [ $CHANNEL_MAP_MONO ] + in_ch_cfg [ $CHANNEL_CONFIG_MONO ] + } + { + in_channels [ 1 ] + in_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_ch_map [ $CHANNEL_MAP_MONO ] + in_ch_cfg [ $CHANNEL_CONFIG_MONO ] + } + { + in_channels [ 1 ] + in_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 24 ] + in_ch_map [ $CHANNEL_MAP_MONO ] + in_ch_cfg [ $CHANNEL_CONFIG_MONO ] + } + { + in_channels [ 1 ] + in_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + in_ch_map [ $CHANNEL_MAP_MONO ] + in_ch_cfg [ $CHANNEL_CONFIG_MONO ] + } + { + in_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + in_bit_depth [ 8 ] + in_valid_bit_depth [ 8 ] + in_sample_type [ $SAMPLE_TYPE_UNSIGNED_INTEGER ] + } + { + in_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + } + { + in_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 24 ] + } + { + in_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + } + ] diff --git a/tools/topology/topology2/include/formats/compr_input_audio_formats_s32_48k.conf b/tools/topology/topology2/include/formats/compr_input_audio_formats_s32_48k.conf new file mode 100644 index 000000000000..9ea5b19a2f16 --- /dev/null +++ b/tools/topology/topology2/include/formats/compr_input_audio_formats_s32_48k.conf @@ -0,0 +1,29 @@ + # Input formats for e.g. micsel + num_input_audio_formats 10 + CombineArrays.Object.Base.input_audio_format [ + { + in_channels [ 1 ] + in_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + in_ch_map [ $CHANNEL_MAP_MONO ] + in_ch_cfg [ $CHANNEL_CONFIG_MONO ] + } + { + in_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + } + ] diff --git a/tools/topology/topology2/include/formats/compr_input_output_formats_src_s32_to_48k.conf b/tools/topology/topology2/include/formats/compr_input_output_formats_src_s32_to_48k.conf new file mode 100644 index 000000000000..836855126233 --- /dev/null +++ b/tools/topology/topology2/include/formats/compr_input_output_formats_src_s32_to_48k.conf @@ -0,0 +1,65 @@ + # Input and output audio formats for SRC + num_input_audio_formats 28 + CombineArrays.Object.Base.input_audio_format [ + { + in_channels [ 1 ] + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + in_ch_map [ $CHANNEL_MAP_MONO ] + in_ch_cfg [ $CHANNEL_CONFIG_MONO ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + } + ] + + num_output_audio_formats 2 + Object.Base.output_audio_format [ + { + out_channels 1 + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_map $CHANNEL_MAP_MONO + out_ch_cfg $CHANNEL_CONFIG_MONO + } + { + out_channels 2 + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] diff --git a/tools/topology/topology2/include/formats/compr_output_audio_formats.conf b/tools/topology/topology2/include/formats/compr_output_audio_formats.conf new file mode 100644 index 000000000000..98d11fa51cbc --- /dev/null +++ b/tools/topology/topology2/include/formats/compr_output_audio_formats.conf @@ -0,0 +1,106 @@ + # Output audio formats for e.g. host-copier and decoder + num_output_audio_formats 40 + CombineArrays.Object.Base.output_audio_format [ + { + out_channels [ 1 ] + out_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + out_bit_depth [ 8 ] + out_valid_bit_depth [ 8 ] + out_sample_type [ $SAMPLE_TYPE_UNSIGNED_INTEGER ] + out_ch_map [ $CHANNEL_MAP_MONO ] + out_ch_cfg [ $CHANNEL_CONFIG_MONO ] + } + { + out_channels [ 1 ] + out_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_ch_map [ $CHANNEL_MAP_MONO ] + out_ch_cfg [ $CHANNEL_CONFIG_MONO ] + } + { + out_channels [ 1 ] + out_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 24 ] + out_ch_map [ $CHANNEL_MAP_MONO ] + out_ch_cfg [ $CHANNEL_CONFIG_MONO ] + } + { + out_channels [ 1 ] + out_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 32 ] + out_ch_map [ $CHANNEL_MAP_MONO ] + out_ch_cfg [ $CHANNEL_CONFIG_MONO ] + } + { + out_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + out_bit_depth [ 8 ] + out_valid_bit_depth [ 8 ] + out_sample_type [ $SAMPLE_TYPE_UNSIGNED_INTEGER ] + } + { + out_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + } + { + out_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 24 ] + } + { + out_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 32 ] + } + ] diff --git a/tools/topology/topology2/include/formats/compr_output_audio_formats_s32.conf b/tools/topology/topology2/include/formats/compr_output_audio_formats_s32.conf new file mode 100644 index 000000000000..e377afa38687 --- /dev/null +++ b/tools/topology/topology2/include/formats/compr_output_audio_formats_s32.conf @@ -0,0 +1,29 @@ + # Output audio formats e.g. module-copier + num_output_audio_formats 10 + CombineArrays.Object.Base.output_audio_format [ + { + out_channels [ 1 ] + out_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 32 ] + out_ch_map [ $CHANNEL_MAP_MONO ] + out_ch_cfg [ $CHANNEL_CONFIG_MONO ] + } + { + out_rate [ + 8000 + 44100 + 48000 + 96000 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 32 ] + } + ] diff --git a/tools/topology/topology2/include/formats/compr_output_audio_formats_s32_48k_stereo.conf b/tools/topology/topology2/include/formats/compr_output_audio_formats_s32_48k_stereo.conf new file mode 100644 index 000000000000..13ebd43e389d --- /dev/null +++ b/tools/topology/topology2/include/formats/compr_output_audio_formats_s32_48k_stereo.conf @@ -0,0 +1,10 @@ + # Micsel single format output + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_channels 2 + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] diff --git a/tools/topology/topology2/include/pipelines/cavs/compr-playback.conf b/tools/topology/topology2/include/pipelines/cavs/compr-playback.conf new file mode 100644 index 000000000000..a9cbdde992aa --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/compr-playback.conf @@ -0,0 +1,103 @@ +# +# FE playback pipeline: compr-playback +# +# All attributes defined herein are namespaced +# by alsatplg to "Object.Pipeline.compr-playback.N.attribute_name" +# +# Usage: compr-playback pipeline object can be instantiated as: +# +# Object.Pipeline.compr-playback."N" { +# period 1000 +# time_domain "timer" +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/common/input_audio_format.conf> +<include/common/output_audio_format.conf> +<include/components/host-copier.conf> +<include/components/module-copier.conf> +<include/components/mixin.conf> +<include/components/pipeline.conf> +<include/components/gain.conf> +<include/components/decoder.conf> +<include/components/micsel.conf> +<include/components/src.conf> + +Class.Pipeline."compr-playback" { + + <include/pipelines/pipeline-common.conf> + + attributes { + !constructor [ + "index" + ] + + !immutable [ + "direction" + ] + + # + # compr-playback objects instantiated within the same alsaconf node must have + # unique pipeline_id attribute + # + unique "instance" + } + + Object.Widget { + host-copier."1" { + type "aif_in" + node_type $HDA_HOST_OUTPUT_CLASS + num_output_pins 1 + deep_buffer_dma_ms $COMPR_DEEPBUFFER_MS + } + + decoder."1" { + scheduler_domain "DP" + } + + module-copier."2" {} + + src."1" {} + + micsel."1" {} + + gain."1" {} + + mixin."1" {} + + pipeline."1" { + priority 0 + # enable lp mode + lp_mode 1 + } + } + + Object.Base.route [ + { + source decoder.$index.1 + sink module-copier.$index.2 + } + { + source module-copier.$index.2 + sink src.$index.1 + } + { + source src.$index.1 + sink micsel.$index.1 + } + { + source micsel.$index.1 + sink gain.$index.1 + } + { + source gain.$index.1 + sink mixin.$index.1 + } + ] + + direction "playback" + dynamic_pipeline 1 + time_domain "timer" +} diff --git a/tools/topology/topology2/include/pipelines/cavs/deepbuffer-capture.conf b/tools/topology/topology2/include/pipelines/cavs/deepbuffer-capture.conf new file mode 100644 index 000000000000..4fa8c82743aa --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/deepbuffer-capture.conf @@ -0,0 +1,111 @@ +# +# FE capture pipeline: deepbuffer-capture +# +# All attributes defined herein are namespaced +# by alsatplg to "Object.Pipeline.deepbuffer-capture.N.attribute_name" +# +# Usage: deepbuffer-capture pipeline object can be instantiated as: +# +# Object.Pipeline.deepbuffer-capture."N" { +# period 1000 +# time_domain "timer" +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/common/input_audio_format.conf> +<include/common/output_audio_format.conf> +<include/components/host-copier.conf> +<include/components/pipeline.conf> + +Class.Pipeline."deepbuffer-capture" { + + <include/pipelines/pipeline-common.conf> + + attributes { + !constructor [ + "index" + ] + + !immutable [ + "direction" + ] + + # + # deepbuffer-capture objects instantiated within the same alsaconf node must have + # unique pipeline_id attribute + # + unique "instance" + } + + Object.Widget { + host-copier."1" { + type "aif_out" + node_type $HDA_HOST_INPUT_CLASS + deep_buffer_dma_ms $DEEPBUFFER_FW_DMA_MS + num_input_pins 1 + num_input_audio_formats 2 + num_output_audio_formats 6 + # 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" { + priority 0 + # enable lp mode + lp_mode 1 + } + } + + direction "capture" + dynamic_pipeline 1 + time_domain "timer" +} diff --git a/tools/topology/topology2/include/pipelines/cavs/host-copier-micsel-gain-mixin-playback.conf b/tools/topology/topology2/include/pipelines/cavs/host-copier-micsel-gain-mixin-playback.conf new file mode 100644 index 000000000000..fcf0598c3e8d --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/host-copier-micsel-gain-mixin-playback.conf @@ -0,0 +1,359 @@ +# +# FE playback pipeline: host-copier-micsel-gain-mixin-playback +# +# All attributes defined herein are namespaced +# by alsatplg to "Object.Pipeline.host-copier-micsel-gain-mixin-playback.N.attribute_name" +# +# Usage: host-copier-micsel-gain-mixin-playback pipeline object can be instantiated as: +# +# Object.Pipeline.host-copier-micsel-gain-mixin-playback."N" { +# period 1000 +# time_domain "timer" +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/common/input_audio_format.conf> +<include/common/output_audio_format.conf> +<include/components/host-copier.conf> +<include/components/micsel.conf> +<include/components/mixin.conf> +<include/components/pipeline.conf> +<include/components/gain.conf> + +Class.Pipeline."host-copier-micsel-gain-mixin-playback" { + + <include/pipelines/pipeline-common.conf> + + attributes { + !constructor [ + "index" + ] + + !immutable [ + "direction" + ] + + # + # host-copier-micsel-gain-mixin-playback objects instantiated within the same alsaconf node must have + # unique pipeline_id attribute + # + unique "instance" + } + + Object.Widget { + host-copier."1" { + type "aif_in" + node_type $HDA_HOST_OUTPUT_CLASS + num_output_pins 1 + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_POINT_1 + } + { + 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 16 + in_valid_bit_depth 16 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + 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 24 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_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 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 2 + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 3 + out_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + out_ch_map $CHANNEL_MAP_2_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 32 + out_valid_bit_depth 32 + out_channels 5 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + out_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 6 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 8 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + } + + micsel."1" { + num_input_audio_formats 7 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 2 + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 3 + in_ch_cfg $CHANNEL_CONFIG_2_POINT_1 + in_ch_map $CHANNEL_MAP_2_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 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 5 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_0 + in_ch_map $CHANNEL_MAP_5_POINT_0 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 6 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 8 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 2 + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + ] + } + + gain."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 + } + ] + } + + mixin."1" {} + + pipeline."1" { + priority 0 + lp_mode 0 + } + } + + Object.Base.route [ + { + source micsel.$index.1 + sink gain.$index.1 + } + { + source gain.$index.1 + sink mixin.$index.1 + } + ] + + direction "playback" + dynamic_pipeline 1 + time_domain "timer" +} diff --git a/tools/topology/topology2/include/pipelines/cavs/host-gateway-src-mfcc-capture.conf b/tools/topology/topology2/include/pipelines/cavs/host-gateway-src-mfcc-capture.conf new file mode 100644 index 000000000000..fe6249018ef1 --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/host-gateway-src-mfcc-capture.conf @@ -0,0 +1,146 @@ +# +# SRC-MFCC capture pipeline +# +# This class provides host pipeline for capture with MFCC audio features input. +# All attributes defined herein are namespaced by alsatplg to +# "Object.Pipeline.host-gateway-src-mfcc-capture.N.attribute_name". +# +# Usage: host-gateway-src-mfcc-capture pipeline object can be instantiated as: +# +# Object.Pipeline.host-gateway-src-mfcc-capture."N" { +# period 1000 +# time_domain "timer" +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/common/input_audio_format.conf> +<include/common/output_audio_format.conf> +<include/components/pipeline.conf> +<include/components/host-copier.conf> +<include/components/src.conf> +<include/components/mfcc.conf> + +Define { + # Default MFCC output frame size (header + coefficients). + # Can be overridden by feature/platform includes or CMake variable overrides. + MFCC_FRAME_BYTES 344 +} + +Class.Pipeline."host-gateway-src-mfcc-capture" { + + <include/pipelines/pipeline-common.conf> + + attributes { + !constructor [ + "index" + ] + + # + # host-gateway-src-mfcc-capture objects instantiated within the same alsaconf + # node must have unique pipeline_id attribute + # + unique "instance" + } + + Object.Widget { + src."1" { + num_input_pins 1 + num_output_pins 1 + num_input_audio_formats 3 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_rate 48000 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_rate 96000 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_rate 192000 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_rate 16000 + } + ] + } + + mfcc."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 + in_rate 16000 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_rate 16000 + # Compress output frame: header + coefficients. + # Size set by MFCC_FRAME_BYTES Define. + obs $MFCC_FRAME_BYTES + } + ] + } + + host-copier."1" { + type "aif_out" + node_type $HDA_HOST_INPUT_CLASS + num_input_pins 1 + 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 + in_rate 16000 + # Match MFCC compress output frame size + ibs $MFCC_FRAME_BYTES + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_rate 16000 + obs $MFCC_FRAME_BYTES + } + ] + } + + pipeline."1" { + priority 0 + lp_mode 0 + } + } + + + Object.Base { + !route [ + { + source src.$index.1 + sink mfcc.$index.1 + } + ] + } + + direction "capture" + dynamic_pipeline 1 + time_domain "timer" +} diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-ctc-alh-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-ctc-alh-dai-copier-playback.conf new file mode 100644 index 000000000000..f8346454824d --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-ctc-alh-dai-copier-playback.conf @@ -0,0 +1,71 @@ +# +# BE playback pipeline: mixout-gain-ctc-alh-dai-copier. +# This pipeline is an extension of the mixout-gain-alh-dai-copier-playback pipeline class. +# +# All attributes defined herein are namespaced +# by alsatplg to "Object.Pipeline.mixout-gain-ctc-alh-dai-copier-playback.N.attribute_name" +# +# Usage: mixout-gain-ctc-alh-dai-copier-playback pipeline object can be instantiated as: +# +# Object.Pipeline.mixout-gain-ctc-alh-dai-copier-playback."N" { +# period 1000 +# time_domain "timer" +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/common/input_audio_format.conf> +<include/common/output_audio_format.conf> +<include/components/alh-dai-copier.conf> +<include/components/gain.conf> +<include/components/mixout.conf> +<include/components/pipeline.conf> +<include/components/ctc.conf> +<platform/intel/efx-default.conf> +<include/pipelines/cavs/mixout-gain-alh-dai-copier-playback.conf> + +Class.Pipeline."mixout-gain-ctc-alh-dai-copier-playback" { + SubTreeCopy.baseclass { + # this class extends the mixout-gain-alh-dai-copier-playback class definition + source "Class.Pipeline.mixout-gain-alh-dai-copier-playback" + + # target node is not defined which means that the new subtree will be copied to + # the parent node containing the SubTreeCopy node i.e in this case the + # Class.Pipeline.mixout-gain-ctc-alh-dai-copier-playback {} node. + + # default copy type is to extend the base class ie the widgets and routes + # will be added to the existing list of widgets/routes in the base class + + tree { + Object.Widget { + ctc."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.Base { + ! route [ + { + source gain.$index.1 + sink ctc.$index.1 + } + ] + } + } + } +} diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-alh-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-alh-dai-copier-playback.conf new file mode 100644 index 000000000000..71c367e48481 --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-alh-dai-copier-playback.conf @@ -0,0 +1,130 @@ +# +# BE playback pipeline: mixout-gain-dax-alh-dai-copier. +# +# All attributes defined herein are namespaced +# by alsatplg to "Object.Pipeline.mixout-gain-dax-alh-dai-copier-playback.N.attribute_name" +# +# Usage: mixout-gain-dax-alh-dai-copier-playback pipeline object can be instantiated as: +# +# Object.Pipeline.mixout-gain-dax-alh-dai-copier-playback."N" { +# time_domain "timer" +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/components/alh-dai-copier.conf> +<include/components/dolby-dax.conf> +<include/components/gain.conf> +<include/components/mixout.conf> +<include/components/pipeline.conf> + +Class.Pipeline."mixout-gain-dax-alh-dai-copier-playback" { + + <include/pipelines/pipeline-common.conf> + + attributes { + !constructor [ + "index" + ] + + !immutable [ + "direction" + ] + + # + # mixout-gain-dax-alh-dai-copier-playback objects instantiated within the same alsaconf + # node must have unique instance attribute + # + unique "instance" + } + + Object.Widget { + mixout."1" {} + alh-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.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + gain."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 + } + ] + } + dolby-dax."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + ibs "$[(256 * ($[($in_bit_depth / 8)])) * ($in_channels)]" + } + ] + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + obs "$[(256 * ($[($out_bit_depth / 8)])) * ($out_channels)]" + } + ] + } + + pipeline."1" { + priority 0 + lp_mode 0 + } + } + + Object.Base { + !route [ + { + source gain.$index.1 + sink dolby-dax.$index.1 + } + { + source mixout.$index.1 + sink gain.$index.1 + } + ] + } + + direction "playback" + dynamic_pipeline 1 + time_domain "timer" +} diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-ctc-alh-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-ctc-alh-dai-copier-playback.conf new file mode 100644 index 000000000000..887aad30ef78 --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-ctc-alh-dai-copier-playback.conf @@ -0,0 +1,57 @@ +# +# BE playback pipeline: mixout-gain-dax-ctc-alh-dai-copier. +# + +<include/components/dolby-dax.conf> +<include/components/ctc.conf> +<include/pipelines/cavs/mixout-gain-dax-alh-dai-copier-playback.conf> + +Class.Pipeline."mixout-gain-dax-ctc-alh-dai-copier-playback" { + SubTreeCopy.baseclass { + # this class extends the mixout-gain-dax-alh-dai-copier-playback class definition + source "Class.Pipeline.mixout-gain-dax-alh-dai-copier-playback" + + tree { + Object.Widget { + ctc."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 + + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + ibs "$[(256 * ($[($in_bit_depth / 8)])) * ($in_channels)]" + } + ] + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + obs "$[(256 * ($[($out_bit_depth / 8)])) * ($out_channels)]" + } + ] + } + } + + Object.Base { + ! route [ + { + source gain.$index.1 + sink dolby-dax.$index.1 + } + { + source dolby-dax.$index.1 + sink ctc.$index.1 + } + { + source mixout.$index.1 + sink gain.$index.1 + } + ] + } + } + } +} diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-ctc-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-ctc-dai-copier-playback.conf new file mode 100644 index 000000000000..2353aa7af719 --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-ctc-dai-copier-playback.conf @@ -0,0 +1,74 @@ +# +# BE playback pipeline: mixout-gain-dax-ctc-dai-copier-playback. +# + +<include/components/dolby-dax.conf> +<include/components/ctc.conf> +<include/pipelines/cavs/mixout-gain-dai-copier-playback.conf> + +Class.Pipeline."mixout-gain-dax-ctc-dai-copier-playback" { + SubTreeCopy.baseclass { + # this class extends the mixout-gain-dai-copier-playback class definition + source "Class.Pipeline.mixout-gain-dai-copier-playback" + + tree { + Object.Widget { + dolby-dax."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + ibs "$[(256 * ($[($in_bit_depth / 8)])) * ($in_channels)]" + } + ] + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + obs "$[(256 * ($[($out_bit_depth / 8)])) * ($out_channels)]" + } + ] + } + + ctc."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 + + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + ibs "$[(256 * ($[($in_bit_depth / 8)])) * ($in_channels)]" + } + ] + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + obs "$[(256 * ($[($out_bit_depth / 8)])) * ($out_channels)]" + } + ] + } + } + + Object.Base { + ! route [ + { + source gain.$index.1 + sink dolby-dax.$index.1 + } + { + source dolby-dax.$index.1 + sink ctc.$index.1 + } + ] + } + } + } +} diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-dai-copier-playback.conf new file mode 100644 index 000000000000..0f136364e3d5 --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dax-dai-copier-playback.conf @@ -0,0 +1,58 @@ +# +# BE playback pipeline: mixout-gain-dax-dai-copier. +# +# All attributes defined herein are namespaced +# by alsatplg to "Object.Pipeline.mixout-gain-dax-dai-copier-playback.N.attribute_name" +# +# Usage: mixout-gain-dax-dai-copier-playback pipeline object can be instantiated as: +# +# Object.Pipeline.mixout-gain-dax-dai-copier-playback."N" { +# period 1000 +# time_domain "timer" +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/components/dolby-dax.conf> +<include/pipelines/cavs/mixout-gain-dai-copier-playback.conf> + +Class.Pipeline."mixout-gain-dax-dai-copier-playback" { + SubTreeCopy.baseclass { + # this class extends the mixout-gain-dai-copier-playback pipeline class. + source "Class.Pipeline.mixout-gain-dai-copier-playback" + tree { + Object.Widget { + dolby-dax."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + ibs "$[(256 * ($[($in_bit_depth / 8)])) * ($in_channels)]" + } + ] + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + obs "$[(256 * ($[($out_bit_depth / 8)])) * ($out_channels)]" + } + ] + } + } + + Object.Base { + !route [ + { + source gain.$index.1 + sink dolby-dax.$index.1 + } + ] + } + } + } +} diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-dts-alh-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-dts-alh-dai-copier-playback.conf new file mode 100644 index 000000000000..a34659b0fdfe --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-dts-alh-dai-copier-playback.conf @@ -0,0 +1,156 @@ +# +# BE playback pipeline: mixout-gain-eqiir-dts-alh-dai-copier. +# +# All attributes defined herein are namespaced +# by alsatplg to "Object.Pipeline.mixout-gain-eqiir-dts-alh-dai-copier-playback.N.attribute_name" +# +# Usage: mixout-gain-eqiir-dts-alh-dai-copier-playback pipeline object can be instantiated as: +# +# Object.Pipeline.mixout-gain-eqiir-dts-alh-dai-copier-playback."N" { +# time_domain "timer" +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/components/alh-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/dts.conf> + +Class.Pipeline."mixout-gain-eqiir-dts-alh-dai-copier-playback" { + + <include/pipelines/pipeline-common.conf> + + attributes { + !constructor [ + "index" + ] + + !immutable [ + "direction" + ] + + # + # mixout-gain-eqiir-dts-alh-dai-copier-playback objects instantiated within the same alsaconf + # node must have unique instance attribute + # + unique "instance" + } + + Object.Widget { + mixout."1" {} + alh-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.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + gain."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 + } + ] + } + + eqiir."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.Control.bytes."1" { + <include/components/eqiir/flat.conf> + } + } + + dts."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 + } + ] + } + + pipeline."1" { + priority 0 + lp_mode 0 + } + } + + Object.Base { + !route [ + { + source mixout.$index.1 + sink gain.$index.1 + } + { + source gain.$index.1 + sink eqiir.$index.1 + } + { + source eqiir.$index.1 + sink dts.$index.1 + } + ] + } + + direction "playback" + dynamic_pipeline 1 + time_domain "timer" +} diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-dts-ctc-alh-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-dts-ctc-alh-dai-copier-playback.conf new file mode 100644 index 000000000000..693d5a04378f --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-dts-ctc-alh-dai-copier-playback.conf @@ -0,0 +1,60 @@ +# +# BE playback pipeline: mixout-gain-eqiir-dts-ctc-alh-dai-copier. +# + +<include/components/ctc.conf> +<include/pipelines/cavs/mixout-gain-eqiir-dts-alh-dai-copier-playback.conf> + +Class.Pipeline."mixout-gain-eqiir-dts-ctc-alh-dai-copier-playback" { + SubTreeCopy.baseclass { + # this class extends the mixout-gain-eqiir-dts-alh-dai-copier-playback class definition + source "Class.Pipeline.mixout-gain-eqiir-dts-alh-dai-copier-playback" + + tree { + Object.Widget { + ctc."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 + + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + ibs "$[(256 * ($[($in_bit_depth / 8)])) * ($in_channels)]" + } + ] + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + obs "$[(256 * ($[($out_bit_depth / 8)])) * ($out_channels)]" + } + ] + } + } + + Object.Base { + ! route [ + { + source gain.$index.1 + sink eqiir.$index.1 + } + { + source eqiir.$index.1 + sink dts.$index.1 + } + { + source dts.$index.1 + sink ctc.$index.1 + } + { + source mixout.$index.1 + sink gain.$index.1 + } + ] + } + } + } +} diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-dts-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-dts-dai-copier-playback.conf index 87b9002f8eb2..4c1836e849ca 100644 --- a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-dts-dai-copier-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-dts-dai-copier-playback.conf @@ -1,12 +1,12 @@ # -# BE playback pipeline: mixout-gain-dts-dai-copier. +# BE playback pipeline: mixout-gain-eqiir-dts-dai-copier. # # All attributes defined herein are namespaced # by alsatplg to "Object.Pipeline.mixout-gain-eqiir-dts-dai-copier-playback.N.attribute_name" # -# Usage: mixout-gain-dts-dai-copier-playback pipeline object can be instantiated as: +# Usage: mixout-gain-eqiir-dts-dai-copier-playback pipeline object can be instantiated as: # -# Object.Pipeline.mixout-gain-dts-dai-copier-playback."N" { +# Object.Pipeline.mixout-gain-eqiir-dts-dai-copier-playback."N" { # period 1000 # time_domain "timer" # } diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-eqfir-drc-micsel-eqiir-eqfir-alh-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-eqfir-drc-micsel-eqiir-eqfir-alh-dai-copier-playback.conf new file mode 100644 index 000000000000..cc95dd9799a7 --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-eqiir-eqfir-drc-micsel-eqiir-eqfir-alh-dai-copier-playback.conf @@ -0,0 +1,132 @@ +# +# BE playback pipeline: mixout-gain-eqiir-eqfir-drc-micsel-eqiir-eqfir-alh-dai-copier. +# +# All attributes defined herein are namespaced +# by alsatplg to "Object.Pipeline.mixout-gain-eqiir-eqfir-drc-micsel-eqiir-eqfir-alh-dai-copier-playback.N.attribute_name" +# +# Usage: mixout-gain-eqiir-eqfir-drc-micsel-eqiir-eqfir-alh-dai-copier-playback pipeline object can be instantiated as: +# +# Object.Pipeline.mixout-gain-eqiir-eqfir-drc-micsel-eqiir-eqfir-alh-dai-copier-playback."N" { +# time_domain "timer" +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/pipelines/cavs/mixout-gain-eqiir-eqfir-drc-alh-dai-copier-playback.conf> +<include/components/micsel.conf> + +Class.Pipeline."mixout-gain-eqiir-eqfir-drc-micsel-eqiir-eqfir-alh-dai-copier-playback" { + + SubTreeCopy.baseclass { + # this class extends the pipeline class. + source "Class.Pipeline.mixout-gain-eqiir-eqfir-drc-alh-dai-copier-playback" + + # target node is not defined which means that the new subtree will be copied to + # the parent node containing the SubTreeCopy node i.e in this case the + # Class.Pipeline.mixout-gain-eqiir-eqfir-drc-micsel-eqiir-eqfir-alh-dai-copier-playback {} node. + + # default copy type is to extend the base class ie the widgets and routes + # will be added to the existing list of widgets/routes in the base class + + tree { + Object.Widget { + micsel."1" { + 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_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + Object.Control { + bytes."1" { + IncludeByKey.SDW_AMP_XOVER_SELECTOR_PARAMS { + "default" "include/components/micsel/passthrough.conf" + "xover_selector_lr_to_llrr" "include/components/micsel/xover_selector_lr_to_llrr.conf" + "xover_selector_lr_to_lrlr" "include/components/micsel/xover_selector_lr_to_lrlr.conf" + } + } + } + } + + eqiir."2" { + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_channels $SDW_AMP_NUM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + Object.Control.bytes."1" { + IncludeByKey.SDW_AMP_XOVER_EQIIR_PARAMS { + "default" "include/components/eqiir/passthrough.conf" + "xover_lr4_2000hz_lhlh_48khz" "include/components/eqiir/xover_lr4_2000hz_lhlh_48khz.conf" + "xover_lr4_2000hz_llhh_48khz" "include/components/eqiir/xover_lr4_2000hz_llhh_48khz.conf" + "xover_lr4_2000hz_hhll_48khz" "include/components/eqiir/xover_lr4_2000hz_hhll_48khz.conf" + } + } + } + eqfir."2" { + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_channels $SDW_AMP_NUM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + Object.Control.bytes."1" { + IncludeByKey.SDW_AMP_XOVER_EQFIR_PARAMS { + "default" "include/components/eqfir/passthrough.conf" + "xover_dd00_100us_48khz.conf" "include/components/eqfir/xover_dd00_100us_48khz.conf" + "xover_00dd_100us_48khz.conf" "include/components/eqfir/xover_00dd_100us_48khz.conf" + } + } + } + } + + Object.Base { + !route [ + { + source drc.$index.1 + sink micsel.$index.1 + } + { + source micsel.$index.1 + sink eqiir.$index.2 + } + { + source eqiir.$index.2 + sink eqfir.$index.2 + } + ] + } + } + } +} diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-micsel-eqiir-eqfir-alh-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-micsel-eqiir-eqfir-alh-dai-copier-playback.conf new file mode 100644 index 000000000000..a12503d5d83a --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-micsel-eqiir-eqfir-alh-dai-copier-playback.conf @@ -0,0 +1,132 @@ +# +# BE playback pipeline: mixout-gain-micsel-eqiir-eqfir-alh-dai-copier. +# +# All attributes defined herein are namespaced +# by alsatplg to "Object.Pipeline.mixout-gain-micsel-eqiir-eqfir-alh-dai-copier-playback.N.attribute_name" +# +# Usage: mixout-gain-micsel-eqiir-eqfir-alh-dai-copier-playback pipeline object can be instantiated as: +# +# Object.Pipeline.mixout-gain-micsel-eqiir-eqfir-alh-dai-copier-playback."N" { +# time_domain "timer" +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/pipelines/cavs/mixout-gain-alh-dai-copier-playback.conf> +<include/components/micsel.conf> + +Class.Pipeline."mixout-gain-micsel-eqiir-eqfir-alh-dai-copier-playback" { + + SubTreeCopy.baseclass { + # this class extends the pipeline class. + source "Class.Pipeline.mixout-gain-alh-dai-copier-playback" + + # target node is not defined which means that the new subtree will be copied to + # the parent node containing the SubTreeCopy node i.e in this case the + # Class.Pipeline.mixout-gain-micsel-eqiir-eqfir-alh-dai-copier-playback {} node. + + # default copy type is to extend the base class ie the widgets and routes + # will be added to the existing list of widgets/routes in the base class + + tree { + Object.Widget { + micsel."1" { + 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_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + Object.Control { + bytes."1" { + IncludeByKey.SDW_AMP_XOVER_SELECTOR_PARAMS { + "default" "include/components/micsel/passthrough.conf" + "xover_selector_lr_to_llrr" "include/components/micsel/xover_selector_lr_to_llrr.conf" + "xover_selector_lr_to_lrlr" "include/components/micsel/xover_selector_lr_to_lrlr.conf" + } + } + } + } + + eqiir."2" { + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_channels $SDW_AMP_NUM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + Object.Control.bytes."1" { + IncludeByKey.SDW_AMP_XOVER_EQIIR_PARAMS { + "default" "include/components/eqiir/passthrough.conf" + "xover_lr4_2000hz_lhlh_48khz" "include/components/eqiir/xover_lr4_2000hz_lhlh_48khz.conf" + "xover_lr4_2000hz_llhh_48khz" "include/components/eqiir/xover_lr4_2000hz_llhh_48khz.conf" + "xover_lr4_2000hz_hhll_48khz" "include/components/eqiir/xover_lr4_2000hz_hhll_48khz.conf" + } + } + } + eqfir."2" { + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_channels $SDW_AMP_NUM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + Object.Control.bytes."1" { + IncludeByKey.SDW_AMP_XOVER_EQFIR_PARAMS { + "default" "include/components/eqfir/passthrough.conf" + "xover_dd00_100us_48khz.conf" "include/components/eqfir/xover_dd00_100us_48khz.conf" + "xover_00dd_100us_48khz.conf" "include/components/eqfir/xover_00dd_100us_48khz.conf" + } + } + } + } + + Object.Base { + !route [ + { + source gain.$index.1 + sink micsel.$index.1 + } + { + source micsel.$index.1 + sink eqiir.$index.2 + } + { + source eqiir.$index.2 + sink eqfir.$index.2 + } + ] + } + } + } +} diff --git a/tools/topology/topology2/include/pipelines/cavs/siggen-host-copier-capture.conf b/tools/topology/topology2/include/pipelines/cavs/siggen-host-copier-capture.conf new file mode 100644 index 000000000000..26de0b1766f0 --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/siggen-host-copier-capture.conf @@ -0,0 +1,98 @@ +# +# Siggen capture pipeline +# +# This class provides host pipeline for capture with siggen input. All +# attributes defined herein are namespaced by alsatplg to +# "Object.Pipeline.siggen-host-copier-capture.N.attribute_name". +# +# Usage: siggen-host-copier-capture pipeline object can be instantiated as: +# +# Object.Pipeline.siggen-host-copier-capture."N" { +# period 1000 +# time_domain "timer" +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/common/input_audio_format.conf> +<include/common/output_audio_format.conf> +<include/components/pipeline.conf> +<include/components/host-copier.conf> +<include/components/siggen.conf> + +Class.Pipeline."siggen-host-copier-capture" { + + <include/pipelines/pipeline-common.conf> + + attributes { + !constructor [ + "index" + ] + + # + # siggen-host-copier-capture objects instantiated within the same alsaconf + # node must have unique pipeline_id attribute + # + unique "instance" + } + + Object.Widget { + siggen."1" { + num_input_pins 1 + 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 + } + ] + } + + host-copier."1" { + type "aif_out" + node_type $HDA_HOST_INPUT_CLASS + num_input_pins 1 + num_output_pins 1 + 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 + } + ] + } + + pipeline."1" { + priority 0 + lp_mode 0 + } + } + + direction "capture" + dynamic_pipeline 1 + time_domain "timer" +} diff --git a/tools/topology/topology2/platform/intel/bt-generic.conf b/tools/topology/topology2/platform/intel/bt-generic.conf index 2b0fd8b80753..e1549fb69a2e 100644 --- a/tools/topology/topology2/platform/intel/bt-generic.conf +++ b/tools/topology/topology2/platform/intel/bt-generic.conf @@ -66,7 +66,7 @@ Object.Pipeline { { index $BT_PB_HOST_PIPELINE_ID Object.Widget.pipeline.1 { - stream_name "dai-copier.SSP.$BT_NAME.playback" + stream_name "dai-copier.SSP.$BT_NAME.playback" } Object.Widget.host-copier.1 { stream_name $BT_PB_PCM_CAPS diff --git a/tools/topology/topology2/platform/intel/bt-ssp-config.conf b/tools/topology/topology2/platform/intel/bt-ssp-config.conf index 1a5353890f5e..2c527b55dcb4 100644 --- a/tools/topology/topology2/platform/intel/bt-ssp-config.conf +++ b/tools/topology/topology2/platform/intel/bt-ssp-config.conf @@ -21,6 +21,8 @@ Object.Dai.SSP [ tdm_slots 1 tx_slots 1 rx_slots 1 + # link_config ignored for <ACE1.5, must be compatible + # with BT_MCLK Object.Base.link_config.1 { clock_source 1 } @@ -39,6 +41,8 @@ Object.Dai.SSP [ tdm_slots 1 tx_slots 1 rx_slots 1 + # link_config ignored for <ACE1.5, must be compatible + # with BT_MCLK Object.Base.link_config.1 { clock_source 1 } @@ -56,6 +60,8 @@ Object.Dai.SSP [ tdm_slots 2 tx_slots 3 rx_slots 0 + # link_config ignored for <ACE1.5, must be compatible + # with BT_MCLK Object.Base.link_config.1 { clock_source 1 } diff --git a/tools/topology/topology2/platform/intel/compr-default.conf b/tools/topology/topology2/platform/intel/compr-default.conf new file mode 100644 index 000000000000..12ab39185f5a --- /dev/null +++ b/tools/topology/topology2/platform/intel/compr-default.conf @@ -0,0 +1,16 @@ +# default settings for Compressed Audio Playback +Define { + COMPRESSED false + COMPR_DEEPBUFFER_MS 100 # 100 ms copier dma size + + COMPRESSED_1 true + COMPR_PCM_NAME 'Compress Playback' + COMPR_PCM_ID 50 + COMPR_PIPELINE_ID 90 + + + COMPRESSED_2 false + COMPR_2_PCM_NAME 'Compress Playback 2' + COMPR_2_PCM_ID 52 + COMPR_2_PIPELINE_ID 92 +} diff --git a/tools/topology/topology2/platform/intel/compr.conf b/tools/topology/topology2/platform/intel/compr.conf new file mode 100644 index 000000000000..14c07a0d974d --- /dev/null +++ b/tools/topology/topology2/platform/intel/compr.conf @@ -0,0 +1,229 @@ + +IncludeByKey.COMPRESSED_1 { +"true" { + Object.Pipeline.compr-playback [ + { + index $COMPR_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name $COMPR_PCM_NAME + pcm_id $COMPR_PCM_ID + <include/formats/compr_input_audio_formats.conf> + <include/formats/compr_output_audio_formats.conf> + } + + Object.Widget.decoder.1 { + core_id 1 + <include/formats/compr_input_audio_formats.conf> + <include/formats/compr_output_audio_formats.conf> + } + + # converts the input to S32_LE + Object.Widget.module-copier.2 { + <include/formats/compr_input_audio_formats.conf> + <include/formats/compr_output_audio_formats_s32.conf> + } + + # converts the input to 48KHz + # note: this is wrong for 96/192KHz HiRes audio!!!! + Object.Widget.src.1 { + rate_out 48000 + <include/formats/compr_input_output_formats_src_s32_to_48k.conf> + } + + # converts the input to stereo + Object.Widget.micsel.1 { + Object.Control.bytes."1" { + name '$COMPR_PCM_NAME selector bytes' + <include/components/micsel/stereo_endpoint_playback_updownmix.conf> + } + <include/formats/compr_input_audio_formats_s32_48k.conf> + <include/formats/compr_output_audio_formats_s32_48k_stereo.conf> + } + + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $COMPR_PCM_NAME Volume' + } + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.mixin.1 { + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + Object.PCM.pcm [ + { + name $COMPR_PCM_NAME + id $COMPR_PCM_ID + direction playback + compress "true" + + Object.Base.fe_dai.1 { + name "$COMPR_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name $COMPR_PCM_NAME + formats 'S32_LE' + rates '8000' + } + } + ] + + Object.Base.route [ + { + source mixin.$COMPR_PIPELINE_ID.1 + sink $COMPR_PIPELINE_SINK + } + { + source host-copier.$COMPR_PCM_ID.playback + sink decoder.$COMPR_PIPELINE_ID.1 + } + ] +} +} + +# Spawn another instance for speaker +IncludeByKey.COMPRESSED_2 { +"true" { + Object.Pipeline.compr-playback [ + { + index $COMPR_2_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name $COMPR_2_PCM_NAME + pcm_id $COMPR_2_PCM_ID + <include/formats/compr_input_audio_formats.conf> + <include/formats/compr_output_audio_formats.conf> + } + + Object.Widget.decoder.1 { + core_id 1 + <include/formats/compr_input_audio_formats.conf> + <include/formats/compr_output_audio_formats.conf> + } + + # converts the input to S32_LE + Object.Widget.module-copier.2 { + <include/formats/compr_input_audio_formats.conf> + <include/formats/compr_output_audio_formats_s32.conf> + } + + # converts the input to 48KHz + # note: this is wrong for 96/192KHz HiRes audio!!!! + Object.Widget.src.1 { + rate_out 48000 + <include/formats/compr_input_output_formats_src_s32_to_48k.conf> + } + + # converts the input to stereo + Object.Widget.micsel.1 { + Object.Control.bytes."1" { + name '$COMPR_2_PCM_NAME selector bytes' + <include/components/micsel/stereo_endpoint_playback_updownmix.conf> + } + <include/formats/compr_input_audio_formats_s32_48k.conf> + <include/formats/compr_output_audio_formats_s32_48k_stereo.conf> + } + + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $COMPR_2_PCM_NAME Volume' + } + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.mixin.1 { + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + Object.PCM.pcm [ + { + name $COMPR_2_PCM_NAME + id $COMPR_2_PCM_ID + direction playback + compress "true" + + Object.Base.fe_dai.1 { + name "$COMPR_2_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name $COMPR_2_PCM_NAME + formats 'S32_LE' + rates '8000' + } + } + ] + + Object.Base.route [ + { + source mixin.$COMPR_2_PIPELINE_ID.1 + sink $COMPR_2_PIPELINE_SINK + } + { + source host-copier.$COMPR_2_PCM_ID.playback + sink decoder.$COMPR_2_PIPELINE_ID.1 + } + ] +} +} diff --git a/tools/topology/topology2/platform/intel/deep-buffer-default.conf b/tools/topology/topology2/platform/intel/deep-buffer-default.conf new file mode 100644 index 000000000000..35d0977bf3c9 --- /dev/null +++ b/tools/topology/topology2/platform/intel/deep-buffer-default.conf @@ -0,0 +1,8 @@ +# default settings for Deep Buffer Speaker +Define { + DEEP_BUF_SPK false + DEEP_BUF_JACK_RATE 48000 + + DEEP_BUFFER_PCM_NAME 'Deepbuffer Jack Out' + DEEP_BUFFER_PCM_NAME_2 'Deepbuffer Speaker' +} diff --git a/tools/topology/topology2/platform/intel/deep-buffer-spk.conf b/tools/topology/topology2/platform/intel/deep-buffer-spk.conf new file mode 100644 index 000000000000..b5743653f84f --- /dev/null +++ b/tools/topology/topology2/platform/intel/deep-buffer-spk.conf @@ -0,0 +1,59 @@ +Define { + SPEAKER_PCM_CORE_ID 0 +} + +Object.Pipeline.deepbuffer-playback [ + { + index $DEEP_BUFFER_PIPELINE_ID_2 + core_id $SPEAKER_PCM_CORE_ID + + Object.Widget.host-copier.1 { + stream_name $DEEP_BUFFER_PCM_NAME_2 + pcm_id $DEEP_BUFFER_PCM_ID_2 + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $DEEP_BUFFER_PCM_NAME_2 Volume' + } + } + Object.Widget.pipeline.1 { + core $SPEAKER_PCM_CORE_ID + } + } +] + +Object.PCM.pcm [ + { + name $DEEP_BUFFER_PCM_NAME_2 + id $DEEP_BUFFER_PCM_ID_2 + direction playback + playback_compatible_d0i3 $DEEPBUFFER_D0I3_COMPATIBLE + + Object.Base.fe_dai.1 { + name "$DEEP_BUFFER_PCM_NAME_2" + } + Object.PCM.pcm_caps.1 { + name $DEEP_BUFFER_PCM_NAME_2 + formats 'S16_LE,S24_LE,S32_LE' + # To avoid DMA spinning on a buffer we need bigger + # buffer than the host buffer size, let's say twice as + # big + # (S16_LE, Stereo, 48KHz, DEEPBUFFER_FW_DMA_MS) * 2 + # + # Note: The lower limit for the buffer size is rate + # dependent + buffer_size_min "$[(((2 * $channels_min) * 48) * $DEEPBUFFER_FW_DMA_MS) * 2]" + } + } +] + +Object.Base.route [ + { + source $DEEP_BUFFER_PIPELINE_SRC_2 + sink $DEEP_BUFFER_PIPELINE_SINK_2 + } + { + source host-copier.$DEEP_BUFFER_PCM_ID_2.playback + sink gain.$DEEP_BUFFER_PIPELINE_ID_2.1 + } +] diff --git a/tools/topology/topology2/platform/intel/deep-buffer.conf b/tools/topology/topology2/platform/intel/deep-buffer.conf index 13885f402c82..5b86088feddf 100644 --- a/tools/topology/topology2/platform/intel/deep-buffer.conf +++ b/tools/topology/topology2/platform/intel/deep-buffer.conf @@ -1,7 +1,3 @@ -Define { - DEEP_BUF_SPK false - DEEP_BUF_JACK_RATE 48000 -} Object.Pipeline.deepbuffer-playback [ { @@ -10,23 +6,60 @@ Object.Pipeline.deepbuffer-playback [ Object.Widget.host-copier.1 { stream_name $DEEP_BUFFER_PCM_NAME pcm_id $DEEP_BUFFER_PCM_ID - Object.Base.input_audio_format [ - { - in_rate $DEEP_BUF_JACK_RATE - in_bit_depth 16 - in_valid_bit_depth 16 + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_input_audio_formats 5 + Object.Base.input_audio_format [ + { + in_rate $DEEP_BUF_JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $DEEP_BUF_JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate $DEEP_BUF_JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_rate $DEEP_BUF_JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_rate $DEEP_BUF_JACK_RATE + in_bit_depth 8 + in_valid_bit_depth 8 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_input_audio_formats 3 + Object.Base.input_audio_format [ + { + in_rate $DEEP_BUF_JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $DEEP_BUF_JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate $DEEP_BUF_JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] } - { - in_rate $DEEP_BUF_JACK_RATE - in_bit_depth 32 - in_valid_bit_depth 24 - } - { - in_rate $DEEP_BUF_JACK_RATE - in_bit_depth 32 - in_valid_bit_depth 32 - } - ] + } Object.Base.output_audio_format [ { out_rate $DEEP_BUF_JACK_RATE @@ -87,7 +120,14 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name $DEEP_BUFFER_PCM_NAME - formats 'S16_LE,S24_LE,S32_LE' + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } # To avoid DMA spinning on a buffer we need bigger # buffer than the host buffer size, let's say twice as # big @@ -124,61 +164,5 @@ Object.Base.route [ # Spawn another instance IncludeByKey.DEEP_BUF_SPK { -"true" { - Object.Pipeline.deepbuffer-playback [ - { - index $DEEP_BUFFER_PIPELINE_ID_2 - core_id $SPEAKER_PCM_CORE_ID - - Object.Widget.host-copier.1 { - stream_name $DEEP_BUFFER_PCM_NAME_2 - pcm_id $DEEP_BUFFER_PCM_ID_2 - } - Object.Widget.gain.1 { - Object.Control.mixer.1 { - name 'Pre Mixer $DEEP_BUFFER_PCM_NAME_2 Volume' - } - } - Object.Widget.pipeline.1 { - core $SPEAKER_PCM_CORE_ID - } - } - ] - - Object.PCM.pcm [ - { - name $DEEP_BUFFER_PCM_NAME_2 - id $DEEP_BUFFER_PCM_ID_2 - direction playback - playback_compatible_d0i3 $DEEPBUFFER_D0I3_COMPATIBLE - - Object.Base.fe_dai.1 { - name "$DEEP_BUFFER_PCM_NAME_2" - } - Object.PCM.pcm_caps.1 { - name $DEEP_BUFFER_PCM_NAME_2 - formats 'S16_LE,S24_LE,S32_LE' - # To avoid DMA spinning on a buffer we need bigger - # buffer than the host buffer size, let's say twice as - # big - # (S16_LE, Stereo, 48KHz, DEEPBUFFER_FW_DMA_MS) * 2 - # - # Note: The lower limit for the buffer size is rate - # dependent - buffer_size_min "$[(((2 * $channels_min) * 48) * $DEEPBUFFER_FW_DMA_MS) * 2]" - } - } - ] - - Object.Base.route [ - { - source $DEEP_BUFFER_PIPELINE_SRC_2 - sink $DEEP_BUFFER_PIPELINE_SINK_2 - } - { - source host-copier.$DEEP_BUFFER_PCM_ID_2.playback - sink gain.$DEEP_BUFFER_PIPELINE_ID_2.1 - } - ] - } +"true" "platform/intel/deep-buffer-spk.conf" } diff --git a/tools/topology/topology2/platform/intel/dmic-deep-buffer.conf b/tools/topology/topology2/platform/intel/dmic-deep-buffer.conf new file mode 100644 index 000000000000..5e8615c2db21 --- /dev/null +++ b/tools/topology/topology2/platform/intel/dmic-deep-buffer.conf @@ -0,0 +1,117 @@ + Object.Pipeline.deepbuffer-capture [ + { + format $FORMAT + index $DMIC0_DEEP_BUFFER_PIPELINE_ID + Object.Widget.pipeline.1 { + stream_name "$DMIC0_DEEP_BUFFER_PCM_NAME" + } + Object.Widget.host-copier.1 { + stream_name $DMIC0_DEEP_BUFFER_PCM_NAME + pcm_id $DMIC0_DEEP_BUFFER_PCM_ID + num_input_audio_formats 2 + Object.Base.input_audio_format [ + { + in_rate $DMIC0_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_rate $DMIC0_RATE + in_channels 4 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + + num_output_audio_formats 6 + Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_rate $DMIC0_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_rate $DMIC0_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + { + out_rate $DMIC0_RATE + out_channels 4 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_rate $DMIC0_RATE + out_channels 4 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_rate $DMIC0_RATE + out_channels 4 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + } + } + + ] + Object.PCM.pcm [ + { + name "$DMIC0_DEEP_BUFFER_PCM_NAME" + id $DMIC0_DEEP_BUFFER_PCM_ID + direction "capture" + capture_compatible_d0i3 $DEEPBUFFER_D0I3_COMPATIBLE + + Object.Base.fe_dai."$DMIC0_DEEP_BUFFER_PCM_NAME" {} + + Object.PCM.pcm_caps."capture" { + name $DMIC0_DEEP_BUFFER_PCM_NAME + formats 'S16_LE,S24_LE,S32_LE' + channels_min $NUM_DMICS + channels_max $NUM_DMICS + # To avoid DMA spinning on a buffer we need bigger + # buffer than the host buffer size, let's say twice as + # big + # (S16_LE, Stereo, 48KHz, DEEPBUFFER_FW_DMA_MS) * 2 + # + # Note: The lower limit for the buffer size is rate + # dependent + IncludeByKey.DMIC0_RATE { + "16000" { + buffer_size_min "$[(((2 * $NUM_DMICS) * 16) * $DEEPBUFFER_FW_DMA_MS) * 2]" + rates '16000' + } + "48000" { + buffer_size_min "$[(((2 * $NUM_DMICS) * 48) * $DEEPBUFFER_FW_DMA_MS) * 2]" + rates '48000' + } + "96000" { + buffer_size_min "$[(((2 * $NUM_DMICS) * 96) * $DEEPBUFFER_FW_DMA_MS) * 2]" + rates '96000' + } + } + } + } + ] + Object.Base.route [ + { + source "module-copier.$DMIC0_DAI_PIPELINE_ID.2" + sink "host-copier.$DMIC0_DEEP_BUFFER_PCM_ID.capture" + } + ] \ No newline at end of file diff --git a/tools/topology/topology2/platform/intel/dmic-default.conf b/tools/topology/topology2/platform/intel/dmic-default.conf index 61569b42ec80..1bb96a45465b 100644 --- a/tools/topology/topology2/platform/intel/dmic-default.conf +++ b/tools/topology/topology2/platform/intel/dmic-default.conf @@ -47,4 +47,10 @@ Define { # Note: This will be redefined in dmic-generic.conf if not set from cmake DMIC0_PCM_CHANNELS 0 + + # Deep buffer capture + DMIC0_DEEP_BUFFER_PCM_NAME "DMIC Deep Buffer" + DMIC0_DEEP_BUFFER_PIPELINE_ID 18 + DMIC0_DEEP_BUFFER_PCM_ID 46 + DMIC0_DEEP_BUFFER false } diff --git a/tools/topology/topology2/platform/intel/dmic-generic.conf b/tools/topology/topology2/platform/intel/dmic-generic.conf index 2788722d476e..c473f1eea470 100644 --- a/tools/topology/topology2/platform/intel/dmic-generic.conf +++ b/tools/topology/topology2/platform/intel/dmic-generic.conf @@ -8,6 +8,11 @@ Define { IncludeByKey.DMIC0_PCM_CHANNELS { "0" { IncludeByKey.NUM_DMICS { + "1" { + Define { + DMIC0_PCM_CHANNELS 1 + } + } "2" { Define { DMIC0_PCM_CHANNELS 2 @@ -102,47 +107,204 @@ IncludeByKey.PASSTHROUGH { stream_name $DMIC0_PCM_CAPS pcm_id $DMIC0_PCM_ID num_input_audio_formats 1 - num_output_audio_formats 1 IncludeByKey.DMIC0_PCM_CHANNELS { - "2" { - Object.Base.input_audio_format [ - { - in_rate $DMIC0_RATE - in_bit_depth 32 - in_valid_bit_depth 32 - } - ] - Object.Base.output_audio_format [ - { - out_rate $DMIC0_RATE - out_bit_depth 32 - out_valid_bit_depth 32 - } - ] - } - "4" { - Object.Base.input_audio_format [ - { - in_rate $DMIC0_RATE - in_channels 4 - in_bit_depth 32 - in_valid_bit_depth 32 - in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - in_ch_map $CHANNEL_MAP_3_POINT_1 - } - ] - Object.Base.output_audio_format [ - { - out_rate $DMIC0_RATE - out_channels 4 - out_bit_depth 32 - out_valid_bit_depth 32 - out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - out_ch_map $CHANNEL_MAP_3_POINT_1 - } - ] - } - } + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC0_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_output_audio_formats 5 + Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_rate $DMIC0_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_rate $DMIC0_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_rate $DMIC0_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + out_sample_type $SAMPLE_TYPE_FLOAT + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_rate $DMIC0_RATE + out_bit_depth 8 + out_valid_bit_depth 8 + out_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } + "false" { + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_channels 1 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } + } + } + "2" { + Object.Base.input_audio_format [ + { + in_rate $DMIC0_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_output_audio_formats 5 + Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_rate $DMIC0_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_rate $DMIC0_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + { + out_rate $DMIC0_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + out_sample_type $SAMPLE_TYPE_FLOAT + } + { + out_rate $DMIC0_RATE + out_bit_depth 8 + out_valid_bit_depth 8 + out_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + } + "4" { + Object.Base.input_audio_format [ + { + in_rate $DMIC0_RATE + in_channels 4 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_output_audio_formats 5 + Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_channels 4 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_rate $DMIC0_RATE + out_channels 4 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_rate $DMIC0_RATE + out_channels 4 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_rate $DMIC0_RATE + out_channels 4 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + out_sample_type $SAMPLE_TYPE_FLOAT + } + { + out_rate $DMIC0_RATE + out_channels 4 + out_bit_depth 8 + out_valid_bit_depth 8 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + out_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_channels 4 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + } + } + } + } } Object.Widget.pipeline."1" { @@ -166,6 +328,45 @@ IncludeByKey.PASSTHROUGH { num_input_audio_formats 3 num_output_audio_formats 1 IncludeByKey.NUM_DMICS { + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC0_RATE + in_channels 1 + in_bit_depth 16 + in_valid_bit_depth 16 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_rate $DMIC0_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 24 + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_rate $DMIC0_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_channels 1 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } "2" { Object.Base.input_audio_format [ { @@ -240,6 +441,28 @@ IncludeByKey.PASSTHROUGH { num_input_audio_formats 1 num_output_audio_formats 1 IncludeByKey.NUM_DMICS { + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC0_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_channels 1 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } "2" { Object.Base.input_audio_format [ { @@ -293,6 +516,28 @@ IncludeByKey.PASSTHROUGH { num_input_audio_formats 1 num_output_audio_formats 1 IncludeByKey.NUM_DMICS { + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC0_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_channels 1 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } "2" { Object.Base.input_audio_format [ { @@ -341,6 +586,28 @@ IncludeByKey.PASSTHROUGH { num_input_audio_formats 1 num_output_audio_formats 1 IncludeByKey.NUM_DMICS { + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC0_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_channels 1 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } "2" { Object.Base.input_audio_format [ { @@ -633,8 +900,33 @@ IncludeByKey.PASSTHROUGH { type dai_out stream_name $DMIC0_NAME node_type $DMIC_LINK_INPUT_CLASS - num_input_audio_formats 6 + num_input_audio_formats 9 Object.Base.input_audio_format [ + { + in_rate $DMIC0_RATE + in_channels 1 + in_bit_depth 16 + in_valid_bit_depth 16 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_rate $DMIC0_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 24 + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_rate $DMIC0_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } { in_rate $DMIC0_RATE in_bit_depth 16 @@ -677,8 +969,16 @@ IncludeByKey.PASSTHROUGH { in_ch_map $CHANNEL_MAP_3_POINT_1 } ] - num_output_audio_formats 2 + num_output_audio_formats 3 Object.Base.output_audio_format [ + { + out_rate $DMIC0_RATE + out_channels 1 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } { out_rate $DMIC0_RATE out_bit_depth 32 @@ -716,8 +1016,14 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name $DMIC0_PCM_CAPS - # only 32-bit capture supported now - formats 'S32_LE' + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S32_LE' + } + } channels_min $DMIC0_PCM_CHANNELS channels_max $DMIC0_PCM_CHANNELS IncludeByKey.DMIC0_RATE { @@ -735,6 +1041,10 @@ Object.PCM.pcm [ } ] +IncludeByKey.DMIC0_DEEP_BUFFER { + "true" "platform/intel/dmic-deep-buffer.conf" +} + IncludeByKey.DMIC1_ENABLE { "passthrough" "platform/intel/dmic1-passthrough.conf" "mfcc" "platform/intel/dmic1-mfcc.conf" diff --git a/tools/topology/topology2/platform/intel/dmic1-mfcc.conf b/tools/topology/topology2/platform/intel/dmic1-mfcc.conf index 27d59d6ae18b..3aad756a85f5 100644 --- a/tools/topology/topology2/platform/intel/dmic1-mfcc.conf +++ b/tools/topology/topology2/platform/intel/dmic1-mfcc.conf @@ -14,6 +14,28 @@ Object.Pipeline.host-gateway-capture [ num_input_audio_formats 1 num_output_audio_formats 1 IncludeByKey.NUM_DMICS { + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 16 + in_valid_bit_depth 16 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_channels 1 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } "2" { Object.Base.input_audio_format [ { @@ -75,6 +97,45 @@ Object.Pipeline.dai-copier-gain-eqiir-module-copier-capture [ num_input_audio_formats 3 num_output_audio_formats 1 IncludeByKey.NUM_DMICS { + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 16 + in_valid_bit_depth 16 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 24 + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_channels 1 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } "2" { Object.Base.input_audio_format [ { @@ -149,6 +210,28 @@ Object.Pipeline.dai-copier-gain-eqiir-module-copier-capture [ num_input_audio_formats 1 num_output_audio_formats 1 IncludeByKey.NUM_DMICS { + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_channels 1 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } "2" { Object.Base.input_audio_format [ { @@ -217,6 +300,28 @@ Object.Pipeline.dai-copier-gain-eqiir-module-copier-capture [ num_input_audio_formats 1 num_output_audio_formats 1 IncludeByKey.NUM_DMICS { + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_channels 1 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } "2" { Object.Base.input_audio_format [ { @@ -265,6 +370,28 @@ Object.Pipeline.dai-copier-gain-eqiir-module-copier-capture [ num_input_audio_formats 1 num_output_audio_formats 1 IncludeByKey.NUM_DMICS { + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_channels 1 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } "2" { Object.Base.input_audio_format [ { @@ -327,13 +454,40 @@ Object.Widget.mfcc.1 { index $DMIC1_HOST_PIPELINE_ID Object.Control { bytes."1" { - name 'Analog Capture TDFB bytes' + name "Dmic1 Capture MFCC bytes" IncludeByKey.DMIC1_MFCC_PARAMS { "default" "include/components/mfcc/default.conf" } } + mixer."1" { + name "Dmic1 Capture MFCC VAD" + } } IncludeByKey.NUM_DMICS { + "1" { + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 16 + in_valid_bit_depth 16 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_channels 1 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } "2" { num_input_audio_formats 1 Object.Base.input_audio_format [ diff --git a/tools/topology/topology2/platform/intel/dmic1-passthrough.conf b/tools/topology/topology2/platform/intel/dmic1-passthrough.conf index 525eaee1a844..2ea85903d5a9 100644 --- a/tools/topology/topology2/platform/intel/dmic1-passthrough.conf +++ b/tools/topology/topology2/platform/intel/dmic1-passthrough.conf @@ -8,38 +8,70 @@ Object.Pipeline.host-gateway-capture [ Object.Widget.host-copier.1 { stream_name $DMIC1_PCM_CAPS pcm_id $DMIC1_PCM_ID - num_input_audio_formats 2 - Object.Base.input_audio_format [ - { - in_rate $DMIC1_RATE - in_bit_depth 32 - in_valid_bit_depth 32 - } - { - in_rate $DMIC1_RATE - in_channels 4 - in_bit_depth 32 - in_valid_bit_depth 32 - in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - in_ch_map $CHANNEL_MAP_3_POINT_1 - } - ] - num_output_audio_formats 2 - Object.Base.output_audio_format [ - { - out_rate $DMIC1_RATE - out_bit_depth 32 - out_valid_bit_depth 32 - } - { - out_rate $DMIC1_RATE - out_channels 4 - out_bit_depth 32 - out_valid_bit_depth 32 - out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - out_ch_map $CHANNEL_MAP_3_POINT_1 - } - ] + num_input_audio_formats 1 + num_output_audio_formats 1 + IncludeByKey.NUM_DMICS { + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_channels 1 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } + "2" { + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + "4" { + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_channels 4 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_channels 4 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + } + } } } ] @@ -54,66 +86,115 @@ Object.Pipeline.io-gateway-capture [ type dai_out stream_name $DMIC1_NAME node_type $DMIC_LINK_INPUT_CLASS - num_input_audio_formats 6 - Object.Base.input_audio_format [ - { - in_rate $DMIC1_RATE - in_bit_depth 16 - in_valid_bit_depth 16 - } - { - in_rate $DMIC1_RATE - in_bit_depth 32 - in_valid_bit_depth 24 - in_sample_type $SAMPLE_TYPE_MSB_INTEGER - } - { - in_rate $DMIC1_RATE - in_bit_depth 32 - in_valid_bit_depth 32 - } - { - in_rate $DMIC1_RATE - in_channels 4 - in_bit_depth 16 - in_valid_bit_depth 16 - in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - in_ch_map $CHANNEL_MAP_3_POINT_1 - } - { - in_rate $DMIC1_RATE - in_channels 4 - in_bit_depth 32 - in_valid_bit_depth 24 - in_sample_type $SAMPLE_TYPE_MSB_INTEGER - in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - in_ch_map $CHANNEL_MAP_3_POINT_1 - } - { - in_rate $DMIC1_RATE - in_channels 4 - in_bit_depth 32 - in_valid_bit_depth 32 - in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - in_ch_map $CHANNEL_MAP_3_POINT_1 - } - ] - num_output_audio_formats 2 - Object.Base.output_audio_format [ - { - out_rate $DMIC1_RATE - out_bit_depth 32 - out_valid_bit_depth 32 - } - { - out_rate $DMIC1_RATE - out_channels 4 - out_bit_depth 32 - out_valid_bit_depth 32 - out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - out_ch_map $CHANNEL_MAP_3_POINT_1 - } - ] + num_input_audio_formats 3 + num_output_audio_formats 1 + IncludeByKey.NUM_DMICS { + "1" { + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 16 + in_valid_bit_depth 16 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 24 + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_rate $DMIC1_RATE + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_channels 1 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + ] + } + "2" { + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $DMIC1_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + } + { + in_rate $DMIC1_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + "4" { + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_channels 4 + in_bit_depth 16 + in_valid_bit_depth 16 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + in_rate $DMIC1_RATE + in_channels 4 + in_bit_depth 32 + in_valid_bit_depth 24 + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + in_rate $DMIC1_RATE + in_channels 4 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_channels 4 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + } + } } } ] @@ -138,10 +219,19 @@ Object.PCM.pcm [ name $DMIC1_PCM_CAPS # only 32-bit capture supported now formats 'S32_LE' - channels_min $NUM_DMICS - channels_max $NUM_DMICS - rate_min $DMIC1_RATE - rate_max $DMIC1_RATE + channels_min $NUM_DMICS + channels_max $NUM_DMICS + IncludeByKey.DMIC1_RATE { + "16000" { + rates '16000' + } + "48000" { + rates '48000' + } + "96000" { + rates '96000' + } + } } } ] diff --git a/tools/topology/topology2/platform/intel/lnl.conf b/tools/topology/topology2/platform/intel/lnl.conf index 547040686c56..2fbb8ed12fa9 100644 --- a/tools/topology/topology2/platform/intel/lnl.conf +++ b/tools/topology/topology2/platform/intel/lnl.conf @@ -3,4 +3,7 @@ Define { DMIC_DRIVER_VERSION 4 SSP_BLOB_VERSION 0x105 NUM_HDMIS 3 + + # matches with clock_source=1 (Audio Cardinal Clock) + BT_MCLK 24576000 } diff --git a/tools/topology/topology2/platform/intel/mtl.conf b/tools/topology/topology2/platform/intel/mtl.conf index b685af3c08b1..8bd04bdf734a 100644 --- a/tools/topology/topology2/platform/intel/mtl.conf +++ b/tools/topology/topology2/platform/intel/mtl.conf @@ -3,4 +3,7 @@ Define { DMIC_DRIVER_VERSION 3 SSP_BLOB_VERSION 0x105 NUM_HDMIS 3 + + # matches with clock_source=1 (Audio Cardinal Clock) + BT_MCLK 24576000 } diff --git a/tools/topology/topology2/platform/intel/ptl.conf b/tools/topology/topology2/platform/intel/ptl.conf index 69d5d4f976f0..6ce5ede82d3b 100644 --- a/tools/topology/topology2/platform/intel/ptl.conf +++ b/tools/topology/topology2/platform/intel/ptl.conf @@ -3,4 +3,7 @@ Define { DMIC_DRIVER_VERSION 5 SSP_BLOB_VERSION 0x300 NUM_HDMIS 3 + + # matches with clock_source=1 (Audio Cardinal Clock) + BT_MCLK 24576000 } diff --git a/tools/topology/topology2/platform/intel/sdw-amp-dax-ctc.conf b/tools/topology/topology2/platform/intel/sdw-amp-dax-ctc.conf new file mode 100644 index 000000000000..6e05f327a1c0 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-amp-dax-ctc.conf @@ -0,0 +1,742 @@ +# route and pipeline index start from pcm id * 10 + +Define { + SDW_SPK_STREAM 'SDW1-Playback' + SDW_SPK_IN_STREAM 'SDW1-Capture' + ALH_2ND_SPK_ID 22 + ALH_3RD_SPK_ID 23 + ALH_2ND_SPK_IN_ID 32 + ALH_3RD_SPK_IN_ID 33 + SDW_AMP_BE_ID 2 + SDW_AMP_IN_BE_ID 3 + AMP_FEEDBACK_CH 2 + AMP_FEEDBACK_CH_PER_LINK 2 + SDW_AMP_FEEDBACK true + AMP_PLAYBACK_NAME 'Speaker Playback' +} + +# include deep buffer config if buffer size is in 1 - 1000 ms. +IncludeByKey.DEEPBUFFER_FW_DMA_MS { + "([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|1000)" { + IncludeByKey.DEEP_BUF_SPK { + "true" { + #deep-buffer-spk.conf is included in deep-buffer.conf + #and deep-buffer.conf is included if SDW_JACK is true. + #Therefore, only include deep-buffer-spk.conf when + #SDW_JACK is false to avoid duplicated. + IncludeByKey.SDW_JACK { + "false" "platform/intel/deep-buffer-spk.conf" + } + } + } + } +} + +Object.Dai.ALH [ + { + dai_index 20 + id $SDW_AMP_BE_ID + direction "playback" + name $SDW_SPK_STREAM + default_hw_conf_id 0 + rate 48000 + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH514" + } + } +] + +Object.Widget.module-copier."22" { + index 21 + num_input_pins 1 + num_output_pins 2 + 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.Pipeline { + host-copier-gain-mixin-playback [ + { + index 20 + + Object.Widget.host-copier.1 { + stream_name "sdw amplifiers" + pcm_id 2 + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_input_audio_formats 5 + 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 32 + in_valid_bit_depth 24 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_input_audio_formats 3 + 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.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $AMP_PLAYBACK_NAME Volume' + } + } + } + ] + + mixout-gain-dax-ctc-alh-dai-copier-playback [ + { + index 21 + + Object.Widget.alh-copier.1 { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $AMP_PLAYBACK_NAME Volume' + } + } + Object.Widget.dolby-dax.1 { + core_id $DOLBY_DAX_CORE_ID + Object.Control { + mixer."1" { + name 'DAX Speaker Switch' + } + mixer."2" { + name 'DAX Speaker Switch CP' + } + mixer."3" { + name 'DAX Speaker Switch CTC' + } + mixer."4" { + name 'DAX Speaker Volume' + } + enum."1" { + name 'DAX Speaker Profile' + } + enum."2" { + name 'DAX Speaker Device' + } + bytes."1" { + name 'DAX Speaker Tuning' + max 8192 + } + } + } + } + ] +} + +IncludeByKey.NUM_SDW_AMP_CTC_LINKS { +"2" { + Define { + AMP_FEEDBACK_CH 4 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + # Add a virtual widget to connect the aggregated 2nd DAI copier + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + ] + } + + Object.Base.route [ + { + source "ctc.21.1" + sink "virtual.sdw-amp" + } + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + ] + } + +"3" { + Define { + AMP_FEEDBACK_CH 6 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + { + index $ALH_3RD_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 2 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + { + index $ALH_3RD_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 2 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + { + name 'virtual.sdw-amp' + type output + index $ALH_3RD_SPK_ID + } + ] + } + + Object.Base.route [ + { + source "ctc.21.1" + sink "virtual.sdw-amp" + } + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.2" + } + ] + } +} + +Object.PCM.pcm [ + { + name "Speaker" + id 2 + direction "playback" + Object.Base.fe_dai.1 { + name "Speaker" + } + + Object.PCM.pcm_caps.1 { + name "sdw amplifiers" + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } + } + } +] + +Object.Base.route [ + { + source "ctc.21.1" + sink "module-copier.21.22" + } + { + source "module-copier.21.22" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + { + source 'mixin.20.1' + sink 'mixout.21.1' + } + { + source 'host-copier.2.playback' + sink 'gain.20.1' + } +] + +IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + Object.Dai.ALH [ + { + dai_index 30 + id $SDW_AMP_IN_BE_ID + direction "capture" + name $SDW_SPK_IN_STREAM + default_hw_conf_id 1 + rate 48000 + channels $AMP_FEEDBACK_CH_PER_LINK + + Object.Base.hw_config.1 { + id 1 + name "ALH515" + } + } + ] + Object.Pipeline { + host-gateway-capture [ + { + index 30 + + Object.Widget.host-copier.1 { + stream_name "amp feedback" + pcm_id 3 + + IncludeByKey.AMP_FEEDBACK_CH { + "6" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 6 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + } + "8" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 8 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + } + } + } + } + ] + } + Object.Widget { + alh-copier [ + { + index 31 + type dai_out + stream_name $SDW_SPK_IN_STREAM + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "4" { + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + } + ] + } + ] + pipeline [ + { + index 31 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + } + Object.PCM.pcm [ + { + name "Amp feedback" + id 3 + direction "capture" + Object.Base.fe_dai.1 { + name "Amp feedback" + } + + Object.PCM.pcm_caps.1 { + name "amp feedback" + formats 'S16_LE,S24_LE,S32_LE' + channels_min $AMP_FEEDBACK_CH + channels_max $AMP_FEEDBACK_CH + } + } + ] + Object.Base.route [ + { + source "alh-copier.$SDW_SPK_IN_STREAM.0" + sink "host-copier.3.capture" + } + ] + } +} diff --git a/tools/topology/topology2/platform/intel/sdw-amp-dax.conf b/tools/topology/topology2/platform/intel/sdw-amp-dax.conf new file mode 100644 index 000000000000..f1d93d01e100 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-amp-dax.conf @@ -0,0 +1,742 @@ +# route and pipeline index start from pcm id * 10 + +Define { + SDW_SPK_STREAM 'SDW1-Playback' + SDW_SPK_IN_STREAM 'SDW1-Capture' + ALH_2ND_SPK_ID 22 + ALH_3RD_SPK_ID 23 + ALH_2ND_SPK_IN_ID 32 + ALH_3RD_SPK_IN_ID 33 + SDW_AMP_BE_ID 2 + SDW_AMP_IN_BE_ID 3 + AMP_FEEDBACK_CH 2 + AMP_FEEDBACK_CH_PER_LINK 2 + SDW_AMP_FEEDBACK true + AMP_PLAYBACK_NAME 'Speaker Playback' +} + +# include deep buffer config if buffer size is in 1 - 1000 ms. +IncludeByKey.DEEPBUFFER_FW_DMA_MS { + "([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|1000)" { + IncludeByKey.DEEP_BUF_SPK { + "true" { + #deep-buffer-spk.conf is included in deep-buffer.conf + #and deep-buffer.conf is included if SDW_JACK is true. + #Therefore, only include deep-buffer-spk.conf when + #SDW_JACK is false to avoid duplicated. + IncludeByKey.SDW_JACK { + "false" "platform/intel/deep-buffer-spk.conf" + } + } + } + } +} + +Object.Dai.ALH [ + { + dai_index 20 + id $SDW_AMP_BE_ID + direction "playback" + name $SDW_SPK_STREAM + default_hw_conf_id 0 + rate 48000 + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH514" + } + } +] + +Object.Widget.module-copier."22" { + index 21 + num_input_pins 1 + num_output_pins 2 + 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.Pipeline { + host-copier-gain-mixin-playback [ + { + index 20 + + Object.Widget.host-copier.1 { + stream_name "sdw amplifiers" + pcm_id 2 + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_input_audio_formats 5 + 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 32 + in_valid_bit_depth 24 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_input_audio_formats 3 + 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.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $AMP_PLAYBACK_NAME Volume' + } + } + } + ] + + mixout-gain-dax-alh-dai-copier-playback [ + { + index 21 + + Object.Widget.alh-copier.1 { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $AMP_PLAYBACK_NAME Volume' + } + } + Object.Widget.dolby-dax.1 { + core_id $DOLBY_DAX_CORE_ID + Object.Control { + mixer."1" { + name 'DAX Speaker Switch' + } + mixer."2" { + name 'DAX Speaker Switch CP' + } + mixer."3" { + name 'DAX Speaker Switch CTC' + } + mixer."4" { + name 'DAX Speaker Volume' + } + enum."1" { + name 'DAX Speaker Profile' + } + enum."2" { + name 'DAX Speaker Device' + } + bytes."1" { + name 'DAX Speaker Tuning' + max 8192 + } + } + } + } + ] +} + +IncludeByKey.NUM_SDW_AMP_LINKS { +"2" { + Define { + AMP_FEEDBACK_CH 4 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + # Add a virtual widget to connect the aggregated 2nd DAI copier + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + ] + } + + Object.Base.route [ + { + source "gain.21.1" + sink "virtual.sdw-amp" + } + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + ] + } + +"3" { + Define { + AMP_FEEDBACK_CH 6 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + { + index $ALH_3RD_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 2 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + { + index $ALH_3RD_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 2 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + { + name 'virtual.sdw-amp' + type output + index $ALH_3RD_SPK_ID + } + ] + } + + Object.Base.route [ + { + source "gain.21.1" + sink "virtual.sdw-amp" + } + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.2" + } + ] + } +} + +Object.PCM.pcm [ + { + name "Speaker" + id 2 + direction "playback" + Object.Base.fe_dai.1 { + name "Speaker" + } + + Object.PCM.pcm_caps.1 { + name "sdw amplifiers" + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } + } + } +] + +Object.Base.route [ + { + source "dolby-dax.21.1" + sink "module-copier.21.22" + } + { + source "module-copier.21.22" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + { + source 'mixin.20.1' + sink 'mixout.21.1' + } + { + source 'host-copier.2.playback' + sink 'gain.20.1' + } +] + +IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + Object.Dai.ALH [ + { + dai_index 30 + id $SDW_AMP_IN_BE_ID + direction "capture" + name $SDW_SPK_IN_STREAM + default_hw_conf_id 1 + rate 48000 + channels $AMP_FEEDBACK_CH_PER_LINK + + Object.Base.hw_config.1 { + id 1 + name "ALH515" + } + } + ] + Object.Pipeline { + host-gateway-capture [ + { + index 30 + + Object.Widget.host-copier.1 { + stream_name "amp feedback" + pcm_id 3 + + IncludeByKey.AMP_FEEDBACK_CH { + "6" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 6 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + } + "8" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 8 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + } + } + } + } + ] + } + Object.Widget { + alh-copier [ + { + index 31 + type dai_out + stream_name $SDW_SPK_IN_STREAM + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "4" { + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + } + ] + } + ] + pipeline [ + { + index 31 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + } + Object.PCM.pcm [ + { + name "Amp feedback" + id 3 + direction "capture" + Object.Base.fe_dai.1 { + name "Amp feedback" + } + + Object.PCM.pcm_caps.1 { + name "amp feedback" + formats 'S16_LE,S24_LE,S32_LE' + channels_min $AMP_FEEDBACK_CH + channels_max $AMP_FEEDBACK_CH + } + } + ] + Object.Base.route [ + { + source "alh-copier.$SDW_SPK_IN_STREAM.0" + sink "host-copier.3.capture" + } + ] + } +} diff --git a/tools/topology/topology2/platform/intel/sdw-amp-dts-ctc.conf b/tools/topology/topology2/platform/intel/sdw-amp-dts-ctc.conf new file mode 100644 index 000000000000..9e401196f2a7 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-amp-dts-ctc.conf @@ -0,0 +1,922 @@ +# route and pipeline index start from pcm id * 10 + +Define { + SDW_SPK_STREAM 'SDW1-Playback' + SDW_SPK_IN_STREAM 'SDW1-Capture' + ALH_2ND_SPK_ID 22 + ALH_3RD_SPK_ID 23 + ALH_2ND_SPK_IN_ID 32 + ALH_3RD_SPK_IN_ID 33 + SDW_AMP_BE_ID 2 + SDW_AMP_IN_BE_ID 3 + AMP_FEEDBACK_CH 2 + AMP_FEEDBACK_CH_PER_LINK 2 + SDW_AMP_FEEDBACK true + AMP_PLAYBACK_NAME 'Speaker Playback' +} + +# include deep buffer config if buffer size is in 1 - 1000 ms. +IncludeByKey.PASSTHROUGH { +"false" { + IncludeByKey.DEEPBUFFER_FW_DMA_MS { + "([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|1000)" { + IncludeByKey.DEEP_BUF_SPK { + "true" { + #deep-buffer-spk.conf is included in deep-buffer.conf + #and deep-buffer.conf is included if SDW_JACK is true. + #Therefore, only include deep-buffer-spk.conf when + #SDW_JACK is false to avoid duplicated. + IncludeByKey.SDW_JACK { + "false" "platform/intel/deep-buffer-spk.conf" + } + } + } + } + } +} +} + +Object.Dai.ALH [ + { + dai_index 20 + id $SDW_AMP_BE_ID + direction "playback" + name $SDW_SPK_STREAM + default_hw_conf_id 0 + rate 48000 + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH514" + } + } +] + +Object.Widget.module-copier."22" { + index 21 + num_input_pins 1 + num_output_pins 2 + 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 + } + ] +} + +IncludeByKey.PASSTHROUGH { +"false" { + Object.Pipeline { + host-copier-gain-mixin-playback [ + { + index 20 + + Object.Widget.host-copier.1 { + stream_name "sdw amplifiers" + pcm_id 2 + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_input_audio_formats 5 + 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 32 + in_valid_bit_depth 24 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_input_audio_formats 3 + 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.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $AMP_PLAYBACK_NAME Volume' + } + } + } + ] + + IncludeByKey.SDW_SPK_ENHANCED_PLAYBACK { + "true" { + mixout-gain-eqiir-dts-ctc-alh-dai-copier-playback [ + { + index 21 + + Object.Widget.alh-copier.1 { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256)) | ($out_sample_type * 65536)]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $AMP_PLAYBACK_NAME Volume' + } + } + + Object.Widget.eqiir.1 { + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME IIR Eq bytes' + } + } + + Object.Widget.dts.1 { + Object.Control { + bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME DTS bytes' + max 2048 + } + } + } + } + ] + } + "false" { + mixout-gain-alh-dai-copier-playback [ + { + index 21 + + Object.Widget.alh-copier.1 { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256)) | ($out_sample_type * 65536)]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $AMP_PLAYBACK_NAME Volume' + } + } + } + ] + } + } + } +} +"true" { + Object.Pipeline.host-gateway-playback [ + { + index 20 + Object.Widget.host-copier.1 { + stream_name "sdw amplifiers" + pcm_id 2 + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 3 + 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 + } + ] + } + } + ] + + Object.Widget { + alh-copier [ + { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_pins 1 + direction playback + type dai_in + index 21 + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + pipeline [ + { + index 21 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + } + } +} + +IncludeByKey.NUM_SDW_AMP_CTC_LINKS { +"2" { + Define { + AMP_FEEDBACK_CH 4 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + # Add a virtual widget to connect the aggregated 2nd DAI copier + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + ] + } + + # Add the connection from the gain module to the aggregated 2nd DAI copier + # via the virtual widget. The virtual widget ensures that the routes between + # the gain and copier do not get established in the firmware. These are purely + # to show the existence of aggregation in the topology graph. + IncludeByKey.PASSTHROUGH { + "false" { + Object.Base.route [ + { + source "ctc.21.1" + sink "virtual.sdw-amp" + } + ] + } + "true" { + Object.Base.route [ + { + source "host-copier.2.playback" + sink "virtual.sdw-amp" + } + ] + } + } + Object.Base.route [ + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + ] + } + +"3" { + Define { + AMP_FEEDBACK_CH 6 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + { + index $ALH_3RD_SPK_ID + stream_name $SDW_SPK_STREAM + dai_index 2 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + { + index $ALH_3RD_SPK_IN_ID + stream_name $SDW_SPK_IN_STREAM + dai_index 2 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + { + name 'virtual.sdw-amp' + type output + index $ALH_3RD_SPK_ID + } + ] + } + + # Add the connection from the gain module to the aggregated 2nd DAI copier + # via the virtual widget. The virtual widget ensures that the routes between + # the gain and copier do not get established in the firmware. These are purely + # to show the existence of aggregation in the topology graph. + IncludeByKey.PASSTHROUGH { + "false" { + Object.Base.route [ + { + source "ctc.21.1" + sink "virtual.sdw-amp" + } + ] + } + "true" { + Object.Base.route [ + { + source "host-copier.2.playback" + sink "virtual.sdw-amp" + } + ] + } + } + Object.Base.route [ + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.2" + } + ] + } +} + +Object.PCM.pcm [ + { + name "Speaker" + id 2 + direction "playback" + Object.Base.fe_dai.1 { + name "Speaker" + } + + Object.PCM.pcm_caps.1 { + name "sdw amplifiers" + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } + } + } +] + +IncludeByKey.PASSTHROUGH { +"false" { + IncludeByKey.SDW_SPK_ENHANCED_PLAYBACK { + "true" { + Object.Base.route [ + { + source "ctc.21.1" + sink "module-copier.21.22" + } + { + source "module-copier.21.22" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] + } + "false" { + Object.Base.route [ + { + source "gain.21.1" + sink "module-copier.21.22" + } + { + source "module-copier.21.22" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] + } + } + Object.Base.route [ + { + source 'mixin.20.1' + sink 'mixout.21.1' + } + { + source 'host-copier.2.playback' + sink 'gain.20.1' + } + ] +} +"true" { + Object.Base.route [ + { + source "host-copier.2.playback" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] +} +} + +IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + Object.Dai.ALH [ + { + dai_index 30 + id $SDW_AMP_IN_BE_ID + direction "capture" + name $SDW_SPK_IN_STREAM + default_hw_conf_id 1 + rate 48000 + channels $AMP_FEEDBACK_CH_PER_LINK + + Object.Base.hw_config.1 { + id 1 + name "ALH515" + } + } + ] + Object.Pipeline { + host-gateway-capture [ + { + index 30 + + Object.Widget.host-copier.1 { + stream_name "amp feedback" + pcm_id 3 + + IncludeByKey.AMP_FEEDBACK_CH { + "6" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 6 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + } + "8" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 8 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + } + } + } + } + ] + } + Object.Widget { + alh-copier [ + { + index 31 + stream_name $SDW_SPK_IN_STREAM + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "4" { + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + } + ] + } + ] + pipeline [ + { + index 31 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + } + Object.PCM.pcm [ + { + name "Amp feedback" + id 3 + direction "capture" + Object.Base.fe_dai.1 { + name "Amp feedback" + } + + Object.PCM.pcm_caps.1 { + name "amp feedback" + formats 'S16_LE,S24_LE,S32_LE' + channels_min $AMP_FEEDBACK_CH + channels_max $AMP_FEEDBACK_CH + } + } + ] + Object.Base.route [ + { + source "alh-copier.$SDW_SPK_IN_STREAM.0" + sink "host-copier.3.capture" + } + ] + } +} diff --git a/tools/topology/topology2/platform/intel/sdw-amp-dts.conf b/tools/topology/topology2/platform/intel/sdw-amp-dts.conf new file mode 100644 index 000000000000..60710c634782 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-amp-dts.conf @@ -0,0 +1,922 @@ +# route and pipeline index start from pcm id * 10 + +Define { + SDW_SPK_STREAM 'SDW1-Playback' + SDW_SPK_IN_STREAM 'SDW1-Capture' + ALH_2ND_SPK_ID 22 + ALH_3RD_SPK_ID 23 + ALH_2ND_SPK_IN_ID 32 + ALH_3RD_SPK_IN_ID 33 + SDW_AMP_BE_ID 2 + SDW_AMP_IN_BE_ID 3 + AMP_FEEDBACK_CH 2 + AMP_FEEDBACK_CH_PER_LINK 2 + SDW_AMP_FEEDBACK true + AMP_PLAYBACK_NAME 'Speaker Playback' +} + +# include deep buffer config if buffer size is in 1 - 1000 ms. +IncludeByKey.PASSTHROUGH { +"false" { + IncludeByKey.DEEPBUFFER_FW_DMA_MS { + "([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|1000)" { + IncludeByKey.DEEP_BUF_SPK { + "true" { + #deep-buffer-spk.conf is included in deep-buffer.conf + #and deep-buffer.conf is included if SDW_JACK is true. + #Therefore, only include deep-buffer-spk.conf when + #SDW_JACK is false to avoid duplicated. + IncludeByKey.SDW_JACK { + "false" "platform/intel/deep-buffer-spk.conf" + } + } + } + } + } +} +} + +Object.Dai.ALH [ + { + dai_index 20 + id $SDW_AMP_BE_ID + direction "playback" + name $SDW_SPK_STREAM + default_hw_conf_id 0 + rate 48000 + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH514" + } + } +] + +Object.Widget.module-copier."22" { + index 21 + num_input_pins 1 + num_output_pins 2 + 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 + } + ] +} + +IncludeByKey.PASSTHROUGH { +"false" { + Object.Pipeline { + host-copier-gain-mixin-playback [ + { + index 20 + + Object.Widget.host-copier.1 { + stream_name "sdw amplifiers" + pcm_id 2 + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_input_audio_formats 5 + 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 32 + in_valid_bit_depth 24 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_input_audio_formats 3 + 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.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $AMP_PLAYBACK_NAME Volume' + } + } + } + ] + + IncludeByKey.SDW_SPK_ENHANCED_PLAYBACK { + "true" { + mixout-gain-eqiir-dts-alh-dai-copier-playback [ + { + index 21 + + Object.Widget.alh-copier.1 { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256)) | ($out_sample_type * 65536)]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $AMP_PLAYBACK_NAME Volume' + } + } + + Object.Widget.eqiir.1 { + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME IIR Eq bytes' + } + } + + Object.Widget.dts.1 { + Object.Control { + bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME DTS bytes' + max 2048 + } + } + } + } + ] + } + "false" { + mixout-gain-alh-dai-copier-playback [ + { + index 21 + + Object.Widget.alh-copier.1 { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256)) | ($out_sample_type * 65536)]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $AMP_PLAYBACK_NAME Volume' + } + } + } + ] + } + } + } +} +"true" { + Object.Pipeline.host-gateway-playback [ + { + index 20 + Object.Widget.host-copier.1 { + stream_name "sdw amplifiers" + pcm_id 2 + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 3 + 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 + } + ] + } + } + ] + + Object.Widget { + alh-copier [ + { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_pins 1 + direction playback + type dai_in + index 21 + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + pipeline [ + { + index 21 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + } + } +} + +IncludeByKey.NUM_SDW_AMP_LINKS { +"2" { + Define { + AMP_FEEDBACK_CH 4 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + # Add a virtual widget to connect the aggregated 2nd DAI copier + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + ] + } + + # Add the connection from the gain module to the aggregated 2nd DAI copier + # via the virtual widget. The virtual widget ensures that the routes between + # the gain and copier do not get established in the firmware. These are purely + # to show the existence of aggregation in the topology graph. + IncludeByKey.PASSTHROUGH { + "false" { + Object.Base.route [ + { + source "gain.21.1" + sink "virtual.sdw-amp" + } + ] + } + "true" { + Object.Base.route [ + { + source "host-copier.2.playback" + sink "virtual.sdw-amp" + } + ] + } + } + Object.Base.route [ + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + ] + } + +"3" { + Define { + AMP_FEEDBACK_CH 6 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + { + index $ALH_3RD_SPK_ID + stream_name $SDW_SPK_STREAM + dai_index 2 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + { + index $ALH_3RD_SPK_IN_ID + stream_name $SDW_SPK_IN_STREAM + dai_index 2 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + { + name 'virtual.sdw-amp' + type output + index $ALH_3RD_SPK_ID + } + ] + } + + # Add the connection from the gain module to the aggregated 2nd DAI copier + # via the virtual widget. The virtual widget ensures that the routes between + # the gain and copier do not get established in the firmware. These are purely + # to show the existence of aggregation in the topology graph. + IncludeByKey.PASSTHROUGH { + "false" { + Object.Base.route [ + { + source "gain.21.1" + sink "virtual.sdw-amp" + } + ] + } + "true" { + Object.Base.route [ + { + source "host-copier.2.playback" + sink "virtual.sdw-amp" + } + ] + } + } + Object.Base.route [ + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.2" + } + ] + } +} + +Object.PCM.pcm [ + { + name "Speaker" + id 2 + direction "playback" + Object.Base.fe_dai.1 { + name "Speaker" + } + + Object.PCM.pcm_caps.1 { + name "sdw amplifiers" + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } + } + } +] + +IncludeByKey.PASSTHROUGH { +"false" { + IncludeByKey.SDW_SPK_ENHANCED_PLAYBACK { + "true" { + Object.Base.route [ + { + source "dts.21.1" + sink "module-copier.21.22" + } + { + source "module-copier.21.22" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] + } + "false" { + Object.Base.route [ + { + source "gain.21.1" + sink "module-copier.21.22" + } + { + source "module-copier.21.22" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] + } + } + Object.Base.route [ + { + source 'mixin.20.1' + sink 'mixout.21.1' + } + { + source 'host-copier.2.playback' + sink 'gain.20.1' + } + ] +} +"true" { + Object.Base.route [ + { + source "host-copier.2.playback" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] +} +} + +IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + Object.Dai.ALH [ + { + dai_index 30 + id $SDW_AMP_IN_BE_ID + direction "capture" + name $SDW_SPK_IN_STREAM + default_hw_conf_id 1 + rate 48000 + channels $AMP_FEEDBACK_CH_PER_LINK + + Object.Base.hw_config.1 { + id 1 + name "ALH515" + } + } + ] + Object.Pipeline { + host-gateway-capture [ + { + index 30 + + Object.Widget.host-copier.1 { + stream_name "amp feedback" + pcm_id 3 + + IncludeByKey.AMP_FEEDBACK_CH { + "6" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 6 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + } + "8" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 8 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + } + } + } + } + ] + } + Object.Widget { + alh-copier [ + { + index 31 + stream_name $SDW_SPK_IN_STREAM + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "4" { + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + } + ] + } + ] + pipeline [ + { + index 31 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + } + Object.PCM.pcm [ + { + name "Amp feedback" + id 3 + direction "capture" + Object.Base.fe_dai.1 { + name "Amp feedback" + } + + Object.PCM.pcm_caps.1 { + name "amp feedback" + formats 'S16_LE,S24_LE,S32_LE' + channels_min $AMP_FEEDBACK_CH + channels_max $AMP_FEEDBACK_CH + } + } + ] + Object.Base.route [ + { + source "alh-copier.$SDW_SPK_IN_STREAM.0" + sink "host-copier.3.capture" + } + ] + } +} diff --git a/tools/topology/topology2/platform/intel/sdw-amp-echo-ref.conf b/tools/topology/topology2/platform/intel/sdw-amp-echo-ref.conf new file mode 100644 index 000000000000..abde20519f2e --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-amp-echo-ref.conf @@ -0,0 +1,52 @@ +Define { + SDW_SPK_ECHO_REF_PCM_ID 12 + SDW_SPK_ECHO_REF_PIPELINE_ID 120 +} + +IncludeByKey.SDW_SPK_ECHO_REF { + "true" { + Object.Pipeline { + siggen-host-copier-capture [ + { + direction "capture" + index $SDW_SPK_ECHO_REF_PIPELINE_ID + Object.Widget.host-copier."1" { + stream_name "Speaker Echo Reference" + pcm_id $SDW_SPK_ECHO_REF_PCM_ID + } + Object.Widget.siggen."1" {} + } + ] + } + + Object.PCM.pcm [ + { + name "Speaker Echo Reference" + id $SDW_SPK_ECHO_REF_PCM_ID + direction "capture" + Object.Base.fe_dai.1 { + name "Speaker Echo Reference" + } + Object.PCM.pcm_caps.1 { + name "Speaker Echo Reference" + formats 'S16_LE,S24_LE,S32_LE' + } + } + ] + + Object.Base.route [ + { + source "alh-copier.Loopback_Virtual.25" + sink "siggen.$SDW_SPK_ECHO_REF_PIPELINE_ID.1" + } + { + source "module-copier.21.22" + sink "siggen.$SDW_SPK_ECHO_REF_PIPELINE_ID.1" + } + { + source "siggen.$SDW_SPK_ECHO_REF_PIPELINE_ID.1" + sink "host-copier.$SDW_SPK_ECHO_REF_PCM_ID.capture" + } + ] + } # SDW_SPK_ECHO_REF true +} diff --git a/tools/topology/topology2/platform/intel/sdw-amp-generic-ctc.conf b/tools/topology/topology2/platform/intel/sdw-amp-generic-ctc.conf new file mode 100644 index 000000000000..5844a0c40729 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-amp-generic-ctc.conf @@ -0,0 +1,853 @@ +# route and pipeline index start from pcm id * 10 + +Define { + SDW_SPK_STREAM 'SDW1-Playback' + SDW_SPK_IN_STREAM 'SDW1-Capture' + ALH_2ND_SPK_ID 22 + ALH_3RD_SPK_ID 23 + ALH_2ND_SPK_IN_ID 32 + ALH_3RD_SPK_IN_ID 33 + SDW_AMP_BE_ID 2 + SDW_AMP_IN_BE_ID 3 + AMP_FEEDBACK_CH 2 + AMP_FEEDBACK_CH_PER_LINK 2 + SDW_AMP_FEEDBACK true + AMP_PLAYBACK_NAME 'Speaker Playback' +} + +Object.Dai.ALH [ + { + dai_index 20 + id $SDW_AMP_BE_ID + direction "playback" + name $SDW_SPK_STREAM + default_hw_conf_id 0 + rate 48000 + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH514" + } + } +] + +IncludeByKey.PASSTHROUGH { +"false" { + Object.Pipeline { + host-copier-gain-mixin-playback [ + { + index 20 + + Object.Widget.host-copier.1 { + stream_name "sdw amplifiers" + pcm_id 2 + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $AMP_PLAYBACK_NAME Volume' + } + } + } + ] + + IncludeByKey.SDW_SPK_ENHANCED_PLAYBACK { + "true" { + mixout-gain-eqiir-eqfir-drc-alh-dai-copier-playback [ + { + index 21 + + Object.Widget.alh-copier.1 { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $AMP_PLAYBACK_NAME Volume' + } + } + + Object.Widget.eqiir.1 { + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME IIR Eq bytes' + } + } + Object.Widget.eqfir.1 { + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME FIR Eq bytes' + } + } + Object.Widget.drc.1 { + Object.Control { + bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME DRC bytes' + } + mixer."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME DRC switch' + } + } + } + } + ] + } + "false" { + mixout-gain-ctc-alh-dai-copier-playback [ + { + index 21 + + Object.Widget.alh-copier.1 { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $AMP_PLAYBACK_NAME Volume' + } + } + Object.Widget.ctc.1 { + Object.Control { + mixer."1" { + name 'CTC Switch' + } + bytes."1" { + name 'CTC.0' + max 4160 + } + } + } + } + ] + } + } + + } + } +"true" { + Object.Pipeline.host-gateway-playback [ + { + index 20 + Object.Widget.host-copier.1 { + stream_name "sdw amplifiers" + pcm_id 2 + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 3 + 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 + } + ] + } + } + ] + + Object.Widget { + alh-copier [ + { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_pins 1 + direction playback + type dai_in + index 21 + num_input_audio_formats 3 + 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 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + pipeline [ + { + index 21 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + } + } +} + +IncludeByKey.NUM_SDW_AMP_CTC_LINKS { +"2" { + Define { + AMP_FEEDBACK_CH 4 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + # Add a virtual widget to connect the aggregated 2nd DAI copier + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + ] + } + + # Add the connection from the gain module to the aggregated 2nd DAI copier + # via the virtual widget. The virtual widget ensures that the routes between + # the gain and copier do not get established in the firmware. These are purely + # to show the existence of aggregation in the topology graph. + IncludeByKey.PASSTHROUGH { + "false" { + Object.Base.route [ + { + source "gain.21.1" + sink "virtual.sdw-amp" + } + ] + } + "true" { + Object.Base.route [ + { + source "host-copier.2.playback" + sink "virtual.sdw-amp" + } + ] + } + } + Object.Base.route [ + { + source "virtual.sdw-amp" + sink "ctc.21.1" + } + { + source "ctc.21.1" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + ] + } + +"3" { + Define { + AMP_FEEDBACK_CH 6 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + { + index $ALH_3RD_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 2 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + { + index $ALH_3RD_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 2 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + { + name 'virtual.sdw-amp' + type output + index $ALH_3RD_SPK_ID + } + ] + } + + # Add the connection from the gain module to the aggregated 2nd DAI copier + # via the virtual widget. The virtual widget ensures that the routes between + # the gain and copier do not get established in the firmware. These are purely + # to show the existence of aggregation in the topology graph. + IncludeByKey.PASSTHROUGH { + "false" { + Object.Base.route [ + { + source "gain.21.1" + sink "virtual.sdw-amp" + } + ] + } + "true" { + Object.Base.route [ + { + source "host-copier.2.playback" + sink "virtual.sdw-amp" + } + ] + } + } + Object.Base.route [ + { + source "virtual.sdw-amp" + sink "ctc.21.1" + } + { + source "ctc.21.1" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + { + source "ctc.21.1" + sink "alh-copier.$SDW_SPK_STREAM.2" + } + ] + } +} + +Object.PCM.pcm [ + { + name "Speaker" + id 2 + direction "playback" + Object.Base.fe_dai.1 { + name "Speaker" + } + + Object.PCM.pcm_caps.1 { + name "sdw amplifiers" + formats 'S16_LE,S24_LE,S32_LE' + } + } +] + +IncludeByKey.PASSTHROUGH { +"false" { + IncludeByKey.SDW_SPK_ENHANCED_PLAYBACK { + "true" { + Object.Base.route [ + { + source "drc.21.1" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] + } + "false" { + Object.Base.route [ + { + source "gain.21.1" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] + } + } + Object.Base.route [ + { + source 'mixin.20.1' + sink 'mixout.21.1' + } + { + source 'host-copier.2.playback' + sink 'gain.20.1' + } + ] +} +"true" { + Object.Base.route [ + { + source "host-copier.2.playback" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] +} +} + +IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + Object.Dai.ALH [ + { + dai_index 30 + id $SDW_AMP_IN_BE_ID + direction "capture" + name $SDW_SPK_IN_STREAM + default_hw_conf_id 1 + rate 48000 + channels $AMP_FEEDBACK_CH_PER_LINK + + Object.Base.hw_config.1 { + id 1 + name "ALH515" + } + } + ] + Object.Pipeline { + host-gateway-capture [ + { + index 30 + + Object.Widget.host-copier.1 { + stream_name "amp feedback" + pcm_id 3 + + IncludeByKey.AMP_FEEDBACK_CH { + "6" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 6 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + } + "8" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 8 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + } + } + } + } + ] + } + Object.Widget { + alh-copier [ + { + index 31 + type dai_out + stream_name $SDW_SPK_IN_STREAM + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "4" { + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + } + ] + } + ] + pipeline [ + { + index 31 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + } + Object.PCM.pcm [ + { + name "Amp feedback" + id 3 + direction "capture" + Object.Base.fe_dai.1 { + name "Amp feedback" + } + + Object.PCM.pcm_caps.1 { + name "amp feedback" + formats 'S16_LE,S24_LE,S32_LE' + channels_min $AMP_FEEDBACK_CH + channels_max $AMP_FEEDBACK_CH + } + } + ] + Object.Base.route [ + { + source "alh-copier.$SDW_SPK_IN_STREAM.0" + sink "host-copier.3.capture" + } + ] + } +} diff --git a/tools/topology/topology2/platform/intel/sdw-amp-generic.conf b/tools/topology/topology2/platform/intel/sdw-amp-generic.conf index 303db9515253..d4913ca7dd4f 100644 --- a/tools/topology/topology2/platform/intel/sdw-amp-generic.conf +++ b/tools/topology/topology2/platform/intel/sdw-amp-generic.conf @@ -15,6 +15,27 @@ Define { AMP_PLAYBACK_NAME 'Speaker Playback' } +# include deep buffer config if buffer size is in 1 - 1000 ms. +IncludeByKey.PASSTHROUGH { +"false" { + IncludeByKey.DEEPBUFFER_FW_DMA_MS { + "([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|1000)" { + IncludeByKey.DEEP_BUF_SPK { + "true" { + #deep-buffer-spk.conf is included in deep-buffer.conf + #and deep-buffer.conf is included if SDW_JACK is true. + #Therefore, only include deep-buffer-spk.conf when + #SDW_JACK is false to avoid duplicated. + IncludeByKey.SDW_JACK { + "false" "platform/intel/deep-buffer-spk.conf" + } + } + } + } + } +} +} + Object.Dai.ALH [ { dai_index 20 @@ -32,6 +53,26 @@ Object.Dai.ALH [ } ] +Object.Widget.module-copier."22" { + index 21 + num_input_pins 1 + num_output_pins 2 + 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 + } + ] +} + IncludeByKey.PASSTHROUGH { "false" { Object.Pipeline { @@ -42,6 +83,52 @@ IncludeByKey.PASSTHROUGH { Object.Widget.host-copier.1 { stream_name "sdw amplifiers" pcm_id 2 + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_input_audio_formats 5 + 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 32 + in_valid_bit_depth 24 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_bit_depth 8 + in_valid_bit_depth 8 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_input_audio_formats 3 + 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.Widget.gain.1 { Object.Control.mixer.1 { @@ -300,6 +387,7 @@ IncludeByKey.NUM_SDW_AMP_LINKS { Object.Base.input_audio_format [ { + in_channels $AMP_FEEDBACK_CH in_bit_depth 32 in_valid_bit_depth $SDW_LINK_VALID_BITS in_sample_type $SAMPLE_TYPE_MSB_INTEGER @@ -308,6 +396,7 @@ IncludeByKey.NUM_SDW_AMP_LINKS { ] Object.Base.output_audio_format [ { + out_channels $AMP_FEEDBACK_CH out_bit_depth 32 out_valid_bit_depth 32 } @@ -448,6 +537,7 @@ IncludeByKey.NUM_SDW_AMP_LINKS { Object.Base.input_audio_format [ { + in_channels $AMP_FEEDBACK_CH in_bit_depth 32 in_valid_bit_depth $SDW_LINK_VALID_BITS in_sample_type $SAMPLE_TYPE_MSB_INTEGER @@ -456,6 +546,7 @@ IncludeByKey.NUM_SDW_AMP_LINKS { ] Object.Base.output_audio_format [ { + out_channels $AMP_FEEDBACK_CH out_bit_depth 32 out_valid_bit_depth 32 } @@ -475,6 +566,7 @@ IncludeByKey.NUM_SDW_AMP_LINKS { Object.Base.input_audio_format [ { + in_channels $AMP_FEEDBACK_CH in_bit_depth 32 in_valid_bit_depth $SDW_LINK_VALID_BITS in_sample_type $SAMPLE_TYPE_MSB_INTEGER @@ -483,6 +575,7 @@ IncludeByKey.NUM_SDW_AMP_LINKS { ] Object.Base.output_audio_format [ { + out_channels $AMP_FEEDBACK_CH out_bit_depth 32 out_valid_bit_depth 32 } @@ -577,50 +670,65 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name "sdw amplifiers" - formats 'S16_LE,S24_LE,S32_LE' + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } } } ] IncludeByKey.PASSTHROUGH { -"false" { - IncludeByKey.SDW_SPK_ENHANCED_PLAYBACK { - "true" { - Object.Base.route [ - { - source "drc.21.1" - sink "alh-copier.$SDW_SPK_STREAM.0" - } - ] - } - "false" { - Object.Base.route [ - { - source "gain.21.1" - sink "alh-copier.$SDW_SPK_STREAM.0" - } - ] - } - } - Object.Base.route [ - { - source 'mixin.20.1' - sink 'mixout.21.1' - } - { - source 'host-copier.2.playback' - sink 'gain.20.1' - } - ] -} -"true" { - Object.Base.route [ - { - source "host-copier.2.playback" - sink "alh-copier.$SDW_SPK_STREAM.0" + "false" { + IncludeByKey.SDW_SPK_ENHANCED_PLAYBACK { + "true" { + Object.Base.route [ + { + source "drc.21.1" + sink "module-copier.21.22" + } + { + source "module-copier.21.22" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] + } + "false" { + Object.Base.route [ + { + source "gain.21.1" + sink "module-copier.21.22" + } + { + source "module-copier.21.22" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] + } } - ] -} + Object.Base.route [ + { + source 'mixin.20.1' + sink 'mixout.21.1' + } + { + source 'host-copier.2.playback' + sink 'gain.20.1' + } + ] + } + "true" { + Object.Base.route [ + { + source "host-copier.2.playback" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + ] + } } IncludeByKey.SDW_AMP_FEEDBACK { diff --git a/tools/topology/topology2/platform/intel/sdw-amp-xover.conf b/tools/topology/topology2/platform/intel/sdw-amp-xover.conf new file mode 100644 index 000000000000..3347d4911bc4 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-amp-xover.conf @@ -0,0 +1,1003 @@ +# route and pipeline index start from pcm id * 10 + +Define { + SDW_SPK_STREAM 'SDW1-Playback' + SDW_SPK_IN_STREAM 'SDW1-Capture' + ALH_2ND_SPK_ID 22 + ALH_3RD_SPK_ID 23 + ALH_2ND_SPK_IN_ID 32 + ALH_3RD_SPK_IN_ID 33 + SDW_AMP_BE_ID 2 + SDW_AMP_IN_BE_ID 3 + AMP_FEEDBACK_CH 2 + AMP_FEEDBACK_CH_PER_LINK 2 + SDW_AMP_FEEDBACK true + AMP_PLAYBACK_NAME 'Speaker Playback' +} + +Object.Dai.ALH [ + { + dai_index 20 + id $SDW_AMP_BE_ID + direction "playback" + name $SDW_SPK_STREAM + default_hw_conf_id 0 + rate 48000 + + Object.Base.hw_config.1 { + id 0 + name "ALH514" + } + } +] + +Object.Pipeline { + host-copier-gain-mixin-playback [ + { + index 20 + + Object.Widget.host-copier.1 { + stream_name "sdw amplifiers" + pcm_id 2 + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $AMP_PLAYBACK_NAME Volume' + } + } + } + ] + + IncludeByKey.SDW_SPK_ENHANCED_PLAYBACK { + "true" { + mixout-gain-eqiir-eqfir-drc-micsel-eqiir-eqfir-alh-dai-copier-playback [ + { + index 21 + Object.Widget.alh-copier.1 { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_channels $SDW_AMP_NUM_CHANNELS + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "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_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_channels $SDW_AMP_NUM_CHANNELS + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $AMP_PLAYBACK_NAME Volume' + } + } + Object.Widget.eqiir.1 { + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME IIR Eq bytes' + } + } + Object.Widget.eqfir.1 { + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME FIR Eq bytes' + } + } + Object.Widget.drc.1 { + Object.Control { + bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME DRC bytes' + } + mixer."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME DRC switch' + } + } + } + Object.Widget.micsel.1 { + 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 [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + } + out_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME Xover Selector bytes' + } + } + Object.Widget.eqiir.2 { + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "4" { + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + } + in_channels $SDW_AMP_NUM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + } + out_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME Xover IIR bytes' + } + } + Object.Widget.eqfir.2 { + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "4" { + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + } + in_channels $SDW_AMP_NUM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + } + out_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME Xover FIR bytes' + } + } + } + ] + } + "false" { + mixout-gain-micsel-eqiir-eqfir-alh-dai-copier-playback [ + { + index 21 + Object.Widget.alh-copier.1 { + stream_name $SDW_SPK_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_channels $SDW_AMP_NUM_CHANNELS + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "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_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_channels $SDW_AMP_NUM_CHANNELS + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $AMP_PLAYBACK_NAME Volume' + } + } + Object.Widget.micsel.1 { + 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 [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + } + out_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME Xover Selector bytes' + } + } + Object.Widget.eqiir.2 { + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "4" { + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + } + in_channels $SDW_AMP_NUM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + } + out_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME Xover IIR bytes' + } + } + Object.Widget.eqfir.2 { + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "4" { + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + } + in_channels $SDW_AMP_NUM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + } + out_channels $SDW_AMP_NUM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + Object.Control.bytes."1" { + name 'Post Mixer $AMP_PLAYBACK_NAME Xover FIR bytes' + } + } + } + ] + } + } +} + +IncludeByKey.NUM_SDW_AMP_LINKS { +"2" { + Define { + AMP_FEEDBACK_CH 4 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 1 + Object.Base.input_audio_format [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "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_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + IncludeByKey.SDW_AMP_NUM_CHANNELS { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + # Add a virtual widget to connect the aggregated 2nd DAI copier + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + ] + } + + # Add the connection from the gain module to the aggregated 2nd DAI copier + # via the virtual widget. The virtual widget ensures that the routes between + # the gain and copier do not get established in the firmware. These are purely + # to show the existence of aggregation in the topology graph. + Object.Base.route [ + { + source "eqfir.21.2" + sink "virtual.sdw-amp" + } + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + ] + } + +"3" { + Define { + AMP_FEEDBACK_CH 6 + AMP_FEEDBACK_CH_PER_LINK 2 + } + + Object.Widget { + alh-copier [ + { + index $ALH_2ND_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 1 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + { + index $ALH_3RD_SPK_ID + type dai_in + stream_name $SDW_SPK_STREAM + dai_index 2 + type "dai_in" + direction "playback" + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 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 $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + alh-copier [ + { + index $ALH_2ND_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 1 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + { + index $ALH_3RD_SPK_IN_ID + type dai_out + stream_name $SDW_SPK_IN_STREAM + dai_index 2 + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_channels $AMP_FEEDBACK_CH + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + } + } + pipeline [ + { + index $ALH_2ND_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_2ND_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + { + index $ALH_3RD_SPK_IN_ID + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + virtual [ + { + name 'virtual.sdw-amp' + type output + index $ALH_2ND_SPK_ID + } + { + name 'virtual.sdw-amp' + type output + index $ALH_3RD_SPK_ID + } + ] + } + + # Add the connection from the gain module to the aggregated 2nd DAI copier + # via the virtual widget. The virtual widget ensures that the routes between + # the gain and copier do not get established in the firmware. These are purely + # to show the existence of aggregation in the topology graph. + Object.Base.route [ + { + source "gain.21.1" + sink "virtual.sdw-amp" + } + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.1" + } + { + source "virtual.sdw-amp" + sink "alh-copier.$SDW_SPK_STREAM.2" + } + ] + } +} + +Object.PCM.pcm [ + { + name "Speaker" + id 2 + direction "playback" + Object.Base.fe_dai.1 { + name "Speaker" + } + + Object.PCM.pcm_caps.1 { + name "sdw amplifiers" + formats 'S16_LE,S24_LE,S32_LE' + } + } +] + +Object.Base.route [ + { + source "eqfir.21.2" + sink "alh-copier.$SDW_SPK_STREAM.0" + } + { + source 'mixin.20.1' + sink 'mixout.21.1' + } + { + source 'host-copier.2.playback' + sink 'gain.20.1' + } +] + +IncludeByKey.SDW_AMP_FEEDBACK { + "true" { + Object.Dai.ALH [ + { + dai_index 30 + id $SDW_AMP_IN_BE_ID + direction "capture" + name $SDW_SPK_IN_STREAM + default_hw_conf_id 1 + rate 48000 + channels $AMP_FEEDBACK_CH_PER_LINK + + Object.Base.hw_config.1 { + id 1 + name "ALH515" + } + } + ] + Object.Pipeline { + host-gateway-capture [ + { + index 30 + + Object.Widget.host-copier.1 { + stream_name "amp feedback" + pcm_id 3 + + IncludeByKey.AMP_FEEDBACK_CH { + "4" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 4 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 4 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_channels 4 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_channels 4 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + } + "6" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 6 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + { + out_channels 6 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + ] + } + "8" { + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels 8 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + { + out_channels 8 + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + ] + } + } + } + } + ] + } + Object.Widget { + alh-copier [ + { + index 31 + type dai_out + stream_name $SDW_SPK_IN_STREAM + type "dai_out" + direction "capture" + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_channels $AMP_FEEDBACK_CH + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + in_ch_cfg $CHANNEL_CONFIG_STEREO + in_ch_map $CHANNEL_MAP_STEREO + } + "4" { + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + in_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + in_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + in_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + in_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_channels $AMP_FEEDBACK_CH + out_bit_depth 32 + out_valid_bit_depth 32 + + IncludeByKey.AMP_FEEDBACK_CH { + "2" { + out_ch_cfg $CHANNEL_CONFIG_STEREO + out_ch_map $CHANNEL_MAP_STEREO + } + "4" { + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + "6" { + out_ch_cfg $CHANNEL_CONFIG_5_POINT_1 + out_ch_map $CHANNEL_MAP_5_POINT_1 + } + "8" { + out_ch_cfg $CHANNEL_CONFIG_7_POINT_1 + out_ch_map $CHANNEL_MAP_7_POINT_1 + } + } + } + ] + } + ] + pipeline [ + { + index 31 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + } + Object.PCM.pcm [ + { + name "Amp feedback" + id 3 + direction "capture" + Object.Base.fe_dai.1 { + name "Amp feedback" + } + + Object.PCM.pcm_caps.1 { + name "amp feedback" + formats 'S16_LE,S24_LE,S32_LE' + channels_min $AMP_FEEDBACK_CH + channels_max $AMP_FEEDBACK_CH + } + } + ] + Object.Base.route [ + { + source "alh-copier.$SDW_SPK_IN_STREAM.0" + sink "host-copier.3.capture" + } + ] + } +} diff --git a/tools/topology/topology2/platform/intel/sdw-dmic-audio-feature-compress.conf b/tools/topology/topology2/platform/intel/sdw-dmic-audio-feature-compress.conf new file mode 100644 index 000000000000..9e307043830b --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-dmic-audio-feature-compress.conf @@ -0,0 +1,71 @@ +Define { + SDW_DMIC_MODULE_COPIER_ID 41 + SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PCM_NAME "Microphone Compress Audio Features" + SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PCM_ID 54 + SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_STREAM_NAME "Microphone Compress Audio Features Stream" + SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PIPELINE_ID 133 + # MFCC compress output frame size in bytes: + # Mel-only (80 bins): 24 + 80*4 = 344 + # Cepstral (13 ceps): 24 + 13*4 = 76 + MFCC_FRAME_BYTES 344 + # MFCC config blob: mel or ceps + MFCC_BLOB mel +} + +Object.Pipeline.host-gateway-src-mfcc-capture [ + { + index $SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name "$SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_STREAM_NAME" + pcm_id $SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PCM_ID + } + + Object.Widget.mfcc.1 { + type "encoder" + Object.Control { + bytes."1" { + name "$SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PCM_NAME MFCC bytes" + IncludeByKey.MFCC_BLOB { + "mel" "include/components/mfcc/mel80_compress_dtx.conf" + "ceps" "include/components/mfcc/ceps13_compress_dtx.conf" + } + } + mixer."1" { + name "$SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PCM_NAME MFCC VAD" + } + } + } + } +] +Object.Base.route [ + { + source "module-copier.$SDW_DMIC_MODULE_COPIER_ID.0" + sink "src.$SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PIPELINE_ID.1" + } + { + source "mfcc.$SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PIPELINE_ID.1" + sink "host-copier.$SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PCM_ID.capture" + } +] + +Object.PCM.pcm [ + { + name "$SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PCM_NAME" + id $SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PCM_ID + direction "capture" + compress "true" + + Object.Base.fe_dai.1 { + name "$SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "$SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE_STREAM_NAME" + formats 'S32_LE' + rates '16000' + channels_min 2 + channels_max 2 + } + } +] diff --git a/tools/topology/topology2/platform/intel/sdw-dmic-audio-feature.conf b/tools/topology/topology2/platform/intel/sdw-dmic-audio-feature.conf new file mode 100644 index 000000000000..7d39c11772c1 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-dmic-audio-feature.conf @@ -0,0 +1,62 @@ +Define { + SDW_DMIC_MODULE_COPIER_ID 41 + SDW_DMIC_AUDIO_FEATURE_CAPTURE_PCM_NAME "Microphone Audio Features" + SDW_DMIC_AUDIO_FEATURE_CAPTURE_PCM_ID 48 + SDW_DMIC_AUDIO_FEATURE_CAPTURE_STREAM_NAME "Microphone Audio Features Stream" + SDW_DMIC_AUDIO_FEATURE_CAPTURE_PIPELINE_ID 131 + # MFCC output frame size in bytes (24-byte header + coefficients): + # Mel-only (80 bins): 24 + 80*4 = 344 + MFCC_FRAME_BYTES 344 +} + +Object.Pipeline.host-gateway-src-mfcc-capture [ + { + index $SDW_DMIC_AUDIO_FEATURE_CAPTURE_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name "$SDW_DMIC_AUDIO_FEATURE_CAPTURE_STREAM_NAME" + pcm_id $SDW_DMIC_AUDIO_FEATURE_CAPTURE_PCM_ID + } + + Object.Widget.mfcc.1 { + Object.Control { + bytes."1" { + name "$SDW_DMIC_AUDIO_FEATURE_CAPTURE_PCM_NAME MFCC bytes" + <include/components/mfcc/mel80.conf> + } + mixer."1" { + name "$SDW_DMIC_AUDIO_FEATURE_CAPTURE_PCM_NAME MFCC VAD" + } + } + } + } +] +Object.Base.route [ + { + source "module-copier.$SDW_DMIC_MODULE_COPIER_ID.0" + sink "src.$SDW_DMIC_AUDIO_FEATURE_CAPTURE_PIPELINE_ID.1" + } + { + source "mfcc.$SDW_DMIC_AUDIO_FEATURE_CAPTURE_PIPELINE_ID.1" + sink "host-copier.$SDW_DMIC_AUDIO_FEATURE_CAPTURE_PCM_ID.capture" + } +] + +Object.PCM.pcm [ + { + name "$SDW_DMIC_AUDIO_FEATURE_CAPTURE_PCM_NAME" + id $SDW_DMIC_AUDIO_FEATURE_CAPTURE_PCM_ID + direction "capture" + Object.Base.fe_dai.1 { + name "$SDW_DMIC_AUDIO_FEATURE_CAPTURE_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "$SDW_DMIC_AUDIO_FEATURE_CAPTURE_STREAM_NAME" + formats 'S32_LE' + rates '16000' + channels_min 2 + channels_max 2 + } + } +] diff --git a/tools/topology/topology2/platform/intel/sdw-dmic-generic.conf b/tools/topology/topology2/platform/intel/sdw-dmic-generic.conf index 7f1fe52fbbda..f8fc51303966 100644 --- a/tools/topology/topology2/platform/intel/sdw-dmic-generic.conf +++ b/tools/topology/topology2/platform/intel/sdw-dmic-generic.conf @@ -36,7 +36,53 @@ IncludeByKey.SDW_DMIC_ENHANCED_CAPTURE { Object.Widget.host-copier.1 { stream_name "sdw dmic" pcm_id 4 - } + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_output_audio_formats 5 + 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 32 + out_valid_bit_depth 24 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_sample_type $SAMPLE_TYPE_FLOAT + } + { + out_bit_depth 8 + out_valid_bit_depth 8 + out_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_output_audio_formats 3 + 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 + } + ] + } + } + } Object.Widget.tdfb.1 { Object.Control { @@ -180,7 +226,14 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name "sdw dmic" - formats 'S16_LE,S24_LE,S32_LE' + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } } } ] diff --git a/tools/topology/topology2/platform/intel/sdw-jack-audio-feature-compress.conf b/tools/topology/topology2/platform/intel/sdw-jack-audio-feature-compress.conf new file mode 100644 index 000000000000..286af8be0323 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-jack-audio-feature-compress.conf @@ -0,0 +1,71 @@ +Define { + SDW_JACK_MODULE_COPIER_ID 11 + SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PCM_NAME "Jack In Compress Audio Features" + SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PCM_ID 53 + SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_STREAM_NAME "Jack In Compress Audio Features Stream" + SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PIPELINE_ID 132 + # MFCC compress output frame size in bytes: + # Mel-only (80 bins): 24 + 80*4 = 344 + # Cepstral (13 ceps): 24 + 13*4 = 76 + MFCC_FRAME_BYTES 344 + # MFCC config blob: mel or ceps + MFCC_BLOB mel +} + +Object.Pipeline.host-gateway-src-mfcc-capture [ + { + index $SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name "$SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_STREAM_NAME" + pcm_id $SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PCM_ID + } + + Object.Widget.mfcc.1 { + type "encoder" + Object.Control { + bytes."1" { + name "$SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PCM_NAME MFCC bytes" + IncludeByKey.MFCC_BLOB { + "mel" "include/components/mfcc/mel80_compress_dtx.conf" + "ceps" "include/components/mfcc/ceps13_compress_dtx.conf" + } + } + mixer."1" { + name "$SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PCM_NAME MFCC VAD" + } + } + } + } +] +Object.Base.route [ + { + source "module-copier.$SDW_JACK_MODULE_COPIER_ID.0" + sink "src.$SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PIPELINE_ID.1" + } + { + source "mfcc.$SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PIPELINE_ID.1" + sink "host-copier.$SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PCM_ID.capture" + } +] + +Object.PCM.pcm [ + { + name "$SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PCM_NAME" + id $SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PCM_ID + direction "capture" + compress "true" + + Object.Base.fe_dai.1 { + name "$SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "$SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE_STREAM_NAME" + formats 'S32_LE' + rates '16000' + channels_min $SDW_JACK_CAPTURE_CH + channels_max $SDW_JACK_CAPTURE_CH + } + } +] diff --git a/tools/topology/topology2/platform/intel/sdw-jack-audio-feature.conf b/tools/topology/topology2/platform/intel/sdw-jack-audio-feature.conf new file mode 100644 index 000000000000..a0a44eae4d87 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-jack-audio-feature.conf @@ -0,0 +1,62 @@ +Define { + SDW_JACK_MODULE_COPIER_ID 11 + SDW_JACK_AUDIO_FEATURE_CAPTURE_PCM_NAME "Jack In Audio Features" + SDW_JACK_AUDIO_FEATURE_CAPTURE_PCM_ID 47 + SDW_JACK_AUDIO_FEATURE_CAPTURE_STREAM_NAME "Jack In Audio Features Stream" + SDW_JACK_AUDIO_FEATURE_CAPTURE_PIPELINE_ID 130 + # MFCC output frame size in bytes (24-byte header + coefficients): + # Mel-only (80 bins): 24 + 80*4 = 344 + MFCC_FRAME_BYTES 344 +} + +Object.Pipeline.host-gateway-src-mfcc-capture [ + { + index $SDW_JACK_AUDIO_FEATURE_CAPTURE_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name "$SDW_JACK_AUDIO_FEATURE_CAPTURE_STREAM_NAME" + pcm_id $SDW_JACK_AUDIO_FEATURE_CAPTURE_PCM_ID + } + + Object.Widget.mfcc.1 { + Object.Control { + bytes."1" { + name "$SDW_JACK_AUDIO_FEATURE_CAPTURE_PCM_NAME MFCC bytes" + <include/components/mfcc/mel80.conf> + } + mixer."1" { + name "$SDW_JACK_AUDIO_FEATURE_CAPTURE_PCM_NAME MFCC VAD" + } + } + } + } +] +Object.Base.route [ + { + source "module-copier.$SDW_JACK_MODULE_COPIER_ID.0" + sink "src.$SDW_JACK_AUDIO_FEATURE_CAPTURE_PIPELINE_ID.1" + } + { + source "mfcc.$SDW_JACK_AUDIO_FEATURE_CAPTURE_PIPELINE_ID.1" + sink "host-copier.$SDW_JACK_AUDIO_FEATURE_CAPTURE_PCM_ID.capture" + } +] + +Object.PCM.pcm [ + { + name "$SDW_JACK_AUDIO_FEATURE_CAPTURE_PCM_NAME" + id $SDW_JACK_AUDIO_FEATURE_CAPTURE_PCM_ID + direction "capture" + Object.Base.fe_dai.1 { + name "$SDW_JACK_AUDIO_FEATURE_CAPTURE_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "$SDW_JACK_AUDIO_FEATURE_CAPTURE_STREAM_NAME" + formats 'S32_LE' + rates '16000' + channels_min $SDW_JACK_CAPTURE_CH + channels_max $SDW_JACK_CAPTURE_CH + } + } +] diff --git a/tools/topology/topology2/platform/intel/sdw-jack-dax.conf b/tools/topology/topology2/platform/intel/sdw-jack-dax.conf new file mode 100644 index 000000000000..9816d85b2018 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-jack-dax.conf @@ -0,0 +1,517 @@ +# include deep buffer config if buffer size is in 1 - 1000 ms. +IncludeByKey.DEEPBUFFER_FW_DMA_MS { + "([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|1000)" "platform/intel/deep-buffer.conf" +} + +Define { + JACK_PLAYBACK_PCM_NAME "Jack Out" + JACK_CAPTURE_PCM_NAME "Jack In" + JACK_RATE 48000 +} + +# +# List of all DAIs +# +Object.Dai.ALH [ + { + dai_index 0 + id $SDW_JACK_OUT_BE_ID + direction "playback" + name $SDW_JACK_OUT_STREAM + default_hw_conf_id 0 + rate $JACK_RATE + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH2" + } + } + { + dai_index 10 + id $SDW_JACK_IN_BE_ID + direction "capture" + name $SDW_JACK_IN_STREAM + default_hw_conf_id 0 + rate $JACK_RATE + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH3" + } + } +] + +# +# Pipeline definitions +# +Object.Pipeline { + host-copier-gain-mixin-playback [ + { + index 0 + + Object.Widget.host-copier.1 { + stream_name "volume playback 0" + pcm_id 0 + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_input_audio_formats 5 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_rate $JACK_RATE + in_bit_depth 8 + in_valid_bit_depth 8 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_input_audio_formats 3 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + ] + } + } + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $JACK_PLAYBACK_PCM_NAME Playback Volume' + } + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.mixin.1 { + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + mixout-gain-dax-alh-dai-copier-playback [ + { + index 1 + + Object.Widget.mixout.1 { + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.alh-copier.1 { + stream_name $SDW_JACK_OUT_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 3 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256)) | ($out_sample_type * 65536)]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $JACK_PLAYBACK_PCM_NAME Playback Volume' + } + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.dolby-dax.1 { + core_id $DOLBY_DAX_CORE_ID + Object.Control { + mixer."1" { + name 'DAX Headphone Switch' + } + mixer."2" { + name 'DAX Headphone Switch CP' + } + mixer."3" { + name 'DAX Headphone Switch CTC' + } + mixer."4" { + name 'DAX Headphone Volume' + } + enum."1" { + name 'DAX Headphone Profile' + } + enum."2" { + name 'DAX Headphone Device' + } + bytes."1" { + name 'DAX Headphone Tuning' + max 8192 + } + } + } + } + ] + +} + +Object.Pipeline.host-gateway-capture [ + { + index 10 + + Object.Widget.host-copier.1 { + stream_name "Passthrough Capture 0" + pcm_id 1 + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_output_audio_formats 5 + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + out_sample_type $SAMPLE_TYPE_FLOAT + } + { + out_rate $JACK_RATE + out_bit_depth 8 + out_valid_bit_depth 8 + out_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_output_audio_formats 3 + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + } + } +] + +# Jack capture pipeline widgets +Object.Widget { + module-copier."12" { + index 1 + num_input_pins 1 + num_output_pins 2 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + alh-copier [ + { + stream_name $SDW_JACK_IN_STREAM + direction "capture" + type "dai_out" + index 11 + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + + pipeline [ + { + index 11 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + + Object.Widget.eqiir [ + { + num_input_audio_formats 1 + num_output_audio_formats 1 + # index 11 is inherited from the pipeline definition + # the instance number is automatically generated as '0' + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + + Object.Control.bytes."1" { + <include/components/eqiir/highpass_40hz_0db_48khz.conf> + name '$JACK_CAPTURE_PCM_NAME Capture IIR Eq' + } + } + ] + } + ] +} + +Object.PCM.pcm [ + { + name "$JACK_PLAYBACK_PCM_NAME" + id 0 + direction "playback" + Object.Base.fe_dai.1 { + name "$JACK_PLAYBACK_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "volume playback 0" + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } + IncludeByKey.JACK_RATE { + "48000" { + rates '48000' + } + "96000" { + rates '96000' + } + "192000" { + rates '192000' + } + } + } + } + { + name "$JACK_CAPTURE_PCM_NAME" + id 1 + direction "capture" + Object.Base.fe_dai.1 { + name "$JACK_CAPTURE_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "Passthrough Capture 0" + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } + IncludeByKey.JACK_RATE { + "48000" { + rates '48000' + } + "96000" { + rates '96000' + } + "192000" { + rates '192000' + } + } + channels_min $SDW_JACK_CAPTURE_CH + channels_max $SDW_JACK_CAPTURE_CH + } + } +] + +Object.Base.route [ + { + source "dolby-dax.1.1" + sink "module-copier.1.12" + } + { + source "module-copier.1.12" + sink "alh-copier.$SDW_JACK_OUT_STREAM.0" + } + { + source "mixin.0.1" + sink "mixout.1.1" + } + { + source "alh-copier.$SDW_JACK_IN_STREAM.0" + sink "eqiir.11.0" + } + { + source "eqiir.11.0" + sink "host-copier.1.capture" + } + { + source "host-copier.0.playback" + sink "gain.0.1" + } +] diff --git a/tools/topology/topology2/platform/intel/sdw-jack-dts.conf b/tools/topology/topology2/platform/intel/sdw-jack-dts.conf new file mode 100644 index 000000000000..3a72531d7219 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-jack-dts.conf @@ -0,0 +1,632 @@ +# include deep buffer config if buffer size is in 1 - 1000 ms. +IncludeByKey.PASSTHROUGH { +"false" { + IncludeByKey.DEEPBUFFER_FW_DMA_MS { + "([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|1000)" "platform/intel/deep-buffer.conf" + } +} +} + +Define { + JACK_PLAYBACK_PCM_NAME "Jack Out" + JACK_CAPTURE_PCM_NAME "Jack In" + JACK_RATE 48000 +} + +# +# List of all DAIs +# +Object.Dai.ALH [ + { + dai_index 0 + id $SDW_JACK_OUT_BE_ID + direction "playback" + name $SDW_JACK_OUT_STREAM + default_hw_conf_id 0 + rate $JACK_RATE + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH2" + } + } + { + dai_index 10 + id $SDW_JACK_IN_BE_ID + direction "capture" + name $SDW_JACK_IN_STREAM + default_hw_conf_id 0 + rate $JACK_RATE + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH3" + } + } +] + +# +# Pipeline definitions +# +IncludeByKey.PASSTHROUGH { +"false" { + Object.Pipeline { + host-copier-gain-mixin-playback [ + { + index 0 + + Object.Widget.host-copier.1 { + stream_name "volume playback 0" + pcm_id 0 + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_input_audio_formats 5 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_rate $JACK_RATE + in_bit_depth 8 + in_valid_bit_depth 8 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_input_audio_formats 3 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + ] + } + } + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $JACK_PLAYBACK_PCM_NAME Playback Volume' + } + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.mixin.1 { + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + mixout-gain-eqiir-dts-alh-dai-copier-playback [ + { + index 1 + + Object.Widget.mixout.1 { + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + Object.Widget.alh-copier.1 { + stream_name $SDW_JACK_OUT_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + num_input_audio_formats 3 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256)) | ($out_sample_type * 65536)]" + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $JACK_PLAYBACK_PCM_NAME Playback Volume' + } + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + Object.Widget.eqiir.1 { + Object.Control.bytes."1" { + name 'Post Mixer $JACK_PLAYBACK_PCM_NAME IIR Eq bytes' + } + } + + Object.Widget.dts.1 { + Object.Control { + bytes."1" { + name 'Post Mixer $JACK_PLAYBACK_PCM_NAME DTS bytes' + max 2048 + } + } + } + } + ] + } +} +"true" { + Object.Pipeline.host-gateway-playback [ + { + index 0 + Object.Widget.host-copier.1 { + stream_name "volume playback 0" + pcm_id 0 + num_input_audio_formats 3 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 3 + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + Object.Widget { + alh-copier [ + { + stream_name $SDW_JACK_OUT_STREAM + node_type $ALH_LINK_OUTPUT_CLASS + index 1 + type dai_in + direction playback + num_input_pins 1 + num_input_audio_formats 3 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth $SDW_LINK_VALID_BITS + out_sample_type $SAMPLE_TYPE_MSB_INTEGER + out_fmt_cfg "$[($out_channels | ($out_valid_bit_depth * 256))]" + } + ] + } + ] + pipeline [ + { + index 1 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + } + ] + } + } +} + +Object.Pipeline.host-gateway-capture [ + { + index 10 + + Object.Widget.host-copier.1 { + stream_name "Passthrough Capture 0" + pcm_id 1 + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_output_audio_formats 5 + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + out_sample_type $SAMPLE_TYPE_FLOAT + } + { + out_rate $JACK_RATE + out_bit_depth 8 + out_valid_bit_depth 8 + out_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] + } + "false" { + num_output_audio_formats 3 + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + } + } +] + +# Jack capture pipeline widgets +Object.Widget { + module-copier."12" { + index 1 + num_input_pins 1 + num_output_pins 2 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + alh-copier [ + { + stream_name $SDW_JACK_IN_STREAM + direction "capture" + type "dai_out" + index 11 + node_type $ALH_LINK_INPUT_CLASS + num_input_audio_formats 1 + num_output_audio_formats 1 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth $SDW_LINK_VALID_BITS + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] + + pipeline [ + { + index 11 + priority 0 + lp_mode 0 + dynamic_pipeline 1 + + IncludeByKey.PASSTHROUGH { + "false" { + Object.Widget.eqiir [ + { + num_input_audio_formats 1 + num_output_audio_formats 1 + # index 11 is inherited from the pipeline definition + # the instance number is automatically generated as '0' + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + + Object.Control.bytes."1" { + <include/components/eqiir/highpass_40hz_0db_48khz.conf> + name '$JACK_CAPTURE_PCM_NAME Capture IIR Eq' + } + } + ] + } + } + } + ] +} + +Object.PCM.pcm [ + { + name "$JACK_PLAYBACK_PCM_NAME" + id 0 + direction "playback" + Object.Base.fe_dai.1 { + name "$JACK_PLAYBACK_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "volume playback 0" + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } + IncludeByKey.JACK_RATE { + "48000" { + rates '48000' + } + "96000" { + rates '96000' + } + "192000" { + rates '192000' + } + } + } + } + { + name "$JACK_CAPTURE_PCM_NAME" + id 1 + direction "capture" + Object.Base.fe_dai.1 { + name "$JACK_CAPTURE_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "Passthrough Capture 0" + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } + IncludeByKey.JACK_RATE { + "48000" { + rates '48000' + } + "96000" { + rates '96000' + } + "192000" { + rates '192000' + } + } + channels_min $SDW_JACK_CAPTURE_CH + channels_max $SDW_JACK_CAPTURE_CH + } + } +] + +IncludeByKey.PASSTHROUGH { +"false" { + Object.Base.route [ + { + source "dts.1.1" + sink "module-copier.1.12" + } + { + source "module-copier.1.12" + sink "alh-copier.$SDW_JACK_OUT_STREAM.0" + } + ] + + Object.Base.route [ + { + source "mixin.0.1" + sink "mixout.1.1" + } + { + source "alh-copier.$SDW_JACK_IN_STREAM.0" + sink "eqiir.11.0" + } + { + source "eqiir.11.0" + sink "host-copier.1.capture" + } + { + source "host-copier.0.playback" + sink "gain.0.1" + } + ] + } +"true" { + Object.Base.route [ + { + source "alh-copier.$SDW_JACK_IN_STREAM.0" + sink "host-copier.1.capture" + } + { + source "host-copier.0.playback" + sink "alh-copier.$SDW_JACK_OUT_STREAM.0" + } + ] + } +} diff --git a/tools/topology/topology2/platform/intel/sdw-jack-echo-ref.conf b/tools/topology/topology2/platform/intel/sdw-jack-echo-ref.conf new file mode 100644 index 000000000000..fa506c6b2d46 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-jack-echo-ref.conf @@ -0,0 +1,108 @@ +Define { + SDW_JACK_ECHO_REF_PCM_ID 11 + SDW_JACK_ECHO_REF_PIPELINE_ID 12 +} + +IncludeByKey.SDW_JACK_ECHO_REF { + "true" { + Object.Pipeline { + siggen-host-copier-capture [ + { + direction "capture" + index $SDW_JACK_ECHO_REF_PIPELINE_ID + Object.Widget.host-copier."1" { + stream_name "Jack Echo Reference" + pcm_id $SDW_JACK_ECHO_REF_PCM_ID + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 3 + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.siggen."1" { + num_input_pins 1 + num_output_pins 1 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + } + + Object.PCM.pcm [ + { + name "Jack Echo Reference" + id $SDW_JACK_ECHO_REF_PCM_ID + direction "capture" + Object.Base.fe_dai.1 { + name "Jack Echo Reference" + } + Object.PCM.pcm_caps.1 { + name "Jack Echo Reference" + formats 'S16_LE,S24_LE,S32_LE' + } + IncludeByKey.JACK_RATE { + "48000" { + rates '48000' + } + "96000" { + rates '96000' + } + "192000" { + rates '192000' + } + } + } + ] + + Object.Base.route [ + { + source "alh-copier.Loopback_Virtual.25" + sink "siggen.$SDW_JACK_ECHO_REF_PIPELINE_ID.1" + } + { + source "module-copier.1.12" + sink "siggen.$SDW_JACK_ECHO_REF_PIPELINE_ID.1" + } + { + source "siggen.$SDW_JACK_ECHO_REF_PIPELINE_ID.1" + sink "host-copier.$SDW_JACK_ECHO_REF_PCM_ID.capture" + } + ] + } # SDW_JACK_ECHO_REF true +} diff --git a/tools/topology/topology2/platform/intel/sdw-jack-generic.conf b/tools/topology/topology2/platform/intel/sdw-jack-generic.conf index 99d15eb0aba8..b2e1a259d9a0 100644 --- a/tools/topology/topology2/platform/intel/sdw-jack-generic.conf +++ b/tools/topology/topology2/platform/intel/sdw-jack-generic.conf @@ -60,23 +60,60 @@ IncludeByKey.PASSTHROUGH { Object.Widget.host-copier.1 { stream_name "volume playback 0" pcm_id 0 - Object.Base.input_audio_format [ - { - in_rate $JACK_RATE - in_bit_depth 16 - in_valid_bit_depth 16 - } - { - in_rate $JACK_RATE - in_bit_depth 32 - in_valid_bit_depth 32 + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_input_audio_formats 5 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_FLOAT + } + { + in_rate $JACK_RATE + in_bit_depth 8 + in_valid_bit_depth 8 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] } - { - in_rate $JACK_RATE - in_bit_depth 32 - in_valid_bit_depth 24 + "false" { + num_input_audio_formats 3 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + } + ] } - ] + } Object.Base.output_audio_format [ { out_rate $JACK_RATE @@ -311,30 +348,88 @@ Object.Pipeline.host-gateway-capture [ in_valid_bit_depth 32 } ] - num_output_audio_formats 3 - Object.Base.output_audio_format [ - { - out_rate $JACK_RATE - out_bit_depth 16 - out_valid_bit_depth 16 - } - { - out_rate $JACK_RATE - out_bit_depth 32 - out_valid_bit_depth 24 + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_output_audio_formats 5 + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + out_sample_type $SAMPLE_TYPE_FLOAT + } + { + out_rate $JACK_RATE + out_bit_depth 8 + out_valid_bit_depth 8 + out_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + } + ] } - { - out_rate $JACK_RATE - out_bit_depth 32 - out_valid_bit_depth 32 + "false" { + num_output_audio_formats 3 + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] } - ] + } } } ] # Jack capture pipeline widgets Object.Widget { + module-copier."12" { + index 1 + num_input_pins 1 + num_output_pins 2 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + alh-copier [ { stream_name $SDW_JACK_IN_STREAM @@ -401,6 +496,28 @@ Object.Widget { } } ] + Object.Widget.module-copier [ + { + num_input_audio_formats 1 + num_output_audio_formats 1 + # index 11 is inherited from the pipeline definition + # the instance number is automatically generated as '0' + Object.Base.input_audio_format [ + { + in_rate $JACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $JACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + ] } } } @@ -418,7 +535,14 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name "volume playback 0" - formats 'S16_LE,S24_LE,S32_LE' + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } IncludeByKey.JACK_RATE { "48000" { rates '48000' @@ -442,7 +566,14 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name "Passthrough Capture 0" - formats 'S16_LE,S24_LE,S32_LE' + IncludeByKey.PCM_FORMAT_ALL { + "true" { + formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' + } + "false" { + formats 'S16_LE,S24_LE,S32_LE' + } + } IncludeByKey.JACK_RATE { "48000" { rates '48000' @@ -465,6 +596,10 @@ IncludeByKey.PASSTHROUGH { Object.Base.route [ { source "gain.1.1" + sink "module-copier.1.12" + } + { + source "module-copier.1.12" sink "alh-copier.$SDW_JACK_OUT_STREAM.0" } { @@ -477,6 +612,10 @@ IncludeByKey.PASSTHROUGH { } { source "eqiir.11.0" + sink "module-copier.11.0" + } + { + source "module-copier.11.0" sink "host-copier.1.capture" } { diff --git a/tools/topology/topology2/production/CMakeLists.txt b/tools/topology/topology2/production/CMakeLists.txt index c278e651af99..c2cb86400e4b 100644 --- a/tools/topology/topology2/production/CMakeLists.txt +++ b/tools/topology/topology2/production/CMakeLists.txt @@ -1,10 +1,12 @@ # SPDX-License-Identifier: BSD-3-Clause include(tplg-targets-hda-generic.cmake) +include(tplg-targets-sdca-generic.cmake) include(tplg-targets-cavs25.cmake) include(tplg-targets-ace1.cmake) include(tplg-targets-ace2.cmake) include(tplg-targets-ace3.cmake) +include(tplg-targets-ace4.cmake) include(tplg-targets-imx8.cmake) add_custom_target(topology2_prod) diff --git a/tools/topology/topology2/production/tplg-targets-ace1.cmake b/tools/topology/topology2/production/tplg-targets-ace1.cmake index 2802eb938525..6c3bc7214663 100644 --- a/tools/topology/topology2/production/tplg-targets-ace1.cmake +++ b/tools/topology/topology2/production/tplg-targets-ace1.cmake @@ -3,6 +3,11 @@ # Array of "input-file-name;output-file-name;comma separated pre-processor variables" list(APPEND TPLGS # SDW + DMIC topology with passthrough pipelines +"cavs-sdw\;sof-mtl-rt711-2ch\;PLATFORM=mtl,NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,\ +DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-rt711-2ch.bin,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + "cavs-sdw\;sof-mtl-rt711-4ch\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-rt711-4ch.bin,\ HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,DMIC0_ENHANCED_CAPTURE=true,\ @@ -102,6 +107,11 @@ SDW_AMP_FEEDBACK=true,SDW_SPK_STREAM=Playback,SDW_SPK_IN_STREAM=Capture,\ AMP_FEEDBACK_CH=8,AMP_FEEDBACK_CH_PER_LINK=4,SDW_JACK=false,NUM_DMICS=0,\ HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,SDW_SPK_ENHANCED_PLAYBACK=false" +"cavs-sdw\;sof-mtl-cs35l56-l01-fb6\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,\ +SDW_AMP_FEEDBACK=true,SDW_SPK_STREAM=Playback,SDW_SPK_IN_STREAM=Capture,\ +AMP_FEEDBACK_CH=6,AMP_FEEDBACK_CH_PER_LINK=3,SDW_JACK=false,NUM_DMICS=0,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,SDW_SPK_ENHANCED_PLAYBACK=false" + # ARL has the same DSP generation. So reuse the platform = mtl. "cavs-sdw\;sof-arl-cs42l43-l0\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=1,SDW_DMIC=1,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ @@ -111,6 +121,14 @@ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" +"cavs-sdw\;sof-arl-cs42l43-l0-cs35l56-l2-2ch\;PLATFORM=mtl,\ +NUM_SDW_AMP_LINKS=1,SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=sof-arl-cs42l43-l0-cs35l56-l2-2ch.bin,\ +HDMI1_ID=5,HDMI2_ID=6,HDMI3_ID=7" + "cavs-sdw\;sof-arl-cs42l43-l0-cs35l56-l23\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,SDW_DMIC=1,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" @@ -123,10 +141,129 @@ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" +"cavs-sdw\;sof-arl-cs42l43-l2-cs35l56-l3-2ch\;PLATFORM=mtl,\ +NUM_SDW_AMP_LINKS=1,SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=sof-arl-cs42l43-l2-cs35l56-l3-2ch.bin,\ +HDMI1_ID=5,HDMI2_ID=6,HDMI3_ID=7" + +"cavs-sdw\;sof-arl-rt711-l0\;PLATFORM=mtl,HDMI1_ID=2,HDMI2_ID=3,HDMI3_ID=4" + +"cavs-sdw\;sof-arl-rt711-l0-2ch\;PLATFORM=mtl,NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,\ +DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-arl-rt711-2ch.bin,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-arl-rt711-l0-4ch\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-arl-rt711-4ch.bin,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + "cavs-sdw\;sof-arl-rt722-l0_rt1320-l2\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=1,SDW_DMIC=1,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" +"cavs-sdw\;sof-arl-rt711-l0-rt1316-l3\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=1,\ +SDW_SPK_STREAM=SDW3-Playback,SDW_SPK_IN_STREAM=SDW3-Capture,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6" + +"cavs-sdw\;sof-arl-rt711-l0-rt1316-l3-4ch\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=1,\ +SDW_SPK_STREAM=SDW3-Playback,SDW_SPK_IN_STREAM=SDW3-Capture,\ +NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-arl-rt711-l0-rt1316-l3-4ch.bin,\ +HDMI1_ID=6,HDMI2_ID=7,HDMI3_ID=8,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-arl-rt711-l0-rt1316-l3-2ch\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=1,\ +SDW_SPK_STREAM=SDW3-Playback,SDW_SPK_IN_STREAM=SDW3-Capture,\ +NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-arl-rt711-l0-rt1316-l3-2ch.bin,\ +HDMI1_ID=6,HDMI2_ID=7,HDMI3_ID=8,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +# Split topologies +"cavs-sdw\;sof-arl-dmic-2ch-id2\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-arl-dmic-2ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-arl-dmic-2ch-id3\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-arl-dmic-2ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-arl-dmic-2ch-id4\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-arl-dmic-2ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-arl-dmic-2ch-id5\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-arl-dmic-2ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-arl-dmic-4ch-id2\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-arl-dmic-4ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-arl-dmic-4ch-id3\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-arl-dmic-4ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-arl-dmic-4ch-id4\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-arl-dmic-4ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-arl-dmic-4ch-id5\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-arl-dmic-4ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-mtl-dmic-2ch-id2\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-mtl-dmic-2ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-mtl-dmic-2ch-id3\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-mtl-dmic-2ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-mtl-dmic-2ch-id4\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-mtl-dmic-2ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-mtl-dmic-2ch-id5\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-mtl-dmic-2ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-mtl-dmic-4ch-id2\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-mtl-dmic-4ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-mtl-dmic-4ch-id3\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-mtl-dmic-4ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-mtl-dmic-4ch-id4\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-mtl-dmic-4ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-mtl-dmic-4ch-id5\;PLATFORM=mtl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-mtl-dmic-4ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + # Below topologies are used on Chromebooks "cavs-rt5682\;sof-mtl-max98357a-rt5682\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ @@ -134,6 +271,12 @@ PDM1_MIC_B_ENABLE=1,DMIC0_PCM_ID=99,PREPROCESS_PLUGINS=nhlt,\ NHLT_BIN=nhlt-sof-mtl-max98357a-rt5682.bin,SPK_ID=6,DEEPBUFFER_FW_DMA_MS=10,INCLUDE_ECHO_REF=true,\ BT_ID=7,BT_PCM_NAME=Bluetooth,DEEP_BUF_SPK=true" +# Note this is same as above but different tplg name +"cavs-rt5682\;sof-mtl-max98360a-rt5682\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ +PDM1_MIC_B_ENABLE=1,DMIC0_PCM_ID=99,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-mtl-max98357a-rt5682.bin,SPK_ID=6,DEEPBUFFER_FW_DMA_MS=10,INCLUDE_ECHO_REF=true,\ +BT_ID=7,BT_PCM_NAME=Bluetooth,DEEP_BUF_SPK=true" + "cavs-rt5682\;sof-mtl-max98357a-rt5682-google-aec\;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-google-aec.bin,SPK_ID=6,DEEPBUFFER_FW_DMA_MS=10,INCLUDE_ECHO_REF=true,\ diff --git a/tools/topology/topology2/production/tplg-targets-ace2.cmake b/tools/topology/topology2/production/tplg-targets-ace2.cmake index 96237b41346e..129a5fc0ceed 100644 --- a/tools/topology/topology2/production/tplg-targets-ace2.cmake +++ b/tools/topology/topology2/production/tplg-targets-ace2.cmake @@ -27,6 +27,10 @@ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" +"cavs-sdw\;sof-lnl-rt713-l0-rt1318-l1\;PLATFORM=lnl,NUM_SDW_AMP_LINKS=1,\ +SDW_SPK_STREAM=SDW1-Playback,SDW_AMP_FEEDBACK=false,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6" + "cavs-sdw\;sof-lnl-rt713-l0-rt1318-l1-2ch\;PLATFORM=lnl,NUM_SDW_AMP_LINKS=1,\ SDW_SPK_STREAM=SDW1-Playback,SDW_AMP_FEEDBACK=false,\ NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,\ @@ -34,10 +38,54 @@ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-lnl-rt713-l0-rt1318-l1-2ch.bin,\ HDMI1_ID=6,HDMI2_ID=7,HDMI3_ID=8,DMIC0_ENHANCED_CAPTURE=true,\ EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" +# Split topologies +"cavs-sdw\;sof-lnl-dmic-2ch-id2\;PLATFORM=lnl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-lnl-dmic-2ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-lnl-dmic-2ch-id3\;PLATFORM=lnl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-lnl-dmic-2ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-lnl-dmic-2ch-id4\;PLATFORM=lnl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-lnl-dmic-2ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-lnl-dmic-2ch-id5\;PLATFORM=lnl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-lnl-dmic-2ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-lnl-dmic-4ch-id2\;PLATFORM=lnl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-lnl-dmic-4ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-lnl-dmic-4ch-id3\;PLATFORM=lnl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-lnl-dmic-4ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-lnl-dmic-4ch-id4\;PLATFORM=lnl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-lnl-dmic-4ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-lnl-dmic-4ch-id5\;PLATFORM=lnl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-lnl-dmic-4ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + # No SDW Jack. SDW DMIC+SPK "cavs-sdw\;sof-lnl-rt1318-l12-rt714-l0\;PLATFORM=lnl,SDW_JACK=false,SDW_DMIC=1,\ NUM_SDW_AMP_LINKS=2,SDW_DMIC_STREAM=SDW0-Capture" +"cavs-sdw\;sof-lnl-rt1320-l12-rt714-l0\;PLATFORM=lnl,SDW_JACK=false,SDW_DMIC=1,\ +NUM_SDW_AMP_LINKS=2,SDW_AMP_FEEDBACK=false,SDW_DMIC_STREAM=SDW0-Capture" + # SDW bridge to SPK and SDW Jack+DMIC+SPK "cavs-sdw\;sof-lnl-cs42l43-l0\;PLATFORM=lnl,NUM_SDW_AMP_LINKS=1,SDW_DMIC=1,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ @@ -64,14 +112,34 @@ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture- SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" "cavs-sdw\;sof-lnl-cs42l43-l0-cs35l56-l3-2ch\;PLATFORM=lnl,\ -NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,\ +NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=sof-lnl-cs42l43-l0-cs35l56-l3-2ch.bin,\ NUM_SDW_AMP_LINKS=1,SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,\ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ -HDMI1_ID=6,HDMI2_ID=7,HDMI3_ID=8,DMIC0_ENHANCED_CAPTURE=true,\ +HDMI1_ID=5,HDMI2_ID=6,HDMI3_ID=7,DMIC0_ENHANCED_CAPTURE=true,\ EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" "cavs-sdw\;sof-lnl-cs42l43-l0-cs35l56-l23\;PLATFORM=lnl,NUM_SDW_AMP_LINKS=2,SDW_DMIC=1,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" + +"cavs-sdw\;sof-lnl-cs42l43-l0-cs35l56-l23-2ch\;PLATFORM=lnl,NUM_SDW_AMP_LINKS=2,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,NUM_DMICS=2,\ +DMIC0_ID=3,DMIC1_ID=4,HDMI1_ID=5,HDMI2_ID=6,HDMI3_ID=7,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=sof-lnl-cs42l43-l0-cs35l56-l23-2ch.bin" + +"cavs-sdw\;sof-lnl-cs42l43-l0-cs35l56-l23-4ch\;PLATFORM=lnl,NUM_SDW_AMP_LINKS=2,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +DMIC0_ID=3,DMIC1_ID=4,HDMI1_ID=5,HDMI2_ID=6,HDMI3_ID=7,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=sof-lnl-cs42l43-l0-cs35l56-l23-4ch.bin" + +"cavs-sdw\;sof-lnl-cs42l43-l2-cs35l56x6-l13\;NUM_SDW_AMP_LINKS=3,SDW_DMIC=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" + ) diff --git a/tools/topology/topology2/production/tplg-targets-ace3.cmake b/tools/topology/topology2/production/tplg-targets-ace3.cmake index bdfc3a0d5edf..3b5dc858fd20 100644 --- a/tools/topology/topology2/production/tplg-targets-ace3.cmake +++ b/tools/topology/topology2/production/tplg-targets-ace3.cmake @@ -2,7 +2,29 @@ # Array of "input-file-name;output-file-name;comma separated pre-processor variables" list(APPEND TPLGS +# MOCKUP topology for PTL +"cavs-sdw\;sof-ptl-rt711-rt1308-rt715\;NUM_SDW_AMP_LINKS=2,SDW_DMIC=1,SDW_AMP_FEEDBACK=false" + +"cavs-sdw\;sof-ptl-rt711-rt1308-mono-rt715\;NUM_SDW_AMP_LINKS=1,SDW_DMIC=1,SDW_AMP_FEEDBACK=false" + +"cavs-sdw\;sof-ptl-rt715-rt711-rt1308-mono\;NUM_SDW_AMP_LINKS=1,SDW_DMIC=1,\ +SDW_JACK_OUT_STREAM=SDW1-Playback,SDW_JACK_IN_STREAM=SDW1-Capture,\ +SDW_SPK_STREAM=SDW2-Playback,SDW_DMIC_STREAM=SDW0-Capture,SDW_AMP_FEEDBACK=false,\ +SDW_SPK_ENHANCED_PLAYBACK=false,SDW_DMIC_ENHANCED_CAPTURE=false" + # SDW topology for PTL RVP +"cavs-sdw\;sof-ptl-rt711\;PLATFORM=ptl,HDMI1_ID=2,HDMI2_ID=3,HDMI3_ID=4" + +"cavs-sdw\;sof-ptl-rt711-2ch\;PLATFORM=ptl,NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,\ +DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt711-2ch.bin,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-ptl-rt711-4ch\;PLATFORM=ptl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt711-4ch.bin,\ +HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + # RT721 eval board with SDW-DMIC, sof_sdw_quirk_table without SOC_SDW_PCH_DMIC "cavs-sdw\;sof-ptl-rt721\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ @@ -13,7 +35,55 @@ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ -PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt721-4ch.bin" +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt721-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true" + +# RT721 eval board with PCH-DMIC, sof_sdw_quirk_table with SOC_SDW_PCH_DMIC, DMIC1 with 96kHz +"cavs-sdw\;sof-ptl-rt721-4ch-dmic1-96k\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt721-4ch-dmic1-96k.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DMIC1_ENABLE=passthrough,DMIC1_RATE=96000,DMIC1_PCM_ID=11,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true" + +# RT721 eval board with PCH-DMIC, sof_sdw_quirk_table with SOC_SDW_PCH_DMIC, 96KHz Jack-rate +"cavs-sdw\;sof-ptl-rt721-4ch-96k\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt721-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,JACK_RATE=96000,DEEP_BUF_JACK_RATE=96000" + +"cavs-sdw\;sof-ptl-rt721-l3-rt1320-l3-4ch-ssp2-bt\;PLATFORM=ptl,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt721-l3-rt1320-l3-4ch-ssp2-bt.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEP_BUF_SPK=true,BT_PCM_ID=8,BT_ID=8,BT_PCM_NAME=Bluetooth,ADD_BT=true" + +# DTS +"cavs-sdw\;sof-ptl-rt721-l3-rt1320-l3-4ch-ssp2-bt-dts\;PLATFORM=ptl,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt721-l3-rt1320-l3-4ch-ssp2-bt.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEP_BUF_SPK=true,BT_PCM_ID=8,BT_ID=8,BT_PCM_NAME=Bluetooth,ADD_BT=true,SDW_AMP_PIPELINE_SRC=dts,\ +SDW_JACK_PIPELINE_SRC=dts" + +"cavs-sdw\;sof-ptl-rt721-l3-rt1320-l3-4ch-ssp2-bt-dts-ctc\;PLATFORM=ptl,NUM_SDW_AMP_CTC_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt721-l3-rt1320-l3-4ch-ssp2-bt-dts-ctc.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEP_BUF_SPK=true,BT_PCM_ID=8,BT_ID=8,BT_PCM_NAME=Bluetooth,ADD_BT=true,SDW_AMP_PIPELINE_SRC=dts,\ +SDW_JACK_PIPELINE_SRC=dts" "cavs-sdw\;sof-ptl-rt722\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ @@ -38,11 +108,267 @@ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt722-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" +"cavs-sdw\;sof-ptl-rt722-2ch\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt722-2ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-ptl-rt722-l0-rt1320-l23\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=2,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" + +"cavs-sdw\;sof-ptl-rt722-l0-rt1320-l23-2ch\;PLATFORM=ptl,NUM_SDW_AMP_LINKS=2,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=SDW2-Playback,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt722-l0-rt1320-l23-2ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-ptl-rt722-l0-rt1320-l23-4ch\;PLATFORM=ptl,NUM_SDW_AMP_LINKS=2,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt722-l0-rt1320-l23-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,\ +BT_PCM_ID=20,BT_ID=10,BT_PCM_NAME=Bluetooth,ADD_BT=true" + "cavs-sdw\;sof-ptl-rt712-l2-rt1320-l1\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=2,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" +"cavs-sdw\;sof-ptl-rt712-l3-rt1320-l2\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=2,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" + +"cavs-sdw\;sof-ptl-rt712-l3-rt1320-l3\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" + +"cavs-sdw\;sof-ptl-rt712-l3-rt1320-l3-ctc\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_CTC_LINKS=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" + +"cavs-sdw\;sof-ptl-rt712-l3-rt1320-l3-4ch\;PLATFORM=ptl,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt712-l3-rt1320-l3-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +BT_PCM_ID=20,BT_ID=10,BT_PCM_NAME=Bluetooth,ADD_BT=true,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true" + "cavs-sdw\;sof-ptl-rt713-l2-rt1320-l13\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=2,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" + +"cavs-sdw\;sof-ptl-rt713-l3-rt1320-l12\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=2,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" + +# LG Gram Pro 2026 (16Z90U-KU7BK) with RT713 on link 3 and single stereo RT1320 on link 1 +"cavs-sdw\;sof-ptl-rt713-l3-rt1320-l1\;PLATFORM=ptl,SDW_DMIC=0,NUM_SDW_AMP_LINKS=1,\ +NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=SDW1-Playback,\ +SDW_JACK_OUT_STREAM=SDW3-Playback,SDW_JACK_IN_STREAM=SDW3-Capture,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt713-l3-rt1320-l1.bin" + +"cavs-sdw\;sof-ptl-cs42l43-l2-cs35l56x6-l13\;NUM_SDW_AMP_LINKS=3,SDW_DMIC=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" + +"cavs-sdw\;sof-ptl-cs42l43-agg-l3-cs35l56-l2\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=2,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,BT_PCM_ID=20,BT_ID=8,BT_PCM_NAME=Bluetooth,ADD_BT=true,\ +SDW_SPK_ENHANCED_PLAYBACK=false" + +"cavs-sdw\;sof-ptl-cs42l43-agg-l3-cs35l56-l2-ctc\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_CTC_LINKS=2,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,BT_PCM_ID=20,BT_ID=8,BT_PCM_NAME=Bluetooth,ADD_BT=true,\ +SDW_SPK_ENHANCED_PLAYBACK=false" + +"cavs-sdw\;sof-ptl-cs42l43-agg-l3-cs35l56-l2-dax\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=2,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,BT_PCM_ID=20,BT_ID=8,BT_PCM_NAME=Bluetooth,ADD_BT=true,\ +SDW_AMP_PIPELINE_SRC=dax,SDW_JACK_PIPELINE_SRC=dax,DOLBY_DAX_CORE_ID=0" + +"cavs-sdw\;sof-ptl-cs42l43-agg-l3-cs35l56-l2-dax-ctc\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_CTC_LINKS=2,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,BT_PCM_ID=20,BT_ID=8,BT_PCM_NAME=Bluetooth,ADD_BT=true,\ +SDW_AMP_PIPELINE_SRC=dax,DOLBY_DAX_CORE_ID=0" + +"cavs-sdw\;sof-ptl-cs42l43-agg-l3-cs35l56-l2-4ch\;PLATFORM=ptl,NUM_SDW_AMP_LINKS=2,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-cs42l43-agg-l3-cs35l56-l2-4ch.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,BT_PCM_ID=20,BT_ID=8,BT_PCM_NAME=Bluetooth,ADD_BT=true,\ +SDW_SPK_ENHANCED_PLAYBACK=false" + +"cavs-sdw\;sof-ptl-cs42l43-agg-l3-cs35l56-l2-4ch-ctc\;PLATFORM=ptl,NUM_SDW_AMP_CTC_LINKS=2,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-cs42l43-agg-l3-cs35l56-l2-4ch-ctc.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,BT_PCM_ID=20,BT_ID=8,BT_PCM_NAME=Bluetooth,ADD_BT=true,\ +SDW_SPK_ENHANCED_PLAYBACK=false" + +# SSP codec topologies for PTL +# ES83x6 codec alone without HDMI-in capture +"cavs-es83x6\;sof-ptl-es8336-ssp1\;PLATFORM=ptl,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-es8336-ssp1.bin,HEADSET_SSP_DAI_INDEX=1,\ +HEADSET_CODEC=true,HEADSET_CODEC_NAME=SSP1-Codec,HDMI1_ID=3,HDMI2_ID=4,HDMI3_ID=5,\ +HDMI_IN_CAPTURE=false" + +#ES83x6+HDMI-IN +"cavs-es83x6\;sof-ptl-es83x6-ssp1-hdmi-ssp02\;PLATFORM=ptl,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-es83x6-ssp1-hdmi-ssp02.bin,HEADSET_SSP_DAI_INDEX=1,\ +HEADSET_CODEC=true,HEADSET_CODEC_NAME=SSP1-Codec,HDMI1_ID=3,HDMI2_ID=4,HDMI3_ID=5,\ +HDMI_IN_CAPTURE=true" + +#No HeadsetCodec+HDMI-IN +"cavs-es83x6\;sof-ptl-hdmi-ssp02\;PLATFORM=ptl,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-hdmi-ssp02.bin,HEADSET_CODEC=false,HDMI_IN_CAPTURE=true,\ +HDMI_IN_1_ID=0,HDMI_IN_2_ID=1" + +# Topology for PTL with rt5682 (SSP 0), tas2563 (SSP 1), BT (SSP 2) and PDM0 enabled +"cavs-rt5682\;sof-ptl-tas2563-rt5682\;PLATFORM=ptl,NUM_DMICS=2,DMIC0_PCM_ID=99,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-tas2563-rt5682.bin,SPK_ID=6,DEEPBUFFER_FW_DMA_MS=10,INCLUDE_ECHO_REF=true,\ +BT_NAME=SSP2-BT,BT_ID=7,BT_PCM_NAME=Bluetooth,DEEP_BUF_SPK=true" + +"cavs-rt5682\;sof-ptl-tas2563-rt5682-ctc\;PLATFORM=ptl,NUM_DMICS=2,DMIC0_PCM_ID=99,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-tas2563-rt5682-ctc.bin,SPK_ID=6,DEEPBUFFER_FW_DMA_MS=10,INCLUDE_ECHO_REF=true,\ +BT_NAME=SSP2-BT,BT_ID=7,BT_PCM_NAME=Bluetooth,DEEP_BUF_SPK=true,PLAYBACK_PIPELINE_SRC=ctc,USE_CTC_SPK=true" + +"cavs-rt5682\;sof-ptl-tas2563-rt5682-dax\;PLATFORM=ptl,NUM_DMICS=2,DMIC0_PCM_ID=99,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-tas2563-rt5682-dax.bin,SPK_ID=6,DEEPBUFFER_FW_DMA_MS=10,\ +INCLUDE_ECHO_REF=true,BT_NAME=SSP2-BT,BT_ID=7,BT_PCM_NAME=Bluetooth,DEEP_BUF_SPK=true,\ +PLAYBACK_PIPELINE_SRC=dax,SSP_HEADSET_DAX=true,DOLBY_DAX_CORE_ID=0" + +"cavs-rt5682\;sof-ptl-tas2563-rt5682-dax-ctc\;PLATFORM=ptl,NUM_DMICS=2,DMIC0_PCM_ID=99,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-tas2563-rt5682-dax-ctc.bin,SPK_ID=6,DEEPBUFFER_FW_DMA_MS=10,\ +INCLUDE_ECHO_REF=true,BT_NAME=SSP2-BT,BT_ID=7,BT_PCM_NAME=Bluetooth,DEEP_BUF_SPK=true,\ +PLAYBACK_PIPELINE_SRC=dax,DOLBY_DAX_CORE_ID=0,USE_CTC_SPK=true" + + +# Split topologies +"cavs-sdw\;sof-ptl-dmic-2ch-id2\;PLATFORM=ptl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-dmic-2ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-ptl-dmic-2ch-id3\;PLATFORM=ptl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-dmic-2ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-ptl-dmic-2ch-id4\;PLATFORM=ptl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-dmic-2ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-ptl-dmic-2ch-id5\;PLATFORM=ptl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-dmic-2ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-ptl-dmic-4ch-id2\;PLATFORM=ptl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-dmic-4ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-ptl-dmic-4ch-id3\;PLATFORM=ptl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-dmic-4ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-ptl-dmic-4ch-id4\;PLATFORM=ptl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-dmic-4ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-ptl-dmic-4ch-id5\;PLATFORM=ptl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-dmic-4ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +# for WCL +"cavs-sdw\;sof-wcl-dmic-2ch-id2\;PLATFORM=wcl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-wcl-dmic-2ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-wcl-dmic-2ch-id3\;PLATFORM=wcl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-wcl-dmic-2ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-wcl-dmic-2ch-id4\;PLATFORM=wcl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-wcl-dmic-2ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-wcl-dmic-2ch-id5\;PLATFORM=wcl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-wcl-dmic-2ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-wcl-dmic-4ch-id2\;PLATFORM=wcl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-wcl-dmic-4ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-wcl-dmic-4ch-id3\;PLATFORM=wcl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-wcl-dmic-4ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-wcl-dmic-4ch-id4\;PLATFORM=wcl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-wcl-dmic-4ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-wcl-dmic-4ch-id5\;PLATFORM=wcl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-wcl-dmic-4ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-es83x6\;sof-ptl-ssp1-jack-id0\;PLATFORM=ptl,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-ssp1-jack-id0.bin,HEADSET_SSP_DAI_INDEX=1,\ +HEADSET_CODEC=true,HEADSET_CODEC_NAME=SSP1-Codec,NUM_HDMIS=0,\ +HDMI_IN_CAPTURE=false" + +# HDMI IN port: SSP0 and SSP2, SSP number is a mask in HDMI_IN_1_ID and HDMI_IN_2_ID +# For example, SSP5 indicates SSP 0 and 2 are used for HDMI IN +"cavs-es83x6\;sof-ptl-ssp5-hdmiin-id1\;PLATFORM=ptl,PREPROCESS_PLUGINS=nhlt,NUM_HDMIS=0,\ +NHLT_BIN=nhlt-sof-ptl-ssp5-hdmiin-id1.bin,HEADSET_CODEC=false,HDMI_IN_CAPTURE=true,\ +HDMI_IN_1_ID=0,HDMI_IN_2_ID=1" + +"cavs-es83x6\;sof-ptl-ssp5-hdmiin-id2\;PLATFORM=ptl,PREPROCESS_PLUGINS=nhlt,NUM_HDMIS=0,\ +NHLT_BIN=nhlt-sof-ptl-ssp5-hdmiin-id2.bin,HEADSET_CODEC=false,HDMI_IN_CAPTURE=true,\ +HDMI_IN_1_ID=1,HDMI_IN_2_ID=2" + +"cavs-es83x6\;sof-ptl-ssp5-hdmiin-id7\;PLATFORM=ptl,PREPROCESS_PLUGINS=nhlt,NUM_HDMIS=0,\ +NHLT_BIN=nhlt-sof-ptl-ssp5-hdmiin-id7.bin,HEADSET_CODEC=false,HDMI_IN_CAPTURE=true,\ +HDMI_IN_1_ID=6,HDMI_IN_2_ID=7" + +"cavs-es83x6\;sof-ptl-ssp2-bt-id2\;PLATFORM=ptl,INCLUDE_BT_OFFLOAD=true,NUM_HDMIS=0,\ +HEADSET_CODEC=false,HDMI_IN_CAPTURE=false,BT_ID=2,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-ssp2-bt-id2.bin" + +#BT_ID=8, 10 for sdw_sof machine +"cavs-sdw\;sof-ptl-ssp2-bt-id8\;PLATFORM=ptl,ADD_BT=true,SDW_JACK=false,NUM_HDMIS=0,\ +HEADSET_CODEC=false,HDMI_IN_CAPTURE=false,BT_ID=8,BT_PCM_ID=20,BT_PCM_NAME=Bluetooth,\ +BT_CP_HOST_PIPELINE_ID=201,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-ssp2-bt-id8.bin" + +"cavs-sdw\;sof-ptl-ssp2-bt-id10\;PLATFORM=ptl,ADD_BT=true,SDW_JACK=false,NUM_HDMIS=0,\ +HEADSET_CODEC=false,HDMI_IN_CAPTURE=false,BT_ID=10,BT_PCM_ID=20,BT_PCM_NAME=Bluetooth,\ +BT_CP_HOST_PIPELINE_ID=201,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-ssp2-bt-id10.bin" ) diff --git a/tools/topology/topology2/production/tplg-targets-ace4.cmake b/tools/topology/topology2/production/tplg-targets-ace4.cmake new file mode 100644 index 000000000000..66edfda9a1a6 --- /dev/null +++ b/tools/topology/topology2/production/tplg-targets-ace4.cmake @@ -0,0 +1,112 @@ +# SPDX-License-Identifier: BSD-3-Clause + +# Array of "input-file-name;output-file-name;comma separated pre-processor variables" +list(APPEND TPLGS +# MOCKUP topology for PTL +"cavs-sdw\;sof-nvl-rt711-rt1308-rt715\;NUM_SDW_AMP_LINKS=2,SDW_DMIC=1,SDW_AMP_FEEDBACK=false" + +"cavs-sdw\;sof-nvl-rt711-rt1308-mono-rt715\;NUM_SDW_AMP_LINKS=1,SDW_DMIC=1,SDW_AMP_FEEDBACK=false" + +"cavs-sdw\;sof-nvl-rt715-rt711-rt1308-mono\;NUM_SDW_AMP_LINKS=1,SDW_DMIC=1,\ +SDW_JACK_OUT_STREAM=SDW1-Playback,SDW_JACK_IN_STREAM=SDW1-Capture,\ +SDW_SPK_STREAM=SDW2-Playback,SDW_DMIC_STREAM=SDW0-Capture,SDW_AMP_FEEDBACK=false,\ +SDW_SPK_ENHANCED_PLAYBACK=false,SDW_DMIC_ENHANCED_CAPTURE=false" + +# RT721 eval board with PCH-DMIC, sof_sdw_quirk_table with SOC_SDW_PCH_DMIC +"cavs-sdw\;sof-nvl-rt721-4ch\;PLATFORM=nvl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-nvl-rt721-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true" + +# RT721 eval board with PCH-DMIC, sof_sdw_quirk_table with SOC_SDW_PCH_DMIC, 96KHz Jack-rate +"cavs-sdw\;sof-nvl-rt721-4ch-96k\;PLATFORM=nvl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-nvl-rt721-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true,JACK_RATE=96000,DEEP_BUF_JACK_RATE=96000" + +"cavs-sdw\;sof-nvl-rt722\;PLATFORM=nvl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" + +"cavs-sdw\;sof-nvl-rt722-96k\;PLATFORM=nvl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +JACK_RATE=96000,DEEP_BUF_JACK_RATE=96000,\ +SDW_SPK_ENHANCED_PLAYBACK=false,SDW_DMIC_ENHANCED_CAPTURE=false" + +"cavs-sdw\;sof-nvl-rt722-192k\;PLATFORM=nvl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +JACK_RATE=192000,DEEP_BUF_JACK_RATE=192000,\ +SDW_SPK_ENHANCED_PLAYBACK=false,SDW_DMIC_ENHANCED_CAPTURE=false" + +"cavs-sdw\;sof-nvl-rt722-4ch\;PLATFORM=nvl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-nvl-rt722-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-nvl-rt722-2ch\;PLATFORM=nvl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-nvl-rt722-2ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-nvl-rt712-l3-rt1320-l3-4ch-ssp2-bt\;PLATFORM=nvl,NUM_SDW_AMP_LINKS=1,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-nvl-rt712-l3-rt1320-l3-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default,\ +BT_PCM_ID=20,BT_ID=10,BT_PCM_NAME=Bluetooth,ADD_BT=true,\ +DEEPBUFFER_FW_DMA_MS=10,DEEP_BUF_SPK=true" + +# Split topologies +"cavs-sdw\;sof-nvl-dmic-2ch-id2\;PLATFORM=nvl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-nvl-dmic-2ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-nvl-dmic-2ch-id3\;PLATFORM=nvl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-nvl-dmic-2ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-nvl-dmic-2ch-id4\;PLATFORM=nvl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-nvl-dmic-2ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-nvl-dmic-2ch-id5\;PLATFORM=nvl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=2,\ +PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-nvl-dmic-2ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-nvl-dmic-4ch-id2\;PLATFORM=nvl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=2,DMIC1_ID=3,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-nvl-dmic-4ch-id2.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-nvl-dmic-4ch-id3\;PLATFORM=nvl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-nvl-dmic-4ch-id3.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-nvl-dmic-4ch-id4\;PLATFORM=nvl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=4,DMIC1_ID=5,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-nvl-dmic-4ch-id4.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"cavs-sdw\;sof-nvl-dmic-4ch-id5\;PLATFORM=nvl,SDW_JACK=false,NUM_HDMIS=0,NUM_DMICS=4,\ +PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ID=5,DMIC1_ID=6,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-nvl-dmic-4ch-id5.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" +) diff --git a/tools/topology/topology2/production/tplg-targets-hda-generic.cmake b/tools/topology/topology2/production/tplg-targets-hda-generic.cmake index e2f64cbe22f7..72872d110a4d 100644 --- a/tools/topology/topology2/production/tplg-targets-hda-generic.cmake +++ b/tools/topology/topology2/production/tplg-targets-hda-generic.cmake @@ -13,9 +13,17 @@ list(APPEND TPLGS "sof-hda-generic\;sof-hda-generic\;HDA_CONFIG=mix,HDA_MIC_ENHANCED_CAPTURE=true,\ EFX_HDA_MIC_TDFB_PARAMS=line2_pass,EFX_HDA_MIC_DRC_PARAMS=passthrough" +"sof-hda-generic\;sof-hda-generic-compr\;HDA_CONFIG=mix,HDA_MIC_ENHANCED_CAPTURE=true,\ +EFX_HDA_MIC_TDFB_PARAMS=line2_pass,EFX_HDA_MIC_DRC_PARAMS=passthrough,COMPRESSED=true" + +"sof-hda-generic\;sof-hda-generic-dax\;HDA_CONFIG=dax,HDA_MIC_ENHANCED_CAPTURE=true,\ +EFX_HDA_MIC_TDFB_PARAMS=line2_pass,EFX_HDA_MIC_DRC_PARAMS=passthrough,DOLBY_DAX_CORE_ID=1" + # HDA topology with mixer-based pipelines for HDA and # passthrough pipelines for HDMI and # 2 or 4 DMIC, no NHLT blob included in topology +"sof-hda-generic\;sof-hda-generic-1ch\;HDA_CONFIG=mix,NUM_DMICS=1,PDM0_MIC_B_ENABLE=0" + "sof-hda-generic\;sof-hda-generic-2ch\;HDA_CONFIG=mix,NUM_DMICS=2,\ DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,\ EFX_DMIC0_DRC_PARAMS=dmic_default" @@ -24,6 +32,10 @@ EFX_DMIC0_DRC_PARAMS=dmic_default" PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,DMIC0_ENHANCED_CAPTURE=true,\ EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" +"sof-hda-generic\;sof-hda-generic-2ch-dax\;HDA_CONFIG=dax,NUM_DMICS=2,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,\ +EFX_DMIC0_DRC_PARAMS=dmic_default,DOLBY_DAX_CORE_ID=1" + # HDA topology with mixer-based pipelines for HDA and # passthrough pipelines for HDMI and # 2 or 4 DMIC, no NHLT blob included in topology @@ -39,6 +51,9 @@ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-cavs25-idisp-2ch.bin" PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-cavs25-idisp-4ch.bin" # HDA + HDMI + DMICs +"sof-hda-generic\;sof-hda-generic-cavs25-1ch\;HDA_CONFIG=mix,NUM_DMICS=1,PDM0_MIC_B_ENABLE=0,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-cavs25-1ch.bin" + "sof-hda-generic\;sof-hda-generic-cavs25-2ch\;HDA_CONFIG=mix,NUM_DMICS=2,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-cavs25-2ch.bin,\ DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,\ @@ -50,6 +65,11 @@ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-cavs25-4ch.bin,\ DMIC0_ENHANCED_CAPTURE=true,\ EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" +"sof-hda-generic\;sof-hda-generic-cavs25-2ch-dax\;HDA_CONFIG=dax,NUM_DMICS=2,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-cavs25-2ch-dax.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,\ +EFX_DMIC0_DRC_PARAMS=dmic_default,DOLBY_DAX_CORE_ID=1" + # Topologies for ACE1 and ACE2 architectures # HDMI + DMICs "sof-hda-generic\;sof-hda-generic-ace1-idisp-2ch\;PLATFORM=mtl,NUM_DMICS=2,\ @@ -58,6 +78,9 @@ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace1-idisp-2ch.bin" PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace1-idisp-4ch.bin" # HDA + HDMI + DMICs +"sof-hda-generic\;sof-hda-generic-ace1-1ch\;PLATFORM=mtl,HDA_CONFIG=mix,NUM_DMICS=1,PDM0_MIC_B_ENABLE=0,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace1-1ch.bin" + "sof-hda-generic\;sof-hda-generic-ace1-2ch\;PLATFORM=mtl,HDA_CONFIG=mix,NUM_DMICS=2,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace1-2ch.bin,\ DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,\ @@ -68,6 +91,11 @@ PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace1-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" +"sof-hda-generic\;sof-hda-generic-ace1-2ch-dax\;PLATFORM=mtl,HDA_CONFIG=dax,NUM_DMICS=2,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace1-2ch-dax.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,\ +EFX_DMIC0_DRC_PARAMS=dmic_default,DOLBY_DAX_CORE_ID=1" + # Topologies for ACE3 architecture # HDMI + DMICs "sof-hda-generic\;sof-hda-generic-ace3-idisp-2ch\;PLATFORM=ptl,NUM_DMICS=2,\ @@ -78,6 +106,9 @@ PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace3-idisp-4ch.bin" # HDA + HDMI + DMICs +"sof-hda-generic\;sof-hda-generic-ace3-1ch\;PLATFORM=ptl,HDA_CONFIG=mix,NUM_DMICS=1,PDM0_MIC_B_ENABLE=0,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace3-1ch.bin" + "sof-hda-generic\;sof-hda-generic-ace3-2ch\;PLATFORM=ptl,HDA_CONFIG=mix,NUM_DMICS=2,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace3-2ch.bin,\ DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,\ @@ -87,4 +118,9 @@ EFX_DMIC0_DRC_PARAMS=dmic_default" PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace3-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" + +"sof-hda-generic\;sof-hda-generic-ace3-2ch-dax\;PLATFORM=ptl,HDA_CONFIG=dax,NUM_DMICS=2,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-ace3-2ch-dax.bin,\ +DMIC0_ENHANCED_CAPTURE=true,EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,\ +EFX_DMIC0_DRC_PARAMS=dmic_default,DOLBY_DAX_CORE_ID=1" ) diff --git a/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake b/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake new file mode 100644 index 000000000000..c7d5b5d8af1b --- /dev/null +++ b/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: BSD-3-Clause + +# Array of "input-file-name;output-file-name;comma separated pre-processor variables" +list(APPEND TPLGS + +"cavs-sdw\;sof-sdw-generic\;SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ +SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" + +# Split topologies +"cavs-sdw\;sof-sdca-jack-id0\;SDW_JACK_OUT_STREAM=Playback-SimpleJack,\ +SDW_JACK_IN_STREAM=Capture-SimpleJack,NUM_HDMIS=0" + +"cavs-sdw\;sof-sdca-1amp-id2\;NUM_SDW_AMP_LINKS=1,SDW_JACK=false,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,NUM_HDMIS=0,\ +DEEP_BUF_SPK=true" + +"cavs-sdw\;sof-sdca-2amp-id2\;NUM_SDW_AMP_LINKS=2,SDW_JACK=false,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,NUM_HDMIS=0,\ +DEEP_BUF_SPK=true" + +"cavs-sdw\;sof-sdca-3amp-id2\;NUM_SDW_AMP_LINKS=3,SDW_JACK=false,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,NUM_HDMIS=0,\ +DEEP_BUF_SPK=true" + +"cavs-sdw\;sof-sdca-4amp-id2\;NUM_SDW_AMP_LINKS=4,SDW_JACK=false,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,NUM_HDMIS=0,\ +DEEP_BUF_SPK=true" + +"cavs-sdw\;sof-sdca-mic-id4\;SDW_JACK=false,SDW_DMIC=1,NUM_HDMIS=0,\ +SDW_DMIC_STREAM=Capture-SmartMic" + +"cavs-sdw\;sof-hdmi-pcm5-id2\;SDW_JACK=false,HDMI1_ID=2,HDMI2_ID=3,HDMI3_ID=4" +"cavs-sdw\;sof-hdmi-pcm5-id3\;SDW_JACK=false,HDMI1_ID=3,HDMI2_ID=4,HDMI3_ID=5" +"cavs-sdw\;sof-hdmi-pcm5-id4\;SDW_JACK=false,HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6" +"cavs-sdw\;sof-hdmi-pcm5-id5\;SDW_JACK=false" +"cavs-sdw\;sof-hdmi-pcm5-id6\;SDW_JACK=false,HDMI1_ID=6,HDMI2_ID=7,HDMI3_ID=8" +"cavs-sdw\;sof-hdmi-pcm5-id7\;SDW_JACK=false,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9" + +# Feature topologies which should work with the function topologies above +"cavs-sdw\;sof-sdca-amp-ref\;SDW_JACK=false,NUM_HDMIS=0,JACK_RATE=48000,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_ECHO_REF=true,SDW_SPK_ECHO_REF_PCM_ID=12" + +"cavs-sdw\;sof-sdca-amp-ref-dai\;SDW_JACK=false,NUM_HDMIS=0,JACK_RATE=48000,\ +SDW_AMP_FEEDBACK=false,SDW_ECHO_REF_DAI=true,SDW_SPK_ECHO_REF=true,SDW_SPK_ECHO_REF_PCM_ID=12" + +"cavs-sdw\;sof-sdca-jack-ref-dai\;SDW_JACK=false,NUM_HDMIS=0,JACK_RATE=48000,\ +SDW_ECHO_REF_DAI=true,SDW_JACK_ECHO_REF=true,SDW_JACK_ECHO_REF_PCM_ID=11" + +# Topology for speaker with 2-way crossover filter in SOF +# with channels order L-low, R-low, L-high, R-high +"cavs-sdw\;sof-sdca-2amp-id2-xover\;NUM_SDW_AMP_LINKS=2,SDW_JACK=false,\ +SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,NUM_HDMIS=0,\ +SDW_AMP_NUM_CHANNELS=4,SDW_AMP_XOVER=true,\ +SDW_AMP_XOVER_SELECTOR_PARAMS=xover_selector_lr_to_lrlr,\ +SDW_AMP_XOVER_EQIIR_PARAMS=xover_lr4_2000hz_llhh_48khz" + +"cavs-sdw\;sof-sdca-2amp-feedback-id3-xover\;NUM_SDW_AMP_LINKS=2,\ +SDW_JACK=false,SDW_AMP_FEEDBACK=true,SDW_SPK_STREAM=Playback-SmartAmp,\ +SDW_SPK_IN_STREAM=Capture-SmartAmp,NUM_HDMIS=0,\ +SDW_AMP_NUM_CHANNELS=4,SDW_AMP_XOVER=true,\ +SDW_AMP_XOVER_SELECTOR_PARAMS=xover_selector_lr_to_lrlr,\ +SDW_AMP_XOVER_EQIIR_PARAMS=xover_lr4_2000hz_llhh_48khz" +) diff --git a/tools/topology/topology2/sof-hda-generic.conf b/tools/topology/topology2/sof-hda-generic.conf index 254ef9426d96..01a020bad17f 100644 --- a/tools/topology/topology2/sof-hda-generic.conf +++ b/tools/topology/topology2/sof-hda-generic.conf @@ -18,12 +18,15 @@ <mixout-gain-dai-copier-playback.conf> <mixout-aria-gain-mixin-playback.conf> <mixout-gain-efx-dai-copier-playback.conf> +<mixout-gain-dax-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> <dai-copier-gain-eqiir-module-copier-capture.conf> <gain-capture.conf> <deepbuffer-playback.conf> +<deepbuffer-capture.conf> +<compr-playback.conf> <io-gateway.conf> <io-gateway-capture.conf> <highpass-capture-be.conf> @@ -40,6 +43,8 @@ <common_definitions.conf> <dmic-default.conf> <hdmi-default.conf> +<deep-buffer-default.conf> +<compr-default.conf> <module-copier.conf> Define { @@ -66,7 +71,7 @@ IncludeByKey.HDA_CONFIG { "mix" "cavs-mixin-mixout-hda.conf" "efx" "cavs-mixin-mixout-efx-hda.conf" "src" "cavs-src-mixin-mixout-hda.conf" - "benchmark" "cavs-benchmark-hda.conf" + "dax" "cavs-mixin-mixout-dax-hda.conf" "passthrough" "cavs-passthrough-hda.conf" } @@ -86,8 +91,9 @@ Define { DMIC0_PCM_ID 6 } -# always include HDMI config -<hdmi-generic.conf> +IncludeByKey.NUM_HDMIS { +"[3-4]" "platform/intel/hdmi-generic.conf" +} Object.Widget.virtual [ { diff --git a/tools/tplg_parser/control.c b/tools/tplg_parser/control.c index e8e8048b4939..c2deddf61a4f 100644 --- a/tools/tplg_parser/control.c +++ b/tools/tplg_parser/control.c @@ -141,8 +141,13 @@ int tplg_create_controls(struct tplg_context *ctx, int num_kcontrols, return -EINVAL; } - if (ctx->ctl_cb && object) - ctx->ctl_cb(ctl_hdr, object, ctx->ctl_arg, index); + if (ctx->ctl_cb && object) { + ret = ctx->ctl_cb(ctl_hdr, object, ctx->ctl_arg, index); + if (ret) { + fprintf(stderr, "error: failed control callback\n"); + goto err; + } + } } if (rctl && ctl_hdr) { diff --git a/tools/tplg_parser/graph.c b/tools/tplg_parser/graph.c index 7bc9f33449bd..f92b316893a9 100644 --- a/tools/tplg_parser/graph.c +++ b/tools/tplg_parser/graph.c @@ -23,6 +23,7 @@ /* load pipeline graph DAPM widget*/ int tplg_create_graph(struct tplg_context *ctx, int count, int pipeline_id, struct tplg_comp_info *temp_comp_list, char *pipeline_string, + size_t pipeline_string_size, struct sof_ipc_pipe_comp_connect *connection, int route_num) { @@ -64,13 +65,21 @@ int tplg_create_graph(struct tplg_context *ctx, int count, int pipeline_id, printf("loading route %s -> %s\n", source, sink); - strcat(pipeline_string, graph_elem->source); - strcat(pipeline_string, "->"); - - if (route_num == (count - 1)) { - strcat(pipeline_string, graph_elem->sink); - strcat(pipeline_string, "\n"); - } + size_t cur_len = strnlen(pipeline_string, pipeline_string_size); + size_t remaining = pipeline_string_size > cur_len ? + pipeline_string_size - cur_len : 0; + int written; + + if (route_num == (count - 1)) + written = snprintf(pipeline_string + cur_len, remaining, + "%s->%s\n", graph_elem->source, + graph_elem->sink); + else + written = snprintf(pipeline_string + cur_len, remaining, + "%s->", graph_elem->source); + + if (written < 0 || (size_t)written >= remaining) + fprintf(stderr, "warning: pipeline string truncated\n"); return 0; } diff --git a/tools/tplg_parser/include/tplg_parser/topology.h b/tools/tplg_parser/include/tplg_parser/topology.h index 04988d688082..b37d14444d14 100644 --- a/tools/tplg_parser/include/tplg_parser/topology.h +++ b/tools/tplg_parser/include/tplg_parser/topology.h @@ -13,6 +13,8 @@ #include <stdbool.h> #include <stdarg.h> #include <stddef.h> +#include <assert.h> +#include <stdio.h> #include <ipc/dai.h> #include <ipc/topology.h> #include <ipc/stream.h> @@ -194,43 +196,65 @@ struct tplg_context { #define tplg_get(ctx) ((void *)(ctx->tplg_base + ctx->tplg_offset)) +#define tplg_check_bounds(ctx, advance) \ + do { \ + if ((long)(advance) < 0 || \ + (ctx)->tplg_offset + (long)(advance) > (long)(ctx)->tplg_size) { \ + printf("%s %d topology offset %ld + %ld > size %zu\n", \ + __func__, __LINE__, (ctx)->tplg_offset, \ + (long)(advance), (ctx)->tplg_size); \ + exit(1); \ + } \ + } while (0) + #define tplg_get_hdr(ctx) \ ({struct snd_soc_tplg_hdr *ptr; \ - ptr = (struct snd_soc_tplg_hdr *)(ctx->tplg_base + ctx->tplg_offset); \ + tplg_check_bounds(ctx, sizeof(*ptr)); \ + ptr = (struct snd_soc_tplg_hdr *)((ctx)->tplg_base + (ctx)->tplg_offset); \ if (ptr->size != sizeof(*ptr)) { \ printf("%s %d hdr size mismatch 0x%x:0x%zx at offset %ld\n", \ __func__, __LINE__, ptr->size, sizeof(*ptr), \ - ctx->tplg_offset); assert(0); \ + (ctx)->tplg_offset); assert(0); \ } \ ctx->tplg_offset += sizeof(*ptr); (void *)ptr; }) #define tplg_skip_hdr_payload(ctx) \ ({struct snd_soc_tplg_hdr *ptr; \ - ptr = (struct snd_soc_tplg_hdr *)(ctx->tplg_base + ctx->tplg_offset); \ - ctx->tplg_offset += hdr->payload_size; (void *)ptr; }) + tplg_check_bounds(ctx, hdr->payload_size); \ + ptr = (struct snd_soc_tplg_hdr *)((ctx)->tplg_base + (ctx)->tplg_offset); \ + (ctx)->tplg_offset += hdr->payload_size; (void *)ptr; }) #define tplg_get_object(ctx, obj) \ - ({void *ptr; ptr = ctx->tplg_base + ctx->tplg_offset; \ - ctx->tplg_offset += sizeof(*(obj)); ptr; }) + ({void *ptr; \ + tplg_check_bounds(ctx, sizeof(*(obj))); \ + ptr = (ctx)->tplg_base + (ctx)->tplg_offset; \ + (ctx)->tplg_offset += sizeof(*(obj)); ptr; }) #define tplg_get_object_priv(ctx, obj, priv_size) \ - ({void *ptr; ptr = ctx->tplg_base + ctx->tplg_offset; \ - ctx->tplg_offset += sizeof(*(obj)) + priv_size; ptr; }) + ({void *ptr; \ + tplg_check_bounds(ctx, sizeof(*(obj)) + (priv_size)); \ + ptr = (ctx)->tplg_base + (ctx)->tplg_offset; \ + (ctx)->tplg_offset += sizeof(*(obj)) + (priv_size); ptr; }) #define tplg_get_widget(ctx) \ ({struct snd_soc_tplg_dapm_widget *w; \ - w = (struct snd_soc_tplg_dapm_widget *)(ctx->tplg_base + ctx->tplg_offset); \ - ctx->tplg_offset += sizeof(*w) + w->priv.size; w; }) + tplg_check_bounds(ctx, sizeof(*w)); \ + w = (struct snd_soc_tplg_dapm_widget *)((ctx)->tplg_base + (ctx)->tplg_offset); \ + tplg_check_bounds(ctx, sizeof(*w) + w->priv.size); \ + (ctx)->tplg_offset += sizeof(*w) + w->priv.size; w; }) #define tplg_get_graph(ctx) \ ({struct snd_soc_tplg_dapm_graph_elem *w; \ - w = (struct snd_soc_tplg_dapm_graph_elem *)(ctx->tplg_base + ctx->tplg_offset); \ - ctx->tplg_offset += sizeof(*w); w; }) + tplg_check_bounds(ctx, sizeof(*w)); \ + w = (struct snd_soc_tplg_dapm_graph_elem *)((ctx)->tplg_base + (ctx)->tplg_offset); \ + (ctx)->tplg_offset += sizeof(*w); w; }) #define tplg_get_pcm(ctx) \ ({struct snd_soc_tplg_pcm *pcm; \ - pcm = (struct snd_soc_tplg_pcm *)(ctx->tplg_base + ctx->tplg_offset); \ - ctx->tplg_offset += sizeof(*pcm) + pcm->priv.size; pcm; }) + tplg_check_bounds(ctx, sizeof(*pcm)); \ + pcm = (struct snd_soc_tplg_pcm *)((ctx)->tplg_base + (ctx)->tplg_offset); \ + tplg_check_bounds(ctx, sizeof(*pcm) + pcm->priv.size); \ + (ctx)->tplg_offset += sizeof(*pcm) + pcm->priv.size; pcm; }) static inline int tplg_valid_widget(struct snd_soc_tplg_dapm_widget *widget) { @@ -314,6 +338,7 @@ int tplg_new_process(struct tplg_context *ctx, void *process, size_t process_siz int tplg_create_graph(struct tplg_context *ctx, int count, int pipeline_id, struct tplg_comp_info *temp_comp_list, char *pipeline_string, + size_t pipeline_string_size, struct sof_ipc_pipe_comp_connect *connection, int route_num); diff --git a/tools/tplg_parser/object.c b/tools/tplg_parser/object.c index 4592031c7c01..ddc31e96f896 100644 --- a/tools/tplg_parser/object.c +++ b/tools/tplg_parser/object.c @@ -62,6 +62,14 @@ int tplg_create_object(struct tplg_context *ctx, return -EINVAL; } + /* a zero-size array never advances the cursor below: bail out + * instead of looping forever on a malformed topology + */ + if (array->size == 0) { + fprintf(stderr, "error: load %s zero-size array\n", name); + return -EINVAL; + } + for (i = 0; i < ipc->num_groups; i++) { const struct sof_topology_token *tokens = ipc->grp[i].tokens; int num_tokens = ipc->grp[i].num_tokens; diff --git a/tools/tplg_parser/process.c b/tools/tplg_parser/process.c index 5f0d8cdddaf2..97f7f5b7022b 100644 --- a/tools/tplg_parser/process.c +++ b/tools/tplg_parser/process.c @@ -151,6 +151,11 @@ static int process_append_data3(void *_process_ipc, /* Size is process IPC plus private data minus ABI header */ bytes_ctl = (struct snd_soc_tplg_bytes_control *)ctl; + if (bytes_ctl->priv.size < sizeof(struct sof_abi_hdr)) { + fprintf(stderr, "error: process priv data too small: %u\n", + bytes_ctl->priv.size); + return -EINVAL; + } size = bytes_ctl->priv.size - sizeof(struct sof_abi_hdr); ipc_size = sizeof(struct sof_ipc_comp_process) + UUID_SIZE + process_ipc->size + size; @@ -184,6 +189,11 @@ static int process_append_data4(void *_process_ipc, /* Size is process IPC plus private data minus ABI header */ bytes_ctl = (struct snd_soc_tplg_bytes_control *)ctl; + if (bytes_ctl->priv.size < sizeof(struct sof_abi_hdr)) { + fprintf(stderr, "error: process priv data too small: %u\n", + bytes_ctl->priv.size); + return -EINVAL; + } size = bytes_ctl->priv.size - sizeof(struct sof_abi_hdr); /* validate if everything will fit */ diff --git a/tools/tune/common/alsactl_write.m b/tools/tune/common/alsactl_write.m deleted file mode 100644 index 92fa67c3844f..000000000000 --- a/tools/tune/common/alsactl_write.m +++ /dev/null @@ -1,30 +0,0 @@ -function alsactl_write(fn, blob8) - -%% Write blob -check_create_dir(fn); -fh = fopen(fn, 'w'); -if fh < 0 - fprintf(1, 'Error: Could not open file %s\n', fn); - error("Failed."); -end - -%% Pad blob length to multiple of four bytes -n_orig = length(blob8); -n_new = ceil(n_orig/4); -blob8_new = zeros(1, n_new*4); -blob8_new(1:n_orig) = blob8; - -%% Convert to 32 bit -blob32 = zeros(1, n_new, 'uint32'); -k = 2.^[0 8 16 24]; -for i=1:n_new - j = (i-1)*4; - blob32(i) = blob8_new(j+1)*k(1) + blob8_new(j+2)*k(2) ... - + blob8_new(j+3)*k(3) + blob8_new(j+4)*k(4); -end -for i=1:n_new-1 - fprintf(fh, '%ld,', blob32(i)); -end -fprintf(fh, '%ld,\n', blob32(end)); -fclose(fh); -end diff --git a/tools/tune/common/blob_write.m b/tools/tune/common/blob_write.m deleted file mode 100644 index e13bea505bba..000000000000 --- a/tools/tune/common/blob_write.m +++ /dev/null @@ -1,28 +0,0 @@ -function blob_write(fn, blob8) - - -%% Write blob -check_create_dir(fn); -fh = fopen(fn, 'wb'); -if fh < 0 - fprintf(1, 'Error: Could not open file %s\n', fn); - error("Failed."); -end - -fwrite(fh, blob8, 'uint8'); -fclose(fh); - -%% Print as 8 bit hex -nb = length(blob8); -nl = ceil(nb/16); -for i = 1:nl - m = min(16, nb-(i-1)*16); - for j = 1:m - fprintf(1, "%02x ", blob8((i-1)*16 + j)); - end - fprintf(1, "\n"); -end - -fprintf(1, "\n"); - -end diff --git a/tools/tune/common/check_create_dir.m b/tools/tune/common/check_create_dir.m deleted file mode 100644 index 9d9ccd7f0e8a..000000000000 --- a/tools/tune/common/check_create_dir.m +++ /dev/null @@ -1,19 +0,0 @@ -function check_create_dir(fn) - -%% Check path of filename create directory if missing -% -% check_create_dir(fn) -% -% Inputs -% fn - string with path and filename - -% SPDX-License-Identifier: BSD-3-Clause -% -% Copyright(c) 2023 Intel Corporation. All rights reserved. - -[filepath, ~, ~] = fileparts(fn); -if ~exist(filepath, "dir") - mkdir(filepath); -end - -end diff --git a/tools/tune/common/get_abi.m b/tools/tune/common/get_abi.m deleted file mode 100644 index f00b74d9f141..000000000000 --- a/tools/tune/common/get_abi.m +++ /dev/null @@ -1,73 +0,0 @@ -function [bytes, nbytes] = get_abi(setsize, ipc_ver, type, param_id) - -%% Return current SOF ABI header -% -% [bytes, nbytes] = get_abi(setsize, ipc_ver, type, param_id) -% Input -% setsize - size of the payload blob -% ipc_ver - 3 or 4, defaults to 3 -% type - for IPC3, normally 0, defaults to 0 -% param_id - for IPC4, 0 - 255, defaults to 0 -% -% Output -% bytes - returned uint8 type array -% nbytes - length of the array - -% SPDX-License-Identifier: BSD-3-Clause -% -% Copyright(c) 2018 Intel Corporation. All rights reserved. -% -% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> - -if nargin < 2 - ipc_ver = 3; -end -if nargin < 3 - type = 0; -end -if nargin < 4 - param_id = 0; -end - -abifn = 'eq_get_abi.bin'; -switch ipc_ver - case 3 - %% Use sof-ctl to write ABI header into a file - cmd = sprintf('sof-ctl -g %d -t %d -b -o %s', setsize, type, abifn); - [bytes, nbytes] = get_abi_with_sofctl(cmd, abifn); - case 4 - cmd = sprintf('sof-ctl -i 4 -g %d -p %d -b -o %s', setsize, param_id, abifn); - [bytes, nbytes] = get_abi_with_sofctl(cmd, abifn); - otherwise - fprintf(1, 'Illegal ipc_ver %d\n', ipc_ver); - error('Failed.'); -end - -end - -function [bytes, nbytes] = get_abi_with_sofctl(cmd, abifn) - -[ret, ~] = system(cmd); -if ret - error('Failed to run sof-ctl. Is it installed?'); -end -fh = fopen(abifn, 'r'); -if fh < 0 - error('Failed to read abi header produced by sof-ctl'); -end -[bytes, nbytes] = fread(fh, inf, 'uint8'); -fclose(fh); -delete(abifn); - -end - -function bytes = w32b(word) - -sh = [0 -8 -16 -24]; -bytes = uint8(zeros(1,4)); -bytes(1) = bitand(bitshift(word, sh(1)), 255); -bytes(2) = bitand(bitshift(word, sh(2)), 255); -bytes(3) = bitand(bitshift(word, sh(3)), 255); -bytes(4) = bitand(bitshift(word, sh(4)), 255); - -end diff --git a/tools/tune/common/sof_alsactl_write.m b/tools/tune/common/sof_alsactl_write.m new file mode 100644 index 000000000000..02bf9ec7dd27 --- /dev/null +++ b/tools/tune/common/sof_alsactl_write.m @@ -0,0 +1,33 @@ +function sof_alsactl_write(fn, blob8) + +%% Check that blob header is sane +sof_check_blob_header(blob8); + +%% Write blob +sof_check_create_dir(fn); +fh = fopen(fn, 'w'); +if fh < 0 + fprintf(1, 'Error: Could not open file %s\n', fn); + error("Failed."); +end + +%% Pad blob length to multiple of four bytes +n_orig = length(blob8); +n_new = ceil(n_orig/4); +blob8_new = zeros(1, n_new*4); +blob8_new(1:n_orig) = blob8; + +%% Convert to 32 bit +blob32 = zeros(1, n_new, 'uint32'); +k = 2.^[0 8 16 24]; +for i=1:n_new + j = (i-1)*4; + blob32(i) = blob8_new(j+1)*k(1) + blob8_new(j+2)*k(2) ... + + blob8_new(j+3)*k(3) + blob8_new(j+4)*k(4); +end +for i=1:n_new-1 + fprintf(fh, '%ld,', blob32(i)); +end +fprintf(fh, '%ld\n', blob32(end)); +fclose(fh); +end diff --git a/tools/tune/common/sof_blob_write.m b/tools/tune/common/sof_blob_write.m new file mode 100644 index 000000000000..df37669618e1 --- /dev/null +++ b/tools/tune/common/sof_blob_write.m @@ -0,0 +1,30 @@ +function sof_blob_write(fn, blob8) + +%% Check that blob header is sane +sof_check_blob_header(blob8); + +%% Write blob +check_create_dir(fn); +fh = fopen(fn, 'wb'); +if fh < 0 + fprintf(1, 'Error: Could not open file %s\n', fn); + error("Failed."); +end + +fwrite(fh, blob8, 'uint8'); +fclose(fh); + +%% Print as 8 bit hex +nb = length(blob8); +nl = ceil(nb/16); +for i = 1:nl + m = min(16, nb-(i-1)*16); + for j = 1:m + fprintf(1, "%02x ", blob8((i-1)*16 + j)); + end + fprintf(1, "\n"); +end + +fprintf(1, "\n"); + +end diff --git a/tools/tune/common/sof_check_blob_header.m b/tools/tune/common/sof_check_blob_header.m new file mode 100644 index 000000000000..46a3aed45497 --- /dev/null +++ b/tools/tune/common/sof_check_blob_header.m @@ -0,0 +1,37 @@ +% sof_check_blob_header(blob) +% +% Check for correct header in bytes data. The function +% errors if header is not correct. +% +% Input +% blob - int8 type numbers data +% +% Output +% <none> + +function sof_check_blob_header(blob8) + +% Correct size in header? +blob_bytes = length(blob8); +header_bytes = b2w(blob8(5:8)); +if blob_bytes ~= header_bytes + 8 + fprintf(1, "Error: blob header size %d does not math blob size %d\n", header_bytes, blob_bytes); + fprintf(1, "Is installed sof-ctl up-to-date?\n"); + error("Failed."); +end + +% Correct command? +SOF_CTRL_CMD_BINARY = 3; +value = b2w(blob8(1:4)); +if value ~= SOF_CTRL_CMD_BINARY + fprintf(1, "Error: blob control command is not set to SOF_CTRL_CMD_BINARY.\n"); + fprintf(1, "Is installed sof-ctl up-to-date?\n"); + error("Failed."); +end + +end + +function word =b2w(bytes) + tmp = int32(bytes); + word = tmp(1) + bitshift(tmp(2), 8) + bitshift(tmp(3), 16) + bitshift(tmp(4), 24); +end diff --git a/tools/tune/common/sof_check_create_dir.m b/tools/tune/common/sof_check_create_dir.m new file mode 100644 index 000000000000..49f4b67c52b0 --- /dev/null +++ b/tools/tune/common/sof_check_create_dir.m @@ -0,0 +1,19 @@ +function sof_check_create_dir(fn) + +%% Check path of filename create directory if missing +% +% check_create_dir(fn) +% +% Inputs +% fn - string with path and filename + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright(c) 2023 Intel Corporation. All rights reserved. + +[filepath, ~, ~] = fileparts(fn); +if ~exist(filepath, "dir") + mkdir(filepath); +end + +end diff --git a/tools/tune/common/sof_get_abi.m b/tools/tune/common/sof_get_abi.m new file mode 100644 index 000000000000..34ebaa3c8e92 --- /dev/null +++ b/tools/tune/common/sof_get_abi.m @@ -0,0 +1,73 @@ +function [bytes, nbytes] = sof_get_abi(setsize, ipc_ver, type, param_id) + +%% Return current SOF ABI header +% +% [bytes, nbytes] = get_abi(setsize, ipc_ver, type, param_id) +% Input +% setsize - size of the payload blob +% ipc_ver - 3 or 4, defaults to 3 +% type - for IPC3, normally 0, defaults to 0 +% param_id - for IPC4, 0 - 255, defaults to 0 +% +% Output +% bytes - returned uint8 type array +% nbytes - length of the array + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright(c) 2018 Intel Corporation. All rights reserved. +% +% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +if nargin < 2 + ipc_ver = 3; +end +if nargin < 3 + type = 0; +end +if nargin < 4 + param_id = 0; +end + +abifn = 'eq_get_abi.bin'; +switch ipc_ver + case 3 + %% Use sof-ctl to write ABI header into a file + cmd = sprintf('sof-ctl -g %d -t %d -b -o %s', setsize, type, abifn); + [bytes, nbytes] = get_abi_with_sofctl(cmd, abifn); + case 4 + cmd = sprintf('sof-ctl -i 4 -g %d -p %d -b -o %s', setsize, param_id, abifn); + [bytes, nbytes] = get_abi_with_sofctl(cmd, abifn); + otherwise + fprintf(1, 'Illegal ipc_ver %d\n', ipc_ver); + error('Failed.'); +end + +end + +function [bytes, nbytes] = get_abi_with_sofctl(cmd, abifn) + +[ret, ~] = system(cmd); +if ret + error('Failed to run sof-ctl. Is it installed?'); +end +fh = fopen(abifn, 'r'); +if fh < 0 + error('Failed to read abi header produced by sof-ctl'); +end +[bytes, nbytes] = fread(fh, inf, 'uint8'); +fclose(fh); +delete(abifn); + +end + +function bytes = w32b(word) + +sh = [0 -8 -16 -24]; +bytes = uint8(zeros(1,4)); +bytes(1) = bitand(bitshift(word, sh(1)), 255); +bytes(2) = bitand(bitshift(word, sh(2)), 255); +bytes(3) = bitand(bitshift(word, sh(3)), 255); +bytes(4) = bitand(bitshift(word, sh(4)), 255); + +end diff --git a/tools/tune/common/sof_tplg2_write.m b/tools/tune/common/sof_tplg2_write.m new file mode 100644 index 000000000000..b0b03b86db11 --- /dev/null +++ b/tools/tune/common/sof_tplg2_write.m @@ -0,0 +1,62 @@ +function sof_tplg2_write(fn, blob8, component, comment, howto) + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2023, Intel Corporation. All rights reserved. +% +% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> + +if nargin < 4 + comment = 'Exported Control Bytes'; +end +if nargin < 5 + howto = []; +end + +%% Check that blob header is sane +sof_check_blob_header(blob8); + +%% Drop the 8 bytes TLV header from topology embedded blop +blob8 = blob8(9:end); + +%% Check that blob length is multiple of 32 bits +n_blob = length(blob8); +n_test = ceil(n_blob/4)*4; +if (n_blob ~= n_test) + fprintf(1, 'Error: ´Blob length %d is not multiple of 32 bits\n', ... + n_blob); + error('Failed.'); +end + +%% Write blob +sof_check_create_dir(fn); +fh = fopen(fn, 'w'); +if fh < 0 + fprintf(1, 'Error: Could not open file %s\n', fn); + error("Failed."); +end +nl = 8; +fprintf(fh, '# %s %s\n', comment, date()); +if ~isempty(howto) + fprintf(fh, '# %s\n', howto); +end +fprintf(fh, 'Object.Base.data.\"%s\" {\n', component); +fprintf(fh, '\tbytes \"\n'); +for i = 1:nl:n_blob + fprintf(fh, '\t\t'); + for j = 0:nl-1 + n = i + j; + if n < n_blob + fprintf(fh, '0x%02x,', blob8(n)); + end + if n == n_blob + fprintf(fh, '0x%02x"', blob8(n)); + end + end + fprintf(fh, '\n'); +end +fprintf(fh, '}\n'); +fclose(fh); +fprintf('Blob size %d was written to file %s\n', n_blob, fn); + +end diff --git a/tools/tune/common/sof_tplg_write.m b/tools/tune/common/sof_tplg_write.m new file mode 100644 index 000000000000..4a766583b726 --- /dev/null +++ b/tools/tune/common/sof_tplg_write.m @@ -0,0 +1,55 @@ +function sof_tplg_write(fn, blob8, name, comment, howto) + +if nargin < 4 + comment = 'Exported Control Bytes'; +end +if nargin < 5 + howto = []; +end + +%% Check that blob header is sane +sof_check_blob_header(blob8); + +%% Drop the 8 bytes TLV header from topology embedded blop +blob8 = blob8(9:end); + +%% Pad blob length to multiple of four bytes +n_orig = length(blob8); +n_new = ceil(n_orig/4)*4; +blob8_new = zeros(1, n_new); +blob8_new(1:n_orig) = blob8; + +%% Write blob +sof_check_create_dir(fn); +fh = fopen(fn, 'w'); +if fh < 0 + fprintf(1, 'Error: Could not open file %s\n', fn); + error("Failed."); +end +nl = 8; +fprintf(fh, '# %s %s\n', comment, date()); +if ~isempty(howto) + fprintf(fh, '# %s\n', howto); +end +fprintf(fh, 'CONTROLBYTES_PRIV(%s_priv,\n', name); +fprintf(fh, '` bytes "'); +for i = 1:nl:n_new + if i > 1 + fprintf(fh, '` '); + end + for j = 0:nl-1 + n = i + j; + if n < n_new + fprintf(fh, '0x%02x,', blob8_new(n)); + end + if n == n_new + fprintf(fh, '0x%02x"', blob8_new(n)); + end + end + fprintf(fh, '''\n'); +end +fprintf(fh, ')\n'); +fclose(fh); +fprintf('Blob size %d was written to file %s\n', n_new, fn); + +end diff --git a/tools/tune/common/sof_ucm_blob_write.m b/tools/tune/common/sof_ucm_blob_write.m index 2a60b0021861..22eca5ce5ac5 100644 --- a/tools/tune/common/sof_ucm_blob_write.m +++ b/tools/tune/common/sof_ucm_blob_write.m @@ -13,45 +13,30 @@ function sof_ucm_blob_write(fn, blob8) % % Copyright (c) 2024, Intel Corporation. All rights reserved. -% Export for UCM cset-tlv with additional 8 bytes header -SOF_CTRL_CMD_BINARY = 3; -nh = 8; -nb = length(blob8); -ublob8 = zeros(nb + nh, 1, 'uint8'); -ublob8(1:4) = w32b(SOF_CTRL_CMD_BINARY); -ublob8(5:8) = w32b(nb); -ublob8(9:end) = blob8; +%% Check that blob header is sane +sof_check_blob_header(blob8); %% Write blob -check_create_dir(fn); +sof_check_create_dir(fn); fh = fopen(fn, 'wb'); if fh < 0 fprintf(1, 'Error: Could not open file %s\n', fn); error("Failed."); end -fwrite(fh, ublob8, 'uint8'); +fwrite(fh, blob8, 'uint8'); fclose(fh); %% Print as 8 bit hex -nb = length(ublob8); +nb = length(blob8); nl = ceil(nb/16); for i = 1:nl m = min(16, nb-(i-1)*16); for j = 1:m - fprintf(1, "%02x ", ublob8((i-1)*16 + j)); + fprintf(1, "%02x ", blob8((i-1)*16 + j)); end fprintf(1, "\n"); end fprintf(1, "\n"); end - -function bytes = w32b(word) -sh = [0 -8 -16 -24]; -bytes = uint8(zeros(1,4)); -bytes(1) = bitand(bitshift(word, sh(1)), 255); -bytes(2) = bitand(bitshift(word, sh(2)), 255); -bytes(3) = bitand(bitshift(word, sh(3)), 255); -bytes(4) = bitand(bitshift(word, sh(4)), 255); -end diff --git a/tools/tune/common/tplg2_write.m b/tools/tune/common/tplg2_write.m deleted file mode 100644 index cff82f79f1ca..000000000000 --- a/tools/tune/common/tplg2_write.m +++ /dev/null @@ -1,55 +0,0 @@ -function tplg2_write(fn, blob8, component, comment, howto) - -% SPDX-License-Identifier: BSD-3-Clause -% -% Copyright (c) 2023, Intel Corporation. All rights reserved. -% -% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> - -if nargin < 4 - comment = 'Exported Control Bytes'; -end -if nargin < 5 - howto = []; -end - -%% Check that blob length is multiple of 32 bits -n_blob = length(blob8); -n_test = ceil(n_blob/4)*4; -if (n_blob ~= n_test) - fprintf(1, 'Error: ´Blob length %d is not multiple of 32 bits\n', ... - n_blob); - error('Failed.'); -end - -%% Write blob -fh = fopen(fn, 'w'); -if fh < 0 - fprintf(1, 'Error: Could not open file %s\n', fn); - error("Failed."); -end -nl = 8; -fprintf(fh, '# %s %s\n', comment, date()); -if ~isempty(howto) - fprintf(fh, '# %s\n', howto); -end -fprintf(fh, 'Object.Base.data.\"%s\" {\n', component); -fprintf(fh, '\tbytes \"\n'); -for i = 1:nl:n_blob - fprintf(fh, '\t\t'); - for j = 0:nl-1 - n = i + j; - if n < n_blob - fprintf(fh, '0x%02x,', blob8(n)); - end - if n == n_blob - fprintf(fh, '0x%02x"', blob8(n)); - end - end - fprintf(fh, '\n'); -end -fprintf(fh, '}\n'); -fclose(fh); -fprintf('Blob size %d was written to file %s\n', n_blob, fn); - -end diff --git a/tools/tune/common/tplg_write.m b/tools/tune/common/tplg_write.m deleted file mode 100644 index 2834af82a919..000000000000 --- a/tools/tune/common/tplg_write.m +++ /dev/null @@ -1,48 +0,0 @@ -function tplg_write(fn, blob8, name, comment, howto) - -if nargin < 4 - comment = 'Exported Control Bytes'; -end -if nargin < 5 - howto = []; -end - -%% Pad blob length to multiple of four bytes -n_orig = length(blob8); -n_new = ceil(n_orig/4)*4; -blob8_new = zeros(1, n_new); -blob8_new(1:n_orig) = blob8; - -%% Write blob -fh = fopen(fn, 'w'); -if fh < 0 - fprintf(1, 'Error: Could not open file %s\n', fn); - error("Failed."); -end -nl = 8; -fprintf(fh, '# %s %s\n', comment, date()); -if ~isempty(howto) - fprintf(fh, '# %s\n', howto); -end -fprintf(fh, 'CONTROLBYTES_PRIV(%s_priv,\n', name); -fprintf(fh, '` bytes "'); -for i = 1:nl:n_new - if i > 1 - fprintf(fh, '` '); - end - for j = 0:nl-1 - n = i + j; - if n < n_new - fprintf(fh, '0x%02x,', blob8_new(n)); - end - if n == n_new - fprintf(fh, '0x%02x"', blob8_new(n)); - end - end - fprintf(fh, '''\n'); -end -fprintf(fh, ')\n'); -fclose(fh); -fprintf('Blob size %d was written to file %s\n', n_new, fn); - -end diff --git a/tools/tune/mfcc/README.txt b/tools/tune/mfcc/README.txt deleted file mode 100644 index fb8208992ed4..000000000000 --- a/tools/tune/mfcc/README.txt +++ /dev/null @@ -1,29 +0,0 @@ -This directory contains a tool to create configuration blob for SOF -MFCC component. It's simply run in Matlab or Octave with command -"setup_mfcc". The MFCC configuration parameters can be edited from the -script. - -The configuration can be test run with testbench. First the test topologies -need to be created with "scripts/build-tools.sh -t". Next the testbench -is build with "scripts/rebuild-testbench.sh". - -Once the previous steps are done, a sample wav file can be processed -into stream of cepstral coefficients with script run_mfcc.sh. E.g. -next command processes an ALSA test file with speech clip "front center". -The output file is hard-coded to mfcc.raw. - -./run_mfcc.sh /usr/share/sounds/alsa/Front_Center.wav - -The output can be plotted and retrieved with Matlab or Octave command: - -[ceps, t, n] = decode_ceps('mfcc.raw', 13); - -In the above it's known from configuration script that MFCC was set up to -output 13 cepstral coefficients from each FFT -> Mel -> DCT -> Cepstral -coefficients computation run. - -Other kind of signals have quite big visual difference in audio features. Try -e.g. other sound files found in computer. - -./run_mfcc.sh /usr/share/sounds/gnome/default/alerts/bark.ogg -./run_mfcc.sh /usr/share/sounds/gnome/default/alerts/sonar.ogg diff --git a/tools/tune/mfcc/decode_ceps.m b/tools/tune/mfcc/decode_ceps.m deleted file mode 100644 index a63677fa3731..000000000000 --- a/tools/tune/mfcc/decode_ceps.m +++ /dev/null @@ -1,93 +0,0 @@ -% [ceps, t, n] = decode_ceps(fn, num_ceps, num_channels) -% -% Input -% fn - File with MFCC data in .raw or .wav format -% num_ceps - number of cepstral coefficients per frame -% num_channels - needed for .raw format, omit for .wav -% -% Outputs -% ceps - cepstral coefficients -% t - time vector for plotting -% n - ceps 1..num_ceps vector for plotting - -% SPDX-License-Identifier: BSD-3-Clause -% Copyright(c) 2022 Intel Corporation. All rights reserved. - -function [ceps, t, n] = decode_ceps(fn, num_ceps, num_channels) - -if nargin < 3 - num_channels = 1; -end - -% MFCC stream -fs = 16e3; -qformat = 7; -magic = [25443 28006]; % ASCII 'mfcc' as int16 - -% Load output data -[data, num_channels] = get_file(fn, num_channels); - -idx1 = find(data == magic(1)); -idx = []; -for i = 1:length(idx1) - if data(idx1(i) + 1) == magic(2) - idx = [idx idx1(i)]; - end -end - -if isempty(idx) - error('No magic value markers found from stream'); -end - -period_ceps = idx(2)-idx(1); -num_frames = length(idx); -t_ceps = period_ceps / num_channels / fs; -t = (0:num_frames -1) * t_ceps; -n = 1:num_ceps; - -ceps = zeros(num_ceps, num_frames); -for i = 1:num_frames - i1 = idx(i) + 2; - i2 = i1 + num_ceps - 1; - ceps(:,i) = data(i1:i2) / 2^qformat; -end - -figure; -surf(t, n, ceps, 'EdgeColor', 'none'); -colormap(jet); -view(45, 60) -tstr = sprintf('SOF MFCC cepstral coefficients (%s)', fn); -title(tstr, 'Interpreter', 'None'); -xlabel('Time (s)'); -ylabel('Cepstral coef #'); - -end - -function [data, num_channels] = get_file(fn, num_channels) - -[~, ~, ext] = fileparts(fn); - -switch lower(ext) - case '.raw' - fh = fopen(fn, 'r'); - data = fread(fh, 'int16'); - fclose(fh); - case '.wav' - tmp = audioread(fn, 'native'); - t = whos('tmp'); - if ~strcmp(t.class, 'int16'); - error('Only 16-bit wav file format is supported'); - end - s = size(tmp); - num_channels = s(2); - if num_channels > 1 - data = int16(zeros(prod(s), 1)); - for i = 1:num_channels - data(i:num_channels:end) = tmp(:, i); - end - end - otherwise - error('Unknown audio format'); -end - -end diff --git a/tools/tune/mfcc/run_mfcc.sh b/tools/tune/mfcc/run_mfcc.sh deleted file mode 100755 index 8a48c97b9def..000000000000 --- a/tools/tune/mfcc/run_mfcc.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2022 Intel Corporation. All rights reserved. - -set -e - -RAW_INPUT=in.raw -RAW_OUTPUT=mfcc.raw - -export LD_LIBRARY_PATH=../../testbench/build_testbench/sof_ep/install/lib:../../testbench/build_testbench/sof_parser/install/lib - -TESTBENCH=../../testbench/build_testbench/install/bin/testbench -OPT="-q -r 16000 -R 16000 -c 1 -n 1 -b S16_LE -t ../../build_tools/test/topology/test-playback-ssp5-mclk-0-I2S-mfcc-s16le-s16le-48k-24576k-codec.tplg" - -# Convert input audio file raw 16 kHz 1 channel 16 bit -sox --encoding signed-integer "$1" -L -r 16000 -c 1 -b 16 "$RAW_INPUT" - -# Run testbench -$TESTBENCH $OPT -i "$RAW_INPUT" -o "$RAW_OUTPUT" - -echo ----------------------------------------------- -echo The MFCC data was output to file $RAW_OUTPUT -echo ----------------------------------------------- diff --git a/tools/tune/mfcc/setup_mfcc.m b/tools/tune/mfcc/setup_mfcc.m deleted file mode 100644 index 9a1d02335b93..000000000000 --- a/tools/tune/mfcc/setup_mfcc.m +++ /dev/null @@ -1,210 +0,0 @@ -% setup_mfcc(cfg) -% -% Input -% cfg - optional MFCC configuration parameters struct, see -% below from code -% -% Create binary configuration blob for MFCC component. The hex data -% is written to tools/topology/topology1/m4/mfcc/mfcc_config.m4 - -% SPDX-License-Identifier: BSD-3-Clause -% -% Copyright (c) 2018-2020, Intel Corporation. All rights reserved. - -function setup_mfcc(cfg) - -if nargin < 1 - cfg.blackman_coef = 0.42; - cfg.cepstral_lifter = 22.0; - cfg.channel = -1; % -1 expect mono, 0 left, 1 right ... - cfg.dither = 0.0; % no support - cfg.energy_floor = 1.0; - cfg.frame_length = 25.0; % ms - cfg.frame_shift = 10.0; % ms - cfg.high_freq = 0.0; % 0 is Nyquist - cfg.htk_compat = false; % no support - cfg.low_freq = 20.0; % Hz - cfg.num_ceps = 13; - cfg.min_duration = 0.0; % no support - cfg.norm = 'none'; % Use none or slaney - cfg.num_mel_bins = 23; - cfg.preemphasis_coefficient = 0; % disable - cfg.raw_energy = true; - cfg.remove_dc_offset = true; - cfg.round_to_power_of_two = true; % must be true - cfg.sample_frequency = 16000; - cfg.snip_edges = true; % must be true - cfg.subtract_mean = false; % must be false - cfg.use_energy = false; - cfg.vtln_high = -500.0; % no support - cfg.vtln_low = 100.0; % no support - cfg.vtln_warp = 1.0; % must be 1.0 (vocal tract length normalization) - cfg.window_type = 'hamming'; - cfg.mel_log = 'log'; % Set to 'db' for librosa, set to 'log10' for matlab - cfg.pmin = 5e-10; % Set to 1e-10 for librosa - cfg.top_db = 200; % Set to 80 for librosa -end - -cfg.tplg_fn = '../../topology/topology1/m4/mfcc/mfcc_config.m4'; -cfg.tplg_ver = 1; -cfg.ipc_ver = 3; -export_mfcc_setup(cfg); - -cfg.tplg_fn = '../../topology/topology2/include/components/mfcc/default.conf'; -cfg.tplg_ver = 2; -cfg.ipc_ver = 4; -export_mfcc_setup(cfg); - -end - -function export_mfcc_setup(cfg) - -%% Use blob tool from EQ -addpath('../common'); - -%% Blob size, size plus reserved(8) + current parameters -nbytes_data = 104; - -%% Little endian -sh32 = [0 -8 -16 -24]; -sh16 = [0 -8]; - -%% Get ABI information -[abi_bytes, nbytes_abi] = get_abi(nbytes_data, cfg.ipc_ver); - -%% Initialize correct size uint8 array -nbytes = nbytes_abi + nbytes_data; -b8 = uint8(zeros(1,nbytes)); - -%% Insert ABI header -fprintf(1, 'MFCC blob size is %d, ABI header is %d, data is %d\n',nbytes, nbytes_abi, nbytes_data); -b8(1:nbytes_abi) = abi_bytes; -j = nbytes_abi + 1; - -%% Apply default MFCC configuration, first struct header and reserved, then data -[b8, j] = add_w32b(nbytes_data, b8, j); -for i = 1:8 - [b8, j] = add_w32b(0, b8, j); -end - -v = q_convert(cfg.sample_frequency, 0); [b8, j] = add_w32b(v, b8, j); -v = q_convert(cfg.pmin, 31); [b8, j] = add_w32b(v, b8, j); -v = 0; [b8, j] = add_w32b(v, b8, j); % enum mel_log -v = 0; [b8, j] = add_w32b(v, b8, j); % enum norm -v = 0; [b8, j] = add_w32b(v, b8, j); % enum pad -v = get_window(cfg); [b8, j] = add_w32b(v, b8, j); % enum window -v = 1; [b8, j] = add_w32b(v, b8, j); % enum dct type -v = q_convert(cfg.blackman_coef, 15); [b8, j] = add_w16b(v, b8, j); -v = q_convert(cfg.cepstral_lifter, 9); [b8, j] = add_w16b(v, b8, j); -v = cfg.channel; [b8, j] = add_w16b(v, b8, j); -v = cfg.dither; [b8, j] = add_w16b(v, b8, j); -v = round(cfg.frame_length/1000 * cfg.sample_frequency); [b8, j] = add_w16b(v, b8, j); -v = round(cfg.frame_shift/1000 * cfg.sample_frequency); [b8, j] = add_w16b(v, b8, j); -v = q_convert(cfg.high_freq, 0); [b8, j] = add_w16b(v, b8, j); -v = q_convert(cfg.low_freq, 0); [b8, j] = add_w16b(v, b8, j); -v = cfg.num_ceps; [b8, j] = add_w16b(v, b8, j); -v = cfg.num_mel_bins; [b8, j] = add_w16b(v, b8, j); -v = q_convert(cfg.preemphasis_coefficient, 15); [b8, j] = add_w16b(v, b8, j); -v = q_convert(cfg.top_db, 7); [b8, j] = add_w16b(v, b8, j); -v = 0; [b8, j] = add_w16b(v, b8, j); % vtln_high Qx.y TBD -v = 0; [b8, j] = add_w16b(v, b8, j); % vtln_low Qx.y TBD -v = 0; [b8, j] = add_w16b(v, b8, j); % vtln_warp Qx.y TBD -v = cfg.htk_compat; [b8, j] = add_w8b(v, b8, j); % bool -v = cfg.raw_energy; [b8, j] = add_w8b(v, b8, j); % bool -v = cfg.remove_dc_offset; [b8, j] = add_w8b(v, b8, j); % bool -v = cfg.round_to_power_of_two; [b8, j] = add_w8b(v, b8, j); % bool -v = cfg.snip_edges; [b8, j] = add_w8b(v, b8, j); % bool -v = cfg.subtract_mean; [b8, j] = add_w8b(v, b8, j); % bool -v = cfg.use_energy; [b8, j] = add_w8b(v, b8, j); % bool - -%% Export -switch cfg.tplg_ver - case 1 - tplg_write(cfg.tplg_fn, b8, "DEF_MFCC_PRIV", ... - "Exported with script setup_mfcc.m", ... - "cd tools/tune/mfcc; octave setup_mfcc.m"); - case 2 - tplg2_write(cfg.tplg_fn, b8, "mfcc_config", ... - "Exported MFCC configuration", ... - "cd tools/tune/mfcc; octave setup_mfcc.m"); - otherwise - error("Illegal cfg.tplg_ver, use 1 for topology v1 or 2 topology v2."); -end - -rmpath('../common'); - -end - -%% Helper functions - -function n = get_window(cfg) - switch lower(cfg.window_type) - case 'rectangular' - n = 0; - case 'blackman' - n = 1; - case 'hamming' - n = 2; - case 'hann' - n = 3; - case 'povey' - n = 4; - otherwise - error('Unknown window type'); - end -end - -function bytes = w8b(word) -bytes = uint8(zeros(1,1)); -bytes(1) = bitand(word, 255); -end - -function bytes = w16b(word) -sh = [0 -8]; -bytes = uint8(zeros(1,2)); -bytes(1) = bitand(bitshift(word, sh(1)), 255); -bytes(2) = bitand(bitshift(word, sh(2)), 255); -end - -function bytes = w32b(word) -sh = [0 -8 -16 -24]; -bytes = uint8(zeros(1,4)); -bytes(1) = bitand(bitshift(word, sh(1)), 255); -bytes(2) = bitand(bitshift(word, sh(2)), 255); -bytes(3) = bitand(bitshift(word, sh(3)), 255); -bytes(4) = bitand(bitshift(word, sh(4)), 255); -end - -function n = q_convert(val, q) -n = round(val * 2^q); -end - -function [blob8, j] = add_w8b(v, blob8, j) -if j > length(blob8) - error('Blob size is not sufficient'); -end -blob8(j) = w8b(v); -j = j + 1; -end - -function [blob8, j] = add_w16b(v, blob8, j) -if j + 1 > length(blob8) - error('Blob size is not sufficient'); -end -if v < 0 - v = 2^16 + v; -end -blob8(j : j + 1) = w16b(v); -j = j + 2; -end - -function [blob8, j] = add_w32b(v, blob8, j) -if j + 3 > length(blob8) - error('Blob size is not sufficient'); -end -if v < 0 - v = 2^32 + v; -end -blob8(j : j + 3) = w32b(v); -j = j + 4; -end diff --git a/uuid-registry.txt b/uuid-registry.txt index bbf92ecd2ec2..e9e8f8e77876 100644 --- a/uuid-registry.txt +++ b/uuid-registry.txt @@ -1,9 +1,10 @@ # -# Global UUID/name registry for SOF components. All IDs used in -# shipped binary artifacts must appear in this list. All names must -# be unique. All names must be legal C identifiers of at most 31 -# characters. No change to a previously distributed mapping is -# allowed, ever. +# Global UUID/name registry for SOF components in alphabetical order. +# +# All IDs used in shipped binary artifacts must appear in this list. +# All names must be unique. +# All names must be legal C identifiers of at most 31 characters. +# No change to a previously distributed mapping is allowed, ever. # # Simple format: "#" indicates a comment to end of line. Remaining # lines must be entirely empty/whitespace, or two whitespace-separated @@ -18,9 +19,9 @@ # are just using random values and won't care about the byte swap. # + ab01db67-84b0-4d2d-93d30e619680576e acp_bt_dma f8a7091c-7d2d-4410-9bb555278378d59f acp_clk -70f2d3f2-cbb6-4984-a2d80dd514b80bc2 acpdma 0ae40946-dfd2-4140-91520dd5a3eaae81 acp_dmic_dai 109c7aba-a7ba-43c3-b94259e20a6611be acp_dmic_dma dc2199ea-cdae-4d23-a413ffe442f785f2 acp_dmic_dma_common @@ -28,6 +29,7 @@ b414df09-9e31-4c59-86577afc8deba70c acp_hs 3ac07334-41ce-4447-a2c5dff0d1fa1392 acp_sp 2ef92c66-78a4-41f7-b52f5539707a9382 acp_sp_common 5871f3ca-dd92-4edb-8a94d651dd208b1e acp_sw_audio +70f2d3f2-cbb6-4984-a2d80dd514b80bc2 acpdma 30290c76-6a05-4784-8464c21f09cee87e afe_dai 4e8f16d1-e935-41f4-b99e42c57e745784 afedrv c63c4e75-8f61-4420-93191395932efa9e agent_work @@ -38,6 +40,7 @@ ea9c4bca-5b7d-48c6-9586553e27235beb ams c8ec72f6-8526-4faf-9d39a23d0b541de2 asrc 66b4402d-b468-42f2-81a7b37121863dd4 asrc4 0e398c32-5ade-ba4b-93b1c50432280ee4 basefw +2B79E4F3-4675-F649-89DF3BC194A91AEB brngup 20865bfe-b833-4ff9-b22a0482c3477497 btdai 42544c92-8e92-4e41-b67934519f1c1d28 buffer d8218443-5ff3-4a4c-b3886cfe07b956aa cadence_codec @@ -46,7 +49,10 @@ ec290e95-4a20-47eb-bbffd9c888431831 chmap 53863428-9a72-44df-af0ffe45ea2348ba clkdrv_mt8186 19d4e680-4479-48cc-af869f63d8b0098b clkdrv_mt8188 23b12fd5-c2a9-41a8-a2b3231ab7dcdc70 clkdrv_mt8195 +e87bf747-e574-4362-bf2cc015d2859dd9 clkdrv_mt8196 +de358908-c146-4411-98b430ebd002957f clkdrv_mt8365 8890ea76-0df9-44ae-87e6994f4c15e9fa clock +D406D134-C3C1-402C-8AEC6821C0C2B0E6 cold 7c42ce8b-0108-43d0-913756d660478c5f component 9ba00c83-ca12-4a83-943c1fa2e82f9dda copier 948c9ad1-806a-4131-ad6cb2bda9e35a9f crossover @@ -58,6 +64,7 @@ bc3526a7-9b86-4ab4-84a52e02ae70cc10 dma 729bf8b5-e873-4bf5-96908e2a3fd33911 dma_copy 58782c63-1326-4185-845922272e12d1f1 dma_trace 2b972272-c5b1-4b7e-926f0fc5cb4c4690 dma_trace_task +40f66c8b-5aa5-4345-891953ec431aaa98 dolby_dax_audio_processing 87858bc2-baa9-40b6-8e4c2c95ba8b1545 dp_sched ee755917-96b9-4130-b49e37b9d0501993 dp_task b36ee4da-006f-47f9-a06dfecbe2d8b6ce drc @@ -71,9 +78,10 @@ f6d15ad3-b122-458c-ae9b0ab0b5867aa0 dummy_dma 5150c0e6-27f9-4ec8-8351c705b642d12f eq_iir 889f6dcd-ddcd-4e05-aa5b0d39f8bca961 esai bfc7488c-75aa-4ce8-9dbed8da08a698c2 file +93446e12-1864-4e04-afe03b1d778ffb79 fir 61bca9a8-18d0-4a18-8e7b2639219804b7 gain -c3c74249-058e-414f-82404da5f3fc2389 google_hotword bf0e1bbc-dc6a-45fe-bc902554cb137ab4 google_ctc_audio_processing +c3c74249-058e-414f-82404da5f3fc2389 google_hotword b780a0a6-269f-466f-b47723dfa05af758 google_rtc_audio_processing 8b9d100c-6d78-418f-90a3e0e805d0852b host 8f00c3bb-e835-4767-9a34b8ec1041e56b hsdai @@ -81,24 +89,31 @@ b780a0a6-269f-466f-b47723dfa05af758 google_rtc_audio_processing a5dacb0e-88dc-415c-a1b53e8df77f1976 idc_cmd_task b90f5a4e-5537-4375-a1df95485472ff9e idc_task 696ae2bc-2877-11eb-adc10242ac120002 igo_nr +b0cdcd9e-ef8b-404f-84800f287fc9d44d iir +2f520e85-49ba-4284-90d83def24af313b intc_mt8196 fa00558c-d653-4851-a03ab21f125a9524 interrupt be60f97d-78df-4796-a0ee435cb56b720a ipc -a814a1ca-0b83-466c-95872f35ff8d12e8 ipcgw 389c9186-5a7d-4ad1-a02ca02ecdadfb33 ipc_task 49be8ff3-71a3-4456-bb7e4723f2e5730c ipc_task_amd a3fe3bf2-39a4-4fc3-b3418a96e0a26759 ipc_task_mt818x +caef4bd7-7a2e-4039-9b061f5ff9ec3899 ipc_task_mt8196 6c8f0d53-ff77-4ca1-b825c0c4e1b0d322 ipc_task_posix +a814a1ca-0b83-466c-95872f35ff8d12e8 ipcgw 1862d39a-3a84-4d64-8c91dce1dfc122db irq 6533d0eb-b785-4709-84f5347c81720189 irq_acp d2e3f730-df39-42ee-81a839bfb4d024c2 irq_mt818x +7eb28333-f08f-436f-bbbd764ac21fc2f1 irq_mt8196 eba8d51f-7827-47b5-82eede6e7743af67 keyword d8218443-5ff3-4a4c-b3886cfe07b9562e kpb a8a0cb32-4a77-4db1-85c753d7ee07bce6 kpb4 e50057a5-8b27-4db4-bd799a639cee5f50 kpb_task +30397456-4661-4644-97e539a9e5ab1778 level_multiplier 54cf5598-8b29-11ec-a8a30242ac120002 lib_manager 4f9c3ec7-7b55-400c-86b3502b4420e625 ll_sched 9f130ed8-2bbf-421c-836ad5269147c9e7 ll_sched_lib 37f1d41f-252d-448d-b9c41e2bee8e1bf1 main_task +107eb437-0347-4336-ab60f4baaeb5ea49 math_fft +590af515-8fc0-4827-8748c8efbe6ac514 math_fft_multi d23cf8d0-8dfe-497c-82025f909cf72735 math_power 0cd84e80-ebd3-11ea-adc10242ac120002 maxim_dsm 425d6e68-145c-4455-b0b2c7260b0600a5 mem @@ -109,14 +124,16 @@ bc06c037-12aa-417c-9a9789282e321a76 mixer 39656eb2-3b71-4049-8d3ff92cd5c43c09 mixin 3c56505a-24d7-418f-bddcc1f5a3ac2ae0 mixout ee2585f2-e7d8-43dc-90ab4224e00c3e84 modules -bb2aa22e-1ab6-4650-85016e67fcc04f4e mtrace_task 0d9f2256-8e4f-47b3-8448239a334f1191 multiband_drc c607ff4d-9cb6-49dc-b6787da3c63ea557 mux 64ce6e35-857a-4878-ace8e2a2f42e3069 mux4 +f36BF24B-9AAF-83f4-8677E072E8AEADB7 notification_pool 1fb15a7a-83cd-4c2e-8b324da1b2adeeaf notifier 7ae671a7-4617-4a09-bf6d9d29c998dbc1 ns +127f4eec-23fa-11f0-a4a6bf0cd6b4583b nxp_eap 376b5e44-9c82-4ec2-bc8310ea101af88f passthrough 64a794f0-55d3-4bca-9d5b7b588badd037 passthru_smart_amp +09fbcb7a-a9c5-4a57-84344440e598ab24 phase_vocoder 4e934adb-b0ec-4d33-a086c1022f921321 pipe f11818eb-e92e-4082-82a3dc54c604ebb3 pipe_task d7f6712d-131c-45a7-82ed6aa9dc2291ea pm_runtime @@ -135,20 +152,29 @@ d7f6712d-131c-45a7-82ed6aa9dc2291ea pm_runtime cf90d851-68a2-4987-a2de85aed0c8531c sgen_mt8186 99316bd9-07b9-4665-81796e048d67cb45 sgen_mt8188 9eb1a55b-fc20-4442-96131ff1023be493 sgen_mt8195 +bcf54c06-5702-4a60-ac4abb509123c649 sgen_mt8196 +654ef011-6d79-414a-9c1b15e72c0be321 sgen_mt8365 dabe8814-47e8-11ed-a58bb309974fecce shmread e2b6031c-47e8-11ed-07a97f801b6efa6c shmwrite 167a961e-8ae4-11ea-89f1000c29ce1635 smart_amp_test +a43f9d7c-ea75-44d5-942d967991a33809 sound_dose 4abd71ba-8619-458a-b33f160fc0cf809b spdai a417b6fb-459d-4cf9-be65d38dc9057b80 spi_completion 9d346d98-203d-4791-baee1770a03d4a71 spinlock c1c5326d-8390-46b4-aa4795c3beca6550 src e61bb28d-149a-4c1f-b70946823ef5f5ae src4 33441051-44cd-466a-83a3178478708aea src_lite +0d116ea6-9150-46de-98b8b2b3a791da29 stft_process eb0bd14b-7d5e-4dfa-bbe27762adb279f0 swaudiodai -37c196ae-3532-4282-8a78dd9d50cc7123 testbench dd511749-d9fa-455c-b3a713585693f1af tdfb +a62de1af-5964-4e2e-b1677fdc97279a29 template +37c196ae-3532-4282-8a78dd9d50cc7123 testbench +08aeb4ff-7f68-4c71-86c3c842b4262898 tester +c51dc642-a2e1-48df-a490e2748cb6363e tflmcly 04e3f894-2c5c-4f2e-8dc1694eeaab53fa tone +e93326d8-0d14-4bf0-bcb9e063d3d80136 twb_sched 42f8060c-832f-4dbf-b24751e961997b34 up_down_mixer +6f6b6f4b-6f73-7466-20e1e62b9779f003 userspace_proxy b77e677e-5ff4-4188-af14fba8bdbf8682 volume 8a171323-94a3-4e1d-afe9fe5dbaa4c393 volume4 1028070e-04e8-46ab-8d8110a0116ce738 wait diff --git a/versions.json b/versions.json index 8349f2f8c868..89bebab40c35 100644 --- a/versions.json +++ b/versions.json @@ -1,7 +1,7 @@ { "SOF": { "MAJOR": "2", - "MINOR": "12", + "MINOR": "14", "MICRO": "99" } } diff --git a/west.yml b/west.yml index 6fd718c542ea..abb3dcaa9736 100644 --- a/west.yml +++ b/west.yml @@ -43,7 +43,7 @@ manifest: - name: zephyr repo-path: zephyr - revision: 42701fdb27298d20b4040cea5cde375b72c27cfc + revision: ef5cfd369f4a0ab3601db9a23c1da8c406cc1a72 remote: zephyrproject # Import some projects listed in zephyr/west.yml@revision @@ -59,7 +59,7 @@ manifest: - mipi-sys-t - lz4 - tinycrypt - - cmsis + - cmsis_6 self: # Changes to submanifests/*.yml files _are_ effective; these have no diff --git a/xtos/include/CMakeLists.txt b/xtos/include/CMakeLists.txt deleted file mode 100644 index fd819740233b..000000000000 --- a/xtos/include/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -target_include_directories(sof_public_headers INTERFACE include) diff --git a/xtos/include/rtos/alloc.h b/xtos/include/rtos/alloc.h deleted file mode 100644 index d64ea319f48e..000000000000 --- a/xtos/include/rtos/alloc.h +++ /dev/null @@ -1,172 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - * Keyon Jie <yang.jie@linux.intel.com> - */ - -/** - * \file xtos/include/rtos/alloc.h - * \brief Memory Allocation API definition - * \author Liam Girdwood <liam.r.girdwood@linux.intel.com> - * \author Keyon Jie <yang.jie@linux.intel.com> - */ - -#ifndef __SOF_LIB_ALLOC_H__ -#define __SOF_LIB_ALLOC_H__ - -#include <rtos/bit.h> -#include <rtos/string.h> -#include <sof/trace/trace.h> -#include <user/trace.h> - -#include <stddef.h> -#include <stdint.h> - -/** \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/xtos/include/rtos/atomic.h b/xtos/include/rtos/atomic.h deleted file mode 100644 index 6d16b6b6c9e6..000000000000 --- a/xtos/include/rtos/atomic.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifndef __SOF_ATOMIC_H__ -#define __SOF_ATOMIC_H__ - -#include <arch/atomic.h> -#include <stdint.h> - -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/xtos/include/rtos/cache.h b/xtos/include/rtos/cache.h deleted file mode 100644 index 914e61b52984..000000000000 --- a/xtos/include/rtos/cache.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2019 Intel Corporation. All rights reserved. - * - * Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -/** - * \file xtos/include/rtos/cache.h - * \brief Cache header file - * \authors Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#ifndef __SOF_LIB_CACHE_H__ -#define __SOF_LIB_CACHE_H__ - -#include <arch/lib/cache.h> - -/* writeback and invalidate data */ -#define CACHE_WRITEBACK_INV 0 - -/* invalidate data */ -#define CACHE_INVALIDATE 1 - -#endif /* __SOF_LIB_CACHE_H__ */ diff --git a/xtos/include/rtos/clk.h b/xtos/include/rtos/clk.h deleted file mode 100644 index e9a36796bc42..000000000000 --- a/xtos/include/rtos/clk.h +++ /dev/null @@ -1,83 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - * Janusz Jankowski <janusz.jankowski@linux.intel.com> - */ - -#ifndef __SOF_LIB_CLK_H__ -#define __SOF_LIB_CLK_H__ - -#include <platform/lib/clk.h> -#include <rtos/sof.h> -#include <rtos/spinlock.h> -#include <stdbool.h> -#include <stdint.h> - -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/xtos/include/rtos/idc.h b/xtos/include/rtos/idc.h deleted file mode 100644 index bb8be2842e71..000000000000 --- a/xtos/include/rtos/idc.h +++ /dev/null @@ -1,182 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -/** - * \file include/rtos/idc.h - * \brief IDC header file - * \authors Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#ifndef __XTOS_RTOS_IDC_H__ -#define __XTOS_RTOS_IDC_H__ - -#include <arch/drivers/idc.h> -#include <platform/drivers/idc.h> -#include <rtos/task.h> -#include <sof/trace/trace.h> -#include <user/trace.h> -#include <stdint.h> -#include <rtos/cache.h> - -/** \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) - -/** \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_MSG_BIND IDC_TYPE(0xD) -#define IDC_MSG_UNBIND IDC_TYPE(0xE) -#define IDC_MSG_GET_ATTRIBUTE IDC_TYPE(0xF) - -#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 /* __XTOS_RTOS_IDC_H__ */ diff --git a/xtos/include/rtos/init.h b/xtos/include/rtos/init.h deleted file mode 100644 index ebe2ffafc062..000000000000 --- a/xtos/include/rtos/init.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright(c) 2023 Intel Corporation. All rights reserved. - */ - -#ifndef __XTOS_RTOS_INIT_H__ -#define __XTOS_RTOS_INIT_H__ - -#define SOF_MODULE_INIT(name, init) - -#endif /* __XTOS_RTOS_INIT_H__ */ diff --git a/xtos/include/rtos/kernel.h b/xtos/include/rtos/kernel.h deleted file mode 100644 index 23dd42960046..000000000000 --- a/xtos/include/rtos/kernel.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2022 Intel Corporation. All rights reserved. - * - * Author: Jyri Sarha <jyri.sarha@intel.com> - */ - -#ifndef __XTOS_RTOS_KERNEL_H__ -#define __XTOS_RTOS_KERNEL_H__ - -#include <rtos/wait.h> - -#include <stdint.h> - -#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) }) - -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 /* __XTOS_RTOS_KERNEL_H__ */ diff --git a/xtos/include/rtos/mutex.h b/xtos/include/rtos/mutex.h deleted file mode 100644 index 947cde944466..000000000000 --- a/xtos/include/rtos/mutex.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2022 Intel Corporation. All rights reserved. - * - */ - -/* - * Simple mutex implementation for SOF. - */ - -#ifndef __XTOS_RTOS_MUTEX_H -#define __XTOS_RTOS_MUTEX_H - -#include <rtos/kernel.h> -#include <rtos/spinlock.h> -#include <stdint.h> - -#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/xtos/include/rtos/panic.h b/xtos/include/rtos/panic.h deleted file mode 100644 index 921ea710d88f..000000000000 --- a/xtos/include/rtos/panic.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright 2023 NXP - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifndef __XTOS_RTOS_PANIC_H__ -#define __XTOS_RTOS_PANIC_H__ - -#include <ipc/trace.h> -#include <stdint.h> -#include <arch/debug/panic.h> - -#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, const 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 /* __XTOS_RTOS_PANIC_H__ */ diff --git a/xtos/include/rtos/sof.h b/xtos/include/rtos/sof.h deleted file mode 100644 index 4214122c9a56..000000000000 --- a/xtos/include/rtos/sof.h +++ /dev/null @@ -1,124 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifndef __XTOS_RTOS_SOF_H__ -#define __XTOS_RTOS_SOF_H__ - -#include <arch/sof.h> -#include <sof/common.h> -#include <sof/lib/memory.h> -#include <rtos/spinlock.h> - -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 /* __XTOS_RTOS_SOF_H__ */ diff --git a/xtos/include/rtos/spinlock.h b/xtos/include/rtos/spinlock.h deleted file mode 100644 index 2c5c7d94fdd8..000000000000 --- a/xtos/include/rtos/spinlock.h +++ /dev/null @@ -1,163 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - * Keyon Jie <yang.jie@linux.intel.com> - */ - -/* - * Simple spinlock implementation for SOF. - */ - -#ifndef __XTOS_RTOS_SPINLOCK_H__ -#define __XTOS_RTOS_SPINLOCK_H__ - -#include <arch/spinlock.h> -typedef uint32_t k_spinlock_key_t; -#include <sof/lib/memory.h> -#include <ipc/trace.h> - -#include <stdint.h> - -/* - * 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 <rtos/panic.h> -#include <sof/trace/trace.h> -#include <ipc/trace.h> -#include <user/trace.h> - -#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 /* __XTOS_RTOS_SPINLOCK_H__ */ diff --git a/xtos/include/rtos/string.h b/xtos/include/rtos/string.h deleted file mode 100644 index 6959475f8c96..000000000000 --- a/xtos/include/rtos/string.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifndef __XTOS_RTOS_STRING_H__ -#define __XTOS_RTOS_STRING_H__ - -#include <arch/string.h> -#include <stddef.h> - -/* 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 /* __XTOS_RTOS_STRING_H__ */ diff --git a/xtos/include/rtos/symbol.h b/xtos/include/rtos/symbol.h deleted file mode 100644 index e234945cb789..000000000000 --- a/xtos/include/rtos/symbol.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2023 Intel Corporation. All rights reserved. - */ - -#ifndef __RTOS_SYMBOL_H__ -#define __RTOS_SYMBOL_H__ - -#define EXPORT_SYMBOL(x) - -#endif diff --git a/xtos/include/rtos/task.h b/xtos/include/rtos/task.h deleted file mode 100644 index ebe096a40af1..000000000000 --- a/xtos/include/rtos/task.h +++ /dev/null @@ -1,123 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifndef __XTOS_RTOS_TASK_H__ -#define __XTOS_RTOS_TASK_H__ - -#include <arch/schedule/task.h> -#include <rtos/panic.h> -#include <sof/list.h> -#include <stdbool.h> -#include <stdint.h> -#include <rtos/kernel.h> -#include <sof/lib/perf_cnt.h> - -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 /* __XTOS_RTOS_TASK_H__ */ diff --git a/xtos/include/rtos/timer.h b/xtos/include/rtos/timer.h deleted file mode 100644 index b9756b66c87c..000000000000 --- a/xtos/include/rtos/timer.h +++ /dev/null @@ -1,132 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Janusz Jankowski <janusz.jankowski@linux.intel.com> - */ - -#ifndef __SOF_DRIVERS_TIMER_H__ -#define __SOF_DRIVERS_TIMER_H__ - -#include <arch/drivers/timer.h> -#include <rtos/clk.h> -#include <sof/lib/cpu.h> -#include <rtos/sof.h> -#include <sof/platform.h> -#include <stdint.h> - -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/xtos/include/rtos/wait.h b/xtos/include/rtos/wait.h deleted file mode 100644 index 03bbcadd506d..000000000000 --- a/xtos/include/rtos/wait.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -/* - * Simple wait for event completion and signaling with timeouts. - */ - -#ifndef __XTOS_RTOS_WAIT_H__ -#define __XTOS_RTOS_WAIT_H__ - -#include <stddef.h> -#include <stdint.h> - -#if !CONFIG_LIBRARY -#include <arch/lib/wait.h> -#include <rtos/interrupt.h> -#include <rtos/timer.h> -#include <rtos/spinlock.h> -#include <sof/trace/trace.h> -#include <user/trace.h> - -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 /* __XTOS_RTOS_WAIT_H__ */ diff --git a/xtos/include/sof/compiler_info.h b/xtos/include/sof/compiler_info.h deleted file mode 100644 index 9716575b7188..000000000000 --- a/xtos/include/sof/compiler_info.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2019 Intel Corporation. All rights reserved. - * - * Author: Karol Trzcinski <karolx.trzcinski@linux.intel.com> - */ - -/** - * \file xtos/include/sof/compiler_info.h - * \brief Compiler version and name descriptor - * \author Karol Trzcinski <karolx.trzcinski@linux.intel.com> - */ - -#ifndef __SOF_COMPILER_INFO_H__ -#define __SOF_COMPILER_INFO_H__ - -#include <arch/compiler_info.h> - -#endif /* __SOF_COMPILER_INFO_H__ */ diff --git a/xtos/include/sof/init.h b/xtos/include/sof/init.h deleted file mode 100644 index ce8522cd34ad..000000000000 --- a/xtos/include/sof/init.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#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/xtos/include/sof/lib/cpu.h b/xtos/include/sof/lib/cpu.h deleted file mode 100644 index d53e15e7535a..000000000000 --- a/xtos/include/sof/lib/cpu.h +++ /dev/null @@ -1,93 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -/** - * \file xtos/include/sof/lib/cpu.h - * \brief CPU header file - * \authors Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#ifndef __SOF_LIB_CPU_H__ -#define __SOF_LIB_CPU_H__ -#ifndef __ZEPHYR__ - -#include <platform/lib/cpu.h> - -#if !defined(__ASSEMBLER__) && !defined(LINKER) - -#include <arch/lib/cpu.h> -#include <stdbool.h> - -/* 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/xtos/include/sof/lib/dai.h b/xtos/include/sof/lib/dai.h deleted file mode 100644 index d1fd463eef3f..000000000000 --- a/xtos/include/sof/lib/dai.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - * Keyon Jie <yang.jie@linux.intel.com> - */ - -/** - * \file xtos/include/sof/lib/dai.h - * \brief DAI Drivers definition - * \author Liam Girdwood <liam.r.girdwood@linux.intel.com> - * \author Keyon Jie <yang.jie@linux.intel.com> - */ - -#ifdef __ZEPHYR__ -#error "Please use zephyr/include/sof/lib/dai.h instead" -#endif - -#ifndef __SOF_LIB_DAI_H__ -#define __SOF_LIB_DAI_H__ - -#include <sof/lib/dai-legacy.h> - -#endif /* __SOF_LIB_DAI_H__ */ diff --git a/xtos/include/sof/lib/dma.h b/xtos/include/sof/lib/dma.h deleted file mode 100644 index 7cfd6cecdc2b..000000000000 --- a/xtos/include/sof/lib/dma.h +++ /dev/null @@ -1,597 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - * Keyon Jie <yang.jie@linux.intel.com> - */ - -/** - * \file xtos/include/sof/lib/dma.h - * \brief DMA Drivers definition - * \author Liam Girdwood <liam.r.girdwood@linux.intel.com> - * \author Keyon Jie <yang.jie@linux.intel.com> - */ - -#ifndef __SOF_LIB_DMA_H__ -#define __SOF_LIB_DMA_H__ - -#include <platform/lib/dma.h> -#include <rtos/atomic.h> -#include <rtos/bit.h> -#include <rtos/alloc.h> -#include <sof/lib/io.h> -#include <sof/lib/memory.h> -#include <rtos/sof.h> -#include <rtos/spinlock.h> -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -#ifdef __ZEPHYR__ -#error "Please use zephyr/include/sof/lib/dma.h instead" -#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 */ -#define SOF_DMA_DIR_MEM_TO_MEM DMA_DIR_MEM_TO_MEM -#define SOF_DMA_DIR_HMEM_TO_LMEM DMA_DIR_HMEM_TO_LMEM -#define SOF_DMA_DIR_LMEM_TO_HMEM DMA_DIR_LMEM_TO_HMEM -#define SOF_DMA_DIR_MEM_TO_DEV DMA_DIR_MEM_TO_DEV -#define SOF_DMA_DIR_DEV_TO_MEM DMA_DIR_DEV_TO_MEM -#define SOF_DMA_DIR_DEV_TO_DEV DMA_DIR_DEV_TO_DEV - -/* 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 */ -#define DMA_CAP_HS BIT(8) /**< HS DMA */ -#define DMA_CAP_SW BIT(9) /**< SW 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 */ -#define DMA_DEV_HS BIT(13) /**< connectable to ACP HS I2S */ -#define DMA_DEV_MICFIL BIT(14) /**< connectable to MICFIL fifo */ -#define DMA_DEV_SW BIT(15) /**< connectable to ACP SW */ -#define SOF_DMA_DEV_HOST DMA_DEV_HOST -#define SOF_DMA_DEV_SAI DMA_DEV_SAI -#define SOF_DMA_DEV_ESAI DMA_DEV_ESAI -#define SOF_DMA_DEV_MICFIL DMA_DEV_MICFIL -#define SOF_DMA_DEV_AFE_MEMIF DMA_DEV_AFE_MEMIF - -/* DMA access privilege flag */ -#define DMA_ACCESS_EXCLUSIVE 1 -#define DMA_ACCESS_SHARED 0 -#define SOF_DMA_ACCESS_EXCLUSIVE DMA_ACCESS_EXCLUSIVE -#define SOF_DMA_ACCESS_SHARED DMA_ACCESS_SHARED - -/* 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, -}; - -#define SOF_DMA_CB_STATUS_RELOAD DMA_CB_STATUS_RELOAD -#define SOF_DMA_CB_STATUS_END 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 -#define SOF_DMA_CHAN_INVALID DMA_CHAN_INVALID -#define SOF_DMA_CORE_INVALID DMA_CORE_INVALID - -/* 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 - -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; -}; - -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 */ - 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 *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t source_samples, uint32_t chmap); - -/** - * \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; -} - -/* copies data from DMA buffer using provided processing function */ -int dma_buffer_copy_from(struct comp_buffer *source, - struct comp_buffer *sink, - dma_process_func process, uint32_t source_bytes, uint32_t chmap); - -/* - * Used when copying stream audio 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 stream_copy_from_no_consume(struct comp_buffer *source, - struct comp_buffer *sink, - dma_process_func process, - uint32_t source_bytes, uint32_t chmap); - -/* copies data to DMA buffer using provided processing function */ -int dma_buffer_copy_to(struct comp_buffer *source, - struct comp_buffer *sink, - dma_process_func process, uint32_t sink_bytes, uint32_t chmap); - -/* 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/xtos/include/sof/lib/io.h b/xtos/include/sof/lib/io.h deleted file mode 100644 index 0ab94b01e6dc..000000000000 --- a/xtos/include/sof/lib/io.h +++ /dev/null @@ -1,88 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - */ - -#ifndef __XTOS_SOF_LIB_IO_H__ -#define __XTOS_SOF_LIB_IO_H__ - - -#include <stdint.h> - -#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_SOF_LIB_IO_H__ */ diff --git a/xtos/include/sof/lib/memory.h b/xtos/include/sof/lib/memory.h deleted file mode 100644 index 9a784ec7f19d..000000000000 --- a/xtos/include/sof/lib/memory.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2019 Intel Corporation. All rights reserved. - * - * Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#ifndef __SOF_LIB_MEMORY_H__ -#define __SOF_LIB_MEMORY_H__ - -#include <platform/lib/memory.h> - -#ifndef __cold -#define __cold -#endif - -#ifndef __cold_rodata -#define __cold_rodata -#endif - -#endif /* __SOF_LIB_MEMORY_H__ */ diff --git a/xtos/include/sof/lib/mm_heap.h b/xtos/include/sof/lib/mm_heap.h deleted file mode 100644 index 931a66ed0cea..000000000000 --- a/xtos/include/sof/lib/mm_heap.h +++ /dev/null @@ -1,117 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> - * Keyon Jie <yang.jie@linux.intel.com> - */ - -#ifndef __SOF_LIB_MM_HEAP_H__ -#define __SOF_LIB_MM_HEAP_H__ - -#ifdef __ZEPHYR__ -#error "Please use zephyr/include/sof/lib/mm_heap.h instead" -#endif - -#include <sof/common.h> -#include <rtos/alloc.h> -#include <rtos/cache.h> -#include <sof/lib/memory.h> -#include <rtos/sof.h> -#include <rtos/spinlock.h> - -#include <stddef.h> -#include <stdint.h> - -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/xtos/include/sof/lib/pm_runtime.h b/xtos/include/sof/lib/pm_runtime.h deleted file mode 100644 index c0a24116e629..000000000000 --- a/xtos/include/sof/lib/pm_runtime.h +++ /dev/null @@ -1,176 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Tomasz Lauda <tomasz.lauda@linux.intel.com> - * Janusz Jankowski <janusz.jankowski@linux.intel.com> - */ - -/** - * \file xtos/include/sof/lib/pm_runtime.h - * \brief Runtime power management header file - * \author Tomasz Lauda <tomasz.lauda@linux.intel.com> - */ - -#ifndef __SOF_LIB_PM_RUNTIME_H__ -#define __SOF_LIB_PM_RUNTIME_H__ - -#include <platform/lib/pm_runtime.h> -#include <rtos/sof.h> -#include <rtos/spinlock.h> -#include <sof/trace/trace.h> -#include <user/trace.h> -#include <stdint.h> - -/** \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/xtos/include/sof/trace/preproc-private-dec.h b/xtos/include/sof/trace/preproc-private-dec.h deleted file mode 100644 index f36df9d38449..000000000000 --- a/xtos/include/sof/trace/preproc-private-dec.h +++ /dev/null @@ -1,98 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Michal Jerzy Wierzbicki <michalx.wierzbicki@intel.com> - */ - -/* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY */ - -#ifdef __SOF_TRACE_PREPROC_PRIVATE_H__ -/* Macros defined in this file are only helpers for the macros that are - * defined in header file containing "namespace" - * __SOF_TRACE_PREPROC_PRIVATE_H__ . - * This combination of #ifdef and #ifndef should sufficently narrow - * the "include-ability" of this dependent header file. - * If you wish to use macros from this file directly, be *V E R Y* careful! - * HIC SUNT DRACONES - */ -#ifndef __SOF_TRACE_PREPROC_PRIVATE_DEC_H__ -#define __SOF_TRACE_PREPROC_PRIVATE_DEC_H__ - -/* The only sane way I found to decrement values in cpreproc */ -/* for instance META_DEC(3) will be tokenized to DEC_3 - * and then expanded again to 2 - */ -#define _META_DEC_0 0 // notice how we deal with underflow -#define _META_DEC_1 0 -#define _META_DEC_2 1 -#define _META_DEC_3 2 -#define _META_DEC_4 3 -#define _META_DEC_5 4 -#define _META_DEC_6 5 -#define _META_DEC_7 6 -#define _META_DEC_8 7 -#define _META_DEC_9 8 -#define _META_DEC_10 9 -#define _META_DEC_11 10 -#define _META_DEC_12 11 -#define _META_DEC_13 12 -#define _META_DEC_14 13 -#define _META_DEC_15 14 -#define _META_DEC_16 15 -#define _META_DEC_17 16 -#define _META_DEC_18 17 -#define _META_DEC_19 18 -#define _META_DEC_20 19 -#define _META_DEC_21 20 -#define _META_DEC_22 21 -#define _META_DEC_23 22 -#define _META_DEC_24 23 -#define _META_DEC_25 24 -#define _META_DEC_26 25 -#define _META_DEC_27 26 -#define _META_DEC_28 27 -#define _META_DEC_29 28 -#define _META_DEC_30 29 -#define _META_DEC_31 30 -#define _META_DEC_32 31 -#define _META_DEC_33 32 -#define _META_DEC_34 33 -#define _META_DEC_35 34 -#define _META_DEC_36 35 -#define _META_DEC_37 36 -#define _META_DEC_38 37 -#define _META_DEC_39 38 -#define _META_DEC_40 39 -#define _META_DEC_41 40 -#define _META_DEC_42 41 -#define _META_DEC_43 42 -#define _META_DEC_44 43 -#define _META_DEC_45 44 -#define _META_DEC_46 45 -#define _META_DEC_47 46 -#define _META_DEC_48 47 -#define _META_DEC_49 48 -#define _META_DEC_50 49 -#define _META_DEC_51 50 -#define _META_DEC_52 51 -#define _META_DEC_53 52 -#define _META_DEC_54 53 -#define _META_DEC_55 54 -#define _META_DEC_56 55 -#define _META_DEC_57 56 -#define _META_DEC_58 57 -#define _META_DEC_59 58 -#define _META_DEC_60 59 -#define _META_DEC_61 60 -#define _META_DEC_62 61 -#define _META_DEC_63 62 -#define _META_DEC_64 63 - -#endif /* __SOF_TRACE_PREPROC_PRIVATE_DEC_H__ */ -#else - #error \ - Illegal use of header file: \ - can only be included from context of \ - __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ -#endif /* __SOF_TRACE_PREPROC_PRIVATE_H__ */ diff --git a/xtos/include/sof/trace/preproc-private-inc.h b/xtos/include/sof/trace/preproc-private-inc.h deleted file mode 100644 index d19205c584cb..000000000000 --- a/xtos/include/sof/trace/preproc-private-inc.h +++ /dev/null @@ -1,98 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Michal Jerzy Wierzbicki <michalx.wierzbicki@intel.com> - */ - -/* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY */ - -#ifdef __SOF_TRACE_PREPROC_PRIVATE_H__ -/* Macros defined in this file are only helpers for the macros that are - * defined in header file containing "namespace" - * __SOF_TRACE_PREPROC_PRIVATE_H__ . - * This combination of #ifdef and #ifndef should sufficently narrow - * the "include-ability" of this dependent header file. - * If you wish to use macros from this file directly, be *V E R Y* careful! - * HIC SUNT DRACONES - */ -#ifndef __SOF_TRACE_PREPROC_PRIVATE_INC_H__ -#define __SOF_TRACE_PREPROC_PRIVATE_INC_H__ - -/* The only sane way I found to increment values in cpreproc */ -/* for instance META_INC(3) will be tokenized to INC_3 - * and then expanded again to 4 - */ -#define _META_INC_0 1 -#define _META_INC_1 2 -#define _META_INC_2 3 -#define _META_INC_3 4 -#define _META_INC_4 5 -#define _META_INC_5 6 -#define _META_INC_6 7 -#define _META_INC_7 8 -#define _META_INC_8 9 -#define _META_INC_9 10 -#define _META_INC_10 11 -#define _META_INC_11 12 -#define _META_INC_12 13 -#define _META_INC_13 14 -#define _META_INC_14 15 -#define _META_INC_15 16 -#define _META_INC_16 17 -#define _META_INC_17 18 -#define _META_INC_18 19 -#define _META_INC_19 20 -#define _META_INC_20 21 -#define _META_INC_21 22 -#define _META_INC_22 23 -#define _META_INC_23 24 -#define _META_INC_24 25 -#define _META_INC_25 26 -#define _META_INC_26 27 -#define _META_INC_27 28 -#define _META_INC_28 29 -#define _META_INC_29 30 -#define _META_INC_30 31 -#define _META_INC_31 32 -#define _META_INC_32 33 -#define _META_INC_33 34 -#define _META_INC_34 35 -#define _META_INC_35 36 -#define _META_INC_36 37 -#define _META_INC_37 38 -#define _META_INC_38 39 -#define _META_INC_39 40 -#define _META_INC_40 41 -#define _META_INC_41 42 -#define _META_INC_42 43 -#define _META_INC_43 44 -#define _META_INC_44 45 -#define _META_INC_45 46 -#define _META_INC_46 47 -#define _META_INC_47 48 -#define _META_INC_48 49 -#define _META_INC_49 50 -#define _META_INC_50 51 -#define _META_INC_51 52 -#define _META_INC_52 53 -#define _META_INC_53 54 -#define _META_INC_54 55 -#define _META_INC_55 56 -#define _META_INC_56 57 -#define _META_INC_57 58 -#define _META_INC_58 59 -#define _META_INC_59 60 -#define _META_INC_60 61 -#define _META_INC_61 62 -#define _META_INC_62 63 -#define _META_INC_63 64 -#define _META_INC_64 64 // notice how we deal with overflow - -#endif /* __SOF_TRACE_PREPROC_PRIVATE_INC_H__ */ -#else - #error \ - Illegal use of header file: \ - can only be included from context of \ - __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ -#endif /* __SOF_TRACE_PREPROC_PRIVATE_H__ */ diff --git a/xtos/include/sof/trace/preproc-private.h b/xtos/include/sof/trace/preproc-private.h deleted file mode 100644 index 37202b5a2044..000000000000 --- a/xtos/include/sof/trace/preproc-private.h +++ /dev/null @@ -1,199 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Michal Jerzy Wierzbicki <michalx.wierzbicki@intel.com> - */ - -/* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY */ - -#ifdef __SOF_TRACE_PREPROC_H__ -/* Macros defined in this file are only helpers for the macros that are - * defined in header file containing "namespace" - * __SOF_TRACE_PREPROC_H__ . - * This combination of #ifdef and #ifndef should sufficently narrow - * the "include-ability" of this dependent header file. - * If you wish to use macros from this file directly, be *V E R Y* careful! - * HIC SUNT DRACONES - */ -#ifndef __SOF_TRACE_PREPROC_PRIVATE_H__ -#define __SOF_TRACE_PREPROC_PRIVATE_H__ - -/* Include - * #define _META_DEC_0 0 - * #define _META_DEC_1 1 - * #define _META_DEC_2 1 - * #define _META_DEC_3 2 - * ... - * #define _META_DEC_N N-1 - */ -#include <sof/trace/preproc-private-dec.h> -/* Include - * #define _META_INC_0 1 - * #define _META_INC_1 2 - * ... - * #define _META_INC_N-1 N - * #define _META_INC_N N - */ -#include <sof/trace/preproc-private-inc.h> - -/* count number of var args - during preprocesing - * works for predefined number of args - * META_COUNT_VARAGS_BEFORE_COMPILE(A,B,C,D) evaluates to 4 - */ -#define _META_PP_NARG_BEFORE_COMPILE_(...) \ - _META_PP_ARG_N(__VA_ARGS__) - -#define _META_PP_ARG_N(\ - _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ - _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ - _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ - _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ - _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ - _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ - _61, _62, _63, N, ...) N - -#define _META_PP_RSEQ_N() \ - 63, 62, 61, 60, \ - 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ - 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ - 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ - 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ - 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ - 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 - -/* treat x as string while forcing x expansion beforehand */ -#define _META_QUOTE(x) #x - -/* concat x and y while forcing x and y expansion beforehand */ -#define _META_CONCAT_BASE(x, y) x##y - -/* discard first x-1 args in vararg and return the xth arg */ -#define _META_GET_ARG_1(arg1, ...) arg1 -#define _META_GET_ARG_2(arg1, arg2, ...) arg2 -/* TODO: GET_ARG version for arbitrary x>2 should be possible using - * META_RECURSE(META_REPEAT - */ - -/* _META_IS_PROBE(...) evaluates to 0 when __VA_ARGS__ is single token - * _META_IS_PROBE(PROBE()) evaulates to 1, because it is equivalent to - * _META_GET_ARG_2(~, 1, 0) - * ~ is no special value, it is just a meaningless placeholder, - * it could be something else if that thing would also have no meaning - * but be a valid C - */ -#define _META_IS_PROBE(...) _META_GET_ARG_2(__VA_ARGS__, 0) -#define _META_PROBE() ~, 1 - -/* _META_NOT_0 evaluates to '~, 1' - * _META_NOT_1 evaluates to '_META_NOT_1' (because it is not a macro) - * _META_IS_PROBE(_META_NOT_0) evaluates to 1, because it is equivalent to - * _META_GET_ARG_2(~, 1, 0) - * _META_IS_PROBE(_NOT_1) evaluates to 0, because it is equivalent to - * _META_GET_ARG_2(_NOT_1, 0) - * - * notice, that any x!=0 would also result in 0 - * e.x. META_NOT(123) evaluates to 0 - */ -#define _META_NOT_0 _META_PROBE() - -/* indirection forces condition to be "cast" to 0 1 - * then for 0 discard first (), and for 1 discard second () - * so META_IF_ELSE(0)(a)(b) expands to b, - * and META_IF_ELSE(1)(a)(b) expands to a - */ -#define _META_IF_ELSE(condition) META_CONCAT(_META_IF_, condition) - -#define _META_IF_1(...) __VA_ARGS__ _META_IF_1_ELSE -#define _META_IF_0(...) _META_IF_0_ELSE - -#define _META_IF_1_ELSE(...) -#define _META_IF_0_ELSE(...) __VA_ARGS__ - -#define _META_IIF(condition) META_CONCAT(_META_IIF_, condition) -#define _META_IIF_0(x, ...) __VA_ARGS__ -#define _META_IIF_1(x, ...) x - -/* primitive recursion */ -#define _META_REQRS_8(...) _META_REQRS_4( _META_REQRS_4 (__VA_ARGS__)) -#define _META_REQRS_4(...) _META_REQRS_2( _META_REQRS_2 (__VA_ARGS__)) -#define _META_REQRS_2(...) _META_REQRS_1( _META_REQRS_1 (__VA_ARGS__)) -#define _META_REQRS_1(...) __VA_ARGS__ - -/* Delay macro m expansion depth times - * IT IS CRUCIAL FOR NO #define _META_EMPTY macro to exist!!! - * _META_DEFER_N(depth) will work for any depth valid in META_REPEAT - * (which is confined only by META_DEC). - * _META_DEFER_N will NOT work inside META_REPEAT, because - * _META_DEFER_N uses META_REPEAT as seen below. - * In order for META_REPEAT to work (which also requires DEFER functionality) - * a duplicate, implicit _META_DEFER_2(m) has to be defined. - * It is because how the c preprocesor works. - */ -#define _META_EMPTY() - -/* Special, implicit defer implementation for META_REPEAT to work */ -#define _META_DEFER_2(m) m _META_EMPTY _META_EMPTY () () - -/* map every group of arg_count arguments onto function m - * i.e. arg_count=2;m=ADD;args=1,2,3,4,5,6,7... - * results in ADD(1,2) ADD(3,4) ADD(5,6) and so on - * MAP##N must exist for arg_count == N to work - */ -#define _META_MAP() META_MAP - -/* implements MAP(1, m, ...) */ -#define _META_MAP_1(m, arg1, ...)\ - m(arg1)\ - _META_DEFER_2(_META_MAP_BODY_TMP)()(1, m, __VA_ARGS__) - -/* implements MAP(2, m, ...) */ -#define _META_MAP_2(m, arg1, arg2, ...)\ - m(arg1, arg2)\ - _META_DEFER_2(_META_MAP_BODY_TMP)()(2, m, __VA_ARGS__) - -/* implements MAP(3, m, ...) */ -#define _META_MAP_3(m, arg1, arg2, arg3, ...)\ - m(arg1, arg2, arg3)\ - _META_DEFER_2(_META_MAP_BODY_TMP)()(3, m, __VA_ARGS__) - -/* used by macro MAP, don't use on its own */ -#define _META_MAP_BODY(arg_count, m, ...)\ - META_IF_ELSE(META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__))(\ - META_CONCAT(_META_MAP_, arg_count)(m, __VA_ARGS__) \ - )() -#define _META_MAP_BODY_TMP() _META_MAP_BODY - -/* map aggregator and every group of arg_count arguments onto function m - * i.e. aggr=x;arg_count=1;m=ADD;args=1,2,3,4,5,6,7... - * results in x = ... ADD(7,ADD(6,ADD(5,ADD(4,ADD(3,ADD(2,ADD(1,x))))))) ... - * MAP##N must exist for arg_count == N to work - */ -#define _META_MAP_AGGREGATE() META_MAP_AGGREGATE - -/* implements MAP_AGGREGATE(1, m, ...) */ -#define _META_MAP_AGGREGATE_1(m, aggr, arg1, ...)\ - _META_MAP_AGGREGATE_BODY(1, m, m(aggr, arg1), __VA_ARGS__) - -/* implements MAP_AGGREGATE(2, m, ...) */ -#define _META_MAP_AGGREGATE_2(m, aggr, arg1, arg2, ...)\ - _META_MAP_AGGREGATE_BODY(2, m, m(aggr, arg1, arg2), __VA_ARGS__) - -/* used by macro MAP_AGGREGATE, don't use on its own */ -#define _META_MAP_AGGREGATE_BODY(arg_count, m, aggr, ...)\ - META_IF_ELSE(META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__))(\ - _META_DEFER_2(_META_MAP_AGGREGATE)()\ - (arg_count, m, aggr, __VA_ARGS__)\ - )(aggr) - -/* UNUSED private macros */ -#define _META_VOID(x) (void)(x) -#define _META_VOID2(x, y) x; _META_VOID(y) - -#endif /* __SOF_TRACE_PREPROC_PRIVATE_H__ */ -#else - #error \ - Illegal use of header file: \ - can only be included from context of \ - __INCLUDE_MACRO_METAPROGRAMMING__ -#endif /* __SOF_TRACE_PREPROC_H__ */ diff --git a/xtos/include/sof/trace/preproc.h b/xtos/include/sof/trace/preproc.h deleted file mode 100644 index 88e4986ea240..000000000000 --- a/xtos/include/sof/trace/preproc.h +++ /dev/null @@ -1,88 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * - * Author: Michal Jerzy Wierzbicki <michalx.wierzbicki@intel.com> - */ - -#ifndef __SOF_TRACE_PREPROC_H__ -#define __SOF_TRACE_PREPROC_H__ - -/* Macros in this file are to be invoked directly from code. - * In order to work, they require a number of other macros that are - * defined in the header file specified below. - * Macros from the file specified below are not to meant to be used - * directly / independently. - * For more detailed commentary of innards of macros in this file, - * see file specified below. - */ -#include <sof/trace/preproc-private.h> -#include <stdint.h> - -/* count number of var args - during preprocesing - * works for predefined number of args - * META_COUNT_VARAGS_BEFORE_COMPILE(A,B,C,D) evaluates to 4 - */ -#define META_COUNT_VARAGS_BEFORE_COMPILE(...)\ - META_DEC(\ - _META_PP_NARG_BEFORE_COMPILE_(\ - _, ##__VA_ARGS__, _META_PP_RSEQ_N()\ - )\ - ) - -/* treat x as string while forcing x expansion beforehand */ -#define META_QUOTE(x) _META_QUOTE(x) - -/* concat x and y while forcing x and y expansion beforehand */ -#define META_CONCAT(x, y) _META_CONCAT_BASE(x, y) - -/* Only META_NOT(0) evaulates to 1 - * notice, that any x!=0 would also result in 0 - * e.x. META_NOT(123) evaluates to 0 - */ -#define META_NOT(x) _META_IS_PROBE(META_CONCAT(_META_NOT_, x)) -/* hacky way to convert tokens into 0 1*/ -#define META_BOOL(x) META_NOT(META_NOT(x)) - -/* META_IF_ELSE(X)(a)(b) expands to - * b for X == 0 - * a for X != 0 - */ -#define META_IF_ELSE(condition) _META_IF_ELSE(META_BOOL(condition)) - -/* same story with indirection as META_IF_ELSE */ -#define META_IF(condition) _META_IIF(META_BOOL(condition)) - -/* primitive recursion - * default depth is 8 - */ -#define META_RECURSE(...) _META_REQRS_8(__VA_ARGS__) - -/* The only sane way I found to increment values in cpreproc */ -#define META_INC(x) META_CONCAT(_META_INC_, x) - -/* The only sane way I found to decrement values in cpreproc */ -#define META_DEC(x) META_CONCAT(_META_DEC_, x) - -/* map every group of arg_count arguments onto function m - * i.e. arg_count=2;m=ADD;args=1,2,3,4,5,6,7... - * results in ADD(1,2) ADD(3,4) ADD(5,6) and so on - * MAP##N must exist for arg_count == N to work - */ -#define META_MAP(arg_count, m, ...) META_RECURSE(\ - _META_MAP_BODY(arg_count, m, __VA_ARGS__)) - -/* map aggregator and every group of arg_count arguments onto function m - * i.e. aggr=x;arg_count=1;m=ADD;args=1,2,3,4,5,6,7... - * results in x = ... ADD(7,ADD(6,ADD(5,ADD(4,ADD(3,ADD(2,ADD(1,x))))))) ... - * MAP##N must exist for arg_count == N to work - */ -#define META_MAP_AGGREGATE(arg_count, m, aggr, ...)\ - META_CONCAT(_META_MAP_AGGREGATE_, arg_count)(m, aggr, __VA_ARGS__) - -/* counteract compiler warning about unused variables */ -#define SOF_TRACE_UNUSED(arg1, ...) do { META_RECURSE( \ - META_MAP_AGGREGATE(1, _META_VOID2, _META_VOID(arg1), __VA_ARGS__)); \ - } while (0) - -#endif /* __SOF_TRACE_PREPROC_H__ */ diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 68eb85834942..5b02dddcbb14 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -2,14 +2,9 @@ # compile every Zephyr module that can be found. See # sof/zephyr/module.yml and # https://docs.zephyrproject.org/latest/develop/modules.html -if(CONFIG_SOF) +if(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) -if(CONFIG_LIBRARY) - set(PLATFORM "library") - set(ARCH host) - set(PLATFORM_HEADERS "posix") - zephyr_include_directories(../src/platform/library/include) -elseif(CONFIG_ZEPHYR_POSIX) +if(CONFIG_ZEPHYR_POSIX) set(ARCH host) set(PLATFORM "posix") set(PLATFORM_HEADERS "posix") @@ -45,30 +40,15 @@ Building LLEXT targets must be serialized. This property contains the \ previously added LLEXT module for the establishment of a dependency chain." ) -# Used by LLEXT modules to create a file with module UUIDs -function(sof_llext_write_uuids module) - file(STRINGS ${CMAKE_CURRENT_LIST_DIR}/../${module}.toml uuids REGEX "^[ \t]*uuid *=") - - set(UUIDS_LIST_FILE ${ZEPHYR_BINARY_DIR}/${module}_llext/llext.uuid) - file(REMOVE ${UUIDS_LIST_FILE}) - foreach(line IN LISTS uuids) - # extract UUID value - drop the 'uuid = ' part of the assignment line - string(REGEX REPLACE "^[ \t]*uuid *= \"([0-9A-F\-]*)\"" "\\1" uuid ${line}) - file(APPEND ${UUIDS_LIST_FILE} "${uuid}\n") - endforeach() -endfunction() - # Build an LLEXT module. Provice a module name, a list of sources and an address # of the .text section as arguments. function(sof_llext_build module) - set(multi_args SOURCES) + set(multi_args SOURCES INCLUDES CFLAGS LIBS LIBS_PATH) set(single_args LIB) cmake_parse_arguments(PARSE_ARGV 1 SOF_LLEXT "${options}" "${single_args}" "${multi_args}") cmake_path(SET SOF_BASE NORMALIZE ${APPLICATION_SOURCE_DIR}/..) - sof_llext_write_uuids(${module}) - add_llext_target(${module} OUTPUT ${PROJECT_BINARY_DIR}/${module}_llext/${module}.llext SOURCES ${SOF_LLEXT_SOURCES} @@ -78,12 +58,36 @@ function(sof_llext_build module) file(WRITE ${PROJECT_BINARY_DIR}/${module}_llext/lib_name.txt ${SOF_LLEXT_LIB}) endif() + if("${ARCH}" STREQUAL "xtensa") + # This makes sure literals are placed in memory before they are used by + # the L32R instruction. Usually this is guaranteed by the linker script. + # However, since a linker script is not used for LLEXT modules builds, + # correct literal placement is ensured with a compilation option here. + set(SOF_LLEXT_CFLAGS ${SOF_LLEXT_CFLAGS} -mtext-section-literals) + endif() + target_include_directories(${module}_llext_lib PRIVATE "${SOF_BASE}/xtos/include" "${SOF_BASE}/src/include" "${SOF_BASE}/tools/rimage/src/include" ) + target_include_directories(${module}_llext_lib PRIVATE + "${SOF_LLEXT_INCLUDES}" + ) + + target_compile_options(${module}_llext_lib PRIVATE + "${SOF_LLEXT_CFLAGS}" + ) + + target_link_libraries(${module}_llext_lib PRIVATE + "${SOF_LLEXT_LIBS}" + ) + + foreach(lib ${SOF_LLEXT_LIBS}) + set(EXTRA_LIBS ${EXTRA_LIBS} -l${lib}) + endforeach() + sof_append_relative_path_definitions(${module}_llext_lib) add_llext_command(TARGET ${module} @@ -91,6 +95,7 @@ function(sof_llext_build module) COMMAND ${CMAKE_C_COMPILER} -E ${CMAKE_CURRENT_LIST_DIR}/llext.toml.h -P -DREM= -I${SOF_BASE} -I${SOF_BASE}src -imacros ../include/generated/zephyr/autoconf.h + -imacros ../include/generated/uuid-registry.h -o rimage_config.toml ) @@ -100,6 +105,11 @@ function(sof_llext_build module) set(EXTRA_LINKER_PARAMS -nostdlib -nodefaultlibs -shared) endif() + foreach(path ${SOF_LLEXT_LIBS_PATH}) + llext_link_options(${module} -L${path}) + set(EXTRA_LINKER_PARAMS ${EXTRA_LINKER_PARAMS} -L${path}) + endforeach() + get_target_property(proc_in_file ${module} lib_output) get_target_property(proc_out_file ${module} pkg_input) get_target_property(proc_pkg_file ${module} pkg_output) @@ -111,13 +121,19 @@ function(sof_llext_build module) endif() set_property(GLOBAL PROPERTY SOF_LLEXT_LAST_TARGET ${module}) + add_llext_command(TARGET ${module} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -DMODULE=${module} -DZEPHYR_BINARY_DIR=${ZEPHYR_BINARY_DIR} + -P ${SOF_BASE}scripts/cmake/llext_write_uuids.cmake + ) + add_llext_command(TARGET ${module} POST_BUILD COMMAND ${PYTHON_EXECUTABLE} ${SOF_BASE}scripts/llext_link_helper.py -s ${size_file} --text-addr=${CONFIG_LIBRARY_BASE_ADDRESS} - -f ${proc_in_file} ${CMAKE_C_COMPILER} -- - -o ${proc_out_file} ${EXTRA_LINKER_PARAMS} - $<TARGET_OBJECTS:${module}_llext_lib> + -c $<TARGET_PROPERTY:bintools,elfconvert_command> + -f ${proc_in_file} -o ${proc_out_file} ${CMAKE_C_COMPILER} -- + ${EXTRA_LINKER_PARAMS} $<TARGET_OBJECTS:${module}_llext_lib> ${EXTRA_LIBS} ) add_llext_command(TARGET ${module} @@ -142,13 +158,7 @@ cmake_path(SET sof_top_dir NORMALIZE "${CMAKE_CURRENT_SOURCE_DIR}/..") set(SOF_SRC_PATH "${sof_top_dir}/src") set(SOF_PLATFORM_PATH "${SOF_SRC_PATH}/platform") -set(SOF_AUDIO_PATH "${SOF_SRC_PATH}/audio") -set(SOF_AUDIO_MODULES_PATH "${SOF_SRC_PATH}/audio/module_adapter/module") -set(SOF_SAMPLES_PATH "${SOF_SRC_PATH}/samples") -set(SOF_LIB_PATH "${SOF_SRC_PATH}/lib") set(SOF_DRIVERS_PATH "${SOF_SRC_PATH}/drivers") -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) @@ -171,9 +181,11 @@ zephyr_library_named(modules_sof) # Zephyr C++ code requires 14 or newer standard set_property(TARGET modules_sof PROPERTY CXX_STANDARD 17) -zephyr_include_directories( - include -) +zephyr_include_directories(include) +zephyr_include_directories(${ZEPHYR_BASE}/kernel/include) +zephyr_include_directories(${ZEPHYR_BASE}/arch/${ARCH}/include) +zephyr_include_directories(${SOF_SRC_PATH}/include/sof/audio/module_adapter/iadk/) +zephyr_include_directories(${SOF_SRC_PATH}/include/sof/audio/module_adapter/library/) # SOC level sources # Files that are commented may not be needed. @@ -206,14 +218,31 @@ macro(add_local_sources_ifdef condition target) endif() zephyr_library_sources_ifdef(${condition} ${ARGN}) endmacro() +macro(sof_list_append_ifdef feature_toggle list) + if(${${feature_toggle}}) + list(APPEND ${list} ${ARGN}) + endif() +endmacro() + +# directories with auxiliary modules need to be listed first +# - llext dependencies need to added to linkage first +add_subdirectory(../src/math/ math_unused_install/) +# remaining directories (in alphabetical order) +add_subdirectory(../src/audio/ audio_unused_install/) +add_subdirectory(../src/debug/ debug_unused_install/) +add_subdirectory(../src/idc/ idc_unused_install/) add_subdirectory(../src/init/ init_unused_install/) add_subdirectory(../src/ipc/ ipc_unused_install/) -add_subdirectory(../src/debug/telemetry/ telemetry_unused_install/) -add_subdirectory(../src/debug/debug_stream/ debug_stream_unused_install/) +add_subdirectory(../src/lib/ lib_unused_install/) +add_subdirectory(../src/library_manager/ library_manager_unused_install/) +add_subdirectory(../src/logging/ logging_unused_install/) +add_subdirectory(../src/probe/ probes_unused_install/) +add_subdirectory(../src/samples/ samples_unused_install/) +add_subdirectory(../src/schedule/ schedule_unused_install/) +add_subdirectory(../src/trace/ trace_unused_install/) add_subdirectory(test/) - # Old way below: all .c files added by this giant CMake file. # Intel TGL and CAVS 2.5 platforms @@ -230,11 +259,6 @@ if (CONFIG_SOC_SERIES_INTEL_CAVS_V25) lib/dma.c ) - # SOF core infrastructure - runs on top of Zephyr - zephyr_library_sources( - ${SOF_SRC_PATH}/schedule/zephyr_ll.c - ) - set(PLATFORM "tigerlake") zephyr_include_directories(${SOF_PLATFORM_PATH}/intel/cavs/include) endif() @@ -249,29 +273,28 @@ if (CONFIG_SOC_SERIES_INTEL_ADSP_ACE) lib/dma.c ) - zephyr_library_sources_ifdef(CONFIG_SOC_INTEL_ACE15_MTPM - ${SOF_PLATFORM_PATH}/meteorlake/lib/clk.c - ) + zephyr_library_sources_ifdef(CONFIG_SOC_ACE15_MTPM + ${SOF_PLATFORM_PATH}/meteorlake/lib/clk.c + ) - zephyr_library_sources_ifdef(CONFIG_SOC_INTEL_ACE20_LNL - ${SOF_PLATFORM_PATH}/lunarlake/lib/clk.c - ) + zephyr_library_sources_ifdef(CONFIG_SOC_ACE20_LNL + ${SOF_PLATFORM_PATH}/lunarlake/lib/clk.c + ) - zephyr_library_sources_ifdef(CONFIG_SOC_INTEL_ACE30 - ${SOF_PLATFORM_PATH}/ace30/lib/clk.c - ) + zephyr_library_sources_ifdef(CONFIG_SOC_ACE30 + ${SOF_PLATFORM_PATH}/ace30/lib/clk.c + ) - # SOF core infrastructure - runs on top of Zephyr - zephyr_library_sources( - ${SOF_SRC_PATH}/schedule/zephyr_ll.c + zephyr_library_sources_ifdef(CONFIG_SOC_ACE40 + ${SOF_PLATFORM_PATH}/novalake/lib/clk.c ) - zephyr_library_sources_ifdef(CONFIG_ZEPHYR_DP_SCHEDULER - ${SOF_SRC_PATH}/schedule/zephyr_dp_schedule.c + zephyr_library_sources_ifdef(CONFIG_SOF_VREGIONS + lib/vpage.c + lib/vregion.c ) - # Sources for virtual heap management - zephyr_library_sources( + zephyr_library_sources_ifdef(CONFIG_VIRTUAL_HEAP lib/regions_mm.c ) @@ -283,12 +306,14 @@ if (CONFIG_SOC_SERIES_INTEL_ADSP_ACE) ${SOF_PLATFORM_PATH}/intel/ace/lib/watchdog.c ) - if (CONFIG_SOC_INTEL_ACE15_MTPM) + if (CONFIG_SOC_ACE15_MTPM) set(PLATFORM "meteorlake") - elseif(CONFIG_SOC_INTEL_ACE20_LNL) + elseif(CONFIG_SOC_ACE20_LNL) set(PLATFORM "lunarlake") - elseif(CONFIG_SOC_INTEL_ACE30) + elseif(CONFIG_SOC_ACE30) set(PLATFORM "ace30") + elseif(CONFIG_SOC_ACE40) + set(PLATFORM "novalake") endif() zephyr_include_directories(${SOF_PLATFORM_PATH}/intel/ace/include) @@ -312,8 +337,6 @@ if (CONFIG_SOC_MIMX8QM6_ADSP OR CONFIG_SOC_MIMX8QX6_ADSP) lib/dma.c ) - zephyr_library_sources(${SOF_SRC_PATH}/schedule/zephyr_ll.c) - set(PLATFORM "imx8") endif() @@ -333,11 +356,37 @@ if (CONFIG_SOC_MIMX8ML8_ADSP) lib/dma.c ) - zephyr_library_sources(${SOF_SRC_PATH}/schedule/zephyr_ll.c) - set(PLATFORM "imx8m") endif() +if (CONFIG_SOC_MIMX8ML8_M7) + zephyr_library_sources( + ${SOF_PLATFORM_PATH}/imx8m_cm7/platform.c + ${SOF_PLATFORM_PATH}/imx8m_cm7/lib/clk.c + lib/dma.c + ) + + zephyr_library_sources( + ${SOF_DRIVERS_PATH}/imx/ipc.c + ) + + # SOF-specific linker script additions + zephyr_linker_sources(DATA_SECTIONS ${sof_top_dir}/src/platform/imx8m_cm7/linker/data-sections.ld) + + set(PLATFORM "imx8m_cm7") + + add_custom_target(zephyr.ri ALL + DEPENDS ${CMAKE_BINARY_DIR}/zephyr/zephyr.ri) + + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/zephyr/zephyr.ri + COMMAND west sign --if-tool-available --tool rimage + --build-dir ${CMAKE_BINARY_DIR} ${WEST_SIGN_OPTS} + DEPENDS ${CMAKE_BINARY_DIR}/zephyr/${KERNEL_ELF_NAME}) + + board_set_rimage_target(imx8m_cm7) + +endif() + if (CONFIG_SOC_MIMX8UD7_ADSP) zephyr_library_sources( ${SOF_DRIVERS_PATH}/imx/ipc.c @@ -354,8 +403,6 @@ if (CONFIG_SOC_MIMX8UD7_ADSP) lib/dma.c ) - zephyr_library_sources(${SOF_SRC_PATH}/schedule/zephyr_ll.c) - set(PLATFORM "imx8ulp") endif() @@ -372,10 +419,6 @@ if (CONFIG_SOC_MIMX9352_A55) ${SOF_DRIVERS_PATH}/imx/ipc.c ) - zephyr_library_sources( - ${SOF_SRC_PATH}/schedule/zephyr_ll.c - ) - set(PLATFORM "imx93_a55") endif() @@ -391,14 +434,26 @@ if (CONFIG_SOC_MIMX9596_M7) ${SOF_DRIVERS_PATH}/imx/ipc.c ) - zephyr_library_sources( - ${SOF_SRC_PATH}/schedule/zephyr_ll.c - ) - # SOF-specific linker script additions zephyr_linker_sources(DATA_SECTIONS ${sof_top_dir}/src/platform/imx95/linker/data-sections.ld) set(PLATFORM "imx95") + + # no longer done in Zephyr and should be handled by SOF + # See [1], [2], and [3] for more context + # + # [1]: https://github.com/zephyrproject-rtos/zephyr/issues/91061 + # [2]: https://github.com/zephyrproject-rtos/zephyr/pull/97946 + # [3]: https://github.com/zephyrproject-rtos/zephyr/pull/97988 + add_custom_target(zephyr.ri ALL + DEPENDS ${CMAKE_BINARY_DIR}/zephyr/zephyr.ri) + + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/zephyr/zephyr.ri + COMMAND west sign --if-tool-available --tool rimage + --build-dir ${CMAKE_BINARY_DIR} ${WEST_SIGN_OPTS} + DEPENDS ${CMAKE_BINARY_DIR}/zephyr/${KERNEL_ELF_NAME}) + + board_set_rimage_target(imx95) endif() # AMD RMB platforms @@ -427,7 +482,6 @@ if (CONFIG_SOC_ACP_6_0) ${SOF_PLATFORM_PATH}/amd/rembrandt/lib/clk.c ${SOF_PLATFORM_PATH}/amd/rembrandt/lib/dai.c ${SOF_PLATFORM_PATH}/amd/rembrandt/lib/dma.c - ${SOF_PLATFORM_PATH}/amd/rembrandt/lib/memory.c ) # SOF core infrastructure - runs on top of Zephyr @@ -435,17 +489,6 @@ if (CONFIG_SOC_ACP_6_0) ${SOF_SRC_PATH}/drivers/interrupt.c ) - # Zephyr DMA domain should only be used with zephyr_ll - if (CONFIG_DMA_DOMAIN) - zephyr_library_sources( - ${SOF_SRC_PATH}/schedule/zephyr_ll.c - ) - else() - zephyr_library_sources( - ${SOF_SRC_PATH}/schedule/ll_schedule.c - ) - endif() - zephyr_include_directories(${SOF_PLATFORM_PATH}/amd/rembrandt/include) zephyr_include_directories(${SOF_PLATFORM_PATH}/amd/common/include) zephyr_include_directories(${SOF_PLATFORM_PATH}/amd/rembrandt/include/arch) @@ -453,23 +496,65 @@ if (CONFIG_SOC_ACP_6_0) set(PLATFORM "acp_6_0") endif() +if (CONFIG_SOC_ACP_7_0) + # Platform sources + zephyr_library_sources( + ${SOF_DRIVERS_PATH}/amd/rembrandt/ipc.c + ${SOF_DRIVERS_PATH}/amd/common/ipc.c + ${SOF_PLATFORM_PATH}/amd/acp_7_0/platform.c + ${SOF_PLATFORM_PATH}/amd/acp_7_0/lib/clk.c + ) + zephyr_library_sources(lib/dma.c) + zephyr_include_directories(${SOF_PLATFORM_PATH}/amd/acp_7_0/include) + zephyr_include_directories(${SOF_PLATFORM_PATH}/amd/common/include) + zephyr_include_directories(${SOF_PLATFORM_PATH}/amd/acp_7_0/include/arch) + + set(PLATFORM "acp_7_0") +endif() + +if (CONFIG_SOC_ACP_7_X) + # Platform sources + zephyr_library_sources( + ${SOF_DRIVERS_PATH}/amd/acp_7_x/ipc.c + ${SOF_PLATFORM_PATH}/amd/acp_7_x/platform.c + ${SOF_PLATFORM_PATH}/amd/acp_7_x/lib/clk.c + ) + zephyr_library_sources(lib/dma.c) + zephyr_include_directories(${SOF_PLATFORM_PATH}/amd/acp_7_x/include) + zephyr_include_directories(${SOF_PLATFORM_PATH}/amd/common/include) + zephyr_include_directories(${SOF_PLATFORM_PATH}/amd/acp_7_x/include/arch) + set(PLATFORM "acp_7_x") +endif() + if (CONFIG_SOC_FAMILY_MTK) set(PLATFORM "mtk") zephyr_library_sources( ${SOF_PLATFORM_PATH}/mtk/platform.c ${SOF_PLATFORM_PATH}/mtk/dai.c - ${SOF_SRC_PATH}/schedule/zephyr_ll.c - ${SOF_DRIVERS_PATH}/generic/dummy-dma.c - ${SOF_SRC_PATH}/drivers/mediatek/afe/afe-memif.c - ${SOF_SRC_PATH}/drivers/mediatek/afe/afe-dai.c ${SOF_SRC_PATH}/drivers/mediatek/afe/afe-drv.c ) + + if (CONFIG_ZEPHYR_NATIVE_DRIVERS) + # Native Zephyr DMA/DAI path + zephyr_library_sources( + lib/dma.c + ${SOF_SRC_PATH}/drivers/mediatek/afe/zephyr_mtk_afe_memif.c + ${SOF_SRC_PATH}/drivers/mediatek/afe/zephyr_mtk_host_dma.c + ${SOF_SRC_PATH}/drivers/mediatek/afe/zephyr_mtk_dai.c + ) + else() + # Legacy DMA path + zephyr_library_sources( + ${SOF_DRIVERS_PATH}/generic/dummy-dma.c + ${SOF_SRC_PATH}/drivers/mediatek/afe/afe-memif.c + ${SOF_SRC_PATH}/drivers/mediatek/afe/afe-dai.c + ) + endif() endif() # Building for native_posix-based whole-OS host emulator zephyr_library_sources_ifdef(CONFIG_ZEPHYR_POSIX - ${SOF_SRC_PATH}/schedule/zephyr_ll.c ${SOF_PLATFORM_PATH}/posix/dma.c ${SOF_PLATFORM_PATH}/posix/dai.c ${SOF_PLATFORM_PATH}/posix/ipc.c @@ -477,54 +562,27 @@ zephyr_library_sources_ifdef(CONFIG_ZEPHYR_POSIX ${SOF_PLATFORM_PATH}/posix/fuzz.c ) -zephyr_library_sources_ifdef(CONFIG_LIBRARY - ${SOF_PLATFORM_PATH}/library/platform.c - ${SOF_PLATFORM_PATH}/library/lib/dai.c - ${SOF_DRIVERS_PATH}/host/ipc.c -) +if (CONFIG_BOARD_QEMU_XTENSA) + set(PLATFORM "qemu_xtensa") + zephyr_library_sources(${SOF_PLATFORM_PATH}/qemu_xtensa/platform.c) +endif() if(NOT DEFINED PLATFORM) message(FATAL_ERROR "PLATFORM is not defined, check your Kconfiguration?") endif() zephyr_include_directories(${SOF_PLATFORM_PATH}/${PLATFORM}/include) +if(CONFIG_SOF_USERSPACE_INTERFACE_DMA) + zephyr_library_sources(syscall/sof_dma.c) + zephyr_syscall_header(include/sof/lib/sof_dma.h) +endif() + # Mandatory Files used on all platforms. # Commented files will be added/removed as integration dictates. zephyr_library_sources( - # SOF math utilities - ${SOF_MATH_PATH}/decibels.c - ${SOF_MATH_PATH}/numbers.c - ${SOF_MATH_PATH}/trig.c - ${SOF_MATH_PATH}/exp_fcn.c - ${SOF_MATH_PATH}/exp_fcn_hifi.c - - # SOF library - parts to transition to Zephyr over time - ${SOF_LIB_PATH}/notifier.c - ${SOF_LIB_PATH}/dma.c - ${SOF_LIB_PATH}/dai.c - - # SOF mandatory audio processing - ${SOF_AUDIO_PATH}/channel_map.c - ${SOF_AUDIO_PATH}/buffers/comp_buffer.c - ${SOF_AUDIO_PATH}/buffers/audio_buffer.c - ${SOF_AUDIO_PATH}/source_api_helper.c - ${SOF_AUDIO_PATH}/sink_api_helper.c - ${SOF_AUDIO_PATH}/sink_source_utils.c - ${SOF_AUDIO_PATH}/audio_stream.c - ${SOF_AUDIO_PATH}/component.c - ${SOF_AUDIO_PATH}/pipeline/pipeline-graph.c - ${SOF_AUDIO_PATH}/pipeline/pipeline-params.c - ${SOF_AUDIO_PATH}/pipeline/pipeline-schedule.c - ${SOF_AUDIO_PATH}/pipeline/pipeline-stream.c - ${SOF_AUDIO_PATH}/pipeline/pipeline-xrun.c - # SOF core infrastructure - runs on top of Zephyr ${SOF_SRC_PATH}/arch/xtensa/drivers/cache_attr.c - ${SOF_SRC_PATH}/schedule/zephyr_domain.c - ${SOF_SRC_PATH}/schedule/schedule.c - - ${SOF_SRC_PATH}/idc/zephyr_idc.c # Bridge wrapper between SOF and Zephyr APIs - Will shrink over time. wrapper.c @@ -533,645 +591,21 @@ zephyr_library_sources( lib/alloc.c lib/cpu.c lib/pm_runtime.c + lib/userspace_helper.c # Common library functions - Will be moved to Zephyr over time lib.c ) -if(NOT CONFIG_SOF_ZEPHYR_NO_SOF_CLOCK) - zephyr_library_sources(${SOF_LIB_PATH}/clk.c) -endif() - -zephyr_library_sources_ifdef(CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL - ${SOF_LIB_PATH}/cpu-clk-manager.c -) - -# Optional math utility -zephyr_library_sources_ifdef(CONFIG_MATH_LUT_SINE_FIXED - ${SOF_MATH_PATH}/lut_trig.c -) - -zephyr_library_sources_ifdef(CONFIG_MATH_FFT - ${SOF_MATH_PATH}/fft/fft_common.c -) - -zephyr_library_sources_ifdef(CONFIG_MATH_16BIT_FFT - ${SOF_MATH_PATH}/fft/fft_16.c - ${SOF_MATH_PATH}/fft/fft_16_hifi3.c -) - -zephyr_library_sources_ifdef(ONFIG_MATH_32BIT_FFT - ${SOF_MATH_PATH}/fft/fft_32.c - ${SOF_MATH_PATH}/fft/fft_32_hifi3.c -) - -zephyr_library_sources_ifdef(CONFIG_MATH_DCT - ${SOF_MATH_PATH}/dct.c -) - -zephyr_library_sources_ifdef(CONFIG_MATH_WINDOW - ${SOF_MATH_PATH}/window.c -) - -zephyr_library_sources_ifdef(CONFIG_MATH_MATRIX - ${SOF_MATH_PATH}/matrix.c -) - -zephyr_library_sources_ifdef(CONFIG_MATH_AUDITORY - ${SOF_MATH_PATH}/auditory/auditory.c -) - -zephyr_library_sources_ifdef(CONFIG_MATH_16BIT_MEL_FILTERBANK - ${SOF_MATH_PATH}/auditory/mel_filterbank_16.c -) - -zephyr_library_sources_ifdef(CONFIG_MATH_32BIT_MEL_FILTERBANK - ${SOF_MATH_PATH}/auditory/mel_filterbank_32.c -) - -zephyr_library_sources_ifdef(CONFIG_NATURAL_LOGARITHM_FIXED - ${SOF_MATH_PATH}/log_e.c -) - -zephyr_library_sources_ifdef(CONFIG_BINARY_LOGARITHM_FIXED - ${SOF_MATH_PATH}/base2log.c -) - # SOF module interface functions add_subdirectory(../src/module module_unused_install/) -if(CONFIG_PIPELINE_2_0) - zephyr_library_sources(${SOF_AUDIO_PATH}/buffers/ring_buffer.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() -if(CONFIG_SCHEDULE_DMA_MULTI_CHANNEL AND NOT(CONFIG_DMA_DOMAIN)) - zephyr_library_sources(${SOF_SRC_PATH}/schedule/dma_multi_chan_domain.c) -endif() -if (CONFIG_DMA_DOMAIN) - zephyr_library_sources(${SOF_SRC_PATH}/schedule/zephyr_dma_domain.c) +if(CONFIG_COLD_STORE_EXECUTE_DRAM) +zephyr_library_sources_ifdef(CONFIG_FAST_GET lib/fast-get.c) endif() -if(CONFIG_COMP_BLOB) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/data_blob.c - ) -endif() - -if(CONFIG_ZEPHYR_NATIVE_DRIVERS) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/host-zephyr.c - ) -else() - zephyr_library_sources( - ${SOF_AUDIO_PATH}/host-legacy.c - ) -endif() - - -zephyr_library_sources_ifdef(CONFIG_TRACE - ${SOF_SRC_PATH}/trace/dma-trace.c - ${SOF_SRC_PATH}/trace/trace.c) - -zephyr_library_sources_ifdef(CONFIG_LOG_BACKEND_SOF_PROBE - ${SOF_SRC_PATH}/logging/log_backend_probe.c) - # Optional SOF sources - depends on Kconfig - WIP -if(CONFIG_IPC_MAJOR_3) -set(ipc_suffix ipc3) -elseif(CONFIG_IPC_MAJOR_4) -set(ipc_suffix ipc4) -endif() - -if(CONFIG_COMP_FIR STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/eq_fir/llext - ${PROJECT_BINARY_DIR}/eq_fir_llext) - add_dependencies(app eq_iir) -elseif(CONFIG_COMP_FIR) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/eq_fir/eq_fir_hifi3.c - ${SOF_AUDIO_PATH}/eq_fir/eq_fir_hifi2ep.c - ${SOF_AUDIO_PATH}/eq_fir/eq_fir_generic.c - ${SOF_AUDIO_PATH}/eq_fir/eq_fir.c - ${SOF_AUDIO_PATH}/eq_fir/eq_fir_${ipc_suffix}.c - ) -endif() - -if(CONFIG_COMP_IIR STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/eq_iir/llext - ${PROJECT_BINARY_DIR}/eq_iir_llext) - add_dependencies(app eq_iir) -elseif(CONFIG_COMP_IIR) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/eq_iir/eq_iir.c - ${SOF_AUDIO_PATH}/eq_iir/eq_iir_${ipc_suffix}.c - ${SOF_AUDIO_PATH}/eq_iir/eq_iir_generic.c - ) -endif() - -zephyr_library_sources_ifdef(CONFIG_MATH_FIR - ${SOF_MATH_PATH}/fir_generic.c - ${SOF_MATH_PATH}/fir_hifi2ep.c - ${SOF_MATH_PATH}/fir_hifi3.c -) - -zephyr_library_sources_ifdef(CONFIG_MATH_IIR_DF1 - ${SOF_MATH_PATH}/iir_df1_generic.c - ${SOF_MATH_PATH}/iir_df1_hifi3.c - ${SOF_MATH_PATH}/iir_df1_hifi4.c - ${SOF_MATH_PATH}/iir_df1_hifi5.c - ${SOF_MATH_PATH}/iir_df1.c -) - -zephyr_library_sources_ifdef(CONFIG_MATH_IIR_DF2T - ${SOF_MATH_PATH}/iir_df2t_generic.c - ${SOF_MATH_PATH}/iir_df2t_hifi3.c - ${SOF_MATH_PATH}/iir_df2t.c -) - -if(CONFIG_COMP_ASRC STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/asrc/llext - ${PROJECT_BINARY_DIR}/asrc_llext) - add_dependencies(app asrc) -elseif(CONFIG_COMP_ASRC) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/asrc/asrc.c - ${SOF_AUDIO_PATH}/asrc/asrc_farrow_hifi3.c - ${SOF_AUDIO_PATH}/asrc/asrc_farrow.c - ${SOF_AUDIO_PATH}/asrc/asrc_farrow_generic.c - ${SOF_AUDIO_PATH}/asrc/asrc_${ipc_suffix}.c - ) -endif() - -if(CONFIG_COMP_DCBLOCK STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/dcblock/llext - ${PROJECT_BINARY_DIR}/dcblock_llext) - add_dependencies(app dcblock) -elseif(CONFIG_COMP_DCBLOCK) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/dcblock/dcblock_generic.c - ${SOF_AUDIO_PATH}/dcblock/dcblock.c - ${SOF_AUDIO_PATH}/dcblock/dcblock_hifi3.c - ${SOF_AUDIO_PATH}/dcblock/dcblock_hifi4.c - ${SOF_AUDIO_PATH}/dcblock/dcblock_${ipc_suffix}.c - ) -endif() - -if(CONFIG_COMP_SEL STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/selector/llext - ${PROJECT_BINARY_DIR}/selector_llext) - add_dependencies(app selector) -elseif(CONFIG_COMP_SEL) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/selector/selector_generic.c - ${SOF_AUDIO_PATH}/selector/selector.c - ) -endif() - -zephyr_library_sources_ifdef(CONFIG_COMP_KPB - ${SOF_AUDIO_PATH}/kpb.c -) - -zephyr_library_sources_ifdef(CONFIG_COMP_MIXER - ${SOF_AUDIO_PATH}/mixer/mixer.c - ${SOF_AUDIO_PATH}/mixer/mixer_generic.c - ${SOF_AUDIO_PATH}/mixer/mixer_hifi3.c -) - -if(CONFIG_COMP_MIXIN_MIXOUT STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/mixin_mixout/llext - ${PROJECT_BINARY_DIR}/mixin_mixout_llext) - add_dependencies(app mixin_mixout) -elseif(CONFIG_COMP_MIXIN_MIXOUT) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/mixin_mixout/mixin_mixout.c - ${SOF_AUDIO_PATH}/mixin_mixout/mixin_mixout_generic.c - ${SOF_AUDIO_PATH}/mixin_mixout/mixin_mixout_hifi3.c - ${SOF_AUDIO_PATH}/mixin_mixout/mixin_mixout_hifi5.c - ) -endif() - -zephyr_library_sources_ifdef(CONFIG_COMP_TONE - ${SOF_AUDIO_PATH}/tone.c -) - -if(CONFIG_ZEPHYR_NATIVE_DRIVERS) - zephyr_library_sources_ifdef(CONFIG_COMP_DAI - ${SOF_AUDIO_PATH}/dai-zephyr.c -) -else() - zephyr_library_sources_ifdef(CONFIG_COMP_DAI - ${SOF_AUDIO_PATH}/dai-legacy.c -) -endif() - -zephyr_library_sources_ifdef(CONFIG_IPC4_GATEWAY - ${SOF_AUDIO_PATH}/copier/copier_ipcgtw.c -) - -zephyr_library_sources_ifdef(CONFIG_COPIER_GAIN - ${SOF_AUDIO_PATH}/copier/copier_gain.c -) - -zephyr_library_sources_ifdef(CONFIG_SAMPLE_KEYPHRASE - ${SOF_SAMPLES_PATH}/audio/detect_test.c -) - -if(CONFIG_COMP_VOLUME STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/volume/llext - ${PROJECT_BINARY_DIR}/volume_llext) - add_dependencies(app volume) -elseif(CONFIG_COMP_VOLUME) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/volume/volume_hifi5.c - ${SOF_AUDIO_PATH}/volume/volume_hifi4.c - ${SOF_AUDIO_PATH}/volume/volume_hifi3.c - ${SOF_AUDIO_PATH}/volume/volume_generic.c - ${SOF_AUDIO_PATH}/volume/volume_hifi5_with_peakvol.c - ${SOF_AUDIO_PATH}/volume/volume_hifi4_with_peakvol.c - ${SOF_AUDIO_PATH}/volume/volume_hifi3_with_peakvol.c - ${SOF_AUDIO_PATH}/volume/volume_generic_with_peakvol.c - ${SOF_AUDIO_PATH}/volume/volume.c - ${SOF_AUDIO_PATH}/volume/volume_${ipc_suffix}.c - ) -endif() - -zephyr_library_sources_ifdef(CONFIG_COMP_MODULE_ADAPTER - ${SOF_AUDIO_PATH}/module_adapter/module_adapter.c - ${SOF_AUDIO_PATH}/module_adapter/module_adapter_${ipc_suffix}.c - ${SOF_AUDIO_PATH}/module_adapter/module/generic.c -) - -zephyr_library_sources_ifdef(CONFIG_LIBRARY_MANAGER - ${SOF_SRC_PATH}/library_manager/lib_manager.c - ${SOF_SRC_PATH}/library_manager/lib_notification.c -) - -if (CONFIG_MM_DRV AND CONFIG_LLEXT) -zephyr_library_sources_ifdef(CONFIG_LIBRARY_MANAGER - ${SOF_SRC_PATH}/library_manager/llext_manager.c -) -endif() - -zephyr_include_directories_ifdef(CONFIG_INTEL_MODULES - ${SOF_SRC_PATH}/include/sof/audio/module_adapter/iadk/ - ${SOF_SRC_PATH}/include/sof/audio/module_adapter/library/ -) - -zephyr_library_sources_ifdef(CONFIG_INTEL_MODULES - ${SOF_AUDIO_PATH}/module_adapter/module/modules.c - ${SOF_AUDIO_PATH}/module_adapter/iadk/module_initial_settings_concrete.cpp - ${SOF_AUDIO_PATH}/module_adapter/iadk/iadk_module_adapter.cpp - ${SOF_AUDIO_PATH}/module_adapter/iadk/system_agent.cpp - ${SOF_AUDIO_PATH}/module_adapter/library/native_system_agent.c - ${SOF_AUDIO_PATH}/module_adapter/library/native_system_service.c -) - -if (CONFIG_COMP_MODULE_ADAPTER) -zephyr_library_sources_ifdef(CONFIG_CADENCE_CODEC - ${SOF_AUDIO_PATH}/module_adapter/module/cadence.c -) - -if (CONFIG_CADENCE_CODEC_MP3_DEC) -zephyr_library_import(xa_mp3_dec ${CONFIG_CADENCE_CODEC_MP3_DEC_LIB}) -endif() - -if (CONFIG_CADENCE_CODEC_MP3_ENC) -zephyr_library_import(xa_mp3_enc ${CONFIG_CADENCE_CODEC_MP3_ENC_LIB}) -endif() - -if (CONFIG_CADENCE_CODEC_AAC_DEC) -zephyr_library_import(xa_aac_dec ${CONFIG_CADENCE_CODEC_AAC_DEC_LIB}) -endif() - -zephyr_library_sources_ifdef(CONFIG_PASSTHROUGH_CODEC - ${SOF_AUDIO_MODULES_PATH}/passthrough.c -) -endif() - -zephyr_library_sources_ifdef(CONFIG_COMP_CHAIN_DMA - ${SOF_AUDIO_PATH}/chain_dma.c -) - -if(CONFIG_COMP_SRC STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/src/llext - ${PROJECT_BINARY_DIR}/src_llext) - add_dependencies(app src) -elseif(CONFIG_COMP_SRC) - 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_common.c - ${SOF_AUDIO_PATH}/src/src.c - ${SOF_AUDIO_PATH}/src/src_${ipc_suffix}.c - ) - - zephyr_library_sources_ifdef(CONFIG_COMP_SRC_LITE - ${SOF_AUDIO_PATH}/src/src_lite.c - ) -endif() - -zephyr_library_sources_ifdef(CONFIG_COMP_BASEFW_IPC4 - ${SOF_AUDIO_PATH}/base_fw.c -) - -zephyr_library_sources_ifdef(CONFIG_IPC4_BASE_FW_INTEL - ${SOF_AUDIO_PATH}/base_fw_intel.c -) - -zephyr_library_sources_ifdef(CONFIG_COMP_COPIER - ${SOF_AUDIO_PATH}/copier/copier_generic.c - ${SOF_AUDIO_PATH}/copier/copier_hifi.c - ${SOF_AUDIO_PATH}/copier/copier.c - ${SOF_AUDIO_PATH}/copier/copier_host.c - ${SOF_AUDIO_PATH}/copier/copier_dai.c -) - -zephyr_library_sources( - ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter_hifi3.c - ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter.c - ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter_generic.c -) -zephyr_library_sources_ifdef(CONFIG_PCM_REMAPPING_CONVERTERS - ${SOF_AUDIO_PATH}/pcm_converter/pcm_remap.c -) - -zephyr_library_sources_ifdef(CONFIG_MAXIM_DSM - ${SOF_AUDIO_PATH}/smart_amp/smart_amp.c - ${SOF_AUDIO_PATH}/smart_amp/smart_amp_generic.c - ${SOF_AUDIO_PATH}/smart_amp/smart_amp_maxim_dsm.c -) - -zephyr_include_directories_ifdef(CONFIG_MAXIM_DSM - ${SOF_AUDIO_PATH}/smart_amp/include/dsm_api/inc/ -) - -zephyr_library_sources_ifdef(CONFIG_MAXIM_DSM_STUB - ${SOF_AUDIO_PATH}/smart_amp/maxim_dsm_stub.c -) - -if(CONFIG_COMP_ARIA STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/aria/llext - ${PROJECT_BINARY_DIR}/aria_llext) - add_dependencies(app aria) -elseif(CONFIG_COMP_ARIA) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/aria/aria.c - ${SOF_AUDIO_PATH}/aria/aria_hifi5.c - ${SOF_AUDIO_PATH}/aria/aria_hifi3.c - ${SOF_AUDIO_PATH}/aria/aria_generic.c - ) -endif() - -if(CONFIG_COMP_CROSSOVER STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/crossover/llext - ${PROJECT_BINARY_DIR}/crossover_llext) - add_dependencies(app crossover) -elseif(CONFIG_COMP_CROSSOVER) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/crossover/crossover.c - ${SOF_AUDIO_PATH}/crossover/crossover_generic.c - ${SOF_AUDIO_PATH}/crossover/crossover_${ipc_suffix}.c - ) -endif() - -if(CONFIG_COMP_DRC STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/drc/llext - ${PROJECT_BINARY_DIR}/drc_llext) - add_dependencies(app drc) -elseif(CONFIG_COMP_DRC) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/drc/drc.c - ${SOF_AUDIO_PATH}/drc/drc_generic.c - ${SOF_AUDIO_PATH}/drc/drc_math_generic.c - ${SOF_AUDIO_PATH}/drc/drc_hifi3.c - ${SOF_AUDIO_PATH}/drc/drc_hifi4.c - ${SOF_AUDIO_PATH}/drc/drc_math_hifi3.c - ) -endif() - -if(NOT CONFIG_COMP_DRC STREQUAL "n") - zephyr_library_sources( - ${SOF_AUDIO_PATH}/drc/drc_log.c - ) -endif() - -if(CONFIG_COMP_MULTIBAND_DRC STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/multiband_drc/llext - ${PROJECT_BINARY_DIR}/multiband_drc_llext) - add_dependencies(app multiband_drc) -elseif(CONFIG_COMP_MULTIBAND_DRC) - zephyr_library_sources_ifdef(CONFIG_COMP_MULTIBAND_DRC - ${SOF_AUDIO_PATH}/multiband_drc/multiband_drc.c - ${SOF_AUDIO_PATH}/multiband_drc/multiband_drc_generic.c - ${SOF_AUDIO_PATH}/multiband_drc/multiband_drc_${ipc_suffix}.c - ) -endif() - -if(CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/google/llext_rtc - ${PROJECT_BINARY_DIR}/google_rtc_audio_processing_llext) - add_dependencies(app google_rtc_audio_processing) -elseif(CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/google/google_rtc_audio_processing.c - ) - - zephyr_library_sources_ifdef(CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK - ${SOF_AUDIO_PATH}/google/google_rtc_audio_processing_mock.c - ) - - if(NOT CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK) - zephyr_include_directories(../third_party/include) - target_link_directories(SOF INTERFACE ../third_party/lib) - target_link_libraries(SOF INTERFACE google_rtc_audio_processing) - target_link_libraries(SOF INTERFACE c++) - target_link_libraries(SOF INTERFACE c++abi) - target_link_libraries(SOF INTERFACE m) - target_link_libraries(SOF INTERFACE c) - target_link_libraries(SOF INTERFACE gcc) - endif() -endif() - -if(CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/google/llext_ctc - ${PROJECT_BINARY_DIR}/google_ctc_audio_processing_llext) - add_dependencies(app google_ctc_audio_processing) -elseif(CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/google/google_ctc_audio_processing.c - ${SOF_AUDIO_PATH}/google/google_ctc_audio_processing_${ipc_suffix}.c - ) - - zephyr_library_sources_ifdef(CONFIG_GOOGLE_CTC_AUDIO_PROCESSING_MOCK - ${SOF_AUDIO_PATH}/google/google_ctc_audio_processing_mock.c - ) - - if(NOT CONFIG_GOOGLE_CTC_AUDIO_PROCESSING_MOCK) - zephyr_include_directories(../third_party/include) - target_link_directories(SOF INTERFACE ../third_party/lib) - target_link_libraries(SOF INTERFACE google_ctc_audio_processing) - target_link_libraries(SOF INTERFACE c++) - target_link_libraries(SOF INTERFACE c++abi) - target_link_libraries(SOF INTERFACE m) - target_link_libraries(SOF INTERFACE c) - target_link_libraries(SOF INTERFACE gcc) - endif() -endif() - -if(CONFIG_COMP_IGO_NR STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/igo_nr/llext - ${PROJECT_BINARY_DIR}/igo_nr_llext) - add_dependencies(app igo_nr) -elseif(CONFIG_COMP_IGO_NR) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/igo_nr/igo_nr.c - ) - - zephyr_library_sources_ifdef(CONFIG_COMP_IGO_NR_STUB - ${SOF_AUDIO_PATH}/igo_nr/igo_nr_stub.c - ) -endif() - -if(CONFIG_COMP_RTNR STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/rtnr/llext - ${PROJECT_BINARY_DIR}/rtnr_llext) - add_dependencies(app rtnr) -elseif(CONFIG_COMP_RTNR) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/rtnr/rtnr.c - ) - - zephyr_library_sources_ifdef(CONFIG_COMP_RTNR_STUB - ${SOF_AUDIO_PATH}/rtnr/rtnr_stub.c - ) -endif() - -if(CONFIG_SAMPLE_SMART_AMP STREQUAL "m") - add_subdirectory(${SOF_SAMPLES_PATH}/audio/smart_amp_test_llext - ${PROJECT_BINARY_DIR}/smart_amp_test_llext) - add_dependencies(app smart_amp_test) -elseif(CONFIG_SAMPLE_SMART_AMP) - zephyr_library_sources( - ${SOF_SAMPLES_PATH}/audio/smart_amp_test_${ipc_suffix}.c - ) -endif() - -if(CONFIG_COMP_TDFB STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/tdfb/llext - ${PROJECT_BINARY_DIR}/tdfb_llext) - add_dependencies(app tdfb) -elseif(CONFIG_COMP_TDFB) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/tdfb/tdfb.c - ${SOF_AUDIO_PATH}/tdfb/tdfb_direction.c - ${SOF_AUDIO_PATH}/tdfb/tdfb_generic.c - ${SOF_AUDIO_PATH}/tdfb/tdfb_hifiep.c - ${SOF_AUDIO_PATH}/tdfb/tdfb_hifi3.c - ${SOF_AUDIO_PATH}/tdfb/tdfb_${ipc_suffix}.c - ) -endif() - -zephyr_library_sources_ifdef(CONFIG_SQRT_FIXED - ${SOF_MATH_PATH}/sqrt_int16.c -) - -zephyr_library_sources_ifdef(CONFIG_MATH_EXP - ${SOF_MATH_PATH}/exp_fcn.c - ${SOF_MATH_PATH}/exp_fcn_hifi.c -) - -zephyr_library_sources_ifdef(CONFIG_COMP_UP_DOWN_MIXER - ${SOF_AUDIO_PATH}/up_down_mixer/up_down_mixer.c - ${SOF_AUDIO_PATH}/up_down_mixer/up_down_mixer_hifi3.c -) - -if(CONFIG_COMP_MUX STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/mux/llext - ${PROJECT_BINARY_DIR}/mux_llext) - add_dependencies(app mux) -elseif(CONFIG_COMP_MUX) - zephyr_library_sources_ifdef(CONFIG_COMP_MUX - ${SOF_AUDIO_PATH}/mux/mux.c - ${SOF_AUDIO_PATH}/mux/mux_generic.c - ${SOF_AUDIO_PATH}/mux/mux_${ipc_suffix}.c - ) -endif() - -if(CONFIG_COMP_MFCC STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/mfcc/llext - ${PROJECT_BINARY_DIR}/mfcc_llext) - add_dependencies(app mfcc) -elseif(CONFIG_COMP_MFCC) - zephyr_library_sources_ifdef(CONFIG_COMP_MFCC - ${SOF_AUDIO_PATH}/mfcc/mfcc.c - ${SOF_AUDIO_PATH}/mfcc/mfcc_setup.c - ${SOF_AUDIO_PATH}/mfcc/mfcc_common.c - ${SOF_AUDIO_PATH}/mfcc/mfcc_generic.c - ${SOF_AUDIO_PATH}/mfcc/mfcc_hifi3.c - ${SOF_AUDIO_PATH}/mfcc/mfcc_hifi4.c - ) -endif() - -zephyr_library_sources_ifdef(CONFIG_COMP_GOOGLE_HOTWORD_DETECT - ${SOF_AUDIO_PATH}/google/google_hotword_detect.c -) - -if(CONFIG_DTS_CODEC STREQUAL "m") - add_subdirectory(${SOF_AUDIO_PATH}/codec/dts/llext - ${PROJECT_BINARY_DIR}/dts_llext) - add_dependencies(app dts) -elseif(CONFIG_DTS_CODEC) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/codec/dts/dts.c - ) - if (CONFIG_DTS_CODEC_STUB) - zephyr_library_sources( - ${SOF_AUDIO_PATH}/codec/dts/dts_stub.c - ) - else() - zephyr_library_import(DtsCodec - ${sof_top_dir}/third_party/lib/libdts-sof-interface-i32.a) - endif() -endif() - -zephyr_library_sources_ifdef(CONFIG_WAVES_CODEC - ${SOF_AUDIO_PATH}/module_adapter/module/waves/waves.c -) - -zephyr_library_sources_ifdef(CONFIG_WAVES_CODEC_STUB - ${SOF_AUDIO_PATH}/module_adapter/module/waves/maxx_stub.c -) - -if(CONFIG_PROBE STREQUAL "m") - add_subdirectory(${SOF_SRC_PATH}/probe/llext - ${PROJECT_BINARY_DIR}/probe_llext) - add_dependencies(app probe) -elseif(CONFIG_PROBE) - zephyr_library_sources(${SOF_SRC_PATH}/probe/probe.c) -endif() - -zephyr_library_sources_ifdef(CONFIG_MULTICORE - ${SOF_SRC_PATH}/idc/idc.c -) - -zephyr_library_sources_ifdef(CONFIG_HAVE_AGENT - ${SOF_LIB_PATH}/agent.c -) - -zephyr_library_sources_ifdef(CONFIG_AMS - ${SOF_LIB_PATH}/ams.c -) - -zephyr_library_sources_ifdef(CONFIG_GDB_DEBUG - ${SOF_DEBUG_PATH}/gdb/gdb.c - ${SOF_DEBUG_PATH}/gdb/ringbuffer.c -) - zephyr_library_sources_ifdef(CONFIG_DW_DMA ${SOF_DRIVERS_PATH}/dw/dma.c ) @@ -1184,6 +618,15 @@ zephyr_library_sources_ifdef(CONFIG_SHELL sof_shell.c ) +zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/audio/module_adapter/module/generic.h) +zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/lib/fast-get.h) +zephyr_syscall_header(include/rtos/alloc.h) +zephyr_library_sources_ifdef(CONFIG_SOF_USERSPACE_INTERFACE_ALLOC syscall/alloc.c) +zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/lib/dai-zephyr.h) +zephyr_library_sources_ifdef(CONFIG_USERSPACE syscall/dai.c) + +zephyr_syscall_header(${SOF_SRC_PATH}/include/user/debug_stream_slot.h) + zephyr_library_link_libraries(SOF) target_link_libraries(SOF INTERFACE zephyr_interface) @@ -1222,4 +665,4 @@ include(../scripts/cmake/uuid-registry.cmake) # Create Trace realtive file paths sof_append_relative_path_definitions(modules_sof) -endif() # CONFIG_SOF +endif() # CONFIG_SOF_FULL_ZEPHYR_APPLICATION diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 803d668857f3..27f37d829b4e 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -1,23 +1,201 @@ -if SOF +config SOF_FULL_ZEPHYR_APPLICATION + bool "Build full SOF Zephyr application" + default y + help + Top-level build option to enable full build of the SOF application + on top of Zephyr. This should be set to no only for unit test and + such special build targets. + +config SOF_STAGING + bool "Enable SOF staging features and modules" + help + SOF staging features are not ready for production but are + upstream to enable developers to continue development in order + to bring the feature to production level faster using the + upstream codebase. + rsource "../Kconfig.sof" +config SOF_USERSPACE + bool "Enable SOF support for userspace modules" + help + SOF userspace modules support will enable modules to run in DP + processing mode as userspace code and data. This feature is WIP + and is not yet ready for production, for developers only. + +config SOF_USERSPACE_INTERFACE_DMA + bool "Enable SOF DMA interface to userspace threads" + depends on USERSPACE + help + Allow user-space threads to use the SOF DMA interface. + +config SOF_USERSPACE_INTERFACE_ALLOC + bool "Enable SOF heap alloc interface to userspace threads" + depends on USERSPACE + help + Allow user-space threads to use sof_heap_alloc/sof_heap_free + as Zephyr system calls. + +config SOF_USERSPACE_LL + bool "Run Low-Latency pipelines in userspace threads" + depends on USERSPACE + select SOF_USERSPACE_INTERFACE_ALLOC + select SOF_USERSPACE_INTERFACE_DMA + help + Run Low-Latency (LL) pipelines in userspace threads. This adds + memory protection between operating system resources and + audio application threads. + If unsure, select "N". + config SOF_ZEPHYR_HEAP_CACHED bool "Cached Zephyr heap for SOF memory non-shared zones" default y if CAVS || ACE - default n help Enable cached heap by mapping cached SOF memory zones to different Zephyr sys_heap objects and enable caching for non-shared zones. +config SOF_ZEPHYR_HEAP_SIZE + hex "Size of the Zephyr heap for SOF" + default 0x40000 if VIRTUAL_HEAP + default 0xF0000 if SOC_ACE15_MTPM || SOC_ACE20_LNL + default 0xD0000 if SOC_ACE30 || SOC_ACE40 + default 0x0 + help + Support scaling of the heap size for different platforms and different types + of heaps. This is the default heap size for most users. + TODO: Currently this setting is only available on platforms with a + simplified heap size configuration. i.e. a single macro that defines the + heap size. This is not the case for all platforms. + NOTE: Keep in mind that the heap size should not be greater than the physical + memory size of the system defined in DT (and this includes baseFW text/data). + +config SOF_USERSPACE_USE_SHARED_HEAP + bool "Use shared heap for SOF userspace modules" + depends on USERSPACE + help + When set a shared heap will be used for audio buffers between SOF + kernel and userspace modules. + +config SOF_ZEPHYR_SHARED_BUFFER_HEAP_SIZE + hex "Size of the shared buffer heap for SOF userspace modules" + default 0x0 if !SOF_USERSPACE_USE_SHARED_HEAP + default 0x1E000 if SOC_ACE15_MTPM || SOC_ACE20_LNL + default 0x10000 if SOC_ACE30 + default 0x0 + depends on USERSPACE + help + The size of the zephyr heap portion designated as the shared buffer heap. + This heap is shared between the sof and userspace modules. It is used exclusively for + allocating audio buffers between the kernel and userspace modules. + NOTE: Keep in mind that the shared heap size should not be greater than the + heap size. + +config VIRTUAL_HEAP_EXTENDED + bool "Extend the Virtual Heap configuration with additional buffers" + depends on MM_DRV_INTEL_ADSP_MTL_TLB + default y + help + Enable additional Virtual Heap buffers. Some configurations need this + while others need the memory for other purposes, e.g. for the virtual + page / virtual region storage. + +config SOF_ZEPHYR_VIRTUAL_HEAP_REGION_SIZE + hex "Size in bytes of virtual memory region for virtual heap shared for all cores" + depends on MM_DRV_INTEL_ADSP_MTL_TLB + default 0x140000 if VIRTUAL_HEAP_EXTENDED + default 0x100000 + help + This config defines size of virtual heap region shared between all cores + +config SOF_USERSPACE_USE_DRIVER_HEAP + bool "Use driver heap for SOF userspace modules" + depends on USERSPACE + help + When selected, multiple instances of the same userspace module will share + a private heap created for that module's driver. Otherwise, each module + instance will have its own independent private heap. + +config SOF_ZEPHYR_USERSPACE_MODULE_HEAP_SIZE + hex "Size of the private heap created for each userspace module" + default 0x1000 + depends on USERSPACE + help + The size of the private heap created for each userspace module. Each userspace + module has its own independent heap to which only it has access. This heap is + shared between instances of the same module. + +config SOF_ZEPHYR_SYS_USER_HEAP_SIZE + hex "Size of the shared LL user-space heap" + default 0x20000 + depends on SOF_USERSPACE_LL + help + The size of the shared heap used by the low-latency (LL) scheduler + user-space thread. This heap is shared across all pipelines running + on the LL thread and must be large enough to hold all host DMA + buffers, chain DMA data, SG elements, and module adapter buffers + for all simultaneously active pipelines. + +config SOF_USERSPACE_PROXY + bool "Use userspace proxy to support userspace modules" + select SOF_USERSPACE_USE_DRIVER_HEAP + select SOF_USERSPACE_USE_SHARED_HEAP + help + When set, userspace modules are launched inside a container created by userspace proxy. + It is responsible for forwarding module function calls coming from sof running in + kernelspace to the module code executed with user privileges. + +config SOF_USERSPACE_MOD_IPC_BY_DP_THREAD + bool "Handle modules IPC in DP thread" + depends on SOF_USERSPACE_PROXY + help + When enabled, IPC requests targeted to a userspace module are executed + in its DP thread instead of the shared user worker thread. + +config SOF_USERSPACE_PROXY_WORKER_STACK_SIZE + int "Userspace IPC worker stack size" + default 4096 + help + Size of the stack used by the IPC worker thread created by the + userspace proxy. This worker handles IPC requests for modules + running in userspace. + +config SOF_USERSPACE_APPLICATION + bool + default USERSPACE && !SOF_USERSPACE_PROXY + depends on SOF_VREGIONS + help + Not manually settable. This is effectively a shortcut to replace numerous + checks for (CONFIG_USERSPACE && !CONFIG_SOF_USERSPACE_PROXY) + +config SOF_VPAGE_MAX_ALLOCS + int "Number of virtual memory page allocations" + default 128 + help + This setting defines the maximum number of virtual memory page + allocations that can be tracked. Each allocation represents a + contiguous block of virtual memory allocated from the virtual memory + region. This API isn't intended for end-user allocations, instead it + should be used by the framework to allocate memory, which is then + used, e.g. to create one or multiple heap allocators in it. Increasing + this number allows for more simultaneous allocations, but also + increases the memory overhead for tracking these allocations. + config ZEPHYR_NATIVE_DRIVERS bool "Use Zephyr native drivers" - default n help Enable Zephyr native api drivers for host and dai audio components host-zephyr dai-zephyr will be used instead of legacy xtos version. +config DMA_MTK_SOF_HOST_DMA + bool "MediaTek SOF host DMA driver" + default y if SOC_FAMILY_MTK && ZEPHYR_NATIVE_DRIVERS + help + Software-based DMA driver for MTK SOF host component. + MTK DSP can access host memory directly, so this driver + implements DMA transfers using memcpy + cache management. + config DMA_DOMAIN bool "Enable the usage of DMA domain." help @@ -43,11 +221,11 @@ config PIPELINE_2_0 config ZEPHYR_DP_SCHEDULER bool "use Zephyr thread based DP scheduler" default y if ACE - default n depends on IPC_MAJOR_4 depends on ZEPHYR_SOF_MODULE depends on ACE depends on PIPELINE_2_0 + imply XTENSA_HIFI_SHARING if XTENSA_HIFI help Enable Data Processing preemptive scheduler based on Zephyr preemptive threads. @@ -65,9 +243,21 @@ config CROSS_CORE_STREAM can be processed on different cores, however, each stream is processed entirely on single core. +config SOF_BOOT_TEST_ALLOWED + bool "Enable SOF boot-time testing" + help + boot-time testing enabled if supported by the platform + +config SOF_BOOT_TEST_SUPPORTED + bool "Platform supports boot-time testing" + default y + help + boot-time testing supported by the platform + config SOF_BOOT_TEST - bool "enable SOF run-time testing" + bool depends on ZTEST + default y help Run tests during boot. This enables an SOF boot-time self-test. When enabled, the resulting image will run a number of self-tests when the @@ -75,18 +265,48 @@ config SOF_BOOT_TEST initialized. After that SOF will continue running and be usable as usual. +config SOF_BOOT_TEST_STANDALONE + bool "enable tests at boot time that are run instead of SOF main" + select SOF_BOOT_TEST + select ZTEST + help + Run extended set of tests at boot that can use IPC and interfere + with system state. Normal IPC handling of the SOF application + is disabled to allow more complex tests to run. + config SOF_ZEPHYR_NO_SOF_CLOCK bool help Do not use SOF clk.h interface to set the DSP clock frequency. Requires implementation of platform/lib/clk.h. +config SOF_VREGIONS + bool "Enable virtual memory regions" + default y if ACE && !ACE_VERSION_1_5 && !ACE_VERSION_2_0 + depends on ACE + help + Enable the virtual regions memory allocator for pipeline resource management. + This provides a way to manage memory resources for audio pipelines, + including + 1) multiple pipeline static lifetime allocations. + 2) runtime pipeline allocations. + config VIRTUAL_HEAP - bool "Use virtual memory heap to allocate a buffers" + bool "Use virtual memory heap to allocate buffers" default y if ACE - default n depends on ACE help Enabling this option will use the virtual memory heap allocator to allocate buffers. It is based on a set of buffers whose size is predetermined. -endif + +config STACK_SIZE_EDF + int "EDF scheduler stack size" + default 8192 + help + EDF scheduler work-queue thread stack size. Keep a power of 2. + +config STACK_SIZE_IPC_TX + int "IPC sender stack size" + default 2048 + help + IPC sender work-queue thread stack size. Keep a power of 2. diff --git a/zephyr/boot_test.c b/zephyr/boot_test.c index 4cbbfa597d8b..020072856ecb 100644 --- a/zephyr/boot_test.c +++ b/zephyr/boot_test.c @@ -12,9 +12,7 @@ LOG_MODULE_REGISTER(sof_boot_test, LOG_LEVEL_DBG); ZTEST_SUITE(sof_boot, NULL, NULL, NULL, NULL, NULL); -void sys_run_boot_tests(void) +void sof_run_boot_tests(void) { ztest_run_all(NULL, false, 1, 1); } -SYS_INIT(sys_run_boot_tests, APPLICATION, 99); - diff --git a/zephyr/docker-build.sh b/zephyr/docker-build.sh index 161ab896c389..fa54fe318d87 100755 --- a/zephyr/docker-build.sh +++ b/zephyr/docker-build.sh @@ -50,8 +50,6 @@ unset ZEPHYR_SDK_INSTALL_DIR # CMake v3.21 changed the order object files are passed to the linker. # This makes builds before that version not reproducible. # To save time don't install if recent enough. -pip install 'cmake>=3.21' -PATH="$HOME"/.local/bin:"$PATH" if test -e .west || test -e zephyr; then init_update='' diff --git a/zephyr/docker-run.sh b/zephyr/docker-run.sh index fccee059be81..e71e266d52b8 100755 --- a/zephyr/docker-run.sh +++ b/zephyr/docker-run.sh @@ -54,8 +54,10 @@ main() run_command() { - # zephyr-build:v0.27.4 has /opt/toolchains/zephyr-sdk-0.17.0 + # zephyr-lite:v0.29.0 has /opt/toolchains/zephyr-sdk-1.0.0 + # zephyr-lite:v0.29.0 is based on zephyr-build:v0.29.0 # https://hub.docker.com/r/zephyrprojectrtos/zephyr-build/tags + # https://hub.docker.com/r/thesofproject/zephyr-lite/tags # # Keep this SDK version identical to the one in # .github/workflows/zephyr.yml#Windows @@ -63,7 +65,7 @@ run_command() --workdir /zep_workspace \ $SOF_DOCKER_RUN \ --env REAL_CC --env http_proxy --env https_proxy \ - ghcr.io/zephyrproject-rtos/zephyr-build:v0.27.4 \ + thesofproject/zephyr-lite:v0.29.0 \ ./sof/scripts/sudo-cwd.sh "$@" } diff --git a/zephyr/edf_schedule.c b/zephyr/edf_schedule.c index ca196842cb1a..a14ed31d060d 100644 --- a/zephyr/edf_schedule.c +++ b/zephyr/edf_schedule.c @@ -5,6 +5,8 @@ // Author: Bartosz Kokoszko <bartoszx.kokoszko@linux.intel.com> #include <sof/audio/component.h> +#include <sof/lib/memory.h> +#include <rtos/alloc.h> #include <rtos/task.h> #include <stdint.h> #include <sof/schedule/edf_schedule.h> @@ -14,7 +16,7 @@ #include <zephyr/sys_clock.h> static struct k_work_q edf_workq; -static K_THREAD_STACK_DEFINE(edf_workq_stack, 8192); +static K_THREAD_STACK_DEFINE(edf_workq_stack, CONFIG_STACK_SIZE_EDF); /* * since only IPC is using the EDF scheduler - we schedule the work in the @@ -98,21 +100,26 @@ static struct scheduler_ops schedule_edf_ops = { .schedule_task_free = schedule_edf_task_free, }; -int scheduler_init_edf(void) +__cold int scheduler_init_edf(void) { struct k_thread *thread = &edf_workq.thread; + assert_can_be_cold(); + scheduler_init(SOF_SCHEDULE_EDF, &schedule_edf_ops, NULL); k_work_queue_start(&edf_workq, edf_workq_stack, K_THREAD_STACK_SIZEOF(edf_workq_stack), - EDF_ZEPHYR_PRIORITY, NULL); + CONFIG_EDF_THREAD_PRIORITY, NULL); k_thread_suspend(thread); + k_thread_heap_assign(thread, sof_sys_heap_get()); +#ifdef CONFIG_SCHED_CPU_MASK k_thread_cpu_mask_clear(thread); k_thread_cpu_mask_enable(thread, PLATFORM_PRIMARY_CORE_ID); +#endif k_thread_name_set(thread, "edf_workq"); k_thread_resume(thread); diff --git a/zephyr/include/rtos/alloc.h b/zephyr/include/rtos/alloc.h index 69228ea8f9c2..b727d1e700fb 100644 --- a/zephyr/include/rtos/alloc.h +++ b/zephyr/include/rtos/alloc.h @@ -19,126 +19,214 @@ * @{ */ -/** - * \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 */ -}; +/* + * for compatibility with the initial `flags` meaning + * SOF_MEM_FLAG_ should start at BIT(2) + * the first two positions are reserved for SOF_BUF_ flags + */ -/** \name Heap zone flags +/** \name Allocation 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) + /** \brief Allocate DMA-able memory. */ +#define SOF_MEM_FLAG_DMA BIT(2) +/** \brief realloc() skips copying the original content. */ +#define SOF_MEM_FLAG_NO_COPY BIT(3) +/** \brief Allocate uncached address. */ +#define SOF_MEM_FLAG_COHERENT BIT(4) +/** \brief Allocate L3 address. */ +#define SOF_MEM_FLAG_L3 BIT(5) +/** \brief Allocate Low power memory address. */ +#define SOF_MEM_FLAG_LOW_POWER BIT(6) +/** \brief Allocate kernel memory address. */ +#define SOF_MEM_FLAG_KERNEL BIT(7) +/** \brief Allocate user memory address. */ +#define SOF_MEM_FLAG_USER BIT(8) +/** \brief Allocate shared user memory address. */ +#define SOF_MEM_FLAG_USER_SHARED_BUFFER BIT(9) +/** \brief Use allocation method for large buffers. */ +#define SOF_MEM_FLAG_LARGE_BUFFER BIT(10) /** @} */ /** * 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 flags Flags, see SOF_MEM_FLAG_.... * @param bytes Size in bytes. + * @param alignment Alignment 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); +void *rmalloc_align(uint32_t flags, size_t bytes, uint32_t alignment); + +/** + * Similar to rmalloc_align(), but no alignment can be specified. + */ +void *rmalloc(uint32_t flags, 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); +void *rzalloc(uint32_t flags, size_t bytes); /** - * Allocates memory block from SOF_MEM_ZONE_BUFFER. + * Allocates memory block. * @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, +void *rballoc_align(uint32_t flags, 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) +static inline void *rballoc(uint32_t flags, size_t bytes) { - return rballoc_align(flags, caps, bytes, PLATFORM_DCACHE_ALIGN); + return rballoc_align(flags, 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. + * Frees the memory block. + * @param ptr Pointer to the memory block. */ -void *rbrealloc_align(void *ptr, uint32_t flags, uint32_t caps, size_t bytes, - size_t old_bytes, uint32_t alignment); +void rfree(void *ptr); /** - * Similar to rballoc_align(), returns resized buffer aligned to - * PLATFORM_DCACHE_ALIGN. + * Save L3 heap over DSP reset + */ +void l3_heap_save(void); + +/* + * This is ugly to define the signatures twice, but this + * is required to support userspace builds that do not export alloc. */ -static inline void *rbrealloc(void *ptr, uint32_t flags, uint32_t caps, - size_t bytes, size_t old_bytes) +#ifdef CONFIG_SOF_USERSPACE_INTERFACE_ALLOC +__syscall void *sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, + size_t alignment); +__syscall void sof_heap_free(struct k_heap *heap, void *addr); +#include <zephyr/syscalls/alloc.h> +#else +void *sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, + size_t alignment); +void sof_heap_free(struct k_heap *heap, void *addr); +#endif + +#if CONFIG_SOF_FULL_ZEPHYR_APPLICATION +struct k_heap *sof_sys_heap_get(void); +#else +/* for unit-testing */ +static inline struct k_heap *sof_sys_heap_get(void) { - return rbrealloc_align(ptr, flags, caps, bytes, old_bytes, - PLATFORM_DCACHE_ALIGN); + return NULL; } +#endif /** - * Frees the memory block. - * @param ptr Pointer to the memory block. + * Returns heap object to use for SOF heap allocations + * for audio application code. + * + * The returned value may be NULL. This matches with semantics + * of sof_heap_alloc() that allows passing NULL as the 'heap'. + * In this case, the heap implementation will choose the heap to + * use. + * + * The function should not be used for heap allocations for objects that + * are only used in SOF kernel space. * - * @note Blocks from SOF_MEM_ZONE_SYS cannot be freed, such a call causes - * panic. + * Note: audio modules should use mod_alloc() instead! */ -void rfree(void *ptr); +struct k_heap *sof_sys_user_heap_get(void); /* TODO: remove - debug only - only needed for linking */ static inline void heap_trace_all(int force) {} /** @}*/ +#if CONFIG_SOF_USERSPACE_USE_SHARED_HEAP +/** + * Returns the start address of shared memory heap for buffers. + * + * @return pointer to shared memory heap start + */ +uintptr_t get_shared_buffer_heap_start(void); + +/** + * Returns the size of shared memory heap for buffers. + * + * @return size of shared memory heap start + */ +size_t get_shared_buffer_heap_size(void); + +#endif + +#include <sof/lib/vregion.h> + +struct mod_alloc_ctx { + struct k_heap *heap; + struct vregion *vreg; +}; + +/** + * Allocate memory from a mod_alloc_ctx context. + * + * When the context has a vregion, allocates from the vregion interim + * partition. Coherent memory is used when SOF_MEM_FLAG_COHERENT is set + * in flags. Falls back to sof_heap_alloc() otherwise. + * + * @param ctx Allocation context (heap + optional vregion). + * @param flags Allocation flags (SOF_MEM_FLAG_*). + * @param size Size in bytes. + * @param alignment Required alignment in bytes. + * @return Pointer to allocated memory or NULL on failure. + */ +static inline void *sof_ctx_alloc(struct mod_alloc_ctx *ctx, uint32_t flags, + size_t size, size_t alignment) +{ + if (!ctx || !ctx->vreg) + return sof_heap_alloc(ctx ? ctx->heap : NULL, flags, size, alignment); + + if (flags & SOF_MEM_FLAG_COHERENT) + return vregion_alloc_coherent_align(ctx->vreg, size, alignment); + + return vregion_alloc_align(ctx->vreg, size, alignment); +} + +/** + * Allocate zero-initialized memory from a mod_alloc_ctx context. + * @param ctx Allocation context. + * @param flags Allocation flags (SOF_MEM_FLAG_*). + * @param size Size in bytes. + * @param alignment Required alignment in bytes. + * @return Pointer to allocated memory or NULL on failure. + */ +static inline void *sof_ctx_zalloc(struct mod_alloc_ctx *ctx, uint32_t flags, + size_t size, size_t alignment) +{ + void *ptr = sof_ctx_alloc(ctx, flags, size, alignment); + + if (ptr) + memset(ptr, 0, size); + + return ptr; +} + +/** + * Free memory allocated from a mod_alloc_ctx context. + * @param ctx Allocation context. + * @param ptr Pointer to free. + */ +static inline void sof_ctx_free(struct mod_alloc_ctx *ctx, void *ptr) +{ + if (!ptr) + return; + + if (ctx && ctx->vreg) + vregion_free(ctx->vreg, ptr); + else + sof_heap_free(ctx ? ctx->heap : NULL, ptr); +} + #endif /* __ZEPHYR_RTOS_ALLOC_H__ */ diff --git a/zephyr/include/rtos/idc.h b/zephyr/include/rtos/idc.h index 8fdfb09f3c99..a8616d9e2a11 100644 --- a/zephyr/include/rtos/idc.h +++ b/zephyr/include/rtos/idc.h @@ -34,9 +34,6 @@ /** \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 @@ -201,8 +198,6 @@ 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); int idc_init(void); diff --git a/zephyr/include/rtos/interrupt.h b/zephyr/include/rtos/interrupt.h index 101aa7e65bef..200d36e4751e 100644 --- a/zephyr/include/rtos/interrupt.h +++ b/zephyr/include/rtos/interrupt.h @@ -11,7 +11,7 @@ /* TODO: to be removed completely when the following platforms are switched * to native drivers. */ -#if defined(CONFIG_AMD) +#if defined(CONFIG_AMD) && !defined(CONFIG_ZEPHYR_NATIVE_DRIVERS) /* imx currently has no IRQ driver in Zephyr so we force to xtos IRQ */ #include "../../../xtos/include/rtos/interrupt.h" #else @@ -86,6 +86,6 @@ static inline void platform_interrupt_init(void) {} #define irq_local_enable(flags) \ arch_irq_unlock(flags) -#endif /* IMX */ +#endif /* CONFIG_AMD && !CONFIG_ZEPHYR_NATIVE_DRIVERS */ #endif /* __ZEPHYR_RTOS_INTERRUPT_H__ */ diff --git a/zephyr/include/rtos/kernel.h b/zephyr/include/rtos/kernel.h index 17d388cbf8e8..328fc96d2eaa 100644 --- a/zephyr/include/rtos/kernel.h +++ b/zephyr/include/rtos/kernel.h @@ -8,4 +8,11 @@ #include <zephyr/kernel.h> +#include <stdbool.h> + +static inline bool thread_is_userspace(struct k_thread *thread) +{ + return !!(thread->base.user_options & K_USER); +} + #endif /* __ZEPHYR_RTOS_KERNEL_H__ */ diff --git a/zephyr/include/rtos/mutex.h b/zephyr/include/rtos/mutex.h index 9f26c7a86d75..a8886f768d1e 100644 --- a/zephyr/include/rtos/mutex.h +++ b/zephyr/include/rtos/mutex.h @@ -7,5 +7,6 @@ #define __ZEPHYR_RTOS_MUTEX_H__ #include <zephyr/kernel.h> /* k_mutex_*() */ +#include <zephyr/sys/mutex.h> /* for sys_mutex */ #endif /* __ZEPHYR_RTOS_MUTEX_H__ */ diff --git a/zephyr/include/rtos/sof.h b/zephyr/include/rtos/sof.h index 1de60c5cd6ff..573e6ac63d77 100644 --- a/zephyr/include/rtos/sof.h +++ b/zephyr/include/rtos/sof.h @@ -111,11 +111,6 @@ struct sof { 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); diff --git a/zephyr/include/rtos/string.h b/zephyr/include/rtos/string.h index 49c26acd17da..37bd657ff91d 100644 --- a/zephyr/include/rtos/string.h +++ b/zephyr/include/rtos/string.h @@ -69,8 +69,14 @@ static inline int memset_s(void *dest, size_t dest_size, int data, size_t count) if (count > dest_size) return -EINVAL; - if (!memset(dest, data, count)) - return -ENOMEM; + memset(dest, data, count); + /* + * Prevent compiler from optimizing away the memset. + * Memory barrier prevents dead store elimination. + */ +#if defined(CONFIG_XTENSA) + __asm__ __volatile__("memw" ::: "memory"); +#endif return 0; } diff --git a/zephyr/include/rtos/task.h b/zephyr/include/rtos/task.h index 9fcc202c1e2e..cfcba9130cef 100644 --- a/zephyr/include/rtos/task.h +++ b/zephyr/include/rtos/task.h @@ -17,6 +17,7 @@ struct comp_dev; struct sof; +struct schedule_data; /** \brief Predefined LL task priorities. */ #define SOF_TASK_PRI_HIGH 0 /* priority level 0 - high */ @@ -59,6 +60,7 @@ struct task { uint16_t priority; /**< priority of the task (used by LL) */ uint16_t core; /**< execution core */ uint16_t flags; /**< custom flags */ + struct schedule_data *sch; /**< scheduler bound to task */ enum task_state state; /**< current state */ void *data; /**< custom data passed to all ops */ struct list_item list; /**< used by schedulers to hold tasks */ diff --git a/zephyr/include/rtos/userspace_helper.h b/zephyr/include/rtos/userspace_helper.h new file mode 100644 index 000000000000..20fb7bd40876 --- /dev/null +++ b/zephyr/include/rtos/userspace_helper.h @@ -0,0 +1,173 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + * Author: Jaroslaw Stelter <jaroslaw.stelter@intel.com> + * Adrian Warecki <adrian.warecki@intel.com> + */ + +/** + * \brief Userspace support functions. + */ +#ifndef __ZEPHYR_LIB_USERSPACE_HELPER_H__ +#define __ZEPHYR_LIB_USERSPACE_HELPER_H__ + +#include <zephyr/kernel.h> + +#ifndef CONFIG_USERSPACE +#define APP_TASK_BSS +#define APP_TASK_DATA +#define APP_SYSUSER_BSS +#define APP_SYSUSER_DATA +#else +#include <zephyr/cache.h> +#include <zephyr/app_memory/app_memdomain.h> + +#define USER_MOD_HEAP_SIZE ALIGN_UP(CONFIG_SOF_ZEPHYR_USERSPACE_MODULE_HEAP_SIZE, \ + CONFIG_MM_DRV_PAGE_SIZE) +#define APP_TASK_BSS K_APP_BMEM(common_partition) +#define APP_TASK_DATA K_APP_DMEM(common_partition) + +#ifdef CONFIG_SOF_USERSPACE_LL +#define APP_SYSUSER_BSS K_APP_BMEM(sysuser_partition) +#define APP_SYSUSER_DATA K_APP_DMEM(sysuser_partition) +#else +#define APP_SYSUSER_BSS +#define APP_SYSUSER_DATA +#endif + +struct processing_module; +struct userspace_context; + +/** + * Initialize private processing module heap. + * @param N/A. + * @return pointer to the k_heap structure. + * + * @note + * Function used only when CONFIG_USERSPACE is set. + * The private heap is used only for non-privileged modules for all processing module allocations + * that should be isolated. The heap helps to accumulate all dynamic allocations in single memory + * region which is then added to modules memory domain. + */ +struct k_heap *module_driver_heap_init(void); + +/** + * Attach common userspace memory partition to a module memory domain. + * @param dom - memory domain to attach the common partition to. + * + * @return 0 for success, error otherwise. + * + * @note + * Function used only when CONFIG_USERSPACE is set. + * The common partition contains shared objects required by user-space modules. + */ +int user_memory_attach_common_partition(struct k_mem_domain *dom); + +#endif + +/** + * Allocates thread stack memory. + * @param stack_size Required stack size. + * @param options Stack configuration options + * K_USER - when creating user thread + * 0 - when creating kernel thread + * @return pointer to the stack or NULL if not created. + * + * When CONFIG_USERSPACE not set function calls rballoc_align(), + * otherwise it uses k_thread_stack_alloc() routine. + * + */ +void *user_stack_allocate(size_t stack_size, uint32_t options); + +/** + * Free thread stack memory. + * @param p_stack Pointer to the stack. + * + * @return 0 for success, error otherwise. + * + * @note + * When CONFIG_USERSPACE not set function calls rfree(), + * otherwise it uses k_thread_stack_free() routine. + * + */ +int user_stack_free(void *p_stack); + +/** + * Free private processing module heap. + * @param sys_heap pointer to the sys_heap structure. + * + * @note + * Function used only when CONFIG_USERSPACE is set. + * Frees private module heap. + */ +void module_driver_heap_remove(struct k_heap *mod_drv_heap); + +#ifdef CONFIG_USERSPACE + +/** + * Add access to mailbox.h interface to a user-space thread. + * + * @param domain memory domain to add the mailbox partitions to + * @param thread_id user-space thread for which access is added + */ +int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id); + +/** + * Derive partition attribute from the pointer. If the address is cacheable, sets the cacheable + * attribute. + * + * @param ptr Address of the partition start + */ +static inline uint32_t user_get_partition_cache_attr(uintptr_t ptr) +{ + return sys_cache_is_ptr_cached(UINT_TO_POINTER(ptr)) ? XTENSA_MMU_CACHED_WB : 0; +} + +/** + * Grant DAI device access to a user-space thread. + * + * @param thread user-space thread for which DAI access is granted + */ +void user_grant_dai_access_all(struct k_thread *thread); + +/** + * Grant DMA device access to a user-space thread. + * + * @param thread user-space thread for which DMA access is granted + */ +void user_grant_dma_access_all(struct k_thread *thread); + +#else + +static inline int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id) +{ + return 0; +} + +#endif /* CONFIG_USERSPACE */ + +#ifdef CONFIG_SOF_USERSPACE_LL + +int user_memory_attach_system_user_partition(struct k_mem_domain *dom); + +#else + +/** + * Attach SOF system user memory partition to a memory domain. + * @param dom - memory domain to attach the sysuser partition to. + * + * @return 0 for success, error otherwise. + * + * @note + * Function used only when CONFIG_USERSPACE is set. + * The sysuser partition contains shared objects required by user-space modules. + */ +static inline int user_memory_attach_system_user_partition(struct k_mem_domain *dom) +{ + return 0; +} + +#endif /* CONFIG_SOF_USERSPACE_LL */ + +#endif /* __ZEPHYR_LIB_USERSPACE_HELPER_H__ */ diff --git a/zephyr/include/sof/lib/dma.h b/zephyr/include/sof/lib/dma.h index e5c68f9b31c9..4408d265804f 100644 --- a/zephyr/include/sof/lib/dma.h +++ b/zephyr/include/sof/lib/dma.h @@ -33,6 +33,8 @@ #include <zephyr/drivers/dma.h> struct comp_buffer; +struct comp_dev; +struct k_heap; /** \addtogroup sof_dma_drivers DMA Drivers * SOF DMA Drivers API specification (deprecated interface, to be @@ -79,6 +81,7 @@ struct comp_buffer; #define SOF_DMA_CAP_HS_VIRTUAL BIT(7) /**< HS VIRTUAL DMA */ #define SOF_DMA_CAP_HS BIT(8) /**< HS DMA */ #define SOF_DMA_CAP_SW BIT(9) /**< SW DMA */ +#define SOF_DMA_CAP_TDM BIT(10) /**< connectable to ACP TDM I2S */ /* DMA dev type bitmasks used to define the type of DMA */ @@ -98,6 +101,7 @@ struct comp_buffer; #define SOF_DMA_DEV_HS BIT(13) /**< connectable to ACP HS I2S */ #define SOF_DMA_DEV_MICFIL BIT(14) /**< connectable to MICFIL fifo */ #define SOF_DMA_DEV_SW BIT(15) /**< connectable to ACP SW */ +#define SOF_DMA_DEV_TDM BIT(16) /**< connectable to ACP TDM I2S */ /* DMA access privilege flag */ #define SOF_DMA_ACCESS_EXCLUSIVE 1 @@ -121,7 +125,11 @@ enum sof_dma_cb_status { /* Attributes have been ported to Zephyr. This condition is necessary until full support of * CONFIG_SOF_ZEPHYR_STRICT_HEADERS. */ +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS +struct sof_dma; +#else struct dma; +#endif /** * \brief Element of SG list (as array item). @@ -193,7 +201,13 @@ struct dma_plat_data { uint32_t period_count; }; +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS +struct k_heap; +struct sof_dma { + struct k_heap *heap; +#else struct dma { +#endif struct dma_plat_data plat_data; struct k_spinlock lock; /**< locking mechanism */ int sref; /**< simple ref counter, guarded by lock */ @@ -205,7 +219,11 @@ struct dma { }; struct dma_chan_data { +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + struct sof_dma *dma; +#else struct dma *dma; +#endif uint32_t status; uint32_t direction; @@ -223,14 +241,22 @@ struct dma_chan_data { }; struct dma_info { +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + struct sof_dma *dma_array; +#else struct dma *dma_array; +#endif size_t num_dmas; }; /* generic DMA DSP <-> Host copier */ struct dma_copy { struct dma_chan_data *chan; +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + struct sof_dma *dmac; +#else struct dma *dmac; +#endif }; struct audio_stream; @@ -245,24 +271,13 @@ typedef int (*dma_process_func)(const struct audio_stream *source, */ 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 *sof_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. +/* + * Need to use sof_dma.h to avoid "syscalls/dma.h" name conflict + * with Zephyr autogenerated headers for syscall support. */ -void sof_dma_put(struct dma *dma); - -#ifndef CONFIG_ZEPHYR_NATIVE_DRIVERS +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS +#include "sof_dma.h" +#else #include "dma-legacy.h" #endif /* !CONFIG_ZEPHYR_NATIVE_DRIVERS */ @@ -281,13 +296,14 @@ static inline void dma_sg_init(struct dma_sg_elem_array *ea) ea->elems = NULL; } -int dma_sg_alloc(struct dma_sg_elem_array *ea, - enum mem_zone zone, +int dma_sg_alloc(struct k_heap *heap, + struct dma_sg_elem_array *ea, + uint32_t flags, 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); +void dma_sg_free(struct k_heap *heap, struct dma_sg_elem_array *ea); /** * \brief Get the total size of SG buffer @@ -316,7 +332,8 @@ int dma_buffer_copy_from(struct comp_buffer *source, * conversion function. DMA buffer consume should be performed after the data has been copied * to all sinks. */ -int stream_copy_from_no_consume(struct comp_buffer *source, +int stream_copy_from_no_consume(struct comp_dev *dev, + struct comp_buffer *source, struct comp_buffer *sink, dma_process_func process, uint32_t source_bytes, uint32_t chmap); diff --git a/zephyr/include/sof/lib/memory.h b/zephyr/include/sof/lib/memory.h index f58686a92981..6fa6a8ef558d 100644 --- a/zephyr/include/sof/lib/memory.h +++ b/zephyr/include/sof/lib/memory.h @@ -16,4 +16,35 @@ #define __cold_rodata #endif +#if CONFIG_COLD_STORE_EXECUTE_DEBUG +#include <rtos/panic.h> + +#ifdef __ZEPHYR__ +bool ll_sch_is_current(void); +#else +#define ll_sch_is_current() false +#endif + +void dbg_path_hot_start_watching(void); +void dbg_path_hot_stop_watching(void); +void dbg_path_hot_confirm(void); +void dbg_path_cold_enter(const char *fn); + +static inline void __assert_can_be_cold(const char *fn) +{ + if (k_is_user_context()) + return; + + __ASSERT(!ll_sch_is_current(), "%s() called from an LL thread!", fn); + dbg_path_cold_enter(fn); +} +#define assert_can_be_cold() __assert_can_be_cold(__func__) +#else +#define dbg_path_hot_start_watching() do {} while (0) +#define dbg_path_hot_stop_watching() do {} while (0) +#define dbg_path_hot_confirm() do {} while (0) +#define dbg_path_cold_enter() do {} while (0) +#define assert_can_be_cold() do {} while (0) +#endif + #endif /* __SOF_LIB_MEMORY_H__ */ diff --git a/zephyr/include/sof/lib/regions_mm.h b/zephyr/include/sof/lib/regions_mm.h index 3cc8766f4d78..abaaf158d3d4 100644 --- a/zephyr/include/sof/lib/regions_mm.h +++ b/zephyr/include/sof/lib/regions_mm.h @@ -17,6 +17,11 @@ #include <zephyr/init.h> #include <zephyr/sys/mem_blocks.h> +/* Attributes for memory regions */ +#define VIRTUAL_REGION_SHARED_HEAP_ATTR 1U /*< region for shared virtual heap */ +#define VIRTUAL_REGION_LLEXT_LIBRARIES_ATTR 2U /*< region for LLEXT libraries */ +#define VIRTUAL_REGION_VPAGES_ATTR 3U /*< region for virtual page allocator */ + /* Dependency on ipc/topology.h created due to memory capability definitions * that are defined there */ @@ -44,33 +49,6 @@ */ #define DEFAULT_CONFIG_ALOCATORS_COUNT 5 -/** @struct vmh_heap - * - * @brief This structure holds all information about virtual memory heap - * it aggregates information about its allocations and - * physical mappings. - * - * @var node generic list member used for list operations - * @var virtual_region pointer to virtual region information, it holds its - * attributes size and beginning ptr provided by zephyr. - * @var physical_blocks_allocators[] a table of block allocators - * each representing a virtual regions part in blocks of a given size - * governed by sys_mem_blocks API. - * @var allocation_sizes[] a table of bit arrays representing sizes of allocations - * made in physical_blocks_allocators directly related to physical_blocks_allocators - * @var core_id id of the core that heap was created on - * @var allocating_continuously configuration value deciding if heap allocations - * will be contiguous or single block. - */ -struct vmh_heap { - struct list_item node; - const struct sys_mm_drv_region *virtual_region; - struct sys_mem_blocks *physical_blocks_allocators[MAX_MEMORY_ALLOCATORS_COUNT]; - struct sys_bitarray *allocation_sizes[MAX_MEMORY_ALLOCATORS_COUNT]; - int core_id; - bool allocating_continuously; -}; - /** @struct vmh_block_bundle_descriptor * * @brief This is a struct describing one bundle of blocks @@ -104,16 +82,15 @@ struct vmh_heap_config { struct vmh_block_bundle_descriptor block_bundles_table[MAX_MEMORY_ALLOCATORS_COUNT]; }; -struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, - int memory_region_attribute, int core_id, bool allocating_continuously); +struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, bool allocating_continuously); void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size); int vmh_free_heap(struct vmh_heap *heap); int vmh_free(struct vmh_heap *heap, void *ptr); -struct vmh_heap *vmh_reconfigure_heap(struct vmh_heap *heap, - struct vmh_heap_config *cfg, int core_id, bool allocating_continuously); void vmh_get_default_heap_config(const struct sys_mm_drv_region *region, struct vmh_heap_config *cfg); -struct vmh_heap *vmh_get_heap_by_attribute(uint32_t attr, uint32_t core_id); +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS +void vmh_log_stats(struct vmh_heap *heap); +#endif /** * @brief Checks if ptr is in range of given memory range * diff --git a/zephyr/include/sof/lib/sof_dma.h b/zephyr/include/sof/lib/sof_dma.h new file mode 100644 index 000000000000..bdd64aeac9fa --- /dev/null +++ b/zephyr/include/sof/lib/sof_dma.h @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2025, Intel Corporation. + */ + +/* + * Need to use sof_dma.h to avoid "syscalls/dma.h" name conflict + * with Zephyr autogenerated headers for syscall support. + */ + +#ifndef SOF_DMA_H +#define SOF_DMA_H + +/** + * \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. + */ +__syscall struct sof_dma *sof_dma_get(uint32_t dir, uint32_t caps, uint32_t dev, uint32_t flags); + +struct sof_dma *z_impl_sof_dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags); + + +/** + * \brief API to release a platform DMAC. + * + * @param[in] dma DMAC to release. + */ +__syscall void sof_dma_put(struct sof_dma *dma); + +void z_impl_sof_dma_put(struct sof_dma *dma); + +__syscall int sof_dma_get_attribute(struct sof_dma *dma, uint32_t type, uint32_t *value); + +__syscall int sof_dma_request_channel(struct sof_dma *dma, uint32_t stream_tag); + +__syscall void sof_dma_release_channel(struct sof_dma *dma, + uint32_t channel); + +__syscall int sof_dma_config(struct sof_dma *dma, uint32_t channel, + struct dma_config *config); + +__syscall int sof_dma_start(struct sof_dma *dma, uint32_t channel); + +__syscall int sof_dma_stop(struct sof_dma *dma, uint32_t channel); + +__syscall int sof_dma_get_status(struct sof_dma *dma, uint32_t channel, struct dma_status *stat); + +__syscall int sof_dma_reload(struct sof_dma *dma, uint32_t channel, size_t size); + +__syscall int sof_dma_suspend(struct sof_dma *dma, uint32_t channel); + +__syscall int sof_dma_resume(struct sof_dma *dma, uint32_t channel); + +static inline int z_impl_sof_dma_get_attribute(struct sof_dma *dma, uint32_t type, uint32_t *value) +{ + return dma_get_attribute(dma->z_dev, type, value); +} + +static inline int z_impl_sof_dma_request_channel(struct sof_dma *dma, uint32_t stream_tag) +{ + return dma_request_channel(dma->z_dev, &stream_tag); +} + +static inline void z_impl_sof_dma_release_channel(struct sof_dma *dma, + uint32_t channel) +{ + dma_release_channel(dma->z_dev, channel); +} + +static inline int z_impl_sof_dma_config(struct sof_dma *dma, uint32_t channel, + struct dma_config *config) +{ + return dma_config(dma->z_dev, channel, config); +} + + +static inline int z_impl_sof_dma_start(struct sof_dma *dma, uint32_t channel) +{ + return dma_start(dma->z_dev, channel); +} + +static inline int z_impl_sof_dma_stop(struct sof_dma *dma, uint32_t channel) +{ + return dma_stop(dma->z_dev, channel); +} + +static inline int z_impl_sof_dma_get_status(struct sof_dma *dma, uint32_t channel, + struct dma_status *stat) +{ + return dma_get_status(dma->z_dev, channel, stat); +} + +static inline int z_impl_sof_dma_reload(struct sof_dma *dma, uint32_t channel, size_t size) +{ + return dma_reload(dma->z_dev, channel, 0, 0, size); +} + +static inline int z_impl_sof_dma_suspend(struct sof_dma *dma, uint32_t channel) +{ + return dma_suspend(dma->z_dev, channel); +} + +static inline int z_impl_sof_dma_resume(struct sof_dma *dma, uint32_t channel) +{ + return dma_resume(dma->z_dev, channel); +} + +#ifdef CONFIG_SOF_USERSPACE_INTERFACE_DMA + +/* include definitions from generated file */ +#include <zephyr/syscalls/sof_dma.h> + +#else /* !CONFIG_SOF_USERSPACE_INTERFACE_DMA */ + +/* + * SOF-specific mechanism to allow building SOF with user-space + * support enabled in Zephyr, but not including all syscall + * interfaces in the SOF binary. Thee downside is we cannot + * use the zephyr/syscalls/sof_dma.h boilerplate that is autogenerated + * but instead need a manual wrapper that is below here. + * + * This can be removed if DMA is used in all SOF user-space builds. + */ + +static inline struct sof_dma *sof_dma_get(uint32_t dir, uint32_t caps, uint32_t dev, uint32_t flags) +{ + return z_impl_sof_dma_get(dir, caps, dev, flags); +} + +static inline void sof_dma_put(struct sof_dma *dma) +{ + return z_impl_sof_dma_put(dma); +} + +static inline int sof_dma_get_attribute(struct sof_dma *dma, uint32_t type, uint32_t *value) +{ + return z_impl_sof_dma_get_attribute(dma, type, value); +} + +static inline int sof_dma_request_channel(struct sof_dma *dma, uint32_t stream_tag) +{ + return z_impl_sof_dma_request_channel(dma, stream_tag); +} + +static inline void sof_dma_release_channel(struct sof_dma *dma, + uint32_t channel) +{ + return z_impl_sof_dma_release_channel(dma, channel); +} + +static inline int sof_dma_config(struct sof_dma *dma, uint32_t channel, + struct dma_config *config) +{ + return z_impl_sof_dma_config(dma, channel, config); +} + +static inline int sof_dma_start(struct sof_dma *dma, uint32_t channel) +{ + return z_impl_sof_dma_start(dma, channel); +} + +static inline int sof_dma_stop(struct sof_dma *dma, uint32_t channel) +{ + return z_impl_sof_dma_stop(dma, channel); +} + +static inline int sof_dma_get_status(struct sof_dma *dma, uint32_t channel, struct dma_status *stat) +{ + return z_impl_sof_dma_get_status(dma, channel, stat); +} + +static inline int sof_dma_reload(struct sof_dma *dma, uint32_t channel, size_t size) +{ + return z_impl_sof_dma_reload(dma, channel, size); +} + +static inline int sof_dma_suspend(struct sof_dma *dma, uint32_t channel) +{ + return z_impl_sof_dma_suspend(dma, channel); +} + +static inline int sof_dma_resume(struct sof_dma *dma, uint32_t channel) +{ + return z_impl_sof_dma_resume(dma, channel); +} + +#endif /* CONFIG_SOF_USERSPACE_INTERFACE_DMA */ + +#endif diff --git a/zephyr/include/sof/lib/vpage.h b/zephyr/include/sof/lib/vpage.h new file mode 100644 index 000000000000..f3fc8b89e968 --- /dev/null +++ b/zephyr/include/sof/lib/vpage.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright(c) 2025 Intel Corporation. + +/* Virtual Page Allocator API */ +#ifndef __SOF_LIB_VPAGE_H__ +#define __SOF_LIB_VPAGE_H__ + +#include <zephyr/kernel.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Allocate virtual pages + * Allocates a specified number of contiguous virtual memory pages by mapping + * physical pages. + * + * @param[in] pages Number of pages (usually 4kB large) to allocate. + * + * @return Pointer to the allocated virtual memory region, or NULL on failure. + */ +void *vpage_alloc(unsigned int pages); + +/** + * @brief Free virtual pages + * Frees previously allocated virtual memory pages and unmaps them. + * + * @param[in] ptr Pointer to the memory pages to free. + */ +void vpage_free(void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* __SOF_LIB_VPAGE_H__ */ diff --git a/zephyr/lib/alloc.c b/zephyr/lib/alloc.c index 8bfe3155477d..0ae0b23add1c 100644 --- a/zephyr/lib/alloc.c +++ b/zephyr/lib/alloc.c @@ -9,25 +9,27 @@ #include <rtos/idc.h> #include <rtos/interrupt.h> #include <sof/drivers/interrupt-map.h> -#include <sof/lib/dma.h> #include <sof/schedule/schedule.h> #include <sof/lib/notifier.h> #include <sof/lib/pm_runtime.h> #include <sof/audio/pipeline.h> -#include <sof/audio/component_ext.h> +#include <sof/schedule/ll_schedule_domain.h> /* for zephyr_ll_user_heap() */ #include <sof/trace/trace.h> #include <rtos/symbol.h> #include <rtos/wait.h> + +#define SHARED_BUFFER_HEAP_MEM_SIZE 0 + +#if CONFIG_L3_HEAP && CONFIG_MMU +#include <kernel_arch_interface.h> +#endif + #if CONFIG_VIRTUAL_HEAP #include <sof/lib/regions_mm.h> +#include <zephyr/drivers/mm/mm_drv_intel_adsp_mtl_tlb.h> -struct vmh_heap *virtual_buffers_heap[CONFIG_MP_MAX_NUM_CPUS]; -struct k_spinlock vmh_lock; - -#undef HEAPMEM_SIZE -/* Buffers are allocated from virtual space so we can safely reduce the heap size. - */ -#define HEAPMEM_SIZE 0x40000 +struct vmh_heap; +struct vmh_heap *virtual_buffers_heap; #endif /* CONFIG_VIRTUAL_HEAP */ @@ -97,7 +99,17 @@ static uint8_t __aligned(PLATFORM_DCACHE_ALIGN) heapmem[HEAPMEM_SIZE]; * to allow memory management driver to control unused * memory pages. */ -__section(".heap_mem") static uint8_t __aligned(PLATFORM_DCACHE_ALIGN) heapmem[HEAPMEM_SIZE]; +#if CONFIG_USERSPACE +#undef SHARED_BUFFER_HEAP_MEM_SIZE +#define SHARED_BUFFER_HEAP_MEM_SIZE ROUND_UP(CONFIG_SOF_ZEPHYR_SHARED_BUFFER_HEAP_SIZE, \ + HOST_PAGE_SIZE) +#if CONFIG_SOF_USERSPACE_USE_SHARED_HEAP +__section(".shared_heap_mem") +static uint8_t __aligned(HOST_PAGE_SIZE) shared_heapmem[SHARED_BUFFER_HEAP_MEM_SIZE]; +#endif +#endif /* CONFIG_USERSPACE */ +__section(".heap_mem") +static uint8_t __aligned(HOST_PAGE_SIZE) heapmem[HEAPMEM_SIZE - SHARED_BUFFER_HEAP_MEM_SIZE]; #elif defined(CONFIG_ARCH_POSIX) @@ -108,11 +120,24 @@ char __aligned(8) heapmem[HEAPMEM_SIZE]; #elif defined(CONFIG_SOC_FAMILY_MTK) extern char _mtk_adsp_sram_end; +#if defined(CONFIG_SOC_MT8365) +#define SRAM_START DT_REG_ADDR(DT_NODELABEL(sram1)) +#define SRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sram1)) +#define heapmem ((uint8_t *)SRAM_START) +#else #define SRAM_START DT_REG_ADDR(DT_NODELABEL(sram0)) #define SRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sram0)) -#define SRAM_END (SRAM_START + SRAM_SIZE) #define heapmem ((uint8_t *)ALIGN_UP((uintptr_t)&_mtk_adsp_sram_end, PLATFORM_DCACHE_ALIGN)) +#endif /* CONFIG_SOC_MT8365 */ + +#define SRAM_END (SRAM_START + SRAM_SIZE) + +/* Heap size is limited to 0x7fffU chunk units when CONFIG_SYS_HEAP_SMALL_ONLY is set */ +#if defined(CONFIG_SYS_HEAP_SMALL_ONLY) +#define HEAPMEM_SIZE MIN(((uint8_t *)SRAM_END - heapmem), 0x7fff * 8) +#else #define HEAPMEM_SIZE ((uint8_t *)SRAM_END - heapmem) +#endif /* CONFIG_SYS_HEAP_SMALL_ONLY */ #else @@ -124,8 +149,51 @@ extern char _end[], _heap_sentry[]; static struct k_heap sof_heap; +/** + * Checks whether pointer is from a given heap memory. + * @param heap Pointer to a heap. + * @param ptr Pointer to memory being checked. + * @return True if pointer falls into heap memory region, false otherwise. + */ +static bool is_heap_pointer(const struct k_heap *heap, void *ptr) +{ + uintptr_t heap_start = + POINTER_TO_UINT(sys_cache_cached_ptr_get(heap->heap.init_mem)); + uintptr_t heap_end = heap_start + heap->heap.init_bytes; + + if (!sys_cache_is_ptr_cached(ptr)) + ptr = (__sparse_force void *)sys_cache_cached_ptr_get(ptr); + + return ((POINTER_TO_UINT(ptr) >= heap_start) && + (POINTER_TO_UINT(ptr) < heap_end)); +} + +#if CONFIG_SOF_USERSPACE_USE_SHARED_HEAP +static struct k_heap shared_buffer_heap; + +/** + * Returns the start of HPSRAM Shared memory heap. + * @return Pointer to the HPSRAM Shared memory location which can be used + * for HPSRAM Shared heap. + */ +uintptr_t get_shared_buffer_heap_start(void) +{ + return ROUND_UP(POINTER_TO_UINT(shared_heapmem), HOST_PAGE_SIZE); +} + +/** + * Returns the size of HPSRAM Shared memory heap. + * @return Size of the HPSRAM Shared memory region which can be used for HPSRAM Shared heap. + */ +size_t get_shared_buffer_heap_size(void) +{ + return ROUND_DOWN(SHARED_BUFFER_HEAP_MEM_SIZE, HOST_PAGE_SIZE); +} +#endif /* CONFIG_SOF_USERSPACE_USE_SHARED_HEAP */ + #if CONFIG_L3_HEAP static struct k_heap l3_heap; +static struct k_heap l3_heap_copy __imrdata; /** * Returns the start of L3 memory heap. @@ -155,23 +223,19 @@ static inline size_t get_l3_heap_size(void) * - IMR base address * - actual IMR heap start */ - return ROUND_DOWN(IMR_L3_HEAP_SIZE, L3_MEM_PAGE_SIZE); + size_t offset = IMR_L3_HEAP_BASE - L3_MEM_BASE_ADDR; + + return ROUND_DOWN(ace_imr_get_mem_size() - offset, L3_MEM_PAGE_SIZE); } -/** - * Checks whether pointer is from L3 heap memory range. - * @param ptr Pointer to memory being checked. - * @return True if pointer falls into L3 heap region, false otherwise. - */ -static bool is_l3_heap_pointer(void *ptr) +void l3_heap_save(void) { - uintptr_t l3_heap_start = get_l3_heap_start(); - uintptr_t l3_heap_end = l3_heap_start + get_l3_heap_size(); - - if ((POINTER_TO_UINT(ptr) >= l3_heap_start) && (POINTER_TO_UINT(ptr) < l3_heap_end)) - return true; - - return false; + l3_heap_copy = l3_heap; + LOG_DBG("L3 heap copy: %p", (void *)l3_heap_copy.heap.heap); + dcache_writeback_region((__sparse_force void __sparse_cache *)&l3_heap_copy, + sizeof(l3_heap_copy)); + dcache_writeback_region((__sparse_force void __sparse_cache *)get_l3_heap_start(), + get_l3_heap_size()); } static void *l3_heap_alloc_aligned(struct k_heap *h, size_t min_align, size_t bytes) @@ -215,15 +279,19 @@ static void l3_heap_free(struct k_heap *h, void *mem) #endif #if CONFIG_VIRTUAL_HEAP -static void *virtual_heap_alloc(struct vmh_heap *heap, uint32_t flags, uint32_t caps, size_t bytes, +static void *virtual_heap_alloc(struct vmh_heap *heap, uint32_t flags, size_t bytes, uint32_t align) { void *mem = vmh_alloc(heap, bytes); - if (!mem) + if (!mem) { +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS + vmh_log_stats(heap); +#endif return NULL; + } - assert(IS_ALIGNED(mem, align)); + assert(align == 0 || IS_ALIGNED(mem, align)); if (flags & SOF_MEM_FLAG_COHERENT) return sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *)mem); @@ -231,6 +299,8 @@ static void *virtual_heap_alloc(struct vmh_heap *heap, uint32_t flags, uint32_t return mem; } +extern int _unused_ram_start_marker; + /** * Checks whether pointer is from virtual memory range. * @param ptr Pointer to memory being checked. @@ -238,11 +308,11 @@ static void *virtual_heap_alloc(struct vmh_heap *heap, uint32_t flags, uint32_t */ static bool is_virtual_heap_pointer(void *ptr) { - uintptr_t virtual_heap_start = POINTER_TO_UINT(sys_cache_cached_ptr_get(&heapmem)) + - HEAPMEM_SIZE; + uintptr_t virtual_heap_start = + POINTER_TO_UINT(sys_cache_cached_ptr_get(&_unused_ram_start_marker)); uintptr_t virtual_heap_end = CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE; - if (!is_cached(ptr)) + if (!sys_cache_is_ptr_cached(ptr)) ptr = (__sparse_force void *)sys_cache_cached_ptr_get(ptr); return ((POINTER_TO_UINT(ptr) >= virtual_heap_start) && @@ -251,14 +321,15 @@ static bool is_virtual_heap_pointer(void *ptr) static void virtual_heap_free(void *ptr) { - struct vmh_heap *const heap = virtual_buffers_heap[cpu_get_id()]; int ret; ptr = (__sparse_force void *)sys_cache_cached_ptr_get(ptr); - ret = vmh_free(heap, ptr); - if (ret) + ret = vmh_free(virtual_buffers_heap, ptr); + if (ret) { tr_err(&zephyr_tr, "Unable to free %p! %d", ptr, ret); + k_panic(); + } } static const struct vmh_heap_config static_hp_buffers = { @@ -269,6 +340,9 @@ static const struct vmh_heap_config static_hp_buffers = { { 2048, 8}, { 4096, 11}, { 8192, 10}, +#if CONFIG_VIRTUAL_HEAP_EXTENDED + { 32768, 8}, +#endif { 65536, 3}, { 131072, 1}, { 524288, 1} /* buffer for kpb */ @@ -277,17 +351,22 @@ static const struct vmh_heap_config static_hp_buffers = { static int virtual_heap_init(void) { - int core; + int ret; - k_spinlock_init(&vmh_lock); + if (virtual_buffers_heap) + return -EEXIST; - for (core = 0; core < CONFIG_MP_MAX_NUM_CPUS; core++) { - struct vmh_heap *heap = vmh_init_heap(&static_hp_buffers, MEM_REG_ATTR_CORE_HEAP, - core, false); - if (!heap) - tr_err(&zephyr_tr, "Unable to init virtual heap for core %d!", core); + /* add a virtual memory region */ + ret = adsp_add_virtual_memory_region(adsp_mm_get_unused_l2_start_aligned(), + CONFIG_SOF_ZEPHYR_VIRTUAL_HEAP_REGION_SIZE, + VIRTUAL_REGION_SHARED_HEAP_ATTR); + if (ret) + return ret; - virtual_buffers_heap[core] = heap; + virtual_buffers_heap = vmh_init_heap(&static_hp_buffers, false); + if (!virtual_buffers_heap) { + tr_err(&zephyr_tr, "Unable to init virtual heap"); + return -ENOMEM; } return 0; @@ -297,6 +376,21 @@ SYS_INIT(virtual_heap_init, POST_KERNEL, 1); #endif /* CONFIG_VIRTUAL_HEAP */ +struct k_heap *sof_sys_heap_get(void) +{ + return &sof_heap; +} + +struct k_heap *sof_sys_user_heap_get(void) +{ +#ifdef CONFIG_SOF_USERSPACE_LL + return zephyr_ll_user_heap(); +#else + /* let sof_heap_alloc() pick */ + return NULL; +#endif +} + static void *heap_alloc_aligned(struct k_heap *h, size_t min_align, size_t bytes) { k_spinlock_key_t key; @@ -305,6 +399,20 @@ static void *heap_alloc_aligned(struct k_heap *h, size_t min_align, size_t bytes struct sys_memory_stats stats; #endif + /* + * Zephyr sys_heap stores metadata at start of each + * heap allocation. To ensure no allocated cached buffer + * overlaps the same cacheline with the metadata chunk, + * align both allocation start and size of allocation + * to cacheline. As cached and non-cached allocations are + * mixed, same rules need to be followed for both type of + * allocations. + */ +#ifdef CONFIG_SOF_ZEPHYR_HEAP_CACHED + min_align = MAX(PLATFORM_DCACHE_ALIGN, min_align); + bytes = ALIGN_UP(bytes, PLATFORM_DCACHE_ALIGN); +#endif + key = k_spin_lock(&h->lock); ret = sys_heap_aligned_alloc(&h->heap, min_align, bytes); k_spin_unlock(&h->lock, key); @@ -323,20 +431,6 @@ static void __sparse_cache *heap_alloc_aligned_cached(struct k_heap *h, { void __sparse_cache *ptr; - /* - * Zephyr sys_heap stores metadata at start of each - * heap allocation. To ensure no allocated cached buffer - * overlaps the same cacheline with the metadata chunk, - * align both allocation start and size of allocation - * to cacheline. As cached and non-cached allocations are - * mixed, same rules need to be followed for both type of - * allocations. - */ -#ifdef CONFIG_SOF_ZEPHYR_HEAP_CACHED - min_align = MAX(PLATFORM_DCACHE_ALIGN, min_align); - bytes = ALIGN_UP(bytes, min_align); -#endif - ptr = (__sparse_force void __sparse_cache *)heap_alloc_aligned(h, min_align, bytes); #ifdef CONFIG_SOF_ZEPHYR_HEAP_CACHED @@ -353,7 +447,7 @@ static void heap_free(struct k_heap *h, void *mem) #ifdef CONFIG_SOF_ZEPHYR_HEAP_CACHED void *mem_uncached; - if (is_cached(mem)) { + if (sys_cache_is_ptr_cached(mem)) { mem_uncached = sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *)mem); sys_cache_data_flush_and_invd_range(mem, sys_heap_usable_size(&h->heap, mem_uncached)); @@ -367,76 +461,58 @@ static void heap_free(struct k_heap *h, void *mem) k_spin_unlock(&h->lock, key); } -static inline bool zone_is_cached(enum mem_zone zone) -{ -#ifdef CONFIG_SOF_ZEPHYR_HEAP_CACHED - switch (zone) { - case SOF_MEM_ZONE_SYS: - case SOF_MEM_ZONE_SYS_RUNTIME: - case SOF_MEM_ZONE_RUNTIME: - case SOF_MEM_ZONE_BUFFER: - return true; - default: - break; - } -#endif - - return false; -} -void *rmalloc(enum mem_zone zone, uint32_t flags, uint32_t caps, size_t bytes) +void *rmalloc_align(uint32_t flags, size_t bytes, uint32_t alignment) { void *ptr; struct k_heap *heap; /* choose a heap */ - if (caps & SOF_MEM_CAPS_L3) { + if (flags & SOF_MEM_FLAG_L3) { #if CONFIG_L3_HEAP heap = &l3_heap; - /* Uncached L3_HEAP should be not used */ - if (!zone_is_cached(zone)) { - tr_err(&zephyr_tr, "L3_HEAP available for cached zones only!"); + /* Uncached L3_HEAP should not be used */ + if (flags & SOF_MEM_FLAG_COHERENT) { + tr_err(&zephyr_tr, "L3_HEAP available for cached addresses only!"); return NULL; } - ptr = (__sparse_force void *)l3_heap_alloc_aligned(heap, 0, bytes); - - if (!ptr && zone == SOF_MEM_ZONE_SYS) - k_panic(); + ptr = (__sparse_force void *)l3_heap_alloc_aligned(heap, alignment, bytes); return ptr; #else k_panic(); +#endif +#if CONFIG_SOF_USERSPACE_USE_SHARED_HEAP + } else if (flags & SOF_MEM_FLAG_USER_SHARED_BUFFER) { + heap = &shared_buffer_heap; #endif } else { heap = &sof_heap; } - if (zone_is_cached(zone) && !(flags & SOF_MEM_FLAG_COHERENT)) { - ptr = (__sparse_force void *)heap_alloc_aligned_cached(heap, 0, bytes); + if (!(flags & SOF_MEM_FLAG_COHERENT)) { + ptr = (__sparse_force void *)heap_alloc_aligned_cached(heap, alignment, bytes); } else { - /* - * XTOS alloc implementation has used dcache alignment, - * so SOF application code is expecting this behaviour. - */ - ptr = heap_alloc_aligned(heap, PLATFORM_DCACHE_ALIGN, bytes); + ptr = heap_alloc_aligned(heap, alignment, bytes); } - if (!ptr && zone == SOF_MEM_ZONE_SYS) - k_panic(); - return ptr; } +EXPORT_SYMBOL(rmalloc_align); + +void *rmalloc(uint32_t flags, size_t bytes) +{ + return rmalloc_align(flags, bytes, 0); +} EXPORT_SYMBOL(rmalloc); -/* Use SOF_MEM_ZONE_BUFFER at the moment */ -void *rbrealloc_align(void *ptr, uint32_t flags, uint32_t caps, size_t bytes, +void *rbrealloc_align(void *ptr, uint32_t flags, size_t bytes, size_t old_bytes, uint32_t alignment) { void *new_ptr; if (!ptr) { - /* TODO: Use correct zone */ - return rballoc_align(flags, caps, bytes, alignment); + return rballoc_align(flags, bytes, alignment); } /* Original version returns NULL without freeing this memory */ @@ -446,7 +522,7 @@ void *rbrealloc_align(void *ptr, uint32_t flags, uint32_t caps, size_t bytes, return NULL; } - new_ptr = rballoc_align(flags, caps, bytes, alignment); + new_ptr = rballoc_align(flags, bytes, alignment); if (!new_ptr) return NULL; @@ -462,13 +538,10 @@ void *rbrealloc_align(void *ptr, 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) +void *rzalloc(uint32_t flags, size_t bytes) { - void *ptr = rmalloc(zone, flags, caps, bytes); + void *ptr = rmalloc(flags, bytes); if (ptr) memset(ptr, 0, bytes); @@ -478,23 +551,18 @@ void *rzalloc(enum mem_zone zone, uint32_t flags, uint32_t caps, size_t bytes) EXPORT_SYMBOL(rzalloc); /** - * Allocates memory block from SOF_MEM_ZONE_BUFFER. + * Allocates memory block. * @param flags see SOF_MEM_FLAG_... - * @param caps Capabilities, see SOF_MEM_CAPS_... * @param bytes Size in bytes. * @param align 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 align) +void *rballoc_align(uint32_t flags, size_t bytes, uint32_t align) { -#if CONFIG_VIRTUAL_HEAP - struct vmh_heap *virtual_heap; -#endif struct k_heap *heap; /* choose a heap */ - if (caps & SOF_MEM_CAPS_L3) { + if (flags & SOF_MEM_FLAG_L3) { #if CONFIG_L3_HEAP heap = &l3_heap; return (__sparse_force void *)l3_heap_alloc_aligned(heap, align, bytes); @@ -502,17 +570,20 @@ void *rballoc_align(uint32_t flags, uint32_t caps, size_t bytes, tr_err(&zephyr_tr, "L3_HEAP not available."); return NULL; #endif +#if CONFIG_SOF_USERSPACE_USE_SHARED_HEAP + } else if (flags & SOF_MEM_FLAG_USER_SHARED_BUFFER) { + heap = &shared_buffer_heap; +#endif /* CONFIG_USERSPACE */ } else { - heap = &sof_heap; - } - #if CONFIG_VIRTUAL_HEAP - /* Use virtual heap if it is available */ - virtual_heap = virtual_buffers_heap[cpu_get_id()]; - if (virtual_heap) - return virtual_heap_alloc(virtual_heap, flags, caps, bytes, align); + /* Use virtual heap if it is available */ + if (virtual_buffers_heap) + return virtual_heap_alloc(virtual_buffers_heap, flags, bytes, align); #endif /* CONFIG_VIRTUAL_HEAP */ + heap = &sof_heap; + } + if (flags & SOF_MEM_FLAG_COHERENT) return heap_alloc_aligned(heap, align, bytes); @@ -529,7 +600,7 @@ void rfree(void *ptr) return; #if CONFIG_L3_HEAP - if (is_l3_heap_pointer(ptr)) { + if (is_heap_pointer(&l3_heap, ptr)) { l3_heap_free(&l3_heap, ptr); return; } @@ -542,16 +613,109 @@ void rfree(void *ptr) } #endif +#if CONFIG_SOF_USERSPACE_USE_SHARED_HEAP + if (is_heap_pointer(&shared_buffer_heap, ptr)) { + heap_free(&shared_buffer_heap, ptr); + return; + } +#endif + heap_free(&sof_heap, ptr); } EXPORT_SYMBOL(rfree); +/* + * To match the fall-back SOF main heap all private heaps should also be in the + * uncached address range. + */ +void *z_impl_sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, + size_t alignment) +{ +#if CONFIG_SOF_USERSPACE_USE_SHARED_HEAP + /* + * FLAG_USER_SHARED_BUFFER maps to a specific heap, so + * the passed 'heap' can be ignored + */ + if (flags & SOF_MEM_FLAG_USER_SHARED_BUFFER) + return rballoc_align(flags, bytes, alignment); +#endif + + if (!heap) { + /* + * Ensure virtual heap is utilized for large buffers + * if no heap is explicitly passed. rballoc_align() + * has this logic. + */ + if (flags & SOF_MEM_FLAG_LARGE_BUFFER) + return rballoc_align(flags, bytes, alignment); + + heap = &sof_heap; + } + + if (flags & SOF_MEM_FLAG_COHERENT) + return heap_alloc_aligned(heap, alignment, bytes); + + return (__sparse_force void *)heap_alloc_aligned_cached(heap, alignment, bytes); +} + +void z_impl_sof_heap_free(struct k_heap *heap, void *addr) +{ + if (heap && addr && is_heap_pointer(heap, addr)) + heap_free(heap, addr); + else + rfree(addr); +} + +#ifndef CONFIG_SOF_USERSPACE_INTERFACE_ALLOC + +/* + * Putting these as inlines in alloc.h breaks Zephyr native + * ztests like sof/test/ztest/unit/fast-get that include rtos/alloc.h + * but do not link lib/alloc.c . To to keep the tests happy, + * implement the functions here. + */ + +void *sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, + size_t alignment) +{ + return z_impl_sof_heap_alloc(heap, flags, bytes, alignment); +} + +void sof_heap_free(struct k_heap *heap, void *addr) +{ + return z_impl_sof_heap_free(heap, addr); +} + +#endif /* CONFIG_SOF_USERSPACE_INTERFACE_ALLOC */ + static int heap_init(void) { - sys_heap_init(&sof_heap.heap, heapmem, HEAPMEM_SIZE); + sys_heap_init(&sof_heap.heap, heapmem, HEAPMEM_SIZE - SHARED_BUFFER_HEAP_MEM_SIZE); + +#if CONFIG_SOF_USERSPACE_USE_SHARED_HEAP + shared_buffer_heap.heap.init_mem = shared_heapmem; + shared_buffer_heap.heap.init_bytes = SHARED_BUFFER_HEAP_MEM_SIZE; + sys_heap_init(&shared_buffer_heap.heap, shared_heapmem, SHARED_BUFFER_HEAP_MEM_SIZE); +#endif #if CONFIG_L3_HEAP - sys_heap_init(&l3_heap.heap, UINT_TO_POINTER(get_l3_heap_start()), get_l3_heap_size()); + if (ace_imr_used()) { + void *l3_heap_start = UINT_TO_POINTER(get_l3_heap_start()); + size_t l3_heap_size = get_l3_heap_size(); +#if CONFIG_MMU + void *cached_ptr = sys_cache_cached_ptr_get(l3_heap_start); + uintptr_t va = POINTER_TO_UINT(cached_ptr); + + arch_mem_map(l3_heap_start, va, l3_heap_size, K_MEM_PERM_RW | K_MEM_CACHE_WB); +#endif + if (l3_heap_copy.heap.heap) { + l3_heap = l3_heap_copy; + } else { + l3_heap.heap.init_mem = l3_heap_start; + l3_heap.heap.init_bytes = l3_heap_size; + sys_heap_init(&l3_heap.heap, l3_heap_start, l3_heap_size); + } + } #endif return 0; diff --git a/zephyr/lib/cpu.c b/zephyr/lib/cpu.c index 79946cc039f1..94f004bd7356 100644 --- a/zephyr/lib/cpu.c +++ b/zephyr/lib/cpu.c @@ -11,6 +11,12 @@ */ #include <sof/audio/component.h> +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include <sof/audio/mic_privacy_manager.h> +#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE +static uint32_t mic_disable_status; +#endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */ +#endif /* CONFIG_INTEL_ADSP_MIC_PRIVACY */ #include <sof/init.h> #include <sof/lib/cpu.h> #include <sof/lib/pm_runtime.h> @@ -64,6 +70,7 @@ extern void *global_imr_ram_storage; * data integrity across D3 transitions, which is critical for SOF's operation * and currently outside the scope of Zephyr's device-level PM capabilities. */ + static void suspend_dais(void) { struct ipc_comp_dev *icd; @@ -79,6 +86,10 @@ static void suspend_dais(void) mod = comp_mod(icd->cd); cd = module_get_private_data(mod); +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + if (cd->mic_priv && mic_privacy_manager_get_policy() == MIC_PRIVACY_FW_MANAGED) + mic_disable_status = mic_privacy_get_mic_disable_status(); +#endif dd = cd->dd[0]; if (dai_remove(dd->dai->dev) < 0) { tr_err(&zephyr_tr, "DAI suspend failed, type %d index %d", @@ -94,6 +105,12 @@ static void resume_dais(void) struct processing_module *mod; struct copier_data *cd; struct dai_data *dd; + size_t gtw_cfg_size; + +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + /* Re-initialize mic privacy manager first to ensure proper state before DAI resume */ + mic_privacy_manager_init(); +#endif list_for_item(clist, &ipc_get()->comp_list) { icd = container_of(clist, struct ipc_comp_dev, list); @@ -103,10 +120,39 @@ static void resume_dais(void) mod = comp_mod(icd->cd); cd = module_get_private_data(mod); dd = cd->dd[0]; + /* gtw_cfg.config_length is in words */ + gtw_cfg_size = cd->config.gtw_cfg.config_length << 2; if (dai_probe(dd->dai->dev) < 0) { - tr_err(&zephyr_tr, "DAI resume failed, type %d index %d", + tr_err(&zephyr_tr, "DAI resume failed on probe, type %d index %d", + dd->dai->type, dd->dai->index); + } else if (dai_set_config(dd->dai, &dd->ipc_config, cd->config.gtw_cfg.config_data, + gtw_cfg_size) < 0) { + tr_err(&zephyr_tr, "DAI resume failed on config, type %d index %d", dd->dai->type, dd->dai->index); } + +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + if (cd->mic_priv && mic_privacy_manager_get_policy() == MIC_PRIVACY_FW_MANAGED) { + uint32_t current_mic_status = mic_privacy_get_mic_disable_status(); + + if (mic_disable_status != current_mic_status) { + tr_dbg(&zephyr_tr, "MIC privacy settings cheange after D3"); + struct mic_privacy_settings settings; + + /* Update privacy settings based on new state */ + mic_privacy_fill_settings(&settings, current_mic_status); + mic_privacy_propagate_settings(&settings); + /* Ensure we're starting from a clean state with no fade effects */ + if (cd->mic_priv->mic_privacy_state) { + /* Force immediate mute without fade effect */ + cd->mic_priv->mic_privacy_state = MIC_PRIV_MUTED; + cd->mic_priv->fade_in_out_bytes = 0; + cd->mic_priv->mic_priv_gain_params.gain_env = 0; + cd->mic_priv->mic_priv_gain_params.fade_in_sg_count = 0; + } + } + } +#endif } } #endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */ @@ -134,7 +180,7 @@ void cpu_notify_state_entry(enum pm_state state) storage_buffer_size += LP_SRAM_SIZE; /* allocate IMR buffer and store it in the global pointer */ - global_imr_ram_storage = rballoc_align(0, SOF_MEM_CAPS_L3, + global_imr_ram_storage = rballoc_align(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_L3, storage_buffer_size, PLATFORM_DCACHE_ALIGN); @@ -172,7 +218,12 @@ void cpu_notify_state_exit(enum pm_state state) global_imr_ram_storage = NULL; /* send FW Ready message */ - platform_boot_complete(0); + int ret = platform_boot_complete(0); + + if (ret) { + tr_err(&zephyr_tr, "platform_boot_complete failed: %d", ret); + k_panic(); + } #endif } } diff --git a/zephyr/lib/dma.c b/zephyr/lib/dma.c index 159e8446fd25..1e28d7215026 100644 --- a/zephyr/lib/dma.c +++ b/zephyr/lib/dma.c @@ -15,12 +15,13 @@ #include <sof/lib/memory.h> #include <rtos/sof.h> #include <rtos/spinlock.h> +#include <rtos/userspace_helper.h> #include <zephyr/device.h> #define DW_DMA_BUFFER_PERIOD_COUNT 0x4 #define HDA_DMA_BUFFER_PERIOD_COUNT 4 -SHARED_DATA struct dma dma[] = { +APP_SYSUSER_DATA SHARED_DATA struct sof_dma dma[] = { #if DT_NODE_HAS_STATUS(DT_NODELABEL(lpgpdma0), okay) { /* Low Power GP DMAC 0 */ .plat_data = { @@ -78,12 +79,13 @@ SHARED_DATA struct dma dma[] = { .plat_data = { .dir = SOF_DMA_DIR_DEV_TO_MEM, .caps = SOF_DMA_CAP_HDA, -#if defined(CONFIG_SOC_INTEL_ACE20_LNL) || defined(CONFIG_SOC_INTEL_ACE30) +#if defined(CONFIG_SOC_ACE20_LNL) || defined(CONFIG_SOC_ACE30) || \ + defined(CONFIG_SOC_ACE40) .devs = SOF_DMA_DEV_HDA | SOF_DMA_DEV_SSP | SOF_DMA_DEV_DMIC | SOF_DMA_DEV_ALH, #else .devs = SOF_DMA_DEV_HDA, -#endif /* CONFIG_SOC_INTEL_ACE20_LNL || CONFIG_SOC_INTEL_ACE30 */ +#endif /* CONFIG_SOC_ACE20_LNL || CONFIG_SOC_ACE30 || CONFIG_SOC_ACE40 */ .channels = DT_PROP(DT_NODELABEL(hda_link_in), dma_channels), .period_count = HDA_DMA_BUFFER_PERIOD_COUNT, }, @@ -95,12 +97,13 @@ SHARED_DATA struct dma dma[] = { .plat_data = { .dir = SOF_DMA_DIR_MEM_TO_DEV, .caps = SOF_DMA_CAP_HDA, -#if defined(CONFIG_SOC_INTEL_ACE20_LNL) || defined(CONFIG_SOC_INTEL_ACE30) +#if defined(CONFIG_SOC_ACE20_LNL) || defined(CONFIG_SOC_ACE30) || \ + defined(CONFIG_SOC_ACE40) .devs = SOF_DMA_DEV_HDA | SOF_DMA_DEV_SSP | SOF_DMA_DEV_DMIC | SOF_DMA_DEV_ALH, #else .devs = SOF_DMA_DEV_HDA, -#endif /* CONFIG_SOC_INTEL_ACE20_LNL || CONFIG_SOC_INTEL_ACE30 */ +#endif /* CONFIG_SOC_ACE20_LNL || CONFIG_SOC_ACE30 || CONFIG_SOC_ACE40 */ .channels = DT_PROP(DT_NODELABEL(hda_link_out), dma_channels), .period_count = HDA_DMA_BUFFER_PERIOD_COUNT, }, @@ -150,7 +153,7 @@ SHARED_DATA struct dma dma[] = { .z_dev = DEVICE_DT_GET(DT_NODELABEL(host_dma)), }, #endif -#if defined(CONFIG_SOC_MIMX8ML8_ADSP) +#if defined(CONFIG_SOC_MIMX8ML8_ADSP) || defined(CONFIG_SOC_MIMX8ML8_M7) { .plat_data = { .dir = SOF_DMA_DIR_MEM_TO_DEV | SOF_DMA_DIR_DEV_TO_MEM, @@ -210,6 +213,73 @@ SHARED_DATA struct dma dma[] = { .z_dev = DEVICE_DT_GET(DT_NODELABEL(host_dma)), }, #endif /* CONFIG_SOC_MIMX9596_M7 */ +#if defined(CONFIG_SOC_ACP_7_0) || defined(CONFIG_SOC_ACP_7_X) +{ + .plat_data = { + .dir = SOF_DMA_DIR_LMEM_TO_HMEM | + SOF_DMA_DIR_HMEM_TO_LMEM, + .devs = SOF_DMA_DEV_HOST, + .base = DMA0_BASE, + .chan_size = DMA0_SIZE, + .channels = 8, + .period_count = 2, + }, + .z_dev = DEVICE_DT_GET(DT_NODELABEL(acp_host_dma)), +}, +{ + .plat_data = { + .dir = SOF_DMA_DIR_MEM_TO_DEV | + SOF_DMA_DIR_DEV_TO_MEM, + .devs = SOF_DMA_DEV_SW, + .caps = SOF_DMA_CAP_SW, + .base = DMA0_BASE, + .chan_size = DMA0_SIZE, + .channels = DT_PROP(DT_NODELABEL(acp_sdw_dma), dma_channels), + .period_count = 2, + }, + .z_dev = DEVICE_DT_GET(DT_NODELABEL(acp_sdw_dma)), +}, +{ + .plat_data = { + .dir = SOF_DMA_DIR_MEM_TO_DEV | + SOF_DMA_DIR_DEV_TO_MEM, +#if defined(CONFIG_SOC_ACP_7_X) + .devs = SOF_DMA_DEV_TDM, + .caps = SOF_DMA_CAP_TDM, +#elif defined(CONFIG_SOC_ACP_7_0) + .devs = SOF_DMA_DEV_HS | SOF_DMA_DEV_SP | SOF_DMA_DEV_BT, + .caps = SOF_DMA_CAP_HS | SOF_DMA_CAP_SP | SOF_DMA_CAP_BT, +#endif + .base = DMA0_BASE, + .chan_size = DMA0_SIZE, + .channels = 6, + .period_count = 2, + }, + .z_dev = DEVICE_DT_GET(DT_NODELABEL(acp_tdm_dma)), +}, +#endif +#if DT_HAS_COMPAT_STATUS_OKAY(mediatek_afe_memif_dma) +{ + .plat_data = { + .dir = SOF_DMA_DIR_MEM_TO_DEV | SOF_DMA_DIR_DEV_TO_MEM, + .devs = SOF_DMA_DEV_AFE_MEMIF, + .channels = DT_PROP(DT_NODELABEL(afe_memif_dma), dma_channels), + .period_count = 4, + }, + .z_dev = DEVICE_DT_GET(DT_NODELABEL(afe_memif_dma)), +}, +#endif +#if DT_HAS_COMPAT_STATUS_OKAY(mediatek_sof_host_dma) +{ + .plat_data = { + .dir = SOF_DMA_DIR_HMEM_TO_LMEM | SOF_DMA_DIR_LMEM_TO_HMEM, + .devs = SOF_DMA_DEV_HOST, + .channels = DT_PROP(DT_NODELABEL(host_dma), dma_channels), + .period_count = 4, + }, + .z_dev = DEVICE_DT_GET(DT_NODELABEL(host_dma)), +}, +#endif }; const struct dma_info lib_dma = { @@ -218,10 +288,12 @@ const struct dma_info lib_dma = { }; /* Initialize all platform DMAC's */ -int dmac_init(struct sof *sof) +__cold int dmac_init(struct sof *sof) { int i; + assert_can_be_cold(); + sof->dma_info = &lib_dma; /* early lock initialization for ref counting */ diff --git a/zephyr/lib/fast-get.c b/zephyr/lib/fast-get.c new file mode 100644 index 000000000000..cb0a2cfb07c7 --- /dev/null +++ b/zephyr/lib/fast-get.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Intel Corporation. All rights reserved. +// +// Author: Jyri Sarha <jyri.sarha@linux.intel.com> + +#include <stdbool.h> +#include <stdint.h> +#include <errno.h> + +#include <sof/audio/component.h> +#include <sof/lib/fast-get.h> +#include <sof/lib/vregion.h> +#include <sof/objpool.h> +#include <rtos/alloc.h> +#include <rtos/cache.h> +#include <rtos/kernel.h> +#include <rtos/spinlock.h> +#include <rtos/symbol.h> +#include <ipc/topology.h> + +#ifdef __ZEPHYR__ +#include <zephyr/logging/log.h> +#else +#define LOG_DBG(...) do {} while (0) +#define LOG_INF(...) do {} while (0) +#define LOG_WRN(...) do {} while (0) +#define LOG_ERR(...) do {} while (0) +#endif + +struct sof_fast_get_entry { + const void *dram_ptr; + void *sram_ptr; + size_t size; + unsigned int refcount; +}; + +struct sof_fast_get_data { + struct k_spinlock lock; + struct objpool_head pool; +}; + +static struct sof_fast_get_data fast_get_data = { + .pool.list = LIST_INIT(fast_get_data.pool.list), +}; + +LOG_MODULE_REGISTER(fast_get, CONFIG_SOF_LOG_LEVEL); + +struct fast_get_find { + const void *ptr; + struct sof_fast_get_entry *entry; +}; + +static bool fast_get_find_entry(void *data, void *arg) +{ + struct sof_fast_get_entry *entry = data; + struct fast_get_find *find = arg; + + if (find->ptr != entry->dram_ptr) + return false; + + find->entry = entry; + return true; +} + +#if CONFIG_MM_DRV +#define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE +#define FAST_GET_MAX_COPY_SIZE (PAGE_SZ / 2) +#else +#include <sof/platform.h> +#define PAGE_SZ HOST_PAGE_SIZE +#define FAST_GET_MAX_COPY_SIZE 0 +#endif + +#if CONFIG_USERSPACE +static bool fast_get_partition_exists(struct k_mem_domain *domain, void *start, size_t size) +{ + for (unsigned int i = 0; i < domain->num_partitions; i++) { + struct k_mem_partition *dpart = &domain->partitions[i]; + + if (dpart->start == (uintptr_t)start && dpart->size == size) + return true; + } + + return false; +} + +static int fast_get_access_grant(struct k_mem_domain *mdom, void *addr, size_t size) +{ + struct k_mem_partition part = { + .start = (uintptr_t)addr, + .size = ALIGN_UP(size, CONFIG_MM_DRV_PAGE_SIZE), + .attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB, + }; + + LOG_DBG("add %#zx @ %p", part.size, addr); + return k_mem_domain_add_partition(mdom, &part); +} +#endif /* CONFIG_USERSPACE */ + +const void *fast_get(struct mod_alloc_ctx *alloc, const void *dram_ptr, size_t size) +{ + struct k_heap *heap = alloc ? alloc->heap : NULL; +#if CONFIG_USERSPACE + bool current_is_userspace = thread_is_userspace(k_current_get()); +#endif + struct sof_fast_get_data *data = &fast_get_data; + uint32_t alloc_flags = SOF_MEM_FLAG_USER; + struct sof_fast_get_entry *entry; + size_t alloc_size, alloc_align; + const void *alloc_ptr; + k_spinlock_key_t key; + void *ret; + + key = k_spin_lock(&data->lock); + if (IS_ENABLED(CONFIG_USERSPACE) && size > FAST_GET_MAX_COPY_SIZE) { + alloc_size = ALIGN_UP(size, PAGE_SZ); + alloc_align = PAGE_SZ; + alloc_flags |= SOF_MEM_FLAG_LARGE_BUFFER; + } else { + alloc_size = size; + alloc_align = PLATFORM_DCACHE_ALIGN; + } + + /* The module driver heap is shared by all instances of a given module. + * Instances can share the allocated buffer. + */ + if (size > FAST_GET_MAX_COPY_SIZE || !IS_ENABLED(CONFIG_USERSPACE) || + IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP)) + alloc_ptr = dram_ptr; + else + /* When userspace is enabled only share large buffers */ + alloc_ptr = NULL; + + struct fast_get_find find = { + .ptr = alloc_ptr, + }; + objpool_iterate(&fast_get_data.pool, fast_get_find_entry, &find); + entry = find.entry; + if (!entry) { + entry = objpool_alloc(&fast_get_data.pool, sizeof(*entry), + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT); + if (!entry) { + ret = NULL; + goto out; + } + } + +#if CONFIG_USERSPACE + LOG_DBG("%s: %#zx bytes alloc %p entry %p DRAM %p", + current_is_userspace ? "userspace" : "kernel", size, + alloc_ptr, entry->sram_ptr, dram_ptr); +#endif + + if (entry->sram_ptr) { + if (entry->size != size || entry->dram_ptr != dram_ptr) { + LOG_ERR("size %u != %u or ptr %p != %p mismatch", + entry->size, size, entry->dram_ptr, dram_ptr); + ret = NULL; + goto out; + } + + ret = entry->sram_ptr; + +#if CONFIG_USERSPACE + struct k_mem_domain *mdom = k_current_get()->mem_domain_info.mem_domain; + + /* + * We only get there for large buffers, since small buffers with + * enabled userspace don't create fast-get entries + * + * We also reach this point when using the module driver heap. + * Since the heap is already shared across module instances, + * we skip memory domain manipulation. + */ + if (current_is_userspace && size > FAST_GET_MAX_COPY_SIZE) { + if (!fast_get_partition_exists(mdom, ret, + ALIGN_UP(size, CONFIG_MM_DRV_PAGE_SIZE))) { + LOG_DBG("grant access to domain %p", mdom); + + int err = fast_get_access_grant(mdom, ret, size); + + if (err < 0) { + LOG_ERR("failed to grant additional access err=%d", err); + ret = NULL; + goto out; + } + /* + * The data is constant, so it's safe to use cached access to + * it, but initially we have to invalidate caches + */ + dcache_invalidate_region((__sparse_force void __sparse_cache *)ret, + size); + } else { + LOG_WRN("Repeated access request by thread"); + } + } +#endif + + entry->refcount++; + goto out; + } + + if (alloc && alloc->vreg && size <= FAST_GET_MAX_COPY_SIZE) + /* A userspace allocation, that won't be shared */ + ret = vregion_alloc_align(alloc->vreg, alloc_size, + alloc_align); + else + ret = sof_heap_alloc(heap, alloc_flags, alloc_size, alloc_align); + if (!ret) + goto out; + + memcpy_s(ret, alloc_size, dram_ptr, size); + dcache_writeback_region((__sparse_force void __sparse_cache *)ret, size); + +#if CONFIG_USERSPACE + if (size > FAST_GET_MAX_COPY_SIZE && current_is_userspace) { + /* Otherwise we've allocated on thread's heap, so it already has access */ + int err = fast_get_access_grant(k_current_get()->mem_domain_info.mem_domain, + ret, size); + + if (err < 0) { + LOG_ERR("failed to grant access err=%d", err); + sof_heap_free(heap, ret); + ret = NULL; + goto out; + } + } +#endif /* CONFIG_USERSPACE */ + + entry->dram_ptr = dram_ptr; + entry->size = size; + entry->sram_ptr = ret; + entry->refcount = 1; +out: + k_spin_unlock(&data->lock, key); + LOG_DBG("get %p, %p, size %u, refcnt %u", dram_ptr, ret, size, entry ? entry->refcount : 0); + + return ret; +} +EXPORT_SYMBOL(fast_get); + +static bool fast_put_find_entry(void *data, void *arg) +{ + struct sof_fast_get_entry *entry = data; + struct fast_get_find *find = arg; + + if (find->ptr != entry->sram_ptr) + return false; + + find->entry = entry; + return true; +} + +void fast_put(struct mod_alloc_ctx *alloc, struct k_mem_domain *mdom, const void *sram_ptr) +{ + struct k_heap *heap = alloc ? alloc->heap : NULL; + struct sof_fast_get_data *data = &fast_get_data; + struct sof_fast_get_entry *entry; + k_spinlock_key_t key; + + key = k_spin_lock(&fast_get_data.lock); + + struct fast_get_find find = { + .ptr = sram_ptr, + }; + objpool_iterate(&fast_get_data.pool, fast_put_find_entry, &find); + entry = find.entry; + if (!entry) { + LOG_ERR("Put called to unknown address %p", sram_ptr); + goto out; + } + + entry->refcount--; + + if (!entry->refcount) { + LOG_DBG("freeing buffer %p", sram_ptr); + if (alloc && alloc->vreg && entry->size <= FAST_GET_MAX_COPY_SIZE) + vregion_free(alloc->vreg, entry->sram_ptr); + else + sof_heap_free(heap, entry->sram_ptr); + } + +#if CONFIG_USERSPACE + /* + * For large buffers, each thread that called fast_get() has a partition + * in its memory domain. Each thread must remove its own partition here + * to prevent partition leaks. + */ + if (entry->size > FAST_GET_MAX_COPY_SIZE && mdom) { + struct k_mem_partition part = { + .start = (uintptr_t)sram_ptr, + .size = ALIGN_UP(entry->size, CONFIG_MM_DRV_PAGE_SIZE), + .attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB, + }; + + LOG_DBG("removing partition %p size %#zx memory domain %p", + (void *)part.start, part.size, mdom); + int err = k_mem_domain_remove_partition(mdom, &part); + + if (err) + LOG_WRN("partition removal failed: %d", err); + } +#endif + + if (!entry->refcount) + memset(entry, 0, sizeof(*entry)); +out: + LOG_DBG("put %p, DRAM %p size %u refcnt %u", sram_ptr, entry ? entry->dram_ptr : 0, + entry ? entry->size : 0, entry ? entry->refcount : 0); + k_spin_unlock(&data->lock, key); +} +EXPORT_SYMBOL(fast_put); diff --git a/zephyr/lib/pm_runtime.c b/zephyr/lib/pm_runtime.c index fcaa03cb7275..21b3e3ae3df5 100644 --- a/zephyr/lib/pm_runtime.c +++ b/zephyr/lib/pm_runtime.c @@ -21,12 +21,12 @@ DECLARE_TR_CTX(power_tr, SOF_UUID(power_uuid), LOG_LEVEL_INFO); #if defined(CONFIG_PM_POLICY_CUSTOM) const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks) { - unsigned int num_cpu_states; + uint8_t num_cpu_states; const struct pm_state_info *cpu_states; num_cpu_states = pm_state_cpu_get_all(cpu, &cpu_states); - for (int i = num_cpu_states - 1; i >= 0; i--) { + for (int i = (int)num_cpu_states - 1; i >= 0; i--) { const struct pm_state_info *state = &cpu_states[i]; uint32_t min_residency, exit_latency; diff --git a/zephyr/lib/regions_mm.c b/zephyr/lib/regions_mm.c index 7b391284d824..9b8db4b504af 100644 --- a/zephyr/lib/regions_mm.c +++ b/zephyr/lib/regions_mm.c @@ -10,8 +10,35 @@ #if defined(CONFIG_MM_DRV) #include <sof/lib/regions_mm.h> -/* list of vmh_heap objects created */ -static struct list_item vmh_list = LIST_INIT(vmh_list); +LOG_MODULE_DECLARE(mem_allocator, CONFIG_SOF_LOG_LEVEL); + +/** @struct vmh_heap + * + * @brief This structure holds all information about virtual memory heap + * it aggregates information about its allocations and + * physical mappings. + * + * @var virtual_region pointer to virtual region information, it holds its + * attributes size and beginning ptr provided by zephyr. + * @var physical_blocks_allocators[] a table of block allocators + * each representing a virtual regions part in blocks of a given size + * governed by sys_mem_blocks API. + * @var allocation_sizes[] a table of bit arrays representing sizes of allocations + * made in physical_blocks_allocators directly related to physical_blocks_allocators + * @var allocating_continuously configuration value deciding if heap allocations + * will be contiguous or single block. + */ +struct vmh_heap { + struct k_mutex lock; + const struct sys_mm_drv_region *virtual_region; + struct sys_mem_blocks *physical_blocks_allocators[MAX_MEMORY_ALLOCATORS_COUNT]; + struct sys_bitarray *allocation_sizes[MAX_MEMORY_ALLOCATORS_COUNT]; +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS + unsigned int out_of_blocks[MAX_MEMORY_ALLOCATORS_COUNT]; + bool logged; +#endif + bool allocating_continuously; +}; /** * @brief Initialize new heap @@ -20,53 +47,34 @@ static struct list_item vmh_list = LIST_INIT(vmh_list); * and config. The heap size overall must be aligned to physical page * size. * @param cfg Configuration structure with block structure for the heap - * @param memory_region_attribute A zephyr defined virtual region identifier - * @param core_id Core id of a heap that will be created * @param allocating_continuously Flag deciding if heap can do contiguous allocation. * * @retval ptr to a new heap if successful. * @retval NULL on creation failure. */ -struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, - int memory_region_attribute, int core_id, bool allocating_continuously) +struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, bool allocating_continuously) { const struct sys_mm_drv_region *virtual_memory_regions = sys_mm_drv_query_memory_regions(); int i; - /* Check if we haven't created heap for this region already */ - if (vmh_get_heap_by_attribute(memory_region_attribute, core_id)) - return NULL; - struct vmh_heap *new_heap = - rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*new_heap)); + rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*new_heap)); if (!new_heap) return NULL; - new_heap->core_id = core_id; - list_init(&new_heap->node); + k_mutex_init(&new_heap->lock); struct vmh_heap_config new_config = {0}; + const struct sys_mm_drv_region *region; - /* Search for matching attribute so we place heap on right - * virtual region. - * In case of core heaps regions we count theme from 0 to max - * available cores - */ - if (memory_region_attribute == MEM_REG_ATTR_CORE_HEAP) { - new_heap->virtual_region = &virtual_memory_regions[core_id]; - } else { - for (i = CONFIG_MP_MAX_NUM_CPUS; - i < CONFIG_MP_MAX_NUM_CPUS + VIRTUAL_REGION_COUNT; i++) { - - if (memory_region_attribute == virtual_memory_regions[i].attr) { - new_heap->virtual_region = &virtual_memory_regions[i]; - break; - } + SYS_MM_DRV_MEMORY_REGION_FOREACH(virtual_memory_regions, region) { + if (region->attr == VIRTUAL_REGION_SHARED_HEAP_ATTR) { + new_heap->virtual_region = region; + break; } } - - if (!new_heap->virtual_region) + if (!new_heap->virtual_region || !new_heap->virtual_region->size) goto fail; /* If no config was specified we will use default one */ @@ -123,8 +131,8 @@ struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, * them in memory on sys_heap. * First create allocator - instance of sys_mem_blocks struct. */ - struct sys_mem_blocks *new_allocator = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, - 0, SOF_MEM_CAPS_RAM, sizeof(sys_mem_blocks_t)); + struct sys_mem_blocks *new_allocator = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + sizeof(sys_mem_blocks_t)); if (!new_allocator) goto fail; @@ -138,8 +146,8 @@ struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, 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 */ - struct sys_bitarray *allocators_bitarray = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, - 0, SOF_MEM_CAPS_RAM, sizeof(sys_bitarray_t)); + struct sys_bitarray *allocators_bitarray = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + sizeof(sys_bitarray_t)); if (!allocators_bitarray) goto fail; @@ -155,8 +163,8 @@ struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, * Mechanism explained in detail in free and alloc function. */ struct sys_bitarray *allocation_sizes_bitarray = - rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, - 0, SOF_MEM_CAPS_RAM, sizeof(sys_bitarray_t)); + rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + sizeof(sys_bitarray_t)); if (!allocation_sizes_bitarray) goto fail; @@ -169,15 +177,15 @@ struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, * based on its size. */ uint32_t *allocator_bitarray_bitfield = - rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, bitfield_size); + rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, bitfield_size); if (!allocator_bitarray_bitfield) goto fail; allocators_bitarray->bundles = allocator_bitarray_bitfield; - uint32_t *sizes_bitarray_bitfield = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, - SOF_MEM_CAPS_RAM, bitfield_size); + uint32_t *sizes_bitarray_bitfield = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + bitfield_size); if (!sizes_bitarray_bitfield) goto fail; @@ -193,9 +201,6 @@ struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, new_heap->allocating_continuously = allocating_continuously; - /* Save the new heap pointer to a linked list */ - list_item_append(&vmh_list, &new_heap->node); - return new_heap; fail: for (i = 0; i < MAX_MEMORY_ALLOCATORS_COUNT; i++) { @@ -327,7 +332,8 @@ static void vmh_get_mapped_size(void *addr, size_t *size) * * @retval 0 on success, error code otherwise. */ -static int vmh_map_region(struct sys_mem_blocks *region, void *ptr, size_t size) +static int vmh_map_region(const struct sys_mm_drv_region *virtual_region, + struct sys_mem_blocks *region, void *ptr, size_t size) { const size_t block_size = 1 << region->info.blk_sz_shift; uintptr_t begin; @@ -340,8 +346,8 @@ static int vmh_map_region(struct sys_mem_blocks *region, void *ptr, size_t size) if (!vmh_get_map_region_boundaries(region, ptr, size, &begin, &size)) return 0; } - - ret = sys_mm_drv_map_region(UINT_TO_POINTER(begin), 0, size, SYS_MM_MEM_PERM_RW); + ret = sys_mm_drv_map_region_safe(virtual_region, UINT_TO_POINTER(begin), 0, size, + SYS_MM_MEM_PERM_RW); /* In case of an error, the pages that were successfully mapped must be manually released */ if (ret) @@ -377,7 +383,7 @@ static int vmh_unmap_region(struct sys_mem_blocks *region, void *ptr, size_t siz } /** - * @brief Alloc function + * @brief Alloc function, not reentrant * * Allocates memory on heap from provided heap pointer. * Check if we need to map physical memory for given allocation @@ -388,18 +394,18 @@ static int vmh_unmap_region(struct sys_mem_blocks *region, void *ptr, size_t siz * @retval ptr to allocated memory if successful * @retval NULL on allocation failure */ -void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) +static void *_vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) { if (!alloc_size) return NULL; - /* Only operations on the same core are allowed */ - if (heap->core_id != cpu_get_id()) - return NULL; void *ptr = NULL; int mem_block_iterator, allocation_error_code = -ENOMEM; size_t allocation_bitarray_offset, block_count = 0, block_size = 0, allocation_bitarray_position = 0; +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS + bool first_match = true; +#endif /* We will gather error code when allocating on physical block * allocators. @@ -489,6 +495,11 @@ void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) sys_bitarray_set_region(heap->allocation_sizes[mem_block_iterator], block_count - 1, allocation_bitarray_position); break; +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS + } else if (first_match) { + ++heap->out_of_blocks[mem_block_iterator]; + first_match = false; +#endif } } @@ -498,7 +509,8 @@ void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) if (!ptr) return NULL; - allocation_error_code = vmh_map_region(heap->physical_blocks_allocators[mem_block_iterator], + allocation_error_code = vmh_map_region(heap->virtual_region, + heap->physical_blocks_allocators[mem_block_iterator], ptr, alloc_size); if (allocation_error_code) { sys_mem_blocks_free_contiguous(heap->physical_blocks_allocators[mem_block_iterator], @@ -509,6 +521,20 @@ void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) return ptr; } +/** + * @brief Alloc function, reentrant + * see _vmh_alloc comment for details + */ +void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) +{ + k_mutex_lock(&heap->lock, K_FOREVER); + + void *ret = _vmh_alloc(heap, alloc_size); + + k_mutex_unlock(&heap->lock); + return ret; +} + /** * @brief Free virtual memory heap * @@ -539,13 +565,12 @@ int vmh_free_heap(struct vmh_heap *heap) rfree(heap->allocation_sizes[i]); } } - list_item_del(&heap->node); rfree(heap); return 0; } /** - * @brief Free ptr allocated on given heap + * @brief Free ptr allocated on given heap, not reentrant * * Free the ptr allocation. After free action is complete * check if any physical memory block can be freed up as @@ -556,13 +581,10 @@ int vmh_free_heap(struct vmh_heap *heap) * @retval 0 on success; * @retval -ENOTEMPTY on heap having active allocations. */ -int vmh_free(struct vmh_heap *heap, void *ptr) +static int _vmh_free(struct vmh_heap *heap, void *ptr) { int retval; - if (heap->core_id != cpu_get_id()) - return -EINVAL; - size_t mem_block_iter, i, size_to_free, block_size, ptr_bit_array_offset, ptr_bit_array_position, blocks_to_free; bool ptr_range_found; @@ -571,6 +593,10 @@ int vmh_free(struct vmh_heap *heap, void *ptr) for (mem_block_iter = 0, ptr_range_found = false; mem_block_iter < MAX_MEMORY_ALLOCATORS_COUNT; mem_block_iter++) { + /* continiue so we do not check mem blocks that do not exist */ + if (!heap->physical_blocks_allocators[mem_block_iter]) + continue; + block_size = 1 << heap->physical_blocks_allocators[mem_block_iter]->info.blk_sz_shift; @@ -673,30 +699,51 @@ int vmh_free(struct vmh_heap *heap, void *ptr) } /** - * @brief Reconfigure heap with given config - * - * This will destroy the heap from the pointer and recreate it - * using provided config. Individual region attribute is the - * "anchor" to the virtual space we use. - * - * @param heap Ptr to the heap that should be reconfigured - * @param cfg heap blocks configuration - * @param allocating_continuously allow contiguous on the reconfigured heap + * @brief Free ptr function, reentrant + * see _vmh_free comment for details + */ +int vmh_free(struct vmh_heap *heap, void *ptr) +{ + k_mutex_lock(&heap->lock, K_FOREVER); + + int ret = _vmh_free(heap, ptr); + + k_mutex_unlock(&heap->lock); + return ret; +} + +#ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS +/** + * @brief Print stats on heap usage per allocator * - * @retval heap_pointer Returns new heap pointer on success - * @retval NULL when reconfiguration failed + * @param heap pointer to a heap for which statistics are collected */ -struct vmh_heap *vmh_reconfigure_heap( - struct vmh_heap *heap, struct vmh_heap_config *cfg, - int core_id, bool allocating_continuously) +void vmh_log_stats(struct vmh_heap *heap) { - uint32_t region_attribute = heap->virtual_region->attr; + if (heap->logged) + return; - if (vmh_free_heap(heap)) - return NULL; + LOG_INF("Virtual heap stats per allocator"); + LOG_INF(" ID | Total | Max use| Times run out of blocks"); + + for (int idx = 0; idx < MAX_MEMORY_ALLOCATORS_COUNT; idx++) { + if (!heap->physical_blocks_allocators[idx]) + continue; - return vmh_init_heap(cfg, region_attribute, core_id, allocating_continuously); + struct sys_memory_stats stats = {0}; + + sys_mem_blocks_runtime_stats_get(heap->physical_blocks_allocators[idx], &stats); + + size_t block_size = 1 << heap->physical_blocks_allocators[idx]->info.blk_sz_shift; + size_t block_num = heap->physical_blocks_allocators[idx]->info.num_blocks; + + LOG_INF("%7d| %7u| %7u| %7u", idx, block_num, + (stats.max_allocated_bytes / block_size), + heap->out_of_blocks[idx]); + } + heap->logged = true; } +#endif /** * @brief Get default configuration for heap @@ -726,47 +773,4 @@ void vmh_get_default_heap_config(const struct sys_mm_drv_region *region, } } -/** - * @brief Gets pointer to already created heap identified by - * provided attribute. - * - * @param attr Virtual memory region attribute. - * @param core_id id of the core that heap was created for (core heap specific). - * - * @retval heap ptr on success - * @retval NULL if there was no heap created fitting the attr. - */ -struct vmh_heap *vmh_get_heap_by_attribute(uint32_t attr, uint32_t core_id) -{ - struct list_item *vm_heaps_iterator; - struct vmh_heap *retval; - - if (attr == MEM_REG_ATTR_CORE_HEAP) { - /* if we look up cpu heap we need to match its cpuid with addr - * we know that regions keep cpu heaps from 0 to max so we match - * the region of the cpu id with lists one to find match - */ - const struct sys_mm_drv_region *virtual_memory_region = - sys_mm_drv_query_memory_regions(); - /* we move ptr to cpu vmr */ - virtual_memory_region = &virtual_memory_region[core_id]; - - list_for_item(vm_heaps_iterator, &vmh_list) { - retval = - CONTAINER_OF(vm_heaps_iterator, struct vmh_heap, node); - - if (retval->virtual_region->addr == virtual_memory_region->addr) - return retval; - } - } else { - list_for_item(vm_heaps_iterator, &vmh_list) { - retval = - CONTAINER_OF(vm_heaps_iterator, struct vmh_heap, node); - if (retval->virtual_region->attr == attr) - return retval; - } - } - return NULL; -} - #endif /* if defined (CONFIG_MM_DRV) */ diff --git a/zephyr/lib/userspace_helper.c b/zephyr/lib/userspace_helper.c new file mode 100644 index 000000000000..ce4368adc077 --- /dev/null +++ b/zephyr/lib/userspace_helper.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// Author: Jaroslaw Stelter <jaroslaw.stelter@intel.com> +// Adrian Warecki <adrian.warecki@intel.com> + +/** + * \file + * \brief Zephyr userspace helper functions + * \authors Jaroslaw Stelter <jaroslaw.stelter@intel.com> + * \authors Adrian Warecki <adrian.warecki@intel.com> + */ + +#include <stdint.h> + +#include <rtos/alloc.h> +#include <rtos/sof.h> +#include <rtos/userspace_helper.h> +#include <sof/audio/module_adapter/module/generic.h> +#include <sof/audio/module_adapter/library/userspace_proxy.h> +#include <sof/lib/mailbox.h> +#include <sof/lib/dai.h> +#include <sof/lib/dma.h> + +/* Zephyr includes */ +#include <zephyr/kernel.h> +#include <zephyr/app_memory/app_memdomain.h> +#include <zephyr/logging/log.h> + +LOG_MODULE_REGISTER(userspace_helper, CONFIG_SOF_LOG_LEVEL); + +#if CONFIG_USERSPACE + +K_APPMEM_PARTITION_DEFINE(common_partition); + +#ifdef CONFIG_SOF_USERSPACE_LL +K_APPMEM_PARTITION_DEFINE(sysuser_partition); +#endif + +struct k_heap *module_driver_heap_init(void) +{ + struct k_heap *mod_drv_heap = rballoc(SOF_MEM_FLAG_USER, sizeof(*mod_drv_heap)); + + if (!mod_drv_heap) + return NULL; + + void *mem = rballoc_align(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, USER_MOD_HEAP_SIZE, + CONFIG_MM_DRV_PAGE_SIZE); + if (!mem) { + rfree(mod_drv_heap); + return NULL; + } + + k_heap_init(mod_drv_heap, mem, USER_MOD_HEAP_SIZE); + mod_drv_heap->heap.init_mem = mem; + mod_drv_heap->heap.init_bytes = USER_MOD_HEAP_SIZE; + + return mod_drv_heap; +} + +void module_driver_heap_remove(struct k_heap *mod_drv_heap) +{ + if (mod_drv_heap) { + rfree(mod_drv_heap->heap.init_mem); + rfree(mod_drv_heap); + } +} + +void *user_stack_allocate(size_t stack_size, uint32_t options) +{ + return k_thread_stack_alloc(stack_size, options & K_USER); +} + +int user_stack_free(void *p_stack) +{ + if (!p_stack) + return 0; + return k_thread_stack_free(p_stack); +} + +int user_memory_attach_common_partition(struct k_mem_domain *dom) +{ + return k_mem_domain_add_partition(dom, &common_partition); +} + +#ifdef CONFIG_SOF_USERSPACE_LL +int user_memory_attach_system_user_partition(struct k_mem_domain *dom) +{ + return k_mem_domain_add_partition(dom, &sysuser_partition); +} + +int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id) +{ + struct k_mem_partition mem_partition; + int ret; + + /* + * Start with mailbox_swregs. This is aligned with mailbox.h + * implementation with uncached addressed used for register I/O. + */ + mem_partition.start = + (uintptr_t)sys_cache_uncached_ptr_get((void __sparse_cache *)MAILBOX_SW_REG_BASE); + + BUILD_ASSERT(MAILBOX_SW_REG_SIZE == CONFIG_MMU_PAGE_SIZE); + mem_partition.size = CONFIG_MMU_PAGE_SIZE; + mem_partition.attr = K_MEM_PARTITION_P_RW_U_RW; + + ret = k_mem_domain_add_partition(domain, &mem_partition); + if (ret < 0) + return ret; + +#ifndef CONFIG_IPC_MAJOR_4 + /* + * Next mailbox_stream (not available in IPC4). Stream access is cached, + * so different mapping this time. + */ + mem_partition.start = + (uintptr_t)sys_cache_cached_ptr_get((void *)SRAM_STREAM_BASE); + BUILD_ASSERT(MAILBOX_STREAM_SIZE == CONFIG_MMU_PAGE_SIZE); + /* size and attr the same as for mailbox_swregs */ + + ret = k_mem_domain_add_partition(domain, &mem_partition); + if (ret < 0) + return ret; +#endif + + k_mem_domain_add_thread(domain, thread_id); + + return 0; +} + +void user_grant_dai_access_all(struct k_thread *thread) +{ + const struct device **devices; + size_t count; + size_t i; + + devices = dai_get_device_list(&count); + + for (i = 0; i < count; i++) + k_thread_access_grant(thread, devices[i]); + + LOG_DBG("Granted DAI access to thread %p for %zu devices", thread, count); +} + +void user_grant_dma_access_all(struct k_thread *thread) +{ + const struct dma_info *info = dma_info_get(); + struct sof_dma *d; + + for (d = info->dma_array; d < info->dma_array + info->num_dmas; d++) { + k_thread_access_grant(thread, d->z_dev); + LOG_DBG("Granted DMA device access: %s to thread %p", d->z_dev->name, thread); + } +} + +#endif /* CONFIG_SOF_USERSPACE_LL */ + +#else /* CONFIG_USERSPACE */ + +void *user_stack_allocate(size_t stack_size, uint32_t options) +{ + /* allocate stack - must be aligned and cached so a separate alloc */ + stack_size = K_KERNEL_STACK_LEN(stack_size); + void *p_stack = rballoc_align(SOF_MEM_FLAG_USER, stack_size, Z_KERNEL_STACK_OBJ_ALIGN); + + return p_stack; +} + +int user_stack_free(void *p_stack) +{ + rfree(p_stack); + return 0; +} + +void module_driver_heap_remove(struct k_heap *mod_drv_heap) +{ } + +#endif /* CONFIG_USERSPACE */ diff --git a/zephyr/lib/vpage.c b/zephyr/lib/vpage.c new file mode 100644 index 000000000000..ce0da7b5ac97 --- /dev/null +++ b/zephyr/lib/vpage.c @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2025 Intel Corporation. + * + * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> + */ + +#include <zephyr/init.h> +#include <zephyr/kernel.h> +#include <zephyr/logging/log.h> +#include <zephyr/sys/check.h> +#include <sof/lib/regions_mm.h> +#include <sof/lib/vpage.h> +#include <zephyr/drivers/mm/mm_drv_intel_adsp_mtl_tlb.h> + +LOG_MODULE_REGISTER(vpage, CONFIG_SOF_LOG_LEVEL); + +/* Simple Page Allocator. + * + * This allocator manages the allocation and deallocation of virtual memory + * pages from a predefined virtual memory region which is larger than the + * physical memory region. + * + * Both memory regions are divided into pages (usually 4kB) that are represented + * as blocks in a bitmap using the zephyr sys_mem_blocks API. The virtual block + * map tracks the allocation of virtual memory pages while the physical block + * map in the Zephyr MM driver tracks the allocation of physical memory pages. + */ + +/* max number of allocations */ +#define VPAGE_MAX_ALLOCS CONFIG_SOF_VPAGE_MAX_ALLOCS + +/* + * Virtual memory allocation element - tracks allocated virtual page id and size + */ +struct valloc_elem { + unsigned short pages; /* number of pages allocated in contiguous block */ + unsigned short vpage; /* virtual page number from start of region */ +}; + +/* + * Virtual page allocator context + * + * This structure holds all information about virtual memory pages including the + * number of free and total pages, the virtual memory region, the block + * allocator for virtual pages and the allocations. + */ +struct vpage_context { + struct k_mutex lock; + unsigned int free_pages; /* number of free pages */ + unsigned int total_pages; /* total number of pages */ + + /* Virtual memory region information */ + const struct sys_mm_drv_region *virtual_region; + struct sys_mem_blocks vpage_blocks; + sys_bitarray_t bitmap; + + /* allocation elements to track page id to allocation size */ + unsigned int num_elems_in_use; /* number of allocated elements in use*/ + struct valloc_elem velems[VPAGE_MAX_ALLOCS]; +}; + +/* uncache persistent across all cores */ +static struct vpage_context vpage_ctx; + +/** + * @brief Allocate and map virtual memory pages + * + * Allocates memory pages from the virtual page allocator. + * Maps physical memory pages to the virtual region as needed. + * + * @param pages Number of pages to allocate. + * @param ptr Pointer to store the address of allocated pages. + * @retval 0 if successful. + */ +static int vpages_alloc_and_map(unsigned int pages, void **ptr) +{ + void *vaddr; + int ret; + + /* check for valid pages and ptr */ + if (!ptr) + return -EINVAL; + + if (!pages) { + *ptr = NULL; + return 0; + } + + /* quick check for enough free pages */ + if (vpage_ctx.free_pages < pages) { + LOG_ERR("error: not enough free pages %u for requested pages %u", + vpage_ctx.free_pages, pages); + return -ENOMEM; + } + + /* check for allocation elements */ + if (vpage_ctx.num_elems_in_use >= VPAGE_MAX_ALLOCS) { + LOG_ERR("error: max allocation elements reached"); + return -ENOMEM; + } + + /* allocate virtual continuous blocks */ + ret = sys_mem_blocks_alloc_contiguous(&vpage_ctx.vpage_blocks, pages, &vaddr); + if (ret < 0) { + LOG_ERR("error: failed to allocate %u continuous virtual pages, free %u", + pages, vpage_ctx.free_pages); + return ret; + } + + /* map the virtual blocks in virtual region to free physical blocks */ + ret = sys_mm_drv_map_region_safe(vpage_ctx.virtual_region, vaddr, + 0, pages * CONFIG_MM_DRV_PAGE_SIZE, SYS_MM_MEM_PERM_RW); + if (ret < 0) { + LOG_ERR("error: failed to map virtual region %p to physical region %p, error %d", + vaddr, vpage_ctx.virtual_region->addr, ret); + sys_mem_blocks_free_contiguous(&vpage_ctx.vpage_blocks, vaddr, pages); + return ret; + } + + /* success update the free pages */ + vpage_ctx.free_pages -= pages; + + /* Elements are acquired densely, just use the next one */ + vpage_ctx.velems[vpage_ctx.num_elems_in_use].pages = pages; + vpage_ctx.velems[vpage_ctx.num_elems_in_use].vpage = + (POINTER_TO_UINT(vaddr) - + POINTER_TO_UINT(vpage_ctx.virtual_region->addr)) / + CONFIG_MM_DRV_PAGE_SIZE; + vpage_ctx.num_elems_in_use++; + + /* return the virtual address */ + *ptr = vaddr; + + return 0; +} + +/** + * @brief Allocate virtual memory pages + * + * Allocates virtual memory pages from the virtual page allocator. + * + * @param pages Number of pages (usually 4kB large) to allocate. + * @retval NULL on allocation failure. + */ +void *vpage_alloc(unsigned int pages) +{ + void *ptr = NULL; + int ret; + + k_mutex_lock(&vpage_ctx.lock, K_FOREVER); + ret = vpages_alloc_and_map(pages, &ptr); + k_mutex_unlock(&vpage_ctx.lock); + if (ret < 0) + LOG_ERR("vpage_alloc failed %d for %d pages, total %d free %d", + ret, pages, vpage_ctx.total_pages, vpage_ctx.free_pages); + else + LOG_INF("vpage_alloc ptr %p pages %u free %u/%u", ptr, pages, vpage_ctx.free_pages, + vpage_ctx.total_pages); + return ptr; +} + +/** + * @brief Free and unmap virtual memory pages + * + * Frees previously allocated virtual memory pages and unmaps them. + * + * @param ptr Pointer to the memory pages to free. + * @retval 0 if successful. + * @retval -EINVAL if ptr is invalid. + */ +static int vpages_free_and_unmap(uintptr_t *ptr) +{ + unsigned int alloc_idx, elem_idx; + unsigned int pages = 0; + int ret; + + /* check for valid ptr which must be page aligned */ + CHECKIF(!IS_ALIGNED(ptr, CONFIG_MM_DRV_PAGE_SIZE)) { + LOG_ERR("error: invalid non aligned page pointer %p", ptr); + return -EINVAL; + } + + alloc_idx = (POINTER_TO_UINT(ptr) - POINTER_TO_UINT(vpage_ctx.virtual_region->addr)) / + CONFIG_MM_DRV_PAGE_SIZE; + + /* find the allocation element */ + for (elem_idx = 0; elem_idx < VPAGE_MAX_ALLOCS; elem_idx++) { + if (vpage_ctx.velems[elem_idx].pages > 0 && + vpage_ctx.velems[elem_idx].vpage == alloc_idx) { + pages = vpage_ctx.velems[elem_idx].pages; + + LOG_DBG("found allocation element %d pages %u vpage %u for ptr %p", + elem_idx, vpage_ctx.velems[elem_idx].pages, + vpage_ctx.velems[elem_idx].vpage, ptr); + break; + } + } + + /* check we found allocation element */ + CHECKIF(!pages) { + LOG_ERR("error: invalid page pointer %p not found", ptr); + return -EINVAL; + } + + /* unmap the pages from virtual region */ + ret = sys_mm_drv_unmap_region((void *)ptr, pages * CONFIG_MM_DRV_PAGE_SIZE); + if (ret < 0) { + LOG_ERR("error: failed to unmap virtual region %p pages %u, error %d", + ptr, pages, ret); + return ret; + } + + /* free physical blocks */ + ret = sys_mem_blocks_free_contiguous(&vpage_ctx.vpage_blocks, ptr, pages); + if (ret < 0) { + LOG_ERR("error: failed to free %u continuous virtual page blocks at %p, error %d", + pages, ptr, ret); + return ret; + } + + /* move the last element over the released one, clear the last element */ + if (vpage_ctx.num_elems_in_use != elem_idx) + vpage_ctx.velems[elem_idx] = vpage_ctx.velems[vpage_ctx.num_elems_in_use]; + vpage_ctx.velems[vpage_ctx.num_elems_in_use].pages = 0; + vpage_ctx.velems[vpage_ctx.num_elems_in_use].vpage = 0; + vpage_ctx.num_elems_in_use--; + + /* success update the free pages */ + vpage_ctx.free_pages += pages; + + return ret; +} + +/** + * @brief Free virtual pages + * Frees previously allocated virtual memory pages and unmaps them. + * + * @param ptr + */ +void vpage_free(void *ptr) +{ + int ret; + + k_mutex_lock(&vpage_ctx.lock, K_FOREVER); + ret = vpages_free_and_unmap((uintptr_t *)ptr); + k_mutex_unlock(&vpage_ctx.lock); + + if (!ret) + LOG_INF("vptr %p free/total pages %d/%d", ptr, vpage_ctx.free_pages, + vpage_ctx.total_pages); +} + +/** + * @brief Initialize virtual page allocator + * + * Initializes a virtual page allocator that manages a virtual memory region + * using a page table and block structures. + * + * @retval 0 if successful. + * @retval -ENOMEM on creation failure. + */ +static int vpage_init(void) +{ + const struct sys_mm_drv_region *virtual_memory_regions; + const struct sys_mm_drv_region *region; + uint32_t *bundles = NULL; + unsigned int block_count, bitmap_num_bundles; + int ret; + + /* create the virtual memory region and add it to the system */ + size_t remaining_ram = L2_SRAM_BASE + L2_SRAM_SIZE - + (adsp_mm_get_unused_l2_start_aligned() + + CONFIG_SOF_ZEPHYR_VIRTUAL_HEAP_REGION_SIZE + + CONFIG_LIBRARY_REGION_SIZE); + + ret = adsp_add_virtual_memory_region(adsp_mm_get_unused_l2_start_aligned() + + CONFIG_SOF_ZEPHYR_VIRTUAL_HEAP_REGION_SIZE, + remaining_ram, VIRTUAL_REGION_VPAGES_ATTR); + if (ret) + return ret; + + k_mutex_init(&vpage_ctx.lock); + + /* now find the virtual region in all memory regions */ + virtual_memory_regions = sys_mm_drv_query_memory_regions(); + SYS_MM_DRV_MEMORY_REGION_FOREACH(virtual_memory_regions, region) { + if (region->attr == VIRTUAL_REGION_VPAGES_ATTR) { + vpage_ctx.virtual_region = region; + break; + } + } + sys_mm_drv_query_memory_regions_free(virtual_memory_regions); + + /* check for a valid region */ + if (!vpage_ctx.virtual_region) { + LOG_ERR("error: no valid virtual region found"); + k_panic(); + } + + block_count = region->size / CONFIG_MM_DRV_PAGE_SIZE; + if (block_count == 0) { + LOG_ERR("error: virtual region too small %zu", region->size); + k_panic(); + } + + vpage_ctx.total_pages = block_count; + vpage_ctx.free_pages = block_count; + vpage_ctx.num_elems_in_use = 0; + + /* bundles are uint32_t of bits */ + bitmap_num_bundles = SOF_DIV_ROUND_UP(block_count, sizeof(uint32_t) * 8); + + /* allocate memory for bitmap bundles */ + bundles = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + bitmap_num_bundles * sizeof(uint32_t)); + if (!bundles) { + LOG_ERR("error: virtual region bitmap alloc failed"); + k_panic(); + } + + /* Fill allocators data based on config and virtual region data */ + vpage_ctx.vpage_blocks.info.num_blocks = block_count; + vpage_ctx.vpage_blocks.info.blk_sz_shift = ilog2(CONFIG_MM_DRV_PAGE_SIZE); + /* buffer is the start of the virtual memory region */ + vpage_ctx.vpage_blocks.buffer = (uint8_t *)vpage_ctx.virtual_region->addr; + + /* initialize bitmap */ + vpage_ctx.bitmap.num_bits = block_count; + vpage_ctx.bitmap.num_bundles = bitmap_num_bundles; + vpage_ctx.bitmap.bundles = bundles; + vpage_ctx.vpage_blocks.bitmap = &vpage_ctx.bitmap; + + LOG_INF("region %p size %#zx pages %u", + (void *)vpage_ctx.virtual_region->addr, + vpage_ctx.virtual_region->size, block_count); + + return 0; +} + +SYS_INIT(vpage_init, POST_KERNEL, 1); diff --git a/zephyr/lib/vregion.c b/zephyr/lib/vregion.c new file mode 100644 index 000000000000..9c8c94c23f97 --- /dev/null +++ b/zephyr/lib/vregion.c @@ -0,0 +1,500 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2025 Intel Corporation. + * + * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> + */ + +#include <sys/types.h> +#include <zephyr/init.h> +#include <zephyr/kernel.h> +#include <zephyr/logging/log.h> +#include <sof/lib/vpage.h> +#include <sof/lib/vregion.h> +#include <rtos/alloc.h> +#include <sof/common.h> + +LOG_MODULE_REGISTER(vregion, CONFIG_SOF_LOG_LEVEL); + +/* + * Pre Allocated Contiguous Virtual Memory Region Allocator + * + * This allocator manages a pre-allocated virtual memory region that uses the + * virtual page allocator to allocate and free memory pages. + * + * It is designed for use cases where a contiguous virtual memory region + * is required, such as for batched allocation of audio pipelines and modules. + * + * New pipelines will create a new virtual region and will specify the size of the region + * which can be divided into multiple areas for different allocation lifetimes, permissions + * and sharing requirements. + * + * Advantages: + * + * 1) Contiguous virtual memory region for easier management and tracking of + * pipeline & DP module memory. i.e. we just need to track the vregion pointer. + * 2) Reduced fragmentation and better cache utilization by using a simple linear + * allocator for lifetime objects. + * + * Note: Software must pass in the size of the region areas at pipeline creation time. + */ + +/** + * @brief virtual region memory structure. + * + * This structure represents a virtual memory region, which includes + * information about the base address, size, and allocation status + * of the region. + * + * Currently the virtual region memory can be partitioned into two areas on + * page-aligned boundaries: + * + * 1. Interim Heap: An interim memory area used for multiple temporary + * allocations and frees over the lifetime of the audio processing pipeline. + * E.g. for module kcontrol derived allocations. + * + * 2. Lifetime Allocator: A simple incrementing allocator used for long-term + * static allocations that persist for the lifetime of the audio processing + * pipeline. This allocator compresses allocations for better cache + * utilization. + * + * More types can be added in the future. + * + * * TODO: Pipeline/module reset() could reset the dynamic heap. + */ + + /* linear heap used for lifetime allocations */ +struct vlinear_heap { + uint8_t *base; /* base address of linear allocator */ + uint8_t *ptr; /* current alloc pointer */ + size_t size; /* size of linear allocator in bytes */ + size_t used; /* used bytes in linear allocator */ + int free_count; /* number of frees - tuning only */ +}; + +/* zephyr k_heap for interim allocations. TODO: make lockless for improved performance */ +struct interim_heap { + struct k_heap heap; +}; + +/* Main vregion context, see above intro for more details. + * TODO: Add support to flag which heaps should have their contexts saved and restored. + */ +struct vregion { + /* region context */ + uint8_t *base; /* base address of entire region */ + size_t size; /* size of whole region in bytes */ + unsigned int pages; /* size of whole region in pages */ + struct k_mutex lock; /* protect vregion heaps and use-count */ + unsigned int use_count; + + /* current allocation mode */ + enum vregion_mem_type type; /* LIFETIME at creation, switch to INTERIM */ + + /* interim heap - created lazily on first interim allocation */ + struct interim_heap interim; /* interim heap */ + + /* lifetime heap */ + struct vlinear_heap lifetime; /* lifetime linear heap */ +}; + +/** + * @brief Create a new virtual region instance. + * + * Create a new VIRTUAL REGION instance with specified memory size. + * Allocations start in LIFETIME mode. + * + * @param[in] memsize Total size of the virtual region memory. + * @return struct vregion* Pointer to the new virtual region instance, or NULL on failure. + */ +struct vregion *vregion_create(size_t memsize) +{ + struct vregion *vr; + unsigned int pages; + size_t total_size; + uint8_t *vregion_base; + + if (!memsize) { + LOG_ERR("error: invalid vregion memsize %zu", memsize); + return NULL; + } + + /* + * Align up the memory size to nearest page. Lifetime + * allocations growing upward from the base. The interim + * k_heap is created lazily from the remaining space when + * initialization phase is ready. + */ + total_size = ALIGN_UP(memsize, CONFIG_MM_DRV_PAGE_SIZE); + + /* allocate vregion metadata separately to keep it inaccessible to the user */ + vr = rmalloc(0, sizeof(*vr)); + if (!vr) + return NULL; + + /* allocate pages for vregion */ + pages = total_size / CONFIG_MM_DRV_PAGE_SIZE; + vregion_base = vpage_alloc(pages); + if (!vregion_base) { + rfree(vr); + return NULL; + } + + /* init vregion */ + vr->base = vregion_base; + vr->size = total_size; + vr->pages = pages; + + /* lifetime linear allocator starts at the beginning of the vregion memory */ + vr->lifetime.base = vregion_base; + vr->lifetime.size = total_size; + vr->lifetime.ptr = vregion_base; + vr->lifetime.used = 0; + vr->lifetime.free_count = 0; + + /* start in lifetime allocation mode */ + vr->type = VREGION_MEM_TYPE_LIFETIME; + + k_mutex_init(&vr->lock); + /* The creator is the first user */ + vr->use_count = 1; + + /* log the new vregion */ + LOG_INF("new at base %p size %#zx pages %u metadata at %p", + (void *)vr->base, total_size, pages, (void *)vr); + + return vr; +} + +struct vregion *vregion_get(struct vregion *vr) +{ + if (!vr) + return NULL; + + k_mutex_lock(&vr->lock, K_FOREVER); + vr->use_count++; + k_mutex_unlock(&vr->lock); + + return vr; +} + +/** + * @brief Decrement virtual region's user count or destroy it. + * + * @param[in] vr Pointer to the virtual region instance to release. + * @return struct vregion* Pointer to the virtual region instance or NULL if it has been destroyed. + */ +struct vregion *vregion_put(struct vregion *vr) +{ + unsigned int use_count; + + if (!vr) + return NULL; + + k_mutex_lock(&vr->lock, K_FOREVER); + use_count = --vr->use_count; + k_mutex_unlock(&vr->lock); + + if (use_count) + return vr; + + /* Last user: nobody else can access the instance. */ + + /* log the vregion being destroyed */ + LOG_DBG("destroy %p size %#zx pages %u", (void *)vr->base, vr->size, vr->pages); + LOG_DBG(" lifetime used %zu free count %d", vr->lifetime.used, vr->lifetime.free_count); + vpage_free(vr->base); + rfree(vr); + + return NULL; +} + +/** + * @brief Initialize the interim heap from remaining vregion space. + * + * Called on first interim allocation. Creates the k_heap from all buffer + * space not yet consumed by lifetime allocations. + * + * @param[in] vr Pointer to the virtual region instance. + */ +static void interim_heap_init(struct vregion *vr) +{ + uint8_t *interim_base; + ssize_t interim_size; + + if (vr->type == VREGION_MEM_TYPE_INTERIM) { + LOG_WRN("vregion %p already in interim mode", (void *)vr); + return; + } + + /* interim heap starts right after current lifetime pointer, page-aligned */ + interim_base = UINT_TO_POINTER(ALIGN_UP(POINTER_TO_UINT(vr->lifetime.ptr), + CONFIG_DCACHE_LINE_SIZE)); + interim_size = (vr->base + vr->size) - interim_base; + /* + * Calling k_heap_init() with too small size causes an assert + * failure. Exact limit is hard to deduce from sys_heap_init() + * code, but 1024 seems to be enough. + */ + if (interim_size < 1024) { + LOG_WRN("Too little memory, %zd bytes, left for interim heap", interim_size); + vr->type = VREGION_MEM_TYPE_INVALID; + return; + } + + LOG_INF("creating interim heap: lifetime used %zu, interim available %zu at %p", + vr->lifetime.used, interim_size, (void *)interim_base); + + /* cap lifetime so no more lifetime allocs can grow into interim */ + vr->lifetime.size = interim_base - vr->base; + + vr->interim.heap.heap.init_mem = interim_base; + vr->interim.heap.heap.init_bytes = interim_size; + + k_heap_init(&vr->interim.heap, interim_base, interim_size); + vr->type = VREGION_MEM_TYPE_INTERIM; + + /* Update lifetime heap with the interim heap usage. */ + vr->lifetime.ptr = (void *)(interim_base + interim_size); + vr->lifetime.used = (uint8_t *)vr->lifetime.ptr - (uint8_t *)vr->lifetime.base; +} + +void vregion_set_interim(struct vregion *vr) +{ + if (!vr) + return; + + k_mutex_lock(&vr->lock, K_FOREVER); + + interim_heap_init(vr); + + k_mutex_unlock(&vr->lock); +} + +/** + * @brief Allocate memory with alignment from the virtual region dynamic heap. + * + * @param[in] heap Pointer to the heap to use. + * @param[in] size Size of the allocation. + * @param[in] align Alignment of the allocation. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +static void *interim_alloc(struct interim_heap *heap, size_t size, size_t align) +{ + void *ptr; + + ptr = k_heap_aligned_alloc(&heap->heap, align, size, K_NO_WAIT); + if (!ptr) + LOG_WRN("interim alloc failed for %d bytes align %d", + size, align); + + return ptr; +} + +/** + * @brief Free memory from the virtual region interim heap. + * + * @param[in] heap Pointer to the heap to use. + * @param[in] ptr Pointer to the memory to free. + */ +static void interim_free(struct interim_heap *heap, void *ptr) +{ + k_heap_free(&heap->heap, ptr); +} + +/** + * @brief Allocate memory from the virtual region lifetime allocator. + * + * If the interim heap has already been created (i.e., an interim allocation + * was made), log a warning and fall back to interim allocation. + * + * @param[in] heap Pointer to the linear heap to use. + * @param[in] size Size of the allocation. + * @param[in] align Alignment of the allocation. + * + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +static void *lifetime_alloc(struct vlinear_heap *heap, size_t size, size_t align) +{ + void *ptr; + uint8_t *aligned_ptr; + size_t heap_obj_size; + + /* align heap pointer to alignment requested */ + aligned_ptr = UINT_TO_POINTER(ALIGN_UP(POINTER_TO_UINT(heap->ptr), align)); + + /* also align up size to D$ bytes if asked - allocation head and tail aligned */ + if (align == CONFIG_DCACHE_LINE_SIZE) + size = ALIGN_UP(size, CONFIG_DCACHE_LINE_SIZE); + + /* calculate new heap object size for object and alignment */ + heap_obj_size = aligned_ptr - heap->ptr + size; + + /* check we have enough lifetime space left */ + if (heap_obj_size + heap->used > heap->size) { + LOG_WRN("lifetime alloc failed for object %d heap %d bytes free %d", + size, heap_obj_size, heap->size - heap->used); + return NULL; + } + + /* allocate memory */ + ptr = aligned_ptr; + heap->ptr += heap_obj_size; + heap->used += heap_obj_size; + + return ptr; +} + +/** + * @brief Free memory from the virtual region lifetime allocator. + * + * @param[in] heap Pointer to the linear heap to use. + * @param[in] ptr Pointer to the memory to free. + */ +static void lifetime_free(struct vlinear_heap *heap, void *ptr) +{ + /* simple free, just increment free count, this is for tuning only */ + heap->free_count++; + + LOG_DBG("lifetime free %p count %d", ptr, heap->free_count); +} + +/** + * @brief Free memory from the virtual region. + * + * @param vr Pointer to the virtual region instance. + * @param ptr Pointer to the memory to free. + */ +void vregion_free(struct vregion *vr, void *ptr) +{ + if (!vr || !ptr) + return; + + k_mutex_lock(&vr->lock, K_FOREVER); + + if (sys_cache_is_ptr_uncached(ptr)) + ptr = sys_cache_cached_ptr_get(ptr); + + /* Check if pointer is in interim heap (if initialized) */ + if (vr->type == VREGION_MEM_TYPE_INTERIM && + ptr >= (void *)vr->interim.heap.heap.init_mem && + ptr < (void *)((uint8_t *)vr->interim.heap.heap.init_mem + + vr->interim.heap.heap.init_bytes)) + interim_free(&vr->interim, ptr); + else if (ptr >= (void *)vr->lifetime.base && + ptr < (void *)(vr->lifetime.base + vr->lifetime.size)) + /* pointer is in lifetime area - no-op free */ + lifetime_free(&vr->lifetime, ptr); + else + LOG_ERR("error: vregion free invalid pointer %p", ptr); + + k_mutex_unlock(&vr->lock); +} +EXPORT_SYMBOL(vregion_free); + +/** + * @brief Allocate memory from the virtual region. + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] size Size of the allocation. + * @param[in] alignment Alignment of the allocation. + * + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment) +{ + void *p; + + if (!vr || !size) + return NULL; + + if (alignment < PLATFORM_DCACHE_ALIGN) + alignment = PLATFORM_DCACHE_ALIGN; + + k_mutex_lock(&vr->lock, K_FOREVER); + + switch (vr->type) { + case VREGION_MEM_TYPE_INTERIM: + p = interim_alloc(&vr->interim, size, alignment); + break; + case VREGION_MEM_TYPE_LIFETIME: + p = lifetime_alloc(&vr->lifetime, size, alignment); + break; + default: + LOG_ERR("error: invalid memory type %d", vr->type); + p = NULL; + } + + k_mutex_unlock(&vr->lock); + + return p; +} +EXPORT_SYMBOL(vregion_alloc_align); + +/** + * @brief Allocate memory from the virtual region. + * @param[in] vr Pointer to the virtual region instance. + * @param[in] size Size of the allocation. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *vregion_alloc(struct vregion *vr, size_t size) +{ + return vregion_alloc_align(vr, size, 0); +} +EXPORT_SYMBOL(vregion_alloc); + +void *vregion_alloc_coherent(struct vregion *vr, size_t size) +{ + size = ALIGN_UP(size, CONFIG_DCACHE_LINE_SIZE); + + void *p = vregion_alloc_align(vr, size, CONFIG_DCACHE_LINE_SIZE); + + if (!p) + return NULL; + + sys_cache_data_invd_range(p, size); + + return sys_cache_uncached_ptr_get(p); +} + +void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment) +{ + if (alignment < CONFIG_DCACHE_LINE_SIZE) + alignment = CONFIG_DCACHE_LINE_SIZE; + size = ALIGN_UP(size, CONFIG_DCACHE_LINE_SIZE); + + void *p = vregion_alloc_align(vr, size, alignment); + + if (!p) + return NULL; + + sys_cache_data_invd_range(p, size); + + return sys_cache_uncached_ptr_get(p); +} + +/** + * @brief Log virtual region memory usage. + * + * @param[in] vr Pointer to the virtual region instance. + */ +void vregion_info(struct vregion *vr) +{ + if (!vr) + return; + + LOG_INF("base %p size %#zx pages %u", + (void *)vr->base, vr->size, vr->pages); + LOG_INF("lifetime used %#zx free count %d", + vr->lifetime.used, vr->lifetime.free_count); +} +EXPORT_SYMBOL(vregion_info); + +void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t *start) +{ + if (size) + *size = vr->size; + + if (start) + *start = (uintptr_t)vr->base; +} diff --git a/zephyr/schedule.c b/zephyr/schedule.c index 75155b5d4913..afc53995610f 100644 --- a/zephyr/schedule.c +++ b/zephyr/schedule.c @@ -10,10 +10,22 @@ #include <sof/schedule/ll_schedule.h> #include <rtos/alloc.h> #include <rtos/symbol.h> +#include <rtos/userspace_helper.h> #include <sof/lib/cpu.h> #include <ipc/topology.h> -static struct schedulers *_schedulers[CONFIG_CORE_COUNT]; +/* Kernel-only scheduler list — depending on how SOF is built, + * either holds all or subset of scheduler types. + * Not accessible from user-space threads. + */ +static struct schedulers *_k_schedulers[CONFIG_CORE_COUNT]; + +#if CONFIG_SOF_USERSPACE_LL +/* User-accessible scheduler list — holds the subset of scheduler + * types that are managed in user-space + */ +static APP_SYSUSER_BSS struct schedulers *_u_schedulers[CONFIG_CORE_COUNT]; +#endif /** * Retrieves registered schedulers. @@ -21,6 +33,45 @@ static struct schedulers *_schedulers[CONFIG_CORE_COUNT]; */ struct schedulers **arch_schedulers_get(void) { - return _schedulers + cpu_get_id(); +#if CONFIG_SOF_USERSPACE_LL + /* user-space callers must use arch_user_schedulers_get() */ + assert(!k_is_user_context()); +#endif + return _k_schedulers + cpu_get_id(); } EXPORT_SYMBOL(arch_schedulers_get); + +/** + * Retrieves registered user schedulers for the current core. + * + * Relies on cpu_get_id(), so it may invoke privileged functions and + * must not be called from a user-space context. User-space callers + * should use arch_user_schedulers_get_for_core() instead. + * + * @return List of registered schedulers. + */ +struct schedulers **arch_user_schedulers_get(void) +{ +#ifdef CONFIG_SOF_USERSPACE_LL + return _u_schedulers + cpu_get_id(); +#else + return NULL; +#endif +} + +/** + * Retrieves registered user schedulers for the given core. + * + * Unlike arch_user_schedulers_get(), this takes the core explicitly and + * is therefore safe to call from a user-space context. + * + * @return List of registered schedulers. + */ +struct schedulers **arch_user_schedulers_get_for_core(int core) +{ +#ifdef CONFIG_SOF_USERSPACE_LL + return _u_schedulers + core; +#else + return NULL; +#endif +} diff --git a/zephyr/sof_shell.c b/zephyr/sof_shell.c index d36344b1b3fe..9e90abe417bb 100644 --- a/zephyr/sof_shell.c +++ b/zephyr/sof_shell.c @@ -7,11 +7,14 @@ #include <rtos/sof.h> /* sof_get() */ #include <sof/schedule/ll_schedule_domain.h> +#include <sof/audio/module_adapter/module/generic.h> #include <zephyr/kernel.h> #include <zephyr/sys/printk.h> #include <zephyr/shell/shell.h> +#include <stdlib.h> + #define SOF_TEST_INJECT_SCHED_GAP_USEC 1500 static int cmd_sof_test_inject_sched_gap(const struct shell *sh, @@ -39,11 +42,41 @@ static int cmd_sof_test_inject_sched_gap(const struct shell *sh, return 0; } +static int cmd_sof_module_heap_usage(const struct shell *sh, + size_t argc, char *argv[]) +{ + struct ipc *ipc = sof_get()->ipc; + struct list_item *clist, *_clist; + struct ipc_comp_dev *icd; + + if (!ipc) { + shell_print(sh, "No IPC"); + return 0; + } + + list_for_item_safe(clist, _clist, &ipc->comp_list) { + size_t usage, hwm; + + icd = container_of(clist, struct ipc_comp_dev, list); + if (icd->type != COMP_TYPE_COMPONENT) + continue; + + usage = module_adapter_heap_usage(comp_mod(icd->cd), &hwm); + shell_print(sh, "comp id 0x%08x%9zu usage%9zu hwm\tbytes", + icd->id, usage, hwm); + } + return 0; +} + SHELL_STATIC_SUBCMD_SET_CREATE(sof_commands, SHELL_CMD(test_inject_sched_gap, NULL, "Inject a gap to audio scheduling\n", cmd_sof_test_inject_sched_gap), + SHELL_CMD(module_heap_usage, NULL, + "Print heap memory usage of each module\n", + cmd_sof_module_heap_usage), + SHELL_SUBCMD_SET_END ); diff --git a/zephyr/syscall/alloc.c b/zephyr/syscall/alloc.c new file mode 100644 index 000000000000..04f402f37d09 --- /dev/null +++ b/zephyr/syscall/alloc.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include <rtos/alloc.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <zephyr/kernel.h> +#include <zephyr/internal/syscall_handler.h> + +static inline void *z_vrfy_sof_heap_alloc(struct k_heap *heap, uint32_t flags, + size_t bytes, size_t alignment) +{ + /* only allow flags that are safe for user-space heap isolation */ + static const uint32_t allowed_flags = + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT | SOF_MEM_FLAG_DMA | + SOF_MEM_FLAG_LARGE_BUFFER; + + K_OOPS(flags & ~allowed_flags); + + /* user-space use of sof_heap_alloc() limited to this single heap */ + K_OOPS(!zephyr_ll_user_heap_verify(heap)); + + return z_impl_sof_heap_alloc(heap, flags, bytes, alignment); +} +#include <zephyr/syscalls/sof_heap_alloc_mrsh.c> + +static inline void z_vrfy_sof_heap_free(struct k_heap *heap, void *addr) +{ + /* user-space use of sof_heap_alloc() limited to this single heap */ + K_OOPS(!zephyr_ll_user_heap_verify(heap)); + + if (addr) { + uintptr_t start = (uintptr_t)heap->heap.init_mem; + uintptr_t addr_uc = (uintptr_t)sys_cache_uncached_ptr_get(addr); + K_OOPS(addr_uc < start || addr_uc >= start + heap->heap.init_bytes); + K_OOPS(K_SYSCALL_MEMORY_WRITE(addr, 1)); + } + z_impl_sof_heap_free(heap, addr); +} +#include <zephyr/syscalls/sof_heap_free_mrsh.c> diff --git a/zephyr/syscall/dai.c b/zephyr/syscall/dai.c new file mode 100644 index 000000000000..2e09187e146b --- /dev/null +++ b/zephyr/syscall/dai.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include <sof/lib/dai.h> +#include <zephyr/kernel.h> +#include <zephyr/internal/syscall_handler.h> + +static inline const struct device *z_vrfy_dai_get_device(enum sof_ipc_dai_type type, + uint32_t index) +{ + const struct device *dev = z_impl_dai_get_device(type, index); + + if (dev && !k_object_is_valid(dev, K_OBJ_DRIVER_DAI)) + return NULL; + + return dev; +} +#include <zephyr/syscalls/dai_get_device_mrsh.c> diff --git a/zephyr/syscall/sof_dma.c b/zephyr/syscall/sof_dma.c new file mode 100644 index 000000000000..05d6df377c95 --- /dev/null +++ b/zephyr/syscall/sof_dma.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. + +#include <sof/lib/dma.h> +#include <zephyr/kernel.h> +#include <zephyr/internal/syscall_handler.h> +#include <zephyr/sys/math_extras.h> + +#ifdef CONFIG_SOF_USERSPACE_INTERFACE_DMA + +static inline bool sof_dma_has_access(struct sof_dma *dma) +{ + /* + * use the Zephyr dma.h device handle to check calling + * thread has access to it + */ + return k_object_is_valid(dma->z_dev, K_OBJ_DRIVER_DMA); +} + +static inline bool sof_dma_is_valid(struct sof_dma *dma) +{ + const struct dma_info *info = dma_info_get(); + uintptr_t offset = (uintptr_t)dma - (uintptr_t)info->dma_array; + struct sof_dma *array_end = info->dma_array + info->num_dmas; + + if (!info->num_dmas) + return false; + + /* + * The 'dma' pointer is not trusted, so we must first ensure it + * points to a valid "struct sof_dma *" kernel object. + */ + if (dma < info->dma_array || dma >= array_end || offset % sizeof(struct sof_dma)) + return false; + + return sof_dma_has_access(dma); +} + +static inline struct sof_dma *z_vrfy_sof_dma_get(uint32_t dir, uint32_t cap, + uint32_t dev, uint32_t flags) +{ + struct sof_dma *dma = z_impl_sof_dma_get(dir, cap, dev, flags); + + /* + * note: Usually validation is done first, but here + * z_impl_sof_dma_get() is first called with unvalidated input + * arguments on purpose. This is done to reuse the existing SOF + * code to track DMA kernel objects. When called from + * user-space, we use existing functionality to look up the + * kernel object, but add an extra layer to check for access + * permission. + */ + if (dma) { + if (sof_dma_has_access(dma)) + return dma; + + /* no access, release reference on error */ + z_impl_sof_dma_put(dma); + } + + return NULL; +} +#include <zephyr/syscalls/sof_dma_get_mrsh.c> + +static inline void z_vrfy_sof_dma_put(struct sof_dma *dma) +{ + K_OOPS(!sof_dma_is_valid(dma)); + + z_impl_sof_dma_put(dma); +} +#include <zephyr/syscalls/sof_dma_put_mrsh.c> + +static inline int z_vrfy_sof_dma_get_attribute(struct sof_dma *dma, uint32_t type, uint32_t *value) +{ + K_OOPS(!sof_dma_is_valid(dma)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(value, sizeof(*value))); + + return z_impl_sof_dma_get_attribute(dma, type, value); +} +#include <zephyr/syscalls/sof_dma_get_attribute_mrsh.c> + +static inline int z_vrfy_sof_dma_request_channel(struct sof_dma *dma, uint32_t stream_tag) +{ + K_OOPS(!sof_dma_is_valid(dma)); + + return z_impl_sof_dma_request_channel(dma, stream_tag); +} +#include <zephyr/syscalls/sof_dma_request_channel_mrsh.c> + +static inline void z_vrfy_sof_dma_release_channel(struct sof_dma *dma, + uint32_t channel) +{ + K_OOPS(!sof_dma_is_valid(dma)); + + return z_impl_sof_dma_release_channel(dma, channel); +} +#include <zephyr/syscalls/sof_dma_release_channel_mrsh.c> + +/** + * Creates a deep copy of the DMA transfer blocks in kernel address space, + * based on the DMA config description given as argument. + * + * All pointers in 'cfg' are validated for access permission, and if + * ok, contents is copied to a kernel side object. + * + * @arg cfg kernel object for DMA configuration that contains + * user-space pointers to DMA transfer objects + * @return array of kernel DMA block/transfer config objects + */ +static inline struct dma_block_config *deep_copy_dma_blk_cfg_list(struct dma_config *cfg) +{ + struct dma_block_config *kern_cfg; + struct dma_block_config *kern_next, *user_next; + size_t alloc_size; + uint32_t i; + + if (!cfg->block_count) + return NULL; + + /* + * block_count is user-controlled, so compute the allocation size + * with an overflow check. Without it, a large block_count would + * wrap the product on 32-bit size_t, yield an undersized buffer, + * and let the copy loop below overflow the kernel heap. + */ + if (size_mul_overflow(sizeof(*kern_cfg), cfg->block_count, &alloc_size)) + return NULL; + + kern_cfg = rmalloc(0, alloc_size); + if (!kern_cfg) + return NULL; + + user_next = cfg->head_block; + for (i = 0, kern_next = kern_cfg; i < cfg->block_count; i++, kern_next++) { + /* + * The user list must contain exactly block_count entries. + * A list that terminates early (NULL before the count is + * reached) is rejected so the kernel copy and block_count + * stay consistent and the driver never walks past the copy. + */ + if (!user_next) + goto err; + + if (k_usermode_from_copy(kern_next, user_next, sizeof(*kern_next))) + goto err; + + /* check access permissions for DMA src/dest memory */ + switch (cfg->channel_direction) { + case MEMORY_TO_MEMORY: + if (K_SYSCALL_MEMORY_WRITE((void *)kern_next->dest_address, + kern_next->block_size)) + goto err; + COMPILER_FALLTHROUGH; + case MEMORY_TO_PERIPHERAL: + case MEMORY_TO_HOST: + if (K_SYSCALL_MEMORY_READ((void *)kern_next->source_address, + kern_next->block_size)) + goto err; + break; + case PERIPHERAL_TO_MEMORY: + case HOST_TO_MEMORY: + if (K_SYSCALL_MEMORY_WRITE((void *)kern_next->dest_address, + kern_next->block_size)) + goto err; + break; + default: + goto err; + } + + /* + * kern_next->next_block now holds the untrusted user-space + * pointer copied above. Never let the kernel walk it: relink + * every block to the kernel copy so the list can never point + * outside the kern_cfg array. + */ + user_next = kern_next->next_block; + + if (i + 1 < cfg->block_count) { + /* link to the next kernel block */ + kern_next->next_block = kern_next + 1; + } else { + /* + * Last block: the user list must end here, either + * NULL-terminated or cyclic back to the first block. + */ + if (user_next == cfg->head_block) + kern_next->next_block = kern_cfg; + else if (!user_next) + kern_next->next_block = NULL; + else + goto err; + } + } + + /* set transfer list to point to first kernel transfer config object */ + cfg->head_block = kern_cfg; + + return kern_cfg; + +err: + /* do not call K_OOPS until kernel memory is freed */ + rfree(kern_cfg); + return NULL; +} + +static inline int z_vrfy_sof_dma_config(struct sof_dma *dma, uint32_t channel, + struct dma_config *config) +{ + struct dma_block_config *blk_cfgs; + struct dma_config kern_cfg = { 0 }; + struct dma_config user_cfg; + int ret; + + K_OOPS(!sof_dma_is_valid(dma)); + K_OOPS(k_usermode_from_copy(&user_cfg, config, sizeof(user_cfg))); + + /* use only DMA config attributes that are safe to use from user-space */ + kern_cfg.dma_slot = user_cfg.dma_slot; + kern_cfg.channel_direction = user_cfg.channel_direction; + kern_cfg.cyclic = user_cfg.cyclic; + kern_cfg.source_data_size = user_cfg.source_data_size; + kern_cfg.dest_data_size = user_cfg.dest_data_size; + kern_cfg.source_burst_length = user_cfg.source_burst_length; + kern_cfg.dest_burst_length = user_cfg.dest_burst_length; + kern_cfg.block_count = user_cfg.block_count; + kern_cfg.head_block = user_cfg.head_block; + + /* validate and copy transfer blocks to kernel */ + blk_cfgs = deep_copy_dma_blk_cfg_list(&kern_cfg); + K_OOPS(blk_cfgs == NULL); + + /* TODO: add checks for peripheral/host FIFO access? */ + + ret = z_impl_sof_dma_config(dma, channel, &kern_cfg); + + rfree(blk_cfgs); + + return ret; +} +#include <zephyr/syscalls/sof_dma_config_mrsh.c> + +static inline int z_vrfy_sof_dma_start(struct sof_dma *dma, uint32_t channel) +{ + K_OOPS(!sof_dma_is_valid(dma)); + + return z_impl_sof_dma_start(dma, channel); +} +#include <zephyr/syscalls/sof_dma_start_mrsh.c> + +static inline int z_vrfy_sof_dma_stop(struct sof_dma *dma, uint32_t channel) +{ + K_OOPS(!sof_dma_is_valid(dma)); + + return z_impl_sof_dma_stop(dma, channel); +} +#include <zephyr/syscalls/sof_dma_stop_mrsh.c> + +static inline int z_vrfy_sof_dma_get_status(struct sof_dma *dma, uint32_t channel, + struct dma_status *stat) +{ + K_OOPS(!sof_dma_is_valid(dma)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(stat, sizeof(*stat))); + + return z_impl_sof_dma_get_status(dma, channel, stat); +} +#include <zephyr/syscalls/sof_dma_get_status_mrsh.c> + +static inline int z_vrfy_sof_dma_reload(struct sof_dma *dma, uint32_t channel, size_t size) +{ + K_OOPS(!sof_dma_is_valid(dma)); + + return z_impl_sof_dma_reload(dma, channel, size); +} +#include <zephyr/syscalls/sof_dma_reload_mrsh.c> + +static inline int z_vrfy_sof_dma_suspend(struct sof_dma *dma, uint32_t channel) +{ + K_OOPS(!sof_dma_is_valid(dma)); + + return z_impl_sof_dma_suspend(dma, channel); +} +#include <zephyr/syscalls/sof_dma_suspend_mrsh.c> + +static inline int z_vrfy_sof_dma_resume(struct sof_dma *dma, uint32_t channel) +{ + K_OOPS(!sof_dma_is_valid(dma)); + + return z_impl_sof_dma_resume(dma, channel); +} +#include <zephyr/syscalls/sof_dma_resume_mrsh.c> + +#endif /* CONFIG_SOF_USERSPACE_INTERFACE_DMA */ diff --git a/zephyr/test/CMakeLists.txt b/zephyr/test/CMakeLists.txt index e0718b8e0754..397e9e31b938 100644 --- a/zephyr/test/CMakeLists.txt +++ b/zephyr/test/CMakeLists.txt @@ -1,5 +1,34 @@ -if (CONFIG_ACE_VERSION_1_5) - zephyr_library_sources_ifdef(CONFIG_SOF_BOOT_TEST - vmh.c - ) +if(CONFIG_SOF_BOOT_TEST) + if(NOT CONFIG_SOF_USERSPACE_LL) + zephyr_library_sources_ifdef(CONFIG_VIRTUAL_HEAP + vmh.c + ) + endif() + + zephyr_library_sources_ifdef(CONFIG_SOF_VREGIONS + vpage.c vregion.c + ) + zephyr_library_sources_ifdef(CONFIG_USERSPACE + userspace/ksem.c + ) + if(CONFIG_USERSPACE AND CONFIG_SOF_USERSPACE_INTERFACE_ALLOC) + zephyr_library_sources(userspace/test_heap_alloc.c) + endif() +endif() + +if(CONFIG_SOF_BOOT_TEST_STANDALONE AND CONFIG_SOF_USERSPACE_INTERFACE_DMA) + if(CONFIG_DT_HAS_INTEL_ADSP_HDA_HOST_IN_ENABLED) + zephyr_library_sources(userspace/test_intel_hda_dma.c) + endif() + if(CONFIG_DT_HAS_INTEL_ADSP_HDA_SSP_CAP_ENABLED) + zephyr_library_sources(userspace/test_intel_ssp_dai.c) + endif() +endif() + +if(CONFIG_SOF_BOOT_TEST_STANDALONE AND CONFIG_USERSPACE) + zephyr_library_sources(userspace/test_mailbox.c) +endif() + +if(CONFIG_SOF_BOOT_TEST_STANDALONE AND CONFIG_SOF_USERSPACE_LL) + zephyr_library_sources(userspace/test_ll_task.c) endif() diff --git a/zephyr/test/userspace/README.md b/zephyr/test/userspace/README.md new file mode 100644 index 000000000000..6c14300ee333 --- /dev/null +++ b/zephyr/test/userspace/README.md @@ -0,0 +1,48 @@ +User-space interface tests for Intel ADSP +----------------------------------------- + +This folder contains multiple tests to exercise Intel DSP device interfaces +from a user-space Zephyr thread. + +Available tests: +- test_intel_hda_dma.c + - Test Intel HDA DMA host interface from a userspace + Zephyr thread. Use cavstool.py as host runner. +- test_intel_ssp_dai.c + - Test Zephyr DAI interface, together with SOF DMA + wrapper from a user thread. Mimics the call flows done in + sof/src/audio/dai-zephyr.c. Use cavstool.py as host runner. +- test_ll_task.c + - Test Low-Latency (LL) scheduler in user-space mode. Creates + a user-space LL scheduler, and uses it to create and run tasks. + - Tests functionality used by SOF audio pipeline framework to + create tasks for audio pipeline logic. +- test_mailbox.c + - Test use of sof/mailbox.h interface from a Zephyr user thread. + +Building for Intel Panther Lake: +./scripts/xtensa-build-zephyr.py --cmake-args=-DCONFIG_SOF_BOOT_TEST_STANDALONE=y \ + --cmake-args=-DCONFIG_SOF_USERSPACE_INTERFACE_DMA=y \ + --cmake-args=-DCONFIG_SOF_USERSPACE_LL=y \ + -o app/overlays/ptl/userspace_overlay.conf -o app/winconsole_overlay.conf ptl + +Running test: +- Copy resulting firmware (sof-ptl.ri) to device under test. +- Boot and run the test with cavstool.py: + sudo ./cavstool.py sof-ptl.ri +- Test results printed to cavstool.py + +Running test on QEMU (dc233c MMU): +- Tests can also be built and run locally using Zephyr's QEMU simulator. +- First, build the test application using `xtensa-build-zephyr.py`: + ./scripts/xtensa-build-zephyr.py qemu_xtensa_mmu --cmake-args=-DCONFIG_SOF_BOOT_TEST_STANDALONE=y \ + --cmake-args=-DCONFIG_SOF_USERSPACE_INTERFACE_DMA=y --cmake-args=-DCONFIG_SOF_USERSPACE_LL=y +- Once built, run the test in QEMU: + west build -d build-qemu_xtensa_mmu -t run + +References to related assets in Zephyr codebase: +- cavstool.py + - zephyr/soc/intel/intel_adsp/tools/cavstool.py +- HD DMA tests in Zephyr + - zephyr/tests/boards/intel_adsp/hda/ + - larger set in kernel space, using DMA interface directly without SOF dependencies diff --git a/zephyr/test/userspace/ksem.c b/zephyr/test/userspace/ksem.c new file mode 100644 index 000000000000..cb167191f956 --- /dev/null +++ b/zephyr/test/userspace/ksem.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2025 Intel Corporation. + */ + +#include <sof/boot_test.h> + +#include <zephyr/kernel.h> +#include <zephyr/ztest.h> +#include <zephyr/logging/log.h> + +LOG_MODULE_DECLARE(sof_boot_test, LOG_LEVEL_DBG); + +#define USER_STACKSIZE 2048 + +static struct k_thread user_thread; +static K_THREAD_STACK_DEFINE(user_stack, USER_STACKSIZE); +K_SEM_DEFINE(user_sem, 0, 1); + +static void user_function(void *p1, void *p2, void *p3) +{ + __ASSERT(k_is_user_context(), "isn't user"); + LOG_INF("SOF thread %s (%s)", + k_is_user_context() ? "UserSpace!" : "privileged mode.", + CONFIG_BOARD_TARGET); +} + +static void user_sem_function(void *p1, void *p2, void *p3) +{ + __ASSERT(k_is_user_context(), "isn't user"); + LOG_INF("SOF thread %s (%s)", + k_is_user_context() ? "UserSpace!" : "privileged mode.", + CONFIG_BOARD_TARGET); + k_sem_give(&user_sem); +} + +static void test_user_thread(void) +{ + k_thread_create(&user_thread, user_stack, USER_STACKSIZE, + user_function, NULL, NULL, NULL, + -1, K_USER, K_MSEC(0)); + k_thread_join(&user_thread, K_FOREVER); +} + +static void test_user_thread_with_sem(void) +{ + /* Start in 10ms to have time to grant the thread access to the semaphore */ + k_thread_create(&user_thread, user_stack, USER_STACKSIZE, + user_sem_function, NULL, NULL, NULL, + -1, K_USER, K_MSEC(10)); + k_thread_access_grant(&user_thread, &user_sem); + k_sem_take(&user_sem, K_FOREVER); + k_thread_join(&user_thread, K_FOREVER); +} + +ZTEST(sof_boot, user_space) +{ + test_user_thread(); + test_user_thread_with_sem(); +} + +#include <zephyr/sys/sem.h> +#include <zephyr/app_memory/mem_domain.h> + +struct sem_mem { + struct sys_sem sem1; + struct sys_sem sem2; + uint8_t reserved[4096 - 2 * sizeof(struct sys_sem)]; +}; + +static struct sem_mem simple_sem __attribute__((aligned(4096))); +static struct k_mem_domain dp_mdom; + +static void sys_sem_function(void *p1, void *p2, void *p3) +{ + __ASSERT(k_is_user_context(), "isn't user"); + /* This is the goal, but it hangs with this disabled too */ + sys_sem_give(&simple_sem.sem1); + int ret = sys_sem_take(&simple_sem.sem2, K_MSEC(20)); + + LOG_INF("SOF thread %s (%s) sem %p: %d", + k_is_user_context() ? "UserSpace!" : "privileged mode.", + CONFIG_BOARD_TARGET, &simple_sem, ret); +} + +static void test_user_thread_sys_sem(void) +{ + struct k_mem_partition mpart = { + .start = (uintptr_t)&simple_sem, + .size = 4096, + .attr = K_MEM_PARTITION_P_RW_U_RW/* | XTENSA_MMU_CACHED_WB*/, + }; + + k_mem_domain_init(&dp_mdom, 0, NULL); + sys_sem_init(&simple_sem.sem1, 0, 1); + sys_sem_init(&simple_sem.sem2, 0, 1); + + k_thread_create(&user_thread, user_stack, USER_STACKSIZE, + sys_sem_function, NULL, NULL, NULL, + -1, K_USER, K_FOREVER); + k_mem_domain_add_partition(&dp_mdom, &mpart); + k_mem_domain_add_thread(&dp_mdom, &user_thread); + + k_thread_start(&user_thread); + + /* This is what doesn't work: enabling this line crashes the DSP */ + zassert_ok(sys_sem_take(&simple_sem.sem1, K_MSEC(20))); + + sys_sem_give(&simple_sem.sem2); + + k_thread_join(&user_thread, K_FOREVER); + k_mem_domain_remove_partition(&dp_mdom, &mpart); +} + +ZTEST(sof_boot, test_sys_sem) +{ + test_user_thread_sys_sem(); +} diff --git a/zephyr/test/userspace/test_heap_alloc.c b/zephyr/test/userspace/test_heap_alloc.c new file mode 100644 index 000000000000..e4dcb567b616 --- /dev/null +++ b/zephyr/test/userspace/test_heap_alloc.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2026 Intel Corporation. + */ + +/* + * Test cases for sof_heap_alloc() / sof_heap_free() use from a Zephyr + * user-space thread. + */ + +#include <sof/boot_test.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <rtos/alloc.h> + +#include <zephyr/kernel.h> +#include <zephyr/ztest.h> +#include <zephyr/logging/log.h> +#include <zephyr/app_memory/app_memdomain.h> + +LOG_MODULE_DECLARE(sof_boot_test, LOG_LEVEL_DBG); + +#define USER_STACKSIZE 2048 + +static struct k_thread user_thread; +static K_THREAD_STACK_DEFINE(user_stack, USER_STACKSIZE); + +K_APPMEM_PARTITION_DEFINE(heap_alloc_test_part); +K_APP_BMEM(heap_alloc_test_part) static uint8_t non_heap_byte; + +enum heap_alloc_test_case { + HEAP_ALLOC_VALID, + HEAP_ALLOC_NULL_HEAP, + HEAP_ALLOC_FORBIDDEN_FLAGS, + HEAP_FREE_NON_HEAP_POINTER, + HEAP_FREE_INACCESSIBLE_POINTER, +}; + +static void user_function(void *p1, void *p2, void *p3) +{ + struct k_heap *heap = p1; + enum heap_alloc_test_case test_case = (enum heap_alloc_test_case)(uintptr_t)p2; + void *free_ptr = p3; + void *ptr; + + __ASSERT(k_is_user_context(), "isn't user"); + + LOG_INF("SOF thread %s (%s)", + k_is_user_context() ? "UserSpace!" : "privileged mode.", + CONFIG_BOARD_TARGET); + + switch (test_case) { + case HEAP_ALLOC_VALID: + ptr = sof_heap_alloc(heap, SOF_MEM_FLAG_USER, 128, 0); + zassert_not_null(ptr, "sof_heap_alloc returned NULL"); + sof_heap_free(heap, ptr); + return; + case HEAP_ALLOC_NULL_HEAP: + (void)sof_heap_alloc(NULL, SOF_MEM_FLAG_USER, 128, 0); + break; + case HEAP_ALLOC_FORBIDDEN_FLAGS: + (void)sof_heap_alloc(heap, SOF_MEM_FLAG_LARGE_BUFFER, 128, 0); + break; + case HEAP_FREE_NON_HEAP_POINTER: + sof_heap_free(heap, &non_heap_byte); + break; + case HEAP_FREE_INACCESSIBLE_POINTER: + sof_heap_free(heap, free_ptr); + break; + default: + zassert_unreachable("unknown heap allocation test case"); + } + + zassert_unreachable("syscall security check did not fault"); +} + +static void run_user_heap_alloc_case(enum heap_alloc_test_case test_case, struct k_heap *heap, + void *ptr, bool grant_ll_domain, bool expect_fault) +{ + int ret; + + k_thread_create(&user_thread, user_stack, USER_STACKSIZE, + user_function, heap, (void *)(uintptr_t)test_case, ptr, + -1, K_USER, K_FOREVER); + + if (grant_ll_domain) + k_mem_domain_add_thread(zephyr_ll_mem_domain(), &user_thread); + + if (expect_fault) + sof_boot_test_set_fault_valid(&user_thread); + + k_thread_start(&user_thread); + ret = k_thread_join(&user_thread, K_FOREVER); + zassert_equal(ret, 0, "user thread join failed: %d", ret); +} + +static void test_user_thread_heap_alloc(enum heap_alloc_test_case test_case) +{ + bool grant_ll_domain = true; + bool expect_fault = false; + void *ptr = NULL; + struct k_heap *heap; + + heap = zephyr_ll_user_heap(); + zassert_not_null(heap, "user heap not found"); + + switch (test_case) { + case HEAP_ALLOC_VALID: + break; + case HEAP_ALLOC_NULL_HEAP: + case HEAP_ALLOC_FORBIDDEN_FLAGS: + case HEAP_FREE_NON_HEAP_POINTER: + expect_fault = true; + break; + case HEAP_FREE_INACCESSIBLE_POINTER: + ptr = sof_heap_alloc(heap, SOF_MEM_FLAG_USER, 128, 0); + zassert_not_null(ptr, "kernel heap allocation failed"); + grant_ll_domain = false; + expect_fault = true; + break; + default: + zassert_unreachable("unknown heap allocation test case"); + } + + run_user_heap_alloc_case(test_case, heap, ptr, grant_ll_domain, expect_fault); + + sof_heap_free(heap, ptr); +} + +ZTEST(sof_boot, user_space_heap_alloc) +{ + test_user_thread_heap_alloc(HEAP_ALLOC_VALID); +} + +ZTEST(sof_boot, user_space_heap_alloc_rejects_null_heap) +{ + test_user_thread_heap_alloc(HEAP_ALLOC_NULL_HEAP); +} + +ZTEST(sof_boot, user_space_heap_alloc_rejects_forbidden_flags) +{ + test_user_thread_heap_alloc(HEAP_ALLOC_FORBIDDEN_FLAGS); +} + +ZTEST(sof_boot, user_space_heap_free_rejects_non_heap_pointer) +{ + k_mem_domain_add_partition(zephyr_ll_mem_domain(), &heap_alloc_test_part); + + test_user_thread_heap_alloc(HEAP_FREE_NON_HEAP_POINTER); + + k_mem_domain_remove_partition(zephyr_ll_mem_domain(), &heap_alloc_test_part); +} + +ZTEST(sof_boot, user_space_heap_free_rejects_inaccessible_pointer) +{ + test_user_thread_heap_alloc(HEAP_FREE_INACCESSIBLE_POINTER); +} diff --git a/zephyr/test/userspace/test_intel_hda_dma.c b/zephyr/test/userspace/test_intel_hda_dma.c new file mode 100644 index 000000000000..dd54e6d85f2a --- /dev/null +++ b/zephyr/test/userspace/test_intel_hda_dma.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2025 Intel Corporation. + */ + +/* + * Test case for user-space use of the SOF DMA interface. The tests + * transfer data from DSP to host using the host HD DMA instance. + * The test uses the cavstool.py infrastructure to perform host side + * programming of the HDA DMA, and to verify the transferred data. + * + * This test is based on the Zephyr kernel tests for Intel HD DMA + * driver (zephyr/tests/boards/intel_adsp/hda/) written by Tom + * Burdick. This test performs only subset of flows. Driver testing + * should primarily done with the Zephyr kernel tests and this test + * is solely to test the added syscall layer added in SOF. + */ + +#include <sof/boot_test.h> + +#include <zephyr/kernel.h> +#include <zephyr/ztest.h> +#include <zephyr/logging/log.h> +#include <sof/lib/dma.h> + +LOG_MODULE_DECLARE(sof_boot_test, LOG_LEVEL_DBG); + +#define USER_STACKSIZE 2048 +#define TEST_BUF_SIZE 256 +#define TEST_CHANNEL 0 +#define HD_DMA_BUF_ALIGN 128 + +static struct k_thread user_thread; +static K_THREAD_STACK_DEFINE(user_stack, USER_STACKSIZE); + +K_SEM_DEFINE(ipc_sem_wake_user, 0, 1); +K_SEM_DEFINE(ipc_sem_wake_kernel, 0, 1); + +static void intel_hda_dma_user(void *p1, void *p2, void *p3) +{ + uint8_t data_buf[TEST_BUF_SIZE] __aligned(HD_DMA_BUF_ALIGN); + struct dma_block_config dma_block_cfg; + struct dma_config config; + struct dma_status stat; + struct sof_dma *dma; + uint32_t addr_align; + int err, channel; + + zassert_true(k_is_user_context(), "isn't user"); + + LOG_INF("SOF thread %s (%s)", + k_is_user_context() ? "UserSpace!" : "privileged mode.", + CONFIG_BOARD_TARGET); + + /* + * note: this gets a pointer to kernel memory this thread + * cannot access + */ + dma = sof_dma_get(SOF_DMA_DIR_LMEM_TO_HMEM, 0, SOF_DMA_DEV_HOST, SOF_DMA_ACCESS_SHARED); + + k_sem_take(&ipc_sem_wake_user, K_FOREVER); + LOG_INF("configure DMA channel"); + + channel = sof_dma_request_channel(dma, TEST_CHANNEL); + zassert_equal(channel, TEST_CHANNEL); + LOG_INF("sof_dma_request_channel: ret %d", channel); + + err = sof_dma_get_attribute(dma, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, + &addr_align); + zassert_equal(err, 0); + zassert_true(addr_align == HD_DMA_BUF_ALIGN); + + /* set up a DMA transfer */ + memset(&dma_block_cfg, 0, sizeof(dma_block_cfg)); + dma_block_cfg.dest_address = 0; /* host fifo */ + dma_block_cfg.source_address = (uintptr_t)data_buf; + dma_block_cfg.block_size = sizeof(data_buf); + + /* + * fill data ramp, this payload is expected by host test + * harness + */ + for (uint32_t i = 0; i < TEST_BUF_SIZE; i++) { + data_buf[i] = i & 0xff; + } + sys_cache_data_flush_range(data_buf, sizeof(data_buf)); + + memset(&config, 0, sizeof(config)); + config.channel_direction = MEMORY_TO_HOST; + config.block_count = 1; + config.head_block = &dma_block_cfg; + + err = sof_dma_config(dma, channel, &config); + zassert_equal(err, 0); + LOG_INF("sof_dma_config: success"); + + err = sof_dma_start(dma, channel); + zassert_equal(err, 0); + LOG_INF("sof_dma_start: ch %d", channel); + + k_sem_give(&ipc_sem_wake_kernel); + LOG_INF("setup ready, waiting for kernel to configure host-side of the test"); + k_sem_take(&ipc_sem_wake_user, K_FOREVER); + LOG_INF("start DMA test and transfer data"); + + err = sof_dma_get_status(dma, channel, &stat); + zassert_equal(err, 0); + LOG_INF("sof_dma_get_status start: pend %u free %u", + stat.pending_length, stat.free); + + err = sof_dma_reload(dma, channel, sizeof(data_buf)); + zassert_equal(err, 0); + + for (int i = 0; stat.pending_length < TEST_BUF_SIZE; i++) { + err = sof_dma_get_status(dma, channel, &stat); + zassert_equal(err, 0); + LOG_INF("sof_dma_get_status %d: pend %u free %u", i, + stat.pending_length, stat.free); + + zassert_true(i < 100, "DMA transfer completes in 100usec"); + + /* let DMA transfer complete */ + k_sleep(K_USEC(1)); + } + + err = sof_dma_get_status(dma, channel, &stat); + zassert_equal(err, 0); + LOG_INF("sof_dma_get_status end: pend %u free %u", + stat.pending_length, stat.free); + + LOG_INF("transfer done, asking host to validate output"); + k_sem_give(&ipc_sem_wake_kernel); + k_sem_take(&ipc_sem_wake_user, K_FOREVER); + LOG_INF("test done, cleaning up resources"); + + err = sof_dma_stop(dma, channel); + zassert_equal(err, 0); + + sof_dma_release_channel(dma, channel); + + sof_dma_put(dma); + + LOG_INF("DMA stopped and resources freed"); + + k_sem_give(&ipc_sem_wake_kernel); +} + +#define IPC_TIMEOUT K_MSEC(1500) +#define DMA_BUF_SIZE 256 + +#define ALIGNMENT DMA_BUF_ADDR_ALIGNMENT(DT_NODELABEL(hda_host_in)) +static __aligned(ALIGNMENT) uint8_t dma_buf[DMA_BUF_SIZE]; + +#include <intel_adsp_hda.h> +#include <../../../../zephyr/tests/boards/intel_adsp/hda/src/tests.h> + +static int msg_validate_res; + +static bool ipc_message(const struct device *dev, void *arg, + uint32_t data, uint32_t ext_data) +{ + LOG_DBG("HDA message received, data %u, ext_data %u", data, ext_data); + msg_validate_res = ext_data; + return true; +} + +static void intel_hda_dma_kernel(void) +{ + const struct device *dma; + + LOG_INF("run %s with buffer at address %p, size %d", + __func__, (void *)dma_buf, DMA_BUF_SIZE); + + intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, ipc_message, NULL); + + k_thread_create(&user_thread, user_stack, USER_STACKSIZE, + intel_hda_dma_user, NULL, NULL, NULL, + -1, K_USER, K_FOREVER); + + k_thread_access_grant(&user_thread, &ipc_sem_wake_user); + k_thread_access_grant(&user_thread, &ipc_sem_wake_kernel); + + dma = DEVICE_DT_GET(DT_NODELABEL(hda_host_in)); + k_thread_access_grant(&user_thread, dma); + + hda_ipc_msg(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_HDA_RESET, + TEST_CHANNEL, IPC_TIMEOUT); + + hda_ipc_msg(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_HDA_CONFIG, + TEST_CHANNEL | (DMA_BUF_SIZE << 8), IPC_TIMEOUT); + + k_thread_start(&user_thread); + + LOG_INF("user started, waiting for it to be ready"); + + k_sem_give(&ipc_sem_wake_user); + k_sem_take(&ipc_sem_wake_kernel, K_FOREVER); + + LOG_INF("user ready, starting HDA test"); + + hda_ipc_msg(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_HDA_START, TEST_CHANNEL, IPC_TIMEOUT); + + k_sem_give(&ipc_sem_wake_user); + k_sem_take(&ipc_sem_wake_kernel, K_FOREVER); + + LOG_INF("transfer done, validating results"); + + hda_ipc_msg(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_HDA_VALIDATE, TEST_CHANNEL, + IPC_TIMEOUT); + + hda_dump_regs(HOST_OUT, HDA_REGBLOCK_SIZE, TEST_CHANNEL, "host reset"); + + k_sem_give(&ipc_sem_wake_user); + k_sem_take(&ipc_sem_wake_kernel, K_FOREVER); + + LOG_INF("test done, terminate user thread"); + + k_thread_join(&user_thread, K_FOREVER); + + zassert_true(msg_validate_res == 1, "DMA transferred data invalid payload"); +} + +ZTEST(userspace_intel_hda_dma, dma_mem_to_host) +{ + intel_hda_dma_kernel(); + + ztest_test_pass(); +} + +ZTEST_SUITE(userspace_intel_hda_dma, NULL, NULL, NULL, NULL, NULL); + +/** + * SOF main has booted up and IPC handling is stopped. + * Run test suites with ztest_run_all. + */ +static int run_tests(void) +{ + ztest_run_test_suite(userspace_intel_hda_dma, false, 1, 1, NULL); + return 0; +} + +SYS_INIT(run_tests, APPLICATION, 99); diff --git a/zephyr/test/userspace/test_intel_ssp_dai.c b/zephyr/test/userspace/test_intel_ssp_dai.c new file mode 100644 index 000000000000..6c700c3839bb --- /dev/null +++ b/zephyr/test/userspace/test_intel_ssp_dai.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2025 Intel Corporation. + */ + +/* + * Test case for user-space use of the SOF DMA interface. The tests + * covers all key interfaces of DMA and DAI, testing their use from + * a user-space threads. Due to hardware constraints, the actual DMA + * transfers cannot be tested as this would require cooperation with a + * host entity that would manage the HDA link DMA in sync with the DP + * test case. Test does check all programming can be done and no + * errors are raised from the drivers. Valid configuration blobs are + * passed, to fully exercise the drivers interfaces. + + * Requirements for host side test execution environment: + * - I2S offload must be enabled on host side (HDAMLI2S) to allow + * the DAI driver to access hardware registers. + */ + +#include <sof/boot_test.h> + +#include <zephyr/kernel.h> +#include <zephyr/ztest.h> +#include <zephyr/logging/log.h> +#include <sof/lib/dai.h> +#include <sof/lib/uuid.h> +#include <sof/lib/dma.h> +#include <sof/audio/component_ext.h> + +#include "../../../src/audio/copier/dai_copier.h" +#include "../../../../zephyr/drivers/dai/intel/ssp/ssp.h" + +LOG_MODULE_DECLARE(sof_boot_test, LOG_LEVEL_DBG); + +#define USER_STACKSIZE 8192 +#define HD_DMA_BUF_ALIGN 128 +#define TEST_BUF_SIZE (2*HD_DMA_BUF_ALIGN) +#define TEST_CHANNEL_OUT 3 +#define TEST_CHANNEL_IN 4 +#define SSP_DEVICE ssp00 + +static struct k_thread user_thread; +static K_THREAD_STACK_DEFINE(user_stack, USER_STACKSIZE); + +static K_SEM_DEFINE(ipc_sem_wake_user, 0, 1); +static K_SEM_DEFINE(ipc_sem_wake_kernel, 0, 1); + +static int call_dai_set_ssp_v3_config_48k_2ch_32bit(const struct device *dai_dev) +{ + union hdalink_cfg link_cfg; + const uint8_t stream_id = 0; + + link_cfg.full = 0; + link_cfg.part.dir = DAI_DIR_TX; + link_cfg.part.stream = stream_id; + + struct dai_config common_config = { + .type = DAI_INTEL_SSP_NHLT, + .dai_index = 0, + .channels = 2, + .rate = 48000, + .format = DAI_CBC_CFC | DAI_PROTO_I2S | DAI_INVERSION_NB_NF, + .options = 0, + .word_size = 32, + .block_size = 0, + .link_config = link_cfg.full, + .tdm_slot_group = 0 + }; + + /* + * There are no suitable struct definitions to create these + * config objects, so we have to define a custom type that + * includes the common header, a single MDIV entry, one TLV + * entry and the link_ctl struct. These are normally part of + * ACPI NHLT and can be alternatively created with alsa-utils + * nhlt plugin. + */ + struct { + struct dai_intel_ipc4_ssp_configuration_blob_ver_3_0 b; + uint32_t mdivr0; + uint32_t type; + uint32_t size; + struct ssp_intel_link_ctl link_ctl; + } __packed blob30; + + memset(&blob30, 0, sizeof(blob30)); + /* DAI config blob header for SSP v3 */ + blob30.b.version = SSP_BLOB_VER_3_0; + blob30.b.size = sizeof(blob30); + /* I2S config matching sof-ptl-nocodec.tplg (32bit/48kHz/2ch) */ + blob30.b.i2s_ssp_config.ssc0 = 0x81d0077f; + blob30.b.i2s_ssp_config.ssc1 = 0xd0400004; + blob30.b.i2s_ssp_config.sscto = 0; + blob30.b.i2s_ssp_config.sspsp = 0x02200000; + blob30.b.i2s_ssp_config.ssc2 = 0x00004002; + blob30.b.i2s_ssp_config.sspsp2 = 0; + blob30.b.i2s_ssp_config.ssc3 = 0; + blob30.b.i2s_ssp_config.ssioc = 0x00000020; + /* clock control settings matching sof-ptl-nocodec.tplg */ + blob30.b.i2s_mclk_control.mdivctlr = 0x00010001; + blob30.b.i2s_mclk_control.mdivrcnt = 1; + /* variable-size section of clock control, one entry for mdivr */ + blob30.mdivr0 = 0xfff; + /* aux-data with one TLV entry for link-clk-source */ + blob30.type = SSP_LINK_CLK_SOURCE; + blob30.size = sizeof(struct ssp_intel_link_ctl); + blob30.link_ctl.clock_source = 1; + + return dai_config_set(dai_dev, &common_config, &blob30, sizeof(blob30)); +} + +static void intel_ssp_dai_user(void *p1, void *p2, void *p3) +{ + struct dma_block_config dma_block_cfg; + struct sof_dma *dma_in, *dma_out; + uint8_t data_buf_out[TEST_BUF_SIZE] __aligned(HD_DMA_BUF_ALIGN); + uint8_t data_buf_in[TEST_BUF_SIZE] __aligned(HD_DMA_BUF_ALIGN); + uint32_t addr_align = 0; + const struct device *dai_dev; + struct dai_properties dai_props; + struct dma_config config; + struct dma_status stat; + int err, channel_out, channel_in; + + zassert_true(k_is_user_context()); + + /* + * note: this gets a pointer to kernel memory this thread + * cannot access + */ + dma_in = sof_dma_get(SOF_DMA_DIR_DEV_TO_MEM, 0, SOF_DMA_DEV_SSP, SOF_DMA_ACCESS_SHARED); + dma_out = sof_dma_get(SOF_DMA_DIR_MEM_TO_DEV, 0, SOF_DMA_DEV_SSP, SOF_DMA_ACCESS_SHARED); + + k_sem_take(&ipc_sem_wake_user, K_FOREVER); + + LOG_INF("create a DAI device for %s", STRINGIFY(SSP_DEVICE)); + + dai_dev = DEVICE_DT_GET(DT_NODELABEL(SSP_DEVICE)); + err = dai_probe(dai_dev); + zassert_equal(err, 0); + + channel_out = sof_dma_request_channel(dma_out, TEST_CHANNEL_OUT); + zassert_equal(channel_out, TEST_CHANNEL_OUT); + LOG_INF("sof_dma_request_channel (out): ret ch %d", channel_out); + channel_in = sof_dma_request_channel(dma_in, TEST_CHANNEL_IN); + zassert_equal(channel_in, TEST_CHANNEL_IN); + LOG_INF("sof_dma_request_channel (in): ret ch %d", channel_in); + + err = sof_dma_get_attribute(dma_out, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, + &addr_align); + zassert_equal(err, 0); + zassert_true(addr_align == HD_DMA_BUF_ALIGN); + + /* set up a DMA transfer */ + memset(&dma_block_cfg, 0, sizeof(dma_block_cfg)); + + err = dai_get_properties_copy(dai_dev, DAI_DIR_TX, 0, &dai_props); + zassert_equal(err, 0); + + LOG_INF("dai_get_properties_copy (TX), ret %d, fifo %u", err, dai_props.fifo_address); + + dma_block_cfg.dest_address = dai_props.fifo_address; /* dai fifo */ + dma_block_cfg.source_address = (uintptr_t)data_buf_out; + dma_block_cfg.block_size = sizeof(data_buf_out); + + memset(&config, 0, sizeof(config)); + config.channel_direction = MEMORY_TO_PERIPHERAL; + config.block_count = 1; + config.head_block = &dma_block_cfg; + config.source_data_size = 4; + config.dest_data_size = 4; + + err = sof_dma_config(dma_out, channel_out, &config); + zassert_equal(err, 0); + + err = dai_get_properties_copy(dai_dev, DAI_DIR_RX, 0, &dai_props); + zassert_equal(err, 0); + LOG_INF("dai_get_properties_copy (RX), ret %d, fifo %u", err, dai_props.fifo_address); + + dma_block_cfg.dest_address = (uintptr_t)data_buf_in; + dma_block_cfg.source_address = dai_props.fifo_address; /* dai fifo */ + dma_block_cfg.block_size = sizeof(data_buf_in); + + config.channel_direction = PERIPHERAL_TO_MEMORY; + config.block_count = 1; + + err = sof_dma_config(dma_in, channel_in, &config); + zassert_equal(err, 0, "dma-config error"); + + err = call_dai_set_ssp_v3_config_48k_2ch_32bit(dai_dev); + zassert_equal(err, 0); + LOG_INF("DAI configuration ready, sync with kernel on start"); + + k_sem_give(&ipc_sem_wake_kernel); + k_sem_take(&ipc_sem_wake_user, K_FOREVER); + LOG_INF("start DMA test and transfer data"); + + err = dai_trigger(dai_dev, DAI_DIR_RX, DAI_TRIGGER_PRE_START); + zassert_equal(err, 0); + + err = dai_trigger(dai_dev, DAI_DIR_TX, DAI_TRIGGER_PRE_START); + zassert_equal(err, 0); + LOG_INF("dai_trigger RX+TX PRE_START done"); + + err = sof_dma_get_status(dma_in, channel_in, &stat); + zassert_equal(err, 0); + LOG_INF("sof_dma_get_status ( dma_in/start):\tpend %3u free %3u", + stat.pending_length, stat.free); + + err = sof_dma_get_status(dma_out, channel_out, &stat); + zassert_equal(err, 0); + LOG_INF("sof_dma_get_status (dma_out/start):\tpend %3u free %3u", + stat.pending_length, stat.free); + + err = sof_dma_start(dma_in, channel_in); + zassert_equal(err, 0); + + err = sof_dma_start(dma_out, channel_out); + zassert_equal(err, 0); + + err = dai_trigger(dai_dev, DAI_DIR_RX, DAI_TRIGGER_START); + zassert_equal(err, 0); + + err = dai_trigger(dai_dev, DAI_DIR_TX, DAI_TRIGGER_START); + zassert_equal(err, 0); + LOG_INF("DMAs and DAIs started."); + + k_sleep(K_USEC(10)); + + err = sof_dma_get_status(dma_in, channel_in, &stat); + zassert_equal(err, 0); + /* after start, there should be at least some free data */ + zassert_true(stat.free > 0); + zassert_true(stat.pending_length < TEST_BUF_SIZE); + LOG_INF("sof_dma_get_status ( dma_in/run):\tpend %3u free %3u", + stat.pending_length, stat.free); + + err = sof_dma_reload(dma_in, channel_in, sizeof(data_buf_in)); + zassert_equal(err, 0); + + err = sof_dma_get_status(dma_in, channel_in, &stat); + zassert_equal(err, 0); + /* after reload, there should be at least some data pending */ + zassert_true(stat.free < TEST_BUF_SIZE); + zassert_true(stat.pending_length > 0); + + err = sof_dma_get_status(dma_out, channel_out, &stat); + zassert_equal(err, 0); + LOG_INF("sof_dma_get_status (dma_out/run):\tpend %3u free %3u", + stat.pending_length, stat.free); + zassert_true(stat.free < TEST_BUF_SIZE); + zassert_true(stat.pending_length > 0); + + LOG_INF("DMA setup done, asking host to clean up "); + k_sem_give(&ipc_sem_wake_kernel); + k_sem_take(&ipc_sem_wake_user, K_FOREVER); + LOG_INF("Cleaning up resources"); + + err = sof_dma_stop(dma_out, channel_out); + zassert_equal(err, 0); + + err = sof_dma_stop(dma_in, channel_in); + zassert_equal(err, 0); + + err = dai_trigger(dai_dev, DAI_DIR_TX, DAI_TRIGGER_STOP); + zassert_equal(err, 0); + + err = dai_trigger(dai_dev, DAI_DIR_RX, DAI_TRIGGER_STOP); + zassert_equal(err, 0); + + sof_dma_release_channel(dma_out, channel_out); + + sof_dma_release_channel(dma_in, channel_in); + + err = dai_remove(dai_dev); + zassert_equal(err, 0); + + sof_dma_put(dma_in); + sof_dma_put(dma_out); + + LOG_INF("Cleanup successful, terminating user thread."); + + k_sem_give(&ipc_sem_wake_kernel); +} + +static void intel_ssp_dai_kernel(void) +{ + const struct device *dma_out, *dma_in; + const struct device *dai_dev; + + k_thread_create(&user_thread, user_stack, USER_STACKSIZE, + intel_ssp_dai_user, NULL, NULL, NULL, + -1, K_USER, K_FOREVER); + + k_thread_access_grant(&user_thread, &ipc_sem_wake_user); + k_thread_access_grant(&user_thread, &ipc_sem_wake_kernel); + + dma_out = DEVICE_DT_GET(DT_NODELABEL(hda_link_out)); + dma_in = DEVICE_DT_GET(DT_NODELABEL(hda_link_in)); + dai_dev = DEVICE_DT_GET(DT_NODELABEL(SSP_DEVICE)); + + k_thread_access_grant(&user_thread, dma_out); + k_thread_access_grant(&user_thread, dma_in); + k_thread_access_grant(&user_thread, dai_dev); + + k_thread_start(&user_thread); + + LOG_INF("user started, waiting for it to be ready"); + + k_sem_give(&ipc_sem_wake_user); + k_sem_take(&ipc_sem_wake_kernel, K_FOREVER); + + LOG_INF("user ready, starting HDA test"); + + k_sem_give(&ipc_sem_wake_user); + k_sem_take(&ipc_sem_wake_kernel, K_FOREVER); + + LOG_INF("transfer done, grant permission to clean up"); + + k_sem_give(&ipc_sem_wake_user); + k_sem_take(&ipc_sem_wake_kernel, K_FOREVER); + + LOG_INF("test done, terminate user thread"); + + k_thread_join(&user_thread, K_FOREVER); +} + +ZTEST(userspace_intel_dai_ssp, dai_ssp_loopback_setup) +{ + intel_ssp_dai_kernel(); + + ztest_test_pass(); +} + +ZTEST_SUITE(userspace_intel_dai_ssp, NULL, NULL, NULL, NULL, NULL); + +/** + * SOF main has booted up and IPC handling is stopped. + * Run test suites with ztest_run_all. + */ +static int run_tests(void) +{ + ztest_run_test_suite(userspace_intel_dai_ssp, false, 1, 1, NULL); + return 0; +} + +SYS_INIT(run_tests, APPLICATION, 99); diff --git a/zephyr/test/userspace/test_ll_task.c b/zephyr/test/userspace/test_ll_task.c new file mode 100644 index 000000000000..234423defc60 --- /dev/null +++ b/zephyr/test/userspace/test_ll_task.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2026 Intel Corporation. + */ + +/* + * Test case for creation of low-latency threads in user-space. + */ + +#include <sof/boot_test.h> +#include <sof/lib/mailbox.h> +#include <sof/lib/uuid.h> +#include <sof/schedule/schedule.h> +#include <sof/schedule/ll_schedule.h> +#include <sof/schedule/ll_schedule_domain.h> +#include <sof/audio/pipeline.h> +#include <rtos/task.h> +#include <rtos/userspace_helper.h> +#include <ipc4/fw_reg.h> + +#include <zephyr/kernel.h> +#include <zephyr/ztest.h> +#include <zephyr/logging/log.h> +#include <zephyr/app_memory/app_memdomain.h> + +#include <stddef.h> /* offsetof() */ + +LOG_MODULE_DECLARE(sof_boot_test, LOG_LEVEL_DBG); + +/* f11818eb-e92e-4082-82a3-dc54c604ebf3 */ +SOF_DEFINE_UUID("test_task", test_task_uuid, 0xf11818eb, 0xe92e, 0x4082, + 0x82, 0xa3, 0xdc, 0x54, 0xc6, 0x04, 0xeb, 0xf3); + +K_APPMEM_PARTITION_DEFINE(userspace_ll_part); + +/* Global variable for test runs counter, accessible from user-space */ +K_APP_BMEM(userspace_ll_part) static int test_runs; + +static enum task_state task_callback(void *arg) +{ + LOG_INF("entry"); + + if (++test_runs > 3) + return SOF_TASK_STATE_COMPLETED; + + return SOF_TASK_STATE_RESCHEDULE; +} + +static void ll_task_test(void) +{ + struct task *task; + int priority = 0; + int core = 0; + int ret; + + /* Initialize global test runs counter */ + test_runs = 0; + + task = zephyr_ll_task_alloc(); + zassert_not_null(task, "task allocation failed"); + + /* allow user space to report status via 'test_runs' */ + k_mem_domain_add_partition(zephyr_ll_mem_domain(), &userspace_ll_part); + + /* work in progress, see pipeline-schedule.c */ + ret = schedule_task_init_ll(task, SOF_UUID(test_task_uuid), SOF_SCHEDULE_LL_TIMER, + priority, task_callback, + (void *)&test_runs, core, 0); + zassert_equal(ret, 0); + + LOG_INF("task init done"); + + /* Schedule the task to run immediately with 1ms period */ + ret = schedule_task(task, 0, 1000); /* 0 = start now, 1000us = 1ms period */ + zassert_equal(ret, 0); + + LOG_INF("task scheduled and running"); + + /* Let the task run for a bit */ + k_sleep(K_MSEC(10)); + + /* Cancel the task to stop any scheduled execution */ + ret = schedule_task_cancel(task); + zassert_equal(ret, 0); + + /* Free task resources */ + ret = schedule_task_free(task); + zassert_equal(ret, 0); + + LOG_INF("test complete"); +} + +ZTEST(userspace_ll, ll_task_test) +{ + ll_task_test(); +} + +static void pipeline_check(void) +{ + struct pipeline *p; + struct k_heap *heap; + uint32_t pipeline_id = 1; + uint32_t priority = 5; + uint32_t comp_id = 10; + int ret; + + heap = zephyr_ll_user_heap(); + zassert_not_null(heap, "user heap not found"); + + /* Create pipeline on user heap */ + p = pipeline_new(heap, pipeline_id, priority, comp_id, NULL); + zassert_not_null(p, "pipeline creation failed"); + + /* Verify heap assignment */ + zassert_equal(p->heap, heap, "pipeline heap not equal to user heap"); + + /* Verify pipeline properties */ + zassert_equal(p->pipeline_id, pipeline_id, "pipeline id mismatch"); + zassert_equal(p->priority, priority, "priority mismatch"); + zassert_equal(p->comp_id, comp_id, "comp id mismatch"); + + /* Free pipeline */ + ret = pipeline_free(p); + zassert_ok(ret, "pipeline free failed"); +} + +ZTEST(userspace_ll, pipeline_check) +{ + pipeline_check(); +} + +ZTEST_SUITE(userspace_ll, NULL, NULL, NULL, NULL, NULL); + +/** + * SOF main has booted up and IPC handling is stopped. + * Run test suites with ztest_run_all. + */ +static int run_tests(void) +{ + ztest_run_test_suite(userspace_ll, false, 1, 1, NULL); + return 0; +} + +SYS_INIT(run_tests, APPLICATION, 99); diff --git a/zephyr/test/userspace/test_mailbox.c b/zephyr/test/userspace/test_mailbox.c new file mode 100644 index 000000000000..766dababb553 --- /dev/null +++ b/zephyr/test/userspace/test_mailbox.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2026 Intel Corporation. + */ + +/* + * Test case for sof/mailbox.h interface use from a Zephyr user + * thread. + */ + +#include <sof/boot_test.h> +#include <sof/lib/mailbox.h> +#include <rtos/userspace_helper.h> + +#include <zephyr/kernel.h> +#include <zephyr/ztest.h> +#include <zephyr/logging/log.h> +#include <zephyr/app_memory/app_memdomain.h> + +#include <ipc4/fw_reg.h> /* mailbox definitions */ + +LOG_MODULE_DECLARE(sof_boot_test, LOG_LEVEL_DBG); + +#define USER_STACKSIZE 2048 + +static struct k_thread user_thread; +static K_THREAD_STACK_DEFINE(user_stack, USER_STACKSIZE); + +static void mailbox_write_to_pipeline_regs(void) +{ + unsigned int offset = offsetof(struct ipc4_fw_registers, pipeline_regs); + struct ipc4_pipeline_registers pipe_reg; + + /* + * IPC4 pipe_reg struct used for test, but this test also + * works for IPC3 targets. + */ + pipe_reg.stream_start_offset = (uint64_t)-1; + pipe_reg.stream_end_offset = (uint64_t)-1; + + LOG_INF("Write to sw_regs mailbox at offset %u", offset); + + mailbox_sw_regs_write(offset, &pipe_reg, sizeof(pipe_reg)); +} + +static void mailbox_test_thread(void *p1, void *p2, void *p3) +{ + zassert_true(k_is_user_context(), "isn't user"); + + LOG_INF("SOF thread %s (%s)", + k_is_user_context() ? "UserSpace!" : "privileged mode.", + CONFIG_BOARD_TARGET); + + mailbox_write_to_pipeline_regs(); +} + +static void mailbox_test(void) +{ + struct k_mem_domain domain; + int ret = k_mem_domain_init(&domain, 0, NULL); + + zassert_equal(ret, 0); + + k_thread_create(&user_thread, user_stack, USER_STACKSIZE, + mailbox_test_thread, NULL, NULL, NULL, + -1, K_USER, K_FOREVER); + + LOG_INF("set up user access to mailbox"); + + ret = user_access_to_mailbox(&domain, &user_thread); + zassert_equal(ret, 0); + + k_thread_start(&user_thread); + + LOG_INF("user started, waiting in kernel until test complete"); + + k_thread_join(&user_thread, K_FOREVER); +} + +ZTEST(userspace_mailbox, mailbox_test) +{ + /* first test from kernel */ + mailbox_write_to_pipeline_regs(); + + /* then full test in userspace */ + mailbox_test(); + + ztest_test_pass(); +} + +ZTEST_SUITE(userspace_mailbox, NULL, NULL, NULL, NULL, NULL); + +/** + * SOF main has booted up and IPC handling is stopped. + * Run test suites with ztest_run_all. + */ +static int run_tests(void) +{ + ztest_run_test_suite(userspace_mailbox, false, 1, 1, NULL); + return 0; +} + +SYS_INIT(run_tests, APPLICATION, 99); diff --git a/zephyr/test/vmh.c b/zephyr/test/vmh.c index c7d3d1882cc6..abb00b561b3d 100644 --- a/zephyr/test/vmh.c +++ b/zephyr/test/vmh.c @@ -17,20 +17,16 @@ #include <zephyr/ztest.h> LOG_MODULE_DECLARE(sof_boot_test, CONFIG_SOF_LOG_LEVEL); +struct vmh_heap; /* Test creating and freeing a virtual memory heap */ -static void test_vmh_init_and_free_heap(int memory_region_attribute, - struct vmh_heap_config *config, - int core_id, +static void test_vmh_init_and_free_heap(struct vmh_heap_config *config, bool allocating_continuously, bool expect_success) { - struct vmh_heap *heap = vmh_init_heap(config, memory_region_attribute, - core_id, allocating_continuously); - if (expect_success) { - zassert_not_null(heap, - "Heap initialization expected to succeed but failed"); - } + struct vmh_heap *heap = vmh_init_heap(config, allocating_continuously); + if (expect_success) + zassert_not_null(heap, "Heap initialization expected to succeed but failed"); else zassert_is_null(heap, "Heap initialization expected to fail but succeeded"); @@ -112,7 +108,6 @@ static void test_vmh_multiple_allocs(struct vmh_heap *heap, int num_allocs, { void *ptrs[num_allocs]; uint32_t alloc_size; - bool success; int ret; /* Perform multiple allocations */ @@ -146,7 +141,7 @@ static void test_vmh_multiple_allocs(struct vmh_heap *heap, int num_allocs, static void test_vmh_alloc_multiple_times(bool allocating_continuously) { struct vmh_heap *heap = - vmh_init_heap(NULL, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); + vmh_init_heap(NULL, allocating_continuously); zassert_not_null(heap, "Heap initialization failed"); @@ -170,7 +165,7 @@ static void test_vmh_alloc_multiple_times(bool allocating_continuously) static void test_vmh_alloc_free(bool allocating_continuously) { struct vmh_heap *heap = - vmh_init_heap(NULL, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); + vmh_init_heap(NULL, allocating_continuously); zassert_not_null(heap, "Heap initialization failed"); @@ -194,7 +189,7 @@ static void test_vmh_alloc_free(bool allocating_continuously) /* Test case for vmh_alloc and vmh_free with and without config */ static void test_heap_creation(void) { - test_vmh_init_and_free_heap(MEM_REG_ATTR_CORE_HEAP, NULL, 0, false, true); + test_vmh_init_and_free_heap(NULL, false, true); /* Try to setup with pre defined heap config */ struct vmh_heap_config config = {0}; @@ -207,7 +202,7 @@ static void test_heap_creation(void) config.block_bundles_table[1].number_of_blocks = 512; - test_vmh_init_and_free_heap(MEM_REG_ATTR_CORE_HEAP, &config, 0, false, true); + test_vmh_init_and_free_heap(&config, false, true); } /* Test case for alloc/free on configured heap */ @@ -223,7 +218,7 @@ static void test_alloc_on_configured_heap(bool allocating_continuously) /* Create continuous allocation heap for success test */ struct vmh_heap *heap = - vmh_init_heap(&config, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); + vmh_init_heap(&config, allocating_continuously); /* Will succeed on continuous and fail with single block alloc */ test_vmh_alloc_free_check(heap, 512, allocating_continuously); @@ -233,42 +228,9 @@ static void test_alloc_on_configured_heap(bool allocating_continuously) zassert_equal(ret, 0, "Failed to free heap"); } -/* Test cases for initializing heaps on all available regions */ -static void test_vmh_init_all_heaps(void) -{ - int num_regions = CONFIG_MP_MAX_NUM_CPUS + VIRTUAL_REGION_COUNT; - int i; - const struct sys_mm_drv_region *virtual_memory_region = - sys_mm_drv_query_memory_regions(); - - /* Test initializing all types of heaps */ - for (i = 0; i < num_regions; i++) { - - /* Zeroed size symbolizes end of regions table */ - if (!virtual_memory_region[i].size) - break; - - struct vmh_heap *heap = vmh_init_heap(NULL, virtual_memory_region[i].attr, - i, true); - - zassert_not_null(heap, "Heap initialization expected to succeed but failed"); - - /* Test if it fails when heap already exists */ - test_vmh_init_and_free_heap(virtual_memory_region[i].attr, NULL, i, true, - false); - - if (heap) { - int ret = vmh_free_heap(heap); - - zassert_equal(ret, 0, "Failed to free heap"); - } - } -} - ZTEST(sof_boot, virtual_memory_heap) { test_heap_creation(); - test_vmh_init_all_heaps(); test_alloc_on_configured_heap(true); test_alloc_on_configured_heap(false); test_vmh_alloc_free(true); diff --git a/zephyr/test/vpage.c b/zephyr/test/vpage.c new file mode 100644 index 000000000000..038e299eba70 --- /dev/null +++ b/zephyr/test/vpage.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2026 Intel Corporation. + */ + +#include <errno.h> +#include <stdbool.h> +#include <stdlib.h> + +#include <sof/boot_test.h> +#include <sof/lib/vpage.h> + +#include <zephyr/logging/log.h> +#include <zephyr/ztest.h> + +LOG_MODULE_DECLARE(sof_boot_test, CONFIG_SOF_LOG_LEVEL); + +ZTEST(sof_boot, vpage) +{ + void *p1 = vpage_alloc(1); + + zassert_not_null(p1); + + void *p2 = vpage_alloc(2); + + zassert_not_null(p2); + + vpage_free(p1); + vpage_free(p2); + + p1 = vpage_alloc(2); + + zassert_not_null(p1); + + vpage_free(p1); +} diff --git a/zephyr/test/vregion.c b/zephyr/test/vregion.c new file mode 100644 index 000000000000..eb36721d582e --- /dev/null +++ b/zephyr/test/vregion.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2026 Intel Corporation. + */ + +#include <errno.h> +#include <stdbool.h> +#include <stdlib.h> + +#include <sof/boot_test.h> +#include <sof/lib/vregion.h> + +#include <zephyr/logging/log.h> +#include <zephyr/ztest.h> + +LOG_MODULE_DECLARE(sof_boot_test, CONFIG_SOF_LOG_LEVEL); + +static struct vregion *test_vreg_create(void) +{ + /* + * Use a 3-page vregion so that after two lifetime allocations there is still + * enough remaining space to initialize and exercise the interim heap. + */ + struct vregion *vreg = vregion_create(3 * CONFIG_MM_DRV_PAGE_SIZE); + + zassert_not_null(vreg); + + return vreg; +} + +static void test_vreg_alloc_lifet(struct vregion *vreg) +{ + void *ptr = vregion_alloc(vreg, 6000); + + zassert_not_null(ptr); + + void *ptr_align = vregion_alloc_align(vreg, 5000, 16); + + zassert_not_null(ptr_align); + zassert_equal((uintptr_t)ptr_align & 15, 0); + + /* + * Seal lifetime, switch to interim. The interim heap is created + * lazily from the remaining ~1 page, so a 6000-byte alloc won't fit. + */ + vregion_set_interim(vreg); + + void *ptr_nomem = vregion_alloc(vreg, 6000); + + zassert_is_null(ptr_nomem); + + /* Lifetime frees are no-ops; re-alloc from interim still fails */ + vregion_free(vreg, ptr_align); + vregion_free(vreg, ptr); + + ptr_nomem = vregion_alloc(vreg, 6000); + + zassert_is_null(ptr_nomem); +} + +static void test_vreg_alloc_tmp(struct vregion *vreg) +{ + void *ptr = vregion_alloc(vreg, 20); + + zassert_not_null(ptr); + + void *ptr_align = vregion_alloc_align(vreg, 1000, 16); + + zassert_not_null(ptr_align); + zassert_equal((uintptr_t)ptr_align & 15, 0); + + void *ptr_nomem = vregion_alloc(vreg, 2000); + + zassert_is_null(ptr_nomem); + + vregion_free(vreg, ptr_align); + vregion_free(vreg, ptr); + + /* Should be possible to allocate again */ + ptr = vregion_alloc(vreg, 1000); + + zassert_not_null(ptr); +} + +static void test_vreg_destroy(struct vregion *vreg) +{ + vregion_info(vreg); + vregion_put(vreg); +} + +ZTEST(sof_boot, vregion) +{ + struct vregion *vreg = test_vreg_create(); + + /* Test lifetime allocations (initial mode), then seal */ + test_vreg_alloc_lifet(vreg); + /* Test interim allocations (already switched by lifet test) */ + test_vreg_alloc_tmp(vreg); + + test_vreg_destroy(vreg); +} diff --git a/zephyr/wrapper.c b/zephyr/wrapper.c index c2129347241e..e929135ce851 100644 --- a/zephyr/wrapper.c +++ b/zephyr/wrapper.c @@ -6,6 +6,8 @@ */ #include <sof/init.h> +#include <sof/boot_test.h> +#include <sof/llext_manager.h> #include <rtos/idc.h> #include <rtos/interrupt.h> #include <sof/drivers/interrupt-map.h> @@ -20,6 +22,9 @@ #include <sof/trace/trace.h> #include <rtos/wait.h> #include <rtos/clk.h> +#if CONFIG_IPC_MAJOR_4 +#include <ipc4/notification.h> +#endif /* Zephyr includes */ #include <zephyr/arch/cpu.h> @@ -53,7 +58,7 @@ const char irq_name_level2[] = "level2"; const char irq_name_level5[] = "level5"; /* imx currently has no IRQ driver in Zephyr so we force to xtos IRQ */ -#if defined(CONFIG_AMD) +#if defined(CONFIG_AMD) && !defined(CONFIG_ZEPHYR_NATIVE_DRIVERS) int interrupt_register(uint32_t irq, void(*handler)(void *arg), void *arg) { #ifdef CONFIG_DYNAMIC_INTERRUPTS @@ -187,8 +192,25 @@ static int boot_complete(void) */ return 0; #else + unsigned int status; + int ret = llext_manager_restore_from_dram(); + + switch (ret) { +#if CONFIG_IPC_MAJOR_4 + case 0: + status = SOF_IPC4_FW_READY_LIB_RESTORED; + break; +#endif + case -ENOSYS: + status = 0; + break; + default: + status = 0; + LOG_ERR("LLEXT restore failed: %d", ret); + } + /* let host know DSP boot is complete */ - return platform_boot_complete(0); + return platform_boot_complete(status); #endif /* CONFIG_IMX93_A55 */ } @@ -236,15 +258,24 @@ void platform_dai_timestamp(struct comp_dev *dai, posn->flags |= SOF_TIME_DAI_VALID; /* get SSP wallclock - DAI sets this to stream start value */ +#ifndef CONFIG_SOF_USERSPACE_LL posn->wallclock = sof_cycle_get_64() - posn->wallclock; posn->wallclock_hz = sys_cycle_get_64_rate(); +#else + posn->wallclock = k_uptime_ticks() - posn->wallclock; + posn->wallclock_hz = CONFIG_SYS_CLOCK_TICKS_PER_SEC; +#endif posn->flags |= SOF_TIME_WALL_VALID; } /* get current wallclock for componnent */ void platform_dai_wallclock(struct comp_dev *dai, uint64_t *wallclock) { +#ifndef CONFIG_SOF_USERSPACE_LL *wallclock = sof_cycle_get_64(); +#else + *wallclock = k_uptime_ticks(); +#endif } /* @@ -304,15 +335,43 @@ volatile int *_sof_fatal_null = NULL; struct arch_esf; +#if CONFIG_SOF_BOOT_TEST +static struct k_thread *sof_boot_test_fault_thread; + +void sof_boot_test_set_fault_valid(struct k_thread *thread) +{ + sof_boot_test_fault_thread = thread; +} + +static bool sof_boot_test_fault_expected(void) +{ + if (sof_boot_test_fault_thread != k_current_get()) + return false; + + sof_boot_test_fault_thread = NULL; + return true; +} +#endif + void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *esf) { ARG_UNUSED(esf); +#if CONFIG_SOF_BOOT_TEST + if (sof_boot_test_fault_expected()) { + LOG_ERR("Expected fatal error as part of boot test"); + return; + } +#endif + /* flush and switch to immediate mode */ LOG_PANIC(); + /* IPC not set up in standalone test mode */ +#ifndef CONFIG_SOF_BOOT_TEST_STANDALONE ipc_send_panic_notification(); +#endif #if defined(CONFIG_ARCH_POSIX) || defined(CONFIG_ZEPHYR_POSIX) LOG_ERR("Halting emulation");